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