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