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