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