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