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