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