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