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 fs::LineEnding;
17use futures::FutureExt as _;
18use gpui::{fonts::HighlightStyle, AppContext, Entity, ModelContext, MutableAppContext, Task};
19use parking_lot::Mutex;
20use rope::point::Point;
21use settings::Settings;
22use similar::{ChangeTag, TextDiff};
23use smol::future::yield_now;
24use std::{
25 any::Any,
26 cmp::{self, Ordering},
27 collections::BTreeMap,
28 ffi::OsStr,
29 future::Future,
30 iter::{self, Iterator, Peekable},
31 mem,
32 ops::{Deref, Range},
33 path::{Path, PathBuf},
34 str,
35 sync::Arc,
36 time::{Duration, Instant, SystemTime, UNIX_EPOCH},
37 vec,
38};
39use sum_tree::TreeMap;
40use text::operation_queue::OperationQueue;
41pub use text::{Buffer as TextBuffer, BufferSnapshot as TextBufferSnapshot, Operation as _, *};
42use theme::SyntaxTheme;
43use util::{RandomCharIter, TryFutureExt as _};
44
45#[cfg(any(test, feature = "test-support"))]
46pub use {tree_sitter_rust, tree_sitter_typescript};
47
48pub use lsp::DiagnosticSeverity;
49
50struct GitDiffStatus {
51 diff: git::diff::BufferDiff,
52 update_in_progress: bool,
53 update_requested: bool,
54}
55
56pub struct Buffer {
57 text: TextBuffer,
58 diff_base: Option<String>,
59 git_diff_status: GitDiffStatus,
60 file: Option<Arc<dyn File>>,
61 saved_version: clock::Global,
62 saved_version_fingerprint: String,
63 saved_mtime: SystemTime,
64 transaction_depth: usize,
65 was_dirty_before_starting_transaction: Option<bool>,
66 language: Option<Arc<Language>>,
67 autoindent_requests: Vec<Arc<AutoindentRequest>>,
68 pending_autoindent: Option<Task<()>>,
69 sync_parse_timeout: Duration,
70 syntax_map: Mutex<SyntaxMap>,
71 parsing_in_background: bool,
72 parse_count: usize,
73 diagnostics: DiagnosticSet,
74 remote_selections: TreeMap<ReplicaId, SelectionSet>,
75 selections_update_count: usize,
76 diagnostics_update_count: usize,
77 diagnostics_timestamp: clock::Lamport,
78 file_update_count: usize,
79 git_diff_update_count: usize,
80 completion_triggers: Vec<String>,
81 completion_triggers_timestamp: clock::Lamport,
82 deferred_ops: OperationQueue<Operation>,
83}
84
85pub struct BufferSnapshot {
86 text: text::BufferSnapshot,
87 pub git_diff: git::diff::BufferDiff,
88 pub(crate) syntax: SyntaxSnapshot,
89 file: Option<Arc<dyn File>>,
90 diagnostics: DiagnosticSet,
91 diagnostics_update_count: usize,
92 file_update_count: usize,
93 git_diff_update_count: usize,
94 remote_selections: TreeMap<ReplicaId, SelectionSet>,
95 selections_update_count: usize,
96 language: Option<Arc<Language>>,
97 parse_count: usize,
98}
99
100#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
101pub struct IndentSize {
102 pub len: u32,
103 pub kind: IndentKind,
104}
105
106#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
107pub enum IndentKind {
108 #[default]
109 Space,
110 Tab,
111}
112
113#[derive(Clone, Debug)]
114struct SelectionSet {
115 line_mode: bool,
116 selections: Arc<[Selection<Anchor>]>,
117 lamport_timestamp: clock::Lamport,
118}
119
120#[derive(Clone, Debug, PartialEq, Eq)]
121pub struct GroupId {
122 source: Arc<str>,
123 id: usize,
124}
125
126#[derive(Clone, Debug, PartialEq, Eq)]
127pub struct Diagnostic {
128 pub code: Option<String>,
129 pub severity: DiagnosticSeverity,
130 pub message: String,
131 pub group_id: usize,
132 pub is_valid: bool,
133 pub is_primary: bool,
134 pub is_disk_based: bool,
135 pub is_unnecessary: bool,
136}
137
138#[derive(Clone, Debug)]
139pub struct Completion {
140 pub old_range: Range<Anchor>,
141 pub new_text: String,
142 pub label: CodeLabel,
143 pub lsp_completion: lsp::CompletionItem,
144}
145
146#[derive(Clone, Debug)]
147pub struct CodeAction {
148 pub range: Range<Anchor>,
149 pub lsp_action: lsp::CodeAction,
150}
151
152#[derive(Clone, Debug, PartialEq, Eq)]
153pub enum Operation {
154 Buffer(text::Operation),
155 UpdateDiagnostics {
156 diagnostics: Arc<[DiagnosticEntry<Anchor>]>,
157 lamport_timestamp: clock::Lamport,
158 },
159 UpdateSelections {
160 selections: Arc<[Selection<Anchor>]>,
161 lamport_timestamp: clock::Lamport,
162 line_mode: bool,
163 },
164 UpdateCompletionTriggers {
165 triggers: Vec<String>,
166 lamport_timestamp: clock::Lamport,
167 },
168}
169
170#[derive(Clone, Debug, PartialEq, Eq)]
171pub enum Event {
172 Operation(Operation),
173 Edited,
174 DirtyChanged,
175 Saved,
176 FileHandleChanged,
177 Reloaded,
178 Reparsed,
179 DiagnosticsUpdated,
180 Closed,
181}
182
183pub trait File: Send + Sync {
184 fn as_local(&self) -> Option<&dyn LocalFile>;
185
186 fn is_local(&self) -> bool {
187 self.as_local().is_some()
188 }
189
190 fn mtime(&self) -> SystemTime;
191
192 /// Returns the path of this file relative to the worktree's root directory.
193 fn path(&self) -> &Arc<Path>;
194
195 /// Returns the path of this file relative to the worktree's parent directory (this means it
196 /// includes the name of the worktree's root folder).
197 fn full_path(&self, cx: &AppContext) -> PathBuf;
198
199 /// Returns the last component of this handle's absolute path. If this handle refers to the root
200 /// of its worktree, then this method will return the name of the worktree itself.
201 fn file_name<'a>(&'a self, cx: &'a AppContext) -> &'a OsStr;
202
203 fn is_deleted(&self) -> bool;
204
205 fn save(
206 &self,
207 buffer_id: u64,
208 text: Rope,
209 version: clock::Global,
210 line_ending: LineEnding,
211 cx: &mut MutableAppContext,
212 ) -> Task<Result<(clock::Global, String, SystemTime)>>;
213
214 fn as_any(&self) -> &dyn Any;
215
216 fn to_proto(&self) -> rpc::proto::File;
217}
218
219pub trait LocalFile: File {
220 /// Returns the absolute path of this file.
221 fn abs_path(&self, cx: &AppContext) -> PathBuf;
222
223 fn load(&self, cx: &AppContext) -> Task<Result<String>>;
224
225 fn buffer_reloaded(
226 &self,
227 buffer_id: u64,
228 version: &clock::Global,
229 fingerprint: String,
230 line_ending: LineEnding,
231 mtime: SystemTime,
232 cx: &mut MutableAppContext,
233 );
234}
235
236#[derive(Clone, Debug)]
237pub enum AutoindentMode {
238 /// Indent each line of inserted text.
239 EachLine,
240 /// Apply the same indentation adjustment to all of the lines
241 /// in a given insertion.
242 Block {
243 /// The original indentation level of the first line of each
244 /// insertion, if it has been copied.
245 original_indent_columns: Vec<u32>,
246 },
247}
248
249#[derive(Clone)]
250struct AutoindentRequest {
251 before_edit: BufferSnapshot,
252 entries: Vec<AutoindentRequestEntry>,
253 is_block_mode: bool,
254}
255
256#[derive(Clone)]
257struct AutoindentRequestEntry {
258 /// A range of the buffer whose indentation should be adjusted.
259 range: Range<Anchor>,
260 /// Whether or not these lines should be considered brand new, for the
261 /// purpose of auto-indent. When text is not new, its indentation will
262 /// only be adjusted if the suggested indentation level has *changed*
263 /// since the edit was made.
264 first_line_is_new: bool,
265 indent_size: IndentSize,
266 original_indent_column: Option<u32>,
267}
268
269#[derive(Debug)]
270struct IndentSuggestion {
271 basis_row: u32,
272 delta: Ordering,
273}
274
275struct BufferChunkHighlights<'a> {
276 captures: SyntaxMapCaptures<'a>,
277 next_capture: Option<SyntaxMapCapture<'a>>,
278 stack: Vec<(usize, HighlightId)>,
279 highlight_maps: Vec<HighlightMap>,
280}
281
282pub struct BufferChunks<'a> {
283 range: Range<usize>,
284 chunks: rope::Chunks<'a>,
285 diagnostic_endpoints: Peekable<vec::IntoIter<DiagnosticEndpoint>>,
286 error_depth: usize,
287 warning_depth: usize,
288 information_depth: usize,
289 hint_depth: usize,
290 unnecessary_depth: usize,
291 highlights: Option<BufferChunkHighlights<'a>>,
292}
293
294#[derive(Clone, Copy, Debug, Default)]
295pub struct Chunk<'a> {
296 pub text: &'a str,
297 pub syntax_highlight_id: Option<HighlightId>,
298 pub highlight_style: Option<HighlightStyle>,
299 pub diagnostic_severity: Option<DiagnosticSeverity>,
300 pub is_unnecessary: bool,
301}
302
303pub struct Diff {
304 base_version: clock::Global,
305 line_ending: LineEnding,
306 edits: Vec<(Range<usize>, Arc<str>)>,
307}
308
309#[derive(Clone, Copy)]
310pub(crate) struct DiagnosticEndpoint {
311 offset: usize,
312 is_start: bool,
313 severity: DiagnosticSeverity,
314 is_unnecessary: bool,
315}
316
317#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug)]
318pub enum CharKind {
319 Punctuation,
320 Whitespace,
321 Word,
322}
323
324impl CharKind {
325 pub fn coerce_punctuation(self, treat_punctuation_as_word: bool) -> Self {
326 if treat_punctuation_as_word && self == CharKind::Punctuation {
327 CharKind::Word
328 } else {
329 self
330 }
331 }
332}
333
334impl Buffer {
335 pub fn new<T: Into<String>>(
336 replica_id: ReplicaId,
337 base_text: T,
338 cx: &mut ModelContext<Self>,
339 ) -> Self {
340 Self::build(
341 TextBuffer::new(replica_id, cx.model_id() as u64, base_text.into()),
342 None,
343 None,
344 )
345 }
346
347 pub fn from_file<T: Into<String>>(
348 replica_id: ReplicaId,
349 base_text: T,
350 diff_base: Option<T>,
351 file: Arc<dyn File>,
352 cx: &mut ModelContext<Self>,
353 ) -> Self {
354 Self::build(
355 TextBuffer::new(replica_id, cx.model_id() as u64, base_text.into()),
356 diff_base.map(|h| h.into().into_boxed_str().into()),
357 Some(file),
358 )
359 }
360
361 pub fn from_proto(
362 replica_id: ReplicaId,
363 message: proto::BufferState,
364 file: Option<Arc<dyn File>>,
365 ) -> Result<Self> {
366 let buffer = TextBuffer::new(replica_id, message.id, message.base_text);
367 let mut this = Self::build(
368 buffer,
369 message.diff_base.map(|text| text.into_boxed_str().into()),
370 file,
371 );
372 this.text.set_line_ending(proto::deserialize_line_ending(
373 rpc::proto::LineEnding::from_i32(message.line_ending)
374 .ok_or_else(|| anyhow!("missing line_ending"))?,
375 ));
376 Ok(this)
377 }
378
379 pub fn to_proto(&self) -> proto::BufferState {
380 proto::BufferState {
381 id: self.remote_id(),
382 file: self.file.as_ref().map(|f| f.to_proto()),
383 base_text: self.base_text().to_string(),
384 diff_base: self.diff_base.as_ref().map(|h| h.to_string()),
385 line_ending: proto::serialize_line_ending(self.line_ending()) as i32,
386 }
387 }
388
389 pub fn serialize_ops(&self, cx: &AppContext) -> Task<Vec<proto::Operation>> {
390 let mut operations = Vec::new();
391 operations.extend(self.deferred_ops.iter().map(proto::serialize_operation));
392 operations.extend(self.remote_selections.iter().map(|(_, set)| {
393 proto::serialize_operation(&Operation::UpdateSelections {
394 selections: set.selections.clone(),
395 lamport_timestamp: set.lamport_timestamp,
396 line_mode: set.line_mode,
397 })
398 }));
399 operations.push(proto::serialize_operation(&Operation::UpdateDiagnostics {
400 diagnostics: self.diagnostics.iter().cloned().collect(),
401 lamport_timestamp: self.diagnostics_timestamp,
402 }));
403 operations.push(proto::serialize_operation(
404 &Operation::UpdateCompletionTriggers {
405 triggers: self.completion_triggers.clone(),
406 lamport_timestamp: self.completion_triggers_timestamp,
407 },
408 ));
409
410 let text_operations = self.text.operations().clone();
411 cx.background().spawn(async move {
412 operations.extend(
413 text_operations
414 .iter()
415 .map(|(_, op)| proto::serialize_operation(&Operation::Buffer(op.clone()))),
416 );
417 operations.sort_unstable_by_key(proto::lamport_timestamp_for_operation);
418 operations
419 })
420 }
421
422 pub fn with_language(mut self, language: Arc<Language>, cx: &mut ModelContext<Self>) -> Self {
423 self.set_language(Some(language), cx);
424 self
425 }
426
427 fn build(buffer: TextBuffer, diff_base: Option<String>, file: Option<Arc<dyn File>>) -> Self {
428 let saved_mtime = if let Some(file) = file.as_ref() {
429 file.mtime()
430 } else {
431 UNIX_EPOCH
432 };
433
434 Self {
435 saved_mtime,
436 saved_version: buffer.version(),
437 saved_version_fingerprint: buffer.as_rope().fingerprint(),
438 transaction_depth: 0,
439 was_dirty_before_starting_transaction: None,
440 text: buffer,
441 diff_base,
442 git_diff_status: GitDiffStatus {
443 diff: git::diff::BufferDiff::new(),
444 update_in_progress: false,
445 update_requested: false,
446 },
447 file,
448 syntax_map: Mutex::new(SyntaxMap::new()),
449 parsing_in_background: false,
450 parse_count: 0,
451 sync_parse_timeout: Duration::from_millis(1),
452 autoindent_requests: Default::default(),
453 pending_autoindent: Default::default(),
454 language: None,
455 remote_selections: Default::default(),
456 selections_update_count: 0,
457 diagnostics: Default::default(),
458 diagnostics_update_count: 0,
459 diagnostics_timestamp: Default::default(),
460 file_update_count: 0,
461 git_diff_update_count: 0,
462 completion_triggers: Default::default(),
463 completion_triggers_timestamp: Default::default(),
464 deferred_ops: OperationQueue::new(),
465 }
466 }
467
468 pub fn snapshot(&self) -> BufferSnapshot {
469 let text = self.text.snapshot();
470 let mut syntax_map = self.syntax_map.lock();
471 syntax_map.interpolate(&text);
472 let syntax = syntax_map.snapshot();
473
474 BufferSnapshot {
475 text,
476 syntax,
477 git_diff: self.git_diff_status.diff.clone(),
478 file: self.file.clone(),
479 remote_selections: self.remote_selections.clone(),
480 diagnostics: self.diagnostics.clone(),
481 diagnostics_update_count: self.diagnostics_update_count,
482 file_update_count: self.file_update_count,
483 git_diff_update_count: self.git_diff_update_count,
484 language: self.language.clone(),
485 parse_count: self.parse_count,
486 selections_update_count: self.selections_update_count,
487 }
488 }
489
490 pub fn as_text_snapshot(&self) -> &text::BufferSnapshot {
491 &self.text
492 }
493
494 pub fn text_snapshot(&self) -> text::BufferSnapshot {
495 self.text.snapshot()
496 }
497
498 pub fn file(&self) -> Option<&dyn File> {
499 self.file.as_deref()
500 }
501
502 pub fn save(
503 &mut self,
504 cx: &mut ModelContext<Self>,
505 ) -> Task<Result<(clock::Global, String, SystemTime)>> {
506 let file = if let Some(file) = self.file.as_ref() {
507 file
508 } else {
509 return Task::ready(Err(anyhow!("buffer has no file")));
510 };
511 let text = self.as_rope().clone();
512 let version = self.version();
513 let save = file.save(
514 self.remote_id(),
515 text,
516 version,
517 self.line_ending(),
518 cx.as_mut(),
519 );
520 cx.spawn(|this, mut cx| async move {
521 let (version, fingerprint, mtime) = save.await?;
522 this.update(&mut cx, |this, cx| {
523 this.did_save(version.clone(), fingerprint.clone(), mtime, None, cx);
524 });
525 Ok((version, fingerprint, mtime))
526 })
527 }
528
529 pub fn saved_version(&self) -> &clock::Global {
530 &self.saved_version
531 }
532
533 pub fn set_language(&mut self, language: Option<Arc<Language>>, cx: &mut ModelContext<Self>) {
534 self.syntax_map.lock().clear();
535 self.language = language;
536 self.reparse(cx);
537 }
538
539 pub fn set_language_registry(&mut self, language_registry: Arc<LanguageRegistry>) {
540 self.syntax_map
541 .lock()
542 .set_language_registry(language_registry);
543 }
544
545 pub fn did_save(
546 &mut self,
547 version: clock::Global,
548 fingerprint: String,
549 mtime: SystemTime,
550 new_file: Option<Arc<dyn File>>,
551 cx: &mut ModelContext<Self>,
552 ) {
553 self.saved_version = version;
554 self.saved_version_fingerprint = fingerprint;
555 self.saved_mtime = mtime;
556 if let Some(new_file) = new_file {
557 self.file = Some(new_file);
558 self.file_update_count += 1;
559 }
560 cx.emit(Event::Saved);
561 cx.notify();
562 }
563
564 pub fn reload(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<Option<Transaction>>> {
565 cx.spawn(|this, mut cx| async move {
566 if let Some((new_mtime, new_text)) = this.read_with(&cx, |this, cx| {
567 let file = this.file.as_ref()?.as_local()?;
568 Some((file.mtime(), file.load(cx)))
569 }) {
570 let new_text = new_text.await?;
571 let diff = this
572 .read_with(&cx, |this, cx| this.diff(new_text, cx))
573 .await;
574 this.update(&mut cx, |this, cx| {
575 if let Some(transaction) = this.apply_diff(diff, cx).cloned() {
576 this.did_reload(
577 this.version(),
578 this.as_rope().fingerprint(),
579 this.line_ending(),
580 new_mtime,
581 cx,
582 );
583 Ok(Some(transaction))
584 } else {
585 Ok(None)
586 }
587 })
588 } else {
589 Ok(None)
590 }
591 })
592 }
593
594 pub fn did_reload(
595 &mut self,
596 version: clock::Global,
597 fingerprint: String,
598 line_ending: LineEnding,
599 mtime: SystemTime,
600 cx: &mut ModelContext<Self>,
601 ) {
602 self.saved_version = version;
603 self.saved_version_fingerprint = fingerprint;
604 self.text.set_line_ending(line_ending);
605 self.saved_mtime = mtime;
606 if let Some(file) = self.file.as_ref().and_then(|f| f.as_local()) {
607 file.buffer_reloaded(
608 self.remote_id(),
609 &self.saved_version,
610 self.saved_version_fingerprint.clone(),
611 self.line_ending(),
612 self.saved_mtime,
613 cx,
614 );
615 }
616 self.git_diff_recalc(cx);
617 cx.emit(Event::Reloaded);
618 cx.notify();
619 }
620
621 pub fn file_updated(
622 &mut self,
623 new_file: Arc<dyn File>,
624 cx: &mut ModelContext<Self>,
625 ) -> Task<()> {
626 let old_file = if let Some(file) = self.file.as_ref() {
627 file
628 } else {
629 return Task::ready(());
630 };
631 let mut file_changed = false;
632 let mut task = Task::ready(());
633
634 if new_file.path() != old_file.path() {
635 file_changed = true;
636 }
637
638 if new_file.is_deleted() {
639 if !old_file.is_deleted() {
640 file_changed = true;
641 if !self.is_dirty() {
642 cx.emit(Event::DirtyChanged);
643 }
644 }
645 } else {
646 let new_mtime = new_file.mtime();
647 if new_mtime != old_file.mtime() {
648 file_changed = true;
649
650 if !self.is_dirty() {
651 let reload = self.reload(cx).log_err().map(drop);
652 task = cx.foreground().spawn(reload);
653 }
654 }
655 }
656
657 if file_changed {
658 self.file_update_count += 1;
659 cx.emit(Event::FileHandleChanged);
660 cx.notify();
661 }
662 self.file = Some(new_file);
663 task
664 }
665
666 #[cfg(any(test, feature = "test-support"))]
667 pub fn diff_base(&self) -> Option<&str> {
668 self.diff_base.as_deref()
669 }
670
671 pub fn update_diff_base(&mut self, diff_base: Option<String>, cx: &mut ModelContext<Self>) {
672 self.diff_base = diff_base;
673 self.git_diff_recalc(cx);
674 }
675
676 pub fn needs_git_diff_recalc(&self) -> bool {
677 self.git_diff_status.diff.needs_update(self)
678 }
679
680 pub fn git_diff_recalc(&mut self, cx: &mut ModelContext<Self>) {
681 if self.git_diff_status.update_in_progress {
682 self.git_diff_status.update_requested = true;
683 return;
684 }
685
686 if let Some(diff_base) = &self.diff_base {
687 let snapshot = self.snapshot();
688 let diff_base = diff_base.clone();
689
690 let mut diff = self.git_diff_status.diff.clone();
691 let diff = cx.background().spawn(async move {
692 diff.update(&diff_base, &snapshot).await;
693 diff
694 });
695
696 cx.spawn_weak(|this, mut cx| async move {
697 let buffer_diff = diff.await;
698 if let Some(this) = this.upgrade(&cx) {
699 this.update(&mut cx, |this, cx| {
700 this.git_diff_status.diff = buffer_diff;
701 this.git_diff_update_count += 1;
702 cx.notify();
703
704 this.git_diff_status.update_in_progress = false;
705 if this.git_diff_status.update_requested {
706 this.git_diff_recalc(cx);
707 }
708 })
709 }
710 })
711 .detach()
712 } else {
713 let snapshot = self.snapshot();
714 self.git_diff_status.diff.clear(&snapshot);
715 self.git_diff_update_count += 1;
716 cx.notify();
717 }
718 }
719
720 pub fn close(&mut self, cx: &mut ModelContext<Self>) {
721 cx.emit(Event::Closed);
722 }
723
724 pub fn language(&self) -> Option<&Arc<Language>> {
725 self.language.as_ref()
726 }
727
728 pub fn language_at<D: ToOffset>(&self, position: D) -> Option<Arc<Language>> {
729 let offset = position.to_offset(self);
730 self.syntax_map
731 .lock()
732 .layers_for_range(offset..offset, &self.text)
733 .last()
734 .map(|info| info.language.clone())
735 .or_else(|| self.language.clone())
736 }
737
738 pub fn parse_count(&self) -> usize {
739 self.parse_count
740 }
741
742 pub fn selections_update_count(&self) -> usize {
743 self.selections_update_count
744 }
745
746 pub fn diagnostics_update_count(&self) -> usize {
747 self.diagnostics_update_count
748 }
749
750 pub fn file_update_count(&self) -> usize {
751 self.file_update_count
752 }
753
754 pub fn git_diff_update_count(&self) -> usize {
755 self.git_diff_update_count
756 }
757
758 #[cfg(any(test, feature = "test-support"))]
759 pub fn is_parsing(&self) -> bool {
760 self.parsing_in_background
761 }
762
763 #[cfg(test)]
764 pub fn set_sync_parse_timeout(&mut self, timeout: Duration) {
765 self.sync_parse_timeout = timeout;
766 }
767
768 fn reparse(&mut self, cx: &mut ModelContext<Self>) {
769 if self.parsing_in_background {
770 return;
771 }
772 let language = if let Some(language) = self.language.clone() {
773 language
774 } else {
775 return;
776 };
777
778 let text = self.text_snapshot();
779 let parsed_version = self.version();
780
781 let mut syntax_map = self.syntax_map.lock();
782 syntax_map.interpolate(&text);
783 let language_registry = syntax_map.language_registry();
784 let mut syntax_snapshot = syntax_map.snapshot();
785 let syntax_map_version = syntax_map.parsed_version();
786 drop(syntax_map);
787
788 let parse_task = cx.background().spawn({
789 let language = language.clone();
790 async move {
791 syntax_snapshot.reparse(&syntax_map_version, &text, language_registry, language);
792 syntax_snapshot
793 }
794 });
795
796 match cx
797 .background()
798 .block_with_timeout(self.sync_parse_timeout, parse_task)
799 {
800 Ok(new_syntax_snapshot) => {
801 self.did_finish_parsing(new_syntax_snapshot, parsed_version, cx);
802 return;
803 }
804 Err(parse_task) => {
805 self.parsing_in_background = true;
806 cx.spawn(move |this, mut cx| async move {
807 let new_syntax_map = parse_task.await;
808 this.update(&mut cx, move |this, cx| {
809 let grammar_changed =
810 this.language.as_ref().map_or(true, |current_language| {
811 !Arc::ptr_eq(&language, current_language)
812 });
813 let parse_again =
814 this.version.changed_since(&parsed_version) || grammar_changed;
815 this.did_finish_parsing(new_syntax_map, parsed_version, cx);
816 this.parsing_in_background = false;
817 if parse_again {
818 this.reparse(cx);
819 }
820 });
821 })
822 .detach();
823 }
824 }
825 }
826
827 fn did_finish_parsing(
828 &mut self,
829 syntax_snapshot: SyntaxSnapshot,
830 version: clock::Global,
831 cx: &mut ModelContext<Self>,
832 ) {
833 self.parse_count += 1;
834 self.syntax_map.lock().did_parse(syntax_snapshot, version);
835 self.request_autoindent(cx);
836 cx.emit(Event::Reparsed);
837 cx.notify();
838 }
839
840 pub fn update_diagnostics(&mut self, diagnostics: DiagnosticSet, cx: &mut ModelContext<Self>) {
841 let lamport_timestamp = self.text.lamport_clock.tick();
842 let op = Operation::UpdateDiagnostics {
843 diagnostics: diagnostics.iter().cloned().collect(),
844 lamport_timestamp,
845 };
846 self.apply_diagnostic_update(diagnostics, lamport_timestamp, cx);
847 self.send_operation(op, cx);
848 }
849
850 fn request_autoindent(&mut self, cx: &mut ModelContext<Self>) {
851 if let Some(indent_sizes) = self.compute_autoindents() {
852 let indent_sizes = cx.background().spawn(indent_sizes);
853 match cx
854 .background()
855 .block_with_timeout(Duration::from_micros(500), indent_sizes)
856 {
857 Ok(indent_sizes) => self.apply_autoindents(indent_sizes, cx),
858 Err(indent_sizes) => {
859 self.pending_autoindent = Some(cx.spawn(|this, mut cx| async move {
860 let indent_sizes = indent_sizes.await;
861 this.update(&mut cx, |this, cx| {
862 this.apply_autoindents(indent_sizes, cx);
863 });
864 }));
865 }
866 }
867 }
868 }
869
870 fn compute_autoindents(&self) -> Option<impl Future<Output = BTreeMap<u32, IndentSize>>> {
871 let max_rows_between_yields = 100;
872 let snapshot = self.snapshot();
873 if snapshot.syntax.is_empty() || self.autoindent_requests.is_empty() {
874 return None;
875 }
876
877 let autoindent_requests = self.autoindent_requests.clone();
878 Some(async move {
879 let mut indent_sizes = BTreeMap::new();
880 for request in autoindent_requests {
881 // Resolve each edited range to its row in the current buffer and in the
882 // buffer before this batch of edits.
883 let mut row_ranges = Vec::new();
884 let mut old_to_new_rows = BTreeMap::new();
885 let mut language_indent_sizes_by_new_row = Vec::new();
886 for entry in &request.entries {
887 let position = entry.range.start;
888 let new_row = position.to_point(&snapshot).row;
889 let new_end_row = entry.range.end.to_point(&snapshot).row + 1;
890 language_indent_sizes_by_new_row.push((new_row, entry.indent_size));
891
892 if !entry.first_line_is_new {
893 let old_row = position.to_point(&request.before_edit).row;
894 old_to_new_rows.insert(old_row, new_row);
895 }
896 row_ranges.push((new_row..new_end_row, entry.original_indent_column));
897 }
898
899 // Build a map containing the suggested indentation for each of the edited lines
900 // with respect to the state of the buffer before these edits. This map is keyed
901 // by the rows for these lines in the current state of the buffer.
902 let mut old_suggestions = BTreeMap::<u32, IndentSize>::default();
903 let old_edited_ranges =
904 contiguous_ranges(old_to_new_rows.keys().copied(), max_rows_between_yields);
905 let mut language_indent_sizes = language_indent_sizes_by_new_row.iter().peekable();
906 let mut language_indent_size = IndentSize::default();
907 for old_edited_range in old_edited_ranges {
908 let suggestions = request
909 .before_edit
910 .suggest_autoindents(old_edited_range.clone())
911 .into_iter()
912 .flatten();
913 for (old_row, suggestion) in old_edited_range.zip(suggestions) {
914 if let Some(suggestion) = suggestion {
915 let new_row = *old_to_new_rows.get(&old_row).unwrap();
916
917 // Find the indent size based on the language for this row.
918 while let Some((row, size)) = language_indent_sizes.peek() {
919 if *row > new_row {
920 break;
921 }
922 language_indent_size = *size;
923 language_indent_sizes.next();
924 }
925
926 let suggested_indent = old_to_new_rows
927 .get(&suggestion.basis_row)
928 .and_then(|from_row| old_suggestions.get(from_row).copied())
929 .unwrap_or_else(|| {
930 request
931 .before_edit
932 .indent_size_for_line(suggestion.basis_row)
933 })
934 .with_delta(suggestion.delta, language_indent_size);
935 old_suggestions.insert(new_row, suggested_indent);
936 }
937 }
938 yield_now().await;
939 }
940
941 // In block mode, only compute indentation suggestions for the first line
942 // of each insertion. Otherwise, compute suggestions for every inserted line.
943 let new_edited_row_ranges = contiguous_ranges(
944 row_ranges.iter().flat_map(|(range, _)| {
945 if request.is_block_mode {
946 range.start..range.start + 1
947 } else {
948 range.clone()
949 }
950 }),
951 max_rows_between_yields,
952 );
953
954 // Compute new suggestions for each line, but only include them in the result
955 // if they differ from the old suggestion for that line.
956 let mut language_indent_sizes = language_indent_sizes_by_new_row.iter().peekable();
957 let mut language_indent_size = IndentSize::default();
958 for new_edited_row_range in new_edited_row_ranges {
959 let suggestions = snapshot
960 .suggest_autoindents(new_edited_row_range.clone())
961 .into_iter()
962 .flatten();
963 for (new_row, suggestion) in new_edited_row_range.zip(suggestions) {
964 if let Some(suggestion) = suggestion {
965 // Find the indent size based on the language for this row.
966 while let Some((row, size)) = language_indent_sizes.peek() {
967 if *row > new_row {
968 break;
969 }
970 language_indent_size = *size;
971 language_indent_sizes.next();
972 }
973
974 let suggested_indent = indent_sizes
975 .get(&suggestion.basis_row)
976 .copied()
977 .unwrap_or_else(|| {
978 snapshot.indent_size_for_line(suggestion.basis_row)
979 })
980 .with_delta(suggestion.delta, language_indent_size);
981 if old_suggestions
982 .get(&new_row)
983 .map_or(true, |old_indentation| {
984 suggested_indent != *old_indentation
985 })
986 {
987 indent_sizes.insert(new_row, suggested_indent);
988 }
989 }
990 }
991 yield_now().await;
992 }
993
994 // For each block of inserted text, adjust the indentation of the remaining
995 // lines of the block by the same amount as the first line was adjusted.
996 if request.is_block_mode {
997 for (row_range, original_indent_column) in
998 row_ranges
999 .into_iter()
1000 .filter_map(|(range, original_indent_column)| {
1001 if range.len() > 1 {
1002 Some((range, original_indent_column?))
1003 } else {
1004 None
1005 }
1006 })
1007 {
1008 let new_indent = indent_sizes
1009 .get(&row_range.start)
1010 .copied()
1011 .unwrap_or_else(|| snapshot.indent_size_for_line(row_range.start));
1012 let delta = new_indent.len as i64 - original_indent_column as i64;
1013 if delta != 0 {
1014 for row in row_range.skip(1) {
1015 indent_sizes.entry(row).or_insert_with(|| {
1016 let mut size = snapshot.indent_size_for_line(row);
1017 if size.kind == new_indent.kind {
1018 match delta.cmp(&0) {
1019 Ordering::Greater => size.len += delta as u32,
1020 Ordering::Less => {
1021 size.len = size.len.saturating_sub(-delta as u32)
1022 }
1023 Ordering::Equal => {}
1024 }
1025 }
1026 size
1027 });
1028 }
1029 }
1030 }
1031 }
1032 }
1033
1034 indent_sizes
1035 })
1036 }
1037
1038 fn apply_autoindents(
1039 &mut self,
1040 indent_sizes: BTreeMap<u32, IndentSize>,
1041 cx: &mut ModelContext<Self>,
1042 ) {
1043 self.autoindent_requests.clear();
1044
1045 let edits: Vec<_> = indent_sizes
1046 .into_iter()
1047 .filter_map(|(row, indent_size)| {
1048 let current_size = indent_size_for_line(self, row);
1049 Self::edit_for_indent_size_adjustment(row, current_size, indent_size)
1050 })
1051 .collect();
1052
1053 self.edit(edits, None, cx);
1054 }
1055
1056 pub fn edit_for_indent_size_adjustment(
1057 row: u32,
1058 current_size: IndentSize,
1059 new_size: IndentSize,
1060 ) -> Option<(Range<Point>, String)> {
1061 if new_size.kind != current_size.kind && current_size.len > 0 {
1062 return None;
1063 }
1064
1065 match new_size.len.cmp(¤t_size.len) {
1066 Ordering::Greater => {
1067 let point = Point::new(row, 0);
1068 Some((
1069 point..point,
1070 iter::repeat(new_size.char())
1071 .take((new_size.len - current_size.len) as usize)
1072 .collect::<String>(),
1073 ))
1074 }
1075
1076 Ordering::Less => Some((
1077 Point::new(row, 0)..Point::new(row, current_size.len - new_size.len),
1078 String::new(),
1079 )),
1080
1081 Ordering::Equal => None,
1082 }
1083 }
1084
1085 pub fn diff(&self, mut new_text: String, cx: &AppContext) -> Task<Diff> {
1086 let old_text = self.as_rope().clone();
1087 let base_version = self.version();
1088 cx.background().spawn(async move {
1089 let old_text = old_text.to_string();
1090 let line_ending = LineEnding::detect(&new_text);
1091 LineEnding::normalize(&mut new_text);
1092 let diff = TextDiff::from_chars(old_text.as_str(), new_text.as_str());
1093 let mut edits = Vec::new();
1094 let mut offset = 0;
1095 let empty: Arc<str> = "".into();
1096 for change in diff.iter_all_changes() {
1097 let value = change.value();
1098 let end_offset = offset + value.len();
1099 match change.tag() {
1100 ChangeTag::Equal => {
1101 offset = end_offset;
1102 }
1103 ChangeTag::Delete => {
1104 edits.push((offset..end_offset, empty.clone()));
1105 offset = end_offset;
1106 }
1107 ChangeTag::Insert => {
1108 edits.push((offset..offset, value.into()));
1109 }
1110 }
1111 }
1112 Diff {
1113 base_version,
1114 line_ending,
1115 edits,
1116 }
1117 })
1118 }
1119
1120 pub fn apply_diff(&mut self, diff: Diff, cx: &mut ModelContext<Self>) -> Option<&Transaction> {
1121 if self.version == diff.base_version {
1122 self.finalize_last_transaction();
1123 self.start_transaction();
1124 self.text.set_line_ending(diff.line_ending);
1125 self.edit(diff.edits, None, cx);
1126 if self.end_transaction(cx).is_some() {
1127 self.finalize_last_transaction()
1128 } else {
1129 None
1130 }
1131 } else {
1132 None
1133 }
1134 }
1135
1136 pub fn is_dirty(&self) -> bool {
1137 self.saved_version_fingerprint != self.as_rope().fingerprint()
1138 || self.file.as_ref().map_or(false, |file| file.is_deleted())
1139 }
1140
1141 pub fn has_conflict(&self) -> bool {
1142 self.saved_version_fingerprint != self.as_rope().fingerprint()
1143 && self
1144 .file
1145 .as_ref()
1146 .map_or(false, |file| file.mtime() > self.saved_mtime)
1147 }
1148
1149 pub fn subscribe(&mut self) -> Subscription {
1150 self.text.subscribe()
1151 }
1152
1153 pub fn start_transaction(&mut self) -> Option<TransactionId> {
1154 self.start_transaction_at(Instant::now())
1155 }
1156
1157 pub fn start_transaction_at(&mut self, now: Instant) -> Option<TransactionId> {
1158 self.transaction_depth += 1;
1159 if self.was_dirty_before_starting_transaction.is_none() {
1160 self.was_dirty_before_starting_transaction = Some(self.is_dirty());
1161 }
1162 self.text.start_transaction_at(now)
1163 }
1164
1165 pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1166 self.end_transaction_at(Instant::now(), cx)
1167 }
1168
1169 pub fn end_transaction_at(
1170 &mut self,
1171 now: Instant,
1172 cx: &mut ModelContext<Self>,
1173 ) -> Option<TransactionId> {
1174 assert!(self.transaction_depth > 0);
1175 self.transaction_depth -= 1;
1176 let was_dirty = if self.transaction_depth == 0 {
1177 self.was_dirty_before_starting_transaction.take().unwrap()
1178 } else {
1179 false
1180 };
1181 if let Some((transaction_id, start_version)) = self.text.end_transaction_at(now) {
1182 self.did_edit(&start_version, was_dirty, cx);
1183 Some(transaction_id)
1184 } else {
1185 None
1186 }
1187 }
1188
1189 pub fn push_transaction(&mut self, transaction: Transaction, now: Instant) {
1190 self.text.push_transaction(transaction, now);
1191 }
1192
1193 pub fn finalize_last_transaction(&mut self) -> Option<&Transaction> {
1194 self.text.finalize_last_transaction()
1195 }
1196
1197 pub fn group_until_transaction(&mut self, transaction_id: TransactionId) {
1198 self.text.group_until_transaction(transaction_id);
1199 }
1200
1201 pub fn forget_transaction(&mut self, transaction_id: TransactionId) {
1202 self.text.forget_transaction(transaction_id);
1203 }
1204
1205 pub fn wait_for_edits(
1206 &mut self,
1207 edit_ids: impl IntoIterator<Item = clock::Local>,
1208 ) -> impl Future<Output = ()> {
1209 self.text.wait_for_edits(edit_ids)
1210 }
1211
1212 pub fn wait_for_anchors<'a>(
1213 &mut self,
1214 anchors: impl IntoIterator<Item = &'a Anchor>,
1215 ) -> impl Future<Output = ()> {
1216 self.text.wait_for_anchors(anchors)
1217 }
1218
1219 pub fn wait_for_version(&mut self, version: clock::Global) -> impl Future<Output = ()> {
1220 self.text.wait_for_version(version)
1221 }
1222
1223 pub fn set_active_selections(
1224 &mut self,
1225 selections: Arc<[Selection<Anchor>]>,
1226 line_mode: bool,
1227 cx: &mut ModelContext<Self>,
1228 ) {
1229 let lamport_timestamp = self.text.lamport_clock.tick();
1230 self.remote_selections.insert(
1231 self.text.replica_id(),
1232 SelectionSet {
1233 selections: selections.clone(),
1234 lamport_timestamp,
1235 line_mode,
1236 },
1237 );
1238 self.send_operation(
1239 Operation::UpdateSelections {
1240 selections,
1241 line_mode,
1242 lamport_timestamp,
1243 },
1244 cx,
1245 );
1246 }
1247
1248 pub fn remove_active_selections(&mut self, cx: &mut ModelContext<Self>) {
1249 self.set_active_selections(Arc::from([]), false, cx);
1250 }
1251
1252 pub fn set_text<T>(&mut self, text: T, cx: &mut ModelContext<Self>) -> Option<clock::Local>
1253 where
1254 T: Into<Arc<str>>,
1255 {
1256 self.edit([(0..self.len(), text)], None, cx)
1257 }
1258
1259 pub fn edit<I, S, T>(
1260 &mut self,
1261 edits_iter: I,
1262 autoindent_mode: Option<AutoindentMode>,
1263 cx: &mut ModelContext<Self>,
1264 ) -> Option<clock::Local>
1265 where
1266 I: IntoIterator<Item = (Range<S>, T)>,
1267 S: ToOffset,
1268 T: Into<Arc<str>>,
1269 {
1270 // Skip invalid edits and coalesce contiguous ones.
1271 let mut edits: Vec<(Range<usize>, Arc<str>)> = Vec::new();
1272 for (range, new_text) in edits_iter {
1273 let mut range = range.start.to_offset(self)..range.end.to_offset(self);
1274 if range.start > range.end {
1275 mem::swap(&mut range.start, &mut range.end);
1276 }
1277 let new_text = new_text.into();
1278 if !new_text.is_empty() || !range.is_empty() {
1279 if let Some((prev_range, prev_text)) = edits.last_mut() {
1280 if prev_range.end >= range.start {
1281 prev_range.end = cmp::max(prev_range.end, range.end);
1282 *prev_text = format!("{prev_text}{new_text}").into();
1283 } else {
1284 edits.push((range, new_text));
1285 }
1286 } else {
1287 edits.push((range, new_text));
1288 }
1289 }
1290 }
1291 if edits.is_empty() {
1292 return None;
1293 }
1294
1295 self.start_transaction();
1296 self.pending_autoindent.take();
1297 let autoindent_request = autoindent_mode
1298 .and_then(|mode| self.language.as_ref().map(|_| (self.snapshot(), mode)));
1299
1300 let edit_operation = self.text.edit(edits.iter().cloned());
1301 let edit_id = edit_operation.local_timestamp();
1302
1303 if let Some((before_edit, mode)) = autoindent_request {
1304 let (start_columns, is_block_mode) = match mode {
1305 AutoindentMode::Block {
1306 original_indent_columns: start_columns,
1307 } => (start_columns, true),
1308 AutoindentMode::EachLine => (Default::default(), false),
1309 };
1310
1311 let mut delta = 0isize;
1312 let entries = edits
1313 .into_iter()
1314 .enumerate()
1315 .zip(&edit_operation.as_edit().unwrap().new_text)
1316 .map(|((ix, (range, _)), new_text)| {
1317 let new_text_len = new_text.len();
1318 let old_start = range.start.to_point(&before_edit);
1319 let new_start = (delta + range.start as isize) as usize;
1320 delta += new_text_len as isize - (range.end as isize - range.start as isize);
1321
1322 let mut range_of_insertion_to_indent = 0..new_text_len;
1323 let mut first_line_is_new = false;
1324 let mut start_column = None;
1325
1326 // When inserting an entire line at the beginning of an existing line,
1327 // treat the insertion as new.
1328 if new_text.contains('\n')
1329 && old_start.column <= before_edit.indent_size_for_line(old_start.row).len
1330 {
1331 first_line_is_new = true;
1332 }
1333
1334 // When inserting text starting with a newline, avoid auto-indenting the
1335 // previous line.
1336 if new_text[range_of_insertion_to_indent.clone()].starts_with('\n') {
1337 range_of_insertion_to_indent.start += 1;
1338 first_line_is_new = true;
1339 }
1340
1341 // Avoid auto-indenting after the insertion.
1342 if is_block_mode {
1343 start_column = start_columns.get(ix).copied();
1344 if new_text[range_of_insertion_to_indent.clone()].ends_with('\n') {
1345 range_of_insertion_to_indent.end -= 1;
1346 }
1347 }
1348
1349 AutoindentRequestEntry {
1350 first_line_is_new,
1351 original_indent_column: start_column,
1352 indent_size: before_edit.language_indent_size_at(range.start, cx),
1353 range: self.anchor_before(new_start + range_of_insertion_to_indent.start)
1354 ..self.anchor_after(new_start + range_of_insertion_to_indent.end),
1355 }
1356 })
1357 .collect();
1358
1359 self.autoindent_requests.push(Arc::new(AutoindentRequest {
1360 before_edit,
1361 entries,
1362 is_block_mode,
1363 }));
1364 }
1365
1366 self.end_transaction(cx);
1367 self.send_operation(Operation::Buffer(edit_operation), cx);
1368 Some(edit_id)
1369 }
1370
1371 fn did_edit(
1372 &mut self,
1373 old_version: &clock::Global,
1374 was_dirty: bool,
1375 cx: &mut ModelContext<Self>,
1376 ) {
1377 if self.edits_since::<usize>(old_version).next().is_none() {
1378 return;
1379 }
1380
1381 self.reparse(cx);
1382
1383 cx.emit(Event::Edited);
1384 if was_dirty != self.is_dirty() {
1385 cx.emit(Event::DirtyChanged);
1386 }
1387 cx.notify();
1388 }
1389
1390 pub fn apply_ops<I: IntoIterator<Item = Operation>>(
1391 &mut self,
1392 ops: I,
1393 cx: &mut ModelContext<Self>,
1394 ) -> Result<()> {
1395 self.pending_autoindent.take();
1396 let was_dirty = self.is_dirty();
1397 let old_version = self.version.clone();
1398 let mut deferred_ops = Vec::new();
1399 let buffer_ops = ops
1400 .into_iter()
1401 .filter_map(|op| match op {
1402 Operation::Buffer(op) => Some(op),
1403 _ => {
1404 if self.can_apply_op(&op) {
1405 self.apply_op(op, cx);
1406 } else {
1407 deferred_ops.push(op);
1408 }
1409 None
1410 }
1411 })
1412 .collect::<Vec<_>>();
1413 self.text.apply_ops(buffer_ops)?;
1414 self.deferred_ops.insert(deferred_ops);
1415 self.flush_deferred_ops(cx);
1416 self.did_edit(&old_version, was_dirty, cx);
1417 // Notify independently of whether the buffer was edited as the operations could include a
1418 // selection update.
1419 cx.notify();
1420 Ok(())
1421 }
1422
1423 fn flush_deferred_ops(&mut self, cx: &mut ModelContext<Self>) {
1424 let mut deferred_ops = Vec::new();
1425 for op in self.deferred_ops.drain().iter().cloned() {
1426 if self.can_apply_op(&op) {
1427 self.apply_op(op, cx);
1428 } else {
1429 deferred_ops.push(op);
1430 }
1431 }
1432 self.deferred_ops.insert(deferred_ops);
1433 }
1434
1435 fn can_apply_op(&self, operation: &Operation) -> bool {
1436 match operation {
1437 Operation::Buffer(_) => {
1438 unreachable!("buffer operations should never be applied at this layer")
1439 }
1440 Operation::UpdateDiagnostics {
1441 diagnostics: diagnostic_set,
1442 ..
1443 } => diagnostic_set.iter().all(|diagnostic| {
1444 self.text.can_resolve(&diagnostic.range.start)
1445 && self.text.can_resolve(&diagnostic.range.end)
1446 }),
1447 Operation::UpdateSelections { selections, .. } => selections
1448 .iter()
1449 .all(|s| self.can_resolve(&s.start) && self.can_resolve(&s.end)),
1450 Operation::UpdateCompletionTriggers { .. } => true,
1451 }
1452 }
1453
1454 fn apply_op(&mut self, operation: Operation, cx: &mut ModelContext<Self>) {
1455 match operation {
1456 Operation::Buffer(_) => {
1457 unreachable!("buffer operations should never be applied at this layer")
1458 }
1459 Operation::UpdateDiagnostics {
1460 diagnostics: diagnostic_set,
1461 lamport_timestamp,
1462 } => {
1463 let snapshot = self.snapshot();
1464 self.apply_diagnostic_update(
1465 DiagnosticSet::from_sorted_entries(diagnostic_set.iter().cloned(), &snapshot),
1466 lamport_timestamp,
1467 cx,
1468 );
1469 }
1470 Operation::UpdateSelections {
1471 selections,
1472 lamport_timestamp,
1473 line_mode,
1474 } => {
1475 if let Some(set) = self.remote_selections.get(&lamport_timestamp.replica_id) {
1476 if set.lamport_timestamp > lamport_timestamp {
1477 return;
1478 }
1479 }
1480
1481 self.remote_selections.insert(
1482 lamport_timestamp.replica_id,
1483 SelectionSet {
1484 selections,
1485 lamport_timestamp,
1486 line_mode,
1487 },
1488 );
1489 self.text.lamport_clock.observe(lamport_timestamp);
1490 self.selections_update_count += 1;
1491 }
1492 Operation::UpdateCompletionTriggers {
1493 triggers,
1494 lamport_timestamp,
1495 } => {
1496 self.completion_triggers = triggers;
1497 self.text.lamport_clock.observe(lamport_timestamp);
1498 }
1499 }
1500 }
1501
1502 fn apply_diagnostic_update(
1503 &mut self,
1504 diagnostics: DiagnosticSet,
1505 lamport_timestamp: clock::Lamport,
1506 cx: &mut ModelContext<Self>,
1507 ) {
1508 if lamport_timestamp > self.diagnostics_timestamp {
1509 self.diagnostics = diagnostics;
1510 self.diagnostics_timestamp = lamport_timestamp;
1511 self.diagnostics_update_count += 1;
1512 self.text.lamport_clock.observe(lamport_timestamp);
1513 cx.notify();
1514 cx.emit(Event::DiagnosticsUpdated);
1515 }
1516 }
1517
1518 fn send_operation(&mut self, operation: Operation, cx: &mut ModelContext<Self>) {
1519 cx.emit(Event::Operation(operation));
1520 }
1521
1522 pub fn remove_peer(&mut self, replica_id: ReplicaId, cx: &mut ModelContext<Self>) {
1523 self.remote_selections.remove(&replica_id);
1524 cx.notify();
1525 }
1526
1527 pub fn undo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1528 let was_dirty = self.is_dirty();
1529 let old_version = self.version.clone();
1530
1531 if let Some((transaction_id, operation)) = self.text.undo() {
1532 self.send_operation(Operation::Buffer(operation), cx);
1533 self.did_edit(&old_version, was_dirty, cx);
1534 Some(transaction_id)
1535 } else {
1536 None
1537 }
1538 }
1539
1540 pub fn undo_to_transaction(
1541 &mut self,
1542 transaction_id: TransactionId,
1543 cx: &mut ModelContext<Self>,
1544 ) -> bool {
1545 let was_dirty = self.is_dirty();
1546 let old_version = self.version.clone();
1547
1548 let operations = self.text.undo_to_transaction(transaction_id);
1549 let undone = !operations.is_empty();
1550 for operation in operations {
1551 self.send_operation(Operation::Buffer(operation), cx);
1552 }
1553 if undone {
1554 self.did_edit(&old_version, was_dirty, cx)
1555 }
1556 undone
1557 }
1558
1559 pub fn redo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1560 let was_dirty = self.is_dirty();
1561 let old_version = self.version.clone();
1562
1563 if let Some((transaction_id, operation)) = self.text.redo() {
1564 self.send_operation(Operation::Buffer(operation), cx);
1565 self.did_edit(&old_version, was_dirty, cx);
1566 Some(transaction_id)
1567 } else {
1568 None
1569 }
1570 }
1571
1572 pub fn redo_to_transaction(
1573 &mut self,
1574 transaction_id: TransactionId,
1575 cx: &mut ModelContext<Self>,
1576 ) -> bool {
1577 let was_dirty = self.is_dirty();
1578 let old_version = self.version.clone();
1579
1580 let operations = self.text.redo_to_transaction(transaction_id);
1581 let redone = !operations.is_empty();
1582 for operation in operations {
1583 self.send_operation(Operation::Buffer(operation), cx);
1584 }
1585 if redone {
1586 self.did_edit(&old_version, was_dirty, cx)
1587 }
1588 redone
1589 }
1590
1591 pub fn set_completion_triggers(&mut self, triggers: Vec<String>, cx: &mut ModelContext<Self>) {
1592 self.completion_triggers = triggers.clone();
1593 self.completion_triggers_timestamp = self.text.lamport_clock.tick();
1594 self.send_operation(
1595 Operation::UpdateCompletionTriggers {
1596 triggers,
1597 lamport_timestamp: self.completion_triggers_timestamp,
1598 },
1599 cx,
1600 );
1601 cx.notify();
1602 }
1603
1604 pub fn completion_triggers(&self) -> &[String] {
1605 &self.completion_triggers
1606 }
1607}
1608
1609#[cfg(any(test, feature = "test-support"))]
1610impl Buffer {
1611 pub fn set_group_interval(&mut self, group_interval: Duration) {
1612 self.text.set_group_interval(group_interval);
1613 }
1614
1615 pub fn randomly_edit<T>(
1616 &mut self,
1617 rng: &mut T,
1618 old_range_count: usize,
1619 cx: &mut ModelContext<Self>,
1620 ) where
1621 T: rand::Rng,
1622 {
1623 let mut edits: Vec<(Range<usize>, String)> = Vec::new();
1624 let mut last_end = None;
1625 for _ in 0..old_range_count {
1626 if last_end.map_or(false, |last_end| last_end >= self.len()) {
1627 break;
1628 }
1629
1630 let new_start = last_end.map_or(0, |last_end| last_end + 1);
1631 let mut range = self.random_byte_range(new_start, rng);
1632 if rng.gen_bool(0.2) {
1633 mem::swap(&mut range.start, &mut range.end);
1634 }
1635 last_end = Some(range.end);
1636
1637 let new_text_len = rng.gen_range(0..10);
1638 let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).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}