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