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