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 if !range.is_empty() {
2781 buffer_ranges.push((range, node_is_name));
2782 }
2783 }
2784
2785 if buffer_ranges.is_empty() {
2786 matches.advance();
2787 continue;
2788 }
2789
2790 let mut text = String::new();
2791 let mut highlight_ranges = Vec::new();
2792 let mut name_ranges = Vec::new();
2793 let mut chunks = self.chunks(
2794 buffer_ranges.first().unwrap().0.start..buffer_ranges.last().unwrap().0.end,
2795 true,
2796 );
2797 let mut last_buffer_range_end = 0;
2798 for (buffer_range, is_name) in buffer_ranges {
2799 if !text.is_empty() && buffer_range.start > last_buffer_range_end {
2800 text.push(' ');
2801 }
2802 last_buffer_range_end = buffer_range.end;
2803 if is_name {
2804 let mut start = text.len();
2805 let end = start + buffer_range.len();
2806
2807 // When multiple names are captured, then the matcheable text
2808 // includes the whitespace in between the names.
2809 if !name_ranges.is_empty() {
2810 start -= 1;
2811 }
2812
2813 name_ranges.push(start..end);
2814 }
2815
2816 let mut offset = buffer_range.start;
2817 chunks.seek(offset);
2818 for mut chunk in chunks.by_ref() {
2819 if chunk.text.len() > buffer_range.end - offset {
2820 chunk.text = &chunk.text[0..(buffer_range.end - offset)];
2821 offset = buffer_range.end;
2822 } else {
2823 offset += chunk.text.len();
2824 }
2825 let style = chunk
2826 .syntax_highlight_id
2827 .zip(theme)
2828 .and_then(|(highlight, theme)| highlight.style(theme));
2829 if let Some(style) = style {
2830 let start = text.len();
2831 let end = start + chunk.text.len();
2832 highlight_ranges.push((start..end, style));
2833 }
2834 text.push_str(chunk.text);
2835 if offset >= buffer_range.end {
2836 break;
2837 }
2838 }
2839 }
2840
2841 matches.advance();
2842 while stack.last().map_or(false, |prev_range| {
2843 prev_range.start > item_range.start || prev_range.end < item_range.end
2844 }) {
2845 stack.pop();
2846 }
2847 stack.push(item_range.clone());
2848
2849 items.push(OutlineItem {
2850 depth: stack.len() - 1,
2851 range: self.anchor_after(item_range.start)..self.anchor_before(item_range.end),
2852 text,
2853 highlight_ranges,
2854 name_ranges,
2855 })
2856 }
2857 Some(items)
2858 }
2859
2860 /// For each grammar in the language, runs the provided
2861 /// [tree_sitter::Query] against the given range.
2862 pub fn matches(
2863 &self,
2864 range: Range<usize>,
2865 query: fn(&Grammar) -> Option<&tree_sitter::Query>,
2866 ) -> SyntaxMapMatches {
2867 self.syntax.matches(range, self, query)
2868 }
2869
2870 /// Returns bracket range pairs overlapping or adjacent to `range`
2871 pub fn bracket_ranges<T: ToOffset>(
2872 &self,
2873 range: Range<T>,
2874 ) -> impl Iterator<Item = (Range<usize>, Range<usize>)> + '_ {
2875 // Find bracket pairs that *inclusively* contain the given range.
2876 let range = range.start.to_offset(self).saturating_sub(1)
2877 ..self.len().min(range.end.to_offset(self) + 1);
2878
2879 let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
2880 grammar.brackets_config.as_ref().map(|c| &c.query)
2881 });
2882 let configs = matches
2883 .grammars()
2884 .iter()
2885 .map(|grammar| grammar.brackets_config.as_ref().unwrap())
2886 .collect::<Vec<_>>();
2887
2888 iter::from_fn(move || {
2889 while let Some(mat) = matches.peek() {
2890 let mut open = None;
2891 let mut close = None;
2892 let config = &configs[mat.grammar_index];
2893 for capture in mat.captures {
2894 if capture.index == config.open_capture_ix {
2895 open = Some(capture.node.byte_range());
2896 } else if capture.index == config.close_capture_ix {
2897 close = Some(capture.node.byte_range());
2898 }
2899 }
2900
2901 matches.advance();
2902
2903 let Some((open, close)) = open.zip(close) else {
2904 continue;
2905 };
2906
2907 let bracket_range = open.start..=close.end;
2908 if !bracket_range.overlaps(&range) {
2909 continue;
2910 }
2911
2912 return Some((open, close));
2913 }
2914 None
2915 })
2916 }
2917
2918 /// Returns enclosing bracket ranges containing the given range
2919 pub fn enclosing_bracket_ranges<T: ToOffset>(
2920 &self,
2921 range: Range<T>,
2922 ) -> impl Iterator<Item = (Range<usize>, Range<usize>)> + '_ {
2923 let range = range.start.to_offset(self)..range.end.to_offset(self);
2924
2925 self.bracket_ranges(range.clone())
2926 .filter(move |(open, close)| open.start <= range.start && close.end >= range.end)
2927 }
2928
2929 /// Returns the smallest enclosing bracket ranges containing the given range or None if no brackets contain range
2930 ///
2931 /// Can optionally pass a range_filter to filter the ranges of brackets to consider
2932 pub fn innermost_enclosing_bracket_ranges<T: ToOffset>(
2933 &self,
2934 range: Range<T>,
2935 range_filter: Option<&dyn Fn(Range<usize>, Range<usize>) -> bool>,
2936 ) -> Option<(Range<usize>, Range<usize>)> {
2937 let range = range.start.to_offset(self)..range.end.to_offset(self);
2938
2939 // Get the ranges of the innermost pair of brackets.
2940 let mut result: Option<(Range<usize>, Range<usize>)> = None;
2941
2942 for (open, close) in self.enclosing_bracket_ranges(range.clone()) {
2943 if let Some(range_filter) = range_filter {
2944 if !range_filter(open.clone(), close.clone()) {
2945 continue;
2946 }
2947 }
2948
2949 let len = close.end - open.start;
2950
2951 if let Some((existing_open, existing_close)) = &result {
2952 let existing_len = existing_close.end - existing_open.start;
2953 if len > existing_len {
2954 continue;
2955 }
2956 }
2957
2958 result = Some((open, close));
2959 }
2960
2961 result
2962 }
2963
2964 /// Returns anchor ranges for any matches of the redaction query.
2965 /// The buffer can be associated with multiple languages, and the redaction query associated with each
2966 /// will be run on the relevant section of the buffer.
2967 pub fn redacted_ranges<T: ToOffset>(
2968 &self,
2969 range: Range<T>,
2970 ) -> impl Iterator<Item = Range<usize>> + '_ {
2971 let offset_range = range.start.to_offset(self)..range.end.to_offset(self);
2972 let mut syntax_matches = self.syntax.matches(offset_range, self, |grammar| {
2973 grammar
2974 .redactions_config
2975 .as_ref()
2976 .map(|config| &config.query)
2977 });
2978
2979 let configs = syntax_matches
2980 .grammars()
2981 .iter()
2982 .map(|grammar| grammar.redactions_config.as_ref())
2983 .collect::<Vec<_>>();
2984
2985 iter::from_fn(move || {
2986 let redacted_range = syntax_matches
2987 .peek()
2988 .and_then(|mat| {
2989 configs[mat.grammar_index].and_then(|config| {
2990 mat.captures
2991 .iter()
2992 .find(|capture| capture.index == config.redaction_capture_ix)
2993 })
2994 })
2995 .map(|mat| mat.node.byte_range());
2996 syntax_matches.advance();
2997 redacted_range
2998 })
2999 }
3000
3001 /// Returns selections for remote peers intersecting the given range.
3002 #[allow(clippy::type_complexity)]
3003 pub fn remote_selections_in_range(
3004 &self,
3005 range: Range<Anchor>,
3006 ) -> impl Iterator<
3007 Item = (
3008 ReplicaId,
3009 bool,
3010 CursorShape,
3011 impl Iterator<Item = &Selection<Anchor>> + '_,
3012 ),
3013 > + '_ {
3014 self.remote_selections
3015 .iter()
3016 .filter(|(replica_id, set)| {
3017 **replica_id != self.text.replica_id() && !set.selections.is_empty()
3018 })
3019 .map(move |(replica_id, set)| {
3020 let start_ix = match set.selections.binary_search_by(|probe| {
3021 probe.end.cmp(&range.start, self).then(Ordering::Greater)
3022 }) {
3023 Ok(ix) | Err(ix) => ix,
3024 };
3025 let end_ix = match set.selections.binary_search_by(|probe| {
3026 probe.start.cmp(&range.end, self).then(Ordering::Less)
3027 }) {
3028 Ok(ix) | Err(ix) => ix,
3029 };
3030
3031 (
3032 *replica_id,
3033 set.line_mode,
3034 set.cursor_shape,
3035 set.selections[start_ix..end_ix].iter(),
3036 )
3037 })
3038 }
3039
3040 /// Whether the buffer contains any git changes.
3041 pub fn has_git_diff(&self) -> bool {
3042 !self.git_diff.is_empty()
3043 }
3044
3045 /// Returns all the Git diff hunks intersecting the given
3046 /// row range.
3047 pub fn git_diff_hunks_in_row_range(
3048 &self,
3049 range: Range<u32>,
3050 ) -> impl '_ + Iterator<Item = git::diff::DiffHunk<u32>> {
3051 self.git_diff.hunks_in_row_range(range, self)
3052 }
3053
3054 /// Returns all the Git diff hunks intersecting the given
3055 /// range.
3056 pub fn git_diff_hunks_intersecting_range(
3057 &self,
3058 range: Range<Anchor>,
3059 ) -> impl '_ + Iterator<Item = git::diff::DiffHunk<u32>> {
3060 self.git_diff.hunks_intersecting_range(range, self)
3061 }
3062
3063 /// Returns all the Git diff hunks intersecting the given
3064 /// range, in reverse order.
3065 pub fn git_diff_hunks_intersecting_range_rev(
3066 &self,
3067 range: Range<Anchor>,
3068 ) -> impl '_ + Iterator<Item = git::diff::DiffHunk<u32>> {
3069 self.git_diff.hunks_intersecting_range_rev(range, self)
3070 }
3071
3072 /// Returns if the buffer contains any diagnostics.
3073 pub fn has_diagnostics(&self) -> bool {
3074 !self.diagnostics.is_empty()
3075 }
3076
3077 /// Returns all the diagnostics intersecting the given range.
3078 pub fn diagnostics_in_range<'a, T, O>(
3079 &'a self,
3080 search_range: Range<T>,
3081 reversed: bool,
3082 ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>>
3083 where
3084 T: 'a + Clone + ToOffset,
3085 O: 'a + FromAnchor + Ord,
3086 {
3087 let mut iterators: Vec<_> = self
3088 .diagnostics
3089 .iter()
3090 .map(|(_, collection)| {
3091 collection
3092 .range::<T, O>(search_range.clone(), self, true, reversed)
3093 .peekable()
3094 })
3095 .collect();
3096
3097 std::iter::from_fn(move || {
3098 let (next_ix, _) = iterators
3099 .iter_mut()
3100 .enumerate()
3101 .flat_map(|(ix, iter)| Some((ix, iter.peek()?)))
3102 .min_by(|(_, a), (_, b)| a.range.start.cmp(&b.range.start))?;
3103 iterators[next_ix].next()
3104 })
3105 }
3106
3107 /// Returns all the diagnostic groups associated with the given
3108 /// language server id. If no language server id is provided,
3109 /// all diagnostics groups are returned.
3110 pub fn diagnostic_groups(
3111 &self,
3112 language_server_id: Option<LanguageServerId>,
3113 ) -> Vec<(LanguageServerId, DiagnosticGroup<Anchor>)> {
3114 let mut groups = Vec::new();
3115
3116 if let Some(language_server_id) = language_server_id {
3117 if let Ok(ix) = self
3118 .diagnostics
3119 .binary_search_by_key(&language_server_id, |e| e.0)
3120 {
3121 self.diagnostics[ix]
3122 .1
3123 .groups(language_server_id, &mut groups, self);
3124 }
3125 } else {
3126 for (language_server_id, diagnostics) in self.diagnostics.iter() {
3127 diagnostics.groups(*language_server_id, &mut groups, self);
3128 }
3129 }
3130
3131 groups.sort_by(|(id_a, group_a), (id_b, group_b)| {
3132 let a_start = &group_a.entries[group_a.primary_ix].range.start;
3133 let b_start = &group_b.entries[group_b.primary_ix].range.start;
3134 a_start.cmp(b_start, self).then_with(|| id_a.cmp(id_b))
3135 });
3136
3137 groups
3138 }
3139
3140 /// Returns an iterator over the diagnostics for the given group.
3141 pub fn diagnostic_group<'a, O>(
3142 &'a self,
3143 group_id: usize,
3144 ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>>
3145 where
3146 O: 'a + FromAnchor,
3147 {
3148 self.diagnostics
3149 .iter()
3150 .flat_map(move |(_, set)| set.group(group_id, self))
3151 }
3152
3153 /// The number of times diagnostics were updated.
3154 pub fn diagnostics_update_count(&self) -> usize {
3155 self.diagnostics_update_count
3156 }
3157
3158 /// The number of times the buffer was parsed.
3159 pub fn parse_count(&self) -> usize {
3160 self.parse_count
3161 }
3162
3163 /// The number of times selections were updated.
3164 pub fn selections_update_count(&self) -> usize {
3165 self.selections_update_count
3166 }
3167
3168 /// Returns a snapshot of underlying file.
3169 pub fn file(&self) -> Option<&Arc<dyn File>> {
3170 self.file.as_ref()
3171 }
3172
3173 /// Resolves the file path (relative to the worktree root) associated with the underlying file.
3174 pub fn resolve_file_path(&self, cx: &AppContext, include_root: bool) -> Option<PathBuf> {
3175 if let Some(file) = self.file() {
3176 if file.path().file_name().is_none() || include_root {
3177 Some(file.full_path(cx))
3178 } else {
3179 Some(file.path().to_path_buf())
3180 }
3181 } else {
3182 None
3183 }
3184 }
3185
3186 /// The number of times the underlying file was updated.
3187 pub fn file_update_count(&self) -> usize {
3188 self.file_update_count
3189 }
3190
3191 /// The number of times the git diff status was updated.
3192 pub fn git_diff_update_count(&self) -> usize {
3193 self.git_diff_update_count
3194 }
3195}
3196
3197fn indent_size_for_line(text: &text::BufferSnapshot, row: u32) -> IndentSize {
3198 indent_size_for_text(text.chars_at(Point::new(row, 0)))
3199}
3200
3201fn indent_size_for_text(text: impl Iterator<Item = char>) -> IndentSize {
3202 let mut result = IndentSize::spaces(0);
3203 for c in text {
3204 let kind = match c {
3205 ' ' => IndentKind::Space,
3206 '\t' => IndentKind::Tab,
3207 _ => break,
3208 };
3209 if result.len == 0 {
3210 result.kind = kind;
3211 }
3212 result.len += 1;
3213 }
3214 result
3215}
3216
3217impl Clone for BufferSnapshot {
3218 fn clone(&self) -> Self {
3219 Self {
3220 text: self.text.clone(),
3221 git_diff: self.git_diff.clone(),
3222 syntax: self.syntax.clone(),
3223 file: self.file.clone(),
3224 remote_selections: self.remote_selections.clone(),
3225 diagnostics: self.diagnostics.clone(),
3226 selections_update_count: self.selections_update_count,
3227 diagnostics_update_count: self.diagnostics_update_count,
3228 file_update_count: self.file_update_count,
3229 git_diff_update_count: self.git_diff_update_count,
3230 language: self.language.clone(),
3231 parse_count: self.parse_count,
3232 }
3233 }
3234}
3235
3236impl Deref for BufferSnapshot {
3237 type Target = text::BufferSnapshot;
3238
3239 fn deref(&self) -> &Self::Target {
3240 &self.text
3241 }
3242}
3243
3244unsafe impl<'a> Send for BufferChunks<'a> {}
3245
3246impl<'a> BufferChunks<'a> {
3247 pub(crate) fn new(
3248 text: &'a Rope,
3249 range: Range<usize>,
3250 syntax: Option<(SyntaxMapCaptures<'a>, Vec<HighlightMap>)>,
3251 diagnostic_endpoints: Vec<DiagnosticEndpoint>,
3252 ) -> Self {
3253 let mut highlights = None;
3254 if let Some((captures, highlight_maps)) = syntax {
3255 highlights = Some(BufferChunkHighlights {
3256 captures,
3257 next_capture: None,
3258 stack: Default::default(),
3259 highlight_maps,
3260 })
3261 }
3262
3263 let diagnostic_endpoints = diagnostic_endpoints.into_iter().peekable();
3264 let chunks = text.chunks_in_range(range.clone());
3265
3266 BufferChunks {
3267 range,
3268 chunks,
3269 diagnostic_endpoints,
3270 error_depth: 0,
3271 warning_depth: 0,
3272 information_depth: 0,
3273 hint_depth: 0,
3274 unnecessary_depth: 0,
3275 highlights,
3276 }
3277 }
3278
3279 /// Seeks to the given byte offset in the buffer.
3280 pub fn seek(&mut self, offset: usize) {
3281 self.range.start = offset;
3282 self.chunks.seek(self.range.start);
3283 if let Some(highlights) = self.highlights.as_mut() {
3284 highlights
3285 .stack
3286 .retain(|(end_offset, _)| *end_offset > offset);
3287 if let Some(capture) = &highlights.next_capture {
3288 if offset >= capture.node.start_byte() {
3289 let next_capture_end = capture.node.end_byte();
3290 if offset < next_capture_end {
3291 highlights.stack.push((
3292 next_capture_end,
3293 highlights.highlight_maps[capture.grammar_index].get(capture.index),
3294 ));
3295 }
3296 highlights.next_capture.take();
3297 }
3298 }
3299 highlights.captures.set_byte_range(self.range.clone());
3300 }
3301 }
3302
3303 /// The current byte offset in the buffer.
3304 pub fn offset(&self) -> usize {
3305 self.range.start
3306 }
3307
3308 fn update_diagnostic_depths(&mut self, endpoint: DiagnosticEndpoint) {
3309 let depth = match endpoint.severity {
3310 DiagnosticSeverity::ERROR => &mut self.error_depth,
3311 DiagnosticSeverity::WARNING => &mut self.warning_depth,
3312 DiagnosticSeverity::INFORMATION => &mut self.information_depth,
3313 DiagnosticSeverity::HINT => &mut self.hint_depth,
3314 _ => return,
3315 };
3316 if endpoint.is_start {
3317 *depth += 1;
3318 } else {
3319 *depth -= 1;
3320 }
3321
3322 if endpoint.is_unnecessary {
3323 if endpoint.is_start {
3324 self.unnecessary_depth += 1;
3325 } else {
3326 self.unnecessary_depth -= 1;
3327 }
3328 }
3329 }
3330
3331 fn current_diagnostic_severity(&self) -> Option<DiagnosticSeverity> {
3332 if self.error_depth > 0 {
3333 Some(DiagnosticSeverity::ERROR)
3334 } else if self.warning_depth > 0 {
3335 Some(DiagnosticSeverity::WARNING)
3336 } else if self.information_depth > 0 {
3337 Some(DiagnosticSeverity::INFORMATION)
3338 } else if self.hint_depth > 0 {
3339 Some(DiagnosticSeverity::HINT)
3340 } else {
3341 None
3342 }
3343 }
3344
3345 fn current_code_is_unnecessary(&self) -> bool {
3346 self.unnecessary_depth > 0
3347 }
3348}
3349
3350impl<'a> Iterator for BufferChunks<'a> {
3351 type Item = Chunk<'a>;
3352
3353 fn next(&mut self) -> Option<Self::Item> {
3354 let mut next_capture_start = usize::MAX;
3355 let mut next_diagnostic_endpoint = usize::MAX;
3356
3357 if let Some(highlights) = self.highlights.as_mut() {
3358 while let Some((parent_capture_end, _)) = highlights.stack.last() {
3359 if *parent_capture_end <= self.range.start {
3360 highlights.stack.pop();
3361 } else {
3362 break;
3363 }
3364 }
3365
3366 if highlights.next_capture.is_none() {
3367 highlights.next_capture = highlights.captures.next();
3368 }
3369
3370 while let Some(capture) = highlights.next_capture.as_ref() {
3371 if self.range.start < capture.node.start_byte() {
3372 next_capture_start = capture.node.start_byte();
3373 break;
3374 } else {
3375 let highlight_id =
3376 highlights.highlight_maps[capture.grammar_index].get(capture.index);
3377 highlights
3378 .stack
3379 .push((capture.node.end_byte(), highlight_id));
3380 highlights.next_capture = highlights.captures.next();
3381 }
3382 }
3383 }
3384
3385 while let Some(endpoint) = self.diagnostic_endpoints.peek().copied() {
3386 if endpoint.offset <= self.range.start {
3387 self.update_diagnostic_depths(endpoint);
3388 self.diagnostic_endpoints.next();
3389 } else {
3390 next_diagnostic_endpoint = endpoint.offset;
3391 break;
3392 }
3393 }
3394
3395 if let Some(chunk) = self.chunks.peek() {
3396 let chunk_start = self.range.start;
3397 let mut chunk_end = (self.chunks.offset() + chunk.len())
3398 .min(next_capture_start)
3399 .min(next_diagnostic_endpoint);
3400 let mut highlight_id = None;
3401 if let Some(highlights) = self.highlights.as_ref() {
3402 if let Some((parent_capture_end, parent_highlight_id)) = highlights.stack.last() {
3403 chunk_end = chunk_end.min(*parent_capture_end);
3404 highlight_id = Some(*parent_highlight_id);
3405 }
3406 }
3407
3408 let slice =
3409 &chunk[chunk_start - self.chunks.offset()..chunk_end - self.chunks.offset()];
3410 self.range.start = chunk_end;
3411 if self.range.start == self.chunks.offset() + chunk.len() {
3412 self.chunks.next().unwrap();
3413 }
3414
3415 Some(Chunk {
3416 text: slice,
3417 syntax_highlight_id: highlight_id,
3418 diagnostic_severity: self.current_diagnostic_severity(),
3419 is_unnecessary: self.current_code_is_unnecessary(),
3420 ..Default::default()
3421 })
3422 } else {
3423 None
3424 }
3425 }
3426}
3427
3428impl operation_queue::Operation for Operation {
3429 fn lamport_timestamp(&self) -> clock::Lamport {
3430 match self {
3431 Operation::Buffer(_) => {
3432 unreachable!("buffer operations should never be deferred at this layer")
3433 }
3434 Operation::UpdateDiagnostics {
3435 lamport_timestamp, ..
3436 }
3437 | Operation::UpdateSelections {
3438 lamport_timestamp, ..
3439 }
3440 | Operation::UpdateCompletionTriggers {
3441 lamport_timestamp, ..
3442 } => *lamport_timestamp,
3443 }
3444 }
3445}
3446
3447impl Default for Diagnostic {
3448 fn default() -> Self {
3449 Self {
3450 source: Default::default(),
3451 code: None,
3452 severity: DiagnosticSeverity::ERROR,
3453 message: Default::default(),
3454 group_id: 0,
3455 is_primary: false,
3456 is_disk_based: false,
3457 is_unnecessary: false,
3458 }
3459 }
3460}
3461
3462impl IndentSize {
3463 /// Returns an [IndentSize] representing the given spaces.
3464 pub fn spaces(len: u32) -> Self {
3465 Self {
3466 len,
3467 kind: IndentKind::Space,
3468 }
3469 }
3470
3471 /// Returns an [IndentSize] representing a tab.
3472 pub fn tab() -> Self {
3473 Self {
3474 len: 1,
3475 kind: IndentKind::Tab,
3476 }
3477 }
3478
3479 /// An iterator over the characters represented by this [IndentSize].
3480 pub fn chars(&self) -> impl Iterator<Item = char> {
3481 iter::repeat(self.char()).take(self.len as usize)
3482 }
3483
3484 /// The character representation of this [IndentSize].
3485 pub fn char(&self) -> char {
3486 match self.kind {
3487 IndentKind::Space => ' ',
3488 IndentKind::Tab => '\t',
3489 }
3490 }
3491
3492 /// Consumes the current [IndentSize] and returns a new one that has
3493 /// been shrunk or enlarged by the given size along the given direction.
3494 pub fn with_delta(mut self, direction: Ordering, size: IndentSize) -> Self {
3495 match direction {
3496 Ordering::Less => {
3497 if self.kind == size.kind && self.len >= size.len {
3498 self.len -= size.len;
3499 }
3500 }
3501 Ordering::Equal => {}
3502 Ordering::Greater => {
3503 if self.len == 0 {
3504 self = size;
3505 } else if self.kind == size.kind {
3506 self.len += size.len;
3507 }
3508 }
3509 }
3510 self
3511 }
3512}
3513
3514impl Completion {
3515 /// A key that can be used to sort completions when displaying
3516 /// them to the user.
3517 pub fn sort_key(&self) -> (usize, &str) {
3518 let kind_key = match self.lsp_completion.kind {
3519 Some(lsp::CompletionItemKind::KEYWORD) => 0,
3520 Some(lsp::CompletionItemKind::VARIABLE) => 1,
3521 _ => 2,
3522 };
3523 (kind_key, &self.label.text[self.label.filter_range.clone()])
3524 }
3525
3526 /// Whether this completion is a snippet.
3527 pub fn is_snippet(&self) -> bool {
3528 self.lsp_completion.insert_text_format == Some(lsp::InsertTextFormat::SNIPPET)
3529 }
3530}
3531
3532#[cfg(any(test, feature = "test-support"))]
3533pub struct TestFile {
3534 pub path: Arc<Path>,
3535 pub root_name: String,
3536}
3537
3538#[cfg(any(test, feature = "test-support"))]
3539impl File for TestFile {
3540 fn path(&self) -> &Arc<Path> {
3541 &self.path
3542 }
3543
3544 fn full_path(&self, _: &gpui::AppContext) -> PathBuf {
3545 PathBuf::from(&self.root_name).join(self.path.as_ref())
3546 }
3547
3548 fn as_local(&self) -> Option<&dyn LocalFile> {
3549 None
3550 }
3551
3552 fn mtime(&self) -> Option<SystemTime> {
3553 unimplemented!()
3554 }
3555
3556 fn file_name<'a>(&'a self, _: &'a gpui::AppContext) -> &'a std::ffi::OsStr {
3557 self.path().file_name().unwrap_or(self.root_name.as_ref())
3558 }
3559
3560 fn worktree_id(&self) -> usize {
3561 0
3562 }
3563
3564 fn is_deleted(&self) -> bool {
3565 unimplemented!()
3566 }
3567
3568 fn as_any(&self) -> &dyn std::any::Any {
3569 unimplemented!()
3570 }
3571
3572 fn to_proto(&self) -> rpc::proto::File {
3573 unimplemented!()
3574 }
3575
3576 fn is_private(&self) -> bool {
3577 false
3578 }
3579}
3580
3581pub(crate) fn contiguous_ranges(
3582 values: impl Iterator<Item = u32>,
3583 max_len: usize,
3584) -> impl Iterator<Item = Range<u32>> {
3585 let mut values = values;
3586 let mut current_range: Option<Range<u32>> = None;
3587 std::iter::from_fn(move || loop {
3588 if let Some(value) = values.next() {
3589 if let Some(range) = &mut current_range {
3590 if value == range.end && range.len() < max_len {
3591 range.end += 1;
3592 continue;
3593 }
3594 }
3595
3596 let prev_range = current_range.clone();
3597 current_range = Some(value..(value + 1));
3598 if prev_range.is_some() {
3599 return prev_range;
3600 }
3601 } else {
3602 return current_range.take();
3603 }
3604 })
3605}
3606
3607/// Returns the [CharKind] for the given character. When a scope is provided,
3608/// the function checks if the character is considered a word character
3609/// based on the language scope's word character settings.
3610pub fn char_kind(scope: &Option<LanguageScope>, c: char) -> CharKind {
3611 if c.is_whitespace() {
3612 return CharKind::Whitespace;
3613 } else if c.is_alphanumeric() || c == '_' {
3614 return CharKind::Word;
3615 }
3616
3617 if let Some(scope) = scope {
3618 if let Some(characters) = scope.word_characters() {
3619 if characters.contains(&c) {
3620 return CharKind::Word;
3621 }
3622 }
3623 }
3624
3625 CharKind::Punctuation
3626}
3627
3628/// Find all of the ranges of whitespace that occur at the ends of lines
3629/// in the given rope.
3630///
3631/// This could also be done with a regex search, but this implementation
3632/// avoids copying text.
3633pub fn trailing_whitespace_ranges(rope: &Rope) -> Vec<Range<usize>> {
3634 let mut ranges = Vec::new();
3635
3636 let mut offset = 0;
3637 let mut prev_chunk_trailing_whitespace_range = 0..0;
3638 for chunk in rope.chunks() {
3639 let mut prev_line_trailing_whitespace_range = 0..0;
3640 for (i, line) in chunk.split('\n').enumerate() {
3641 let line_end_offset = offset + line.len();
3642 let trimmed_line_len = line.trim_end_matches(|c| matches!(c, ' ' | '\t')).len();
3643 let mut trailing_whitespace_range = (offset + trimmed_line_len)..line_end_offset;
3644
3645 if i == 0 && trimmed_line_len == 0 {
3646 trailing_whitespace_range.start = prev_chunk_trailing_whitespace_range.start;
3647 }
3648 if !prev_line_trailing_whitespace_range.is_empty() {
3649 ranges.push(prev_line_trailing_whitespace_range);
3650 }
3651
3652 offset = line_end_offset + 1;
3653 prev_line_trailing_whitespace_range = trailing_whitespace_range;
3654 }
3655
3656 offset -= 1;
3657 prev_chunk_trailing_whitespace_range = prev_line_trailing_whitespace_range;
3658 }
3659
3660 if !prev_chunk_trailing_whitespace_range.is_empty() {
3661 ranges.push(prev_chunk_trailing_whitespace_range);
3662 }
3663
3664 ranges
3665}