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