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