1pub use crate::{
2 diagnostic_set::DiagnosticSet,
3 highlight_map::{HighlightId, HighlightMap},
4 proto, BracketPair, Grammar, Language, LanguageConfig, LanguageRegistry, PLAIN_TEXT,
5};
6use crate::{
7 diagnostic_set::{DiagnosticEntry, DiagnosticGroup},
8 outline::OutlineItem,
9 syntax_map::{
10 SyntaxMap, SyntaxMapCapture, SyntaxMapCaptures, SyntaxSnapshot, ToTreeSitterPoint,
11 },
12 CodeLabel, LanguageScope, Outline,
13};
14use anyhow::{anyhow, Result};
15use clock::ReplicaId;
16use fs::LineEnding;
17use futures::FutureExt as _;
18use gpui::{fonts::HighlightStyle, AppContext, Entity, ModelContext, MutableAppContext, Task};
19use parking_lot::Mutex;
20use settings::Settings;
21use similar::{ChangeTag, TextDiff};
22use smol::future::yield_now;
23use std::{
24 any::Any,
25 cmp::{self, Ordering},
26 collections::BTreeMap,
27 ffi::OsStr,
28 future::Future,
29 iter::{self, Iterator, Peekable},
30 mem,
31 ops::{Deref, Range},
32 path::{Path, PathBuf},
33 str,
34 sync::Arc,
35 time::{Duration, Instant, SystemTime, UNIX_EPOCH},
36 vec,
37};
38use sum_tree::TreeMap;
39use text::operation_queue::OperationQueue;
40pub use text::{Buffer as TextBuffer, BufferSnapshot as TextBufferSnapshot, Operation as _, *};
41use theme::SyntaxTheme;
42#[cfg(any(test, feature = "test-support"))]
43use util::RandomCharIter;
44use util::TryFutureExt as _;
45
46#[cfg(any(test, feature = "test-support"))]
47pub use {tree_sitter_rust, tree_sitter_typescript};
48
49pub use lsp::DiagnosticSeverity;
50
51struct GitDiffStatus {
52 diff: git::diff::BufferDiff,
53 update_in_progress: bool,
54 update_requested: bool,
55}
56
57pub struct Buffer {
58 text: TextBuffer,
59 diff_base: Option<String>,
60 git_diff_status: GitDiffStatus,
61 file: Option<Arc<dyn File>>,
62 saved_version: clock::Global,
63 saved_version_fingerprint: RopeFingerprint,
64 saved_mtime: SystemTime,
65 transaction_depth: usize,
66 was_dirty_before_starting_transaction: Option<bool>,
67 language: Option<Arc<Language>>,
68 autoindent_requests: Vec<Arc<AutoindentRequest>>,
69 pending_autoindent: Option<Task<()>>,
70 sync_parse_timeout: Duration,
71 syntax_map: Mutex<SyntaxMap>,
72 parsing_in_background: bool,
73 parse_count: usize,
74 diagnostics: DiagnosticSet,
75 remote_selections: TreeMap<ReplicaId, SelectionSet>,
76 selections_update_count: usize,
77 diagnostics_update_count: usize,
78 diagnostics_timestamp: clock::Lamport,
79 file_update_count: usize,
80 git_diff_update_count: usize,
81 completion_triggers: Vec<String>,
82 completion_triggers_timestamp: clock::Lamport,
83 deferred_ops: OperationQueue<Operation>,
84}
85
86pub struct BufferSnapshot {
87 text: text::BufferSnapshot,
88 pub git_diff: git::diff::BufferDiff,
89 pub(crate) syntax: SyntaxSnapshot,
90 file: Option<Arc<dyn File>>,
91 diagnostics: DiagnosticSet,
92 diagnostics_update_count: usize,
93 file_update_count: usize,
94 git_diff_update_count: usize,
95 remote_selections: TreeMap<ReplicaId, SelectionSet>,
96 selections_update_count: usize,
97 language: Option<Arc<Language>>,
98 parse_count: usize,
99}
100
101#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
102pub struct IndentSize {
103 pub len: u32,
104 pub kind: IndentKind,
105}
106
107#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
108pub enum IndentKind {
109 #[default]
110 Space,
111 Tab,
112}
113
114#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
115pub enum CursorShape {
116 #[default]
117 Bar,
118 Block,
119 Underscore,
120 Hollow,
121}
122
123#[derive(Clone, Debug)]
124struct SelectionSet {
125 line_mode: bool,
126 cursor_shape: CursorShape,
127 selections: Arc<[Selection<Anchor>]>,
128 lamport_timestamp: clock::Lamport,
129}
130
131#[derive(Clone, Debug, PartialEq, Eq)]
132pub struct GroupId {
133 source: Arc<str>,
134 id: usize,
135}
136
137#[derive(Clone, Debug, PartialEq, Eq)]
138pub struct Diagnostic {
139 pub code: Option<String>,
140 pub severity: DiagnosticSeverity,
141 pub message: String,
142 pub group_id: usize,
143 pub is_valid: bool,
144 pub is_primary: bool,
145 pub is_disk_based: bool,
146 pub is_unnecessary: bool,
147}
148
149#[derive(Clone, Debug)]
150pub struct Completion {
151 pub old_range: Range<Anchor>,
152 pub new_text: String,
153 pub label: CodeLabel,
154 pub lsp_completion: lsp::CompletionItem,
155}
156
157#[derive(Clone, Debug)]
158pub struct CodeAction {
159 pub range: Range<Anchor>,
160 pub lsp_action: lsp::CodeAction,
161}
162
163#[derive(Clone, Debug, PartialEq, Eq)]
164pub enum Operation {
165 Buffer(text::Operation),
166 UpdateDiagnostics {
167 diagnostics: Arc<[DiagnosticEntry<Anchor>]>,
168 lamport_timestamp: clock::Lamport,
169 },
170 UpdateSelections {
171 selections: Arc<[Selection<Anchor>]>,
172 lamport_timestamp: clock::Lamport,
173 line_mode: bool,
174 cursor_shape: CursorShape,
175 },
176 UpdateCompletionTriggers {
177 triggers: Vec<String>,
178 lamport_timestamp: clock::Lamport,
179 },
180}
181
182#[derive(Clone, Debug, PartialEq, Eq)]
183pub enum Event {
184 Operation(Operation),
185 Edited,
186 DirtyChanged,
187 Saved,
188 FileHandleChanged,
189 Reloaded,
190 Reparsed,
191 DiagnosticsUpdated,
192 Closed,
193}
194
195pub trait File: Send + Sync {
196 fn as_local(&self) -> Option<&dyn LocalFile>;
197
198 fn is_local(&self) -> bool {
199 self.as_local().is_some()
200 }
201
202 fn mtime(&self) -> SystemTime;
203
204 /// Returns the path of this file relative to the worktree's root directory.
205 fn path(&self) -> &Arc<Path>;
206
207 /// Returns the path of this file relative to the worktree's parent directory (this means it
208 /// includes the name of the worktree's root folder).
209 fn full_path(&self, cx: &AppContext) -> PathBuf;
210
211 /// Returns the last component of this handle's absolute path. If this handle refers to the root
212 /// of its worktree, then this method will return the name of the worktree itself.
213 fn file_name<'a>(&'a self, cx: &'a AppContext) -> &'a OsStr;
214
215 fn is_deleted(&self) -> bool;
216
217 fn as_any(&self) -> &dyn Any;
218
219 fn to_proto(&self) -> rpc::proto::File;
220}
221
222pub trait LocalFile: File {
223 /// Returns the absolute path of this file.
224 fn abs_path(&self, cx: &AppContext) -> PathBuf;
225
226 fn load(&self, cx: &AppContext) -> Task<Result<String>>;
227
228 fn buffer_reloaded(
229 &self,
230 buffer_id: u64,
231 version: &clock::Global,
232 fingerprint: RopeFingerprint,
233 line_ending: LineEnding,
234 mtime: SystemTime,
235 cx: &mut MutableAppContext,
236 );
237}
238
239#[derive(Clone, Debug)]
240pub enum AutoindentMode {
241 /// Indent each line of inserted text.
242 EachLine,
243 /// Apply the same indentation adjustment to all of the lines
244 /// in a given insertion.
245 Block {
246 /// The original indentation level of the first line of each
247 /// insertion, if it has been copied.
248 original_indent_columns: Vec<u32>,
249 },
250}
251
252#[derive(Clone)]
253struct AutoindentRequest {
254 before_edit: BufferSnapshot,
255 entries: Vec<AutoindentRequestEntry>,
256 is_block_mode: bool,
257}
258
259#[derive(Clone)]
260struct AutoindentRequestEntry {
261 /// A range of the buffer whose indentation should be adjusted.
262 range: Range<Anchor>,
263 /// Whether or not these lines should be considered brand new, for the
264 /// purpose of auto-indent. When text is not new, its indentation will
265 /// only be adjusted if the suggested indentation level has *changed*
266 /// since the edit was made.
267 first_line_is_new: bool,
268 indent_size: IndentSize,
269 original_indent_column: Option<u32>,
270}
271
272#[derive(Debug)]
273struct IndentSuggestion {
274 basis_row: u32,
275 delta: Ordering,
276 within_error: bool,
277}
278
279struct BufferChunkHighlights<'a> {
280 captures: SyntaxMapCaptures<'a>,
281 next_capture: Option<SyntaxMapCapture<'a>>,
282 stack: Vec<(usize, HighlightId)>,
283 highlight_maps: Vec<HighlightMap>,
284}
285
286pub struct BufferChunks<'a> {
287 range: Range<usize>,
288 chunks: text::Chunks<'a>,
289 diagnostic_endpoints: Peekable<vec::IntoIter<DiagnosticEndpoint>>,
290 error_depth: usize,
291 warning_depth: usize,
292 information_depth: usize,
293 hint_depth: usize,
294 unnecessary_depth: usize,
295 highlights: Option<BufferChunkHighlights<'a>>,
296}
297
298#[derive(Clone, Copy, Debug, Default)]
299pub struct Chunk<'a> {
300 pub text: &'a str,
301 pub syntax_highlight_id: Option<HighlightId>,
302 pub highlight_style: Option<HighlightStyle>,
303 pub diagnostic_severity: Option<DiagnosticSeverity>,
304 pub is_unnecessary: bool,
305}
306
307pub struct Diff {
308 base_version: clock::Global,
309 line_ending: LineEnding,
310 edits: Vec<(Range<usize>, Arc<str>)>,
311}
312
313#[derive(Clone, Copy)]
314pub(crate) struct DiagnosticEndpoint {
315 offset: usize,
316 is_start: bool,
317 severity: DiagnosticSeverity,
318 is_unnecessary: bool,
319}
320
321#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug)]
322pub enum CharKind {
323 Punctuation,
324 Whitespace,
325 Word,
326}
327
328impl CharKind {
329 pub fn coerce_punctuation(self, treat_punctuation_as_word: bool) -> Self {
330 if treat_punctuation_as_word && self == CharKind::Punctuation {
331 CharKind::Word
332 } else {
333 self
334 }
335 }
336}
337
338impl Buffer {
339 pub fn new<T: Into<String>>(
340 replica_id: ReplicaId,
341 base_text: T,
342 cx: &mut ModelContext<Self>,
343 ) -> Self {
344 Self::build(
345 TextBuffer::new(replica_id, cx.model_id() as u64, base_text.into()),
346 None,
347 None,
348 )
349 }
350
351 pub fn from_file<T: Into<String>>(
352 replica_id: ReplicaId,
353 base_text: T,
354 diff_base: Option<T>,
355 file: Arc<dyn File>,
356 cx: &mut ModelContext<Self>,
357 ) -> Self {
358 Self::build(
359 TextBuffer::new(replica_id, cx.model_id() as u64, base_text.into()),
360 diff_base.map(|h| h.into().into_boxed_str().into()),
361 Some(file),
362 )
363 }
364
365 pub fn from_proto(
366 replica_id: ReplicaId,
367 message: proto::BufferState,
368 file: Option<Arc<dyn File>>,
369 ) -> Result<Self> {
370 let buffer = TextBuffer::new(replica_id, message.id, message.base_text);
371 let mut this = Self::build(
372 buffer,
373 message.diff_base.map(|text| text.into_boxed_str().into()),
374 file,
375 );
376 this.text.set_line_ending(proto::deserialize_line_ending(
377 rpc::proto::LineEnding::from_i32(message.line_ending)
378 .ok_or_else(|| anyhow!("missing line_ending"))?,
379 ));
380 this.saved_version = proto::deserialize_version(message.saved_version);
381 this.saved_version_fingerprint =
382 proto::deserialize_fingerprint(&message.saved_version_fingerprint)?;
383 this.saved_mtime = message
384 .saved_mtime
385 .ok_or_else(|| anyhow!("invalid saved_mtime"))?
386 .into();
387 Ok(this)
388 }
389
390 pub fn to_proto(&self) -> proto::BufferState {
391 proto::BufferState {
392 id: self.remote_id(),
393 file: self.file.as_ref().map(|f| f.to_proto()),
394 base_text: self.base_text().to_string(),
395 diff_base: self.diff_base.as_ref().map(|h| h.to_string()),
396 line_ending: proto::serialize_line_ending(self.line_ending()) as i32,
397 saved_version: proto::serialize_version(&self.saved_version),
398 saved_version_fingerprint: proto::serialize_fingerprint(self.saved_version_fingerprint),
399 saved_mtime: Some(self.saved_mtime.into()),
400 }
401 }
402
403 pub fn serialize_ops(
404 &self,
405 since: Option<clock::Global>,
406 cx: &AppContext,
407 ) -> Task<Vec<proto::Operation>> {
408 let mut operations = Vec::new();
409 operations.extend(self.deferred_ops.iter().map(proto::serialize_operation));
410 operations.extend(self.remote_selections.iter().map(|(_, set)| {
411 proto::serialize_operation(&Operation::UpdateSelections {
412 selections: set.selections.clone(),
413 lamport_timestamp: set.lamport_timestamp,
414 line_mode: set.line_mode,
415 cursor_shape: set.cursor_shape,
416 })
417 }));
418 operations.push(proto::serialize_operation(&Operation::UpdateDiagnostics {
419 diagnostics: self.diagnostics.iter().cloned().collect(),
420 lamport_timestamp: self.diagnostics_timestamp,
421 }));
422 operations.push(proto::serialize_operation(
423 &Operation::UpdateCompletionTriggers {
424 triggers: self.completion_triggers.clone(),
425 lamport_timestamp: self.completion_triggers_timestamp,
426 },
427 ));
428
429 let text_operations = self.text.operations().clone();
430 cx.background().spawn(async move {
431 let since = since.unwrap_or_default();
432 operations.extend(
433 text_operations
434 .iter()
435 .filter(|(_, op)| !since.observed(op.local_timestamp()))
436 .map(|(_, op)| proto::serialize_operation(&Operation::Buffer(op.clone()))),
437 );
438 operations.sort_unstable_by_key(proto::lamport_timestamp_for_operation);
439 operations
440 })
441 }
442
443 pub fn with_language(mut self, language: Arc<Language>, cx: &mut ModelContext<Self>) -> Self {
444 self.set_language(Some(language), cx);
445 self
446 }
447
448 fn build(buffer: TextBuffer, diff_base: Option<String>, file: Option<Arc<dyn File>>) -> Self {
449 let saved_mtime = if let Some(file) = file.as_ref() {
450 file.mtime()
451 } else {
452 UNIX_EPOCH
453 };
454
455 Self {
456 saved_mtime,
457 saved_version: buffer.version(),
458 saved_version_fingerprint: buffer.as_rope().fingerprint(),
459 transaction_depth: 0,
460 was_dirty_before_starting_transaction: None,
461 text: buffer,
462 diff_base,
463 git_diff_status: GitDiffStatus {
464 diff: git::diff::BufferDiff::new(),
465 update_in_progress: false,
466 update_requested: false,
467 },
468 file,
469 syntax_map: Mutex::new(SyntaxMap::new()),
470 parsing_in_background: false,
471 parse_count: 0,
472 sync_parse_timeout: Duration::from_millis(1),
473 autoindent_requests: Default::default(),
474 pending_autoindent: Default::default(),
475 language: None,
476 remote_selections: Default::default(),
477 selections_update_count: 0,
478 diagnostics: Default::default(),
479 diagnostics_update_count: 0,
480 diagnostics_timestamp: Default::default(),
481 file_update_count: 0,
482 git_diff_update_count: 0,
483 completion_triggers: Default::default(),
484 completion_triggers_timestamp: Default::default(),
485 deferred_ops: OperationQueue::new(),
486 }
487 }
488
489 pub fn snapshot(&self) -> BufferSnapshot {
490 let text = self.text.snapshot();
491 let mut syntax_map = self.syntax_map.lock();
492 syntax_map.interpolate(&text);
493 let syntax = syntax_map.snapshot();
494
495 BufferSnapshot {
496 text,
497 syntax,
498 git_diff: self.git_diff_status.diff.clone(),
499 file: self.file.clone(),
500 remote_selections: self.remote_selections.clone(),
501 diagnostics: self.diagnostics.clone(),
502 diagnostics_update_count: self.diagnostics_update_count,
503 file_update_count: self.file_update_count,
504 git_diff_update_count: self.git_diff_update_count,
505 language: self.language.clone(),
506 parse_count: self.parse_count,
507 selections_update_count: self.selections_update_count,
508 }
509 }
510
511 pub fn as_text_snapshot(&self) -> &text::BufferSnapshot {
512 &self.text
513 }
514
515 pub fn text_snapshot(&self) -> text::BufferSnapshot {
516 self.text.snapshot()
517 }
518
519 pub fn file(&self) -> Option<&Arc<dyn File>> {
520 self.file.as_ref()
521 }
522
523 pub fn saved_version(&self) -> &clock::Global {
524 &self.saved_version
525 }
526
527 pub fn saved_version_fingerprint(&self) -> RopeFingerprint {
528 self.saved_version_fingerprint
529 }
530
531 pub fn saved_mtime(&self) -> SystemTime {
532 self.saved_mtime
533 }
534
535 pub fn set_language(&mut self, language: Option<Arc<Language>>, cx: &mut ModelContext<Self>) {
536 self.syntax_map.lock().clear();
537 self.language = language;
538 self.reparse(cx);
539 }
540
541 pub fn set_language_registry(&mut self, language_registry: Arc<LanguageRegistry>) {
542 self.syntax_map
543 .lock()
544 .set_language_registry(language_registry);
545 }
546
547 pub fn did_save(
548 &mut self,
549 version: clock::Global,
550 fingerprint: RopeFingerprint,
551 mtime: SystemTime,
552 cx: &mut ModelContext<Self>,
553 ) {
554 self.saved_version = version;
555 self.saved_version_fingerprint = fingerprint;
556 self.saved_mtime = mtime;
557 cx.emit(Event::Saved);
558 cx.notify();
559 }
560
561 pub fn reload(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<Option<Transaction>>> {
562 cx.spawn(|this, mut cx| async move {
563 if let Some((new_mtime, new_text)) = this.read_with(&cx, |this, cx| {
564 let file = this.file.as_ref()?.as_local()?;
565 Some((file.mtime(), file.load(cx)))
566 }) {
567 let new_text = new_text.await?;
568 let diff = this
569 .read_with(&cx, |this, cx| this.diff(new_text, cx))
570 .await;
571 this.update(&mut cx, |this, cx| {
572 if let Some(transaction) = this.apply_diff(diff, cx).cloned() {
573 this.did_reload(
574 this.version(),
575 this.as_rope().fingerprint(),
576 this.line_ending(),
577 new_mtime,
578 cx,
579 );
580 Ok(Some(transaction))
581 } else {
582 Ok(None)
583 }
584 })
585 } else {
586 Ok(None)
587 }
588 })
589 }
590
591 pub fn did_reload(
592 &mut self,
593 version: clock::Global,
594 fingerprint: RopeFingerprint,
595 line_ending: LineEnding,
596 mtime: SystemTime,
597 cx: &mut ModelContext<Self>,
598 ) {
599 self.saved_version = version;
600 self.saved_version_fingerprint = fingerprint;
601 self.text.set_line_ending(line_ending);
602 self.saved_mtime = mtime;
603 if let Some(file) = self.file.as_ref().and_then(|f| f.as_local()) {
604 file.buffer_reloaded(
605 self.remote_id(),
606 &self.saved_version,
607 self.saved_version_fingerprint,
608 self.line_ending(),
609 self.saved_mtime,
610 cx,
611 );
612 }
613 self.git_diff_recalc(cx);
614 cx.emit(Event::Reloaded);
615 cx.notify();
616 }
617
618 pub fn file_updated(
619 &mut self,
620 new_file: Arc<dyn File>,
621 cx: &mut ModelContext<Self>,
622 ) -> Task<()> {
623 let mut file_changed = false;
624 let mut task = Task::ready(());
625
626 if let Some(old_file) = self.file.as_ref() {
627 if new_file.path() != old_file.path() {
628 file_changed = true;
629 }
630
631 if new_file.is_deleted() {
632 if !old_file.is_deleted() {
633 file_changed = true;
634 if !self.is_dirty() {
635 cx.emit(Event::DirtyChanged);
636 }
637 }
638 } else {
639 let new_mtime = new_file.mtime();
640 if new_mtime != old_file.mtime() {
641 file_changed = true;
642
643 if !self.is_dirty() {
644 let reload = self.reload(cx).log_err().map(drop);
645 task = cx.foreground().spawn(reload);
646 }
647 }
648 }
649 } else {
650 file_changed = true;
651 };
652
653 if file_changed {
654 self.file_update_count += 1;
655 cx.emit(Event::FileHandleChanged);
656 cx.notify();
657 }
658 self.file = Some(new_file);
659 task
660 }
661
662 pub fn diff_base(&self) -> Option<&str> {
663 self.diff_base.as_deref()
664 }
665
666 pub fn set_diff_base(&mut self, diff_base: Option<String>, cx: &mut ModelContext<Self>) {
667 self.diff_base = diff_base;
668 self.git_diff_recalc(cx);
669 }
670
671 pub fn needs_git_diff_recalc(&self) -> bool {
672 self.git_diff_status.diff.needs_update(self)
673 }
674
675 pub fn git_diff_recalc(&mut self, cx: &mut ModelContext<Self>) {
676 if self.git_diff_status.update_in_progress {
677 self.git_diff_status.update_requested = true;
678 return;
679 }
680
681 if let Some(diff_base) = &self.diff_base {
682 let snapshot = self.snapshot();
683 let diff_base = diff_base.clone();
684
685 let mut diff = self.git_diff_status.diff.clone();
686 let diff = cx.background().spawn(async move {
687 diff.update(&diff_base, &snapshot).await;
688 diff
689 });
690
691 cx.spawn_weak(|this, mut cx| async move {
692 let buffer_diff = diff.await;
693 if let Some(this) = this.upgrade(&cx) {
694 this.update(&mut cx, |this, cx| {
695 this.git_diff_status.diff = buffer_diff;
696 this.git_diff_update_count += 1;
697 cx.notify();
698
699 this.git_diff_status.update_in_progress = false;
700 if this.git_diff_status.update_requested {
701 this.git_diff_recalc(cx);
702 }
703 })
704 }
705 })
706 .detach()
707 } else {
708 let snapshot = self.snapshot();
709 self.git_diff_status.diff.clear(&snapshot);
710 self.git_diff_update_count += 1;
711 cx.notify();
712 }
713 }
714
715 pub fn close(&mut self, cx: &mut ModelContext<Self>) {
716 cx.emit(Event::Closed);
717 }
718
719 pub fn language(&self) -> Option<&Arc<Language>> {
720 self.language.as_ref()
721 }
722
723 pub fn language_at<D: ToOffset>(&self, position: D) -> Option<Arc<Language>> {
724 let offset = position.to_offset(self);
725 self.syntax_map
726 .lock()
727 .layers_for_range(offset..offset, &self.text)
728 .last()
729 .map(|info| info.language.clone())
730 .or_else(|| self.language.clone())
731 }
732
733 pub fn parse_count(&self) -> usize {
734 self.parse_count
735 }
736
737 pub fn selections_update_count(&self) -> usize {
738 self.selections_update_count
739 }
740
741 pub fn diagnostics_update_count(&self) -> usize {
742 self.diagnostics_update_count
743 }
744
745 pub fn file_update_count(&self) -> usize {
746 self.file_update_count
747 }
748
749 pub fn git_diff_update_count(&self) -> usize {
750 self.git_diff_update_count
751 }
752
753 #[cfg(any(test, feature = "test-support"))]
754 pub fn is_parsing(&self) -> bool {
755 self.parsing_in_background
756 }
757
758 pub fn contains_unknown_injections(&self) -> bool {
759 self.syntax_map.lock().contains_unknown_injections()
760 }
761
762 #[cfg(test)]
763 pub fn set_sync_parse_timeout(&mut self, timeout: Duration) {
764 self.sync_parse_timeout = timeout;
765 }
766
767 /// Called after an edit to synchronize the buffer's main parse tree with
768 /// the buffer's new underlying state.
769 ///
770 /// Locks the syntax map and interpolates the edits since the last reparse
771 /// into the foreground syntax tree.
772 ///
773 /// Then takes a stable snapshot of the syntax map before unlocking it.
774 /// The snapshot with the interpolated edits is sent to a background thread,
775 /// where we ask Tree-sitter to perform an incremental parse.
776 ///
777 /// Meanwhile, in the foreground, we block the main thread for up to 1ms
778 /// waiting on the parse to complete. As soon as it completes, we proceed
779 /// synchronously, unless a 1ms timeout elapses.
780 ///
781 /// If we time out waiting on the parse, we spawn a second task waiting
782 /// until the parse does complete and return with the interpolated tree still
783 /// in the foreground. When the background parse completes, call back into
784 /// the main thread and assign the foreground parse state.
785 ///
786 /// If the buffer or grammar changed since the start of the background parse,
787 /// initiate an additional reparse recursively. To avoid concurrent parses
788 /// for the same buffer, we only initiate a new parse if we are not already
789 /// parsing in the background.
790 pub fn reparse(&mut self, cx: &mut ModelContext<Self>) {
791 if self.parsing_in_background {
792 return;
793 }
794 let language = if let Some(language) = self.language.clone() {
795 language
796 } else {
797 return;
798 };
799
800 let text = self.text_snapshot();
801 let parsed_version = self.version();
802
803 let mut syntax_map = self.syntax_map.lock();
804 syntax_map.interpolate(&text);
805 let language_registry = syntax_map.language_registry();
806 let mut syntax_snapshot = syntax_map.snapshot();
807 drop(syntax_map);
808
809 let parse_task = cx.background().spawn({
810 let language = language.clone();
811 let language_registry = language_registry.clone();
812 async move {
813 syntax_snapshot.reparse(&text, language_registry, language);
814 syntax_snapshot
815 }
816 });
817
818 match cx
819 .background()
820 .block_with_timeout(self.sync_parse_timeout, parse_task)
821 {
822 Ok(new_syntax_snapshot) => {
823 self.did_finish_parsing(new_syntax_snapshot, cx);
824 return;
825 }
826 Err(parse_task) => {
827 self.parsing_in_background = true;
828 cx.spawn(move |this, mut cx| async move {
829 let new_syntax_map = parse_task.await;
830 this.update(&mut cx, move |this, cx| {
831 let grammar_changed =
832 this.language.as_ref().map_or(true, |current_language| {
833 !Arc::ptr_eq(&language, current_language)
834 });
835 let language_registry_changed = new_syntax_map
836 .contains_unknown_injections()
837 && language_registry.map_or(false, |registry| {
838 registry.version() != new_syntax_map.language_registry_version()
839 });
840 let parse_again = language_registry_changed
841 || grammar_changed
842 || this.version.changed_since(&parsed_version);
843 this.did_finish_parsing(new_syntax_map, cx);
844 this.parsing_in_background = false;
845 if parse_again {
846 this.reparse(cx);
847 }
848 });
849 })
850 .detach();
851 }
852 }
853 }
854
855 fn did_finish_parsing(&mut self, syntax_snapshot: SyntaxSnapshot, cx: &mut ModelContext<Self>) {
856 self.parse_count += 1;
857 self.syntax_map.lock().did_parse(syntax_snapshot);
858 self.request_autoindent(cx);
859 cx.emit(Event::Reparsed);
860 cx.notify();
861 }
862
863 pub fn update_diagnostics(&mut self, diagnostics: DiagnosticSet, cx: &mut ModelContext<Self>) {
864 let lamport_timestamp = self.text.lamport_clock.tick();
865 let op = Operation::UpdateDiagnostics {
866 diagnostics: diagnostics.iter().cloned().collect(),
867 lamport_timestamp,
868 };
869 self.apply_diagnostic_update(diagnostics, lamport_timestamp, cx);
870 self.send_operation(op, cx);
871 }
872
873 fn request_autoindent(&mut self, cx: &mut ModelContext<Self>) {
874 if let Some(indent_sizes) = self.compute_autoindents() {
875 let indent_sizes = cx.background().spawn(indent_sizes);
876 match cx
877 .background()
878 .block_with_timeout(Duration::from_micros(500), indent_sizes)
879 {
880 Ok(indent_sizes) => self.apply_autoindents(indent_sizes, cx),
881 Err(indent_sizes) => {
882 self.pending_autoindent = Some(cx.spawn(|this, mut cx| async move {
883 let indent_sizes = indent_sizes.await;
884 this.update(&mut cx, |this, cx| {
885 this.apply_autoindents(indent_sizes, cx);
886 });
887 }));
888 }
889 }
890 } else {
891 self.autoindent_requests.clear();
892 }
893 }
894
895 fn compute_autoindents(&self) -> Option<impl Future<Output = BTreeMap<u32, IndentSize>>> {
896 let max_rows_between_yields = 100;
897 let snapshot = self.snapshot();
898 if snapshot.syntax.is_empty() || self.autoindent_requests.is_empty() {
899 return None;
900 }
901
902 let autoindent_requests = self.autoindent_requests.clone();
903 Some(async move {
904 let mut indent_sizes = BTreeMap::new();
905 for request in autoindent_requests {
906 // Resolve each edited range to its row in the current buffer and in the
907 // buffer before this batch of edits.
908 let mut row_ranges = Vec::new();
909 let mut old_to_new_rows = BTreeMap::new();
910 let mut language_indent_sizes_by_new_row = Vec::new();
911 for entry in &request.entries {
912 let position = entry.range.start;
913 let new_row = position.to_point(&snapshot).row;
914 let new_end_row = entry.range.end.to_point(&snapshot).row + 1;
915 language_indent_sizes_by_new_row.push((new_row, entry.indent_size));
916
917 if !entry.first_line_is_new {
918 let old_row = position.to_point(&request.before_edit).row;
919 old_to_new_rows.insert(old_row, new_row);
920 }
921 row_ranges.push((new_row..new_end_row, entry.original_indent_column));
922 }
923
924 // Build a map containing the suggested indentation for each of the edited lines
925 // with respect to the state of the buffer before these edits. This map is keyed
926 // by the rows for these lines in the current state of the buffer.
927 let mut old_suggestions = BTreeMap::<u32, (IndentSize, bool)>::default();
928 let old_edited_ranges =
929 contiguous_ranges(old_to_new_rows.keys().copied(), max_rows_between_yields);
930 let mut language_indent_sizes = language_indent_sizes_by_new_row.iter().peekable();
931 let mut language_indent_size = IndentSize::default();
932 for old_edited_range in old_edited_ranges {
933 let suggestions = request
934 .before_edit
935 .suggest_autoindents(old_edited_range.clone())
936 .into_iter()
937 .flatten();
938 for (old_row, suggestion) in old_edited_range.zip(suggestions) {
939 if let Some(suggestion) = suggestion {
940 let new_row = *old_to_new_rows.get(&old_row).unwrap();
941
942 // Find the indent size based on the language for this row.
943 while let Some((row, size)) = language_indent_sizes.peek() {
944 if *row > new_row {
945 break;
946 }
947 language_indent_size = *size;
948 language_indent_sizes.next();
949 }
950
951 let suggested_indent = old_to_new_rows
952 .get(&suggestion.basis_row)
953 .and_then(|from_row| {
954 Some(old_suggestions.get(from_row).copied()?.0)
955 })
956 .unwrap_or_else(|| {
957 request
958 .before_edit
959 .indent_size_for_line(suggestion.basis_row)
960 })
961 .with_delta(suggestion.delta, language_indent_size);
962 old_suggestions
963 .insert(new_row, (suggested_indent, suggestion.within_error));
964 }
965 }
966 yield_now().await;
967 }
968
969 // In block mode, only compute indentation suggestions for the first line
970 // of each insertion. Otherwise, compute suggestions for every inserted line.
971 let new_edited_row_ranges = contiguous_ranges(
972 row_ranges.iter().flat_map(|(range, _)| {
973 if request.is_block_mode {
974 range.start..range.start + 1
975 } else {
976 range.clone()
977 }
978 }),
979 max_rows_between_yields,
980 );
981
982 // Compute new suggestions for each line, but only include them in the result
983 // if they differ from the old suggestion for that line.
984 let mut language_indent_sizes = language_indent_sizes_by_new_row.iter().peekable();
985 let mut language_indent_size = IndentSize::default();
986 for new_edited_row_range in new_edited_row_ranges {
987 let suggestions = snapshot
988 .suggest_autoindents(new_edited_row_range.clone())
989 .into_iter()
990 .flatten();
991 for (new_row, suggestion) in new_edited_row_range.zip(suggestions) {
992 if let Some(suggestion) = suggestion {
993 // Find the indent size based on the language for this row.
994 while let Some((row, size)) = language_indent_sizes.peek() {
995 if *row > new_row {
996 break;
997 }
998 language_indent_size = *size;
999 language_indent_sizes.next();
1000 }
1001
1002 let suggested_indent = indent_sizes
1003 .get(&suggestion.basis_row)
1004 .copied()
1005 .unwrap_or_else(|| {
1006 snapshot.indent_size_for_line(suggestion.basis_row)
1007 })
1008 .with_delta(suggestion.delta, language_indent_size);
1009 if old_suggestions.get(&new_row).map_or(
1010 true,
1011 |(old_indentation, was_within_error)| {
1012 suggested_indent != *old_indentation
1013 && (!suggestion.within_error || *was_within_error)
1014 },
1015 ) {
1016 indent_sizes.insert(new_row, suggested_indent);
1017 }
1018 }
1019 }
1020 yield_now().await;
1021 }
1022
1023 // For each block of inserted text, adjust the indentation of the remaining
1024 // lines of the block by the same amount as the first line was adjusted.
1025 if request.is_block_mode {
1026 for (row_range, original_indent_column) in
1027 row_ranges
1028 .into_iter()
1029 .filter_map(|(range, original_indent_column)| {
1030 if range.len() > 1 {
1031 Some((range, original_indent_column?))
1032 } else {
1033 None
1034 }
1035 })
1036 {
1037 let new_indent = indent_sizes
1038 .get(&row_range.start)
1039 .copied()
1040 .unwrap_or_else(|| snapshot.indent_size_for_line(row_range.start));
1041 let delta = new_indent.len as i64 - original_indent_column as i64;
1042 if delta != 0 {
1043 for row in row_range.skip(1) {
1044 indent_sizes.entry(row).or_insert_with(|| {
1045 let mut size = snapshot.indent_size_for_line(row);
1046 if size.kind == new_indent.kind {
1047 match delta.cmp(&0) {
1048 Ordering::Greater => size.len += delta as u32,
1049 Ordering::Less => {
1050 size.len = size.len.saturating_sub(-delta as u32)
1051 }
1052 Ordering::Equal => {}
1053 }
1054 }
1055 size
1056 });
1057 }
1058 }
1059 }
1060 }
1061 }
1062
1063 indent_sizes
1064 })
1065 }
1066
1067 fn apply_autoindents(
1068 &mut self,
1069 indent_sizes: BTreeMap<u32, IndentSize>,
1070 cx: &mut ModelContext<Self>,
1071 ) {
1072 self.autoindent_requests.clear();
1073
1074 let edits: Vec<_> = indent_sizes
1075 .into_iter()
1076 .filter_map(|(row, indent_size)| {
1077 let current_size = indent_size_for_line(self, row);
1078 Self::edit_for_indent_size_adjustment(row, current_size, indent_size)
1079 })
1080 .collect();
1081
1082 self.edit(edits, None, cx);
1083 }
1084
1085 // Create a minimal edit that will cause the the given row to be indented
1086 // with the given size. After applying this edit, the length of the line
1087 // will always be at least `new_size.len`.
1088 pub fn edit_for_indent_size_adjustment(
1089 row: u32,
1090 current_size: IndentSize,
1091 new_size: IndentSize,
1092 ) -> Option<(Range<Point>, String)> {
1093 if new_size.kind != current_size.kind {
1094 Some((
1095 Point::new(row, 0)..Point::new(row, current_size.len),
1096 iter::repeat(new_size.char())
1097 .take(new_size.len as usize)
1098 .collect::<String>(),
1099 ))
1100 } else {
1101 match new_size.len.cmp(¤t_size.len) {
1102 Ordering::Greater => {
1103 let point = Point::new(row, 0);
1104 Some((
1105 point..point,
1106 iter::repeat(new_size.char())
1107 .take((new_size.len - current_size.len) as usize)
1108 .collect::<String>(),
1109 ))
1110 }
1111
1112 Ordering::Less => Some((
1113 Point::new(row, 0)..Point::new(row, current_size.len - new_size.len),
1114 String::new(),
1115 )),
1116
1117 Ordering::Equal => None,
1118 }
1119 }
1120 }
1121
1122 pub fn diff(&self, mut new_text: String, cx: &AppContext) -> Task<Diff> {
1123 let old_text = self.as_rope().clone();
1124 let base_version = self.version();
1125 cx.background().spawn(async move {
1126 let old_text = old_text.to_string();
1127 let line_ending = LineEnding::detect(&new_text);
1128 LineEnding::normalize(&mut new_text);
1129 let diff = TextDiff::from_chars(old_text.as_str(), new_text.as_str());
1130 let mut edits = Vec::new();
1131 let mut offset = 0;
1132 let empty: Arc<str> = "".into();
1133 for change in diff.iter_all_changes() {
1134 let value = change.value();
1135 let end_offset = offset + value.len();
1136 match change.tag() {
1137 ChangeTag::Equal => {
1138 offset = end_offset;
1139 }
1140 ChangeTag::Delete => {
1141 edits.push((offset..end_offset, empty.clone()));
1142 offset = end_offset;
1143 }
1144 ChangeTag::Insert => {
1145 edits.push((offset..offset, value.into()));
1146 }
1147 }
1148 }
1149 Diff {
1150 base_version,
1151 line_ending,
1152 edits,
1153 }
1154 })
1155 }
1156
1157 pub fn apply_diff(&mut self, diff: Diff, cx: &mut ModelContext<Self>) -> Option<&Transaction> {
1158 if self.version == diff.base_version {
1159 self.finalize_last_transaction();
1160 self.start_transaction();
1161 self.text.set_line_ending(diff.line_ending);
1162 self.edit(diff.edits, None, cx);
1163 if self.end_transaction(cx).is_some() {
1164 self.finalize_last_transaction()
1165 } else {
1166 None
1167 }
1168 } else {
1169 None
1170 }
1171 }
1172
1173 pub fn is_dirty(&self) -> bool {
1174 self.saved_version_fingerprint != self.as_rope().fingerprint()
1175 || self.file.as_ref().map_or(false, |file| file.is_deleted())
1176 }
1177
1178 pub fn has_conflict(&self) -> bool {
1179 self.saved_version_fingerprint != self.as_rope().fingerprint()
1180 && self
1181 .file
1182 .as_ref()
1183 .map_or(false, |file| file.mtime() > self.saved_mtime)
1184 }
1185
1186 pub fn subscribe(&mut self) -> Subscription {
1187 self.text.subscribe()
1188 }
1189
1190 pub fn start_transaction(&mut self) -> Option<TransactionId> {
1191 self.start_transaction_at(Instant::now())
1192 }
1193
1194 pub fn start_transaction_at(&mut self, now: Instant) -> Option<TransactionId> {
1195 self.transaction_depth += 1;
1196 if self.was_dirty_before_starting_transaction.is_none() {
1197 self.was_dirty_before_starting_transaction = Some(self.is_dirty());
1198 }
1199 self.text.start_transaction_at(now)
1200 }
1201
1202 pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1203 self.end_transaction_at(Instant::now(), cx)
1204 }
1205
1206 pub fn end_transaction_at(
1207 &mut self,
1208 now: Instant,
1209 cx: &mut ModelContext<Self>,
1210 ) -> Option<TransactionId> {
1211 assert!(self.transaction_depth > 0);
1212 self.transaction_depth -= 1;
1213 let was_dirty = if self.transaction_depth == 0 {
1214 self.was_dirty_before_starting_transaction.take().unwrap()
1215 } else {
1216 false
1217 };
1218 if let Some((transaction_id, start_version)) = self.text.end_transaction_at(now) {
1219 self.did_edit(&start_version, was_dirty, cx);
1220 Some(transaction_id)
1221 } else {
1222 None
1223 }
1224 }
1225
1226 pub fn push_transaction(&mut self, transaction: Transaction, now: Instant) {
1227 self.text.push_transaction(transaction, now);
1228 }
1229
1230 pub fn finalize_last_transaction(&mut self) -> Option<&Transaction> {
1231 self.text.finalize_last_transaction()
1232 }
1233
1234 pub fn group_until_transaction(&mut self, transaction_id: TransactionId) {
1235 self.text.group_until_transaction(transaction_id);
1236 }
1237
1238 pub fn forget_transaction(&mut self, transaction_id: TransactionId) {
1239 self.text.forget_transaction(transaction_id);
1240 }
1241
1242 pub fn wait_for_edits(
1243 &mut self,
1244 edit_ids: impl IntoIterator<Item = clock::Local>,
1245 ) -> impl Future<Output = ()> {
1246 self.text.wait_for_edits(edit_ids)
1247 }
1248
1249 pub fn wait_for_anchors<'a>(
1250 &mut self,
1251 anchors: impl IntoIterator<Item = &'a Anchor>,
1252 ) -> impl Future<Output = ()> {
1253 self.text.wait_for_anchors(anchors)
1254 }
1255
1256 pub fn wait_for_version(&mut self, version: clock::Global) -> impl Future<Output = ()> {
1257 self.text.wait_for_version(version)
1258 }
1259
1260 pub fn set_active_selections(
1261 &mut self,
1262 selections: Arc<[Selection<Anchor>]>,
1263 line_mode: bool,
1264 cursor_shape: CursorShape,
1265 cx: &mut ModelContext<Self>,
1266 ) {
1267 let lamport_timestamp = self.text.lamport_clock.tick();
1268 self.remote_selections.insert(
1269 self.text.replica_id(),
1270 SelectionSet {
1271 selections: selections.clone(),
1272 lamport_timestamp,
1273 line_mode,
1274 cursor_shape,
1275 },
1276 );
1277 self.send_operation(
1278 Operation::UpdateSelections {
1279 selections,
1280 line_mode,
1281 lamport_timestamp,
1282 cursor_shape,
1283 },
1284 cx,
1285 );
1286 }
1287
1288 pub fn remove_active_selections(&mut self, cx: &mut ModelContext<Self>) {
1289 self.set_active_selections(Arc::from([]), false, Default::default(), cx);
1290 }
1291
1292 pub fn set_text<T>(&mut self, text: T, cx: &mut ModelContext<Self>) -> Option<clock::Local>
1293 where
1294 T: Into<Arc<str>>,
1295 {
1296 self.edit([(0..self.len(), text)], None, cx)
1297 }
1298
1299 pub fn edit<I, S, T>(
1300 &mut self,
1301 edits_iter: I,
1302 autoindent_mode: Option<AutoindentMode>,
1303 cx: &mut ModelContext<Self>,
1304 ) -> Option<clock::Local>
1305 where
1306 I: IntoIterator<Item = (Range<S>, T)>,
1307 S: ToOffset,
1308 T: Into<Arc<str>>,
1309 {
1310 // Skip invalid edits and coalesce contiguous ones.
1311 let mut edits: Vec<(Range<usize>, Arc<str>)> = Vec::new();
1312 for (range, new_text) in edits_iter {
1313 let mut range = range.start.to_offset(self)..range.end.to_offset(self);
1314 if range.start > range.end {
1315 mem::swap(&mut range.start, &mut range.end);
1316 }
1317 let new_text = new_text.into();
1318 if !new_text.is_empty() || !range.is_empty() {
1319 if let Some((prev_range, prev_text)) = edits.last_mut() {
1320 if prev_range.end >= range.start {
1321 prev_range.end = cmp::max(prev_range.end, range.end);
1322 *prev_text = format!("{prev_text}{new_text}").into();
1323 } else {
1324 edits.push((range, new_text));
1325 }
1326 } else {
1327 edits.push((range, new_text));
1328 }
1329 }
1330 }
1331 if edits.is_empty() {
1332 return None;
1333 }
1334
1335 self.start_transaction();
1336 self.pending_autoindent.take();
1337 let autoindent_request = autoindent_mode
1338 .and_then(|mode| self.language.as_ref().map(|_| (self.snapshot(), mode)));
1339
1340 let edit_operation = self.text.edit(edits.iter().cloned());
1341 let edit_id = edit_operation.local_timestamp();
1342
1343 if let Some((before_edit, mode)) = autoindent_request {
1344 let mut delta = 0isize;
1345 let entries = edits
1346 .into_iter()
1347 .enumerate()
1348 .zip(&edit_operation.as_edit().unwrap().new_text)
1349 .map(|((ix, (range, _)), new_text)| {
1350 let new_text_len = new_text.len();
1351 let old_start = range.start.to_point(&before_edit);
1352 let new_start = (delta + range.start as isize) as usize;
1353 delta += new_text_len as isize - (range.end as isize - range.start as isize);
1354
1355 let mut range_of_insertion_to_indent = 0..new_text_len;
1356 let mut first_line_is_new = false;
1357 let mut original_indent_column = None;
1358
1359 // When inserting an entire line at the beginning of an existing line,
1360 // treat the insertion as new.
1361 if new_text.contains('\n')
1362 && old_start.column <= before_edit.indent_size_for_line(old_start.row).len
1363 {
1364 first_line_is_new = true;
1365 }
1366
1367 // When inserting text starting with a newline, avoid auto-indenting the
1368 // previous line.
1369 if new_text.starts_with('\n') {
1370 range_of_insertion_to_indent.start += 1;
1371 first_line_is_new = true;
1372 }
1373
1374 // Avoid auto-indenting after the insertion.
1375 if let AutoindentMode::Block {
1376 original_indent_columns,
1377 } = &mode
1378 {
1379 original_indent_column =
1380 Some(original_indent_columns.get(ix).copied().unwrap_or_else(|| {
1381 indent_size_for_text(
1382 new_text[range_of_insertion_to_indent.clone()].chars(),
1383 )
1384 .len
1385 }));
1386 if new_text[range_of_insertion_to_indent.clone()].ends_with('\n') {
1387 range_of_insertion_to_indent.end -= 1;
1388 }
1389 }
1390
1391 AutoindentRequestEntry {
1392 first_line_is_new,
1393 original_indent_column,
1394 indent_size: before_edit.language_indent_size_at(range.start, cx),
1395 range: self.anchor_before(new_start + range_of_insertion_to_indent.start)
1396 ..self.anchor_after(new_start + range_of_insertion_to_indent.end),
1397 }
1398 })
1399 .collect();
1400
1401 self.autoindent_requests.push(Arc::new(AutoindentRequest {
1402 before_edit,
1403 entries,
1404 is_block_mode: matches!(mode, AutoindentMode::Block { .. }),
1405 }));
1406 }
1407
1408 self.end_transaction(cx);
1409 self.send_operation(Operation::Buffer(edit_operation), cx);
1410 Some(edit_id)
1411 }
1412
1413 fn did_edit(
1414 &mut self,
1415 old_version: &clock::Global,
1416 was_dirty: bool,
1417 cx: &mut ModelContext<Self>,
1418 ) {
1419 if self.edits_since::<usize>(old_version).next().is_none() {
1420 return;
1421 }
1422
1423 self.reparse(cx);
1424
1425 cx.emit(Event::Edited);
1426 if was_dirty != self.is_dirty() {
1427 cx.emit(Event::DirtyChanged);
1428 }
1429 cx.notify();
1430 }
1431
1432 pub fn apply_ops<I: IntoIterator<Item = Operation>>(
1433 &mut self,
1434 ops: I,
1435 cx: &mut ModelContext<Self>,
1436 ) -> Result<()> {
1437 self.pending_autoindent.take();
1438 let was_dirty = self.is_dirty();
1439 let old_version = self.version.clone();
1440 let mut deferred_ops = Vec::new();
1441 let buffer_ops = ops
1442 .into_iter()
1443 .filter_map(|op| match op {
1444 Operation::Buffer(op) => Some(op),
1445 _ => {
1446 if self.can_apply_op(&op) {
1447 self.apply_op(op, cx);
1448 } else {
1449 deferred_ops.push(op);
1450 }
1451 None
1452 }
1453 })
1454 .collect::<Vec<_>>();
1455 self.text.apply_ops(buffer_ops)?;
1456 self.deferred_ops.insert(deferred_ops);
1457 self.flush_deferred_ops(cx);
1458 self.did_edit(&old_version, was_dirty, cx);
1459 // Notify independently of whether the buffer was edited as the operations could include a
1460 // selection update.
1461 cx.notify();
1462 Ok(())
1463 }
1464
1465 fn flush_deferred_ops(&mut self, cx: &mut ModelContext<Self>) {
1466 let mut deferred_ops = Vec::new();
1467 for op in self.deferred_ops.drain().iter().cloned() {
1468 if self.can_apply_op(&op) {
1469 self.apply_op(op, cx);
1470 } else {
1471 deferred_ops.push(op);
1472 }
1473 }
1474 self.deferred_ops.insert(deferred_ops);
1475 }
1476
1477 fn can_apply_op(&self, operation: &Operation) -> bool {
1478 match operation {
1479 Operation::Buffer(_) => {
1480 unreachable!("buffer operations should never be applied at this layer")
1481 }
1482 Operation::UpdateDiagnostics {
1483 diagnostics: diagnostic_set,
1484 ..
1485 } => diagnostic_set.iter().all(|diagnostic| {
1486 self.text.can_resolve(&diagnostic.range.start)
1487 && self.text.can_resolve(&diagnostic.range.end)
1488 }),
1489 Operation::UpdateSelections { selections, .. } => selections
1490 .iter()
1491 .all(|s| self.can_resolve(&s.start) && self.can_resolve(&s.end)),
1492 Operation::UpdateCompletionTriggers { .. } => true,
1493 }
1494 }
1495
1496 fn apply_op(&mut self, operation: Operation, cx: &mut ModelContext<Self>) {
1497 match operation {
1498 Operation::Buffer(_) => {
1499 unreachable!("buffer operations should never be applied at this layer")
1500 }
1501 Operation::UpdateDiagnostics {
1502 diagnostics: diagnostic_set,
1503 lamport_timestamp,
1504 } => {
1505 let snapshot = self.snapshot();
1506 self.apply_diagnostic_update(
1507 DiagnosticSet::from_sorted_entries(diagnostic_set.iter().cloned(), &snapshot),
1508 lamport_timestamp,
1509 cx,
1510 );
1511 }
1512 Operation::UpdateSelections {
1513 selections,
1514 lamport_timestamp,
1515 line_mode,
1516 cursor_shape,
1517 } => {
1518 if let Some(set) = self.remote_selections.get(&lamport_timestamp.replica_id) {
1519 if set.lamport_timestamp > lamport_timestamp {
1520 return;
1521 }
1522 }
1523
1524 self.remote_selections.insert(
1525 lamport_timestamp.replica_id,
1526 SelectionSet {
1527 selections,
1528 lamport_timestamp,
1529 line_mode,
1530 cursor_shape,
1531 },
1532 );
1533 self.text.lamport_clock.observe(lamport_timestamp);
1534 self.selections_update_count += 1;
1535 }
1536 Operation::UpdateCompletionTriggers {
1537 triggers,
1538 lamport_timestamp,
1539 } => {
1540 self.completion_triggers = triggers;
1541 self.text.lamport_clock.observe(lamport_timestamp);
1542 }
1543 }
1544 }
1545
1546 fn apply_diagnostic_update(
1547 &mut self,
1548 diagnostics: DiagnosticSet,
1549 lamport_timestamp: clock::Lamport,
1550 cx: &mut ModelContext<Self>,
1551 ) {
1552 if lamport_timestamp > self.diagnostics_timestamp {
1553 self.diagnostics = diagnostics;
1554 self.diagnostics_timestamp = lamport_timestamp;
1555 self.diagnostics_update_count += 1;
1556 self.text.lamport_clock.observe(lamport_timestamp);
1557 cx.notify();
1558 cx.emit(Event::DiagnosticsUpdated);
1559 }
1560 }
1561
1562 fn send_operation(&mut self, operation: Operation, cx: &mut ModelContext<Self>) {
1563 cx.emit(Event::Operation(operation));
1564 }
1565
1566 pub fn remove_peer(&mut self, replica_id: ReplicaId, cx: &mut ModelContext<Self>) {
1567 self.remote_selections.remove(&replica_id);
1568 cx.notify();
1569 }
1570
1571 pub fn undo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1572 let was_dirty = self.is_dirty();
1573 let old_version = self.version.clone();
1574
1575 if let Some((transaction_id, operation)) = self.text.undo() {
1576 self.send_operation(Operation::Buffer(operation), cx);
1577 self.did_edit(&old_version, was_dirty, cx);
1578 Some(transaction_id)
1579 } else {
1580 None
1581 }
1582 }
1583
1584 pub fn undo_to_transaction(
1585 &mut self,
1586 transaction_id: TransactionId,
1587 cx: &mut ModelContext<Self>,
1588 ) -> bool {
1589 let was_dirty = self.is_dirty();
1590 let old_version = self.version.clone();
1591
1592 let operations = self.text.undo_to_transaction(transaction_id);
1593 let undone = !operations.is_empty();
1594 for operation in operations {
1595 self.send_operation(Operation::Buffer(operation), cx);
1596 }
1597 if undone {
1598 self.did_edit(&old_version, was_dirty, cx)
1599 }
1600 undone
1601 }
1602
1603 pub fn redo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1604 let was_dirty = self.is_dirty();
1605 let old_version = self.version.clone();
1606
1607 if let Some((transaction_id, operation)) = self.text.redo() {
1608 self.send_operation(Operation::Buffer(operation), cx);
1609 self.did_edit(&old_version, was_dirty, cx);
1610 Some(transaction_id)
1611 } else {
1612 None
1613 }
1614 }
1615
1616 pub fn redo_to_transaction(
1617 &mut self,
1618 transaction_id: TransactionId,
1619 cx: &mut ModelContext<Self>,
1620 ) -> bool {
1621 let was_dirty = self.is_dirty();
1622 let old_version = self.version.clone();
1623
1624 let operations = self.text.redo_to_transaction(transaction_id);
1625 let redone = !operations.is_empty();
1626 for operation in operations {
1627 self.send_operation(Operation::Buffer(operation), cx);
1628 }
1629 if redone {
1630 self.did_edit(&old_version, was_dirty, cx)
1631 }
1632 redone
1633 }
1634
1635 pub fn set_completion_triggers(&mut self, triggers: Vec<String>, cx: &mut ModelContext<Self>) {
1636 self.completion_triggers = triggers.clone();
1637 self.completion_triggers_timestamp = self.text.lamport_clock.tick();
1638 self.send_operation(
1639 Operation::UpdateCompletionTriggers {
1640 triggers,
1641 lamport_timestamp: self.completion_triggers_timestamp,
1642 },
1643 cx,
1644 );
1645 cx.notify();
1646 }
1647
1648 pub fn completion_triggers(&self) -> &[String] {
1649 &self.completion_triggers
1650 }
1651}
1652
1653#[cfg(any(test, feature = "test-support"))]
1654impl Buffer {
1655 pub fn edit_via_marked_text(
1656 &mut self,
1657 marked_string: &str,
1658 autoindent_mode: Option<AutoindentMode>,
1659 cx: &mut ModelContext<Self>,
1660 ) {
1661 let edits = self.edits_for_marked_text(marked_string);
1662 self.edit(edits, autoindent_mode, cx);
1663 }
1664
1665 pub fn set_group_interval(&mut self, group_interval: Duration) {
1666 self.text.set_group_interval(group_interval);
1667 }
1668
1669 pub fn randomly_edit<T>(
1670 &mut self,
1671 rng: &mut T,
1672 old_range_count: usize,
1673 cx: &mut ModelContext<Self>,
1674 ) where
1675 T: rand::Rng,
1676 {
1677 let mut edits: Vec<(Range<usize>, String)> = Vec::new();
1678 let mut last_end = None;
1679 for _ in 0..old_range_count {
1680 if last_end.map_or(false, |last_end| last_end >= self.len()) {
1681 break;
1682 }
1683
1684 let new_start = last_end.map_or(0, |last_end| last_end + 1);
1685 let mut range = self.random_byte_range(new_start, rng);
1686 if rng.gen_bool(0.2) {
1687 mem::swap(&mut range.start, &mut range.end);
1688 }
1689 last_end = Some(range.end);
1690
1691 let new_text_len = rng.gen_range(0..10);
1692 let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
1693
1694 edits.push((range, new_text));
1695 }
1696 log::info!("mutating buffer {} with {:?}", self.replica_id(), edits);
1697 self.edit(edits, None, cx);
1698 }
1699
1700 pub fn randomly_undo_redo(&mut self, rng: &mut impl rand::Rng, cx: &mut ModelContext<Self>) {
1701 let was_dirty = self.is_dirty();
1702 let old_version = self.version.clone();
1703
1704 let ops = self.text.randomly_undo_redo(rng);
1705 if !ops.is_empty() {
1706 for op in ops {
1707 self.send_operation(Operation::Buffer(op), cx);
1708 self.did_edit(&old_version, was_dirty, cx);
1709 }
1710 }
1711 }
1712}
1713
1714impl Entity for Buffer {
1715 type Event = Event;
1716}
1717
1718impl Deref for Buffer {
1719 type Target = TextBuffer;
1720
1721 fn deref(&self) -> &Self::Target {
1722 &self.text
1723 }
1724}
1725
1726impl BufferSnapshot {
1727 pub fn indent_size_for_line(&self, row: u32) -> IndentSize {
1728 indent_size_for_line(self, row)
1729 }
1730
1731 pub fn language_indent_size_at<T: ToOffset>(&self, position: T, cx: &AppContext) -> IndentSize {
1732 let language_name = self.language_at(position).map(|language| language.name());
1733 let settings = cx.global::<Settings>();
1734 if settings.hard_tabs(language_name.as_deref()) {
1735 IndentSize::tab()
1736 } else {
1737 IndentSize::spaces(settings.tab_size(language_name.as_deref()).get())
1738 }
1739 }
1740
1741 pub fn suggested_indents(
1742 &self,
1743 rows: impl Iterator<Item = u32>,
1744 single_indent_size: IndentSize,
1745 ) -> BTreeMap<u32, IndentSize> {
1746 let mut result = BTreeMap::new();
1747
1748 for row_range in contiguous_ranges(rows, 10) {
1749 let suggestions = match self.suggest_autoindents(row_range.clone()) {
1750 Some(suggestions) => suggestions,
1751 _ => break,
1752 };
1753
1754 for (row, suggestion) in row_range.zip(suggestions) {
1755 let indent_size = if let Some(suggestion) = suggestion {
1756 result
1757 .get(&suggestion.basis_row)
1758 .copied()
1759 .unwrap_or_else(|| self.indent_size_for_line(suggestion.basis_row))
1760 .with_delta(suggestion.delta, single_indent_size)
1761 } else {
1762 self.indent_size_for_line(row)
1763 };
1764
1765 result.insert(row, indent_size);
1766 }
1767 }
1768
1769 result
1770 }
1771
1772 fn suggest_autoindents(
1773 &self,
1774 row_range: Range<u32>,
1775 ) -> Option<impl Iterator<Item = Option<IndentSuggestion>> + '_> {
1776 let config = &self.language.as_ref()?.config;
1777 let prev_non_blank_row = self.prev_non_blank_row(row_range.start);
1778
1779 // Find the suggested indentation ranges based on the syntax tree.
1780 let start = Point::new(prev_non_blank_row.unwrap_or(row_range.start), 0);
1781 let end = Point::new(row_range.end, 0);
1782 let range = (start..end).to_offset(&self.text);
1783 let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
1784 Some(&grammar.indents_config.as_ref()?.query)
1785 });
1786 let indent_configs = matches
1787 .grammars()
1788 .iter()
1789 .map(|grammar| grammar.indents_config.as_ref().unwrap())
1790 .collect::<Vec<_>>();
1791
1792 let mut indent_ranges = Vec::<Range<Point>>::new();
1793 let mut outdent_positions = Vec::<Point>::new();
1794 while let Some(mat) = matches.peek() {
1795 let mut start: Option<Point> = None;
1796 let mut end: Option<Point> = None;
1797
1798 let config = &indent_configs[mat.grammar_index];
1799 for capture in mat.captures {
1800 if capture.index == config.indent_capture_ix {
1801 start.get_or_insert(Point::from_ts_point(capture.node.start_position()));
1802 end.get_or_insert(Point::from_ts_point(capture.node.end_position()));
1803 } else if Some(capture.index) == config.start_capture_ix {
1804 start = Some(Point::from_ts_point(capture.node.end_position()));
1805 } else if Some(capture.index) == config.end_capture_ix {
1806 end = Some(Point::from_ts_point(capture.node.start_position()));
1807 } else if Some(capture.index) == config.outdent_capture_ix {
1808 outdent_positions.push(Point::from_ts_point(capture.node.start_position()));
1809 }
1810 }
1811
1812 matches.advance();
1813 if let Some((start, end)) = start.zip(end) {
1814 if start.row == end.row {
1815 continue;
1816 }
1817
1818 let range = start..end;
1819 match indent_ranges.binary_search_by_key(&range.start, |r| r.start) {
1820 Err(ix) => indent_ranges.insert(ix, range),
1821 Ok(ix) => {
1822 let prev_range = &mut indent_ranges[ix];
1823 prev_range.end = prev_range.end.max(range.end);
1824 }
1825 }
1826 }
1827 }
1828
1829 let mut error_ranges = Vec::<Range<Point>>::new();
1830 let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
1831 Some(&grammar.error_query)
1832 });
1833 while let Some(mat) = matches.peek() {
1834 let node = mat.captures[0].node;
1835 let start = Point::from_ts_point(node.start_position());
1836 let end = Point::from_ts_point(node.end_position());
1837 let range = start..end;
1838 let ix = match error_ranges.binary_search_by_key(&range.start, |r| r.start) {
1839 Ok(ix) | Err(ix) => ix,
1840 };
1841 let mut end_ix = ix;
1842 while let Some(existing_range) = error_ranges.get(end_ix) {
1843 if existing_range.end < end {
1844 end_ix += 1;
1845 } else {
1846 break;
1847 }
1848 }
1849 error_ranges.splice(ix..end_ix, [range]);
1850 matches.advance();
1851 }
1852
1853 outdent_positions.sort();
1854 for outdent_position in outdent_positions {
1855 // find the innermost indent range containing this outdent_position
1856 // set its end to the outdent position
1857 if let Some(range_to_truncate) = indent_ranges
1858 .iter_mut()
1859 .filter(|indent_range| indent_range.contains(&outdent_position))
1860 .last()
1861 {
1862 range_to_truncate.end = outdent_position;
1863 }
1864 }
1865
1866 // Find the suggested indentation increases and decreased based on regexes.
1867 let mut indent_change_rows = Vec::<(u32, Ordering)>::new();
1868 self.for_each_line(
1869 Point::new(prev_non_blank_row.unwrap_or(row_range.start), 0)
1870 ..Point::new(row_range.end, 0),
1871 |row, line| {
1872 if config
1873 .decrease_indent_pattern
1874 .as_ref()
1875 .map_or(false, |regex| regex.is_match(line))
1876 {
1877 indent_change_rows.push((row, Ordering::Less));
1878 }
1879 if config
1880 .increase_indent_pattern
1881 .as_ref()
1882 .map_or(false, |regex| regex.is_match(line))
1883 {
1884 indent_change_rows.push((row + 1, Ordering::Greater));
1885 }
1886 },
1887 );
1888
1889 let mut indent_changes = indent_change_rows.into_iter().peekable();
1890 let mut prev_row = if config.auto_indent_using_last_non_empty_line {
1891 prev_non_blank_row.unwrap_or(0)
1892 } else {
1893 row_range.start.saturating_sub(1)
1894 };
1895 let mut prev_row_start = Point::new(prev_row, self.indent_size_for_line(prev_row).len);
1896 Some(row_range.map(move |row| {
1897 let row_start = Point::new(row, self.indent_size_for_line(row).len);
1898
1899 let mut indent_from_prev_row = false;
1900 let mut outdent_from_prev_row = false;
1901 let mut outdent_to_row = u32::MAX;
1902
1903 while let Some((indent_row, delta)) = indent_changes.peek() {
1904 match indent_row.cmp(&row) {
1905 Ordering::Equal => match delta {
1906 Ordering::Less => outdent_from_prev_row = true,
1907 Ordering::Greater => indent_from_prev_row = true,
1908 _ => {}
1909 },
1910
1911 Ordering::Greater => break,
1912 Ordering::Less => {}
1913 }
1914
1915 indent_changes.next();
1916 }
1917
1918 for range in &indent_ranges {
1919 if range.start.row >= row {
1920 break;
1921 }
1922 if range.start.row == prev_row && range.end > row_start {
1923 indent_from_prev_row = true;
1924 }
1925 if range.end > prev_row_start && range.end <= row_start {
1926 outdent_to_row = outdent_to_row.min(range.start.row);
1927 }
1928 }
1929
1930 let within_error = error_ranges
1931 .iter()
1932 .any(|e| e.start.row < row && e.end > row_start);
1933
1934 let suggestion = if outdent_to_row == prev_row
1935 || (outdent_from_prev_row && indent_from_prev_row)
1936 {
1937 Some(IndentSuggestion {
1938 basis_row: prev_row,
1939 delta: Ordering::Equal,
1940 within_error,
1941 })
1942 } else if indent_from_prev_row {
1943 Some(IndentSuggestion {
1944 basis_row: prev_row,
1945 delta: Ordering::Greater,
1946 within_error,
1947 })
1948 } else if outdent_to_row < prev_row {
1949 Some(IndentSuggestion {
1950 basis_row: outdent_to_row,
1951 delta: Ordering::Equal,
1952 within_error,
1953 })
1954 } else if outdent_from_prev_row {
1955 Some(IndentSuggestion {
1956 basis_row: prev_row,
1957 delta: Ordering::Less,
1958 within_error,
1959 })
1960 } else if config.auto_indent_using_last_non_empty_line || !self.is_line_blank(prev_row)
1961 {
1962 Some(IndentSuggestion {
1963 basis_row: prev_row,
1964 delta: Ordering::Equal,
1965 within_error,
1966 })
1967 } else {
1968 None
1969 };
1970
1971 prev_row = row;
1972 prev_row_start = row_start;
1973 suggestion
1974 }))
1975 }
1976
1977 fn prev_non_blank_row(&self, mut row: u32) -> Option<u32> {
1978 while row > 0 {
1979 row -= 1;
1980 if !self.is_line_blank(row) {
1981 return Some(row);
1982 }
1983 }
1984 None
1985 }
1986
1987 pub fn chunks<T: ToOffset>(&self, range: Range<T>, language_aware: bool) -> BufferChunks {
1988 let range = range.start.to_offset(self)..range.end.to_offset(self);
1989
1990 let mut syntax = None;
1991 let mut diagnostic_endpoints = Vec::new();
1992 if language_aware {
1993 let captures = self.syntax.captures(range.clone(), &self.text, |grammar| {
1994 grammar.highlights_query.as_ref()
1995 });
1996 let highlight_maps = captures
1997 .grammars()
1998 .into_iter()
1999 .map(|grammar| grammar.highlight_map())
2000 .collect();
2001 syntax = Some((captures, highlight_maps));
2002 for entry in self.diagnostics_in_range::<_, usize>(range.clone(), false) {
2003 diagnostic_endpoints.push(DiagnosticEndpoint {
2004 offset: entry.range.start,
2005 is_start: true,
2006 severity: entry.diagnostic.severity,
2007 is_unnecessary: entry.diagnostic.is_unnecessary,
2008 });
2009 diagnostic_endpoints.push(DiagnosticEndpoint {
2010 offset: entry.range.end,
2011 is_start: false,
2012 severity: entry.diagnostic.severity,
2013 is_unnecessary: entry.diagnostic.is_unnecessary,
2014 });
2015 }
2016 diagnostic_endpoints
2017 .sort_unstable_by_key(|endpoint| (endpoint.offset, !endpoint.is_start));
2018 }
2019
2020 BufferChunks::new(self.text.as_rope(), range, syntax, diagnostic_endpoints)
2021 }
2022
2023 pub fn for_each_line(&self, range: Range<Point>, mut callback: impl FnMut(u32, &str)) {
2024 let mut line = String::new();
2025 let mut row = range.start.row;
2026 for chunk in self
2027 .as_rope()
2028 .chunks_in_range(range.to_offset(self))
2029 .chain(["\n"])
2030 {
2031 for (newline_ix, text) in chunk.split('\n').enumerate() {
2032 if newline_ix > 0 {
2033 callback(row, &line);
2034 row += 1;
2035 line.clear();
2036 }
2037 line.push_str(text);
2038 }
2039 }
2040 }
2041
2042 pub fn language_at<D: ToOffset>(&self, position: D) -> Option<&Arc<Language>> {
2043 let offset = position.to_offset(self);
2044 self.syntax
2045 .layers_for_range(offset..offset, &self.text)
2046 .filter(|l| l.node.end_byte() > offset)
2047 .last()
2048 .map(|info| info.language)
2049 .or(self.language.as_ref())
2050 }
2051
2052 pub fn language_scope_at<D: ToOffset>(&self, position: D) -> Option<LanguageScope> {
2053 let offset = position.to_offset(self);
2054
2055 if let Some(layer_info) = self
2056 .syntax
2057 .layers_for_range(offset..offset, &self.text)
2058 .filter(|l| l.node.end_byte() > offset)
2059 .last()
2060 {
2061 Some(LanguageScope {
2062 language: layer_info.language.clone(),
2063 override_id: layer_info.override_id(offset, &self.text),
2064 })
2065 } else {
2066 self.language.clone().map(|language| LanguageScope {
2067 language,
2068 override_id: None,
2069 })
2070 }
2071 }
2072
2073 pub fn surrounding_word<T: ToOffset>(&self, start: T) -> (Range<usize>, Option<CharKind>) {
2074 let mut start = start.to_offset(self);
2075 let mut end = start;
2076 let mut next_chars = self.chars_at(start).peekable();
2077 let mut prev_chars = self.reversed_chars_at(start).peekable();
2078 let word_kind = cmp::max(
2079 prev_chars.peek().copied().map(char_kind),
2080 next_chars.peek().copied().map(char_kind),
2081 );
2082
2083 for ch in prev_chars {
2084 if Some(char_kind(ch)) == word_kind && ch != '\n' {
2085 start -= ch.len_utf8();
2086 } else {
2087 break;
2088 }
2089 }
2090
2091 for ch in next_chars {
2092 if Some(char_kind(ch)) == word_kind && ch != '\n' {
2093 end += ch.len_utf8();
2094 } else {
2095 break;
2096 }
2097 }
2098
2099 (start..end, word_kind)
2100 }
2101
2102 pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
2103 let range = range.start.to_offset(self)..range.end.to_offset(self);
2104 let mut result: Option<Range<usize>> = None;
2105 'outer: for layer in self.syntax.layers_for_range(range.clone(), &self.text) {
2106 let mut cursor = layer.node.walk();
2107
2108 // Descend to the first leaf that touches the start of the range,
2109 // and if the range is non-empty, extends beyond the start.
2110 while cursor.goto_first_child_for_byte(range.start).is_some() {
2111 if !range.is_empty() && cursor.node().end_byte() == range.start {
2112 cursor.goto_next_sibling();
2113 }
2114 }
2115
2116 // Ascend to the smallest ancestor that strictly contains the range.
2117 loop {
2118 let node_range = cursor.node().byte_range();
2119 if node_range.start <= range.start
2120 && node_range.end >= range.end
2121 && node_range.len() > range.len()
2122 {
2123 break;
2124 }
2125 if !cursor.goto_parent() {
2126 continue 'outer;
2127 }
2128 }
2129
2130 let left_node = cursor.node();
2131 let mut layer_result = left_node.byte_range();
2132
2133 // For an empty range, try to find another node immediately to the right of the range.
2134 if left_node.end_byte() == range.start {
2135 let mut right_node = None;
2136 while !cursor.goto_next_sibling() {
2137 if !cursor.goto_parent() {
2138 break;
2139 }
2140 }
2141
2142 while cursor.node().start_byte() == range.start {
2143 right_node = Some(cursor.node());
2144 if !cursor.goto_first_child() {
2145 break;
2146 }
2147 }
2148
2149 // If there is a candidate node on both sides of the (empty) range, then
2150 // decide between the two by favoring a named node over an anonymous token.
2151 // If both nodes are the same in that regard, favor the right one.
2152 if let Some(right_node) = right_node {
2153 if right_node.is_named() || !left_node.is_named() {
2154 layer_result = right_node.byte_range();
2155 }
2156 }
2157 }
2158
2159 if let Some(previous_result) = &result {
2160 if previous_result.len() < layer_result.len() {
2161 continue;
2162 }
2163 }
2164 result = Some(layer_result);
2165 }
2166
2167 result
2168 }
2169
2170 pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
2171 self.outline_items_containing(0..self.len(), theme)
2172 .map(Outline::new)
2173 }
2174
2175 pub fn symbols_containing<T: ToOffset>(
2176 &self,
2177 position: T,
2178 theme: Option<&SyntaxTheme>,
2179 ) -> Option<Vec<OutlineItem<Anchor>>> {
2180 let position = position.to_offset(self);
2181 let mut items = self.outline_items_containing(
2182 position.saturating_sub(1)..self.len().min(position + 1),
2183 theme,
2184 )?;
2185 let mut prev_depth = None;
2186 items.retain(|item| {
2187 let result = prev_depth.map_or(true, |prev_depth| item.depth > prev_depth);
2188 prev_depth = Some(item.depth);
2189 result
2190 });
2191 Some(items)
2192 }
2193
2194 fn outline_items_containing(
2195 &self,
2196 range: Range<usize>,
2197 theme: Option<&SyntaxTheme>,
2198 ) -> Option<Vec<OutlineItem<Anchor>>> {
2199 let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
2200 grammar.outline_config.as_ref().map(|c| &c.query)
2201 });
2202 let configs = matches
2203 .grammars()
2204 .iter()
2205 .map(|g| g.outline_config.as_ref().unwrap())
2206 .collect::<Vec<_>>();
2207
2208 let mut stack = Vec::<Range<usize>>::new();
2209 let mut items = Vec::new();
2210 while let Some(mat) = matches.peek() {
2211 let config = &configs[mat.grammar_index];
2212 let item_node = mat.captures.iter().find_map(|cap| {
2213 if cap.index == config.item_capture_ix {
2214 Some(cap.node)
2215 } else {
2216 None
2217 }
2218 })?;
2219
2220 let item_range = item_node.byte_range();
2221 if item_range.end < range.start || item_range.start > range.end {
2222 matches.advance();
2223 continue;
2224 }
2225
2226 let mut buffer_ranges = Vec::new();
2227 for capture in mat.captures {
2228 let node_is_name;
2229 if capture.index == config.name_capture_ix {
2230 node_is_name = true;
2231 } else if Some(capture.index) == config.context_capture_ix {
2232 node_is_name = false;
2233 } else {
2234 continue;
2235 }
2236
2237 let mut range = capture.node.start_byte()..capture.node.end_byte();
2238 let start = capture.node.start_position();
2239 if capture.node.end_position().row > start.row {
2240 range.end =
2241 range.start + self.line_len(start.row as u32) as usize - start.column;
2242 }
2243
2244 buffer_ranges.push((range, node_is_name));
2245 }
2246
2247 if buffer_ranges.is_empty() {
2248 continue;
2249 }
2250
2251 let mut text = String::new();
2252 let mut highlight_ranges = Vec::new();
2253 let mut name_ranges = Vec::new();
2254 let mut chunks = self.chunks(
2255 buffer_ranges.first().unwrap().0.start..buffer_ranges.last().unwrap().0.end,
2256 true,
2257 );
2258 for (buffer_range, is_name) in buffer_ranges {
2259 if !text.is_empty() {
2260 text.push(' ');
2261 }
2262 if is_name {
2263 let mut start = text.len();
2264 let end = start + buffer_range.len();
2265
2266 // When multiple names are captured, then the matcheable text
2267 // includes the whitespace in between the names.
2268 if !name_ranges.is_empty() {
2269 start -= 1;
2270 }
2271
2272 name_ranges.push(start..end);
2273 }
2274
2275 let mut offset = buffer_range.start;
2276 chunks.seek(offset);
2277 for mut chunk in chunks.by_ref() {
2278 if chunk.text.len() > buffer_range.end - offset {
2279 chunk.text = &chunk.text[0..(buffer_range.end - offset)];
2280 offset = buffer_range.end;
2281 } else {
2282 offset += chunk.text.len();
2283 }
2284 let style = chunk
2285 .syntax_highlight_id
2286 .zip(theme)
2287 .and_then(|(highlight, theme)| highlight.style(theme));
2288 if let Some(style) = style {
2289 let start = text.len();
2290 let end = start + chunk.text.len();
2291 highlight_ranges.push((start..end, style));
2292 }
2293 text.push_str(chunk.text);
2294 if offset >= buffer_range.end {
2295 break;
2296 }
2297 }
2298 }
2299
2300 matches.advance();
2301 while stack.last().map_or(false, |prev_range| {
2302 prev_range.start > item_range.start || prev_range.end < item_range.end
2303 }) {
2304 stack.pop();
2305 }
2306 stack.push(item_range.clone());
2307
2308 items.push(OutlineItem {
2309 depth: stack.len() - 1,
2310 range: self.anchor_after(item_range.start)..self.anchor_before(item_range.end),
2311 text,
2312 highlight_ranges,
2313 name_ranges,
2314 })
2315 }
2316 Some(items)
2317 }
2318
2319 pub fn enclosing_bracket_ranges<'a, T: ToOffset>(
2320 &'a self,
2321 range: Range<T>,
2322 ) -> impl Iterator<Item = (Range<usize>, Range<usize>)> + 'a {
2323 // Find bracket pairs that *inclusively* contain the given range.
2324 let range = range.start.to_offset(self)..range.end.to_offset(self);
2325
2326 let mut matches = self.syntax.matches(
2327 range.start.saturating_sub(1)..self.len().min(range.end + 1),
2328 &self.text,
2329 |grammar| grammar.brackets_config.as_ref().map(|c| &c.query),
2330 );
2331 let configs = matches
2332 .grammars()
2333 .iter()
2334 .map(|grammar| grammar.brackets_config.as_ref().unwrap())
2335 .collect::<Vec<_>>();
2336
2337 iter::from_fn(move || {
2338 while let Some(mat) = matches.peek() {
2339 let mut open = None;
2340 let mut close = None;
2341 let config = &configs[mat.grammar_index];
2342 for capture in mat.captures {
2343 if capture.index == config.open_capture_ix {
2344 open = Some(capture.node.byte_range());
2345 } else if capture.index == config.close_capture_ix {
2346 close = Some(capture.node.byte_range());
2347 }
2348 }
2349
2350 matches.advance();
2351
2352 let Some((open, close)) = open.zip(close) else { continue };
2353
2354 if open.start > range.start || close.end < range.end {
2355 continue;
2356 }
2357
2358 return Some((open, close));
2359 }
2360 None
2361 })
2362 }
2363
2364 #[allow(clippy::type_complexity)]
2365 pub fn remote_selections_in_range(
2366 &self,
2367 range: Range<Anchor>,
2368 ) -> impl Iterator<
2369 Item = (
2370 ReplicaId,
2371 bool,
2372 CursorShape,
2373 impl Iterator<Item = &Selection<Anchor>> + '_,
2374 ),
2375 > + '_ {
2376 self.remote_selections
2377 .iter()
2378 .filter(|(replica_id, set)| {
2379 **replica_id != self.text.replica_id() && !set.selections.is_empty()
2380 })
2381 .map(move |(replica_id, set)| {
2382 let start_ix = match set.selections.binary_search_by(|probe| {
2383 probe.end.cmp(&range.start, self).then(Ordering::Greater)
2384 }) {
2385 Ok(ix) | Err(ix) => ix,
2386 };
2387 let end_ix = match set.selections.binary_search_by(|probe| {
2388 probe.start.cmp(&range.end, self).then(Ordering::Less)
2389 }) {
2390 Ok(ix) | Err(ix) => ix,
2391 };
2392
2393 (
2394 *replica_id,
2395 set.line_mode,
2396 set.cursor_shape,
2397 set.selections[start_ix..end_ix].iter(),
2398 )
2399 })
2400 }
2401
2402 pub fn git_diff_hunks_in_row_range<'a>(
2403 &'a self,
2404 range: Range<u32>,
2405 reversed: bool,
2406 ) -> impl 'a + Iterator<Item = git::diff::DiffHunk<u32>> {
2407 self.git_diff.hunks_in_row_range(range, self, reversed)
2408 }
2409
2410 pub fn git_diff_hunks_intersecting_range<'a>(
2411 &'a self,
2412 range: Range<Anchor>,
2413 reversed: bool,
2414 ) -> impl 'a + Iterator<Item = git::diff::DiffHunk<u32>> {
2415 self.git_diff
2416 .hunks_intersecting_range(range, self, reversed)
2417 }
2418
2419 pub fn diagnostics_in_range<'a, T, O>(
2420 &'a self,
2421 search_range: Range<T>,
2422 reversed: bool,
2423 ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>>
2424 where
2425 T: 'a + Clone + ToOffset,
2426 O: 'a + FromAnchor,
2427 {
2428 self.diagnostics.range(search_range, self, true, reversed)
2429 }
2430
2431 pub fn diagnostic_groups(&self) -> Vec<DiagnosticGroup<Anchor>> {
2432 let mut groups = Vec::new();
2433 self.diagnostics.groups(&mut groups, self);
2434 groups
2435 }
2436
2437 pub fn diagnostic_group<'a, O>(
2438 &'a self,
2439 group_id: usize,
2440 ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>>
2441 where
2442 O: 'a + FromAnchor,
2443 {
2444 self.diagnostics.group(group_id, self)
2445 }
2446
2447 pub fn diagnostics_update_count(&self) -> usize {
2448 self.diagnostics_update_count
2449 }
2450
2451 pub fn parse_count(&self) -> usize {
2452 self.parse_count
2453 }
2454
2455 pub fn selections_update_count(&self) -> usize {
2456 self.selections_update_count
2457 }
2458
2459 pub fn file(&self) -> Option<&Arc<dyn File>> {
2460 self.file.as_ref()
2461 }
2462
2463 pub fn resolve_file_path(&self, cx: &AppContext, include_root: bool) -> Option<PathBuf> {
2464 if let Some(file) = self.file() {
2465 if file.path().file_name().is_none() || include_root {
2466 Some(file.full_path(cx))
2467 } else {
2468 Some(file.path().to_path_buf())
2469 }
2470 } else {
2471 None
2472 }
2473 }
2474
2475 pub fn file_update_count(&self) -> usize {
2476 self.file_update_count
2477 }
2478
2479 pub fn git_diff_update_count(&self) -> usize {
2480 self.git_diff_update_count
2481 }
2482}
2483
2484fn indent_size_for_line(text: &text::BufferSnapshot, row: u32) -> IndentSize {
2485 indent_size_for_text(text.chars_at(Point::new(row, 0)))
2486}
2487
2488pub fn indent_size_for_text(text: impl Iterator<Item = char>) -> IndentSize {
2489 let mut result = IndentSize::spaces(0);
2490 for c in text {
2491 let kind = match c {
2492 ' ' => IndentKind::Space,
2493 '\t' => IndentKind::Tab,
2494 _ => break,
2495 };
2496 if result.len == 0 {
2497 result.kind = kind;
2498 }
2499 result.len += 1;
2500 }
2501 result
2502}
2503
2504impl Clone for BufferSnapshot {
2505 fn clone(&self) -> Self {
2506 Self {
2507 text: self.text.clone(),
2508 git_diff: self.git_diff.clone(),
2509 syntax: self.syntax.clone(),
2510 file: self.file.clone(),
2511 remote_selections: self.remote_selections.clone(),
2512 diagnostics: self.diagnostics.clone(),
2513 selections_update_count: self.selections_update_count,
2514 diagnostics_update_count: self.diagnostics_update_count,
2515 file_update_count: self.file_update_count,
2516 git_diff_update_count: self.git_diff_update_count,
2517 language: self.language.clone(),
2518 parse_count: self.parse_count,
2519 }
2520 }
2521}
2522
2523impl Deref for BufferSnapshot {
2524 type Target = text::BufferSnapshot;
2525
2526 fn deref(&self) -> &Self::Target {
2527 &self.text
2528 }
2529}
2530
2531unsafe impl<'a> Send for BufferChunks<'a> {}
2532
2533impl<'a> BufferChunks<'a> {
2534 pub(crate) fn new(
2535 text: &'a Rope,
2536 range: Range<usize>,
2537 syntax: Option<(SyntaxMapCaptures<'a>, Vec<HighlightMap>)>,
2538 diagnostic_endpoints: Vec<DiagnosticEndpoint>,
2539 ) -> Self {
2540 let mut highlights = None;
2541 if let Some((captures, highlight_maps)) = syntax {
2542 highlights = Some(BufferChunkHighlights {
2543 captures,
2544 next_capture: None,
2545 stack: Default::default(),
2546 highlight_maps,
2547 })
2548 }
2549
2550 let diagnostic_endpoints = diagnostic_endpoints.into_iter().peekable();
2551 let chunks = text.chunks_in_range(range.clone());
2552
2553 BufferChunks {
2554 range,
2555 chunks,
2556 diagnostic_endpoints,
2557 error_depth: 0,
2558 warning_depth: 0,
2559 information_depth: 0,
2560 hint_depth: 0,
2561 unnecessary_depth: 0,
2562 highlights,
2563 }
2564 }
2565
2566 pub fn seek(&mut self, offset: usize) {
2567 self.range.start = offset;
2568 self.chunks.seek(self.range.start);
2569 if let Some(highlights) = self.highlights.as_mut() {
2570 highlights
2571 .stack
2572 .retain(|(end_offset, _)| *end_offset > offset);
2573 if let Some(capture) = &highlights.next_capture {
2574 if offset >= capture.node.start_byte() {
2575 let next_capture_end = capture.node.end_byte();
2576 if offset < next_capture_end {
2577 highlights.stack.push((
2578 next_capture_end,
2579 highlights.highlight_maps[capture.grammar_index].get(capture.index),
2580 ));
2581 }
2582 highlights.next_capture.take();
2583 }
2584 }
2585 highlights.captures.set_byte_range(self.range.clone());
2586 }
2587 }
2588
2589 pub fn offset(&self) -> usize {
2590 self.range.start
2591 }
2592
2593 fn update_diagnostic_depths(&mut self, endpoint: DiagnosticEndpoint) {
2594 let depth = match endpoint.severity {
2595 DiagnosticSeverity::ERROR => &mut self.error_depth,
2596 DiagnosticSeverity::WARNING => &mut self.warning_depth,
2597 DiagnosticSeverity::INFORMATION => &mut self.information_depth,
2598 DiagnosticSeverity::HINT => &mut self.hint_depth,
2599 _ => return,
2600 };
2601 if endpoint.is_start {
2602 *depth += 1;
2603 } else {
2604 *depth -= 1;
2605 }
2606
2607 if endpoint.is_unnecessary {
2608 if endpoint.is_start {
2609 self.unnecessary_depth += 1;
2610 } else {
2611 self.unnecessary_depth -= 1;
2612 }
2613 }
2614 }
2615
2616 fn current_diagnostic_severity(&self) -> Option<DiagnosticSeverity> {
2617 if self.error_depth > 0 {
2618 Some(DiagnosticSeverity::ERROR)
2619 } else if self.warning_depth > 0 {
2620 Some(DiagnosticSeverity::WARNING)
2621 } else if self.information_depth > 0 {
2622 Some(DiagnosticSeverity::INFORMATION)
2623 } else if self.hint_depth > 0 {
2624 Some(DiagnosticSeverity::HINT)
2625 } else {
2626 None
2627 }
2628 }
2629
2630 fn current_code_is_unnecessary(&self) -> bool {
2631 self.unnecessary_depth > 0
2632 }
2633}
2634
2635impl<'a> Iterator for BufferChunks<'a> {
2636 type Item = Chunk<'a>;
2637
2638 fn next(&mut self) -> Option<Self::Item> {
2639 let mut next_capture_start = usize::MAX;
2640 let mut next_diagnostic_endpoint = usize::MAX;
2641
2642 if let Some(highlights) = self.highlights.as_mut() {
2643 while let Some((parent_capture_end, _)) = highlights.stack.last() {
2644 if *parent_capture_end <= self.range.start {
2645 highlights.stack.pop();
2646 } else {
2647 break;
2648 }
2649 }
2650
2651 if highlights.next_capture.is_none() {
2652 highlights.next_capture = highlights.captures.next();
2653 }
2654
2655 while let Some(capture) = highlights.next_capture.as_ref() {
2656 if self.range.start < capture.node.start_byte() {
2657 next_capture_start = capture.node.start_byte();
2658 break;
2659 } else {
2660 let highlight_id =
2661 highlights.highlight_maps[capture.grammar_index].get(capture.index);
2662 highlights
2663 .stack
2664 .push((capture.node.end_byte(), highlight_id));
2665 highlights.next_capture = highlights.captures.next();
2666 }
2667 }
2668 }
2669
2670 while let Some(endpoint) = self.diagnostic_endpoints.peek().copied() {
2671 if endpoint.offset <= self.range.start {
2672 self.update_diagnostic_depths(endpoint);
2673 self.diagnostic_endpoints.next();
2674 } else {
2675 next_diagnostic_endpoint = endpoint.offset;
2676 break;
2677 }
2678 }
2679
2680 if let Some(chunk) = self.chunks.peek() {
2681 let chunk_start = self.range.start;
2682 let mut chunk_end = (self.chunks.offset() + chunk.len())
2683 .min(next_capture_start)
2684 .min(next_diagnostic_endpoint);
2685 let mut highlight_id = None;
2686 if let Some(highlights) = self.highlights.as_ref() {
2687 if let Some((parent_capture_end, parent_highlight_id)) = highlights.stack.last() {
2688 chunk_end = chunk_end.min(*parent_capture_end);
2689 highlight_id = Some(*parent_highlight_id);
2690 }
2691 }
2692
2693 let slice =
2694 &chunk[chunk_start - self.chunks.offset()..chunk_end - self.chunks.offset()];
2695 self.range.start = chunk_end;
2696 if self.range.start == self.chunks.offset() + chunk.len() {
2697 self.chunks.next().unwrap();
2698 }
2699
2700 Some(Chunk {
2701 text: slice,
2702 syntax_highlight_id: highlight_id,
2703 highlight_style: None,
2704 diagnostic_severity: self.current_diagnostic_severity(),
2705 is_unnecessary: self.current_code_is_unnecessary(),
2706 })
2707 } else {
2708 None
2709 }
2710 }
2711}
2712
2713impl operation_queue::Operation for Operation {
2714 fn lamport_timestamp(&self) -> clock::Lamport {
2715 match self {
2716 Operation::Buffer(_) => {
2717 unreachable!("buffer operations should never be deferred at this layer")
2718 }
2719 Operation::UpdateDiagnostics {
2720 lamport_timestamp, ..
2721 }
2722 | Operation::UpdateSelections {
2723 lamport_timestamp, ..
2724 }
2725 | Operation::UpdateCompletionTriggers {
2726 lamport_timestamp, ..
2727 } => *lamport_timestamp,
2728 }
2729 }
2730}
2731
2732impl Default for Diagnostic {
2733 fn default() -> Self {
2734 Self {
2735 code: None,
2736 severity: DiagnosticSeverity::ERROR,
2737 message: Default::default(),
2738 group_id: 0,
2739 is_primary: false,
2740 is_valid: true,
2741 is_disk_based: false,
2742 is_unnecessary: false,
2743 }
2744 }
2745}
2746
2747impl IndentSize {
2748 pub fn spaces(len: u32) -> Self {
2749 Self {
2750 len,
2751 kind: IndentKind::Space,
2752 }
2753 }
2754
2755 pub fn tab() -> Self {
2756 Self {
2757 len: 1,
2758 kind: IndentKind::Tab,
2759 }
2760 }
2761
2762 pub fn chars(&self) -> impl Iterator<Item = char> {
2763 iter::repeat(self.char()).take(self.len as usize)
2764 }
2765
2766 pub fn char(&self) -> char {
2767 match self.kind {
2768 IndentKind::Space => ' ',
2769 IndentKind::Tab => '\t',
2770 }
2771 }
2772
2773 pub fn with_delta(mut self, direction: Ordering, size: IndentSize) -> Self {
2774 match direction {
2775 Ordering::Less => {
2776 if self.kind == size.kind && self.len >= size.len {
2777 self.len -= size.len;
2778 }
2779 }
2780 Ordering::Equal => {}
2781 Ordering::Greater => {
2782 if self.len == 0 {
2783 self = size;
2784 } else if self.kind == size.kind {
2785 self.len += size.len;
2786 }
2787 }
2788 }
2789 self
2790 }
2791}
2792
2793impl Completion {
2794 pub fn sort_key(&self) -> (usize, &str) {
2795 let kind_key = match self.lsp_completion.kind {
2796 Some(lsp::CompletionItemKind::VARIABLE) => 0,
2797 _ => 1,
2798 };
2799 (kind_key, &self.label.text[self.label.filter_range.clone()])
2800 }
2801
2802 pub fn is_snippet(&self) -> bool {
2803 self.lsp_completion.insert_text_format == Some(lsp::InsertTextFormat::SNIPPET)
2804 }
2805}
2806
2807pub fn contiguous_ranges(
2808 values: impl Iterator<Item = u32>,
2809 max_len: usize,
2810) -> impl Iterator<Item = Range<u32>> {
2811 let mut values = values;
2812 let mut current_range: Option<Range<u32>> = None;
2813 std::iter::from_fn(move || loop {
2814 if let Some(value) = values.next() {
2815 if let Some(range) = &mut current_range {
2816 if value == range.end && range.len() < max_len {
2817 range.end += 1;
2818 continue;
2819 }
2820 }
2821
2822 let prev_range = current_range.clone();
2823 current_range = Some(value..(value + 1));
2824 if prev_range.is_some() {
2825 return prev_range;
2826 }
2827 } else {
2828 return current_range.take();
2829 }
2830 })
2831}
2832
2833pub fn char_kind(c: char) -> CharKind {
2834 if c.is_whitespace() {
2835 CharKind::Whitespace
2836 } else if c.is_alphanumeric() || c == '_' {
2837 CharKind::Word
2838 } else {
2839 CharKind::Punctuation
2840 }
2841}