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