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