1use crate::diagnostic_set::{DiagnosticEntry, DiagnosticGroup};
2pub use crate::{
3 diagnostic_set::DiagnosticSet,
4 highlight_map::{HighlightId, HighlightMap},
5 proto, BracketPair, Grammar, Language, LanguageConfig, LanguageRegistry, LanguageServerConfig,
6 PLAIN_TEXT,
7};
8use anyhow::{anyhow, Result};
9use clock::ReplicaId;
10use futures::FutureExt as _;
11use gpui::{fonts::HighlightStyle, AppContext, Entity, ModelContext, MutableAppContext, Task};
12use lazy_static::lazy_static;
13use lsp::LanguageServer;
14use parking_lot::Mutex;
15use postage::{prelude::Stream, sink::Sink, watch};
16use similar::{ChangeTag, TextDiff};
17use smol::future::yield_now;
18use std::{
19 any::Any,
20 cell::RefCell,
21 cmp::{self, Ordering},
22 collections::{BTreeMap, HashMap},
23 ffi::OsString,
24 future::Future,
25 iter::{Iterator, Peekable},
26 ops::{Deref, DerefMut, Range},
27 path::{Path, PathBuf},
28 str,
29 sync::Arc,
30 time::{Duration, Instant, SystemTime, UNIX_EPOCH},
31 vec,
32};
33use sum_tree::TreeMap;
34use text::operation_queue::OperationQueue;
35pub use text::{Buffer as TextBuffer, Operation as _, *};
36use theme::SyntaxTheme;
37use tree_sitter::{InputEdit, Parser, QueryCursor, Tree};
38use util::{post_inc, TryFutureExt as _};
39
40#[cfg(any(test, feature = "test-support"))]
41pub use tree_sitter_rust;
42
43pub use lsp::DiagnosticSeverity;
44
45thread_local! {
46 static PARSER: RefCell<Parser> = RefCell::new(Parser::new());
47}
48
49lazy_static! {
50 static ref QUERY_CURSORS: Mutex<Vec<QueryCursor>> = Default::default();
51}
52
53// TODO - Make this configurable
54const INDENT_SIZE: u32 = 4;
55
56pub struct Buffer {
57 text: TextBuffer,
58 file: Option<Box<dyn File>>,
59 saved_version: clock::Global,
60 saved_mtime: SystemTime,
61 language: Option<Arc<Language>>,
62 autoindent_requests: Vec<Arc<AutoindentRequest>>,
63 pending_autoindent: Option<Task<()>>,
64 sync_parse_timeout: Duration,
65 syntax_tree: Mutex<Option<SyntaxTree>>,
66 parsing_in_background: bool,
67 parse_count: usize,
68 remote_selections: TreeMap<ReplicaId, Arc<[Selection<Anchor>]>>,
69 diagnostics: DiagnosticSet,
70 diagnostics_update_count: usize,
71 language_server: Option<LanguageServerState>,
72 deferred_ops: OperationQueue<Operation>,
73 #[cfg(test)]
74 pub(crate) operations: Vec<Operation>,
75}
76
77pub struct BufferSnapshot {
78 text: text::BufferSnapshot,
79 tree: Option<Tree>,
80 diagnostics: HashMap<&'static str, DiagnosticSet>,
81 remote_selections: TreeMap<ReplicaId, Arc<[Selection<Anchor>]>>,
82 diagnostics_update_count: usize,
83 is_parsing: bool,
84 language: Option<Arc<Language>>,
85 parse_count: usize,
86}
87
88#[derive(Clone, Debug, PartialEq, Eq)]
89pub struct Diagnostic {
90 pub code: Option<String>,
91 pub severity: DiagnosticSeverity,
92 pub message: String,
93 pub group_id: usize,
94 pub is_valid: bool,
95 pub is_primary: bool,
96 pub is_disk_based: bool,
97}
98
99struct LanguageServerState {
100 server: Arc<LanguageServer>,
101 latest_snapshot: watch::Sender<Option<LanguageServerSnapshot>>,
102 pending_snapshots: BTreeMap<usize, LanguageServerSnapshot>,
103 next_version: usize,
104 _maintain_server: Task<Option<()>>,
105}
106
107#[derive(Clone)]
108struct LanguageServerSnapshot {
109 buffer_snapshot: text::BufferSnapshot,
110 version: usize,
111 path: Arc<Path>,
112}
113
114#[derive(Clone, Debug)]
115pub enum Operation {
116 Buffer(text::Operation),
117 UpdateDiagnostics {
118 diagnostic_set: Arc<DiagnosticSet>,
119 lamport_timestamp: clock::Lamport,
120 },
121 UpdateSelections {
122 replica_id: ReplicaId,
123 selections: Arc<[Selection<Anchor>]>,
124 lamport_timestamp: clock::Lamport,
125 },
126 RemoveSelections {
127 replica_id: ReplicaId,
128 lamport_timestamp: clock::Lamport,
129 },
130}
131
132#[derive(Clone, Debug, Eq, PartialEq)]
133pub enum Event {
134 Edited,
135 Dirtied,
136 Saved,
137 FileHandleChanged,
138 Reloaded,
139 Reparsed,
140 DiagnosticsUpdated,
141 Closed,
142}
143
144pub trait File {
145 fn worktree_id(&self) -> usize;
146
147 fn entry_id(&self) -> Option<usize>;
148
149 fn mtime(&self) -> SystemTime;
150
151 /// Returns the path of this file relative to the worktree's root directory.
152 fn path(&self) -> &Arc<Path>;
153
154 /// Returns the absolute path of this file.
155 fn abs_path(&self) -> Option<PathBuf>;
156
157 /// Returns the path of this file relative to the worktree's parent directory (this means it
158 /// includes the name of the worktree's root folder).
159 fn full_path(&self) -> PathBuf;
160
161 /// Returns the last component of this handle's absolute path. If this handle refers to the root
162 /// of its worktree, then this method will return the name of the worktree itself.
163 fn file_name(&self) -> Option<OsString>;
164
165 fn is_deleted(&self) -> bool;
166
167 fn save(
168 &self,
169 buffer_id: u64,
170 text: Rope,
171 version: clock::Global,
172 cx: &mut MutableAppContext,
173 ) -> Task<Result<(clock::Global, SystemTime)>>;
174
175 fn load_local(&self, cx: &AppContext) -> Option<Task<Result<String>>>;
176
177 fn buffer_updated(&self, buffer_id: u64, operation: Operation, cx: &mut MutableAppContext);
178
179 fn buffer_removed(&self, buffer_id: u64, cx: &mut MutableAppContext);
180
181 fn boxed_clone(&self) -> Box<dyn File>;
182
183 fn as_any(&self) -> &dyn Any;
184}
185
186struct QueryCursorHandle(Option<QueryCursor>);
187
188#[derive(Clone)]
189struct SyntaxTree {
190 tree: Tree,
191 version: clock::Global,
192}
193
194#[derive(Clone)]
195struct AutoindentRequest {
196 before_edit: BufferSnapshot,
197 edited: Vec<Anchor>,
198 inserted: Option<Vec<Range<Anchor>>>,
199}
200
201#[derive(Debug)]
202struct IndentSuggestion {
203 basis_row: u32,
204 indent: bool,
205}
206
207struct TextProvider<'a>(&'a Rope);
208
209struct BufferChunkHighlights<'a> {
210 captures: tree_sitter::QueryCaptures<'a, 'a, TextProvider<'a>>,
211 next_capture: Option<(tree_sitter::QueryMatch<'a, 'a>, usize)>,
212 stack: Vec<(usize, HighlightId)>,
213 highlight_map: HighlightMap,
214 theme: &'a SyntaxTheme,
215 _query_cursor: QueryCursorHandle,
216}
217
218pub struct BufferChunks<'a> {
219 range: Range<usize>,
220 chunks: rope::Chunks<'a>,
221 diagnostic_endpoints: Peekable<vec::IntoIter<DiagnosticEndpoint>>,
222 error_depth: usize,
223 warning_depth: usize,
224 information_depth: usize,
225 hint_depth: usize,
226 highlights: Option<BufferChunkHighlights<'a>>,
227}
228
229#[derive(Clone, Copy, Debug, Default)]
230pub struct Chunk<'a> {
231 pub text: &'a str,
232 pub highlight_style: Option<HighlightStyle>,
233 pub diagnostic: Option<DiagnosticSeverity>,
234}
235
236pub(crate) struct Diff {
237 base_version: clock::Global,
238 new_text: Arc<str>,
239 changes: Vec<(ChangeTag, usize)>,
240}
241
242#[derive(Clone, Copy)]
243struct DiagnosticEndpoint {
244 offset: usize,
245 is_start: bool,
246 severity: DiagnosticSeverity,
247}
248
249impl Buffer {
250 pub fn new<T: Into<Arc<str>>>(
251 replica_id: ReplicaId,
252 base_text: T,
253 cx: &mut ModelContext<Self>,
254 ) -> Self {
255 Self::build(
256 TextBuffer::new(
257 replica_id,
258 cx.model_id() as u64,
259 History::new(base_text.into()),
260 ),
261 None,
262 )
263 }
264
265 pub fn from_file<T: Into<Arc<str>>>(
266 replica_id: ReplicaId,
267 base_text: T,
268 file: Box<dyn File>,
269 cx: &mut ModelContext<Self>,
270 ) -> Self {
271 Self::build(
272 TextBuffer::new(
273 replica_id,
274 cx.model_id() as u64,
275 History::new(base_text.into()),
276 ),
277 Some(file),
278 )
279 }
280
281 pub fn from_proto(
282 replica_id: ReplicaId,
283 message: proto::Buffer,
284 file: Option<Box<dyn File>>,
285 cx: &mut ModelContext<Self>,
286 ) -> Result<Self> {
287 let mut buffer =
288 text::Buffer::new(replica_id, message.id, History::new(message.content.into()));
289 let ops = message
290 .history
291 .into_iter()
292 .map(|op| text::Operation::Edit(proto::deserialize_edit_operation(op)));
293 buffer.apply_ops(ops)?;
294 let mut this = Self::build(buffer, file);
295 for selection_set in message.selections {
296 this.remote_selections.insert(
297 selection_set.replica_id as ReplicaId,
298 proto::deserialize_selections(selection_set.selections),
299 );
300 }
301 for diagnostic_set in message.diagnostic_sets {
302 this.apply_diagnostic_update(
303 Arc::from(proto::deserialize_diagnostics(diagnostic_set)),
304 cx,
305 );
306 }
307
308 Ok(this)
309 }
310
311 pub fn to_proto(&self) -> proto::Buffer {
312 proto::Buffer {
313 id: self.remote_id(),
314 content: self.text.base_text().to_string(),
315 history: self
316 .text
317 .history()
318 .map(proto::serialize_edit_operation)
319 .collect(),
320 selections: self
321 .remote_selections
322 .iter()
323 .map(|(replica_id, selections)| proto::SelectionSet {
324 replica_id: *replica_id as u32,
325 selections: proto::serialize_selections(selections),
326 })
327 .collect(),
328 diagnostics: proto::serialize_diagnostic_set(self.diagnostics.iter()),
329 }
330 }
331
332 pub fn with_language(
333 mut self,
334 language: Option<Arc<Language>>,
335 language_server: Option<Arc<LanguageServer>>,
336 cx: &mut ModelContext<Self>,
337 ) -> Self {
338 self.set_language(language, language_server, cx);
339 self
340 }
341
342 fn build(buffer: TextBuffer, file: Option<Box<dyn File>>) -> Self {
343 let saved_mtime;
344 if let Some(file) = file.as_ref() {
345 saved_mtime = file.mtime();
346 } else {
347 saved_mtime = UNIX_EPOCH;
348 }
349
350 Self {
351 saved_mtime,
352 saved_version: buffer.version(),
353 text: buffer,
354 file,
355 syntax_tree: Mutex::new(None),
356 parsing_in_background: false,
357 parse_count: 0,
358 sync_parse_timeout: Duration::from_millis(1),
359 autoindent_requests: Default::default(),
360 pending_autoindent: Default::default(),
361 language: None,
362 remote_selections: Default::default(),
363 diagnostics: Default::default(),
364 diagnostics_update_count: 0,
365 language_server: None,
366 deferred_ops: OperationQueue::new(),
367 #[cfg(test)]
368 operations: Default::default(),
369 }
370 }
371
372 pub fn snapshot(&self) -> BufferSnapshot {
373 BufferSnapshot {
374 text: self.text.snapshot(),
375 tree: self.syntax_tree(),
376 remote_selections: self.remote_selections.clone(),
377 diagnostics: self.diagnostics.clone(),
378 diagnostics_update_count: self.diagnostics_update_count,
379 is_parsing: self.parsing_in_background,
380 language: self.language.clone(),
381 parse_count: self.parse_count,
382 }
383 }
384
385 pub fn file(&self) -> Option<&dyn File> {
386 self.file.as_deref()
387 }
388
389 pub fn save(
390 &mut self,
391 cx: &mut ModelContext<Self>,
392 ) -> Result<Task<Result<(clock::Global, SystemTime)>>> {
393 let file = self
394 .file
395 .as_ref()
396 .ok_or_else(|| anyhow!("buffer has no file"))?;
397 let text = self.as_rope().clone();
398 let version = self.version();
399 let save = file.save(self.remote_id(), text, version, cx.as_mut());
400 Ok(cx.spawn(|this, mut cx| async move {
401 let (version, mtime) = save.await?;
402 this.update(&mut cx, |this, cx| {
403 this.did_save(version.clone(), mtime, None, cx);
404 });
405 Ok((version, mtime))
406 }))
407 }
408
409 pub fn set_language(
410 &mut self,
411 language: Option<Arc<Language>>,
412 language_server: Option<Arc<lsp::LanguageServer>>,
413 cx: &mut ModelContext<Self>,
414 ) {
415 self.language = language;
416 self.language_server = if let Some(server) = language_server {
417 let (latest_snapshot_tx, mut latest_snapshot_rx) = watch::channel();
418 Some(LanguageServerState {
419 latest_snapshot: latest_snapshot_tx,
420 pending_snapshots: Default::default(),
421 next_version: 0,
422 server: server.clone(),
423 _maintain_server: cx.background().spawn(
424 async move {
425 let mut prev_snapshot: Option<LanguageServerSnapshot> = None;
426 while let Some(snapshot) = latest_snapshot_rx.recv().await {
427 if let Some(snapshot) = snapshot {
428 let uri = lsp::Url::from_file_path(&snapshot.path).unwrap();
429 if let Some(prev_snapshot) = prev_snapshot {
430 let changes = lsp::DidChangeTextDocumentParams {
431 text_document: lsp::VersionedTextDocumentIdentifier::new(
432 uri,
433 snapshot.version as i32,
434 ),
435 content_changes: snapshot
436 .buffer_snapshot
437 .edits_since::<(PointUtf16, usize)>(
438 prev_snapshot.buffer_snapshot.version(),
439 )
440 .map(|edit| {
441 let edit_start = edit.new.start.0;
442 let edit_end = edit_start
443 + (edit.old.end.0 - edit.old.start.0);
444 let new_text = snapshot
445 .buffer_snapshot
446 .text_for_range(
447 edit.new.start.1..edit.new.end.1,
448 )
449 .collect();
450 lsp::TextDocumentContentChangeEvent {
451 range: Some(lsp::Range::new(
452 lsp::Position::new(
453 edit_start.row,
454 edit_start.column,
455 ),
456 lsp::Position::new(
457 edit_end.row,
458 edit_end.column,
459 ),
460 )),
461 range_length: None,
462 text: new_text,
463 }
464 })
465 .collect(),
466 };
467 server
468 .notify::<lsp::notification::DidChangeTextDocument>(changes)
469 .await?;
470 } else {
471 server
472 .notify::<lsp::notification::DidOpenTextDocument>(
473 lsp::DidOpenTextDocumentParams {
474 text_document: lsp::TextDocumentItem::new(
475 uri,
476 Default::default(),
477 snapshot.version as i32,
478 snapshot.buffer_snapshot.text().to_string(),
479 ),
480 },
481 )
482 .await?;
483 }
484
485 prev_snapshot = Some(snapshot);
486 }
487 }
488 Ok(())
489 }
490 .log_err(),
491 ),
492 })
493 } else {
494 None
495 };
496
497 self.reparse(cx);
498 self.update_language_server();
499 }
500
501 pub fn did_save(
502 &mut self,
503 version: clock::Global,
504 mtime: SystemTime,
505 new_file: Option<Box<dyn File>>,
506 cx: &mut ModelContext<Self>,
507 ) {
508 self.saved_mtime = mtime;
509 self.saved_version = version;
510 if let Some(new_file) = new_file {
511 self.file = Some(new_file);
512 }
513 if let Some(state) = &self.language_server {
514 cx.background()
515 .spawn(
516 state
517 .server
518 .notify::<lsp::notification::DidSaveTextDocument>(
519 lsp::DidSaveTextDocumentParams {
520 text_document: lsp::TextDocumentIdentifier {
521 uri: lsp::Url::from_file_path(
522 self.file.as_ref().unwrap().abs_path().unwrap(),
523 )
524 .unwrap(),
525 },
526 text: None,
527 },
528 ),
529 )
530 .detach()
531 }
532 cx.emit(Event::Saved);
533 }
534
535 pub fn file_updated(
536 &mut self,
537 new_file: Box<dyn File>,
538 cx: &mut ModelContext<Self>,
539 ) -> Option<Task<()>> {
540 let old_file = self.file.as_ref()?;
541 let mut file_changed = false;
542 let mut task = None;
543
544 if new_file.path() != old_file.path() {
545 file_changed = true;
546 }
547
548 if new_file.is_deleted() {
549 if !old_file.is_deleted() {
550 file_changed = true;
551 if !self.is_dirty() {
552 cx.emit(Event::Dirtied);
553 }
554 }
555 } else {
556 let new_mtime = new_file.mtime();
557 if new_mtime != old_file.mtime() {
558 file_changed = true;
559
560 if !self.is_dirty() {
561 task = Some(cx.spawn(|this, mut cx| {
562 async move {
563 let new_text = this.read_with(&cx, |this, cx| {
564 this.file.as_ref().and_then(|file| file.load_local(cx))
565 });
566 if let Some(new_text) = new_text {
567 let new_text = new_text.await?;
568 let diff = this
569 .read_with(&cx, |this, cx| this.diff(new_text.into(), cx))
570 .await;
571 this.update(&mut cx, |this, cx| {
572 if this.apply_diff(diff, cx) {
573 this.saved_version = this.version();
574 this.saved_mtime = new_mtime;
575 cx.emit(Event::Reloaded);
576 }
577 });
578 }
579 Ok(())
580 }
581 .log_err()
582 .map(drop)
583 }));
584 }
585 }
586 }
587
588 if file_changed {
589 cx.emit(Event::FileHandleChanged);
590 }
591 self.file = Some(new_file);
592 task
593 }
594
595 pub fn close(&mut self, cx: &mut ModelContext<Self>) {
596 cx.emit(Event::Closed);
597 }
598
599 pub fn language(&self) -> Option<&Arc<Language>> {
600 self.language.as_ref()
601 }
602
603 pub fn parse_count(&self) -> usize {
604 self.parse_count
605 }
606
607 pub fn diagnostics_update_count(&self) -> usize {
608 self.diagnostics_update_count
609 }
610
611 pub(crate) fn syntax_tree(&self) -> Option<Tree> {
612 if let Some(syntax_tree) = self.syntax_tree.lock().as_mut() {
613 self.interpolate_tree(syntax_tree);
614 Some(syntax_tree.tree.clone())
615 } else {
616 None
617 }
618 }
619
620 #[cfg(any(test, feature = "test-support"))]
621 pub fn is_parsing(&self) -> bool {
622 self.parsing_in_background
623 }
624
625 #[cfg(test)]
626 pub fn set_sync_parse_timeout(&mut self, timeout: Duration) {
627 self.sync_parse_timeout = timeout;
628 }
629
630 fn reparse(&mut self, cx: &mut ModelContext<Self>) -> bool {
631 if self.parsing_in_background {
632 return false;
633 }
634
635 if let Some(grammar) = self.grammar().cloned() {
636 let old_tree = self.syntax_tree();
637 let text = self.as_rope().clone();
638 let parsed_version = self.version();
639 let parse_task = cx.background().spawn({
640 let grammar = grammar.clone();
641 async move { Self::parse_text(&text, old_tree, &grammar) }
642 });
643
644 match cx
645 .background()
646 .block_with_timeout(self.sync_parse_timeout, parse_task)
647 {
648 Ok(new_tree) => {
649 self.did_finish_parsing(new_tree, parsed_version, cx);
650 return true;
651 }
652 Err(parse_task) => {
653 self.parsing_in_background = true;
654 cx.spawn(move |this, mut cx| async move {
655 let new_tree = parse_task.await;
656 this.update(&mut cx, move |this, cx| {
657 let grammar_changed = this
658 .grammar()
659 .map_or(true, |curr_grammar| !Arc::ptr_eq(&grammar, curr_grammar));
660 let parse_again = this.version.gt(&parsed_version) || grammar_changed;
661 this.parsing_in_background = false;
662 this.did_finish_parsing(new_tree, parsed_version, cx);
663
664 if parse_again && this.reparse(cx) {
665 return;
666 }
667 });
668 })
669 .detach();
670 }
671 }
672 }
673 false
674 }
675
676 fn parse_text(text: &Rope, old_tree: Option<Tree>, grammar: &Grammar) -> Tree {
677 PARSER.with(|parser| {
678 let mut parser = parser.borrow_mut();
679 parser
680 .set_language(grammar.ts_language)
681 .expect("incompatible grammar");
682 let mut chunks = text.chunks_in_range(0..text.len());
683 let tree = parser
684 .parse_with(
685 &mut move |offset, _| {
686 chunks.seek(offset);
687 chunks.next().unwrap_or("").as_bytes()
688 },
689 old_tree.as_ref(),
690 )
691 .unwrap();
692 tree
693 })
694 }
695
696 fn interpolate_tree(&self, tree: &mut SyntaxTree) {
697 for edit in self.edits_since::<(usize, Point)>(&tree.version) {
698 let (bytes, lines) = edit.flatten();
699 tree.tree.edit(&InputEdit {
700 start_byte: bytes.new.start,
701 old_end_byte: bytes.new.start + bytes.old.len(),
702 new_end_byte: bytes.new.end,
703 start_position: lines.new.start.to_ts_point(),
704 old_end_position: (lines.new.start + (lines.old.end - lines.old.start))
705 .to_ts_point(),
706 new_end_position: lines.new.end.to_ts_point(),
707 });
708 }
709 tree.version = self.version();
710 }
711
712 fn did_finish_parsing(
713 &mut self,
714 tree: Tree,
715 version: clock::Global,
716 cx: &mut ModelContext<Self>,
717 ) {
718 self.parse_count += 1;
719 *self.syntax_tree.lock() = Some(SyntaxTree { tree, version });
720 self.request_autoindent(cx);
721 cx.emit(Event::Reparsed);
722 cx.notify();
723 }
724
725 pub fn all_diagnostics<'a>(&'a self) -> impl 'a + Iterator<Item = &'a DiagnosticEntry<Anchor>> {
726 self.diagnostics.iter()
727 }
728
729 pub fn update_diagnostics(
730 &mut self,
731 version: Option<i32>,
732 mut diagnostics: Vec<DiagnosticEntry<PointUtf16>>,
733 cx: &mut ModelContext<Self>,
734 ) -> Result<Operation> {
735 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
736 Ordering::Equal
737 .then_with(|| b.is_primary.cmp(&a.is_primary))
738 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
739 .then_with(|| a.severity.cmp(&b.severity))
740 .then_with(|| a.message.cmp(&b.message))
741 }
742
743 diagnostics.sort_unstable_by(|a, b| {
744 Ordering::Equal
745 .then_with(|| a.range.start.cmp(&b.range.start))
746 .then_with(|| b.range.end.cmp(&a.range.end))
747 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
748 });
749
750 let version = version.map(|version| version as usize);
751 let content = if let Some(version) = version {
752 let language_server = self.language_server.as_mut().unwrap();
753 language_server
754 .pending_snapshots
755 .retain(|&v, _| v >= version);
756 let snapshot = language_server
757 .pending_snapshots
758 .get(&version)
759 .ok_or_else(|| anyhow!("missing snapshot"))?;
760 &snapshot.buffer_snapshot
761 } else {
762 self.deref()
763 };
764
765 let mut edits_since_save = content
766 .edits_since::<PointUtf16>(&self.saved_version)
767 .peekable();
768 let mut last_edit_old_end = PointUtf16::zero();
769 let mut last_edit_new_end = PointUtf16::zero();
770 let mut ix = 0;
771 'outer: while ix < diagnostics.len() {
772 let entry = &mut diagnostics[ix];
773 let mut start = entry.range.start;
774 let mut end = entry.range.end;
775
776 // Some diagnostics are based on files on disk instead of buffers'
777 // current contents. Adjust these diagnostics' ranges to reflect
778 // any unsaved edits.
779 if entry.diagnostic.is_disk_based {
780 while let Some(edit) = edits_since_save.peek() {
781 if edit.old.end <= start {
782 last_edit_old_end = edit.old.end;
783 last_edit_new_end = edit.new.end;
784 edits_since_save.next();
785 } else if edit.old.start <= end && edit.old.end >= start {
786 diagnostics.remove(ix);
787 continue 'outer;
788 } else {
789 break;
790 }
791 }
792
793 start = last_edit_new_end + (start - last_edit_old_end);
794 end = last_edit_new_end + (end - last_edit_old_end);
795 }
796
797 entry.range = content.clip_point_utf16(start, Bias::Left)
798 ..content.clip_point_utf16(end, Bias::Right);
799
800 // Expand empty ranges by one character
801 if entry.range.start == entry.range.end {
802 entry.range.end.column += 1;
803 entry.range.end = content.clip_point_utf16(entry.range.end, Bias::Right);
804 if entry.range.start == entry.range.end && entry.range.end.column > 0 {
805 entry.range.start.column -= 1;
806 entry.range.start = content.clip_point_utf16(entry.range.start, Bias::Left);
807 }
808 }
809 ix += 1;
810 }
811 drop(edits_since_save);
812 self.diagnostics = DiagnosticSet::new(diagnostics, content);
813 self.diagnostics_update_count += 1;
814 cx.notify();
815 cx.emit(Event::DiagnosticsUpdated);
816 Ok(Operation::UpdateDiagnostics {
817 diagnostics: Arc::from(self.diagnostics.iter().cloned().collect::<Vec<_>>()),
818 lamport_timestamp: self.text.lamport_clock.tick(),
819 })
820 }
821
822 fn request_autoindent(&mut self, cx: &mut ModelContext<Self>) {
823 if let Some(indent_columns) = self.compute_autoindents() {
824 let indent_columns = cx.background().spawn(indent_columns);
825 match cx
826 .background()
827 .block_with_timeout(Duration::from_micros(500), indent_columns)
828 {
829 Ok(indent_columns) => self.apply_autoindents(indent_columns, cx),
830 Err(indent_columns) => {
831 self.pending_autoindent = Some(cx.spawn(|this, mut cx| async move {
832 let indent_columns = indent_columns.await;
833 this.update(&mut cx, |this, cx| {
834 this.apply_autoindents(indent_columns, cx);
835 });
836 }));
837 }
838 }
839 }
840 }
841
842 fn compute_autoindents(&self) -> Option<impl Future<Output = BTreeMap<u32, u32>>> {
843 let max_rows_between_yields = 100;
844 let snapshot = self.snapshot();
845 if snapshot.language.is_none()
846 || snapshot.tree.is_none()
847 || self.autoindent_requests.is_empty()
848 {
849 return None;
850 }
851
852 let autoindent_requests = self.autoindent_requests.clone();
853 Some(async move {
854 let mut indent_columns = BTreeMap::new();
855 for request in autoindent_requests {
856 let old_to_new_rows = request
857 .edited
858 .iter()
859 .map(|anchor| anchor.summary::<Point>(&request.before_edit).row)
860 .zip(
861 request
862 .edited
863 .iter()
864 .map(|anchor| anchor.summary::<Point>(&snapshot).row),
865 )
866 .collect::<BTreeMap<u32, u32>>();
867
868 let mut old_suggestions = HashMap::<u32, u32>::default();
869 let old_edited_ranges =
870 contiguous_ranges(old_to_new_rows.keys().copied(), max_rows_between_yields);
871 for old_edited_range in old_edited_ranges {
872 let suggestions = request
873 .before_edit
874 .suggest_autoindents(old_edited_range.clone())
875 .into_iter()
876 .flatten();
877 for (old_row, suggestion) in old_edited_range.zip(suggestions) {
878 let indentation_basis = old_to_new_rows
879 .get(&suggestion.basis_row)
880 .and_then(|from_row| old_suggestions.get(from_row).copied())
881 .unwrap_or_else(|| {
882 request
883 .before_edit
884 .indent_column_for_line(suggestion.basis_row)
885 });
886 let delta = if suggestion.indent { INDENT_SIZE } else { 0 };
887 old_suggestions.insert(
888 *old_to_new_rows.get(&old_row).unwrap(),
889 indentation_basis + delta,
890 );
891 }
892 yield_now().await;
893 }
894
895 // At this point, old_suggestions contains the suggested indentation for all edited lines with respect to the state of the
896 // buffer before the edit, but keyed by the row for these lines after the edits were applied.
897 let new_edited_row_ranges =
898 contiguous_ranges(old_to_new_rows.values().copied(), max_rows_between_yields);
899 for new_edited_row_range in new_edited_row_ranges {
900 let suggestions = snapshot
901 .suggest_autoindents(new_edited_row_range.clone())
902 .into_iter()
903 .flatten();
904 for (new_row, suggestion) in new_edited_row_range.zip(suggestions) {
905 let delta = if suggestion.indent { INDENT_SIZE } else { 0 };
906 let new_indentation = indent_columns
907 .get(&suggestion.basis_row)
908 .copied()
909 .unwrap_or_else(|| {
910 snapshot.indent_column_for_line(suggestion.basis_row)
911 })
912 + delta;
913 if old_suggestions
914 .get(&new_row)
915 .map_or(true, |old_indentation| new_indentation != *old_indentation)
916 {
917 indent_columns.insert(new_row, new_indentation);
918 }
919 }
920 yield_now().await;
921 }
922
923 if let Some(inserted) = request.inserted.as_ref() {
924 let inserted_row_ranges = contiguous_ranges(
925 inserted
926 .iter()
927 .map(|range| range.to_point(&snapshot))
928 .flat_map(|range| range.start.row..range.end.row + 1),
929 max_rows_between_yields,
930 );
931 for inserted_row_range in inserted_row_ranges {
932 let suggestions = snapshot
933 .suggest_autoindents(inserted_row_range.clone())
934 .into_iter()
935 .flatten();
936 for (row, suggestion) in inserted_row_range.zip(suggestions) {
937 let delta = if suggestion.indent { INDENT_SIZE } else { 0 };
938 let new_indentation = indent_columns
939 .get(&suggestion.basis_row)
940 .copied()
941 .unwrap_or_else(|| {
942 snapshot.indent_column_for_line(suggestion.basis_row)
943 })
944 + delta;
945 indent_columns.insert(row, new_indentation);
946 }
947 yield_now().await;
948 }
949 }
950 }
951 indent_columns
952 })
953 }
954
955 fn apply_autoindents(
956 &mut self,
957 indent_columns: BTreeMap<u32, u32>,
958 cx: &mut ModelContext<Self>,
959 ) {
960 self.start_transaction();
961 for (row, indent_column) in &indent_columns {
962 self.set_indent_column_for_line(*row, *indent_column, cx);
963 }
964 self.end_transaction(cx);
965 }
966
967 fn set_indent_column_for_line(&mut self, row: u32, column: u32, cx: &mut ModelContext<Self>) {
968 let current_column = self.indent_column_for_line(row);
969 if column > current_column {
970 let offset = Point::new(row, 0).to_offset(&*self);
971 self.edit(
972 [offset..offset],
973 " ".repeat((column - current_column) as usize),
974 cx,
975 );
976 } else if column < current_column {
977 self.edit(
978 [Point::new(row, 0)..Point::new(row, current_column - column)],
979 "",
980 cx,
981 );
982 }
983 }
984
985 pub(crate) fn diff(&self, new_text: Arc<str>, cx: &AppContext) -> Task<Diff> {
986 // TODO: it would be nice to not allocate here.
987 let old_text = self.text();
988 let base_version = self.version();
989 cx.background().spawn(async move {
990 let changes = TextDiff::from_lines(old_text.as_str(), new_text.as_ref())
991 .iter_all_changes()
992 .map(|c| (c.tag(), c.value().len()))
993 .collect::<Vec<_>>();
994 Diff {
995 base_version,
996 new_text,
997 changes,
998 }
999 })
1000 }
1001
1002 pub(crate) fn apply_diff(&mut self, diff: Diff, cx: &mut ModelContext<Self>) -> bool {
1003 if self.version == diff.base_version {
1004 self.start_transaction();
1005 let mut offset = 0;
1006 for (tag, len) in diff.changes {
1007 let range = offset..(offset + len);
1008 match tag {
1009 ChangeTag::Equal => offset += len,
1010 ChangeTag::Delete => self.edit(Some(range), "", cx),
1011 ChangeTag::Insert => {
1012 self.edit(Some(offset..offset), &diff.new_text[range], cx);
1013 offset += len;
1014 }
1015 }
1016 }
1017 self.end_transaction(cx);
1018 true
1019 } else {
1020 false
1021 }
1022 }
1023
1024 pub fn is_dirty(&self) -> bool {
1025 !self.saved_version.ge(&self.version)
1026 || self.file.as_ref().map_or(false, |file| file.is_deleted())
1027 }
1028
1029 pub fn has_conflict(&self) -> bool {
1030 !self.saved_version.ge(&self.version)
1031 && self
1032 .file
1033 .as_ref()
1034 .map_or(false, |file| file.mtime() > self.saved_mtime)
1035 }
1036
1037 pub fn subscribe(&mut self) -> Subscription {
1038 self.text.subscribe()
1039 }
1040
1041 pub fn start_transaction(&mut self) -> Option<TransactionId> {
1042 self.start_transaction_at(Instant::now())
1043 }
1044
1045 pub fn start_transaction_at(&mut self, now: Instant) -> Option<TransactionId> {
1046 self.text.start_transaction_at(now)
1047 }
1048
1049 pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1050 self.end_transaction_at(Instant::now(), cx)
1051 }
1052
1053 pub fn end_transaction_at(
1054 &mut self,
1055 now: Instant,
1056 cx: &mut ModelContext<Self>,
1057 ) -> Option<TransactionId> {
1058 if let Some((transaction_id, start_version)) = self.text.end_transaction_at(now) {
1059 let was_dirty = start_version != self.saved_version;
1060 self.did_edit(&start_version, was_dirty, cx);
1061 Some(transaction_id)
1062 } else {
1063 None
1064 }
1065 }
1066
1067 pub fn set_active_selections(
1068 &mut self,
1069 selections: Arc<[Selection<Anchor>]>,
1070 cx: &mut ModelContext<Self>,
1071 ) {
1072 let lamport_timestamp = self.text.lamport_clock.tick();
1073 self.remote_selections
1074 .insert(self.text.replica_id(), selections.clone());
1075 self.send_operation(
1076 Operation::UpdateSelections {
1077 replica_id: self.text.replica_id(),
1078 selections,
1079 lamport_timestamp,
1080 },
1081 cx,
1082 );
1083 }
1084
1085 pub fn remove_active_selections(&mut self, cx: &mut ModelContext<Self>) {
1086 let lamport_timestamp = self.text.lamport_clock.tick();
1087 self.send_operation(
1088 Operation::RemoveSelections {
1089 replica_id: self.text.replica_id(),
1090 lamport_timestamp,
1091 },
1092 cx,
1093 );
1094 }
1095
1096 fn update_language_server(&mut self) {
1097 let language_server = if let Some(language_server) = self.language_server.as_mut() {
1098 language_server
1099 } else {
1100 return;
1101 };
1102 let abs_path = self
1103 .file
1104 .as_ref()
1105 .map_or(Path::new("/").to_path_buf(), |file| {
1106 file.abs_path().unwrap()
1107 });
1108
1109 let version = post_inc(&mut language_server.next_version);
1110 let snapshot = LanguageServerSnapshot {
1111 buffer_snapshot: self.text.snapshot(),
1112 version,
1113 path: Arc::from(abs_path),
1114 };
1115 language_server
1116 .pending_snapshots
1117 .insert(version, snapshot.clone());
1118 let _ = language_server
1119 .latest_snapshot
1120 .blocking_send(Some(snapshot));
1121 }
1122
1123 pub fn edit<I, S, T>(&mut self, ranges_iter: I, new_text: T, cx: &mut ModelContext<Self>)
1124 where
1125 I: IntoIterator<Item = Range<S>>,
1126 S: ToOffset,
1127 T: Into<String>,
1128 {
1129 self.edit_internal(ranges_iter, new_text, false, cx)
1130 }
1131
1132 pub fn edit_with_autoindent<I, S, T>(
1133 &mut self,
1134 ranges_iter: I,
1135 new_text: T,
1136 cx: &mut ModelContext<Self>,
1137 ) where
1138 I: IntoIterator<Item = Range<S>>,
1139 S: ToOffset,
1140 T: Into<String>,
1141 {
1142 self.edit_internal(ranges_iter, new_text, true, cx)
1143 }
1144
1145 pub fn edit_internal<I, S, T>(
1146 &mut self,
1147 ranges_iter: I,
1148 new_text: T,
1149 autoindent: bool,
1150 cx: &mut ModelContext<Self>,
1151 ) where
1152 I: IntoIterator<Item = Range<S>>,
1153 S: ToOffset,
1154 T: Into<String>,
1155 {
1156 let new_text = new_text.into();
1157
1158 // Skip invalid ranges and coalesce contiguous ones.
1159 let mut ranges: Vec<Range<usize>> = Vec::new();
1160 for range in ranges_iter {
1161 let range = range.start.to_offset(self)..range.end.to_offset(self);
1162 if !new_text.is_empty() || !range.is_empty() {
1163 if let Some(prev_range) = ranges.last_mut() {
1164 if prev_range.end >= range.start {
1165 prev_range.end = cmp::max(prev_range.end, range.end);
1166 } else {
1167 ranges.push(range);
1168 }
1169 } else {
1170 ranges.push(range);
1171 }
1172 }
1173 }
1174 if ranges.is_empty() {
1175 return;
1176 }
1177
1178 self.start_transaction();
1179 self.pending_autoindent.take();
1180 let autoindent_request = if autoindent && self.language.is_some() {
1181 let before_edit = self.snapshot();
1182 let edited = ranges
1183 .iter()
1184 .filter_map(|range| {
1185 let start = range.start.to_point(self);
1186 if new_text.starts_with('\n') && start.column == self.line_len(start.row) {
1187 None
1188 } else {
1189 Some(self.anchor_before(range.start))
1190 }
1191 })
1192 .collect();
1193 Some((before_edit, edited))
1194 } else {
1195 None
1196 };
1197
1198 let first_newline_ix = new_text.find('\n');
1199 let new_text_len = new_text.len();
1200
1201 let edit = self.text.edit(ranges.iter().cloned(), new_text);
1202
1203 if let Some((before_edit, edited)) = autoindent_request {
1204 let mut inserted = None;
1205 if let Some(first_newline_ix) = first_newline_ix {
1206 let mut delta = 0isize;
1207 inserted = Some(
1208 ranges
1209 .iter()
1210 .map(|range| {
1211 let start =
1212 (delta + range.start as isize) as usize + first_newline_ix + 1;
1213 let end = (delta + range.start as isize) as usize + new_text_len;
1214 delta +=
1215 (range.end as isize - range.start as isize) + new_text_len as isize;
1216 self.anchor_before(start)..self.anchor_after(end)
1217 })
1218 .collect(),
1219 );
1220 }
1221
1222 self.autoindent_requests.push(Arc::new(AutoindentRequest {
1223 before_edit,
1224 edited,
1225 inserted,
1226 }));
1227 }
1228
1229 self.end_transaction(cx);
1230 self.send_operation(Operation::Buffer(text::Operation::Edit(edit)), cx);
1231 }
1232
1233 fn did_edit(
1234 &mut self,
1235 old_version: &clock::Global,
1236 was_dirty: bool,
1237 cx: &mut ModelContext<Self>,
1238 ) {
1239 if self.edits_since::<usize>(old_version).next().is_none() {
1240 return;
1241 }
1242
1243 self.reparse(cx);
1244 self.update_language_server();
1245
1246 cx.emit(Event::Edited);
1247 if !was_dirty {
1248 cx.emit(Event::Dirtied);
1249 }
1250 cx.notify();
1251 }
1252
1253 fn grammar(&self) -> Option<&Arc<Grammar>> {
1254 self.language.as_ref().and_then(|l| l.grammar.as_ref())
1255 }
1256
1257 pub fn apply_ops<I: IntoIterator<Item = Operation>>(
1258 &mut self,
1259 ops: I,
1260 cx: &mut ModelContext<Self>,
1261 ) -> Result<()> {
1262 self.pending_autoindent.take();
1263 let was_dirty = self.is_dirty();
1264 let old_version = self.version.clone();
1265 let mut deferred_ops = Vec::new();
1266 let buffer_ops = ops
1267 .into_iter()
1268 .filter_map(|op| match op {
1269 Operation::Buffer(op) => Some(op),
1270 _ => {
1271 if self.can_apply_op(&op) {
1272 self.apply_op(op, cx);
1273 } else {
1274 deferred_ops.push(op);
1275 }
1276 None
1277 }
1278 })
1279 .collect::<Vec<_>>();
1280 self.text.apply_ops(buffer_ops)?;
1281 self.flush_deferred_ops(cx);
1282 self.did_edit(&old_version, was_dirty, cx);
1283 // Notify independently of whether the buffer was edited as the operations could include a
1284 // selection update.
1285 cx.notify();
1286 Ok(())
1287 }
1288
1289 fn flush_deferred_ops(&mut self, cx: &mut ModelContext<Self>) {
1290 let mut deferred_ops = Vec::new();
1291 for op in self.deferred_ops.drain().iter().cloned() {
1292 if self.can_apply_op(&op) {
1293 self.apply_op(op, cx);
1294 } else {
1295 deferred_ops.push(op);
1296 }
1297 }
1298 self.deferred_ops.insert(deferred_ops);
1299 }
1300
1301 fn can_apply_op(&self, operation: &Operation) -> bool {
1302 match operation {
1303 Operation::Buffer(_) => {
1304 unreachable!("buffer operations should never be applied at this layer")
1305 }
1306 Operation::UpdateDiagnostics { diagnostics, .. } => {
1307 diagnostics.iter().all(|diagnostic| {
1308 self.text.can_resolve(&diagnostic.range.start)
1309 && self.text.can_resolve(&diagnostic.range.end)
1310 })
1311 }
1312 Operation::UpdateSelections { selections, .. } => selections
1313 .iter()
1314 .all(|s| self.can_resolve(&s.start) && self.can_resolve(&s.end)),
1315 Operation::RemoveSelections { .. } => true,
1316 }
1317 }
1318
1319 fn apply_op(&mut self, operation: Operation, cx: &mut ModelContext<Self>) {
1320 match operation {
1321 Operation::Buffer(_) => {
1322 unreachable!("buffer operations should never be applied at this layer")
1323 }
1324 Operation::UpdateDiagnostics { diagnostics, .. } => {
1325 self.apply_diagnostic_update(diagnostics, cx);
1326 }
1327 Operation::UpdateSelections {
1328 replica_id,
1329 selections,
1330 lamport_timestamp,
1331 } => {
1332 self.remote_selections.insert(replica_id, selections);
1333 self.text.lamport_clock.observe(lamport_timestamp);
1334 }
1335 Operation::RemoveSelections {
1336 replica_id,
1337 lamport_timestamp,
1338 } => {
1339 self.remote_selections.remove(&replica_id);
1340 self.text.lamport_clock.observe(lamport_timestamp);
1341 }
1342 }
1343 }
1344
1345 fn apply_diagnostic_update(
1346 &mut self,
1347 diagnostics: Arc<[DiagnosticEntry<Anchor>]>,
1348 cx: &mut ModelContext<Self>,
1349 ) {
1350 self.diagnostics = DiagnosticSet::from_sorted_entries(diagnostics.iter().cloned(), self);
1351 self.diagnostics_update_count += 1;
1352 cx.notify();
1353 }
1354
1355 #[cfg(not(test))]
1356 pub fn send_operation(&mut self, operation: Operation, cx: &mut ModelContext<Self>) {
1357 if let Some(file) = &self.file {
1358 file.buffer_updated(self.remote_id(), operation, cx.as_mut());
1359 }
1360 }
1361
1362 #[cfg(test)]
1363 pub fn send_operation(&mut self, operation: Operation, _: &mut ModelContext<Self>) {
1364 self.operations.push(operation);
1365 }
1366
1367 pub fn remove_peer(&mut self, replica_id: ReplicaId, cx: &mut ModelContext<Self>) {
1368 self.remote_selections.remove(&replica_id);
1369 cx.notify();
1370 }
1371
1372 pub fn undo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1373 let was_dirty = self.is_dirty();
1374 let old_version = self.version.clone();
1375
1376 if let Some((transaction_id, operation)) = self.text.undo() {
1377 self.send_operation(Operation::Buffer(operation), cx);
1378 self.did_edit(&old_version, was_dirty, cx);
1379 Some(transaction_id)
1380 } else {
1381 None
1382 }
1383 }
1384
1385 pub fn undo_transaction(
1386 &mut self,
1387 transaction_id: TransactionId,
1388 cx: &mut ModelContext<Self>,
1389 ) -> bool {
1390 let was_dirty = self.is_dirty();
1391 let old_version = self.version.clone();
1392
1393 if let Some(operation) = self.text.undo_transaction(transaction_id) {
1394 self.send_operation(Operation::Buffer(operation), cx);
1395 self.did_edit(&old_version, was_dirty, cx);
1396 true
1397 } else {
1398 false
1399 }
1400 }
1401
1402 pub fn redo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1403 let was_dirty = self.is_dirty();
1404 let old_version = self.version.clone();
1405
1406 if let Some((transaction_id, operation)) = self.text.redo() {
1407 self.send_operation(Operation::Buffer(operation), cx);
1408 self.did_edit(&old_version, was_dirty, cx);
1409 Some(transaction_id)
1410 } else {
1411 None
1412 }
1413 }
1414
1415 pub fn redo_transaction(
1416 &mut self,
1417 transaction_id: TransactionId,
1418 cx: &mut ModelContext<Self>,
1419 ) -> bool {
1420 let was_dirty = self.is_dirty();
1421 let old_version = self.version.clone();
1422
1423 if let Some(operation) = self.text.redo_transaction(transaction_id) {
1424 self.send_operation(Operation::Buffer(operation), cx);
1425 self.did_edit(&old_version, was_dirty, cx);
1426 true
1427 } else {
1428 false
1429 }
1430 }
1431}
1432
1433#[cfg(any(test, feature = "test-support"))]
1434impl Buffer {
1435 pub fn randomly_edit<T>(
1436 &mut self,
1437 rng: &mut T,
1438 old_range_count: usize,
1439 cx: &mut ModelContext<Self>,
1440 ) where
1441 T: rand::Rng,
1442 {
1443 self.start_transaction();
1444 self.text.randomly_edit(rng, old_range_count);
1445 self.end_transaction(cx);
1446 }
1447}
1448
1449impl Entity for Buffer {
1450 type Event = Event;
1451
1452 fn release(&mut self, cx: &mut gpui::MutableAppContext) {
1453 if let Some(file) = self.file.as_ref() {
1454 file.buffer_removed(self.remote_id(), cx);
1455 }
1456 }
1457}
1458
1459impl Deref for Buffer {
1460 type Target = TextBuffer;
1461
1462 fn deref(&self) -> &Self::Target {
1463 &self.text
1464 }
1465}
1466
1467impl BufferSnapshot {
1468 fn suggest_autoindents<'a>(
1469 &'a self,
1470 row_range: Range<u32>,
1471 ) -> Option<impl Iterator<Item = IndentSuggestion> + 'a> {
1472 let mut query_cursor = QueryCursorHandle::new();
1473 if let Some((grammar, tree)) = self.grammar().zip(self.tree.as_ref()) {
1474 let prev_non_blank_row = self.prev_non_blank_row(row_range.start);
1475
1476 // Get the "indentation ranges" that intersect this row range.
1477 let indent_capture_ix = grammar.indents_query.capture_index_for_name("indent");
1478 let end_capture_ix = grammar.indents_query.capture_index_for_name("end");
1479 query_cursor.set_point_range(
1480 Point::new(prev_non_blank_row.unwrap_or(row_range.start), 0).to_ts_point()
1481 ..Point::new(row_range.end, 0).to_ts_point(),
1482 );
1483 let mut indentation_ranges = Vec::<(Range<Point>, &'static str)>::new();
1484 for mat in query_cursor.matches(
1485 &grammar.indents_query,
1486 tree.root_node(),
1487 TextProvider(self.as_rope()),
1488 ) {
1489 let mut node_kind = "";
1490 let mut start: Option<Point> = None;
1491 let mut end: Option<Point> = None;
1492 for capture in mat.captures {
1493 if Some(capture.index) == indent_capture_ix {
1494 node_kind = capture.node.kind();
1495 start.get_or_insert(Point::from_ts_point(capture.node.start_position()));
1496 end.get_or_insert(Point::from_ts_point(capture.node.end_position()));
1497 } else if Some(capture.index) == end_capture_ix {
1498 end = Some(Point::from_ts_point(capture.node.start_position().into()));
1499 }
1500 }
1501
1502 if let Some((start, end)) = start.zip(end) {
1503 if start.row == end.row {
1504 continue;
1505 }
1506
1507 let range = start..end;
1508 match indentation_ranges.binary_search_by_key(&range.start, |r| r.0.start) {
1509 Err(ix) => indentation_ranges.insert(ix, (range, node_kind)),
1510 Ok(ix) => {
1511 let prev_range = &mut indentation_ranges[ix];
1512 prev_range.0.end = prev_range.0.end.max(range.end);
1513 }
1514 }
1515 }
1516 }
1517
1518 let mut prev_row = prev_non_blank_row.unwrap_or(0);
1519 Some(row_range.map(move |row| {
1520 let row_start = Point::new(row, self.indent_column_for_line(row));
1521
1522 let mut indent_from_prev_row = false;
1523 let mut outdent_to_row = u32::MAX;
1524 for (range, _node_kind) in &indentation_ranges {
1525 if range.start.row >= row {
1526 break;
1527 }
1528
1529 if range.start.row == prev_row && range.end > row_start {
1530 indent_from_prev_row = true;
1531 }
1532 if range.end.row >= prev_row && range.end <= row_start {
1533 outdent_to_row = outdent_to_row.min(range.start.row);
1534 }
1535 }
1536
1537 let suggestion = if outdent_to_row == prev_row {
1538 IndentSuggestion {
1539 basis_row: prev_row,
1540 indent: false,
1541 }
1542 } else if indent_from_prev_row {
1543 IndentSuggestion {
1544 basis_row: prev_row,
1545 indent: true,
1546 }
1547 } else if outdent_to_row < prev_row {
1548 IndentSuggestion {
1549 basis_row: outdent_to_row,
1550 indent: false,
1551 }
1552 } else {
1553 IndentSuggestion {
1554 basis_row: prev_row,
1555 indent: false,
1556 }
1557 };
1558
1559 prev_row = row;
1560 suggestion
1561 }))
1562 } else {
1563 None
1564 }
1565 }
1566
1567 fn prev_non_blank_row(&self, mut row: u32) -> Option<u32> {
1568 while row > 0 {
1569 row -= 1;
1570 if !self.is_line_blank(row) {
1571 return Some(row);
1572 }
1573 }
1574 None
1575 }
1576
1577 pub fn chunks<'a, T: ToOffset>(
1578 &'a self,
1579 range: Range<T>,
1580 theme: Option<&'a SyntaxTheme>,
1581 ) -> BufferChunks<'a> {
1582 let range = range.start.to_offset(self)..range.end.to_offset(self);
1583
1584 let mut highlights = None;
1585 let mut diagnostic_endpoints = Vec::<DiagnosticEndpoint>::new();
1586 if let Some(theme) = theme {
1587 for entry in self
1588 .diagnostics
1589 .range::<_, usize>(range.clone(), self, true)
1590 {
1591 diagnostic_endpoints.push(DiagnosticEndpoint {
1592 offset: entry.range.start,
1593 is_start: true,
1594 severity: entry.diagnostic.severity,
1595 });
1596 diagnostic_endpoints.push(DiagnosticEndpoint {
1597 offset: entry.range.end,
1598 is_start: false,
1599 severity: entry.diagnostic.severity,
1600 });
1601 }
1602 diagnostic_endpoints
1603 .sort_unstable_by_key(|endpoint| (endpoint.offset, !endpoint.is_start));
1604
1605 if let Some((grammar, tree)) = self.grammar().zip(self.tree.as_ref()) {
1606 let mut query_cursor = QueryCursorHandle::new();
1607
1608 // TODO - add a Tree-sitter API to remove the need for this.
1609 let cursor = unsafe {
1610 std::mem::transmute::<_, &'static mut QueryCursor>(query_cursor.deref_mut())
1611 };
1612 let captures = cursor.set_byte_range(range.clone()).captures(
1613 &grammar.highlights_query,
1614 tree.root_node(),
1615 TextProvider(self.text.as_rope()),
1616 );
1617 highlights = Some(BufferChunkHighlights {
1618 captures,
1619 next_capture: None,
1620 stack: Default::default(),
1621 highlight_map: grammar.highlight_map(),
1622 _query_cursor: query_cursor,
1623 theme,
1624 })
1625 }
1626 }
1627
1628 let diagnostic_endpoints = diagnostic_endpoints.into_iter().peekable();
1629 let chunks = self.text.as_rope().chunks_in_range(range.clone());
1630
1631 BufferChunks {
1632 range,
1633 chunks,
1634 diagnostic_endpoints,
1635 error_depth: 0,
1636 warning_depth: 0,
1637 information_depth: 0,
1638 hint_depth: 0,
1639 highlights,
1640 }
1641 }
1642
1643 pub fn language(&self) -> Option<&Arc<Language>> {
1644 self.language.as_ref()
1645 }
1646
1647 fn grammar(&self) -> Option<&Arc<Grammar>> {
1648 self.language
1649 .as_ref()
1650 .and_then(|language| language.grammar.as_ref())
1651 }
1652
1653 pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
1654 if let Some(tree) = self.tree.as_ref() {
1655 let root = tree.root_node();
1656 let range = range.start.to_offset(self)..range.end.to_offset(self);
1657 let mut node = root.descendant_for_byte_range(range.start, range.end);
1658 while node.map_or(false, |n| n.byte_range() == range) {
1659 node = node.unwrap().parent();
1660 }
1661 node.map(|n| n.byte_range())
1662 } else {
1663 None
1664 }
1665 }
1666
1667 pub fn enclosing_bracket_ranges<T: ToOffset>(
1668 &self,
1669 range: Range<T>,
1670 ) -> Option<(Range<usize>, Range<usize>)> {
1671 let (grammar, tree) = self.grammar().zip(self.tree.as_ref())?;
1672 let open_capture_ix = grammar.brackets_query.capture_index_for_name("open")?;
1673 let close_capture_ix = grammar.brackets_query.capture_index_for_name("close")?;
1674
1675 // Find bracket pairs that *inclusively* contain the given range.
1676 let range = range.start.to_offset(self).saturating_sub(1)..range.end.to_offset(self) + 1;
1677 let mut cursor = QueryCursorHandle::new();
1678 let matches = cursor.set_byte_range(range).matches(
1679 &grammar.brackets_query,
1680 tree.root_node(),
1681 TextProvider(self.as_rope()),
1682 );
1683
1684 // Get the ranges of the innermost pair of brackets.
1685 matches
1686 .filter_map(|mat| {
1687 let open = mat.nodes_for_capture_index(open_capture_ix).next()?;
1688 let close = mat.nodes_for_capture_index(close_capture_ix).next()?;
1689 Some((open.byte_range(), close.byte_range()))
1690 })
1691 .min_by_key(|(open_range, close_range)| close_range.end - open_range.start)
1692 }
1693
1694 pub fn remote_selections_in_range<'a>(
1695 &'a self,
1696 range: Range<Anchor>,
1697 ) -> impl 'a + Iterator<Item = (ReplicaId, impl 'a + Iterator<Item = &'a Selection<Anchor>>)>
1698 {
1699 self.remote_selections
1700 .iter()
1701 .filter(|(replica_id, _)| **replica_id != self.text.replica_id())
1702 .map(move |(replica_id, selections)| {
1703 let start_ix = match selections
1704 .binary_search_by(|probe| probe.end.cmp(&range.start, self).unwrap())
1705 {
1706 Ok(ix) | Err(ix) => ix,
1707 };
1708 let end_ix = match selections
1709 .binary_search_by(|probe| probe.start.cmp(&range.end, self).unwrap())
1710 {
1711 Ok(ix) | Err(ix) => ix,
1712 };
1713
1714 (*replica_id, selections[start_ix..end_ix].iter())
1715 })
1716 }
1717
1718 pub fn diagnostics_in_range<'a, T, O>(
1719 &'a self,
1720 search_range: Range<T>,
1721 ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>>
1722 where
1723 T: 'a + ToOffset,
1724 O: 'a + FromAnchor,
1725 {
1726 self.diagnostics.range(search_range, self, true)
1727 }
1728
1729 pub fn diagnostic_groups(&self) -> Vec<DiagnosticGroup<Anchor>> {
1730 self.diagnostics.groups(self)
1731 }
1732
1733 pub fn diagnostic_group<'a, O>(
1734 &'a self,
1735 group_id: usize,
1736 ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>>
1737 where
1738 O: 'a + FromAnchor,
1739 {
1740 self.diagnostics.group(group_id, self)
1741 }
1742
1743 pub fn diagnostics_update_count(&self) -> usize {
1744 self.diagnostics_update_count
1745 }
1746
1747 pub fn parse_count(&self) -> usize {
1748 self.parse_count
1749 }
1750}
1751
1752impl Clone for BufferSnapshot {
1753 fn clone(&self) -> Self {
1754 Self {
1755 text: self.text.clone(),
1756 tree: self.tree.clone(),
1757 remote_selections: self.remote_selections.clone(),
1758 diagnostics: self.diagnostics.clone(),
1759 diagnostics_update_count: self.diagnostics_update_count,
1760 is_parsing: self.is_parsing,
1761 language: self.language.clone(),
1762 parse_count: self.parse_count,
1763 }
1764 }
1765}
1766
1767impl Deref for BufferSnapshot {
1768 type Target = text::BufferSnapshot;
1769
1770 fn deref(&self) -> &Self::Target {
1771 &self.text
1772 }
1773}
1774
1775impl<'a> tree_sitter::TextProvider<'a> for TextProvider<'a> {
1776 type I = ByteChunks<'a>;
1777
1778 fn text(&mut self, node: tree_sitter::Node) -> Self::I {
1779 ByteChunks(self.0.chunks_in_range(node.byte_range()))
1780 }
1781}
1782
1783struct ByteChunks<'a>(rope::Chunks<'a>);
1784
1785impl<'a> Iterator for ByteChunks<'a> {
1786 type Item = &'a [u8];
1787
1788 fn next(&mut self) -> Option<Self::Item> {
1789 self.0.next().map(str::as_bytes)
1790 }
1791}
1792
1793unsafe impl<'a> Send for BufferChunks<'a> {}
1794
1795impl<'a> BufferChunks<'a> {
1796 pub fn seek(&mut self, offset: usize) {
1797 self.range.start = offset;
1798 self.chunks.seek(self.range.start);
1799 if let Some(highlights) = self.highlights.as_mut() {
1800 highlights
1801 .stack
1802 .retain(|(end_offset, _)| *end_offset > offset);
1803 if let Some((mat, capture_ix)) = &highlights.next_capture {
1804 let capture = mat.captures[*capture_ix as usize];
1805 if offset >= capture.node.start_byte() {
1806 let next_capture_end = capture.node.end_byte();
1807 if offset < next_capture_end {
1808 highlights.stack.push((
1809 next_capture_end,
1810 highlights.highlight_map.get(capture.index),
1811 ));
1812 }
1813 highlights.next_capture.take();
1814 }
1815 }
1816 highlights.captures.set_byte_range(self.range.clone());
1817 }
1818 }
1819
1820 pub fn offset(&self) -> usize {
1821 self.range.start
1822 }
1823
1824 fn update_diagnostic_depths(&mut self, endpoint: DiagnosticEndpoint) {
1825 let depth = match endpoint.severity {
1826 DiagnosticSeverity::ERROR => &mut self.error_depth,
1827 DiagnosticSeverity::WARNING => &mut self.warning_depth,
1828 DiagnosticSeverity::INFORMATION => &mut self.information_depth,
1829 DiagnosticSeverity::HINT => &mut self.hint_depth,
1830 _ => return,
1831 };
1832 if endpoint.is_start {
1833 *depth += 1;
1834 } else {
1835 *depth -= 1;
1836 }
1837 }
1838
1839 fn current_diagnostic_severity(&mut self) -> Option<DiagnosticSeverity> {
1840 if self.error_depth > 0 {
1841 Some(DiagnosticSeverity::ERROR)
1842 } else if self.warning_depth > 0 {
1843 Some(DiagnosticSeverity::WARNING)
1844 } else if self.information_depth > 0 {
1845 Some(DiagnosticSeverity::INFORMATION)
1846 } else if self.hint_depth > 0 {
1847 Some(DiagnosticSeverity::HINT)
1848 } else {
1849 None
1850 }
1851 }
1852}
1853
1854impl<'a> Iterator for BufferChunks<'a> {
1855 type Item = Chunk<'a>;
1856
1857 fn next(&mut self) -> Option<Self::Item> {
1858 let mut next_capture_start = usize::MAX;
1859 let mut next_diagnostic_endpoint = usize::MAX;
1860
1861 if let Some(highlights) = self.highlights.as_mut() {
1862 while let Some((parent_capture_end, _)) = highlights.stack.last() {
1863 if *parent_capture_end <= self.range.start {
1864 highlights.stack.pop();
1865 } else {
1866 break;
1867 }
1868 }
1869
1870 if highlights.next_capture.is_none() {
1871 highlights.next_capture = highlights.captures.next();
1872 }
1873
1874 while let Some((mat, capture_ix)) = highlights.next_capture.as_ref() {
1875 let capture = mat.captures[*capture_ix as usize];
1876 if self.range.start < capture.node.start_byte() {
1877 next_capture_start = capture.node.start_byte();
1878 break;
1879 } else {
1880 let highlight_id = highlights.highlight_map.get(capture.index);
1881 highlights
1882 .stack
1883 .push((capture.node.end_byte(), highlight_id));
1884 highlights.next_capture = highlights.captures.next();
1885 }
1886 }
1887 }
1888
1889 while let Some(endpoint) = self.diagnostic_endpoints.peek().copied() {
1890 if endpoint.offset <= self.range.start {
1891 self.update_diagnostic_depths(endpoint);
1892 self.diagnostic_endpoints.next();
1893 } else {
1894 next_diagnostic_endpoint = endpoint.offset;
1895 break;
1896 }
1897 }
1898
1899 if let Some(chunk) = self.chunks.peek() {
1900 let chunk_start = self.range.start;
1901 let mut chunk_end = (self.chunks.offset() + chunk.len())
1902 .min(next_capture_start)
1903 .min(next_diagnostic_endpoint);
1904 let mut highlight_style = None;
1905 if let Some(highlights) = self.highlights.as_ref() {
1906 if let Some((parent_capture_end, parent_highlight_id)) = highlights.stack.last() {
1907 chunk_end = chunk_end.min(*parent_capture_end);
1908 highlight_style = parent_highlight_id.style(highlights.theme);
1909 }
1910 }
1911
1912 let slice =
1913 &chunk[chunk_start - self.chunks.offset()..chunk_end - self.chunks.offset()];
1914 self.range.start = chunk_end;
1915 if self.range.start == self.chunks.offset() + chunk.len() {
1916 self.chunks.next().unwrap();
1917 }
1918
1919 Some(Chunk {
1920 text: slice,
1921 highlight_style,
1922 diagnostic: self.current_diagnostic_severity(),
1923 })
1924 } else {
1925 None
1926 }
1927 }
1928}
1929
1930impl QueryCursorHandle {
1931 fn new() -> Self {
1932 QueryCursorHandle(Some(
1933 QUERY_CURSORS
1934 .lock()
1935 .pop()
1936 .unwrap_or_else(|| QueryCursor::new()),
1937 ))
1938 }
1939}
1940
1941impl Deref for QueryCursorHandle {
1942 type Target = QueryCursor;
1943
1944 fn deref(&self) -> &Self::Target {
1945 self.0.as_ref().unwrap()
1946 }
1947}
1948
1949impl DerefMut for QueryCursorHandle {
1950 fn deref_mut(&mut self) -> &mut Self::Target {
1951 self.0.as_mut().unwrap()
1952 }
1953}
1954
1955impl Drop for QueryCursorHandle {
1956 fn drop(&mut self) {
1957 let mut cursor = self.0.take().unwrap();
1958 cursor.set_byte_range(0..usize::MAX);
1959 cursor.set_point_range(Point::zero().to_ts_point()..Point::MAX.to_ts_point());
1960 QUERY_CURSORS.lock().push(cursor)
1961 }
1962}
1963
1964trait ToTreeSitterPoint {
1965 fn to_ts_point(self) -> tree_sitter::Point;
1966 fn from_ts_point(point: tree_sitter::Point) -> Self;
1967}
1968
1969impl ToTreeSitterPoint for Point {
1970 fn to_ts_point(self) -> tree_sitter::Point {
1971 tree_sitter::Point::new(self.row as usize, self.column as usize)
1972 }
1973
1974 fn from_ts_point(point: tree_sitter::Point) -> Self {
1975 Point::new(point.row as u32, point.column as u32)
1976 }
1977}
1978
1979impl operation_queue::Operation for Operation {
1980 fn lamport_timestamp(&self) -> clock::Lamport {
1981 match self {
1982 Operation::Buffer(_) => {
1983 unreachable!("buffer operations should never be deferred at this layer")
1984 }
1985 Operation::UpdateDiagnostics {
1986 lamport_timestamp, ..
1987 }
1988 | Operation::UpdateSelections {
1989 lamport_timestamp, ..
1990 }
1991 | Operation::RemoveSelections {
1992 lamport_timestamp, ..
1993 } => *lamport_timestamp,
1994 }
1995 }
1996}
1997
1998impl Default for Diagnostic {
1999 fn default() -> Self {
2000 Self {
2001 code: Default::default(),
2002 severity: DiagnosticSeverity::ERROR,
2003 message: Default::default(),
2004 group_id: Default::default(),
2005 is_primary: Default::default(),
2006 is_valid: true,
2007 is_disk_based: false,
2008 }
2009 }
2010}
2011
2012pub fn contiguous_ranges(
2013 values: impl Iterator<Item = u32>,
2014 max_len: usize,
2015) -> impl Iterator<Item = Range<u32>> {
2016 let mut values = values.into_iter();
2017 let mut current_range: Option<Range<u32>> = None;
2018 std::iter::from_fn(move || loop {
2019 if let Some(value) = values.next() {
2020 if let Some(range) = &mut current_range {
2021 if value == range.end && range.len() < max_len {
2022 range.end += 1;
2023 continue;
2024 }
2025 }
2026
2027 let prev_range = current_range.clone();
2028 current_range = Some(value..(value + 1));
2029 if prev_range.is_some() {
2030 return prev_range;
2031 }
2032 } else {
2033 return current_range.take();
2034 }
2035 })
2036}