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