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