1pub use crate::{
2 diagnostic_set::DiagnosticSet,
3 highlight_map::{HighlightId, HighlightMap},
4 markdown::ParsedMarkdown,
5 proto, Grammar, Language, LanguageRegistry,
6};
7use crate::{
8 diagnostic_set::{DiagnosticEntry, DiagnosticGroup},
9 language_settings::{language_settings, LanguageSettings},
10 markdown::parse_markdown,
11 outline::OutlineItem,
12 syntax_map::{
13 SyntaxLayer, SyntaxMap, SyntaxMapCapture, SyntaxMapCaptures, SyntaxMapMatches,
14 SyntaxSnapshot, ToTreeSitterPoint,
15 },
16 CodeLabel, LanguageScope, Outline,
17};
18use anyhow::{anyhow, Context, Result};
19pub use clock::ReplicaId;
20use futures::channel::oneshot;
21use gpui::{AppContext, EventEmitter, HighlightStyle, ModelContext, Task, TaskLabel};
22use lazy_static::lazy_static;
23use lsp::LanguageServerId;
24use parking_lot::Mutex;
25use similar::{ChangeTag, TextDiff};
26use smallvec::SmallVec;
27use smol::future::yield_now;
28use std::{
29 any::Any,
30 cmp::{self, Ordering},
31 collections::BTreeMap,
32 ffi::OsStr,
33 future::Future,
34 iter::{self, Iterator, Peekable},
35 mem,
36 ops::{Deref, Range},
37 path::{Path, PathBuf},
38 str,
39 sync::Arc,
40 time::{Duration, Instant, SystemTime, UNIX_EPOCH},
41 vec,
42};
43use sum_tree::TreeMap;
44use text::operation_queue::OperationQueue;
45use text::*;
46pub use text::{
47 Anchor, Bias, Buffer as TextBuffer, BufferId, BufferSnapshot as TextBufferSnapshot, Edit,
48 OffsetRangeExt, OffsetUtf16, Patch, Point, PointUtf16, Rope, RopeFingerprint, Selection,
49 SelectionGoal, Subscription, TextDimension, TextSummary, ToOffset, ToOffsetUtf16, ToPoint,
50 ToPointUtf16, Transaction, TransactionId, Unclipped,
51};
52use theme::SyntaxTheme;
53#[cfg(any(test, feature = "test-support"))]
54use util::RandomCharIter;
55use util::RangeExt;
56
57#[cfg(any(test, feature = "test-support"))]
58pub use {tree_sitter_rust, tree_sitter_typescript};
59
60pub use lsp::DiagnosticSeverity;
61
62lazy_static! {
63 /// A label for the background task spawned by the buffer to compute
64 /// a diff against the contents of its file.
65 pub static ref BUFFER_DIFF_TASK: TaskLabel = TaskLabel::new();
66}
67
68/// Indicate whether a [Buffer] has permissions to edit.
69#[derive(PartialEq, Clone, Copy, Debug)]
70pub enum Capability {
71 /// The buffer is a mutable replica.
72 ReadWrite,
73 /// The buffer is a read-only replica.
74 ReadOnly,
75}
76
77/// An in-memory representation of a source code file, including its text,
78/// syntax trees, git status, and diagnostics.
79pub struct Buffer {
80 text: TextBuffer,
81 diff_base: Option<String>,
82 git_diff: git::diff::BufferDiff,
83 file: Option<Arc<dyn File>>,
84 /// The mtime of the file when this buffer was last loaded from
85 /// or saved to disk.
86 saved_mtime: SystemTime,
87 /// The version vector when this buffer was last loaded from
88 /// or saved to disk.
89 saved_version: clock::Global,
90 /// A hash of the current contents of the buffer's file.
91 file_fingerprint: RopeFingerprint,
92 transaction_depth: usize,
93 was_dirty_before_starting_transaction: Option<bool>,
94 reload_task: Option<Task<Result<()>>>,
95 language: Option<Arc<Language>>,
96 autoindent_requests: Vec<Arc<AutoindentRequest>>,
97 pending_autoindent: Option<Task<()>>,
98 sync_parse_timeout: Duration,
99 syntax_map: Mutex<SyntaxMap>,
100 parsing_in_background: bool,
101 parse_count: usize,
102 diagnostics: SmallVec<[(LanguageServerId, DiagnosticSet); 2]>,
103 remote_selections: TreeMap<ReplicaId, SelectionSet>,
104 selections_update_count: usize,
105 diagnostics_update_count: usize,
106 diagnostics_timestamp: clock::Lamport,
107 file_update_count: usize,
108 git_diff_update_count: usize,
109 completion_triggers: Vec<String>,
110 completion_triggers_timestamp: clock::Lamport,
111 deferred_ops: OperationQueue<Operation>,
112 capability: Capability,
113}
114
115/// An immutable, cheaply cloneable representation of a fixed
116/// state of a buffer.
117pub struct BufferSnapshot {
118 text: text::BufferSnapshot,
119 git_diff: git::diff::BufferDiff,
120 pub(crate) syntax: SyntaxSnapshot,
121 file: Option<Arc<dyn File>>,
122 diagnostics: SmallVec<[(LanguageServerId, DiagnosticSet); 2]>,
123 diagnostics_update_count: usize,
124 file_update_count: usize,
125 git_diff_update_count: usize,
126 remote_selections: TreeMap<ReplicaId, SelectionSet>,
127 selections_update_count: usize,
128 language: Option<Arc<Language>>,
129 parse_count: usize,
130}
131
132/// The kind and amount of indentation in a particular line. For now,
133/// assumes that indentation is all the same character.
134#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
135pub struct IndentSize {
136 /// The number of bytes that comprise the indentation.
137 pub len: u32,
138 /// The kind of whitespace used for indentation.
139 pub kind: IndentKind,
140}
141
142/// A whitespace character that's used for indentation.
143#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
144pub enum IndentKind {
145 /// An ASCII space character.
146 #[default]
147 Space,
148 /// An ASCII tab character.
149 Tab,
150}
151
152/// The shape of a selection cursor.
153#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
154pub enum CursorShape {
155 /// A vertical bar
156 #[default]
157 Bar,
158 /// A block that surrounds the following character
159 Block,
160 /// An underline that runs along the following character
161 Underscore,
162 /// A box drawn around the following character
163 Hollow,
164}
165
166#[derive(Clone, Debug)]
167struct SelectionSet {
168 line_mode: bool,
169 cursor_shape: CursorShape,
170 selections: Arc<[Selection<Anchor>]>,
171 lamport_timestamp: clock::Lamport,
172}
173
174/// A diagnostic associated with a certain range of a buffer.
175#[derive(Clone, Debug, PartialEq, Eq)]
176pub struct Diagnostic {
177 /// The name of the service that produced this diagnostic.
178 pub source: Option<String>,
179 /// A machine-readable code that identifies this diagnostic.
180 pub code: Option<String>,
181 /// Whether this diagnostic is a hint, warning, or error.
182 pub severity: DiagnosticSeverity,
183 /// The human-readable message associated with this diagnostic.
184 pub message: String,
185 /// An id that identifies the group to which this diagnostic belongs.
186 ///
187 /// When a language server produces a diagnostic with
188 /// one or more associated diagnostics, those diagnostics are all
189 /// assigned a single group id.
190 pub group_id: usize,
191 /// Whether this diagnostic is the primary diagnostic for its group.
192 ///
193 /// In a given group, the primary diagnostic is the top-level diagnostic
194 /// returned by the language server. The non-primary diagnostics are the
195 /// associated diagnostics.
196 pub is_primary: bool,
197 /// Whether this diagnostic is considered to originate from an analysis of
198 /// files on disk, as opposed to any unsaved buffer contents. This is a
199 /// property of a given diagnostic source, and is configured for a given
200 /// language server via the [`LspAdapter::disk_based_diagnostic_sources`](crate::LspAdapter::disk_based_diagnostic_sources) method
201 /// for the language server.
202 pub is_disk_based: bool,
203 /// Whether this diagnostic marks unnecessary code.
204 pub is_unnecessary: bool,
205}
206
207/// TODO - move this into the `project` crate and make it private.
208pub async fn prepare_completion_documentation(
209 documentation: &lsp::Documentation,
210 language_registry: &Arc<LanguageRegistry>,
211 language: Option<Arc<Language>>,
212) -> Documentation {
213 match documentation {
214 lsp::Documentation::String(text) => {
215 if text.lines().count() <= 1 {
216 Documentation::SingleLine(text.clone())
217 } else {
218 Documentation::MultiLinePlainText(text.clone())
219 }
220 }
221
222 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
223 lsp::MarkupKind::PlainText => {
224 if value.lines().count() <= 1 {
225 Documentation::SingleLine(value.clone())
226 } else {
227 Documentation::MultiLinePlainText(value.clone())
228 }
229 }
230
231 lsp::MarkupKind::Markdown => {
232 let parsed = parse_markdown(value, language_registry, language).await;
233 Documentation::MultiLineMarkdown(parsed)
234 }
235 },
236 }
237}
238
239/// Documentation associated with a [`Completion`].
240#[derive(Clone, Debug)]
241pub enum Documentation {
242 /// There is no documentation for this completion.
243 Undocumented,
244 /// A single line of documentation.
245 SingleLine(String),
246 /// Multiple lines of plain text documentation.
247 MultiLinePlainText(String),
248 /// Markdown documentation.
249 MultiLineMarkdown(ParsedMarkdown),
250}
251
252/// A completion provided by a language server
253#[derive(Clone, Debug)]
254pub struct Completion {
255 /// The range of the buffer that will be replaced.
256 pub old_range: Range<Anchor>,
257 /// The new text that will be inserted.
258 pub new_text: String,
259 /// A label for this completion that is shown in the menu.
260 pub label: CodeLabel,
261 /// The id of the language server that produced this completion.
262 pub server_id: LanguageServerId,
263 /// The documentation for this completion.
264 pub documentation: Option<Documentation>,
265 /// The raw completion provided by the language server.
266 pub lsp_completion: lsp::CompletionItem,
267}
268
269/// A code action provided by a language server.
270#[derive(Clone, Debug)]
271pub struct CodeAction {
272 /// The id of the language server that produced this code action.
273 pub server_id: LanguageServerId,
274 /// The range of the buffer where this code action is applicable.
275 pub range: Range<Anchor>,
276 /// The raw code action provided by the language server.
277 pub lsp_action: lsp::CodeAction,
278}
279
280/// An operation used to synchronize this buffer with its other replicas.
281#[derive(Clone, Debug, PartialEq)]
282pub enum Operation {
283 /// A text operation.
284 Buffer(text::Operation),
285
286 /// An update to the buffer's diagnostics.
287 UpdateDiagnostics {
288 /// The id of the language server that produced the new diagnostics.
289 server_id: LanguageServerId,
290 /// The diagnostics.
291 diagnostics: Arc<[DiagnosticEntry<Anchor>]>,
292 /// The buffer's lamport timestamp.
293 lamport_timestamp: clock::Lamport,
294 },
295
296 /// An update to the most recent selections in this buffer.
297 UpdateSelections {
298 /// The selections.
299 selections: Arc<[Selection<Anchor>]>,
300 /// The buffer's lamport timestamp.
301 lamport_timestamp: clock::Lamport,
302 /// Whether the selections are in 'line mode'.
303 line_mode: bool,
304 /// The [`CursorShape`] associated with these selections.
305 cursor_shape: CursorShape,
306 },
307
308 /// An update to the characters that should trigger autocompletion
309 /// for this buffer.
310 UpdateCompletionTriggers {
311 /// The characters that trigger autocompletion.
312 triggers: Vec<String>,
313 /// The buffer's lamport timestamp.
314 lamport_timestamp: clock::Lamport,
315 },
316}
317
318/// An event that occurs in a buffer.
319#[derive(Clone, Debug, PartialEq)]
320pub enum Event {
321 /// The buffer was changed in a way that must be
322 /// propagated to its other replicas.
323 Operation(Operation),
324 /// The buffer was edited.
325 Edited,
326 /// The buffer's `dirty` bit changed.
327 DirtyChanged,
328 /// The buffer was saved.
329 Saved,
330 /// The buffer's file was changed on disk.
331 FileHandleChanged,
332 /// The buffer was reloaded.
333 Reloaded,
334 /// The buffer's diff_base changed.
335 DiffBaseChanged,
336 /// The buffer's language was changed.
337 LanguageChanged,
338 /// The buffer's syntax trees were updated.
339 Reparsed,
340 /// The buffer's diagnostics were updated.
341 DiagnosticsUpdated,
342 /// The buffer gained or lost editing capabilities.
343 CapabilityChanged,
344 /// The buffer was explicitly requested to close.
345 Closed,
346}
347
348/// The file associated with a buffer.
349pub trait File: Send + Sync {
350 /// Returns the [`LocalFile`] associated with this file, if the
351 /// file is local.
352 fn as_local(&self) -> Option<&dyn LocalFile>;
353
354 /// Returns whether this file is local.
355 fn is_local(&self) -> bool {
356 self.as_local().is_some()
357 }
358
359 /// Returns the file's mtime.
360 fn mtime(&self) -> SystemTime;
361
362 /// Returns the path of this file relative to the worktree's root directory.
363 fn path(&self) -> &Arc<Path>;
364
365 /// Returns the path of this file relative to the worktree's parent directory (this means it
366 /// includes the name of the worktree's root folder).
367 fn full_path(&self, cx: &AppContext) -> PathBuf;
368
369 /// Returns the last component of this handle's absolute path. If this handle refers to the root
370 /// of its worktree, then this method will return the name of the worktree itself.
371 fn file_name<'a>(&'a self, cx: &'a AppContext) -> &'a OsStr;
372
373 /// Returns the id of the worktree to which this file belongs.
374 ///
375 /// This is needed for looking up project-specific settings.
376 fn worktree_id(&self) -> usize;
377
378 /// Returns whether the file has been deleted.
379 fn is_deleted(&self) -> bool;
380
381 /// Converts this file into an [`Any`] trait object.
382 fn as_any(&self) -> &dyn Any;
383
384 /// Converts this file into a protobuf message.
385 fn to_proto(&self) -> rpc::proto::File;
386}
387
388/// The file associated with a buffer, in the case where the file is on the local disk.
389pub trait LocalFile: File {
390 /// Returns the absolute path of this file.
391 fn abs_path(&self, cx: &AppContext) -> PathBuf;
392
393 /// Loads the file's contents from disk.
394 fn load(&self, cx: &AppContext) -> Task<Result<String>>;
395
396 /// Called when the buffer is reloaded from disk.
397 fn buffer_reloaded(
398 &self,
399 buffer_id: BufferId,
400 version: &clock::Global,
401 fingerprint: RopeFingerprint,
402 line_ending: LineEnding,
403 mtime: SystemTime,
404 cx: &mut AppContext,
405 );
406}
407
408/// The auto-indent behavior associated with an editing operation.
409/// For some editing operations, each affected line of text has its
410/// indentation recomputed. For other operations, the entire block
411/// of edited text is adjusted uniformly.
412#[derive(Clone, Debug)]
413pub enum AutoindentMode {
414 /// Indent each line of inserted text.
415 EachLine,
416 /// Apply the same indentation adjustment to all of the lines
417 /// in a given insertion.
418 Block {
419 /// The original indentation level of the first line of each
420 /// insertion, if it has been copied.
421 original_indent_columns: Vec<u32>,
422 },
423}
424
425#[derive(Clone)]
426struct AutoindentRequest {
427 before_edit: BufferSnapshot,
428 entries: Vec<AutoindentRequestEntry>,
429 is_block_mode: bool,
430}
431
432#[derive(Clone)]
433struct AutoindentRequestEntry {
434 /// A range of the buffer whose indentation should be adjusted.
435 range: Range<Anchor>,
436 /// Whether or not these lines should be considered brand new, for the
437 /// purpose of auto-indent. When text is not new, its indentation will
438 /// only be adjusted if the suggested indentation level has *changed*
439 /// since the edit was made.
440 first_line_is_new: bool,
441 indent_size: IndentSize,
442 original_indent_column: Option<u32>,
443}
444
445#[derive(Debug)]
446struct IndentSuggestion {
447 basis_row: u32,
448 delta: Ordering,
449 within_error: bool,
450}
451
452struct BufferChunkHighlights<'a> {
453 captures: SyntaxMapCaptures<'a>,
454 next_capture: Option<SyntaxMapCapture<'a>>,
455 stack: Vec<(usize, HighlightId)>,
456 highlight_maps: Vec<HighlightMap>,
457}
458
459/// An iterator that yields chunks of a buffer's text, along with their
460/// syntax highlights and diagnostic status.
461pub struct BufferChunks<'a> {
462 range: Range<usize>,
463 chunks: text::Chunks<'a>,
464 diagnostic_endpoints: Peekable<vec::IntoIter<DiagnosticEndpoint>>,
465 error_depth: usize,
466 warning_depth: usize,
467 information_depth: usize,
468 hint_depth: usize,
469 unnecessary_depth: usize,
470 highlights: Option<BufferChunkHighlights<'a>>,
471}
472
473/// A chunk of a buffer's text, along with its syntax highlight and
474/// diagnostic status.
475#[derive(Clone, Copy, Debug, Default)]
476pub struct Chunk<'a> {
477 /// The text of the chunk.
478 pub text: &'a str,
479 /// The syntax highlighting style of the chunk.
480 pub syntax_highlight_id: Option<HighlightId>,
481 /// The highlight style that has been applied to this chunk in
482 /// the editor.
483 pub highlight_style: Option<HighlightStyle>,
484 /// The severity of diagnostic associated with this chunk, if any.
485 pub diagnostic_severity: Option<DiagnosticSeverity>,
486 /// Whether this chunk of text is marked as unnecessary.
487 pub is_unnecessary: bool,
488 /// Whether this chunk of text was originally a tab character.
489 pub is_tab: bool,
490}
491
492/// A set of edits to a given version of a buffer, computed asynchronously.
493pub struct Diff {
494 pub(crate) base_version: clock::Global,
495 line_ending: LineEnding,
496 edits: Vec<(Range<usize>, Arc<str>)>,
497}
498
499#[derive(Clone, Copy)]
500pub(crate) struct DiagnosticEndpoint {
501 offset: usize,
502 is_start: bool,
503 severity: DiagnosticSeverity,
504 is_unnecessary: bool,
505}
506
507/// A class of characters, used for characterizing a run of text.
508#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug)]
509pub enum CharKind {
510 /// Whitespace.
511 Whitespace,
512 /// Punctuation.
513 Punctuation,
514 /// Word.
515 Word,
516}
517
518impl Buffer {
519 /// Create a new buffer with the given base text.
520 pub fn new<T: Into<String>>(replica_id: ReplicaId, id: BufferId, base_text: T) -> Self {
521 Self::build(
522 TextBuffer::new(replica_id, id, base_text.into()),
523 None,
524 None,
525 Capability::ReadWrite,
526 )
527 }
528
529 /// Create a new buffer that is a replica of a remote buffer.
530 pub fn remote(
531 remote_id: BufferId,
532 replica_id: ReplicaId,
533 capability: Capability,
534 base_text: String,
535 ) -> Self {
536 Self::build(
537 TextBuffer::new(replica_id, remote_id, base_text),
538 None,
539 None,
540 capability,
541 )
542 }
543
544 /// Create a new buffer that is a replica of a remote buffer, populating its
545 /// state from the given protobuf message.
546 pub fn from_proto(
547 replica_id: ReplicaId,
548 capability: Capability,
549 message: proto::BufferState,
550 file: Option<Arc<dyn File>>,
551 ) -> Result<Self> {
552 let buffer_id = BufferId::new(message.id)
553 .with_context(|| anyhow!("Could not deserialize buffer_id"))?;
554 let buffer = TextBuffer::new(replica_id, buffer_id, message.base_text);
555 let mut this = Self::build(
556 buffer,
557 message.diff_base.map(|text| text.into_boxed_str().into()),
558 file,
559 capability,
560 );
561 this.text.set_line_ending(proto::deserialize_line_ending(
562 rpc::proto::LineEnding::from_i32(message.line_ending)
563 .ok_or_else(|| anyhow!("missing line_ending"))?,
564 ));
565 this.saved_version = proto::deserialize_version(&message.saved_version);
566 this.file_fingerprint = proto::deserialize_fingerprint(&message.saved_version_fingerprint)?;
567 this.saved_mtime = message
568 .saved_mtime
569 .ok_or_else(|| anyhow!("invalid saved_mtime"))?
570 .into();
571 Ok(this)
572 }
573
574 /// Serialize the buffer's state to a protobuf message.
575 pub fn to_proto(&self) -> proto::BufferState {
576 proto::BufferState {
577 id: self.remote_id().into(),
578 file: self.file.as_ref().map(|f| f.to_proto()),
579 base_text: self.base_text().to_string(),
580 diff_base: self.diff_base.as_ref().map(|h| h.to_string()),
581 line_ending: proto::serialize_line_ending(self.line_ending()) as i32,
582 saved_version: proto::serialize_version(&self.saved_version),
583 saved_version_fingerprint: proto::serialize_fingerprint(self.file_fingerprint),
584 saved_mtime: Some(self.saved_mtime.into()),
585 }
586 }
587
588 /// Serialize as protobufs all of the changes to the buffer since the given version.
589 pub fn serialize_ops(
590 &self,
591 since: Option<clock::Global>,
592 cx: &AppContext,
593 ) -> Task<Vec<proto::Operation>> {
594 let mut operations = Vec::new();
595 operations.extend(self.deferred_ops.iter().map(proto::serialize_operation));
596
597 operations.extend(self.remote_selections.iter().map(|(_, set)| {
598 proto::serialize_operation(&Operation::UpdateSelections {
599 selections: set.selections.clone(),
600 lamport_timestamp: set.lamport_timestamp,
601 line_mode: set.line_mode,
602 cursor_shape: set.cursor_shape,
603 })
604 }));
605
606 for (server_id, diagnostics) in &self.diagnostics {
607 operations.push(proto::serialize_operation(&Operation::UpdateDiagnostics {
608 lamport_timestamp: self.diagnostics_timestamp,
609 server_id: *server_id,
610 diagnostics: diagnostics.iter().cloned().collect(),
611 }));
612 }
613
614 operations.push(proto::serialize_operation(
615 &Operation::UpdateCompletionTriggers {
616 triggers: self.completion_triggers.clone(),
617 lamport_timestamp: self.completion_triggers_timestamp,
618 },
619 ));
620
621 let text_operations = self.text.operations().clone();
622 cx.background_executor().spawn(async move {
623 let since = since.unwrap_or_default();
624 operations.extend(
625 text_operations
626 .iter()
627 .filter(|(_, op)| !since.observed(op.timestamp()))
628 .map(|(_, op)| proto::serialize_operation(&Operation::Buffer(op.clone()))),
629 );
630 operations.sort_unstable_by_key(proto::lamport_timestamp_for_operation);
631 operations
632 })
633 }
634
635 /// Assign a language to the buffer, returning the buffer.
636 pub fn with_language(mut self, language: Arc<Language>, cx: &mut ModelContext<Self>) -> Self {
637 self.set_language(Some(language), cx);
638 self
639 }
640
641 /// Returns the [Capability] of this buffer.
642 pub fn capability(&self) -> Capability {
643 self.capability
644 }
645
646 /// Whether this buffer can only be read.
647 pub fn read_only(&self) -> bool {
648 self.capability == Capability::ReadOnly
649 }
650
651 /// Builds a [Buffer] with the given underlying [TextBuffer], diff base, [File] and [Capability].
652 pub fn build(
653 buffer: TextBuffer,
654 diff_base: Option<String>,
655 file: Option<Arc<dyn File>>,
656 capability: Capability,
657 ) -> Self {
658 let saved_mtime = if let Some(file) = file.as_ref() {
659 file.mtime()
660 } else {
661 UNIX_EPOCH
662 };
663
664 Self {
665 saved_mtime,
666 saved_version: buffer.version(),
667 file_fingerprint: buffer.as_rope().fingerprint(),
668 reload_task: None,
669 transaction_depth: 0,
670 was_dirty_before_starting_transaction: None,
671 text: buffer,
672 diff_base,
673 git_diff: git::diff::BufferDiff::new(),
674 file,
675 capability,
676 syntax_map: Mutex::new(SyntaxMap::new()),
677 parsing_in_background: false,
678 parse_count: 0,
679 sync_parse_timeout: Duration::from_millis(1),
680 autoindent_requests: Default::default(),
681 pending_autoindent: Default::default(),
682 language: None,
683 remote_selections: Default::default(),
684 selections_update_count: 0,
685 diagnostics: Default::default(),
686 diagnostics_update_count: 0,
687 diagnostics_timestamp: Default::default(),
688 file_update_count: 0,
689 git_diff_update_count: 0,
690 completion_triggers: Default::default(),
691 completion_triggers_timestamp: Default::default(),
692 deferred_ops: OperationQueue::new(),
693 }
694 }
695
696 /// Retrieve a snapshot of the buffer's current state. This is computationally
697 /// cheap, and allows reading from the buffer on a background thread.
698 pub fn snapshot(&self) -> BufferSnapshot {
699 let text = self.text.snapshot();
700 let mut syntax_map = self.syntax_map.lock();
701 syntax_map.interpolate(&text);
702 let syntax = syntax_map.snapshot();
703
704 BufferSnapshot {
705 text,
706 syntax,
707 git_diff: self.git_diff.clone(),
708 file: self.file.clone(),
709 remote_selections: self.remote_selections.clone(),
710 diagnostics: self.diagnostics.clone(),
711 diagnostics_update_count: self.diagnostics_update_count,
712 file_update_count: self.file_update_count,
713 git_diff_update_count: self.git_diff_update_count,
714 language: self.language.clone(),
715 parse_count: self.parse_count,
716 selections_update_count: self.selections_update_count,
717 }
718 }
719
720 #[cfg(test)]
721 pub(crate) fn as_text_snapshot(&self) -> &text::BufferSnapshot {
722 &self.text
723 }
724
725 /// Retrieve a snapshot of the buffer's raw text, without any
726 /// language-related state like the syntax tree or diagnostics.
727 pub fn text_snapshot(&self) -> text::BufferSnapshot {
728 self.text.snapshot()
729 }
730
731 /// The file associated with the buffer, if any.
732 pub fn file(&self) -> Option<&Arc<dyn File>> {
733 self.file.as_ref()
734 }
735
736 /// The version of the buffer that was last saved or reloaded from disk.
737 pub fn saved_version(&self) -> &clock::Global {
738 &self.saved_version
739 }
740
741 /// The fingerprint of the buffer's text when the buffer was last saved or reloaded from disk.
742 pub fn saved_version_fingerprint(&self) -> RopeFingerprint {
743 self.file_fingerprint
744 }
745
746 /// The mtime of the buffer's file when the buffer was last saved or reloaded from disk.
747 pub fn saved_mtime(&self) -> SystemTime {
748 self.saved_mtime
749 }
750
751 /// Assign a language to the buffer.
752 pub fn set_language(&mut self, language: Option<Arc<Language>>, cx: &mut ModelContext<Self>) {
753 self.syntax_map.lock().clear();
754 self.language = language;
755 self.reparse(cx);
756 cx.emit(Event::LanguageChanged);
757 }
758
759 /// Assign a language registry to the buffer. This allows the buffer to retrieve
760 /// other languages if parts of the buffer are written in different languages.
761 pub fn set_language_registry(&mut self, language_registry: Arc<LanguageRegistry>) {
762 self.syntax_map
763 .lock()
764 .set_language_registry(language_registry);
765 }
766
767 /// Assign the buffer a new [Capability].
768 pub fn set_capability(&mut self, capability: Capability, cx: &mut ModelContext<Self>) {
769 self.capability = capability;
770 cx.emit(Event::CapabilityChanged)
771 }
772
773 /// This method is called to signal that the buffer has been saved.
774 pub fn did_save(
775 &mut self,
776 version: clock::Global,
777 fingerprint: RopeFingerprint,
778 mtime: SystemTime,
779 cx: &mut ModelContext<Self>,
780 ) {
781 self.saved_version = version;
782 self.file_fingerprint = fingerprint;
783 self.saved_mtime = mtime;
784 cx.emit(Event::Saved);
785 cx.notify();
786 }
787
788 /// Reloads the contents of the buffer from disk.
789 pub fn reload(
790 &mut self,
791 cx: &mut ModelContext<Self>,
792 ) -> oneshot::Receiver<Option<Transaction>> {
793 let (tx, rx) = futures::channel::oneshot::channel();
794 let prev_version = self.text.version();
795 self.reload_task = Some(cx.spawn(|this, mut cx| async move {
796 let Some((new_mtime, new_text)) = this.update(&mut cx, |this, cx| {
797 let file = this.file.as_ref()?.as_local()?;
798 Some((file.mtime(), file.load(cx)))
799 })?
800 else {
801 return Ok(());
802 };
803
804 let new_text = new_text.await?;
805 let diff = this
806 .update(&mut cx, |this, cx| this.diff(new_text.clone(), cx))?
807 .await;
808 this.update(&mut cx, |this, cx| {
809 if this.version() == diff.base_version {
810 this.finalize_last_transaction();
811 this.apply_diff(diff, cx);
812 tx.send(this.finalize_last_transaction().cloned()).ok();
813
814 this.did_reload(
815 this.version(),
816 this.as_rope().fingerprint(),
817 this.line_ending(),
818 new_mtime,
819 cx,
820 );
821 } else {
822 this.did_reload(
823 prev_version,
824 Rope::text_fingerprint(&new_text),
825 this.line_ending(),
826 this.saved_mtime,
827 cx,
828 );
829 }
830
831 this.reload_task.take();
832 })
833 }));
834 rx
835 }
836
837 /// This method is called to signal that the buffer has been reloaded.
838 pub fn did_reload(
839 &mut self,
840 version: clock::Global,
841 fingerprint: RopeFingerprint,
842 line_ending: LineEnding,
843 mtime: SystemTime,
844 cx: &mut ModelContext<Self>,
845 ) {
846 self.saved_version = version;
847 self.file_fingerprint = fingerprint;
848 self.text.set_line_ending(line_ending);
849 self.saved_mtime = mtime;
850 if let Some(file) = self.file.as_ref().and_then(|f| f.as_local()) {
851 file.buffer_reloaded(
852 self.remote_id(),
853 &self.saved_version,
854 self.file_fingerprint,
855 self.line_ending(),
856 self.saved_mtime,
857 cx,
858 );
859 }
860 cx.emit(Event::Reloaded);
861 cx.notify();
862 }
863
864 /// Updates the [File] backing this buffer. This should be called when
865 /// the file has changed or has been deleted.
866 pub fn file_updated(&mut self, new_file: Arc<dyn File>, cx: &mut ModelContext<Self>) {
867 let mut file_changed = false;
868
869 if let Some(old_file) = self.file.as_ref() {
870 if new_file.path() != old_file.path() {
871 file_changed = true;
872 }
873
874 if new_file.is_deleted() {
875 if !old_file.is_deleted() {
876 file_changed = true;
877 if !self.is_dirty() {
878 cx.emit(Event::DirtyChanged);
879 }
880 }
881 } else {
882 let new_mtime = new_file.mtime();
883 if new_mtime != old_file.mtime() {
884 file_changed = true;
885
886 if !self.is_dirty() {
887 self.reload(cx).close();
888 }
889 }
890 }
891 } else {
892 file_changed = true;
893 };
894
895 self.file = Some(new_file);
896 if file_changed {
897 self.file_update_count += 1;
898 cx.emit(Event::FileHandleChanged);
899 cx.notify();
900 }
901 }
902
903 /// Returns the current diff base, see [Buffer::set_diff_base].
904 pub fn diff_base(&self) -> Option<&str> {
905 self.diff_base.as_deref()
906 }
907
908 /// Sets the text that will be used to compute a Git diff
909 /// against the buffer text.
910 pub fn set_diff_base(&mut self, diff_base: Option<String>, cx: &mut ModelContext<Self>) {
911 self.diff_base = diff_base;
912 self.git_diff_recalc(cx);
913 cx.emit(Event::DiffBaseChanged);
914 }
915
916 /// Recomputes the Git diff status.
917 pub fn git_diff_recalc(&mut self, cx: &mut ModelContext<Self>) -> Option<Task<()>> {
918 let diff_base = self.diff_base.clone()?; // TODO: Make this an Arc
919 let snapshot = self.snapshot();
920
921 let mut diff = self.git_diff.clone();
922 let diff = cx.background_executor().spawn(async move {
923 diff.update(&diff_base, &snapshot).await;
924 diff
925 });
926
927 Some(cx.spawn(|this, mut cx| async move {
928 let buffer_diff = diff.await;
929 this.update(&mut cx, |this, _| {
930 this.git_diff = buffer_diff;
931 this.git_diff_update_count += 1;
932 })
933 .ok();
934 }))
935 }
936
937 /// Returns the primary [Language] assigned to this [Buffer].
938 pub fn language(&self) -> Option<&Arc<Language>> {
939 self.language.as_ref()
940 }
941
942 /// Returns the [Language] at the given location.
943 pub fn language_at<D: ToOffset>(&self, position: D) -> Option<Arc<Language>> {
944 let offset = position.to_offset(self);
945 self.syntax_map
946 .lock()
947 .layers_for_range(offset..offset, &self.text)
948 .last()
949 .map(|info| info.language.clone())
950 .or_else(|| self.language.clone())
951 }
952
953 /// The number of times the buffer was parsed.
954 pub fn parse_count(&self) -> usize {
955 self.parse_count
956 }
957
958 /// The number of times selections were updated.
959 pub fn selections_update_count(&self) -> usize {
960 self.selections_update_count
961 }
962
963 /// The number of times diagnostics were updated.
964 pub fn diagnostics_update_count(&self) -> usize {
965 self.diagnostics_update_count
966 }
967
968 /// The number of times the underlying file was updated.
969 pub fn file_update_count(&self) -> usize {
970 self.file_update_count
971 }
972
973 /// The number of times the git diff status was updated.
974 pub fn git_diff_update_count(&self) -> usize {
975 self.git_diff_update_count
976 }
977
978 /// Whether the buffer is being parsed in the background.
979 #[cfg(any(test, feature = "test-support"))]
980 pub fn is_parsing(&self) -> bool {
981 self.parsing_in_background
982 }
983
984 /// Indicates whether the buffer contains any regions that may be
985 /// written in a language that hasn't been loaded yet.
986 pub fn contains_unknown_injections(&self) -> bool {
987 self.syntax_map.lock().contains_unknown_injections()
988 }
989
990 #[cfg(test)]
991 pub fn set_sync_parse_timeout(&mut self, timeout: Duration) {
992 self.sync_parse_timeout = timeout;
993 }
994
995 /// Called after an edit to synchronize the buffer's main parse tree with
996 /// the buffer's new underlying state.
997 ///
998 /// Locks the syntax map and interpolates the edits since the last reparse
999 /// into the foreground syntax tree.
1000 ///
1001 /// Then takes a stable snapshot of the syntax map before unlocking it.
1002 /// The snapshot with the interpolated edits is sent to a background thread,
1003 /// where we ask Tree-sitter to perform an incremental parse.
1004 ///
1005 /// Meanwhile, in the foreground, we block the main thread for up to 1ms
1006 /// waiting on the parse to complete. As soon as it completes, we proceed
1007 /// synchronously, unless a 1ms timeout elapses.
1008 ///
1009 /// If we time out waiting on the parse, we spawn a second task waiting
1010 /// until the parse does complete and return with the interpolated tree still
1011 /// in the foreground. When the background parse completes, call back into
1012 /// the main thread and assign the foreground parse state.
1013 ///
1014 /// If the buffer or grammar changed since the start of the background parse,
1015 /// initiate an additional reparse recursively. To avoid concurrent parses
1016 /// for the same buffer, we only initiate a new parse if we are not already
1017 /// parsing in the background.
1018 pub fn reparse(&mut self, cx: &mut ModelContext<Self>) {
1019 if self.parsing_in_background {
1020 return;
1021 }
1022 let language = if let Some(language) = self.language.clone() {
1023 language
1024 } else {
1025 return;
1026 };
1027
1028 let text = self.text_snapshot();
1029 let parsed_version = self.version();
1030
1031 let mut syntax_map = self.syntax_map.lock();
1032 syntax_map.interpolate(&text);
1033 let language_registry = syntax_map.language_registry();
1034 let mut syntax_snapshot = syntax_map.snapshot();
1035 drop(syntax_map);
1036
1037 let parse_task = cx.background_executor().spawn({
1038 let language = language.clone();
1039 let language_registry = language_registry.clone();
1040 async move {
1041 syntax_snapshot.reparse(&text, language_registry, language);
1042 syntax_snapshot
1043 }
1044 });
1045
1046 match cx
1047 .background_executor()
1048 .block_with_timeout(self.sync_parse_timeout, parse_task)
1049 {
1050 Ok(new_syntax_snapshot) => {
1051 self.did_finish_parsing(new_syntax_snapshot, cx);
1052 return;
1053 }
1054 Err(parse_task) => {
1055 self.parsing_in_background = true;
1056 cx.spawn(move |this, mut cx| async move {
1057 let new_syntax_map = parse_task.await;
1058 this.update(&mut cx, move |this, cx| {
1059 let grammar_changed =
1060 this.language.as_ref().map_or(true, |current_language| {
1061 !Arc::ptr_eq(&language, current_language)
1062 });
1063 let language_registry_changed = new_syntax_map
1064 .contains_unknown_injections()
1065 && language_registry.map_or(false, |registry| {
1066 registry.version() != new_syntax_map.language_registry_version()
1067 });
1068 let parse_again = language_registry_changed
1069 || grammar_changed
1070 || this.version.changed_since(&parsed_version);
1071 this.did_finish_parsing(new_syntax_map, cx);
1072 this.parsing_in_background = false;
1073 if parse_again {
1074 this.reparse(cx);
1075 }
1076 })
1077 .ok();
1078 })
1079 .detach();
1080 }
1081 }
1082 }
1083
1084 fn did_finish_parsing(&mut self, syntax_snapshot: SyntaxSnapshot, cx: &mut ModelContext<Self>) {
1085 self.parse_count += 1;
1086 self.syntax_map.lock().did_parse(syntax_snapshot);
1087 self.request_autoindent(cx);
1088 cx.emit(Event::Reparsed);
1089 cx.notify();
1090 }
1091
1092 /// Assign to the buffer a set of diagnostics created by a given language server.
1093 pub fn update_diagnostics(
1094 &mut self,
1095 server_id: LanguageServerId,
1096 diagnostics: DiagnosticSet,
1097 cx: &mut ModelContext<Self>,
1098 ) {
1099 let lamport_timestamp = self.text.lamport_clock.tick();
1100 let op = Operation::UpdateDiagnostics {
1101 server_id,
1102 diagnostics: diagnostics.iter().cloned().collect(),
1103 lamport_timestamp,
1104 };
1105 self.apply_diagnostic_update(server_id, diagnostics, lamport_timestamp, cx);
1106 self.send_operation(op, cx);
1107 }
1108
1109 fn request_autoindent(&mut self, cx: &mut ModelContext<Self>) {
1110 if let Some(indent_sizes) = self.compute_autoindents() {
1111 let indent_sizes = cx.background_executor().spawn(indent_sizes);
1112 match cx
1113 .background_executor()
1114 .block_with_timeout(Duration::from_micros(500), indent_sizes)
1115 {
1116 Ok(indent_sizes) => self.apply_autoindents(indent_sizes, cx),
1117 Err(indent_sizes) => {
1118 self.pending_autoindent = Some(cx.spawn(|this, mut cx| async move {
1119 let indent_sizes = indent_sizes.await;
1120 this.update(&mut cx, |this, cx| {
1121 this.apply_autoindents(indent_sizes, cx);
1122 })
1123 .ok();
1124 }));
1125 }
1126 }
1127 } else {
1128 self.autoindent_requests.clear();
1129 }
1130 }
1131
1132 fn compute_autoindents(&self) -> Option<impl Future<Output = BTreeMap<u32, IndentSize>>> {
1133 let max_rows_between_yields = 100;
1134 let snapshot = self.snapshot();
1135 if snapshot.syntax.is_empty() || self.autoindent_requests.is_empty() {
1136 return None;
1137 }
1138
1139 let autoindent_requests = self.autoindent_requests.clone();
1140 Some(async move {
1141 let mut indent_sizes = BTreeMap::new();
1142 for request in autoindent_requests {
1143 // Resolve each edited range to its row in the current buffer and in the
1144 // buffer before this batch of edits.
1145 let mut row_ranges = Vec::new();
1146 let mut old_to_new_rows = BTreeMap::new();
1147 let mut language_indent_sizes_by_new_row = Vec::new();
1148 for entry in &request.entries {
1149 let position = entry.range.start;
1150 let new_row = position.to_point(&snapshot).row;
1151 let new_end_row = entry.range.end.to_point(&snapshot).row + 1;
1152 language_indent_sizes_by_new_row.push((new_row, entry.indent_size));
1153
1154 if !entry.first_line_is_new {
1155 let old_row = position.to_point(&request.before_edit).row;
1156 old_to_new_rows.insert(old_row, new_row);
1157 }
1158 row_ranges.push((new_row..new_end_row, entry.original_indent_column));
1159 }
1160
1161 // Build a map containing the suggested indentation for each of the edited lines
1162 // with respect to the state of the buffer before these edits. This map is keyed
1163 // by the rows for these lines in the current state of the buffer.
1164 let mut old_suggestions = BTreeMap::<u32, (IndentSize, bool)>::default();
1165 let old_edited_ranges =
1166 contiguous_ranges(old_to_new_rows.keys().copied(), max_rows_between_yields);
1167 let mut language_indent_sizes = language_indent_sizes_by_new_row.iter().peekable();
1168 let mut language_indent_size = IndentSize::default();
1169 for old_edited_range in old_edited_ranges {
1170 let suggestions = request
1171 .before_edit
1172 .suggest_autoindents(old_edited_range.clone())
1173 .into_iter()
1174 .flatten();
1175 for (old_row, suggestion) in old_edited_range.zip(suggestions) {
1176 if let Some(suggestion) = suggestion {
1177 let new_row = *old_to_new_rows.get(&old_row).unwrap();
1178
1179 // Find the indent size based on the language for this row.
1180 while let Some((row, size)) = language_indent_sizes.peek() {
1181 if *row > new_row {
1182 break;
1183 }
1184 language_indent_size = *size;
1185 language_indent_sizes.next();
1186 }
1187
1188 let suggested_indent = old_to_new_rows
1189 .get(&suggestion.basis_row)
1190 .and_then(|from_row| {
1191 Some(old_suggestions.get(from_row).copied()?.0)
1192 })
1193 .unwrap_or_else(|| {
1194 request
1195 .before_edit
1196 .indent_size_for_line(suggestion.basis_row)
1197 })
1198 .with_delta(suggestion.delta, language_indent_size);
1199 old_suggestions
1200 .insert(new_row, (suggested_indent, suggestion.within_error));
1201 }
1202 }
1203 yield_now().await;
1204 }
1205
1206 // In block mode, only compute indentation suggestions for the first line
1207 // of each insertion. Otherwise, compute suggestions for every inserted line.
1208 let new_edited_row_ranges = contiguous_ranges(
1209 row_ranges.iter().flat_map(|(range, _)| {
1210 if request.is_block_mode {
1211 range.start..range.start + 1
1212 } else {
1213 range.clone()
1214 }
1215 }),
1216 max_rows_between_yields,
1217 );
1218
1219 // Compute new suggestions for each line, but only include them in the result
1220 // if they differ from the old suggestion for that line.
1221 let mut language_indent_sizes = language_indent_sizes_by_new_row.iter().peekable();
1222 let mut language_indent_size = IndentSize::default();
1223 for new_edited_row_range in new_edited_row_ranges {
1224 let suggestions = snapshot
1225 .suggest_autoindents(new_edited_row_range.clone())
1226 .into_iter()
1227 .flatten();
1228 for (new_row, suggestion) in new_edited_row_range.zip(suggestions) {
1229 if let Some(suggestion) = suggestion {
1230 // Find the indent size based on the language for this row.
1231 while let Some((row, size)) = language_indent_sizes.peek() {
1232 if *row > new_row {
1233 break;
1234 }
1235 language_indent_size = *size;
1236 language_indent_sizes.next();
1237 }
1238
1239 let suggested_indent = indent_sizes
1240 .get(&suggestion.basis_row)
1241 .copied()
1242 .unwrap_or_else(|| {
1243 snapshot.indent_size_for_line(suggestion.basis_row)
1244 })
1245 .with_delta(suggestion.delta, language_indent_size);
1246 if old_suggestions.get(&new_row).map_or(
1247 true,
1248 |(old_indentation, was_within_error)| {
1249 suggested_indent != *old_indentation
1250 && (!suggestion.within_error || *was_within_error)
1251 },
1252 ) {
1253 indent_sizes.insert(new_row, suggested_indent);
1254 }
1255 }
1256 }
1257 yield_now().await;
1258 }
1259
1260 // For each block of inserted text, adjust the indentation of the remaining
1261 // lines of the block by the same amount as the first line was adjusted.
1262 if request.is_block_mode {
1263 for (row_range, original_indent_column) in
1264 row_ranges
1265 .into_iter()
1266 .filter_map(|(range, original_indent_column)| {
1267 if range.len() > 1 {
1268 Some((range, original_indent_column?))
1269 } else {
1270 None
1271 }
1272 })
1273 {
1274 let new_indent = indent_sizes
1275 .get(&row_range.start)
1276 .copied()
1277 .unwrap_or_else(|| snapshot.indent_size_for_line(row_range.start));
1278 let delta = new_indent.len as i64 - original_indent_column as i64;
1279 if delta != 0 {
1280 for row in row_range.skip(1) {
1281 indent_sizes.entry(row).or_insert_with(|| {
1282 let mut size = snapshot.indent_size_for_line(row);
1283 if size.kind == new_indent.kind {
1284 match delta.cmp(&0) {
1285 Ordering::Greater => size.len += delta as u32,
1286 Ordering::Less => {
1287 size.len = size.len.saturating_sub(-delta as u32)
1288 }
1289 Ordering::Equal => {}
1290 }
1291 }
1292 size
1293 });
1294 }
1295 }
1296 }
1297 }
1298 }
1299
1300 indent_sizes
1301 })
1302 }
1303
1304 fn apply_autoindents(
1305 &mut self,
1306 indent_sizes: BTreeMap<u32, IndentSize>,
1307 cx: &mut ModelContext<Self>,
1308 ) {
1309 self.autoindent_requests.clear();
1310
1311 let edits: Vec<_> = indent_sizes
1312 .into_iter()
1313 .filter_map(|(row, indent_size)| {
1314 let current_size = indent_size_for_line(self, row);
1315 Self::edit_for_indent_size_adjustment(row, current_size, indent_size)
1316 })
1317 .collect();
1318
1319 self.edit(edits, None, cx);
1320 }
1321
1322 /// Create a minimal edit that will cause the the given row to be indented
1323 /// with the given size. After applying this edit, the length of the line
1324 /// will always be at least `new_size.len`.
1325 pub fn edit_for_indent_size_adjustment(
1326 row: u32,
1327 current_size: IndentSize,
1328 new_size: IndentSize,
1329 ) -> Option<(Range<Point>, String)> {
1330 if new_size.kind != current_size.kind {
1331 Some((
1332 Point::new(row, 0)..Point::new(row, current_size.len),
1333 iter::repeat(new_size.char())
1334 .take(new_size.len as usize)
1335 .collect::<String>(),
1336 ))
1337 } else {
1338 match new_size.len.cmp(¤t_size.len) {
1339 Ordering::Greater => {
1340 let point = Point::new(row, 0);
1341 Some((
1342 point..point,
1343 iter::repeat(new_size.char())
1344 .take((new_size.len - current_size.len) as usize)
1345 .collect::<String>(),
1346 ))
1347 }
1348
1349 Ordering::Less => Some((
1350 Point::new(row, 0)..Point::new(row, current_size.len - new_size.len),
1351 String::new(),
1352 )),
1353
1354 Ordering::Equal => None,
1355 }
1356 }
1357 }
1358
1359 /// Spawns a background task that asynchronously computes a `Diff` between the buffer's text
1360 /// and the given new text.
1361 pub fn diff(&self, mut new_text: String, cx: &AppContext) -> Task<Diff> {
1362 let old_text = self.as_rope().clone();
1363 let base_version = self.version();
1364 cx.background_executor()
1365 .spawn_labeled(*BUFFER_DIFF_TASK, async move {
1366 let old_text = old_text.to_string();
1367 let line_ending = LineEnding::detect(&new_text);
1368 LineEnding::normalize(&mut new_text);
1369
1370 let diff = TextDiff::from_chars(old_text.as_str(), new_text.as_str());
1371 let empty: Arc<str> = "".into();
1372
1373 let mut edits = Vec::new();
1374 let mut old_offset = 0;
1375 let mut new_offset = 0;
1376 let mut last_edit: Option<(Range<usize>, Range<usize>)> = None;
1377 for change in diff.iter_all_changes().map(Some).chain([None]) {
1378 if let Some(change) = &change {
1379 let len = change.value().len();
1380 match change.tag() {
1381 ChangeTag::Equal => {
1382 old_offset += len;
1383 new_offset += len;
1384 }
1385 ChangeTag::Delete => {
1386 let old_end_offset = old_offset + len;
1387 if let Some((last_old_range, _)) = &mut last_edit {
1388 last_old_range.end = old_end_offset;
1389 } else {
1390 last_edit =
1391 Some((old_offset..old_end_offset, new_offset..new_offset));
1392 }
1393 old_offset = old_end_offset;
1394 }
1395 ChangeTag::Insert => {
1396 let new_end_offset = new_offset + len;
1397 if let Some((_, last_new_range)) = &mut last_edit {
1398 last_new_range.end = new_end_offset;
1399 } else {
1400 last_edit =
1401 Some((old_offset..old_offset, new_offset..new_end_offset));
1402 }
1403 new_offset = new_end_offset;
1404 }
1405 }
1406 }
1407
1408 if let Some((old_range, new_range)) = &last_edit {
1409 if old_offset > old_range.end
1410 || new_offset > new_range.end
1411 || change.is_none()
1412 {
1413 let text = if new_range.is_empty() {
1414 empty.clone()
1415 } else {
1416 new_text[new_range.clone()].into()
1417 };
1418 edits.push((old_range.clone(), text));
1419 last_edit.take();
1420 }
1421 }
1422 }
1423
1424 Diff {
1425 base_version,
1426 line_ending,
1427 edits,
1428 }
1429 })
1430 }
1431
1432 /// Spawns a background task that searches the buffer for any whitespace
1433 /// at the ends of a lines, and returns a `Diff` that removes that whitespace.
1434 pub fn remove_trailing_whitespace(&self, cx: &AppContext) -> Task<Diff> {
1435 let old_text = self.as_rope().clone();
1436 let line_ending = self.line_ending();
1437 let base_version = self.version();
1438 cx.background_executor().spawn(async move {
1439 let ranges = trailing_whitespace_ranges(&old_text);
1440 let empty = Arc::<str>::from("");
1441 Diff {
1442 base_version,
1443 line_ending,
1444 edits: ranges
1445 .into_iter()
1446 .map(|range| (range, empty.clone()))
1447 .collect(),
1448 }
1449 })
1450 }
1451
1452 /// Ensures that the buffer ends with a single newline character, and
1453 /// no other whitespace.
1454 pub fn ensure_final_newline(&mut self, cx: &mut ModelContext<Self>) {
1455 let len = self.len();
1456 let mut offset = len;
1457 for chunk in self.as_rope().reversed_chunks_in_range(0..len) {
1458 let non_whitespace_len = chunk
1459 .trim_end_matches(|c: char| c.is_ascii_whitespace())
1460 .len();
1461 offset -= chunk.len();
1462 offset += non_whitespace_len;
1463 if non_whitespace_len != 0 {
1464 if offset == len - 1 && chunk.get(non_whitespace_len..) == Some("\n") {
1465 return;
1466 }
1467 break;
1468 }
1469 }
1470 self.edit([(offset..len, "\n")], None, cx);
1471 }
1472
1473 /// Applies a diff to the buffer. If the buffer has changed since the given diff was
1474 /// calculated, then adjust the diff to account for those changes, and discard any
1475 /// parts of the diff that conflict with those changes.
1476 pub fn apply_diff(&mut self, diff: Diff, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1477 // Check for any edits to the buffer that have occurred since this diff
1478 // was computed.
1479 let snapshot = self.snapshot();
1480 let mut edits_since = snapshot.edits_since::<usize>(&diff.base_version).peekable();
1481 let mut delta = 0;
1482 let adjusted_edits = diff.edits.into_iter().filter_map(|(range, new_text)| {
1483 while let Some(edit_since) = edits_since.peek() {
1484 // If the edit occurs after a diff hunk, then it does not
1485 // affect that hunk.
1486 if edit_since.old.start > range.end {
1487 break;
1488 }
1489 // If the edit precedes the diff hunk, then adjust the hunk
1490 // to reflect the edit.
1491 else if edit_since.old.end < range.start {
1492 delta += edit_since.new_len() as i64 - edit_since.old_len() as i64;
1493 edits_since.next();
1494 }
1495 // If the edit intersects a diff hunk, then discard that hunk.
1496 else {
1497 return None;
1498 }
1499 }
1500
1501 let start = (range.start as i64 + delta) as usize;
1502 let end = (range.end as i64 + delta) as usize;
1503 Some((start..end, new_text))
1504 });
1505
1506 self.start_transaction();
1507 self.text.set_line_ending(diff.line_ending);
1508 self.edit(adjusted_edits, None, cx);
1509 self.end_transaction(cx)
1510 }
1511
1512 /// Checks if the buffer has unsaved changes.
1513 pub fn is_dirty(&self) -> bool {
1514 self.file_fingerprint != self.as_rope().fingerprint()
1515 || self.file.as_ref().map_or(false, |file| file.is_deleted())
1516 }
1517
1518 /// Checks if the buffer and its file have both changed since the buffer
1519 /// was last saved or reloaded.
1520 pub fn has_conflict(&self) -> bool {
1521 self.file_fingerprint != self.as_rope().fingerprint()
1522 && self
1523 .file
1524 .as_ref()
1525 .map_or(false, |file| file.mtime() > self.saved_mtime)
1526 }
1527
1528 /// Gets a [`Subscription`] that tracks all of the changes to the buffer's text.
1529 pub fn subscribe(&mut self) -> Subscription {
1530 self.text.subscribe()
1531 }
1532
1533 /// Starts a transaction, if one is not already in-progress. When undoing or
1534 /// redoing edits, all of the edits performed within a transaction are undone
1535 /// or redone together.
1536 pub fn start_transaction(&mut self) -> Option<TransactionId> {
1537 self.start_transaction_at(Instant::now())
1538 }
1539
1540 /// Starts a transaction, providing the current time. Subsequent transactions
1541 /// that occur within a short period of time will be grouped together. This
1542 /// is controlled by the buffer's undo grouping duration.
1543 pub fn start_transaction_at(&mut self, now: Instant) -> Option<TransactionId> {
1544 self.transaction_depth += 1;
1545 if self.was_dirty_before_starting_transaction.is_none() {
1546 self.was_dirty_before_starting_transaction = Some(self.is_dirty());
1547 }
1548 self.text.start_transaction_at(now)
1549 }
1550
1551 /// Terminates the current transaction, if this is the outermost transaction.
1552 pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1553 self.end_transaction_at(Instant::now(), cx)
1554 }
1555
1556 /// Terminates the current transaction, providing the current time. Subsequent transactions
1557 /// that occur within a short period of time will be grouped together. This
1558 /// is controlled by the buffer's undo grouping duration.
1559 pub fn end_transaction_at(
1560 &mut self,
1561 now: Instant,
1562 cx: &mut ModelContext<Self>,
1563 ) -> Option<TransactionId> {
1564 assert!(self.transaction_depth > 0);
1565 self.transaction_depth -= 1;
1566 let was_dirty = if self.transaction_depth == 0 {
1567 self.was_dirty_before_starting_transaction.take().unwrap()
1568 } else {
1569 false
1570 };
1571 if let Some((transaction_id, start_version)) = self.text.end_transaction_at(now) {
1572 self.did_edit(&start_version, was_dirty, cx);
1573 Some(transaction_id)
1574 } else {
1575 None
1576 }
1577 }
1578
1579 /// Manually add a transaction to the buffer's undo history.
1580 pub fn push_transaction(&mut self, transaction: Transaction, now: Instant) {
1581 self.text.push_transaction(transaction, now);
1582 }
1583
1584 /// Prevent the last transaction from being grouped with any subsequent transactions,
1585 /// even if they occur with the buffer's undo grouping duration.
1586 pub fn finalize_last_transaction(&mut self) -> Option<&Transaction> {
1587 self.text.finalize_last_transaction()
1588 }
1589
1590 /// Manually group all changes since a given transaction.
1591 pub fn group_until_transaction(&mut self, transaction_id: TransactionId) {
1592 self.text.group_until_transaction(transaction_id);
1593 }
1594
1595 /// Manually remove a transaction from the buffer's undo history
1596 pub fn forget_transaction(&mut self, transaction_id: TransactionId) {
1597 self.text.forget_transaction(transaction_id);
1598 }
1599
1600 /// Manually merge two adjacent transactions in the buffer's undo history.
1601 pub fn merge_transactions(&mut self, transaction: TransactionId, destination: TransactionId) {
1602 self.text.merge_transactions(transaction, destination);
1603 }
1604
1605 /// Waits for the buffer to receive operations with the given timestamps.
1606 pub fn wait_for_edits(
1607 &mut self,
1608 edit_ids: impl IntoIterator<Item = clock::Lamport>,
1609 ) -> impl Future<Output = Result<()>> {
1610 self.text.wait_for_edits(edit_ids)
1611 }
1612
1613 /// Waits for the buffer to receive the operations necessary for resolving the given anchors.
1614 pub fn wait_for_anchors(
1615 &mut self,
1616 anchors: impl IntoIterator<Item = Anchor>,
1617 ) -> impl 'static + Future<Output = Result<()>> {
1618 self.text.wait_for_anchors(anchors)
1619 }
1620
1621 /// Waits for the buffer to receive operations up to the given version.
1622 pub fn wait_for_version(&mut self, version: clock::Global) -> impl Future<Output = Result<()>> {
1623 self.text.wait_for_version(version)
1624 }
1625
1626 /// Forces all futures returned by [`Buffer::wait_for_version`], [`Buffer::wait_for_edits`], or
1627 /// [`Buffer::wait_for_version`] to resolve with an error.
1628 pub fn give_up_waiting(&mut self) {
1629 self.text.give_up_waiting();
1630 }
1631
1632 /// Stores a set of selections that should be broadcasted to all of the buffer's replicas.
1633 pub fn set_active_selections(
1634 &mut self,
1635 selections: Arc<[Selection<Anchor>]>,
1636 line_mode: bool,
1637 cursor_shape: CursorShape,
1638 cx: &mut ModelContext<Self>,
1639 ) {
1640 let lamport_timestamp = self.text.lamport_clock.tick();
1641 self.remote_selections.insert(
1642 self.text.replica_id(),
1643 SelectionSet {
1644 selections: selections.clone(),
1645 lamport_timestamp,
1646 line_mode,
1647 cursor_shape,
1648 },
1649 );
1650 self.send_operation(
1651 Operation::UpdateSelections {
1652 selections,
1653 line_mode,
1654 lamport_timestamp,
1655 cursor_shape,
1656 },
1657 cx,
1658 );
1659 }
1660
1661 /// Clears the selections, so that other replicas of the buffer do not see any selections for
1662 /// this replica.
1663 pub fn remove_active_selections(&mut self, cx: &mut ModelContext<Self>) {
1664 if self
1665 .remote_selections
1666 .get(&self.text.replica_id())
1667 .map_or(true, |set| !set.selections.is_empty())
1668 {
1669 self.set_active_selections(Arc::from([]), false, Default::default(), cx);
1670 }
1671 }
1672
1673 /// Replaces the buffer's entire text.
1674 pub fn set_text<T>(&mut self, text: T, cx: &mut ModelContext<Self>) -> Option<clock::Lamport>
1675 where
1676 T: Into<Arc<str>>,
1677 {
1678 self.autoindent_requests.clear();
1679 self.edit([(0..self.len(), text)], None, cx)
1680 }
1681
1682 /// Applies the given edits to the buffer. Each edit is specified as a range of text to
1683 /// delete, and a string of text to insert at that location.
1684 ///
1685 /// If an [`AutoindentMode`] is provided, then the buffer will enqueue an auto-indent
1686 /// request for the edited ranges, which will be processed when the buffer finishes
1687 /// parsing.
1688 ///
1689 /// Parsing takes place at the end of a transaction, and may compute synchronously
1690 /// or asynchronously, depending on the changes.
1691 pub fn edit<I, S, T>(
1692 &mut self,
1693 edits_iter: I,
1694 autoindent_mode: Option<AutoindentMode>,
1695 cx: &mut ModelContext<Self>,
1696 ) -> Option<clock::Lamport>
1697 where
1698 I: IntoIterator<Item = (Range<S>, T)>,
1699 S: ToOffset,
1700 T: Into<Arc<str>>,
1701 {
1702 // Skip invalid edits and coalesce contiguous ones.
1703 let mut edits: Vec<(Range<usize>, Arc<str>)> = Vec::new();
1704 for (range, new_text) in edits_iter {
1705 let mut range = range.start.to_offset(self)..range.end.to_offset(self);
1706 if range.start > range.end {
1707 mem::swap(&mut range.start, &mut range.end);
1708 }
1709 let new_text = new_text.into();
1710 if !new_text.is_empty() || !range.is_empty() {
1711 if let Some((prev_range, prev_text)) = edits.last_mut() {
1712 if prev_range.end >= range.start {
1713 prev_range.end = cmp::max(prev_range.end, range.end);
1714 *prev_text = format!("{prev_text}{new_text}").into();
1715 } else {
1716 edits.push((range, new_text));
1717 }
1718 } else {
1719 edits.push((range, new_text));
1720 }
1721 }
1722 }
1723 if edits.is_empty() {
1724 return None;
1725 }
1726
1727 self.start_transaction();
1728 self.pending_autoindent.take();
1729 let autoindent_request = autoindent_mode
1730 .and_then(|mode| self.language.as_ref().map(|_| (self.snapshot(), mode)));
1731
1732 let edit_operation = self.text.edit(edits.iter().cloned());
1733 let edit_id = edit_operation.timestamp();
1734
1735 if let Some((before_edit, mode)) = autoindent_request {
1736 let mut delta = 0isize;
1737 let entries = edits
1738 .into_iter()
1739 .enumerate()
1740 .zip(&edit_operation.as_edit().unwrap().new_text)
1741 .map(|((ix, (range, _)), new_text)| {
1742 let new_text_length = new_text.len();
1743 let old_start = range.start.to_point(&before_edit);
1744 let new_start = (delta + range.start as isize) as usize;
1745 delta += new_text_length as isize - (range.end as isize - range.start as isize);
1746
1747 let mut range_of_insertion_to_indent = 0..new_text_length;
1748 let mut first_line_is_new = false;
1749 let mut original_indent_column = None;
1750
1751 // When inserting an entire line at the beginning of an existing line,
1752 // treat the insertion as new.
1753 if new_text.contains('\n')
1754 && old_start.column <= before_edit.indent_size_for_line(old_start.row).len
1755 {
1756 first_line_is_new = true;
1757 }
1758
1759 // When inserting text starting with a newline, avoid auto-indenting the
1760 // previous line.
1761 if new_text.starts_with('\n') {
1762 range_of_insertion_to_indent.start += 1;
1763 first_line_is_new = true;
1764 }
1765
1766 // Avoid auto-indenting after the insertion.
1767 if let AutoindentMode::Block {
1768 original_indent_columns,
1769 } = &mode
1770 {
1771 original_indent_column =
1772 Some(original_indent_columns.get(ix).copied().unwrap_or_else(|| {
1773 indent_size_for_text(
1774 new_text[range_of_insertion_to_indent.clone()].chars(),
1775 )
1776 .len
1777 }));
1778 if new_text[range_of_insertion_to_indent.clone()].ends_with('\n') {
1779 range_of_insertion_to_indent.end -= 1;
1780 }
1781 }
1782
1783 AutoindentRequestEntry {
1784 first_line_is_new,
1785 original_indent_column,
1786 indent_size: before_edit.language_indent_size_at(range.start, cx),
1787 range: self.anchor_before(new_start + range_of_insertion_to_indent.start)
1788 ..self.anchor_after(new_start + range_of_insertion_to_indent.end),
1789 }
1790 })
1791 .collect();
1792
1793 self.autoindent_requests.push(Arc::new(AutoindentRequest {
1794 before_edit,
1795 entries,
1796 is_block_mode: matches!(mode, AutoindentMode::Block { .. }),
1797 }));
1798 }
1799
1800 self.end_transaction(cx);
1801 self.send_operation(Operation::Buffer(edit_operation), cx);
1802 Some(edit_id)
1803 }
1804
1805 fn did_edit(
1806 &mut self,
1807 old_version: &clock::Global,
1808 was_dirty: bool,
1809 cx: &mut ModelContext<Self>,
1810 ) {
1811 if self.edits_since::<usize>(old_version).next().is_none() {
1812 return;
1813 }
1814
1815 self.reparse(cx);
1816
1817 cx.emit(Event::Edited);
1818 if was_dirty != self.is_dirty() {
1819 cx.emit(Event::DirtyChanged);
1820 }
1821 cx.notify();
1822 }
1823
1824 /// Applies the given remote operations to the buffer.
1825 pub fn apply_ops<I: IntoIterator<Item = Operation>>(
1826 &mut self,
1827 ops: I,
1828 cx: &mut ModelContext<Self>,
1829 ) -> Result<()> {
1830 self.pending_autoindent.take();
1831 let was_dirty = self.is_dirty();
1832 let old_version = self.version.clone();
1833 let mut deferred_ops = Vec::new();
1834 let buffer_ops = ops
1835 .into_iter()
1836 .filter_map(|op| match op {
1837 Operation::Buffer(op) => Some(op),
1838 _ => {
1839 if self.can_apply_op(&op) {
1840 self.apply_op(op, cx);
1841 } else {
1842 deferred_ops.push(op);
1843 }
1844 None
1845 }
1846 })
1847 .collect::<Vec<_>>();
1848 self.text.apply_ops(buffer_ops)?;
1849 self.deferred_ops.insert(deferred_ops);
1850 self.flush_deferred_ops(cx);
1851 self.did_edit(&old_version, was_dirty, cx);
1852 // Notify independently of whether the buffer was edited as the operations could include a
1853 // selection update.
1854 cx.notify();
1855 Ok(())
1856 }
1857
1858 fn flush_deferred_ops(&mut self, cx: &mut ModelContext<Self>) {
1859 let mut deferred_ops = Vec::new();
1860 for op in self.deferred_ops.drain().iter().cloned() {
1861 if self.can_apply_op(&op) {
1862 self.apply_op(op, cx);
1863 } else {
1864 deferred_ops.push(op);
1865 }
1866 }
1867 self.deferred_ops.insert(deferred_ops);
1868 }
1869
1870 fn can_apply_op(&self, operation: &Operation) -> bool {
1871 match operation {
1872 Operation::Buffer(_) => {
1873 unreachable!("buffer operations should never be applied at this layer")
1874 }
1875 Operation::UpdateDiagnostics {
1876 diagnostics: diagnostic_set,
1877 ..
1878 } => diagnostic_set.iter().all(|diagnostic| {
1879 self.text.can_resolve(&diagnostic.range.start)
1880 && self.text.can_resolve(&diagnostic.range.end)
1881 }),
1882 Operation::UpdateSelections { selections, .. } => selections
1883 .iter()
1884 .all(|s| self.can_resolve(&s.start) && self.can_resolve(&s.end)),
1885 Operation::UpdateCompletionTriggers { .. } => true,
1886 }
1887 }
1888
1889 fn apply_op(&mut self, operation: Operation, cx: &mut ModelContext<Self>) {
1890 match operation {
1891 Operation::Buffer(_) => {
1892 unreachable!("buffer operations should never be applied at this layer")
1893 }
1894 Operation::UpdateDiagnostics {
1895 server_id,
1896 diagnostics: diagnostic_set,
1897 lamport_timestamp,
1898 } => {
1899 let snapshot = self.snapshot();
1900 self.apply_diagnostic_update(
1901 server_id,
1902 DiagnosticSet::from_sorted_entries(diagnostic_set.iter().cloned(), &snapshot),
1903 lamport_timestamp,
1904 cx,
1905 );
1906 }
1907 Operation::UpdateSelections {
1908 selections,
1909 lamport_timestamp,
1910 line_mode,
1911 cursor_shape,
1912 } => {
1913 if let Some(set) = self.remote_selections.get(&lamport_timestamp.replica_id) {
1914 if set.lamport_timestamp > lamport_timestamp {
1915 return;
1916 }
1917 }
1918
1919 self.remote_selections.insert(
1920 lamport_timestamp.replica_id,
1921 SelectionSet {
1922 selections,
1923 lamport_timestamp,
1924 line_mode,
1925 cursor_shape,
1926 },
1927 );
1928 self.text.lamport_clock.observe(lamport_timestamp);
1929 self.selections_update_count += 1;
1930 }
1931 Operation::UpdateCompletionTriggers {
1932 triggers,
1933 lamport_timestamp,
1934 } => {
1935 self.completion_triggers = triggers;
1936 self.text.lamport_clock.observe(lamport_timestamp);
1937 }
1938 }
1939 }
1940
1941 fn apply_diagnostic_update(
1942 &mut self,
1943 server_id: LanguageServerId,
1944 diagnostics: DiagnosticSet,
1945 lamport_timestamp: clock::Lamport,
1946 cx: &mut ModelContext<Self>,
1947 ) {
1948 if lamport_timestamp > self.diagnostics_timestamp {
1949 let ix = self.diagnostics.binary_search_by_key(&server_id, |e| e.0);
1950 if diagnostics.len() == 0 {
1951 if let Ok(ix) = ix {
1952 self.diagnostics.remove(ix);
1953 }
1954 } else {
1955 match ix {
1956 Err(ix) => self.diagnostics.insert(ix, (server_id, diagnostics)),
1957 Ok(ix) => self.diagnostics[ix].1 = diagnostics,
1958 };
1959 }
1960 self.diagnostics_timestamp = lamport_timestamp;
1961 self.diagnostics_update_count += 1;
1962 self.text.lamport_clock.observe(lamport_timestamp);
1963 cx.notify();
1964 cx.emit(Event::DiagnosticsUpdated);
1965 }
1966 }
1967
1968 fn send_operation(&mut self, operation: Operation, cx: &mut ModelContext<Self>) {
1969 cx.emit(Event::Operation(operation));
1970 }
1971
1972 /// Removes the selections for a given peer.
1973 pub fn remove_peer(&mut self, replica_id: ReplicaId, cx: &mut ModelContext<Self>) {
1974 self.remote_selections.remove(&replica_id);
1975 cx.notify();
1976 }
1977
1978 /// Undoes the most recent transaction.
1979 pub fn undo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1980 let was_dirty = self.is_dirty();
1981 let old_version = self.version.clone();
1982
1983 if let Some((transaction_id, operation)) = self.text.undo() {
1984 self.send_operation(Operation::Buffer(operation), cx);
1985 self.did_edit(&old_version, was_dirty, cx);
1986 Some(transaction_id)
1987 } else {
1988 None
1989 }
1990 }
1991
1992 /// Manually undoes a specific transaction in the buffer's undo history.
1993 pub fn undo_transaction(
1994 &mut self,
1995 transaction_id: TransactionId,
1996 cx: &mut ModelContext<Self>,
1997 ) -> bool {
1998 let was_dirty = self.is_dirty();
1999 let old_version = self.version.clone();
2000 if let Some(operation) = self.text.undo_transaction(transaction_id) {
2001 self.send_operation(Operation::Buffer(operation), cx);
2002 self.did_edit(&old_version, was_dirty, cx);
2003 true
2004 } else {
2005 false
2006 }
2007 }
2008
2009 /// Manually undoes all changes after a given transaction in the buffer's undo history.
2010 pub fn undo_to_transaction(
2011 &mut self,
2012 transaction_id: TransactionId,
2013 cx: &mut ModelContext<Self>,
2014 ) -> bool {
2015 let was_dirty = self.is_dirty();
2016 let old_version = self.version.clone();
2017
2018 let operations = self.text.undo_to_transaction(transaction_id);
2019 let undone = !operations.is_empty();
2020 for operation in operations {
2021 self.send_operation(Operation::Buffer(operation), cx);
2022 }
2023 if undone {
2024 self.did_edit(&old_version, was_dirty, cx)
2025 }
2026 undone
2027 }
2028
2029 /// Manually redoes a specific transaction in the buffer's redo history.
2030 pub fn redo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
2031 let was_dirty = self.is_dirty();
2032 let old_version = self.version.clone();
2033
2034 if let Some((transaction_id, operation)) = self.text.redo() {
2035 self.send_operation(Operation::Buffer(operation), cx);
2036 self.did_edit(&old_version, was_dirty, cx);
2037 Some(transaction_id)
2038 } else {
2039 None
2040 }
2041 }
2042
2043 /// Manually undoes all changes until a given transaction in the buffer's redo history.
2044 pub fn redo_to_transaction(
2045 &mut self,
2046 transaction_id: TransactionId,
2047 cx: &mut ModelContext<Self>,
2048 ) -> bool {
2049 let was_dirty = self.is_dirty();
2050 let old_version = self.version.clone();
2051
2052 let operations = self.text.redo_to_transaction(transaction_id);
2053 let redone = !operations.is_empty();
2054 for operation in operations {
2055 self.send_operation(Operation::Buffer(operation), cx);
2056 }
2057 if redone {
2058 self.did_edit(&old_version, was_dirty, cx)
2059 }
2060 redone
2061 }
2062
2063 /// Override current completion triggers with the user-provided completion triggers.
2064 pub fn set_completion_triggers(&mut self, triggers: Vec<String>, cx: &mut ModelContext<Self>) {
2065 self.completion_triggers = triggers.clone();
2066 self.completion_triggers_timestamp = self.text.lamport_clock.tick();
2067 self.send_operation(
2068 Operation::UpdateCompletionTriggers {
2069 triggers,
2070 lamport_timestamp: self.completion_triggers_timestamp,
2071 },
2072 cx,
2073 );
2074 cx.notify();
2075 }
2076
2077 /// Returns a list of strings which trigger a completion menu for this language.
2078 /// Usually this is driven by LSP server which returns a list of trigger characters for completions.
2079 pub fn completion_triggers(&self) -> &[String] {
2080 &self.completion_triggers
2081 }
2082}
2083
2084#[doc(hidden)]
2085#[cfg(any(test, feature = "test-support"))]
2086impl Buffer {
2087 pub fn edit_via_marked_text(
2088 &mut self,
2089 marked_string: &str,
2090 autoindent_mode: Option<AutoindentMode>,
2091 cx: &mut ModelContext<Self>,
2092 ) {
2093 let edits = self.edits_for_marked_text(marked_string);
2094 self.edit(edits, autoindent_mode, cx);
2095 }
2096
2097 pub fn set_group_interval(&mut self, group_interval: Duration) {
2098 self.text.set_group_interval(group_interval);
2099 }
2100
2101 pub fn randomly_edit<T>(
2102 &mut self,
2103 rng: &mut T,
2104 old_range_count: usize,
2105 cx: &mut ModelContext<Self>,
2106 ) where
2107 T: rand::Rng,
2108 {
2109 let mut edits: Vec<(Range<usize>, String)> = Vec::new();
2110 let mut last_end = None;
2111 for _ in 0..old_range_count {
2112 if last_end.map_or(false, |last_end| last_end >= self.len()) {
2113 break;
2114 }
2115
2116 let new_start = last_end.map_or(0, |last_end| last_end + 1);
2117 let mut range = self.random_byte_range(new_start, rng);
2118 if rng.gen_bool(0.2) {
2119 mem::swap(&mut range.start, &mut range.end);
2120 }
2121 last_end = Some(range.end);
2122
2123 let new_text_len = rng.gen_range(0..10);
2124 let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
2125
2126 edits.push((range, new_text));
2127 }
2128 log::info!("mutating buffer {} with {:?}", self.replica_id(), edits);
2129 self.edit(edits, None, cx);
2130 }
2131
2132 pub fn randomly_undo_redo(&mut self, rng: &mut impl rand::Rng, cx: &mut ModelContext<Self>) {
2133 let was_dirty = self.is_dirty();
2134 let old_version = self.version.clone();
2135
2136 let ops = self.text.randomly_undo_redo(rng);
2137 if !ops.is_empty() {
2138 for op in ops {
2139 self.send_operation(Operation::Buffer(op), cx);
2140 self.did_edit(&old_version, was_dirty, cx);
2141 }
2142 }
2143 }
2144}
2145
2146impl EventEmitter<Event> for Buffer {}
2147
2148impl Deref for Buffer {
2149 type Target = TextBuffer;
2150
2151 fn deref(&self) -> &Self::Target {
2152 &self.text
2153 }
2154}
2155
2156impl BufferSnapshot {
2157 /// Returns [`IndentSize`] for a given line that respects user settings and /// language preferences.
2158 pub fn indent_size_for_line(&self, row: u32) -> IndentSize {
2159 indent_size_for_line(self, row)
2160 }
2161 /// Returns [`IndentSize`] for a given position that respects user settings
2162 /// and language preferences.
2163 pub fn language_indent_size_at<T: ToOffset>(&self, position: T, cx: &AppContext) -> IndentSize {
2164 let settings = language_settings(self.language_at(position), self.file(), cx);
2165 if settings.hard_tabs {
2166 IndentSize::tab()
2167 } else {
2168 IndentSize::spaces(settings.tab_size.get())
2169 }
2170 }
2171
2172 /// Retrieve the suggested indent size for all of the given rows. The unit of indentation
2173 /// is passed in as `single_indent_size`.
2174 pub fn suggested_indents(
2175 &self,
2176 rows: impl Iterator<Item = u32>,
2177 single_indent_size: IndentSize,
2178 ) -> BTreeMap<u32, IndentSize> {
2179 let mut result = BTreeMap::new();
2180
2181 for row_range in contiguous_ranges(rows, 10) {
2182 let suggestions = match self.suggest_autoindents(row_range.clone()) {
2183 Some(suggestions) => suggestions,
2184 _ => break,
2185 };
2186
2187 for (row, suggestion) in row_range.zip(suggestions) {
2188 let indent_size = if let Some(suggestion) = suggestion {
2189 result
2190 .get(&suggestion.basis_row)
2191 .copied()
2192 .unwrap_or_else(|| self.indent_size_for_line(suggestion.basis_row))
2193 .with_delta(suggestion.delta, single_indent_size)
2194 } else {
2195 self.indent_size_for_line(row)
2196 };
2197
2198 result.insert(row, indent_size);
2199 }
2200 }
2201
2202 result
2203 }
2204
2205 fn suggest_autoindents(
2206 &self,
2207 row_range: Range<u32>,
2208 ) -> Option<impl Iterator<Item = Option<IndentSuggestion>> + '_> {
2209 let config = &self.language.as_ref()?.config;
2210 let prev_non_blank_row = self.prev_non_blank_row(row_range.start);
2211
2212 // Find the suggested indentation ranges based on the syntax tree.
2213 let start = Point::new(prev_non_blank_row.unwrap_or(row_range.start), 0);
2214 let end = Point::new(row_range.end, 0);
2215 let range = (start..end).to_offset(&self.text);
2216 let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
2217 Some(&grammar.indents_config.as_ref()?.query)
2218 });
2219 let indent_configs = matches
2220 .grammars()
2221 .iter()
2222 .map(|grammar| grammar.indents_config.as_ref().unwrap())
2223 .collect::<Vec<_>>();
2224
2225 let mut indent_ranges = Vec::<Range<Point>>::new();
2226 let mut outdent_positions = Vec::<Point>::new();
2227 while let Some(mat) = matches.peek() {
2228 let mut start: Option<Point> = None;
2229 let mut end: Option<Point> = None;
2230
2231 let config = &indent_configs[mat.grammar_index];
2232 for capture in mat.captures {
2233 if capture.index == config.indent_capture_ix {
2234 start.get_or_insert(Point::from_ts_point(capture.node.start_position()));
2235 end.get_or_insert(Point::from_ts_point(capture.node.end_position()));
2236 } else if Some(capture.index) == config.start_capture_ix {
2237 start = Some(Point::from_ts_point(capture.node.end_position()));
2238 } else if Some(capture.index) == config.end_capture_ix {
2239 end = Some(Point::from_ts_point(capture.node.start_position()));
2240 } else if Some(capture.index) == config.outdent_capture_ix {
2241 outdent_positions.push(Point::from_ts_point(capture.node.start_position()));
2242 }
2243 }
2244
2245 matches.advance();
2246 if let Some((start, end)) = start.zip(end) {
2247 if start.row == end.row {
2248 continue;
2249 }
2250
2251 let range = start..end;
2252 match indent_ranges.binary_search_by_key(&range.start, |r| r.start) {
2253 Err(ix) => indent_ranges.insert(ix, range),
2254 Ok(ix) => {
2255 let prev_range = &mut indent_ranges[ix];
2256 prev_range.end = prev_range.end.max(range.end);
2257 }
2258 }
2259 }
2260 }
2261
2262 let mut error_ranges = Vec::<Range<Point>>::new();
2263 let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
2264 Some(&grammar.error_query)
2265 });
2266 while let Some(mat) = matches.peek() {
2267 let node = mat.captures[0].node;
2268 let start = Point::from_ts_point(node.start_position());
2269 let end = Point::from_ts_point(node.end_position());
2270 let range = start..end;
2271 let ix = match error_ranges.binary_search_by_key(&range.start, |r| r.start) {
2272 Ok(ix) | Err(ix) => ix,
2273 };
2274 let mut end_ix = ix;
2275 while let Some(existing_range) = error_ranges.get(end_ix) {
2276 if existing_range.end < end {
2277 end_ix += 1;
2278 } else {
2279 break;
2280 }
2281 }
2282 error_ranges.splice(ix..end_ix, [range]);
2283 matches.advance();
2284 }
2285
2286 outdent_positions.sort();
2287 for outdent_position in outdent_positions {
2288 // find the innermost indent range containing this outdent_position
2289 // set its end to the outdent position
2290 if let Some(range_to_truncate) = indent_ranges
2291 .iter_mut()
2292 .filter(|indent_range| indent_range.contains(&outdent_position))
2293 .last()
2294 {
2295 range_to_truncate.end = outdent_position;
2296 }
2297 }
2298
2299 // Find the suggested indentation increases and decreased based on regexes.
2300 let mut indent_change_rows = Vec::<(u32, Ordering)>::new();
2301 self.for_each_line(
2302 Point::new(prev_non_blank_row.unwrap_or(row_range.start), 0)
2303 ..Point::new(row_range.end, 0),
2304 |row, line| {
2305 if config
2306 .decrease_indent_pattern
2307 .as_ref()
2308 .map_or(false, |regex| regex.is_match(line))
2309 {
2310 indent_change_rows.push((row, Ordering::Less));
2311 }
2312 if config
2313 .increase_indent_pattern
2314 .as_ref()
2315 .map_or(false, |regex| regex.is_match(line))
2316 {
2317 indent_change_rows.push((row + 1, Ordering::Greater));
2318 }
2319 },
2320 );
2321
2322 let mut indent_changes = indent_change_rows.into_iter().peekable();
2323 let mut prev_row = if config.auto_indent_using_last_non_empty_line {
2324 prev_non_blank_row.unwrap_or(0)
2325 } else {
2326 row_range.start.saturating_sub(1)
2327 };
2328 let mut prev_row_start = Point::new(prev_row, self.indent_size_for_line(prev_row).len);
2329 Some(row_range.map(move |row| {
2330 let row_start = Point::new(row, self.indent_size_for_line(row).len);
2331
2332 let mut indent_from_prev_row = false;
2333 let mut outdent_from_prev_row = false;
2334 let mut outdent_to_row = u32::MAX;
2335
2336 while let Some((indent_row, delta)) = indent_changes.peek() {
2337 match indent_row.cmp(&row) {
2338 Ordering::Equal => match delta {
2339 Ordering::Less => outdent_from_prev_row = true,
2340 Ordering::Greater => indent_from_prev_row = true,
2341 _ => {}
2342 },
2343
2344 Ordering::Greater => break,
2345 Ordering::Less => {}
2346 }
2347
2348 indent_changes.next();
2349 }
2350
2351 for range in &indent_ranges {
2352 if range.start.row >= row {
2353 break;
2354 }
2355 if range.start.row == prev_row && range.end > row_start {
2356 indent_from_prev_row = true;
2357 }
2358 if range.end > prev_row_start && range.end <= row_start {
2359 outdent_to_row = outdent_to_row.min(range.start.row);
2360 }
2361 }
2362
2363 let within_error = error_ranges
2364 .iter()
2365 .any(|e| e.start.row < row && e.end > row_start);
2366
2367 let suggestion = if outdent_to_row == prev_row
2368 || (outdent_from_prev_row && indent_from_prev_row)
2369 {
2370 Some(IndentSuggestion {
2371 basis_row: prev_row,
2372 delta: Ordering::Equal,
2373 within_error,
2374 })
2375 } else if indent_from_prev_row {
2376 Some(IndentSuggestion {
2377 basis_row: prev_row,
2378 delta: Ordering::Greater,
2379 within_error,
2380 })
2381 } else if outdent_to_row < prev_row {
2382 Some(IndentSuggestion {
2383 basis_row: outdent_to_row,
2384 delta: Ordering::Equal,
2385 within_error,
2386 })
2387 } else if outdent_from_prev_row {
2388 Some(IndentSuggestion {
2389 basis_row: prev_row,
2390 delta: Ordering::Less,
2391 within_error,
2392 })
2393 } else if config.auto_indent_using_last_non_empty_line || !self.is_line_blank(prev_row)
2394 {
2395 Some(IndentSuggestion {
2396 basis_row: prev_row,
2397 delta: Ordering::Equal,
2398 within_error,
2399 })
2400 } else {
2401 None
2402 };
2403
2404 prev_row = row;
2405 prev_row_start = row_start;
2406 suggestion
2407 }))
2408 }
2409
2410 fn prev_non_blank_row(&self, mut row: u32) -> Option<u32> {
2411 while row > 0 {
2412 row -= 1;
2413 if !self.is_line_blank(row) {
2414 return Some(row);
2415 }
2416 }
2417 None
2418 }
2419
2420 /// Iterates over chunks of text in the given range of the buffer. Text is chunked
2421 /// in an arbitrary way due to being stored in a [`Rope`](text::Rope). The text is also
2422 /// returned in chunks where each chunk has a single syntax highlighting style and
2423 /// diagnostic status.
2424 pub fn chunks<T: ToOffset>(&self, range: Range<T>, language_aware: bool) -> BufferChunks {
2425 let range = range.start.to_offset(self)..range.end.to_offset(self);
2426
2427 let mut syntax = None;
2428 let mut diagnostic_endpoints = Vec::new();
2429 if language_aware {
2430 let captures = self.syntax.captures(range.clone(), &self.text, |grammar| {
2431 grammar.highlights_query.as_ref()
2432 });
2433 let highlight_maps = captures
2434 .grammars()
2435 .into_iter()
2436 .map(|grammar| grammar.highlight_map())
2437 .collect();
2438 syntax = Some((captures, highlight_maps));
2439 for entry in self.diagnostics_in_range::<_, usize>(range.clone(), false) {
2440 diagnostic_endpoints.push(DiagnosticEndpoint {
2441 offset: entry.range.start,
2442 is_start: true,
2443 severity: entry.diagnostic.severity,
2444 is_unnecessary: entry.diagnostic.is_unnecessary,
2445 });
2446 diagnostic_endpoints.push(DiagnosticEndpoint {
2447 offset: entry.range.end,
2448 is_start: false,
2449 severity: entry.diagnostic.severity,
2450 is_unnecessary: entry.diagnostic.is_unnecessary,
2451 });
2452 }
2453 diagnostic_endpoints
2454 .sort_unstable_by_key(|endpoint| (endpoint.offset, !endpoint.is_start));
2455 }
2456
2457 BufferChunks::new(self.text.as_rope(), range, syntax, diagnostic_endpoints)
2458 }
2459
2460 /// Invokes the given callback for each line of text in the given range of the buffer.
2461 /// Uses callback to avoid allocating a string for each line.
2462 fn for_each_line(&self, range: Range<Point>, mut callback: impl FnMut(u32, &str)) {
2463 let mut line = String::new();
2464 let mut row = range.start.row;
2465 for chunk in self
2466 .as_rope()
2467 .chunks_in_range(range.to_offset(self))
2468 .chain(["\n"])
2469 {
2470 for (newline_ix, text) in chunk.split('\n').enumerate() {
2471 if newline_ix > 0 {
2472 callback(row, &line);
2473 row += 1;
2474 line.clear();
2475 }
2476 line.push_str(text);
2477 }
2478 }
2479 }
2480
2481 /// Iterates over every [`SyntaxLayer`] in the buffer.
2482 pub fn syntax_layers(&self) -> impl Iterator<Item = SyntaxLayer> + '_ {
2483 self.syntax.layers_for_range(0..self.len(), &self.text)
2484 }
2485
2486 fn syntax_layer_at<D: ToOffset>(&self, position: D) -> Option<SyntaxLayer> {
2487 let offset = position.to_offset(self);
2488 self.syntax
2489 .layers_for_range(offset..offset, &self.text)
2490 .filter(|l| l.node().end_byte() > offset)
2491 .last()
2492 }
2493
2494 /// Returns the [Language] at the given location.
2495 pub fn language_at<D: ToOffset>(&self, position: D) -> Option<&Arc<Language>> {
2496 self.syntax_layer_at(position)
2497 .map(|info| info.language)
2498 .or(self.language.as_ref())
2499 }
2500
2501 /// Returns the settings for the language at the given location.
2502 pub fn settings_at<'a, D: ToOffset>(
2503 &self,
2504 position: D,
2505 cx: &'a AppContext,
2506 ) -> &'a LanguageSettings {
2507 language_settings(self.language_at(position), self.file.as_ref(), cx)
2508 }
2509
2510 /// Returns the [LanguageScope] at the given location.
2511 pub fn language_scope_at<D: ToOffset>(&self, position: D) -> Option<LanguageScope> {
2512 let offset = position.to_offset(self);
2513 let mut scope = None;
2514 let mut smallest_range: Option<Range<usize>> = None;
2515
2516 // Use the layer that has the smallest node intersecting the given point.
2517 for layer in self.syntax.layers_for_range(offset..offset, &self.text) {
2518 let mut cursor = layer.node().walk();
2519
2520 let mut range = None;
2521 loop {
2522 let child_range = cursor.node().byte_range();
2523 if !child_range.to_inclusive().contains(&offset) {
2524 break;
2525 }
2526
2527 range = Some(child_range);
2528 if cursor.goto_first_child_for_byte(offset).is_none() {
2529 break;
2530 }
2531 }
2532
2533 if let Some(range) = range {
2534 if smallest_range
2535 .as_ref()
2536 .map_or(true, |smallest_range| range.len() < smallest_range.len())
2537 {
2538 smallest_range = Some(range);
2539 scope = Some(LanguageScope {
2540 language: layer.language.clone(),
2541 override_id: layer.override_id(offset, &self.text),
2542 });
2543 }
2544 }
2545 }
2546
2547 scope.or_else(|| {
2548 self.language.clone().map(|language| LanguageScope {
2549 language,
2550 override_id: None,
2551 })
2552 })
2553 }
2554
2555 /// Returns a tuple of the range and character kind of the word
2556 /// surrounding the given position.
2557 pub fn surrounding_word<T: ToOffset>(&self, start: T) -> (Range<usize>, Option<CharKind>) {
2558 let mut start = start.to_offset(self);
2559 let mut end = start;
2560 let mut next_chars = self.chars_at(start).peekable();
2561 let mut prev_chars = self.reversed_chars_at(start).peekable();
2562
2563 let scope = self.language_scope_at(start);
2564 let kind = |c| char_kind(&scope, c);
2565 let word_kind = cmp::max(
2566 prev_chars.peek().copied().map(kind),
2567 next_chars.peek().copied().map(kind),
2568 );
2569
2570 for ch in prev_chars {
2571 if Some(kind(ch)) == word_kind && ch != '\n' {
2572 start -= ch.len_utf8();
2573 } else {
2574 break;
2575 }
2576 }
2577
2578 for ch in next_chars {
2579 if Some(kind(ch)) == word_kind && ch != '\n' {
2580 end += ch.len_utf8();
2581 } else {
2582 break;
2583 }
2584 }
2585
2586 (start..end, word_kind)
2587 }
2588
2589 /// Returns the range for the closes syntax node enclosing the given range.
2590 pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
2591 let range = range.start.to_offset(self)..range.end.to_offset(self);
2592 let mut result: Option<Range<usize>> = None;
2593 'outer: for layer in self.syntax.layers_for_range(range.clone(), &self.text) {
2594 let mut cursor = layer.node().walk();
2595
2596 // Descend to the first leaf that touches the start of the range,
2597 // and if the range is non-empty, extends beyond the start.
2598 while cursor.goto_first_child_for_byte(range.start).is_some() {
2599 if !range.is_empty() && cursor.node().end_byte() == range.start {
2600 cursor.goto_next_sibling();
2601 }
2602 }
2603
2604 // Ascend to the smallest ancestor that strictly contains the range.
2605 loop {
2606 let node_range = cursor.node().byte_range();
2607 if node_range.start <= range.start
2608 && node_range.end >= range.end
2609 && node_range.len() > range.len()
2610 {
2611 break;
2612 }
2613 if !cursor.goto_parent() {
2614 continue 'outer;
2615 }
2616 }
2617
2618 let left_node = cursor.node();
2619 let mut layer_result = left_node.byte_range();
2620
2621 // For an empty range, try to find another node immediately to the right of the range.
2622 if left_node.end_byte() == range.start {
2623 let mut right_node = None;
2624 while !cursor.goto_next_sibling() {
2625 if !cursor.goto_parent() {
2626 break;
2627 }
2628 }
2629
2630 while cursor.node().start_byte() == range.start {
2631 right_node = Some(cursor.node());
2632 if !cursor.goto_first_child() {
2633 break;
2634 }
2635 }
2636
2637 // If there is a candidate node on both sides of the (empty) range, then
2638 // decide between the two by favoring a named node over an anonymous token.
2639 // If both nodes are the same in that regard, favor the right one.
2640 if let Some(right_node) = right_node {
2641 if right_node.is_named() || !left_node.is_named() {
2642 layer_result = right_node.byte_range();
2643 }
2644 }
2645 }
2646
2647 if let Some(previous_result) = &result {
2648 if previous_result.len() < layer_result.len() {
2649 continue;
2650 }
2651 }
2652 result = Some(layer_result);
2653 }
2654
2655 result
2656 }
2657
2658 /// Returns the outline for the buffer.
2659 ///
2660 /// This method allows passing an optional [SyntaxTheme] to
2661 /// syntax-highlight the returned symbols.
2662 pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
2663 self.outline_items_containing(0..self.len(), true, theme)
2664 .map(Outline::new)
2665 }
2666
2667 /// Returns all the symbols that contain the given position.
2668 ///
2669 /// This method allows passing an optional [SyntaxTheme] to
2670 /// syntax-highlight the returned symbols.
2671 pub fn symbols_containing<T: ToOffset>(
2672 &self,
2673 position: T,
2674 theme: Option<&SyntaxTheme>,
2675 ) -> Option<Vec<OutlineItem<Anchor>>> {
2676 let position = position.to_offset(self);
2677 let mut items = self.outline_items_containing(
2678 position.saturating_sub(1)..self.len().min(position + 1),
2679 false,
2680 theme,
2681 )?;
2682 let mut prev_depth = None;
2683 items.retain(|item| {
2684 let result = prev_depth.map_or(true, |prev_depth| item.depth > prev_depth);
2685 prev_depth = Some(item.depth);
2686 result
2687 });
2688 Some(items)
2689 }
2690
2691 fn outline_items_containing(
2692 &self,
2693 range: Range<usize>,
2694 include_extra_context: bool,
2695 theme: Option<&SyntaxTheme>,
2696 ) -> Option<Vec<OutlineItem<Anchor>>> {
2697 let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
2698 grammar.outline_config.as_ref().map(|c| &c.query)
2699 });
2700 let configs = matches
2701 .grammars()
2702 .iter()
2703 .map(|g| g.outline_config.as_ref().unwrap())
2704 .collect::<Vec<_>>();
2705
2706 let mut stack = Vec::<Range<usize>>::new();
2707 let mut items = Vec::new();
2708 while let Some(mat) = matches.peek() {
2709 let config = &configs[mat.grammar_index];
2710 let item_node = mat.captures.iter().find_map(|cap| {
2711 if cap.index == config.item_capture_ix {
2712 Some(cap.node)
2713 } else {
2714 None
2715 }
2716 })?;
2717
2718 let item_range = item_node.byte_range();
2719 if item_range.end < range.start || item_range.start > range.end {
2720 matches.advance();
2721 continue;
2722 }
2723
2724 let mut buffer_ranges = Vec::new();
2725 for capture in mat.captures {
2726 let node_is_name;
2727 if capture.index == config.name_capture_ix {
2728 node_is_name = true;
2729 } else if Some(capture.index) == config.context_capture_ix
2730 || (Some(capture.index) == config.extra_context_capture_ix
2731 && include_extra_context)
2732 {
2733 node_is_name = false;
2734 } else {
2735 continue;
2736 }
2737
2738 let mut range = capture.node.start_byte()..capture.node.end_byte();
2739 let start = capture.node.start_position();
2740 if capture.node.end_position().row > start.row {
2741 range.end =
2742 range.start + self.line_len(start.row as u32) as usize - start.column;
2743 }
2744
2745 buffer_ranges.push((range, node_is_name));
2746 }
2747
2748 if buffer_ranges.is_empty() {
2749 continue;
2750 }
2751
2752 let mut text = String::new();
2753 let mut highlight_ranges = Vec::new();
2754 let mut name_ranges = Vec::new();
2755 let mut chunks = self.chunks(
2756 buffer_ranges.first().unwrap().0.start..buffer_ranges.last().unwrap().0.end,
2757 true,
2758 );
2759 let mut last_buffer_range_end = 0;
2760 for (buffer_range, is_name) in buffer_ranges {
2761 if !text.is_empty() && buffer_range.start > last_buffer_range_end {
2762 text.push(' ');
2763 }
2764 last_buffer_range_end = buffer_range.end;
2765 if is_name {
2766 let mut start = text.len();
2767 let end = start + buffer_range.len();
2768
2769 // When multiple names are captured, then the matcheable text
2770 // includes the whitespace in between the names.
2771 if !name_ranges.is_empty() {
2772 start -= 1;
2773 }
2774
2775 name_ranges.push(start..end);
2776 }
2777
2778 let mut offset = buffer_range.start;
2779 chunks.seek(offset);
2780 for mut chunk in chunks.by_ref() {
2781 if chunk.text.len() > buffer_range.end - offset {
2782 chunk.text = &chunk.text[0..(buffer_range.end - offset)];
2783 offset = buffer_range.end;
2784 } else {
2785 offset += chunk.text.len();
2786 }
2787 let style = chunk
2788 .syntax_highlight_id
2789 .zip(theme)
2790 .and_then(|(highlight, theme)| highlight.style(theme));
2791 if let Some(style) = style {
2792 let start = text.len();
2793 let end = start + chunk.text.len();
2794 highlight_ranges.push((start..end, style));
2795 }
2796 text.push_str(chunk.text);
2797 if offset >= buffer_range.end {
2798 break;
2799 }
2800 }
2801 }
2802
2803 matches.advance();
2804 while stack.last().map_or(false, |prev_range| {
2805 prev_range.start > item_range.start || prev_range.end < item_range.end
2806 }) {
2807 stack.pop();
2808 }
2809 stack.push(item_range.clone());
2810
2811 items.push(OutlineItem {
2812 depth: stack.len() - 1,
2813 range: self.anchor_after(item_range.start)..self.anchor_before(item_range.end),
2814 text,
2815 highlight_ranges,
2816 name_ranges,
2817 })
2818 }
2819 Some(items)
2820 }
2821
2822 /// For each grammar in the language, runs the provided
2823 /// [tree_sitter::Query] against the given range.
2824 pub fn matches(
2825 &self,
2826 range: Range<usize>,
2827 query: fn(&Grammar) -> Option<&tree_sitter::Query>,
2828 ) -> SyntaxMapMatches {
2829 self.syntax.matches(range, self, query)
2830 }
2831
2832 /// Returns bracket range pairs overlapping or adjacent to `range`
2833 pub fn bracket_ranges<'a, T: ToOffset>(
2834 &'a self,
2835 range: Range<T>,
2836 ) -> impl Iterator<Item = (Range<usize>, Range<usize>)> + 'a {
2837 // Find bracket pairs that *inclusively* contain the given range.
2838 let range = range.start.to_offset(self).saturating_sub(1)
2839 ..self.len().min(range.end.to_offset(self) + 1);
2840
2841 let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
2842 grammar.brackets_config.as_ref().map(|c| &c.query)
2843 });
2844 let configs = matches
2845 .grammars()
2846 .iter()
2847 .map(|grammar| grammar.brackets_config.as_ref().unwrap())
2848 .collect::<Vec<_>>();
2849
2850 iter::from_fn(move || {
2851 while let Some(mat) = matches.peek() {
2852 let mut open = None;
2853 let mut close = None;
2854 let config = &configs[mat.grammar_index];
2855 for capture in mat.captures {
2856 if capture.index == config.open_capture_ix {
2857 open = Some(capture.node.byte_range());
2858 } else if capture.index == config.close_capture_ix {
2859 close = Some(capture.node.byte_range());
2860 }
2861 }
2862
2863 matches.advance();
2864
2865 let Some((open, close)) = open.zip(close) else {
2866 continue;
2867 };
2868
2869 let bracket_range = open.start..=close.end;
2870 if !bracket_range.overlaps(&range) {
2871 continue;
2872 }
2873
2874 return Some((open, close));
2875 }
2876 None
2877 })
2878 }
2879
2880 /// Returns selections for remote peers intersecting the given range.
2881 #[allow(clippy::type_complexity)]
2882 pub fn remote_selections_in_range(
2883 &self,
2884 range: Range<Anchor>,
2885 ) -> impl Iterator<
2886 Item = (
2887 ReplicaId,
2888 bool,
2889 CursorShape,
2890 impl Iterator<Item = &Selection<Anchor>> + '_,
2891 ),
2892 > + '_ {
2893 self.remote_selections
2894 .iter()
2895 .filter(|(replica_id, set)| {
2896 **replica_id != self.text.replica_id() && !set.selections.is_empty()
2897 })
2898 .map(move |(replica_id, set)| {
2899 let start_ix = match set.selections.binary_search_by(|probe| {
2900 probe.end.cmp(&range.start, self).then(Ordering::Greater)
2901 }) {
2902 Ok(ix) | Err(ix) => ix,
2903 };
2904 let end_ix = match set.selections.binary_search_by(|probe| {
2905 probe.start.cmp(&range.end, self).then(Ordering::Less)
2906 }) {
2907 Ok(ix) | Err(ix) => ix,
2908 };
2909
2910 (
2911 *replica_id,
2912 set.line_mode,
2913 set.cursor_shape,
2914 set.selections[start_ix..end_ix].iter(),
2915 )
2916 })
2917 }
2918
2919 /// Whether the buffer contains any git changes.
2920 pub fn has_git_diff(&self) -> bool {
2921 !self.git_diff.is_empty()
2922 }
2923
2924 /// Returns all the Git diff hunks intersecting the given
2925 /// row range.
2926 pub fn git_diff_hunks_in_row_range<'a>(
2927 &'a self,
2928 range: Range<u32>,
2929 ) -> impl 'a + Iterator<Item = git::diff::DiffHunk<u32>> {
2930 self.git_diff.hunks_in_row_range(range, self)
2931 }
2932
2933 /// Returns all the Git diff hunks intersecting the given
2934 /// range.
2935 pub fn git_diff_hunks_intersecting_range<'a>(
2936 &'a self,
2937 range: Range<Anchor>,
2938 ) -> impl 'a + Iterator<Item = git::diff::DiffHunk<u32>> {
2939 self.git_diff.hunks_intersecting_range(range, self)
2940 }
2941
2942 /// Returns all the Git diff hunks intersecting the given
2943 /// range, in reverse order.
2944 pub fn git_diff_hunks_intersecting_range_rev<'a>(
2945 &'a self,
2946 range: Range<Anchor>,
2947 ) -> impl 'a + Iterator<Item = git::diff::DiffHunk<u32>> {
2948 self.git_diff.hunks_intersecting_range_rev(range, self)
2949 }
2950
2951 /// Returns all the diagnostics intersecting the given range.
2952 pub fn diagnostics_in_range<'a, T, O>(
2953 &'a self,
2954 search_range: Range<T>,
2955 reversed: bool,
2956 ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>>
2957 where
2958 T: 'a + Clone + ToOffset,
2959 O: 'a + FromAnchor + Ord,
2960 {
2961 let mut iterators: Vec<_> = self
2962 .diagnostics
2963 .iter()
2964 .map(|(_, collection)| {
2965 collection
2966 .range::<T, O>(search_range.clone(), self, true, reversed)
2967 .peekable()
2968 })
2969 .collect();
2970
2971 std::iter::from_fn(move || {
2972 let (next_ix, _) = iterators
2973 .iter_mut()
2974 .enumerate()
2975 .flat_map(|(ix, iter)| Some((ix, iter.peek()?)))
2976 .min_by(|(_, a), (_, b)| a.range.start.cmp(&b.range.start))?;
2977 iterators[next_ix].next()
2978 })
2979 }
2980
2981 /// Returns all the diagnostic groups associated with the given
2982 /// language server id. If no language server id is provided,
2983 /// all diagnostics groups are returned.
2984 pub fn diagnostic_groups(
2985 &self,
2986 language_server_id: Option<LanguageServerId>,
2987 ) -> Vec<(LanguageServerId, DiagnosticGroup<Anchor>)> {
2988 let mut groups = Vec::new();
2989
2990 if let Some(language_server_id) = language_server_id {
2991 if let Ok(ix) = self
2992 .diagnostics
2993 .binary_search_by_key(&language_server_id, |e| e.0)
2994 {
2995 self.diagnostics[ix]
2996 .1
2997 .groups(language_server_id, &mut groups, self);
2998 }
2999 } else {
3000 for (language_server_id, diagnostics) in self.diagnostics.iter() {
3001 diagnostics.groups(*language_server_id, &mut groups, self);
3002 }
3003 }
3004
3005 groups.sort_by(|(id_a, group_a), (id_b, group_b)| {
3006 let a_start = &group_a.entries[group_a.primary_ix].range.start;
3007 let b_start = &group_b.entries[group_b.primary_ix].range.start;
3008 a_start.cmp(b_start, self).then_with(|| id_a.cmp(id_b))
3009 });
3010
3011 groups
3012 }
3013
3014 /// Returns an iterator over the diagnostics for the given group.
3015 pub fn diagnostic_group<'a, O>(
3016 &'a self,
3017 group_id: usize,
3018 ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>>
3019 where
3020 O: 'a + FromAnchor,
3021 {
3022 self.diagnostics
3023 .iter()
3024 .flat_map(move |(_, set)| set.group(group_id, self))
3025 }
3026
3027 /// The number of times diagnostics were updated.
3028 pub fn diagnostics_update_count(&self) -> usize {
3029 self.diagnostics_update_count
3030 }
3031
3032 /// The number of times the buffer was parsed.
3033 pub fn parse_count(&self) -> usize {
3034 self.parse_count
3035 }
3036
3037 /// The number of times selections were updated.
3038 pub fn selections_update_count(&self) -> usize {
3039 self.selections_update_count
3040 }
3041
3042 /// Returns a snapshot of underlying file.
3043 pub fn file(&self) -> Option<&Arc<dyn File>> {
3044 self.file.as_ref()
3045 }
3046
3047 /// Resolves the file path (relative to the worktree root) associated with the underlying file.
3048 pub fn resolve_file_path(&self, cx: &AppContext, include_root: bool) -> Option<PathBuf> {
3049 if let Some(file) = self.file() {
3050 if file.path().file_name().is_none() || include_root {
3051 Some(file.full_path(cx))
3052 } else {
3053 Some(file.path().to_path_buf())
3054 }
3055 } else {
3056 None
3057 }
3058 }
3059
3060 /// The number of times the underlying file was updated.
3061 pub fn file_update_count(&self) -> usize {
3062 self.file_update_count
3063 }
3064
3065 /// The number of times the git diff status was updated.
3066 pub fn git_diff_update_count(&self) -> usize {
3067 self.git_diff_update_count
3068 }
3069}
3070
3071fn indent_size_for_line(text: &text::BufferSnapshot, row: u32) -> IndentSize {
3072 indent_size_for_text(text.chars_at(Point::new(row, 0)))
3073}
3074
3075fn indent_size_for_text(text: impl Iterator<Item = char>) -> IndentSize {
3076 let mut result = IndentSize::spaces(0);
3077 for c in text {
3078 let kind = match c {
3079 ' ' => IndentKind::Space,
3080 '\t' => IndentKind::Tab,
3081 _ => break,
3082 };
3083 if result.len == 0 {
3084 result.kind = kind;
3085 }
3086 result.len += 1;
3087 }
3088 result
3089}
3090
3091impl Clone for BufferSnapshot {
3092 fn clone(&self) -> Self {
3093 Self {
3094 text: self.text.clone(),
3095 git_diff: self.git_diff.clone(),
3096 syntax: self.syntax.clone(),
3097 file: self.file.clone(),
3098 remote_selections: self.remote_selections.clone(),
3099 diagnostics: self.diagnostics.clone(),
3100 selections_update_count: self.selections_update_count,
3101 diagnostics_update_count: self.diagnostics_update_count,
3102 file_update_count: self.file_update_count,
3103 git_diff_update_count: self.git_diff_update_count,
3104 language: self.language.clone(),
3105 parse_count: self.parse_count,
3106 }
3107 }
3108}
3109
3110impl Deref for BufferSnapshot {
3111 type Target = text::BufferSnapshot;
3112
3113 fn deref(&self) -> &Self::Target {
3114 &self.text
3115 }
3116}
3117
3118unsafe impl<'a> Send for BufferChunks<'a> {}
3119
3120impl<'a> BufferChunks<'a> {
3121 pub(crate) fn new(
3122 text: &'a Rope,
3123 range: Range<usize>,
3124 syntax: Option<(SyntaxMapCaptures<'a>, Vec<HighlightMap>)>,
3125 diagnostic_endpoints: Vec<DiagnosticEndpoint>,
3126 ) -> Self {
3127 let mut highlights = None;
3128 if let Some((captures, highlight_maps)) = syntax {
3129 highlights = Some(BufferChunkHighlights {
3130 captures,
3131 next_capture: None,
3132 stack: Default::default(),
3133 highlight_maps,
3134 })
3135 }
3136
3137 let diagnostic_endpoints = diagnostic_endpoints.into_iter().peekable();
3138 let chunks = text.chunks_in_range(range.clone());
3139
3140 BufferChunks {
3141 range,
3142 chunks,
3143 diagnostic_endpoints,
3144 error_depth: 0,
3145 warning_depth: 0,
3146 information_depth: 0,
3147 hint_depth: 0,
3148 unnecessary_depth: 0,
3149 highlights,
3150 }
3151 }
3152
3153 /// Seeks to the given byte offset in the buffer.
3154 pub fn seek(&mut self, offset: usize) {
3155 self.range.start = offset;
3156 self.chunks.seek(self.range.start);
3157 if let Some(highlights) = self.highlights.as_mut() {
3158 highlights
3159 .stack
3160 .retain(|(end_offset, _)| *end_offset > offset);
3161 if let Some(capture) = &highlights.next_capture {
3162 if offset >= capture.node.start_byte() {
3163 let next_capture_end = capture.node.end_byte();
3164 if offset < next_capture_end {
3165 highlights.stack.push((
3166 next_capture_end,
3167 highlights.highlight_maps[capture.grammar_index].get(capture.index),
3168 ));
3169 }
3170 highlights.next_capture.take();
3171 }
3172 }
3173 highlights.captures.set_byte_range(self.range.clone());
3174 }
3175 }
3176
3177 /// The current byte offset in the buffer.
3178 pub fn offset(&self) -> usize {
3179 self.range.start
3180 }
3181
3182 fn update_diagnostic_depths(&mut self, endpoint: DiagnosticEndpoint) {
3183 let depth = match endpoint.severity {
3184 DiagnosticSeverity::ERROR => &mut self.error_depth,
3185 DiagnosticSeverity::WARNING => &mut self.warning_depth,
3186 DiagnosticSeverity::INFORMATION => &mut self.information_depth,
3187 DiagnosticSeverity::HINT => &mut self.hint_depth,
3188 _ => return,
3189 };
3190 if endpoint.is_start {
3191 *depth += 1;
3192 } else {
3193 *depth -= 1;
3194 }
3195
3196 if endpoint.is_unnecessary {
3197 if endpoint.is_start {
3198 self.unnecessary_depth += 1;
3199 } else {
3200 self.unnecessary_depth -= 1;
3201 }
3202 }
3203 }
3204
3205 fn current_diagnostic_severity(&self) -> Option<DiagnosticSeverity> {
3206 if self.error_depth > 0 {
3207 Some(DiagnosticSeverity::ERROR)
3208 } else if self.warning_depth > 0 {
3209 Some(DiagnosticSeverity::WARNING)
3210 } else if self.information_depth > 0 {
3211 Some(DiagnosticSeverity::INFORMATION)
3212 } else if self.hint_depth > 0 {
3213 Some(DiagnosticSeverity::HINT)
3214 } else {
3215 None
3216 }
3217 }
3218
3219 fn current_code_is_unnecessary(&self) -> bool {
3220 self.unnecessary_depth > 0
3221 }
3222}
3223
3224impl<'a> Iterator for BufferChunks<'a> {
3225 type Item = Chunk<'a>;
3226
3227 fn next(&mut self) -> Option<Self::Item> {
3228 let mut next_capture_start = usize::MAX;
3229 let mut next_diagnostic_endpoint = usize::MAX;
3230
3231 if let Some(highlights) = self.highlights.as_mut() {
3232 while let Some((parent_capture_end, _)) = highlights.stack.last() {
3233 if *parent_capture_end <= self.range.start {
3234 highlights.stack.pop();
3235 } else {
3236 break;
3237 }
3238 }
3239
3240 if highlights.next_capture.is_none() {
3241 highlights.next_capture = highlights.captures.next();
3242 }
3243
3244 while let Some(capture) = highlights.next_capture.as_ref() {
3245 if self.range.start < capture.node.start_byte() {
3246 next_capture_start = capture.node.start_byte();
3247 break;
3248 } else {
3249 let highlight_id =
3250 highlights.highlight_maps[capture.grammar_index].get(capture.index);
3251 highlights
3252 .stack
3253 .push((capture.node.end_byte(), highlight_id));
3254 highlights.next_capture = highlights.captures.next();
3255 }
3256 }
3257 }
3258
3259 while let Some(endpoint) = self.diagnostic_endpoints.peek().copied() {
3260 if endpoint.offset <= self.range.start {
3261 self.update_diagnostic_depths(endpoint);
3262 self.diagnostic_endpoints.next();
3263 } else {
3264 next_diagnostic_endpoint = endpoint.offset;
3265 break;
3266 }
3267 }
3268
3269 if let Some(chunk) = self.chunks.peek() {
3270 let chunk_start = self.range.start;
3271 let mut chunk_end = (self.chunks.offset() + chunk.len())
3272 .min(next_capture_start)
3273 .min(next_diagnostic_endpoint);
3274 let mut highlight_id = None;
3275 if let Some(highlights) = self.highlights.as_ref() {
3276 if let Some((parent_capture_end, parent_highlight_id)) = highlights.stack.last() {
3277 chunk_end = chunk_end.min(*parent_capture_end);
3278 highlight_id = Some(*parent_highlight_id);
3279 }
3280 }
3281
3282 let slice =
3283 &chunk[chunk_start - self.chunks.offset()..chunk_end - self.chunks.offset()];
3284 self.range.start = chunk_end;
3285 if self.range.start == self.chunks.offset() + chunk.len() {
3286 self.chunks.next().unwrap();
3287 }
3288
3289 Some(Chunk {
3290 text: slice,
3291 syntax_highlight_id: highlight_id,
3292 diagnostic_severity: self.current_diagnostic_severity(),
3293 is_unnecessary: self.current_code_is_unnecessary(),
3294 ..Default::default()
3295 })
3296 } else {
3297 None
3298 }
3299 }
3300}
3301
3302impl operation_queue::Operation for Operation {
3303 fn lamport_timestamp(&self) -> clock::Lamport {
3304 match self {
3305 Operation::Buffer(_) => {
3306 unreachable!("buffer operations should never be deferred at this layer")
3307 }
3308 Operation::UpdateDiagnostics {
3309 lamport_timestamp, ..
3310 }
3311 | Operation::UpdateSelections {
3312 lamport_timestamp, ..
3313 }
3314 | Operation::UpdateCompletionTriggers {
3315 lamport_timestamp, ..
3316 } => *lamport_timestamp,
3317 }
3318 }
3319}
3320
3321impl Default for Diagnostic {
3322 fn default() -> Self {
3323 Self {
3324 source: Default::default(),
3325 code: None,
3326 severity: DiagnosticSeverity::ERROR,
3327 message: Default::default(),
3328 group_id: 0,
3329 is_primary: false,
3330 is_disk_based: false,
3331 is_unnecessary: false,
3332 }
3333 }
3334}
3335
3336impl IndentSize {
3337 /// Returns an [IndentSize] representing the given spaces.
3338 pub fn spaces(len: u32) -> Self {
3339 Self {
3340 len,
3341 kind: IndentKind::Space,
3342 }
3343 }
3344
3345 /// Returns an [IndentSize] representing a tab.
3346 pub fn tab() -> Self {
3347 Self {
3348 len: 1,
3349 kind: IndentKind::Tab,
3350 }
3351 }
3352
3353 /// An iterator over the characters represented by this [IndentSize].
3354 pub fn chars(&self) -> impl Iterator<Item = char> {
3355 iter::repeat(self.char()).take(self.len as usize)
3356 }
3357
3358 /// The character representation of this [IndentSize].
3359 pub fn char(&self) -> char {
3360 match self.kind {
3361 IndentKind::Space => ' ',
3362 IndentKind::Tab => '\t',
3363 }
3364 }
3365
3366 /// Consumes the current [IndentSize] and returns a new one that has
3367 /// been shrunk or enlarged by the given size along the given direction.
3368 pub fn with_delta(mut self, direction: Ordering, size: IndentSize) -> Self {
3369 match direction {
3370 Ordering::Less => {
3371 if self.kind == size.kind && self.len >= size.len {
3372 self.len -= size.len;
3373 }
3374 }
3375 Ordering::Equal => {}
3376 Ordering::Greater => {
3377 if self.len == 0 {
3378 self = size;
3379 } else if self.kind == size.kind {
3380 self.len += size.len;
3381 }
3382 }
3383 }
3384 self
3385 }
3386}
3387
3388impl Completion {
3389 /// A key that can be used to sort completions when displaying
3390 /// them to the user.
3391 pub fn sort_key(&self) -> (usize, &str) {
3392 let kind_key = match self.lsp_completion.kind {
3393 Some(lsp::CompletionItemKind::VARIABLE) => 0,
3394 _ => 1,
3395 };
3396 (kind_key, &self.label.text[self.label.filter_range.clone()])
3397 }
3398
3399 /// Whether this completion is a snippet.
3400 pub fn is_snippet(&self) -> bool {
3401 self.lsp_completion.insert_text_format == Some(lsp::InsertTextFormat::SNIPPET)
3402 }
3403}
3404
3405pub(crate) fn contiguous_ranges(
3406 values: impl Iterator<Item = u32>,
3407 max_len: usize,
3408) -> impl Iterator<Item = Range<u32>> {
3409 let mut values = values;
3410 let mut current_range: Option<Range<u32>> = None;
3411 std::iter::from_fn(move || loop {
3412 if let Some(value) = values.next() {
3413 if let Some(range) = &mut current_range {
3414 if value == range.end && range.len() < max_len {
3415 range.end += 1;
3416 continue;
3417 }
3418 }
3419
3420 let prev_range = current_range.clone();
3421 current_range = Some(value..(value + 1));
3422 if prev_range.is_some() {
3423 return prev_range;
3424 }
3425 } else {
3426 return current_range.take();
3427 }
3428 })
3429}
3430
3431/// Returns the [CharKind] for the given character. When a scope is provided,
3432/// the function checks if the character is considered a word character
3433/// based on the language scope's word character settings.
3434pub fn char_kind(scope: &Option<LanguageScope>, c: char) -> CharKind {
3435 if c.is_whitespace() {
3436 return CharKind::Whitespace;
3437 } else if c.is_alphanumeric() || c == '_' {
3438 return CharKind::Word;
3439 }
3440
3441 if let Some(scope) = scope {
3442 if let Some(characters) = scope.word_characters() {
3443 if characters.contains(&c) {
3444 return CharKind::Word;
3445 }
3446 }
3447 }
3448
3449 CharKind::Punctuation
3450}
3451
3452/// Find all of the ranges of whitespace that occur at the ends of lines
3453/// in the given rope.
3454///
3455/// This could also be done with a regex search, but this implementation
3456/// avoids copying text.
3457pub fn trailing_whitespace_ranges(rope: &Rope) -> Vec<Range<usize>> {
3458 let mut ranges = Vec::new();
3459
3460 let mut offset = 0;
3461 let mut prev_chunk_trailing_whitespace_range = 0..0;
3462 for chunk in rope.chunks() {
3463 let mut prev_line_trailing_whitespace_range = 0..0;
3464 for (i, line) in chunk.split('\n').enumerate() {
3465 let line_end_offset = offset + line.len();
3466 let trimmed_line_len = line.trim_end_matches(|c| matches!(c, ' ' | '\t')).len();
3467 let mut trailing_whitespace_range = (offset + trimmed_line_len)..line_end_offset;
3468
3469 if i == 0 && trimmed_line_len == 0 {
3470 trailing_whitespace_range.start = prev_chunk_trailing_whitespace_range.start;
3471 }
3472 if !prev_line_trailing_whitespace_range.is_empty() {
3473 ranges.push(prev_line_trailing_whitespace_range);
3474 }
3475
3476 offset = line_end_offset + 1;
3477 prev_line_trailing_whitespace_range = trailing_whitespace_range;
3478 }
3479
3480 offset -= 1;
3481 prev_chunk_trailing_whitespace_range = prev_line_trailing_whitespace_range;
3482 }
3483
3484 if !prev_chunk_trailing_whitespace_range.is_empty() {
3485 ranges.push(prev_chunk_trailing_whitespace_range);
3486 }
3487
3488 ranges
3489}