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