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