1pub use crate::{
2 diagnostic_set::DiagnosticSet,
3 highlight_map::{HighlightId, HighlightMap},
4 markdown::ParsedMarkdown,
5 proto, BracketPair, Grammar, Language, LanguageConfig, LanguageRegistry, PLAIN_TEXT,
6};
7use crate::{
8 diagnostic_set::{DiagnosticEntry, DiagnosticGroup},
9 language_settings::{language_settings, LanguageSettings},
10 markdown::parse_markdown,
11 outline::OutlineItem,
12 syntax_map::{
13 SyntaxLayerInfo, SyntaxMap, SyntaxMapCapture, SyntaxMapCaptures, SyntaxMapMatches,
14 SyntaxSnapshot, ToTreeSitterPoint,
15 },
16 CodeLabel, LanguageScope, Outline,
17};
18use anyhow::{anyhow, Result};
19pub use clock::ReplicaId;
20use futures::channel::oneshot;
21use gpui::{fonts::HighlightStyle, AppContext, Entity, ModelContext, Task};
22use lsp::LanguageServerId;
23use parking_lot::Mutex;
24use similar::{ChangeTag, TextDiff};
25use smallvec::SmallVec;
26use smol::future::yield_now;
27use std::{
28 any::Any,
29 cmp::{self, Ordering},
30 collections::BTreeMap,
31 ffi::OsStr,
32 future::Future,
33 iter::{self, Iterator, Peekable},
34 mem,
35 ops::{Deref, Range},
36 path::{Path, PathBuf},
37 str,
38 sync::Arc,
39 time::{Duration, Instant, SystemTime, UNIX_EPOCH},
40 vec,
41};
42use sum_tree::TreeMap;
43use text::operation_queue::OperationQueue;
44pub use text::{Buffer as TextBuffer, BufferSnapshot as TextBufferSnapshot, *};
45use theme::SyntaxTheme;
46#[cfg(any(test, feature = "test-support"))]
47use util::RandomCharIter;
48use util::RangeExt;
49
50#[cfg(any(test, feature = "test-support"))]
51pub use {tree_sitter_rust, tree_sitter_typescript};
52
53pub use lsp::DiagnosticSeverity;
54
55pub struct Buffer {
56 text: TextBuffer,
57 diff_base: Option<String>,
58 git_diff: git::diff::BufferDiff,
59 file: Option<Arc<dyn File>>,
60 saved_version: clock::Global,
61 saved_version_fingerprint: RopeFingerprint,
62 saved_mtime: SystemTime,
63 transaction_depth: usize,
64 was_dirty_before_starting_transaction: Option<bool>,
65 reload_task: Option<Task<Result<()>>>,
66 language: Option<Arc<Language>>,
67 autoindent_requests: Vec<Arc<AutoindentRequest>>,
68 pending_autoindent: Option<Task<()>>,
69 sync_parse_timeout: Duration,
70 syntax_map: Mutex<SyntaxMap>,
71 parsing_in_background: bool,
72 parse_count: usize,
73 diagnostics: SmallVec<[(LanguageServerId, DiagnosticSet); 2]>,
74 remote_selections: TreeMap<ReplicaId, SelectionSet>,
75 selections_update_count: usize,
76 diagnostics_update_count: usize,
77 diagnostics_timestamp: clock::Lamport,
78 file_update_count: usize,
79 git_diff_update_count: usize,
80 completion_triggers: Vec<String>,
81 completion_triggers_timestamp: clock::Lamport,
82 deferred_ops: OperationQueue<Operation>,
83}
84
85pub struct BufferSnapshot {
86 text: text::BufferSnapshot,
87 pub git_diff: git::diff::BufferDiff,
88 pub(crate) syntax: SyntaxSnapshot,
89 file: Option<Arc<dyn File>>,
90 diagnostics: SmallVec<[(LanguageServerId, DiagnosticSet); 2]>,
91 diagnostics_update_count: usize,
92 file_update_count: usize,
93 git_diff_update_count: usize,
94 remote_selections: TreeMap<ReplicaId, SelectionSet>,
95 selections_update_count: usize,
96 language: Option<Arc<Language>>,
97 parse_count: usize,
98}
99
100#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
101pub struct IndentSize {
102 pub len: u32,
103 pub kind: IndentKind,
104}
105
106#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
107pub enum IndentKind {
108 #[default]
109 Space,
110 Tab,
111}
112
113#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
114pub enum CursorShape {
115 #[default]
116 Bar,
117 Block,
118 Underscore,
119 Hollow,
120}
121
122#[derive(Clone, Debug)]
123struct SelectionSet {
124 line_mode: bool,
125 cursor_shape: CursorShape,
126 selections: Arc<[Selection<Anchor>]>,
127 lamport_timestamp: clock::Lamport,
128}
129
130#[derive(Clone, Debug, PartialEq, Eq)]
131pub struct GroupId {
132 source: Arc<str>,
133 id: usize,
134}
135
136#[derive(Clone, Debug, PartialEq, Eq)]
137pub struct Diagnostic {
138 pub source: Option<String>,
139 pub code: Option<String>,
140 pub severity: DiagnosticSeverity,
141 pub message: String,
142 pub group_id: usize,
143 pub is_valid: bool,
144 pub is_primary: bool,
145 pub is_disk_based: bool,
146 pub is_unnecessary: bool,
147}
148
149pub async fn prepare_completion_documentation(
150 documentation: &lsp::Documentation,
151 language_registry: &Arc<LanguageRegistry>,
152 language: Option<Arc<Language>>,
153) -> Documentation {
154 match documentation {
155 lsp::Documentation::String(text) => {
156 if text.lines().count() <= 1 {
157 Documentation::SingleLine(text.clone())
158 } else {
159 Documentation::MultiLinePlainText(text.clone())
160 }
161 }
162
163 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
164 lsp::MarkupKind::PlainText => {
165 if value.lines().count() <= 1 {
166 Documentation::SingleLine(value.clone())
167 } else {
168 Documentation::MultiLinePlainText(value.clone())
169 }
170 }
171
172 lsp::MarkupKind::Markdown => {
173 let parsed = parse_markdown(value, language_registry, language).await;
174 Documentation::MultiLineMarkdown(parsed)
175 }
176 },
177 }
178}
179
180#[derive(Clone, Debug)]
181pub enum Documentation {
182 Undocumented,
183 SingleLine(String),
184 MultiLinePlainText(String),
185 MultiLineMarkdown(ParsedMarkdown),
186}
187
188#[derive(Clone, Debug)]
189pub struct Completion {
190 pub old_range: Range<Anchor>,
191 pub new_text: String,
192 pub label: CodeLabel,
193 pub documentation: Option<Documentation>,
194 pub server_id: LanguageServerId,
195 pub lsp_completion: lsp::CompletionItem,
196}
197
198#[derive(Clone, Debug)]
199pub struct CodeAction {
200 pub server_id: LanguageServerId,
201 pub range: Range<Anchor>,
202 pub lsp_action: lsp::CodeAction,
203}
204
205#[derive(Clone, Debug, PartialEq)]
206pub enum Operation {
207 Buffer(text::Operation),
208
209 UpdateDiagnostics {
210 server_id: LanguageServerId,
211 diagnostics: Arc<[DiagnosticEntry<Anchor>]>,
212 lamport_timestamp: clock::Lamport,
213 },
214
215 UpdateSelections {
216 selections: Arc<[Selection<Anchor>]>,
217 lamport_timestamp: clock::Lamport,
218 line_mode: bool,
219 cursor_shape: CursorShape,
220 },
221
222 UpdateCompletionTriggers {
223 triggers: Vec<String>,
224 lamport_timestamp: clock::Lamport,
225 },
226}
227
228#[derive(Clone, Debug, PartialEq)]
229pub enum Event {
230 Operation(Operation),
231 Edited,
232 DirtyChanged,
233 Saved,
234 FileHandleChanged,
235 Reloaded,
236 DiffBaseChanged,
237 LanguageChanged,
238 Reparsed,
239 DiagnosticsUpdated,
240 Closed,
241}
242
243pub trait File: Send + Sync {
244 fn as_local(&self) -> Option<&dyn LocalFile>;
245
246 fn is_local(&self) -> bool {
247 self.as_local().is_some()
248 }
249
250 fn mtime(&self) -> SystemTime;
251
252 /// Returns the path of this file relative to the worktree's root directory.
253 fn path(&self) -> &Arc<Path>;
254
255 /// Returns the path of this file relative to the worktree's parent directory (this means it
256 /// includes the name of the worktree's root folder).
257 fn full_path(&self, cx: &AppContext) -> PathBuf;
258
259 /// Returns the last component of this handle's absolute path. If this handle refers to the root
260 /// of its worktree, then this method will return the name of the worktree itself.
261 fn file_name<'a>(&'a self, cx: &'a AppContext) -> &'a OsStr;
262
263 /// Returns the id of the worktree to which this file belongs.
264 ///
265 /// This is needed for looking up project-specific settings.
266 fn worktree_id(&self) -> usize;
267
268 fn is_deleted(&self) -> bool;
269
270 fn as_any(&self) -> &dyn Any;
271
272 fn to_proto(&self) -> rpc::proto::File;
273}
274
275pub trait LocalFile: File {
276 /// Returns the absolute path of this file.
277 fn abs_path(&self, cx: &AppContext) -> PathBuf;
278
279 fn load(&self, cx: &AppContext) -> Task<Result<String>>;
280
281 fn buffer_reloaded(
282 &self,
283 buffer_id: u64,
284 version: &clock::Global,
285 fingerprint: RopeFingerprint,
286 line_ending: LineEnding,
287 mtime: SystemTime,
288 cx: &mut AppContext,
289 );
290}
291
292#[derive(Clone, Debug)]
293pub enum AutoindentMode {
294 /// Indent each line of inserted text.
295 EachLine,
296 /// Apply the same indentation adjustment to all of the lines
297 /// in a given insertion.
298 Block {
299 /// The original indentation level of the first line of each
300 /// insertion, if it has been copied.
301 original_indent_columns: Vec<u32>,
302 },
303}
304
305#[derive(Clone)]
306struct AutoindentRequest {
307 before_edit: BufferSnapshot,
308 entries: Vec<AutoindentRequestEntry>,
309 is_block_mode: bool,
310}
311
312#[derive(Clone)]
313struct AutoindentRequestEntry {
314 /// A range of the buffer whose indentation should be adjusted.
315 range: Range<Anchor>,
316 /// Whether or not these lines should be considered brand new, for the
317 /// purpose of auto-indent. When text is not new, its indentation will
318 /// only be adjusted if the suggested indentation level has *changed*
319 /// since the edit was made.
320 first_line_is_new: bool,
321 indent_size: IndentSize,
322 original_indent_column: Option<u32>,
323}
324
325#[derive(Debug)]
326struct IndentSuggestion {
327 basis_row: u32,
328 delta: Ordering,
329 within_error: bool,
330}
331
332struct BufferChunkHighlights<'a> {
333 captures: SyntaxMapCaptures<'a>,
334 next_capture: Option<SyntaxMapCapture<'a>>,
335 stack: Vec<(usize, HighlightId)>,
336 highlight_maps: Vec<HighlightMap>,
337}
338
339pub struct BufferChunks<'a> {
340 range: Range<usize>,
341 chunks: text::Chunks<'a>,
342 diagnostic_endpoints: Peekable<vec::IntoIter<DiagnosticEndpoint>>,
343 error_depth: usize,
344 warning_depth: usize,
345 information_depth: usize,
346 hint_depth: usize,
347 unnecessary_depth: usize,
348 highlights: Option<BufferChunkHighlights<'a>>,
349}
350
351#[derive(Clone, Copy, Debug, Default)]
352pub struct Chunk<'a> {
353 pub text: &'a str,
354 pub syntax_highlight_id: Option<HighlightId>,
355 pub highlight_style: Option<HighlightStyle>,
356 pub diagnostic_severity: Option<DiagnosticSeverity>,
357 pub is_unnecessary: bool,
358 pub is_tab: bool,
359}
360
361pub struct Diff {
362 pub(crate) base_version: clock::Global,
363 line_ending: LineEnding,
364 edits: Vec<(Range<usize>, Arc<str>)>,
365}
366
367#[derive(Clone, Copy)]
368pub(crate) struct DiagnosticEndpoint {
369 offset: usize,
370 is_start: bool,
371 severity: DiagnosticSeverity,
372 is_unnecessary: bool,
373}
374
375#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug)]
376pub enum CharKind {
377 Whitespace,
378 Punctuation,
379 Word,
380}
381
382impl CharKind {
383 pub fn coerce_punctuation(self, treat_punctuation_as_word: bool) -> Self {
384 if treat_punctuation_as_word && self == CharKind::Punctuation {
385 CharKind::Word
386 } else {
387 self
388 }
389 }
390}
391
392impl Buffer {
393 pub fn new<T: Into<String>>(replica_id: ReplicaId, id: u64, base_text: T) -> Self {
394 Self::build(
395 TextBuffer::new(replica_id, id, base_text.into()),
396 None,
397 None,
398 )
399 }
400
401 pub fn remote(remote_id: u64, replica_id: ReplicaId, base_text: String) -> Self {
402 Self::build(
403 TextBuffer::new(replica_id, remote_id, base_text),
404 None,
405 None,
406 )
407 }
408
409 pub fn from_proto(
410 replica_id: ReplicaId,
411 message: proto::BufferState,
412 file: Option<Arc<dyn File>>,
413 ) -> Result<Self> {
414 let buffer = TextBuffer::new(replica_id, message.id, message.base_text);
415 let mut this = Self::build(
416 buffer,
417 message.diff_base.map(|text| text.into_boxed_str().into()),
418 file,
419 );
420 this.text.set_line_ending(proto::deserialize_line_ending(
421 rpc::proto::LineEnding::from_i32(message.line_ending)
422 .ok_or_else(|| anyhow!("missing line_ending"))?,
423 ));
424 this.saved_version = proto::deserialize_version(&message.saved_version);
425 this.saved_version_fingerprint =
426 proto::deserialize_fingerprint(&message.saved_version_fingerprint)?;
427 this.saved_mtime = message
428 .saved_mtime
429 .ok_or_else(|| anyhow!("invalid saved_mtime"))?
430 .into();
431 Ok(this)
432 }
433
434 pub fn to_proto(&self) -> proto::BufferState {
435 proto::BufferState {
436 id: self.remote_id(),
437 file: self.file.as_ref().map(|f| f.to_proto()),
438 base_text: self.base_text().to_string(),
439 diff_base: self.diff_base.as_ref().map(|h| h.to_string()),
440 line_ending: proto::serialize_line_ending(self.line_ending()) as i32,
441 saved_version: proto::serialize_version(&self.saved_version),
442 saved_version_fingerprint: proto::serialize_fingerprint(self.saved_version_fingerprint),
443 saved_mtime: Some(self.saved_mtime.into()),
444 }
445 }
446
447 pub fn serialize_ops(
448 &self,
449 since: Option<clock::Global>,
450 cx: &AppContext,
451 ) -> Task<Vec<proto::Operation>> {
452 let mut operations = Vec::new();
453 operations.extend(self.deferred_ops.iter().map(proto::serialize_operation));
454
455 operations.extend(self.remote_selections.iter().map(|(_, set)| {
456 proto::serialize_operation(&Operation::UpdateSelections {
457 selections: set.selections.clone(),
458 lamport_timestamp: set.lamport_timestamp,
459 line_mode: set.line_mode,
460 cursor_shape: set.cursor_shape,
461 })
462 }));
463
464 for (server_id, diagnostics) in &self.diagnostics {
465 operations.push(proto::serialize_operation(&Operation::UpdateDiagnostics {
466 lamport_timestamp: self.diagnostics_timestamp,
467 server_id: *server_id,
468 diagnostics: diagnostics.iter().cloned().collect(),
469 }));
470 }
471
472 operations.push(proto::serialize_operation(
473 &Operation::UpdateCompletionTriggers {
474 triggers: self.completion_triggers.clone(),
475 lamport_timestamp: self.completion_triggers_timestamp,
476 },
477 ));
478
479 let text_operations = self.text.operations().clone();
480 cx.background().spawn(async move {
481 let since = since.unwrap_or_default();
482 operations.extend(
483 text_operations
484 .iter()
485 .filter(|(_, op)| !since.observed(op.timestamp()))
486 .map(|(_, op)| proto::serialize_operation(&Operation::Buffer(op.clone()))),
487 );
488 operations.sort_unstable_by_key(proto::lamport_timestamp_for_operation);
489 operations
490 })
491 }
492
493 pub fn with_language(mut self, language: Arc<Language>, cx: &mut ModelContext<Self>) -> Self {
494 self.set_language(Some(language), cx);
495 self
496 }
497
498 pub fn build(
499 buffer: TextBuffer,
500 diff_base: Option<String>,
501 file: Option<Arc<dyn File>>,
502 ) -> Self {
503 let saved_mtime = if let Some(file) = file.as_ref() {
504 file.mtime()
505 } else {
506 UNIX_EPOCH
507 };
508
509 Self {
510 saved_mtime,
511 saved_version: buffer.version(),
512 saved_version_fingerprint: buffer.as_rope().fingerprint(),
513 reload_task: None,
514 transaction_depth: 0,
515 was_dirty_before_starting_transaction: None,
516 text: buffer,
517 diff_base,
518 git_diff: git::diff::BufferDiff::new(),
519 file,
520 syntax_map: Mutex::new(SyntaxMap::new()),
521 parsing_in_background: false,
522 parse_count: 0,
523 sync_parse_timeout: Duration::from_millis(1),
524 autoindent_requests: Default::default(),
525 pending_autoindent: Default::default(),
526 language: None,
527 remote_selections: Default::default(),
528 selections_update_count: 0,
529 diagnostics: Default::default(),
530 diagnostics_update_count: 0,
531 diagnostics_timestamp: Default::default(),
532 file_update_count: 0,
533 git_diff_update_count: 0,
534 completion_triggers: Default::default(),
535 completion_triggers_timestamp: Default::default(),
536 deferred_ops: OperationQueue::new(),
537 }
538 }
539
540 pub fn snapshot(&self) -> BufferSnapshot {
541 let text = self.text.snapshot();
542 let mut syntax_map = self.syntax_map.lock();
543 syntax_map.interpolate(&text);
544 let syntax = syntax_map.snapshot();
545
546 BufferSnapshot {
547 text,
548 syntax,
549 git_diff: self.git_diff.clone(),
550 file: self.file.clone(),
551 remote_selections: self.remote_selections.clone(),
552 diagnostics: self.diagnostics.clone(),
553 diagnostics_update_count: self.diagnostics_update_count,
554 file_update_count: self.file_update_count,
555 git_diff_update_count: self.git_diff_update_count,
556 language: self.language.clone(),
557 parse_count: self.parse_count,
558 selections_update_count: self.selections_update_count,
559 }
560 }
561
562 pub fn as_text_snapshot(&self) -> &text::BufferSnapshot {
563 &self.text
564 }
565
566 pub fn text_snapshot(&self) -> text::BufferSnapshot {
567 self.text.snapshot()
568 }
569
570 pub fn file(&self) -> Option<&Arc<dyn File>> {
571 self.file.as_ref()
572 }
573
574 pub fn saved_version(&self) -> &clock::Global {
575 &self.saved_version
576 }
577
578 pub fn saved_version_fingerprint(&self) -> RopeFingerprint {
579 self.saved_version_fingerprint
580 }
581
582 pub fn saved_mtime(&self) -> SystemTime {
583 self.saved_mtime
584 }
585
586 pub fn set_language(&mut self, language: Option<Arc<Language>>, cx: &mut ModelContext<Self>) {
587 self.syntax_map.lock().clear();
588 self.language = language;
589 self.reparse(cx);
590 cx.emit(Event::LanguageChanged);
591 }
592
593 pub fn set_language_registry(&mut self, language_registry: Arc<LanguageRegistry>) {
594 self.syntax_map
595 .lock()
596 .set_language_registry(language_registry);
597 }
598
599 pub fn did_save(
600 &mut self,
601 version: clock::Global,
602 fingerprint: RopeFingerprint,
603 mtime: SystemTime,
604 cx: &mut ModelContext<Self>,
605 ) {
606 self.saved_version = version;
607 self.saved_version_fingerprint = fingerprint;
608 self.saved_mtime = mtime;
609 cx.emit(Event::Saved);
610 cx.notify();
611 }
612
613 pub fn reload(
614 &mut self,
615 cx: &mut ModelContext<Self>,
616 ) -> oneshot::Receiver<Option<Transaction>> {
617 let (tx, rx) = futures::channel::oneshot::channel();
618 let prev_version = self.text.version();
619 self.reload_task = Some(cx.spawn(|this, mut cx| async move {
620 let Some((new_mtime, new_text)) = this.update(&mut cx, |this, cx| {
621 let file = this.file.as_ref()?.as_local()?;
622 Some((file.mtime(), file.load(cx)))
623 }) else {
624 return Ok(());
625 };
626
627 let new_text = new_text.await?;
628 let diff = this
629 .update(&mut cx, |this, cx| this.diff(new_text.clone(), cx))
630 .await;
631 this.update(&mut cx, |this, cx| {
632 if this.version() == diff.base_version {
633 this.finalize_last_transaction();
634 this.apply_diff(diff, cx);
635 tx.send(this.finalize_last_transaction().cloned()).ok();
636
637 this.did_reload(
638 this.version(),
639 this.as_rope().fingerprint(),
640 this.line_ending(),
641 new_mtime,
642 cx,
643 );
644 } else {
645 this.did_reload(
646 prev_version,
647 Rope::text_fingerprint(&new_text),
648 this.line_ending(),
649 this.saved_mtime,
650 cx,
651 );
652 }
653
654 this.reload_task.take();
655 });
656 Ok(())
657 }));
658 rx
659 }
660
661 pub fn did_reload(
662 &mut self,
663 version: clock::Global,
664 fingerprint: RopeFingerprint,
665 line_ending: LineEnding,
666 mtime: SystemTime,
667 cx: &mut ModelContext<Self>,
668 ) {
669 self.saved_version = version;
670 self.saved_version_fingerprint = fingerprint;
671 self.text.set_line_ending(line_ending);
672 self.saved_mtime = mtime;
673 if let Some(file) = self.file.as_ref().and_then(|f| f.as_local()) {
674 file.buffer_reloaded(
675 self.remote_id(),
676 &self.saved_version,
677 self.saved_version_fingerprint,
678 self.line_ending(),
679 self.saved_mtime,
680 cx,
681 );
682 }
683 cx.emit(Event::Reloaded);
684 cx.notify();
685 }
686
687 pub fn file_updated(&mut self, new_file: Arc<dyn File>, cx: &mut ModelContext<Self>) {
688 let mut file_changed = false;
689
690 if let Some(old_file) = self.file.as_ref() {
691 if new_file.path() != old_file.path() {
692 file_changed = true;
693 }
694
695 if new_file.is_deleted() {
696 if !old_file.is_deleted() {
697 file_changed = true;
698 if !self.is_dirty() {
699 cx.emit(Event::DirtyChanged);
700 }
701 }
702 } else {
703 let new_mtime = new_file.mtime();
704 if new_mtime != old_file.mtime() {
705 file_changed = true;
706
707 if !self.is_dirty() {
708 self.reload(cx).close();
709 }
710 }
711 }
712 } else {
713 file_changed = true;
714 };
715
716 self.file = Some(new_file);
717 if file_changed {
718 self.file_update_count += 1;
719 cx.emit(Event::FileHandleChanged);
720 cx.notify();
721 }
722 }
723
724 pub fn diff_base(&self) -> Option<&str> {
725 self.diff_base.as_deref()
726 }
727
728 pub fn set_diff_base(&mut self, diff_base: Option<String>, cx: &mut ModelContext<Self>) {
729 self.diff_base = diff_base;
730 self.git_diff_recalc(cx);
731 cx.emit(Event::DiffBaseChanged);
732 }
733
734 pub fn git_diff_recalc(&mut self, cx: &mut ModelContext<Self>) -> Option<Task<()>> {
735 let diff_base = self.diff_base.clone()?; // TODO: Make this an Arc
736 let snapshot = self.snapshot();
737
738 let mut diff = self.git_diff.clone();
739 let diff = cx.background().spawn(async move {
740 diff.update(&diff_base, &snapshot).await;
741 diff
742 });
743
744 let handle = cx.weak_handle();
745 Some(cx.spawn_weak(|_, mut cx| async move {
746 let buffer_diff = diff.await;
747 if let Some(this) = handle.upgrade(&mut cx) {
748 this.update(&mut cx, |this, _| {
749 this.git_diff = buffer_diff;
750 this.git_diff_update_count += 1;
751 })
752 }
753 }))
754 }
755
756 pub fn close(&mut self, cx: &mut ModelContext<Self>) {
757 cx.emit(Event::Closed);
758 }
759
760 pub fn language(&self) -> Option<&Arc<Language>> {
761 self.language.as_ref()
762 }
763
764 pub fn language_at<D: ToOffset>(&self, position: D) -> Option<Arc<Language>> {
765 let offset = position.to_offset(self);
766 self.syntax_map
767 .lock()
768 .layers_for_range(offset..offset, &self.text)
769 .last()
770 .map(|info| info.language.clone())
771 .or_else(|| self.language.clone())
772 }
773
774 pub fn parse_count(&self) -> usize {
775 self.parse_count
776 }
777
778 pub fn selections_update_count(&self) -> usize {
779 self.selections_update_count
780 }
781
782 pub fn diagnostics_update_count(&self) -> usize {
783 self.diagnostics_update_count
784 }
785
786 pub fn file_update_count(&self) -> usize {
787 self.file_update_count
788 }
789
790 pub fn git_diff_update_count(&self) -> usize {
791 self.git_diff_update_count
792 }
793
794 #[cfg(any(test, feature = "test-support"))]
795 pub fn is_parsing(&self) -> bool {
796 self.parsing_in_background
797 }
798
799 pub fn contains_unknown_injections(&self) -> bool {
800 self.syntax_map.lock().contains_unknown_injections()
801 }
802
803 #[cfg(test)]
804 pub fn set_sync_parse_timeout(&mut self, timeout: Duration) {
805 self.sync_parse_timeout = timeout;
806 }
807
808 /// Called after an edit to synchronize the buffer's main parse tree with
809 /// the buffer's new underlying state.
810 ///
811 /// Locks the syntax map and interpolates the edits since the last reparse
812 /// into the foreground syntax tree.
813 ///
814 /// Then takes a stable snapshot of the syntax map before unlocking it.
815 /// The snapshot with the interpolated edits is sent to a background thread,
816 /// where we ask Tree-sitter to perform an incremental parse.
817 ///
818 /// Meanwhile, in the foreground, we block the main thread for up to 1ms
819 /// waiting on the parse to complete. As soon as it completes, we proceed
820 /// synchronously, unless a 1ms timeout elapses.
821 ///
822 /// If we time out waiting on the parse, we spawn a second task waiting
823 /// until the parse does complete and return with the interpolated tree still
824 /// in the foreground. When the background parse completes, call back into
825 /// the main thread and assign the foreground parse state.
826 ///
827 /// If the buffer or grammar changed since the start of the background parse,
828 /// initiate an additional reparse recursively. To avoid concurrent parses
829 /// for the same buffer, we only initiate a new parse if we are not already
830 /// parsing in the background.
831 pub fn reparse(&mut self, cx: &mut ModelContext<Self>) {
832 if self.parsing_in_background {
833 return;
834 }
835 let language = if let Some(language) = self.language.clone() {
836 language
837 } else {
838 return;
839 };
840
841 let text = self.text_snapshot();
842 let parsed_version = self.version();
843
844 let mut syntax_map = self.syntax_map.lock();
845 syntax_map.interpolate(&text);
846 let language_registry = syntax_map.language_registry();
847 let mut syntax_snapshot = syntax_map.snapshot();
848 drop(syntax_map);
849
850 let parse_task = cx.background().spawn({
851 let language = language.clone();
852 let language_registry = language_registry.clone();
853 async move {
854 syntax_snapshot.reparse(&text, language_registry, language);
855 syntax_snapshot
856 }
857 });
858
859 match cx
860 .background()
861 .block_with_timeout(self.sync_parse_timeout, parse_task)
862 {
863 Ok(new_syntax_snapshot) => {
864 self.did_finish_parsing(new_syntax_snapshot, cx);
865 return;
866 }
867 Err(parse_task) => {
868 self.parsing_in_background = true;
869 cx.spawn(move |this, mut cx| async move {
870 let new_syntax_map = parse_task.await;
871 this.update(&mut cx, move |this, cx| {
872 let grammar_changed =
873 this.language.as_ref().map_or(true, |current_language| {
874 !Arc::ptr_eq(&language, current_language)
875 });
876 let language_registry_changed = new_syntax_map
877 .contains_unknown_injections()
878 && language_registry.map_or(false, |registry| {
879 registry.version() != new_syntax_map.language_registry_version()
880 });
881 let parse_again = language_registry_changed
882 || grammar_changed
883 || this.version.changed_since(&parsed_version);
884 this.did_finish_parsing(new_syntax_map, cx);
885 this.parsing_in_background = false;
886 if parse_again {
887 this.reparse(cx);
888 }
889 });
890 })
891 .detach();
892 }
893 }
894 }
895
896 fn did_finish_parsing(&mut self, syntax_snapshot: SyntaxSnapshot, cx: &mut ModelContext<Self>) {
897 self.parse_count += 1;
898 self.syntax_map.lock().did_parse(syntax_snapshot);
899 self.request_autoindent(cx);
900 cx.emit(Event::Reparsed);
901 cx.notify();
902 }
903
904 pub fn update_diagnostics(
905 &mut self,
906 server_id: LanguageServerId,
907 diagnostics: DiagnosticSet,
908 cx: &mut ModelContext<Self>,
909 ) {
910 let lamport_timestamp = self.text.lamport_clock.tick();
911 let op = Operation::UpdateDiagnostics {
912 server_id,
913 diagnostics: diagnostics.iter().cloned().collect(),
914 lamport_timestamp,
915 };
916 self.apply_diagnostic_update(server_id, diagnostics, lamport_timestamp, cx);
917 self.send_operation(op, cx);
918 }
919
920 fn request_autoindent(&mut self, cx: &mut ModelContext<Self>) {
921 if let Some(indent_sizes) = self.compute_autoindents() {
922 let indent_sizes = cx.background().spawn(indent_sizes);
923 match cx
924 .background()
925 .block_with_timeout(Duration::from_micros(500), indent_sizes)
926 {
927 Ok(indent_sizes) => self.apply_autoindents(indent_sizes, cx),
928 Err(indent_sizes) => {
929 self.pending_autoindent = Some(cx.spawn(|this, mut cx| async move {
930 let indent_sizes = indent_sizes.await;
931 this.update(&mut cx, |this, cx| {
932 this.apply_autoindents(indent_sizes, cx);
933 });
934 }));
935 }
936 }
937 } else {
938 self.autoindent_requests.clear();
939 }
940 }
941
942 fn compute_autoindents(&self) -> Option<impl Future<Output = BTreeMap<u32, IndentSize>>> {
943 let max_rows_between_yields = 100;
944 let snapshot = self.snapshot();
945 if snapshot.syntax.is_empty() || self.autoindent_requests.is_empty() {
946 return None;
947 }
948
949 let autoindent_requests = self.autoindent_requests.clone();
950 Some(async move {
951 let mut indent_sizes = BTreeMap::new();
952 for request in autoindent_requests {
953 // Resolve each edited range to its row in the current buffer and in the
954 // buffer before this batch of edits.
955 let mut row_ranges = Vec::new();
956 let mut old_to_new_rows = BTreeMap::new();
957 let mut language_indent_sizes_by_new_row = Vec::new();
958 for entry in &request.entries {
959 let position = entry.range.start;
960 let new_row = position.to_point(&snapshot).row;
961 let new_end_row = entry.range.end.to_point(&snapshot).row + 1;
962 language_indent_sizes_by_new_row.push((new_row, entry.indent_size));
963
964 if !entry.first_line_is_new {
965 let old_row = position.to_point(&request.before_edit).row;
966 old_to_new_rows.insert(old_row, new_row);
967 }
968 row_ranges.push((new_row..new_end_row, entry.original_indent_column));
969 }
970
971 // Build a map containing the suggested indentation for each of the edited lines
972 // with respect to the state of the buffer before these edits. This map is keyed
973 // by the rows for these lines in the current state of the buffer.
974 let mut old_suggestions = BTreeMap::<u32, (IndentSize, bool)>::default();
975 let old_edited_ranges =
976 contiguous_ranges(old_to_new_rows.keys().copied(), max_rows_between_yields);
977 let mut language_indent_sizes = language_indent_sizes_by_new_row.iter().peekable();
978 let mut language_indent_size = IndentSize::default();
979 for old_edited_range in old_edited_ranges {
980 let suggestions = request
981 .before_edit
982 .suggest_autoindents(old_edited_range.clone())
983 .into_iter()
984 .flatten();
985 for (old_row, suggestion) in old_edited_range.zip(suggestions) {
986 if let Some(suggestion) = suggestion {
987 let new_row = *old_to_new_rows.get(&old_row).unwrap();
988
989 // Find the indent size based on the language for this row.
990 while let Some((row, size)) = language_indent_sizes.peek() {
991 if *row > new_row {
992 break;
993 }
994 language_indent_size = *size;
995 language_indent_sizes.next();
996 }
997
998 let suggested_indent = old_to_new_rows
999 .get(&suggestion.basis_row)
1000 .and_then(|from_row| {
1001 Some(old_suggestions.get(from_row).copied()?.0)
1002 })
1003 .unwrap_or_else(|| {
1004 request
1005 .before_edit
1006 .indent_size_for_line(suggestion.basis_row)
1007 })
1008 .with_delta(suggestion.delta, language_indent_size);
1009 old_suggestions
1010 .insert(new_row, (suggested_indent, suggestion.within_error));
1011 }
1012 }
1013 yield_now().await;
1014 }
1015
1016 // In block mode, only compute indentation suggestions for the first line
1017 // of each insertion. Otherwise, compute suggestions for every inserted line.
1018 let new_edited_row_ranges = contiguous_ranges(
1019 row_ranges.iter().flat_map(|(range, _)| {
1020 if request.is_block_mode {
1021 range.start..range.start + 1
1022 } else {
1023 range.clone()
1024 }
1025 }),
1026 max_rows_between_yields,
1027 );
1028
1029 // Compute new suggestions for each line, but only include them in the result
1030 // if they differ from the old suggestion for that line.
1031 let mut language_indent_sizes = language_indent_sizes_by_new_row.iter().peekable();
1032 let mut language_indent_size = IndentSize::default();
1033 for new_edited_row_range in new_edited_row_ranges {
1034 let suggestions = snapshot
1035 .suggest_autoindents(new_edited_row_range.clone())
1036 .into_iter()
1037 .flatten();
1038 for (new_row, suggestion) in new_edited_row_range.zip(suggestions) {
1039 if let Some(suggestion) = suggestion {
1040 // Find the indent size based on the language for this row.
1041 while let Some((row, size)) = language_indent_sizes.peek() {
1042 if *row > new_row {
1043 break;
1044 }
1045 language_indent_size = *size;
1046 language_indent_sizes.next();
1047 }
1048
1049 let suggested_indent = indent_sizes
1050 .get(&suggestion.basis_row)
1051 .copied()
1052 .unwrap_or_else(|| {
1053 snapshot.indent_size_for_line(suggestion.basis_row)
1054 })
1055 .with_delta(suggestion.delta, language_indent_size);
1056 if old_suggestions.get(&new_row).map_or(
1057 true,
1058 |(old_indentation, was_within_error)| {
1059 suggested_indent != *old_indentation
1060 && (!suggestion.within_error || *was_within_error)
1061 },
1062 ) {
1063 indent_sizes.insert(new_row, suggested_indent);
1064 }
1065 }
1066 }
1067 yield_now().await;
1068 }
1069
1070 // For each block of inserted text, adjust the indentation of the remaining
1071 // lines of the block by the same amount as the first line was adjusted.
1072 if request.is_block_mode {
1073 for (row_range, original_indent_column) in
1074 row_ranges
1075 .into_iter()
1076 .filter_map(|(range, original_indent_column)| {
1077 if range.len() > 1 {
1078 Some((range, original_indent_column?))
1079 } else {
1080 None
1081 }
1082 })
1083 {
1084 let new_indent = indent_sizes
1085 .get(&row_range.start)
1086 .copied()
1087 .unwrap_or_else(|| snapshot.indent_size_for_line(row_range.start));
1088 let delta = new_indent.len as i64 - original_indent_column as i64;
1089 if delta != 0 {
1090 for row in row_range.skip(1) {
1091 indent_sizes.entry(row).or_insert_with(|| {
1092 let mut size = snapshot.indent_size_for_line(row);
1093 if size.kind == new_indent.kind {
1094 match delta.cmp(&0) {
1095 Ordering::Greater => size.len += delta as u32,
1096 Ordering::Less => {
1097 size.len = size.len.saturating_sub(-delta as u32)
1098 }
1099 Ordering::Equal => {}
1100 }
1101 }
1102 size
1103 });
1104 }
1105 }
1106 }
1107 }
1108 }
1109
1110 indent_sizes
1111 })
1112 }
1113
1114 fn apply_autoindents(
1115 &mut self,
1116 indent_sizes: BTreeMap<u32, IndentSize>,
1117 cx: &mut ModelContext<Self>,
1118 ) {
1119 self.autoindent_requests.clear();
1120
1121 let edits: Vec<_> = indent_sizes
1122 .into_iter()
1123 .filter_map(|(row, indent_size)| {
1124 let current_size = indent_size_for_line(self, row);
1125 Self::edit_for_indent_size_adjustment(row, current_size, indent_size)
1126 })
1127 .collect();
1128
1129 self.edit(edits, None, cx);
1130 }
1131
1132 // Create a minimal edit that will cause the the given row to be indented
1133 // with the given size. After applying this edit, the length of the line
1134 // will always be at least `new_size.len`.
1135 pub fn edit_for_indent_size_adjustment(
1136 row: u32,
1137 current_size: IndentSize,
1138 new_size: IndentSize,
1139 ) -> Option<(Range<Point>, String)> {
1140 if new_size.kind != current_size.kind {
1141 Some((
1142 Point::new(row, 0)..Point::new(row, current_size.len),
1143 iter::repeat(new_size.char())
1144 .take(new_size.len as usize)
1145 .collect::<String>(),
1146 ))
1147 } else {
1148 match new_size.len.cmp(¤t_size.len) {
1149 Ordering::Greater => {
1150 let point = Point::new(row, 0);
1151 Some((
1152 point..point,
1153 iter::repeat(new_size.char())
1154 .take((new_size.len - current_size.len) as usize)
1155 .collect::<String>(),
1156 ))
1157 }
1158
1159 Ordering::Less => Some((
1160 Point::new(row, 0)..Point::new(row, current_size.len - new_size.len),
1161 String::new(),
1162 )),
1163
1164 Ordering::Equal => None,
1165 }
1166 }
1167 }
1168
1169 pub fn diff(&self, mut new_text: String, cx: &AppContext) -> Task<Diff> {
1170 let old_text = self.as_rope().clone();
1171 let base_version = self.version();
1172 cx.background().spawn(async move {
1173 let old_text = old_text.to_string();
1174 let line_ending = LineEnding::detect(&new_text);
1175 LineEnding::normalize(&mut new_text);
1176 let diff = TextDiff::from_chars(old_text.as_str(), new_text.as_str());
1177 let mut edits = Vec::new();
1178 let mut offset = 0;
1179 let empty: Arc<str> = "".into();
1180 for change in diff.iter_all_changes() {
1181 let value = change.value();
1182 let end_offset = offset + value.len();
1183 match change.tag() {
1184 ChangeTag::Equal => {
1185 offset = end_offset;
1186 }
1187 ChangeTag::Delete => {
1188 edits.push((offset..end_offset, empty.clone()));
1189 offset = end_offset;
1190 }
1191 ChangeTag::Insert => {
1192 edits.push((offset..offset, value.into()));
1193 }
1194 }
1195 }
1196 Diff {
1197 base_version,
1198 line_ending,
1199 edits,
1200 }
1201 })
1202 }
1203
1204 /// Spawn a background task that searches the buffer for any whitespace
1205 /// at the ends of a lines, and returns a `Diff` that removes that whitespace.
1206 pub fn remove_trailing_whitespace(&self, cx: &AppContext) -> Task<Diff> {
1207 let old_text = self.as_rope().clone();
1208 let line_ending = self.line_ending();
1209 let base_version = self.version();
1210 cx.background().spawn(async move {
1211 let ranges = trailing_whitespace_ranges(&old_text);
1212 let empty = Arc::<str>::from("");
1213 Diff {
1214 base_version,
1215 line_ending,
1216 edits: ranges
1217 .into_iter()
1218 .map(|range| (range, empty.clone()))
1219 .collect(),
1220 }
1221 })
1222 }
1223
1224 /// Ensure that the buffer ends with a single newline character, and
1225 /// no other whitespace.
1226 pub fn ensure_final_newline(&mut self, cx: &mut ModelContext<Self>) {
1227 let len = self.len();
1228 let mut offset = len;
1229 for chunk in self.as_rope().reversed_chunks_in_range(0..len) {
1230 let non_whitespace_len = chunk
1231 .trim_end_matches(|c: char| c.is_ascii_whitespace())
1232 .len();
1233 offset -= chunk.len();
1234 offset += non_whitespace_len;
1235 if non_whitespace_len != 0 {
1236 if offset == len - 1 && chunk.get(non_whitespace_len..) == Some("\n") {
1237 return;
1238 }
1239 break;
1240 }
1241 }
1242 self.edit([(offset..len, "\n")], None, cx);
1243 }
1244
1245 /// Apply a diff to the buffer. If the buffer has changed since the given diff was
1246 /// calculated, then adjust the diff to account for those changes, and discard any
1247 /// parts of the diff that conflict with those changes.
1248 pub fn apply_diff(&mut self, diff: Diff, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1249 // Check for any edits to the buffer that have occurred since this diff
1250 // was computed.
1251 let snapshot = self.snapshot();
1252 let mut edits_since = snapshot.edits_since::<usize>(&diff.base_version).peekable();
1253 let mut delta = 0;
1254 let adjusted_edits = diff.edits.into_iter().filter_map(|(range, new_text)| {
1255 while let Some(edit_since) = edits_since.peek() {
1256 // If the edit occurs after a diff hunk, then it does not
1257 // affect that hunk.
1258 if edit_since.old.start > range.end {
1259 break;
1260 }
1261 // If the edit precedes the diff hunk, then adjust the hunk
1262 // to reflect the edit.
1263 else if edit_since.old.end < range.start {
1264 delta += edit_since.new_len() as i64 - edit_since.old_len() as i64;
1265 edits_since.next();
1266 }
1267 // If the edit intersects a diff hunk, then discard that hunk.
1268 else {
1269 return None;
1270 }
1271 }
1272
1273 let start = (range.start as i64 + delta) as usize;
1274 let end = (range.end as i64 + delta) as usize;
1275 Some((start..end, new_text))
1276 });
1277
1278 self.start_transaction();
1279 self.text.set_line_ending(diff.line_ending);
1280 self.edit(adjusted_edits, None, cx);
1281 self.end_transaction(cx)
1282 }
1283
1284 pub fn is_dirty(&self) -> bool {
1285 self.saved_version_fingerprint != self.as_rope().fingerprint()
1286 || self.file.as_ref().map_or(false, |file| file.is_deleted())
1287 }
1288
1289 pub fn has_conflict(&self) -> bool {
1290 self.saved_version_fingerprint != self.as_rope().fingerprint()
1291 && self
1292 .file
1293 .as_ref()
1294 .map_or(false, |file| file.mtime() > self.saved_mtime)
1295 }
1296
1297 pub fn subscribe(&mut self) -> Subscription {
1298 self.text.subscribe()
1299 }
1300
1301 pub fn start_transaction(&mut self) -> Option<TransactionId> {
1302 self.start_transaction_at(Instant::now())
1303 }
1304
1305 pub fn start_transaction_at(&mut self, now: Instant) -> Option<TransactionId> {
1306 self.transaction_depth += 1;
1307 if self.was_dirty_before_starting_transaction.is_none() {
1308 self.was_dirty_before_starting_transaction = Some(self.is_dirty());
1309 }
1310 self.text.start_transaction_at(now)
1311 }
1312
1313 pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1314 self.end_transaction_at(Instant::now(), cx)
1315 }
1316
1317 pub fn end_transaction_at(
1318 &mut self,
1319 now: Instant,
1320 cx: &mut ModelContext<Self>,
1321 ) -> Option<TransactionId> {
1322 assert!(self.transaction_depth > 0);
1323 self.transaction_depth -= 1;
1324 let was_dirty = if self.transaction_depth == 0 {
1325 self.was_dirty_before_starting_transaction.take().unwrap()
1326 } else {
1327 false
1328 };
1329 if let Some((transaction_id, start_version)) = self.text.end_transaction_at(now) {
1330 self.did_edit(&start_version, was_dirty, cx);
1331 Some(transaction_id)
1332 } else {
1333 None
1334 }
1335 }
1336
1337 pub fn push_transaction(&mut self, transaction: Transaction, now: Instant) {
1338 self.text.push_transaction(transaction, now);
1339 }
1340
1341 pub fn finalize_last_transaction(&mut self) -> Option<&Transaction> {
1342 self.text.finalize_last_transaction()
1343 }
1344
1345 pub fn group_until_transaction(&mut self, transaction_id: TransactionId) {
1346 self.text.group_until_transaction(transaction_id);
1347 }
1348
1349 pub fn forget_transaction(&mut self, transaction_id: TransactionId) {
1350 self.text.forget_transaction(transaction_id);
1351 }
1352
1353 pub fn merge_transactions(&mut self, transaction: TransactionId, destination: TransactionId) {
1354 self.text.merge_transactions(transaction, destination);
1355 }
1356
1357 pub fn wait_for_edits(
1358 &mut self,
1359 edit_ids: impl IntoIterator<Item = clock::Lamport>,
1360 ) -> impl Future<Output = Result<()>> {
1361 self.text.wait_for_edits(edit_ids)
1362 }
1363
1364 pub fn wait_for_anchors(
1365 &mut self,
1366 anchors: impl IntoIterator<Item = Anchor>,
1367 ) -> impl 'static + Future<Output = Result<()>> {
1368 self.text.wait_for_anchors(anchors)
1369 }
1370
1371 pub fn wait_for_version(&mut self, version: clock::Global) -> impl Future<Output = Result<()>> {
1372 self.text.wait_for_version(version)
1373 }
1374
1375 pub fn give_up_waiting(&mut self) {
1376 self.text.give_up_waiting();
1377 }
1378
1379 pub fn set_active_selections(
1380 &mut self,
1381 selections: Arc<[Selection<Anchor>]>,
1382 line_mode: bool,
1383 cursor_shape: CursorShape,
1384 cx: &mut ModelContext<Self>,
1385 ) {
1386 let lamport_timestamp = self.text.lamport_clock.tick();
1387 self.remote_selections.insert(
1388 self.text.replica_id(),
1389 SelectionSet {
1390 selections: selections.clone(),
1391 lamport_timestamp,
1392 line_mode,
1393 cursor_shape,
1394 },
1395 );
1396 self.send_operation(
1397 Operation::UpdateSelections {
1398 selections,
1399 line_mode,
1400 lamport_timestamp,
1401 cursor_shape,
1402 },
1403 cx,
1404 );
1405 }
1406
1407 pub fn remove_active_selections(&mut self, cx: &mut ModelContext<Self>) {
1408 if self
1409 .remote_selections
1410 .get(&self.text.replica_id())
1411 .map_or(true, |set| !set.selections.is_empty())
1412 {
1413 self.set_active_selections(Arc::from([]), false, Default::default(), cx);
1414 }
1415 }
1416
1417 pub fn set_text<T>(&mut self, text: T, cx: &mut ModelContext<Self>) -> Option<clock::Lamport>
1418 where
1419 T: Into<Arc<str>>,
1420 {
1421 self.autoindent_requests.clear();
1422 self.edit([(0..self.len(), text)], None, cx)
1423 }
1424
1425 pub fn edit<I, S, T>(
1426 &mut self,
1427 edits_iter: I,
1428 autoindent_mode: Option<AutoindentMode>,
1429 cx: &mut ModelContext<Self>,
1430 ) -> Option<clock::Lamport>
1431 where
1432 I: IntoIterator<Item = (Range<S>, T)>,
1433 S: ToOffset,
1434 T: Into<Arc<str>>,
1435 {
1436 // Skip invalid edits and coalesce contiguous ones.
1437 let mut edits: Vec<(Range<usize>, Arc<str>)> = Vec::new();
1438 for (range, new_text) in edits_iter {
1439 let mut range = range.start.to_offset(self)..range.end.to_offset(self);
1440 if range.start > range.end {
1441 mem::swap(&mut range.start, &mut range.end);
1442 }
1443 let new_text = new_text.into();
1444 if !new_text.is_empty() || !range.is_empty() {
1445 if let Some((prev_range, prev_text)) = edits.last_mut() {
1446 if prev_range.end >= range.start {
1447 prev_range.end = cmp::max(prev_range.end, range.end);
1448 *prev_text = format!("{prev_text}{new_text}").into();
1449 } else {
1450 edits.push((range, new_text));
1451 }
1452 } else {
1453 edits.push((range, new_text));
1454 }
1455 }
1456 }
1457 if edits.is_empty() {
1458 return None;
1459 }
1460
1461 // Non-generic part hoisted out to reduce LLVM IR size.
1462 fn tail(
1463 this: &mut Buffer,
1464 edits: Vec<(Range<usize>, Arc<str>)>,
1465 autoindent_mode: Option<AutoindentMode>,
1466 cx: &mut ModelContext<Buffer>,
1467 ) -> Option<clock::Lamport> {
1468 this.start_transaction();
1469 this.pending_autoindent.take();
1470 let autoindent_request = autoindent_mode
1471 .and_then(|mode| this.language.as_ref().map(|_| (this.snapshot(), mode)));
1472
1473 let edit_operation = this.text.edit(edits.iter().cloned());
1474 let edit_id = edit_operation.timestamp();
1475
1476 if let Some((before_edit, mode)) = autoindent_request {
1477 let mut delta = 0isize;
1478 let entries = edits
1479 .into_iter()
1480 .enumerate()
1481 .zip(&edit_operation.as_edit().unwrap().new_text)
1482 .map(|((ix, (range, _)), new_text)| {
1483 let new_text_length = new_text.len();
1484 let old_start = range.start.to_point(&before_edit);
1485 let new_start = (delta + range.start as isize) as usize;
1486 delta +=
1487 new_text_length as isize - (range.end as isize - range.start as isize);
1488
1489 let mut range_of_insertion_to_indent = 0..new_text_length;
1490 let mut first_line_is_new = false;
1491 let mut original_indent_column = None;
1492
1493 // When inserting an entire line at the beginning of an existing line,
1494 // treat the insertion as new.
1495 if new_text.contains('\n')
1496 && old_start.column
1497 <= before_edit.indent_size_for_line(old_start.row).len
1498 {
1499 first_line_is_new = true;
1500 }
1501
1502 // When inserting text starting with a newline, avoid auto-indenting the
1503 // previous line.
1504 if new_text.starts_with('\n') {
1505 range_of_insertion_to_indent.start += 1;
1506 first_line_is_new = true;
1507 }
1508
1509 // Avoid auto-indenting after the insertion.
1510 if let AutoindentMode::Block {
1511 original_indent_columns,
1512 } = &mode
1513 {
1514 original_indent_column = Some(
1515 original_indent_columns.get(ix).copied().unwrap_or_else(|| {
1516 indent_size_for_text(
1517 new_text[range_of_insertion_to_indent.clone()].chars(),
1518 )
1519 .len
1520 }),
1521 );
1522 if new_text[range_of_insertion_to_indent.clone()].ends_with('\n') {
1523 range_of_insertion_to_indent.end -= 1;
1524 }
1525 }
1526
1527 AutoindentRequestEntry {
1528 first_line_is_new,
1529 original_indent_column,
1530 indent_size: before_edit.language_indent_size_at(range.start, cx),
1531 range: this
1532 .anchor_before(new_start + range_of_insertion_to_indent.start)
1533 ..this.anchor_after(new_start + range_of_insertion_to_indent.end),
1534 }
1535 })
1536 .collect();
1537
1538 this.autoindent_requests.push(Arc::new(AutoindentRequest {
1539 before_edit,
1540 entries,
1541 is_block_mode: matches!(mode, AutoindentMode::Block { .. }),
1542 }));
1543 }
1544
1545 this.end_transaction(cx);
1546 this.send_operation(Operation::Buffer(edit_operation), cx);
1547 Some(edit_id)
1548 }
1549 tail(self, edits, autoindent_mode, cx)
1550 }
1551
1552 fn did_edit(
1553 &mut self,
1554 old_version: &clock::Global,
1555 was_dirty: bool,
1556 cx: &mut ModelContext<Self>,
1557 ) {
1558 if self.edits_since::<usize>(old_version).next().is_none() {
1559 return;
1560 }
1561
1562 self.reparse(cx);
1563
1564 cx.emit(Event::Edited);
1565 if was_dirty != self.is_dirty() {
1566 cx.emit(Event::DirtyChanged);
1567 }
1568 cx.notify();
1569 }
1570
1571 pub fn apply_ops<I: IntoIterator<Item = Operation>>(
1572 &mut self,
1573 ops: I,
1574 cx: &mut ModelContext<Self>,
1575 ) -> Result<()> {
1576 self.pending_autoindent.take();
1577 let was_dirty = self.is_dirty();
1578 let old_version = self.version.clone();
1579 let mut deferred_ops = Vec::new();
1580 let buffer_ops = ops
1581 .into_iter()
1582 .filter_map(|op| match op {
1583 Operation::Buffer(op) => Some(op),
1584 _ => {
1585 if self.can_apply_op(&op) {
1586 self.apply_op(op, cx);
1587 } else {
1588 deferred_ops.push(op);
1589 }
1590 None
1591 }
1592 })
1593 .collect::<Vec<_>>();
1594 self.text.apply_ops(buffer_ops)?;
1595 self.deferred_ops.insert(deferred_ops);
1596 self.flush_deferred_ops(cx);
1597 self.did_edit(&old_version, was_dirty, cx);
1598 // Notify independently of whether the buffer was edited as the operations could include a
1599 // selection update.
1600 cx.notify();
1601 Ok(())
1602 }
1603
1604 fn flush_deferred_ops(&mut self, cx: &mut ModelContext<Self>) {
1605 let mut deferred_ops = Vec::new();
1606 for op in self.deferred_ops.drain().iter().cloned() {
1607 if self.can_apply_op(&op) {
1608 self.apply_op(op, cx);
1609 } else {
1610 deferred_ops.push(op);
1611 }
1612 }
1613 self.deferred_ops.insert(deferred_ops);
1614 }
1615
1616 fn can_apply_op(&self, operation: &Operation) -> bool {
1617 match operation {
1618 Operation::Buffer(_) => {
1619 unreachable!("buffer operations should never be applied at this layer")
1620 }
1621 Operation::UpdateDiagnostics {
1622 diagnostics: diagnostic_set,
1623 ..
1624 } => diagnostic_set.iter().all(|diagnostic| {
1625 self.text.can_resolve(&diagnostic.range.start)
1626 && self.text.can_resolve(&diagnostic.range.end)
1627 }),
1628 Operation::UpdateSelections { selections, .. } => selections
1629 .iter()
1630 .all(|s| self.can_resolve(&s.start) && self.can_resolve(&s.end)),
1631 Operation::UpdateCompletionTriggers { .. } => true,
1632 }
1633 }
1634
1635 fn apply_op(&mut self, operation: Operation, cx: &mut ModelContext<Self>) {
1636 match operation {
1637 Operation::Buffer(_) => {
1638 unreachable!("buffer operations should never be applied at this layer")
1639 }
1640 Operation::UpdateDiagnostics {
1641 server_id,
1642 diagnostics: diagnostic_set,
1643 lamport_timestamp,
1644 } => {
1645 let snapshot = self.snapshot();
1646 self.apply_diagnostic_update(
1647 server_id,
1648 DiagnosticSet::from_sorted_entries(diagnostic_set.iter().cloned(), &snapshot),
1649 lamport_timestamp,
1650 cx,
1651 );
1652 }
1653 Operation::UpdateSelections {
1654 selections,
1655 lamport_timestamp,
1656 line_mode,
1657 cursor_shape,
1658 } => {
1659 if let Some(set) = self.remote_selections.get(&lamport_timestamp.replica_id) {
1660 if set.lamport_timestamp > lamport_timestamp {
1661 return;
1662 }
1663 }
1664
1665 self.remote_selections.insert(
1666 lamport_timestamp.replica_id,
1667 SelectionSet {
1668 selections,
1669 lamport_timestamp,
1670 line_mode,
1671 cursor_shape,
1672 },
1673 );
1674 self.text.lamport_clock.observe(lamport_timestamp);
1675 self.selections_update_count += 1;
1676 }
1677 Operation::UpdateCompletionTriggers {
1678 triggers,
1679 lamport_timestamp,
1680 } => {
1681 self.completion_triggers = triggers;
1682 self.text.lamport_clock.observe(lamport_timestamp);
1683 }
1684 }
1685 }
1686
1687 fn apply_diagnostic_update(
1688 &mut self,
1689 server_id: LanguageServerId,
1690 diagnostics: DiagnosticSet,
1691 lamport_timestamp: clock::Lamport,
1692 cx: &mut ModelContext<Self>,
1693 ) {
1694 if lamport_timestamp > self.diagnostics_timestamp {
1695 let ix = self.diagnostics.binary_search_by_key(&server_id, |e| e.0);
1696 if diagnostics.len() == 0 {
1697 if let Ok(ix) = ix {
1698 self.diagnostics.remove(ix);
1699 }
1700 } else {
1701 match ix {
1702 Err(ix) => self.diagnostics.insert(ix, (server_id, diagnostics)),
1703 Ok(ix) => self.diagnostics[ix].1 = diagnostics,
1704 };
1705 }
1706 self.diagnostics_timestamp = lamport_timestamp;
1707 self.diagnostics_update_count += 1;
1708 self.text.lamport_clock.observe(lamport_timestamp);
1709 cx.notify();
1710 cx.emit(Event::DiagnosticsUpdated);
1711 }
1712 }
1713
1714 fn send_operation(&mut self, operation: Operation, cx: &mut ModelContext<Self>) {
1715 cx.emit(Event::Operation(operation));
1716 }
1717
1718 pub fn remove_peer(&mut self, replica_id: ReplicaId, cx: &mut ModelContext<Self>) {
1719 self.remote_selections.remove(&replica_id);
1720 cx.notify();
1721 }
1722
1723 pub fn undo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1724 let was_dirty = self.is_dirty();
1725 let old_version = self.version.clone();
1726
1727 if let Some((transaction_id, operation)) = self.text.undo() {
1728 self.send_operation(Operation::Buffer(operation), cx);
1729 self.did_edit(&old_version, was_dirty, cx);
1730 Some(transaction_id)
1731 } else {
1732 None
1733 }
1734 }
1735
1736 pub fn undo_transaction(
1737 &mut self,
1738 transaction_id: TransactionId,
1739 cx: &mut ModelContext<Self>,
1740 ) -> bool {
1741 let was_dirty = self.is_dirty();
1742 let old_version = self.version.clone();
1743 if let Some(operation) = self.text.undo_transaction(transaction_id) {
1744 self.send_operation(Operation::Buffer(operation), cx);
1745 self.did_edit(&old_version, was_dirty, cx);
1746 true
1747 } else {
1748 false
1749 }
1750 }
1751
1752 pub fn undo_to_transaction(
1753 &mut self,
1754 transaction_id: TransactionId,
1755 cx: &mut ModelContext<Self>,
1756 ) -> bool {
1757 let was_dirty = self.is_dirty();
1758 let old_version = self.version.clone();
1759
1760 let operations = self.text.undo_to_transaction(transaction_id);
1761 let undone = !operations.is_empty();
1762 for operation in operations {
1763 self.send_operation(Operation::Buffer(operation), cx);
1764 }
1765 if undone {
1766 self.did_edit(&old_version, was_dirty, cx)
1767 }
1768 undone
1769 }
1770
1771 pub fn redo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
1772 let was_dirty = self.is_dirty();
1773 let old_version = self.version.clone();
1774
1775 if let Some((transaction_id, operation)) = self.text.redo() {
1776 self.send_operation(Operation::Buffer(operation), cx);
1777 self.did_edit(&old_version, was_dirty, cx);
1778 Some(transaction_id)
1779 } else {
1780 None
1781 }
1782 }
1783
1784 pub fn redo_to_transaction(
1785 &mut self,
1786 transaction_id: TransactionId,
1787 cx: &mut ModelContext<Self>,
1788 ) -> bool {
1789 let was_dirty = self.is_dirty();
1790 let old_version = self.version.clone();
1791
1792 let operations = self.text.redo_to_transaction(transaction_id);
1793 let redone = !operations.is_empty();
1794 for operation in operations {
1795 self.send_operation(Operation::Buffer(operation), cx);
1796 }
1797 if redone {
1798 self.did_edit(&old_version, was_dirty, cx)
1799 }
1800 redone
1801 }
1802
1803 pub fn set_completion_triggers(&mut self, triggers: Vec<String>, cx: &mut ModelContext<Self>) {
1804 self.completion_triggers = triggers.clone();
1805 self.completion_triggers_timestamp = self.text.lamport_clock.tick();
1806 self.send_operation(
1807 Operation::UpdateCompletionTriggers {
1808 triggers,
1809 lamport_timestamp: self.completion_triggers_timestamp,
1810 },
1811 cx,
1812 );
1813 cx.notify();
1814 }
1815
1816 pub fn completion_triggers(&self) -> &[String] {
1817 &self.completion_triggers
1818 }
1819}
1820
1821#[cfg(any(test, feature = "test-support"))]
1822impl Buffer {
1823 pub fn edit_via_marked_text(
1824 &mut self,
1825 marked_string: &str,
1826 autoindent_mode: Option<AutoindentMode>,
1827 cx: &mut ModelContext<Self>,
1828 ) {
1829 let edits = self.edits_for_marked_text(marked_string);
1830 self.edit(edits, autoindent_mode, cx);
1831 }
1832
1833 pub fn set_group_interval(&mut self, group_interval: Duration) {
1834 self.text.set_group_interval(group_interval);
1835 }
1836
1837 pub fn randomly_edit<T>(
1838 &mut self,
1839 rng: &mut T,
1840 old_range_count: usize,
1841 cx: &mut ModelContext<Self>,
1842 ) where
1843 T: rand::Rng,
1844 {
1845 let mut edits: Vec<(Range<usize>, String)> = Vec::new();
1846 let mut last_end = None;
1847 for _ in 0..old_range_count {
1848 if last_end.map_or(false, |last_end| last_end >= self.len()) {
1849 break;
1850 }
1851
1852 let new_start = last_end.map_or(0, |last_end| last_end + 1);
1853 let mut range = self.random_byte_range(new_start, rng);
1854 if rng.gen_bool(0.2) {
1855 mem::swap(&mut range.start, &mut range.end);
1856 }
1857 last_end = Some(range.end);
1858
1859 let new_text_len = rng.gen_range(0..10);
1860 let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
1861
1862 edits.push((range, new_text));
1863 }
1864 log::info!("mutating buffer {} with {:?}", self.replica_id(), edits);
1865 self.edit(edits, None, cx);
1866 }
1867
1868 pub fn randomly_undo_redo(&mut self, rng: &mut impl rand::Rng, cx: &mut ModelContext<Self>) {
1869 let was_dirty = self.is_dirty();
1870 let old_version = self.version.clone();
1871
1872 let ops = self.text.randomly_undo_redo(rng);
1873 if !ops.is_empty() {
1874 for op in ops {
1875 self.send_operation(Operation::Buffer(op), cx);
1876 self.did_edit(&old_version, was_dirty, cx);
1877 }
1878 }
1879 }
1880}
1881
1882impl Entity for Buffer {
1883 type Event = Event;
1884}
1885
1886impl Deref for Buffer {
1887 type Target = TextBuffer;
1888
1889 fn deref(&self) -> &Self::Target {
1890 &self.text
1891 }
1892}
1893
1894impl BufferSnapshot {
1895 pub fn indent_size_for_line(&self, row: u32) -> IndentSize {
1896 indent_size_for_line(self, row)
1897 }
1898
1899 pub fn language_indent_size_at<T: ToOffset>(&self, position: T, cx: &AppContext) -> IndentSize {
1900 let settings = language_settings(self.language_at(position), self.file(), cx);
1901 if settings.hard_tabs {
1902 IndentSize::tab()
1903 } else {
1904 IndentSize::spaces(settings.tab_size.get())
1905 }
1906 }
1907
1908 pub fn suggested_indents(
1909 &self,
1910 rows: impl Iterator<Item = u32>,
1911 single_indent_size: IndentSize,
1912 ) -> BTreeMap<u32, IndentSize> {
1913 let mut result = BTreeMap::new();
1914
1915 for row_range in contiguous_ranges(rows, 10) {
1916 let suggestions = match self.suggest_autoindents(row_range.clone()) {
1917 Some(suggestions) => suggestions,
1918 _ => break,
1919 };
1920
1921 for (row, suggestion) in row_range.zip(suggestions) {
1922 let indent_size = if let Some(suggestion) = suggestion {
1923 result
1924 .get(&suggestion.basis_row)
1925 .copied()
1926 .unwrap_or_else(|| self.indent_size_for_line(suggestion.basis_row))
1927 .with_delta(suggestion.delta, single_indent_size)
1928 } else {
1929 self.indent_size_for_line(row)
1930 };
1931
1932 result.insert(row, indent_size);
1933 }
1934 }
1935
1936 result
1937 }
1938
1939 fn suggest_autoindents(
1940 &self,
1941 row_range: Range<u32>,
1942 ) -> Option<impl Iterator<Item = Option<IndentSuggestion>> + '_> {
1943 let config = &self.language.as_ref()?.config;
1944 let prev_non_blank_row = self.prev_non_blank_row(row_range.start);
1945
1946 // Find the suggested indentation ranges based on the syntax tree.
1947 let start = Point::new(prev_non_blank_row.unwrap_or(row_range.start), 0);
1948 let end = Point::new(row_range.end, 0);
1949 let range = (start..end).to_offset(&self.text);
1950 let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
1951 Some(&grammar.indents_config.as_ref()?.query)
1952 });
1953 let indent_configs = matches
1954 .grammars()
1955 .iter()
1956 .map(|grammar| grammar.indents_config.as_ref().unwrap())
1957 .collect::<Vec<_>>();
1958
1959 let mut indent_ranges = Vec::<Range<Point>>::new();
1960 let mut outdent_positions = Vec::<Point>::new();
1961 while let Some(mat) = matches.peek() {
1962 let mut start: Option<Point> = None;
1963 let mut end: Option<Point> = None;
1964
1965 let config = &indent_configs[mat.grammar_index];
1966 for capture in mat.captures {
1967 if capture.index == config.indent_capture_ix {
1968 start.get_or_insert(Point::from_ts_point(capture.node.start_position()));
1969 end.get_or_insert(Point::from_ts_point(capture.node.end_position()));
1970 } else if Some(capture.index) == config.start_capture_ix {
1971 start = Some(Point::from_ts_point(capture.node.end_position()));
1972 } else if Some(capture.index) == config.end_capture_ix {
1973 end = Some(Point::from_ts_point(capture.node.start_position()));
1974 } else if Some(capture.index) == config.outdent_capture_ix {
1975 outdent_positions.push(Point::from_ts_point(capture.node.start_position()));
1976 }
1977 }
1978
1979 matches.advance();
1980 if let Some((start, end)) = start.zip(end) {
1981 if start.row == end.row {
1982 continue;
1983 }
1984
1985 let range = start..end;
1986 match indent_ranges.binary_search_by_key(&range.start, |r| r.start) {
1987 Err(ix) => indent_ranges.insert(ix, range),
1988 Ok(ix) => {
1989 let prev_range = &mut indent_ranges[ix];
1990 prev_range.end = prev_range.end.max(range.end);
1991 }
1992 }
1993 }
1994 }
1995
1996 let mut error_ranges = Vec::<Range<Point>>::new();
1997 let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
1998 Some(&grammar.error_query)
1999 });
2000 while let Some(mat) = matches.peek() {
2001 let node = mat.captures[0].node;
2002 let start = Point::from_ts_point(node.start_position());
2003 let end = Point::from_ts_point(node.end_position());
2004 let range = start..end;
2005 let ix = match error_ranges.binary_search_by_key(&range.start, |r| r.start) {
2006 Ok(ix) | Err(ix) => ix,
2007 };
2008 let mut end_ix = ix;
2009 while let Some(existing_range) = error_ranges.get(end_ix) {
2010 if existing_range.end < end {
2011 end_ix += 1;
2012 } else {
2013 break;
2014 }
2015 }
2016 error_ranges.splice(ix..end_ix, [range]);
2017 matches.advance();
2018 }
2019
2020 outdent_positions.sort();
2021 for outdent_position in outdent_positions {
2022 // find the innermost indent range containing this outdent_position
2023 // set its end to the outdent position
2024 if let Some(range_to_truncate) = indent_ranges
2025 .iter_mut()
2026 .filter(|indent_range| indent_range.contains(&outdent_position))
2027 .last()
2028 {
2029 range_to_truncate.end = outdent_position;
2030 }
2031 }
2032
2033 // Find the suggested indentation increases and decreased based on regexes.
2034 let mut indent_change_rows = Vec::<(u32, Ordering)>::new();
2035 self.for_each_line(
2036 Point::new(prev_non_blank_row.unwrap_or(row_range.start), 0)
2037 ..Point::new(row_range.end, 0),
2038 |row, line| {
2039 if config
2040 .decrease_indent_pattern
2041 .as_ref()
2042 .map_or(false, |regex| regex.is_match(line))
2043 {
2044 indent_change_rows.push((row, Ordering::Less));
2045 }
2046 if config
2047 .increase_indent_pattern
2048 .as_ref()
2049 .map_or(false, |regex| regex.is_match(line))
2050 {
2051 indent_change_rows.push((row + 1, Ordering::Greater));
2052 }
2053 },
2054 );
2055
2056 let mut indent_changes = indent_change_rows.into_iter().peekable();
2057 let mut prev_row = if config.auto_indent_using_last_non_empty_line {
2058 prev_non_blank_row.unwrap_or(0)
2059 } else {
2060 row_range.start.saturating_sub(1)
2061 };
2062 let mut prev_row_start = Point::new(prev_row, self.indent_size_for_line(prev_row).len);
2063 Some(row_range.map(move |row| {
2064 let row_start = Point::new(row, self.indent_size_for_line(row).len);
2065
2066 let mut indent_from_prev_row = false;
2067 let mut outdent_from_prev_row = false;
2068 let mut outdent_to_row = u32::MAX;
2069
2070 while let Some((indent_row, delta)) = indent_changes.peek() {
2071 match indent_row.cmp(&row) {
2072 Ordering::Equal => match delta {
2073 Ordering::Less => outdent_from_prev_row = true,
2074 Ordering::Greater => indent_from_prev_row = true,
2075 _ => {}
2076 },
2077
2078 Ordering::Greater => break,
2079 Ordering::Less => {}
2080 }
2081
2082 indent_changes.next();
2083 }
2084
2085 for range in &indent_ranges {
2086 if range.start.row >= row {
2087 break;
2088 }
2089 if range.start.row == prev_row && range.end > row_start {
2090 indent_from_prev_row = true;
2091 }
2092 if range.end > prev_row_start && range.end <= row_start {
2093 outdent_to_row = outdent_to_row.min(range.start.row);
2094 }
2095 }
2096
2097 let within_error = error_ranges
2098 .iter()
2099 .any(|e| e.start.row < row && e.end > row_start);
2100
2101 let suggestion = if outdent_to_row == prev_row
2102 || (outdent_from_prev_row && indent_from_prev_row)
2103 {
2104 Some(IndentSuggestion {
2105 basis_row: prev_row,
2106 delta: Ordering::Equal,
2107 within_error,
2108 })
2109 } else if indent_from_prev_row {
2110 Some(IndentSuggestion {
2111 basis_row: prev_row,
2112 delta: Ordering::Greater,
2113 within_error,
2114 })
2115 } else if outdent_to_row < prev_row {
2116 Some(IndentSuggestion {
2117 basis_row: outdent_to_row,
2118 delta: Ordering::Equal,
2119 within_error,
2120 })
2121 } else if outdent_from_prev_row {
2122 Some(IndentSuggestion {
2123 basis_row: prev_row,
2124 delta: Ordering::Less,
2125 within_error,
2126 })
2127 } else if config.auto_indent_using_last_non_empty_line || !self.is_line_blank(prev_row)
2128 {
2129 Some(IndentSuggestion {
2130 basis_row: prev_row,
2131 delta: Ordering::Equal,
2132 within_error,
2133 })
2134 } else {
2135 None
2136 };
2137
2138 prev_row = row;
2139 prev_row_start = row_start;
2140 suggestion
2141 }))
2142 }
2143
2144 fn prev_non_blank_row(&self, mut row: u32) -> Option<u32> {
2145 while row > 0 {
2146 row -= 1;
2147 if !self.is_line_blank(row) {
2148 return Some(row);
2149 }
2150 }
2151 None
2152 }
2153
2154 pub fn chunks<T: ToOffset>(&self, range: Range<T>, language_aware: bool) -> BufferChunks {
2155 let range = range.start.to_offset(self)..range.end.to_offset(self);
2156
2157 let mut syntax = None;
2158 let mut diagnostic_endpoints = Vec::new();
2159 if language_aware {
2160 let captures = self.syntax.captures(range.clone(), &self.text, |grammar| {
2161 grammar.highlights_query.as_ref()
2162 });
2163 let highlight_maps = captures
2164 .grammars()
2165 .into_iter()
2166 .map(|grammar| grammar.highlight_map())
2167 .collect();
2168 syntax = Some((captures, highlight_maps));
2169 for entry in self.diagnostics_in_range::<_, usize>(range.clone(), false) {
2170 diagnostic_endpoints.push(DiagnosticEndpoint {
2171 offset: entry.range.start,
2172 is_start: true,
2173 severity: entry.diagnostic.severity,
2174 is_unnecessary: entry.diagnostic.is_unnecessary,
2175 });
2176 diagnostic_endpoints.push(DiagnosticEndpoint {
2177 offset: entry.range.end,
2178 is_start: false,
2179 severity: entry.diagnostic.severity,
2180 is_unnecessary: entry.diagnostic.is_unnecessary,
2181 });
2182 }
2183 diagnostic_endpoints
2184 .sort_unstable_by_key(|endpoint| (endpoint.offset, !endpoint.is_start));
2185 }
2186
2187 BufferChunks::new(self.text.as_rope(), range, syntax, diagnostic_endpoints)
2188 }
2189
2190 pub fn for_each_line(&self, range: Range<Point>, mut callback: impl FnMut(u32, &str)) {
2191 let mut line = String::new();
2192 let mut row = range.start.row;
2193 for chunk in self
2194 .as_rope()
2195 .chunks_in_range(range.to_offset(self))
2196 .chain(["\n"])
2197 {
2198 for (newline_ix, text) in chunk.split('\n').enumerate() {
2199 if newline_ix > 0 {
2200 callback(row, &line);
2201 row += 1;
2202 line.clear();
2203 }
2204 line.push_str(text);
2205 }
2206 }
2207 }
2208
2209 pub fn syntax_layers(&self) -> impl Iterator<Item = SyntaxLayerInfo> + '_ {
2210 self.syntax.layers_for_range(0..self.len(), &self.text)
2211 }
2212
2213 pub fn syntax_layer_at<D: ToOffset>(&self, position: D) -> Option<SyntaxLayerInfo> {
2214 let offset = position.to_offset(self);
2215 self.syntax
2216 .layers_for_range(offset..offset, &self.text)
2217 .filter(|l| l.node().end_byte() > offset)
2218 .last()
2219 }
2220
2221 pub fn language_at<D: ToOffset>(&self, position: D) -> Option<&Arc<Language>> {
2222 self.syntax_layer_at(position)
2223 .map(|info| info.language)
2224 .or(self.language.as_ref())
2225 }
2226
2227 pub fn settings_at<'a, D: ToOffset>(
2228 &self,
2229 position: D,
2230 cx: &'a AppContext,
2231 ) -> &'a LanguageSettings {
2232 language_settings(self.language_at(position), self.file.as_ref(), cx)
2233 }
2234
2235 pub fn language_scope_at<D: ToOffset>(&self, position: D) -> Option<LanguageScope> {
2236 let offset = position.to_offset(self);
2237 let mut scope = None;
2238 let mut smallest_range: Option<Range<usize>> = None;
2239
2240 // Use the layer that has the smallest node intersecting the given point.
2241 for layer in self.syntax.layers_for_range(offset..offset, &self.text) {
2242 let mut cursor = layer.node().walk();
2243
2244 let mut range = None;
2245 loop {
2246 let child_range = cursor.node().byte_range();
2247 if !child_range.to_inclusive().contains(&offset) {
2248 break;
2249 }
2250
2251 range = Some(child_range);
2252 if cursor.goto_first_child_for_byte(offset).is_none() {
2253 break;
2254 }
2255 }
2256
2257 if let Some(range) = range {
2258 if smallest_range
2259 .as_ref()
2260 .map_or(true, |smallest_range| range.len() < smallest_range.len())
2261 {
2262 smallest_range = Some(range);
2263 scope = Some(LanguageScope {
2264 language: layer.language.clone(),
2265 override_id: layer.override_id(offset, &self.text),
2266 });
2267 }
2268 }
2269 }
2270
2271 scope.or_else(|| {
2272 self.language.clone().map(|language| LanguageScope {
2273 language,
2274 override_id: None,
2275 })
2276 })
2277 }
2278
2279 pub fn surrounding_word<T: ToOffset>(&self, start: T) -> (Range<usize>, Option<CharKind>) {
2280 let mut start = start.to_offset(self);
2281 let mut end = start;
2282 let mut next_chars = self.chars_at(start).peekable();
2283 let mut prev_chars = self.reversed_chars_at(start).peekable();
2284
2285 let scope = self.language_scope_at(start);
2286 let kind = |c| char_kind(&scope, c);
2287 let word_kind = cmp::max(
2288 prev_chars.peek().copied().map(kind),
2289 next_chars.peek().copied().map(kind),
2290 );
2291
2292 for ch in prev_chars {
2293 if Some(kind(ch)) == word_kind && ch != '\n' {
2294 start -= ch.len_utf8();
2295 } else {
2296 break;
2297 }
2298 }
2299
2300 for ch in next_chars {
2301 if Some(kind(ch)) == word_kind && ch != '\n' {
2302 end += ch.len_utf8();
2303 } else {
2304 break;
2305 }
2306 }
2307
2308 (start..end, word_kind)
2309 }
2310
2311 pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
2312 let range = range.start.to_offset(self)..range.end.to_offset(self);
2313 let mut result: Option<Range<usize>> = None;
2314 'outer: for layer in self.syntax.layers_for_range(range.clone(), &self.text) {
2315 let mut cursor = layer.node().walk();
2316
2317 // Descend to the first leaf that touches the start of the range,
2318 // and if the range is non-empty, extends beyond the start.
2319 while cursor.goto_first_child_for_byte(range.start).is_some() {
2320 if !range.is_empty() && cursor.node().end_byte() == range.start {
2321 cursor.goto_next_sibling();
2322 }
2323 }
2324
2325 // Ascend to the smallest ancestor that strictly contains the range.
2326 loop {
2327 let node_range = cursor.node().byte_range();
2328 if node_range.start <= range.start
2329 && node_range.end >= range.end
2330 && node_range.len() > range.len()
2331 {
2332 break;
2333 }
2334 if !cursor.goto_parent() {
2335 continue 'outer;
2336 }
2337 }
2338
2339 let left_node = cursor.node();
2340 let mut layer_result = left_node.byte_range();
2341
2342 // For an empty range, try to find another node immediately to the right of the range.
2343 if left_node.end_byte() == range.start {
2344 let mut right_node = None;
2345 while !cursor.goto_next_sibling() {
2346 if !cursor.goto_parent() {
2347 break;
2348 }
2349 }
2350
2351 while cursor.node().start_byte() == range.start {
2352 right_node = Some(cursor.node());
2353 if !cursor.goto_first_child() {
2354 break;
2355 }
2356 }
2357
2358 // If there is a candidate node on both sides of the (empty) range, then
2359 // decide between the two by favoring a named node over an anonymous token.
2360 // If both nodes are the same in that regard, favor the right one.
2361 if let Some(right_node) = right_node {
2362 if right_node.is_named() || !left_node.is_named() {
2363 layer_result = right_node.byte_range();
2364 }
2365 }
2366 }
2367
2368 if let Some(previous_result) = &result {
2369 if previous_result.len() < layer_result.len() {
2370 continue;
2371 }
2372 }
2373 result = Some(layer_result);
2374 }
2375
2376 result
2377 }
2378
2379 pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
2380 self.outline_items_containing(0..self.len(), true, theme)
2381 .map(Outline::new)
2382 }
2383
2384 pub fn symbols_containing<T: ToOffset>(
2385 &self,
2386 position: T,
2387 theme: Option<&SyntaxTheme>,
2388 ) -> Option<Vec<OutlineItem<Anchor>>> {
2389 let position = position.to_offset(self);
2390 let mut items = self.outline_items_containing(
2391 position.saturating_sub(1)..self.len().min(position + 1),
2392 false,
2393 theme,
2394 )?;
2395 let mut prev_depth = None;
2396 items.retain(|item| {
2397 let result = prev_depth.map_or(true, |prev_depth| item.depth > prev_depth);
2398 prev_depth = Some(item.depth);
2399 result
2400 });
2401 Some(items)
2402 }
2403
2404 fn outline_items_containing(
2405 &self,
2406 range: Range<usize>,
2407 include_extra_context: bool,
2408 theme: Option<&SyntaxTheme>,
2409 ) -> Option<Vec<OutlineItem<Anchor>>> {
2410 let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
2411 grammar.outline_config.as_ref().map(|c| &c.query)
2412 });
2413 let configs = matches
2414 .grammars()
2415 .iter()
2416 .map(|g| g.outline_config.as_ref().unwrap())
2417 .collect::<Vec<_>>();
2418
2419 let mut stack = Vec::<Range<usize>>::new();
2420 let mut items = Vec::new();
2421 while let Some(mat) = matches.peek() {
2422 let config = &configs[mat.grammar_index];
2423 let item_node = mat.captures.iter().find_map(|cap| {
2424 if cap.index == config.item_capture_ix {
2425 Some(cap.node)
2426 } else {
2427 None
2428 }
2429 })?;
2430
2431 let item_range = item_node.byte_range();
2432 if item_range.end < range.start || item_range.start > range.end {
2433 matches.advance();
2434 continue;
2435 }
2436
2437 let mut buffer_ranges = Vec::new();
2438 for capture in mat.captures {
2439 let node_is_name;
2440 if capture.index == config.name_capture_ix {
2441 node_is_name = true;
2442 } else if Some(capture.index) == config.context_capture_ix
2443 || (Some(capture.index) == config.extra_context_capture_ix
2444 && include_extra_context)
2445 {
2446 node_is_name = false;
2447 } else {
2448 continue;
2449 }
2450
2451 let mut range = capture.node.start_byte()..capture.node.end_byte();
2452 let start = capture.node.start_position();
2453 if capture.node.end_position().row > start.row {
2454 range.end =
2455 range.start + self.line_len(start.row as u32) as usize - start.column;
2456 }
2457
2458 buffer_ranges.push((range, node_is_name));
2459 }
2460
2461 if buffer_ranges.is_empty() {
2462 continue;
2463 }
2464
2465 let mut text = String::new();
2466 let mut highlight_ranges = Vec::new();
2467 let mut name_ranges = Vec::new();
2468 let mut chunks = self.chunks(
2469 buffer_ranges.first().unwrap().0.start..buffer_ranges.last().unwrap().0.end,
2470 true,
2471 );
2472 let mut last_buffer_range_end = 0;
2473 for (buffer_range, is_name) in buffer_ranges {
2474 if !text.is_empty() && buffer_range.start > last_buffer_range_end {
2475 text.push(' ');
2476 }
2477 last_buffer_range_end = buffer_range.end;
2478 if is_name {
2479 let mut start = text.len();
2480 let end = start + buffer_range.len();
2481
2482 // When multiple names are captured, then the matcheable text
2483 // includes the whitespace in between the names.
2484 if !name_ranges.is_empty() {
2485 start -= 1;
2486 }
2487
2488 name_ranges.push(start..end);
2489 }
2490
2491 let mut offset = buffer_range.start;
2492 chunks.seek(offset);
2493 for mut chunk in chunks.by_ref() {
2494 if chunk.text.len() > buffer_range.end - offset {
2495 chunk.text = &chunk.text[0..(buffer_range.end - offset)];
2496 offset = buffer_range.end;
2497 } else {
2498 offset += chunk.text.len();
2499 }
2500 let style = chunk
2501 .syntax_highlight_id
2502 .zip(theme)
2503 .and_then(|(highlight, theme)| highlight.style(theme));
2504 if let Some(style) = style {
2505 let start = text.len();
2506 let end = start + chunk.text.len();
2507 highlight_ranges.push((start..end, style));
2508 }
2509 text.push_str(chunk.text);
2510 if offset >= buffer_range.end {
2511 break;
2512 }
2513 }
2514 }
2515
2516 matches.advance();
2517 while stack.last().map_or(false, |prev_range| {
2518 prev_range.start > item_range.start || prev_range.end < item_range.end
2519 }) {
2520 stack.pop();
2521 }
2522 stack.push(item_range.clone());
2523
2524 items.push(OutlineItem {
2525 depth: stack.len() - 1,
2526 range: self.anchor_after(item_range.start)..self.anchor_before(item_range.end),
2527 text,
2528 highlight_ranges,
2529 name_ranges,
2530 })
2531 }
2532 Some(items)
2533 }
2534
2535 pub fn matches(
2536 &self,
2537 range: Range<usize>,
2538 query: fn(&Grammar) -> Option<&tree_sitter::Query>,
2539 ) -> SyntaxMapMatches {
2540 self.syntax.matches(range, self, query)
2541 }
2542
2543 /// Returns bracket range pairs overlapping or adjacent to `range`
2544 pub fn bracket_ranges<'a, T: ToOffset>(
2545 &'a self,
2546 range: Range<T>,
2547 ) -> impl Iterator<Item = (Range<usize>, Range<usize>)> + 'a {
2548 // Find bracket pairs that *inclusively* contain the given range.
2549 let range = range.start.to_offset(self).saturating_sub(1)
2550 ..self.len().min(range.end.to_offset(self) + 1);
2551
2552 let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
2553 grammar.brackets_config.as_ref().map(|c| &c.query)
2554 });
2555 let configs = matches
2556 .grammars()
2557 .iter()
2558 .map(|grammar| grammar.brackets_config.as_ref().unwrap())
2559 .collect::<Vec<_>>();
2560
2561 iter::from_fn(move || {
2562 while let Some(mat) = matches.peek() {
2563 let mut open = None;
2564 let mut close = None;
2565 let config = &configs[mat.grammar_index];
2566 for capture in mat.captures {
2567 if capture.index == config.open_capture_ix {
2568 open = Some(capture.node.byte_range());
2569 } else if capture.index == config.close_capture_ix {
2570 close = Some(capture.node.byte_range());
2571 }
2572 }
2573
2574 matches.advance();
2575
2576 let Some((open, close)) = open.zip(close) else {
2577 continue;
2578 };
2579
2580 let bracket_range = open.start..=close.end;
2581 if !bracket_range.overlaps(&range) {
2582 continue;
2583 }
2584
2585 return Some((open, close));
2586 }
2587 None
2588 })
2589 }
2590
2591 #[allow(clippy::type_complexity)]
2592 pub fn remote_selections_in_range(
2593 &self,
2594 range: Range<Anchor>,
2595 ) -> impl Iterator<
2596 Item = (
2597 ReplicaId,
2598 bool,
2599 CursorShape,
2600 impl Iterator<Item = &Selection<Anchor>> + '_,
2601 ),
2602 > + '_ {
2603 self.remote_selections
2604 .iter()
2605 .filter(|(replica_id, set)| {
2606 **replica_id != self.text.replica_id() && !set.selections.is_empty()
2607 })
2608 .map(move |(replica_id, set)| {
2609 let start_ix = match set.selections.binary_search_by(|probe| {
2610 probe.end.cmp(&range.start, self).then(Ordering::Greater)
2611 }) {
2612 Ok(ix) | Err(ix) => ix,
2613 };
2614 let end_ix = match set.selections.binary_search_by(|probe| {
2615 probe.start.cmp(&range.end, self).then(Ordering::Less)
2616 }) {
2617 Ok(ix) | Err(ix) => ix,
2618 };
2619
2620 (
2621 *replica_id,
2622 set.line_mode,
2623 set.cursor_shape,
2624 set.selections[start_ix..end_ix].iter(),
2625 )
2626 })
2627 }
2628
2629 pub fn git_diff_hunks_in_row_range<'a>(
2630 &'a self,
2631 range: Range<u32>,
2632 ) -> impl 'a + Iterator<Item = git::diff::DiffHunk<u32>> {
2633 self.git_diff.hunks_in_row_range(range, self)
2634 }
2635
2636 pub fn git_diff_hunks_intersecting_range<'a>(
2637 &'a self,
2638 range: Range<Anchor>,
2639 ) -> impl 'a + Iterator<Item = git::diff::DiffHunk<u32>> {
2640 self.git_diff.hunks_intersecting_range(range, self)
2641 }
2642
2643 pub fn git_diff_hunks_intersecting_range_rev<'a>(
2644 &'a self,
2645 range: Range<Anchor>,
2646 ) -> impl 'a + Iterator<Item = git::diff::DiffHunk<u32>> {
2647 self.git_diff.hunks_intersecting_range_rev(range, self)
2648 }
2649
2650 pub fn diagnostics_in_range<'a, T, O>(
2651 &'a self,
2652 search_range: Range<T>,
2653 reversed: bool,
2654 ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>>
2655 where
2656 T: 'a + Clone + ToOffset,
2657 O: 'a + FromAnchor + Ord,
2658 {
2659 let mut iterators: Vec<_> = self
2660 .diagnostics
2661 .iter()
2662 .map(|(_, collection)| {
2663 collection
2664 .range::<T, O>(search_range.clone(), self, true, reversed)
2665 .peekable()
2666 })
2667 .collect();
2668
2669 std::iter::from_fn(move || {
2670 let (next_ix, _) = iterators
2671 .iter_mut()
2672 .enumerate()
2673 .flat_map(|(ix, iter)| Some((ix, iter.peek()?)))
2674 .min_by(|(_, a), (_, b)| a.range.start.cmp(&b.range.start))?;
2675 iterators[next_ix].next()
2676 })
2677 }
2678
2679 pub fn diagnostic_groups(
2680 &self,
2681 language_server_id: Option<LanguageServerId>,
2682 ) -> Vec<(LanguageServerId, DiagnosticGroup<Anchor>)> {
2683 let mut groups = Vec::new();
2684
2685 if let Some(language_server_id) = language_server_id {
2686 if let Ok(ix) = self
2687 .diagnostics
2688 .binary_search_by_key(&language_server_id, |e| e.0)
2689 {
2690 self.diagnostics[ix]
2691 .1
2692 .groups(language_server_id, &mut groups, self);
2693 }
2694 } else {
2695 for (language_server_id, diagnostics) in self.diagnostics.iter() {
2696 diagnostics.groups(*language_server_id, &mut groups, self);
2697 }
2698 }
2699
2700 groups.sort_by(|(id_a, group_a), (id_b, group_b)| {
2701 let a_start = &group_a.entries[group_a.primary_ix].range.start;
2702 let b_start = &group_b.entries[group_b.primary_ix].range.start;
2703 a_start.cmp(b_start, self).then_with(|| id_a.cmp(&id_b))
2704 });
2705
2706 groups
2707 }
2708
2709 pub fn diagnostic_group<'a, O>(
2710 &'a self,
2711 group_id: usize,
2712 ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>>
2713 where
2714 O: 'a + FromAnchor,
2715 {
2716 self.diagnostics
2717 .iter()
2718 .flat_map(move |(_, set)| set.group(group_id, self))
2719 }
2720
2721 pub fn diagnostics_update_count(&self) -> usize {
2722 self.diagnostics_update_count
2723 }
2724
2725 pub fn parse_count(&self) -> usize {
2726 self.parse_count
2727 }
2728
2729 pub fn selections_update_count(&self) -> usize {
2730 self.selections_update_count
2731 }
2732
2733 pub fn file(&self) -> Option<&Arc<dyn File>> {
2734 self.file.as_ref()
2735 }
2736
2737 pub fn resolve_file_path(&self, cx: &AppContext, include_root: bool) -> Option<PathBuf> {
2738 if let Some(file) = self.file() {
2739 if file.path().file_name().is_none() || include_root {
2740 Some(file.full_path(cx))
2741 } else {
2742 Some(file.path().to_path_buf())
2743 }
2744 } else {
2745 None
2746 }
2747 }
2748
2749 pub fn file_update_count(&self) -> usize {
2750 self.file_update_count
2751 }
2752
2753 pub fn git_diff_update_count(&self) -> usize {
2754 self.git_diff_update_count
2755 }
2756}
2757
2758fn indent_size_for_line(text: &text::BufferSnapshot, row: u32) -> IndentSize {
2759 indent_size_for_text(text.chars_at(Point::new(row, 0)))
2760}
2761
2762pub fn indent_size_for_text(text: impl Iterator<Item = char>) -> IndentSize {
2763 let mut result = IndentSize::spaces(0);
2764 for c in text {
2765 let kind = match c {
2766 ' ' => IndentKind::Space,
2767 '\t' => IndentKind::Tab,
2768 _ => break,
2769 };
2770 if result.len == 0 {
2771 result.kind = kind;
2772 }
2773 result.len += 1;
2774 }
2775 result
2776}
2777
2778impl Clone for BufferSnapshot {
2779 fn clone(&self) -> Self {
2780 Self {
2781 text: self.text.clone(),
2782 git_diff: self.git_diff.clone(),
2783 syntax: self.syntax.clone(),
2784 file: self.file.clone(),
2785 remote_selections: self.remote_selections.clone(),
2786 diagnostics: self.diagnostics.clone(),
2787 selections_update_count: self.selections_update_count,
2788 diagnostics_update_count: self.diagnostics_update_count,
2789 file_update_count: self.file_update_count,
2790 git_diff_update_count: self.git_diff_update_count,
2791 language: self.language.clone(),
2792 parse_count: self.parse_count,
2793 }
2794 }
2795}
2796
2797impl Deref for BufferSnapshot {
2798 type Target = text::BufferSnapshot;
2799
2800 fn deref(&self) -> &Self::Target {
2801 &self.text
2802 }
2803}
2804
2805unsafe impl<'a> Send for BufferChunks<'a> {}
2806
2807impl<'a> BufferChunks<'a> {
2808 pub(crate) fn new(
2809 text: &'a Rope,
2810 range: Range<usize>,
2811 syntax: Option<(SyntaxMapCaptures<'a>, Vec<HighlightMap>)>,
2812 diagnostic_endpoints: Vec<DiagnosticEndpoint>,
2813 ) -> Self {
2814 let mut highlights = None;
2815 if let Some((captures, highlight_maps)) = syntax {
2816 highlights = Some(BufferChunkHighlights {
2817 captures,
2818 next_capture: None,
2819 stack: Default::default(),
2820 highlight_maps,
2821 })
2822 }
2823
2824 let diagnostic_endpoints = diagnostic_endpoints.into_iter().peekable();
2825 let chunks = text.chunks_in_range(range.clone());
2826
2827 BufferChunks {
2828 range,
2829 chunks,
2830 diagnostic_endpoints,
2831 error_depth: 0,
2832 warning_depth: 0,
2833 information_depth: 0,
2834 hint_depth: 0,
2835 unnecessary_depth: 0,
2836 highlights,
2837 }
2838 }
2839
2840 pub fn seek(&mut self, offset: usize) {
2841 self.range.start = offset;
2842 self.chunks.seek(self.range.start);
2843 if let Some(highlights) = self.highlights.as_mut() {
2844 highlights
2845 .stack
2846 .retain(|(end_offset, _)| *end_offset > offset);
2847 if let Some(capture) = &highlights.next_capture {
2848 if offset >= capture.node.start_byte() {
2849 let next_capture_end = capture.node.end_byte();
2850 if offset < next_capture_end {
2851 highlights.stack.push((
2852 next_capture_end,
2853 highlights.highlight_maps[capture.grammar_index].get(capture.index),
2854 ));
2855 }
2856 highlights.next_capture.take();
2857 }
2858 }
2859 highlights.captures.set_byte_range(self.range.clone());
2860 }
2861 }
2862
2863 pub fn offset(&self) -> usize {
2864 self.range.start
2865 }
2866
2867 fn update_diagnostic_depths(&mut self, endpoint: DiagnosticEndpoint) {
2868 let depth = match endpoint.severity {
2869 DiagnosticSeverity::ERROR => &mut self.error_depth,
2870 DiagnosticSeverity::WARNING => &mut self.warning_depth,
2871 DiagnosticSeverity::INFORMATION => &mut self.information_depth,
2872 DiagnosticSeverity::HINT => &mut self.hint_depth,
2873 _ => return,
2874 };
2875 if endpoint.is_start {
2876 *depth += 1;
2877 } else {
2878 *depth -= 1;
2879 }
2880
2881 if endpoint.is_unnecessary {
2882 if endpoint.is_start {
2883 self.unnecessary_depth += 1;
2884 } else {
2885 self.unnecessary_depth -= 1;
2886 }
2887 }
2888 }
2889
2890 fn current_diagnostic_severity(&self) -> Option<DiagnosticSeverity> {
2891 if self.error_depth > 0 {
2892 Some(DiagnosticSeverity::ERROR)
2893 } else if self.warning_depth > 0 {
2894 Some(DiagnosticSeverity::WARNING)
2895 } else if self.information_depth > 0 {
2896 Some(DiagnosticSeverity::INFORMATION)
2897 } else if self.hint_depth > 0 {
2898 Some(DiagnosticSeverity::HINT)
2899 } else {
2900 None
2901 }
2902 }
2903
2904 fn current_code_is_unnecessary(&self) -> bool {
2905 self.unnecessary_depth > 0
2906 }
2907}
2908
2909impl<'a> Iterator for BufferChunks<'a> {
2910 type Item = Chunk<'a>;
2911
2912 fn next(&mut self) -> Option<Self::Item> {
2913 let mut next_capture_start = usize::MAX;
2914 let mut next_diagnostic_endpoint = usize::MAX;
2915
2916 if let Some(highlights) = self.highlights.as_mut() {
2917 while let Some((parent_capture_end, _)) = highlights.stack.last() {
2918 if *parent_capture_end <= self.range.start {
2919 highlights.stack.pop();
2920 } else {
2921 break;
2922 }
2923 }
2924
2925 if highlights.next_capture.is_none() {
2926 highlights.next_capture = highlights.captures.next();
2927 }
2928
2929 while let Some(capture) = highlights.next_capture.as_ref() {
2930 if self.range.start < capture.node.start_byte() {
2931 next_capture_start = capture.node.start_byte();
2932 break;
2933 } else {
2934 let highlight_id =
2935 highlights.highlight_maps[capture.grammar_index].get(capture.index);
2936 highlights
2937 .stack
2938 .push((capture.node.end_byte(), highlight_id));
2939 highlights.next_capture = highlights.captures.next();
2940 }
2941 }
2942 }
2943
2944 while let Some(endpoint) = self.diagnostic_endpoints.peek().copied() {
2945 if endpoint.offset <= self.range.start {
2946 self.update_diagnostic_depths(endpoint);
2947 self.diagnostic_endpoints.next();
2948 } else {
2949 next_diagnostic_endpoint = endpoint.offset;
2950 break;
2951 }
2952 }
2953
2954 if let Some(chunk) = self.chunks.peek() {
2955 let chunk_start = self.range.start;
2956 let mut chunk_end = (self.chunks.offset() + chunk.len())
2957 .min(next_capture_start)
2958 .min(next_diagnostic_endpoint);
2959 let mut highlight_id = None;
2960 if let Some(highlights) = self.highlights.as_ref() {
2961 if let Some((parent_capture_end, parent_highlight_id)) = highlights.stack.last() {
2962 chunk_end = chunk_end.min(*parent_capture_end);
2963 highlight_id = Some(*parent_highlight_id);
2964 }
2965 }
2966
2967 let slice =
2968 &chunk[chunk_start - self.chunks.offset()..chunk_end - self.chunks.offset()];
2969 self.range.start = chunk_end;
2970 if self.range.start == self.chunks.offset() + chunk.len() {
2971 self.chunks.next().unwrap();
2972 }
2973
2974 Some(Chunk {
2975 text: slice,
2976 syntax_highlight_id: highlight_id,
2977 diagnostic_severity: self.current_diagnostic_severity(),
2978 is_unnecessary: self.current_code_is_unnecessary(),
2979 ..Default::default()
2980 })
2981 } else {
2982 None
2983 }
2984 }
2985}
2986
2987impl operation_queue::Operation for Operation {
2988 fn lamport_timestamp(&self) -> clock::Lamport {
2989 match self {
2990 Operation::Buffer(_) => {
2991 unreachable!("buffer operations should never be deferred at this layer")
2992 }
2993 Operation::UpdateDiagnostics {
2994 lamport_timestamp, ..
2995 }
2996 | Operation::UpdateSelections {
2997 lamport_timestamp, ..
2998 }
2999 | Operation::UpdateCompletionTriggers {
3000 lamport_timestamp, ..
3001 } => *lamport_timestamp,
3002 }
3003 }
3004}
3005
3006impl Default for Diagnostic {
3007 fn default() -> Self {
3008 Self {
3009 source: Default::default(),
3010 code: None,
3011 severity: DiagnosticSeverity::ERROR,
3012 message: Default::default(),
3013 group_id: 0,
3014 is_primary: false,
3015 is_valid: true,
3016 is_disk_based: false,
3017 is_unnecessary: false,
3018 }
3019 }
3020}
3021
3022impl IndentSize {
3023 pub fn spaces(len: u32) -> Self {
3024 Self {
3025 len,
3026 kind: IndentKind::Space,
3027 }
3028 }
3029
3030 pub fn tab() -> Self {
3031 Self {
3032 len: 1,
3033 kind: IndentKind::Tab,
3034 }
3035 }
3036
3037 pub fn chars(&self) -> impl Iterator<Item = char> {
3038 iter::repeat(self.char()).take(self.len as usize)
3039 }
3040
3041 pub fn char(&self) -> char {
3042 match self.kind {
3043 IndentKind::Space => ' ',
3044 IndentKind::Tab => '\t',
3045 }
3046 }
3047
3048 pub fn with_delta(mut self, direction: Ordering, size: IndentSize) -> Self {
3049 match direction {
3050 Ordering::Less => {
3051 if self.kind == size.kind && self.len >= size.len {
3052 self.len -= size.len;
3053 }
3054 }
3055 Ordering::Equal => {}
3056 Ordering::Greater => {
3057 if self.len == 0 {
3058 self = size;
3059 } else if self.kind == size.kind {
3060 self.len += size.len;
3061 }
3062 }
3063 }
3064 self
3065 }
3066}
3067
3068impl Completion {
3069 pub fn sort_key(&self) -> (usize, &str) {
3070 let kind_key = match self.lsp_completion.kind {
3071 Some(lsp::CompletionItemKind::VARIABLE) => 0,
3072 _ => 1,
3073 };
3074 (kind_key, &self.label.text[self.label.filter_range.clone()])
3075 }
3076
3077 pub fn is_snippet(&self) -> bool {
3078 self.lsp_completion.insert_text_format == Some(lsp::InsertTextFormat::SNIPPET)
3079 }
3080}
3081
3082pub fn contiguous_ranges(
3083 values: impl Iterator<Item = u32>,
3084 max_len: usize,
3085) -> impl Iterator<Item = Range<u32>> {
3086 let mut values = values;
3087 let mut current_range: Option<Range<u32>> = None;
3088 std::iter::from_fn(move || loop {
3089 if let Some(value) = values.next() {
3090 if let Some(range) = &mut current_range {
3091 if value == range.end && range.len() < max_len {
3092 range.end += 1;
3093 continue;
3094 }
3095 }
3096
3097 let prev_range = current_range.clone();
3098 current_range = Some(value..(value + 1));
3099 if prev_range.is_some() {
3100 return prev_range;
3101 }
3102 } else {
3103 return current_range.take();
3104 }
3105 })
3106}
3107
3108pub fn char_kind(scope: &Option<LanguageScope>, c: char) -> CharKind {
3109 if c.is_whitespace() {
3110 return CharKind::Whitespace;
3111 } else if c.is_alphanumeric() || c == '_' {
3112 return CharKind::Word;
3113 }
3114
3115 if let Some(scope) = scope {
3116 if let Some(characters) = scope.word_characters() {
3117 if characters.contains(&c) {
3118 return CharKind::Word;
3119 }
3120 }
3121 }
3122
3123 CharKind::Punctuation
3124}
3125
3126/// Find all of the ranges of whitespace that occur at the ends of lines
3127/// in the given rope.
3128///
3129/// This could also be done with a regex search, but this implementation
3130/// avoids copying text.
3131pub fn trailing_whitespace_ranges(rope: &Rope) -> Vec<Range<usize>> {
3132 let mut ranges = Vec::new();
3133
3134 let mut offset = 0;
3135 let mut prev_chunk_trailing_whitespace_range = 0..0;
3136 for chunk in rope.chunks() {
3137 let mut prev_line_trailing_whitespace_range = 0..0;
3138 for (i, line) in chunk.split('\n').enumerate() {
3139 let line_end_offset = offset + line.len();
3140 let trimmed_line_len = line.trim_end_matches(|c| matches!(c, ' ' | '\t')).len();
3141 let mut trailing_whitespace_range = (offset + trimmed_line_len)..line_end_offset;
3142
3143 if i == 0 && trimmed_line_len == 0 {
3144 trailing_whitespace_range.start = prev_chunk_trailing_whitespace_range.start;
3145 }
3146 if !prev_line_trailing_whitespace_range.is_empty() {
3147 ranges.push(prev_line_trailing_whitespace_range);
3148 }
3149
3150 offset = line_end_offset + 1;
3151 prev_line_trailing_whitespace_range = trailing_whitespace_range;
3152 }
3153
3154 offset -= 1;
3155 prev_chunk_trailing_whitespace_range = prev_line_trailing_whitespace_range;
3156 }
3157
3158 if !prev_chunk_trailing_whitespace_range.is_empty() {
3159 ranges.push(prev_chunk_trailing_whitespace_range);
3160 }
3161
3162 ranges
3163}