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