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