mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-26 17:33:32 +03:00
Add docs for buffer.rs
Co-authored-by: Antonio <antonio@zed.dev>
This commit is contained in:
parent
ebe2c3658c
commit
6457ccf9ec
@ -60,12 +60,15 @@ pub use {tree_sitter_rust, tree_sitter_typescript};
|
||||
pub use lsp::DiagnosticSeverity;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref BUFFER_DIFF_TASK: TaskLabel = TaskLabel::new();
|
||||
static ref BUFFER_DIFF_TASK: TaskLabel = TaskLabel::new();
|
||||
}
|
||||
|
||||
/// 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 read-only replica.
|
||||
ReadOnly,
|
||||
}
|
||||
|
||||
@ -107,11 +110,11 @@ pub struct Buffer {
|
||||
capability: Capability,
|
||||
}
|
||||
|
||||
/// An immutable, cheaply cloneable representation of a certain
|
||||
/// An immutable, cheaply cloneable representation of a fixed
|
||||
/// state of a buffer.
|
||||
pub struct BufferSnapshot {
|
||||
text: text::BufferSnapshot,
|
||||
pub git_diff: git::diff::BufferDiff,
|
||||
git_diff: git::diff::BufferDiff,
|
||||
pub(crate) syntax: SyntaxSnapshot,
|
||||
file: Option<Arc<dyn File>>,
|
||||
diagnostics: SmallVec<[(LanguageServerId, DiagnosticSet); 2]>,
|
||||
@ -128,25 +131,33 @@ pub struct BufferSnapshot {
|
||||
/// assumes that indentation is all the same character.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, 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, Default)]
|
||||
pub enum IndentKind {
|
||||
/// An ASCII space character.
|
||||
#[default]
|
||||
Space,
|
||||
/// An ASCII tab chracter.
|
||||
Tab,
|
||||
}
|
||||
|
||||
/// The shape of a selection cursor.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
|
||||
pub enum CursorShape {
|
||||
/// A vertical bar
|
||||
#[default]
|
||||
Bar,
|
||||
/// A block that surrounds the following character
|
||||
Block,
|
||||
/// An underline that runs along the following character
|
||||
Underscore,
|
||||
/// A box drawn around the following character
|
||||
Hollow,
|
||||
}
|
||||
|
||||
@ -158,26 +169,40 @@ struct SelectionSet {
|
||||
lamport_timestamp: clock::Lamport,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct GroupId {
|
||||
source: Arc<str>,
|
||||
id: usize,
|
||||
}
|
||||
|
||||
/// A diagnostic associated with a certain range of a buffer.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Diagnostic {
|
||||
/// The name of the service that produced this diagnostic.
|
||||
pub source: Option<String>,
|
||||
/// A machine-readable code that identifies this diagnostic.
|
||||
pub code: Option<String>,
|
||||
/// Whether this diagnostic is a hint, warning, or error.
|
||||
pub severity: DiagnosticSeverity,
|
||||
/// The human-readable message associated with this diagnostic.
|
||||
pub message: 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,
|
||||
pub is_valid: bool,
|
||||
/// 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] method
|
||||
/// for the language server.
|
||||
pub is_disk_based: bool,
|
||||
/// Whether this diagnostic marks unnecessary code.
|
||||
pub is_unnecessary: bool,
|
||||
}
|
||||
|
||||
/// TODO - move this into the `project` crate and make it private.
|
||||
pub async fn prepare_completion_documentation(
|
||||
documentation: &lsp::Documentation,
|
||||
language_registry: &Arc<LanguageRegistry>,
|
||||
@ -209,77 +234,125 @@ pub async fn prepare_completion_documentation(
|
||||
}
|
||||
}
|
||||
|
||||
/// Documentation associated with a [Completion].
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Documentation {
|
||||
/// There is no documentation for this completion.
|
||||
Undocumented,
|
||||
/// A single line of documentation.
|
||||
SingleLine(String),
|
||||
/// Multiple lines of plain text documentation.
|
||||
MultiLinePlainText(String),
|
||||
/// Markdown documentation.
|
||||
MultiLineMarkdown(ParsedMarkdown),
|
||||
}
|
||||
|
||||
/// A completion provided by a language server
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Completion {
|
||||
/// The range of the buffer that will be replaced.
|
||||
pub old_range: Range<Anchor>,
|
||||
/// The new text that will be inserted.
|
||||
pub new_text: String,
|
||||
/// A label for this completion that is shown in the menu.
|
||||
pub label: CodeLabel,
|
||||
/// The id of the language server that produced this completion.
|
||||
pub server_id: LanguageServerId,
|
||||
/// The documentation for this completion.
|
||||
pub documentation: Option<Documentation>,
|
||||
/// The raw completion provided by the language server.
|
||||
pub lsp_completion: lsp::CompletionItem,
|
||||
}
|
||||
|
||||
/// A code action provided by a language server.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CodeAction {
|
||||
/// The id of the language server that produced this code action.
|
||||
pub server_id: LanguageServerId,
|
||||
/// The range of the buffer where this code action is applicable.
|
||||
pub range: Range<Anchor>,
|
||||
/// The raw code action provided by the language server.
|
||||
pub lsp_action: lsp::CodeAction,
|
||||
}
|
||||
|
||||
/// 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,
|
||||
},
|
||||
}
|
||||
|
||||
/// An event that occurs in a buffer.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Event {
|
||||
/// The buffer was changed in a way that must be
|
||||
/// propagated to its other replicas.
|
||||
Operation(Operation),
|
||||
/// The buffer was edited.
|
||||
Edited,
|
||||
/// 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's diff_base changed.
|
||||
DiffBaseChanged,
|
||||
/// The buffer's language was changed.
|
||||
LanguageChanged,
|
||||
/// The buffer's syntax trees were updated.
|
||||
Reparsed,
|
||||
/// The buffer's diagnostics were updated.
|
||||
DiagnosticsUpdated,
|
||||
/// The buffer was explicitly requested to close.
|
||||
Closed,
|
||||
}
|
||||
|
||||
/// The file associated with a buffer.
|
||||
pub trait File: Send + Sync {
|
||||
/// 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 the file's mtime.
|
||||
fn mtime(&self) -> SystemTime;
|
||||
|
||||
/// Returns the path of this file relative to the worktree's root directory.
|
||||
@ -298,10 +371,13 @@ pub trait File: Send + Sync {
|
||||
/// This is needed for looking up project-specific settings.
|
||||
fn worktree_id(&self) -> usize;
|
||||
|
||||
/// Returns whether the file has been deleted.
|
||||
fn is_deleted(&self) -> bool;
|
||||
|
||||
/// Converts this file into an [Any] trait object.
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
|
||||
/// Converts this file into a protobuf message.
|
||||
fn to_proto(&self) -> rpc::proto::File;
|
||||
}
|
||||
|
||||
@ -310,8 +386,10 @@ pub trait LocalFile: File {
|
||||
/// Returns the absolute path of this file.
|
||||
fn abs_path(&self, cx: &AppContext) -> PathBuf;
|
||||
|
||||
/// Loads the file's contents from disk.
|
||||
fn load(&self, cx: &AppContext) -> Task<Result<String>>;
|
||||
|
||||
/// Called when the buffer is reloaded from disk.
|
||||
fn buffer_reloaded(
|
||||
&self,
|
||||
buffer_id: u64,
|
||||
@ -392,11 +470,18 @@ pub struct BufferChunks<'a> {
|
||||
/// diagnostic status.
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct Chunk<'a> {
|
||||
/// The text of the chunk.
|
||||
pub text: &'a str,
|
||||
/// The syntax highlighting style of the chunk.
|
||||
pub syntax_highlight_id: Option<HighlightId>,
|
||||
/// The highlight style that has been applied to this chunk in
|
||||
/// the editor.
|
||||
pub highlight_style: Option<HighlightStyle>,
|
||||
/// The severity of diagnostic associated with this chunk, if any.
|
||||
pub diagnostic_severity: Option<DiagnosticSeverity>,
|
||||
/// Whether this chunk of text is marked as unnecessary.
|
||||
pub is_unnecessary: bool,
|
||||
/// Whether this chunk of text was originally a tab character.
|
||||
pub is_tab: bool,
|
||||
}
|
||||
|
||||
@ -418,21 +503,14 @@ pub(crate) struct DiagnosticEndpoint {
|
||||
/// A class of characters, used for characterizing a run of text.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug)]
|
||||
pub enum CharKind {
|
||||
/// Whitespace.
|
||||
Whitespace,
|
||||
/// Punctuation.
|
||||
Punctuation,
|
||||
/// Word.
|
||||
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 {
|
||||
/// Create a new buffer with the given base text.
|
||||
pub fn new<T: Into<String>>(replica_id: ReplicaId, id: u64, base_text: T) -> Self {
|
||||
@ -554,14 +632,17 @@ impl Buffer {
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns the [Capability] of this buffer.
|
||||
pub fn capability(&self) -> Capability {
|
||||
self.capability
|
||||
}
|
||||
|
||||
/// Whether this buffer can only be read.
|
||||
pub fn read_only(&self) -> bool {
|
||||
self.capability == Capability::ReadOnly
|
||||
}
|
||||
|
||||
/// Builds a [Buffer] with the given underlying [TextBuffer], diff base, [File] and [Capability].
|
||||
pub fn build(
|
||||
buffer: TextBuffer,
|
||||
diff_base: Option<String>,
|
||||
@ -675,6 +756,7 @@ impl Buffer {
|
||||
.set_language_registry(language_registry);
|
||||
}
|
||||
|
||||
/// This method is called to signal that the buffer has been saved.
|
||||
pub fn did_save(
|
||||
&mut self,
|
||||
version: clock::Global,
|
||||
@ -689,6 +771,7 @@ impl Buffer {
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
/// Reloads the contents of the buffer from disk.
|
||||
pub fn reload(
|
||||
&mut self,
|
||||
cx: &mut ModelContext<Self>,
|
||||
@ -737,6 +820,7 @@ impl Buffer {
|
||||
rx
|
||||
}
|
||||
|
||||
/// This method is called to signal that the buffer has been reloaded.
|
||||
pub fn did_reload(
|
||||
&mut self,
|
||||
version: clock::Global,
|
||||
@ -763,6 +847,8 @@ impl Buffer {
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
/// Updates the [File] backing this buffer. This should be called when
|
||||
/// the file has changed or has been deleted.
|
||||
pub fn file_updated(&mut self, new_file: Arc<dyn File>, cx: &mut ModelContext<Self>) {
|
||||
let mut file_changed = false;
|
||||
|
||||
@ -800,16 +886,20 @@ impl Buffer {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the current diff base, see [Buffer::set_diff_base].
|
||||
pub fn diff_base(&self) -> Option<&str> {
|
||||
self.diff_base.as_deref()
|
||||
}
|
||||
|
||||
/// Sets the text that will be used to compute a Git diff
|
||||
/// against the buffer text.
|
||||
pub fn set_diff_base(&mut self, diff_base: Option<String>, cx: &mut ModelContext<Self>) {
|
||||
self.diff_base = diff_base;
|
||||
self.git_diff_recalc(cx);
|
||||
cx.emit(Event::DiffBaseChanged);
|
||||
}
|
||||
|
||||
/// Recomputes the Git diff status.
|
||||
pub fn git_diff_recalc(&mut self, cx: &mut ModelContext<Self>) -> Option<Task<()>> {
|
||||
let diff_base = self.diff_base.clone()?; // TODO: Make this an Arc
|
||||
let snapshot = self.snapshot();
|
||||
@ -830,14 +920,12 @@ impl Buffer {
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn close(&mut self, cx: &mut ModelContext<Self>) {
|
||||
cx.emit(Event::Closed);
|
||||
}
|
||||
|
||||
/// Returns the primary [Language] assigned to this [Buffer].
|
||||
pub fn language(&self) -> Option<&Arc<Language>> {
|
||||
self.language.as_ref()
|
||||
}
|
||||
|
||||
/// Returns the [Language] at the given location.
|
||||
pub fn language_at<D: ToOffset>(&self, position: D) -> Option<Arc<Language>> {
|
||||
let offset = position.to_offset(self);
|
||||
self.syntax_map
|
||||
@ -848,26 +936,32 @@ impl Buffer {
|
||||
.or_else(|| self.language.clone())
|
||||
}
|
||||
|
||||
/// The number of times the buffer was parsed.
|
||||
pub fn parse_count(&self) -> usize {
|
||||
self.parse_count
|
||||
}
|
||||
|
||||
/// The number of times selections were updated.
|
||||
pub fn selections_update_count(&self) -> usize {
|
||||
self.selections_update_count
|
||||
}
|
||||
|
||||
/// The number of times diagnostics were updated.
|
||||
pub fn diagnostics_update_count(&self) -> usize {
|
||||
self.diagnostics_update_count
|
||||
}
|
||||
|
||||
/// The number of times the underlying file was updated.
|
||||
pub fn file_update_count(&self) -> usize {
|
||||
self.file_update_count
|
||||
}
|
||||
|
||||
/// The number of times the git diff status was updated.
|
||||
pub fn git_diff_update_count(&self) -> usize {
|
||||
self.git_diff_update_count
|
||||
}
|
||||
|
||||
/// Whether the buffer is being parsed in the background.
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn is_parsing(&self) -> bool {
|
||||
self.parsing_in_background
|
||||
@ -2377,7 +2471,7 @@ impl BufferSnapshot {
|
||||
self.syntax.layers_for_range(0..self.len(), &self.text)
|
||||
}
|
||||
|
||||
pub fn syntax_layer_at<D: ToOffset>(&self, position: D) -> Option<SyntaxLayer> {
|
||||
fn syntax_layer_at<D: ToOffset>(&self, position: D) -> Option<SyntaxLayer> {
|
||||
let offset = position.to_offset(self);
|
||||
self.syntax
|
||||
.layers_for_range(offset..offset, &self.text)
|
||||
@ -2385,12 +2479,14 @@ impl BufferSnapshot {
|
||||
.last()
|
||||
}
|
||||
|
||||
/// Returns the [Language] at the given location.
|
||||
pub fn language_at<D: ToOffset>(&self, position: D) -> Option<&Arc<Language>> {
|
||||
self.syntax_layer_at(position)
|
||||
.map(|info| info.language)
|
||||
.or(self.language.as_ref())
|
||||
}
|
||||
|
||||
/// Returns the settings for the language at the given location.
|
||||
pub fn settings_at<'a, D: ToOffset>(
|
||||
&self,
|
||||
position: D,
|
||||
@ -2399,6 +2495,7 @@ impl BufferSnapshot {
|
||||
language_settings(self.language_at(position), self.file.as_ref(), cx)
|
||||
}
|
||||
|
||||
/// Returns the [LanguageScope] at the given location.
|
||||
pub fn language_scope_at<D: ToOffset>(&self, position: D) -> Option<LanguageScope> {
|
||||
let offset = position.to_offset(self);
|
||||
let mut scope = None;
|
||||
@ -2443,6 +2540,8 @@ impl BufferSnapshot {
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a tuple of the range and character kind of the word
|
||||
/// surrounding the given position.
|
||||
pub fn surrounding_word<T: ToOffset>(&self, start: T) -> (Range<usize>, Option<CharKind>) {
|
||||
let mut start = start.to_offset(self);
|
||||
let mut end = start;
|
||||
@ -2475,6 +2574,7 @@ impl BufferSnapshot {
|
||||
(start..end, word_kind)
|
||||
}
|
||||
|
||||
/// Returns the range for the closes syntax node enclosing the given range.
|
||||
pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
|
||||
let range = range.start.to_offset(self)..range.end.to_offset(self);
|
||||
let mut result: Option<Range<usize>> = None;
|
||||
@ -2543,11 +2643,19 @@ impl BufferSnapshot {
|
||||
result
|
||||
}
|
||||
|
||||
/// Returns the outline for the buffer.
|
||||
///
|
||||
/// This method allows passing an optional [SyntaxTheme] to
|
||||
/// syntax-highlight the returned symbols.
|
||||
pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
|
||||
self.outline_items_containing(0..self.len(), true, theme)
|
||||
.map(Outline::new)
|
||||
}
|
||||
|
||||
/// Returns all the symbols that contain the given position.
|
||||
///
|
||||
/// This method allows passing an optional [SyntaxTheme] to
|
||||
/// syntax-highlight the returned symbols.
|
||||
pub fn symbols_containing<T: ToOffset>(
|
||||
&self,
|
||||
position: T,
|
||||
@ -2699,6 +2807,8 @@ impl BufferSnapshot {
|
||||
Some(items)
|
||||
}
|
||||
|
||||
/// For each grammar in the language, runs the provided
|
||||
/// [tree_sitter::Query] against the given range.
|
||||
pub fn matches(
|
||||
&self,
|
||||
range: Range<usize>,
|
||||
@ -2755,6 +2865,7 @@ impl BufferSnapshot {
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns selections for remote peers intersecting the given range.
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn remote_selections_in_range(
|
||||
&self,
|
||||
@ -2793,6 +2904,13 @@ impl BufferSnapshot {
|
||||
})
|
||||
}
|
||||
|
||||
/// Whether the buffer contains any git changes.
|
||||
pub fn has_git_diff(&self) -> bool {
|
||||
!self.git_diff.is_empty()
|
||||
}
|
||||
|
||||
/// Returns all the Git diff hunks intersecting the given
|
||||
/// row range.
|
||||
pub fn git_diff_hunks_in_row_range<'a>(
|
||||
&'a self,
|
||||
range: Range<u32>,
|
||||
@ -2800,6 +2918,8 @@ impl BufferSnapshot {
|
||||
self.git_diff.hunks_in_row_range(range, self)
|
||||
}
|
||||
|
||||
/// Returns all the Git diff hunks intersecting the given
|
||||
/// range.
|
||||
pub fn git_diff_hunks_intersecting_range<'a>(
|
||||
&'a self,
|
||||
range: Range<Anchor>,
|
||||
@ -2807,6 +2927,8 @@ impl BufferSnapshot {
|
||||
self.git_diff.hunks_intersecting_range(range, self)
|
||||
}
|
||||
|
||||
/// Returns all the Git diff hunks intersecting the given
|
||||
/// range, in reverse order.
|
||||
pub fn git_diff_hunks_intersecting_range_rev<'a>(
|
||||
&'a self,
|
||||
range: Range<Anchor>,
|
||||
@ -2814,6 +2936,7 @@ impl BufferSnapshot {
|
||||
self.git_diff.hunks_intersecting_range_rev(range, self)
|
||||
}
|
||||
|
||||
/// Returns all the diagnostics intersecting the given range.
|
||||
pub fn diagnostics_in_range<'a, T, O>(
|
||||
&'a self,
|
||||
search_range: Range<T>,
|
||||
@ -2843,6 +2966,9 @@ impl BufferSnapshot {
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns all the diagnostic groups associated with the given
|
||||
/// language server id. If no language server id is provided,
|
||||
/// all diagnostics groups are returned.
|
||||
pub fn diagnostic_groups(
|
||||
&self,
|
||||
language_server_id: Option<LanguageServerId>,
|
||||
@ -2873,6 +2999,7 @@ impl BufferSnapshot {
|
||||
groups
|
||||
}
|
||||
|
||||
/// Returns an iterator over the diagnostics for the given group.
|
||||
pub fn diagnostic_group<'a, O>(
|
||||
&'a self,
|
||||
group_id: usize,
|
||||
@ -2885,22 +3012,27 @@ impl BufferSnapshot {
|
||||
.flat_map(move |(_, set)| set.group(group_id, self))
|
||||
}
|
||||
|
||||
/// The number of times diagnostics were updated.
|
||||
pub fn diagnostics_update_count(&self) -> usize {
|
||||
self.diagnostics_update_count
|
||||
}
|
||||
|
||||
/// The number of times the buffer was parsed.
|
||||
pub fn parse_count(&self) -> usize {
|
||||
self.parse_count
|
||||
}
|
||||
|
||||
/// The number of times selections were updated.
|
||||
pub fn selections_update_count(&self) -> usize {
|
||||
self.selections_update_count
|
||||
}
|
||||
|
||||
/// Returns a snapshot of underlying file.
|
||||
pub fn file(&self) -> Option<&Arc<dyn File>> {
|
||||
self.file.as_ref()
|
||||
}
|
||||
|
||||
/// Resolves the file path (relative to the worktree root) associated with the underlying file.
|
||||
pub fn resolve_file_path(&self, cx: &AppContext, include_root: bool) -> Option<PathBuf> {
|
||||
if let Some(file) = self.file() {
|
||||
if file.path().file_name().is_none() || include_root {
|
||||
@ -2913,10 +3045,12 @@ impl BufferSnapshot {
|
||||
}
|
||||
}
|
||||
|
||||
/// The number of times the underlying file was updated.
|
||||
pub fn file_update_count(&self) -> usize {
|
||||
self.file_update_count
|
||||
}
|
||||
|
||||
/// The number of times the git diff status was updated.
|
||||
pub fn git_diff_update_count(&self) -> usize {
|
||||
self.git_diff_update_count
|
||||
}
|
||||
@ -2926,7 +3060,7 @@ fn indent_size_for_line(text: &text::BufferSnapshot, row: u32) -> IndentSize {
|
||||
indent_size_for_text(text.chars_at(Point::new(row, 0)))
|
||||
}
|
||||
|
||||
pub fn indent_size_for_text(text: impl Iterator<Item = char>) -> IndentSize {
|
||||
fn indent_size_for_text(text: impl Iterator<Item = char>) -> IndentSize {
|
||||
let mut result = IndentSize::spaces(0);
|
||||
for c in text {
|
||||
let kind = match c {
|
||||
@ -3004,6 +3138,7 @@ impl<'a> BufferChunks<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Seeks to the given byte offset in the buffer.
|
||||
pub fn seek(&mut self, offset: usize) {
|
||||
self.range.start = offset;
|
||||
self.chunks.seek(self.range.start);
|
||||
@ -3027,6 +3162,7 @@ impl<'a> BufferChunks<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The current byte offset in the buffer.
|
||||
pub fn offset(&self) -> usize {
|
||||
self.range.start
|
||||
}
|
||||
@ -3179,7 +3315,6 @@ impl Default for Diagnostic {
|
||||
message: Default::default(),
|
||||
group_id: 0,
|
||||
is_primary: false,
|
||||
is_valid: true,
|
||||
is_disk_based: false,
|
||||
is_unnecessary: false,
|
||||
}
|
||||
@ -3187,6 +3322,7 @@ impl Default for Diagnostic {
|
||||
}
|
||||
|
||||
impl IndentSize {
|
||||
/// Returns an [IndentSize] representing the given spaces.
|
||||
pub fn spaces(len: u32) -> Self {
|
||||
Self {
|
||||
len,
|
||||
@ -3194,6 +3330,7 @@ impl IndentSize {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an [IndentSize] representing a tab.
|
||||
pub fn tab() -> Self {
|
||||
Self {
|
||||
len: 1,
|
||||
@ -3201,10 +3338,12 @@ impl IndentSize {
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over the characters represented by this [IndentSize].
|
||||
pub fn chars(&self) -> impl Iterator<Item = char> {
|
||||
iter::repeat(self.char()).take(self.len as usize)
|
||||
}
|
||||
|
||||
/// The character representation of this [IndentSize].
|
||||
pub fn char(&self) -> char {
|
||||
match self.kind {
|
||||
IndentKind::Space => ' ',
|
||||
@ -3212,6 +3351,8 @@ impl IndentSize {
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes the current [IndentSize] and returns a new one that has
|
||||
/// been shrunk or enlarged by the given size along the given direction.
|
||||
pub fn with_delta(mut self, direction: Ordering, size: IndentSize) -> Self {
|
||||
match direction {
|
||||
Ordering::Less => {
|
||||
@ -3233,6 +3374,8 @@ impl IndentSize {
|
||||
}
|
||||
|
||||
impl Completion {
|
||||
/// A key that can be used to sort completions when displaying
|
||||
/// them to the user.
|
||||
pub fn sort_key(&self) -> (usize, &str) {
|
||||
let kind_key = match self.lsp_completion.kind {
|
||||
Some(lsp::CompletionItemKind::VARIABLE) => 0,
|
||||
@ -3241,12 +3384,13 @@ impl Completion {
|
||||
(kind_key, &self.label.text[self.label.filter_range.clone()])
|
||||
}
|
||||
|
||||
/// Whether this completion is a snippet.
|
||||
pub fn is_snippet(&self) -> bool {
|
||||
self.lsp_completion.insert_text_format == Some(lsp::InsertTextFormat::SNIPPET)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contiguous_ranges(
|
||||
pub(crate) fn contiguous_ranges(
|
||||
values: impl Iterator<Item = u32>,
|
||||
max_len: usize,
|
||||
) -> impl Iterator<Item = Range<u32>> {
|
||||
@ -3272,6 +3416,9 @@ pub fn contiguous_ranges(
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the [CharKind] for the given character. When a scope is provided,
|
||||
/// the function checks if the character is considered a word character
|
||||
/// based on the language scope's word character settings.
|
||||
pub fn char_kind(scope: &Option<LanguageScope>, c: char) -> CharKind {
|
||||
if c.is_whitespace() {
|
||||
return CharKind::Whitespace;
|
||||
|
@ -223,7 +223,7 @@ pub fn serialize_diagnostics<'a>(
|
||||
} as i32,
|
||||
group_id: entry.diagnostic.group_id as u64,
|
||||
is_primary: entry.diagnostic.is_primary,
|
||||
is_valid: entry.diagnostic.is_valid,
|
||||
is_valid: true,
|
||||
code: entry.diagnostic.code.clone(),
|
||||
is_disk_based: entry.diagnostic.is_disk_based,
|
||||
is_unnecessary: entry.diagnostic.is_unnecessary,
|
||||
@ -409,7 +409,6 @@ pub fn deserialize_diagnostics(
|
||||
message: diagnostic.message,
|
||||
group_id: diagnostic.group_id as usize,
|
||||
code: diagnostic.code,
|
||||
is_valid: diagnostic.is_valid,
|
||||
is_primary: diagnostic.is_primary,
|
||||
is_disk_based: diagnostic.is_disk_based,
|
||||
is_unnecessary: diagnostic.is_unnecessary,
|
||||
|
@ -3023,7 +3023,7 @@ impl MultiBufferSnapshot {
|
||||
|
||||
pub fn has_git_diffs(&self) -> bool {
|
||||
for excerpt in self.excerpts.iter() {
|
||||
if !excerpt.buffer.git_diff.is_empty() {
|
||||
if excerpt.buffer.has_git_diff() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -3912,7 +3912,6 @@ impl Project {
|
||||
message: diagnostic.message.clone(),
|
||||
group_id,
|
||||
is_primary: true,
|
||||
is_valid: true,
|
||||
is_disk_based,
|
||||
is_unnecessary,
|
||||
},
|
||||
@ -3930,7 +3929,6 @@ impl Project {
|
||||
message: info.message.clone(),
|
||||
group_id,
|
||||
is_primary: false,
|
||||
is_valid: true,
|
||||
is_disk_based,
|
||||
is_unnecessary: false,
|
||||
},
|
||||
|
@ -1471,7 +1471,10 @@ message Diagnostic {
|
||||
optional string code = 6;
|
||||
uint64 group_id = 7;
|
||||
bool is_primary = 8;
|
||||
|
||||
// TODO: remove this field
|
||||
bool is_valid = 9;
|
||||
|
||||
bool is_disk_based = 10;
|
||||
bool is_unnecessary = 11;
|
||||
|
||||
|
@ -681,8 +681,8 @@ pub(crate) fn next_word_start(
|
||||
for _ in 0..times {
|
||||
let mut crossed_newline = false;
|
||||
point = movement::find_boundary(map, point, FindRange::MultiLine, |left, right| {
|
||||
let left_kind = char_kind(&scope, left).coerce_punctuation(ignore_punctuation);
|
||||
let right_kind = char_kind(&scope, right).coerce_punctuation(ignore_punctuation);
|
||||
let left_kind = coerce_punctuation(char_kind(&scope, left), ignore_punctuation);
|
||||
let right_kind = coerce_punctuation(char_kind(&scope, right), ignore_punctuation);
|
||||
let at_newline = right == '\n';
|
||||
|
||||
let found = (left_kind != right_kind && right_kind != CharKind::Whitespace)
|
||||
@ -711,8 +711,8 @@ fn next_word_end(
|
||||
*point.column_mut() = 0;
|
||||
}
|
||||
point = movement::find_boundary(map, point, FindRange::MultiLine, |left, right| {
|
||||
let left_kind = char_kind(&scope, left).coerce_punctuation(ignore_punctuation);
|
||||
let right_kind = char_kind(&scope, right).coerce_punctuation(ignore_punctuation);
|
||||
let left_kind = coerce_punctuation(char_kind(&scope, left), ignore_punctuation);
|
||||
let right_kind = ccoerce_punctuation(har_kind(&scope, right), ignore_punctuation);
|
||||
|
||||
left_kind != right_kind && left_kind != CharKind::Whitespace
|
||||
});
|
||||
@ -744,8 +744,8 @@ fn previous_word_start(
|
||||
// cursor because the newline is checked only once.
|
||||
point =
|
||||
movement::find_preceding_boundary(map, point, FindRange::MultiLine, |left, right| {
|
||||
let left_kind = char_kind(&scope, left).coerce_punctuation(ignore_punctuation);
|
||||
let right_kind = char_kind(&scope, right).coerce_punctuation(ignore_punctuation);
|
||||
let left_kind = coerce_punctuation(char_kind(&scope, left), ignore_punctuation);
|
||||
let right_kind = coerce_punctuation(char_kind(&scope, right), ignore_punctuation);
|
||||
|
||||
(left_kind != right_kind && !right.is_whitespace()) || left == '\n'
|
||||
});
|
||||
@ -952,6 +952,14 @@ pub(crate) fn next_line_end(
|
||||
end_of_line(map, false, point)
|
||||
}
|
||||
|
||||
fn coerce_punctuation(kind: CharKind, treat_punctuation_as_word: bool) -> Self {
|
||||
if treat_punctuation_as_word && kind == CharKind::Punctuation {
|
||||
CharKind::Word
|
||||
} else {
|
||||
kind
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user