pub use crate::{ diagnostic_set::DiagnosticSet, highlight_map::{HighlightId, HighlightMap}, proto, BracketPair, Grammar, Language, LanguageConfig, LanguageRegistry, PLAIN_TEXT,};use crate::{ diagnostic_set::{DiagnosticEntry, DiagnosticGroup}, language_settings::{language_settings, LanguageSettings}, outline::OutlineItem, syntax_map::{ SyntaxLayerInfo, SyntaxMap, SyntaxMapCapture, SyntaxMapCaptures, SyntaxSnapshot, ToTreeSitterPoint, }, CodeLabel, LanguageScope, Outline,};use anyhow::{anyhow, Result};pub use clock::ReplicaId;use futures::FutureExt as _;use gpui::{fonts::HighlightStyle, AppContext, Entity, ModelContext, Task};use lsp::LanguageServerId;use parking_lot::Mutex;use similar::{ChangeTag, TextDiff};use smallvec::SmallVec;use smol::future::yield_now;use std::{ any::Any, cmp::{self, Ordering}, collections::BTreeMap, ffi::OsStr, future::Future, iter::{self, Iterator, Peekable}, mem, ops::{Deref, Range}, path::{Path, PathBuf}, str, sync::Arc, time::{Duration, Instant, SystemTime, UNIX_EPOCH}, vec,};use sum_tree::TreeMap;use text::operation_queue::OperationQueue;pub use text::{Buffer as TextBuffer, BufferSnapshot as TextBufferSnapshot, *};use theme::SyntaxTheme;#[cfg(any(test, feature = "test-support"))]use util::RandomCharIter;use util::{RangeExt, TryFutureExt as _}; #[cfg(any(test, feature = "test-support"))]pub use {tree_sitter_rust, tree_sitter_typescript}; pub use lsp::DiagnosticSeverity; pub struct Buffer { text: TextBuffer, diff_base: Option<String>, git_diff: git::diff::BufferDiff, file: Option<Arc<dyn File>>, saved_version: clock::Global, saved_version_fingerprint: RopeFingerprint, saved_mtime: SystemTime, transaction_depth: usize, was_dirty_before_starting_transaction: Option<bool>, language: Option<Arc<Language>>, autoindent_requests: Vec<Arc<AutoindentRequest>>, pending_autoindent: Option<Task<()>>, sync_parse_timeout: Duration, syntax_map: Mutex<SyntaxMap>, parsing_in_background: bool, parse_count: usize, diagnostics: SmallVec<[(LanguageServerId, DiagnosticSet); 2]>, remote_selections: TreeMap<ReplicaId, SelectionSet>, selections_update_count: usize, diagnostics_update_count: usize, diagnostics_timestamp: clock::Lamport, file_update_count: usize, git_diff_update_count: usize, completion_triggers: Vec<String>, completion_triggers_timestamp: clock::Lamport, deferred_ops: OperationQueue<Operation>,} pub struct BufferSnapshot { text: text::BufferSnapshot, pub git_diff: git::diff::BufferDiff, pub(crate) syntax: SyntaxSnapshot, file: Option<Arc<dyn File>>, diagnostics: SmallVec<[(LanguageServerId, DiagnosticSet); 2]>, diagnostics_update_count: usize, file_update_count: usize, git_diff_update_count: usize, remote_selections: TreeMap<ReplicaId, SelectionSet>, selections_update_count: usize, language: Option<Arc<Language>>, parse_count: usize,} #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]pub struct IndentSize { pub len: u32, pub kind: IndentKind,} #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]pub enum IndentKind { #[default] Space, Tab,} #[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]pub enum CursorShape { #[default] Bar, Block, Underscore, Hollow,} #[derive(Clone, Debug)]struct SelectionSet { line_mode: bool, cursor_shape: CursorShape, selections: Arc<[Selection<Anchor>]>, lamport_timestamp: clock::Lamport,} #[derive(Clone, Debug, PartialEq, Eq)]pub struct GroupId { source: Arc<str>, id: usize,} #[derive(Clone, Debug, PartialEq, Eq)]pub struct Diagnostic { pub source: Option<String>, pub code: Option<String>, pub severity: DiagnosticSeverity, pub message: String, pub group_id: usize, pub is_valid: bool, pub is_primary: bool, pub is_disk_based: bool, pub is_unnecessary: bool,} #[derive(Clone, Debug)]pub struct Completion { pub old_range: Range<Anchor>, pub new_text: String, pub label: CodeLabel, pub lsp_completion: lsp::CompletionItem,} #[derive(Clone, Debug)]pub struct CodeAction { pub server_id: LanguageServerId, pub range: Range<Anchor>, pub lsp_action: lsp::CodeAction,} #[derive(Clone, Debug, PartialEq, Eq)]pub enum Operation { Buffer(text::Operation), UpdateDiagnostics { server_id: LanguageServerId, diagnostics: Arc<[DiagnosticEntry<Anchor>]>, lamport_timestamp: clock::Lamport, }, UpdateSelections { selections: Arc<[Selection<Anchor>]>, lamport_timestamp: clock::Lamport, line_mode: bool, cursor_shape: CursorShape, }, UpdateCompletionTriggers { triggers: Vec<String>, lamport_timestamp: clock::Lamport, },} #[derive(Clone, Debug, PartialEq, Eq)]pub enum Event { Operation(Operation), Edited, DirtyChanged, Saved, FileHandleChanged, Reloaded, DiffBaseChanged, LanguageChanged, Reparsed, DiagnosticsUpdated, Closed,} pub trait File: Send + Sync { fn as_local(&self) -> Option<&dyn LocalFile>; fn is_local(&self) -> bool { self.as_local().is_some() } fn mtime(&self) -> SystemTime; /// Returns the path of this file relative to the worktree's root directory. fn path(&self) -> &Arc<Path>; /// Returns the path of this file relative to the worktree's parent directory (this means it /// includes the name of the worktree's root folder). fn full_path(&self, cx: &AppContext) -> PathBuf; /// Returns the last component of this handle's absolute path. If this handle refers to the root /// of its worktree, then this method will return the name of the worktree itself. fn file_name<'a>(&'a self, cx: &'a AppContext) -> &'a OsStr; /// Returns the id of the worktree to which this file belongs. /// /// This is needed for looking up project-specific settings. fn worktree_id(&self) -> usize; fn is_deleted(&self) -> bool; fn as_any(&self) -> &dyn Any; fn to_proto(&self) -> rpc::proto::File;} pub trait LocalFile: File { /// Returns the absolute path of this file. fn abs_path(&self, cx: &AppContext) -> PathBuf; fn load(&self, cx: &AppContext) -> Task<Result<String>>; fn buffer_reloaded( &self, buffer_id: u64, version: &clock::Global, fingerprint: RopeFingerprint, line_ending: LineEnding, mtime: SystemTime, cx: &mut AppContext, );} #[derive(Clone, Debug)]pub enum AutoindentMode { /// Indent each line of inserted text. EachLine, /// Apply the same indentation adjustment to all of the lines /// in a given insertion. Block { /// The original indentation level of the first line of each /// insertion, if it has been copied. original_indent_columns: Vec<u32>, },} #[derive(Clone)]struct AutoindentRequest { before_edit: BufferSnapshot, entries: Vec<AutoindentRequestEntry>, is_block_mode: bool,} #[derive(Clone)]struct AutoindentRequestEntry { /// A range of the buffer whose indentation should be adjusted. range: Range<Anchor>, /// Whether or not these lines should be considered brand new, for the /// purpose of auto-indent. When text is not new, its indentation will /// only be adjusted if the suggested indentation level has *changed* /// since the edit was made. first_line_is_new: bool, indent_size: IndentSize, original_indent_column: Option<u32>,} #[derive(Debug)]struct IndentSuggestion { basis_row: u32, delta: Ordering, within_error: bool,} struct BufferChunkHighlights<'a> { captures: SyntaxMapCaptures<'a>, next_capture: Option<SyntaxMapCapture<'a>>, stack: Vec<(usize, HighlightId)>, highlight_maps: Vec<HighlightMap>,} pub struct BufferChunks<'a> { range: Range<usize>, chunks: text::Chunks<'a>, diagnostic_endpoints: Peekable<vec::IntoIter<DiagnosticEndpoint>>, error_depth: usize, warning_depth: usize, information_depth: usize, hint_depth: usize, unnecessary_depth: usize, highlights: Option<BufferChunkHighlights<'a>>,} #[derive(Clone, Copy, Debug, Default)]pub struct Chunk<'a> { pub text: &'a str, pub syntax_highlight_id: Option<HighlightId>, pub highlight_style: Option<HighlightStyle>, pub diagnostic_severity: Option<DiagnosticSeverity>, pub is_unnecessary: bool, pub is_tab: bool,} pub struct Diff { pub(crate) base_version: clock::Global, line_ending: LineEnding, edits: Vec<(Range<usize>, Arc<str>)>,} #[derive(Clone, Copy)]pub(crate) struct DiagnosticEndpoint { offset: usize, is_start: bool, severity: DiagnosticSeverity, is_unnecessary: bool,} #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug)]pub enum CharKind { Punctuation, Whitespace, Word,} impl CharKind { pub fn coerce_punctuation(self, treat_punctuation_as_word: bool) -> Self { if treat_punctuation_as_word && self == CharKind::Punctuation { CharKind::Word } else { self } }} impl Buffer { pub fn new<T: Into<String>>(replica_id: ReplicaId, id: u64, base_text: T) -> Self { Self::build( TextBuffer::new(replica_id, id, base_text.into()), None, None, ) } pub fn remote(remote_id: u64, replica_id: ReplicaId, base_text: String) -> Self { Self::build( TextBuffer::new(replica_id, remote_id, base_text), None, None, ) } pub fn from_proto( replica_id: ReplicaId, message: proto::BufferState, file: Option<Arc<dyn File>>, ) -> Result<Self> { let buffer = TextBuffer::new(replica_id, message.id, message.base_text); let mut this = Self::build( buffer, message.diff_base.map(|text| text.into_boxed_str().into()), file, ); this.text.set_line_ending(proto::deserialize_line_ending( rpc::proto::LineEnding::from_i32(message.line_ending) .ok_or_else(|| anyhow!("missing line_ending"))?, )); this.saved_version = proto::deserialize_version(&message.saved_version); this.saved_version_fingerprint = proto::deserialize_fingerprint(&message.saved_version_fingerprint)?; this.saved_mtime = message .saved_mtime .ok_or_else(|| anyhow!("invalid saved_mtime"))? .into(); Ok(this) } pub fn to_proto(&self) -> proto::BufferState { proto::BufferState { id: self.remote_id(), file: self.file.as_ref().map(|f| f.to_proto()), base_text: self.base_text().to_string(), diff_base: self.diff_base.as_ref().map(|h| h.to_string()), line_ending: proto::serialize_line_ending(self.line_ending()) as i32, saved_version: proto::serialize_version(&self.saved_version), saved_version_fingerprint: proto::serialize_fingerprint(self.saved_version_fingerprint), saved_mtime: Some(self.saved_mtime.into()), } } pub fn serialize_ops( &self, since: Option<clock::Global>, cx: &AppContext, ) -> Task<Vec<proto::Operation>> { let mut operations = Vec::new(); operations.extend(self.deferred_ops.iter().map(proto::serialize_operation)); operations.extend(self.remote_selections.iter().map(|(_, set)| { proto::serialize_operation(&Operation::UpdateSelections { selections: set.selections.clone(), lamport_timestamp: set.lamport_timestamp, line_mode: set.line_mode, cursor_shape: set.cursor_shape, }) })); for (server_id, diagnostics) in &self.diagnostics { operations.push(proto::serialize_operation(&Operation::UpdateDiagnostics { lamport_timestamp: self.diagnostics_timestamp, server_id: *server_id, diagnostics: diagnostics.iter().cloned().collect(), })); } operations.push(proto::serialize_operation( &Operation::UpdateCompletionTriggers { triggers: self.completion_triggers.clone(), lamport_timestamp: self.completion_triggers_timestamp, }, )); let text_operations = self.text.operations().clone(); cx.background().spawn(async move { let since = since.unwrap_or_default(); operations.extend( text_operations .iter() .filter(|(_, op)| !since.observed(op.local_timestamp())) .map(|(_, op)| proto::serialize_operation(&Operation::Buffer(op.clone()))), ); operations.sort_unstable_by_key(proto::lamport_timestamp_for_operation); operations }) } pub fn with_language(mut self, language: Arc<Language>, cx: &mut ModelContext<Self>) -> Self { self.set_language(Some(language), cx); self } pub fn build( buffer: TextBuffer, diff_base: Option<String>, file: Option<Arc<dyn File>>, ) -> Self { let saved_mtime = if let Some(file) = file.as_ref() { file.mtime() } else { UNIX_EPOCH }; Self { saved_mtime, saved_version: buffer.version(), saved_version_fingerprint: buffer.as_rope().fingerprint(), transaction_depth: 0, was_dirty_before_starting_transaction: None, text: buffer, diff_base, git_diff: git::diff::BufferDiff::new(), file, syntax_map: Mutex::new(SyntaxMap::new()), parsing_in_background: false, parse_count: 0, sync_parse_timeout: Duration::from_millis(1), autoindent_requests: Default::default(), pending_autoindent: Default::default(), language: None, remote_selections: Default::default(), selections_update_count: 0, diagnostics: Default::default(), diagnostics_update_count: 0, diagnostics_timestamp: Default::default(), file_update_count: 0, git_diff_update_count: 0, completion_triggers: Default::default(), completion_triggers_timestamp: Default::default(), deferred_ops: OperationQueue::new(), } } pub fn snapshot(&self) -> BufferSnapshot { let text = self.text.snapshot(); let mut syntax_map = self.syntax_map.lock(); syntax_map.interpolate(&text); let syntax = syntax_map.snapshot(); Lines 1–500 of 3085. Load more
pub use crate::{ diagnostic_set::DiagnosticSet, highlight_map::{HighlightId, HighlightMap}, proto, BracketPair, Grammar, Language, LanguageConfig, LanguageRegistry, PLAIN_TEXT, }; use crate::{ diagnostic_set::{DiagnosticEntry, DiagnosticGroup}, language_settings::{language_settings, LanguageSettings}, outline::OutlineItem, syntax_map::{ SyntaxLayerInfo, SyntaxMap, SyntaxMapCapture, SyntaxMapCaptures, SyntaxSnapshot, ToTreeSitterPoint, }, CodeLabel, LanguageScope, Outline, }; use anyhow::{anyhow, Result}; pub use clock::ReplicaId; use futures::FutureExt as _; use gpui::{fonts::HighlightStyle, AppContext, Entity, ModelContext, Task}; use lsp::LanguageServerId; use parking_lot::Mutex; use similar::{ChangeTag, TextDiff}; use smallvec::SmallVec; use smol::future::yield_now; use std::{ any::Any, cmp::{self, Ordering}, collections::BTreeMap, ffi::OsStr, future::Future, iter::{self, Iterator, Peekable}, mem, ops::{Deref, Range}, path::{Path, PathBuf}, str, sync::Arc, time::{Duration, Instant, SystemTime, UNIX_EPOCH}, vec, }; use sum_tree::TreeMap; use text::operation_queue::OperationQueue; pub use text::{Buffer as TextBuffer, BufferSnapshot as TextBufferSnapshot, *}; use theme::SyntaxTheme; #[cfg(any(test, feature = "test-support"))] use util::RandomCharIter; use util::{RangeExt, TryFutureExt as _}; #[cfg(any(test, feature = "test-support"))] pub use {tree_sitter_rust, tree_sitter_typescript}; pub use lsp::DiagnosticSeverity; pub struct Buffer { text: TextBuffer, diff_base: Option<String>, git_diff: git::diff::BufferDiff, file: Option<Arc<dyn File>>, saved_version: clock::Global, saved_version_fingerprint: RopeFingerprint, saved_mtime: SystemTime, transaction_depth: usize, was_dirty_before_starting_transaction: Option<bool>, language: Option<Arc<Language>>, autoindent_requests: Vec<Arc<AutoindentRequest>>, pending_autoindent: Option<Task<()>>, sync_parse_timeout: Duration, syntax_map: Mutex<SyntaxMap>, parsing_in_background: bool, parse_count: usize, diagnostics: SmallVec<[(LanguageServerId, DiagnosticSet); 2]>, remote_selections: TreeMap<ReplicaId, SelectionSet>, selections_update_count: usize, diagnostics_update_count: usize, diagnostics_timestamp: clock::Lamport, file_update_count: usize, git_diff_update_count: usize, completion_triggers: Vec<String>, completion_triggers_timestamp: clock::Lamport, deferred_ops: OperationQueue<Operation>, } pub struct BufferSnapshot { text: text::BufferSnapshot, pub git_diff: git::diff::BufferDiff, pub(crate) syntax: SyntaxSnapshot, file: Option<Arc<dyn File>>, diagnostics: SmallVec<[(LanguageServerId, DiagnosticSet); 2]>, diagnostics_update_count: usize, file_update_count: usize, git_diff_update_count: usize, remote_selections: TreeMap<ReplicaId, SelectionSet>, selections_update_count: usize, language: Option<Arc<Language>>, parse_count: usize, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] pub struct IndentSize { pub len: u32, pub kind: IndentKind, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] pub enum IndentKind { #[default] Space, Tab, } #[derive(Copy, Clone, PartialEq, Eq, Debug, Default)] pub enum CursorShape { #[default] Bar, Block, Underscore, Hollow, } #[derive(Clone, Debug)] struct SelectionSet { line_mode: bool, cursor_shape: CursorShape, selections: Arc<[Selection<Anchor>]>, lamport_timestamp: clock::Lamport, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct GroupId { source: Arc<str>, id: usize, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct Diagnostic { pub source: Option<String>, pub code: Option<String>, pub severity: DiagnosticSeverity, pub message: String, pub group_id: usize, pub is_valid: bool, pub is_primary: bool, pub is_disk_based: bool, pub is_unnecessary: bool, } #[derive(Clone, Debug)] pub struct Completion { pub old_range: Range<Anchor>, pub new_text: String, pub label: CodeLabel, pub lsp_completion: lsp::CompletionItem, } #[derive(Clone, Debug)] pub struct CodeAction { pub server_id: LanguageServerId, pub range: Range<Anchor>, pub lsp_action: lsp::CodeAction, } #[derive(Clone, Debug, PartialEq, Eq)] pub enum Operation { Buffer(text::Operation), UpdateDiagnostics { server_id: LanguageServerId, diagnostics: Arc<[DiagnosticEntry<Anchor>]>, lamport_timestamp: clock::Lamport, }, UpdateSelections { selections: Arc<[Selection<Anchor>]>, lamport_timestamp: clock::Lamport, line_mode: bool, cursor_shape: CursorShape, }, UpdateCompletionTriggers { triggers: Vec<String>, lamport_timestamp: clock::Lamport, }, } #[derive(Clone, Debug, PartialEq, Eq)] pub enum Event { Operation(Operation), Edited, DirtyChanged, Saved, FileHandleChanged, Reloaded, DiffBaseChanged, LanguageChanged, Reparsed, DiagnosticsUpdated, Closed, } pub trait File: Send + Sync { fn as_local(&self) -> Option<&dyn LocalFile>; fn is_local(&self) -> bool { self.as_local().is_some() } fn mtime(&self) -> SystemTime; /// Returns the path of this file relative to the worktree's root directory. fn path(&self) -> &Arc<Path>; /// Returns the path of this file relative to the worktree's parent directory (this means it /// includes the name of the worktree's root folder). fn full_path(&self, cx: &AppContext) -> PathBuf; /// Returns the last component of this handle's absolute path. If this handle refers to the root /// of its worktree, then this method will return the name of the worktree itself. fn file_name<'a>(&'a self, cx: &'a AppContext) -> &'a OsStr; /// Returns the id of the worktree to which this file belongs. /// /// This is needed for looking up project-specific settings. fn worktree_id(&self) -> usize; fn is_deleted(&self) -> bool; fn as_any(&self) -> &dyn Any; fn to_proto(&self) -> rpc::proto::File; } pub trait LocalFile: File { /// Returns the absolute path of this file. fn abs_path(&self, cx: &AppContext) -> PathBuf; fn load(&self, cx: &AppContext) -> Task<Result<String>>; fn buffer_reloaded( &self, buffer_id: u64, version: &clock::Global, fingerprint: RopeFingerprint, line_ending: LineEnding, mtime: SystemTime, cx: &mut AppContext, ); } #[derive(Clone, Debug)] pub enum AutoindentMode { /// Indent each line of inserted text. EachLine, /// Apply the same indentation adjustment to all of the lines /// in a given insertion. Block { /// The original indentation level of the first line of each /// insertion, if it has been copied. original_indent_columns: Vec<u32>, }, } #[derive(Clone)] struct AutoindentRequest { before_edit: BufferSnapshot, entries: Vec<AutoindentRequestEntry>, is_block_mode: bool, } #[derive(Clone)] struct AutoindentRequestEntry { /// A range of the buffer whose indentation should be adjusted. range: Range<Anchor>, /// Whether or not these lines should be considered brand new, for the /// purpose of auto-indent. When text is not new, its indentation will /// only be adjusted if the suggested indentation level has *changed* /// since the edit was made. first_line_is_new: bool, indent_size: IndentSize, original_indent_column: Option<u32>, } #[derive(Debug)] struct IndentSuggestion { basis_row: u32, delta: Ordering, within_error: bool, } struct BufferChunkHighlights<'a> { captures: SyntaxMapCaptures<'a>, next_capture: Option<SyntaxMapCapture<'a>>, stack: Vec<(usize, HighlightId)>, highlight_maps: Vec<HighlightMap>, } pub struct BufferChunks<'a> { range: Range<usize>, chunks: text::Chunks<'a>, diagnostic_endpoints: Peekable<vec::IntoIter<DiagnosticEndpoint>>, error_depth: usize, warning_depth: usize, information_depth: usize, hint_depth: usize, unnecessary_depth: usize, highlights: Option<BufferChunkHighlights<'a>>, } #[derive(Clone, Copy, Debug, Default)] pub struct Chunk<'a> { pub text: &'a str, pub syntax_highlight_id: Option<HighlightId>, pub highlight_style: Option<HighlightStyle>, pub diagnostic_severity: Option<DiagnosticSeverity>, pub is_unnecessary: bool, pub is_tab: bool, } pub struct Diff { pub(crate) base_version: clock::Global, line_ending: LineEnding, edits: Vec<(Range<usize>, Arc<str>)>, } #[derive(Clone, Copy)] pub(crate) struct DiagnosticEndpoint { offset: usize, is_start: bool, severity: DiagnosticSeverity, is_unnecessary: bool, } #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug)] pub enum CharKind { Punctuation, Whitespace, Word, } impl CharKind { pub fn coerce_punctuation(self, treat_punctuation_as_word: bool) -> Self { if treat_punctuation_as_word && self == CharKind::Punctuation { CharKind::Word } else { self } } } impl Buffer { pub fn new<T: Into<String>>(replica_id: ReplicaId, id: u64, base_text: T) -> Self { Self::build( TextBuffer::new(replica_id, id, base_text.into()), None, None, ) } pub fn remote(remote_id: u64, replica_id: ReplicaId, base_text: String) -> Self { Self::build( TextBuffer::new(replica_id, remote_id, base_text), None, None, ) } pub fn from_proto( replica_id: ReplicaId, message: proto::BufferState, file: Option<Arc<dyn File>>, ) -> Result<Self> { let buffer = TextBuffer::new(replica_id, message.id, message.base_text); let mut this = Self::build( buffer, message.diff_base.map(|text| text.into_boxed_str().into()), file, ); this.text.set_line_ending(proto::deserialize_line_ending( rpc::proto::LineEnding::from_i32(message.line_ending) .ok_or_else(|| anyhow!("missing line_ending"))?, )); this.saved_version = proto::deserialize_version(&message.saved_version); this.saved_version_fingerprint = proto::deserialize_fingerprint(&message.saved_version_fingerprint)?; this.saved_mtime = message .saved_mtime .ok_or_else(|| anyhow!("invalid saved_mtime"))? .into(); Ok(this) } pub fn to_proto(&self) -> proto::BufferState { proto::BufferState { id: self.remote_id(), file: self.file.as_ref().map(|f| f.to_proto()), base_text: self.base_text().to_string(), diff_base: self.diff_base.as_ref().map(|h| h.to_string()), line_ending: proto::serialize_line_ending(self.line_ending()) as i32, saved_version: proto::serialize_version(&self.saved_version), saved_version_fingerprint: proto::serialize_fingerprint(self.saved_version_fingerprint), saved_mtime: Some(self.saved_mtime.into()), } } pub fn serialize_ops( &self, since: Option<clock::Global>, cx: &AppContext, ) -> Task<Vec<proto::Operation>> { let mut operations = Vec::new(); operations.extend(self.deferred_ops.iter().map(proto::serialize_operation)); operations.extend(self.remote_selections.iter().map(|(_, set)| { proto::serialize_operation(&Operation::UpdateSelections { selections: set.selections.clone(), lamport_timestamp: set.lamport_timestamp, line_mode: set.line_mode, cursor_shape: set.cursor_shape, }) })); for (server_id, diagnostics) in &self.diagnostics { operations.push(proto::serialize_operation(&Operation::UpdateDiagnostics { lamport_timestamp: self.diagnostics_timestamp, server_id: *server_id, diagnostics: diagnostics.iter().cloned().collect(), })); } operations.push(proto::serialize_operation( &Operation::UpdateCompletionTriggers { triggers: self.completion_triggers.clone(), lamport_timestamp: self.completion_triggers_timestamp, }, )); let text_operations = self.text.operations().clone(); cx.background().spawn(async move { let since = since.unwrap_or_default(); operations.extend( text_operations .iter() .filter(|(_, op)| !since.observed(op.local_timestamp())) .map(|(_, op)| proto::serialize_operation(&Operation::Buffer(op.clone()))), ); operations.sort_unstable_by_key(proto::lamport_timestamp_for_operation); operations }) } pub fn with_language(mut self, language: Arc<Language>, cx: &mut ModelContext<Self>) -> Self { self.set_language(Some(language), cx); self } pub fn build( buffer: TextBuffer, diff_base: Option<String>, file: Option<Arc<dyn File>>, ) -> Self { let saved_mtime = if let Some(file) = file.as_ref() { file.mtime() } else { UNIX_EPOCH }; Self { saved_mtime, saved_version: buffer.version(), saved_version_fingerprint: buffer.as_rope().fingerprint(), transaction_depth: 0, was_dirty_before_starting_transaction: None, text: buffer, diff_base, git_diff: git::diff::BufferDiff::new(), file, syntax_map: Mutex::new(SyntaxMap::new()), parsing_in_background: false, parse_count: 0, sync_parse_timeout: Duration::from_millis(1), autoindent_requests: Default::default(), pending_autoindent: Default::default(), language: None, remote_selections: Default::default(), selections_update_count: 0, diagnostics: Default::default(), diagnostics_update_count: 0, diagnostics_timestamp: Default::default(), file_update_count: 0, git_diff_update_count: 0, completion_triggers: Default::default(), completion_triggers_timestamp: Default::default(), deferred_ops: OperationQueue::new(), } } pub fn snapshot(&self) -> BufferSnapshot { let text = self.text.snapshot(); let mut syntax_map = self.syntax_map.lock(); syntax_map.interpolate(&text); let syntax = syntax_map.snapshot();