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