1use crate::diagnostic_set::{DiagnosticEntry, DiagnosticGroup};
2pub use crate::{
3 diagnostic_set::DiagnosticSet,
4 highlight_map::{HighlightId, HighlightMap},
5 proto, BracketPair, Grammar, Language, LanguageConfig, LanguageRegistry, LanguageServerConfig,
6 PLAIN_TEXT,
7};
8use anyhow::{anyhow, Result};
9use clock::ReplicaId;
10use collections::hash_map;
11use futures::FutureExt as _;
12use gpui::{fonts::HighlightStyle, AppContext, Entity, ModelContext, MutableAppContext, Task};
13use lazy_static::lazy_static;
14use lsp::LanguageServer;
15use parking_lot::Mutex;
16use postage::{prelude::Stream, sink::Sink, watch};
17use similar::{ChangeTag, TextDiff};
18use smol::future::yield_now;
19use std::{
20 any::Any,
21 cell::RefCell,
22 cmp::{self, Ordering},
23 collections::{BTreeMap, HashMap, HashSet},
24 ffi::OsString,
25 future::Future,
26 iter::{Iterator, Peekable},
27 ops::{Deref, DerefMut, Range},
28 path::{Path, PathBuf},
29 str,
30 sync::Arc,
31 time::{Duration, Instant, SystemTime, UNIX_EPOCH},
32 vec,
33};
34use sum_tree::TreeMap;
35use text::operation_queue::OperationQueue;
36pub use text::{Buffer as TextBuffer, Operation as _, *};
37use theme::SyntaxTheme;
38use tree_sitter::{InputEdit, Parser, QueryCursor, Tree};
39use util::{post_inc, TryFutureExt as _};
40
41#[cfg(any(test, feature = "test-support"))]
42pub use tree_sitter_rust;
43
44pub use lsp::DiagnosticSeverity;
45
46thread_local! {
47 static PARSER: RefCell<Parser> = RefCell::new(Parser::new());
48}
49
50lazy_static! {
51 static ref QUERY_CURSORS: Mutex<Vec<QueryCursor>> = Default::default();
52}
53
54// TODO - Make this configurable
55const INDENT_SIZE: u32 = 4;
56
57pub struct Buffer {
58 text: TextBuffer,
59 file: Option<Box<dyn File>>,
60 saved_version: clock::Global,
61 saved_mtime: SystemTime,
62 language: Option<Arc<Language>>,
63 autoindent_requests: Vec<Arc<AutoindentRequest>>,
64 pending_autoindent: Option<Task<()>>,
65 sync_parse_timeout: Duration,
66 syntax_tree: Mutex<Option<SyntaxTree>>,
67 parsing_in_background: bool,
68 parse_count: usize,
69 remote_selections: TreeMap<ReplicaId, Arc<[Selection<Anchor>]>>,
70 diagnostics: DiagnosticSet,
71 diagnostics_update_count: usize,
72 clear_invalid_diagnostics_task: Option<Task<()>>,
73 next_diagnostic_group_id: usize,
74 language_server: Option<LanguageServerState>,
75 deferred_ops: OperationQueue<Operation>,
76 #[cfg(test)]
77 pub(crate) operations: Vec<Operation>,
78}
79
80pub struct BufferSnapshot {
81 text: text::BufferSnapshot,
82 tree: Option<Tree>,
83 diagnostics: DiagnosticSet,
84 remote_selections: TreeMap<ReplicaId, Arc<[Selection<Anchor>]>>,
85 diagnostics_update_count: usize,
86 is_parsing: bool,
87 language: Option<Arc<Language>>,
88 parse_count: usize,
89}
90
91#[derive(Clone, Debug, PartialEq, Eq)]
92pub struct Diagnostic {
93 pub source: Option<String>,
94 pub code: Option<String>,
95 pub severity: DiagnosticSeverity,
96 pub message: String,
97 pub group_id: usize,
98 pub is_valid: bool,
99 pub is_primary: bool,
100}
101
102struct LanguageServerState {
103 server: Arc<LanguageServer>,
104 latest_snapshot: watch::Sender<Option<LanguageServerSnapshot>>,
105 pending_snapshots: BTreeMap<usize, LanguageServerSnapshot>,
106 next_version: usize,
107 _maintain_server: Task<Option<()>>,
108}
109
110#[derive(Clone)]
111struct LanguageServerSnapshot {
112 buffer_snapshot: text::BufferSnapshot,
113 version: usize,
114 path: Arc<Path>,
115}
116
117#[derive(Clone, Debug)]
118pub enum Operation {
119 Buffer(text::Operation),
120 UpdateDiagnostics {
121 diagnostics: Arc<[DiagnosticEntry<Anchor>]>,
122 lamport_timestamp: clock::Lamport,
123 },
124 UpdateSelections {
125 replica_id: ReplicaId,
126 selections: Arc<[Selection<Anchor>]>,
127 lamport_timestamp: clock::Lamport,
128 },
129 RemoveSelections {
130 replica_id: ReplicaId,
131 lamport_timestamp: clock::Lamport,
132 },
133}
134
135#[derive(Clone, Debug, Eq, PartialEq)]
136pub enum Event {
137 Edited,
138 Dirtied,
139 Saved,
140 FileHandleChanged,
141 Reloaded,
142 Reparsed,
143 DiagnosticsUpdated,
144 Closed,
145}
146
147pub trait File {
148 fn worktree_id(&self) -> usize;
149
150 fn entry_id(&self) -> Option<usize>;
151
152 fn mtime(&self) -> SystemTime;
153
154 /// Returns the path of this file relative to the worktree's root directory.
155 fn path(&self) -> &Arc<Path>;
156
157 /// Returns the absolute path of this file.
158 fn abs_path(&self) -> Option<PathBuf>;
159
160 /// Returns the path of this file relative to the worktree's parent directory (this means it
161 /// includes the name of the worktree's root folder).
162 fn full_path(&self) -> PathBuf;
163
164 /// Returns the last component of this handle's absolute path. If this handle refers to the root
165 /// of its worktree, then this method will return the name of the worktree itself.
166 fn file_name(&self) -> Option<OsString>;
167
168 fn is_deleted(&self) -> bool;
169
170 fn save(
171 &self,
172 buffer_id: u64,
173 text: Rope,
174 version: clock::Global,
175 cx: &mut MutableAppContext,
176 ) -> Task<Result<(clock::Global, SystemTime)>>;
177
178 fn load_local(&self, cx: &AppContext) -> Option<Task<Result<String>>>;
179
180 fn buffer_updated(&self, buffer_id: u64, operation: Operation, cx: &mut MutableAppContext);
181
182 fn buffer_removed(&self, buffer_id: u64, cx: &mut MutableAppContext);
183
184 fn boxed_clone(&self) -> Box<dyn File>;
185
186 fn as_any(&self) -> &dyn Any;
187}
188
189struct QueryCursorHandle(Option<QueryCursor>);
190
191#[derive(Clone)]
192struct SyntaxTree {
193 tree: Tree,
194 version: clock::Global,
195}
196
197#[derive(Clone)]
198struct AutoindentRequest {
199 before_edit: BufferSnapshot,
200 edited: Vec<Anchor>,
201 inserted: Option<Vec<Range<Anchor>>>,
202}
203
204#[derive(Debug)]
205struct IndentSuggestion {
206 basis_row: u32,
207 indent: bool,
208}
209
210struct TextProvider<'a>(&'a Rope);
211
212struct BufferChunkHighlights<'a> {
213 captures: tree_sitter::QueryCaptures<'a, 'a, TextProvider<'a>>,
214 next_capture: Option<(tree_sitter::QueryMatch<'a, 'a>, usize)>,
215 stack: Vec<(usize, HighlightId)>,
216 highlight_map: HighlightMap,
217 theme: &'a SyntaxTheme,
218 _query_cursor: QueryCursorHandle,
219}
220
221pub struct BufferChunks<'a> {
222 range: Range<usize>,
223 chunks: rope::Chunks<'a>,
224 diagnostic_endpoints: Peekable<vec::IntoIter<DiagnosticEndpoint>>,
225 error_depth: usize,
226 warning_depth: usize,
227 information_depth: usize,
228 hint_depth: usize,
229 highlights: Option<BufferChunkHighlights<'a>>,
230}
231
232#[derive(Clone, Copy, Debug, Default)]
233pub struct Chunk<'a> {
234 pub text: &'a str,
235 pub highlight_style: Option<HighlightStyle>,
236 pub diagnostic: Option<DiagnosticSeverity>,
237}
238
239pub(crate) struct Diff {
240 base_version: clock::Global,
241 new_text: Arc<str>,
242 changes: Vec<(ChangeTag, usize)>,
243}
244
245#[derive(Clone, Copy)]
246struct DiagnosticEndpoint {
247 offset: usize,
248 is_start: bool,
249 severity: DiagnosticSeverity,
250}
251
252impl Buffer {
253 pub fn new<T: Into<Arc<str>>>(
254 replica_id: ReplicaId,
255 base_text: T,
256 cx: &mut ModelContext<Self>,
257 ) -> Self {
258 Self::build(
259 TextBuffer::new(
260 replica_id,
261 cx.model_id() as u64,
262 History::new(base_text.into()),
263 ),
264 None,
265 )
266 }
267
268 pub fn from_file<T: Into<Arc<str>>>(
269 replica_id: ReplicaId,
270 base_text: T,
271 file: Box<dyn File>,
272 cx: &mut ModelContext<Self>,
273 ) -> Self {
274 Self::build(
275 TextBuffer::new(
276 replica_id,
277 cx.model_id() as u64,
278 History::new(base_text.into()),
279 ),
280 Some(file),
281 )
282 }
283
284 pub fn from_proto(
285 replica_id: ReplicaId,
286 message: proto::Buffer,
287 file: Option<Box<dyn File>>,
288 cx: &mut ModelContext<Self>,
289 ) -> Result<Self> {
290 let mut buffer =
291 text::Buffer::new(replica_id, message.id, History::new(message.content.into()));
292 let ops = message
293 .history
294 .into_iter()
295 .map(|op| text::Operation::Edit(proto::deserialize_edit_operation(op)));
296 buffer.apply_ops(ops)?;
297 let mut this = Self::build(buffer, file);
298 for selection_set in message.selections {
299 this.remote_selections.insert(
300 selection_set.replica_id as ReplicaId,
301 proto::deserialize_selections(selection_set.selections),
302 );
303 }
304 this.apply_diagnostic_update(
305 Arc::from(proto::deserialize_diagnostics(message.diagnostics)),
306 cx,
307 );
308
309 Ok(this)
310 }
311
312 pub fn to_proto(&self) -> proto::Buffer {
313 proto::Buffer {
314 id: self.remote_id(),
315 content: self.text.base_text().to_string(),
316 history: self
317 .text
318 .history()
319 .map(proto::serialize_edit_operation)
320 .collect(),
321 selections: self
322 .remote_selections
323 .iter()
324 .map(|(replica_id, selections)| proto::SelectionSet {
325 replica_id: *replica_id as u32,
326 selections: proto::serialize_selections(selections),
327 })
328 .collect(),
329 diagnostics: proto::serialize_diagnostics(self.diagnostics.iter()),
330 }
331 }
332
333 pub fn with_language(
334 mut self,
335 language: Option<Arc<Language>>,
336 language_server: Option<Arc<LanguageServer>>,
337 cx: &mut ModelContext<Self>,
338 ) -> Self {
339 self.set_language(language, language_server, cx);
340 self
341 }
342
343 fn build(buffer: TextBuffer, file: Option<Box<dyn File>>) -> Self {
344 let saved_mtime;
345 if let Some(file) = file.as_ref() {
346 saved_mtime = file.mtime();
347 } else {
348 saved_mtime = UNIX_EPOCH;
349 }
350
351 Self {
352 saved_mtime,
353 saved_version: buffer.version(),
354 text: buffer,
355 file,
356 syntax_tree: Mutex::new(None),
357 parsing_in_background: false,
358 parse_count: 0,
359 sync_parse_timeout: Duration::from_millis(1),
360 autoindent_requests: Default::default(),
361 pending_autoindent: Default::default(),
362 language: None,
363 remote_selections: Default::default(),
364 diagnostics: Default::default(),
365 diagnostics_update_count: 0,
366 next_diagnostic_group_id: 0,
367 clear_invalid_diagnostics_task: None,
368 language_server: None,
369 deferred_ops: OperationQueue::new(),
370 #[cfg(test)]
371 operations: Default::default(),
372 }
373 }
374
375 pub fn snapshot(&self) -> BufferSnapshot {
376 BufferSnapshot {
377 text: self.text.snapshot(),
378 tree: self.syntax_tree(),
379 remote_selections: self.remote_selections.clone(),
380 diagnostics: self.diagnostics.clone(),
381 diagnostics_update_count: self.diagnostics_update_count,
382 is_parsing: self.parsing_in_background,
383 language: self.language.clone(),
384 parse_count: self.parse_count,
385 }
386 }
387
388 pub fn file(&self) -> Option<&dyn File> {
389 self.file.as_deref()
390 }
391
392 pub fn save(
393 &mut self,
394 cx: &mut ModelContext<Self>,
395 ) -> Result<Task<Result<(clock::Global, SystemTime)>>> {
396 let file = self
397 .file
398 .as_ref()
399 .ok_or_else(|| anyhow!("buffer has no file"))?;
400 let text = self.as_rope().clone();
401 let version = self.version();
402 let save = file.save(self.remote_id(), text, version, cx.as_mut());
403 Ok(cx.spawn(|this, mut cx| async move {
404 let (version, mtime) = save.await?;
405 this.update(&mut cx, |this, cx| {
406 this.did_save(version.clone(), mtime, None, cx);
407 });
408 Ok((version, mtime))
409 }))
410 }
411
412 pub fn set_language(
413 &mut self,
414 language: Option<Arc<Language>>,
415 language_server: Option<Arc<lsp::LanguageServer>>,
416 cx: &mut ModelContext<Self>,
417 ) {
418 self.language = language;
419 self.language_server = if let Some(server) = language_server {
420 let (latest_snapshot_tx, mut latest_snapshot_rx) = watch::channel();
421 Some(LanguageServerState {
422 latest_snapshot: latest_snapshot_tx,
423 pending_snapshots: Default::default(),
424 next_version: 0,
425 server: server.clone(),
426 _maintain_server: cx.background().spawn(
427 async move {
428 let mut prev_snapshot: Option<LanguageServerSnapshot> = None;
429 while let Some(snapshot) = latest_snapshot_rx.recv().await {
430 if let Some(snapshot) = snapshot {
431 let uri = lsp::Url::from_file_path(&snapshot.path).unwrap();
432 if let Some(prev_snapshot) = prev_snapshot {
433 let changes = lsp::DidChangeTextDocumentParams {
434 text_document: lsp::VersionedTextDocumentIdentifier::new(
435 uri,
436 snapshot.version as i32,
437 ),
438 content_changes: snapshot
439 .buffer_snapshot
440 .edits_since::<(PointUtf16, usize)>(
441 prev_snapshot.buffer_snapshot.version(),
442 )
443 .map(|edit| {
444 let edit_start = edit.new.start.0;
445 let edit_end = edit_start
446 + (edit.old.end.0 - edit.old.start.0);
447 let new_text = snapshot
448 .buffer_snapshot
449 .text_for_range(
450 edit.new.start.1..edit.new.end.1,
451 )
452 .collect();
453 lsp::TextDocumentContentChangeEvent {
454 range: Some(lsp::Range::new(
455 lsp::Position::new(
456 edit_start.row,
457 edit_start.column,
458 ),
459 lsp::Position::new(
460 edit_end.row,
461 edit_end.column,
462 ),
463 )),
464 range_length: None,
465 text: new_text,
466 }
467 })
468 .collect(),
469 };
470 server
471 .notify::<lsp::notification::DidChangeTextDocument>(changes)
472 .await?;
473 } else {
474 server
475 .notify::<lsp::notification::DidOpenTextDocument>(
476 lsp::DidOpenTextDocumentParams {
477 text_document: lsp::TextDocumentItem::new(
478 uri,
479 Default::default(),
480 snapshot.version as i32,
481 snapshot.buffer_snapshot.text().to_string(),
482 ),
483 },
484 )
485 .await?;
486 }
487
488 prev_snapshot = Some(snapshot);
489 }
490 }
491 Ok(())
492 }
493 .log_err(),
494 ),
495 })
496 } else {
497 None
498 };
499
500 self.reparse(cx);
501 self.update_language_server();
502 }
503
504 pub fn did_save(
505 &mut self,
506 version: clock::Global,
507 mtime: SystemTime,
508 new_file: Option<Box<dyn File>>,
509 cx: &mut ModelContext<Self>,
510 ) {
511 self.saved_mtime = mtime;
512 self.saved_version = version;
513 if let Some(new_file) = new_file {
514 self.file = Some(new_file);
515 }
516 if let Some(state) = &self.language_server {
517 cx.background()
518 .spawn(
519 state
520 .server
521 .notify::<lsp::notification::DidSaveTextDocument>(
522 lsp::DidSaveTextDocumentParams {
523 text_document: lsp::TextDocumentIdentifier {
524 uri: lsp::Url::from_file_path(
525 self.file.as_ref().unwrap().abs_path().unwrap(),
526 )
527 .unwrap(),
528 },
529 text: None,
530 },
531 ),
532 )
533 .detach()
534 }
535 cx.emit(Event::Saved);
536 }
537
538 pub fn file_updated(
539 &mut self,
540 new_file: Box<dyn File>,
541 cx: &mut ModelContext<Self>,
542 ) -> Option<Task<()>> {
543 let old_file = self.file.as_ref()?;
544 let mut file_changed = false;
545 let mut task = None;
546
547 if new_file.path() != old_file.path() {
548 file_changed = true;
549 }
550
551 if new_file.is_deleted() {
552 if !old_file.is_deleted() {
553 file_changed = true;
554 if !self.is_dirty() {
555 cx.emit(Event::Dirtied);
556 }
557 }
558 } else {
559 let new_mtime = new_file.mtime();
560 if new_mtime != old_file.mtime() {
561 file_changed = true;
562
563 if !self.is_dirty() {
564 task = Some(cx.spawn(|this, mut cx| {
565 async move {
566 let new_text = this.read_with(&cx, |this, cx| {
567 this.file.as_ref().and_then(|file| file.load_local(cx))
568 });
569 if let Some(new_text) = new_text {
570 let new_text = new_text.await?;
571 let diff = this
572 .read_with(&cx, |this, cx| this.diff(new_text.into(), cx))
573 .await;
574 this.update(&mut cx, |this, cx| {
575 if this.apply_diff(diff, cx) {
576 this.saved_version = this.version();
577 this.saved_mtime = new_mtime;
578 cx.emit(Event::Reloaded);
579 }
580 });
581 }
582 Ok(())
583 }
584 .log_err()
585 .map(drop)
586 }));
587 }
588 }
589 }
590
591 if file_changed {
592 cx.emit(Event::FileHandleChanged);
593 }
594 self.file = Some(new_file);
595 task
596 }
597
598 pub fn close(&mut self, cx: &mut ModelContext<Self>) {
599 cx.emit(Event::Closed);
600 }
601
602 pub fn language(&self) -> Option<&Arc<Language>> {
603 self.language.as_ref()
604 }
605
606 pub fn parse_count(&self) -> usize {
607 self.parse_count
608 }
609
610 pub fn diagnostics_update_count(&self) -> usize {
611 self.diagnostics_update_count
612 }
613
614 pub(crate) fn syntax_tree(&self) -> Option<Tree> {
615 if let Some(syntax_tree) = self.syntax_tree.lock().as_mut() {
616 self.interpolate_tree(syntax_tree);
617 Some(syntax_tree.tree.clone())
618 } else {
619 None
620 }
621 }
622
623 #[cfg(any(test, feature = "test-support"))]
624 pub fn is_parsing(&self) -> bool {
625 self.parsing_in_background
626 }
627
628 #[cfg(test)]
629 pub fn set_sync_parse_timeout(&mut self, timeout: Duration) {
630 self.sync_parse_timeout = timeout;
631 }
632
633 fn reparse(&mut self, cx: &mut ModelContext<Self>) -> bool {
634 if self.parsing_in_background {
635 return false;
636 }
637
638 if let Some(grammar) = self.grammar().cloned() {
639 let old_tree = self.syntax_tree();
640 let text = self.as_rope().clone();
641 let parsed_version = self.version();
642 let parse_task = cx.background().spawn({
643 let grammar = grammar.clone();
644 async move { Self::parse_text(&text, old_tree, &grammar) }
645 });
646
647 match cx
648 .background()
649 .block_with_timeout(self.sync_parse_timeout, parse_task)
650 {
651 Ok(new_tree) => {
652 self.did_finish_parsing(new_tree, parsed_version, cx);
653 return true;
654 }
655 Err(parse_task) => {
656 self.parsing_in_background = true;
657 cx.spawn(move |this, mut cx| async move {
658 let new_tree = parse_task.await;
659 this.update(&mut cx, move |this, cx| {
660 let grammar_changed = this
661 .grammar()
662 .map_or(true, |curr_grammar| !Arc::ptr_eq(&grammar, curr_grammar));
663 let parse_again = this.version.gt(&parsed_version) || grammar_changed;
664 this.parsing_in_background = false;
665 this.did_finish_parsing(new_tree, parsed_version, cx);
666
667 if parse_again && this.reparse(cx) {
668 return;
669 }
670 });
671 })
672 .detach();
673 }
674 }
675 }
676 false
677 }
678
679 fn parse_text(text: &Rope, old_tree: Option<Tree>, grammar: &Grammar) -> Tree {
680 PARSER.with(|parser| {
681 let mut parser = parser.borrow_mut();
682 parser
683 .set_language(grammar.ts_language)
684 .expect("incompatible grammar");
685 let mut chunks = text.chunks_in_range(0..text.len());
686 let tree = parser
687 .parse_with(
688 &mut move |offset, _| {
689 chunks.seek(offset);
690 chunks.next().unwrap_or("").as_bytes()
691 },
692 old_tree.as_ref(),
693 )
694 .unwrap();
695 tree
696 })
697 }
698
699 fn interpolate_tree(&self, tree: &mut SyntaxTree) {
700 for edit in self.edits_since::<(usize, Point)>(&tree.version) {
701 let (bytes, lines) = edit.flatten();
702 tree.tree.edit(&InputEdit {
703 start_byte: bytes.new.start,
704 old_end_byte: bytes.new.start + bytes.old.len(),
705 new_end_byte: bytes.new.end,
706 start_position: lines.new.start.to_ts_point(),
707 old_end_position: (lines.new.start + (lines.old.end - lines.old.start))
708 .to_ts_point(),
709 new_end_position: lines.new.end.to_ts_point(),
710 });
711 }
712 tree.version = self.version();
713 }
714
715 fn did_finish_parsing(
716 &mut self,
717 tree: Tree,
718 version: clock::Global,
719 cx: &mut ModelContext<Self>,
720 ) {
721 self.parse_count += 1;
722 *self.syntax_tree.lock() = Some(SyntaxTree { tree, version });
723 self.request_autoindent(cx);
724 cx.emit(Event::Reparsed);
725 cx.notify();
726 }
727
728 pub fn all_diagnostics<'a>(&'a self) -> impl 'a + Iterator<Item = &'a DiagnosticEntry<Anchor>> {
729 self.diagnostics.iter()
730 }
731
732 pub fn update_diagnostics(
733 &mut self,
734 version: Option<i32>,
735 mut diagnostics: Vec<DiagnosticEntry<PointUtf16>>,
736 cx: &mut ModelContext<Self>,
737 ) -> Result<Operation> {
738 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
739 Ordering::Equal
740 .then_with(|| b.is_primary.cmp(&a.is_primary))
741 .then_with(|| a.source.cmp(&b.source))
742 .then_with(|| a.severity.cmp(&b.severity))
743 .then_with(|| a.message.cmp(&b.message))
744 }
745
746 diagnostics.sort_unstable_by(|a, b| {
747 Ordering::Equal
748 .then_with(|| a.range.start.cmp(&b.range.start))
749 .then_with(|| b.range.end.cmp(&a.range.end))
750 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
751 });
752
753 let version = version.map(|version| version as usize);
754 let content = if let Some(version) = version {
755 let language_server = self.language_server.as_mut().unwrap();
756 language_server
757 .pending_snapshots
758 .retain(|&v, _| v >= version);
759 let snapshot = language_server
760 .pending_snapshots
761 .get(&version)
762 .ok_or_else(|| anyhow!("missing snapshot"))?;
763 &snapshot.buffer_snapshot
764 } else {
765 self.deref()
766 };
767
768 let empty_set = HashSet::new();
769 let disk_based_sources = self
770 .language
771 .as_ref()
772 .and_then(|language| language.disk_based_diagnostic_sources())
773 .unwrap_or(&empty_set);
774
775 let mut edits_since_save = content
776 .edits_since::<PointUtf16>(&self.saved_version)
777 .peekable();
778 let mut last_edit_old_end = PointUtf16::zero();
779 let mut last_edit_new_end = PointUtf16::zero();
780 let mut has_disk_based_diagnostics = false;
781 let mut ix = 0;
782 'outer: while ix < diagnostics.len() {
783 let entry = &mut diagnostics[ix];
784 let mut start = entry.range.start;
785 let mut end = entry.range.end;
786
787 // Some diagnostics are based on files on disk instead of buffers'
788 // current contents. Adjust these diagnostics' ranges to reflect
789 // any unsaved edits.
790 if entry
791 .diagnostic
792 .source
793 .as_ref()
794 .map_or(false, |source| disk_based_sources.contains(source))
795 {
796 has_disk_based_diagnostics = true;
797 while let Some(edit) = edits_since_save.peek() {
798 if edit.old.end <= start {
799 last_edit_old_end = edit.old.end;
800 last_edit_new_end = edit.new.end;
801 edits_since_save.next();
802 } else if edit.old.start <= end && edit.old.end >= start {
803 diagnostics.remove(ix);
804 continue 'outer;
805 } else {
806 break;
807 }
808 }
809
810 start = last_edit_new_end + (start - last_edit_old_end);
811 end = last_edit_new_end + (end - last_edit_old_end);
812 }
813
814 entry.range = content.clip_point_utf16(start, Bias::Left)
815 ..content.clip_point_utf16(end, Bias::Right);
816
817 // Expand empty ranges by one character
818 if entry.range.start == entry.range.end {
819 entry.range.end.column += 1;
820 entry.range.end = content.clip_point_utf16(entry.range.end, Bias::Right);
821 if entry.range.start == entry.range.end && entry.range.end.column > 0 {
822 entry.range.start.column -= 1;
823 entry.range.start = content.clip_point_utf16(entry.range.start, Bias::Left);
824 }
825 }
826 ix += 1;
827 }
828 drop(edits_since_save);
829
830 let mut merged_diagnostics = Vec::with_capacity(diagnostics.len());
831 let mut old_diagnostics = self
832 .diagnostics
833 .iter()
834 .map(|entry| {
835 (
836 entry,
837 entry
838 .diagnostic
839 .source
840 .as_ref()
841 .map_or(false, |source| disk_based_sources.contains(source)),
842 )
843 })
844 .peekable();
845 let mut new_diagnostics = diagnostics
846 .into_iter()
847 .map(|entry| DiagnosticEntry {
848 range: content.anchor_before(entry.range.start)
849 ..content.anchor_after(entry.range.end),
850 diagnostic: entry.diagnostic,
851 })
852 .peekable();
853
854 // Incorporate the *old* diagnostics into the new diagnostics set, in two ways:
855 // 1. Recycle group ids - diagnostic groups whose primary diagnostic has not
856 // changed should use the same group id as before, so that downstream code
857 // can determine which diagnostics are new.
858 // 2. Preserve disk-based diagnostics - Some diagnostic sources are reported
859 // on a less frequent basis than others. If these sources are absent from this
860 // message, then preserve the previous diagnostics for those sources, but mark
861 // them as invalid, and set a timer to clear them out.
862 let mut group_id_replacements = HashMap::new();
863 let mut merged_old_disk_based_diagnostics = false;
864 loop {
865 match (old_diagnostics.peek(), new_diagnostics.peek()) {
866 (None, None) => break,
867 (None, Some(_)) => {
868 merged_diagnostics.push(new_diagnostics.next().unwrap());
869 }
870 (Some(_), None) => {
871 let (old_entry, is_disk_based) = old_diagnostics.next().unwrap();
872 if is_disk_based && !has_disk_based_diagnostics {
873 let mut old_entry = old_entry.clone();
874 old_entry.diagnostic.is_valid = false;
875 merged_old_disk_based_diagnostics = true;
876 merged_diagnostics.push(old_entry);
877 }
878 }
879 (Some((old, _)), Some(new)) => {
880 let ordering = Ordering::Equal
881 .then_with(|| old.range.start.cmp(&new.range.start, content).unwrap())
882 .then_with(|| new.range.end.cmp(&old.range.end, content).unwrap())
883 .then_with(|| compare_diagnostics(&old.diagnostic, &new.diagnostic));
884 match ordering {
885 Ordering::Less => {
886 let (old_entry, is_disk_based) = old_diagnostics.next().unwrap();
887 if is_disk_based && !has_disk_based_diagnostics {
888 let mut old_entry = old_entry.clone();
889 old_entry.diagnostic.is_valid = false;
890 merged_old_disk_based_diagnostics = true;
891 merged_diagnostics.push(old_entry);
892 }
893 }
894 Ordering::Equal => {
895 let (old_entry, _) = old_diagnostics.next().unwrap();
896 let new_entry = new_diagnostics.next().unwrap();
897 if new_entry.diagnostic.is_primary {
898 group_id_replacements.insert(
899 new_entry.diagnostic.group_id,
900 old_entry.diagnostic.group_id,
901 );
902 }
903 merged_diagnostics.push(new_entry);
904 }
905 Ordering::Greater => {
906 let new_entry = new_diagnostics.next().unwrap();
907 merged_diagnostics.push(new_entry);
908 }
909 }
910 }
911 }
912 }
913 drop(old_diagnostics);
914
915 // Having determined which group ids should be recycled, renumber all of
916 // groups. Any new group that does not correspond to an old group receives
917 // a brand new group id.
918 let mut next_diagnostic_group_id = self.next_diagnostic_group_id;
919 for entry in &mut merged_diagnostics {
920 if entry.diagnostic.is_valid {
921 match group_id_replacements.entry(entry.diagnostic.group_id) {
922 hash_map::Entry::Occupied(e) => entry.diagnostic.group_id = *e.get(),
923 hash_map::Entry::Vacant(e) => {
924 entry.diagnostic.group_id = post_inc(&mut next_diagnostic_group_id);
925 e.insert(entry.diagnostic.group_id);
926 }
927 }
928 }
929 }
930
931 self.diagnostics = DiagnosticSet::from_sorted_entries(merged_diagnostics, content);
932 self.next_diagnostic_group_id = next_diagnostic_group_id;
933
934 // If old disk-based diagnostics were included in this new set, then
935 // set a timer to remove them if enough time passes before the next
936 // diagnostics update.
937 if merged_old_disk_based_diagnostics {
938 self.clear_invalid_diagnostics_task = Some(cx.spawn(|this, mut cx| async move {
939 smol::Timer::after(Duration::from_secs(2)).await;
940 this.update(&mut cx, |this, cx| {
941 let content = this.snapshot();
942 this.diagnostics = DiagnosticSet::from_sorted_entries(
943 this.diagnostics
944 .iter()
945 .filter(|d| d.diagnostic.is_valid)
946 .cloned(),
947 &content,
948 );
949 let operation = this.did_update_diagnostics(cx);
950 this.send_operation(operation, cx);
951 });
952 }));
953 } else if has_disk_based_diagnostics {
954 self.clear_invalid_diagnostics_task.take();
955 }
956
957 Ok(self.did_update_diagnostics(cx))
958 }
959
960 fn did_update_diagnostics(&mut self, cx: &mut ModelContext<Self>) -> Operation {
961 self.diagnostics_update_count += 1;
962 cx.notify();
963 cx.emit(Event::DiagnosticsUpdated);
964 Operation::UpdateDiagnostics {
965 diagnostics: Arc::from(self.diagnostics.iter().cloned().collect::<Vec<_>>()),
966 lamport_timestamp: self.text.lamport_clock.tick(),
967 }
968 }
969
970 fn request_autoindent(&mut self, cx: &mut ModelContext<Self>) {
971 if let Some(indent_columns) = self.compute_autoindents() {
972 let indent_columns = cx.background().spawn(indent_columns);
973 match cx
974 .background()
975 .block_with_timeout(Duration::from_micros(500), indent_columns)
976 {
977 Ok(indent_columns) => self.apply_autoindents(indent_columns, cx),
978 Err(indent_columns) => {
979 self.pending_autoindent = Some(cx.spawn(|this, mut cx| async move {
980 let indent_columns = indent_columns.await;
981 this.update(&mut cx, |this, cx| {
982 this.apply_autoindents(indent_columns, cx);
983 });
984 }));
985 }
986 }
987 }
988 }
989
990 fn compute_autoindents(&self) -> Option<impl Future<Output = BTreeMap<u32, u32>>> {
991 let max_rows_between_yields = 100;
992 let snapshot = self.snapshot();
993 if snapshot.language.is_none()
994 || snapshot.tree.is_none()
995 || self.autoindent_requests.is_empty()
996 {
997 return None;
998 }
999
1000 let autoindent_requests = self.autoindent_requests.clone();
1001 Some(async move {
1002 let mut indent_columns = BTreeMap::new();
1003 for request in autoindent_requests {
1004 let old_to_new_rows = request
1005 .edited
1006 .iter()
1007 .map(|anchor| anchor.summary::<Point>(&request.before_edit).row)
1008 .zip(
1009 request
1010 .edited
1011 .iter()
1012 .map(|anchor| anchor.summary::<Point>(&snapshot).row),
1013 )
1014 .collect::<BTreeMap<u32, u32>>();
1015
1016 let mut old_suggestions = HashMap::<u32, u32>::default();
1017 let old_edited_ranges =
1018 contiguous_ranges(old_to_new_rows.keys().copied(), max_rows_between_yields);
1019 for old_edited_range in old_edited_ranges {
1020 let suggestions = request
1021 .before_edit
1022 .suggest_autoindents(old_edited_range.clone())
1023 .into_iter()
1024 .flatten();
1025 for (old_row, suggestion) in old_edited_range.zip(suggestions) {
1026 let indentation_basis = old_to_new_rows
1027 .get(&suggestion.basis_row)
1028 .and_then(|from_row| old_suggestions.get(from_row).copied())
1029 .unwrap_or_else(|| {
1030 request
1031 .before_edit
1032 .indent_column_for_line(suggestion.basis_row)
1033 });
1034 let delta = if suggestion.indent { INDENT_SIZE } else { 0 };
1035 old_suggestions.insert(
1036 *old_to_new_rows.get(&old_row).unwrap(),
1037 indentation_basis + delta,
1038 );
1039 }
1040 yield_now().await;
1041 }
1042
1043 // At this point, old_suggestions contains the suggested indentation for all edited lines with respect to the state of the
1044 // buffer before the edit, but keyed by the row for these lines after the edits were applied.
1045 let new_edited_row_ranges =
1046 contiguous_ranges(old_to_new_rows.values().copied(), max_rows_between_yields);
1047 for new_edited_row_range in new_edited_row_ranges {
1048 let suggestions = snapshot
1049 .suggest_autoindents(new_edited_row_range.clone())
1050 .into_iter()
1051 .flatten();
1052 for (new_row, suggestion) in new_edited_row_range.zip(suggestions) {
1053 let delta = if suggestion.indent { INDENT_SIZE } else { 0 };
1054 let new_indentation = indent_columns
1055 .get(&suggestion.basis_row)
1056 .copied()
1057 .unwrap_or_else(|| {
1058 snapshot.indent_column_for_line(suggestion.basis_row)
1059 })
1060 + delta;
1061 if old_suggestions
1062 .get(&new_row)
1063 .map_or(true, |old_indentation| new_indentation != *old_indentation)
1064 {
1065 indent_columns.insert(new_row, new_indentation);
1066 }
1067 }
1068 yield_now().await;
1069 }
1070
1071 if let Some(inserted) = request.inserted.as_ref() {
1072 let inserted_row_ranges = contiguous_ranges(
1073 inserted
1074 .iter()
1075 .map(|range| range.to_point(&snapshot))
1076 .flat_map(|range| range.start.row..range.end.row + 1),
1077 max_rows_between_yields,
1078 );
1079 for inserted_row_range in inserted_row_ranges {
1080 let suggestions = snapshot
1081 .suggest_autoindents(inserted_row_range.clone())
1082 .into_iter()
1083 .flatten();
1084 for (row, suggestion) in inserted_row_range.zip(suggestions) {
1085 let delta = if suggestion.indent { INDENT_SIZE } else { 0 };
1086 let new_indentation = indent_columns
1087 .get(&suggestion.basis_row)
1088 .copied()
1089 .unwrap_or_else(|| {
1090 snapshot.indent_column_for_line(suggestion.basis_row)
1091 })
1092 + delta;
1093 indent_columns.insert(row, new_indentation);
1094 }
1095 yield_now().await;
1096 }
1097 }
1098 }
1099 indent_columns
1100 })
1101 }
1102
1103 fn apply_autoindents(
1104 &mut self,
1105 indent_columns: BTreeMap<u32, u32>,
1106 cx: &mut ModelContext<Self>,
1107 ) {
1108 self.start_transaction();
1109 for (row, indent_column) in &indent_columns {
1110 self.set_indent_column_for_line(*row, *indent_column, cx);
1111 }
1112 self.end_transaction(cx);
1113 }
1114
1115 fn set_indent_column_for_line(&mut self, row: u32, column: u32, cx: &mut ModelContext<Self>) {
1116 let current_column = self.indent_column_for_line(row);
1117 if column > current_column {
1118 let offset = Point::new(row, 0).to_offset(&*self);
1119 self.edit(
1120 [offset..offset],
1121 " ".repeat((column - current_column) as usize),
1122 cx,
1123 );
1124 } else if column < current_column {
1125 self.edit(
1126 [Point::new(row, 0)..Point::new(row, current_column - column)],
1127 "",
1128 cx,
1129 );
1130 }
1131 }
1132
1133 pub(crate) fn diff(&self, new_text: Arc<str>, cx: &AppContext) -> Task<Diff> {
1134 // TODO: it would be nice to not allocate here.
1135 let old_text = self.text();
1136 let base_version = self.version();
1137 cx.background().spawn(async move {
1138 let changes = TextDiff::from_lines(old_text.as_str(), new_text.as_ref())
1139 .iter_all_changes()
1140 .map(|c| (c.tag(), c.value().len()))
1141 .collect::<Vec<_>>();
1142 Diff {
1143 base_version,
1144 new_text,
1145 changes,
1146 }
1147 })
1148 }
1149
1150 pub(crate) fn apply_diff(&mut self, diff: Diff, cx: &mut ModelContext<Self>) -> bool {
1151 if self.version == diff.base_version {
1152 self.start_transaction();
1153 let mut offset = 0;
1154 for (tag, len) in diff.changes {
1155 let range = offset..(offset + len);
1156 match tag {
1157 ChangeTag::Equal => offset += len,
1158 ChangeTag::Delete => self.edit(Some(range), "", cx),
1159 ChangeTag::Insert => {
1160 self.edit(Some(offset..offset), &diff.new_text[range], cx);
1161 offset += len;
1162 }
1163 }
1164 }
1165 self.end_transaction(cx);
1166 true
1167 } else {
1168 false
1169 }
1170 }
1171
1172 pub fn is_dirty(&self) -> bool {
1173 !self.saved_version.ge(&self.version)
1174 || self.file.as_ref().map_or(false, |file| file.is_deleted())
1175 }
1176
1177 pub fn has_conflict(&self) -> bool {
1178 !self.saved_version.ge(&self.version)
1179 && self
1180 .file
1181 .as_ref()
1182 .map_or(false, |file| file.mtime() > self.saved_mtime)
1183 }
1184
1185 pub fn subscribe(&mut self) -> Subscription {
1186 self.text.subscribe()
1187 }
1188
1189 pub fn start_transaction(&mut self) -> Option<TransactionId> {
1190 self.start_transaction_at(Instant::now())
1191 }
1192
1193 pub fn start_transaction_at(&mut self, now: Instant) -> Option<TransactionId> {
1194 self.text.start_transaction_at(now)
1195 }
1196
1197 pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1198 self.end_transaction_at(Instant::now(), cx)
1199 }
1200
1201 pub fn end_transaction_at(
1202 &mut self,
1203 now: Instant,
1204 cx: &mut ModelContext<Self>,
1205 ) -> Option<TransactionId> {
1206 if let Some((transaction_id, start_version)) = self.text.end_transaction_at(now) {
1207 let was_dirty = start_version != self.saved_version;
1208 self.did_edit(&start_version, was_dirty, cx);
1209 Some(transaction_id)
1210 } else {
1211 None
1212 }
1213 }
1214
1215 pub fn set_active_selections(
1216 &mut self,
1217 selections: Arc<[Selection<Anchor>]>,
1218 cx: &mut ModelContext<Self>,
1219 ) {
1220 let lamport_timestamp = self.text.lamport_clock.tick();
1221 self.remote_selections
1222 .insert(self.text.replica_id(), selections.clone());
1223 self.send_operation(
1224 Operation::UpdateSelections {
1225 replica_id: self.text.replica_id(),
1226 selections,
1227 lamport_timestamp,
1228 },
1229 cx,
1230 );
1231 }
1232
1233 pub fn remove_active_selections(&mut self, cx: &mut ModelContext<Self>) {
1234 let lamport_timestamp = self.text.lamport_clock.tick();
1235 self.send_operation(
1236 Operation::RemoveSelections {
1237 replica_id: self.text.replica_id(),
1238 lamport_timestamp,
1239 },
1240 cx,
1241 );
1242 }
1243
1244 fn update_language_server(&mut self) {
1245 let language_server = if let Some(language_server) = self.language_server.as_mut() {
1246 language_server
1247 } else {
1248 return;
1249 };
1250 let abs_path = self
1251 .file
1252 .as_ref()
1253 .map_or(Path::new("/").to_path_buf(), |file| {
1254 file.abs_path().unwrap()
1255 });
1256
1257 let version = post_inc(&mut language_server.next_version);
1258 let snapshot = LanguageServerSnapshot {
1259 buffer_snapshot: self.text.snapshot(),
1260 version,
1261 path: Arc::from(abs_path),
1262 };
1263 language_server
1264 .pending_snapshots
1265 .insert(version, snapshot.clone());
1266 let _ = language_server
1267 .latest_snapshot
1268 .blocking_send(Some(snapshot));
1269 }
1270
1271 pub fn edit<I, S, T>(&mut self, ranges_iter: I, new_text: T, cx: &mut ModelContext<Self>)
1272 where
1273 I: IntoIterator<Item = Range<S>>,
1274 S: ToOffset,
1275 T: Into<String>,
1276 {
1277 self.edit_internal(ranges_iter, new_text, false, cx)
1278 }
1279
1280 pub fn edit_with_autoindent<I, S, T>(
1281 &mut self,
1282 ranges_iter: I,
1283 new_text: T,
1284 cx: &mut ModelContext<Self>,
1285 ) where
1286 I: IntoIterator<Item = Range<S>>,
1287 S: ToOffset,
1288 T: Into<String>,
1289 {
1290 self.edit_internal(ranges_iter, new_text, true, cx)
1291 }
1292
1293 pub fn edit_internal<I, S, T>(
1294 &mut self,
1295 ranges_iter: I,
1296 new_text: T,
1297 autoindent: bool,
1298 cx: &mut ModelContext<Self>,
1299 ) where
1300 I: IntoIterator<Item = Range<S>>,
1301 S: ToOffset,
1302 T: Into<String>,
1303 {
1304 let new_text = new_text.into();
1305
1306 // Skip invalid ranges and coalesce contiguous ones.
1307 let mut ranges: Vec<Range<usize>> = Vec::new();
1308 for range in ranges_iter {
1309 let range = range.start.to_offset(self)..range.end.to_offset(self);
1310 if !new_text.is_empty() || !range.is_empty() {
1311 if let Some(prev_range) = ranges.last_mut() {
1312 if prev_range.end >= range.start {
1313 prev_range.end = cmp::max(prev_range.end, range.end);
1314 } else {
1315 ranges.push(range);
1316 }
1317 } else {
1318 ranges.push(range);
1319 }
1320 }
1321 }
1322 if ranges.is_empty() {
1323 return;
1324 }
1325
1326 self.start_transaction();
1327 self.pending_autoindent.take();
1328 let autoindent_request = if autoindent && self.language.is_some() {
1329 let before_edit = self.snapshot();
1330 let edited = ranges
1331 .iter()
1332 .filter_map(|range| {
1333 let start = range.start.to_point(self);
1334 if new_text.starts_with('\n') && start.column == self.line_len(start.row) {
1335 None
1336 } else {
1337 Some(self.anchor_before(range.start))
1338 }
1339 })
1340 .collect();
1341 Some((before_edit, edited))
1342 } else {
1343 None
1344 };
1345
1346 let first_newline_ix = new_text.find('\n');
1347 let new_text_len = new_text.len();
1348
1349 let edit = self.text.edit(ranges.iter().cloned(), new_text);
1350
1351 if let Some((before_edit, edited)) = autoindent_request {
1352 let mut inserted = None;
1353 if let Some(first_newline_ix) = first_newline_ix {
1354 let mut delta = 0isize;
1355 inserted = Some(
1356 ranges
1357 .iter()
1358 .map(|range| {
1359 let start =
1360 (delta + range.start as isize) as usize + first_newline_ix + 1;
1361 let end = (delta + range.start as isize) as usize + new_text_len;
1362 delta +=
1363 (range.end as isize - range.start as isize) + new_text_len as isize;
1364 self.anchor_before(start)..self.anchor_after(end)
1365 })
1366 .collect(),
1367 );
1368 }
1369
1370 self.autoindent_requests.push(Arc::new(AutoindentRequest {
1371 before_edit,
1372 edited,
1373 inserted,
1374 }));
1375 }
1376
1377 self.end_transaction(cx);
1378 self.send_operation(Operation::Buffer(text::Operation::Edit(edit)), cx);
1379 }
1380
1381 fn did_edit(
1382 &mut self,
1383 old_version: &clock::Global,
1384 was_dirty: bool,
1385 cx: &mut ModelContext<Self>,
1386 ) {
1387 if self.edits_since::<usize>(old_version).next().is_none() {
1388 return;
1389 }
1390
1391 self.reparse(cx);
1392 self.update_language_server();
1393
1394 cx.emit(Event::Edited);
1395 if !was_dirty {
1396 cx.emit(Event::Dirtied);
1397 }
1398 cx.notify();
1399 }
1400
1401 fn grammar(&self) -> Option<&Arc<Grammar>> {
1402 self.language.as_ref().and_then(|l| l.grammar.as_ref())
1403 }
1404
1405 pub fn apply_ops<I: IntoIterator<Item = Operation>>(
1406 &mut self,
1407 ops: I,
1408 cx: &mut ModelContext<Self>,
1409 ) -> Result<()> {
1410 self.pending_autoindent.take();
1411 let was_dirty = self.is_dirty();
1412 let old_version = self.version.clone();
1413 let mut deferred_ops = Vec::new();
1414 let buffer_ops = ops
1415 .into_iter()
1416 .filter_map(|op| match op {
1417 Operation::Buffer(op) => Some(op),
1418 _ => {
1419 if self.can_apply_op(&op) {
1420 self.apply_op(op, cx);
1421 } else {
1422 deferred_ops.push(op);
1423 }
1424 None
1425 }
1426 })
1427 .collect::<Vec<_>>();
1428 self.text.apply_ops(buffer_ops)?;
1429 self.flush_deferred_ops(cx);
1430 self.did_edit(&old_version, was_dirty, cx);
1431 // Notify independently of whether the buffer was edited as the operations could include a
1432 // selection update.
1433 cx.notify();
1434 Ok(())
1435 }
1436
1437 fn flush_deferred_ops(&mut self, cx: &mut ModelContext<Self>) {
1438 let mut deferred_ops = Vec::new();
1439 for op in self.deferred_ops.drain().iter().cloned() {
1440 if self.can_apply_op(&op) {
1441 self.apply_op(op, cx);
1442 } else {
1443 deferred_ops.push(op);
1444 }
1445 }
1446 self.deferred_ops.insert(deferred_ops);
1447 }
1448
1449 fn can_apply_op(&self, operation: &Operation) -> bool {
1450 match operation {
1451 Operation::Buffer(_) => {
1452 unreachable!("buffer operations should never be applied at this layer")
1453 }
1454 Operation::UpdateDiagnostics { diagnostics, .. } => {
1455 diagnostics.iter().all(|diagnostic| {
1456 self.text.can_resolve(&diagnostic.range.start)
1457 && self.text.can_resolve(&diagnostic.range.end)
1458 })
1459 }
1460 Operation::UpdateSelections { selections, .. } => selections
1461 .iter()
1462 .all(|s| self.can_resolve(&s.start) && self.can_resolve(&s.end)),
1463 Operation::RemoveSelections { .. } => true,
1464 }
1465 }
1466
1467 fn apply_op(&mut self, operation: Operation, cx: &mut ModelContext<Self>) {
1468 match operation {
1469 Operation::Buffer(_) => {
1470 unreachable!("buffer operations should never be applied at this layer")
1471 }
1472 Operation::UpdateDiagnostics { diagnostics, .. } => {
1473 self.apply_diagnostic_update(diagnostics, cx);
1474 }
1475 Operation::UpdateSelections {
1476 replica_id,
1477 selections,
1478 lamport_timestamp,
1479 } => {
1480 self.remote_selections.insert(replica_id, selections);
1481 self.text.lamport_clock.observe(lamport_timestamp);
1482 }
1483 Operation::RemoveSelections {
1484 replica_id,
1485 lamport_timestamp,
1486 } => {
1487 self.remote_selections.remove(&replica_id);
1488 self.text.lamport_clock.observe(lamport_timestamp);
1489 }
1490 }
1491 }
1492
1493 fn apply_diagnostic_update(
1494 &mut self,
1495 diagnostics: Arc<[DiagnosticEntry<Anchor>]>,
1496 cx: &mut ModelContext<Self>,
1497 ) {
1498 self.diagnostics = DiagnosticSet::from_sorted_entries(diagnostics.iter().cloned(), self);
1499 self.diagnostics_update_count += 1;
1500 cx.notify();
1501 }
1502
1503 #[cfg(not(test))]
1504 pub fn send_operation(&mut self, operation: Operation, cx: &mut ModelContext<Self>) {
1505 if let Some(file) = &self.file {
1506 file.buffer_updated(self.remote_id(), operation, cx.as_mut());
1507 }
1508 }
1509
1510 #[cfg(test)]
1511 pub fn send_operation(&mut self, operation: Operation, _: &mut ModelContext<Self>) {
1512 self.operations.push(operation);
1513 }
1514
1515 pub fn remove_peer(&mut self, replica_id: ReplicaId, cx: &mut ModelContext<Self>) {
1516 self.remote_selections.remove(&replica_id);
1517 cx.notify();
1518 }
1519
1520 pub fn undo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1521 let was_dirty = self.is_dirty();
1522 let old_version = self.version.clone();
1523
1524 if let Some((transaction_id, operation)) = self.text.undo() {
1525 self.send_operation(Operation::Buffer(operation), cx);
1526 self.did_edit(&old_version, was_dirty, cx);
1527 Some(transaction_id)
1528 } else {
1529 None
1530 }
1531 }
1532
1533 pub fn undo_transaction(
1534 &mut self,
1535 transaction_id: TransactionId,
1536 cx: &mut ModelContext<Self>,
1537 ) -> bool {
1538 let was_dirty = self.is_dirty();
1539 let old_version = self.version.clone();
1540
1541 if let Some(operation) = self.text.undo_transaction(transaction_id) {
1542 self.send_operation(Operation::Buffer(operation), cx);
1543 self.did_edit(&old_version, was_dirty, cx);
1544 true
1545 } else {
1546 false
1547 }
1548 }
1549
1550 pub fn redo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1551 let was_dirty = self.is_dirty();
1552 let old_version = self.version.clone();
1553
1554 if let Some((transaction_id, operation)) = self.text.redo() {
1555 self.send_operation(Operation::Buffer(operation), cx);
1556 self.did_edit(&old_version, was_dirty, cx);
1557 Some(transaction_id)
1558 } else {
1559 None
1560 }
1561 }
1562
1563 pub fn redo_transaction(
1564 &mut self,
1565 transaction_id: TransactionId,
1566 cx: &mut ModelContext<Self>,
1567 ) -> bool {
1568 let was_dirty = self.is_dirty();
1569 let old_version = self.version.clone();
1570
1571 if let Some(operation) = self.text.redo_transaction(transaction_id) {
1572 self.send_operation(Operation::Buffer(operation), cx);
1573 self.did_edit(&old_version, was_dirty, cx);
1574 true
1575 } else {
1576 false
1577 }
1578 }
1579}
1580
1581#[cfg(any(test, feature = "test-support"))]
1582impl Buffer {
1583 pub fn randomly_edit<T>(
1584 &mut self,
1585 rng: &mut T,
1586 old_range_count: usize,
1587 cx: &mut ModelContext<Self>,
1588 ) where
1589 T: rand::Rng,
1590 {
1591 self.start_transaction();
1592 self.text.randomly_edit(rng, old_range_count);
1593 self.end_transaction(cx);
1594 }
1595}
1596
1597impl Entity for Buffer {
1598 type Event = Event;
1599
1600 fn release(&mut self, cx: &mut gpui::MutableAppContext) {
1601 if let Some(file) = self.file.as_ref() {
1602 file.buffer_removed(self.remote_id(), cx);
1603 }
1604 }
1605}
1606
1607impl Deref for Buffer {
1608 type Target = TextBuffer;
1609
1610 fn deref(&self) -> &Self::Target {
1611 &self.text
1612 }
1613}
1614
1615impl BufferSnapshot {
1616 fn suggest_autoindents<'a>(
1617 &'a self,
1618 row_range: Range<u32>,
1619 ) -> Option<impl Iterator<Item = IndentSuggestion> + 'a> {
1620 let mut query_cursor = QueryCursorHandle::new();
1621 if let Some((grammar, tree)) = self.grammar().zip(self.tree.as_ref()) {
1622 let prev_non_blank_row = self.prev_non_blank_row(row_range.start);
1623
1624 // Get the "indentation ranges" that intersect this row range.
1625 let indent_capture_ix = grammar.indents_query.capture_index_for_name("indent");
1626 let end_capture_ix = grammar.indents_query.capture_index_for_name("end");
1627 query_cursor.set_point_range(
1628 Point::new(prev_non_blank_row.unwrap_or(row_range.start), 0).to_ts_point()
1629 ..Point::new(row_range.end, 0).to_ts_point(),
1630 );
1631 let mut indentation_ranges = Vec::<(Range<Point>, &'static str)>::new();
1632 for mat in query_cursor.matches(
1633 &grammar.indents_query,
1634 tree.root_node(),
1635 TextProvider(self.as_rope()),
1636 ) {
1637 let mut node_kind = "";
1638 let mut start: Option<Point> = None;
1639 let mut end: Option<Point> = None;
1640 for capture in mat.captures {
1641 if Some(capture.index) == indent_capture_ix {
1642 node_kind = capture.node.kind();
1643 start.get_or_insert(Point::from_ts_point(capture.node.start_position()));
1644 end.get_or_insert(Point::from_ts_point(capture.node.end_position()));
1645 } else if Some(capture.index) == end_capture_ix {
1646 end = Some(Point::from_ts_point(capture.node.start_position().into()));
1647 }
1648 }
1649
1650 if let Some((start, end)) = start.zip(end) {
1651 if start.row == end.row {
1652 continue;
1653 }
1654
1655 let range = start..end;
1656 match indentation_ranges.binary_search_by_key(&range.start, |r| r.0.start) {
1657 Err(ix) => indentation_ranges.insert(ix, (range, node_kind)),
1658 Ok(ix) => {
1659 let prev_range = &mut indentation_ranges[ix];
1660 prev_range.0.end = prev_range.0.end.max(range.end);
1661 }
1662 }
1663 }
1664 }
1665
1666 let mut prev_row = prev_non_blank_row.unwrap_or(0);
1667 Some(row_range.map(move |row| {
1668 let row_start = Point::new(row, self.indent_column_for_line(row));
1669
1670 let mut indent_from_prev_row = false;
1671 let mut outdent_to_row = u32::MAX;
1672 for (range, _node_kind) in &indentation_ranges {
1673 if range.start.row >= row {
1674 break;
1675 }
1676
1677 if range.start.row == prev_row && range.end > row_start {
1678 indent_from_prev_row = true;
1679 }
1680 if range.end.row >= prev_row && range.end <= row_start {
1681 outdent_to_row = outdent_to_row.min(range.start.row);
1682 }
1683 }
1684
1685 let suggestion = if outdent_to_row == prev_row {
1686 IndentSuggestion {
1687 basis_row: prev_row,
1688 indent: false,
1689 }
1690 } else if indent_from_prev_row {
1691 IndentSuggestion {
1692 basis_row: prev_row,
1693 indent: true,
1694 }
1695 } else if outdent_to_row < prev_row {
1696 IndentSuggestion {
1697 basis_row: outdent_to_row,
1698 indent: false,
1699 }
1700 } else {
1701 IndentSuggestion {
1702 basis_row: prev_row,
1703 indent: false,
1704 }
1705 };
1706
1707 prev_row = row;
1708 suggestion
1709 }))
1710 } else {
1711 None
1712 }
1713 }
1714
1715 fn prev_non_blank_row(&self, mut row: u32) -> Option<u32> {
1716 while row > 0 {
1717 row -= 1;
1718 if !self.is_line_blank(row) {
1719 return Some(row);
1720 }
1721 }
1722 None
1723 }
1724
1725 pub fn chunks<'a, T: ToOffset>(
1726 &'a self,
1727 range: Range<T>,
1728 theme: Option<&'a SyntaxTheme>,
1729 ) -> BufferChunks<'a> {
1730 let range = range.start.to_offset(self)..range.end.to_offset(self);
1731
1732 let mut highlights = None;
1733 let mut diagnostic_endpoints = Vec::<DiagnosticEndpoint>::new();
1734 if let Some(theme) = theme {
1735 for entry in self
1736 .diagnostics
1737 .range::<_, usize>(range.clone(), self, true)
1738 {
1739 diagnostic_endpoints.push(DiagnosticEndpoint {
1740 offset: entry.range.start,
1741 is_start: true,
1742 severity: entry.diagnostic.severity,
1743 });
1744 diagnostic_endpoints.push(DiagnosticEndpoint {
1745 offset: entry.range.end,
1746 is_start: false,
1747 severity: entry.diagnostic.severity,
1748 });
1749 }
1750 diagnostic_endpoints
1751 .sort_unstable_by_key(|endpoint| (endpoint.offset, !endpoint.is_start));
1752
1753 if let Some((grammar, tree)) = self.grammar().zip(self.tree.as_ref()) {
1754 let mut query_cursor = QueryCursorHandle::new();
1755
1756 // TODO - add a Tree-sitter API to remove the need for this.
1757 let cursor = unsafe {
1758 std::mem::transmute::<_, &'static mut QueryCursor>(query_cursor.deref_mut())
1759 };
1760 let captures = cursor.set_byte_range(range.clone()).captures(
1761 &grammar.highlights_query,
1762 tree.root_node(),
1763 TextProvider(self.text.as_rope()),
1764 );
1765 highlights = Some(BufferChunkHighlights {
1766 captures,
1767 next_capture: None,
1768 stack: Default::default(),
1769 highlight_map: grammar.highlight_map(),
1770 _query_cursor: query_cursor,
1771 theme,
1772 })
1773 }
1774 }
1775
1776 let diagnostic_endpoints = diagnostic_endpoints.into_iter().peekable();
1777 let chunks = self.text.as_rope().chunks_in_range(range.clone());
1778
1779 BufferChunks {
1780 range,
1781 chunks,
1782 diagnostic_endpoints,
1783 error_depth: 0,
1784 warning_depth: 0,
1785 information_depth: 0,
1786 hint_depth: 0,
1787 highlights,
1788 }
1789 }
1790
1791 pub fn language(&self) -> Option<&Arc<Language>> {
1792 self.language.as_ref()
1793 }
1794
1795 fn grammar(&self) -> Option<&Arc<Grammar>> {
1796 self.language
1797 .as_ref()
1798 .and_then(|language| language.grammar.as_ref())
1799 }
1800
1801 pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
1802 if let Some(tree) = self.tree.as_ref() {
1803 let root = tree.root_node();
1804 let range = range.start.to_offset(self)..range.end.to_offset(self);
1805 let mut node = root.descendant_for_byte_range(range.start, range.end);
1806 while node.map_or(false, |n| n.byte_range() == range) {
1807 node = node.unwrap().parent();
1808 }
1809 node.map(|n| n.byte_range())
1810 } else {
1811 None
1812 }
1813 }
1814
1815 pub fn enclosing_bracket_ranges<T: ToOffset>(
1816 &self,
1817 range: Range<T>,
1818 ) -> Option<(Range<usize>, Range<usize>)> {
1819 let (grammar, tree) = self.grammar().zip(self.tree.as_ref())?;
1820 let open_capture_ix = grammar.brackets_query.capture_index_for_name("open")?;
1821 let close_capture_ix = grammar.brackets_query.capture_index_for_name("close")?;
1822
1823 // Find bracket pairs that *inclusively* contain the given range.
1824 let range = range.start.to_offset(self).saturating_sub(1)..range.end.to_offset(self) + 1;
1825 let mut cursor = QueryCursorHandle::new();
1826 let matches = cursor.set_byte_range(range).matches(
1827 &grammar.brackets_query,
1828 tree.root_node(),
1829 TextProvider(self.as_rope()),
1830 );
1831
1832 // Get the ranges of the innermost pair of brackets.
1833 matches
1834 .filter_map(|mat| {
1835 let open = mat.nodes_for_capture_index(open_capture_ix).next()?;
1836 let close = mat.nodes_for_capture_index(close_capture_ix).next()?;
1837 Some((open.byte_range(), close.byte_range()))
1838 })
1839 .min_by_key(|(open_range, close_range)| close_range.end - open_range.start)
1840 }
1841
1842 pub fn remote_selections_in_range<'a>(
1843 &'a self,
1844 range: Range<Anchor>,
1845 ) -> impl 'a + Iterator<Item = (ReplicaId, impl 'a + Iterator<Item = &'a Selection<Anchor>>)>
1846 {
1847 self.remote_selections
1848 .iter()
1849 .filter(|(replica_id, _)| **replica_id != self.text.replica_id())
1850 .map(move |(replica_id, selections)| {
1851 let start_ix = match selections
1852 .binary_search_by(|probe| probe.end.cmp(&range.start, self).unwrap())
1853 {
1854 Ok(ix) | Err(ix) => ix,
1855 };
1856 let end_ix = match selections
1857 .binary_search_by(|probe| probe.start.cmp(&range.end, self).unwrap())
1858 {
1859 Ok(ix) | Err(ix) => ix,
1860 };
1861
1862 (*replica_id, selections[start_ix..end_ix].iter())
1863 })
1864 }
1865
1866 pub fn diagnostics_in_range<'a, T, O>(
1867 &'a self,
1868 search_range: Range<T>,
1869 ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>>
1870 where
1871 T: 'a + ToOffset,
1872 O: 'a + FromAnchor,
1873 {
1874 self.diagnostics.range(search_range, self, true)
1875 }
1876
1877 pub fn diagnostic_groups<O>(&self) -> Vec<DiagnosticGroup<O>>
1878 where
1879 O: FromAnchor + Ord + Copy,
1880 {
1881 self.diagnostics.groups(self)
1882 }
1883
1884 pub fn diagnostic_group<'a, O>(
1885 &'a self,
1886 group_id: usize,
1887 ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>>
1888 where
1889 O: 'a + FromAnchor,
1890 {
1891 self.diagnostics.group(group_id, self)
1892 }
1893
1894 pub fn diagnostics_update_count(&self) -> usize {
1895 self.diagnostics_update_count
1896 }
1897
1898 pub fn parse_count(&self) -> usize {
1899 self.parse_count
1900 }
1901}
1902
1903impl Clone for BufferSnapshot {
1904 fn clone(&self) -> Self {
1905 Self {
1906 text: self.text.clone(),
1907 tree: self.tree.clone(),
1908 remote_selections: self.remote_selections.clone(),
1909 diagnostics: self.diagnostics.clone(),
1910 diagnostics_update_count: self.diagnostics_update_count,
1911 is_parsing: self.is_parsing,
1912 language: self.language.clone(),
1913 parse_count: self.parse_count,
1914 }
1915 }
1916}
1917
1918impl Deref for BufferSnapshot {
1919 type Target = text::BufferSnapshot;
1920
1921 fn deref(&self) -> &Self::Target {
1922 &self.text
1923 }
1924}
1925
1926impl<'a> tree_sitter::TextProvider<'a> for TextProvider<'a> {
1927 type I = ByteChunks<'a>;
1928
1929 fn text(&mut self, node: tree_sitter::Node) -> Self::I {
1930 ByteChunks(self.0.chunks_in_range(node.byte_range()))
1931 }
1932}
1933
1934struct ByteChunks<'a>(rope::Chunks<'a>);
1935
1936impl<'a> Iterator for ByteChunks<'a> {
1937 type Item = &'a [u8];
1938
1939 fn next(&mut self) -> Option<Self::Item> {
1940 self.0.next().map(str::as_bytes)
1941 }
1942}
1943
1944unsafe impl<'a> Send for BufferChunks<'a> {}
1945
1946impl<'a> BufferChunks<'a> {
1947 pub fn seek(&mut self, offset: usize) {
1948 self.range.start = offset;
1949 self.chunks.seek(self.range.start);
1950 if let Some(highlights) = self.highlights.as_mut() {
1951 highlights
1952 .stack
1953 .retain(|(end_offset, _)| *end_offset > offset);
1954 if let Some((mat, capture_ix)) = &highlights.next_capture {
1955 let capture = mat.captures[*capture_ix as usize];
1956 if offset >= capture.node.start_byte() {
1957 let next_capture_end = capture.node.end_byte();
1958 if offset < next_capture_end {
1959 highlights.stack.push((
1960 next_capture_end,
1961 highlights.highlight_map.get(capture.index),
1962 ));
1963 }
1964 highlights.next_capture.take();
1965 }
1966 }
1967 highlights.captures.set_byte_range(self.range.clone());
1968 }
1969 }
1970
1971 pub fn offset(&self) -> usize {
1972 self.range.start
1973 }
1974
1975 fn update_diagnostic_depths(&mut self, endpoint: DiagnosticEndpoint) {
1976 let depth = match endpoint.severity {
1977 DiagnosticSeverity::ERROR => &mut self.error_depth,
1978 DiagnosticSeverity::WARNING => &mut self.warning_depth,
1979 DiagnosticSeverity::INFORMATION => &mut self.information_depth,
1980 DiagnosticSeverity::HINT => &mut self.hint_depth,
1981 _ => return,
1982 };
1983 if endpoint.is_start {
1984 *depth += 1;
1985 } else {
1986 *depth -= 1;
1987 }
1988 }
1989
1990 fn current_diagnostic_severity(&mut self) -> Option<DiagnosticSeverity> {
1991 if self.error_depth > 0 {
1992 Some(DiagnosticSeverity::ERROR)
1993 } else if self.warning_depth > 0 {
1994 Some(DiagnosticSeverity::WARNING)
1995 } else if self.information_depth > 0 {
1996 Some(DiagnosticSeverity::INFORMATION)
1997 } else if self.hint_depth > 0 {
1998 Some(DiagnosticSeverity::HINT)
1999 } else {
2000 None
2001 }
2002 }
2003}
2004
2005impl<'a> Iterator for BufferChunks<'a> {
2006 type Item = Chunk<'a>;
2007
2008 fn next(&mut self) -> Option<Self::Item> {
2009 let mut next_capture_start = usize::MAX;
2010 let mut next_diagnostic_endpoint = usize::MAX;
2011
2012 if let Some(highlights) = self.highlights.as_mut() {
2013 while let Some((parent_capture_end, _)) = highlights.stack.last() {
2014 if *parent_capture_end <= self.range.start {
2015 highlights.stack.pop();
2016 } else {
2017 break;
2018 }
2019 }
2020
2021 if highlights.next_capture.is_none() {
2022 highlights.next_capture = highlights.captures.next();
2023 }
2024
2025 while let Some((mat, capture_ix)) = highlights.next_capture.as_ref() {
2026 let capture = mat.captures[*capture_ix as usize];
2027 if self.range.start < capture.node.start_byte() {
2028 next_capture_start = capture.node.start_byte();
2029 break;
2030 } else {
2031 let highlight_id = highlights.highlight_map.get(capture.index);
2032 highlights
2033 .stack
2034 .push((capture.node.end_byte(), highlight_id));
2035 highlights.next_capture = highlights.captures.next();
2036 }
2037 }
2038 }
2039
2040 while let Some(endpoint) = self.diagnostic_endpoints.peek().copied() {
2041 if endpoint.offset <= self.range.start {
2042 self.update_diagnostic_depths(endpoint);
2043 self.diagnostic_endpoints.next();
2044 } else {
2045 next_diagnostic_endpoint = endpoint.offset;
2046 break;
2047 }
2048 }
2049
2050 if let Some(chunk) = self.chunks.peek() {
2051 let chunk_start = self.range.start;
2052 let mut chunk_end = (self.chunks.offset() + chunk.len())
2053 .min(next_capture_start)
2054 .min(next_diagnostic_endpoint);
2055 let mut highlight_style = None;
2056 if let Some(highlights) = self.highlights.as_ref() {
2057 if let Some((parent_capture_end, parent_highlight_id)) = highlights.stack.last() {
2058 chunk_end = chunk_end.min(*parent_capture_end);
2059 highlight_style = parent_highlight_id.style(highlights.theme);
2060 }
2061 }
2062
2063 let slice =
2064 &chunk[chunk_start - self.chunks.offset()..chunk_end - self.chunks.offset()];
2065 self.range.start = chunk_end;
2066 if self.range.start == self.chunks.offset() + chunk.len() {
2067 self.chunks.next().unwrap();
2068 }
2069
2070 Some(Chunk {
2071 text: slice,
2072 highlight_style,
2073 diagnostic: self.current_diagnostic_severity(),
2074 })
2075 } else {
2076 None
2077 }
2078 }
2079}
2080
2081impl QueryCursorHandle {
2082 fn new() -> Self {
2083 QueryCursorHandle(Some(
2084 QUERY_CURSORS
2085 .lock()
2086 .pop()
2087 .unwrap_or_else(|| QueryCursor::new()),
2088 ))
2089 }
2090}
2091
2092impl Deref for QueryCursorHandle {
2093 type Target = QueryCursor;
2094
2095 fn deref(&self) -> &Self::Target {
2096 self.0.as_ref().unwrap()
2097 }
2098}
2099
2100impl DerefMut for QueryCursorHandle {
2101 fn deref_mut(&mut self) -> &mut Self::Target {
2102 self.0.as_mut().unwrap()
2103 }
2104}
2105
2106impl Drop for QueryCursorHandle {
2107 fn drop(&mut self) {
2108 let mut cursor = self.0.take().unwrap();
2109 cursor.set_byte_range(0..usize::MAX);
2110 cursor.set_point_range(Point::zero().to_ts_point()..Point::MAX.to_ts_point());
2111 QUERY_CURSORS.lock().push(cursor)
2112 }
2113}
2114
2115trait ToTreeSitterPoint {
2116 fn to_ts_point(self) -> tree_sitter::Point;
2117 fn from_ts_point(point: tree_sitter::Point) -> Self;
2118}
2119
2120impl ToTreeSitterPoint for Point {
2121 fn to_ts_point(self) -> tree_sitter::Point {
2122 tree_sitter::Point::new(self.row as usize, self.column as usize)
2123 }
2124
2125 fn from_ts_point(point: tree_sitter::Point) -> Self {
2126 Point::new(point.row as u32, point.column as u32)
2127 }
2128}
2129
2130impl operation_queue::Operation for Operation {
2131 fn lamport_timestamp(&self) -> clock::Lamport {
2132 match self {
2133 Operation::Buffer(_) => {
2134 unreachable!("buffer operations should never be deferred at this layer")
2135 }
2136 Operation::UpdateDiagnostics {
2137 lamport_timestamp, ..
2138 }
2139 | Operation::UpdateSelections {
2140 lamport_timestamp, ..
2141 }
2142 | Operation::RemoveSelections {
2143 lamport_timestamp, ..
2144 } => *lamport_timestamp,
2145 }
2146 }
2147}
2148
2149impl Default for Diagnostic {
2150 fn default() -> Self {
2151 Self {
2152 source: Default::default(),
2153 code: Default::default(),
2154 severity: DiagnosticSeverity::ERROR,
2155 message: Default::default(),
2156 group_id: Default::default(),
2157 is_primary: Default::default(),
2158 is_valid: true,
2159 }
2160 }
2161}
2162
2163pub fn contiguous_ranges(
2164 values: impl Iterator<Item = u32>,
2165 max_len: usize,
2166) -> impl Iterator<Item = Range<u32>> {
2167 let mut values = values.into_iter();
2168 let mut current_range: Option<Range<u32>> = None;
2169 std::iter::from_fn(move || loop {
2170 if let Some(value) = values.next() {
2171 if let Some(range) = &mut current_range {
2172 if value == range.end && range.len() < max_len {
2173 range.end += 1;
2174 continue;
2175 }
2176 }
2177
2178 let prev_range = current_range.clone();
2179 current_range = Some(value..(value + 1));
2180 if prev_range.is_some() {
2181 return prev_range;
2182 }
2183 } else {
2184 return current_range.take();
2185 }
2186 })
2187}