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