pub mod row_chunk; use crate::{ DebuggerTextObject, LanguageScope, Outline, OutlineConfig, PLAIN_TEXT, RunnableCapture, RunnableTag, TextObject, TreeSitterOptions, diagnostic_set::{DiagnosticEntry, DiagnosticEntryRef, DiagnosticGroup}, language_settings::{AutoIndentMode, LanguageSettings, language_settings}, outline::OutlineItem, row_chunk::RowChunks, syntax_map::{ MAX_BYTES_TO_QUERY, SyntaxLayer, SyntaxMap, SyntaxMapCapture, SyntaxMapCaptures, SyntaxMapMatch, SyntaxMapMatches, SyntaxSnapshot, ToTreeSitterPoint, }, task_context::RunnableRange, text_diff::text_diff, unified_diff_with_offsets,};pub use crate::{ Grammar, Language, LanguageRegistry, diagnostic_set::DiagnosticSet, highlight_map::{HighlightId, HighlightMap}, proto,};use anyhow::{Context as _, Result};use clock::Lamport;pub use clock::ReplicaId;use collections::{HashMap, HashSet};use encoding_rs::Encoding;use fs::MTime;use futures::channel::oneshot;use gpui::{ App, AppContext as _, Context, Entity, EventEmitter, HighlightStyle, SharedString, StyledText, Task, TextStyle,}; use lsp::{LanguageServerId, NumberOrString};use parking_lot::Mutex;use serde::{Deserialize, Serialize};use serde_json::Value;use settings::WorktreeId;use smallvec::SmallVec;use smol::future::yield_now;use std::{ any::Any, borrow::Cow, cell::Cell, cmp::{self, Ordering, Reverse}, collections::{BTreeMap, BTreeSet}, future::Future, iter::{self, Iterator, Peekable}, mem, num::NonZeroU32, ops::{Deref, Range}, path::PathBuf, rc, sync::Arc, time::{Duration, Instant}, vec,};use sum_tree::TreeMap;use text::operation_queue::OperationQueue;use text::*;pub use text::{ Anchor, Bias, Buffer as TextBuffer, BufferId, BufferSnapshot as TextBufferSnapshot, Edit, LineIndent, OffsetRangeExt, OffsetUtf16, Patch, Point, PointUtf16, Rope, Selection, SelectionGoal, Subscription, TextDimension, TextSummary, ToOffset, ToOffsetUtf16, ToPoint, ToPointUtf16, Transaction, TransactionId, Unclipped,};use theme::{ActiveTheme as _, SyntaxTheme};#[cfg(any(test, feature = "test-support"))]use util::RandomCharIter;use util::{RangeExt, debug_panic, maybe, paths::PathStyle, rel_path::RelPath}; #[cfg(any(test, feature = "test-support"))]pub use {tree_sitter_python, tree_sitter_rust, tree_sitter_typescript}; pub use lsp::DiagnosticSeverity; /// Indicate whether a [`Buffer`] has permissions to edit.#[derive(PartialEq, Clone, Copy, Debug)]pub enum Capability { /// The buffer is a mutable replica. ReadWrite, /// The buffer is a mutable replica, but toggled to be only readable. Read, /// The buffer is a read-only replica. ReadOnly,} impl Capability { /// Returns `true` if the capability is `ReadWrite`. pub fn editable(self) -> bool { matches!(self, Capability::ReadWrite) }} pub type BufferRow = u32; /// An in-memory representation of a source code file, including its text,/// syntax trees, git status, and diagnostics.pub struct Buffer { text: TextBuffer, branch_state: Option<BufferBranchState>, /// Filesystem state, `None` when there is no path. file: Option<Arc<dyn File>>, /// The mtime of the file when this buffer was last loaded from /// or saved to disk. saved_mtime: Option<MTime>, /// The version vector when this buffer was last loaded from /// or saved to disk. saved_version: clock::Global, preview_version: clock::Global, transaction_depth: usize, was_dirty_before_starting_transaction: Option<bool>, reload_task: Option<Task<Result<()>>>, language: Option<Arc<Language>>, autoindent_requests: Vec<Arc<AutoindentRequest>>, wait_for_autoindent_txs: Vec<oneshot::Sender<()>>, pending_autoindent: Option<Task<()>>, sync_parse_timeout: Option<Duration>, syntax_map: Mutex<SyntaxMap>, reparse: Option<Task<()>>, parse_status: (watch::Sender<ParseStatus>, watch::Receiver<ParseStatus>), non_text_state_update_count: usize, diagnostics: TreeMap<LanguageServerId, DiagnosticSet>, remote_selections: TreeMap<ReplicaId, SelectionSet>, diagnostics_timestamp: clock::Lamport, completion_triggers: BTreeSet<String>, completion_triggers_per_language_server: HashMap<LanguageServerId, BTreeSet<String>>, completion_triggers_timestamp: clock::Lamport, deferred_ops: OperationQueue<Operation>, capability: Capability, has_conflict: bool, /// Memoize calls to has_changes_since(saved_version). /// The contents of a cell are (self.version, has_changes) at the time of a last call. has_unsaved_edits: Cell<(clock::Global, bool)>, change_bits: Vec<rc::Weak<Cell<bool>>>, _subscriptions: Vec<gpui::Subscription>, tree_sitter_data: Arc<TreeSitterData>, encoding: &'static Encoding, has_bom: bool, reload_with_encoding_txns: HashMap<TransactionId, (&'static Encoding, bool)>,} #[derive(Debug)]pub struct TreeSitterData { chunks: RowChunks, brackets_by_chunks: Mutex<Vec<Option<Vec<BracketMatch<usize>>>>>,} const MAX_ROWS_IN_A_CHUNK: u32 = 50; impl TreeSitterData { fn clear(&mut self, snapshot: &text::BufferSnapshot) { self.chunks = RowChunks::new(&snapshot, MAX_ROWS_IN_A_CHUNK); self.brackets_by_chunks.get_mut().clear(); self.brackets_by_chunks .get_mut() .resize(self.chunks.len(), None); } fn new(snapshot: &text::BufferSnapshot) -> Self { let chunks = RowChunks::new(&snapshot, MAX_ROWS_IN_A_CHUNK); Self { brackets_by_chunks: Mutex::new(vec![None; chunks.len()]), chunks, } } fn version(&self) -> &clock::Global { self.chunks.version() }} #[derive(Copy, Clone, Debug, PartialEq, Eq)]pub enum ParseStatus { Idle, Parsing,} struct BufferBranchState { base_buffer: Entity<Buffer>, merged_operations: Vec<Lamport>,} /// An immutable, cheaply cloneable representation of a fixed/// state of a buffer.pub struct BufferSnapshot { pub text: text::BufferSnapshot, pub(crate) syntax: SyntaxSnapshot, tree_sitter_data: Arc<TreeSitterData>, diagnostics: TreeMap<LanguageServerId, DiagnosticSet>, remote_selections: TreeMap<ReplicaId, SelectionSet>, language: Option<Arc<Language>>, file: Option<Arc<dyn File>>, non_text_state_update_count: usize, pub capability: Capability,} /// The kind and amount of indentation in a particular line. For now,/// assumes that indentation is all the same character.#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]pub struct IndentSize { /// The number of bytes that comprise the indentation. pub len: u32, /// The kind of whitespace used for indentation. pub kind: IndentKind,} /// A whitespace character that's used for indentation.#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]pub enum IndentKind { /// An ASCII space character. #[default] Space, /// An ASCII tab character. Tab,} /// The shape of a selection cursor.#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]pub enum CursorShape { /// A vertical bar #[default] Bar, /// A block that surrounds the following character Block, /// An underline that runs along the following character Underline, /// A box drawn around the following character Hollow,} impl From<settings::CursorShape> for CursorShape { fn from(shape: settings::CursorShape) -> Self { match shape { settings::CursorShape::Bar => CursorShape::Bar, settings::CursorShape::Block => CursorShape::Block, settings::CursorShape::Underline => CursorShape::Underline, settings::CursorShape::Hollow => CursorShape::Hollow, } }} #[derive(Clone, Debug)]struct SelectionSet { line_mode: bool, cursor_shape: CursorShape, selections: Arc<[Selection<Anchor>]>, lamport_timestamp: clock::Lamport,} /// A diagnostic associated with a certain range of a buffer.#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]pub struct Diagnostic { /// The name of the service that produced this diagnostic. pub source: Option<String>, /// The ID provided by the dynamic registration that produced this diagnostic. pub registration_id: Option<SharedString>, /// A machine-readable code that identifies this diagnostic. pub code: Option<NumberOrString>, pub code_description: Option<lsp::Uri>, /// Whether this diagnostic is a hint, warning, or error. pub severity: DiagnosticSeverity, /// The human-readable message associated with this diagnostic. pub message: String, /// The human-readable message (in markdown format) pub markdown: Option<String>, /// An id that identifies the group to which this diagnostic belongs. /// /// When a language server produces a diagnostic with /// one or more associated diagnostics, those diagnostics are all /// assigned a single group ID. pub group_id: usize, /// Whether this diagnostic is the primary diagnostic for its group. /// /// In a given group, the primary diagnostic is the top-level diagnostic /// returned by the language server. The non-primary diagnostics are the /// associated diagnostics. pub is_primary: bool, /// Whether this diagnostic is considered to originate from an analysis of /// files on disk, as opposed to any unsaved buffer contents. This is a /// property of a given diagnostic source, and is configured for a given /// language server via the [`LspAdapter::disk_based_diagnostic_sources`](crate::LspAdapter::disk_based_diagnostic_sources) method /// for the language server. pub is_disk_based: bool, /// Whether this diagnostic marks unnecessary code. pub is_unnecessary: bool, /// Quick separation of diagnostics groups based by their source. pub source_kind: DiagnosticSourceKind, /// Data from language server that produced this diagnostic. Passed back to the LS when we request code actions for this diagnostic. pub data: Option<Value>, /// Whether to underline the corresponding text range in the editor. pub underline: bool,} #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]pub enum DiagnosticSourceKind { Pulled, Pushed, Other,} /// An operation used to synchronize this buffer with its other replicas.#[derive(Clone, Debug, PartialEq)]pub enum Operation { /// A text operation. Buffer(text::Operation), /// An update to the buffer's diagnostics. UpdateDiagnostics { /// The id of the language server that produced the new diagnostics. server_id: LanguageServerId, /// The diagnostics. diagnostics: Arc<[DiagnosticEntry<Anchor>]>, /// The buffer's lamport timestamp. lamport_timestamp: clock::Lamport, }, /// An update to the most recent selections in this buffer. UpdateSelections { /// The selections. selections: Arc<[Selection<Anchor>]>, /// The buffer's lamport timestamp. lamport_timestamp: clock::Lamport, /// Whether the selections are in 'line mode'. line_mode: bool, /// The [`CursorShape`] associated with these selections. cursor_shape: CursorShape, }, /// An update to the characters that should trigger autocompletion /// for this buffer. UpdateCompletionTriggers { /// The characters that trigger autocompletion. triggers: Vec<String>, /// The buffer's lamport timestamp. lamport_timestamp: clock::Lamport, /// The language server ID. server_id: LanguageServerId, }, /// An update to the line ending type of this buffer. UpdateLineEnding { /// The line ending type. line_ending: LineEnding, /// The buffer's lamport timestamp. lamport_timestamp: clock::Lamport, },} /// An event that occurs in a buffer.#[derive(Clone, Debug, PartialEq)]pub enum BufferEvent { /// The buffer was changed in a way that must be /// propagated to its other replicas. Operation { operation: Operation, is_local: bool, }, /// The buffer was edited. Edited { is_local: bool }, /// The buffer's `dirty` bit changed. DirtyChanged, /// The buffer was saved. Saved, /// The buffer's file was changed on disk. FileHandleChanged, /// The buffer was reloaded. Reloaded, /// The buffer is in need of a reload ReloadNeeded, /// The buffer's language was changed. /// The boolean indicates whether this buffer did not have a language before, but does now. LanguageChanged(bool), /// The buffer's syntax trees were updated. Reparsed, /// The buffer's diagnostics were updated. DiagnosticsUpdated, /// The buffer gained or lost editing capabilities. CapabilityChanged,} /// The file associated with a buffer.pub trait File: Send + Sync + Any { /// Returns the [`LocalFile`] associated with this file, if the /// file is local. fn as_local(&self) -> Option<&dyn LocalFile>; /// Returns whether this file is local. fn is_local(&self) -> bool { self.as_local().is_some() } /// Returns whether the file is new, exists in storage, or has been deleted. Includes metadata /// only available in some states, such as modification time. fn disk_state(&self) -> DiskState; /// Returns the path of this file relative to the worktree's root directory. fn path(&self) -> &Arc<RelPath>; /// 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: &App) -> PathBuf; /// Returns the path style of this file. fn path_style(&self, cx: &App) -> PathStyle; /// 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 App) -> &'a str; /// Returns the id of the worktree to which this file belongs. /// /// This is needed for looking up project-specific settings. fn worktree_id(&self, cx: &App) -> WorktreeId; /// Converts this file into a protobuf message. fn to_proto(&self, cx: &App) -> rpc::proto::File; /// Return whether Zed considers this to be a private file. fn is_private(&self) -> bool; fn can_open(&self) -> bool { !self.is_local() }} /// The file's storage status - whether it's stored (`Present`), and if so when it was last/// modified. In the case where the file is not stored, it can be either `New` or `Deleted`. In the/// UI these two states are distinguished. For example, the buffer tab does not display a deletion/// indicator for new files.#[derive(Copy, Clone, Debug, PartialEq)]pub enum DiskState { /// File created in Zed that has not been saved. New, /// File present on the filesystem. Present { mtime: MTime, size: u64 }, /// Deleted file that was previously present. Deleted, /// An old version of a file that was previously present /// usually from a version control system. e.g. A git blob Historic { was_deleted: bool },} impl DiskState { /// Returns the file's last known modification time on disk. pub fn mtime(self) -> Option<MTime> { match self { DiskState::New => None, DiskState::Present { mtime, .. } => Some(mtime), DiskState::Deleted => None, DiskState::Historic { .. } => None, } } /// Returns the file's size on disk in bytes. pub fn size(self) -> Option<u64> { match self { DiskState::New => None, DiskState::Present { size, .. } => Some(size), DiskState::Deleted => None, DiskState::Historic { .. } => None, } } pub fn exists(&self) -> bool { match self { DiskState::New => false, DiskState::Present { .. } => true, DiskState::Deleted => false, DiskState::Historic { .. } => false, } } /// Returns true if this state represents a deleted file. pub fn is_deleted(&self) -> bool { match self { DiskState::Deleted => true, DiskState::Historic { was_deleted } => *was_deleted, _ => false, } }} /// The file associated with a buffer, in the case where the file is on the local disk.pub trait LocalFile: File { /// Returns the absolute path of this file fn abs_path(&self, cx: &App) -> PathBuf; /// Loads the file contents from disk and returns them as a UTF-8 encoded string. fn load(&self, cx: &App) -> Task<Result<String>>; /// Loads the file's contents from disk. fn load_bytes(&self, cx: &App) -> Task<Result<Vec<u8>>>;} /// The auto-indent behavior associated with an editing operation./// For some editing operations, each affected line of text has its/// indentation recomputed. For other operations, the entire blockLines 1–500 of 6062. Load more
pub mod row_chunk; use crate::{ DebuggerTextObject, LanguageScope, Outline, OutlineConfig, PLAIN_TEXT, RunnableCapture, RunnableTag, TextObject, TreeSitterOptions, diagnostic_set::{DiagnosticEntry, DiagnosticEntryRef, DiagnosticGroup}, language_settings::{AutoIndentMode, LanguageSettings, language_settings}, outline::OutlineItem, row_chunk::RowChunks, syntax_map::{ MAX_BYTES_TO_QUERY, SyntaxLayer, SyntaxMap, SyntaxMapCapture, SyntaxMapCaptures, SyntaxMapMatch, SyntaxMapMatches, SyntaxSnapshot, ToTreeSitterPoint, }, task_context::RunnableRange, text_diff::text_diff, unified_diff_with_offsets, }; pub use crate::{ Grammar, Language, LanguageRegistry, diagnostic_set::DiagnosticSet, highlight_map::{HighlightId, HighlightMap}, proto, }; use anyhow::{Context as _, Result}; use clock::Lamport; pub use clock::ReplicaId; use collections::{HashMap, HashSet}; use encoding_rs::Encoding; use fs::MTime; use futures::channel::oneshot; use gpui::{ App, AppContext as _, Context, Entity, EventEmitter, HighlightStyle, SharedString, StyledText, Task, TextStyle, }; use lsp::{LanguageServerId, NumberOrString}; use parking_lot::Mutex; use serde::{Deserialize, Serialize}; use serde_json::Value; use settings::WorktreeId; use smallvec::SmallVec; use smol::future::yield_now; use std::{ any::Any, borrow::Cow, cell::Cell, cmp::{self, Ordering, Reverse}, collections::{BTreeMap, BTreeSet}, future::Future, iter::{self, Iterator, Peekable}, mem, num::NonZeroU32, ops::{Deref, Range}, path::PathBuf, rc, sync::Arc, time::{Duration, Instant}, vec, }; use sum_tree::TreeMap; use text::operation_queue::OperationQueue; use text::*; pub use text::{ Anchor, Bias, Buffer as TextBuffer, BufferId, BufferSnapshot as TextBufferSnapshot, Edit, LineIndent, OffsetRangeExt, OffsetUtf16, Patch, Point, PointUtf16, Rope, Selection, SelectionGoal, Subscription, TextDimension, TextSummary, ToOffset, ToOffsetUtf16, ToPoint, ToPointUtf16, Transaction, TransactionId, Unclipped, }; use theme::{ActiveTheme as _, SyntaxTheme}; #[cfg(any(test, feature = "test-support"))] use util::RandomCharIter; use util::{RangeExt, debug_panic, maybe, paths::PathStyle, rel_path::RelPath}; #[cfg(any(test, feature = "test-support"))] pub use {tree_sitter_python, tree_sitter_rust, tree_sitter_typescript}; pub use lsp::DiagnosticSeverity; /// Indicate whether a [`Buffer`] has permissions to edit. #[derive(PartialEq, Clone, Copy, Debug)] pub enum Capability { /// The buffer is a mutable replica. ReadWrite, /// The buffer is a mutable replica, but toggled to be only readable. Read, /// The buffer is a read-only replica. ReadOnly, } impl Capability { /// Returns `true` if the capability is `ReadWrite`. pub fn editable(self) -> bool { matches!(self, Capability::ReadWrite) } } pub type BufferRow = u32; /// An in-memory representation of a source code file, including its text, /// syntax trees, git status, and diagnostics. pub struct Buffer { text: TextBuffer, branch_state: Option<BufferBranchState>, /// Filesystem state, `None` when there is no path. file: Option<Arc<dyn File>>, /// The mtime of the file when this buffer was last loaded from /// or saved to disk. saved_mtime: Option<MTime>, /// The version vector when this buffer was last loaded from /// or saved to disk. saved_version: clock::Global, preview_version: clock::Global, transaction_depth: usize, was_dirty_before_starting_transaction: Option<bool>, reload_task: Option<Task<Result<()>>>, language: Option<Arc<Language>>, autoindent_requests: Vec<Arc<AutoindentRequest>>, wait_for_autoindent_txs: Vec<oneshot::Sender<()>>, pending_autoindent: Option<Task<()>>, sync_parse_timeout: Option<Duration>, syntax_map: Mutex<SyntaxMap>, reparse: Option<Task<()>>, parse_status: (watch::Sender<ParseStatus>, watch::Receiver<ParseStatus>), non_text_state_update_count: usize, diagnostics: TreeMap<LanguageServerId, DiagnosticSet>, remote_selections: TreeMap<ReplicaId, SelectionSet>, diagnostics_timestamp: clock::Lamport, completion_triggers: BTreeSet<String>, completion_triggers_per_language_server: HashMap<LanguageServerId, BTreeSet<String>>, completion_triggers_timestamp: clock::Lamport, deferred_ops: OperationQueue<Operation>, capability: Capability, has_conflict: bool, /// Memoize calls to has_changes_since(saved_version). /// The contents of a cell are (self.version, has_changes) at the time of a last call. has_unsaved_edits: Cell<(clock::Global, bool)>, change_bits: Vec<rc::Weak<Cell<bool>>>, _subscriptions: Vec<gpui::Subscription>, tree_sitter_data: Arc<TreeSitterData>, encoding: &'static Encoding, has_bom: bool, reload_with_encoding_txns: HashMap<TransactionId, (&'static Encoding, bool)>, } #[derive(Debug)] pub struct TreeSitterData { chunks: RowChunks, brackets_by_chunks: Mutex<Vec<Option<Vec<BracketMatch<usize>>>>>, } const MAX_ROWS_IN_A_CHUNK: u32 = 50; impl TreeSitterData { fn clear(&mut self, snapshot: &text::BufferSnapshot) { self.chunks = RowChunks::new(&snapshot, MAX_ROWS_IN_A_CHUNK); self.brackets_by_chunks.get_mut().clear(); self.brackets_by_chunks .get_mut() .resize(self.chunks.len(), None); } fn new(snapshot: &text::BufferSnapshot) -> Self { let chunks = RowChunks::new(&snapshot, MAX_ROWS_IN_A_CHUNK); Self { brackets_by_chunks: Mutex::new(vec![None; chunks.len()]), chunks, } } fn version(&self) -> &clock::Global { self.chunks.version() } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum ParseStatus { Idle, Parsing, } struct BufferBranchState { base_buffer: Entity<Buffer>, merged_operations: Vec<Lamport>, } /// An immutable, cheaply cloneable representation of a fixed /// state of a buffer. pub struct BufferSnapshot { pub text: text::BufferSnapshot, pub(crate) syntax: SyntaxSnapshot, tree_sitter_data: Arc<TreeSitterData>, diagnostics: TreeMap<LanguageServerId, DiagnosticSet>, remote_selections: TreeMap<ReplicaId, SelectionSet>, language: Option<Arc<Language>>, file: Option<Arc<dyn File>>, non_text_state_update_count: usize, pub capability: Capability, } /// The kind and amount of indentation in a particular line. For now, /// assumes that indentation is all the same character. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)] pub struct IndentSize { /// The number of bytes that comprise the indentation. pub len: u32, /// The kind of whitespace used for indentation. pub kind: IndentKind, } /// A whitespace character that's used for indentation. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)] pub enum IndentKind { /// An ASCII space character. #[default] Space, /// An ASCII tab character. Tab, } /// The shape of a selection cursor. #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] pub enum CursorShape { /// A vertical bar #[default] Bar, /// A block that surrounds the following character Block, /// An underline that runs along the following character Underline, /// A box drawn around the following character Hollow, } impl From<settings::CursorShape> for CursorShape { fn from(shape: settings::CursorShape) -> Self { match shape { settings::CursorShape::Bar => CursorShape::Bar, settings::CursorShape::Block => CursorShape::Block, settings::CursorShape::Underline => CursorShape::Underline, settings::CursorShape::Hollow => CursorShape::Hollow, } } } #[derive(Clone, Debug)] struct SelectionSet { line_mode: bool, cursor_shape: CursorShape, selections: Arc<[Selection<Anchor>]>, lamport_timestamp: clock::Lamport, } /// A diagnostic associated with a certain range of a buffer. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Diagnostic { /// The name of the service that produced this diagnostic. pub source: Option<String>, /// The ID provided by the dynamic registration that produced this diagnostic. pub registration_id: Option<SharedString>, /// A machine-readable code that identifies this diagnostic. pub code: Option<NumberOrString>, pub code_description: Option<lsp::Uri>, /// Whether this diagnostic is a hint, warning, or error. pub severity: DiagnosticSeverity, /// The human-readable message associated with this diagnostic. pub message: String, /// The human-readable message (in markdown format) pub markdown: Option<String>, /// An id that identifies the group to which this diagnostic belongs. /// /// When a language server produces a diagnostic with /// one or more associated diagnostics, those diagnostics are all /// assigned a single group ID. pub group_id: usize, /// Whether this diagnostic is the primary diagnostic for its group. /// /// In a given group, the primary diagnostic is the top-level diagnostic /// returned by the language server. The non-primary diagnostics are the /// associated diagnostics. pub is_primary: bool, /// Whether this diagnostic is considered to originate from an analysis of /// files on disk, as opposed to any unsaved buffer contents. This is a /// property of a given diagnostic source, and is configured for a given /// language server via the [`LspAdapter::disk_based_diagnostic_sources`](crate::LspAdapter::disk_based_diagnostic_sources) method /// for the language server. pub is_disk_based: bool, /// Whether this diagnostic marks unnecessary code. pub is_unnecessary: bool, /// Quick separation of diagnostics groups based by their source. pub source_kind: DiagnosticSourceKind, /// Data from language server that produced this diagnostic. Passed back to the LS when we request code actions for this diagnostic. pub data: Option<Value>, /// Whether to underline the corresponding text range in the editor. pub underline: bool, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum DiagnosticSourceKind { Pulled, Pushed, Other, } /// An operation used to synchronize this buffer with its other replicas. #[derive(Clone, Debug, PartialEq)] pub enum Operation { /// A text operation. Buffer(text::Operation), /// An update to the buffer's diagnostics. UpdateDiagnostics { /// The id of the language server that produced the new diagnostics. server_id: LanguageServerId, /// The diagnostics. diagnostics: Arc<[DiagnosticEntry<Anchor>]>, /// The buffer's lamport timestamp. lamport_timestamp: clock::Lamport, }, /// An update to the most recent selections in this buffer. UpdateSelections { /// The selections. selections: Arc<[Selection<Anchor>]>, /// The buffer's lamport timestamp. lamport_timestamp: clock::Lamport, /// Whether the selections are in 'line mode'. line_mode: bool, /// The [`CursorShape`] associated with these selections. cursor_shape: CursorShape, }, /// An update to the characters that should trigger autocompletion /// for this buffer. UpdateCompletionTriggers { /// The characters that trigger autocompletion. triggers: Vec<String>, /// The buffer's lamport timestamp. lamport_timestamp: clock::Lamport, /// The language server ID. server_id: LanguageServerId, }, /// An update to the line ending type of this buffer. UpdateLineEnding { /// The line ending type. line_ending: LineEnding, /// The buffer's lamport timestamp. lamport_timestamp: clock::Lamport, }, } /// An event that occurs in a buffer. #[derive(Clone, Debug, PartialEq)] pub enum BufferEvent { /// The buffer was changed in a way that must be /// propagated to its other replicas. Operation { operation: Operation, is_local: bool, }, /// The buffer was edited. Edited { is_local: bool }, /// The buffer's `dirty` bit changed. DirtyChanged, /// The buffer was saved. Saved, /// The buffer's file was changed on disk. FileHandleChanged, /// The buffer was reloaded. Reloaded, /// The buffer is in need of a reload ReloadNeeded, /// The buffer's language was changed. /// The boolean indicates whether this buffer did not have a language before, but does now. LanguageChanged(bool), /// The buffer's syntax trees were updated. Reparsed, /// The buffer's diagnostics were updated. DiagnosticsUpdated, /// The buffer gained or lost editing capabilities. CapabilityChanged, } /// The file associated with a buffer. pub trait File: Send + Sync + Any { /// Returns the [`LocalFile`] associated with this file, if the /// file is local. fn as_local(&self) -> Option<&dyn LocalFile>; /// Returns whether this file is local. fn is_local(&self) -> bool { self.as_local().is_some() } /// Returns whether the file is new, exists in storage, or has been deleted. Includes metadata /// only available in some states, such as modification time. fn disk_state(&self) -> DiskState; /// Returns the path of this file relative to the worktree's root directory. fn path(&self) -> &Arc<RelPath>; /// 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: &App) -> PathBuf; /// Returns the path style of this file. fn path_style(&self, cx: &App) -> PathStyle; /// 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 App) -> &'a str; /// Returns the id of the worktree to which this file belongs. /// /// This is needed for looking up project-specific settings. fn worktree_id(&self, cx: &App) -> WorktreeId; /// Converts this file into a protobuf message. fn to_proto(&self, cx: &App) -> rpc::proto::File; /// Return whether Zed considers this to be a private file. fn is_private(&self) -> bool; fn can_open(&self) -> bool { !self.is_local() } } /// The file's storage status - whether it's stored (`Present`), and if so when it was last /// modified. In the case where the file is not stored, it can be either `New` or `Deleted`. In the /// UI these two states are distinguished. For example, the buffer tab does not display a deletion /// indicator for new files. #[derive(Copy, Clone, Debug, PartialEq)] pub enum DiskState { /// File created in Zed that has not been saved. New, /// File present on the filesystem. Present { mtime: MTime, size: u64 }, /// Deleted file that was previously present. Deleted, /// An old version of a file that was previously present /// usually from a version control system. e.g. A git blob Historic { was_deleted: bool }, } impl DiskState { /// Returns the file's last known modification time on disk. pub fn mtime(self) -> Option<MTime> { match self { DiskState::New => None, DiskState::Present { mtime, .. } => Some(mtime), DiskState::Deleted => None, DiskState::Historic { .. } => None, } } /// Returns the file's size on disk in bytes. pub fn size(self) -> Option<u64> { match self { DiskState::New => None, DiskState::Present { size, .. } => Some(size), DiskState::Deleted => None, DiskState::Historic { .. } => None, } } pub fn exists(&self) -> bool { match self { DiskState::New => false, DiskState::Present { .. } => true, DiskState::Deleted => false, DiskState::Historic { .. } => false, } } /// Returns true if this state represents a deleted file. pub fn is_deleted(&self) -> bool { match self { DiskState::Deleted => true, DiskState::Historic { was_deleted } => *was_deleted, _ => false, } } } /// The file associated with a buffer, in the case where the file is on the local disk. pub trait LocalFile: File { /// Returns the absolute path of this file fn abs_path(&self, cx: &App) -> PathBuf; /// Loads the file contents from disk and returns them as a UTF-8 encoded string. fn load(&self, cx: &App) -> Task<Result<String>>; /// Loads the file's contents from disk. fn load_bytes(&self, cx: &App) -> Task<Result<Vec<u8>>>; } /// The auto-indent behavior associated with an editing operation. /// For some editing operations, each affected line of text has its /// indentation recomputed. For other operations, the entire block