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