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