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