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 }
711 }
712
713 pub fn close(&mut self, cx: &mut ModelContext<Self>) {
714 cx.emit(Event::Closed);
715 }
716
717 pub fn language(&self) -> Option<&Arc<Language>> {
718 self.language.as_ref()
719 }
720
721 pub fn language_at<D: ToOffset>(&self, position: D) -> Option<Arc<Language>> {
722 let offset = position.to_offset(self);
723 self.syntax_map
724 .lock()
725 .layers_for_range(offset..offset, &self.text)
726 .last()
727 .map(|info| info.language.clone())
728 .or_else(|| self.language.clone())
729 }
730
731 pub fn parse_count(&self) -> usize {
732 self.parse_count
733 }
734
735 pub fn selections_update_count(&self) -> usize {
736 self.selections_update_count
737 }
738
739 pub fn diagnostics_update_count(&self) -> usize {
740 self.diagnostics_update_count
741 }
742
743 pub fn file_update_count(&self) -> usize {
744 self.file_update_count
745 }
746
747 pub fn git_diff_update_count(&self) -> usize {
748 self.git_diff_update_count
749 }
750
751 #[cfg(any(test, feature = "test-support"))]
752 pub fn is_parsing(&self) -> bool {
753 self.parsing_in_background
754 }
755
756 #[cfg(test)]
757 pub fn set_sync_parse_timeout(&mut self, timeout: Duration) {
758 self.sync_parse_timeout = timeout;
759 }
760
761 fn reparse(&mut self, cx: &mut ModelContext<Self>) {
762 if self.parsing_in_background {
763 return;
764 }
765 let language = if let Some(language) = self.language.clone() {
766 language
767 } else {
768 return;
769 };
770
771 let text = self.text_snapshot();
772 let parsed_version = self.version();
773
774 let mut syntax_map = self.syntax_map.lock();
775 syntax_map.interpolate(&text);
776 let language_registry = syntax_map.language_registry();
777 let mut syntax_snapshot = syntax_map.snapshot();
778 let syntax_map_version = syntax_map.parsed_version();
779 drop(syntax_map);
780
781 let parse_task = cx.background().spawn({
782 let language = language.clone();
783 async move {
784 syntax_snapshot.reparse(&syntax_map_version, &text, language_registry, language);
785 syntax_snapshot
786 }
787 });
788
789 match cx
790 .background()
791 .block_with_timeout(self.sync_parse_timeout, parse_task)
792 {
793 Ok(new_syntax_snapshot) => {
794 self.did_finish_parsing(new_syntax_snapshot, parsed_version, cx);
795 return;
796 }
797 Err(parse_task) => {
798 self.parsing_in_background = true;
799 cx.spawn(move |this, mut cx| async move {
800 let new_syntax_map = parse_task.await;
801 this.update(&mut cx, move |this, cx| {
802 let grammar_changed =
803 this.language.as_ref().map_or(true, |current_language| {
804 !Arc::ptr_eq(&language, current_language)
805 });
806 let parse_again =
807 this.version.changed_since(&parsed_version) || grammar_changed;
808 this.did_finish_parsing(new_syntax_map, parsed_version, cx);
809 this.parsing_in_background = false;
810 if parse_again {
811 this.reparse(cx);
812 }
813 });
814 })
815 .detach();
816 }
817 }
818 }
819
820 fn did_finish_parsing(
821 &mut self,
822 syntax_snapshot: SyntaxSnapshot,
823 version: clock::Global,
824 cx: &mut ModelContext<Self>,
825 ) {
826 self.parse_count += 1;
827 self.syntax_map.lock().did_parse(syntax_snapshot, version);
828 self.request_autoindent(cx);
829 cx.emit(Event::Reparsed);
830 cx.notify();
831 }
832
833 pub fn update_diagnostics(&mut self, diagnostics: DiagnosticSet, cx: &mut ModelContext<Self>) {
834 let lamport_timestamp = self.text.lamport_clock.tick();
835 let op = Operation::UpdateDiagnostics {
836 diagnostics: diagnostics.iter().cloned().collect(),
837 lamport_timestamp,
838 };
839 self.apply_diagnostic_update(diagnostics, lamport_timestamp, cx);
840 self.send_operation(op, cx);
841 }
842
843 fn request_autoindent(&mut self, cx: &mut ModelContext<Self>) {
844 if let Some(indent_sizes) = self.compute_autoindents() {
845 let indent_sizes = cx.background().spawn(indent_sizes);
846 match cx
847 .background()
848 .block_with_timeout(Duration::from_micros(500), indent_sizes)
849 {
850 Ok(indent_sizes) => self.apply_autoindents(indent_sizes, cx),
851 Err(indent_sizes) => {
852 self.pending_autoindent = Some(cx.spawn(|this, mut cx| async move {
853 let indent_sizes = indent_sizes.await;
854 this.update(&mut cx, |this, cx| {
855 this.apply_autoindents(indent_sizes, cx);
856 });
857 }));
858 }
859 }
860 }
861 }
862
863 fn compute_autoindents(&self) -> Option<impl Future<Output = BTreeMap<u32, IndentSize>>> {
864 let max_rows_between_yields = 100;
865 let snapshot = self.snapshot();
866 if snapshot.syntax.is_empty() || self.autoindent_requests.is_empty() {
867 return None;
868 }
869
870 let autoindent_requests = self.autoindent_requests.clone();
871 Some(async move {
872 let mut indent_sizes = BTreeMap::new();
873 for request in autoindent_requests {
874 // Resolve each edited range to its row in the current buffer and in the
875 // buffer before this batch of edits.
876 let mut row_ranges = Vec::new();
877 let mut old_to_new_rows = BTreeMap::new();
878 let mut language_indent_sizes_by_new_row = Vec::new();
879 for entry in &request.entries {
880 let position = entry.range.start;
881 let new_row = position.to_point(&snapshot).row;
882 let new_end_row = entry.range.end.to_point(&snapshot).row + 1;
883 language_indent_sizes_by_new_row.push((new_row, entry.indent_size));
884
885 if !entry.first_line_is_new {
886 let old_row = position.to_point(&request.before_edit).row;
887 old_to_new_rows.insert(old_row, new_row);
888 }
889 row_ranges.push((new_row..new_end_row, entry.original_indent_column));
890 }
891
892 // Build a map containing the suggested indentation for each of the edited lines
893 // with respect to the state of the buffer before these edits. This map is keyed
894 // by the rows for these lines in the current state of the buffer.
895 let mut old_suggestions = BTreeMap::<u32, IndentSize>::default();
896 let old_edited_ranges =
897 contiguous_ranges(old_to_new_rows.keys().copied(), max_rows_between_yields);
898 let mut language_indent_sizes = language_indent_sizes_by_new_row.iter().peekable();
899 let mut language_indent_size = IndentSize::default();
900 for old_edited_range in old_edited_ranges {
901 let suggestions = request
902 .before_edit
903 .suggest_autoindents(old_edited_range.clone())
904 .into_iter()
905 .flatten();
906 for (old_row, suggestion) in old_edited_range.zip(suggestions) {
907 if let Some(suggestion) = suggestion {
908 let new_row = *old_to_new_rows.get(&old_row).unwrap();
909
910 // Find the indent size based on the language for this row.
911 while let Some((row, size)) = language_indent_sizes.peek() {
912 if *row > new_row {
913 break;
914 }
915 language_indent_size = *size;
916 language_indent_sizes.next();
917 }
918
919 let suggested_indent = old_to_new_rows
920 .get(&suggestion.basis_row)
921 .and_then(|from_row| old_suggestions.get(from_row).copied())
922 .unwrap_or_else(|| {
923 request
924 .before_edit
925 .indent_size_for_line(suggestion.basis_row)
926 })
927 .with_delta(suggestion.delta, language_indent_size);
928 old_suggestions.insert(new_row, suggested_indent);
929 }
930 }
931 yield_now().await;
932 }
933
934 // In block mode, only compute indentation suggestions for the first line
935 // of each insertion. Otherwise, compute suggestions for every inserted line.
936 let new_edited_row_ranges = contiguous_ranges(
937 row_ranges.iter().flat_map(|(range, _)| {
938 if request.is_block_mode {
939 range.start..range.start + 1
940 } else {
941 range.clone()
942 }
943 }),
944 max_rows_between_yields,
945 );
946
947 // Compute new suggestions for each line, but only include them in the result
948 // if they differ from the old suggestion for that line.
949 let mut language_indent_sizes = language_indent_sizes_by_new_row.iter().peekable();
950 let mut language_indent_size = IndentSize::default();
951 for new_edited_row_range in new_edited_row_ranges {
952 let suggestions = snapshot
953 .suggest_autoindents(new_edited_row_range.clone())
954 .into_iter()
955 .flatten();
956 for (new_row, suggestion) in new_edited_row_range.zip(suggestions) {
957 if let Some(suggestion) = suggestion {
958 // Find the indent size based on the language for this row.
959 while let Some((row, size)) = language_indent_sizes.peek() {
960 if *row > new_row {
961 break;
962 }
963 language_indent_size = *size;
964 language_indent_sizes.next();
965 }
966
967 let suggested_indent = indent_sizes
968 .get(&suggestion.basis_row)
969 .copied()
970 .unwrap_or_else(|| {
971 snapshot.indent_size_for_line(suggestion.basis_row)
972 })
973 .with_delta(suggestion.delta, language_indent_size);
974 if old_suggestions
975 .get(&new_row)
976 .map_or(true, |old_indentation| {
977 suggested_indent != *old_indentation
978 })
979 {
980 indent_sizes.insert(new_row, suggested_indent);
981 }
982 }
983 }
984 yield_now().await;
985 }
986
987 // For each block of inserted text, adjust the indentation of the remaining
988 // lines of the block by the same amount as the first line was adjusted.
989 if request.is_block_mode {
990 for (row_range, original_indent_column) in
991 row_ranges
992 .into_iter()
993 .filter_map(|(range, original_indent_column)| {
994 if range.len() > 1 {
995 Some((range, original_indent_column?))
996 } else {
997 None
998 }
999 })
1000 {
1001 let new_indent = indent_sizes
1002 .get(&row_range.start)
1003 .copied()
1004 .unwrap_or_else(|| snapshot.indent_size_for_line(row_range.start));
1005 let delta = new_indent.len as i64 - original_indent_column as i64;
1006 if delta != 0 {
1007 for row in row_range.skip(1) {
1008 indent_sizes.entry(row).or_insert_with(|| {
1009 let mut size = snapshot.indent_size_for_line(row);
1010 if size.kind == new_indent.kind {
1011 match delta.cmp(&0) {
1012 Ordering::Greater => size.len += delta as u32,
1013 Ordering::Less => {
1014 size.len = size.len.saturating_sub(-delta as u32)
1015 }
1016 Ordering::Equal => {}
1017 }
1018 }
1019 size
1020 });
1021 }
1022 }
1023 }
1024 }
1025 }
1026
1027 indent_sizes
1028 })
1029 }
1030
1031 fn apply_autoindents(
1032 &mut self,
1033 indent_sizes: BTreeMap<u32, IndentSize>,
1034 cx: &mut ModelContext<Self>,
1035 ) {
1036 self.autoindent_requests.clear();
1037
1038 let edits: Vec<_> = indent_sizes
1039 .into_iter()
1040 .filter_map(|(row, indent_size)| {
1041 let current_size = indent_size_for_line(self, row);
1042 Self::edit_for_indent_size_adjustment(row, current_size, indent_size)
1043 })
1044 .collect();
1045
1046 self.edit(edits, None, cx);
1047 }
1048
1049 pub fn edit_for_indent_size_adjustment(
1050 row: u32,
1051 current_size: IndentSize,
1052 new_size: IndentSize,
1053 ) -> Option<(Range<Point>, String)> {
1054 if new_size.kind != current_size.kind && current_size.len > 0 {
1055 return None;
1056 }
1057
1058 match new_size.len.cmp(¤t_size.len) {
1059 Ordering::Greater => {
1060 let point = Point::new(row, 0);
1061 Some((
1062 point..point,
1063 iter::repeat(new_size.char())
1064 .take((new_size.len - current_size.len) as usize)
1065 .collect::<String>(),
1066 ))
1067 }
1068
1069 Ordering::Less => Some((
1070 Point::new(row, 0)..Point::new(row, current_size.len - new_size.len),
1071 String::new(),
1072 )),
1073
1074 Ordering::Equal => None,
1075 }
1076 }
1077
1078 pub fn diff(&self, mut new_text: String, cx: &AppContext) -> Task<Diff> {
1079 let old_text = self.as_rope().clone();
1080 let base_version = self.version();
1081 cx.background().spawn(async move {
1082 let old_text = old_text.to_string();
1083 let line_ending = LineEnding::detect(&new_text);
1084 LineEnding::normalize(&mut new_text);
1085 let diff = TextDiff::from_chars(old_text.as_str(), new_text.as_str());
1086 let mut edits = Vec::new();
1087 let mut offset = 0;
1088 let empty: Arc<str> = "".into();
1089 for change in diff.iter_all_changes() {
1090 let value = change.value();
1091 let end_offset = offset + value.len();
1092 match change.tag() {
1093 ChangeTag::Equal => {
1094 offset = end_offset;
1095 }
1096 ChangeTag::Delete => {
1097 edits.push((offset..end_offset, empty.clone()));
1098 offset = end_offset;
1099 }
1100 ChangeTag::Insert => {
1101 edits.push((offset..offset, value.into()));
1102 }
1103 }
1104 }
1105 Diff {
1106 base_version,
1107 line_ending,
1108 edits,
1109 }
1110 })
1111 }
1112
1113 pub fn apply_diff(&mut self, diff: Diff, cx: &mut ModelContext<Self>) -> Option<&Transaction> {
1114 if self.version == diff.base_version {
1115 self.finalize_last_transaction();
1116 self.start_transaction();
1117 self.text.set_line_ending(diff.line_ending);
1118 self.edit(diff.edits, None, cx);
1119 if self.end_transaction(cx).is_some() {
1120 self.finalize_last_transaction()
1121 } else {
1122 None
1123 }
1124 } else {
1125 None
1126 }
1127 }
1128
1129 pub fn is_dirty(&self) -> bool {
1130 self.saved_version_fingerprint != self.as_rope().fingerprint()
1131 || self.file.as_ref().map_or(false, |file| file.is_deleted())
1132 }
1133
1134 pub fn has_conflict(&self) -> bool {
1135 self.saved_version_fingerprint != self.as_rope().fingerprint()
1136 && self
1137 .file
1138 .as_ref()
1139 .map_or(false, |file| file.mtime() > self.saved_mtime)
1140 }
1141
1142 pub fn subscribe(&mut self) -> Subscription {
1143 self.text.subscribe()
1144 }
1145
1146 pub fn start_transaction(&mut self) -> Option<TransactionId> {
1147 self.start_transaction_at(Instant::now())
1148 }
1149
1150 pub fn start_transaction_at(&mut self, now: Instant) -> Option<TransactionId> {
1151 self.transaction_depth += 1;
1152 if self.was_dirty_before_starting_transaction.is_none() {
1153 self.was_dirty_before_starting_transaction = Some(self.is_dirty());
1154 }
1155 self.text.start_transaction_at(now)
1156 }
1157
1158 pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1159 self.end_transaction_at(Instant::now(), cx)
1160 }
1161
1162 pub fn end_transaction_at(
1163 &mut self,
1164 now: Instant,
1165 cx: &mut ModelContext<Self>,
1166 ) -> Option<TransactionId> {
1167 assert!(self.transaction_depth > 0);
1168 self.transaction_depth -= 1;
1169 let was_dirty = if self.transaction_depth == 0 {
1170 self.was_dirty_before_starting_transaction.take().unwrap()
1171 } else {
1172 false
1173 };
1174 if let Some((transaction_id, start_version)) = self.text.end_transaction_at(now) {
1175 self.did_edit(&start_version, was_dirty, cx);
1176 Some(transaction_id)
1177 } else {
1178 None
1179 }
1180 }
1181
1182 pub fn push_transaction(&mut self, transaction: Transaction, now: Instant) {
1183 self.text.push_transaction(transaction, now);
1184 }
1185
1186 pub fn finalize_last_transaction(&mut self) -> Option<&Transaction> {
1187 self.text.finalize_last_transaction()
1188 }
1189
1190 pub fn group_until_transaction(&mut self, transaction_id: TransactionId) {
1191 self.text.group_until_transaction(transaction_id);
1192 }
1193
1194 pub fn forget_transaction(&mut self, transaction_id: TransactionId) {
1195 self.text.forget_transaction(transaction_id);
1196 }
1197
1198 pub fn wait_for_edits(
1199 &mut self,
1200 edit_ids: impl IntoIterator<Item = clock::Local>,
1201 ) -> impl Future<Output = ()> {
1202 self.text.wait_for_edits(edit_ids)
1203 }
1204
1205 pub fn wait_for_anchors<'a>(
1206 &mut self,
1207 anchors: impl IntoIterator<Item = &'a Anchor>,
1208 ) -> impl Future<Output = ()> {
1209 self.text.wait_for_anchors(anchors)
1210 }
1211
1212 pub fn wait_for_version(&mut self, version: clock::Global) -> impl Future<Output = ()> {
1213 self.text.wait_for_version(version)
1214 }
1215
1216 pub fn set_active_selections(
1217 &mut self,
1218 selections: Arc<[Selection<Anchor>]>,
1219 line_mode: bool,
1220 cx: &mut ModelContext<Self>,
1221 ) {
1222 let lamport_timestamp = self.text.lamport_clock.tick();
1223 self.remote_selections.insert(
1224 self.text.replica_id(),
1225 SelectionSet {
1226 selections: selections.clone(),
1227 lamport_timestamp,
1228 line_mode,
1229 },
1230 );
1231 self.send_operation(
1232 Operation::UpdateSelections {
1233 selections,
1234 line_mode,
1235 lamport_timestamp,
1236 },
1237 cx,
1238 );
1239 }
1240
1241 pub fn remove_active_selections(&mut self, cx: &mut ModelContext<Self>) {
1242 self.set_active_selections(Arc::from([]), false, cx);
1243 }
1244
1245 pub fn set_text<T>(&mut self, text: T, cx: &mut ModelContext<Self>) -> Option<clock::Local>
1246 where
1247 T: Into<Arc<str>>,
1248 {
1249 self.edit([(0..self.len(), text)], None, cx)
1250 }
1251
1252 pub fn edit<I, S, T>(
1253 &mut self,
1254 edits_iter: I,
1255 autoindent_mode: Option<AutoindentMode>,
1256 cx: &mut ModelContext<Self>,
1257 ) -> Option<clock::Local>
1258 where
1259 I: IntoIterator<Item = (Range<S>, T)>,
1260 S: ToOffset,
1261 T: Into<Arc<str>>,
1262 {
1263 // Skip invalid edits and coalesce contiguous ones.
1264 let mut edits: Vec<(Range<usize>, Arc<str>)> = Vec::new();
1265 for (range, new_text) in edits_iter {
1266 let mut range = range.start.to_offset(self)..range.end.to_offset(self);
1267 if range.start > range.end {
1268 mem::swap(&mut range.start, &mut range.end);
1269 }
1270 let new_text = new_text.into();
1271 if !new_text.is_empty() || !range.is_empty() {
1272 if let Some((prev_range, prev_text)) = edits.last_mut() {
1273 if prev_range.end >= range.start {
1274 prev_range.end = cmp::max(prev_range.end, range.end);
1275 *prev_text = format!("{prev_text}{new_text}").into();
1276 } else {
1277 edits.push((range, new_text));
1278 }
1279 } else {
1280 edits.push((range, new_text));
1281 }
1282 }
1283 }
1284 if edits.is_empty() {
1285 return None;
1286 }
1287
1288 self.start_transaction();
1289 self.pending_autoindent.take();
1290 let autoindent_request = autoindent_mode
1291 .and_then(|mode| self.language.as_ref().map(|_| (self.snapshot(), mode)));
1292
1293 let edit_operation = self.text.edit(edits.iter().cloned());
1294 let edit_id = edit_operation.local_timestamp();
1295
1296 if let Some((before_edit, mode)) = autoindent_request {
1297 let (start_columns, is_block_mode) = match mode {
1298 AutoindentMode::Block {
1299 original_indent_columns: start_columns,
1300 } => (start_columns, true),
1301 AutoindentMode::EachLine => (Default::default(), false),
1302 };
1303
1304 let mut delta = 0isize;
1305 let entries = edits
1306 .into_iter()
1307 .enumerate()
1308 .zip(&edit_operation.as_edit().unwrap().new_text)
1309 .map(|((ix, (range, _)), new_text)| {
1310 let new_text_len = new_text.len();
1311 let old_start = range.start.to_point(&before_edit);
1312 let new_start = (delta + range.start as isize) as usize;
1313 delta += new_text_len as isize - (range.end as isize - range.start as isize);
1314
1315 let mut range_of_insertion_to_indent = 0..new_text_len;
1316 let mut first_line_is_new = false;
1317 let mut start_column = None;
1318
1319 // When inserting an entire line at the beginning of an existing line,
1320 // treat the insertion as new.
1321 if new_text.contains('\n')
1322 && old_start.column <= before_edit.indent_size_for_line(old_start.row).len
1323 {
1324 first_line_is_new = true;
1325 }
1326
1327 // When inserting text starting with a newline, avoid auto-indenting the
1328 // previous line.
1329 if new_text[range_of_insertion_to_indent.clone()].starts_with('\n') {
1330 range_of_insertion_to_indent.start += 1;
1331 first_line_is_new = true;
1332 }
1333
1334 // Avoid auto-indenting after the insertion.
1335 if is_block_mode {
1336 start_column = start_columns.get(ix).copied();
1337 if new_text[range_of_insertion_to_indent.clone()].ends_with('\n') {
1338 range_of_insertion_to_indent.end -= 1;
1339 }
1340 }
1341
1342 AutoindentRequestEntry {
1343 first_line_is_new,
1344 original_indent_column: start_column,
1345 indent_size: before_edit.language_indent_size_at(range.start, cx),
1346 range: self.anchor_before(new_start + range_of_insertion_to_indent.start)
1347 ..self.anchor_after(new_start + range_of_insertion_to_indent.end),
1348 }
1349 })
1350 .collect();
1351
1352 self.autoindent_requests.push(Arc::new(AutoindentRequest {
1353 before_edit,
1354 entries,
1355 is_block_mode,
1356 }));
1357 }
1358
1359 self.end_transaction(cx);
1360 self.send_operation(Operation::Buffer(edit_operation), cx);
1361 Some(edit_id)
1362 }
1363
1364 fn did_edit(
1365 &mut self,
1366 old_version: &clock::Global,
1367 was_dirty: bool,
1368 cx: &mut ModelContext<Self>,
1369 ) {
1370 if self.edits_since::<usize>(old_version).next().is_none() {
1371 return;
1372 }
1373
1374 self.reparse(cx);
1375
1376 cx.emit(Event::Edited);
1377 if was_dirty != self.is_dirty() {
1378 cx.emit(Event::DirtyChanged);
1379 }
1380 cx.notify();
1381 }
1382
1383 pub fn apply_ops<I: IntoIterator<Item = Operation>>(
1384 &mut self,
1385 ops: I,
1386 cx: &mut ModelContext<Self>,
1387 ) -> Result<()> {
1388 self.pending_autoindent.take();
1389 let was_dirty = self.is_dirty();
1390 let old_version = self.version.clone();
1391 let mut deferred_ops = Vec::new();
1392 let buffer_ops = ops
1393 .into_iter()
1394 .filter_map(|op| match op {
1395 Operation::Buffer(op) => Some(op),
1396 _ => {
1397 if self.can_apply_op(&op) {
1398 self.apply_op(op, cx);
1399 } else {
1400 deferred_ops.push(op);
1401 }
1402 None
1403 }
1404 })
1405 .collect::<Vec<_>>();
1406 self.text.apply_ops(buffer_ops)?;
1407 self.deferred_ops.insert(deferred_ops);
1408 self.flush_deferred_ops(cx);
1409 self.did_edit(&old_version, was_dirty, cx);
1410 // Notify independently of whether the buffer was edited as the operations could include a
1411 // selection update.
1412 cx.notify();
1413 Ok(())
1414 }
1415
1416 fn flush_deferred_ops(&mut self, cx: &mut ModelContext<Self>) {
1417 let mut deferred_ops = Vec::new();
1418 for op in self.deferred_ops.drain().iter().cloned() {
1419 if self.can_apply_op(&op) {
1420 self.apply_op(op, cx);
1421 } else {
1422 deferred_ops.push(op);
1423 }
1424 }
1425 self.deferred_ops.insert(deferred_ops);
1426 }
1427
1428 fn can_apply_op(&self, operation: &Operation) -> bool {
1429 match operation {
1430 Operation::Buffer(_) => {
1431 unreachable!("buffer operations should never be applied at this layer")
1432 }
1433 Operation::UpdateDiagnostics {
1434 diagnostics: diagnostic_set,
1435 ..
1436 } => diagnostic_set.iter().all(|diagnostic| {
1437 self.text.can_resolve(&diagnostic.range.start)
1438 && self.text.can_resolve(&diagnostic.range.end)
1439 }),
1440 Operation::UpdateSelections { selections, .. } => selections
1441 .iter()
1442 .all(|s| self.can_resolve(&s.start) && self.can_resolve(&s.end)),
1443 Operation::UpdateCompletionTriggers { .. } => true,
1444 }
1445 }
1446
1447 fn apply_op(&mut self, operation: Operation, cx: &mut ModelContext<Self>) {
1448 match operation {
1449 Operation::Buffer(_) => {
1450 unreachable!("buffer operations should never be applied at this layer")
1451 }
1452 Operation::UpdateDiagnostics {
1453 diagnostics: diagnostic_set,
1454 lamport_timestamp,
1455 } => {
1456 let snapshot = self.snapshot();
1457 self.apply_diagnostic_update(
1458 DiagnosticSet::from_sorted_entries(diagnostic_set.iter().cloned(), &snapshot),
1459 lamport_timestamp,
1460 cx,
1461 );
1462 }
1463 Operation::UpdateSelections {
1464 selections,
1465 lamport_timestamp,
1466 line_mode,
1467 } => {
1468 if let Some(set) = self.remote_selections.get(&lamport_timestamp.replica_id) {
1469 if set.lamport_timestamp > lamport_timestamp {
1470 return;
1471 }
1472 }
1473
1474 self.remote_selections.insert(
1475 lamport_timestamp.replica_id,
1476 SelectionSet {
1477 selections,
1478 lamport_timestamp,
1479 line_mode,
1480 },
1481 );
1482 self.text.lamport_clock.observe(lamport_timestamp);
1483 self.selections_update_count += 1;
1484 }
1485 Operation::UpdateCompletionTriggers {
1486 triggers,
1487 lamport_timestamp,
1488 } => {
1489 self.completion_triggers = triggers;
1490 self.text.lamport_clock.observe(lamport_timestamp);
1491 }
1492 }
1493 }
1494
1495 fn apply_diagnostic_update(
1496 &mut self,
1497 diagnostics: DiagnosticSet,
1498 lamport_timestamp: clock::Lamport,
1499 cx: &mut ModelContext<Self>,
1500 ) {
1501 if lamport_timestamp > self.diagnostics_timestamp {
1502 self.diagnostics = diagnostics;
1503 self.diagnostics_timestamp = lamport_timestamp;
1504 self.diagnostics_update_count += 1;
1505 self.text.lamport_clock.observe(lamport_timestamp);
1506 cx.notify();
1507 cx.emit(Event::DiagnosticsUpdated);
1508 }
1509 }
1510
1511 fn send_operation(&mut self, operation: Operation, cx: &mut ModelContext<Self>) {
1512 cx.emit(Event::Operation(operation));
1513 }
1514
1515 pub fn remove_peer(&mut self, replica_id: ReplicaId, cx: &mut ModelContext<Self>) {
1516 self.remote_selections.remove(&replica_id);
1517 cx.notify();
1518 }
1519
1520 pub fn undo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1521 let was_dirty = self.is_dirty();
1522 let old_version = self.version.clone();
1523
1524 if let Some((transaction_id, operation)) = self.text.undo() {
1525 self.send_operation(Operation::Buffer(operation), cx);
1526 self.did_edit(&old_version, was_dirty, cx);
1527 Some(transaction_id)
1528 } else {
1529 None
1530 }
1531 }
1532
1533 pub fn undo_to_transaction(
1534 &mut self,
1535 transaction_id: TransactionId,
1536 cx: &mut ModelContext<Self>,
1537 ) -> bool {
1538 let was_dirty = self.is_dirty();
1539 let old_version = self.version.clone();
1540
1541 let operations = self.text.undo_to_transaction(transaction_id);
1542 let undone = !operations.is_empty();
1543 for operation in operations {
1544 self.send_operation(Operation::Buffer(operation), cx);
1545 }
1546 if undone {
1547 self.did_edit(&old_version, was_dirty, cx)
1548 }
1549 undone
1550 }
1551
1552 pub fn redo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1553 let was_dirty = self.is_dirty();
1554 let old_version = self.version.clone();
1555
1556 if let Some((transaction_id, operation)) = self.text.redo() {
1557 self.send_operation(Operation::Buffer(operation), cx);
1558 self.did_edit(&old_version, was_dirty, cx);
1559 Some(transaction_id)
1560 } else {
1561 None
1562 }
1563 }
1564
1565 pub fn redo_to_transaction(
1566 &mut self,
1567 transaction_id: TransactionId,
1568 cx: &mut ModelContext<Self>,
1569 ) -> bool {
1570 let was_dirty = self.is_dirty();
1571 let old_version = self.version.clone();
1572
1573 let operations = self.text.redo_to_transaction(transaction_id);
1574 let redone = !operations.is_empty();
1575 for operation in operations {
1576 self.send_operation(Operation::Buffer(operation), cx);
1577 }
1578 if redone {
1579 self.did_edit(&old_version, was_dirty, cx)
1580 }
1581 redone
1582 }
1583
1584 pub fn set_completion_triggers(&mut self, triggers: Vec<String>, cx: &mut ModelContext<Self>) {
1585 self.completion_triggers = triggers.clone();
1586 self.completion_triggers_timestamp = self.text.lamport_clock.tick();
1587 self.send_operation(
1588 Operation::UpdateCompletionTriggers {
1589 triggers,
1590 lamport_timestamp: self.completion_triggers_timestamp,
1591 },
1592 cx,
1593 );
1594 cx.notify();
1595 }
1596
1597 pub fn completion_triggers(&self) -> &[String] {
1598 &self.completion_triggers
1599 }
1600}
1601
1602#[cfg(any(test, feature = "test-support"))]
1603impl Buffer {
1604 pub fn set_group_interval(&mut self, group_interval: Duration) {
1605 self.text.set_group_interval(group_interval);
1606 }
1607
1608 pub fn randomly_edit<T>(
1609 &mut self,
1610 rng: &mut T,
1611 old_range_count: usize,
1612 cx: &mut ModelContext<Self>,
1613 ) where
1614 T: rand::Rng,
1615 {
1616 let mut edits: Vec<(Range<usize>, String)> = Vec::new();
1617 let mut last_end = None;
1618 for _ in 0..old_range_count {
1619 if last_end.map_or(false, |last_end| last_end >= self.len()) {
1620 break;
1621 }
1622
1623 let new_start = last_end.map_or(0, |last_end| last_end + 1);
1624 let mut range = self.random_byte_range(new_start, rng);
1625 if rng.gen_bool(0.2) {
1626 mem::swap(&mut range.start, &mut range.end);
1627 }
1628 last_end = Some(range.end);
1629
1630 let new_text_len = rng.gen_range(0..10);
1631 let new_text: String = crate::random_char_iter::RandomCharIter::new(&mut *rng)
1632 .take(new_text_len)
1633 .collect();
1634
1635 edits.push((range, new_text));
1636 }
1637 log::info!("mutating buffer {} with {:?}", self.replica_id(), edits);
1638 self.edit(edits, None, cx);
1639 }
1640
1641 pub fn randomly_undo_redo(&mut self, rng: &mut impl rand::Rng, cx: &mut ModelContext<Self>) {
1642 let was_dirty = self.is_dirty();
1643 let old_version = self.version.clone();
1644
1645 let ops = self.text.randomly_undo_redo(rng);
1646 if !ops.is_empty() {
1647 for op in ops {
1648 self.send_operation(Operation::Buffer(op), cx);
1649 self.did_edit(&old_version, was_dirty, cx);
1650 }
1651 }
1652 }
1653}
1654
1655impl Entity for Buffer {
1656 type Event = Event;
1657}
1658
1659impl Deref for Buffer {
1660 type Target = TextBuffer;
1661
1662 fn deref(&self) -> &Self::Target {
1663 &self.text
1664 }
1665}
1666
1667impl BufferSnapshot {
1668 pub fn indent_size_for_line(&self, row: u32) -> IndentSize {
1669 indent_size_for_line(self, row)
1670 }
1671
1672 pub fn language_indent_size_at<T: ToOffset>(&self, position: T, cx: &AppContext) -> IndentSize {
1673 let language_name = self.language_at(position).map(|language| language.name());
1674 let settings = cx.global::<Settings>();
1675 if settings.hard_tabs(language_name.as_deref()) {
1676 IndentSize::tab()
1677 } else {
1678 IndentSize::spaces(settings.tab_size(language_name.as_deref()).get())
1679 }
1680 }
1681
1682 pub fn suggested_indents(
1683 &self,
1684 rows: impl Iterator<Item = u32>,
1685 single_indent_size: IndentSize,
1686 ) -> BTreeMap<u32, IndentSize> {
1687 let mut result = BTreeMap::new();
1688
1689 for row_range in contiguous_ranges(rows, 10) {
1690 let suggestions = match self.suggest_autoindents(row_range.clone()) {
1691 Some(suggestions) => suggestions,
1692 _ => break,
1693 };
1694
1695 for (row, suggestion) in row_range.zip(suggestions) {
1696 let indent_size = if let Some(suggestion) = suggestion {
1697 result
1698 .get(&suggestion.basis_row)
1699 .copied()
1700 .unwrap_or_else(|| self.indent_size_for_line(suggestion.basis_row))
1701 .with_delta(suggestion.delta, single_indent_size)
1702 } else {
1703 self.indent_size_for_line(row)
1704 };
1705
1706 result.insert(row, indent_size);
1707 }
1708 }
1709
1710 result
1711 }
1712
1713 fn suggest_autoindents(
1714 &self,
1715 row_range: Range<u32>,
1716 ) -> Option<impl Iterator<Item = Option<IndentSuggestion>> + '_> {
1717 let config = &self.language.as_ref()?.config;
1718 let prev_non_blank_row = self.prev_non_blank_row(row_range.start);
1719
1720 // Find the suggested indentation ranges based on the syntax tree.
1721 let start = Point::new(prev_non_blank_row.unwrap_or(row_range.start), 0);
1722 let end = Point::new(row_range.end, 0);
1723 let range = (start..end).to_offset(&self.text);
1724 let mut matches = self.syntax.matches(range, &self.text, |grammar| {
1725 Some(&grammar.indents_config.as_ref()?.query)
1726 });
1727 let indent_configs = matches
1728 .grammars()
1729 .iter()
1730 .map(|grammar| grammar.indents_config.as_ref().unwrap())
1731 .collect::<Vec<_>>();
1732
1733 let mut indent_ranges = Vec::<Range<Point>>::new();
1734 while let Some(mat) = matches.peek() {
1735 let mut start: Option<Point> = None;
1736 let mut end: Option<Point> = None;
1737
1738 let config = &indent_configs[mat.grammar_index];
1739 for capture in mat.captures {
1740 if capture.index == config.indent_capture_ix {
1741 start.get_or_insert(Point::from_ts_point(capture.node.start_position()));
1742 end.get_or_insert(Point::from_ts_point(capture.node.end_position()));
1743 } else if Some(capture.index) == config.start_capture_ix {
1744 start = Some(Point::from_ts_point(capture.node.end_position()));
1745 } else if Some(capture.index) == config.end_capture_ix {
1746 end = Some(Point::from_ts_point(capture.node.start_position()));
1747 }
1748 }
1749
1750 matches.advance();
1751 if let Some((start, end)) = start.zip(end) {
1752 if start.row == end.row {
1753 continue;
1754 }
1755
1756 let range = start..end;
1757 match indent_ranges.binary_search_by_key(&range.start, |r| r.start) {
1758 Err(ix) => indent_ranges.insert(ix, range),
1759 Ok(ix) => {
1760 let prev_range = &mut indent_ranges[ix];
1761 prev_range.end = prev_range.end.max(range.end);
1762 }
1763 }
1764 }
1765 }
1766
1767 // Find the suggested indentation increases and decreased based on regexes.
1768 let mut indent_change_rows = Vec::<(u32, Ordering)>::new();
1769 self.for_each_line(
1770 Point::new(prev_non_blank_row.unwrap_or(row_range.start), 0)
1771 ..Point::new(row_range.end, 0),
1772 |row, line| {
1773 if config
1774 .decrease_indent_pattern
1775 .as_ref()
1776 .map_or(false, |regex| regex.is_match(line))
1777 {
1778 indent_change_rows.push((row, Ordering::Less));
1779 }
1780 if config
1781 .increase_indent_pattern
1782 .as_ref()
1783 .map_or(false, |regex| regex.is_match(line))
1784 {
1785 indent_change_rows.push((row + 1, Ordering::Greater));
1786 }
1787 },
1788 );
1789
1790 let mut indent_changes = indent_change_rows.into_iter().peekable();
1791 let mut prev_row = if config.auto_indent_using_last_non_empty_line {
1792 prev_non_blank_row.unwrap_or(0)
1793 } else {
1794 row_range.start.saturating_sub(1)
1795 };
1796 let mut prev_row_start = Point::new(prev_row, self.indent_size_for_line(prev_row).len);
1797 Some(row_range.map(move |row| {
1798 let row_start = Point::new(row, self.indent_size_for_line(row).len);
1799
1800 let mut indent_from_prev_row = false;
1801 let mut outdent_from_prev_row = false;
1802 let mut outdent_to_row = u32::MAX;
1803
1804 while let Some((indent_row, delta)) = indent_changes.peek() {
1805 match indent_row.cmp(&row) {
1806 Ordering::Equal => match delta {
1807 Ordering::Less => outdent_from_prev_row = true,
1808 Ordering::Greater => indent_from_prev_row = true,
1809 _ => {}
1810 },
1811
1812 Ordering::Greater => break,
1813 Ordering::Less => {}
1814 }
1815
1816 indent_changes.next();
1817 }
1818
1819 for range in &indent_ranges {
1820 if range.start.row >= row {
1821 break;
1822 }
1823 if range.start.row == prev_row && range.end > row_start {
1824 indent_from_prev_row = true;
1825 }
1826 if range.end > prev_row_start && range.end <= row_start {
1827 outdent_to_row = outdent_to_row.min(range.start.row);
1828 }
1829 }
1830
1831 let suggestion = if outdent_to_row == prev_row
1832 || (outdent_from_prev_row && indent_from_prev_row)
1833 {
1834 Some(IndentSuggestion {
1835 basis_row: prev_row,
1836 delta: Ordering::Equal,
1837 })
1838 } else if indent_from_prev_row {
1839 Some(IndentSuggestion {
1840 basis_row: prev_row,
1841 delta: Ordering::Greater,
1842 })
1843 } else if outdent_to_row < prev_row {
1844 Some(IndentSuggestion {
1845 basis_row: outdent_to_row,
1846 delta: Ordering::Equal,
1847 })
1848 } else if outdent_from_prev_row {
1849 Some(IndentSuggestion {
1850 basis_row: prev_row,
1851 delta: Ordering::Less,
1852 })
1853 } else if config.auto_indent_using_last_non_empty_line || !self.is_line_blank(prev_row)
1854 {
1855 Some(IndentSuggestion {
1856 basis_row: prev_row,
1857 delta: Ordering::Equal,
1858 })
1859 } else {
1860 None
1861 };
1862
1863 prev_row = row;
1864 prev_row_start = row_start;
1865 suggestion
1866 }))
1867 }
1868
1869 fn prev_non_blank_row(&self, mut row: u32) -> Option<u32> {
1870 while row > 0 {
1871 row -= 1;
1872 if !self.is_line_blank(row) {
1873 return Some(row);
1874 }
1875 }
1876 None
1877 }
1878
1879 pub fn chunks<T: ToOffset>(&self, range: Range<T>, language_aware: bool) -> BufferChunks {
1880 let range = range.start.to_offset(self)..range.end.to_offset(self);
1881
1882 let mut syntax = None;
1883 let mut diagnostic_endpoints = Vec::new();
1884 if language_aware {
1885 let captures = self.syntax.captures(range.clone(), &self.text, |grammar| {
1886 grammar.highlights_query.as_ref()
1887 });
1888 let highlight_maps = captures
1889 .grammars()
1890 .into_iter()
1891 .map(|grammar| grammar.highlight_map())
1892 .collect();
1893 syntax = Some((captures, highlight_maps));
1894 for entry in self.diagnostics_in_range::<_, usize>(range.clone(), false) {
1895 diagnostic_endpoints.push(DiagnosticEndpoint {
1896 offset: entry.range.start,
1897 is_start: true,
1898 severity: entry.diagnostic.severity,
1899 is_unnecessary: entry.diagnostic.is_unnecessary,
1900 });
1901 diagnostic_endpoints.push(DiagnosticEndpoint {
1902 offset: entry.range.end,
1903 is_start: false,
1904 severity: entry.diagnostic.severity,
1905 is_unnecessary: entry.diagnostic.is_unnecessary,
1906 });
1907 }
1908 diagnostic_endpoints
1909 .sort_unstable_by_key(|endpoint| (endpoint.offset, !endpoint.is_start));
1910 }
1911
1912 BufferChunks::new(self.text.as_rope(), range, syntax, diagnostic_endpoints)
1913 }
1914
1915 pub fn for_each_line(&self, range: Range<Point>, mut callback: impl FnMut(u32, &str)) {
1916 let mut line = String::new();
1917 let mut row = range.start.row;
1918 for chunk in self
1919 .as_rope()
1920 .chunks_in_range(range.to_offset(self))
1921 .chain(["\n"])
1922 {
1923 for (newline_ix, text) in chunk.split('\n').enumerate() {
1924 if newline_ix > 0 {
1925 callback(row, &line);
1926 row += 1;
1927 line.clear();
1928 }
1929 line.push_str(text);
1930 }
1931 }
1932 }
1933
1934 pub fn language_at<D: ToOffset>(&self, position: D) -> Option<&Arc<Language>> {
1935 let offset = position.to_offset(self);
1936 self.syntax
1937 .layers_for_range(offset..offset, &self.text)
1938 .filter(|l| l.node.end_byte() > offset)
1939 .last()
1940 .map(|info| info.language)
1941 .or(self.language.as_ref())
1942 }
1943
1944 pub fn surrounding_word<T: ToOffset>(&self, start: T) -> (Range<usize>, Option<CharKind>) {
1945 let mut start = start.to_offset(self);
1946 let mut end = start;
1947 let mut next_chars = self.chars_at(start).peekable();
1948 let mut prev_chars = self.reversed_chars_at(start).peekable();
1949 let word_kind = cmp::max(
1950 prev_chars.peek().copied().map(char_kind),
1951 next_chars.peek().copied().map(char_kind),
1952 );
1953
1954 for ch in prev_chars {
1955 if Some(char_kind(ch)) == word_kind && ch != '\n' {
1956 start -= ch.len_utf8();
1957 } else {
1958 break;
1959 }
1960 }
1961
1962 for ch in next_chars {
1963 if Some(char_kind(ch)) == word_kind && ch != '\n' {
1964 end += ch.len_utf8();
1965 } else {
1966 break;
1967 }
1968 }
1969
1970 (start..end, word_kind)
1971 }
1972
1973 pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
1974 let range = range.start.to_offset(self)..range.end.to_offset(self);
1975 let mut result: Option<Range<usize>> = None;
1976 'outer: for layer in self.syntax.layers_for_range(range.clone(), &self.text) {
1977 let mut cursor = layer.node.walk();
1978
1979 // Descend to the first leaf that touches the start of the range,
1980 // and if the range is non-empty, extends beyond the start.
1981 while cursor.goto_first_child_for_byte(range.start).is_some() {
1982 if !range.is_empty() && cursor.node().end_byte() == range.start {
1983 cursor.goto_next_sibling();
1984 }
1985 }
1986
1987 // Ascend to the smallest ancestor that strictly contains the range.
1988 loop {
1989 let node_range = cursor.node().byte_range();
1990 if node_range.start <= range.start
1991 && node_range.end >= range.end
1992 && node_range.len() > range.len()
1993 {
1994 break;
1995 }
1996 if !cursor.goto_parent() {
1997 continue 'outer;
1998 }
1999 }
2000
2001 let left_node = cursor.node();
2002 let mut layer_result = left_node.byte_range();
2003
2004 // For an empty range, try to find another node immediately to the right of the range.
2005 if left_node.end_byte() == range.start {
2006 let mut right_node = None;
2007 while !cursor.goto_next_sibling() {
2008 if !cursor.goto_parent() {
2009 break;
2010 }
2011 }
2012
2013 while cursor.node().start_byte() == range.start {
2014 right_node = Some(cursor.node());
2015 if !cursor.goto_first_child() {
2016 break;
2017 }
2018 }
2019
2020 // If there is a candidate node on both sides of the (empty) range, then
2021 // decide between the two by favoring a named node over an anonymous token.
2022 // If both nodes are the same in that regard, favor the right one.
2023 if let Some(right_node) = right_node {
2024 if right_node.is_named() || !left_node.is_named() {
2025 layer_result = right_node.byte_range();
2026 }
2027 }
2028 }
2029
2030 if let Some(previous_result) = &result {
2031 if previous_result.len() < layer_result.len() {
2032 continue;
2033 }
2034 }
2035 result = Some(layer_result);
2036 }
2037
2038 result
2039 }
2040
2041 pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
2042 self.outline_items_containing(0..self.len(), theme)
2043 .map(Outline::new)
2044 }
2045
2046 pub fn symbols_containing<T: ToOffset>(
2047 &self,
2048 position: T,
2049 theme: Option<&SyntaxTheme>,
2050 ) -> Option<Vec<OutlineItem<Anchor>>> {
2051 let position = position.to_offset(self);
2052 let mut items = self.outline_items_containing(
2053 position.saturating_sub(1)..self.len().min(position + 1),
2054 theme,
2055 )?;
2056 let mut prev_depth = None;
2057 items.retain(|item| {
2058 let result = prev_depth.map_or(true, |prev_depth| item.depth > prev_depth);
2059 prev_depth = Some(item.depth);
2060 result
2061 });
2062 Some(items)
2063 }
2064
2065 fn outline_items_containing(
2066 &self,
2067 range: Range<usize>,
2068 theme: Option<&SyntaxTheme>,
2069 ) -> Option<Vec<OutlineItem<Anchor>>> {
2070 let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
2071 grammar.outline_config.as_ref().map(|c| &c.query)
2072 });
2073 let configs = matches
2074 .grammars()
2075 .iter()
2076 .map(|g| g.outline_config.as_ref().unwrap())
2077 .collect::<Vec<_>>();
2078
2079 let mut chunks = self.chunks(0..self.len(), true);
2080 let mut stack = Vec::<Range<usize>>::new();
2081 let mut items = Vec::new();
2082 while let Some(mat) = matches.peek() {
2083 let config = &configs[mat.grammar_index];
2084 let item_node = mat.captures.iter().find_map(|cap| {
2085 if cap.index == config.item_capture_ix {
2086 Some(cap.node)
2087 } else {
2088 None
2089 }
2090 })?;
2091
2092 let item_range = item_node.byte_range();
2093 if item_range.end < range.start || item_range.start > range.end {
2094 matches.advance();
2095 continue;
2096 }
2097
2098 // TODO - move later, after processing captures
2099
2100 let mut text = String::new();
2101 let mut name_ranges = Vec::new();
2102 let mut highlight_ranges = Vec::new();
2103 for capture in mat.captures {
2104 let node_is_name;
2105 if capture.index == config.name_capture_ix {
2106 node_is_name = true;
2107 } else if Some(capture.index) == config.context_capture_ix {
2108 node_is_name = false;
2109 } else {
2110 continue;
2111 }
2112
2113 let range = capture.node.start_byte()..capture.node.end_byte();
2114 if !text.is_empty() {
2115 text.push(' ');
2116 }
2117 if node_is_name {
2118 let mut start = text.len();
2119 let end = start + range.len();
2120
2121 // When multiple names are captured, then the matcheable text
2122 // includes the whitespace in between the names.
2123 if !name_ranges.is_empty() {
2124 start -= 1;
2125 }
2126
2127 name_ranges.push(start..end);
2128 }
2129
2130 let mut offset = range.start;
2131 chunks.seek(offset);
2132 for mut chunk in chunks.by_ref() {
2133 if chunk.text.len() > range.end - offset {
2134 chunk.text = &chunk.text[0..(range.end - offset)];
2135 offset = range.end;
2136 } else {
2137 offset += chunk.text.len();
2138 }
2139 let style = chunk
2140 .syntax_highlight_id
2141 .zip(theme)
2142 .and_then(|(highlight, theme)| highlight.style(theme));
2143 if let Some(style) = style {
2144 let start = text.len();
2145 let end = start + chunk.text.len();
2146 highlight_ranges.push((start..end, style));
2147 }
2148 text.push_str(chunk.text);
2149 if offset >= range.end {
2150 break;
2151 }
2152 }
2153 }
2154
2155 matches.advance();
2156 while stack.last().map_or(false, |prev_range| {
2157 prev_range.start > item_range.start || prev_range.end < item_range.end
2158 }) {
2159 stack.pop();
2160 }
2161 stack.push(item_range.clone());
2162
2163 items.push(OutlineItem {
2164 depth: stack.len() - 1,
2165 range: self.anchor_after(item_range.start)..self.anchor_before(item_range.end),
2166 text,
2167 highlight_ranges,
2168 name_ranges,
2169 })
2170 }
2171 Some(items)
2172 }
2173
2174 pub fn enclosing_bracket_ranges<T: ToOffset>(
2175 &self,
2176 range: Range<T>,
2177 ) -> Option<(Range<usize>, Range<usize>)> {
2178 // Find bracket pairs that *inclusively* contain the given range.
2179 let range = range.start.to_offset(self).saturating_sub(1)
2180 ..self.len().min(range.end.to_offset(self) + 1);
2181 let mut matches = self.syntax.matches(range, &self.text, |grammar| {
2182 grammar.brackets_config.as_ref().map(|c| &c.query)
2183 });
2184 let configs = matches
2185 .grammars()
2186 .iter()
2187 .map(|grammar| grammar.brackets_config.as_ref().unwrap())
2188 .collect::<Vec<_>>();
2189
2190 // Get the ranges of the innermost pair of brackets.
2191 let mut result: Option<(Range<usize>, Range<usize>)> = None;
2192 while let Some(mat) = matches.peek() {
2193 let mut open = None;
2194 let mut close = None;
2195 let config = &configs[mat.grammar_index];
2196 for capture in mat.captures {
2197 if capture.index == config.open_capture_ix {
2198 open = Some(capture.node.byte_range());
2199 } else if capture.index == config.close_capture_ix {
2200 close = Some(capture.node.byte_range());
2201 }
2202 }
2203
2204 matches.advance();
2205
2206 if let Some((open, close)) = open.zip(close) {
2207 let len = close.end - open.start;
2208
2209 if let Some((existing_open, existing_close)) = &result {
2210 let existing_len = existing_close.end - existing_open.start;
2211 if len > existing_len {
2212 continue;
2213 }
2214 }
2215
2216 result = Some((open, close));
2217 }
2218 }
2219
2220 result
2221 }
2222
2223 #[allow(clippy::type_complexity)]
2224 pub fn remote_selections_in_range(
2225 &self,
2226 range: Range<Anchor>,
2227 ) -> impl Iterator<
2228 Item = (
2229 ReplicaId,
2230 bool,
2231 impl Iterator<Item = &Selection<Anchor>> + '_,
2232 ),
2233 > + '_ {
2234 self.remote_selections
2235 .iter()
2236 .filter(|(replica_id, set)| {
2237 **replica_id != self.text.replica_id() && !set.selections.is_empty()
2238 })
2239 .map(move |(replica_id, set)| {
2240 let start_ix = match set.selections.binary_search_by(|probe| {
2241 probe.end.cmp(&range.start, self).then(Ordering::Greater)
2242 }) {
2243 Ok(ix) | Err(ix) => ix,
2244 };
2245 let end_ix = match set.selections.binary_search_by(|probe| {
2246 probe.start.cmp(&range.end, self).then(Ordering::Less)
2247 }) {
2248 Ok(ix) | Err(ix) => ix,
2249 };
2250
2251 (
2252 *replica_id,
2253 set.line_mode,
2254 set.selections[start_ix..end_ix].iter(),
2255 )
2256 })
2257 }
2258
2259 pub fn git_diff_hunks_in_range<'a>(
2260 &'a self,
2261 query_row_range: Range<u32>,
2262 ) -> impl 'a + Iterator<Item = git::diff::DiffHunk<u32>> {
2263 self.git_diff.hunks_in_range(query_row_range, self)
2264 }
2265
2266 pub fn diagnostics_in_range<'a, T, O>(
2267 &'a self,
2268 search_range: Range<T>,
2269 reversed: bool,
2270 ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>>
2271 where
2272 T: 'a + Clone + ToOffset,
2273 O: 'a + FromAnchor,
2274 {
2275 self.diagnostics.range(search_range, self, true, reversed)
2276 }
2277
2278 pub fn diagnostic_groups(&self) -> Vec<DiagnosticGroup<Anchor>> {
2279 let mut groups = Vec::new();
2280 self.diagnostics.groups(&mut groups, self);
2281 groups
2282 }
2283
2284 pub fn diagnostic_group<'a, O>(
2285 &'a self,
2286 group_id: usize,
2287 ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>>
2288 where
2289 O: 'a + FromAnchor,
2290 {
2291 self.diagnostics.group(group_id, self)
2292 }
2293
2294 pub fn diagnostics_update_count(&self) -> usize {
2295 self.diagnostics_update_count
2296 }
2297
2298 pub fn parse_count(&self) -> usize {
2299 self.parse_count
2300 }
2301
2302 pub fn selections_update_count(&self) -> usize {
2303 self.selections_update_count
2304 }
2305
2306 pub fn file(&self) -> Option<&dyn File> {
2307 self.file.as_deref()
2308 }
2309
2310 pub fn file_update_count(&self) -> usize {
2311 self.file_update_count
2312 }
2313
2314 pub fn git_diff_update_count(&self) -> usize {
2315 self.git_diff_update_count
2316 }
2317}
2318
2319pub fn indent_size_for_line(text: &text::BufferSnapshot, row: u32) -> IndentSize {
2320 indent_size_for_text(text.chars_at(Point::new(row, 0)))
2321}
2322
2323pub fn indent_size_for_text(text: impl Iterator<Item = char>) -> IndentSize {
2324 let mut result = IndentSize::spaces(0);
2325 for c in text {
2326 let kind = match c {
2327 ' ' => IndentKind::Space,
2328 '\t' => IndentKind::Tab,
2329 _ => break,
2330 };
2331 if result.len == 0 {
2332 result.kind = kind;
2333 }
2334 result.len += 1;
2335 }
2336 result
2337}
2338
2339impl Clone for BufferSnapshot {
2340 fn clone(&self) -> Self {
2341 Self {
2342 text: self.text.clone(),
2343 git_diff: self.git_diff.clone(),
2344 syntax: self.syntax.clone(),
2345 file: self.file.clone(),
2346 remote_selections: self.remote_selections.clone(),
2347 diagnostics: self.diagnostics.clone(),
2348 selections_update_count: self.selections_update_count,
2349 diagnostics_update_count: self.diagnostics_update_count,
2350 file_update_count: self.file_update_count,
2351 git_diff_update_count: self.git_diff_update_count,
2352 language: self.language.clone(),
2353 parse_count: self.parse_count,
2354 }
2355 }
2356}
2357
2358impl Deref for BufferSnapshot {
2359 type Target = text::BufferSnapshot;
2360
2361 fn deref(&self) -> &Self::Target {
2362 &self.text
2363 }
2364}
2365
2366unsafe impl<'a> Send for BufferChunks<'a> {}
2367
2368impl<'a> BufferChunks<'a> {
2369 pub(crate) fn new(
2370 text: &'a Rope,
2371 range: Range<usize>,
2372 syntax: Option<(SyntaxMapCaptures<'a>, Vec<HighlightMap>)>,
2373 diagnostic_endpoints: Vec<DiagnosticEndpoint>,
2374 ) -> Self {
2375 let mut highlights = None;
2376 if let Some((captures, highlight_maps)) = syntax {
2377 highlights = Some(BufferChunkHighlights {
2378 captures,
2379 next_capture: None,
2380 stack: Default::default(),
2381 highlight_maps,
2382 })
2383 }
2384
2385 let diagnostic_endpoints = diagnostic_endpoints.into_iter().peekable();
2386 let chunks = text.chunks_in_range(range.clone());
2387
2388 BufferChunks {
2389 range,
2390 chunks,
2391 diagnostic_endpoints,
2392 error_depth: 0,
2393 warning_depth: 0,
2394 information_depth: 0,
2395 hint_depth: 0,
2396 unnecessary_depth: 0,
2397 highlights,
2398 }
2399 }
2400
2401 pub fn seek(&mut self, offset: usize) {
2402 self.range.start = offset;
2403 self.chunks.seek(self.range.start);
2404 if let Some(highlights) = self.highlights.as_mut() {
2405 highlights
2406 .stack
2407 .retain(|(end_offset, _)| *end_offset > offset);
2408 if let Some(capture) = &highlights.next_capture {
2409 if offset >= capture.node.start_byte() {
2410 let next_capture_end = capture.node.end_byte();
2411 if offset < next_capture_end {
2412 highlights.stack.push((
2413 next_capture_end,
2414 highlights.highlight_maps[capture.grammar_index].get(capture.index),
2415 ));
2416 }
2417 highlights.next_capture.take();
2418 }
2419 }
2420 highlights.captures.set_byte_range(self.range.clone());
2421 }
2422 }
2423
2424 pub fn offset(&self) -> usize {
2425 self.range.start
2426 }
2427
2428 fn update_diagnostic_depths(&mut self, endpoint: DiagnosticEndpoint) {
2429 let depth = match endpoint.severity {
2430 DiagnosticSeverity::ERROR => &mut self.error_depth,
2431 DiagnosticSeverity::WARNING => &mut self.warning_depth,
2432 DiagnosticSeverity::INFORMATION => &mut self.information_depth,
2433 DiagnosticSeverity::HINT => &mut self.hint_depth,
2434 _ => return,
2435 };
2436 if endpoint.is_start {
2437 *depth += 1;
2438 } else {
2439 *depth -= 1;
2440 }
2441
2442 if endpoint.is_unnecessary {
2443 if endpoint.is_start {
2444 self.unnecessary_depth += 1;
2445 } else {
2446 self.unnecessary_depth -= 1;
2447 }
2448 }
2449 }
2450
2451 fn current_diagnostic_severity(&self) -> Option<DiagnosticSeverity> {
2452 if self.error_depth > 0 {
2453 Some(DiagnosticSeverity::ERROR)
2454 } else if self.warning_depth > 0 {
2455 Some(DiagnosticSeverity::WARNING)
2456 } else if self.information_depth > 0 {
2457 Some(DiagnosticSeverity::INFORMATION)
2458 } else if self.hint_depth > 0 {
2459 Some(DiagnosticSeverity::HINT)
2460 } else {
2461 None
2462 }
2463 }
2464
2465 fn current_code_is_unnecessary(&self) -> bool {
2466 self.unnecessary_depth > 0
2467 }
2468}
2469
2470impl<'a> Iterator for BufferChunks<'a> {
2471 type Item = Chunk<'a>;
2472
2473 fn next(&mut self) -> Option<Self::Item> {
2474 let mut next_capture_start = usize::MAX;
2475 let mut next_diagnostic_endpoint = usize::MAX;
2476
2477 if let Some(highlights) = self.highlights.as_mut() {
2478 while let Some((parent_capture_end, _)) = highlights.stack.last() {
2479 if *parent_capture_end <= self.range.start {
2480 highlights.stack.pop();
2481 } else {
2482 break;
2483 }
2484 }
2485
2486 if highlights.next_capture.is_none() {
2487 highlights.next_capture = highlights.captures.next();
2488 }
2489
2490 while let Some(capture) = highlights.next_capture.as_ref() {
2491 if self.range.start < capture.node.start_byte() {
2492 next_capture_start = capture.node.start_byte();
2493 break;
2494 } else {
2495 let highlight_id =
2496 highlights.highlight_maps[capture.grammar_index].get(capture.index);
2497 highlights
2498 .stack
2499 .push((capture.node.end_byte(), highlight_id));
2500 highlights.next_capture = highlights.captures.next();
2501 }
2502 }
2503 }
2504
2505 while let Some(endpoint) = self.diagnostic_endpoints.peek().copied() {
2506 if endpoint.offset <= self.range.start {
2507 self.update_diagnostic_depths(endpoint);
2508 self.diagnostic_endpoints.next();
2509 } else {
2510 next_diagnostic_endpoint = endpoint.offset;
2511 break;
2512 }
2513 }
2514
2515 if let Some(chunk) = self.chunks.peek() {
2516 let chunk_start = self.range.start;
2517 let mut chunk_end = (self.chunks.offset() + chunk.len())
2518 .min(next_capture_start)
2519 .min(next_diagnostic_endpoint);
2520 let mut highlight_id = None;
2521 if let Some(highlights) = self.highlights.as_ref() {
2522 if let Some((parent_capture_end, parent_highlight_id)) = highlights.stack.last() {
2523 chunk_end = chunk_end.min(*parent_capture_end);
2524 highlight_id = Some(*parent_highlight_id);
2525 }
2526 }
2527
2528 let slice =
2529 &chunk[chunk_start - self.chunks.offset()..chunk_end - self.chunks.offset()];
2530 self.range.start = chunk_end;
2531 if self.range.start == self.chunks.offset() + chunk.len() {
2532 self.chunks.next().unwrap();
2533 }
2534
2535 Some(Chunk {
2536 text: slice,
2537 syntax_highlight_id: highlight_id,
2538 highlight_style: None,
2539 diagnostic_severity: self.current_diagnostic_severity(),
2540 is_unnecessary: self.current_code_is_unnecessary(),
2541 })
2542 } else {
2543 None
2544 }
2545 }
2546}
2547
2548impl operation_queue::Operation for Operation {
2549 fn lamport_timestamp(&self) -> clock::Lamport {
2550 match self {
2551 Operation::Buffer(_) => {
2552 unreachable!("buffer operations should never be deferred at this layer")
2553 }
2554 Operation::UpdateDiagnostics {
2555 lamport_timestamp, ..
2556 }
2557 | Operation::UpdateSelections {
2558 lamport_timestamp, ..
2559 }
2560 | Operation::UpdateCompletionTriggers {
2561 lamport_timestamp, ..
2562 } => *lamport_timestamp,
2563 }
2564 }
2565}
2566
2567impl Default for Diagnostic {
2568 fn default() -> Self {
2569 Self {
2570 code: None,
2571 severity: DiagnosticSeverity::ERROR,
2572 message: Default::default(),
2573 group_id: 0,
2574 is_primary: false,
2575 is_valid: true,
2576 is_disk_based: false,
2577 is_unnecessary: false,
2578 }
2579 }
2580}
2581
2582impl IndentSize {
2583 pub fn spaces(len: u32) -> Self {
2584 Self {
2585 len,
2586 kind: IndentKind::Space,
2587 }
2588 }
2589
2590 pub fn tab() -> Self {
2591 Self {
2592 len: 1,
2593 kind: IndentKind::Tab,
2594 }
2595 }
2596
2597 pub fn chars(&self) -> impl Iterator<Item = char> {
2598 iter::repeat(self.char()).take(self.len as usize)
2599 }
2600
2601 pub fn char(&self) -> char {
2602 match self.kind {
2603 IndentKind::Space => ' ',
2604 IndentKind::Tab => '\t',
2605 }
2606 }
2607
2608 pub fn with_delta(mut self, direction: Ordering, size: IndentSize) -> Self {
2609 match direction {
2610 Ordering::Less => {
2611 if self.kind == size.kind && self.len >= size.len {
2612 self.len -= size.len;
2613 }
2614 }
2615 Ordering::Equal => {}
2616 Ordering::Greater => {
2617 if self.len == 0 {
2618 self = size;
2619 } else if self.kind == size.kind {
2620 self.len += size.len;
2621 }
2622 }
2623 }
2624 self
2625 }
2626}
2627
2628impl Completion {
2629 pub fn sort_key(&self) -> (usize, &str) {
2630 let kind_key = match self.lsp_completion.kind {
2631 Some(lsp::CompletionItemKind::VARIABLE) => 0,
2632 _ => 1,
2633 };
2634 (kind_key, &self.label.text[self.label.filter_range.clone()])
2635 }
2636
2637 pub fn is_snippet(&self) -> bool {
2638 self.lsp_completion.insert_text_format == Some(lsp::InsertTextFormat::SNIPPET)
2639 }
2640}
2641
2642pub fn contiguous_ranges(
2643 values: impl Iterator<Item = u32>,
2644 max_len: usize,
2645) -> impl Iterator<Item = Range<u32>> {
2646 let mut values = values;
2647 let mut current_range: Option<Range<u32>> = None;
2648 std::iter::from_fn(move || loop {
2649 if let Some(value) = values.next() {
2650 if let Some(range) = &mut current_range {
2651 if value == range.end && range.len() < max_len {
2652 range.end += 1;
2653 continue;
2654 }
2655 }
2656
2657 let prev_range = current_range.clone();
2658 current_range = Some(value..(value + 1));
2659 if prev_range.is_some() {
2660 return prev_range;
2661 }
2662 } else {
2663 return current_range.take();
2664 }
2665 })
2666}
2667
2668pub fn char_kind(c: char) -> CharKind {
2669 if c.is_whitespace() {
2670 CharKind::Whitespace
2671 } else if c.is_alphanumeric() || c == '_' {
2672 CharKind::Word
2673 } else {
2674 CharKind::Punctuation
2675 }
2676}