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