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