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