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>(&self, range: Range<T>, language_aware: bool) -> BufferChunks<'_> {
3737 let range = range.start.to_offset(self)..range.end.to_offset(self);
3738
3739 let mut syntax = None;
3740 if language_aware {
3741 syntax = Some(self.get_highlights(range.clone()));
3742 }
3743 // We want to look at diagnostic spans only when iterating over language-annotated chunks.
3744 let diagnostics = language_aware;
3745 BufferChunks::new(self.text.as_rope(), range, syntax, diagnostics, Some(self))
3746 }
3747
3748 pub fn highlighted_text_for_range<T: ToOffset>(
3749 &self,
3750 range: Range<T>,
3751 override_style: Option<HighlightStyle>,
3752 syntax_theme: &SyntaxTheme,
3753 ) -> HighlightedText {
3754 HighlightedText::from_buffer_range(
3755 range,
3756 &self.text,
3757 &self.syntax,
3758 override_style,
3759 syntax_theme,
3760 )
3761 }
3762
3763 /// Invokes the given callback for each line of text in the given range of the buffer.
3764 /// Uses callback to avoid allocating a string for each line.
3765 fn for_each_line(&self, range: Range<Point>, mut callback: impl FnMut(u32, &str)) {
3766 let mut line = String::new();
3767 let mut row = range.start.row;
3768 for chunk in self
3769 .as_rope()
3770 .chunks_in_range(range.to_offset(self))
3771 .chain(["\n"])
3772 {
3773 for (newline_ix, text) in chunk.split('\n').enumerate() {
3774 if newline_ix > 0 {
3775 callback(row, &line);
3776 row += 1;
3777 line.clear();
3778 }
3779 line.push_str(text);
3780 }
3781 }
3782 }
3783
3784 /// Iterates over every [`SyntaxLayer`] in the buffer.
3785 pub fn syntax_layers(&self) -> impl Iterator<Item = SyntaxLayer<'_>> + '_ {
3786 self.syntax_layers_for_range(0..self.len(), true)
3787 }
3788
3789 pub fn syntax_layer_at<D: ToOffset>(&self, position: D) -> Option<SyntaxLayer<'_>> {
3790 let offset = position.to_offset(self);
3791 self.syntax_layers_for_range(offset..offset, false)
3792 .filter(|l| {
3793 if let Some(ranges) = l.included_sub_ranges {
3794 ranges.iter().any(|range| {
3795 let start = range.start.to_offset(self);
3796 start <= offset && {
3797 let end = range.end.to_offset(self);
3798 offset < end
3799 }
3800 })
3801 } else {
3802 l.node().start_byte() <= offset && l.node().end_byte() > offset
3803 }
3804 })
3805 .last()
3806 }
3807
3808 pub fn syntax_layers_for_range<D: ToOffset>(
3809 &self,
3810 range: Range<D>,
3811 include_hidden: bool,
3812 ) -> impl Iterator<Item = SyntaxLayer<'_>> + '_ {
3813 self.syntax
3814 .layers_for_range(range, &self.text, include_hidden)
3815 }
3816
3817 pub fn syntax_layers_languages(&self) -> impl Iterator<Item = &Arc<Language>> {
3818 self.syntax.languages(&self, true)
3819 }
3820
3821 pub fn smallest_syntax_layer_containing<D: ToOffset>(
3822 &self,
3823 range: Range<D>,
3824 ) -> Option<SyntaxLayer<'_>> {
3825 let range = range.to_offset(self);
3826 self.syntax
3827 .layers_for_range(range, &self.text, false)
3828 .max_by(|a, b| {
3829 if a.depth != b.depth {
3830 a.depth.cmp(&b.depth)
3831 } else if a.offset.0 != b.offset.0 {
3832 a.offset.0.cmp(&b.offset.0)
3833 } else {
3834 a.node().end_byte().cmp(&b.node().end_byte()).reverse()
3835 }
3836 })
3837 }
3838
3839 /// Returns the [`ModelineSettings`].
3840 pub fn modeline(&self) -> Option<&Arc<ModelineSettings>> {
3841 self.modeline.as_ref()
3842 }
3843
3844 /// Returns the main [`Language`].
3845 pub fn language(&self) -> Option<&Arc<Language>> {
3846 self.language.as_ref()
3847 }
3848
3849 /// Returns the [`Language`] at the given location.
3850 pub fn language_at<D: ToOffset>(&self, position: D) -> Option<&Arc<Language>> {
3851 self.syntax_layer_at(position)
3852 .map(|info| info.language)
3853 .or(self.language.as_ref())
3854 }
3855
3856 /// Returns the settings for the language at the given location.
3857 pub fn settings_at<'a, D: ToOffset>(
3858 &'a self,
3859 position: D,
3860 cx: &'a App,
3861 ) -> Cow<'a, LanguageSettings> {
3862 LanguageSettings::for_buffer_snapshot(self, Some(position.to_offset(self)), cx)
3863 }
3864
3865 pub fn char_classifier_at<T: ToOffset>(&self, point: T) -> CharClassifier {
3866 CharClassifier::new(self.language_scope_at(point))
3867 }
3868
3869 /// Returns the [`LanguageScope`] at the given location.
3870 pub fn language_scope_at<D: ToOffset>(&self, position: D) -> Option<LanguageScope> {
3871 let offset = position.to_offset(self);
3872 let mut scope = None;
3873 let mut smallest_range_and_depth: Option<(Range<usize>, usize)> = None;
3874 let text: &TextBufferSnapshot = self;
3875
3876 // Use the layer that has the smallest node intersecting the given point.
3877 for layer in self
3878 .syntax
3879 .layers_for_range(offset..offset, &self.text, false)
3880 {
3881 if let Some(ranges) = layer.included_sub_ranges
3882 && !offset_in_sub_ranges(ranges, offset, text)
3883 {
3884 continue;
3885 }
3886
3887 let mut cursor = layer.node().walk();
3888
3889 let mut range = None;
3890 loop {
3891 let child_range = cursor.node().byte_range();
3892 if !child_range.contains(&offset) {
3893 break;
3894 }
3895
3896 range = Some(child_range);
3897 if cursor.goto_first_child_for_byte(offset).is_none() {
3898 break;
3899 }
3900 }
3901
3902 if let Some(range) = range
3903 && smallest_range_and_depth.as_ref().is_none_or(
3904 |(smallest_range, smallest_range_depth)| {
3905 if layer.depth > *smallest_range_depth {
3906 true
3907 } else if layer.depth == *smallest_range_depth {
3908 range.len() < smallest_range.len()
3909 } else {
3910 false
3911 }
3912 },
3913 )
3914 {
3915 smallest_range_and_depth = Some((range, layer.depth));
3916 scope = Some(LanguageScope {
3917 language: layer.language.clone(),
3918 override_id: layer.override_id(offset, &self.text),
3919 });
3920 }
3921 }
3922
3923 scope.or_else(|| {
3924 self.language.clone().map(|language| LanguageScope {
3925 language,
3926 override_id: None,
3927 })
3928 })
3929 }
3930
3931 /// Returns a tuple of the range and character kind of the word
3932 /// surrounding the given position.
3933 pub fn surrounding_word<T: ToOffset>(
3934 &self,
3935 start: T,
3936 scope_context: Option<CharScopeContext>,
3937 ) -> (Range<usize>, Option<CharKind>) {
3938 let mut start = start.to_offset(self);
3939 let mut end = start;
3940 let mut next_chars = self.chars_at(start).take(128).peekable();
3941 let mut prev_chars = self.reversed_chars_at(start).take(128).peekable();
3942
3943 let classifier = self.char_classifier_at(start).scope_context(scope_context);
3944 let word_kind = cmp::max(
3945 prev_chars.peek().copied().map(|c| classifier.kind(c)),
3946 next_chars.peek().copied().map(|c| classifier.kind(c)),
3947 );
3948
3949 for ch in prev_chars {
3950 if Some(classifier.kind(ch)) == word_kind && ch != '\n' {
3951 start -= ch.len_utf8();
3952 } else {
3953 break;
3954 }
3955 }
3956
3957 for ch in next_chars {
3958 if Some(classifier.kind(ch)) == word_kind && ch != '\n' {
3959 end += ch.len_utf8();
3960 } else {
3961 break;
3962 }
3963 }
3964
3965 (start..end, word_kind)
3966 }
3967
3968 /// Moves the TreeCursor to the smallest descendant or ancestor syntax node enclosing the given
3969 /// range. When `require_larger` is true, the node found must be larger than the query range.
3970 ///
3971 /// Returns true if a node was found, and false otherwise. In the `false` case the cursor will
3972 /// be moved to the root of the tree.
3973 fn goto_node_enclosing_range(
3974 cursor: &mut tree_sitter::TreeCursor,
3975 query_range: &Range<usize>,
3976 require_larger: bool,
3977 ) -> bool {
3978 let mut ascending = false;
3979 loop {
3980 let mut range = cursor.node().byte_range();
3981 if query_range.is_empty() {
3982 // When the query range is empty and the current node starts after it, move to the
3983 // previous sibling to find the node the containing node.
3984 if range.start > query_range.start {
3985 cursor.goto_previous_sibling();
3986 range = cursor.node().byte_range();
3987 }
3988 } else {
3989 // When the query range is non-empty and the current node ends exactly at the start,
3990 // move to the next sibling to find a node that extends beyond the start.
3991 if range.end == query_range.start {
3992 cursor.goto_next_sibling();
3993 range = cursor.node().byte_range();
3994 }
3995 }
3996
3997 let encloses = range.contains_inclusive(query_range)
3998 && (!require_larger || range.len() > query_range.len());
3999 if !encloses {
4000 ascending = true;
4001 if !cursor.goto_parent() {
4002 return false;
4003 }
4004 continue;
4005 } else if ascending {
4006 return true;
4007 }
4008
4009 // Descend into the current node.
4010 if cursor
4011 .goto_first_child_for_byte(query_range.start)
4012 .is_none()
4013 {
4014 return true;
4015 }
4016 }
4017 }
4018
4019 pub fn syntax_ancestor<'a, T: ToOffset>(
4020 &'a self,
4021 range: Range<T>,
4022 ) -> Option<tree_sitter::Node<'a>> {
4023 let range = range.start.to_offset(self)..range.end.to_offset(self);
4024 let mut result: Option<tree_sitter::Node<'a>> = None;
4025 for layer in self
4026 .syntax
4027 .layers_for_range(range.clone(), &self.text, true)
4028 {
4029 let mut cursor = layer.node().walk();
4030
4031 // Find the node that both contains the range and is larger than it.
4032 if !Self::goto_node_enclosing_range(&mut cursor, &range, true) {
4033 continue;
4034 }
4035
4036 let left_node = cursor.node();
4037 let mut layer_result = left_node;
4038
4039 // For an empty range, try to find another node immediately to the right of the range.
4040 if left_node.end_byte() == range.start {
4041 let mut right_node = None;
4042 while !cursor.goto_next_sibling() {
4043 if !cursor.goto_parent() {
4044 break;
4045 }
4046 }
4047
4048 while cursor.node().start_byte() == range.start {
4049 right_node = Some(cursor.node());
4050 if !cursor.goto_first_child() {
4051 break;
4052 }
4053 }
4054
4055 // If there is a candidate node on both sides of the (empty) range, then
4056 // decide between the two by favoring a named node over an anonymous token.
4057 // If both nodes are the same in that regard, favor the right one.
4058 if let Some(right_node) = right_node
4059 && (right_node.is_named() || !left_node.is_named())
4060 {
4061 layer_result = right_node;
4062 }
4063 }
4064
4065 if let Some(previous_result) = &result
4066 && previous_result.byte_range().len() < layer_result.byte_range().len()
4067 {
4068 continue;
4069 }
4070 result = Some(layer_result);
4071 }
4072
4073 result
4074 }
4075
4076 /// Find the previous sibling syntax node at the given range.
4077 ///
4078 /// This function locates the syntax node that precedes the node containing
4079 /// the given range. It searches hierarchically by:
4080 /// 1. Finding the node that contains the given range
4081 /// 2. Looking for the previous sibling at the same tree level
4082 /// 3. If no sibling is found, moving up to parent levels and searching for siblings
4083 ///
4084 /// Returns `None` if there is no previous sibling at any ancestor level.
4085 pub fn syntax_prev_sibling<'a, T: ToOffset>(
4086 &'a self,
4087 range: Range<T>,
4088 ) -> Option<tree_sitter::Node<'a>> {
4089 let range = range.start.to_offset(self)..range.end.to_offset(self);
4090 let mut result: Option<tree_sitter::Node<'a>> = None;
4091
4092 for layer in self
4093 .syntax
4094 .layers_for_range(range.clone(), &self.text, true)
4095 {
4096 let mut cursor = layer.node().walk();
4097
4098 // Find the node that contains the range
4099 if !Self::goto_node_enclosing_range(&mut cursor, &range, false) {
4100 continue;
4101 }
4102
4103 // Look for the previous sibling, moving up ancestor levels if needed
4104 loop {
4105 if cursor.goto_previous_sibling() {
4106 let layer_result = cursor.node();
4107
4108 if let Some(previous_result) = &result {
4109 if previous_result.byte_range().end < layer_result.byte_range().end {
4110 continue;
4111 }
4112 }
4113 result = Some(layer_result);
4114 break;
4115 }
4116
4117 // No sibling found at this level, try moving up to parent
4118 if !cursor.goto_parent() {
4119 break;
4120 }
4121 }
4122 }
4123
4124 result
4125 }
4126
4127 /// Find the next sibling syntax node at the given range.
4128 ///
4129 /// This function locates the syntax node that follows the node containing
4130 /// the given range. It searches hierarchically by:
4131 /// 1. Finding the node that contains the given range
4132 /// 2. Looking for the next sibling at the same tree level
4133 /// 3. If no sibling is found, moving up to parent levels and searching for siblings
4134 ///
4135 /// Returns `None` if there is no next sibling at any ancestor level.
4136 pub fn syntax_next_sibling<'a, T: ToOffset>(
4137 &'a self,
4138 range: Range<T>,
4139 ) -> Option<tree_sitter::Node<'a>> {
4140 let range = range.start.to_offset(self)..range.end.to_offset(self);
4141 let mut result: Option<tree_sitter::Node<'a>> = None;
4142
4143 for layer in self
4144 .syntax
4145 .layers_for_range(range.clone(), &self.text, true)
4146 {
4147 let mut cursor = layer.node().walk();
4148
4149 // Find the node that contains the range
4150 if !Self::goto_node_enclosing_range(&mut cursor, &range, false) {
4151 continue;
4152 }
4153
4154 // Look for the next sibling, moving up ancestor levels if needed
4155 loop {
4156 if cursor.goto_next_sibling() {
4157 let layer_result = cursor.node();
4158
4159 if let Some(previous_result) = &result {
4160 if previous_result.byte_range().start > layer_result.byte_range().start {
4161 continue;
4162 }
4163 }
4164 result = Some(layer_result);
4165 break;
4166 }
4167
4168 // No sibling found at this level, try moving up to parent
4169 if !cursor.goto_parent() {
4170 break;
4171 }
4172 }
4173 }
4174
4175 result
4176 }
4177
4178 /// Returns the root syntax node within the given row
4179 pub fn syntax_root_ancestor(&self, position: Anchor) -> Option<tree_sitter::Node<'_>> {
4180 let start_offset = position.to_offset(self);
4181
4182 let row = self.summary_for_anchor::<text::PointUtf16>(&position).row as usize;
4183
4184 let layer = self
4185 .syntax
4186 .layers_for_range(start_offset..start_offset, &self.text, true)
4187 .next()?;
4188
4189 let mut cursor = layer.node().walk();
4190
4191 // Descend to the first leaf that touches the start of the range.
4192 while cursor.goto_first_child_for_byte(start_offset).is_some() {
4193 if cursor.node().end_byte() == start_offset {
4194 cursor.goto_next_sibling();
4195 }
4196 }
4197
4198 // Ascend to the root node within the same row.
4199 while cursor.goto_parent() {
4200 if cursor.node().start_position().row != row {
4201 break;
4202 }
4203 }
4204
4205 Some(cursor.node())
4206 }
4207
4208 /// Returns the outline for the buffer.
4209 ///
4210 /// This method allows passing an optional [`SyntaxTheme`] to
4211 /// syntax-highlight the returned symbols.
4212 pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Outline<Anchor> {
4213 Outline::new(self.outline_items_containing(0..self.len(), true, theme))
4214 }
4215
4216 /// Returns all the symbols that contain the given position.
4217 ///
4218 /// This method allows passing an optional [`SyntaxTheme`] to
4219 /// syntax-highlight the returned symbols.
4220 pub fn symbols_containing<T: ToOffset>(
4221 &self,
4222 position: T,
4223 theme: Option<&SyntaxTheme>,
4224 ) -> Vec<OutlineItem<Anchor>> {
4225 let position = position.to_offset(self);
4226 let start = self.clip_offset(position.saturating_sub(1), Bias::Left);
4227 let end = self.clip_offset(position + 1, Bias::Right);
4228 let mut items = self.outline_items_containing(start..end, false, theme);
4229 let mut prev_depth = None;
4230 items.retain(|item| {
4231 let result = prev_depth.is_none_or(|prev_depth| item.depth > prev_depth);
4232 prev_depth = Some(item.depth);
4233 result
4234 });
4235 items
4236 }
4237
4238 pub fn outline_range_containing<T: ToOffset>(&self, range: Range<T>) -> Option<Range<Point>> {
4239 let range = range.to_offset(self);
4240 let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
4241 grammar.outline_config.as_ref().map(|c| &c.query)
4242 });
4243 let configs = matches
4244 .grammars()
4245 .iter()
4246 .map(|g| g.outline_config.as_ref().unwrap())
4247 .collect::<Vec<_>>();
4248
4249 while let Some(mat) = matches.peek() {
4250 let config = &configs[mat.grammar_index];
4251 let containing_item_node = maybe!({
4252 let item_node = mat.captures.iter().find_map(|cap| {
4253 if cap.index == config.item_capture_ix {
4254 Some(cap.node)
4255 } else {
4256 None
4257 }
4258 })?;
4259
4260 let item_byte_range = item_node.byte_range();
4261 if item_byte_range.end < range.start || item_byte_range.start > range.end {
4262 None
4263 } else {
4264 Some(item_node)
4265 }
4266 });
4267
4268 if let Some(item_node) = containing_item_node {
4269 return Some(
4270 Point::from_ts_point(item_node.start_position())
4271 ..Point::from_ts_point(item_node.end_position()),
4272 );
4273 }
4274
4275 matches.advance();
4276 }
4277 None
4278 }
4279
4280 pub fn outline_items_containing<T: ToOffset>(
4281 &self,
4282 range: Range<T>,
4283 include_extra_context: bool,
4284 theme: Option<&SyntaxTheme>,
4285 ) -> Vec<OutlineItem<Anchor>> {
4286 self.outline_items_containing_internal(
4287 range,
4288 include_extra_context,
4289 theme,
4290 |this, range| this.anchor_after(range.start)..this.anchor_before(range.end),
4291 )
4292 }
4293
4294 pub fn outline_items_as_points_containing<T: ToOffset>(
4295 &self,
4296 range: Range<T>,
4297 include_extra_context: bool,
4298 theme: Option<&SyntaxTheme>,
4299 ) -> Vec<OutlineItem<Point>> {
4300 self.outline_items_containing_internal(range, include_extra_context, theme, |_, range| {
4301 range
4302 })
4303 }
4304
4305 pub fn outline_items_as_offsets_containing<T: ToOffset>(
4306 &self,
4307 range: Range<T>,
4308 include_extra_context: bool,
4309 theme: Option<&SyntaxTheme>,
4310 ) -> Vec<OutlineItem<usize>> {
4311 self.outline_items_containing_internal(
4312 range,
4313 include_extra_context,
4314 theme,
4315 |buffer, range| range.to_offset(buffer),
4316 )
4317 }
4318
4319 fn outline_items_containing_internal<T: ToOffset, U>(
4320 &self,
4321 range: Range<T>,
4322 include_extra_context: bool,
4323 theme: Option<&SyntaxTheme>,
4324 range_callback: fn(&Self, Range<Point>) -> Range<U>,
4325 ) -> Vec<OutlineItem<U>> {
4326 let range = range.to_offset(self);
4327 let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
4328 grammar.outline_config.as_ref().map(|c| &c.query)
4329 });
4330
4331 let mut items = Vec::new();
4332 let mut annotation_row_ranges: Vec<Range<u32>> = Vec::new();
4333 while let Some(mat) = matches.peek() {
4334 let config = matches.grammars()[mat.grammar_index]
4335 .outline_config
4336 .as_ref()
4337 .unwrap();
4338 if let Some(item) =
4339 self.next_outline_item(config, &mat, &range, include_extra_context, theme)
4340 {
4341 items.push(item);
4342 } else if let Some(capture) = mat
4343 .captures
4344 .iter()
4345 .find(|capture| Some(capture.index) == config.annotation_capture_ix)
4346 {
4347 let capture_range = capture.node.start_position()..capture.node.end_position();
4348 let mut capture_row_range =
4349 capture_range.start.row as u32..capture_range.end.row as u32;
4350 if capture_range.end.row > capture_range.start.row && capture_range.end.column == 0
4351 {
4352 capture_row_range.end -= 1;
4353 }
4354 if let Some(last_row_range) = annotation_row_ranges.last_mut() {
4355 if last_row_range.end >= capture_row_range.start.saturating_sub(1) {
4356 last_row_range.end = capture_row_range.end;
4357 } else {
4358 annotation_row_ranges.push(capture_row_range);
4359 }
4360 } else {
4361 annotation_row_ranges.push(capture_row_range);
4362 }
4363 }
4364 matches.advance();
4365 }
4366
4367 items.sort_by_key(|item| (item.range.start, Reverse(item.range.end)));
4368
4369 // Assign depths based on containment relationships and convert to anchors.
4370 let mut item_ends_stack = Vec::<Point>::new();
4371 let mut anchor_items = Vec::new();
4372 let mut annotation_row_ranges = annotation_row_ranges.into_iter().peekable();
4373 for item in items {
4374 while let Some(last_end) = item_ends_stack.last().copied() {
4375 if last_end < item.range.end {
4376 item_ends_stack.pop();
4377 } else {
4378 break;
4379 }
4380 }
4381
4382 let mut annotation_row_range = None;
4383 while let Some(next_annotation_row_range) = annotation_row_ranges.peek() {
4384 let row_preceding_item = item.range.start.row.saturating_sub(1);
4385 if next_annotation_row_range.end < row_preceding_item {
4386 annotation_row_ranges.next();
4387 } else {
4388 if next_annotation_row_range.end == row_preceding_item {
4389 annotation_row_range = Some(next_annotation_row_range.clone());
4390 annotation_row_ranges.next();
4391 }
4392 break;
4393 }
4394 }
4395
4396 anchor_items.push(OutlineItem {
4397 depth: item_ends_stack.len(),
4398 range: range_callback(self, item.range.clone()),
4399 source_range_for_text: range_callback(self, item.source_range_for_text.clone()),
4400 text: item.text,
4401 highlight_ranges: item.highlight_ranges,
4402 name_ranges: item.name_ranges,
4403 body_range: item.body_range.map(|r| range_callback(self, r)),
4404 annotation_range: annotation_row_range.map(|annotation_range| {
4405 let point_range = Point::new(annotation_range.start, 0)
4406 ..Point::new(annotation_range.end, self.line_len(annotation_range.end));
4407 range_callback(self, point_range)
4408 }),
4409 });
4410 item_ends_stack.push(item.range.end);
4411 }
4412
4413 anchor_items
4414 }
4415
4416 fn next_outline_item(
4417 &self,
4418 config: &OutlineConfig,
4419 mat: &SyntaxMapMatch,
4420 range: &Range<usize>,
4421 include_extra_context: bool,
4422 theme: Option<&SyntaxTheme>,
4423 ) -> Option<OutlineItem<Point>> {
4424 let item_node = mat.captures.iter().find_map(|cap| {
4425 if cap.index == config.item_capture_ix {
4426 Some(cap.node)
4427 } else {
4428 None
4429 }
4430 })?;
4431
4432 let item_byte_range = item_node.byte_range();
4433 if item_byte_range.end < range.start || item_byte_range.start > range.end {
4434 return None;
4435 }
4436 let item_point_range = Point::from_ts_point(item_node.start_position())
4437 ..Point::from_ts_point(item_node.end_position());
4438
4439 let mut open_point = None;
4440 let mut close_point = None;
4441
4442 let mut buffer_ranges = Vec::new();
4443 let mut add_to_buffer_ranges = |node: tree_sitter::Node, node_is_name| {
4444 let mut range = node.start_byte()..node.end_byte();
4445 let start = node.start_position();
4446 if node.end_position().row > start.row {
4447 range.end = range.start + self.line_len(start.row as u32) as usize - start.column;
4448 }
4449
4450 if !range.is_empty() {
4451 buffer_ranges.push((range, node_is_name));
4452 }
4453 };
4454
4455 for capture in mat.captures {
4456 if capture.index == config.name_capture_ix {
4457 add_to_buffer_ranges(capture.node, true);
4458 } else if Some(capture.index) == config.context_capture_ix
4459 || (Some(capture.index) == config.extra_context_capture_ix && include_extra_context)
4460 {
4461 add_to_buffer_ranges(capture.node, false);
4462 } else {
4463 if Some(capture.index) == config.open_capture_ix {
4464 open_point = Some(Point::from_ts_point(capture.node.end_position()));
4465 } else if Some(capture.index) == config.close_capture_ix {
4466 close_point = Some(Point::from_ts_point(capture.node.start_position()));
4467 }
4468 }
4469 }
4470
4471 if buffer_ranges.is_empty() {
4472 return None;
4473 }
4474 let source_range_for_text =
4475 buffer_ranges.first().unwrap().0.start..buffer_ranges.last().unwrap().0.end;
4476
4477 let mut text = String::new();
4478 let mut highlight_ranges = Vec::new();
4479 let mut name_ranges = Vec::new();
4480 let mut chunks = self.chunks(source_range_for_text.clone(), true);
4481 let mut last_buffer_range_end = 0;
4482 for (buffer_range, is_name) in buffer_ranges {
4483 let space_added = !text.is_empty() && buffer_range.start > last_buffer_range_end;
4484 if space_added {
4485 text.push(' ');
4486 }
4487 let before_append_len = text.len();
4488 let mut offset = buffer_range.start;
4489 chunks.seek(buffer_range.clone());
4490 for mut chunk in chunks.by_ref() {
4491 if chunk.text.len() > buffer_range.end - offset {
4492 chunk.text = &chunk.text[0..(buffer_range.end - offset)];
4493 offset = buffer_range.end;
4494 } else {
4495 offset += chunk.text.len();
4496 }
4497 let style = chunk
4498 .syntax_highlight_id
4499 .zip(theme)
4500 .and_then(|(highlight, theme)| theme.get(highlight).cloned());
4501
4502 if let Some(style) = style {
4503 let start = text.len();
4504 let end = start + chunk.text.len();
4505 highlight_ranges.push((start..end, style));
4506 }
4507 text.push_str(chunk.text);
4508 if offset >= buffer_range.end {
4509 break;
4510 }
4511 }
4512 if is_name {
4513 let after_append_len = text.len();
4514 let start = if space_added && !name_ranges.is_empty() {
4515 before_append_len - 1
4516 } else {
4517 before_append_len
4518 };
4519 name_ranges.push(start..after_append_len);
4520 }
4521 last_buffer_range_end = buffer_range.end;
4522 }
4523
4524 Some(OutlineItem {
4525 depth: 0, // We'll calculate the depth later
4526 range: item_point_range,
4527 source_range_for_text: source_range_for_text.to_point(self),
4528 text,
4529 highlight_ranges,
4530 name_ranges,
4531 body_range: open_point.zip(close_point).map(|(start, end)| start..end),
4532 annotation_range: None,
4533 })
4534 }
4535
4536 pub fn function_body_fold_ranges<T: ToOffset>(
4537 &self,
4538 within: Range<T>,
4539 ) -> impl Iterator<Item = Range<usize>> + '_ {
4540 self.text_object_ranges(within, TreeSitterOptions::default())
4541 .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
4542 }
4543
4544 /// For each grammar in the language, runs the provided
4545 /// [`tree_sitter::Query`] against the given range.
4546 pub fn matches(
4547 &self,
4548 range: Range<usize>,
4549 query: fn(&Grammar) -> Option<&tree_sitter::Query>,
4550 ) -> SyntaxMapMatches<'_> {
4551 self.syntax.matches(range, self, query)
4552 }
4553
4554 /// Finds all [`RowChunks`] applicable to the given range, then returns all bracket pairs that intersect with those chunks.
4555 /// Hence, may return more bracket pairs than the range contains.
4556 ///
4557 /// Will omit known chunks.
4558 /// The resulting bracket match collections are not ordered.
4559 pub fn fetch_bracket_ranges(
4560 &self,
4561 range: Range<usize>,
4562 known_chunks: Option<&HashSet<Range<BufferRow>>>,
4563 ) -> HashMap<Range<BufferRow>, Vec<BracketMatch<usize>>> {
4564 let mut all_bracket_matches = HashMap::default();
4565
4566 for chunk in self
4567 .tree_sitter_data
4568 .chunks
4569 .applicable_chunks(&[range.to_point(self)])
4570 {
4571 if known_chunks.is_some_and(|chunks| chunks.contains(&chunk.row_range())) {
4572 continue;
4573 }
4574 let chunk_range = chunk.anchor_range();
4575 let chunk_range = chunk_range.to_offset(&self);
4576
4577 if let Some(cached_brackets) =
4578 &self.tree_sitter_data.brackets_by_chunks.lock()[chunk.id]
4579 {
4580 all_bracket_matches.insert(chunk.row_range(), cached_brackets.clone());
4581 continue;
4582 }
4583
4584 let mut all_brackets: Vec<(BracketMatch<usize>, usize, bool)> = Vec::new();
4585 let mut opens = Vec::new();
4586 let mut color_pairs = Vec::new();
4587
4588 let mut matches = self.syntax.matches_with_options(
4589 chunk_range.clone(),
4590 &self.text,
4591 TreeSitterOptions {
4592 max_bytes_to_query: Some(MAX_BYTES_TO_QUERY),
4593 max_start_depth: None,
4594 },
4595 |grammar| grammar.brackets_config.as_ref().map(|c| &c.query),
4596 );
4597 let configs = matches
4598 .grammars()
4599 .iter()
4600 .map(|grammar| grammar.brackets_config.as_ref().unwrap())
4601 .collect::<Vec<_>>();
4602
4603 // Group matches by open range so we can either trust grammar output
4604 // or repair it by picking a single closest close per open.
4605 let mut open_to_close_ranges = BTreeMap::new();
4606 while let Some(mat) = matches.peek() {
4607 let mut open = None;
4608 let mut close = None;
4609 let syntax_layer_depth = mat.depth;
4610 let pattern_index = mat.pattern_index;
4611 let config = configs[mat.grammar_index];
4612 let pattern = &config.patterns[pattern_index];
4613 for capture in mat.captures {
4614 if capture.index == config.open_capture_ix {
4615 open = Some(capture.node.byte_range());
4616 } else if capture.index == config.close_capture_ix {
4617 close = Some(capture.node.byte_range());
4618 }
4619 }
4620
4621 matches.advance();
4622
4623 let Some((open_range, close_range)) = open.zip(close) else {
4624 continue;
4625 };
4626
4627 let bracket_range = open_range.start..=close_range.end;
4628 if !bracket_range.overlaps(&chunk_range) {
4629 continue;
4630 }
4631
4632 open_to_close_ranges
4633 .entry((open_range.start, open_range.end, pattern_index))
4634 .or_insert_with(BTreeMap::new)
4635 .insert(
4636 (close_range.start, close_range.end),
4637 BracketMatch {
4638 open_range: open_range.clone(),
4639 close_range: close_range.clone(),
4640 syntax_layer_depth,
4641 newline_only: pattern.newline_only,
4642 color_index: None,
4643 },
4644 );
4645
4646 all_brackets.push((
4647 BracketMatch {
4648 open_range,
4649 close_range,
4650 syntax_layer_depth,
4651 newline_only: pattern.newline_only,
4652 color_index: None,
4653 },
4654 pattern_index,
4655 pattern.rainbow_exclude,
4656 ));
4657 }
4658
4659 let has_bogus_matches = open_to_close_ranges
4660 .iter()
4661 .any(|(_, end_ranges)| end_ranges.len() > 1);
4662 if has_bogus_matches {
4663 // Grammar is producing bogus matches where one open is paired with multiple
4664 // closes. Build a valid stack by walking through positions in order.
4665 // For each close, we know the expected open_len from tree-sitter matches.
4666
4667 // Map each close to its expected open length (for inferring opens)
4668 let close_to_open_len: HashMap<(usize, usize, usize), usize> = all_brackets
4669 .iter()
4670 .map(|(bracket_match, pattern_index, _)| {
4671 (
4672 (
4673 bracket_match.close_range.start,
4674 bracket_match.close_range.end,
4675 *pattern_index,
4676 ),
4677 bracket_match.open_range.len(),
4678 )
4679 })
4680 .collect();
4681
4682 // Collect unique opens and closes within this chunk
4683 let mut unique_opens: HashSet<(usize, usize, usize)> = all_brackets
4684 .iter()
4685 .map(|(bracket_match, pattern_index, _)| {
4686 (
4687 bracket_match.open_range.start,
4688 bracket_match.open_range.end,
4689 *pattern_index,
4690 )
4691 })
4692 .filter(|(start, _, _)| chunk_range.contains(start))
4693 .collect();
4694
4695 let mut unique_closes: Vec<(usize, usize, usize)> = all_brackets
4696 .iter()
4697 .map(|(bracket_match, pattern_index, _)| {
4698 (
4699 bracket_match.close_range.start,
4700 bracket_match.close_range.end,
4701 *pattern_index,
4702 )
4703 })
4704 .filter(|(start, _, _)| chunk_range.contains(start))
4705 .collect();
4706 unique_closes.sort();
4707 unique_closes.dedup();
4708
4709 // Build valid pairs by walking through closes in order
4710 let mut unique_opens_vec: Vec<_> = unique_opens.iter().copied().collect();
4711 unique_opens_vec.sort();
4712
4713 let mut valid_pairs: HashSet<((usize, usize, usize), (usize, usize, usize))> =
4714 HashSet::default();
4715 let mut open_stacks: HashMap<usize, Vec<(usize, usize)>> = HashMap::default();
4716 let mut open_idx = 0;
4717
4718 for close in &unique_closes {
4719 // Push all opens before this close onto stack
4720 while open_idx < unique_opens_vec.len()
4721 && unique_opens_vec[open_idx].0 < close.0
4722 {
4723 let (start, end, pattern_index) = unique_opens_vec[open_idx];
4724 open_stacks
4725 .entry(pattern_index)
4726 .or_default()
4727 .push((start, end));
4728 open_idx += 1;
4729 }
4730
4731 // Try to match with most recent open
4732 let (close_start, close_end, pattern_index) = *close;
4733 if let Some(open) = open_stacks
4734 .get_mut(&pattern_index)
4735 .and_then(|open_stack| open_stack.pop())
4736 {
4737 valid_pairs.insert(((open.0, open.1, pattern_index), *close));
4738 } else if let Some(&open_len) = close_to_open_len.get(close) {
4739 // No open on stack - infer one based on expected open_len
4740 if close_start >= open_len {
4741 let inferred = (close_start - open_len, close_start, pattern_index);
4742 unique_opens.insert(inferred);
4743 valid_pairs.insert((inferred, *close));
4744 all_brackets.push((
4745 BracketMatch {
4746 open_range: inferred.0..inferred.1,
4747 close_range: close_start..close_end,
4748 newline_only: false,
4749 syntax_layer_depth: 0,
4750 color_index: None,
4751 },
4752 pattern_index,
4753 false,
4754 ));
4755 }
4756 }
4757 }
4758
4759 all_brackets.retain(|(bracket_match, pattern_index, _)| {
4760 let open = (
4761 bracket_match.open_range.start,
4762 bracket_match.open_range.end,
4763 *pattern_index,
4764 );
4765 let close = (
4766 bracket_match.close_range.start,
4767 bracket_match.close_range.end,
4768 *pattern_index,
4769 );
4770 valid_pairs.contains(&(open, close))
4771 });
4772 }
4773
4774 let mut all_brackets = all_brackets
4775 .into_iter()
4776 .enumerate()
4777 .map(|(index, (bracket_match, _, rainbow_exclude))| {
4778 // Certain languages have "brackets" that are not brackets, e.g. tags. and such
4779 // bracket will match the entire tag with all text inside.
4780 // For now, avoid highlighting any pair that has more than single char in each bracket.
4781 // We need to colorize `<Element/>` bracket pairs, so cannot make this check stricter.
4782 let should_color = !rainbow_exclude
4783 && (bracket_match.open_range.len() == 1
4784 || bracket_match.close_range.len() == 1);
4785 if should_color {
4786 opens.push(bracket_match.open_range.clone());
4787 color_pairs.push((
4788 bracket_match.open_range.clone(),
4789 bracket_match.close_range.clone(),
4790 index,
4791 ));
4792 }
4793 bracket_match
4794 })
4795 .collect::<Vec<_>>();
4796
4797 opens.sort_by_key(|r| (r.start, r.end));
4798 opens.dedup_by(|a, b| a.start == b.start && a.end == b.end);
4799 color_pairs.sort_by_key(|(_, close, _)| close.end);
4800
4801 let mut open_stack = Vec::new();
4802 let mut open_index = 0;
4803 for (open, close, index) in color_pairs {
4804 while open_index < opens.len() && opens[open_index].start < close.start {
4805 open_stack.push(opens[open_index].clone());
4806 open_index += 1;
4807 }
4808
4809 if open_stack.last() == Some(&open) {
4810 let depth_index = open_stack.len() - 1;
4811 all_brackets[index].color_index = Some(depth_index);
4812 open_stack.pop();
4813 }
4814 }
4815
4816 all_brackets.sort_by_key(|bracket_match| {
4817 (bracket_match.open_range.start, bracket_match.open_range.end)
4818 });
4819
4820 if let empty_slot @ None =
4821 &mut self.tree_sitter_data.brackets_by_chunks.lock()[chunk.id]
4822 {
4823 *empty_slot = Some(all_brackets.clone());
4824 }
4825 all_bracket_matches.insert(chunk.row_range(), all_brackets);
4826 }
4827
4828 all_bracket_matches
4829 }
4830
4831 pub fn all_bracket_ranges(
4832 &self,
4833 range: Range<usize>,
4834 ) -> impl Iterator<Item = BracketMatch<usize>> {
4835 self.fetch_bracket_ranges(range.clone(), None)
4836 .into_values()
4837 .flatten()
4838 .filter(move |bracket_match| {
4839 let bracket_range = bracket_match.open_range.start..bracket_match.close_range.end;
4840 bracket_range.overlaps(&range)
4841 })
4842 }
4843
4844 /// Returns bracket range pairs overlapping or adjacent to `range`
4845 pub fn bracket_ranges<T: ToOffset>(
4846 &self,
4847 range: Range<T>,
4848 ) -> impl Iterator<Item = BracketMatch<usize>> + '_ {
4849 // Find bracket pairs that *inclusively* contain the given range.
4850 let range = range.start.to_previous_offset(self)..range.end.to_next_offset(self);
4851 self.all_bracket_ranges(range)
4852 .filter(|pair| !pair.newline_only)
4853 }
4854
4855 pub fn debug_variables_query<T: ToOffset>(
4856 &self,
4857 range: Range<T>,
4858 ) -> impl Iterator<Item = (Range<usize>, DebuggerTextObject)> + '_ {
4859 let range = range.start.to_previous_offset(self)..range.end.to_next_offset(self);
4860
4861 let mut matches = self.syntax.matches_with_options(
4862 range.clone(),
4863 &self.text,
4864 TreeSitterOptions::default(),
4865 |grammar| grammar.debug_variables_config.as_ref().map(|c| &c.query),
4866 );
4867
4868 let configs = matches
4869 .grammars()
4870 .iter()
4871 .map(|grammar| grammar.debug_variables_config.as_ref())
4872 .collect::<Vec<_>>();
4873
4874 let mut captures = Vec::<(Range<usize>, DebuggerTextObject)>::new();
4875
4876 iter::from_fn(move || {
4877 loop {
4878 while let Some(capture) = captures.pop() {
4879 if capture.0.overlaps(&range) {
4880 return Some(capture);
4881 }
4882 }
4883
4884 let mat = matches.peek()?;
4885
4886 let Some(config) = configs[mat.grammar_index].as_ref() else {
4887 matches.advance();
4888 continue;
4889 };
4890
4891 for capture in mat.captures {
4892 let Some(ix) = config
4893 .objects_by_capture_ix
4894 .binary_search_by_key(&capture.index, |e| e.0)
4895 .ok()
4896 else {
4897 continue;
4898 };
4899 let text_object = config.objects_by_capture_ix[ix].1;
4900 let byte_range = capture.node.byte_range();
4901
4902 let mut found = false;
4903 for (range, existing) in captures.iter_mut() {
4904 if existing == &text_object {
4905 range.start = range.start.min(byte_range.start);
4906 range.end = range.end.max(byte_range.end);
4907 found = true;
4908 break;
4909 }
4910 }
4911
4912 if !found {
4913 captures.push((byte_range, text_object));
4914 }
4915 }
4916
4917 matches.advance();
4918 }
4919 })
4920 }
4921
4922 pub fn text_object_ranges<T: ToOffset>(
4923 &self,
4924 range: Range<T>,
4925 options: TreeSitterOptions,
4926 ) -> impl Iterator<Item = (Range<usize>, TextObject)> + '_ {
4927 let range =
4928 range.start.to_previous_offset(self)..self.len().min(range.end.to_next_offset(self));
4929
4930 let mut matches =
4931 self.syntax
4932 .matches_with_options(range.clone(), &self.text, options, |grammar| {
4933 grammar.text_object_config.as_ref().map(|c| &c.query)
4934 });
4935
4936 let configs = matches
4937 .grammars()
4938 .iter()
4939 .map(|grammar| grammar.text_object_config.as_ref())
4940 .collect::<Vec<_>>();
4941
4942 let mut captures = Vec::<(Range<usize>, TextObject)>::new();
4943
4944 iter::from_fn(move || {
4945 loop {
4946 while let Some(capture) = captures.pop() {
4947 if capture.0.overlaps(&range) {
4948 return Some(capture);
4949 }
4950 }
4951
4952 let mat = matches.peek()?;
4953
4954 let Some(config) = configs[mat.grammar_index].as_ref() else {
4955 matches.advance();
4956 continue;
4957 };
4958
4959 for capture in mat.captures {
4960 let Some(ix) = config
4961 .text_objects_by_capture_ix
4962 .binary_search_by_key(&capture.index, |e| e.0)
4963 .ok()
4964 else {
4965 continue;
4966 };
4967 let text_object = config.text_objects_by_capture_ix[ix].1;
4968 let byte_range = capture.node.byte_range();
4969
4970 let mut found = false;
4971 for (range, existing) in captures.iter_mut() {
4972 if existing == &text_object {
4973 range.start = range.start.min(byte_range.start);
4974 range.end = range.end.max(byte_range.end);
4975 found = true;
4976 break;
4977 }
4978 }
4979
4980 if !found {
4981 captures.push((byte_range, text_object));
4982 }
4983 }
4984
4985 matches.advance();
4986 }
4987 })
4988 }
4989
4990 /// Returns enclosing bracket ranges containing the given range
4991 pub fn enclosing_bracket_ranges<T: ToOffset>(
4992 &self,
4993 range: Range<T>,
4994 ) -> impl Iterator<Item = BracketMatch<usize>> + '_ {
4995 let range = range.start.to_offset(self)..range.end.to_offset(self);
4996
4997 let result: Vec<_> = self.bracket_ranges(range.clone()).collect();
4998 let max_depth = result
4999 .iter()
5000 .map(|mat| mat.syntax_layer_depth)
5001 .max()
5002 .unwrap_or(0);
5003 result.into_iter().filter(move |pair| {
5004 pair.open_range.start <= range.start
5005 && pair.close_range.end >= range.end
5006 && pair.syntax_layer_depth == max_depth
5007 })
5008 }
5009
5010 /// Returns the smallest enclosing bracket ranges containing the given range or None if no brackets contain range
5011 ///
5012 /// Can optionally pass a range_filter to filter the ranges of brackets to consider
5013 pub fn innermost_enclosing_bracket_ranges<T: ToOffset>(
5014 &self,
5015 range: Range<T>,
5016 range_filter: Option<&dyn Fn(Range<usize>, Range<usize>) -> bool>,
5017 ) -> Option<(Range<usize>, Range<usize>)> {
5018 let range = range.start.to_offset(self)..range.end.to_offset(self);
5019
5020 // Get the ranges of the innermost pair of brackets.
5021 let mut result: Option<(Range<usize>, Range<usize>)> = None;
5022
5023 for pair in self.enclosing_bracket_ranges(range) {
5024 if let Some(range_filter) = range_filter
5025 && !range_filter(pair.open_range.clone(), pair.close_range.clone())
5026 {
5027 continue;
5028 }
5029
5030 let len = pair.close_range.end - pair.open_range.start;
5031
5032 if let Some((existing_open, existing_close)) = &result {
5033 let existing_len = existing_close.end - existing_open.start;
5034 if len > existing_len {
5035 continue;
5036 }
5037 }
5038
5039 result = Some((pair.open_range, pair.close_range));
5040 }
5041
5042 result
5043 }
5044
5045 /// Returns anchor ranges for any matches of the redaction query.
5046 /// The buffer can be associated with multiple languages, and the redaction query associated with each
5047 /// will be run on the relevant section of the buffer.
5048 pub fn redacted_ranges<T: ToOffset>(
5049 &self,
5050 range: Range<T>,
5051 ) -> impl Iterator<Item = Range<usize>> + '_ {
5052 let offset_range = range.start.to_offset(self)..range.end.to_offset(self);
5053 let mut syntax_matches = self.syntax.matches(offset_range, self, |grammar| {
5054 grammar
5055 .redactions_config
5056 .as_ref()
5057 .map(|config| &config.query)
5058 });
5059
5060 let configs = syntax_matches
5061 .grammars()
5062 .iter()
5063 .map(|grammar| grammar.redactions_config.as_ref())
5064 .collect::<Vec<_>>();
5065
5066 iter::from_fn(move || {
5067 let redacted_range = syntax_matches
5068 .peek()
5069 .and_then(|mat| {
5070 configs[mat.grammar_index].and_then(|config| {
5071 mat.captures
5072 .iter()
5073 .find(|capture| capture.index == config.redaction_capture_ix)
5074 })
5075 })
5076 .map(|mat| mat.node.byte_range());
5077 syntax_matches.advance();
5078 redacted_range
5079 })
5080 }
5081
5082 pub fn injections_intersecting_range<T: ToOffset>(
5083 &self,
5084 range: Range<T>,
5085 ) -> impl Iterator<Item = (Range<usize>, &Arc<Language>)> + '_ {
5086 let offset_range = range.start.to_offset(self)..range.end.to_offset(self);
5087
5088 let mut syntax_matches = self.syntax.matches(offset_range, self, |grammar| {
5089 grammar
5090 .injection_config
5091 .as_ref()
5092 .map(|config| &config.query)
5093 });
5094
5095 let configs = syntax_matches
5096 .grammars()
5097 .iter()
5098 .map(|grammar| grammar.injection_config.as_ref())
5099 .collect::<Vec<_>>();
5100
5101 iter::from_fn(move || {
5102 let ranges = syntax_matches.peek().and_then(|mat| {
5103 let config = &configs[mat.grammar_index]?;
5104 let content_capture_range = mat.captures.iter().find_map(|capture| {
5105 if capture.index == config.content_capture_ix {
5106 Some(capture.node.byte_range())
5107 } else {
5108 None
5109 }
5110 })?;
5111 let language = self.language_at(content_capture_range.start)?;
5112 Some((content_capture_range, language))
5113 });
5114 syntax_matches.advance();
5115 ranges
5116 })
5117 }
5118
5119 pub fn runnable_ranges(
5120 &self,
5121 offset_range: Range<usize>,
5122 ) -> impl Iterator<Item = RunnableRange> + '_ {
5123 let mut syntax_matches = self.syntax.matches(offset_range, self, |grammar| {
5124 grammar.runnable_config.as_ref().map(|config| &config.query)
5125 });
5126
5127 let test_configs = syntax_matches
5128 .grammars()
5129 .iter()
5130 .map(|grammar| grammar.runnable_config.as_ref())
5131 .collect::<Vec<_>>();
5132
5133 iter::from_fn(move || {
5134 loop {
5135 let mat = syntax_matches.peek()?;
5136
5137 let test_range = test_configs[mat.grammar_index].and_then(|test_configs| {
5138 let mut run_range = None;
5139 let full_range = mat.captures.iter().fold(
5140 Range {
5141 start: usize::MAX,
5142 end: 0,
5143 },
5144 |mut acc, next| {
5145 let byte_range = next.node.byte_range();
5146 if acc.start > byte_range.start {
5147 acc.start = byte_range.start;
5148 }
5149 if acc.end < byte_range.end {
5150 acc.end = byte_range.end;
5151 }
5152 acc
5153 },
5154 );
5155 if full_range.start > full_range.end {
5156 // We did not find a full spanning range of this match.
5157 return None;
5158 }
5159 let extra_captures: SmallVec<[_; 1]> =
5160 SmallVec::from_iter(mat.captures.iter().filter_map(|capture| {
5161 test_configs
5162 .extra_captures
5163 .get(capture.index as usize)
5164 .cloned()
5165 .and_then(|tag_name| match tag_name {
5166 RunnableCapture::Named(name) => {
5167 Some((capture.node.byte_range(), name))
5168 }
5169 RunnableCapture::Run => {
5170 let _ = run_range.insert(capture.node.byte_range());
5171 None
5172 }
5173 })
5174 }));
5175 let run_range = run_range?;
5176 let tags = test_configs
5177 .query
5178 .property_settings(mat.pattern_index)
5179 .iter()
5180 .filter_map(|property| {
5181 if *property.key == *"tag" {
5182 property
5183 .value
5184 .as_ref()
5185 .map(|value| RunnableTag(value.to_string().into()))
5186 } else {
5187 None
5188 }
5189 })
5190 .collect();
5191 let extra_captures = extra_captures
5192 .into_iter()
5193 .map(|(range, name)| {
5194 (
5195 name.to_string(),
5196 self.text_for_range(range).collect::<String>(),
5197 )
5198 })
5199 .collect();
5200 // All tags should have the same range.
5201 Some(RunnableRange {
5202 run_range,
5203 full_range,
5204 runnable: Runnable {
5205 tags,
5206 language: mat.language,
5207 buffer: self.remote_id(),
5208 },
5209 extra_captures,
5210 buffer_id: self.remote_id(),
5211 })
5212 });
5213
5214 syntax_matches.advance();
5215 if test_range.is_some() {
5216 // It's fine for us to short-circuit on .peek()? returning None. We don't want to return None from this iter if we
5217 // had a capture that did not contain a run marker, hence we'll just loop around for the next capture.
5218 return test_range;
5219 }
5220 }
5221 })
5222 }
5223
5224 /// Returns selections for remote peers intersecting the given range.
5225 #[allow(clippy::type_complexity)]
5226 pub fn selections_in_range(
5227 &self,
5228 range: Range<Anchor>,
5229 include_local: bool,
5230 ) -> impl Iterator<
5231 Item = (
5232 ReplicaId,
5233 bool,
5234 CursorShape,
5235 impl Iterator<Item = &Selection<Anchor>> + '_,
5236 ),
5237 > + '_ {
5238 self.remote_selections
5239 .iter()
5240 .filter(move |(replica_id, set)| {
5241 (include_local || **replica_id != self.text.replica_id())
5242 && !set.selections.is_empty()
5243 })
5244 .map(move |(replica_id, set)| {
5245 let start_ix = match set.selections.binary_search_by(|probe| {
5246 probe.end.cmp(&range.start, self).then(Ordering::Greater)
5247 }) {
5248 Ok(ix) | Err(ix) => ix,
5249 };
5250 let end_ix = match set.selections.binary_search_by(|probe| {
5251 probe.start.cmp(&range.end, self).then(Ordering::Less)
5252 }) {
5253 Ok(ix) | Err(ix) => ix,
5254 };
5255
5256 (
5257 *replica_id,
5258 set.line_mode,
5259 set.cursor_shape,
5260 set.selections[start_ix..end_ix].iter(),
5261 )
5262 })
5263 }
5264
5265 /// Returns if the buffer contains any diagnostics.
5266 pub fn has_diagnostics(&self) -> bool {
5267 !self.diagnostics.is_empty()
5268 }
5269
5270 /// Returns all the diagnostics intersecting the given range.
5271 pub fn diagnostics_in_range<'a, T, O>(
5272 &'a self,
5273 search_range: Range<T>,
5274 reversed: bool,
5275 ) -> impl 'a + Iterator<Item = DiagnosticEntryRef<'a, O>>
5276 where
5277 T: 'a + Clone + ToOffset,
5278 O: 'a + FromAnchor,
5279 {
5280 let mut iterators: Vec<_> = self
5281 .diagnostics
5282 .iter()
5283 .map(|(_, collection)| {
5284 collection
5285 .range::<T, text::Anchor>(search_range.clone(), self, true, reversed)
5286 .peekable()
5287 })
5288 .collect();
5289
5290 std::iter::from_fn(move || {
5291 let (next_ix, _) = iterators
5292 .iter_mut()
5293 .enumerate()
5294 .flat_map(|(ix, iter)| Some((ix, iter.peek()?)))
5295 .min_by(|(_, a), (_, b)| {
5296 let cmp = a
5297 .range
5298 .start
5299 .cmp(&b.range.start, self)
5300 // when range is equal, sort by diagnostic severity
5301 .then(a.diagnostic.severity.cmp(&b.diagnostic.severity))
5302 // and stabilize order with group_id
5303 .then(a.diagnostic.group_id.cmp(&b.diagnostic.group_id));
5304 if reversed { cmp.reverse() } else { cmp }
5305 })?;
5306 iterators[next_ix]
5307 .next()
5308 .map(
5309 |DiagnosticEntryRef { range, diagnostic }| DiagnosticEntryRef {
5310 diagnostic,
5311 range: FromAnchor::from_anchor(&range.start, self)
5312 ..FromAnchor::from_anchor(&range.end, self),
5313 },
5314 )
5315 })
5316 }
5317
5318 /// Returns all the diagnostic groups associated with the given
5319 /// language server ID. If no language server ID is provided,
5320 /// all diagnostics groups are returned.
5321 pub fn diagnostic_groups(
5322 &self,
5323 language_server_id: Option<LanguageServerId>,
5324 ) -> Vec<(LanguageServerId, DiagnosticGroup<'_, Anchor>)> {
5325 let mut groups = Vec::new();
5326
5327 if let Some(language_server_id) = language_server_id {
5328 if let Some(set) = self.diagnostics.get(&language_server_id) {
5329 set.groups(language_server_id, &mut groups, self);
5330 }
5331 } else {
5332 for (language_server_id, diagnostics) in self.diagnostics.iter() {
5333 diagnostics.groups(*language_server_id, &mut groups, self);
5334 }
5335 }
5336
5337 groups.sort_by(|(id_a, group_a), (id_b, group_b)| {
5338 let a_start = &group_a.entries[group_a.primary_ix].range.start;
5339 let b_start = &group_b.entries[group_b.primary_ix].range.start;
5340 a_start.cmp(b_start, self).then_with(|| id_a.cmp(id_b))
5341 });
5342
5343 groups
5344 }
5345
5346 /// Returns an iterator over the diagnostics for the given group.
5347 pub fn diagnostic_group<O>(
5348 &self,
5349 group_id: usize,
5350 ) -> impl Iterator<Item = DiagnosticEntryRef<'_, O>> + use<'_, O>
5351 where
5352 O: FromAnchor + 'static,
5353 {
5354 self.diagnostics
5355 .iter()
5356 .flat_map(move |(_, set)| set.group(group_id, self))
5357 }
5358
5359 /// An integer version number that accounts for all updates besides
5360 /// the buffer's text itself (which is versioned via a version vector).
5361 pub fn non_text_state_update_count(&self) -> usize {
5362 self.non_text_state_update_count
5363 }
5364
5365 /// An integer version that changes when the buffer's syntax changes.
5366 pub fn syntax_update_count(&self) -> usize {
5367 self.syntax.update_count()
5368 }
5369
5370 /// Returns a snapshot of underlying file.
5371 pub fn file(&self) -> Option<&Arc<dyn File>> {
5372 self.file.as_ref()
5373 }
5374
5375 pub fn resolve_file_path(&self, include_root: bool, cx: &App) -> Option<String> {
5376 if let Some(file) = self.file() {
5377 if file.path().file_name().is_none() || include_root {
5378 Some(file.full_path(cx).to_string_lossy().into_owned())
5379 } else {
5380 Some(file.path().display(file.path_style(cx)).to_string())
5381 }
5382 } else {
5383 None
5384 }
5385 }
5386
5387 pub fn words_in_range(&self, query: WordsQuery) -> BTreeMap<String, Range<Anchor>> {
5388 let query_str = query.fuzzy_contents;
5389 if query_str.is_some_and(|query| query.is_empty()) {
5390 return BTreeMap::default();
5391 }
5392
5393 let classifier = CharClassifier::new(self.language.clone().map(|language| LanguageScope {
5394 language,
5395 override_id: None,
5396 }));
5397
5398 let mut query_ix = 0;
5399 let query_chars = query_str.map(|query| query.chars().collect::<Vec<_>>());
5400 let query_len = query_chars.as_ref().map_or(0, |query| query.len());
5401
5402 let mut words = BTreeMap::default();
5403 let mut current_word_start_ix = None;
5404 let mut chunk_ix = query.range.start;
5405 for chunk in self.chunks(query.range, false) {
5406 for (i, c) in chunk.text.char_indices() {
5407 let ix = chunk_ix + i;
5408 if classifier.is_word(c) {
5409 if current_word_start_ix.is_none() {
5410 current_word_start_ix = Some(ix);
5411 }
5412
5413 if let Some(query_chars) = &query_chars
5414 && query_ix < query_len
5415 && c.to_lowercase().eq(query_chars[query_ix].to_lowercase())
5416 {
5417 query_ix += 1;
5418 }
5419 continue;
5420 } else if let Some(word_start) = current_word_start_ix.take()
5421 && query_ix == query_len
5422 {
5423 let word_range = self.anchor_before(word_start)..self.anchor_after(ix);
5424 let mut word_text = self.text_for_range(word_start..ix).peekable();
5425 let first_char = word_text
5426 .peek()
5427 .and_then(|first_chunk| first_chunk.chars().next());
5428 // Skip empty and "words" starting with digits as a heuristic to reduce useless completions
5429 if !query.skip_digits
5430 || first_char.is_none_or(|first_char| !first_char.is_digit(10))
5431 {
5432 words.insert(word_text.collect(), word_range);
5433 }
5434 }
5435 query_ix = 0;
5436 }
5437 chunk_ix += chunk.text.len();
5438 }
5439
5440 words
5441 }
5442}
5443
5444pub struct WordsQuery<'a> {
5445 /// Only returns words with all chars from the fuzzy string in them.
5446 pub fuzzy_contents: Option<&'a str>,
5447 /// Skips words that start with a digit.
5448 pub skip_digits: bool,
5449 /// Buffer offset range, to look for words.
5450 pub range: Range<usize>,
5451}
5452
5453fn indent_size_for_line(text: &text::BufferSnapshot, row: u32) -> IndentSize {
5454 indent_size_for_text(text.chars_at(Point::new(row, 0)))
5455}
5456
5457fn indent_size_for_text(text: impl Iterator<Item = char>) -> IndentSize {
5458 let mut result = IndentSize::spaces(0);
5459 for c in text {
5460 let kind = match c {
5461 ' ' => IndentKind::Space,
5462 '\t' => IndentKind::Tab,
5463 _ => break,
5464 };
5465 if result.len == 0 {
5466 result.kind = kind;
5467 }
5468 result.len += 1;
5469 }
5470 result
5471}
5472
5473impl Clone for BufferSnapshot {
5474 fn clone(&self) -> Self {
5475 Self {
5476 text: self.text.clone(),
5477 syntax: self.syntax.clone(),
5478 file: self.file.clone(),
5479 remote_selections: self.remote_selections.clone(),
5480 diagnostics: self.diagnostics.clone(),
5481 language: self.language.clone(),
5482 tree_sitter_data: self.tree_sitter_data.clone(),
5483 non_text_state_update_count: self.non_text_state_update_count,
5484 capability: self.capability,
5485 modeline: self.modeline.clone(),
5486 }
5487 }
5488}
5489
5490impl Deref for BufferSnapshot {
5491 type Target = text::BufferSnapshot;
5492
5493 fn deref(&self) -> &Self::Target {
5494 &self.text
5495 }
5496}
5497
5498unsafe impl Send for BufferChunks<'_> {}
5499
5500impl<'a> BufferChunks<'a> {
5501 pub(crate) fn new(
5502 text: &'a Rope,
5503 range: Range<usize>,
5504 syntax: Option<(SyntaxMapCaptures<'a>, Vec<HighlightMap>)>,
5505 diagnostics: bool,
5506 buffer_snapshot: Option<&'a BufferSnapshot>,
5507 ) -> Self {
5508 let mut highlights = None;
5509 if let Some((captures, highlight_maps)) = syntax {
5510 highlights = Some(BufferChunkHighlights {
5511 captures,
5512 next_capture: None,
5513 stack: Default::default(),
5514 highlight_maps,
5515 })
5516 }
5517
5518 let diagnostic_endpoints = diagnostics.then(|| Vec::new().into_iter().peekable());
5519 let chunks = text.chunks_in_range(range.clone());
5520
5521 let mut this = BufferChunks {
5522 range,
5523 buffer_snapshot,
5524 chunks,
5525 diagnostic_endpoints,
5526 error_depth: 0,
5527 warning_depth: 0,
5528 information_depth: 0,
5529 hint_depth: 0,
5530 unnecessary_depth: 0,
5531 underline: true,
5532 highlights,
5533 };
5534 this.initialize_diagnostic_endpoints();
5535 this
5536 }
5537
5538 /// Seeks to the given byte offset in the buffer.
5539 pub fn seek(&mut self, range: Range<usize>) {
5540 let old_range = std::mem::replace(&mut self.range, range.clone());
5541 self.chunks.set_range(self.range.clone());
5542 if let Some(highlights) = self.highlights.as_mut() {
5543 if old_range.start <= self.range.start && old_range.end >= self.range.end {
5544 // Reuse existing highlights stack, as the new range is a subrange of the old one.
5545 highlights
5546 .stack
5547 .retain(|(end_offset, _)| *end_offset > range.start);
5548 if let Some(capture) = &highlights.next_capture
5549 && range.start >= capture.node.start_byte()
5550 {
5551 let next_capture_end = capture.node.end_byte();
5552 if range.start < next_capture_end
5553 && let Some(capture_id) =
5554 highlights.highlight_maps[capture.grammar_index].get(capture.index)
5555 {
5556 highlights.stack.push((next_capture_end, capture_id));
5557 }
5558 highlights.next_capture.take();
5559 }
5560 } else if let Some(snapshot) = self.buffer_snapshot {
5561 let (captures, highlight_maps) = snapshot.get_highlights(self.range.clone());
5562 *highlights = BufferChunkHighlights {
5563 captures,
5564 next_capture: None,
5565 stack: Default::default(),
5566 highlight_maps,
5567 };
5568 } else {
5569 // We cannot obtain new highlights for a language-aware buffer iterator, as we don't have a buffer snapshot.
5570 // Seeking such BufferChunks is not supported.
5571 debug_assert!(
5572 false,
5573 "Attempted to seek on a language-aware buffer iterator without associated buffer snapshot"
5574 );
5575 }
5576
5577 highlights.captures.set_byte_range(self.range.clone());
5578 self.initialize_diagnostic_endpoints();
5579 }
5580 }
5581
5582 fn initialize_diagnostic_endpoints(&mut self) {
5583 if let Some(diagnostics) = self.diagnostic_endpoints.as_mut()
5584 && let Some(buffer) = self.buffer_snapshot
5585 {
5586 let mut diagnostic_endpoints = Vec::new();
5587 for entry in buffer.diagnostics_in_range::<_, usize>(self.range.clone(), false) {
5588 diagnostic_endpoints.push(DiagnosticEndpoint {
5589 offset: entry.range.start,
5590 is_start: true,
5591 severity: entry.diagnostic.severity,
5592 is_unnecessary: entry.diagnostic.is_unnecessary,
5593 underline: entry.diagnostic.underline,
5594 });
5595 diagnostic_endpoints.push(DiagnosticEndpoint {
5596 offset: entry.range.end,
5597 is_start: false,
5598 severity: entry.diagnostic.severity,
5599 is_unnecessary: entry.diagnostic.is_unnecessary,
5600 underline: entry.diagnostic.underline,
5601 });
5602 }
5603 diagnostic_endpoints
5604 .sort_unstable_by_key(|endpoint| (endpoint.offset, !endpoint.is_start));
5605 *diagnostics = diagnostic_endpoints.into_iter().peekable();
5606 self.hint_depth = 0;
5607 self.error_depth = 0;
5608 self.warning_depth = 0;
5609 self.information_depth = 0;
5610 }
5611 }
5612
5613 /// The current byte offset in the buffer.
5614 pub fn offset(&self) -> usize {
5615 self.range.start
5616 }
5617
5618 pub fn range(&self) -> Range<usize> {
5619 self.range.clone()
5620 }
5621
5622 fn update_diagnostic_depths(&mut self, endpoint: DiagnosticEndpoint) {
5623 let depth = match endpoint.severity {
5624 DiagnosticSeverity::ERROR => &mut self.error_depth,
5625 DiagnosticSeverity::WARNING => &mut self.warning_depth,
5626 DiagnosticSeverity::INFORMATION => &mut self.information_depth,
5627 DiagnosticSeverity::HINT => &mut self.hint_depth,
5628 _ => return,
5629 };
5630 if endpoint.is_start {
5631 *depth += 1;
5632 } else {
5633 *depth -= 1;
5634 }
5635
5636 if endpoint.is_unnecessary {
5637 if endpoint.is_start {
5638 self.unnecessary_depth += 1;
5639 } else {
5640 self.unnecessary_depth -= 1;
5641 }
5642 }
5643 }
5644
5645 fn current_diagnostic_severity(&self) -> Option<DiagnosticSeverity> {
5646 if self.error_depth > 0 {
5647 Some(DiagnosticSeverity::ERROR)
5648 } else if self.warning_depth > 0 {
5649 Some(DiagnosticSeverity::WARNING)
5650 } else if self.information_depth > 0 {
5651 Some(DiagnosticSeverity::INFORMATION)
5652 } else if self.hint_depth > 0 {
5653 Some(DiagnosticSeverity::HINT)
5654 } else {
5655 None
5656 }
5657 }
5658
5659 fn current_code_is_unnecessary(&self) -> bool {
5660 self.unnecessary_depth > 0
5661 }
5662}
5663
5664impl<'a> Iterator for BufferChunks<'a> {
5665 type Item = Chunk<'a>;
5666
5667 fn next(&mut self) -> Option<Self::Item> {
5668 let mut next_capture_start = usize::MAX;
5669 let mut next_diagnostic_endpoint = usize::MAX;
5670
5671 if let Some(highlights) = self.highlights.as_mut() {
5672 while let Some((parent_capture_end, _)) = highlights.stack.last() {
5673 if *parent_capture_end <= self.range.start {
5674 highlights.stack.pop();
5675 } else {
5676 break;
5677 }
5678 }
5679
5680 if highlights.next_capture.is_none() {
5681 highlights.next_capture = highlights.captures.next();
5682 }
5683
5684 while let Some(capture) = highlights.next_capture.as_ref() {
5685 if self.range.start < capture.node.start_byte() {
5686 next_capture_start = capture.node.start_byte();
5687 break;
5688 } else {
5689 let highlight_id =
5690 highlights.highlight_maps[capture.grammar_index].get(capture.index);
5691 if let Some(highlight_id) = highlight_id {
5692 highlights
5693 .stack
5694 .push((capture.node.end_byte(), highlight_id));
5695 }
5696 highlights.next_capture = highlights.captures.next();
5697 }
5698 }
5699 }
5700
5701 let mut diagnostic_endpoints = std::mem::take(&mut self.diagnostic_endpoints);
5702 if let Some(diagnostic_endpoints) = diagnostic_endpoints.as_mut() {
5703 while let Some(endpoint) = diagnostic_endpoints.peek().copied() {
5704 if endpoint.offset <= self.range.start {
5705 self.update_diagnostic_depths(endpoint);
5706 diagnostic_endpoints.next();
5707 self.underline = endpoint.underline;
5708 } else {
5709 next_diagnostic_endpoint = endpoint.offset;
5710 break;
5711 }
5712 }
5713 }
5714 self.diagnostic_endpoints = diagnostic_endpoints;
5715
5716 if let Some(ChunkBitmaps {
5717 text: chunk,
5718 chars: chars_map,
5719 tabs,
5720 newlines,
5721 }) = self.chunks.peek_with_bitmaps()
5722 {
5723 let chunk_start = self.range.start;
5724 let mut chunk_end = (self.chunks.offset() + chunk.len())
5725 .min(next_capture_start)
5726 .min(next_diagnostic_endpoint);
5727 let mut highlight_id = None;
5728 if let Some(highlights) = self.highlights.as_ref()
5729 && let Some((parent_capture_end, parent_highlight_id)) = highlights.stack.last()
5730 {
5731 chunk_end = chunk_end.min(*parent_capture_end);
5732 highlight_id = Some(*parent_highlight_id);
5733 }
5734 let bit_start = chunk_start - self.chunks.offset();
5735 let bit_end = chunk_end - self.chunks.offset();
5736
5737 let slice = &chunk[bit_start..bit_end];
5738
5739 let mask = 1u128.unbounded_shl(bit_end as u32).wrapping_sub(1);
5740 let tabs = (tabs >> bit_start) & mask;
5741 let chars = (chars_map >> bit_start) & mask;
5742 let newlines = (newlines >> bit_start) & mask;
5743
5744 self.range.start = chunk_end;
5745 if self.range.start == self.chunks.offset() + chunk.len() {
5746 self.chunks.next().unwrap();
5747 }
5748
5749 Some(Chunk {
5750 text: slice,
5751 syntax_highlight_id: highlight_id,
5752 underline: self.underline,
5753 diagnostic_severity: self.current_diagnostic_severity(),
5754 is_unnecessary: self.current_code_is_unnecessary(),
5755 tabs,
5756 chars,
5757 newlines,
5758 ..Chunk::default()
5759 })
5760 } else {
5761 None
5762 }
5763 }
5764}
5765
5766impl operation_queue::Operation for Operation {
5767 fn lamport_timestamp(&self) -> clock::Lamport {
5768 match self {
5769 Operation::Buffer(_) => {
5770 unreachable!("buffer operations should never be deferred at this layer")
5771 }
5772 Operation::UpdateDiagnostics {
5773 lamport_timestamp, ..
5774 }
5775 | Operation::UpdateSelections {
5776 lamport_timestamp, ..
5777 }
5778 | Operation::UpdateCompletionTriggers {
5779 lamport_timestamp, ..
5780 }
5781 | Operation::UpdateLineEnding {
5782 lamport_timestamp, ..
5783 } => *lamport_timestamp,
5784 }
5785 }
5786}
5787
5788impl IndentSize {
5789 /// Returns an [`IndentSize`] representing the given spaces.
5790 pub fn spaces(len: u32) -> Self {
5791 Self {
5792 len,
5793 kind: IndentKind::Space,
5794 }
5795 }
5796
5797 /// Returns an [`IndentSize`] representing a tab.
5798 pub fn tab() -> Self {
5799 Self {
5800 len: 1,
5801 kind: IndentKind::Tab,
5802 }
5803 }
5804
5805 /// An iterator over the characters represented by this [`IndentSize`].
5806 pub fn chars(&self) -> impl Iterator<Item = char> {
5807 iter::repeat(self.char()).take(self.len as usize)
5808 }
5809
5810 /// The character representation of this [`IndentSize`].
5811 pub fn char(&self) -> char {
5812 match self.kind {
5813 IndentKind::Space => ' ',
5814 IndentKind::Tab => '\t',
5815 }
5816 }
5817
5818 /// Consumes the current [`IndentSize`] and returns a new one that has
5819 /// been shrunk or enlarged by the given size along the given direction.
5820 pub fn with_delta(mut self, direction: Ordering, size: IndentSize) -> Self {
5821 match direction {
5822 Ordering::Less => {
5823 if self.kind == size.kind && self.len >= size.len {
5824 self.len -= size.len;
5825 }
5826 }
5827 Ordering::Equal => {}
5828 Ordering::Greater => {
5829 if self.len == 0 {
5830 self = size;
5831 } else if self.kind == size.kind {
5832 self.len += size.len;
5833 }
5834 }
5835 }
5836 self
5837 }
5838
5839 pub fn len_with_expanded_tabs(&self, tab_size: NonZeroU32) -> usize {
5840 match self.kind {
5841 IndentKind::Space => self.len as usize,
5842 IndentKind::Tab => self.len as usize * tab_size.get() as usize,
5843 }
5844 }
5845}
5846
5847#[cfg(any(test, feature = "test-support"))]
5848pub struct TestFile {
5849 pub path: Arc<RelPath>,
5850 pub root_name: String,
5851 pub local_root: Option<PathBuf>,
5852}
5853
5854#[cfg(any(test, feature = "test-support"))]
5855impl File for TestFile {
5856 fn path(&self) -> &Arc<RelPath> {
5857 &self.path
5858 }
5859
5860 fn full_path(&self, _: &gpui::App) -> PathBuf {
5861 PathBuf::from(self.root_name.clone()).join(self.path.as_std_path())
5862 }
5863
5864 fn as_local(&self) -> Option<&dyn LocalFile> {
5865 if self.local_root.is_some() {
5866 Some(self)
5867 } else {
5868 None
5869 }
5870 }
5871
5872 fn disk_state(&self) -> DiskState {
5873 unimplemented!()
5874 }
5875
5876 fn file_name<'a>(&'a self, _: &'a gpui::App) -> &'a str {
5877 self.path().file_name().unwrap_or(self.root_name.as_ref())
5878 }
5879
5880 fn worktree_id(&self, _: &App) -> WorktreeId {
5881 WorktreeId::from_usize(0)
5882 }
5883
5884 fn to_proto(&self, _: &App) -> rpc::proto::File {
5885 unimplemented!()
5886 }
5887
5888 fn is_private(&self) -> bool {
5889 false
5890 }
5891
5892 fn path_style(&self, _cx: &App) -> PathStyle {
5893 PathStyle::local()
5894 }
5895}
5896
5897#[cfg(any(test, feature = "test-support"))]
5898impl LocalFile for TestFile {
5899 fn abs_path(&self, _cx: &App) -> PathBuf {
5900 PathBuf::from(self.local_root.as_ref().unwrap())
5901 .join(&self.root_name)
5902 .join(self.path.as_std_path())
5903 }
5904
5905 fn load(&self, _cx: &App) -> Task<Result<String>> {
5906 unimplemented!()
5907 }
5908
5909 fn load_bytes(&self, _cx: &App) -> Task<Result<Vec<u8>>> {
5910 unimplemented!()
5911 }
5912}
5913
5914pub(crate) fn contiguous_ranges(
5915 values: impl Iterator<Item = u32>,
5916 max_len: usize,
5917) -> impl Iterator<Item = Range<u32>> {
5918 let mut values = values;
5919 let mut current_range: Option<Range<u32>> = None;
5920 std::iter::from_fn(move || {
5921 loop {
5922 if let Some(value) = values.next() {
5923 if let Some(range) = &mut current_range
5924 && value == range.end
5925 && range.len() < max_len
5926 {
5927 range.end += 1;
5928 continue;
5929 }
5930
5931 let prev_range = current_range.clone();
5932 current_range = Some(value..(value + 1));
5933 if prev_range.is_some() {
5934 return prev_range;
5935 }
5936 } else {
5937 return current_range.take();
5938 }
5939 }
5940 })
5941}
5942
5943#[derive(Default, Debug)]
5944pub struct CharClassifier {
5945 scope: Option<LanguageScope>,
5946 scope_context: Option<CharScopeContext>,
5947 ignore_punctuation: bool,
5948}
5949
5950impl CharClassifier {
5951 pub fn new(scope: Option<LanguageScope>) -> Self {
5952 Self {
5953 scope,
5954 scope_context: None,
5955 ignore_punctuation: false,
5956 }
5957 }
5958
5959 pub fn scope_context(self, scope_context: Option<CharScopeContext>) -> Self {
5960 Self {
5961 scope_context,
5962 ..self
5963 }
5964 }
5965
5966 pub fn ignore_punctuation(self, ignore_punctuation: bool) -> Self {
5967 Self {
5968 ignore_punctuation,
5969 ..self
5970 }
5971 }
5972
5973 pub fn is_whitespace(&self, c: char) -> bool {
5974 self.kind(c) == CharKind::Whitespace
5975 }
5976
5977 pub fn is_word(&self, c: char) -> bool {
5978 self.kind(c) == CharKind::Word
5979 }
5980
5981 pub fn is_punctuation(&self, c: char) -> bool {
5982 self.kind(c) == CharKind::Punctuation
5983 }
5984
5985 pub fn kind_with(&self, c: char, ignore_punctuation: bool) -> CharKind {
5986 if c.is_alphanumeric() || c == '_' {
5987 return CharKind::Word;
5988 }
5989
5990 if let Some(scope) = &self.scope {
5991 let characters = match self.scope_context {
5992 Some(CharScopeContext::Completion) => scope.completion_query_characters(),
5993 Some(CharScopeContext::LinkedEdit) => scope.linked_edit_characters(),
5994 None => scope.word_characters(),
5995 };
5996 if let Some(characters) = characters
5997 && characters.contains(&c)
5998 {
5999 return CharKind::Word;
6000 }
6001 }
6002
6003 if c.is_whitespace() {
6004 return CharKind::Whitespace;
6005 }
6006
6007 if ignore_punctuation {
6008 CharKind::Word
6009 } else {
6010 CharKind::Punctuation
6011 }
6012 }
6013
6014 pub fn kind(&self, c: char) -> CharKind {
6015 self.kind_with(c, self.ignore_punctuation)
6016 }
6017}
6018
6019/// Find all of the ranges of whitespace that occur at the ends of lines
6020/// in the given rope.
6021///
6022/// This could also be done with a regex search, but this implementation
6023/// avoids copying text.
6024pub fn trailing_whitespace_ranges(rope: &Rope) -> Vec<Range<usize>> {
6025 let mut ranges = Vec::new();
6026
6027 let mut offset = 0;
6028 let mut prev_chunk_trailing_whitespace_range = 0..0;
6029 for chunk in rope.chunks() {
6030 let mut prev_line_trailing_whitespace_range = 0..0;
6031 for (i, line) in chunk.split('\n').enumerate() {
6032 let line_end_offset = offset + line.len();
6033 let trimmed_line_len = line.trim_end_matches([' ', '\t']).len();
6034 let mut trailing_whitespace_range = (offset + trimmed_line_len)..line_end_offset;
6035
6036 if i == 0 && trimmed_line_len == 0 {
6037 trailing_whitespace_range.start = prev_chunk_trailing_whitespace_range.start;
6038 }
6039 if !prev_line_trailing_whitespace_range.is_empty() {
6040 ranges.push(prev_line_trailing_whitespace_range);
6041 }
6042
6043 offset = line_end_offset + 1;
6044 prev_line_trailing_whitespace_range = trailing_whitespace_range;
6045 }
6046
6047 offset -= 1;
6048 prev_chunk_trailing_whitespace_range = prev_line_trailing_whitespace_range;
6049 }
6050
6051 if !prev_chunk_trailing_whitespace_range.is_empty() {
6052 ranges.push(prev_chunk_trailing_whitespace_range);
6053 }
6054
6055 ranges
6056}