1pub mod row_chunk;
2
3use crate::{
4 DebuggerTextObject, LanguageScope, ModelineSettings, Outline, OutlineConfig, PLAIN_TEXT,
5 RunnableCapture, RunnableTag, TextObject, TreeSitterOptions,
6 diagnostic_set::{DiagnosticEntry, DiagnosticEntryRef, DiagnosticGroup},
7 language_settings::{AutoIndentMode, LanguageSettings},
8 outline::OutlineItem,
9 row_chunk::RowChunks,
10 syntax_map::{
11 MAX_BYTES_TO_QUERY, SyntaxLayer, SyntaxMap, SyntaxMapCapture, SyntaxMapCaptures,
12 SyntaxMapMatch, SyntaxMapMatches, SyntaxSnapshot, ToTreeSitterPoint,
13 },
14 task_context::RunnableRange,
15 text_diff::text_diff,
16 unified_diff_with_offsets,
17};
18pub use crate::{
19 Grammar, HighlightId, HighlightMap, Language, LanguageRegistry, diagnostic_set::DiagnosticSet,
20 proto,
21};
22
23use anyhow::{Context as _, Result};
24use clock::Lamport;
25pub use clock::ReplicaId;
26use collections::{HashMap, HashSet};
27use encoding_rs::Encoding;
28use fs::MTime;
29use futures::channel::oneshot;
30use gpui::{
31 App, AppContext as _, Context, Entity, EventEmitter, HighlightStyle, SharedString, StyledText,
32 Task, TextStyle,
33};
34
35use lsp::LanguageServerId;
36use parking_lot::Mutex;
37use settings::WorktreeId;
38use smallvec::SmallVec;
39use smol::future::yield_now;
40use std::{
41 any::Any,
42 borrow::Cow,
43 cell::Cell,
44 cmp::{self, Ordering, Reverse},
45 collections::{BTreeMap, BTreeSet},
46 future::Future,
47 iter::{self, Iterator, Peekable},
48 mem,
49 num::NonZeroU32,
50 ops::{Deref, Range},
51 path::PathBuf,
52 rc,
53 sync::Arc,
54 time::{Duration, Instant},
55 vec,
56};
57use sum_tree::TreeMap;
58use text::operation_queue::OperationQueue;
59use text::*;
60pub use text::{
61 Anchor, Bias, Buffer as TextBuffer, BufferId, BufferSnapshot as TextBufferSnapshot, Edit,
62 LineIndent, OffsetRangeExt, OffsetUtf16, Patch, Point, PointUtf16, Rope, Selection,
63 SelectionGoal, Subscription, TextDimension, TextSummary, ToOffset, ToOffsetUtf16, ToPoint,
64 ToPointUtf16, Transaction, TransactionId, Unclipped,
65};
66use theme::{ActiveTheme as _, SyntaxTheme};
67#[cfg(any(test, feature = "test-support"))]
68use util::RandomCharIter;
69use util::{RangeExt, debug_panic, maybe, paths::PathStyle, rel_path::RelPath};
70
71#[cfg(any(test, feature = "test-support"))]
72pub use {tree_sitter_python, tree_sitter_rust, tree_sitter_typescript};
73
74pub use lsp::DiagnosticSeverity;
75
76/// Indicate whether a [`Buffer`] has permissions to edit.
77#[derive(PartialEq, Clone, Copy, Debug)]
78pub enum Capability {
79 /// The buffer is a mutable replica.
80 ReadWrite,
81 /// The buffer is a mutable replica, but toggled to be only readable.
82 Read,
83 /// The buffer is a read-only replica.
84 ReadOnly,
85}
86
87impl Capability {
88 /// Returns `true` if the capability is `ReadWrite`.
89 pub fn editable(self) -> bool {
90 matches!(self, Capability::ReadWrite)
91 }
92}
93
94pub type BufferRow = u32;
95
96/// An in-memory representation of a source code file, including its text,
97/// syntax trees, git status, and diagnostics.
98pub struct Buffer {
99 text: TextBuffer,
100 branch_state: Option<BufferBranchState>,
101 /// Filesystem state, `None` when there is no path.
102 file: Option<Arc<dyn File>>,
103 /// The mtime of the file when this buffer was last loaded from
104 /// or saved to disk.
105 saved_mtime: Option<MTime>,
106 /// The version vector when this buffer was last loaded from
107 /// or saved to disk.
108 saved_version: clock::Global,
109 preview_version: clock::Global,
110 transaction_depth: usize,
111 was_dirty_before_starting_transaction: Option<bool>,
112 reload_task: Option<Task<Result<()>>>,
113 language: Option<Arc<Language>>,
114 autoindent_requests: Vec<Arc<AutoindentRequest>>,
115 wait_for_autoindent_txs: Vec<oneshot::Sender<()>>,
116 pending_autoindent: Option<Task<()>>,
117 sync_parse_timeout: Option<Duration>,
118 syntax_map: Mutex<SyntaxMap>,
119 reparse: Option<Task<()>>,
120 parse_status: (watch::Sender<ParseStatus>, watch::Receiver<ParseStatus>),
121 non_text_state_update_count: usize,
122 diagnostics: TreeMap<LanguageServerId, DiagnosticSet>,
123 remote_selections: TreeMap<ReplicaId, SelectionSet>,
124 diagnostics_timestamp: clock::Lamport,
125 completion_triggers: BTreeSet<String>,
126 completion_triggers_per_language_server: HashMap<LanguageServerId, BTreeSet<String>>,
127 completion_triggers_timestamp: clock::Lamport,
128 deferred_ops: OperationQueue<Operation>,
129 capability: Capability,
130 has_conflict: bool,
131 /// Memoize calls to has_changes_since(saved_version).
132 /// The contents of a cell are (self.version, has_changes) at the time of a last call.
133 has_unsaved_edits: Cell<(clock::Global, bool)>,
134 change_bits: Vec<rc::Weak<Cell<bool>>>,
135 modeline: Option<Arc<ModelineSettings>>,
136 _subscriptions: Vec<gpui::Subscription>,
137 tree_sitter_data: Arc<TreeSitterData>,
138 encoding: &'static Encoding,
139 has_bom: bool,
140 reload_with_encoding_txns: HashMap<TransactionId, (&'static Encoding, bool)>,
141}
142
143#[derive(Debug)]
144pub struct TreeSitterData {
145 chunks: RowChunks,
146 brackets_by_chunks: Mutex<Vec<Option<Vec<BracketMatch<usize>>>>>,
147}
148
149const MAX_ROWS_IN_A_CHUNK: u32 = 50;
150
151impl TreeSitterData {
152 fn clear(&mut self, snapshot: &text::BufferSnapshot) {
153 self.chunks = RowChunks::new(&snapshot, MAX_ROWS_IN_A_CHUNK);
154 self.brackets_by_chunks.get_mut().clear();
155 self.brackets_by_chunks
156 .get_mut()
157 .resize(self.chunks.len(), None);
158 }
159
160 fn new(snapshot: &text::BufferSnapshot) -> Self {
161 let chunks = RowChunks::new(&snapshot, MAX_ROWS_IN_A_CHUNK);
162 Self {
163 brackets_by_chunks: Mutex::new(vec![None; chunks.len()]),
164 chunks,
165 }
166 }
167
168 fn version(&self) -> &clock::Global {
169 self.chunks.version()
170 }
171}
172
173#[derive(Copy, Clone, Debug, PartialEq, Eq)]
174pub enum ParseStatus {
175 Idle,
176 Parsing,
177}
178
179struct BufferBranchState {
180 base_buffer: Entity<Buffer>,
181 merged_operations: Vec<Lamport>,
182}
183
184/// An immutable, cheaply cloneable representation of a fixed
185/// state of a buffer.
186pub struct BufferSnapshot {
187 pub text: text::BufferSnapshot,
188 pub(crate) syntax: SyntaxSnapshot,
189 tree_sitter_data: Arc<TreeSitterData>,
190 diagnostics: TreeMap<LanguageServerId, DiagnosticSet>,
191 remote_selections: TreeMap<ReplicaId, SelectionSet>,
192 language: Option<Arc<Language>>,
193 file: Option<Arc<dyn File>>,
194 non_text_state_update_count: usize,
195 pub capability: Capability,
196 modeline: Option<Arc<ModelineSettings>>,
197}
198
199/// The kind and amount of indentation in a particular line. For now,
200/// assumes that indentation is all the same character.
201#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
202pub struct IndentSize {
203 /// The number of bytes that comprise the indentation.
204 pub len: u32,
205 /// The kind of whitespace used for indentation.
206 pub kind: IndentKind,
207}
208
209/// A whitespace character that's used for indentation.
210#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
211pub enum IndentKind {
212 /// An ASCII space character.
213 #[default]
214 Space,
215 /// An ASCII tab character.
216 Tab,
217}
218
219/// The shape of a selection cursor.
220#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
221pub enum CursorShape {
222 /// A vertical bar
223 #[default]
224 Bar,
225 /// A block that surrounds the following character
226 Block,
227 /// An underline that runs along the following character
228 Underline,
229 /// A box drawn around the following character
230 Hollow,
231}
232
233impl From<settings::CursorShape> for CursorShape {
234 fn from(shape: settings::CursorShape) -> Self {
235 match shape {
236 settings::CursorShape::Bar => CursorShape::Bar,
237 settings::CursorShape::Block => CursorShape::Block,
238 settings::CursorShape::Underline => CursorShape::Underline,
239 settings::CursorShape::Hollow => CursorShape::Hollow,
240 }
241 }
242}
243
244#[derive(Clone, Debug)]
245struct SelectionSet {
246 line_mode: bool,
247 cursor_shape: CursorShape,
248 selections: Arc<[Selection<Anchor>]>,
249 lamport_timestamp: clock::Lamport,
250}
251
252/// An operation used to synchronize this buffer with its other replicas.
253#[derive(Clone, Debug, PartialEq)]
254pub enum Operation {
255 /// A text operation.
256 Buffer(text::Operation),
257
258 /// An update to the buffer's diagnostics.
259 UpdateDiagnostics {
260 /// The id of the language server that produced the new diagnostics.
261 server_id: LanguageServerId,
262 /// The diagnostics.
263 diagnostics: Arc<[DiagnosticEntry<Anchor>]>,
264 /// The buffer's lamport timestamp.
265 lamport_timestamp: clock::Lamport,
266 },
267
268 /// An update to the most recent selections in this buffer.
269 UpdateSelections {
270 /// The selections.
271 selections: Arc<[Selection<Anchor>]>,
272 /// The buffer's lamport timestamp.
273 lamport_timestamp: clock::Lamport,
274 /// Whether the selections are in 'line mode'.
275 line_mode: bool,
276 /// The [`CursorShape`] associated with these selections.
277 cursor_shape: CursorShape,
278 },
279
280 /// An update to the characters that should trigger autocompletion
281 /// for this buffer.
282 UpdateCompletionTriggers {
283 /// The characters that trigger autocompletion.
284 triggers: Vec<String>,
285 /// The buffer's lamport timestamp.
286 lamport_timestamp: clock::Lamport,
287 /// The language server ID.
288 server_id: LanguageServerId,
289 },
290
291 /// An update to the line ending type of this buffer.
292 UpdateLineEnding {
293 /// The line ending type.
294 line_ending: LineEnding,
295 /// The buffer's lamport timestamp.
296 lamport_timestamp: clock::Lamport,
297 },
298}
299
300/// An event that occurs in a buffer.
301#[derive(Clone, Debug, PartialEq)]
302pub enum BufferEvent {
303 /// The buffer was changed in a way that must be
304 /// propagated to its other replicas.
305 Operation {
306 operation: Operation,
307 is_local: bool,
308 },
309 /// The buffer was edited.
310 Edited { is_local: bool },
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 is in need of a reload
320 ReloadNeeded,
321 /// The buffer's language was changed.
322 /// The boolean indicates whether this buffer did not have a language before, but does now.
323 LanguageChanged(bool),
324 /// The buffer's syntax trees were updated.
325 Reparsed,
326 /// The buffer's diagnostics were updated.
327 DiagnosticsUpdated,
328 /// The buffer gained or lost editing capabilities.
329 CapabilityChanged,
330}
331
332/// The file associated with a buffer.
333pub trait File: Send + Sync + Any {
334 /// Returns the [`LocalFile`] associated with this file, if the
335 /// file is local.
336 fn as_local(&self) -> Option<&dyn LocalFile>;
337
338 /// Returns whether this file is local.
339 fn is_local(&self) -> bool {
340 self.as_local().is_some()
341 }
342
343 /// Returns whether the file is new, exists in storage, or has been deleted. Includes metadata
344 /// only available in some states, such as modification time.
345 fn disk_state(&self) -> DiskState;
346
347 /// Returns the path of this file relative to the worktree's root directory.
348 fn path(&self) -> &Arc<RelPath>;
349
350 /// Returns the path of this file relative to the worktree's parent directory (this means it
351 /// includes the name of the worktree's root folder).
352 fn full_path(&self, cx: &App) -> PathBuf;
353
354 /// Returns the path style of this file.
355 fn path_style(&self, cx: &App) -> PathStyle;
356
357 /// Returns the last component of this handle's absolute path. If this handle refers to the root
358 /// of its worktree, then this method will return the name of the worktree itself.
359 fn file_name<'a>(&'a self, cx: &'a App) -> &'a str;
360
361 /// Returns the id of the worktree to which this file belongs.
362 ///
363 /// This is needed for looking up project-specific settings.
364 fn worktree_id(&self, cx: &App) -> WorktreeId;
365
366 /// Converts this file into a protobuf message.
367 fn to_proto(&self, cx: &App) -> rpc::proto::File;
368
369 /// Return whether Zed considers this to be a private file.
370 fn is_private(&self) -> bool;
371
372 fn can_open(&self) -> bool {
373 !self.is_local()
374 }
375}
376
377/// The file's storage status - whether it's stored (`Present`), and if so when it was last
378/// modified. In the case where the file is not stored, it can be either `New` or `Deleted`. In the
379/// UI these two states are distinguished. For example, the buffer tab does not display a deletion
380/// indicator for new files.
381#[derive(Copy, Clone, Debug, PartialEq)]
382pub enum DiskState {
383 /// File created in Zed that has not been saved.
384 New,
385 /// File present on the filesystem.
386 Present { mtime: MTime, size: u64 },
387 /// Deleted file that was previously present.
388 Deleted,
389 /// An old version of a file that was previously present
390 /// usually from a version control system. e.g. A git blob
391 Historic { was_deleted: bool },
392}
393
394impl DiskState {
395 /// Returns the file's last known modification time on disk.
396 pub fn mtime(self) -> Option<MTime> {
397 match self {
398 DiskState::New => None,
399 DiskState::Present { mtime, .. } => Some(mtime),
400 DiskState::Deleted => None,
401 DiskState::Historic { .. } => None,
402 }
403 }
404
405 /// Returns the file's size on disk in bytes.
406 pub fn size(self) -> Option<u64> {
407 match self {
408 DiskState::New => None,
409 DiskState::Present { size, .. } => Some(size),
410 DiskState::Deleted => None,
411 DiskState::Historic { .. } => None,
412 }
413 }
414
415 pub fn exists(&self) -> bool {
416 match self {
417 DiskState::New => false,
418 DiskState::Present { .. } => true,
419 DiskState::Deleted => false,
420 DiskState::Historic { .. } => false,
421 }
422 }
423
424 /// Returns true if this state represents a deleted file.
425 pub fn is_deleted(&self) -> bool {
426 match self {
427 DiskState::Deleted => true,
428 DiskState::Historic { was_deleted } => *was_deleted,
429 _ => false,
430 }
431 }
432}
433
434/// The file associated with a buffer, in the case where the file is on the local disk.
435pub trait LocalFile: File {
436 /// Returns the absolute path of this file
437 fn abs_path(&self, cx: &App) -> PathBuf;
438
439 /// Loads the file contents from disk and returns them as a UTF-8 encoded string.
440 fn load(&self, cx: &App) -> Task<Result<String>>;
441
442 /// Loads the file's contents from disk.
443 fn load_bytes(&self, cx: &App) -> Task<Result<Vec<u8>>>;
444}
445
446/// The auto-indent behavior associated with an editing operation.
447/// For some editing operations, each affected line of text has its
448/// indentation recomputed. For other operations, the entire block
449/// of edited text is adjusted uniformly.
450#[derive(Clone, Debug)]
451pub enum AutoindentMode {
452 /// Indent each line of inserted text.
453 EachLine,
454 /// Apply the same indentation adjustment to all of the lines
455 /// in a given insertion.
456 Block {
457 /// The original indentation column of the first line of each
458 /// insertion, if it has been copied.
459 ///
460 /// Knowing this makes it possible to preserve the relative indentation
461 /// of every line in the insertion from when it was copied.
462 ///
463 /// If the original indent column is `a`, and the first line of insertion
464 /// is then auto-indented to column `b`, then every other line of
465 /// the insertion will be auto-indented to column `b - a`
466 original_indent_columns: Vec<Option<u32>>,
467 },
468}
469
470#[derive(Clone)]
471struct AutoindentRequest {
472 before_edit: BufferSnapshot,
473 entries: Vec<AutoindentRequestEntry>,
474 is_block_mode: bool,
475 ignore_empty_lines: bool,
476}
477
478#[derive(Debug, Clone)]
479struct AutoindentRequestEntry {
480 /// A range of the buffer whose indentation should be adjusted.
481 range: Range<Anchor>,
482 /// The row of the edit start in the buffer before the edit was applied.
483 /// This is stored here because the anchor in range is created after
484 /// the edit, so it cannot be used with the before_edit snapshot.
485 old_row: Option<u32>,
486 indent_size: IndentSize,
487 original_indent_column: Option<u32>,
488}
489
490#[derive(Debug)]
491struct IndentSuggestion {
492 basis_row: u32,
493 delta: Ordering,
494 within_error: bool,
495}
496
497struct BufferChunkHighlights<'a> {
498 captures: SyntaxMapCaptures<'a>,
499 next_capture: Option<SyntaxMapCapture<'a>>,
500 stack: Vec<(usize, HighlightId)>,
501 highlight_maps: Vec<HighlightMap>,
502}
503
504/// An iterator that yields chunks of a buffer's text, along with their
505/// syntax highlights and diagnostic status.
506pub struct BufferChunks<'a> {
507 buffer_snapshot: Option<&'a BufferSnapshot>,
508 range: Range<usize>,
509 chunks: text::Chunks<'a>,
510 diagnostic_endpoints: Option<Peekable<vec::IntoIter<DiagnosticEndpoint>>>,
511 error_depth: usize,
512 warning_depth: usize,
513 information_depth: usize,
514 hint_depth: usize,
515 unnecessary_depth: usize,
516 underline: bool,
517 highlights: Option<BufferChunkHighlights<'a>>,
518}
519
520/// A chunk of a buffer's text, along with its syntax highlight and
521/// diagnostic status.
522#[derive(Clone, Debug, Default)]
523pub struct Chunk<'a> {
524 /// The text of the chunk.
525 pub text: &'a str,
526 /// The syntax highlighting style of the chunk.
527 pub syntax_highlight_id: Option<HighlightId>,
528 /// The highlight style that has been applied to this chunk in
529 /// the editor.
530 pub highlight_style: Option<HighlightStyle>,
531 /// The severity of diagnostic associated with this chunk, if any.
532 pub diagnostic_severity: Option<DiagnosticSeverity>,
533 /// A bitset of which characters are tabs in this string.
534 pub tabs: u128,
535 /// Bitmap of character indices in this chunk
536 pub chars: u128,
537 /// Bitmap of newline indices in this chunk
538 pub newlines: u128,
539 /// Whether this chunk of text is marked as unnecessary.
540 pub is_unnecessary: bool,
541 /// Whether this chunk of text was originally a tab character.
542 pub is_tab: bool,
543 /// Whether this chunk of text was originally an inlay.
544 pub is_inlay: bool,
545 /// Whether to underline the corresponding text range in the editor.
546 pub underline: bool,
547}
548
549/// A set of edits to a given version of a buffer, computed asynchronously.
550#[derive(Debug, Clone)]
551pub struct Diff {
552 pub base_version: clock::Global,
553 pub line_ending: LineEnding,
554 pub edits: Vec<(Range<usize>, Arc<str>)>,
555}
556
557#[derive(Debug, Clone, Copy)]
558pub(crate) struct DiagnosticEndpoint {
559 offset: usize,
560 is_start: bool,
561 underline: bool,
562 severity: DiagnosticSeverity,
563 is_unnecessary: bool,
564}
565
566/// A class of characters, used for characterizing a run of text.
567#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug)]
568pub enum CharKind {
569 /// Whitespace.
570 Whitespace,
571 /// Punctuation.
572 Punctuation,
573 /// Word.
574 Word,
575}
576
577/// Context for character classification within a specific scope.
578#[derive(Copy, Clone, Eq, PartialEq, Debug)]
579pub enum CharScopeContext {
580 /// Character classification for completion queries.
581 ///
582 /// This context treats certain characters as word constituents that would
583 /// normally be considered punctuation, such as '-' in Tailwind classes
584 /// ("bg-yellow-100") or '.' in import paths ("foo.ts").
585 Completion,
586 /// Character classification for linked edits.
587 ///
588 /// This context handles characters that should be treated as part of
589 /// identifiers during linked editing operations, such as '.' in JSX
590 /// component names like `<Animated.View>`.
591 LinkedEdit,
592}
593
594/// A runnable is a set of data about a region that could be resolved into a task
595pub struct Runnable {
596 pub tags: SmallVec<[RunnableTag; 1]>,
597 pub language: Arc<Language>,
598 pub buffer: BufferId,
599}
600
601#[derive(Default, Clone, Debug)]
602pub struct HighlightedText {
603 pub text: SharedString,
604 pub highlights: Vec<(Range<usize>, HighlightStyle)>,
605}
606
607#[derive(Default, Debug)]
608struct HighlightedTextBuilder {
609 pub text: String,
610 highlights: Vec<(Range<usize>, HighlightStyle)>,
611}
612
613impl HighlightedText {
614 pub fn from_buffer_range<T: ToOffset>(
615 range: Range<T>,
616 snapshot: &text::BufferSnapshot,
617 syntax_snapshot: &SyntaxSnapshot,
618 override_style: Option<HighlightStyle>,
619 syntax_theme: &SyntaxTheme,
620 ) -> Self {
621 let mut highlighted_text = HighlightedTextBuilder::default();
622 highlighted_text.add_text_from_buffer_range(
623 range,
624 snapshot,
625 syntax_snapshot,
626 override_style,
627 syntax_theme,
628 );
629 highlighted_text.build()
630 }
631
632 pub fn to_styled_text(&self, default_style: &TextStyle) -> StyledText {
633 gpui::StyledText::new(self.text.clone())
634 .with_default_highlights(default_style, self.highlights.iter().cloned())
635 }
636
637 /// Returns the first line without leading whitespace unless highlighted
638 /// and a boolean indicating if there are more lines after
639 pub fn first_line_preview(self) -> (Self, bool) {
640 let newline_ix = self.text.find('\n').unwrap_or(self.text.len());
641 let first_line = &self.text[..newline_ix];
642
643 // Trim leading whitespace, unless an edit starts prior to it.
644 let mut preview_start_ix = first_line.len() - first_line.trim_start().len();
645 if let Some((first_highlight_range, _)) = self.highlights.first() {
646 preview_start_ix = preview_start_ix.min(first_highlight_range.start);
647 }
648
649 let preview_text = &first_line[preview_start_ix..];
650 let preview_highlights = self
651 .highlights
652 .into_iter()
653 .skip_while(|(range, _)| range.end <= preview_start_ix)
654 .take_while(|(range, _)| range.start < newline_ix)
655 .filter_map(|(mut range, highlight)| {
656 range.start = range.start.saturating_sub(preview_start_ix);
657 range.end = range.end.min(newline_ix).saturating_sub(preview_start_ix);
658 if range.is_empty() {
659 None
660 } else {
661 Some((range, highlight))
662 }
663 });
664
665 let preview = Self {
666 text: SharedString::new(preview_text),
667 highlights: preview_highlights.collect(),
668 };
669
670 (preview, self.text.len() > newline_ix)
671 }
672}
673
674impl HighlightedTextBuilder {
675 pub fn build(self) -> HighlightedText {
676 HighlightedText {
677 text: self.text.into(),
678 highlights: self.highlights,
679 }
680 }
681
682 pub fn add_text_from_buffer_range<T: ToOffset>(
683 &mut self,
684 range: Range<T>,
685 snapshot: &text::BufferSnapshot,
686 syntax_snapshot: &SyntaxSnapshot,
687 override_style: Option<HighlightStyle>,
688 syntax_theme: &SyntaxTheme,
689 ) {
690 let range = range.to_offset(snapshot);
691 for chunk in Self::highlighted_chunks(range, snapshot, syntax_snapshot) {
692 let start = self.text.len();
693 self.text.push_str(chunk.text);
694 let end = self.text.len();
695
696 if let Some(highlight_style) = chunk
697 .syntax_highlight_id
698 .and_then(|id| syntax_theme.get(id).cloned())
699 {
700 let highlight_style = override_style.map_or(highlight_style, |override_style| {
701 highlight_style.highlight(override_style)
702 });
703 self.highlights.push((start..end, highlight_style));
704 } else if let Some(override_style) = override_style {
705 self.highlights.push((start..end, override_style));
706 }
707 }
708 }
709
710 fn highlighted_chunks<'a>(
711 range: Range<usize>,
712 snapshot: &'a text::BufferSnapshot,
713 syntax_snapshot: &'a SyntaxSnapshot,
714 ) -> BufferChunks<'a> {
715 let captures = syntax_snapshot.captures(range.clone(), snapshot, |grammar| {
716 grammar
717 .highlights_config
718 .as_ref()
719 .map(|config| &config.query)
720 });
721
722 let highlight_maps = captures
723 .grammars()
724 .iter()
725 .map(|grammar| grammar.highlight_map())
726 .collect();
727
728 BufferChunks::new(
729 snapshot.as_rope(),
730 range,
731 Some((captures, highlight_maps)),
732 false,
733 None,
734 )
735 }
736}
737
738#[derive(Clone)]
739pub struct EditPreview {
740 old_snapshot: text::BufferSnapshot,
741 applied_edits_snapshot: text::BufferSnapshot,
742 syntax_snapshot: SyntaxSnapshot,
743}
744
745impl EditPreview {
746 pub fn as_unified_diff(
747 &self,
748 file: Option<&Arc<dyn File>>,
749 edits: &[(Range<Anchor>, impl AsRef<str>)],
750 ) -> Option<String> {
751 let (first, _) = edits.first()?;
752 let (last, _) = edits.last()?;
753
754 let start = first.start.to_point(&self.old_snapshot);
755 let old_end = last.end.to_point(&self.old_snapshot);
756 let new_end = last
757 .end
758 .bias_right(&self.old_snapshot)
759 .to_point(&self.applied_edits_snapshot);
760
761 let start = Point::new(start.row.saturating_sub(3), 0);
762 let old_end = Point::new(old_end.row + 4, 0).min(self.old_snapshot.max_point());
763 let new_end = Point::new(new_end.row + 4, 0).min(self.applied_edits_snapshot.max_point());
764
765 let diff_body = unified_diff_with_offsets(
766 &self
767 .old_snapshot
768 .text_for_range(start..old_end)
769 .collect::<String>(),
770 &self
771 .applied_edits_snapshot
772 .text_for_range(start..new_end)
773 .collect::<String>(),
774 start.row,
775 start.row,
776 );
777
778 let path = file.map(|f| f.path().as_unix_str());
779 let header = match path {
780 Some(p) => format!("--- a/{}\n+++ b/{}\n", p, p),
781 None => String::new(),
782 };
783
784 Some(format!("{}{}", header, diff_body))
785 }
786
787 pub fn highlight_edits(
788 &self,
789 current_snapshot: &BufferSnapshot,
790 edits: &[(Range<Anchor>, impl AsRef<str>)],
791 include_deletions: bool,
792 cx: &App,
793 ) -> HighlightedText {
794 let Some(visible_range_in_preview_snapshot) = self.compute_visible_range(edits) else {
795 return HighlightedText::default();
796 };
797
798 let mut highlighted_text = HighlightedTextBuilder::default();
799
800 let visible_range_in_preview_snapshot =
801 visible_range_in_preview_snapshot.to_offset(&self.applied_edits_snapshot);
802 let mut offset_in_preview_snapshot = visible_range_in_preview_snapshot.start;
803
804 let insertion_highlight_style = HighlightStyle {
805 background_color: Some(cx.theme().status().created_background),
806 ..Default::default()
807 };
808 let deletion_highlight_style = HighlightStyle {
809 background_color: Some(cx.theme().status().deleted_background),
810 ..Default::default()
811 };
812 let syntax_theme = cx.theme().syntax();
813
814 for (range, edit_text) in edits {
815 let edit_new_end_in_preview_snapshot = range
816 .end
817 .bias_right(&self.old_snapshot)
818 .to_offset(&self.applied_edits_snapshot);
819 let edit_start_in_preview_snapshot =
820 edit_new_end_in_preview_snapshot - edit_text.as_ref().len();
821
822 let unchanged_range_in_preview_snapshot =
823 offset_in_preview_snapshot..edit_start_in_preview_snapshot;
824 if !unchanged_range_in_preview_snapshot.is_empty() {
825 highlighted_text.add_text_from_buffer_range(
826 unchanged_range_in_preview_snapshot,
827 &self.applied_edits_snapshot,
828 &self.syntax_snapshot,
829 None,
830 syntax_theme,
831 );
832 }
833
834 let range_in_current_snapshot = range.to_offset(current_snapshot);
835 if include_deletions && !range_in_current_snapshot.is_empty() {
836 highlighted_text.add_text_from_buffer_range(
837 range_in_current_snapshot,
838 ¤t_snapshot.text,
839 ¤t_snapshot.syntax,
840 Some(deletion_highlight_style),
841 syntax_theme,
842 );
843 }
844
845 if !edit_text.as_ref().is_empty() {
846 highlighted_text.add_text_from_buffer_range(
847 edit_start_in_preview_snapshot..edit_new_end_in_preview_snapshot,
848 &self.applied_edits_snapshot,
849 &self.syntax_snapshot,
850 Some(insertion_highlight_style),
851 syntax_theme,
852 );
853 }
854
855 offset_in_preview_snapshot = edit_new_end_in_preview_snapshot;
856 }
857
858 highlighted_text.add_text_from_buffer_range(
859 offset_in_preview_snapshot..visible_range_in_preview_snapshot.end,
860 &self.applied_edits_snapshot,
861 &self.syntax_snapshot,
862 None,
863 syntax_theme,
864 );
865
866 highlighted_text.build()
867 }
868
869 pub fn build_result_buffer(&self, cx: &mut App) -> Entity<Buffer> {
870 cx.new(|cx| {
871 let mut buffer = Buffer::local_normalized(
872 self.applied_edits_snapshot.as_rope().clone(),
873 self.applied_edits_snapshot.line_ending(),
874 cx,
875 );
876 buffer.set_language_async(self.syntax_snapshot.root_language(), cx);
877 buffer
878 })
879 }
880
881 pub fn anchor_to_offset_in_result(&self, anchor: Anchor) -> usize {
882 anchor
883 .bias_right(&self.old_snapshot)
884 .to_offset(&self.applied_edits_snapshot)
885 }
886
887 pub fn compute_visible_range<T>(&self, edits: &[(Range<Anchor>, T)]) -> Option<Range<Point>> {
888 let (first, _) = edits.first()?;
889 let (last, _) = edits.last()?;
890
891 let start = first
892 .start
893 .bias_left(&self.old_snapshot)
894 .to_point(&self.applied_edits_snapshot);
895 let end = last
896 .end
897 .bias_right(&self.old_snapshot)
898 .to_point(&self.applied_edits_snapshot);
899
900 // Ensure that the first line of the first edit and the last line of the last edit are always fully visible
901 let range = Point::new(start.row, 0)
902 ..Point::new(end.row, self.applied_edits_snapshot.line_len(end.row));
903
904 Some(range)
905 }
906}
907
908#[derive(Clone, Debug, PartialEq, Eq)]
909pub struct BracketMatch<T> {
910 pub open_range: Range<T>,
911 pub close_range: Range<T>,
912 pub newline_only: bool,
913 pub syntax_layer_depth: usize,
914 pub color_index: Option<usize>,
915}
916
917impl<T> BracketMatch<T> {
918 pub fn bracket_ranges(self) -> (Range<T>, Range<T>) {
919 (self.open_range, self.close_range)
920 }
921}
922
923impl Buffer {
924 /// Create a new buffer with the given base text.
925 pub fn local<T: Into<String>>(base_text: T, cx: &Context<Self>) -> Self {
926 Self::build(
927 TextBuffer::new(
928 ReplicaId::LOCAL,
929 cx.entity_id().as_non_zero_u64().into(),
930 base_text.into(),
931 ),
932 None,
933 Capability::ReadWrite,
934 )
935 }
936
937 /// Create a new buffer with the given base text that has proper line endings and other normalization applied.
938 pub fn local_normalized(
939 base_text_normalized: Rope,
940 line_ending: LineEnding,
941 cx: &Context<Self>,
942 ) -> Self {
943 Self::build(
944 TextBuffer::new_normalized(
945 ReplicaId::LOCAL,
946 cx.entity_id().as_non_zero_u64().into(),
947 line_ending,
948 base_text_normalized,
949 ),
950 None,
951 Capability::ReadWrite,
952 )
953 }
954
955 /// Create a new buffer that is a replica of a remote buffer.
956 pub fn remote(
957 remote_id: BufferId,
958 replica_id: ReplicaId,
959 capability: Capability,
960 base_text: impl Into<String>,
961 ) -> Self {
962 Self::build(
963 TextBuffer::new(replica_id, remote_id, base_text.into()),
964 None,
965 capability,
966 )
967 }
968
969 /// Create a new buffer that is a replica of a remote buffer, populating its
970 /// state from the given protobuf message.
971 pub fn from_proto(
972 replica_id: ReplicaId,
973 capability: Capability,
974 message: proto::BufferState,
975 file: Option<Arc<dyn File>>,
976 ) -> Result<Self> {
977 let buffer_id = BufferId::new(message.id).context("Could not deserialize buffer_id")?;
978 let buffer = TextBuffer::new(replica_id, buffer_id, message.base_text);
979 let mut this = Self::build(buffer, file, capability);
980 this.text.set_line_ending(proto::deserialize_line_ending(
981 rpc::proto::LineEnding::from_i32(message.line_ending).context("missing line_ending")?,
982 ));
983 this.saved_version = proto::deserialize_version(&message.saved_version);
984 this.saved_mtime = message.saved_mtime.map(|time| time.into());
985 Ok(this)
986 }
987
988 /// Serialize the buffer's state to a protobuf message.
989 pub fn to_proto(&self, cx: &App) -> proto::BufferState {
990 proto::BufferState {
991 id: self.remote_id().into(),
992 file: self.file.as_ref().map(|f| f.to_proto(cx)),
993 base_text: self.base_text().to_string(),
994 line_ending: proto::serialize_line_ending(self.line_ending()) as i32,
995 saved_version: proto::serialize_version(&self.saved_version),
996 saved_mtime: self.saved_mtime.map(|time| time.into()),
997 }
998 }
999
1000 /// Serialize as protobufs all of the changes to the buffer since the given version.
1001 pub fn serialize_ops(
1002 &self,
1003 since: Option<clock::Global>,
1004 cx: &App,
1005 ) -> Task<Vec<proto::Operation>> {
1006 let mut operations = Vec::new();
1007 operations.extend(self.deferred_ops.iter().map(proto::serialize_operation));
1008
1009 operations.extend(self.remote_selections.iter().map(|(_, set)| {
1010 proto::serialize_operation(&Operation::UpdateSelections {
1011 selections: set.selections.clone(),
1012 lamport_timestamp: set.lamport_timestamp,
1013 line_mode: set.line_mode,
1014 cursor_shape: set.cursor_shape,
1015 })
1016 }));
1017
1018 for (server_id, diagnostics) in self.diagnostics.iter() {
1019 operations.push(proto::serialize_operation(&Operation::UpdateDiagnostics {
1020 lamport_timestamp: self.diagnostics_timestamp,
1021 server_id: *server_id,
1022 diagnostics: diagnostics.iter().cloned().collect(),
1023 }));
1024 }
1025
1026 for (server_id, completions) in &self.completion_triggers_per_language_server {
1027 operations.push(proto::serialize_operation(
1028 &Operation::UpdateCompletionTriggers {
1029 triggers: completions.iter().cloned().collect(),
1030 lamport_timestamp: self.completion_triggers_timestamp,
1031 server_id: *server_id,
1032 },
1033 ));
1034 }
1035
1036 let text_operations = self.text.operations().clone();
1037 cx.background_spawn(async move {
1038 let since = since.unwrap_or_default();
1039 operations.extend(
1040 text_operations
1041 .iter()
1042 .filter(|(_, op)| !since.observed(op.timestamp()))
1043 .map(|(_, op)| proto::serialize_operation(&Operation::Buffer(op.clone()))),
1044 );
1045 operations.sort_unstable_by_key(proto::lamport_timestamp_for_operation);
1046 operations
1047 })
1048 }
1049
1050 /// Assign a language to the buffer, returning the buffer.
1051 pub fn with_language_async(mut self, language: Arc<Language>, cx: &mut Context<Self>) -> Self {
1052 self.set_language_async(Some(language), cx);
1053 self
1054 }
1055
1056 /// Assign a language to the buffer, blocking for up to 1ms to reparse the buffer, returning the buffer.
1057 #[ztracing::instrument(skip_all, fields(lang = language.config.name.0.as_str()))]
1058 pub fn with_language(mut self, language: Arc<Language>, cx: &mut Context<Self>) -> Self {
1059 self.set_language(Some(language), cx);
1060 self
1061 }
1062
1063 /// Returns the [`Capability`] of this buffer.
1064 pub fn capability(&self) -> Capability {
1065 self.capability
1066 }
1067
1068 /// Whether this buffer can only be read.
1069 pub fn read_only(&self) -> bool {
1070 !self.capability.editable()
1071 }
1072
1073 /// Builds a [`Buffer`] with the given underlying [`TextBuffer`], diff base, [`File`] and [`Capability`].
1074 pub fn build(buffer: TextBuffer, file: Option<Arc<dyn File>>, capability: Capability) -> Self {
1075 let saved_mtime = file.as_ref().and_then(|file| file.disk_state().mtime());
1076 let snapshot = buffer.snapshot();
1077 let syntax_map = Mutex::new(SyntaxMap::new(&snapshot));
1078 let tree_sitter_data = TreeSitterData::new(snapshot);
1079 Self {
1080 saved_mtime,
1081 tree_sitter_data: Arc::new(tree_sitter_data),
1082 saved_version: buffer.version(),
1083 preview_version: buffer.version(),
1084 reload_task: None,
1085 transaction_depth: 0,
1086 was_dirty_before_starting_transaction: None,
1087 has_unsaved_edits: Cell::new((buffer.version(), false)),
1088 text: buffer,
1089 branch_state: None,
1090 file,
1091 capability,
1092 syntax_map,
1093 reparse: None,
1094 non_text_state_update_count: 0,
1095 sync_parse_timeout: if cfg!(any(test, feature = "test-support")) {
1096 Some(Duration::from_millis(10))
1097 } else {
1098 Some(Duration::from_millis(1))
1099 },
1100 parse_status: watch::channel(ParseStatus::Idle),
1101 autoindent_requests: Default::default(),
1102 wait_for_autoindent_txs: Default::default(),
1103 pending_autoindent: Default::default(),
1104 language: None,
1105 remote_selections: Default::default(),
1106 diagnostics: Default::default(),
1107 diagnostics_timestamp: Lamport::MIN,
1108 completion_triggers: Default::default(),
1109 completion_triggers_per_language_server: Default::default(),
1110 completion_triggers_timestamp: Lamport::MIN,
1111 deferred_ops: OperationQueue::new(),
1112 has_conflict: false,
1113 change_bits: Default::default(),
1114 modeline: None,
1115 _subscriptions: Vec::new(),
1116 encoding: encoding_rs::UTF_8,
1117 has_bom: false,
1118 reload_with_encoding_txns: HashMap::default(),
1119 }
1120 }
1121
1122 #[ztracing::instrument(skip_all)]
1123 pub fn build_snapshot(
1124 text: Rope,
1125 language: Option<Arc<Language>>,
1126 language_registry: Option<Arc<LanguageRegistry>>,
1127 modeline: Option<Arc<ModelineSettings>>,
1128 cx: &mut App,
1129 ) -> impl Future<Output = BufferSnapshot> + use<> {
1130 let entity_id = cx.reserve_entity::<Self>().entity_id();
1131 let buffer_id = entity_id.as_non_zero_u64().into();
1132 async move {
1133 let text =
1134 TextBuffer::new_normalized(ReplicaId::LOCAL, buffer_id, Default::default(), text);
1135 let text = text.into_snapshot();
1136 let mut syntax = SyntaxMap::new(&text).snapshot();
1137 if let Some(language) = language.clone() {
1138 let language_registry = language_registry.clone();
1139 syntax.reparse(&text, language_registry, language);
1140 }
1141 let tree_sitter_data = TreeSitterData::new(&text);
1142 BufferSnapshot {
1143 text,
1144 syntax,
1145 file: None,
1146 diagnostics: Default::default(),
1147 remote_selections: Default::default(),
1148 tree_sitter_data: Arc::new(tree_sitter_data),
1149 language,
1150 non_text_state_update_count: 0,
1151 capability: Capability::ReadOnly,
1152 modeline,
1153 }
1154 }
1155 }
1156
1157 pub fn build_empty_snapshot(cx: &mut App) -> BufferSnapshot {
1158 let entity_id = cx.reserve_entity::<Self>().entity_id();
1159 let buffer_id = entity_id.as_non_zero_u64().into();
1160 let text = TextBuffer::new_normalized(
1161 ReplicaId::LOCAL,
1162 buffer_id,
1163 Default::default(),
1164 Rope::new(),
1165 );
1166 let text = text.into_snapshot();
1167 let syntax = SyntaxMap::new(&text).snapshot();
1168 let tree_sitter_data = TreeSitterData::new(&text);
1169 BufferSnapshot {
1170 text,
1171 syntax,
1172 tree_sitter_data: Arc::new(tree_sitter_data),
1173 file: None,
1174 diagnostics: Default::default(),
1175 remote_selections: Default::default(),
1176 language: None,
1177 non_text_state_update_count: 0,
1178 capability: Capability::ReadOnly,
1179 modeline: None,
1180 }
1181 }
1182
1183 #[cfg(any(test, feature = "test-support"))]
1184 pub fn build_snapshot_sync(
1185 text: Rope,
1186 language: Option<Arc<Language>>,
1187 language_registry: Option<Arc<LanguageRegistry>>,
1188 cx: &mut App,
1189 ) -> BufferSnapshot {
1190 let entity_id = cx.reserve_entity::<Self>().entity_id();
1191 let buffer_id = entity_id.as_non_zero_u64().into();
1192 let text =
1193 TextBuffer::new_normalized(ReplicaId::LOCAL, buffer_id, Default::default(), text)
1194 .into_snapshot();
1195 let mut syntax = SyntaxMap::new(&text).snapshot();
1196 if let Some(language) = language.clone() {
1197 syntax.reparse(&text, language_registry, language);
1198 }
1199 let tree_sitter_data = TreeSitterData::new(&text);
1200 BufferSnapshot {
1201 text,
1202 syntax,
1203 tree_sitter_data: Arc::new(tree_sitter_data),
1204 file: None,
1205 diagnostics: Default::default(),
1206 remote_selections: Default::default(),
1207 language,
1208 non_text_state_update_count: 0,
1209 capability: Capability::ReadOnly,
1210 modeline: None,
1211 }
1212 }
1213
1214 /// Retrieve a snapshot of the buffer's current state. This is computationally
1215 /// cheap, and allows reading from the buffer on a background thread.
1216 pub fn snapshot(&self) -> BufferSnapshot {
1217 let text = self.text.snapshot();
1218
1219 let syntax = {
1220 let mut syntax_map = self.syntax_map.lock();
1221 syntax_map.interpolate(text);
1222 syntax_map.snapshot()
1223 };
1224
1225 let tree_sitter_data = if self.text.version() != *self.tree_sitter_data.version() {
1226 Arc::new(TreeSitterData::new(text))
1227 } else {
1228 self.tree_sitter_data.clone()
1229 };
1230
1231 BufferSnapshot {
1232 text: text.clone(),
1233 syntax,
1234 tree_sitter_data,
1235 file: self.file.clone(),
1236 remote_selections: self.remote_selections.clone(),
1237 diagnostics: self.diagnostics.clone(),
1238 language: self.language.clone(),
1239 non_text_state_update_count: self.non_text_state_update_count,
1240 capability: self.capability,
1241 modeline: self.modeline.clone(),
1242 }
1243 }
1244
1245 pub fn branch(&mut self, cx: &mut Context<Self>) -> Entity<Self> {
1246 let this = cx.entity();
1247 cx.new(|cx| {
1248 let mut branch = Self {
1249 branch_state: Some(BufferBranchState {
1250 base_buffer: this.clone(),
1251 merged_operations: Default::default(),
1252 }),
1253 language: self.language.clone(),
1254 has_conflict: self.has_conflict,
1255 has_unsaved_edits: Cell::new(self.has_unsaved_edits.get_mut().clone()),
1256 _subscriptions: vec![cx.subscribe(&this, Self::on_base_buffer_event)],
1257 ..Self::build(self.text.branch(), self.file.clone(), self.capability())
1258 };
1259 if let Some(language_registry) = self.language_registry() {
1260 branch.set_language_registry(language_registry);
1261 }
1262
1263 // Reparse the branch buffer so that we get syntax highlighting immediately.
1264 branch.reparse(cx, true);
1265
1266 branch
1267 })
1268 }
1269
1270 #[ztracing::instrument(skip_all)]
1271 pub fn preview_edits(
1272 &self,
1273 edits: Arc<[(Range<Anchor>, Arc<str>)]>,
1274 cx: &App,
1275 ) -> Task<EditPreview> {
1276 let registry = self.language_registry();
1277 let language = self.language().cloned();
1278 let old_snapshot = self.text.snapshot().clone();
1279 let mut branch_buffer = self.text.branch();
1280 let mut syntax_snapshot = self.syntax_map.lock().snapshot();
1281 cx.background_spawn(async move {
1282 if !edits.is_empty() {
1283 if let Some(language) = language.clone() {
1284 syntax_snapshot.reparse(&old_snapshot, registry.clone(), language);
1285 }
1286
1287 branch_buffer.edit(edits.iter().cloned());
1288 let snapshot = branch_buffer.snapshot();
1289 syntax_snapshot.interpolate(&snapshot);
1290
1291 if let Some(language) = language {
1292 syntax_snapshot.reparse(&snapshot, registry, language);
1293 }
1294 }
1295 EditPreview {
1296 old_snapshot,
1297 applied_edits_snapshot: branch_buffer.into_snapshot(),
1298 syntax_snapshot,
1299 }
1300 })
1301 }
1302
1303 /// Applies all of the changes in this buffer that intersect any of the
1304 /// given `ranges` to its base buffer.
1305 ///
1306 /// If `ranges` is empty, then all changes will be applied. This buffer must
1307 /// be a branch buffer to call this method.
1308 pub fn merge_into_base(&mut self, ranges: Vec<Range<usize>>, cx: &mut Context<Self>) {
1309 let Some(base_buffer) = self.base_buffer() else {
1310 debug_panic!("not a branch buffer");
1311 return;
1312 };
1313
1314 let mut ranges = if ranges.is_empty() {
1315 &[0..usize::MAX]
1316 } else {
1317 ranges.as_slice()
1318 }
1319 .iter()
1320 .peekable();
1321
1322 let mut edits = Vec::new();
1323 for edit in self.edits_since::<usize>(&base_buffer.read(cx).version()) {
1324 let mut is_included = false;
1325 while let Some(range) = ranges.peek() {
1326 if range.end < edit.new.start {
1327 ranges.next().unwrap();
1328 } else {
1329 if range.start <= edit.new.end {
1330 is_included = true;
1331 }
1332 break;
1333 }
1334 }
1335
1336 if is_included {
1337 edits.push((
1338 edit.old.clone(),
1339 self.text_for_range(edit.new.clone()).collect::<String>(),
1340 ));
1341 }
1342 }
1343
1344 let operation = base_buffer.update(cx, |base_buffer, cx| {
1345 // cx.emit(BufferEvent::DiffBaseChanged);
1346 base_buffer.edit(edits, None, cx)
1347 });
1348
1349 if let Some(operation) = operation
1350 && let Some(BufferBranchState {
1351 merged_operations, ..
1352 }) = &mut self.branch_state
1353 {
1354 merged_operations.push(operation);
1355 }
1356 }
1357
1358 fn on_base_buffer_event(
1359 &mut self,
1360 _: Entity<Buffer>,
1361 event: &BufferEvent,
1362 cx: &mut Context<Self>,
1363 ) {
1364 let BufferEvent::Operation { operation, .. } = event else {
1365 return;
1366 };
1367 let Some(BufferBranchState {
1368 merged_operations, ..
1369 }) = &mut self.branch_state
1370 else {
1371 return;
1372 };
1373
1374 let mut operation_to_undo = None;
1375 if let Operation::Buffer(text::Operation::Edit(operation)) = &operation
1376 && let Ok(ix) = merged_operations.binary_search(&operation.timestamp)
1377 {
1378 merged_operations.remove(ix);
1379 operation_to_undo = Some(operation.timestamp);
1380 }
1381
1382 self.apply_ops([operation.clone()], cx);
1383
1384 if let Some(timestamp) = operation_to_undo {
1385 let counts = [(timestamp, u32::MAX)].into_iter().collect();
1386 self.undo_operations(counts, cx);
1387 }
1388 }
1389
1390 pub fn as_text_snapshot(&self) -> &text::BufferSnapshot {
1391 &self.text
1392 }
1393
1394 /// Retrieve a snapshot of the buffer's raw text, without any
1395 /// language-related state like the syntax tree or diagnostics.
1396 #[ztracing::instrument(skip_all)]
1397 pub fn text_snapshot(&self) -> text::BufferSnapshot {
1398 // todo lw
1399 self.text.snapshot().clone()
1400 }
1401
1402 /// The file associated with the buffer, if any.
1403 pub fn file(&self) -> Option<&Arc<dyn File>> {
1404 self.file.as_ref()
1405 }
1406
1407 /// The version of the buffer that was last saved or reloaded from disk.
1408 pub fn saved_version(&self) -> &clock::Global {
1409 &self.saved_version
1410 }
1411
1412 /// The mtime of the buffer's file when the buffer was last saved or reloaded from disk.
1413 pub fn saved_mtime(&self) -> Option<MTime> {
1414 self.saved_mtime
1415 }
1416
1417 /// Returns the character encoding of the buffer's file.
1418 pub fn encoding(&self) -> &'static Encoding {
1419 self.encoding
1420 }
1421
1422 /// Sets the character encoding of the buffer.
1423 pub fn set_encoding(&mut self, encoding: &'static Encoding) {
1424 self.encoding = encoding;
1425 }
1426
1427 /// Returns whether the buffer has a Byte Order Mark.
1428 pub fn has_bom(&self) -> bool {
1429 self.has_bom
1430 }
1431
1432 /// Sets whether the buffer has a Byte Order Mark.
1433 pub fn set_has_bom(&mut self, has_bom: bool) {
1434 self.has_bom = has_bom;
1435 }
1436
1437 /// Assign a language to the buffer.
1438 pub fn set_language_async(&mut self, language: Option<Arc<Language>>, cx: &mut Context<Self>) {
1439 self.set_language_(language, cfg!(any(test, feature = "test-support")), cx);
1440 }
1441
1442 /// Assign a language to the buffer, blocking for up to 1ms to reparse the buffer.
1443 pub fn set_language(&mut self, language: Option<Arc<Language>>, cx: &mut Context<Self>) {
1444 self.set_language_(language, true, cx);
1445 }
1446
1447 #[ztracing::instrument(skip_all)]
1448 fn set_language_(
1449 &mut self,
1450 language: Option<Arc<Language>>,
1451 may_block: bool,
1452 cx: &mut Context<Self>,
1453 ) {
1454 if language == self.language {
1455 return;
1456 }
1457 self.non_text_state_update_count += 1;
1458 self.syntax_map.lock().clear(&self.text);
1459 let old_language = std::mem::replace(&mut self.language, language);
1460 self.was_changed();
1461 self.reparse(cx, may_block);
1462 let has_fresh_language =
1463 self.language.is_some() && old_language.is_none_or(|old| old == *PLAIN_TEXT);
1464 cx.emit(BufferEvent::LanguageChanged(has_fresh_language));
1465 }
1466
1467 /// Assign a language registry to the buffer. This allows the buffer to retrieve
1468 /// other languages if parts of the buffer are written in different languages.
1469 pub fn set_language_registry(&self, language_registry: Arc<LanguageRegistry>) {
1470 self.syntax_map
1471 .lock()
1472 .set_language_registry(language_registry);
1473 }
1474
1475 pub fn language_registry(&self) -> Option<Arc<LanguageRegistry>> {
1476 self.syntax_map.lock().language_registry()
1477 }
1478
1479 /// Assign the line ending type to the buffer.
1480 pub fn set_line_ending(&mut self, line_ending: LineEnding, cx: &mut Context<Self>) {
1481 self.text.set_line_ending(line_ending);
1482
1483 let lamport_timestamp = self.text.lamport_clock.tick();
1484 self.send_operation(
1485 Operation::UpdateLineEnding {
1486 line_ending,
1487 lamport_timestamp,
1488 },
1489 true,
1490 cx,
1491 );
1492 }
1493
1494 /// Assign the buffer [`ModelineSettings`].
1495 pub fn set_modeline(&mut self, modeline: Option<ModelineSettings>) -> bool {
1496 if modeline.as_ref() != self.modeline.as_deref() {
1497 self.modeline = modeline.map(Arc::new);
1498 true
1499 } else {
1500 false
1501 }
1502 }
1503
1504 /// Returns the [`ModelineSettings`].
1505 pub fn modeline(&self) -> Option<&Arc<ModelineSettings>> {
1506 self.modeline.as_ref()
1507 }
1508
1509 /// Assign the buffer a new [`Capability`].
1510 pub fn set_capability(&mut self, capability: Capability, cx: &mut Context<Self>) {
1511 if self.capability != capability {
1512 self.capability = capability;
1513 cx.emit(BufferEvent::CapabilityChanged)
1514 }
1515 }
1516
1517 /// This method is called to signal that the buffer has been saved.
1518 pub fn did_save(
1519 &mut self,
1520 version: clock::Global,
1521 mtime: Option<MTime>,
1522 cx: &mut Context<Self>,
1523 ) {
1524 self.saved_version = version.clone();
1525 self.has_unsaved_edits.set((version, false));
1526 self.has_conflict = false;
1527 self.saved_mtime = mtime;
1528 self.was_changed();
1529 cx.emit(BufferEvent::Saved);
1530 cx.notify();
1531 }
1532
1533 /// Reloads the contents of the buffer from disk.
1534 pub fn reload(&mut self, cx: &Context<Self>) -> oneshot::Receiver<Option<Transaction>> {
1535 self.reload_impl(None, cx)
1536 }
1537
1538 /// Reloads the contents of the buffer from disk using the specified encoding.
1539 ///
1540 /// This bypasses automatic encoding detection heuristics (like BOM checks) for non-Unicode encodings,
1541 /// allowing users to force a specific interpretation of the bytes.
1542 pub fn reload_with_encoding(
1543 &mut self,
1544 encoding: &'static Encoding,
1545 cx: &Context<Self>,
1546 ) -> oneshot::Receiver<Option<Transaction>> {
1547 self.reload_impl(Some(encoding), cx)
1548 }
1549
1550 fn reload_impl(
1551 &mut self,
1552 force_encoding: Option<&'static Encoding>,
1553 cx: &Context<Self>,
1554 ) -> oneshot::Receiver<Option<Transaction>> {
1555 let (tx, rx) = futures::channel::oneshot::channel();
1556 let prev_version = self.text.version();
1557
1558 self.reload_task = Some(cx.spawn(async move |this, cx| {
1559 let Some((new_mtime, load_bytes_task, current_encoding)) =
1560 this.update(cx, |this, cx| {
1561 let file = this.file.as_ref()?.as_local()?;
1562 Some((
1563 file.disk_state().mtime(),
1564 file.load_bytes(cx),
1565 this.encoding,
1566 ))
1567 })?
1568 else {
1569 return Ok(());
1570 };
1571
1572 let target_encoding = force_encoding.unwrap_or(current_encoding);
1573
1574 let is_unicode = target_encoding == encoding_rs::UTF_8
1575 || target_encoding == encoding_rs::UTF_16LE
1576 || target_encoding == encoding_rs::UTF_16BE;
1577
1578 let (new_text, has_bom, encoding_used) = if force_encoding.is_some() && !is_unicode {
1579 let bytes = load_bytes_task.await?;
1580 let (cow, _had_errors) = target_encoding.decode_without_bom_handling(&bytes);
1581 (cow.into_owned(), false, target_encoding)
1582 } else {
1583 let bytes = load_bytes_task.await?;
1584 let (cow, used_enc, _had_errors) = target_encoding.decode(&bytes);
1585
1586 let actual_has_bom = if used_enc == encoding_rs::UTF_8 {
1587 bytes.starts_with(&[0xEF, 0xBB, 0xBF])
1588 } else if used_enc == encoding_rs::UTF_16LE {
1589 bytes.starts_with(&[0xFF, 0xFE])
1590 } else if used_enc == encoding_rs::UTF_16BE {
1591 bytes.starts_with(&[0xFE, 0xFF])
1592 } else {
1593 false
1594 };
1595 (cow.into_owned(), actual_has_bom, used_enc)
1596 };
1597
1598 let diff = this.update(cx, |this, cx| this.diff(new_text, cx))?.await;
1599 this.update(cx, |this, cx| {
1600 if this.version() == diff.base_version {
1601 this.finalize_last_transaction();
1602 let old_encoding = this.encoding;
1603 let old_has_bom = this.has_bom;
1604 this.apply_diff(diff, cx);
1605 this.encoding = encoding_used;
1606 this.has_bom = has_bom;
1607 let transaction = this.finalize_last_transaction().cloned();
1608 if let Some(ref txn) = transaction {
1609 if old_encoding != encoding_used || old_has_bom != has_bom {
1610 this.reload_with_encoding_txns
1611 .insert(txn.id, (old_encoding, old_has_bom));
1612 }
1613 }
1614 tx.send(transaction).ok();
1615 this.has_conflict = false;
1616 this.did_reload(this.version(), this.line_ending(), new_mtime, cx);
1617 } else {
1618 if !diff.edits.is_empty()
1619 || this
1620 .edits_since::<usize>(&diff.base_version)
1621 .next()
1622 .is_some()
1623 {
1624 this.has_conflict = true;
1625 }
1626
1627 this.did_reload(prev_version, this.line_ending(), this.saved_mtime, cx);
1628 }
1629
1630 this.reload_task.take();
1631 })
1632 }));
1633 rx
1634 }
1635
1636 /// This method is called to signal that the buffer has been reloaded.
1637 pub fn did_reload(
1638 &mut self,
1639 version: clock::Global,
1640 line_ending: LineEnding,
1641 mtime: Option<MTime>,
1642 cx: &mut Context<Self>,
1643 ) {
1644 self.saved_version = version;
1645 self.has_unsaved_edits
1646 .set((self.saved_version.clone(), false));
1647 self.text.set_line_ending(line_ending);
1648 self.saved_mtime = mtime;
1649 cx.emit(BufferEvent::Reloaded);
1650 cx.notify();
1651 }
1652
1653 /// Updates the [`File`] backing this buffer. This should be called when
1654 /// the file has changed or has been deleted.
1655 pub fn file_updated(&mut self, new_file: Arc<dyn File>, cx: &mut Context<Self>) {
1656 let was_dirty = self.is_dirty();
1657 let mut file_changed = false;
1658
1659 if let Some(old_file) = self.file.as_ref() {
1660 if new_file.path() != old_file.path() {
1661 file_changed = true;
1662 }
1663
1664 let old_state = old_file.disk_state();
1665 let new_state = new_file.disk_state();
1666 if old_state != new_state {
1667 file_changed = true;
1668 if !was_dirty && matches!(new_state, DiskState::Present { .. }) {
1669 cx.emit(BufferEvent::ReloadNeeded)
1670 }
1671 }
1672 } else {
1673 file_changed = true;
1674 };
1675
1676 self.file = Some(new_file);
1677 if file_changed {
1678 self.was_changed();
1679 self.non_text_state_update_count += 1;
1680 if was_dirty != self.is_dirty() {
1681 cx.emit(BufferEvent::DirtyChanged);
1682 }
1683 cx.emit(BufferEvent::FileHandleChanged);
1684 cx.notify();
1685 }
1686 }
1687
1688 pub fn base_buffer(&self) -> Option<Entity<Self>> {
1689 Some(self.branch_state.as_ref()?.base_buffer.clone())
1690 }
1691
1692 /// Returns the primary [`Language`] assigned to this [`Buffer`].
1693 pub fn language(&self) -> Option<&Arc<Language>> {
1694 self.language.as_ref()
1695 }
1696
1697 /// Returns the [`Language`] at the given location.
1698 pub fn language_at<D: ToOffset>(&self, position: D) -> Option<Arc<Language>> {
1699 let offset = position.to_offset(self);
1700 let text: &TextBufferSnapshot = &self.text;
1701 self.syntax_map
1702 .lock()
1703 .layers_for_range(offset..offset, text, false)
1704 .filter(|layer| {
1705 layer
1706 .included_sub_ranges
1707 .is_none_or(|ranges| offset_in_sub_ranges(ranges, offset, text))
1708 })
1709 .last()
1710 .map(|info| info.language.clone())
1711 .or_else(|| self.language.clone())
1712 }
1713
1714 /// Returns each [`Language`] for the active syntax layers at the given location.
1715 pub fn languages_at<D: ToOffset>(&self, position: D) -> Vec<Arc<Language>> {
1716 let offset = position.to_offset(self);
1717 let text: &TextBufferSnapshot = &self.text;
1718 let mut languages: Vec<Arc<Language>> = self
1719 .syntax_map
1720 .lock()
1721 .layers_for_range(offset..offset, text, false)
1722 .filter(|layer| {
1723 // For combined injections, check if offset is within the actual sub-ranges.
1724 layer
1725 .included_sub_ranges
1726 .is_none_or(|ranges| offset_in_sub_ranges(ranges, offset, text))
1727 })
1728 .map(|info| info.language.clone())
1729 .collect();
1730
1731 if languages.is_empty()
1732 && let Some(buffer_language) = self.language()
1733 {
1734 languages.push(buffer_language.clone());
1735 }
1736
1737 languages
1738 }
1739
1740 /// An integer version number that accounts for all updates besides
1741 /// the buffer's text itself (which is versioned via a version vector).
1742 pub fn non_text_state_update_count(&self) -> usize {
1743 self.non_text_state_update_count
1744 }
1745
1746 /// Whether the buffer is being parsed in the background.
1747 #[cfg(any(test, feature = "test-support"))]
1748 pub fn is_parsing(&self) -> bool {
1749 self.reparse.is_some()
1750 }
1751
1752 /// Indicates whether the buffer contains any regions that may be
1753 /// written in a language that hasn't been loaded yet.
1754 pub fn contains_unknown_injections(&self) -> bool {
1755 self.syntax_map.lock().contains_unknown_injections()
1756 }
1757
1758 /// Sets the sync parse timeout for this buffer.
1759 ///
1760 /// Setting this to `None` disables sync parsing entirely.
1761 pub fn set_sync_parse_timeout(&mut self, timeout: Option<Duration>) {
1762 self.sync_parse_timeout = timeout;
1763 }
1764
1765 fn invalidate_tree_sitter_data(
1766 tree_sitter_data: &mut Arc<TreeSitterData>,
1767 snapshot: &text::BufferSnapshot,
1768 ) {
1769 match Arc::get_mut(tree_sitter_data) {
1770 Some(tree_sitter_data) => tree_sitter_data.clear(snapshot),
1771 None => {
1772 let new_tree_sitter_data = TreeSitterData::new(snapshot);
1773 *tree_sitter_data = Arc::new(new_tree_sitter_data)
1774 }
1775 }
1776 }
1777
1778 /// Called after an edit to synchronize the buffer's main parse tree with
1779 /// the buffer's new underlying state.
1780 ///
1781 /// Locks the syntax map and interpolates the edits since the last reparse
1782 /// into the foreground syntax tree.
1783 ///
1784 /// Then takes a stable snapshot of the syntax map before unlocking it.
1785 /// The snapshot with the interpolated edits is sent to a background thread,
1786 /// where we ask Tree-sitter to perform an incremental parse.
1787 ///
1788 /// Meanwhile, in the foreground if `may_block` is true, we block the main
1789 /// thread for up to 1ms waiting on the parse to complete. As soon as it
1790 /// completes, we proceed synchronously, unless a 1ms timeout elapses.
1791 ///
1792 /// If we time out waiting on the parse, we spawn a second task waiting
1793 /// until the parse does complete and return with the interpolated tree still
1794 /// in the foreground. When the background parse completes, call back into
1795 /// the main thread and assign the foreground parse state.
1796 ///
1797 /// If the buffer or grammar changed since the start of the background parse,
1798 /// initiate an additional reparse recursively. To avoid concurrent parses
1799 /// for the same buffer, we only initiate a new parse if we are not already
1800 /// parsing in the background.
1801 #[ztracing::instrument(skip_all)]
1802 pub fn reparse(&mut self, cx: &mut Context<Self>, may_block: bool) {
1803 if self.text.version() != *self.tree_sitter_data.version() {
1804 Self::invalidate_tree_sitter_data(&mut self.tree_sitter_data, self.text.snapshot());
1805 }
1806 if self.reparse.is_some() {
1807 return;
1808 }
1809 let language = if let Some(language) = self.language.clone() {
1810 language
1811 } else {
1812 return;
1813 };
1814
1815 let text = self.text_snapshot();
1816 let parsed_version = self.version();
1817
1818 let mut syntax_map = self.syntax_map.lock();
1819 syntax_map.interpolate(&text);
1820 let language_registry = syntax_map.language_registry();
1821 let mut syntax_snapshot = syntax_map.snapshot();
1822 drop(syntax_map);
1823
1824 self.parse_status.0.send(ParseStatus::Parsing).unwrap();
1825 if may_block && let Some(sync_parse_timeout) = self.sync_parse_timeout {
1826 if let Ok(()) = syntax_snapshot.reparse_with_timeout(
1827 &text,
1828 language_registry.clone(),
1829 language.clone(),
1830 sync_parse_timeout,
1831 ) {
1832 self.did_finish_parsing(syntax_snapshot, Some(Duration::from_millis(300)), cx);
1833 self.reparse = None;
1834 return;
1835 }
1836 }
1837
1838 let parse_task = cx.background_spawn({
1839 let language = language.clone();
1840 let language_registry = language_registry.clone();
1841 async move {
1842 syntax_snapshot.reparse(&text, language_registry, language);
1843 syntax_snapshot
1844 }
1845 });
1846
1847 self.reparse = Some(cx.spawn(async move |this, cx| {
1848 let new_syntax_map = parse_task.await;
1849 this.update(cx, move |this, cx| {
1850 let grammar_changed = || {
1851 this.language
1852 .as_ref()
1853 .is_none_or(|current_language| !Arc::ptr_eq(&language, current_language))
1854 };
1855 let language_registry_changed = || {
1856 new_syntax_map.contains_unknown_injections()
1857 && language_registry.is_some_and(|registry| {
1858 registry.version() != new_syntax_map.language_registry_version()
1859 })
1860 };
1861 let parse_again = this.version.changed_since(&parsed_version)
1862 || language_registry_changed()
1863 || grammar_changed();
1864 this.did_finish_parsing(new_syntax_map, None, cx);
1865 this.reparse = None;
1866 if parse_again {
1867 this.reparse(cx, false);
1868 }
1869 })
1870 .ok();
1871 }));
1872 }
1873
1874 fn did_finish_parsing(
1875 &mut self,
1876 syntax_snapshot: SyntaxSnapshot,
1877 block_budget: Option<Duration>,
1878 cx: &mut Context<Self>,
1879 ) {
1880 self.non_text_state_update_count += 1;
1881 self.syntax_map.lock().did_parse(syntax_snapshot);
1882 self.was_changed();
1883 self.request_autoindent(cx, block_budget);
1884 self.parse_status.0.send(ParseStatus::Idle).unwrap();
1885 Self::invalidate_tree_sitter_data(&mut self.tree_sitter_data, &self.text.snapshot());
1886 cx.emit(BufferEvent::Reparsed);
1887 cx.notify();
1888 }
1889
1890 pub fn parse_status(&self) -> watch::Receiver<ParseStatus> {
1891 self.parse_status.1.clone()
1892 }
1893
1894 /// Wait until the buffer is no longer parsing
1895 pub fn parsing_idle(&self) -> impl Future<Output = ()> + use<> {
1896 let mut parse_status = self.parse_status();
1897 async move {
1898 while *parse_status.borrow() != ParseStatus::Idle {
1899 if parse_status.changed().await.is_err() {
1900 break;
1901 }
1902 }
1903 }
1904 }
1905
1906 /// Assign to the buffer a set of diagnostics created by a given language server.
1907 pub fn update_diagnostics(
1908 &mut self,
1909 server_id: LanguageServerId,
1910 diagnostics: DiagnosticSet,
1911 cx: &mut Context<Self>,
1912 ) {
1913 let lamport_timestamp = self.text.lamport_clock.tick();
1914 let op = Operation::UpdateDiagnostics {
1915 server_id,
1916 diagnostics: diagnostics.iter().cloned().collect(),
1917 lamport_timestamp,
1918 };
1919
1920 self.apply_diagnostic_update(server_id, diagnostics, lamport_timestamp, cx);
1921 self.send_operation(op, true, cx);
1922 }
1923
1924 pub fn buffer_diagnostics(
1925 &self,
1926 for_server: Option<LanguageServerId>,
1927 ) -> Vec<&DiagnosticEntry<Anchor>> {
1928 match for_server {
1929 Some(server_id) => self
1930 .diagnostics
1931 .get(&server_id)
1932 .map_or_else(Vec::new, |diagnostics| diagnostics.iter().collect()),
1933 None => self
1934 .diagnostics
1935 .iter()
1936 .flat_map(|(_, diagnostic_set)| diagnostic_set.iter())
1937 .collect(),
1938 }
1939 }
1940
1941 fn request_autoindent(&mut self, cx: &mut Context<Self>, block_budget: Option<Duration>) {
1942 if let Some(indent_sizes) = self.compute_autoindents() {
1943 let indent_sizes = cx.background_spawn(indent_sizes);
1944 let Some(block_budget) = block_budget else {
1945 self.pending_autoindent = Some(cx.spawn(async move |this, cx| {
1946 let indent_sizes = indent_sizes.await;
1947 this.update(cx, |this, cx| {
1948 this.apply_autoindents(indent_sizes, cx);
1949 })
1950 .ok();
1951 }));
1952 return;
1953 };
1954 match cx
1955 .foreground_executor()
1956 .block_with_timeout(block_budget, indent_sizes)
1957 {
1958 Ok(indent_sizes) => self.apply_autoindents(indent_sizes, cx),
1959 Err(indent_sizes) => {
1960 self.pending_autoindent = Some(cx.spawn(async move |this, cx| {
1961 let indent_sizes = indent_sizes.await;
1962 this.update(cx, |this, cx| {
1963 this.apply_autoindents(indent_sizes, cx);
1964 })
1965 .ok();
1966 }));
1967 }
1968 }
1969 } else {
1970 self.autoindent_requests.clear();
1971 for tx in self.wait_for_autoindent_txs.drain(..) {
1972 tx.send(()).ok();
1973 }
1974 }
1975 }
1976
1977 fn compute_autoindents(
1978 &self,
1979 ) -> Option<impl Future<Output = BTreeMap<u32, IndentSize>> + use<>> {
1980 let max_rows_between_yields = 100;
1981 let snapshot = self.snapshot();
1982 if snapshot.syntax.is_empty() || self.autoindent_requests.is_empty() {
1983 return None;
1984 }
1985
1986 let autoindent_requests = self.autoindent_requests.clone();
1987 Some(async move {
1988 let mut indent_sizes = BTreeMap::<u32, (IndentSize, bool)>::new();
1989 for request in autoindent_requests {
1990 // Resolve each edited range to its row in the current buffer and in the
1991 // buffer before this batch of edits.
1992 let mut row_ranges = Vec::new();
1993 let mut old_to_new_rows = BTreeMap::new();
1994 let mut language_indent_sizes_by_new_row = Vec::new();
1995 for entry in &request.entries {
1996 let position = entry.range.start;
1997 let new_row = position.to_point(&snapshot).row;
1998 let new_end_row = entry.range.end.to_point(&snapshot).row + 1;
1999 language_indent_sizes_by_new_row.push((new_row, entry.indent_size));
2000
2001 if let Some(old_row) = entry.old_row {
2002 old_to_new_rows.insert(old_row, new_row);
2003 }
2004 row_ranges.push((new_row..new_end_row, entry.original_indent_column));
2005 }
2006
2007 // Build a map containing the suggested indentation for each of the edited lines
2008 // with respect to the state of the buffer before these edits. This map is keyed
2009 // by the rows for these lines in the current state of the buffer.
2010 let mut old_suggestions = BTreeMap::<u32, (IndentSize, bool)>::default();
2011 let old_edited_ranges =
2012 contiguous_ranges(old_to_new_rows.keys().copied(), max_rows_between_yields);
2013 let mut language_indent_sizes = language_indent_sizes_by_new_row.iter().peekable();
2014 let mut language_indent_size = IndentSize::default();
2015 for old_edited_range in old_edited_ranges {
2016 let suggestions = request
2017 .before_edit
2018 .suggest_autoindents(old_edited_range.clone())
2019 .into_iter()
2020 .flatten();
2021 for (old_row, suggestion) in old_edited_range.zip(suggestions) {
2022 if let Some(suggestion) = suggestion {
2023 let new_row = *old_to_new_rows.get(&old_row).unwrap();
2024
2025 // Find the indent size based on the language for this row.
2026 while let Some((row, size)) = language_indent_sizes.peek() {
2027 if *row > new_row {
2028 break;
2029 }
2030 language_indent_size = *size;
2031 language_indent_sizes.next();
2032 }
2033
2034 let suggested_indent = old_to_new_rows
2035 .get(&suggestion.basis_row)
2036 .and_then(|from_row| {
2037 Some(old_suggestions.get(from_row).copied()?.0)
2038 })
2039 .unwrap_or_else(|| {
2040 request
2041 .before_edit
2042 .indent_size_for_line(suggestion.basis_row)
2043 })
2044 .with_delta(suggestion.delta, language_indent_size);
2045 old_suggestions
2046 .insert(new_row, (suggested_indent, suggestion.within_error));
2047 }
2048 }
2049 yield_now().await;
2050 }
2051
2052 // Compute new suggestions for each line, but only include them in the result
2053 // if they differ from the old suggestion for that line.
2054 let mut language_indent_sizes = language_indent_sizes_by_new_row.iter().peekable();
2055 let mut language_indent_size = IndentSize::default();
2056 for (row_range, original_indent_column) in row_ranges {
2057 let new_edited_row_range = if request.is_block_mode {
2058 row_range.start..row_range.start + 1
2059 } else {
2060 row_range.clone()
2061 };
2062
2063 let suggestions = snapshot
2064 .suggest_autoindents(new_edited_row_range.clone())
2065 .into_iter()
2066 .flatten();
2067 for (new_row, suggestion) in new_edited_row_range.zip(suggestions) {
2068 if let Some(suggestion) = suggestion {
2069 // Find the indent size based on the language for this row.
2070 while let Some((row, size)) = language_indent_sizes.peek() {
2071 if *row > new_row {
2072 break;
2073 }
2074 language_indent_size = *size;
2075 language_indent_sizes.next();
2076 }
2077
2078 let suggested_indent = indent_sizes
2079 .get(&suggestion.basis_row)
2080 .copied()
2081 .map(|e| e.0)
2082 .unwrap_or_else(|| {
2083 snapshot.indent_size_for_line(suggestion.basis_row)
2084 })
2085 .with_delta(suggestion.delta, language_indent_size);
2086
2087 if old_suggestions.get(&new_row).is_none_or(
2088 |(old_indentation, was_within_error)| {
2089 suggested_indent != *old_indentation
2090 && (!suggestion.within_error || *was_within_error)
2091 },
2092 ) {
2093 indent_sizes.insert(
2094 new_row,
2095 (suggested_indent, request.ignore_empty_lines),
2096 );
2097 }
2098 }
2099 }
2100
2101 if let (true, Some(original_indent_column)) =
2102 (request.is_block_mode, original_indent_column)
2103 {
2104 let new_indent =
2105 if let Some((indent, _)) = indent_sizes.get(&row_range.start) {
2106 *indent
2107 } else {
2108 snapshot.indent_size_for_line(row_range.start)
2109 };
2110 let delta = new_indent.len as i64 - original_indent_column as i64;
2111 if delta != 0 {
2112 for row in row_range.skip(1) {
2113 indent_sizes.entry(row).or_insert_with(|| {
2114 let mut size = snapshot.indent_size_for_line(row);
2115 if size.kind == new_indent.kind {
2116 match delta.cmp(&0) {
2117 Ordering::Greater => size.len += delta as u32,
2118 Ordering::Less => {
2119 size.len = size.len.saturating_sub(-delta as u32)
2120 }
2121 Ordering::Equal => {}
2122 }
2123 }
2124 (size, request.ignore_empty_lines)
2125 });
2126 }
2127 }
2128 }
2129
2130 yield_now().await;
2131 }
2132 }
2133
2134 indent_sizes
2135 .into_iter()
2136 .filter_map(|(row, (indent, ignore_empty_lines))| {
2137 if ignore_empty_lines && snapshot.line_len(row) == 0 {
2138 None
2139 } else {
2140 Some((row, indent))
2141 }
2142 })
2143 .collect()
2144 })
2145 }
2146
2147 fn apply_autoindents(
2148 &mut self,
2149 indent_sizes: BTreeMap<u32, IndentSize>,
2150 cx: &mut Context<Self>,
2151 ) {
2152 self.autoindent_requests.clear();
2153 for tx in self.wait_for_autoindent_txs.drain(..) {
2154 tx.send(()).ok();
2155 }
2156
2157 let edits: Vec<_> = indent_sizes
2158 .into_iter()
2159 .filter_map(|(row, indent_size)| {
2160 let current_size = indent_size_for_line(self, row);
2161 Self::edit_for_indent_size_adjustment(row, current_size, indent_size)
2162 })
2163 .collect();
2164
2165 let preserve_preview = self.preserve_preview();
2166 self.edit(edits, None, cx);
2167 if preserve_preview {
2168 self.refresh_preview();
2169 }
2170 }
2171
2172 /// Create a minimal edit that will cause the given row to be indented
2173 /// with the given size. After applying this edit, the length of the line
2174 /// will always be at least `new_size.len`.
2175 pub fn edit_for_indent_size_adjustment(
2176 row: u32,
2177 current_size: IndentSize,
2178 new_size: IndentSize,
2179 ) -> Option<(Range<Point>, String)> {
2180 if new_size.kind == current_size.kind {
2181 match new_size.len.cmp(¤t_size.len) {
2182 Ordering::Greater => {
2183 let point = Point::new(row, 0);
2184 Some((
2185 point..point,
2186 iter::repeat(new_size.char())
2187 .take((new_size.len - current_size.len) as usize)
2188 .collect::<String>(),
2189 ))
2190 }
2191
2192 Ordering::Less => Some((
2193 Point::new(row, 0)..Point::new(row, current_size.len - new_size.len),
2194 String::new(),
2195 )),
2196
2197 Ordering::Equal => None,
2198 }
2199 } else {
2200 Some((
2201 Point::new(row, 0)..Point::new(row, current_size.len),
2202 iter::repeat(new_size.char())
2203 .take(new_size.len as usize)
2204 .collect::<String>(),
2205 ))
2206 }
2207 }
2208
2209 /// Spawns a background task that asynchronously computes a `Diff` between the buffer's text
2210 /// and the given new text.
2211 pub fn diff<T>(&self, new_text: T, cx: &App) -> Task<Diff>
2212 where
2213 T: AsRef<str> + Send + 'static,
2214 {
2215 let old_text = self.as_rope().clone();
2216 let base_version = self.version();
2217 cx.background_spawn(async move {
2218 let old_text = old_text.to_string();
2219 let mut new_text = new_text.as_ref().to_owned();
2220 let line_ending = LineEnding::detect(&new_text);
2221 LineEnding::normalize(&mut new_text);
2222 let edits = text_diff(&old_text, &new_text);
2223 Diff {
2224 base_version,
2225 line_ending,
2226 edits,
2227 }
2228 })
2229 }
2230
2231 /// Spawns a background task that searches the buffer for any whitespace
2232 /// at the ends of a lines, and returns a `Diff` that removes that whitespace.
2233 pub fn remove_trailing_whitespace(&self, cx: &App) -> Task<Diff> {
2234 let old_text = self.as_rope().clone();
2235 let line_ending = self.line_ending();
2236 let base_version = self.version();
2237 cx.background_spawn(async move {
2238 let ranges = trailing_whitespace_ranges(&old_text);
2239 let empty = Arc::<str>::from("");
2240 Diff {
2241 base_version,
2242 line_ending,
2243 edits: ranges
2244 .into_iter()
2245 .map(|range| (range, empty.clone()))
2246 .collect(),
2247 }
2248 })
2249 }
2250
2251 /// Ensures that the buffer ends with a single newline character, and
2252 /// no other whitespace. Skips if the buffer is empty.
2253 pub fn ensure_final_newline(&mut self, cx: &mut Context<Self>) {
2254 let len = self.len();
2255 if len == 0 {
2256 return;
2257 }
2258 let mut offset = len;
2259 for chunk in self.as_rope().reversed_chunks_in_range(0..len) {
2260 let non_whitespace_len = chunk
2261 .trim_end_matches(|c: char| c.is_ascii_whitespace())
2262 .len();
2263 offset -= chunk.len();
2264 offset += non_whitespace_len;
2265 if non_whitespace_len != 0 {
2266 if offset == len - 1 && chunk.get(non_whitespace_len..) == Some("\n") {
2267 return;
2268 }
2269 break;
2270 }
2271 }
2272 self.edit([(offset..len, "\n")], None, cx);
2273 }
2274
2275 /// Applies a diff to the buffer. If the buffer has changed since the given diff was
2276 /// calculated, then adjust the diff to account for those changes, and discard any
2277 /// parts of the diff that conflict with those changes.
2278 pub fn apply_diff(&mut self, diff: Diff, cx: &mut Context<Self>) -> Option<TransactionId> {
2279 let snapshot = self.snapshot();
2280 let mut edits_since = snapshot.edits_since::<usize>(&diff.base_version).peekable();
2281 let mut delta = 0;
2282 let adjusted_edits = diff.edits.into_iter().filter_map(|(range, new_text)| {
2283 while let Some(edit_since) = edits_since.peek() {
2284 // If the edit occurs after a diff hunk, then it does not
2285 // affect that hunk.
2286 if edit_since.old.start > range.end {
2287 break;
2288 }
2289 // If the edit precedes the diff hunk, then adjust the hunk
2290 // to reflect the edit.
2291 else if edit_since.old.end < range.start {
2292 delta += edit_since.new_len() as i64 - edit_since.old_len() as i64;
2293 edits_since.next();
2294 }
2295 // If the edit intersects a diff hunk, then discard that hunk.
2296 else {
2297 return None;
2298 }
2299 }
2300
2301 let start = (range.start as i64 + delta) as usize;
2302 let end = (range.end as i64 + delta) as usize;
2303 Some((start..end, new_text))
2304 });
2305
2306 self.start_transaction();
2307 self.text.set_line_ending(diff.line_ending);
2308 self.edit(adjusted_edits, None, cx);
2309 self.end_transaction(cx)
2310 }
2311
2312 pub fn has_unsaved_edits(&self) -> bool {
2313 let (last_version, has_unsaved_edits) = self.has_unsaved_edits.take();
2314
2315 if last_version == self.version {
2316 self.has_unsaved_edits
2317 .set((last_version, has_unsaved_edits));
2318 return has_unsaved_edits;
2319 }
2320
2321 let has_edits = self.has_edits_since(&self.saved_version);
2322 self.has_unsaved_edits
2323 .set((self.version.clone(), has_edits));
2324 has_edits
2325 }
2326
2327 /// Checks if the buffer has unsaved changes.
2328 pub fn is_dirty(&self) -> bool {
2329 if self.capability == Capability::ReadOnly {
2330 return false;
2331 }
2332 if self.has_conflict {
2333 return true;
2334 }
2335 match self.file.as_ref().map(|f| f.disk_state()) {
2336 Some(DiskState::New) | Some(DiskState::Deleted) => {
2337 !self.is_empty() && self.has_unsaved_edits()
2338 }
2339 _ => self.has_unsaved_edits(),
2340 }
2341 }
2342
2343 /// Marks the buffer as having a conflict regardless of current buffer state.
2344 pub fn set_conflict(&mut self) {
2345 self.has_conflict = true;
2346 }
2347
2348 /// Checks if the buffer and its file have both changed since the buffer
2349 /// was last saved or reloaded.
2350 pub fn has_conflict(&self) -> bool {
2351 if self.has_conflict {
2352 return true;
2353 }
2354 let Some(file) = self.file.as_ref() else {
2355 return false;
2356 };
2357 match file.disk_state() {
2358 DiskState::New => false,
2359 DiskState::Present { mtime, .. } => match self.saved_mtime {
2360 Some(saved_mtime) => {
2361 mtime.bad_is_greater_than(saved_mtime) && self.has_unsaved_edits()
2362 }
2363 None => true,
2364 },
2365 DiskState::Deleted => false,
2366 DiskState::Historic { .. } => false,
2367 }
2368 }
2369
2370 /// Gets a [`Subscription`] that tracks all of the changes to the buffer's text.
2371 pub fn subscribe(&mut self) -> Subscription<usize> {
2372 self.text.subscribe()
2373 }
2374
2375 /// Adds a bit to the list of bits that are set when the buffer's text changes.
2376 ///
2377 /// This allows downstream code to check if the buffer's text has changed without
2378 /// waiting for an effect cycle, which would be required if using eents.
2379 pub fn record_changes(&mut self, bit: rc::Weak<Cell<bool>>) {
2380 if let Err(ix) = self
2381 .change_bits
2382 .binary_search_by_key(&rc::Weak::as_ptr(&bit), rc::Weak::as_ptr)
2383 {
2384 self.change_bits.insert(ix, bit);
2385 }
2386 }
2387
2388 /// Set the change bit for all "listeners".
2389 fn was_changed(&mut self) {
2390 self.change_bits.retain(|change_bit| {
2391 change_bit
2392 .upgrade()
2393 .inspect(|bit| {
2394 _ = bit.replace(true);
2395 })
2396 .is_some()
2397 });
2398 }
2399
2400 /// Starts a transaction, if one is not already in-progress. When undoing or
2401 /// redoing edits, all of the edits performed within a transaction are undone
2402 /// or redone together.
2403 pub fn start_transaction(&mut self) -> Option<TransactionId> {
2404 self.start_transaction_at(Instant::now())
2405 }
2406
2407 /// Starts a transaction, providing the current time. Subsequent transactions
2408 /// that occur within a short period of time will be grouped together. This
2409 /// is controlled by the buffer's undo grouping duration.
2410 pub fn start_transaction_at(&mut self, now: Instant) -> Option<TransactionId> {
2411 self.transaction_depth += 1;
2412 if self.was_dirty_before_starting_transaction.is_none() {
2413 self.was_dirty_before_starting_transaction = Some(self.is_dirty());
2414 }
2415 self.text.start_transaction_at(now)
2416 }
2417
2418 /// Terminates the current transaction, if this is the outermost transaction.
2419 pub fn end_transaction(&mut self, cx: &mut Context<Self>) -> Option<TransactionId> {
2420 self.end_transaction_at(Instant::now(), cx)
2421 }
2422
2423 /// Terminates the current transaction, providing the current time. Subsequent transactions
2424 /// that occur within a short period of time will be grouped together. This
2425 /// is controlled by the buffer's undo grouping duration.
2426 pub fn end_transaction_at(
2427 &mut self,
2428 now: Instant,
2429 cx: &mut Context<Self>,
2430 ) -> Option<TransactionId> {
2431 assert!(self.transaction_depth > 0);
2432 self.transaction_depth -= 1;
2433 let was_dirty = if self.transaction_depth == 0 {
2434 self.was_dirty_before_starting_transaction.take().unwrap()
2435 } else {
2436 false
2437 };
2438 if let Some((transaction_id, start_version)) = self.text.end_transaction_at(now) {
2439 self.did_edit(&start_version, was_dirty, true, cx);
2440 Some(transaction_id)
2441 } else {
2442 None
2443 }
2444 }
2445
2446 /// Manually add a transaction to the buffer's undo history.
2447 pub fn push_transaction(&mut self, transaction: Transaction, now: Instant) {
2448 self.text.push_transaction(transaction, now);
2449 }
2450
2451 /// Differs from `push_transaction` in that it does not clear the redo
2452 /// stack. Intended to be used to create a parent transaction to merge
2453 /// potential child transactions into.
2454 ///
2455 /// The caller is responsible for removing it from the undo history using
2456 /// `forget_transaction` if no edits are merged into it. Otherwise, if edits
2457 /// are merged into this transaction, the caller is responsible for ensuring
2458 /// the redo stack is cleared. The easiest way to ensure the redo stack is
2459 /// cleared is to create transactions with the usual `start_transaction` and
2460 /// `end_transaction` methods and merging the resulting transactions into
2461 /// the transaction created by this method
2462 pub fn push_empty_transaction(&mut self, now: Instant) -> TransactionId {
2463 self.text.push_empty_transaction(now)
2464 }
2465
2466 /// Prevent the last transaction from being grouped with any subsequent transactions,
2467 /// even if they occur with the buffer's undo grouping duration.
2468 pub fn finalize_last_transaction(&mut self) -> Option<&Transaction> {
2469 self.text.finalize_last_transaction()
2470 }
2471
2472 /// Manually group all changes since a given transaction.
2473 pub fn group_until_transaction(&mut self, transaction_id: TransactionId) {
2474 self.text.group_until_transaction(transaction_id);
2475 }
2476
2477 /// Manually remove a transaction from the buffer's undo history
2478 pub fn forget_transaction(&mut self, transaction_id: TransactionId) -> Option<Transaction> {
2479 self.text.forget_transaction(transaction_id)
2480 }
2481
2482 /// Retrieve a transaction from the buffer's undo history
2483 pub fn get_transaction(&self, transaction_id: TransactionId) -> Option<&Transaction> {
2484 self.text.get_transaction(transaction_id)
2485 }
2486
2487 /// Manually merge two transactions in the buffer's undo history.
2488 pub fn merge_transactions(&mut self, transaction: TransactionId, destination: TransactionId) {
2489 self.text.merge_transactions(transaction, destination);
2490 }
2491
2492 /// Waits for the buffer to receive operations with the given timestamps.
2493 pub fn wait_for_edits<It: IntoIterator<Item = clock::Lamport>>(
2494 &mut self,
2495 edit_ids: It,
2496 ) -> impl Future<Output = Result<()>> + use<It> {
2497 self.text.wait_for_edits(edit_ids)
2498 }
2499
2500 /// Waits for the buffer to receive the operations necessary for resolving the given anchors.
2501 pub fn wait_for_anchors<It: IntoIterator<Item = Anchor>>(
2502 &mut self,
2503 anchors: It,
2504 ) -> impl 'static + Future<Output = Result<()>> + use<It> {
2505 self.text.wait_for_anchors(anchors)
2506 }
2507
2508 /// Waits for the buffer to receive operations up to the given version.
2509 pub fn wait_for_version(
2510 &mut self,
2511 version: clock::Global,
2512 ) -> impl Future<Output = Result<()>> + use<> {
2513 self.text.wait_for_version(version)
2514 }
2515
2516 /// Forces all futures returned by [`Buffer::wait_for_version`], [`Buffer::wait_for_edits`], or
2517 /// [`Buffer::wait_for_version`] to resolve with an error.
2518 pub fn give_up_waiting(&mut self) {
2519 self.text.give_up_waiting();
2520 }
2521
2522 pub fn wait_for_autoindent_applied(&mut self) -> Option<oneshot::Receiver<()>> {
2523 let mut rx = None;
2524 if !self.autoindent_requests.is_empty() {
2525 let channel = oneshot::channel();
2526 self.wait_for_autoindent_txs.push(channel.0);
2527 rx = Some(channel.1);
2528 }
2529 rx
2530 }
2531
2532 /// Stores a set of selections that should be broadcasted to all of the buffer's replicas.
2533 pub fn set_active_selections(
2534 &mut self,
2535 selections: Arc<[Selection<Anchor>]>,
2536 line_mode: bool,
2537 cursor_shape: CursorShape,
2538 cx: &mut Context<Self>,
2539 ) {
2540 let lamport_timestamp = self.text.lamport_clock.tick();
2541 self.remote_selections.insert(
2542 self.text.replica_id(),
2543 SelectionSet {
2544 selections: selections.clone(),
2545 lamport_timestamp,
2546 line_mode,
2547 cursor_shape,
2548 },
2549 );
2550 self.send_operation(
2551 Operation::UpdateSelections {
2552 selections,
2553 line_mode,
2554 lamport_timestamp,
2555 cursor_shape,
2556 },
2557 true,
2558 cx,
2559 );
2560 self.non_text_state_update_count += 1;
2561 cx.notify();
2562 }
2563
2564 /// Clears the selections, so that other replicas of the buffer do not see any selections for
2565 /// this replica.
2566 pub fn remove_active_selections(&mut self, cx: &mut Context<Self>) {
2567 if self
2568 .remote_selections
2569 .get(&self.text.replica_id())
2570 .is_none_or(|set| !set.selections.is_empty())
2571 {
2572 self.set_active_selections(Arc::default(), false, Default::default(), cx);
2573 }
2574 }
2575
2576 pub fn set_agent_selections(
2577 &mut self,
2578 selections: Arc<[Selection<Anchor>]>,
2579 line_mode: bool,
2580 cursor_shape: CursorShape,
2581 cx: &mut Context<Self>,
2582 ) {
2583 let lamport_timestamp = self.text.lamport_clock.tick();
2584 self.remote_selections.insert(
2585 ReplicaId::AGENT,
2586 SelectionSet {
2587 selections,
2588 lamport_timestamp,
2589 line_mode,
2590 cursor_shape,
2591 },
2592 );
2593 self.non_text_state_update_count += 1;
2594 cx.notify();
2595 }
2596
2597 pub fn remove_agent_selections(&mut self, cx: &mut Context<Self>) {
2598 self.set_agent_selections(Arc::default(), false, Default::default(), cx);
2599 }
2600
2601 /// Replaces the buffer's entire text.
2602 pub fn set_text<T>(&mut self, text: T, cx: &mut Context<Self>) -> Option<clock::Lamport>
2603 where
2604 T: Into<Arc<str>>,
2605 {
2606 self.autoindent_requests.clear();
2607 self.edit([(0..self.len(), text)], None, cx)
2608 }
2609
2610 /// Appends the given text to the end of the buffer.
2611 pub fn append<T>(&mut self, text: T, cx: &mut Context<Self>) -> Option<clock::Lamport>
2612 where
2613 T: Into<Arc<str>>,
2614 {
2615 self.edit([(self.len()..self.len(), text)], None, cx)
2616 }
2617
2618 /// Applies the given edits to the buffer. Each edit is specified as a range of text to
2619 /// delete, and a string of text to insert at that location. Adjacent edits are coalesced.
2620 ///
2621 /// If an [`AutoindentMode`] is provided, then the buffer will enqueue an auto-indent
2622 /// request for the edited ranges, which will be processed when the buffer finishes
2623 /// parsing.
2624 ///
2625 /// Parsing takes place at the end of a transaction, and may compute synchronously
2626 /// or asynchronously, depending on the changes.
2627 pub fn edit<I, S, T>(
2628 &mut self,
2629 edits_iter: I,
2630 autoindent_mode: Option<AutoindentMode>,
2631 cx: &mut Context<Self>,
2632 ) -> Option<clock::Lamport>
2633 where
2634 I: IntoIterator<Item = (Range<S>, T)>,
2635 S: ToOffset,
2636 T: Into<Arc<str>>,
2637 {
2638 self.edit_internal(edits_iter, autoindent_mode, true, cx)
2639 }
2640
2641 /// Like [`edit`](Self::edit), but does not coalesce adjacent edits.
2642 pub fn edit_non_coalesce<I, S, T>(
2643 &mut self,
2644 edits_iter: I,
2645 autoindent_mode: Option<AutoindentMode>,
2646 cx: &mut Context<Self>,
2647 ) -> Option<clock::Lamport>
2648 where
2649 I: IntoIterator<Item = (Range<S>, T)>,
2650 S: ToOffset,
2651 T: Into<Arc<str>>,
2652 {
2653 self.edit_internal(edits_iter, autoindent_mode, false, cx)
2654 }
2655
2656 fn edit_internal<I, S, T>(
2657 &mut self,
2658 edits_iter: I,
2659 autoindent_mode: Option<AutoindentMode>,
2660 coalesce_adjacent: bool,
2661 cx: &mut Context<Self>,
2662 ) -> Option<clock::Lamport>
2663 where
2664 I: IntoIterator<Item = (Range<S>, T)>,
2665 S: ToOffset,
2666 T: Into<Arc<str>>,
2667 {
2668 // Skip invalid edits and coalesce contiguous ones.
2669 let mut edits: Vec<(Range<usize>, Arc<str>)> = Vec::new();
2670
2671 for (range, new_text) in edits_iter {
2672 let mut range = range.start.to_offset(self)..range.end.to_offset(self);
2673
2674 if range.start > range.end {
2675 mem::swap(&mut range.start, &mut range.end);
2676 }
2677 let new_text = new_text.into();
2678 if !new_text.is_empty() || !range.is_empty() {
2679 let prev_edit = edits.last_mut();
2680 let should_coalesce = prev_edit.as_ref().is_some_and(|(prev_range, _)| {
2681 if coalesce_adjacent {
2682 prev_range.end >= range.start
2683 } else {
2684 prev_range.end > range.start
2685 }
2686 });
2687
2688 if let Some((prev_range, prev_text)) = prev_edit
2689 && should_coalesce
2690 {
2691 prev_range.end = cmp::max(prev_range.end, range.end);
2692 *prev_text = format!("{prev_text}{new_text}").into();
2693 } else {
2694 edits.push((range, new_text));
2695 }
2696 }
2697 }
2698 if edits.is_empty() {
2699 return None;
2700 }
2701
2702 self.start_transaction();
2703 self.pending_autoindent.take();
2704 let autoindent_request = autoindent_mode
2705 .and_then(|mode| self.language.as_ref().map(|_| (self.snapshot(), mode)));
2706
2707 let edit_operation = self.text.edit(edits.iter().cloned());
2708 let edit_id = edit_operation.timestamp();
2709
2710 if let Some((before_edit, mode)) = autoindent_request {
2711 let mut delta = 0isize;
2712 let mut previous_setting = None;
2713 let entries: Vec<_> = edits
2714 .into_iter()
2715 .enumerate()
2716 .zip(&edit_operation.as_edit().unwrap().new_text)
2717 .filter(|((_, (range, _)), _)| {
2718 let language = before_edit.language_at(range.start);
2719 let language_id = language.map(|l| l.id());
2720 if let Some((cached_language_id, apply_syntax_indent)) = previous_setting
2721 && cached_language_id == language_id
2722 {
2723 apply_syntax_indent
2724 } else {
2725 // The auto-indent setting is not present in editorconfigs, hence
2726 // we can avoid passing the file here.
2727 let auto_indent_mode = LanguageSettings::resolve(
2728 None,
2729 language.map(|l| l.name()).as_ref(),
2730 cx,
2731 )
2732 .auto_indent;
2733 let apply_syntax_indent = auto_indent_mode == AutoIndentMode::SyntaxAware;
2734 previous_setting = Some((language_id, apply_syntax_indent));
2735 apply_syntax_indent
2736 }
2737 })
2738 .map(|((ix, (range, _)), new_text)| {
2739 let new_text_length = new_text.len();
2740 let old_start = range.start.to_point(&before_edit);
2741 let new_start = (delta + range.start as isize) as usize;
2742 let range_len = range.end - range.start;
2743 delta += new_text_length as isize - range_len as isize;
2744
2745 // Decide what range of the insertion to auto-indent, and whether
2746 // the first line of the insertion should be considered a newly-inserted line
2747 // or an edit to an existing line.
2748 let mut range_of_insertion_to_indent = 0..new_text_length;
2749 let mut first_line_is_new = true;
2750
2751 let old_line_start = before_edit.indent_size_for_line(old_start.row).len;
2752 let old_line_end = before_edit.line_len(old_start.row);
2753
2754 if old_start.column > old_line_start {
2755 first_line_is_new = false;
2756 }
2757
2758 if !new_text.contains('\n')
2759 && (old_start.column + (range_len as u32) < old_line_end
2760 || old_line_end == old_line_start)
2761 {
2762 first_line_is_new = false;
2763 }
2764
2765 // When inserting text starting with a newline, avoid auto-indenting the
2766 // previous line.
2767 if new_text.starts_with('\n') {
2768 range_of_insertion_to_indent.start += 1;
2769 first_line_is_new = true;
2770 }
2771
2772 let mut original_indent_column = None;
2773 if let AutoindentMode::Block {
2774 original_indent_columns,
2775 } = &mode
2776 {
2777 original_indent_column = Some(if new_text.starts_with('\n') {
2778 indent_size_for_text(
2779 new_text[range_of_insertion_to_indent.clone()].chars(),
2780 )
2781 .len
2782 } else {
2783 original_indent_columns
2784 .get(ix)
2785 .copied()
2786 .flatten()
2787 .unwrap_or_else(|| {
2788 indent_size_for_text(
2789 new_text[range_of_insertion_to_indent.clone()].chars(),
2790 )
2791 .len
2792 })
2793 });
2794
2795 // Avoid auto-indenting the line after the edit.
2796 if new_text[range_of_insertion_to_indent.clone()].ends_with('\n') {
2797 range_of_insertion_to_indent.end -= 1;
2798 }
2799 }
2800
2801 AutoindentRequestEntry {
2802 original_indent_column,
2803 old_row: if first_line_is_new {
2804 None
2805 } else {
2806 Some(old_start.row)
2807 },
2808 indent_size: before_edit.language_indent_size_at(range.start, cx),
2809 range: self.anchor_before(new_start + range_of_insertion_to_indent.start)
2810 ..self.anchor_after(new_start + range_of_insertion_to_indent.end),
2811 }
2812 })
2813 .collect();
2814
2815 if !entries.is_empty() {
2816 self.autoindent_requests.push(Arc::new(AutoindentRequest {
2817 before_edit,
2818 entries,
2819 is_block_mode: matches!(mode, AutoindentMode::Block { .. }),
2820 ignore_empty_lines: false,
2821 }));
2822 }
2823 }
2824
2825 self.end_transaction(cx);
2826 self.send_operation(Operation::Buffer(edit_operation), true, cx);
2827 Some(edit_id)
2828 }
2829
2830 fn did_edit(
2831 &mut self,
2832 old_version: &clock::Global,
2833 was_dirty: bool,
2834 is_local: bool,
2835 cx: &mut Context<Self>,
2836 ) {
2837 self.was_changed();
2838
2839 if self.edits_since::<usize>(old_version).next().is_none() {
2840 return;
2841 }
2842
2843 self.reparse(cx, true);
2844 cx.emit(BufferEvent::Edited { is_local });
2845 let is_dirty = self.is_dirty();
2846 if was_dirty != is_dirty {
2847 cx.emit(BufferEvent::DirtyChanged);
2848 }
2849 if was_dirty && !is_dirty {
2850 if let Some(file) = self.file.as_ref() {
2851 if matches!(file.disk_state(), DiskState::Present { .. })
2852 && file.disk_state().mtime() != self.saved_mtime
2853 {
2854 cx.emit(BufferEvent::ReloadNeeded);
2855 }
2856 }
2857 }
2858 cx.notify();
2859 }
2860
2861 pub fn autoindent_ranges<I, T>(&mut self, ranges: I, cx: &mut Context<Self>)
2862 where
2863 I: IntoIterator<Item = Range<T>>,
2864 T: ToOffset + Copy,
2865 {
2866 let before_edit = self.snapshot();
2867 let entries = ranges
2868 .into_iter()
2869 .map(|range| AutoindentRequestEntry {
2870 range: before_edit.anchor_before(range.start)..before_edit.anchor_after(range.end),
2871 old_row: None,
2872 indent_size: before_edit.language_indent_size_at(range.start, cx),
2873 original_indent_column: None,
2874 })
2875 .collect();
2876 self.autoindent_requests.push(Arc::new(AutoindentRequest {
2877 before_edit,
2878 entries,
2879 is_block_mode: false,
2880 ignore_empty_lines: true,
2881 }));
2882 self.request_autoindent(cx, Some(Duration::from_micros(300)));
2883 }
2884
2885 // Inserts newlines at the given position to create an empty line, returning the start of the new line.
2886 // You can also request the insertion of empty lines above and below the line starting at the returned point.
2887 pub fn insert_empty_line(
2888 &mut self,
2889 position: impl ToPoint,
2890 space_above: bool,
2891 space_below: bool,
2892 cx: &mut Context<Self>,
2893 ) -> Point {
2894 let mut position = position.to_point(self);
2895
2896 self.start_transaction();
2897
2898 self.edit(
2899 [(position..position, "\n")],
2900 Some(AutoindentMode::EachLine),
2901 cx,
2902 );
2903
2904 if position.column > 0 {
2905 position += Point::new(1, 0);
2906 }
2907
2908 if !self.is_line_blank(position.row) {
2909 self.edit(
2910 [(position..position, "\n")],
2911 Some(AutoindentMode::EachLine),
2912 cx,
2913 );
2914 }
2915
2916 if space_above && position.row > 0 && !self.is_line_blank(position.row - 1) {
2917 self.edit(
2918 [(position..position, "\n")],
2919 Some(AutoindentMode::EachLine),
2920 cx,
2921 );
2922 position.row += 1;
2923 }
2924
2925 if space_below
2926 && (position.row == self.max_point().row || !self.is_line_blank(position.row + 1))
2927 {
2928 self.edit(
2929 [(position..position, "\n")],
2930 Some(AutoindentMode::EachLine),
2931 cx,
2932 );
2933 }
2934
2935 self.end_transaction(cx);
2936
2937 position
2938 }
2939
2940 /// Applies the given remote operations to the buffer.
2941 pub fn apply_ops<I: IntoIterator<Item = Operation>>(&mut self, ops: I, cx: &mut Context<Self>) {
2942 self.pending_autoindent.take();
2943 let was_dirty = self.is_dirty();
2944 let old_version = self.version.clone();
2945 let mut deferred_ops = Vec::new();
2946 let buffer_ops = ops
2947 .into_iter()
2948 .filter_map(|op| match op {
2949 Operation::Buffer(op) => Some(op),
2950 _ => {
2951 if self.can_apply_op(&op) {
2952 self.apply_op(op, cx);
2953 } else {
2954 deferred_ops.push(op);
2955 }
2956 None
2957 }
2958 })
2959 .collect::<Vec<_>>();
2960 for operation in buffer_ops.iter() {
2961 self.send_operation(Operation::Buffer(operation.clone()), false, cx);
2962 }
2963 self.text.apply_ops(buffer_ops);
2964 self.deferred_ops.insert(deferred_ops);
2965 self.flush_deferred_ops(cx);
2966 self.did_edit(&old_version, was_dirty, false, cx);
2967 // Notify independently of whether the buffer was edited as the operations could include a
2968 // selection update.
2969 cx.notify();
2970 }
2971
2972 fn flush_deferred_ops(&mut self, cx: &mut Context<Self>) {
2973 let mut deferred_ops = Vec::new();
2974 for op in self.deferred_ops.drain().iter().cloned() {
2975 if self.can_apply_op(&op) {
2976 self.apply_op(op, cx);
2977 } else {
2978 deferred_ops.push(op);
2979 }
2980 }
2981 self.deferred_ops.insert(deferred_ops);
2982 }
2983
2984 pub fn has_deferred_ops(&self) -> bool {
2985 !self.deferred_ops.is_empty() || self.text.has_deferred_ops()
2986 }
2987
2988 fn can_apply_op(&self, operation: &Operation) -> bool {
2989 match operation {
2990 Operation::Buffer(_) => {
2991 unreachable!("buffer operations should never be applied at this layer")
2992 }
2993 Operation::UpdateDiagnostics {
2994 diagnostics: diagnostic_set,
2995 ..
2996 } => diagnostic_set.iter().all(|diagnostic| {
2997 self.text.can_resolve(&diagnostic.range.start)
2998 && self.text.can_resolve(&diagnostic.range.end)
2999 }),
3000 Operation::UpdateSelections { selections, .. } => selections
3001 .iter()
3002 .all(|s| self.can_resolve(&s.start) && self.can_resolve(&s.end)),
3003 Operation::UpdateCompletionTriggers { .. } | Operation::UpdateLineEnding { .. } => true,
3004 }
3005 }
3006
3007 fn apply_op(&mut self, operation: Operation, cx: &mut Context<Self>) {
3008 match operation {
3009 Operation::Buffer(_) => {
3010 unreachable!("buffer operations should never be applied at this layer")
3011 }
3012 Operation::UpdateDiagnostics {
3013 server_id,
3014 diagnostics: diagnostic_set,
3015 lamport_timestamp,
3016 } => {
3017 let snapshot = self.snapshot();
3018 self.apply_diagnostic_update(
3019 server_id,
3020 DiagnosticSet::from_sorted_entries(diagnostic_set.iter().cloned(), &snapshot),
3021 lamport_timestamp,
3022 cx,
3023 );
3024 }
3025 Operation::UpdateSelections {
3026 selections,
3027 lamport_timestamp,
3028 line_mode,
3029 cursor_shape,
3030 } => {
3031 if let Some(set) = self.remote_selections.get(&lamport_timestamp.replica_id)
3032 && set.lamport_timestamp > lamport_timestamp
3033 {
3034 return;
3035 }
3036
3037 self.remote_selections.insert(
3038 lamport_timestamp.replica_id,
3039 SelectionSet {
3040 selections,
3041 lamport_timestamp,
3042 line_mode,
3043 cursor_shape,
3044 },
3045 );
3046 self.text.lamport_clock.observe(lamport_timestamp);
3047 self.non_text_state_update_count += 1;
3048 }
3049 Operation::UpdateCompletionTriggers {
3050 triggers,
3051 lamport_timestamp,
3052 server_id,
3053 } => {
3054 if triggers.is_empty() {
3055 self.completion_triggers_per_language_server
3056 .remove(&server_id);
3057 self.completion_triggers = self
3058 .completion_triggers_per_language_server
3059 .values()
3060 .flat_map(|triggers| triggers.iter().cloned())
3061 .collect();
3062 } else {
3063 self.completion_triggers_per_language_server
3064 .insert(server_id, triggers.iter().cloned().collect());
3065 self.completion_triggers.extend(triggers);
3066 }
3067 self.text.lamport_clock.observe(lamport_timestamp);
3068 }
3069 Operation::UpdateLineEnding {
3070 line_ending,
3071 lamport_timestamp,
3072 } => {
3073 self.text.set_line_ending(line_ending);
3074 self.text.lamport_clock.observe(lamport_timestamp);
3075 }
3076 }
3077 }
3078
3079 fn apply_diagnostic_update(
3080 &mut self,
3081 server_id: LanguageServerId,
3082 diagnostics: DiagnosticSet,
3083 lamport_timestamp: clock::Lamport,
3084 cx: &mut Context<Self>,
3085 ) {
3086 if lamport_timestamp > self.diagnostics_timestamp {
3087 if diagnostics.is_empty() {
3088 self.diagnostics.remove(&server_id);
3089 } else {
3090 self.diagnostics.insert(server_id, diagnostics);
3091 }
3092 self.diagnostics_timestamp = lamport_timestamp;
3093 self.non_text_state_update_count += 1;
3094 self.text.lamport_clock.observe(lamport_timestamp);
3095 cx.notify();
3096 cx.emit(BufferEvent::DiagnosticsUpdated);
3097 }
3098 }
3099
3100 fn send_operation(&mut self, operation: Operation, is_local: bool, cx: &mut Context<Self>) {
3101 self.was_changed();
3102 cx.emit(BufferEvent::Operation {
3103 operation,
3104 is_local,
3105 });
3106 }
3107
3108 /// Removes the selections for a given peer.
3109 pub fn remove_peer(&mut self, replica_id: ReplicaId, cx: &mut Context<Self>) {
3110 self.remote_selections.remove(&replica_id);
3111 cx.notify();
3112 }
3113
3114 /// Undoes the most recent transaction.
3115 pub fn undo(&mut self, cx: &mut Context<Self>) -> Option<TransactionId> {
3116 let was_dirty = self.is_dirty();
3117 let old_version = self.version.clone();
3118
3119 if let Some((transaction_id, operation)) = self.text.undo() {
3120 self.send_operation(Operation::Buffer(operation), true, cx);
3121 self.did_edit(&old_version, was_dirty, true, cx);
3122 self.restore_encoding_for_transaction(transaction_id, was_dirty);
3123 Some(transaction_id)
3124 } else {
3125 None
3126 }
3127 }
3128
3129 /// Manually undoes a specific transaction in the buffer's undo history.
3130 pub fn undo_transaction(
3131 &mut self,
3132 transaction_id: TransactionId,
3133 cx: &mut Context<Self>,
3134 ) -> bool {
3135 let was_dirty = self.is_dirty();
3136 let old_version = self.version.clone();
3137 if let Some(operation) = self.text.undo_transaction(transaction_id) {
3138 self.send_operation(Operation::Buffer(operation), true, cx);
3139 self.did_edit(&old_version, was_dirty, true, cx);
3140 true
3141 } else {
3142 false
3143 }
3144 }
3145
3146 /// Manually undoes all changes after a given transaction in the buffer's undo history.
3147 pub fn undo_to_transaction(
3148 &mut self,
3149 transaction_id: TransactionId,
3150 cx: &mut Context<Self>,
3151 ) -> bool {
3152 let was_dirty = self.is_dirty();
3153 let old_version = self.version.clone();
3154
3155 let operations = self.text.undo_to_transaction(transaction_id);
3156 let undone = !operations.is_empty();
3157 for operation in operations {
3158 self.send_operation(Operation::Buffer(operation), true, cx);
3159 }
3160 if undone {
3161 self.did_edit(&old_version, was_dirty, true, cx)
3162 }
3163 undone
3164 }
3165
3166 pub fn undo_operations(&mut self, counts: HashMap<Lamport, u32>, cx: &mut Context<Buffer>) {
3167 let was_dirty = self.is_dirty();
3168 let operation = self.text.undo_operations(counts);
3169 let old_version = self.version.clone();
3170 self.send_operation(Operation::Buffer(operation), true, cx);
3171 self.did_edit(&old_version, was_dirty, true, cx);
3172 }
3173
3174 /// Manually redoes a specific transaction in the buffer's redo history.
3175 pub fn redo(&mut self, cx: &mut Context<Self>) -> Option<TransactionId> {
3176 let was_dirty = self.is_dirty();
3177 let old_version = self.version.clone();
3178
3179 if let Some((transaction_id, operation)) = self.text.redo() {
3180 self.send_operation(Operation::Buffer(operation), true, cx);
3181 self.did_edit(&old_version, was_dirty, true, cx);
3182 self.restore_encoding_for_transaction(transaction_id, was_dirty);
3183 Some(transaction_id)
3184 } else {
3185 None
3186 }
3187 }
3188
3189 fn restore_encoding_for_transaction(&mut self, transaction_id: TransactionId, was_dirty: bool) {
3190 if let Some((old_encoding, old_has_bom)) =
3191 self.reload_with_encoding_txns.get(&transaction_id)
3192 {
3193 let current_encoding = self.encoding;
3194 let current_has_bom = self.has_bom;
3195 self.encoding = *old_encoding;
3196 self.has_bom = *old_has_bom;
3197 if !was_dirty {
3198 self.saved_version = self.version.clone();
3199 self.has_unsaved_edits
3200 .set((self.saved_version.clone(), false));
3201 }
3202 self.reload_with_encoding_txns
3203 .insert(transaction_id, (current_encoding, current_has_bom));
3204 }
3205 }
3206
3207 /// Manually undoes all changes until a given transaction in the buffer's redo history.
3208 pub fn redo_to_transaction(
3209 &mut self,
3210 transaction_id: TransactionId,
3211 cx: &mut Context<Self>,
3212 ) -> bool {
3213 let was_dirty = self.is_dirty();
3214 let old_version = self.version.clone();
3215
3216 let operations = self.text.redo_to_transaction(transaction_id);
3217 let redone = !operations.is_empty();
3218 for operation in operations {
3219 self.send_operation(Operation::Buffer(operation), true, cx);
3220 }
3221 if redone {
3222 self.did_edit(&old_version, was_dirty, true, cx)
3223 }
3224 redone
3225 }
3226
3227 /// Override current completion triggers with the user-provided completion triggers.
3228 pub fn set_completion_triggers(
3229 &mut self,
3230 server_id: LanguageServerId,
3231 triggers: BTreeSet<String>,
3232 cx: &mut Context<Self>,
3233 ) {
3234 self.completion_triggers_timestamp = self.text.lamport_clock.tick();
3235 if triggers.is_empty() {
3236 self.completion_triggers_per_language_server
3237 .remove(&server_id);
3238 self.completion_triggers = self
3239 .completion_triggers_per_language_server
3240 .values()
3241 .flat_map(|triggers| triggers.iter().cloned())
3242 .collect();
3243 } else {
3244 self.completion_triggers_per_language_server
3245 .insert(server_id, triggers.clone());
3246 self.completion_triggers.extend(triggers.iter().cloned());
3247 }
3248 self.send_operation(
3249 Operation::UpdateCompletionTriggers {
3250 triggers: triggers.into_iter().collect(),
3251 lamport_timestamp: self.completion_triggers_timestamp,
3252 server_id,
3253 },
3254 true,
3255 cx,
3256 );
3257 cx.notify();
3258 }
3259
3260 /// Returns a list of strings which trigger a completion menu for this language.
3261 /// Usually this is driven by LSP server which returns a list of trigger characters for completions.
3262 pub fn completion_triggers(&self) -> &BTreeSet<String> {
3263 &self.completion_triggers
3264 }
3265
3266 /// Call this directly after performing edits to prevent the preview tab
3267 /// from being dismissed by those edits. It causes `should_dismiss_preview`
3268 /// to return false until there are additional edits.
3269 pub fn refresh_preview(&mut self) {
3270 self.preview_version = self.version.clone();
3271 }
3272
3273 /// Whether we should preserve the preview status of a tab containing this buffer.
3274 pub fn preserve_preview(&self) -> bool {
3275 !self.has_edits_since(&self.preview_version)
3276 }
3277
3278 pub fn set_group_interval(&mut self, group_interval: Duration) {
3279 self.text.set_group_interval(group_interval);
3280 }
3281}
3282
3283#[doc(hidden)]
3284#[cfg(any(test, feature = "test-support"))]
3285impl Buffer {
3286 pub fn edit_via_marked_text(
3287 &mut self,
3288 marked_string: &str,
3289 autoindent_mode: Option<AutoindentMode>,
3290 cx: &mut Context<Self>,
3291 ) {
3292 let edits = self.edits_for_marked_text(marked_string);
3293 self.edit(edits, autoindent_mode, cx);
3294 }
3295
3296 pub fn randomly_edit<T>(&mut self, rng: &mut T, old_range_count: usize, cx: &mut Context<Self>)
3297 where
3298 T: rand::Rng,
3299 {
3300 let mut edits: Vec<(Range<usize>, String)> = Vec::new();
3301 let mut last_end = None;
3302 for _ in 0..old_range_count {
3303 if last_end.is_some_and(|last_end| last_end >= self.len()) {
3304 break;
3305 }
3306
3307 let new_start = last_end.map_or(0, |last_end| last_end + 1);
3308 let mut range = self.random_byte_range(new_start, rng);
3309 if rng.random_bool(0.2) {
3310 mem::swap(&mut range.start, &mut range.end);
3311 }
3312 last_end = Some(range.end);
3313
3314 let new_text_len = rng.random_range(0..10);
3315 let mut new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
3316 new_text = new_text.to_uppercase();
3317
3318 edits.push((range, new_text));
3319 }
3320 log::info!("mutating buffer {:?} with {:?}", self.replica_id(), edits);
3321 self.edit(edits, None, cx);
3322 }
3323
3324 pub fn randomly_undo_redo(&mut self, rng: &mut impl rand::Rng, cx: &mut Context<Self>) {
3325 let was_dirty = self.is_dirty();
3326 let old_version = self.version.clone();
3327
3328 let ops = self.text.randomly_undo_redo(rng);
3329 if !ops.is_empty() {
3330 for op in ops {
3331 self.send_operation(Operation::Buffer(op), true, cx);
3332 self.did_edit(&old_version, was_dirty, true, cx);
3333 }
3334 }
3335 }
3336}
3337
3338impl EventEmitter<BufferEvent> for Buffer {}
3339
3340fn offset_in_sub_ranges(
3341 sub_ranges: &[Range<Anchor>],
3342 offset: usize,
3343 snapshot: &TextBufferSnapshot,
3344) -> bool {
3345 let start_anchor = snapshot.anchor_before(offset);
3346 let end_anchor = snapshot.anchor_after(offset);
3347
3348 sub_ranges.iter().any(|sub_range| {
3349 let is_before_start = sub_range.end.cmp(&start_anchor, snapshot).is_lt();
3350 let is_after_end = sub_range.start.cmp(&end_anchor, snapshot).is_gt();
3351 !is_before_start && !is_after_end
3352 })
3353}
3354
3355impl Deref for Buffer {
3356 type Target = TextBuffer;
3357
3358 fn deref(&self) -> &Self::Target {
3359 &self.text
3360 }
3361}
3362
3363impl BufferSnapshot {
3364 /// Returns [`IndentSize`] for a given line that respects user settings and
3365 /// language preferences.
3366 pub fn indent_size_for_line(&self, row: u32) -> IndentSize {
3367 indent_size_for_line(self, row)
3368 }
3369
3370 /// Returns [`IndentSize`] for a given position that respects user settings
3371 /// and language preferences.
3372 pub fn language_indent_size_at<T: ToOffset>(&self, position: T, cx: &App) -> IndentSize {
3373 let settings = self.settings_at(position, cx);
3374 if settings.hard_tabs {
3375 IndentSize::tab()
3376 } else {
3377 IndentSize::spaces(settings.tab_size.get())
3378 }
3379 }
3380
3381 /// Retrieve the suggested indent size for all of the given rows. The unit of indentation
3382 /// is passed in as `single_indent_size`.
3383 pub fn suggested_indents(
3384 &self,
3385 rows: impl Iterator<Item = u32>,
3386 single_indent_size: IndentSize,
3387 ) -> BTreeMap<u32, IndentSize> {
3388 let mut result = BTreeMap::new();
3389
3390 for row_range in contiguous_ranges(rows, 10) {
3391 let suggestions = match self.suggest_autoindents(row_range.clone()) {
3392 Some(suggestions) => suggestions,
3393 _ => break,
3394 };
3395
3396 for (row, suggestion) in row_range.zip(suggestions) {
3397 let indent_size = if let Some(suggestion) = suggestion {
3398 result
3399 .get(&suggestion.basis_row)
3400 .copied()
3401 .unwrap_or_else(|| self.indent_size_for_line(suggestion.basis_row))
3402 .with_delta(suggestion.delta, single_indent_size)
3403 } else {
3404 self.indent_size_for_line(row)
3405 };
3406
3407 result.insert(row, indent_size);
3408 }
3409 }
3410
3411 result
3412 }
3413
3414 fn suggest_autoindents(
3415 &self,
3416 row_range: Range<u32>,
3417 ) -> Option<impl Iterator<Item = Option<IndentSuggestion>> + '_> {
3418 let config = &self.language.as_ref()?.config;
3419 let prev_non_blank_row = self.prev_non_blank_row(row_range.start);
3420
3421 #[derive(Debug, Clone)]
3422 struct StartPosition {
3423 start: Point,
3424 suffix: SharedString,
3425 language: Arc<Language>,
3426 }
3427
3428 // Find the suggested indentation ranges based on the syntax tree.
3429 let start = Point::new(prev_non_blank_row.unwrap_or(row_range.start), 0);
3430 let end = Point::new(row_range.end, 0);
3431 let range = (start..end).to_offset(&self.text);
3432 let mut matches = self.syntax.matches_with_options(
3433 range.clone(),
3434 &self.text,
3435 TreeSitterOptions {
3436 max_bytes_to_query: Some(MAX_BYTES_TO_QUERY),
3437 max_start_depth: None,
3438 },
3439 |grammar| Some(&grammar.indents_config.as_ref()?.query),
3440 );
3441 let indent_configs = matches
3442 .grammars()
3443 .iter()
3444 .map(|grammar| grammar.indents_config.as_ref().unwrap())
3445 .collect::<Vec<_>>();
3446
3447 let mut indent_ranges = Vec::<Range<Point>>::new();
3448 let mut start_positions = Vec::<StartPosition>::new();
3449 let mut outdent_positions = Vec::<Point>::new();
3450 while let Some(mat) = matches.peek() {
3451 let mut start: Option<Point> = None;
3452 let mut end: Option<Point> = None;
3453
3454 let config = indent_configs[mat.grammar_index];
3455 for capture in mat.captures {
3456 if capture.index == config.indent_capture_ix {
3457 start.get_or_insert(Point::from_ts_point(capture.node.start_position()));
3458 end.get_or_insert(Point::from_ts_point(capture.node.end_position()));
3459 } else if Some(capture.index) == config.start_capture_ix {
3460 start = Some(Point::from_ts_point(capture.node.end_position()));
3461 } else if Some(capture.index) == config.end_capture_ix {
3462 end = Some(Point::from_ts_point(capture.node.start_position()));
3463 } else if Some(capture.index) == config.outdent_capture_ix {
3464 outdent_positions.push(Point::from_ts_point(capture.node.start_position()));
3465 } else if let Some(suffix) = config.suffixed_start_captures.get(&capture.index) {
3466 start_positions.push(StartPosition {
3467 start: Point::from_ts_point(capture.node.start_position()),
3468 suffix: suffix.clone(),
3469 language: mat.language.clone(),
3470 });
3471 }
3472 }
3473
3474 matches.advance();
3475 if let Some((start, end)) = start.zip(end) {
3476 if start.row == end.row {
3477 continue;
3478 }
3479 let range = start..end;
3480 match indent_ranges.binary_search_by_key(&range.start, |r| r.start) {
3481 Err(ix) => indent_ranges.insert(ix, range),
3482 Ok(ix) => {
3483 let prev_range = &mut indent_ranges[ix];
3484 prev_range.end = prev_range.end.max(range.end);
3485 }
3486 }
3487 }
3488 }
3489
3490 let mut error_ranges = Vec::<Range<Point>>::new();
3491 let mut matches = self
3492 .syntax
3493 .matches(range, &self.text, |grammar| grammar.error_query.as_ref());
3494 while let Some(mat) = matches.peek() {
3495 let node = mat.captures[0].node;
3496 let start = Point::from_ts_point(node.start_position());
3497 let end = Point::from_ts_point(node.end_position());
3498 let range = start..end;
3499 let ix = match error_ranges.binary_search_by_key(&range.start, |r| r.start) {
3500 Ok(ix) | Err(ix) => ix,
3501 };
3502 let mut end_ix = ix;
3503 while let Some(existing_range) = error_ranges.get(end_ix) {
3504 if existing_range.end < end {
3505 end_ix += 1;
3506 } else {
3507 break;
3508 }
3509 }
3510 error_ranges.splice(ix..end_ix, [range]);
3511 matches.advance();
3512 }
3513
3514 outdent_positions.sort();
3515 for outdent_position in outdent_positions {
3516 // find the innermost indent range containing this outdent_position
3517 // set its end to the outdent position
3518 if let Some(range_to_truncate) = indent_ranges
3519 .iter_mut()
3520 .rfind(|indent_range| indent_range.contains(&outdent_position))
3521 {
3522 range_to_truncate.end = outdent_position;
3523 }
3524 }
3525
3526 start_positions.sort_by_key(|b| b.start);
3527
3528 // Find the suggested indentation increases and decreased based on regexes.
3529 let mut regex_outdent_map = HashMap::default();
3530 let mut last_seen_suffix: HashMap<String, Vec<StartPosition>> = HashMap::default();
3531 let mut start_positions_iter = start_positions.iter().peekable();
3532
3533 let mut indent_change_rows = Vec::<(u32, Ordering)>::new();
3534 self.for_each_line(
3535 Point::new(prev_non_blank_row.unwrap_or(row_range.start), 0)
3536 ..Point::new(row_range.end, 0),
3537 |row, line| {
3538 let indent_len = self.indent_size_for_line(row).len;
3539 let row_language = self.language_at(Point::new(row, indent_len)).cloned();
3540 let row_language_config = row_language
3541 .as_ref()
3542 .map(|lang| lang.config())
3543 .unwrap_or(config);
3544
3545 if row_language_config
3546 .decrease_indent_pattern
3547 .as_ref()
3548 .is_some_and(|regex| regex.is_match(line))
3549 {
3550 indent_change_rows.push((row, Ordering::Less));
3551 }
3552 if row_language_config
3553 .increase_indent_pattern
3554 .as_ref()
3555 .is_some_and(|regex| regex.is_match(line))
3556 {
3557 indent_change_rows.push((row + 1, Ordering::Greater));
3558 }
3559 while let Some(pos) = start_positions_iter.peek() {
3560 if pos.start.row < row {
3561 let pos = start_positions_iter.next().unwrap().clone();
3562 last_seen_suffix
3563 .entry(pos.suffix.to_string())
3564 .or_default()
3565 .push(pos);
3566 } else {
3567 break;
3568 }
3569 }
3570 for rule in &row_language_config.decrease_indent_patterns {
3571 if rule.pattern.as_ref().is_some_and(|r| r.is_match(line)) {
3572 let row_start_column = self.indent_size_for_line(row).len;
3573 let basis_row = rule
3574 .valid_after
3575 .iter()
3576 .filter_map(|valid_suffix| last_seen_suffix.get(valid_suffix))
3577 .flatten()
3578 .filter(|pos| {
3579 row_language
3580 .as_ref()
3581 .or(self.language.as_ref())
3582 .is_some_and(|lang| Arc::ptr_eq(lang, &pos.language))
3583 })
3584 .filter(|pos| pos.start.column <= row_start_column)
3585 .max_by_key(|pos| pos.start.row);
3586 if let Some(outdent_to) = basis_row {
3587 regex_outdent_map.insert(row, outdent_to.start.row);
3588 }
3589 break;
3590 }
3591 }
3592 },
3593 );
3594
3595 let mut indent_changes = indent_change_rows.into_iter().peekable();
3596 let mut prev_row = if config.auto_indent_using_last_non_empty_line {
3597 prev_non_blank_row.unwrap_or(0)
3598 } else {
3599 row_range.start.saturating_sub(1)
3600 };
3601
3602 let mut prev_row_start = Point::new(prev_row, self.indent_size_for_line(prev_row).len);
3603 Some(row_range.map(move |row| {
3604 let row_start = Point::new(row, self.indent_size_for_line(row).len);
3605
3606 let mut indent_from_prev_row = false;
3607 let mut outdent_from_prev_row = false;
3608 let mut outdent_to_row = u32::MAX;
3609 let mut from_regex = false;
3610
3611 while let Some((indent_row, delta)) = indent_changes.peek() {
3612 match indent_row.cmp(&row) {
3613 Ordering::Equal => match delta {
3614 Ordering::Less => {
3615 from_regex = true;
3616 outdent_from_prev_row = true
3617 }
3618 Ordering::Greater => {
3619 indent_from_prev_row = true;
3620 from_regex = true
3621 }
3622 _ => {}
3623 },
3624
3625 Ordering::Greater => break,
3626 Ordering::Less => {}
3627 }
3628
3629 indent_changes.next();
3630 }
3631
3632 for range in &indent_ranges {
3633 if range.start.row >= row {
3634 break;
3635 }
3636 if range.start.row == prev_row && range.end > row_start {
3637 indent_from_prev_row = true;
3638 }
3639 if range.end > prev_row_start && range.end <= row_start {
3640 outdent_to_row = outdent_to_row.min(range.start.row);
3641 }
3642 }
3643
3644 if let Some(basis_row) = regex_outdent_map.get(&row) {
3645 indent_from_prev_row = false;
3646 outdent_to_row = *basis_row;
3647 from_regex = true;
3648 }
3649
3650 let within_error = error_ranges
3651 .iter()
3652 .any(|e| e.start.row < row && e.end > row_start);
3653
3654 let suggestion = if outdent_to_row == prev_row
3655 || (outdent_from_prev_row && indent_from_prev_row)
3656 {
3657 Some(IndentSuggestion {
3658 basis_row: prev_row,
3659 delta: Ordering::Equal,
3660 within_error: within_error && !from_regex,
3661 })
3662 } else if indent_from_prev_row {
3663 Some(IndentSuggestion {
3664 basis_row: prev_row,
3665 delta: Ordering::Greater,
3666 within_error: within_error && !from_regex,
3667 })
3668 } else if outdent_to_row < prev_row {
3669 Some(IndentSuggestion {
3670 basis_row: outdent_to_row,
3671 delta: Ordering::Equal,
3672 within_error: within_error && !from_regex,
3673 })
3674 } else if outdent_from_prev_row {
3675 Some(IndentSuggestion {
3676 basis_row: prev_row,
3677 delta: Ordering::Less,
3678 within_error: within_error && !from_regex,
3679 })
3680 } else if config.auto_indent_using_last_non_empty_line || !self.is_line_blank(prev_row)
3681 {
3682 Some(IndentSuggestion {
3683 basis_row: prev_row,
3684 delta: Ordering::Equal,
3685 within_error: within_error && !from_regex,
3686 })
3687 } else {
3688 None
3689 };
3690
3691 prev_row = row;
3692 prev_row_start = row_start;
3693 suggestion
3694 }))
3695 }
3696
3697 fn prev_non_blank_row(&self, mut row: u32) -> Option<u32> {
3698 while row > 0 {
3699 row -= 1;
3700 if !self.is_line_blank(row) {
3701 return Some(row);
3702 }
3703 }
3704 None
3705 }
3706
3707 pub fn captures(
3708 &self,
3709 range: Range<usize>,
3710 query: fn(&Grammar) -> Option<&tree_sitter::Query>,
3711 ) -> SyntaxMapCaptures<'_> {
3712 self.syntax.captures(range, &self.text, query)
3713 }
3714
3715 #[ztracing::instrument(skip_all)]
3716 fn get_highlights(&self, range: Range<usize>) -> (SyntaxMapCaptures<'_>, Vec<HighlightMap>) {
3717 let captures = self.syntax.captures(range, &self.text, |grammar| {
3718 grammar
3719 .highlights_config
3720 .as_ref()
3721 .map(|config| &config.query)
3722 });
3723 let highlight_maps = captures
3724 .grammars()
3725 .iter()
3726 .map(|grammar| grammar.highlight_map())
3727 .collect();
3728 (captures, highlight_maps)
3729 }
3730
3731 /// Iterates over chunks of text in the given range of the buffer. Text is chunked
3732 /// in an arbitrary way due to being stored in a [`Rope`](text::Rope). The text is also
3733 /// returned in chunks where each chunk has a single syntax highlighting style and
3734 /// diagnostic status.
3735 #[ztracing::instrument(skip_all)]
3736 pub fn chunks<T: ToOffset>(
3737 &self,
3738 range: Range<T>,
3739 language_aware: LanguageAwareStyling,
3740 ) -> BufferChunks<'_> {
3741 let range = range.start.to_offset(self)..range.end.to_offset(self);
3742
3743 let mut syntax = None;
3744 if language_aware.tree_sitter {
3745 syntax = Some(self.get_highlights(range.clone()));
3746 }
3747 BufferChunks::new(
3748 self.text.as_rope(),
3749 range,
3750 syntax,
3751 language_aware.diagnostics,
3752 Some(self),
3753 )
3754 }
3755
3756 pub fn highlighted_text_for_range<T: ToOffset>(
3757 &self,
3758 range: Range<T>,
3759 override_style: Option<HighlightStyle>,
3760 syntax_theme: &SyntaxTheme,
3761 ) -> HighlightedText {
3762 HighlightedText::from_buffer_range(
3763 range,
3764 &self.text,
3765 &self.syntax,
3766 override_style,
3767 syntax_theme,
3768 )
3769 }
3770
3771 /// Invokes the given callback for each line of text in the given range of the buffer.
3772 /// Uses callback to avoid allocating a string for each line.
3773 fn for_each_line(&self, range: Range<Point>, mut callback: impl FnMut(u32, &str)) {
3774 let mut line = String::new();
3775 let mut row = range.start.row;
3776 for chunk in self
3777 .as_rope()
3778 .chunks_in_range(range.to_offset(self))
3779 .chain(["\n"])
3780 {
3781 for (newline_ix, text) in chunk.split('\n').enumerate() {
3782 if newline_ix > 0 {
3783 callback(row, &line);
3784 row += 1;
3785 line.clear();
3786 }
3787 line.push_str(text);
3788 }
3789 }
3790 }
3791
3792 /// Iterates over every [`SyntaxLayer`] in the buffer.
3793 pub fn syntax_layers(&self) -> impl Iterator<Item = SyntaxLayer<'_>> + '_ {
3794 self.syntax_layers_for_range(0..self.len(), true)
3795 }
3796
3797 pub fn syntax_layer_at<D: ToOffset>(&self, position: D) -> Option<SyntaxLayer<'_>> {
3798 let offset = position.to_offset(self);
3799 self.syntax_layers_for_range(offset..offset, false)
3800 .filter(|l| {
3801 if let Some(ranges) = l.included_sub_ranges {
3802 ranges.iter().any(|range| {
3803 let start = range.start.to_offset(self);
3804 start <= offset && {
3805 let end = range.end.to_offset(self);
3806 offset < end
3807 }
3808 })
3809 } else {
3810 l.node().start_byte() <= offset && l.node().end_byte() > offset
3811 }
3812 })
3813 .last()
3814 }
3815
3816 pub fn syntax_layers_for_range<D: ToOffset>(
3817 &self,
3818 range: Range<D>,
3819 include_hidden: bool,
3820 ) -> impl Iterator<Item = SyntaxLayer<'_>> + '_ {
3821 self.syntax
3822 .layers_for_range(range, &self.text, include_hidden)
3823 }
3824
3825 pub fn syntax_layers_languages(&self) -> impl Iterator<Item = &Arc<Language>> {
3826 self.syntax.languages(&self, true)
3827 }
3828
3829 pub fn smallest_syntax_layer_containing<D: ToOffset>(
3830 &self,
3831 range: Range<D>,
3832 ) -> Option<SyntaxLayer<'_>> {
3833 let range = range.to_offset(self);
3834 self.syntax
3835 .layers_for_range(range, &self.text, false)
3836 .max_by(|a, b| {
3837 if a.depth != b.depth {
3838 a.depth.cmp(&b.depth)
3839 } else if a.offset.0 != b.offset.0 {
3840 a.offset.0.cmp(&b.offset.0)
3841 } else {
3842 a.node().end_byte().cmp(&b.node().end_byte()).reverse()
3843 }
3844 })
3845 }
3846
3847 /// Returns the [`ModelineSettings`].
3848 pub fn modeline(&self) -> Option<&Arc<ModelineSettings>> {
3849 self.modeline.as_ref()
3850 }
3851
3852 /// Returns the main [`Language`].
3853 pub fn language(&self) -> Option<&Arc<Language>> {
3854 self.language.as_ref()
3855 }
3856
3857 /// Returns the [`Language`] at the given location.
3858 pub fn language_at<D: ToOffset>(&self, position: D) -> Option<&Arc<Language>> {
3859 self.syntax_layer_at(position)
3860 .map(|info| info.language)
3861 .or(self.language.as_ref())
3862 }
3863
3864 /// Returns the settings for the language at the given location.
3865 pub fn settings_at<'a, D: ToOffset>(
3866 &'a self,
3867 position: D,
3868 cx: &'a App,
3869 ) -> Cow<'a, LanguageSettings> {
3870 LanguageSettings::for_buffer_snapshot(self, Some(position.to_offset(self)), cx)
3871 }
3872
3873 pub fn char_classifier_at<T: ToOffset>(&self, point: T) -> CharClassifier {
3874 CharClassifier::new(self.language_scope_at(point))
3875 }
3876
3877 /// Returns the [`LanguageScope`] at the given location.
3878 pub fn language_scope_at<D: ToOffset>(&self, position: D) -> Option<LanguageScope> {
3879 let offset = position.to_offset(self);
3880 let mut scope = None;
3881 let mut smallest_range_and_depth: Option<(Range<usize>, usize)> = None;
3882 let text: &TextBufferSnapshot = self;
3883
3884 // Use the layer that has the smallest node intersecting the given point.
3885 for layer in self
3886 .syntax
3887 .layers_for_range(offset..offset, &self.text, false)
3888 {
3889 if let Some(ranges) = layer.included_sub_ranges
3890 && !offset_in_sub_ranges(ranges, offset, text)
3891 {
3892 continue;
3893 }
3894
3895 let mut cursor = layer.node().walk();
3896
3897 let mut range = None;
3898 loop {
3899 let child_range = cursor.node().byte_range();
3900 if !child_range.contains(&offset) {
3901 break;
3902 }
3903
3904 range = Some(child_range);
3905 if cursor.goto_first_child_for_byte(offset).is_none() {
3906 break;
3907 }
3908 }
3909
3910 if let Some(range) = range
3911 && smallest_range_and_depth.as_ref().is_none_or(
3912 |(smallest_range, smallest_range_depth)| {
3913 if layer.depth > *smallest_range_depth {
3914 true
3915 } else if layer.depth == *smallest_range_depth {
3916 range.len() < smallest_range.len()
3917 } else {
3918 false
3919 }
3920 },
3921 )
3922 {
3923 smallest_range_and_depth = Some((range, layer.depth));
3924 scope = Some(LanguageScope {
3925 language: layer.language.clone(),
3926 override_id: layer.override_id(offset, &self.text),
3927 });
3928 }
3929 }
3930
3931 scope.or_else(|| {
3932 self.language.clone().map(|language| LanguageScope {
3933 language,
3934 override_id: None,
3935 })
3936 })
3937 }
3938
3939 /// Returns a tuple of the range and character kind of the word
3940 /// surrounding the given position.
3941 pub fn surrounding_word<T: ToOffset>(
3942 &self,
3943 start: T,
3944 scope_context: Option<CharScopeContext>,
3945 ) -> (Range<usize>, Option<CharKind>) {
3946 let mut start = start.to_offset(self);
3947 let mut end = start;
3948 let mut next_chars = self.chars_at(start).take(128).peekable();
3949 let mut prev_chars = self.reversed_chars_at(start).take(128).peekable();
3950
3951 let classifier = self.char_classifier_at(start).scope_context(scope_context);
3952 let word_kind = cmp::max(
3953 prev_chars.peek().copied().map(|c| classifier.kind(c)),
3954 next_chars.peek().copied().map(|c| classifier.kind(c)),
3955 );
3956
3957 for ch in prev_chars {
3958 if Some(classifier.kind(ch)) == word_kind && ch != '\n' {
3959 start -= ch.len_utf8();
3960 } else {
3961 break;
3962 }
3963 }
3964
3965 for ch in next_chars {
3966 if Some(classifier.kind(ch)) == word_kind && ch != '\n' {
3967 end += ch.len_utf8();
3968 } else {
3969 break;
3970 }
3971 }
3972
3973 (start..end, word_kind)
3974 }
3975
3976 /// Moves the TreeCursor to the smallest descendant or ancestor syntax node enclosing the given
3977 /// range. When `require_larger` is true, the node found must be larger than the query range.
3978 ///
3979 /// Returns true if a node was found, and false otherwise. In the `false` case the cursor will
3980 /// be moved to the root of the tree.
3981 fn goto_node_enclosing_range(
3982 cursor: &mut tree_sitter::TreeCursor,
3983 query_range: &Range<usize>,
3984 require_larger: bool,
3985 ) -> bool {
3986 let mut ascending = false;
3987 loop {
3988 let mut range = cursor.node().byte_range();
3989 if query_range.is_empty() {
3990 // When the query range is empty and the current node starts after it, move to the
3991 // previous sibling to find the node the containing node.
3992 if range.start > query_range.start {
3993 cursor.goto_previous_sibling();
3994 range = cursor.node().byte_range();
3995 }
3996 } else {
3997 // When the query range is non-empty and the current node ends exactly at the start,
3998 // move to the next sibling to find a node that extends beyond the start.
3999 if range.end == query_range.start {
4000 cursor.goto_next_sibling();
4001 range = cursor.node().byte_range();
4002 }
4003 }
4004
4005 let encloses = range.contains_inclusive(query_range)
4006 && (!require_larger || range.len() > query_range.len());
4007 if !encloses {
4008 ascending = true;
4009 if !cursor.goto_parent() {
4010 return false;
4011 }
4012 continue;
4013 } else if ascending {
4014 return true;
4015 }
4016
4017 // Descend into the current node.
4018 if cursor
4019 .goto_first_child_for_byte(query_range.start)
4020 .is_none()
4021 {
4022 return true;
4023 }
4024 }
4025 }
4026
4027 pub fn syntax_ancestor<'a, T: ToOffset>(
4028 &'a self,
4029 range: Range<T>,
4030 ) -> Option<tree_sitter::Node<'a>> {
4031 let range = range.start.to_offset(self)..range.end.to_offset(self);
4032 let mut result: Option<tree_sitter::Node<'a>> = None;
4033 for layer in self
4034 .syntax
4035 .layers_for_range(range.clone(), &self.text, true)
4036 {
4037 let mut cursor = layer.node().walk();
4038
4039 // Find the node that both contains the range and is larger than it.
4040 if !Self::goto_node_enclosing_range(&mut cursor, &range, true) {
4041 continue;
4042 }
4043
4044 let left_node = cursor.node();
4045 let mut layer_result = left_node;
4046
4047 // For an empty range, try to find another node immediately to the right of the range.
4048 if left_node.end_byte() == range.start {
4049 let mut right_node = None;
4050 while !cursor.goto_next_sibling() {
4051 if !cursor.goto_parent() {
4052 break;
4053 }
4054 }
4055
4056 while cursor.node().start_byte() == range.start {
4057 right_node = Some(cursor.node());
4058 if !cursor.goto_first_child() {
4059 break;
4060 }
4061 }
4062
4063 // If there is a candidate node on both sides of the (empty) range, then
4064 // decide between the two by favoring a named node over an anonymous token.
4065 // If both nodes are the same in that regard, favor the right one.
4066 if let Some(right_node) = right_node
4067 && (right_node.is_named() || !left_node.is_named())
4068 {
4069 layer_result = right_node;
4070 }
4071 }
4072
4073 if let Some(previous_result) = &result
4074 && previous_result.byte_range().len() < layer_result.byte_range().len()
4075 {
4076 continue;
4077 }
4078 result = Some(layer_result);
4079 }
4080
4081 result
4082 }
4083
4084 /// Find the previous sibling syntax node at the given range.
4085 ///
4086 /// This function locates the syntax node that precedes the node containing
4087 /// the given range. It searches hierarchically by:
4088 /// 1. Finding the node that contains the given range
4089 /// 2. Looking for the previous sibling at the same tree level
4090 /// 3. If no sibling is found, moving up to parent levels and searching for siblings
4091 ///
4092 /// Returns `None` if there is no previous sibling at any ancestor level.
4093 pub fn syntax_prev_sibling<'a, T: ToOffset>(
4094 &'a self,
4095 range: Range<T>,
4096 ) -> Option<tree_sitter::Node<'a>> {
4097 let range = range.start.to_offset(self)..range.end.to_offset(self);
4098 let mut result: Option<tree_sitter::Node<'a>> = None;
4099
4100 for layer in self
4101 .syntax
4102 .layers_for_range(range.clone(), &self.text, true)
4103 {
4104 let mut cursor = layer.node().walk();
4105
4106 // Find the node that contains the range
4107 if !Self::goto_node_enclosing_range(&mut cursor, &range, false) {
4108 continue;
4109 }
4110
4111 // Look for the previous sibling, moving up ancestor levels if needed
4112 loop {
4113 if cursor.goto_previous_sibling() {
4114 let layer_result = cursor.node();
4115
4116 if let Some(previous_result) = &result {
4117 if previous_result.byte_range().end < layer_result.byte_range().end {
4118 continue;
4119 }
4120 }
4121 result = Some(layer_result);
4122 break;
4123 }
4124
4125 // No sibling found at this level, try moving up to parent
4126 if !cursor.goto_parent() {
4127 break;
4128 }
4129 }
4130 }
4131
4132 result
4133 }
4134
4135 /// Find the next sibling syntax node at the given range.
4136 ///
4137 /// This function locates the syntax node that follows the node containing
4138 /// the given range. It searches hierarchically by:
4139 /// 1. Finding the node that contains the given range
4140 /// 2. Looking for the next sibling at the same tree level
4141 /// 3. If no sibling is found, moving up to parent levels and searching for siblings
4142 ///
4143 /// Returns `None` if there is no next sibling at any ancestor level.
4144 pub fn syntax_next_sibling<'a, T: ToOffset>(
4145 &'a self,
4146 range: Range<T>,
4147 ) -> Option<tree_sitter::Node<'a>> {
4148 let range = range.start.to_offset(self)..range.end.to_offset(self);
4149 let mut result: Option<tree_sitter::Node<'a>> = None;
4150
4151 for layer in self
4152 .syntax
4153 .layers_for_range(range.clone(), &self.text, true)
4154 {
4155 let mut cursor = layer.node().walk();
4156
4157 // Find the node that contains the range
4158 if !Self::goto_node_enclosing_range(&mut cursor, &range, false) {
4159 continue;
4160 }
4161
4162 // Look for the next sibling, moving up ancestor levels if needed
4163 loop {
4164 if cursor.goto_next_sibling() {
4165 let layer_result = cursor.node();
4166
4167 if let Some(previous_result) = &result {
4168 if previous_result.byte_range().start > layer_result.byte_range().start {
4169 continue;
4170 }
4171 }
4172 result = Some(layer_result);
4173 break;
4174 }
4175
4176 // No sibling found at this level, try moving up to parent
4177 if !cursor.goto_parent() {
4178 break;
4179 }
4180 }
4181 }
4182
4183 result
4184 }
4185
4186 /// Returns the root syntax node within the given row
4187 pub fn syntax_root_ancestor(&self, position: Anchor) -> Option<tree_sitter::Node<'_>> {
4188 let start_offset = position.to_offset(self);
4189
4190 let row = self.summary_for_anchor::<text::PointUtf16>(&position).row as usize;
4191
4192 let layer = self
4193 .syntax
4194 .layers_for_range(start_offset..start_offset, &self.text, true)
4195 .next()?;
4196
4197 let mut cursor = layer.node().walk();
4198
4199 // Descend to the first leaf that touches the start of the range.
4200 while cursor.goto_first_child_for_byte(start_offset).is_some() {
4201 if cursor.node().end_byte() == start_offset {
4202 cursor.goto_next_sibling();
4203 }
4204 }
4205
4206 // Ascend to the root node within the same row.
4207 while cursor.goto_parent() {
4208 if cursor.node().start_position().row != row {
4209 break;
4210 }
4211 }
4212
4213 Some(cursor.node())
4214 }
4215
4216 /// Returns the outline for the buffer.
4217 ///
4218 /// This method allows passing an optional [`SyntaxTheme`] to
4219 /// syntax-highlight the returned symbols.
4220 pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Outline<Anchor> {
4221 Outline::new(self.outline_items_containing(0..self.len(), true, theme))
4222 }
4223
4224 /// Returns all the symbols that contain the given position.
4225 ///
4226 /// This method allows passing an optional [`SyntaxTheme`] to
4227 /// syntax-highlight the returned symbols.
4228 pub fn symbols_containing<T: ToOffset>(
4229 &self,
4230 position: T,
4231 theme: Option<&SyntaxTheme>,
4232 ) -> Vec<OutlineItem<Anchor>> {
4233 let position = position.to_offset(self);
4234 let start = self.clip_offset(position.saturating_sub(1), Bias::Left);
4235 let end = self.clip_offset(position + 1, Bias::Right);
4236 let mut items = self.outline_items_containing(start..end, false, theme);
4237 let mut prev_depth = None;
4238 items.retain(|item| {
4239 let result = prev_depth.is_none_or(|prev_depth| item.depth > prev_depth);
4240 prev_depth = Some(item.depth);
4241 result
4242 });
4243 items
4244 }
4245
4246 pub fn outline_range_containing<T: ToOffset>(&self, range: Range<T>) -> Option<Range<Point>> {
4247 let range = range.to_offset(self);
4248 let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
4249 grammar.outline_config.as_ref().map(|c| &c.query)
4250 });
4251 let configs = matches
4252 .grammars()
4253 .iter()
4254 .map(|g| g.outline_config.as_ref().unwrap())
4255 .collect::<Vec<_>>();
4256
4257 while let Some(mat) = matches.peek() {
4258 let config = &configs[mat.grammar_index];
4259 let containing_item_node = maybe!({
4260 let item_node = mat.captures.iter().find_map(|cap| {
4261 if cap.index == config.item_capture_ix {
4262 Some(cap.node)
4263 } else {
4264 None
4265 }
4266 })?;
4267
4268 let item_byte_range = item_node.byte_range();
4269 if item_byte_range.end < range.start || item_byte_range.start > range.end {
4270 None
4271 } else {
4272 Some(item_node)
4273 }
4274 });
4275
4276 if let Some(item_node) = containing_item_node {
4277 return Some(
4278 Point::from_ts_point(item_node.start_position())
4279 ..Point::from_ts_point(item_node.end_position()),
4280 );
4281 }
4282
4283 matches.advance();
4284 }
4285 None
4286 }
4287
4288 pub fn outline_items_containing<T: ToOffset>(
4289 &self,
4290 range: Range<T>,
4291 include_extra_context: bool,
4292 theme: Option<&SyntaxTheme>,
4293 ) -> Vec<OutlineItem<Anchor>> {
4294 self.outline_items_containing_internal(
4295 range,
4296 include_extra_context,
4297 theme,
4298 |this, range| this.anchor_after(range.start)..this.anchor_before(range.end),
4299 )
4300 }
4301
4302 pub fn outline_items_as_points_containing<T: ToOffset>(
4303 &self,
4304 range: Range<T>,
4305 include_extra_context: bool,
4306 theme: Option<&SyntaxTheme>,
4307 ) -> Vec<OutlineItem<Point>> {
4308 self.outline_items_containing_internal(range, include_extra_context, theme, |_, range| {
4309 range
4310 })
4311 }
4312
4313 pub fn outline_items_as_offsets_containing<T: ToOffset>(
4314 &self,
4315 range: Range<T>,
4316 include_extra_context: bool,
4317 theme: Option<&SyntaxTheme>,
4318 ) -> Vec<OutlineItem<usize>> {
4319 self.outline_items_containing_internal(
4320 range,
4321 include_extra_context,
4322 theme,
4323 |buffer, range| range.to_offset(buffer),
4324 )
4325 }
4326
4327 fn outline_items_containing_internal<T: ToOffset, U>(
4328 &self,
4329 range: Range<T>,
4330 include_extra_context: bool,
4331 theme: Option<&SyntaxTheme>,
4332 range_callback: fn(&Self, Range<Point>) -> Range<U>,
4333 ) -> Vec<OutlineItem<U>> {
4334 let range = range.to_offset(self);
4335 let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
4336 grammar.outline_config.as_ref().map(|c| &c.query)
4337 });
4338
4339 let mut items = Vec::new();
4340 let mut annotation_row_ranges: Vec<Range<u32>> = Vec::new();
4341 while let Some(mat) = matches.peek() {
4342 let config = matches.grammars()[mat.grammar_index]
4343 .outline_config
4344 .as_ref()
4345 .unwrap();
4346 if let Some(item) =
4347 self.next_outline_item(config, &mat, &range, include_extra_context, theme)
4348 {
4349 items.push(item);
4350 } else if let Some(capture) = mat
4351 .captures
4352 .iter()
4353 .find(|capture| Some(capture.index) == config.annotation_capture_ix)
4354 {
4355 let capture_range = capture.node.start_position()..capture.node.end_position();
4356 let mut capture_row_range =
4357 capture_range.start.row as u32..capture_range.end.row as u32;
4358 if capture_range.end.row > capture_range.start.row && capture_range.end.column == 0
4359 {
4360 capture_row_range.end -= 1;
4361 }
4362 if let Some(last_row_range) = annotation_row_ranges.last_mut() {
4363 if last_row_range.end >= capture_row_range.start.saturating_sub(1) {
4364 last_row_range.end = capture_row_range.end;
4365 } else {
4366 annotation_row_ranges.push(capture_row_range);
4367 }
4368 } else {
4369 annotation_row_ranges.push(capture_row_range);
4370 }
4371 }
4372 matches.advance();
4373 }
4374
4375 items.sort_by_key(|item| (item.range.start, Reverse(item.range.end)));
4376
4377 // Assign depths based on containment relationships and convert to anchors.
4378 let mut item_ends_stack = Vec::<Point>::new();
4379 let mut anchor_items = Vec::new();
4380 let mut annotation_row_ranges = annotation_row_ranges.into_iter().peekable();
4381 for item in items {
4382 while let Some(last_end) = item_ends_stack.last().copied() {
4383 if last_end < item.range.end {
4384 item_ends_stack.pop();
4385 } else {
4386 break;
4387 }
4388 }
4389
4390 let mut annotation_row_range = None;
4391 while let Some(next_annotation_row_range) = annotation_row_ranges.peek() {
4392 let row_preceding_item = item.range.start.row.saturating_sub(1);
4393 if next_annotation_row_range.end < row_preceding_item {
4394 annotation_row_ranges.next();
4395 } else {
4396 if next_annotation_row_range.end == row_preceding_item {
4397 annotation_row_range = Some(next_annotation_row_range.clone());
4398 annotation_row_ranges.next();
4399 }
4400 break;
4401 }
4402 }
4403
4404 anchor_items.push(OutlineItem {
4405 depth: item_ends_stack.len(),
4406 range: range_callback(self, item.range.clone()),
4407 source_range_for_text: range_callback(self, item.source_range_for_text.clone()),
4408 text: item.text,
4409 highlight_ranges: item.highlight_ranges,
4410 name_ranges: item.name_ranges,
4411 body_range: item.body_range.map(|r| range_callback(self, r)),
4412 annotation_range: annotation_row_range.map(|annotation_range| {
4413 let point_range = Point::new(annotation_range.start, 0)
4414 ..Point::new(annotation_range.end, self.line_len(annotation_range.end));
4415 range_callback(self, point_range)
4416 }),
4417 });
4418 item_ends_stack.push(item.range.end);
4419 }
4420
4421 anchor_items
4422 }
4423
4424 fn next_outline_item(
4425 &self,
4426 config: &OutlineConfig,
4427 mat: &SyntaxMapMatch,
4428 range: &Range<usize>,
4429 include_extra_context: bool,
4430 theme: Option<&SyntaxTheme>,
4431 ) -> Option<OutlineItem<Point>> {
4432 let item_node = mat.captures.iter().find_map(|cap| {
4433 if cap.index == config.item_capture_ix {
4434 Some(cap.node)
4435 } else {
4436 None
4437 }
4438 })?;
4439
4440 let item_byte_range = item_node.byte_range();
4441 if item_byte_range.end < range.start || item_byte_range.start > range.end {
4442 return None;
4443 }
4444 let item_point_range = Point::from_ts_point(item_node.start_position())
4445 ..Point::from_ts_point(item_node.end_position());
4446
4447 let mut open_point = None;
4448 let mut close_point = None;
4449
4450 let mut buffer_ranges = Vec::new();
4451 let mut add_to_buffer_ranges = |node: tree_sitter::Node, node_is_name| {
4452 let mut range = node.start_byte()..node.end_byte();
4453 let start = node.start_position();
4454 if node.end_position().row > start.row {
4455 range.end = range.start + self.line_len(start.row as u32) as usize - start.column;
4456 }
4457
4458 if !range.is_empty() {
4459 buffer_ranges.push((range, node_is_name));
4460 }
4461 };
4462
4463 for capture in mat.captures {
4464 if capture.index == config.name_capture_ix {
4465 add_to_buffer_ranges(capture.node, true);
4466 } else if Some(capture.index) == config.context_capture_ix
4467 || (Some(capture.index) == config.extra_context_capture_ix && include_extra_context)
4468 {
4469 add_to_buffer_ranges(capture.node, false);
4470 } else {
4471 if Some(capture.index) == config.open_capture_ix {
4472 open_point = Some(Point::from_ts_point(capture.node.end_position()));
4473 } else if Some(capture.index) == config.close_capture_ix {
4474 close_point = Some(Point::from_ts_point(capture.node.start_position()));
4475 }
4476 }
4477 }
4478
4479 if buffer_ranges.is_empty() {
4480 return None;
4481 }
4482 let source_range_for_text =
4483 buffer_ranges.first().unwrap().0.start..buffer_ranges.last().unwrap().0.end;
4484
4485 let mut text = String::new();
4486 let mut highlight_ranges = Vec::new();
4487 let mut name_ranges = Vec::new();
4488 let mut chunks = self.chunks(
4489 source_range_for_text.clone(),
4490 LanguageAwareStyling {
4491 tree_sitter: true,
4492 diagnostics: true,
4493 },
4494 );
4495 let mut last_buffer_range_end = 0;
4496 for (buffer_range, is_name) in buffer_ranges {
4497 let space_added = !text.is_empty() && buffer_range.start > last_buffer_range_end;
4498 if space_added {
4499 text.push(' ');
4500 }
4501 let before_append_len = text.len();
4502 let mut offset = buffer_range.start;
4503 chunks.seek(buffer_range.clone());
4504 for mut chunk in chunks.by_ref() {
4505 if chunk.text.len() > buffer_range.end - offset {
4506 chunk.text = &chunk.text[0..(buffer_range.end - offset)];
4507 offset = buffer_range.end;
4508 } else {
4509 offset += chunk.text.len();
4510 }
4511 let style = chunk
4512 .syntax_highlight_id
4513 .zip(theme)
4514 .and_then(|(highlight, theme)| theme.get(highlight).cloned());
4515
4516 if let Some(style) = style {
4517 let start = text.len();
4518 let end = start + chunk.text.len();
4519 highlight_ranges.push((start..end, style));
4520 }
4521 text.push_str(chunk.text);
4522 if offset >= buffer_range.end {
4523 break;
4524 }
4525 }
4526 if is_name {
4527 let after_append_len = text.len();
4528 let start = if space_added && !name_ranges.is_empty() {
4529 before_append_len - 1
4530 } else {
4531 before_append_len
4532 };
4533 name_ranges.push(start..after_append_len);
4534 }
4535 last_buffer_range_end = buffer_range.end;
4536 }
4537
4538 Some(OutlineItem {
4539 depth: 0, // We'll calculate the depth later
4540 range: item_point_range,
4541 source_range_for_text: source_range_for_text.to_point(self),
4542 text,
4543 highlight_ranges,
4544 name_ranges,
4545 body_range: open_point.zip(close_point).map(|(start, end)| start..end),
4546 annotation_range: None,
4547 })
4548 }
4549
4550 pub fn function_body_fold_ranges<T: ToOffset>(
4551 &self,
4552 within: Range<T>,
4553 ) -> impl Iterator<Item = Range<usize>> + '_ {
4554 self.text_object_ranges(within, TreeSitterOptions::default())
4555 .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
4556 }
4557
4558 /// For each grammar in the language, runs the provided
4559 /// [`tree_sitter::Query`] against the given range.
4560 pub fn matches(
4561 &self,
4562 range: Range<usize>,
4563 query: fn(&Grammar) -> Option<&tree_sitter::Query>,
4564 ) -> SyntaxMapMatches<'_> {
4565 self.syntax.matches(range, self, query)
4566 }
4567
4568 /// Finds all [`RowChunks`] applicable to the given range, then returns all bracket pairs that intersect with those chunks.
4569 /// Hence, may return more bracket pairs than the range contains.
4570 ///
4571 /// Will omit known chunks.
4572 /// The resulting bracket match collections are not ordered.
4573 pub fn fetch_bracket_ranges(
4574 &self,
4575 range: Range<usize>,
4576 known_chunks: Option<&HashSet<Range<BufferRow>>>,
4577 ) -> HashMap<Range<BufferRow>, Vec<BracketMatch<usize>>> {
4578 let mut all_bracket_matches = HashMap::default();
4579
4580 for chunk in self
4581 .tree_sitter_data
4582 .chunks
4583 .applicable_chunks(&[range.to_point(self)])
4584 {
4585 if known_chunks.is_some_and(|chunks| chunks.contains(&chunk.row_range())) {
4586 continue;
4587 }
4588 let chunk_range = chunk.anchor_range();
4589 let chunk_range = chunk_range.to_offset(&self);
4590
4591 if let Some(cached_brackets) =
4592 &self.tree_sitter_data.brackets_by_chunks.lock()[chunk.id]
4593 {
4594 all_bracket_matches.insert(chunk.row_range(), cached_brackets.clone());
4595 continue;
4596 }
4597
4598 let mut all_brackets: Vec<(BracketMatch<usize>, usize, bool)> = Vec::new();
4599 let mut opens = Vec::new();
4600 let mut color_pairs = Vec::new();
4601
4602 let mut matches = self.syntax.matches_with_options(
4603 chunk_range.clone(),
4604 &self.text,
4605 TreeSitterOptions {
4606 max_bytes_to_query: Some(MAX_BYTES_TO_QUERY),
4607 max_start_depth: None,
4608 },
4609 |grammar| grammar.brackets_config.as_ref().map(|c| &c.query),
4610 );
4611 let configs = matches
4612 .grammars()
4613 .iter()
4614 .map(|grammar| grammar.brackets_config.as_ref().unwrap())
4615 .collect::<Vec<_>>();
4616
4617 // Group matches by open range so we can either trust grammar output
4618 // or repair it by picking a single closest close per open.
4619 let mut open_to_close_ranges = BTreeMap::new();
4620 while let Some(mat) = matches.peek() {
4621 let mut open = None;
4622 let mut close = None;
4623 let syntax_layer_depth = mat.depth;
4624 let pattern_index = mat.pattern_index;
4625 let config = configs[mat.grammar_index];
4626 let pattern = &config.patterns[pattern_index];
4627 for capture in mat.captures {
4628 if capture.index == config.open_capture_ix {
4629 open = Some(capture.node.byte_range());
4630 } else if capture.index == config.close_capture_ix {
4631 close = Some(capture.node.byte_range());
4632 }
4633 }
4634
4635 matches.advance();
4636
4637 let Some((open_range, close_range)) = open.zip(close) else {
4638 continue;
4639 };
4640
4641 let bracket_range = open_range.start..=close_range.end;
4642 if !bracket_range.overlaps(&chunk_range) {
4643 continue;
4644 }
4645
4646 open_to_close_ranges
4647 .entry((open_range.start, open_range.end, pattern_index))
4648 .or_insert_with(BTreeMap::new)
4649 .insert(
4650 (close_range.start, close_range.end),
4651 BracketMatch {
4652 open_range: open_range.clone(),
4653 close_range: close_range.clone(),
4654 syntax_layer_depth,
4655 newline_only: pattern.newline_only,
4656 color_index: None,
4657 },
4658 );
4659
4660 all_brackets.push((
4661 BracketMatch {
4662 open_range,
4663 close_range,
4664 syntax_layer_depth,
4665 newline_only: pattern.newline_only,
4666 color_index: None,
4667 },
4668 pattern_index,
4669 pattern.rainbow_exclude,
4670 ));
4671 }
4672
4673 let has_bogus_matches = open_to_close_ranges
4674 .iter()
4675 .any(|(_, end_ranges)| end_ranges.len() > 1);
4676 if has_bogus_matches {
4677 // Grammar is producing bogus matches where one open is paired with multiple
4678 // closes. Build a valid stack by walking through positions in order.
4679 // For each close, we know the expected open_len from tree-sitter matches.
4680
4681 // Map each close to its expected open length (for inferring opens)
4682 let close_to_open_len: HashMap<(usize, usize, usize), usize> = all_brackets
4683 .iter()
4684 .map(|(bracket_match, pattern_index, _)| {
4685 (
4686 (
4687 bracket_match.close_range.start,
4688 bracket_match.close_range.end,
4689 *pattern_index,
4690 ),
4691 bracket_match.open_range.len(),
4692 )
4693 })
4694 .collect();
4695
4696 // Collect unique opens and closes within this chunk
4697 let mut unique_opens: HashSet<(usize, usize, usize)> = all_brackets
4698 .iter()
4699 .map(|(bracket_match, pattern_index, _)| {
4700 (
4701 bracket_match.open_range.start,
4702 bracket_match.open_range.end,
4703 *pattern_index,
4704 )
4705 })
4706 .filter(|(start, _, _)| chunk_range.contains(start))
4707 .collect();
4708
4709 let mut unique_closes: Vec<(usize, usize, usize)> = all_brackets
4710 .iter()
4711 .map(|(bracket_match, pattern_index, _)| {
4712 (
4713 bracket_match.close_range.start,
4714 bracket_match.close_range.end,
4715 *pattern_index,
4716 )
4717 })
4718 .filter(|(start, _, _)| chunk_range.contains(start))
4719 .collect();
4720 unique_closes.sort();
4721 unique_closes.dedup();
4722
4723 // Build valid pairs by walking through closes in order
4724 let mut unique_opens_vec: Vec<_> = unique_opens.iter().copied().collect();
4725 unique_opens_vec.sort();
4726
4727 let mut valid_pairs: HashSet<((usize, usize, usize), (usize, usize, usize))> =
4728 HashSet::default();
4729 let mut open_stacks: HashMap<usize, Vec<(usize, usize)>> = HashMap::default();
4730 let mut open_idx = 0;
4731
4732 for close in &unique_closes {
4733 // Push all opens before this close onto stack
4734 while open_idx < unique_opens_vec.len()
4735 && unique_opens_vec[open_idx].0 < close.0
4736 {
4737 let (start, end, pattern_index) = unique_opens_vec[open_idx];
4738 open_stacks
4739 .entry(pattern_index)
4740 .or_default()
4741 .push((start, end));
4742 open_idx += 1;
4743 }
4744
4745 // Try to match with most recent open
4746 let (close_start, close_end, pattern_index) = *close;
4747 if let Some(open) = open_stacks
4748 .get_mut(&pattern_index)
4749 .and_then(|open_stack| open_stack.pop())
4750 {
4751 valid_pairs.insert(((open.0, open.1, pattern_index), *close));
4752 } else if let Some(&open_len) = close_to_open_len.get(close) {
4753 // No open on stack - infer one based on expected open_len
4754 if close_start >= open_len {
4755 let inferred = (close_start - open_len, close_start, pattern_index);
4756 unique_opens.insert(inferred);
4757 valid_pairs.insert((inferred, *close));
4758 all_brackets.push((
4759 BracketMatch {
4760 open_range: inferred.0..inferred.1,
4761 close_range: close_start..close_end,
4762 newline_only: false,
4763 syntax_layer_depth: 0,
4764 color_index: None,
4765 },
4766 pattern_index,
4767 false,
4768 ));
4769 }
4770 }
4771 }
4772
4773 all_brackets.retain(|(bracket_match, pattern_index, _)| {
4774 let open = (
4775 bracket_match.open_range.start,
4776 bracket_match.open_range.end,
4777 *pattern_index,
4778 );
4779 let close = (
4780 bracket_match.close_range.start,
4781 bracket_match.close_range.end,
4782 *pattern_index,
4783 );
4784 valid_pairs.contains(&(open, close))
4785 });
4786 }
4787
4788 let mut all_brackets = all_brackets
4789 .into_iter()
4790 .enumerate()
4791 .map(|(index, (bracket_match, _, rainbow_exclude))| {
4792 // Certain languages have "brackets" that are not brackets, e.g. tags. and such
4793 // bracket will match the entire tag with all text inside.
4794 // For now, avoid highlighting any pair that has more than single char in each bracket.
4795 // We need to colorize `<Element/>` bracket pairs, so cannot make this check stricter.
4796 let should_color = !rainbow_exclude
4797 && (bracket_match.open_range.len() == 1
4798 || bracket_match.close_range.len() == 1);
4799 if should_color {
4800 opens.push(bracket_match.open_range.clone());
4801 color_pairs.push((
4802 bracket_match.open_range.clone(),
4803 bracket_match.close_range.clone(),
4804 index,
4805 ));
4806 }
4807 bracket_match
4808 })
4809 .collect::<Vec<_>>();
4810
4811 opens.sort_by_key(|r| (r.start, r.end));
4812 opens.dedup_by(|a, b| a.start == b.start && a.end == b.end);
4813 color_pairs.sort_by_key(|(_, close, _)| close.end);
4814
4815 let mut open_stack = Vec::new();
4816 let mut open_index = 0;
4817 for (open, close, index) in color_pairs {
4818 while open_index < opens.len() && opens[open_index].start < close.start {
4819 open_stack.push(opens[open_index].clone());
4820 open_index += 1;
4821 }
4822
4823 if open_stack.last() == Some(&open) {
4824 let depth_index = open_stack.len() - 1;
4825 all_brackets[index].color_index = Some(depth_index);
4826 open_stack.pop();
4827 }
4828 }
4829
4830 all_brackets.sort_by_key(|bracket_match| {
4831 (bracket_match.open_range.start, bracket_match.open_range.end)
4832 });
4833
4834 if let empty_slot @ None =
4835 &mut self.tree_sitter_data.brackets_by_chunks.lock()[chunk.id]
4836 {
4837 *empty_slot = Some(all_brackets.clone());
4838 }
4839 all_bracket_matches.insert(chunk.row_range(), all_brackets);
4840 }
4841
4842 all_bracket_matches
4843 }
4844
4845 pub fn all_bracket_ranges(
4846 &self,
4847 range: Range<usize>,
4848 ) -> impl Iterator<Item = BracketMatch<usize>> {
4849 self.fetch_bracket_ranges(range.clone(), None)
4850 .into_values()
4851 .flatten()
4852 .filter(move |bracket_match| {
4853 let bracket_range = bracket_match.open_range.start..bracket_match.close_range.end;
4854 bracket_range.overlaps(&range)
4855 })
4856 }
4857
4858 /// Returns bracket range pairs overlapping or adjacent to `range`
4859 pub fn bracket_ranges<T: ToOffset>(
4860 &self,
4861 range: Range<T>,
4862 ) -> impl Iterator<Item = BracketMatch<usize>> + '_ {
4863 // Find bracket pairs that *inclusively* contain the given range.
4864 let range = range.start.to_previous_offset(self)..range.end.to_next_offset(self);
4865 self.all_bracket_ranges(range)
4866 .filter(|pair| !pair.newline_only)
4867 }
4868
4869 pub fn debug_variables_query<T: ToOffset>(
4870 &self,
4871 range: Range<T>,
4872 ) -> impl Iterator<Item = (Range<usize>, DebuggerTextObject)> + '_ {
4873 let range = range.start.to_previous_offset(self)..range.end.to_next_offset(self);
4874
4875 let mut matches = self.syntax.matches_with_options(
4876 range.clone(),
4877 &self.text,
4878 TreeSitterOptions::default(),
4879 |grammar| grammar.debug_variables_config.as_ref().map(|c| &c.query),
4880 );
4881
4882 let configs = matches
4883 .grammars()
4884 .iter()
4885 .map(|grammar| grammar.debug_variables_config.as_ref())
4886 .collect::<Vec<_>>();
4887
4888 let mut captures = Vec::<(Range<usize>, DebuggerTextObject)>::new();
4889
4890 iter::from_fn(move || {
4891 loop {
4892 while let Some(capture) = captures.pop() {
4893 if capture.0.overlaps(&range) {
4894 return Some(capture);
4895 }
4896 }
4897
4898 let mat = matches.peek()?;
4899
4900 let Some(config) = configs[mat.grammar_index].as_ref() else {
4901 matches.advance();
4902 continue;
4903 };
4904
4905 for capture in mat.captures {
4906 let Some(ix) = config
4907 .objects_by_capture_ix
4908 .binary_search_by_key(&capture.index, |e| e.0)
4909 .ok()
4910 else {
4911 continue;
4912 };
4913 let text_object = config.objects_by_capture_ix[ix].1;
4914 let byte_range = capture.node.byte_range();
4915
4916 let mut found = false;
4917 for (range, existing) in captures.iter_mut() {
4918 if existing == &text_object {
4919 range.start = range.start.min(byte_range.start);
4920 range.end = range.end.max(byte_range.end);
4921 found = true;
4922 break;
4923 }
4924 }
4925
4926 if !found {
4927 captures.push((byte_range, text_object));
4928 }
4929 }
4930
4931 matches.advance();
4932 }
4933 })
4934 }
4935
4936 pub fn text_object_ranges<T: ToOffset>(
4937 &self,
4938 range: Range<T>,
4939 options: TreeSitterOptions,
4940 ) -> impl Iterator<Item = (Range<usize>, TextObject)> + '_ {
4941 let range =
4942 range.start.to_previous_offset(self)..self.len().min(range.end.to_next_offset(self));
4943
4944 let mut matches =
4945 self.syntax
4946 .matches_with_options(range.clone(), &self.text, options, |grammar| {
4947 grammar.text_object_config.as_ref().map(|c| &c.query)
4948 });
4949
4950 let configs = matches
4951 .grammars()
4952 .iter()
4953 .map(|grammar| grammar.text_object_config.as_ref())
4954 .collect::<Vec<_>>();
4955
4956 let mut captures = Vec::<(Range<usize>, TextObject)>::new();
4957
4958 iter::from_fn(move || {
4959 loop {
4960 while let Some(capture) = captures.pop() {
4961 if capture.0.overlaps(&range) {
4962 return Some(capture);
4963 }
4964 }
4965
4966 let mat = matches.peek()?;
4967
4968 let Some(config) = configs[mat.grammar_index].as_ref() else {
4969 matches.advance();
4970 continue;
4971 };
4972
4973 for capture in mat.captures {
4974 let Some(ix) = config
4975 .text_objects_by_capture_ix
4976 .binary_search_by_key(&capture.index, |e| e.0)
4977 .ok()
4978 else {
4979 continue;
4980 };
4981 let text_object = config.text_objects_by_capture_ix[ix].1;
4982 let byte_range = capture.node.byte_range();
4983
4984 let mut found = false;
4985 for (range, existing) in captures.iter_mut() {
4986 if existing == &text_object {
4987 range.start = range.start.min(byte_range.start);
4988 range.end = range.end.max(byte_range.end);
4989 found = true;
4990 break;
4991 }
4992 }
4993
4994 if !found {
4995 captures.push((byte_range, text_object));
4996 }
4997 }
4998
4999 matches.advance();
5000 }
5001 })
5002 }
5003
5004 /// Returns enclosing bracket ranges containing the given range
5005 pub fn enclosing_bracket_ranges<T: ToOffset>(
5006 &self,
5007 range: Range<T>,
5008 ) -> impl Iterator<Item = BracketMatch<usize>> + '_ {
5009 let range = range.start.to_offset(self)..range.end.to_offset(self);
5010
5011 let result: Vec<_> = self.bracket_ranges(range.clone()).collect();
5012 let max_depth = result
5013 .iter()
5014 .map(|mat| mat.syntax_layer_depth)
5015 .max()
5016 .unwrap_or(0);
5017 result.into_iter().filter(move |pair| {
5018 pair.open_range.start <= range.start
5019 && pair.close_range.end >= range.end
5020 && pair.syntax_layer_depth == max_depth
5021 })
5022 }
5023
5024 /// Returns the smallest enclosing bracket ranges containing the given range or None if no brackets contain range
5025 ///
5026 /// Can optionally pass a range_filter to filter the ranges of brackets to consider
5027 pub fn innermost_enclosing_bracket_ranges<T: ToOffset>(
5028 &self,
5029 range: Range<T>,
5030 range_filter: Option<&dyn Fn(Range<usize>, Range<usize>) -> bool>,
5031 ) -> Option<(Range<usize>, Range<usize>)> {
5032 let range = range.start.to_offset(self)..range.end.to_offset(self);
5033
5034 // Get the ranges of the innermost pair of brackets.
5035 let mut result: Option<(Range<usize>, Range<usize>)> = None;
5036
5037 for pair in self.enclosing_bracket_ranges(range) {
5038 if let Some(range_filter) = range_filter
5039 && !range_filter(pair.open_range.clone(), pair.close_range.clone())
5040 {
5041 continue;
5042 }
5043
5044 let len = pair.close_range.end - pair.open_range.start;
5045
5046 if let Some((existing_open, existing_close)) = &result {
5047 let existing_len = existing_close.end - existing_open.start;
5048 if len > existing_len {
5049 continue;
5050 }
5051 }
5052
5053 result = Some((pair.open_range, pair.close_range));
5054 }
5055
5056 result
5057 }
5058
5059 /// Returns anchor ranges for any matches of the redaction query.
5060 /// The buffer can be associated with multiple languages, and the redaction query associated with each
5061 /// will be run on the relevant section of the buffer.
5062 pub fn redacted_ranges<T: ToOffset>(
5063 &self,
5064 range: Range<T>,
5065 ) -> impl Iterator<Item = Range<usize>> + '_ {
5066 let offset_range = range.start.to_offset(self)..range.end.to_offset(self);
5067 let mut syntax_matches = self.syntax.matches(offset_range, self, |grammar| {
5068 grammar
5069 .redactions_config
5070 .as_ref()
5071 .map(|config| &config.query)
5072 });
5073
5074 let configs = syntax_matches
5075 .grammars()
5076 .iter()
5077 .map(|grammar| grammar.redactions_config.as_ref())
5078 .collect::<Vec<_>>();
5079
5080 iter::from_fn(move || {
5081 let redacted_range = syntax_matches
5082 .peek()
5083 .and_then(|mat| {
5084 configs[mat.grammar_index].and_then(|config| {
5085 mat.captures
5086 .iter()
5087 .find(|capture| capture.index == config.redaction_capture_ix)
5088 })
5089 })
5090 .map(|mat| mat.node.byte_range());
5091 syntax_matches.advance();
5092 redacted_range
5093 })
5094 }
5095
5096 pub fn injections_intersecting_range<T: ToOffset>(
5097 &self,
5098 range: Range<T>,
5099 ) -> impl Iterator<Item = (Range<usize>, &Arc<Language>)> + '_ {
5100 let offset_range = range.start.to_offset(self)..range.end.to_offset(self);
5101
5102 let mut syntax_matches = self.syntax.matches(offset_range, self, |grammar| {
5103 grammar
5104 .injection_config
5105 .as_ref()
5106 .map(|config| &config.query)
5107 });
5108
5109 let configs = syntax_matches
5110 .grammars()
5111 .iter()
5112 .map(|grammar| grammar.injection_config.as_ref())
5113 .collect::<Vec<_>>();
5114
5115 iter::from_fn(move || {
5116 let ranges = syntax_matches.peek().and_then(|mat| {
5117 let config = &configs[mat.grammar_index]?;
5118 let content_capture_range = mat.captures.iter().find_map(|capture| {
5119 if capture.index == config.content_capture_ix {
5120 Some(capture.node.byte_range())
5121 } else {
5122 None
5123 }
5124 })?;
5125 let language = self.language_at(content_capture_range.start)?;
5126 Some((content_capture_range, language))
5127 });
5128 syntax_matches.advance();
5129 ranges
5130 })
5131 }
5132
5133 pub fn runnable_ranges(
5134 &self,
5135 offset_range: Range<usize>,
5136 ) -> impl Iterator<Item = RunnableRange> + '_ {
5137 let mut syntax_matches = self.syntax.matches(offset_range, self, |grammar| {
5138 grammar.runnable_config.as_ref().map(|config| &config.query)
5139 });
5140
5141 let test_configs = syntax_matches
5142 .grammars()
5143 .iter()
5144 .map(|grammar| grammar.runnable_config.as_ref())
5145 .collect::<Vec<_>>();
5146
5147 iter::from_fn(move || {
5148 loop {
5149 let mat = syntax_matches.peek()?;
5150
5151 let test_range = test_configs[mat.grammar_index].and_then(|test_configs| {
5152 let mut run_range = None;
5153 let full_range = mat.captures.iter().fold(
5154 Range {
5155 start: usize::MAX,
5156 end: 0,
5157 },
5158 |mut acc, next| {
5159 let byte_range = next.node.byte_range();
5160 if acc.start > byte_range.start {
5161 acc.start = byte_range.start;
5162 }
5163 if acc.end < byte_range.end {
5164 acc.end = byte_range.end;
5165 }
5166 acc
5167 },
5168 );
5169 if full_range.start > full_range.end {
5170 // We did not find a full spanning range of this match.
5171 return None;
5172 }
5173 let extra_captures: SmallVec<[_; 1]> =
5174 SmallVec::from_iter(mat.captures.iter().filter_map(|capture| {
5175 test_configs
5176 .extra_captures
5177 .get(capture.index as usize)
5178 .cloned()
5179 .and_then(|tag_name| match tag_name {
5180 RunnableCapture::Named(name) => {
5181 Some((capture.node.byte_range(), name))
5182 }
5183 RunnableCapture::Run => {
5184 let _ = run_range.insert(capture.node.byte_range());
5185 None
5186 }
5187 })
5188 }));
5189 let run_range = run_range?;
5190 let tags = test_configs
5191 .query
5192 .property_settings(mat.pattern_index)
5193 .iter()
5194 .filter_map(|property| {
5195 if *property.key == *"tag" {
5196 property
5197 .value
5198 .as_ref()
5199 .map(|value| RunnableTag(value.to_string().into()))
5200 } else {
5201 None
5202 }
5203 })
5204 .collect();
5205 let extra_captures = extra_captures
5206 .into_iter()
5207 .map(|(range, name)| {
5208 (
5209 name.to_string(),
5210 self.text_for_range(range).collect::<String>(),
5211 )
5212 })
5213 .collect();
5214 // All tags should have the same range.
5215 Some(RunnableRange {
5216 run_range,
5217 full_range,
5218 runnable: Runnable {
5219 tags,
5220 language: mat.language,
5221 buffer: self.remote_id(),
5222 },
5223 extra_captures,
5224 buffer_id: self.remote_id(),
5225 })
5226 });
5227
5228 syntax_matches.advance();
5229 if test_range.is_some() {
5230 // It's fine for us to short-circuit on .peek()? returning None. We don't want to return None from this iter if we
5231 // had a capture that did not contain a run marker, hence we'll just loop around for the next capture.
5232 return test_range;
5233 }
5234 }
5235 })
5236 }
5237
5238 /// Returns selections for remote peers intersecting the given range.
5239 #[allow(clippy::type_complexity)]
5240 pub fn selections_in_range(
5241 &self,
5242 range: Range<Anchor>,
5243 include_local: bool,
5244 ) -> impl Iterator<
5245 Item = (
5246 ReplicaId,
5247 bool,
5248 CursorShape,
5249 impl Iterator<Item = &Selection<Anchor>> + '_,
5250 ),
5251 > + '_ {
5252 self.remote_selections
5253 .iter()
5254 .filter(move |(replica_id, set)| {
5255 (include_local || **replica_id != self.text.replica_id())
5256 && !set.selections.is_empty()
5257 })
5258 .map(move |(replica_id, set)| {
5259 let start_ix = match set.selections.binary_search_by(|probe| {
5260 probe.end.cmp(&range.start, self).then(Ordering::Greater)
5261 }) {
5262 Ok(ix) | Err(ix) => ix,
5263 };
5264 let end_ix = match set.selections.binary_search_by(|probe| {
5265 probe.start.cmp(&range.end, self).then(Ordering::Less)
5266 }) {
5267 Ok(ix) | Err(ix) => ix,
5268 };
5269
5270 (
5271 *replica_id,
5272 set.line_mode,
5273 set.cursor_shape,
5274 set.selections[start_ix..end_ix].iter(),
5275 )
5276 })
5277 }
5278
5279 /// Returns if the buffer contains any diagnostics.
5280 pub fn has_diagnostics(&self) -> bool {
5281 !self.diagnostics.is_empty()
5282 }
5283
5284 /// Returns all the diagnostics intersecting the given range.
5285 pub fn diagnostics_in_range<'a, T, O>(
5286 &'a self,
5287 search_range: Range<T>,
5288 reversed: bool,
5289 ) -> impl 'a + Iterator<Item = DiagnosticEntryRef<'a, O>>
5290 where
5291 T: 'a + Clone + ToOffset,
5292 O: 'a + FromAnchor,
5293 {
5294 let mut iterators: Vec<_> = self
5295 .diagnostics
5296 .iter()
5297 .map(|(_, collection)| {
5298 collection
5299 .range::<T, text::Anchor>(search_range.clone(), self, true, reversed)
5300 .peekable()
5301 })
5302 .collect();
5303
5304 std::iter::from_fn(move || {
5305 let (next_ix, _) = iterators
5306 .iter_mut()
5307 .enumerate()
5308 .flat_map(|(ix, iter)| Some((ix, iter.peek()?)))
5309 .min_by(|(_, a), (_, b)| {
5310 let cmp = a
5311 .range
5312 .start
5313 .cmp(&b.range.start, self)
5314 // when range is equal, sort by diagnostic severity
5315 .then(a.diagnostic.severity.cmp(&b.diagnostic.severity))
5316 // and stabilize order with group_id
5317 .then(a.diagnostic.group_id.cmp(&b.diagnostic.group_id));
5318 if reversed { cmp.reverse() } else { cmp }
5319 })?;
5320 iterators[next_ix]
5321 .next()
5322 .map(
5323 |DiagnosticEntryRef { range, diagnostic }| DiagnosticEntryRef {
5324 diagnostic,
5325 range: FromAnchor::from_anchor(&range.start, self)
5326 ..FromAnchor::from_anchor(&range.end, self),
5327 },
5328 )
5329 })
5330 }
5331
5332 /// Returns all the diagnostic groups associated with the given
5333 /// language server ID. If no language server ID is provided,
5334 /// all diagnostics groups are returned.
5335 pub fn diagnostic_groups(
5336 &self,
5337 language_server_id: Option<LanguageServerId>,
5338 ) -> Vec<(LanguageServerId, DiagnosticGroup<'_, Anchor>)> {
5339 let mut groups = Vec::new();
5340
5341 if let Some(language_server_id) = language_server_id {
5342 if let Some(set) = self.diagnostics.get(&language_server_id) {
5343 set.groups(language_server_id, &mut groups, self);
5344 }
5345 } else {
5346 for (language_server_id, diagnostics) in self.diagnostics.iter() {
5347 diagnostics.groups(*language_server_id, &mut groups, self);
5348 }
5349 }
5350
5351 groups.sort_by(|(id_a, group_a), (id_b, group_b)| {
5352 let a_start = &group_a.entries[group_a.primary_ix].range.start;
5353 let b_start = &group_b.entries[group_b.primary_ix].range.start;
5354 a_start.cmp(b_start, self).then_with(|| id_a.cmp(id_b))
5355 });
5356
5357 groups
5358 }
5359
5360 /// Returns an iterator over the diagnostics for the given group.
5361 pub fn diagnostic_group<O>(
5362 &self,
5363 group_id: usize,
5364 ) -> impl Iterator<Item = DiagnosticEntryRef<'_, O>> + use<'_, O>
5365 where
5366 O: FromAnchor + 'static,
5367 {
5368 self.diagnostics
5369 .iter()
5370 .flat_map(move |(_, set)| set.group(group_id, self))
5371 }
5372
5373 /// An integer version number that accounts for all updates besides
5374 /// the buffer's text itself (which is versioned via a version vector).
5375 pub fn non_text_state_update_count(&self) -> usize {
5376 self.non_text_state_update_count
5377 }
5378
5379 /// An integer version that changes when the buffer's syntax changes.
5380 pub fn syntax_update_count(&self) -> usize {
5381 self.syntax.update_count()
5382 }
5383
5384 /// Returns a snapshot of underlying file.
5385 pub fn file(&self) -> Option<&Arc<dyn File>> {
5386 self.file.as_ref()
5387 }
5388
5389 pub fn resolve_file_path(&self, include_root: bool, cx: &App) -> Option<String> {
5390 if let Some(file) = self.file() {
5391 if file.path().file_name().is_none() || include_root {
5392 Some(file.full_path(cx).to_string_lossy().into_owned())
5393 } else {
5394 Some(file.path().display(file.path_style(cx)).to_string())
5395 }
5396 } else {
5397 None
5398 }
5399 }
5400
5401 pub fn words_in_range(&self, query: WordsQuery) -> BTreeMap<String, Range<Anchor>> {
5402 let query_str = query.fuzzy_contents;
5403 if query_str.is_some_and(|query| query.is_empty()) {
5404 return BTreeMap::default();
5405 }
5406
5407 let classifier = CharClassifier::new(self.language.clone().map(|language| LanguageScope {
5408 language,
5409 override_id: None,
5410 }));
5411
5412 let mut query_ix = 0;
5413 let query_chars = query_str.map(|query| query.chars().collect::<Vec<_>>());
5414 let query_len = query_chars.as_ref().map_or(0, |query| query.len());
5415
5416 let mut words = BTreeMap::default();
5417 let mut current_word_start_ix = None;
5418 let mut chunk_ix = query.range.start;
5419 for chunk in self.chunks(
5420 query.range,
5421 LanguageAwareStyling {
5422 tree_sitter: false,
5423 diagnostics: false,
5424 },
5425 ) {
5426 for (i, c) in chunk.text.char_indices() {
5427 let ix = chunk_ix + i;
5428 if classifier.is_word(c) {
5429 if current_word_start_ix.is_none() {
5430 current_word_start_ix = Some(ix);
5431 }
5432
5433 if let Some(query_chars) = &query_chars
5434 && query_ix < query_len
5435 && c.to_lowercase().eq(query_chars[query_ix].to_lowercase())
5436 {
5437 query_ix += 1;
5438 }
5439 continue;
5440 } else if let Some(word_start) = current_word_start_ix.take()
5441 && query_ix == query_len
5442 {
5443 let word_range = self.anchor_before(word_start)..self.anchor_after(ix);
5444 let mut word_text = self.text_for_range(word_start..ix).peekable();
5445 let first_char = word_text
5446 .peek()
5447 .and_then(|first_chunk| first_chunk.chars().next());
5448 // Skip empty and "words" starting with digits as a heuristic to reduce useless completions
5449 if !query.skip_digits
5450 || first_char.is_none_or(|first_char| !first_char.is_digit(10))
5451 {
5452 words.insert(word_text.collect(), word_range);
5453 }
5454 }
5455 query_ix = 0;
5456 }
5457 chunk_ix += chunk.text.len();
5458 }
5459
5460 words
5461 }
5462}
5463
5464/// A configuration to use when producing styled text chunks.
5465#[derive(Clone, Copy)]
5466pub struct LanguageAwareStyling {
5467 /// Whether to highlight text chunks using tree-sitter.
5468 pub tree_sitter: bool,
5469 /// Whether to highlight text chunks based on the diagnostics data.
5470 pub diagnostics: bool,
5471}
5472
5473pub struct WordsQuery<'a> {
5474 /// Only returns words with all chars from the fuzzy string in them.
5475 pub fuzzy_contents: Option<&'a str>,
5476 /// Skips words that start with a digit.
5477 pub skip_digits: bool,
5478 /// Buffer offset range, to look for words.
5479 pub range: Range<usize>,
5480}
5481
5482fn indent_size_for_line(text: &text::BufferSnapshot, row: u32) -> IndentSize {
5483 indent_size_for_text(text.chars_at(Point::new(row, 0)))
5484}
5485
5486fn indent_size_for_text(text: impl Iterator<Item = char>) -> IndentSize {
5487 let mut result = IndentSize::spaces(0);
5488 for c in text {
5489 let kind = match c {
5490 ' ' => IndentKind::Space,
5491 '\t' => IndentKind::Tab,
5492 _ => break,
5493 };
5494 if result.len == 0 {
5495 result.kind = kind;
5496 }
5497 result.len += 1;
5498 }
5499 result
5500}
5501
5502impl Clone for BufferSnapshot {
5503 fn clone(&self) -> Self {
5504 Self {
5505 text: self.text.clone(),
5506 syntax: self.syntax.clone(),
5507 file: self.file.clone(),
5508 remote_selections: self.remote_selections.clone(),
5509 diagnostics: self.diagnostics.clone(),
5510 language: self.language.clone(),
5511 tree_sitter_data: self.tree_sitter_data.clone(),
5512 non_text_state_update_count: self.non_text_state_update_count,
5513 capability: self.capability,
5514 modeline: self.modeline.clone(),
5515 }
5516 }
5517}
5518
5519impl Deref for BufferSnapshot {
5520 type Target = text::BufferSnapshot;
5521
5522 fn deref(&self) -> &Self::Target {
5523 &self.text
5524 }
5525}
5526
5527unsafe impl Send for BufferChunks<'_> {}
5528
5529impl<'a> BufferChunks<'a> {
5530 pub(crate) fn new(
5531 text: &'a Rope,
5532 range: Range<usize>,
5533 syntax: Option<(SyntaxMapCaptures<'a>, Vec<HighlightMap>)>,
5534 diagnostics: bool,
5535 buffer_snapshot: Option<&'a BufferSnapshot>,
5536 ) -> Self {
5537 let mut highlights = None;
5538 if let Some((captures, highlight_maps)) = syntax {
5539 highlights = Some(BufferChunkHighlights {
5540 captures,
5541 next_capture: None,
5542 stack: Default::default(),
5543 highlight_maps,
5544 })
5545 }
5546
5547 let diagnostic_endpoints = diagnostics.then(|| Vec::new().into_iter().peekable());
5548 let chunks = text.chunks_in_range(range.clone());
5549
5550 let mut this = BufferChunks {
5551 range,
5552 buffer_snapshot,
5553 chunks,
5554 diagnostic_endpoints,
5555 error_depth: 0,
5556 warning_depth: 0,
5557 information_depth: 0,
5558 hint_depth: 0,
5559 unnecessary_depth: 0,
5560 underline: true,
5561 highlights,
5562 };
5563 this.initialize_diagnostic_endpoints();
5564 this
5565 }
5566
5567 /// Seeks to the given byte offset in the buffer.
5568 pub fn seek(&mut self, range: Range<usize>) {
5569 let old_range = std::mem::replace(&mut self.range, range.clone());
5570 self.chunks.set_range(self.range.clone());
5571 if let Some(highlights) = self.highlights.as_mut() {
5572 if old_range.start <= self.range.start && old_range.end >= self.range.end {
5573 // Reuse existing highlights stack, as the new range is a subrange of the old one.
5574 highlights
5575 .stack
5576 .retain(|(end_offset, _)| *end_offset > range.start);
5577 if let Some(capture) = &highlights.next_capture
5578 && range.start >= capture.node.start_byte()
5579 {
5580 let next_capture_end = capture.node.end_byte();
5581 if range.start < next_capture_end
5582 && let Some(capture_id) =
5583 highlights.highlight_maps[capture.grammar_index].get(capture.index)
5584 {
5585 highlights.stack.push((next_capture_end, capture_id));
5586 }
5587 highlights.next_capture.take();
5588 }
5589 } else if let Some(snapshot) = self.buffer_snapshot {
5590 let (captures, highlight_maps) = snapshot.get_highlights(self.range.clone());
5591 *highlights = BufferChunkHighlights {
5592 captures,
5593 next_capture: None,
5594 stack: Default::default(),
5595 highlight_maps,
5596 };
5597 } else {
5598 // We cannot obtain new highlights for a language-aware buffer iterator, as we don't have a buffer snapshot.
5599 // Seeking such BufferChunks is not supported.
5600 debug_assert!(
5601 false,
5602 "Attempted to seek on a language-aware buffer iterator without associated buffer snapshot"
5603 );
5604 }
5605
5606 highlights.captures.set_byte_range(self.range.clone());
5607 self.initialize_diagnostic_endpoints();
5608 }
5609 }
5610
5611 fn initialize_diagnostic_endpoints(&mut self) {
5612 if let Some(diagnostics) = self.diagnostic_endpoints.as_mut()
5613 && let Some(buffer) = self.buffer_snapshot
5614 {
5615 let mut diagnostic_endpoints = Vec::new();
5616 for entry in buffer.diagnostics_in_range::<_, usize>(self.range.clone(), false) {
5617 diagnostic_endpoints.push(DiagnosticEndpoint {
5618 offset: entry.range.start,
5619 is_start: true,
5620 severity: entry.diagnostic.severity,
5621 is_unnecessary: entry.diagnostic.is_unnecessary,
5622 underline: entry.diagnostic.underline,
5623 });
5624 diagnostic_endpoints.push(DiagnosticEndpoint {
5625 offset: entry.range.end,
5626 is_start: false,
5627 severity: entry.diagnostic.severity,
5628 is_unnecessary: entry.diagnostic.is_unnecessary,
5629 underline: entry.diagnostic.underline,
5630 });
5631 }
5632 diagnostic_endpoints
5633 .sort_unstable_by_key(|endpoint| (endpoint.offset, !endpoint.is_start));
5634 *diagnostics = diagnostic_endpoints.into_iter().peekable();
5635 self.hint_depth = 0;
5636 self.error_depth = 0;
5637 self.warning_depth = 0;
5638 self.information_depth = 0;
5639 }
5640 }
5641
5642 /// The current byte offset in the buffer.
5643 pub fn offset(&self) -> usize {
5644 self.range.start
5645 }
5646
5647 pub fn range(&self) -> Range<usize> {
5648 self.range.clone()
5649 }
5650
5651 fn update_diagnostic_depths(&mut self, endpoint: DiagnosticEndpoint) {
5652 let depth = match endpoint.severity {
5653 DiagnosticSeverity::ERROR => &mut self.error_depth,
5654 DiagnosticSeverity::WARNING => &mut self.warning_depth,
5655 DiagnosticSeverity::INFORMATION => &mut self.information_depth,
5656 DiagnosticSeverity::HINT => &mut self.hint_depth,
5657 _ => return,
5658 };
5659 if endpoint.is_start {
5660 *depth += 1;
5661 } else {
5662 *depth -= 1;
5663 }
5664
5665 if endpoint.is_unnecessary {
5666 if endpoint.is_start {
5667 self.unnecessary_depth += 1;
5668 } else {
5669 self.unnecessary_depth -= 1;
5670 }
5671 }
5672 }
5673
5674 fn current_diagnostic_severity(&self) -> Option<DiagnosticSeverity> {
5675 if self.error_depth > 0 {
5676 Some(DiagnosticSeverity::ERROR)
5677 } else if self.warning_depth > 0 {
5678 Some(DiagnosticSeverity::WARNING)
5679 } else if self.information_depth > 0 {
5680 Some(DiagnosticSeverity::INFORMATION)
5681 } else if self.hint_depth > 0 {
5682 Some(DiagnosticSeverity::HINT)
5683 } else {
5684 None
5685 }
5686 }
5687
5688 fn current_code_is_unnecessary(&self) -> bool {
5689 self.unnecessary_depth > 0
5690 }
5691}
5692
5693impl<'a> Iterator for BufferChunks<'a> {
5694 type Item = Chunk<'a>;
5695
5696 fn next(&mut self) -> Option<Self::Item> {
5697 let mut next_capture_start = usize::MAX;
5698 let mut next_diagnostic_endpoint = usize::MAX;
5699
5700 if let Some(highlights) = self.highlights.as_mut() {
5701 while let Some((parent_capture_end, _)) = highlights.stack.last() {
5702 if *parent_capture_end <= self.range.start {
5703 highlights.stack.pop();
5704 } else {
5705 break;
5706 }
5707 }
5708
5709 if highlights.next_capture.is_none() {
5710 highlights.next_capture = highlights.captures.next();
5711 }
5712
5713 while let Some(capture) = highlights.next_capture.as_ref() {
5714 if self.range.start < capture.node.start_byte() {
5715 next_capture_start = capture.node.start_byte();
5716 break;
5717 } else {
5718 let highlight_id =
5719 highlights.highlight_maps[capture.grammar_index].get(capture.index);
5720 if let Some(highlight_id) = highlight_id {
5721 highlights
5722 .stack
5723 .push((capture.node.end_byte(), highlight_id));
5724 }
5725 highlights.next_capture = highlights.captures.next();
5726 }
5727 }
5728 }
5729
5730 let mut diagnostic_endpoints = std::mem::take(&mut self.diagnostic_endpoints);
5731 if let Some(diagnostic_endpoints) = diagnostic_endpoints.as_mut() {
5732 while let Some(endpoint) = diagnostic_endpoints.peek().copied() {
5733 if endpoint.offset <= self.range.start {
5734 self.update_diagnostic_depths(endpoint);
5735 diagnostic_endpoints.next();
5736 self.underline = endpoint.underline;
5737 } else {
5738 next_diagnostic_endpoint = endpoint.offset;
5739 break;
5740 }
5741 }
5742 }
5743 self.diagnostic_endpoints = diagnostic_endpoints;
5744
5745 if let Some(ChunkBitmaps {
5746 text: chunk,
5747 chars: chars_map,
5748 tabs,
5749 newlines,
5750 }) = self.chunks.peek_with_bitmaps()
5751 {
5752 let chunk_start = self.range.start;
5753 let mut chunk_end = (self.chunks.offset() + chunk.len())
5754 .min(next_capture_start)
5755 .min(next_diagnostic_endpoint);
5756 let mut highlight_id = None;
5757 if let Some(highlights) = self.highlights.as_ref()
5758 && let Some((parent_capture_end, parent_highlight_id)) = highlights.stack.last()
5759 {
5760 chunk_end = chunk_end.min(*parent_capture_end);
5761 highlight_id = Some(*parent_highlight_id);
5762 }
5763 let bit_start = chunk_start - self.chunks.offset();
5764 let bit_end = chunk_end - self.chunks.offset();
5765
5766 let slice = &chunk[bit_start..bit_end];
5767
5768 let mask = 1u128.unbounded_shl(bit_end as u32).wrapping_sub(1);
5769 let tabs = (tabs >> bit_start) & mask;
5770 let chars = (chars_map >> bit_start) & mask;
5771 let newlines = (newlines >> bit_start) & mask;
5772
5773 self.range.start = chunk_end;
5774 if self.range.start == self.chunks.offset() + chunk.len() {
5775 self.chunks.next().unwrap();
5776 }
5777
5778 Some(Chunk {
5779 text: slice,
5780 syntax_highlight_id: highlight_id,
5781 underline: self.underline,
5782 diagnostic_severity: self.current_diagnostic_severity(),
5783 is_unnecessary: self.current_code_is_unnecessary(),
5784 tabs,
5785 chars,
5786 newlines,
5787 ..Chunk::default()
5788 })
5789 } else {
5790 None
5791 }
5792 }
5793}
5794
5795impl operation_queue::Operation for Operation {
5796 fn lamport_timestamp(&self) -> clock::Lamport {
5797 match self {
5798 Operation::Buffer(_) => {
5799 unreachable!("buffer operations should never be deferred at this layer")
5800 }
5801 Operation::UpdateDiagnostics {
5802 lamport_timestamp, ..
5803 }
5804 | Operation::UpdateSelections {
5805 lamport_timestamp, ..
5806 }
5807 | Operation::UpdateCompletionTriggers {
5808 lamport_timestamp, ..
5809 }
5810 | Operation::UpdateLineEnding {
5811 lamport_timestamp, ..
5812 } => *lamport_timestamp,
5813 }
5814 }
5815}
5816
5817impl IndentSize {
5818 /// Returns an [`IndentSize`] representing the given spaces.
5819 pub fn spaces(len: u32) -> Self {
5820 Self {
5821 len,
5822 kind: IndentKind::Space,
5823 }
5824 }
5825
5826 /// Returns an [`IndentSize`] representing a tab.
5827 pub fn tab() -> Self {
5828 Self {
5829 len: 1,
5830 kind: IndentKind::Tab,
5831 }
5832 }
5833
5834 /// An iterator over the characters represented by this [`IndentSize`].
5835 pub fn chars(&self) -> impl Iterator<Item = char> {
5836 iter::repeat(self.char()).take(self.len as usize)
5837 }
5838
5839 /// The character representation of this [`IndentSize`].
5840 pub fn char(&self) -> char {
5841 match self.kind {
5842 IndentKind::Space => ' ',
5843 IndentKind::Tab => '\t',
5844 }
5845 }
5846
5847 /// Consumes the current [`IndentSize`] and returns a new one that has
5848 /// been shrunk or enlarged by the given size along the given direction.
5849 pub fn with_delta(mut self, direction: Ordering, size: IndentSize) -> Self {
5850 match direction {
5851 Ordering::Less => {
5852 if self.kind == size.kind && self.len >= size.len {
5853 self.len -= size.len;
5854 }
5855 }
5856 Ordering::Equal => {}
5857 Ordering::Greater => {
5858 if self.len == 0 {
5859 self = size;
5860 } else if self.kind == size.kind {
5861 self.len += size.len;
5862 }
5863 }
5864 }
5865 self
5866 }
5867
5868 pub fn len_with_expanded_tabs(&self, tab_size: NonZeroU32) -> usize {
5869 match self.kind {
5870 IndentKind::Space => self.len as usize,
5871 IndentKind::Tab => self.len as usize * tab_size.get() as usize,
5872 }
5873 }
5874}
5875
5876#[cfg(any(test, feature = "test-support"))]
5877pub struct TestFile {
5878 pub path: Arc<RelPath>,
5879 pub root_name: String,
5880 pub local_root: Option<PathBuf>,
5881}
5882
5883#[cfg(any(test, feature = "test-support"))]
5884impl File for TestFile {
5885 fn path(&self) -> &Arc<RelPath> {
5886 &self.path
5887 }
5888
5889 fn full_path(&self, _: &gpui::App) -> PathBuf {
5890 PathBuf::from(self.root_name.clone()).join(self.path.as_std_path())
5891 }
5892
5893 fn as_local(&self) -> Option<&dyn LocalFile> {
5894 if self.local_root.is_some() {
5895 Some(self)
5896 } else {
5897 None
5898 }
5899 }
5900
5901 fn disk_state(&self) -> DiskState {
5902 unimplemented!()
5903 }
5904
5905 fn file_name<'a>(&'a self, _: &'a gpui::App) -> &'a str {
5906 self.path().file_name().unwrap_or(self.root_name.as_ref())
5907 }
5908
5909 fn worktree_id(&self, _: &App) -> WorktreeId {
5910 WorktreeId::from_usize(0)
5911 }
5912
5913 fn to_proto(&self, _: &App) -> rpc::proto::File {
5914 unimplemented!()
5915 }
5916
5917 fn is_private(&self) -> bool {
5918 false
5919 }
5920
5921 fn path_style(&self, _cx: &App) -> PathStyle {
5922 PathStyle::local()
5923 }
5924}
5925
5926#[cfg(any(test, feature = "test-support"))]
5927impl LocalFile for TestFile {
5928 fn abs_path(&self, _cx: &App) -> PathBuf {
5929 PathBuf::from(self.local_root.as_ref().unwrap())
5930 .join(&self.root_name)
5931 .join(self.path.as_std_path())
5932 }
5933
5934 fn load(&self, _cx: &App) -> Task<Result<String>> {
5935 unimplemented!()
5936 }
5937
5938 fn load_bytes(&self, _cx: &App) -> Task<Result<Vec<u8>>> {
5939 unimplemented!()
5940 }
5941}
5942
5943pub(crate) fn contiguous_ranges(
5944 values: impl Iterator<Item = u32>,
5945 max_len: usize,
5946) -> impl Iterator<Item = Range<u32>> {
5947 let mut values = values;
5948 let mut current_range: Option<Range<u32>> = None;
5949 std::iter::from_fn(move || {
5950 loop {
5951 if let Some(value) = values.next() {
5952 if let Some(range) = &mut current_range
5953 && value == range.end
5954 && range.len() < max_len
5955 {
5956 range.end += 1;
5957 continue;
5958 }
5959
5960 let prev_range = current_range.clone();
5961 current_range = Some(value..(value + 1));
5962 if prev_range.is_some() {
5963 return prev_range;
5964 }
5965 } else {
5966 return current_range.take();
5967 }
5968 }
5969 })
5970}
5971
5972#[derive(Default, Debug)]
5973pub struct CharClassifier {
5974 scope: Option<LanguageScope>,
5975 scope_context: Option<CharScopeContext>,
5976 ignore_punctuation: bool,
5977}
5978
5979impl CharClassifier {
5980 pub fn new(scope: Option<LanguageScope>) -> Self {
5981 Self {
5982 scope,
5983 scope_context: None,
5984 ignore_punctuation: false,
5985 }
5986 }
5987
5988 pub fn scope_context(self, scope_context: Option<CharScopeContext>) -> Self {
5989 Self {
5990 scope_context,
5991 ..self
5992 }
5993 }
5994
5995 pub fn ignore_punctuation(self, ignore_punctuation: bool) -> Self {
5996 Self {
5997 ignore_punctuation,
5998 ..self
5999 }
6000 }
6001
6002 pub fn is_whitespace(&self, c: char) -> bool {
6003 self.kind(c) == CharKind::Whitespace
6004 }
6005
6006 pub fn is_word(&self, c: char) -> bool {
6007 self.kind(c) == CharKind::Word
6008 }
6009
6010 pub fn is_punctuation(&self, c: char) -> bool {
6011 self.kind(c) == CharKind::Punctuation
6012 }
6013
6014 pub fn kind_with(&self, c: char, ignore_punctuation: bool) -> CharKind {
6015 if c.is_alphanumeric() || c == '_' {
6016 return CharKind::Word;
6017 }
6018
6019 if let Some(scope) = &self.scope {
6020 let characters = match self.scope_context {
6021 Some(CharScopeContext::Completion) => scope.completion_query_characters(),
6022 Some(CharScopeContext::LinkedEdit) => scope.linked_edit_characters(),
6023 None => scope.word_characters(),
6024 };
6025 if let Some(characters) = characters
6026 && characters.contains(&c)
6027 {
6028 return CharKind::Word;
6029 }
6030 }
6031
6032 if c.is_whitespace() {
6033 return CharKind::Whitespace;
6034 }
6035
6036 if ignore_punctuation {
6037 CharKind::Word
6038 } else {
6039 CharKind::Punctuation
6040 }
6041 }
6042
6043 pub fn kind(&self, c: char) -> CharKind {
6044 self.kind_with(c, self.ignore_punctuation)
6045 }
6046}
6047
6048/// Find all of the ranges of whitespace that occur at the ends of lines
6049/// in the given rope.
6050///
6051/// This could also be done with a regex search, but this implementation
6052/// avoids copying text.
6053pub fn trailing_whitespace_ranges(rope: &Rope) -> Vec<Range<usize>> {
6054 let mut ranges = Vec::new();
6055
6056 let mut offset = 0;
6057 let mut prev_chunk_trailing_whitespace_range = 0..0;
6058 for chunk in rope.chunks() {
6059 let mut prev_line_trailing_whitespace_range = 0..0;
6060 for (i, line) in chunk.split('\n').enumerate() {
6061 let line_end_offset = offset + line.len();
6062 let trimmed_line_len = line.trim_end_matches([' ', '\t']).len();
6063 let mut trailing_whitespace_range = (offset + trimmed_line_len)..line_end_offset;
6064
6065 if i == 0 && trimmed_line_len == 0 {
6066 trailing_whitespace_range.start = prev_chunk_trailing_whitespace_range.start;
6067 }
6068 if !prev_line_trailing_whitespace_range.is_empty() {
6069 ranges.push(prev_line_trailing_whitespace_range);
6070 }
6071
6072 offset = line_end_offset + 1;
6073 prev_line_trailing_whitespace_range = trailing_whitespace_range;
6074 }
6075
6076 offset -= 1;
6077 prev_chunk_trailing_whitespace_range = prev_line_trailing_whitespace_range;
6078 }
6079
6080 if !prev_chunk_trailing_whitespace_range.is_empty() {
6081 ranges.push(prev_chunk_trailing_whitespace_range);
6082 }
6083
6084 ranges
6085}