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::{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,
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, 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, auto_indent)) = previous_setting
2742 && cached_language_id == language_id
2743 {
2744 auto_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 =
2749 language_settings(language.map(|l| l.name()), None, cx).auto_indent;
2750 previous_setting = Some((language_id, auto_indent));
2751 auto_indent
2752 }
2753 })
2754 .map(|((ix, (range, _)), new_text)| {
2755 let new_text_length = new_text.len();
2756 let old_start = range.start.to_point(&before_edit);
2757 let new_start = (delta + range.start as isize) as usize;
2758 let range_len = range.end - range.start;
2759 delta += new_text_length as isize - range_len as isize;
2760
2761 // Decide what range of the insertion to auto-indent, and whether
2762 // the first line of the insertion should be considered a newly-inserted line
2763 // or an edit to an existing line.
2764 let mut range_of_insertion_to_indent = 0..new_text_length;
2765 let mut first_line_is_new = true;
2766
2767 let old_line_start = before_edit.indent_size_for_line(old_start.row).len;
2768 let old_line_end = before_edit.line_len(old_start.row);
2769
2770 if old_start.column > old_line_start {
2771 first_line_is_new = false;
2772 }
2773
2774 if !new_text.contains('\n')
2775 && (old_start.column + (range_len as u32) < old_line_end
2776 || old_line_end == old_line_start)
2777 {
2778 first_line_is_new = false;
2779 }
2780
2781 // When inserting text starting with a newline, avoid auto-indenting the
2782 // previous line.
2783 if new_text.starts_with('\n') {
2784 range_of_insertion_to_indent.start += 1;
2785 first_line_is_new = true;
2786 }
2787
2788 let mut original_indent_column = None;
2789 if let AutoindentMode::Block {
2790 original_indent_columns,
2791 } = &mode
2792 {
2793 original_indent_column = Some(if new_text.starts_with('\n') {
2794 indent_size_for_text(
2795 new_text[range_of_insertion_to_indent.clone()].chars(),
2796 )
2797 .len
2798 } else {
2799 original_indent_columns
2800 .get(ix)
2801 .copied()
2802 .flatten()
2803 .unwrap_or_else(|| {
2804 indent_size_for_text(
2805 new_text[range_of_insertion_to_indent.clone()].chars(),
2806 )
2807 .len
2808 })
2809 });
2810
2811 // Avoid auto-indenting the line after the edit.
2812 if new_text[range_of_insertion_to_indent.clone()].ends_with('\n') {
2813 range_of_insertion_to_indent.end -= 1;
2814 }
2815 }
2816
2817 AutoindentRequestEntry {
2818 original_indent_column,
2819 old_row: if first_line_is_new {
2820 None
2821 } else {
2822 Some(old_start.row)
2823 },
2824 indent_size: before_edit.language_indent_size_at(range.start, cx),
2825 range: self.anchor_before(new_start + range_of_insertion_to_indent.start)
2826 ..self.anchor_after(new_start + range_of_insertion_to_indent.end),
2827 }
2828 })
2829 .collect();
2830
2831 if !entries.is_empty() {
2832 self.autoindent_requests.push(Arc::new(AutoindentRequest {
2833 before_edit,
2834 entries,
2835 is_block_mode: matches!(mode, AutoindentMode::Block { .. }),
2836 ignore_empty_lines: false,
2837 }));
2838 }
2839 }
2840
2841 self.end_transaction(cx);
2842 self.send_operation(Operation::Buffer(edit_operation), true, cx);
2843 Some(edit_id)
2844 }
2845
2846 fn did_edit(&mut self, old_version: &clock::Global, was_dirty: bool, cx: &mut Context<Self>) {
2847 self.was_changed();
2848
2849 if self.edits_since::<usize>(old_version).next().is_none() {
2850 return;
2851 }
2852
2853 self.reparse(cx, true);
2854 cx.emit(BufferEvent::Edited);
2855 if was_dirty != self.is_dirty() {
2856 cx.emit(BufferEvent::DirtyChanged);
2857 }
2858 cx.notify();
2859 }
2860
2861 pub fn autoindent_ranges<I, T>(&mut self, ranges: I, cx: &mut Context<Self>)
2862 where
2863 I: IntoIterator<Item = Range<T>>,
2864 T: ToOffset + Copy,
2865 {
2866 let before_edit = self.snapshot();
2867 let entries = ranges
2868 .into_iter()
2869 .map(|range| AutoindentRequestEntry {
2870 range: before_edit.anchor_before(range.start)..before_edit.anchor_after(range.end),
2871 old_row: None,
2872 indent_size: before_edit.language_indent_size_at(range.start, cx),
2873 original_indent_column: None,
2874 })
2875 .collect();
2876 self.autoindent_requests.push(Arc::new(AutoindentRequest {
2877 before_edit,
2878 entries,
2879 is_block_mode: false,
2880 ignore_empty_lines: true,
2881 }));
2882 self.request_autoindent(cx, Some(Duration::from_micros(300)));
2883 }
2884
2885 // Inserts newlines at the given position to create an empty line, returning the start of the new line.
2886 // You can also request the insertion of empty lines above and below the line starting at the returned point.
2887 pub fn insert_empty_line(
2888 &mut self,
2889 position: impl ToPoint,
2890 space_above: bool,
2891 space_below: bool,
2892 cx: &mut Context<Self>,
2893 ) -> Point {
2894 let mut position = position.to_point(self);
2895
2896 self.start_transaction();
2897
2898 self.edit(
2899 [(position..position, "\n")],
2900 Some(AutoindentMode::EachLine),
2901 cx,
2902 );
2903
2904 if position.column > 0 {
2905 position += Point::new(1, 0);
2906 }
2907
2908 if !self.is_line_blank(position.row) {
2909 self.edit(
2910 [(position..position, "\n")],
2911 Some(AutoindentMode::EachLine),
2912 cx,
2913 );
2914 }
2915
2916 if space_above && position.row > 0 && !self.is_line_blank(position.row - 1) {
2917 self.edit(
2918 [(position..position, "\n")],
2919 Some(AutoindentMode::EachLine),
2920 cx,
2921 );
2922 position.row += 1;
2923 }
2924
2925 if space_below
2926 && (position.row == self.max_point().row || !self.is_line_blank(position.row + 1))
2927 {
2928 self.edit(
2929 [(position..position, "\n")],
2930 Some(AutoindentMode::EachLine),
2931 cx,
2932 );
2933 }
2934
2935 self.end_transaction(cx);
2936
2937 position
2938 }
2939
2940 /// Applies the given remote operations to the buffer.
2941 pub fn apply_ops<I: IntoIterator<Item = Operation>>(&mut self, ops: I, cx: &mut Context<Self>) {
2942 self.pending_autoindent.take();
2943 let was_dirty = self.is_dirty();
2944 let old_version = self.version.clone();
2945 let mut deferred_ops = Vec::new();
2946 let buffer_ops = ops
2947 .into_iter()
2948 .filter_map(|op| match op {
2949 Operation::Buffer(op) => Some(op),
2950 _ => {
2951 if self.can_apply_op(&op) {
2952 self.apply_op(op, cx);
2953 } else {
2954 deferred_ops.push(op);
2955 }
2956 None
2957 }
2958 })
2959 .collect::<Vec<_>>();
2960 for operation in buffer_ops.iter() {
2961 self.send_operation(Operation::Buffer(operation.clone()), false, cx);
2962 }
2963 self.text.apply_ops(buffer_ops);
2964 self.deferred_ops.insert(deferred_ops);
2965 self.flush_deferred_ops(cx);
2966 self.did_edit(&old_version, was_dirty, cx);
2967 // Notify independently of whether the buffer was edited as the operations could include a
2968 // selection update.
2969 cx.notify();
2970 }
2971
2972 fn flush_deferred_ops(&mut self, cx: &mut Context<Self>) {
2973 let mut deferred_ops = Vec::new();
2974 for op in self.deferred_ops.drain().iter().cloned() {
2975 if self.can_apply_op(&op) {
2976 self.apply_op(op, cx);
2977 } else {
2978 deferred_ops.push(op);
2979 }
2980 }
2981 self.deferred_ops.insert(deferred_ops);
2982 }
2983
2984 pub fn has_deferred_ops(&self) -> bool {
2985 !self.deferred_ops.is_empty() || self.text.has_deferred_ops()
2986 }
2987
2988 fn can_apply_op(&self, operation: &Operation) -> bool {
2989 match operation {
2990 Operation::Buffer(_) => {
2991 unreachable!("buffer operations should never be applied at this layer")
2992 }
2993 Operation::UpdateDiagnostics {
2994 diagnostics: diagnostic_set,
2995 ..
2996 } => diagnostic_set.iter().all(|diagnostic| {
2997 self.text.can_resolve(&diagnostic.range.start)
2998 && self.text.can_resolve(&diagnostic.range.end)
2999 }),
3000 Operation::UpdateSelections { selections, .. } => selections
3001 .iter()
3002 .all(|s| self.can_resolve(&s.start) && self.can_resolve(&s.end)),
3003 Operation::UpdateCompletionTriggers { .. } | Operation::UpdateLineEnding { .. } => true,
3004 }
3005 }
3006
3007 fn apply_op(&mut self, operation: Operation, cx: &mut Context<Self>) {
3008 match operation {
3009 Operation::Buffer(_) => {
3010 unreachable!("buffer operations should never be applied at this layer")
3011 }
3012 Operation::UpdateDiagnostics {
3013 server_id,
3014 diagnostics: diagnostic_set,
3015 lamport_timestamp,
3016 } => {
3017 let snapshot = self.snapshot();
3018 self.apply_diagnostic_update(
3019 server_id,
3020 DiagnosticSet::from_sorted_entries(diagnostic_set.iter().cloned(), &snapshot),
3021 lamport_timestamp,
3022 cx,
3023 );
3024 }
3025 Operation::UpdateSelections {
3026 selections,
3027 lamport_timestamp,
3028 line_mode,
3029 cursor_shape,
3030 } => {
3031 if let Some(set) = self.remote_selections.get(&lamport_timestamp.replica_id)
3032 && set.lamport_timestamp > lamport_timestamp
3033 {
3034 return;
3035 }
3036
3037 self.remote_selections.insert(
3038 lamport_timestamp.replica_id,
3039 SelectionSet {
3040 selections,
3041 lamport_timestamp,
3042 line_mode,
3043 cursor_shape,
3044 },
3045 );
3046 self.text.lamport_clock.observe(lamport_timestamp);
3047 self.non_text_state_update_count += 1;
3048 }
3049 Operation::UpdateCompletionTriggers {
3050 triggers,
3051 lamport_timestamp,
3052 server_id,
3053 } => {
3054 if triggers.is_empty() {
3055 self.completion_triggers_per_language_server
3056 .remove(&server_id);
3057 self.completion_triggers = self
3058 .completion_triggers_per_language_server
3059 .values()
3060 .flat_map(|triggers| triggers.iter().cloned())
3061 .collect();
3062 } else {
3063 self.completion_triggers_per_language_server
3064 .insert(server_id, triggers.iter().cloned().collect());
3065 self.completion_triggers.extend(triggers);
3066 }
3067 self.text.lamport_clock.observe(lamport_timestamp);
3068 }
3069 Operation::UpdateLineEnding {
3070 line_ending,
3071 lamport_timestamp,
3072 } => {
3073 self.text.set_line_ending(line_ending);
3074 self.text.lamport_clock.observe(lamport_timestamp);
3075 }
3076 }
3077 }
3078
3079 fn apply_diagnostic_update(
3080 &mut self,
3081 server_id: LanguageServerId,
3082 diagnostics: DiagnosticSet,
3083 lamport_timestamp: clock::Lamport,
3084 cx: &mut Context<Self>,
3085 ) {
3086 if lamport_timestamp > self.diagnostics_timestamp {
3087 if diagnostics.is_empty() {
3088 self.diagnostics.remove(&server_id);
3089 } else {
3090 self.diagnostics.insert(server_id, diagnostics);
3091 }
3092 self.diagnostics_timestamp = lamport_timestamp;
3093 self.non_text_state_update_count += 1;
3094 self.text.lamport_clock.observe(lamport_timestamp);
3095 cx.notify();
3096 cx.emit(BufferEvent::DiagnosticsUpdated);
3097 }
3098 }
3099
3100 fn send_operation(&mut self, operation: Operation, is_local: bool, cx: &mut Context<Self>) {
3101 self.was_changed();
3102 cx.emit(BufferEvent::Operation {
3103 operation,
3104 is_local,
3105 });
3106 }
3107
3108 /// Removes the selections for a given peer.
3109 pub fn remove_peer(&mut self, replica_id: ReplicaId, cx: &mut Context<Self>) {
3110 self.remote_selections.remove(&replica_id);
3111 cx.notify();
3112 }
3113
3114 /// Undoes the most recent transaction.
3115 pub fn undo(&mut self, cx: &mut Context<Self>) -> Option<TransactionId> {
3116 let was_dirty = self.is_dirty();
3117 let old_version = self.version.clone();
3118
3119 if let Some((transaction_id, operation)) = self.text.undo() {
3120 self.send_operation(Operation::Buffer(operation), true, cx);
3121 self.did_edit(&old_version, was_dirty, cx);
3122 self.restore_encoding_for_transaction(transaction_id, was_dirty);
3123 Some(transaction_id)
3124 } else {
3125 None
3126 }
3127 }
3128
3129 /// Manually undoes a specific transaction in the buffer's undo history.
3130 pub fn undo_transaction(
3131 &mut self,
3132 transaction_id: TransactionId,
3133 cx: &mut Context<Self>,
3134 ) -> bool {
3135 let was_dirty = self.is_dirty();
3136 let old_version = self.version.clone();
3137 if let Some(operation) = self.text.undo_transaction(transaction_id) {
3138 self.send_operation(Operation::Buffer(operation), true, cx);
3139 self.did_edit(&old_version, was_dirty, cx);
3140 true
3141 } else {
3142 false
3143 }
3144 }
3145
3146 /// Manually undoes all changes after a given transaction in the buffer's undo history.
3147 pub fn undo_to_transaction(
3148 &mut self,
3149 transaction_id: TransactionId,
3150 cx: &mut Context<Self>,
3151 ) -> bool {
3152 let was_dirty = self.is_dirty();
3153 let old_version = self.version.clone();
3154
3155 let operations = self.text.undo_to_transaction(transaction_id);
3156 let undone = !operations.is_empty();
3157 for operation in operations {
3158 self.send_operation(Operation::Buffer(operation), true, cx);
3159 }
3160 if undone {
3161 self.did_edit(&old_version, was_dirty, cx)
3162 }
3163 undone
3164 }
3165
3166 pub fn undo_operations(&mut self, counts: HashMap<Lamport, u32>, cx: &mut Context<Buffer>) {
3167 let was_dirty = self.is_dirty();
3168 let operation = self.text.undo_operations(counts);
3169 let old_version = self.version.clone();
3170 self.send_operation(Operation::Buffer(operation), true, cx);
3171 self.did_edit(&old_version, was_dirty, cx);
3172 }
3173
3174 /// Manually redoes a specific transaction in the buffer's redo history.
3175 pub fn redo(&mut self, cx: &mut Context<Self>) -> Option<TransactionId> {
3176 let was_dirty = self.is_dirty();
3177 let old_version = self.version.clone();
3178
3179 if let Some((transaction_id, operation)) = self.text.redo() {
3180 self.send_operation(Operation::Buffer(operation), true, cx);
3181 self.did_edit(&old_version, was_dirty, cx);
3182 self.restore_encoding_for_transaction(transaction_id, was_dirty);
3183 Some(transaction_id)
3184 } else {
3185 None
3186 }
3187 }
3188
3189 fn restore_encoding_for_transaction(&mut self, transaction_id: TransactionId, was_dirty: bool) {
3190 if let Some((old_encoding, old_has_bom)) =
3191 self.reload_with_encoding_txns.get(&transaction_id)
3192 {
3193 let current_encoding = self.encoding;
3194 let current_has_bom = self.has_bom;
3195 self.encoding = *old_encoding;
3196 self.has_bom = *old_has_bom;
3197 if !was_dirty {
3198 self.saved_version = self.version.clone();
3199 self.has_unsaved_edits
3200 .set((self.saved_version.clone(), false));
3201 }
3202 self.reload_with_encoding_txns
3203 .insert(transaction_id, (current_encoding, current_has_bom));
3204 }
3205 }
3206
3207 /// Manually undoes all changes until a given transaction in the buffer's redo history.
3208 pub fn redo_to_transaction(
3209 &mut self,
3210 transaction_id: TransactionId,
3211 cx: &mut Context<Self>,
3212 ) -> bool {
3213 let was_dirty = self.is_dirty();
3214 let old_version = self.version.clone();
3215
3216 let operations = self.text.redo_to_transaction(transaction_id);
3217 let redone = !operations.is_empty();
3218 for operation in operations {
3219 self.send_operation(Operation::Buffer(operation), true, cx);
3220 }
3221 if redone {
3222 self.did_edit(&old_version, was_dirty, cx)
3223 }
3224 redone
3225 }
3226
3227 /// Override current completion triggers with the user-provided completion triggers.
3228 pub fn set_completion_triggers(
3229 &mut self,
3230 server_id: LanguageServerId,
3231 triggers: BTreeSet<String>,
3232 cx: &mut Context<Self>,
3233 ) {
3234 self.completion_triggers_timestamp = self.text.lamport_clock.tick();
3235 if triggers.is_empty() {
3236 self.completion_triggers_per_language_server
3237 .remove(&server_id);
3238 self.completion_triggers = self
3239 .completion_triggers_per_language_server
3240 .values()
3241 .flat_map(|triggers| triggers.iter().cloned())
3242 .collect();
3243 } else {
3244 self.completion_triggers_per_language_server
3245 .insert(server_id, triggers.clone());
3246 self.completion_triggers.extend(triggers.iter().cloned());
3247 }
3248 self.send_operation(
3249 Operation::UpdateCompletionTriggers {
3250 triggers: triggers.into_iter().collect(),
3251 lamport_timestamp: self.completion_triggers_timestamp,
3252 server_id,
3253 },
3254 true,
3255 cx,
3256 );
3257 cx.notify();
3258 }
3259
3260 /// Returns a list of strings which trigger a completion menu for this language.
3261 /// Usually this is driven by LSP server which returns a list of trigger characters for completions.
3262 pub fn completion_triggers(&self) -> &BTreeSet<String> {
3263 &self.completion_triggers
3264 }
3265
3266 /// Call this directly after performing edits to prevent the preview tab
3267 /// from being dismissed by those edits. It causes `should_dismiss_preview`
3268 /// to return false until there are additional edits.
3269 pub fn refresh_preview(&mut self) {
3270 self.preview_version = self.version.clone();
3271 }
3272
3273 /// Whether we should preserve the preview status of a tab containing this buffer.
3274 pub fn preserve_preview(&self) -> bool {
3275 !self.has_edits_since(&self.preview_version)
3276 }
3277}
3278
3279#[doc(hidden)]
3280#[cfg(any(test, feature = "test-support"))]
3281impl Buffer {
3282 pub fn edit_via_marked_text(
3283 &mut self,
3284 marked_string: &str,
3285 autoindent_mode: Option<AutoindentMode>,
3286 cx: &mut Context<Self>,
3287 ) {
3288 let edits = self.edits_for_marked_text(marked_string);
3289 self.edit(edits, autoindent_mode, cx);
3290 }
3291
3292 pub fn set_group_interval(&mut self, group_interval: Duration) {
3293 self.text.set_group_interval(group_interval);
3294 }
3295
3296 pub fn randomly_edit<T>(&mut self, rng: &mut T, old_range_count: usize, cx: &mut Context<Self>)
3297 where
3298 T: rand::Rng,
3299 {
3300 let mut edits: Vec<(Range<usize>, String)> = Vec::new();
3301 let mut last_end = None;
3302 for _ in 0..old_range_count {
3303 if last_end.is_some_and(|last_end| last_end >= self.len()) {
3304 break;
3305 }
3306
3307 let new_start = last_end.map_or(0, |last_end| last_end + 1);
3308 let mut range = self.random_byte_range(new_start, rng);
3309 if rng.random_bool(0.2) {
3310 mem::swap(&mut range.start, &mut range.end);
3311 }
3312 last_end = Some(range.end);
3313
3314 let new_text_len = rng.random_range(0..10);
3315 let mut new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
3316 new_text = new_text.to_uppercase();
3317
3318 edits.push((range, new_text));
3319 }
3320 log::info!("mutating buffer {:?} with {:?}", self.replica_id(), edits);
3321 self.edit(edits, None, cx);
3322 }
3323
3324 pub fn randomly_undo_redo(&mut self, rng: &mut impl rand::Rng, cx: &mut Context<Self>) {
3325 let was_dirty = self.is_dirty();
3326 let old_version = self.version.clone();
3327
3328 let ops = self.text.randomly_undo_redo(rng);
3329 if !ops.is_empty() {
3330 for op in ops {
3331 self.send_operation(Operation::Buffer(op), true, cx);
3332 self.did_edit(&old_version, was_dirty, cx);
3333 }
3334 }
3335 }
3336}
3337
3338impl EventEmitter<BufferEvent> for Buffer {}
3339
3340fn offset_in_sub_ranges(
3341 sub_ranges: &[Range<Anchor>],
3342 offset: usize,
3343 snapshot: &TextBufferSnapshot,
3344) -> bool {
3345 let start_anchor = snapshot.anchor_before(offset);
3346 let end_anchor = snapshot.anchor_after(offset);
3347
3348 sub_ranges.iter().any(|sub_range| {
3349 let is_before_start = sub_range.end.cmp(&start_anchor, snapshot).is_lt();
3350 let is_after_end = sub_range.start.cmp(&end_anchor, snapshot).is_gt();
3351 !is_before_start && !is_after_end
3352 })
3353}
3354
3355impl Deref for Buffer {
3356 type Target = TextBuffer;
3357
3358 fn deref(&self) -> &Self::Target {
3359 &self.text
3360 }
3361}
3362
3363impl BufferSnapshot {
3364 /// Returns [`IndentSize`] for a given line that respects user settings and
3365 /// language preferences.
3366 pub fn indent_size_for_line(&self, row: u32) -> IndentSize {
3367 indent_size_for_line(self, row)
3368 }
3369
3370 /// Returns [`IndentSize`] for a given position that respects user settings
3371 /// and language preferences.
3372 pub fn language_indent_size_at<T: ToOffset>(&self, position: T, cx: &App) -> IndentSize {
3373 let settings = language_settings(
3374 self.language_at(position).map(|l| l.name()),
3375 self.file(),
3376 cx,
3377 );
3378 if settings.hard_tabs {
3379 IndentSize::tab()
3380 } else {
3381 IndentSize::spaces(settings.tab_size.get())
3382 }
3383 }
3384
3385 /// Retrieve the suggested indent size for all of the given rows. The unit of indentation
3386 /// is passed in as `single_indent_size`.
3387 pub fn suggested_indents(
3388 &self,
3389 rows: impl Iterator<Item = u32>,
3390 single_indent_size: IndentSize,
3391 ) -> BTreeMap<u32, IndentSize> {
3392 let mut result = BTreeMap::new();
3393
3394 for row_range in contiguous_ranges(rows, 10) {
3395 let suggestions = match self.suggest_autoindents(row_range.clone()) {
3396 Some(suggestions) => suggestions,
3397 _ => break,
3398 };
3399
3400 for (row, suggestion) in row_range.zip(suggestions) {
3401 let indent_size = if let Some(suggestion) = suggestion {
3402 result
3403 .get(&suggestion.basis_row)
3404 .copied()
3405 .unwrap_or_else(|| self.indent_size_for_line(suggestion.basis_row))
3406 .with_delta(suggestion.delta, single_indent_size)
3407 } else {
3408 self.indent_size_for_line(row)
3409 };
3410
3411 result.insert(row, indent_size);
3412 }
3413 }
3414
3415 result
3416 }
3417
3418 fn suggest_autoindents(
3419 &self,
3420 row_range: Range<u32>,
3421 ) -> Option<impl Iterator<Item = Option<IndentSuggestion>> + '_> {
3422 let config = &self.language.as_ref()?.config;
3423 let prev_non_blank_row = self.prev_non_blank_row(row_range.start);
3424
3425 #[derive(Debug, Clone)]
3426 struct StartPosition {
3427 start: Point,
3428 suffix: SharedString,
3429 language: Arc<Language>,
3430 }
3431
3432 // Find the suggested indentation ranges based on the syntax tree.
3433 let start = Point::new(prev_non_blank_row.unwrap_or(row_range.start), 0);
3434 let end = Point::new(row_range.end, 0);
3435 let range = (start..end).to_offset(&self.text);
3436 let mut matches = self.syntax.matches_with_options(
3437 range.clone(),
3438 &self.text,
3439 TreeSitterOptions {
3440 max_bytes_to_query: Some(MAX_BYTES_TO_QUERY),
3441 max_start_depth: None,
3442 },
3443 |grammar| Some(&grammar.indents_config.as_ref()?.query),
3444 );
3445 let indent_configs = matches
3446 .grammars()
3447 .iter()
3448 .map(|grammar| grammar.indents_config.as_ref().unwrap())
3449 .collect::<Vec<_>>();
3450
3451 let mut indent_ranges = Vec::<Range<Point>>::new();
3452 let mut start_positions = Vec::<StartPosition>::new();
3453 let mut outdent_positions = Vec::<Point>::new();
3454 while let Some(mat) = matches.peek() {
3455 let mut start: Option<Point> = None;
3456 let mut end: Option<Point> = None;
3457
3458 let config = indent_configs[mat.grammar_index];
3459 for capture in mat.captures {
3460 if capture.index == config.indent_capture_ix {
3461 start.get_or_insert(Point::from_ts_point(capture.node.start_position()));
3462 end.get_or_insert(Point::from_ts_point(capture.node.end_position()));
3463 } else if Some(capture.index) == config.start_capture_ix {
3464 start = Some(Point::from_ts_point(capture.node.end_position()));
3465 } else if Some(capture.index) == config.end_capture_ix {
3466 end = Some(Point::from_ts_point(capture.node.start_position()));
3467 } else if Some(capture.index) == config.outdent_capture_ix {
3468 outdent_positions.push(Point::from_ts_point(capture.node.start_position()));
3469 } else if let Some(suffix) = config.suffixed_start_captures.get(&capture.index) {
3470 start_positions.push(StartPosition {
3471 start: Point::from_ts_point(capture.node.start_position()),
3472 suffix: suffix.clone(),
3473 language: mat.language.clone(),
3474 });
3475 }
3476 }
3477
3478 matches.advance();
3479 if let Some((start, end)) = start.zip(end) {
3480 if start.row == end.row {
3481 continue;
3482 }
3483 let range = start..end;
3484 match indent_ranges.binary_search_by_key(&range.start, |r| r.start) {
3485 Err(ix) => indent_ranges.insert(ix, range),
3486 Ok(ix) => {
3487 let prev_range = &mut indent_ranges[ix];
3488 prev_range.end = prev_range.end.max(range.end);
3489 }
3490 }
3491 }
3492 }
3493
3494 let mut error_ranges = Vec::<Range<Point>>::new();
3495 let mut matches = self
3496 .syntax
3497 .matches(range, &self.text, |grammar| grammar.error_query.as_ref());
3498 while let Some(mat) = matches.peek() {
3499 let node = mat.captures[0].node;
3500 let start = Point::from_ts_point(node.start_position());
3501 let end = Point::from_ts_point(node.end_position());
3502 let range = start..end;
3503 let ix = match error_ranges.binary_search_by_key(&range.start, |r| r.start) {
3504 Ok(ix) | Err(ix) => ix,
3505 };
3506 let mut end_ix = ix;
3507 while let Some(existing_range) = error_ranges.get(end_ix) {
3508 if existing_range.end < end {
3509 end_ix += 1;
3510 } else {
3511 break;
3512 }
3513 }
3514 error_ranges.splice(ix..end_ix, [range]);
3515 matches.advance();
3516 }
3517
3518 outdent_positions.sort();
3519 for outdent_position in outdent_positions {
3520 // find the innermost indent range containing this outdent_position
3521 // set its end to the outdent position
3522 if let Some(range_to_truncate) = indent_ranges
3523 .iter_mut()
3524 .rfind(|indent_range| indent_range.contains(&outdent_position))
3525 {
3526 range_to_truncate.end = outdent_position;
3527 }
3528 }
3529
3530 start_positions.sort_by_key(|b| b.start);
3531
3532 // Find the suggested indentation increases and decreased based on regexes.
3533 let mut regex_outdent_map = HashMap::default();
3534 let mut last_seen_suffix: HashMap<String, Vec<StartPosition>> = HashMap::default();
3535 let mut start_positions_iter = start_positions.iter().peekable();
3536
3537 let mut indent_change_rows = Vec::<(u32, Ordering)>::new();
3538 self.for_each_line(
3539 Point::new(prev_non_blank_row.unwrap_or(row_range.start), 0)
3540 ..Point::new(row_range.end, 0),
3541 |row, line| {
3542 let indent_len = self.indent_size_for_line(row).len;
3543 let row_language = self.language_at(Point::new(row, indent_len)).cloned();
3544 let row_language_config = row_language
3545 .as_ref()
3546 .map(|lang| lang.config())
3547 .unwrap_or(config);
3548
3549 if row_language_config
3550 .decrease_indent_pattern
3551 .as_ref()
3552 .is_some_and(|regex| regex.is_match(line))
3553 {
3554 indent_change_rows.push((row, Ordering::Less));
3555 }
3556 if row_language_config
3557 .increase_indent_pattern
3558 .as_ref()
3559 .is_some_and(|regex| regex.is_match(line))
3560 {
3561 indent_change_rows.push((row + 1, Ordering::Greater));
3562 }
3563 while let Some(pos) = start_positions_iter.peek() {
3564 if pos.start.row < row {
3565 let pos = start_positions_iter.next().unwrap().clone();
3566 last_seen_suffix
3567 .entry(pos.suffix.to_string())
3568 .or_default()
3569 .push(pos);
3570 } else {
3571 break;
3572 }
3573 }
3574 for rule in &row_language_config.decrease_indent_patterns {
3575 if rule.pattern.as_ref().is_some_and(|r| r.is_match(line)) {
3576 let row_start_column = self.indent_size_for_line(row).len;
3577 let basis_row = rule
3578 .valid_after
3579 .iter()
3580 .filter_map(|valid_suffix| last_seen_suffix.get(valid_suffix))
3581 .flatten()
3582 .filter(|pos| {
3583 row_language
3584 .as_ref()
3585 .or(self.language.as_ref())
3586 .is_some_and(|lang| Arc::ptr_eq(lang, &pos.language))
3587 })
3588 .filter(|pos| pos.start.column <= row_start_column)
3589 .max_by_key(|pos| pos.start.row);
3590 if let Some(outdent_to) = basis_row {
3591 regex_outdent_map.insert(row, outdent_to.start.row);
3592 }
3593 break;
3594 }
3595 }
3596 },
3597 );
3598
3599 let mut indent_changes = indent_change_rows.into_iter().peekable();
3600 let mut prev_row = if config.auto_indent_using_last_non_empty_line {
3601 prev_non_blank_row.unwrap_or(0)
3602 } else {
3603 row_range.start.saturating_sub(1)
3604 };
3605
3606 let mut prev_row_start = Point::new(prev_row, self.indent_size_for_line(prev_row).len);
3607 Some(row_range.map(move |row| {
3608 let row_start = Point::new(row, self.indent_size_for_line(row).len);
3609
3610 let mut indent_from_prev_row = false;
3611 let mut outdent_from_prev_row = false;
3612 let mut outdent_to_row = u32::MAX;
3613 let mut from_regex = false;
3614
3615 while let Some((indent_row, delta)) = indent_changes.peek() {
3616 match indent_row.cmp(&row) {
3617 Ordering::Equal => match delta {
3618 Ordering::Less => {
3619 from_regex = true;
3620 outdent_from_prev_row = true
3621 }
3622 Ordering::Greater => {
3623 indent_from_prev_row = true;
3624 from_regex = true
3625 }
3626 _ => {}
3627 },
3628
3629 Ordering::Greater => break,
3630 Ordering::Less => {}
3631 }
3632
3633 indent_changes.next();
3634 }
3635
3636 for range in &indent_ranges {
3637 if range.start.row >= row {
3638 break;
3639 }
3640 if range.start.row == prev_row && range.end > row_start {
3641 indent_from_prev_row = true;
3642 }
3643 if range.end > prev_row_start && range.end <= row_start {
3644 outdent_to_row = outdent_to_row.min(range.start.row);
3645 }
3646 }
3647
3648 if let Some(basis_row) = regex_outdent_map.get(&row) {
3649 indent_from_prev_row = false;
3650 outdent_to_row = *basis_row;
3651 from_regex = true;
3652 }
3653
3654 let within_error = error_ranges
3655 .iter()
3656 .any(|e| e.start.row < row && e.end > row_start);
3657
3658 let suggestion = if outdent_to_row == prev_row
3659 || (outdent_from_prev_row && indent_from_prev_row)
3660 {
3661 Some(IndentSuggestion {
3662 basis_row: prev_row,
3663 delta: Ordering::Equal,
3664 within_error: within_error && !from_regex,
3665 })
3666 } else if indent_from_prev_row {
3667 Some(IndentSuggestion {
3668 basis_row: prev_row,
3669 delta: Ordering::Greater,
3670 within_error: within_error && !from_regex,
3671 })
3672 } else if outdent_to_row < prev_row {
3673 Some(IndentSuggestion {
3674 basis_row: outdent_to_row,
3675 delta: Ordering::Equal,
3676 within_error: within_error && !from_regex,
3677 })
3678 } else if outdent_from_prev_row {
3679 Some(IndentSuggestion {
3680 basis_row: prev_row,
3681 delta: Ordering::Less,
3682 within_error: within_error && !from_regex,
3683 })
3684 } else if config.auto_indent_using_last_non_empty_line || !self.is_line_blank(prev_row)
3685 {
3686 Some(IndentSuggestion {
3687 basis_row: prev_row,
3688 delta: Ordering::Equal,
3689 within_error: within_error && !from_regex,
3690 })
3691 } else {
3692 None
3693 };
3694
3695 prev_row = row;
3696 prev_row_start = row_start;
3697 suggestion
3698 }))
3699 }
3700
3701 fn prev_non_blank_row(&self, mut row: u32) -> Option<u32> {
3702 while row > 0 {
3703 row -= 1;
3704 if !self.is_line_blank(row) {
3705 return Some(row);
3706 }
3707 }
3708 None
3709 }
3710
3711 pub fn captures(
3712 &self,
3713 range: Range<usize>,
3714 query: fn(&Grammar) -> Option<&tree_sitter::Query>,
3715 ) -> SyntaxMapCaptures<'_> {
3716 self.syntax.captures(range, &self.text, query)
3717 }
3718
3719 #[ztracing::instrument(skip_all)]
3720 fn get_highlights(&self, range: Range<usize>) -> (SyntaxMapCaptures<'_>, Vec<HighlightMap>) {
3721 let captures = self.syntax.captures(range, &self.text, |grammar| {
3722 grammar
3723 .highlights_config
3724 .as_ref()
3725 .map(|config| &config.query)
3726 });
3727 let highlight_maps = captures
3728 .grammars()
3729 .iter()
3730 .map(|grammar| grammar.highlight_map())
3731 .collect();
3732 (captures, highlight_maps)
3733 }
3734
3735 /// Iterates over chunks of text in the given range of the buffer. Text is chunked
3736 /// in an arbitrary way due to being stored in a [`Rope`](text::Rope). The text is also
3737 /// returned in chunks where each chunk has a single syntax highlighting style and
3738 /// diagnostic status.
3739 #[ztracing::instrument(skip_all)]
3740 pub fn chunks<T: ToOffset>(&self, range: Range<T>, language_aware: bool) -> BufferChunks<'_> {
3741 let range = range.start.to_offset(self)..range.end.to_offset(self);
3742
3743 let mut syntax = None;
3744 if language_aware {
3745 syntax = Some(self.get_highlights(range.clone()));
3746 }
3747 // We want to look at diagnostic spans only when iterating over language-annotated chunks.
3748 let diagnostics = language_aware;
3749 BufferChunks::new(self.text.as_rope(), range, syntax, diagnostics, Some(self))
3750 }
3751
3752 pub fn highlighted_text_for_range<T: ToOffset>(
3753 &self,
3754 range: Range<T>,
3755 override_style: Option<HighlightStyle>,
3756 syntax_theme: &SyntaxTheme,
3757 ) -> HighlightedText {
3758 HighlightedText::from_buffer_range(
3759 range,
3760 &self.text,
3761 &self.syntax,
3762 override_style,
3763 syntax_theme,
3764 )
3765 }
3766
3767 /// Invokes the given callback for each line of text in the given range of the buffer.
3768 /// Uses callback to avoid allocating a string for each line.
3769 fn for_each_line(&self, range: Range<Point>, mut callback: impl FnMut(u32, &str)) {
3770 let mut line = String::new();
3771 let mut row = range.start.row;
3772 for chunk in self
3773 .as_rope()
3774 .chunks_in_range(range.to_offset(self))
3775 .chain(["\n"])
3776 {
3777 for (newline_ix, text) in chunk.split('\n').enumerate() {
3778 if newline_ix > 0 {
3779 callback(row, &line);
3780 row += 1;
3781 line.clear();
3782 }
3783 line.push_str(text);
3784 }
3785 }
3786 }
3787
3788 /// Iterates over every [`SyntaxLayer`] in the buffer.
3789 pub fn syntax_layers(&self) -> impl Iterator<Item = SyntaxLayer<'_>> + '_ {
3790 self.syntax_layers_for_range(0..self.len(), true)
3791 }
3792
3793 pub fn syntax_layer_at<D: ToOffset>(&self, position: D) -> Option<SyntaxLayer<'_>> {
3794 let offset = position.to_offset(self);
3795 self.syntax_layers_for_range(offset..offset, false)
3796 .filter(|l| {
3797 if let Some(ranges) = l.included_sub_ranges {
3798 ranges.iter().any(|range| {
3799 let start = range.start.to_offset(self);
3800 start <= offset && {
3801 let end = range.end.to_offset(self);
3802 offset < end
3803 }
3804 })
3805 } else {
3806 l.node().start_byte() <= offset && l.node().end_byte() > offset
3807 }
3808 })
3809 .last()
3810 }
3811
3812 pub fn syntax_layers_for_range<D: ToOffset>(
3813 &self,
3814 range: Range<D>,
3815 include_hidden: bool,
3816 ) -> impl Iterator<Item = SyntaxLayer<'_>> + '_ {
3817 self.syntax
3818 .layers_for_range(range, &self.text, include_hidden)
3819 }
3820
3821 pub fn syntax_layers_languages(&self) -> impl Iterator<Item = &Arc<Language>> {
3822 self.syntax.languages(&self, true)
3823 }
3824
3825 pub fn smallest_syntax_layer_containing<D: ToOffset>(
3826 &self,
3827 range: Range<D>,
3828 ) -> Option<SyntaxLayer<'_>> {
3829 let range = range.to_offset(self);
3830 self.syntax
3831 .layers_for_range(range, &self.text, false)
3832 .max_by(|a, b| {
3833 if a.depth != b.depth {
3834 a.depth.cmp(&b.depth)
3835 } else if a.offset.0 != b.offset.0 {
3836 a.offset.0.cmp(&b.offset.0)
3837 } else {
3838 a.node().end_byte().cmp(&b.node().end_byte()).reverse()
3839 }
3840 })
3841 }
3842
3843 /// Returns the main [`Language`].
3844 pub fn language(&self) -> Option<&Arc<Language>> {
3845 self.language.as_ref()
3846 }
3847
3848 /// Returns the [`Language`] at the given location.
3849 pub fn language_at<D: ToOffset>(&self, position: D) -> Option<&Arc<Language>> {
3850 self.syntax_layer_at(position)
3851 .map(|info| info.language)
3852 .or(self.language.as_ref())
3853 }
3854
3855 /// Returns the settings for the language at the given location.
3856 pub fn settings_at<'a, D: ToOffset>(
3857 &'a self,
3858 position: D,
3859 cx: &'a App,
3860 ) -> Cow<'a, LanguageSettings> {
3861 language_settings(
3862 self.language_at(position).map(|l| l.name()),
3863 self.file.as_ref(),
3864 cx,
3865 )
3866 }
3867
3868 pub fn char_classifier_at<T: ToOffset>(&self, point: T) -> CharClassifier {
3869 CharClassifier::new(self.language_scope_at(point))
3870 }
3871
3872 /// Returns the [`LanguageScope`] at the given location.
3873 pub fn language_scope_at<D: ToOffset>(&self, position: D) -> Option<LanguageScope> {
3874 let offset = position.to_offset(self);
3875 let mut scope = None;
3876 let mut smallest_range_and_depth: Option<(Range<usize>, usize)> = None;
3877 let text: &TextBufferSnapshot = self;
3878
3879 // Use the layer that has the smallest node intersecting the given point.
3880 for layer in self
3881 .syntax
3882 .layers_for_range(offset..offset, &self.text, false)
3883 {
3884 if let Some(ranges) = layer.included_sub_ranges
3885 && !offset_in_sub_ranges(ranges, offset, text)
3886 {
3887 continue;
3888 }
3889
3890 let mut cursor = layer.node().walk();
3891
3892 let mut range = None;
3893 loop {
3894 let child_range = cursor.node().byte_range();
3895 if !child_range.contains(&offset) {
3896 break;
3897 }
3898
3899 range = Some(child_range);
3900 if cursor.goto_first_child_for_byte(offset).is_none() {
3901 break;
3902 }
3903 }
3904
3905 if let Some(range) = range
3906 && smallest_range_and_depth.as_ref().is_none_or(
3907 |(smallest_range, smallest_range_depth)| {
3908 if layer.depth > *smallest_range_depth {
3909 true
3910 } else if layer.depth == *smallest_range_depth {
3911 range.len() < smallest_range.len()
3912 } else {
3913 false
3914 }
3915 },
3916 )
3917 {
3918 smallest_range_and_depth = Some((range, layer.depth));
3919 scope = Some(LanguageScope {
3920 language: layer.language.clone(),
3921 override_id: layer.override_id(offset, &self.text),
3922 });
3923 }
3924 }
3925
3926 scope.or_else(|| {
3927 self.language.clone().map(|language| LanguageScope {
3928 language,
3929 override_id: None,
3930 })
3931 })
3932 }
3933
3934 /// Returns a tuple of the range and character kind of the word
3935 /// surrounding the given position.
3936 pub fn surrounding_word<T: ToOffset>(
3937 &self,
3938 start: T,
3939 scope_context: Option<CharScopeContext>,
3940 ) -> (Range<usize>, Option<CharKind>) {
3941 let mut start = start.to_offset(self);
3942 let mut end = start;
3943 let mut next_chars = self.chars_at(start).take(128).peekable();
3944 let mut prev_chars = self.reversed_chars_at(start).take(128).peekable();
3945
3946 let classifier = self.char_classifier_at(start).scope_context(scope_context);
3947 let word_kind = cmp::max(
3948 prev_chars.peek().copied().map(|c| classifier.kind(c)),
3949 next_chars.peek().copied().map(|c| classifier.kind(c)),
3950 );
3951
3952 for ch in prev_chars {
3953 if Some(classifier.kind(ch)) == word_kind && ch != '\n' {
3954 start -= ch.len_utf8();
3955 } else {
3956 break;
3957 }
3958 }
3959
3960 for ch in next_chars {
3961 if Some(classifier.kind(ch)) == word_kind && ch != '\n' {
3962 end += ch.len_utf8();
3963 } else {
3964 break;
3965 }
3966 }
3967
3968 (start..end, word_kind)
3969 }
3970
3971 /// Moves the TreeCursor to the smallest descendant or ancestor syntax node enclosing the given
3972 /// range. When `require_larger` is true, the node found must be larger than the query range.
3973 ///
3974 /// Returns true if a node was found, and false otherwise. In the `false` case the cursor will
3975 /// be moved to the root of the tree.
3976 fn goto_node_enclosing_range(
3977 cursor: &mut tree_sitter::TreeCursor,
3978 query_range: &Range<usize>,
3979 require_larger: bool,
3980 ) -> bool {
3981 let mut ascending = false;
3982 loop {
3983 let mut range = cursor.node().byte_range();
3984 if query_range.is_empty() {
3985 // When the query range is empty and the current node starts after it, move to the
3986 // previous sibling to find the node the containing node.
3987 if range.start > query_range.start {
3988 cursor.goto_previous_sibling();
3989 range = cursor.node().byte_range();
3990 }
3991 } else {
3992 // When the query range is non-empty and the current node ends exactly at the start,
3993 // move to the next sibling to find a node that extends beyond the start.
3994 if range.end == query_range.start {
3995 cursor.goto_next_sibling();
3996 range = cursor.node().byte_range();
3997 }
3998 }
3999
4000 let encloses = range.contains_inclusive(query_range)
4001 && (!require_larger || range.len() > query_range.len());
4002 if !encloses {
4003 ascending = true;
4004 if !cursor.goto_parent() {
4005 return false;
4006 }
4007 continue;
4008 } else if ascending {
4009 return true;
4010 }
4011
4012 // Descend into the current node.
4013 if cursor
4014 .goto_first_child_for_byte(query_range.start)
4015 .is_none()
4016 {
4017 return true;
4018 }
4019 }
4020 }
4021
4022 pub fn syntax_ancestor<'a, T: ToOffset>(
4023 &'a self,
4024 range: Range<T>,
4025 ) -> Option<tree_sitter::Node<'a>> {
4026 let range = range.start.to_offset(self)..range.end.to_offset(self);
4027 let mut result: Option<tree_sitter::Node<'a>> = None;
4028 for layer in self
4029 .syntax
4030 .layers_for_range(range.clone(), &self.text, true)
4031 {
4032 let mut cursor = layer.node().walk();
4033
4034 // Find the node that both contains the range and is larger than it.
4035 if !Self::goto_node_enclosing_range(&mut cursor, &range, true) {
4036 continue;
4037 }
4038
4039 let left_node = cursor.node();
4040 let mut layer_result = left_node;
4041
4042 // For an empty range, try to find another node immediately to the right of the range.
4043 if left_node.end_byte() == range.start {
4044 let mut right_node = None;
4045 while !cursor.goto_next_sibling() {
4046 if !cursor.goto_parent() {
4047 break;
4048 }
4049 }
4050
4051 while cursor.node().start_byte() == range.start {
4052 right_node = Some(cursor.node());
4053 if !cursor.goto_first_child() {
4054 break;
4055 }
4056 }
4057
4058 // If there is a candidate node on both sides of the (empty) range, then
4059 // decide between the two by favoring a named node over an anonymous token.
4060 // If both nodes are the same in that regard, favor the right one.
4061 if let Some(right_node) = right_node
4062 && (right_node.is_named() || !left_node.is_named())
4063 {
4064 layer_result = right_node;
4065 }
4066 }
4067
4068 if let Some(previous_result) = &result
4069 && previous_result.byte_range().len() < layer_result.byte_range().len()
4070 {
4071 continue;
4072 }
4073 result = Some(layer_result);
4074 }
4075
4076 result
4077 }
4078
4079 /// Find the previous sibling syntax node at the given range.
4080 ///
4081 /// This function locates the syntax node that precedes the node containing
4082 /// the given range. It searches hierarchically by:
4083 /// 1. Finding the node that contains the given range
4084 /// 2. Looking for the previous sibling at the same tree level
4085 /// 3. If no sibling is found, moving up to parent levels and searching for siblings
4086 ///
4087 /// Returns `None` if there is no previous sibling at any ancestor level.
4088 pub fn syntax_prev_sibling<'a, T: ToOffset>(
4089 &'a self,
4090 range: Range<T>,
4091 ) -> Option<tree_sitter::Node<'a>> {
4092 let range = range.start.to_offset(self)..range.end.to_offset(self);
4093 let mut result: Option<tree_sitter::Node<'a>> = None;
4094
4095 for layer in self
4096 .syntax
4097 .layers_for_range(range.clone(), &self.text, true)
4098 {
4099 let mut cursor = layer.node().walk();
4100
4101 // Find the node that contains the range
4102 if !Self::goto_node_enclosing_range(&mut cursor, &range, false) {
4103 continue;
4104 }
4105
4106 // Look for the previous sibling, moving up ancestor levels if needed
4107 loop {
4108 if cursor.goto_previous_sibling() {
4109 let layer_result = cursor.node();
4110
4111 if let Some(previous_result) = &result {
4112 if previous_result.byte_range().end < layer_result.byte_range().end {
4113 continue;
4114 }
4115 }
4116 result = Some(layer_result);
4117 break;
4118 }
4119
4120 // No sibling found at this level, try moving up to parent
4121 if !cursor.goto_parent() {
4122 break;
4123 }
4124 }
4125 }
4126
4127 result
4128 }
4129
4130 /// Find the next sibling syntax node at the given range.
4131 ///
4132 /// This function locates the syntax node that follows the node containing
4133 /// the given range. It searches hierarchically by:
4134 /// 1. Finding the node that contains the given range
4135 /// 2. Looking for the next sibling at the same tree level
4136 /// 3. If no sibling is found, moving up to parent levels and searching for siblings
4137 ///
4138 /// Returns `None` if there is no next sibling at any ancestor level.
4139 pub fn syntax_next_sibling<'a, T: ToOffset>(
4140 &'a self,
4141 range: Range<T>,
4142 ) -> Option<tree_sitter::Node<'a>> {
4143 let range = range.start.to_offset(self)..range.end.to_offset(self);
4144 let mut result: Option<tree_sitter::Node<'a>> = None;
4145
4146 for layer in self
4147 .syntax
4148 .layers_for_range(range.clone(), &self.text, true)
4149 {
4150 let mut cursor = layer.node().walk();
4151
4152 // Find the node that contains the range
4153 if !Self::goto_node_enclosing_range(&mut cursor, &range, false) {
4154 continue;
4155 }
4156
4157 // Look for the next sibling, moving up ancestor levels if needed
4158 loop {
4159 if cursor.goto_next_sibling() {
4160 let layer_result = cursor.node();
4161
4162 if let Some(previous_result) = &result {
4163 if previous_result.byte_range().start > layer_result.byte_range().start {
4164 continue;
4165 }
4166 }
4167 result = Some(layer_result);
4168 break;
4169 }
4170
4171 // No sibling found at this level, try moving up to parent
4172 if !cursor.goto_parent() {
4173 break;
4174 }
4175 }
4176 }
4177
4178 result
4179 }
4180
4181 /// Returns the root syntax node within the given row
4182 pub fn syntax_root_ancestor(&self, position: Anchor) -> Option<tree_sitter::Node<'_>> {
4183 let start_offset = position.to_offset(self);
4184
4185 let row = self.summary_for_anchor::<text::PointUtf16>(&position).row as usize;
4186
4187 let layer = self
4188 .syntax
4189 .layers_for_range(start_offset..start_offset, &self.text, true)
4190 .next()?;
4191
4192 let mut cursor = layer.node().walk();
4193
4194 // Descend to the first leaf that touches the start of the range.
4195 while cursor.goto_first_child_for_byte(start_offset).is_some() {
4196 if cursor.node().end_byte() == start_offset {
4197 cursor.goto_next_sibling();
4198 }
4199 }
4200
4201 // Ascend to the root node within the same row.
4202 while cursor.goto_parent() {
4203 if cursor.node().start_position().row != row {
4204 break;
4205 }
4206 }
4207
4208 Some(cursor.node())
4209 }
4210
4211 /// Returns the outline for the buffer.
4212 ///
4213 /// This method allows passing an optional [`SyntaxTheme`] to
4214 /// syntax-highlight the returned symbols.
4215 pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Outline<Anchor> {
4216 Outline::new(self.outline_items_containing(0..self.len(), true, theme))
4217 }
4218
4219 /// Returns all the symbols that contain the given position.
4220 ///
4221 /// This method allows passing an optional [`SyntaxTheme`] to
4222 /// syntax-highlight the returned symbols.
4223 pub fn symbols_containing<T: ToOffset>(
4224 &self,
4225 position: T,
4226 theme: Option<&SyntaxTheme>,
4227 ) -> Vec<OutlineItem<Anchor>> {
4228 let position = position.to_offset(self);
4229 let start = self.clip_offset(position.saturating_sub(1), Bias::Left);
4230 let end = self.clip_offset(position + 1, Bias::Right);
4231 let mut items = self.outline_items_containing(start..end, false, theme);
4232 let mut prev_depth = None;
4233 items.retain(|item| {
4234 let result = prev_depth.is_none_or(|prev_depth| item.depth > prev_depth);
4235 prev_depth = Some(item.depth);
4236 result
4237 });
4238 items
4239 }
4240
4241 pub fn outline_range_containing<T: ToOffset>(&self, range: Range<T>) -> Option<Range<Point>> {
4242 let range = range.to_offset(self);
4243 let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
4244 grammar.outline_config.as_ref().map(|c| &c.query)
4245 });
4246 let configs = matches
4247 .grammars()
4248 .iter()
4249 .map(|g| g.outline_config.as_ref().unwrap())
4250 .collect::<Vec<_>>();
4251
4252 while let Some(mat) = matches.peek() {
4253 let config = &configs[mat.grammar_index];
4254 let containing_item_node = maybe!({
4255 let item_node = mat.captures.iter().find_map(|cap| {
4256 if cap.index == config.item_capture_ix {
4257 Some(cap.node)
4258 } else {
4259 None
4260 }
4261 })?;
4262
4263 let item_byte_range = item_node.byte_range();
4264 if item_byte_range.end < range.start || item_byte_range.start > range.end {
4265 None
4266 } else {
4267 Some(item_node)
4268 }
4269 });
4270
4271 if let Some(item_node) = containing_item_node {
4272 return Some(
4273 Point::from_ts_point(item_node.start_position())
4274 ..Point::from_ts_point(item_node.end_position()),
4275 );
4276 }
4277
4278 matches.advance();
4279 }
4280 None
4281 }
4282
4283 pub fn outline_items_containing<T: ToOffset>(
4284 &self,
4285 range: Range<T>,
4286 include_extra_context: bool,
4287 theme: Option<&SyntaxTheme>,
4288 ) -> Vec<OutlineItem<Anchor>> {
4289 self.outline_items_containing_internal(
4290 range,
4291 include_extra_context,
4292 theme,
4293 |this, range| this.anchor_after(range.start)..this.anchor_before(range.end),
4294 )
4295 }
4296
4297 pub fn outline_items_as_points_containing<T: ToOffset>(
4298 &self,
4299 range: Range<T>,
4300 include_extra_context: bool,
4301 theme: Option<&SyntaxTheme>,
4302 ) -> Vec<OutlineItem<Point>> {
4303 self.outline_items_containing_internal(range, include_extra_context, theme, |_, range| {
4304 range
4305 })
4306 }
4307
4308 pub fn outline_items_as_offsets_containing<T: ToOffset>(
4309 &self,
4310 range: Range<T>,
4311 include_extra_context: bool,
4312 theme: Option<&SyntaxTheme>,
4313 ) -> Vec<OutlineItem<usize>> {
4314 self.outline_items_containing_internal(
4315 range,
4316 include_extra_context,
4317 theme,
4318 |buffer, range| range.to_offset(buffer),
4319 )
4320 }
4321
4322 fn outline_items_containing_internal<T: ToOffset, U>(
4323 &self,
4324 range: Range<T>,
4325 include_extra_context: bool,
4326 theme: Option<&SyntaxTheme>,
4327 range_callback: fn(&Self, Range<Point>) -> Range<U>,
4328 ) -> Vec<OutlineItem<U>> {
4329 let range = range.to_offset(self);
4330 let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
4331 grammar.outline_config.as_ref().map(|c| &c.query)
4332 });
4333
4334 let mut items = Vec::new();
4335 let mut annotation_row_ranges: Vec<Range<u32>> = Vec::new();
4336 while let Some(mat) = matches.peek() {
4337 let config = matches.grammars()[mat.grammar_index]
4338 .outline_config
4339 .as_ref()
4340 .unwrap();
4341 if let Some(item) =
4342 self.next_outline_item(config, &mat, &range, include_extra_context, theme)
4343 {
4344 items.push(item);
4345 } else if let Some(capture) = mat
4346 .captures
4347 .iter()
4348 .find(|capture| Some(capture.index) == config.annotation_capture_ix)
4349 {
4350 let capture_range = capture.node.start_position()..capture.node.end_position();
4351 let mut capture_row_range =
4352 capture_range.start.row as u32..capture_range.end.row as u32;
4353 if capture_range.end.row > capture_range.start.row && capture_range.end.column == 0
4354 {
4355 capture_row_range.end -= 1;
4356 }
4357 if let Some(last_row_range) = annotation_row_ranges.last_mut() {
4358 if last_row_range.end >= capture_row_range.start.saturating_sub(1) {
4359 last_row_range.end = capture_row_range.end;
4360 } else {
4361 annotation_row_ranges.push(capture_row_range);
4362 }
4363 } else {
4364 annotation_row_ranges.push(capture_row_range);
4365 }
4366 }
4367 matches.advance();
4368 }
4369
4370 items.sort_by_key(|item| (item.range.start, Reverse(item.range.end)));
4371
4372 // Assign depths based on containment relationships and convert to anchors.
4373 let mut item_ends_stack = Vec::<Point>::new();
4374 let mut anchor_items = Vec::new();
4375 let mut annotation_row_ranges = annotation_row_ranges.into_iter().peekable();
4376 for item in items {
4377 while let Some(last_end) = item_ends_stack.last().copied() {
4378 if last_end < item.range.end {
4379 item_ends_stack.pop();
4380 } else {
4381 break;
4382 }
4383 }
4384
4385 let mut annotation_row_range = None;
4386 while let Some(next_annotation_row_range) = annotation_row_ranges.peek() {
4387 let row_preceding_item = item.range.start.row.saturating_sub(1);
4388 if next_annotation_row_range.end < row_preceding_item {
4389 annotation_row_ranges.next();
4390 } else {
4391 if next_annotation_row_range.end == row_preceding_item {
4392 annotation_row_range = Some(next_annotation_row_range.clone());
4393 annotation_row_ranges.next();
4394 }
4395 break;
4396 }
4397 }
4398
4399 anchor_items.push(OutlineItem {
4400 depth: item_ends_stack.len(),
4401 range: range_callback(self, item.range.clone()),
4402 source_range_for_text: range_callback(self, item.source_range_for_text.clone()),
4403 text: item.text,
4404 highlight_ranges: item.highlight_ranges,
4405 name_ranges: item.name_ranges,
4406 body_range: item.body_range.map(|r| range_callback(self, r)),
4407 annotation_range: annotation_row_range.map(|annotation_range| {
4408 let point_range = Point::new(annotation_range.start, 0)
4409 ..Point::new(annotation_range.end, self.line_len(annotation_range.end));
4410 range_callback(self, point_range)
4411 }),
4412 });
4413 item_ends_stack.push(item.range.end);
4414 }
4415
4416 anchor_items
4417 }
4418
4419 fn next_outline_item(
4420 &self,
4421 config: &OutlineConfig,
4422 mat: &SyntaxMapMatch,
4423 range: &Range<usize>,
4424 include_extra_context: bool,
4425 theme: Option<&SyntaxTheme>,
4426 ) -> Option<OutlineItem<Point>> {
4427 let item_node = mat.captures.iter().find_map(|cap| {
4428 if cap.index == config.item_capture_ix {
4429 Some(cap.node)
4430 } else {
4431 None
4432 }
4433 })?;
4434
4435 let item_byte_range = item_node.byte_range();
4436 if item_byte_range.end < range.start || item_byte_range.start > range.end {
4437 return None;
4438 }
4439 let item_point_range = Point::from_ts_point(item_node.start_position())
4440 ..Point::from_ts_point(item_node.end_position());
4441
4442 let mut open_point = None;
4443 let mut close_point = None;
4444
4445 let mut buffer_ranges = Vec::new();
4446 let mut add_to_buffer_ranges = |node: tree_sitter::Node, node_is_name| {
4447 let mut range = node.start_byte()..node.end_byte();
4448 let start = node.start_position();
4449 if node.end_position().row > start.row {
4450 range.end = range.start + self.line_len(start.row as u32) as usize - start.column;
4451 }
4452
4453 if !range.is_empty() {
4454 buffer_ranges.push((range, node_is_name));
4455 }
4456 };
4457
4458 for capture in mat.captures {
4459 if capture.index == config.name_capture_ix {
4460 add_to_buffer_ranges(capture.node, true);
4461 } else if Some(capture.index) == config.context_capture_ix
4462 || (Some(capture.index) == config.extra_context_capture_ix && include_extra_context)
4463 {
4464 add_to_buffer_ranges(capture.node, false);
4465 } else {
4466 if Some(capture.index) == config.open_capture_ix {
4467 open_point = Some(Point::from_ts_point(capture.node.end_position()));
4468 } else if Some(capture.index) == config.close_capture_ix {
4469 close_point = Some(Point::from_ts_point(capture.node.start_position()));
4470 }
4471 }
4472 }
4473
4474 if buffer_ranges.is_empty() {
4475 return None;
4476 }
4477 let source_range_for_text =
4478 buffer_ranges.first().unwrap().0.start..buffer_ranges.last().unwrap().0.end;
4479
4480 let mut text = String::new();
4481 let mut highlight_ranges = Vec::new();
4482 let mut name_ranges = Vec::new();
4483 let mut chunks = self.chunks(source_range_for_text.clone(), true);
4484 let mut last_buffer_range_end = 0;
4485 for (buffer_range, is_name) in buffer_ranges {
4486 let space_added = !text.is_empty() && buffer_range.start > last_buffer_range_end;
4487 if space_added {
4488 text.push(' ');
4489 }
4490 let before_append_len = text.len();
4491 let mut offset = buffer_range.start;
4492 chunks.seek(buffer_range.clone());
4493 for mut chunk in chunks.by_ref() {
4494 if chunk.text.len() > buffer_range.end - offset {
4495 chunk.text = &chunk.text[0..(buffer_range.end - offset)];
4496 offset = buffer_range.end;
4497 } else {
4498 offset += chunk.text.len();
4499 }
4500 let style = chunk
4501 .syntax_highlight_id
4502 .zip(theme)
4503 .and_then(|(highlight, theme)| highlight.style(theme));
4504 if let Some(style) = style {
4505 let start = text.len();
4506 let end = start + chunk.text.len();
4507 highlight_ranges.push((start..end, style));
4508 }
4509 text.push_str(chunk.text);
4510 if offset >= buffer_range.end {
4511 break;
4512 }
4513 }
4514 if is_name {
4515 let after_append_len = text.len();
4516 let start = if space_added && !name_ranges.is_empty() {
4517 before_append_len - 1
4518 } else {
4519 before_append_len
4520 };
4521 name_ranges.push(start..after_append_len);
4522 }
4523 last_buffer_range_end = buffer_range.end;
4524 }
4525
4526 Some(OutlineItem {
4527 depth: 0, // We'll calculate the depth later
4528 range: item_point_range,
4529 source_range_for_text: source_range_for_text.to_point(self),
4530 text,
4531 highlight_ranges,
4532 name_ranges,
4533 body_range: open_point.zip(close_point).map(|(start, end)| start..end),
4534 annotation_range: None,
4535 })
4536 }
4537
4538 pub fn function_body_fold_ranges<T: ToOffset>(
4539 &self,
4540 within: Range<T>,
4541 ) -> impl Iterator<Item = Range<usize>> + '_ {
4542 self.text_object_ranges(within, TreeSitterOptions::default())
4543 .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
4544 }
4545
4546 /// For each grammar in the language, runs the provided
4547 /// [`tree_sitter::Query`] against the given range.
4548 pub fn matches(
4549 &self,
4550 range: Range<usize>,
4551 query: fn(&Grammar) -> Option<&tree_sitter::Query>,
4552 ) -> SyntaxMapMatches<'_> {
4553 self.syntax.matches(range, self, query)
4554 }
4555
4556 /// Finds all [`RowChunks`] applicable to the given range, then returns all bracket pairs that intersect with those chunks.
4557 /// Hence, may return more bracket pairs than the range contains.
4558 ///
4559 /// Will omit known chunks.
4560 /// The resulting bracket match collections are not ordered.
4561 pub fn fetch_bracket_ranges(
4562 &self,
4563 range: Range<usize>,
4564 known_chunks: Option<&HashSet<Range<BufferRow>>>,
4565 ) -> HashMap<Range<BufferRow>, Vec<BracketMatch<usize>>> {
4566 let mut all_bracket_matches = HashMap::default();
4567
4568 for chunk in self
4569 .tree_sitter_data
4570 .chunks
4571 .applicable_chunks(&[range.to_point(self)])
4572 {
4573 if known_chunks.is_some_and(|chunks| chunks.contains(&chunk.row_range())) {
4574 continue;
4575 }
4576 let chunk_range = chunk.anchor_range();
4577 let chunk_range = chunk_range.to_offset(&self);
4578
4579 if let Some(cached_brackets) =
4580 &self.tree_sitter_data.brackets_by_chunks.lock()[chunk.id]
4581 {
4582 all_bracket_matches.insert(chunk.row_range(), cached_brackets.clone());
4583 continue;
4584 }
4585
4586 let mut all_brackets: Vec<(BracketMatch<usize>, bool)> = Vec::new();
4587 let mut opens = Vec::new();
4588 let mut color_pairs = Vec::new();
4589
4590 let mut matches = self.syntax.matches_with_options(
4591 chunk_range.clone(),
4592 &self.text,
4593 TreeSitterOptions {
4594 max_bytes_to_query: Some(MAX_BYTES_TO_QUERY),
4595 max_start_depth: None,
4596 },
4597 |grammar| grammar.brackets_config.as_ref().map(|c| &c.query),
4598 );
4599 let configs = matches
4600 .grammars()
4601 .iter()
4602 .map(|grammar| grammar.brackets_config.as_ref().unwrap())
4603 .collect::<Vec<_>>();
4604
4605 // Group matches by open range so we can either trust grammar output
4606 // or repair it by picking a single closest close per open.
4607 let mut open_to_close_ranges = BTreeMap::new();
4608 while let Some(mat) = matches.peek() {
4609 let mut open = None;
4610 let mut close = None;
4611 let syntax_layer_depth = mat.depth;
4612 let config = configs[mat.grammar_index];
4613 let pattern = &config.patterns[mat.pattern_index];
4614 for capture in mat.captures {
4615 if capture.index == config.open_capture_ix {
4616 open = Some(capture.node.byte_range());
4617 } else if capture.index == config.close_capture_ix {
4618 close = Some(capture.node.byte_range());
4619 }
4620 }
4621
4622 matches.advance();
4623
4624 let Some((open_range, close_range)) = open.zip(close) else {
4625 continue;
4626 };
4627
4628 let bracket_range = open_range.start..=close_range.end;
4629 if !bracket_range.overlaps(&chunk_range) {
4630 continue;
4631 }
4632
4633 open_to_close_ranges
4634 .entry((open_range.start, open_range.end))
4635 .or_insert_with(BTreeMap::new)
4636 .insert(
4637 (close_range.start, close_range.end),
4638 BracketMatch {
4639 open_range: open_range.clone(),
4640 close_range: close_range.clone(),
4641 syntax_layer_depth,
4642 newline_only: pattern.newline_only,
4643 color_index: None,
4644 },
4645 );
4646
4647 all_brackets.push((
4648 BracketMatch {
4649 open_range,
4650 close_range,
4651 syntax_layer_depth,
4652 newline_only: pattern.newline_only,
4653 color_index: None,
4654 },
4655 pattern.rainbow_exclude,
4656 ));
4657 }
4658
4659 let has_bogus_matches = open_to_close_ranges
4660 .iter()
4661 .any(|(_, end_ranges)| end_ranges.len() > 1);
4662 if has_bogus_matches {
4663 // Grammar is producing bogus matches where one open is paired with multiple
4664 // closes. Build a valid stack by walking through positions in order.
4665 // For each close, we know the expected open_len from tree-sitter matches.
4666
4667 // Map each close to its expected open length (for inferring opens)
4668 let close_to_open_len: HashMap<(usize, usize), usize> = all_brackets
4669 .iter()
4670 .map(|(m, _)| ((m.close_range.start, m.close_range.end), m.open_range.len()))
4671 .collect();
4672
4673 // Collect unique opens and closes within this chunk
4674 let mut unique_opens: HashSet<(usize, usize)> = all_brackets
4675 .iter()
4676 .map(|(m, _)| (m.open_range.start, m.open_range.end))
4677 .filter(|(start, _)| chunk_range.contains(start))
4678 .collect();
4679
4680 let mut unique_closes: Vec<(usize, usize)> = all_brackets
4681 .iter()
4682 .map(|(m, _)| (m.close_range.start, m.close_range.end))
4683 .filter(|(start, _)| chunk_range.contains(start))
4684 .collect();
4685 unique_closes.sort();
4686 unique_closes.dedup();
4687
4688 // Build valid pairs by walking through closes in order
4689 let mut unique_opens_vec: Vec<_> = unique_opens.iter().copied().collect();
4690 unique_opens_vec.sort();
4691
4692 let mut valid_pairs: HashSet<((usize, usize), (usize, usize))> = HashSet::default();
4693 let mut open_stack: Vec<(usize, usize)> = Vec::new();
4694 let mut open_idx = 0;
4695
4696 for close in &unique_closes {
4697 // Push all opens before this close onto stack
4698 while open_idx < unique_opens_vec.len()
4699 && unique_opens_vec[open_idx].0 < close.0
4700 {
4701 open_stack.push(unique_opens_vec[open_idx]);
4702 open_idx += 1;
4703 }
4704
4705 // Try to match with most recent open
4706 if let Some(open) = open_stack.pop() {
4707 valid_pairs.insert((open, *close));
4708 } else if let Some(&open_len) = close_to_open_len.get(close) {
4709 // No open on stack - infer one based on expected open_len
4710 if close.0 >= open_len {
4711 let inferred = (close.0 - open_len, close.0);
4712 unique_opens.insert(inferred);
4713 valid_pairs.insert((inferred, *close));
4714 all_brackets.push((
4715 BracketMatch {
4716 open_range: inferred.0..inferred.1,
4717 close_range: close.0..close.1,
4718 newline_only: false,
4719 syntax_layer_depth: 0,
4720 color_index: None,
4721 },
4722 false,
4723 ));
4724 }
4725 }
4726 }
4727
4728 all_brackets.retain(|(m, _)| {
4729 let open = (m.open_range.start, m.open_range.end);
4730 let close = (m.close_range.start, m.close_range.end);
4731 valid_pairs.contains(&(open, close))
4732 });
4733 }
4734
4735 let mut all_brackets = all_brackets
4736 .into_iter()
4737 .enumerate()
4738 .map(|(index, (bracket_match, rainbow_exclude))| {
4739 // Certain languages have "brackets" that are not brackets, e.g. tags. and such
4740 // bracket will match the entire tag with all text inside.
4741 // For now, avoid highlighting any pair that has more than single char in each bracket.
4742 // We need to colorize `<Element/>` bracket pairs, so cannot make this check stricter.
4743 let should_color = !rainbow_exclude
4744 && (bracket_match.open_range.len() == 1
4745 || bracket_match.close_range.len() == 1);
4746 if should_color {
4747 opens.push(bracket_match.open_range.clone());
4748 color_pairs.push((
4749 bracket_match.open_range.clone(),
4750 bracket_match.close_range.clone(),
4751 index,
4752 ));
4753 }
4754 bracket_match
4755 })
4756 .collect::<Vec<_>>();
4757
4758 opens.sort_by_key(|r| (r.start, r.end));
4759 opens.dedup_by(|a, b| a.start == b.start && a.end == b.end);
4760 color_pairs.sort_by_key(|(_, close, _)| close.end);
4761
4762 let mut open_stack = Vec::new();
4763 let mut open_index = 0;
4764 for (open, close, index) in color_pairs {
4765 while open_index < opens.len() && opens[open_index].start < close.start {
4766 open_stack.push(opens[open_index].clone());
4767 open_index += 1;
4768 }
4769
4770 if open_stack.last() == Some(&open) {
4771 let depth_index = open_stack.len() - 1;
4772 all_brackets[index].color_index = Some(depth_index);
4773 open_stack.pop();
4774 }
4775 }
4776
4777 all_brackets.sort_by_key(|bracket_match| {
4778 (bracket_match.open_range.start, bracket_match.open_range.end)
4779 });
4780
4781 if let empty_slot @ None =
4782 &mut self.tree_sitter_data.brackets_by_chunks.lock()[chunk.id]
4783 {
4784 *empty_slot = Some(all_brackets.clone());
4785 }
4786 all_bracket_matches.insert(chunk.row_range(), all_brackets);
4787 }
4788
4789 all_bracket_matches
4790 }
4791
4792 pub fn all_bracket_ranges(
4793 &self,
4794 range: Range<usize>,
4795 ) -> impl Iterator<Item = BracketMatch<usize>> {
4796 self.fetch_bracket_ranges(range.clone(), None)
4797 .into_values()
4798 .flatten()
4799 .filter(move |bracket_match| {
4800 let bracket_range = bracket_match.open_range.start..bracket_match.close_range.end;
4801 bracket_range.overlaps(&range)
4802 })
4803 }
4804
4805 /// Returns bracket range pairs overlapping or adjacent to `range`
4806 pub fn bracket_ranges<T: ToOffset>(
4807 &self,
4808 range: Range<T>,
4809 ) -> impl Iterator<Item = BracketMatch<usize>> + '_ {
4810 // Find bracket pairs that *inclusively* contain the given range.
4811 let range = range.start.to_previous_offset(self)..range.end.to_next_offset(self);
4812 self.all_bracket_ranges(range)
4813 .filter(|pair| !pair.newline_only)
4814 }
4815
4816 pub fn debug_variables_query<T: ToOffset>(
4817 &self,
4818 range: Range<T>,
4819 ) -> impl Iterator<Item = (Range<usize>, DebuggerTextObject)> + '_ {
4820 let range = range.start.to_previous_offset(self)..range.end.to_next_offset(self);
4821
4822 let mut matches = self.syntax.matches_with_options(
4823 range.clone(),
4824 &self.text,
4825 TreeSitterOptions::default(),
4826 |grammar| grammar.debug_variables_config.as_ref().map(|c| &c.query),
4827 );
4828
4829 let configs = matches
4830 .grammars()
4831 .iter()
4832 .map(|grammar| grammar.debug_variables_config.as_ref())
4833 .collect::<Vec<_>>();
4834
4835 let mut captures = Vec::<(Range<usize>, DebuggerTextObject)>::new();
4836
4837 iter::from_fn(move || {
4838 loop {
4839 while let Some(capture) = captures.pop() {
4840 if capture.0.overlaps(&range) {
4841 return Some(capture);
4842 }
4843 }
4844
4845 let mat = matches.peek()?;
4846
4847 let Some(config) = configs[mat.grammar_index].as_ref() else {
4848 matches.advance();
4849 continue;
4850 };
4851
4852 for capture in mat.captures {
4853 let Some(ix) = config
4854 .objects_by_capture_ix
4855 .binary_search_by_key(&capture.index, |e| e.0)
4856 .ok()
4857 else {
4858 continue;
4859 };
4860 let text_object = config.objects_by_capture_ix[ix].1;
4861 let byte_range = capture.node.byte_range();
4862
4863 let mut found = false;
4864 for (range, existing) in captures.iter_mut() {
4865 if existing == &text_object {
4866 range.start = range.start.min(byte_range.start);
4867 range.end = range.end.max(byte_range.end);
4868 found = true;
4869 break;
4870 }
4871 }
4872
4873 if !found {
4874 captures.push((byte_range, text_object));
4875 }
4876 }
4877
4878 matches.advance();
4879 }
4880 })
4881 }
4882
4883 pub fn text_object_ranges<T: ToOffset>(
4884 &self,
4885 range: Range<T>,
4886 options: TreeSitterOptions,
4887 ) -> impl Iterator<Item = (Range<usize>, TextObject)> + '_ {
4888 let range =
4889 range.start.to_previous_offset(self)..self.len().min(range.end.to_next_offset(self));
4890
4891 let mut matches =
4892 self.syntax
4893 .matches_with_options(range.clone(), &self.text, options, |grammar| {
4894 grammar.text_object_config.as_ref().map(|c| &c.query)
4895 });
4896
4897 let configs = matches
4898 .grammars()
4899 .iter()
4900 .map(|grammar| grammar.text_object_config.as_ref())
4901 .collect::<Vec<_>>();
4902
4903 let mut captures = Vec::<(Range<usize>, TextObject)>::new();
4904
4905 iter::from_fn(move || {
4906 loop {
4907 while let Some(capture) = captures.pop() {
4908 if capture.0.overlaps(&range) {
4909 return Some(capture);
4910 }
4911 }
4912
4913 let mat = matches.peek()?;
4914
4915 let Some(config) = configs[mat.grammar_index].as_ref() else {
4916 matches.advance();
4917 continue;
4918 };
4919
4920 for capture in mat.captures {
4921 let Some(ix) = config
4922 .text_objects_by_capture_ix
4923 .binary_search_by_key(&capture.index, |e| e.0)
4924 .ok()
4925 else {
4926 continue;
4927 };
4928 let text_object = config.text_objects_by_capture_ix[ix].1;
4929 let byte_range = capture.node.byte_range();
4930
4931 let mut found = false;
4932 for (range, existing) in captures.iter_mut() {
4933 if existing == &text_object {
4934 range.start = range.start.min(byte_range.start);
4935 range.end = range.end.max(byte_range.end);
4936 found = true;
4937 break;
4938 }
4939 }
4940
4941 if !found {
4942 captures.push((byte_range, text_object));
4943 }
4944 }
4945
4946 matches.advance();
4947 }
4948 })
4949 }
4950
4951 /// Returns enclosing bracket ranges containing the given range
4952 pub fn enclosing_bracket_ranges<T: ToOffset>(
4953 &self,
4954 range: Range<T>,
4955 ) -> impl Iterator<Item = BracketMatch<usize>> + '_ {
4956 let range = range.start.to_offset(self)..range.end.to_offset(self);
4957
4958 let result: Vec<_> = self.bracket_ranges(range.clone()).collect();
4959 let max_depth = result
4960 .iter()
4961 .map(|mat| mat.syntax_layer_depth)
4962 .max()
4963 .unwrap_or(0);
4964 result.into_iter().filter(move |pair| {
4965 pair.open_range.start <= range.start
4966 && pair.close_range.end >= range.end
4967 && pair.syntax_layer_depth == max_depth
4968 })
4969 }
4970
4971 /// Returns the smallest enclosing bracket ranges containing the given range or None if no brackets contain range
4972 ///
4973 /// Can optionally pass a range_filter to filter the ranges of brackets to consider
4974 pub fn innermost_enclosing_bracket_ranges<T: ToOffset>(
4975 &self,
4976 range: Range<T>,
4977 range_filter: Option<&dyn Fn(Range<usize>, Range<usize>) -> bool>,
4978 ) -> Option<(Range<usize>, Range<usize>)> {
4979 let range = range.start.to_offset(self)..range.end.to_offset(self);
4980
4981 // Get the ranges of the innermost pair of brackets.
4982 let mut result: Option<(Range<usize>, Range<usize>)> = None;
4983
4984 for pair in self.enclosing_bracket_ranges(range) {
4985 if let Some(range_filter) = range_filter
4986 && !range_filter(pair.open_range.clone(), pair.close_range.clone())
4987 {
4988 continue;
4989 }
4990
4991 let len = pair.close_range.end - pair.open_range.start;
4992
4993 if let Some((existing_open, existing_close)) = &result {
4994 let existing_len = existing_close.end - existing_open.start;
4995 if len > existing_len {
4996 continue;
4997 }
4998 }
4999
5000 result = Some((pair.open_range, pair.close_range));
5001 }
5002
5003 result
5004 }
5005
5006 /// Returns anchor ranges for any matches of the redaction query.
5007 /// The buffer can be associated with multiple languages, and the redaction query associated with each
5008 /// will be run on the relevant section of the buffer.
5009 pub fn redacted_ranges<T: ToOffset>(
5010 &self,
5011 range: Range<T>,
5012 ) -> impl Iterator<Item = Range<usize>> + '_ {
5013 let offset_range = range.start.to_offset(self)..range.end.to_offset(self);
5014 let mut syntax_matches = self.syntax.matches(offset_range, self, |grammar| {
5015 grammar
5016 .redactions_config
5017 .as_ref()
5018 .map(|config| &config.query)
5019 });
5020
5021 let configs = syntax_matches
5022 .grammars()
5023 .iter()
5024 .map(|grammar| grammar.redactions_config.as_ref())
5025 .collect::<Vec<_>>();
5026
5027 iter::from_fn(move || {
5028 let redacted_range = syntax_matches
5029 .peek()
5030 .and_then(|mat| {
5031 configs[mat.grammar_index].and_then(|config| {
5032 mat.captures
5033 .iter()
5034 .find(|capture| capture.index == config.redaction_capture_ix)
5035 })
5036 })
5037 .map(|mat| mat.node.byte_range());
5038 syntax_matches.advance();
5039 redacted_range
5040 })
5041 }
5042
5043 pub fn injections_intersecting_range<T: ToOffset>(
5044 &self,
5045 range: Range<T>,
5046 ) -> impl Iterator<Item = (Range<usize>, &Arc<Language>)> + '_ {
5047 let offset_range = range.start.to_offset(self)..range.end.to_offset(self);
5048
5049 let mut syntax_matches = self.syntax.matches(offset_range, self, |grammar| {
5050 grammar
5051 .injection_config
5052 .as_ref()
5053 .map(|config| &config.query)
5054 });
5055
5056 let configs = syntax_matches
5057 .grammars()
5058 .iter()
5059 .map(|grammar| grammar.injection_config.as_ref())
5060 .collect::<Vec<_>>();
5061
5062 iter::from_fn(move || {
5063 let ranges = syntax_matches.peek().and_then(|mat| {
5064 let config = &configs[mat.grammar_index]?;
5065 let content_capture_range = mat.captures.iter().find_map(|capture| {
5066 if capture.index == config.content_capture_ix {
5067 Some(capture.node.byte_range())
5068 } else {
5069 None
5070 }
5071 })?;
5072 let language = self.language_at(content_capture_range.start)?;
5073 Some((content_capture_range, language))
5074 });
5075 syntax_matches.advance();
5076 ranges
5077 })
5078 }
5079
5080 pub fn runnable_ranges(
5081 &self,
5082 offset_range: Range<usize>,
5083 ) -> impl Iterator<Item = RunnableRange> + '_ {
5084 let mut syntax_matches = self.syntax.matches(offset_range, self, |grammar| {
5085 grammar.runnable_config.as_ref().map(|config| &config.query)
5086 });
5087
5088 let test_configs = syntax_matches
5089 .grammars()
5090 .iter()
5091 .map(|grammar| grammar.runnable_config.as_ref())
5092 .collect::<Vec<_>>();
5093
5094 iter::from_fn(move || {
5095 loop {
5096 let mat = syntax_matches.peek()?;
5097
5098 let test_range = test_configs[mat.grammar_index].and_then(|test_configs| {
5099 let mut run_range = None;
5100 let full_range = mat.captures.iter().fold(
5101 Range {
5102 start: usize::MAX,
5103 end: 0,
5104 },
5105 |mut acc, next| {
5106 let byte_range = next.node.byte_range();
5107 if acc.start > byte_range.start {
5108 acc.start = byte_range.start;
5109 }
5110 if acc.end < byte_range.end {
5111 acc.end = byte_range.end;
5112 }
5113 acc
5114 },
5115 );
5116 if full_range.start > full_range.end {
5117 // We did not find a full spanning range of this match.
5118 return None;
5119 }
5120 let extra_captures: SmallVec<[_; 1]> =
5121 SmallVec::from_iter(mat.captures.iter().filter_map(|capture| {
5122 test_configs
5123 .extra_captures
5124 .get(capture.index as usize)
5125 .cloned()
5126 .and_then(|tag_name| match tag_name {
5127 RunnableCapture::Named(name) => {
5128 Some((capture.node.byte_range(), name))
5129 }
5130 RunnableCapture::Run => {
5131 let _ = run_range.insert(capture.node.byte_range());
5132 None
5133 }
5134 })
5135 }));
5136 let run_range = run_range?;
5137 let tags = test_configs
5138 .query
5139 .property_settings(mat.pattern_index)
5140 .iter()
5141 .filter_map(|property| {
5142 if *property.key == *"tag" {
5143 property
5144 .value
5145 .as_ref()
5146 .map(|value| RunnableTag(value.to_string().into()))
5147 } else {
5148 None
5149 }
5150 })
5151 .collect();
5152 let extra_captures = extra_captures
5153 .into_iter()
5154 .map(|(range, name)| {
5155 (
5156 name.to_string(),
5157 self.text_for_range(range).collect::<String>(),
5158 )
5159 })
5160 .collect();
5161 // All tags should have the same range.
5162 Some(RunnableRange {
5163 run_range,
5164 full_range,
5165 runnable: Runnable {
5166 tags,
5167 language: mat.language,
5168 buffer: self.remote_id(),
5169 },
5170 extra_captures,
5171 buffer_id: self.remote_id(),
5172 })
5173 });
5174
5175 syntax_matches.advance();
5176 if test_range.is_some() {
5177 // It's fine for us to short-circuit on .peek()? returning None. We don't want to return None from this iter if we
5178 // had a capture that did not contain a run marker, hence we'll just loop around for the next capture.
5179 return test_range;
5180 }
5181 }
5182 })
5183 }
5184
5185 /// Returns selections for remote peers intersecting the given range.
5186 #[allow(clippy::type_complexity)]
5187 pub fn selections_in_range(
5188 &self,
5189 range: Range<Anchor>,
5190 include_local: bool,
5191 ) -> impl Iterator<
5192 Item = (
5193 ReplicaId,
5194 bool,
5195 CursorShape,
5196 impl Iterator<Item = &Selection<Anchor>> + '_,
5197 ),
5198 > + '_ {
5199 self.remote_selections
5200 .iter()
5201 .filter(move |(replica_id, set)| {
5202 (include_local || **replica_id != self.text.replica_id())
5203 && !set.selections.is_empty()
5204 })
5205 .map(move |(replica_id, set)| {
5206 let start_ix = match set.selections.binary_search_by(|probe| {
5207 probe.end.cmp(&range.start, self).then(Ordering::Greater)
5208 }) {
5209 Ok(ix) | Err(ix) => ix,
5210 };
5211 let end_ix = match set.selections.binary_search_by(|probe| {
5212 probe.start.cmp(&range.end, self).then(Ordering::Less)
5213 }) {
5214 Ok(ix) | Err(ix) => ix,
5215 };
5216
5217 (
5218 *replica_id,
5219 set.line_mode,
5220 set.cursor_shape,
5221 set.selections[start_ix..end_ix].iter(),
5222 )
5223 })
5224 }
5225
5226 /// Returns if the buffer contains any diagnostics.
5227 pub fn has_diagnostics(&self) -> bool {
5228 !self.diagnostics.is_empty()
5229 }
5230
5231 /// Returns all the diagnostics intersecting the given range.
5232 pub fn diagnostics_in_range<'a, T, O>(
5233 &'a self,
5234 search_range: Range<T>,
5235 reversed: bool,
5236 ) -> impl 'a + Iterator<Item = DiagnosticEntryRef<'a, O>>
5237 where
5238 T: 'a + Clone + ToOffset,
5239 O: 'a + FromAnchor,
5240 {
5241 let mut iterators: Vec<_> = self
5242 .diagnostics
5243 .iter()
5244 .map(|(_, collection)| {
5245 collection
5246 .range::<T, text::Anchor>(search_range.clone(), self, true, reversed)
5247 .peekable()
5248 })
5249 .collect();
5250
5251 std::iter::from_fn(move || {
5252 let (next_ix, _) = iterators
5253 .iter_mut()
5254 .enumerate()
5255 .flat_map(|(ix, iter)| Some((ix, iter.peek()?)))
5256 .min_by(|(_, a), (_, b)| {
5257 let cmp = a
5258 .range
5259 .start
5260 .cmp(&b.range.start, self)
5261 // when range is equal, sort by diagnostic severity
5262 .then(a.diagnostic.severity.cmp(&b.diagnostic.severity))
5263 // and stabilize order with group_id
5264 .then(a.diagnostic.group_id.cmp(&b.diagnostic.group_id));
5265 if reversed { cmp.reverse() } else { cmp }
5266 })?;
5267 iterators[next_ix]
5268 .next()
5269 .map(
5270 |DiagnosticEntryRef { range, diagnostic }| DiagnosticEntryRef {
5271 diagnostic,
5272 range: FromAnchor::from_anchor(&range.start, self)
5273 ..FromAnchor::from_anchor(&range.end, self),
5274 },
5275 )
5276 })
5277 }
5278
5279 /// Returns all the diagnostic groups associated with the given
5280 /// language server ID. If no language server ID is provided,
5281 /// all diagnostics groups are returned.
5282 pub fn diagnostic_groups(
5283 &self,
5284 language_server_id: Option<LanguageServerId>,
5285 ) -> Vec<(LanguageServerId, DiagnosticGroup<'_, Anchor>)> {
5286 let mut groups = Vec::new();
5287
5288 if let Some(language_server_id) = language_server_id {
5289 if let Some(set) = self.diagnostics.get(&language_server_id) {
5290 set.groups(language_server_id, &mut groups, self);
5291 }
5292 } else {
5293 for (language_server_id, diagnostics) in self.diagnostics.iter() {
5294 diagnostics.groups(*language_server_id, &mut groups, self);
5295 }
5296 }
5297
5298 groups.sort_by(|(id_a, group_a), (id_b, group_b)| {
5299 let a_start = &group_a.entries[group_a.primary_ix].range.start;
5300 let b_start = &group_b.entries[group_b.primary_ix].range.start;
5301 a_start.cmp(b_start, self).then_with(|| id_a.cmp(id_b))
5302 });
5303
5304 groups
5305 }
5306
5307 /// Returns an iterator over the diagnostics for the given group.
5308 pub fn diagnostic_group<O>(
5309 &self,
5310 group_id: usize,
5311 ) -> impl Iterator<Item = DiagnosticEntryRef<'_, O>> + use<'_, O>
5312 where
5313 O: FromAnchor + 'static,
5314 {
5315 self.diagnostics
5316 .iter()
5317 .flat_map(move |(_, set)| set.group(group_id, self))
5318 }
5319
5320 /// An integer version number that accounts for all updates besides
5321 /// the buffer's text itself (which is versioned via a version vector).
5322 pub fn non_text_state_update_count(&self) -> usize {
5323 self.non_text_state_update_count
5324 }
5325
5326 /// An integer version that changes when the buffer's syntax changes.
5327 pub fn syntax_update_count(&self) -> usize {
5328 self.syntax.update_count()
5329 }
5330
5331 /// Returns a snapshot of underlying file.
5332 pub fn file(&self) -> Option<&Arc<dyn File>> {
5333 self.file.as_ref()
5334 }
5335
5336 pub fn resolve_file_path(&self, include_root: bool, cx: &App) -> Option<String> {
5337 if let Some(file) = self.file() {
5338 if file.path().file_name().is_none() || include_root {
5339 Some(file.full_path(cx).to_string_lossy().into_owned())
5340 } else {
5341 Some(file.path().display(file.path_style(cx)).to_string())
5342 }
5343 } else {
5344 None
5345 }
5346 }
5347
5348 pub fn words_in_range(&self, query: WordsQuery) -> BTreeMap<String, Range<Anchor>> {
5349 let query_str = query.fuzzy_contents;
5350 if query_str.is_some_and(|query| query.is_empty()) {
5351 return BTreeMap::default();
5352 }
5353
5354 let classifier = CharClassifier::new(self.language.clone().map(|language| LanguageScope {
5355 language,
5356 override_id: None,
5357 }));
5358
5359 let mut query_ix = 0;
5360 let query_chars = query_str.map(|query| query.chars().collect::<Vec<_>>());
5361 let query_len = query_chars.as_ref().map_or(0, |query| query.len());
5362
5363 let mut words = BTreeMap::default();
5364 let mut current_word_start_ix = None;
5365 let mut chunk_ix = query.range.start;
5366 for chunk in self.chunks(query.range, false) {
5367 for (i, c) in chunk.text.char_indices() {
5368 let ix = chunk_ix + i;
5369 if classifier.is_word(c) {
5370 if current_word_start_ix.is_none() {
5371 current_word_start_ix = Some(ix);
5372 }
5373
5374 if let Some(query_chars) = &query_chars
5375 && query_ix < query_len
5376 && c.to_lowercase().eq(query_chars[query_ix].to_lowercase())
5377 {
5378 query_ix += 1;
5379 }
5380 continue;
5381 } else if let Some(word_start) = current_word_start_ix.take()
5382 && query_ix == query_len
5383 {
5384 let word_range = self.anchor_before(word_start)..self.anchor_after(ix);
5385 let mut word_text = self.text_for_range(word_start..ix).peekable();
5386 let first_char = word_text
5387 .peek()
5388 .and_then(|first_chunk| first_chunk.chars().next());
5389 // Skip empty and "words" starting with digits as a heuristic to reduce useless completions
5390 if !query.skip_digits
5391 || first_char.is_none_or(|first_char| !first_char.is_digit(10))
5392 {
5393 words.insert(word_text.collect(), word_range);
5394 }
5395 }
5396 query_ix = 0;
5397 }
5398 chunk_ix += chunk.text.len();
5399 }
5400
5401 words
5402 }
5403}
5404
5405pub struct WordsQuery<'a> {
5406 /// Only returns words with all chars from the fuzzy string in them.
5407 pub fuzzy_contents: Option<&'a str>,
5408 /// Skips words that start with a digit.
5409 pub skip_digits: bool,
5410 /// Buffer offset range, to look for words.
5411 pub range: Range<usize>,
5412}
5413
5414fn indent_size_for_line(text: &text::BufferSnapshot, row: u32) -> IndentSize {
5415 indent_size_for_text(text.chars_at(Point::new(row, 0)))
5416}
5417
5418fn indent_size_for_text(text: impl Iterator<Item = char>) -> IndentSize {
5419 let mut result = IndentSize::spaces(0);
5420 for c in text {
5421 let kind = match c {
5422 ' ' => IndentKind::Space,
5423 '\t' => IndentKind::Tab,
5424 _ => break,
5425 };
5426 if result.len == 0 {
5427 result.kind = kind;
5428 }
5429 result.len += 1;
5430 }
5431 result
5432}
5433
5434impl Clone for BufferSnapshot {
5435 fn clone(&self) -> Self {
5436 Self {
5437 text: self.text.clone(),
5438 syntax: self.syntax.clone(),
5439 file: self.file.clone(),
5440 remote_selections: self.remote_selections.clone(),
5441 diagnostics: self.diagnostics.clone(),
5442 language: self.language.clone(),
5443 tree_sitter_data: self.tree_sitter_data.clone(),
5444 non_text_state_update_count: self.non_text_state_update_count,
5445 capability: self.capability,
5446 }
5447 }
5448}
5449
5450impl Deref for BufferSnapshot {
5451 type Target = text::BufferSnapshot;
5452
5453 fn deref(&self) -> &Self::Target {
5454 &self.text
5455 }
5456}
5457
5458unsafe impl Send for BufferChunks<'_> {}
5459
5460impl<'a> BufferChunks<'a> {
5461 pub(crate) fn new(
5462 text: &'a Rope,
5463 range: Range<usize>,
5464 syntax: Option<(SyntaxMapCaptures<'a>, Vec<HighlightMap>)>,
5465 diagnostics: bool,
5466 buffer_snapshot: Option<&'a BufferSnapshot>,
5467 ) -> Self {
5468 let mut highlights = None;
5469 if let Some((captures, highlight_maps)) = syntax {
5470 highlights = Some(BufferChunkHighlights {
5471 captures,
5472 next_capture: None,
5473 stack: Default::default(),
5474 highlight_maps,
5475 })
5476 }
5477
5478 let diagnostic_endpoints = diagnostics.then(|| Vec::new().into_iter().peekable());
5479 let chunks = text.chunks_in_range(range.clone());
5480
5481 let mut this = BufferChunks {
5482 range,
5483 buffer_snapshot,
5484 chunks,
5485 diagnostic_endpoints,
5486 error_depth: 0,
5487 warning_depth: 0,
5488 information_depth: 0,
5489 hint_depth: 0,
5490 unnecessary_depth: 0,
5491 underline: true,
5492 highlights,
5493 };
5494 this.initialize_diagnostic_endpoints();
5495 this
5496 }
5497
5498 /// Seeks to the given byte offset in the buffer.
5499 pub fn seek(&mut self, range: Range<usize>) {
5500 let old_range = std::mem::replace(&mut self.range, range.clone());
5501 self.chunks.set_range(self.range.clone());
5502 if let Some(highlights) = self.highlights.as_mut() {
5503 if old_range.start <= self.range.start && old_range.end >= self.range.end {
5504 // Reuse existing highlights stack, as the new range is a subrange of the old one.
5505 highlights
5506 .stack
5507 .retain(|(end_offset, _)| *end_offset > range.start);
5508 if let Some(capture) = &highlights.next_capture
5509 && range.start >= capture.node.start_byte()
5510 {
5511 let next_capture_end = capture.node.end_byte();
5512 if range.start < next_capture_end {
5513 highlights.stack.push((
5514 next_capture_end,
5515 highlights.highlight_maps[capture.grammar_index].get(capture.index),
5516 ));
5517 }
5518 highlights.next_capture.take();
5519 }
5520 } else if let Some(snapshot) = self.buffer_snapshot {
5521 let (captures, highlight_maps) = snapshot.get_highlights(self.range.clone());
5522 *highlights = BufferChunkHighlights {
5523 captures,
5524 next_capture: None,
5525 stack: Default::default(),
5526 highlight_maps,
5527 };
5528 } else {
5529 // We cannot obtain new highlights for a language-aware buffer iterator, as we don't have a buffer snapshot.
5530 // Seeking such BufferChunks is not supported.
5531 debug_assert!(
5532 false,
5533 "Attempted to seek on a language-aware buffer iterator without associated buffer snapshot"
5534 );
5535 }
5536
5537 highlights.captures.set_byte_range(self.range.clone());
5538 self.initialize_diagnostic_endpoints();
5539 }
5540 }
5541
5542 fn initialize_diagnostic_endpoints(&mut self) {
5543 if let Some(diagnostics) = self.diagnostic_endpoints.as_mut()
5544 && let Some(buffer) = self.buffer_snapshot
5545 {
5546 let mut diagnostic_endpoints = Vec::new();
5547 for entry in buffer.diagnostics_in_range::<_, usize>(self.range.clone(), false) {
5548 diagnostic_endpoints.push(DiagnosticEndpoint {
5549 offset: entry.range.start,
5550 is_start: true,
5551 severity: entry.diagnostic.severity,
5552 is_unnecessary: entry.diagnostic.is_unnecessary,
5553 underline: entry.diagnostic.underline,
5554 });
5555 diagnostic_endpoints.push(DiagnosticEndpoint {
5556 offset: entry.range.end,
5557 is_start: false,
5558 severity: entry.diagnostic.severity,
5559 is_unnecessary: entry.diagnostic.is_unnecessary,
5560 underline: entry.diagnostic.underline,
5561 });
5562 }
5563 diagnostic_endpoints
5564 .sort_unstable_by_key(|endpoint| (endpoint.offset, !endpoint.is_start));
5565 *diagnostics = diagnostic_endpoints.into_iter().peekable();
5566 self.hint_depth = 0;
5567 self.error_depth = 0;
5568 self.warning_depth = 0;
5569 self.information_depth = 0;
5570 }
5571 }
5572
5573 /// The current byte offset in the buffer.
5574 pub fn offset(&self) -> usize {
5575 self.range.start
5576 }
5577
5578 pub fn range(&self) -> Range<usize> {
5579 self.range.clone()
5580 }
5581
5582 fn update_diagnostic_depths(&mut self, endpoint: DiagnosticEndpoint) {
5583 let depth = match endpoint.severity {
5584 DiagnosticSeverity::ERROR => &mut self.error_depth,
5585 DiagnosticSeverity::WARNING => &mut self.warning_depth,
5586 DiagnosticSeverity::INFORMATION => &mut self.information_depth,
5587 DiagnosticSeverity::HINT => &mut self.hint_depth,
5588 _ => return,
5589 };
5590 if endpoint.is_start {
5591 *depth += 1;
5592 } else {
5593 *depth -= 1;
5594 }
5595
5596 if endpoint.is_unnecessary {
5597 if endpoint.is_start {
5598 self.unnecessary_depth += 1;
5599 } else {
5600 self.unnecessary_depth -= 1;
5601 }
5602 }
5603 }
5604
5605 fn current_diagnostic_severity(&self) -> Option<DiagnosticSeverity> {
5606 if self.error_depth > 0 {
5607 Some(DiagnosticSeverity::ERROR)
5608 } else if self.warning_depth > 0 {
5609 Some(DiagnosticSeverity::WARNING)
5610 } else if self.information_depth > 0 {
5611 Some(DiagnosticSeverity::INFORMATION)
5612 } else if self.hint_depth > 0 {
5613 Some(DiagnosticSeverity::HINT)
5614 } else {
5615 None
5616 }
5617 }
5618
5619 fn current_code_is_unnecessary(&self) -> bool {
5620 self.unnecessary_depth > 0
5621 }
5622}
5623
5624impl<'a> Iterator for BufferChunks<'a> {
5625 type Item = Chunk<'a>;
5626
5627 fn next(&mut self) -> Option<Self::Item> {
5628 let mut next_capture_start = usize::MAX;
5629 let mut next_diagnostic_endpoint = usize::MAX;
5630
5631 if let Some(highlights) = self.highlights.as_mut() {
5632 while let Some((parent_capture_end, _)) = highlights.stack.last() {
5633 if *parent_capture_end <= self.range.start {
5634 highlights.stack.pop();
5635 } else {
5636 break;
5637 }
5638 }
5639
5640 if highlights.next_capture.is_none() {
5641 highlights.next_capture = highlights.captures.next();
5642 }
5643
5644 while let Some(capture) = highlights.next_capture.as_ref() {
5645 if self.range.start < capture.node.start_byte() {
5646 next_capture_start = capture.node.start_byte();
5647 break;
5648 } else {
5649 let highlight_id =
5650 highlights.highlight_maps[capture.grammar_index].get(capture.index);
5651 highlights
5652 .stack
5653 .push((capture.node.end_byte(), highlight_id));
5654 highlights.next_capture = highlights.captures.next();
5655 }
5656 }
5657 }
5658
5659 let mut diagnostic_endpoints = std::mem::take(&mut self.diagnostic_endpoints);
5660 if let Some(diagnostic_endpoints) = diagnostic_endpoints.as_mut() {
5661 while let Some(endpoint) = diagnostic_endpoints.peek().copied() {
5662 if endpoint.offset <= self.range.start {
5663 self.update_diagnostic_depths(endpoint);
5664 diagnostic_endpoints.next();
5665 self.underline = endpoint.underline;
5666 } else {
5667 next_diagnostic_endpoint = endpoint.offset;
5668 break;
5669 }
5670 }
5671 }
5672 self.diagnostic_endpoints = diagnostic_endpoints;
5673
5674 if let Some(ChunkBitmaps {
5675 text: chunk,
5676 chars: chars_map,
5677 tabs,
5678 newlines,
5679 }) = self.chunks.peek_with_bitmaps()
5680 {
5681 let chunk_start = self.range.start;
5682 let mut chunk_end = (self.chunks.offset() + chunk.len())
5683 .min(next_capture_start)
5684 .min(next_diagnostic_endpoint);
5685 let mut highlight_id = None;
5686 if let Some(highlights) = self.highlights.as_ref()
5687 && let Some((parent_capture_end, parent_highlight_id)) = highlights.stack.last()
5688 {
5689 chunk_end = chunk_end.min(*parent_capture_end);
5690 highlight_id = Some(*parent_highlight_id);
5691 }
5692 let bit_start = chunk_start - self.chunks.offset();
5693 let bit_end = chunk_end - self.chunks.offset();
5694
5695 let slice = &chunk[bit_start..bit_end];
5696
5697 let mask = 1u128.unbounded_shl(bit_end as u32).wrapping_sub(1);
5698 let tabs = (tabs >> bit_start) & mask;
5699 let chars = (chars_map >> bit_start) & mask;
5700 let newlines = (newlines >> bit_start) & mask;
5701
5702 self.range.start = chunk_end;
5703 if self.range.start == self.chunks.offset() + chunk.len() {
5704 self.chunks.next().unwrap();
5705 }
5706
5707 Some(Chunk {
5708 text: slice,
5709 syntax_highlight_id: highlight_id,
5710 underline: self.underline,
5711 diagnostic_severity: self.current_diagnostic_severity(),
5712 is_unnecessary: self.current_code_is_unnecessary(),
5713 tabs,
5714 chars,
5715 newlines,
5716 ..Chunk::default()
5717 })
5718 } else {
5719 None
5720 }
5721 }
5722}
5723
5724impl operation_queue::Operation for Operation {
5725 fn lamport_timestamp(&self) -> clock::Lamport {
5726 match self {
5727 Operation::Buffer(_) => {
5728 unreachable!("buffer operations should never be deferred at this layer")
5729 }
5730 Operation::UpdateDiagnostics {
5731 lamport_timestamp, ..
5732 }
5733 | Operation::UpdateSelections {
5734 lamport_timestamp, ..
5735 }
5736 | Operation::UpdateCompletionTriggers {
5737 lamport_timestamp, ..
5738 }
5739 | Operation::UpdateLineEnding {
5740 lamport_timestamp, ..
5741 } => *lamport_timestamp,
5742 }
5743 }
5744}
5745
5746impl Default for Diagnostic {
5747 fn default() -> Self {
5748 Self {
5749 source: Default::default(),
5750 source_kind: DiagnosticSourceKind::Other,
5751 code: None,
5752 code_description: None,
5753 severity: DiagnosticSeverity::ERROR,
5754 message: Default::default(),
5755 markdown: None,
5756 group_id: 0,
5757 is_primary: false,
5758 is_disk_based: false,
5759 is_unnecessary: false,
5760 underline: true,
5761 data: None,
5762 registration_id: None,
5763 }
5764 }
5765}
5766
5767impl IndentSize {
5768 /// Returns an [`IndentSize`] representing the given spaces.
5769 pub fn spaces(len: u32) -> Self {
5770 Self {
5771 len,
5772 kind: IndentKind::Space,
5773 }
5774 }
5775
5776 /// Returns an [`IndentSize`] representing a tab.
5777 pub fn tab() -> Self {
5778 Self {
5779 len: 1,
5780 kind: IndentKind::Tab,
5781 }
5782 }
5783
5784 /// An iterator over the characters represented by this [`IndentSize`].
5785 pub fn chars(&self) -> impl Iterator<Item = char> {
5786 iter::repeat(self.char()).take(self.len as usize)
5787 }
5788
5789 /// The character representation of this [`IndentSize`].
5790 pub fn char(&self) -> char {
5791 match self.kind {
5792 IndentKind::Space => ' ',
5793 IndentKind::Tab => '\t',
5794 }
5795 }
5796
5797 /// Consumes the current [`IndentSize`] and returns a new one that has
5798 /// been shrunk or enlarged by the given size along the given direction.
5799 pub fn with_delta(mut self, direction: Ordering, size: IndentSize) -> Self {
5800 match direction {
5801 Ordering::Less => {
5802 if self.kind == size.kind && self.len >= size.len {
5803 self.len -= size.len;
5804 }
5805 }
5806 Ordering::Equal => {}
5807 Ordering::Greater => {
5808 if self.len == 0 {
5809 self = size;
5810 } else if self.kind == size.kind {
5811 self.len += size.len;
5812 }
5813 }
5814 }
5815 self
5816 }
5817
5818 pub fn len_with_expanded_tabs(&self, tab_size: NonZeroU32) -> usize {
5819 match self.kind {
5820 IndentKind::Space => self.len as usize,
5821 IndentKind::Tab => self.len as usize * tab_size.get() as usize,
5822 }
5823 }
5824}
5825
5826#[cfg(any(test, feature = "test-support"))]
5827pub struct TestFile {
5828 pub path: Arc<RelPath>,
5829 pub root_name: String,
5830 pub local_root: Option<PathBuf>,
5831}
5832
5833#[cfg(any(test, feature = "test-support"))]
5834impl File for TestFile {
5835 fn path(&self) -> &Arc<RelPath> {
5836 &self.path
5837 }
5838
5839 fn full_path(&self, _: &gpui::App) -> PathBuf {
5840 PathBuf::from(self.root_name.clone()).join(self.path.as_std_path())
5841 }
5842
5843 fn as_local(&self) -> Option<&dyn LocalFile> {
5844 if self.local_root.is_some() {
5845 Some(self)
5846 } else {
5847 None
5848 }
5849 }
5850
5851 fn disk_state(&self) -> DiskState {
5852 unimplemented!()
5853 }
5854
5855 fn file_name<'a>(&'a self, _: &'a gpui::App) -> &'a str {
5856 self.path().file_name().unwrap_or(self.root_name.as_ref())
5857 }
5858
5859 fn worktree_id(&self, _: &App) -> WorktreeId {
5860 WorktreeId::from_usize(0)
5861 }
5862
5863 fn to_proto(&self, _: &App) -> rpc::proto::File {
5864 unimplemented!()
5865 }
5866
5867 fn is_private(&self) -> bool {
5868 false
5869 }
5870
5871 fn path_style(&self, _cx: &App) -> PathStyle {
5872 PathStyle::local()
5873 }
5874}
5875
5876#[cfg(any(test, feature = "test-support"))]
5877impl LocalFile for TestFile {
5878 fn abs_path(&self, _cx: &App) -> PathBuf {
5879 PathBuf::from(self.local_root.as_ref().unwrap())
5880 .join(&self.root_name)
5881 .join(self.path.as_std_path())
5882 }
5883
5884 fn load(&self, _cx: &App) -> Task<Result<String>> {
5885 unimplemented!()
5886 }
5887
5888 fn load_bytes(&self, _cx: &App) -> Task<Result<Vec<u8>>> {
5889 unimplemented!()
5890 }
5891}
5892
5893pub(crate) fn contiguous_ranges(
5894 values: impl Iterator<Item = u32>,
5895 max_len: usize,
5896) -> impl Iterator<Item = Range<u32>> {
5897 let mut values = values;
5898 let mut current_range: Option<Range<u32>> = None;
5899 std::iter::from_fn(move || {
5900 loop {
5901 if let Some(value) = values.next() {
5902 if let Some(range) = &mut current_range
5903 && value == range.end
5904 && range.len() < max_len
5905 {
5906 range.end += 1;
5907 continue;
5908 }
5909
5910 let prev_range = current_range.clone();
5911 current_range = Some(value..(value + 1));
5912 if prev_range.is_some() {
5913 return prev_range;
5914 }
5915 } else {
5916 return current_range.take();
5917 }
5918 }
5919 })
5920}
5921
5922#[derive(Default, Debug)]
5923pub struct CharClassifier {
5924 scope: Option<LanguageScope>,
5925 scope_context: Option<CharScopeContext>,
5926 ignore_punctuation: bool,
5927}
5928
5929impl CharClassifier {
5930 pub fn new(scope: Option<LanguageScope>) -> Self {
5931 Self {
5932 scope,
5933 scope_context: None,
5934 ignore_punctuation: false,
5935 }
5936 }
5937
5938 pub fn scope_context(self, scope_context: Option<CharScopeContext>) -> Self {
5939 Self {
5940 scope_context,
5941 ..self
5942 }
5943 }
5944
5945 pub fn ignore_punctuation(self, ignore_punctuation: bool) -> Self {
5946 Self {
5947 ignore_punctuation,
5948 ..self
5949 }
5950 }
5951
5952 pub fn is_whitespace(&self, c: char) -> bool {
5953 self.kind(c) == CharKind::Whitespace
5954 }
5955
5956 pub fn is_word(&self, c: char) -> bool {
5957 self.kind(c) == CharKind::Word
5958 }
5959
5960 pub fn is_punctuation(&self, c: char) -> bool {
5961 self.kind(c) == CharKind::Punctuation
5962 }
5963
5964 pub fn kind_with(&self, c: char, ignore_punctuation: bool) -> CharKind {
5965 if c.is_alphanumeric() || c == '_' {
5966 return CharKind::Word;
5967 }
5968
5969 if let Some(scope) = &self.scope {
5970 let characters = match self.scope_context {
5971 Some(CharScopeContext::Completion) => scope.completion_query_characters(),
5972 Some(CharScopeContext::LinkedEdit) => scope.linked_edit_characters(),
5973 None => scope.word_characters(),
5974 };
5975 if let Some(characters) = characters
5976 && characters.contains(&c)
5977 {
5978 return CharKind::Word;
5979 }
5980 }
5981
5982 if c.is_whitespace() {
5983 return CharKind::Whitespace;
5984 }
5985
5986 if ignore_punctuation {
5987 CharKind::Word
5988 } else {
5989 CharKind::Punctuation
5990 }
5991 }
5992
5993 pub fn kind(&self, c: char) -> CharKind {
5994 self.kind_with(c, self.ignore_punctuation)
5995 }
5996}
5997
5998/// Find all of the ranges of whitespace that occur at the ends of lines
5999/// in the given rope.
6000///
6001/// This could also be done with a regex search, but this implementation
6002/// avoids copying text.
6003pub fn trailing_whitespace_ranges(rope: &Rope) -> Vec<Range<usize>> {
6004 let mut ranges = Vec::new();
6005
6006 let mut offset = 0;
6007 let mut prev_chunk_trailing_whitespace_range = 0..0;
6008 for chunk in rope.chunks() {
6009 let mut prev_line_trailing_whitespace_range = 0..0;
6010 for (i, line) in chunk.split('\n').enumerate() {
6011 let line_end_offset = offset + line.len();
6012 let trimmed_line_len = line.trim_end_matches([' ', '\t']).len();
6013 let mut trailing_whitespace_range = (offset + trimmed_line_len)..line_end_offset;
6014
6015 if i == 0 && trimmed_line_len == 0 {
6016 trailing_whitespace_range.start = prev_chunk_trailing_whitespace_range.start;
6017 }
6018 if !prev_line_trailing_whitespace_range.is_empty() {
6019 ranges.push(prev_line_trailing_whitespace_range);
6020 }
6021
6022 offset = line_end_offset + 1;
6023 prev_line_trailing_whitespace_range = trailing_whitespace_range;
6024 }
6025
6026 offset -= 1;
6027 prev_chunk_trailing_whitespace_range = prev_line_trailing_whitespace_range;
6028 }
6029
6030 if !prev_chunk_trailing_whitespace_range.is_empty() {
6031 ranges.push(prev_chunk_trailing_whitespace_range);
6032 }
6033
6034 ranges
6035}