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