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