mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-08 07:35:01 +03:00
Start work on API docs for the language crate (#3981)
This commit is contained in:
commit
9ec6855e6b
File diff suppressed because it is too large
Load Diff
@ -9,20 +9,36 @@ use std::{
|
|||||||
use sum_tree::{self, Bias, SumTree};
|
use sum_tree::{self, Bias, SumTree};
|
||||||
use text::{Anchor, FromAnchor, PointUtf16, ToOffset};
|
use text::{Anchor, FromAnchor, PointUtf16, ToOffset};
|
||||||
|
|
||||||
|
/// A set of diagnostics associated with a given buffer, provided
|
||||||
|
/// by a single language server.
|
||||||
|
///
|
||||||
|
/// The diagnostics are stored in a [SumTree], which allows this struct
|
||||||
|
/// to be cheaply copied, and allows for efficient retrieval of the
|
||||||
|
/// diagnostics that intersect a given range of the buffer.
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct DiagnosticSet {
|
pub struct DiagnosticSet {
|
||||||
diagnostics: SumTree<DiagnosticEntry<Anchor>>,
|
diagnostics: SumTree<DiagnosticEntry<Anchor>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A single diagnostic in a set. Generic over its range type, because
|
||||||
|
/// the diagnostics are stored internally as [Anchor]s, but can be
|
||||||
|
/// resolved to different coordinates types like [usize] byte offsets or
|
||||||
|
/// [Point]s.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct DiagnosticEntry<T> {
|
pub struct DiagnosticEntry<T> {
|
||||||
|
/// The range of the buffer where the diagnostic applies.
|
||||||
pub range: Range<T>,
|
pub range: Range<T>,
|
||||||
|
/// The information about the diagnostic.
|
||||||
pub diagnostic: Diagnostic,
|
pub diagnostic: Diagnostic,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A group of related diagnostics, ordered by their start position
|
||||||
|
/// in the buffer.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DiagnosticGroup<T> {
|
pub struct DiagnosticGroup<T> {
|
||||||
|
/// The diagnostics.
|
||||||
pub entries: Vec<DiagnosticEntry<T>>,
|
pub entries: Vec<DiagnosticEntry<T>>,
|
||||||
|
/// The index into `entries` where the primary diagnostic is stored.
|
||||||
pub primary_ix: usize,
|
pub primary_ix: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +52,8 @@ pub struct Summary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T> DiagnosticEntry<T> {
|
impl<T> DiagnosticEntry<T> {
|
||||||
// Used to provide diagnostic context to lsp codeAction request
|
/// Returns a raw LSP diagnostic ssed to provide diagnostic context to lsp
|
||||||
|
/// codeAction request
|
||||||
pub fn to_lsp_diagnostic_stub(&self) -> lsp::Diagnostic {
|
pub fn to_lsp_diagnostic_stub(&self) -> lsp::Diagnostic {
|
||||||
let code = self
|
let code = self
|
||||||
.diagnostic
|
.diagnostic
|
||||||
@ -53,6 +70,8 @@ impl<T> DiagnosticEntry<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DiagnosticSet {
|
impl DiagnosticSet {
|
||||||
|
/// Constructs a [DiagnosticSet] from a sequence of entries, ordered by
|
||||||
|
/// their position in the buffer.
|
||||||
pub fn from_sorted_entries<I>(iter: I, buffer: &text::BufferSnapshot) -> Self
|
pub fn from_sorted_entries<I>(iter: I, buffer: &text::BufferSnapshot) -> Self
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = DiagnosticEntry<Anchor>>,
|
I: IntoIterator<Item = DiagnosticEntry<Anchor>>,
|
||||||
@ -62,6 +81,7 @@ impl DiagnosticSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs a [DiagnosticSet] from a sequence of entries in an arbitrary order.
|
||||||
pub fn new<I>(iter: I, buffer: &text::BufferSnapshot) -> Self
|
pub fn new<I>(iter: I, buffer: &text::BufferSnapshot) -> Self
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = DiagnosticEntry<PointUtf16>>,
|
I: IntoIterator<Item = DiagnosticEntry<PointUtf16>>,
|
||||||
@ -80,14 +100,18 @@ impl DiagnosticSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the number of diagnostics in the set.
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.diagnostics.summary().count
|
self.diagnostics.summary().count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over the diagnostic entries in the set.
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &DiagnosticEntry<Anchor>> {
|
pub fn iter(&self) -> impl Iterator<Item = &DiagnosticEntry<Anchor>> {
|
||||||
self.diagnostics.iter()
|
self.diagnostics.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over the diagnostic entries that intersect the
|
||||||
|
/// given range of the buffer.
|
||||||
pub fn range<'a, T, O>(
|
pub fn range<'a, T, O>(
|
||||||
&'a self,
|
&'a self,
|
||||||
range: Range<T>,
|
range: Range<T>,
|
||||||
@ -134,6 +158,7 @@ impl DiagnosticSet {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds all of this set's diagnostic groups to the given output vector.
|
||||||
pub fn groups(
|
pub fn groups(
|
||||||
&self,
|
&self,
|
||||||
language_server_id: LanguageServerId,
|
language_server_id: LanguageServerId,
|
||||||
@ -173,6 +198,8 @@ impl DiagnosticSet {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns all of the diagnostics in a particular diagnostic group,
|
||||||
|
/// in order of their position in the buffer.
|
||||||
pub fn group<'a, O: FromAnchor>(
|
pub fn group<'a, O: FromAnchor>(
|
||||||
&'a self,
|
&'a self,
|
||||||
group_id: usize,
|
group_id: usize,
|
||||||
@ -183,6 +210,7 @@ impl DiagnosticSet {
|
|||||||
.map(|entry| entry.resolve(buffer))
|
.map(|entry| entry.resolve(buffer))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl sum_tree::Item for DiagnosticEntry<Anchor> {
|
impl sum_tree::Item for DiagnosticEntry<Anchor> {
|
||||||
type Summary = Summary;
|
type Summary = Summary;
|
||||||
|
|
||||||
@ -198,6 +226,7 @@ impl sum_tree::Item for DiagnosticEntry<Anchor> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DiagnosticEntry<Anchor> {
|
impl DiagnosticEntry<Anchor> {
|
||||||
|
/// Converts the [DiagnosticEntry] to a different buffer coordinate type.
|
||||||
pub fn resolve<O: FromAnchor>(&self, buffer: &text::BufferSnapshot) -> DiagnosticEntry<O> {
|
pub fn resolve<O: FromAnchor>(&self, buffer: &text::BufferSnapshot) -> DiagnosticEntry<O> {
|
||||||
DiagnosticEntry {
|
DiagnosticEntry {
|
||||||
range: O::from_anchor(&self.range.start, buffer)
|
range: O::from_anchor(&self.range.start, buffer)
|
||||||
|
@ -11,7 +11,7 @@ pub struct HighlightId(pub u32);
|
|||||||
const DEFAULT_SYNTAX_HIGHLIGHT_ID: HighlightId = HighlightId(u32::MAX);
|
const DEFAULT_SYNTAX_HIGHLIGHT_ID: HighlightId = HighlightId(u32::MAX);
|
||||||
|
|
||||||
impl HighlightMap {
|
impl HighlightMap {
|
||||||
pub fn new(capture_names: &[&str], theme: &SyntaxTheme) -> Self {
|
pub(crate) fn new(capture_names: &[&str], theme: &SyntaxTheme) -> Self {
|
||||||
// For each capture name in the highlight query, find the longest
|
// For each capture name in the highlight query, find the longest
|
||||||
// key in the theme's syntax styles that matches all of the
|
// key in the theme's syntax styles that matches all of the
|
||||||
// dot-separated components of the capture name.
|
// dot-separated components of the capture name.
|
||||||
@ -51,7 +51,7 @@ impl HighlightMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl HighlightId {
|
impl HighlightId {
|
||||||
pub fn is_default(&self) -> bool {
|
pub(crate) fn is_default(&self) -> bool {
|
||||||
*self == DEFAULT_SYNTAX_HIGHLIGHT_ID
|
*self == DEFAULT_SYNTAX_HIGHLIGHT_ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,11 @@
|
|||||||
|
//! The `language` crate provides a large chunk of Zed's language-related
|
||||||
|
//! features (the other big contributors being project and lsp crates that revolve around LSP features).
|
||||||
|
//! Namely, this crate:
|
||||||
|
//! - Provides [`Language`], [`Grammar`] and [`LanguageRegistry`] types that
|
||||||
|
//! use Tree-sitter to provide syntax highlighting to the editor; note though that `language` doesn't perform the highlighting by itself. It only maps ranges in a buffer to colors. Treesitter is also used for buffer outlines (lists of symbols in a buffer)
|
||||||
|
//! - Exposes [`LanguageConfig`] that describes how constructs (like brackets or line comments) should be handled by the editor for a source file of a particular language.
|
||||||
|
//!
|
||||||
|
//! Notably we do *not* assign a single language to a single file; in real world a single file can consist of multiple programming languages - HTML is a good example of that - and `language` crate tends to reflect that status quo in it's API.
|
||||||
mod buffer;
|
mod buffer;
|
||||||
mod diagnostic_set;
|
mod diagnostic_set;
|
||||||
mod highlight_map;
|
mod highlight_map;
|
||||||
@ -54,10 +62,13 @@ pub use buffer::*;
|
|||||||
pub use diagnostic_set::DiagnosticEntry;
|
pub use diagnostic_set::DiagnosticEntry;
|
||||||
pub use lsp::LanguageServerId;
|
pub use lsp::LanguageServerId;
|
||||||
pub use outline::{Outline, OutlineItem};
|
pub use outline::{Outline, OutlineItem};
|
||||||
pub use syntax_map::{OwnedSyntaxLayerInfo, SyntaxLayerInfo};
|
pub use syntax_map::{OwnedSyntaxLayer, SyntaxLayer};
|
||||||
pub use text::LineEnding;
|
pub use text::LineEnding;
|
||||||
pub use tree_sitter::{Parser, Tree};
|
pub use tree_sitter::{Parser, Tree};
|
||||||
|
|
||||||
|
/// Initializes the `language` crate.
|
||||||
|
///
|
||||||
|
/// This should be called before making use of items from the create.
|
||||||
pub fn init(cx: &mut AppContext) {
|
pub fn init(cx: &mut AppContext) {
|
||||||
language_settings::init(cx);
|
language_settings::init(cx);
|
||||||
}
|
}
|
||||||
@ -90,7 +101,9 @@ thread_local! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref NEXT_GRAMMAR_ID: AtomicUsize = Default::default();
|
pub(crate) static ref NEXT_GRAMMAR_ID: AtomicUsize = Default::default();
|
||||||
|
/// A shared grammar for plain text, exposed for reuse by downstream crates.
|
||||||
|
#[doc(hidden)]
|
||||||
pub static ref PLAIN_TEXT: Arc<Language> = Arc::new(Language::new(
|
pub static ref PLAIN_TEXT: Arc<Language> = Arc::new(Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: "Plain Text".into(),
|
name: "Plain Text".into(),
|
||||||
@ -100,10 +113,14 @@ lazy_static! {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Types that represent a position in a buffer, and can be converted into
|
||||||
|
/// an LSP position, to send to a language server.
|
||||||
pub trait ToLspPosition {
|
pub trait ToLspPosition {
|
||||||
|
/// Converts the value into an LSP position.
|
||||||
fn to_lsp_position(self) -> lsp::Position;
|
fn to_lsp_position(self) -> lsp::Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A name of a language server.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct LanguageServerName(pub Arc<str>);
|
pub struct LanguageServerName(pub Arc<str>);
|
||||||
|
|
||||||
@ -239,6 +256,8 @@ impl CachedLspAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// [`LspAdapterDelegate`] allows [`LspAdapter]` implementations to interface with the application
|
||||||
|
// e.g. to display a notification or fetch data from the web.
|
||||||
pub trait LspAdapterDelegate: Send + Sync {
|
pub trait LspAdapterDelegate: Send + Sync {
|
||||||
fn show_notification(&self, message: &str, cx: &mut AppContext);
|
fn show_notification(&self, message: &str, cx: &mut AppContext);
|
||||||
fn http_client(&self) -> Arc<dyn HttpClient>;
|
fn http_client(&self) -> Arc<dyn HttpClient>;
|
||||||
@ -284,6 +303,10 @@ pub trait LspAdapter: 'static + Send + Sync {
|
|||||||
delegate: &dyn LspAdapterDelegate,
|
delegate: &dyn LspAdapterDelegate,
|
||||||
) -> Option<LanguageServerBinary>;
|
) -> Option<LanguageServerBinary>;
|
||||||
|
|
||||||
|
/// Returns true if a language server can be reinstalled.
|
||||||
|
/// If language server initialization fails, a reinstallation will be attempted unless the value returned from this method is false.
|
||||||
|
/// Implementations that rely on software already installed on user's system
|
||||||
|
/// should have [`can_be_reinstalled`] return false.
|
||||||
fn can_be_reinstalled(&self) -> bool {
|
fn can_be_reinstalled(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -295,6 +318,9 @@ pub trait LspAdapter: 'static + Send + Sync {
|
|||||||
|
|
||||||
fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
|
fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
|
||||||
|
|
||||||
|
/// A callback called for each [`lsp_types::CompletionItem`] obtained from LSP server.
|
||||||
|
/// Some LspAdapter implementations might want to modify the obtained item to
|
||||||
|
/// change how it's displayed.
|
||||||
async fn process_completion(&self, _: &mut lsp::CompletionItem) {}
|
async fn process_completion(&self, _: &mut lsp::CompletionItem) {}
|
||||||
|
|
||||||
async fn label_for_completion(
|
async fn label_for_completion(
|
||||||
@ -314,6 +340,7 @@ pub trait LspAdapter: 'static + Send + Sync {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns initialization options that are going to be sent to a LSP server as a part of [`lsp_types::InitializeParams`]
|
||||||
async fn initialization_options(&self) -> Option<Value> {
|
async fn initialization_options(&self) -> Option<Value> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -322,6 +349,7 @@ pub trait LspAdapter: 'static + Send + Sync {
|
|||||||
futures::future::ready(serde_json::json!({})).boxed()
|
futures::future::ready(serde_json::json!({})).boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a list of code actions supported by a given LspAdapter
|
||||||
fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
|
fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
|
||||||
Some(vec![
|
Some(vec![
|
||||||
CodeActionKind::EMPTY,
|
CodeActionKind::EMPTY,
|
||||||
@ -358,36 +386,59 @@ pub struct CodeLabel {
|
|||||||
|
|
||||||
#[derive(Clone, Deserialize)]
|
#[derive(Clone, Deserialize)]
|
||||||
pub struct LanguageConfig {
|
pub struct LanguageConfig {
|
||||||
|
/// Human-readable name of the language.
|
||||||
pub name: Arc<str>,
|
pub name: Arc<str>,
|
||||||
|
// The name of the grammar in a WASM bundle (experimental).
|
||||||
pub grammar_name: Option<Arc<str>>,
|
pub grammar_name: Option<Arc<str>>,
|
||||||
|
/// Given a list of `LanguageConfig`'s, the language of a file can be determined based on the path extension matching any of the `path_suffixes`.
|
||||||
pub path_suffixes: Vec<String>,
|
pub path_suffixes: Vec<String>,
|
||||||
|
/// List of bracket types in a language.
|
||||||
pub brackets: BracketPairConfig,
|
pub brackets: BracketPairConfig,
|
||||||
|
/// A regex pattern that determines whether the language should be assigned to a file or not.
|
||||||
#[serde(default, deserialize_with = "deserialize_regex")]
|
#[serde(default, deserialize_with = "deserialize_regex")]
|
||||||
pub first_line_pattern: Option<Regex>,
|
pub first_line_pattern: Option<Regex>,
|
||||||
|
/// If set to true, auto indentation uses last non empty line to determine
|
||||||
|
/// the indentation level for a new line.
|
||||||
#[serde(default = "auto_indent_using_last_non_empty_line_default")]
|
#[serde(default = "auto_indent_using_last_non_empty_line_default")]
|
||||||
pub auto_indent_using_last_non_empty_line: bool,
|
pub auto_indent_using_last_non_empty_line: bool,
|
||||||
|
/// A regex that is used to determine whether the indentation level should be
|
||||||
|
/// increased in the following line.
|
||||||
#[serde(default, deserialize_with = "deserialize_regex")]
|
#[serde(default, deserialize_with = "deserialize_regex")]
|
||||||
pub increase_indent_pattern: Option<Regex>,
|
pub increase_indent_pattern: Option<Regex>,
|
||||||
|
/// A regex that is used to determine whether the indentation level should be
|
||||||
|
/// decreased in the following line.
|
||||||
#[serde(default, deserialize_with = "deserialize_regex")]
|
#[serde(default, deserialize_with = "deserialize_regex")]
|
||||||
pub decrease_indent_pattern: Option<Regex>,
|
pub decrease_indent_pattern: Option<Regex>,
|
||||||
|
/// A list of characters that trigger the automatic insertion of a closing
|
||||||
|
/// bracket when they immediately precede the point where an opening
|
||||||
|
/// bracket is inserted.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub autoclose_before: String,
|
pub autoclose_before: String,
|
||||||
#[serde(default)]
|
/// A placeholder used internally by Semantic Index.
|
||||||
pub line_comment: Option<Arc<str>>,
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub collapsed_placeholder: String,
|
pub collapsed_placeholder: String,
|
||||||
|
/// A line comment string that is inserted in e.g. `toggle comments` action.
|
||||||
|
#[serde(default)]
|
||||||
|
pub line_comment: Option<Arc<str>>,
|
||||||
|
/// Starting and closing characters of a block comment.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub block_comment: Option<(Arc<str>, Arc<str>)>,
|
pub block_comment: Option<(Arc<str>, Arc<str>)>,
|
||||||
|
/// A list of language servers that are allowed to run on subranges of a given language.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub scope_opt_in_language_servers: Vec<String>,
|
pub scope_opt_in_language_servers: Vec<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub overrides: HashMap<String, LanguageConfigOverride>,
|
pub overrides: HashMap<String, LanguageConfigOverride>,
|
||||||
|
/// A list of characters that Zed should treat as word characters for the
|
||||||
|
/// purpose of features that operate on word boundaries, like 'move to next word end'
|
||||||
|
/// or a whole-word search in buffer search.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub word_characters: HashSet<char>,
|
pub word_characters: HashSet<char>,
|
||||||
|
/// The name of a Prettier parser that should be used for this language.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub prettier_parser_name: Option<String>,
|
pub prettier_parser_name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tree-sitter language queries for a given language.
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct LanguageQueries {
|
pub struct LanguageQueries {
|
||||||
pub highlights: Option<Cow<'static, str>>,
|
pub highlights: Option<Cow<'static, str>>,
|
||||||
@ -399,6 +450,9 @@ pub struct LanguageQueries {
|
|||||||
pub overrides: Option<Cow<'static, str>>,
|
pub overrides: Option<Cow<'static, str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents a language for the given range. Some languages (e.g. HTML)
|
||||||
|
/// interleave several languages together, thus a single buffer might actually contain
|
||||||
|
/// several nested scopes.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct LanguageScope {
|
pub struct LanguageScope {
|
||||||
language: Arc<Language>,
|
language: Arc<Language>,
|
||||||
@ -458,9 +512,9 @@ impl Default for LanguageConfig {
|
|||||||
block_comment: Default::default(),
|
block_comment: Default::default(),
|
||||||
scope_opt_in_language_servers: Default::default(),
|
scope_opt_in_language_servers: Default::default(),
|
||||||
overrides: Default::default(),
|
overrides: Default::default(),
|
||||||
collapsed_placeholder: Default::default(),
|
|
||||||
word_characters: Default::default(),
|
word_characters: Default::default(),
|
||||||
prettier_parser_name: None,
|
prettier_parser_name: None,
|
||||||
|
collapsed_placeholder: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -478,6 +532,7 @@ fn deserialize_regex<'de, D: Deserializer<'de>>(d: D) -> Result<Option<Regex>, D
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
pub struct FakeLspAdapter {
|
pub struct FakeLspAdapter {
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
@ -489,9 +544,16 @@ pub struct FakeLspAdapter {
|
|||||||
pub prettier_plugins: Vec<&'static str>,
|
pub prettier_plugins: Vec<&'static str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configuration of handling bracket pairs for a given language.
|
||||||
|
///
|
||||||
|
/// This struct includes settings for defining which pairs of characters are considered brackets and
|
||||||
|
/// also specifies any language-specific scopes where these pairs should be ignored for bracket matching purposes.
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct BracketPairConfig {
|
pub struct BracketPairConfig {
|
||||||
|
/// A list of character pairs that should be treated as brackets in the context of a given language.
|
||||||
pub pairs: Vec<BracketPair>,
|
pub pairs: Vec<BracketPair>,
|
||||||
|
/// A list of tree-sitter scopes for which a given bracket should not be active.
|
||||||
|
/// N-th entry in `[Self::disabled_scopes_by_bracket_ix]` contains a list of disabled scopes for an n-th entry in `[Self::pairs]`
|
||||||
pub disabled_scopes_by_bracket_ix: Vec<Vec<String>>,
|
pub disabled_scopes_by_bracket_ix: Vec<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,11 +585,18 @@ impl<'de> Deserialize<'de> for BracketPairConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Describes a single bracket pair and how an editor should react to e.g. inserting
|
||||||
|
/// an opening bracket or to a newline character insertion inbetween `start` and `end` characters.
|
||||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||||
pub struct BracketPair {
|
pub struct BracketPair {
|
||||||
|
/// Starting substring for a bracket.
|
||||||
pub start: String,
|
pub start: String,
|
||||||
|
/// Ending substring for a bracket.
|
||||||
pub end: String,
|
pub end: String,
|
||||||
|
/// True if `end` should be automatically inserted right after `start` characters.
|
||||||
pub close: bool,
|
pub close: bool,
|
||||||
|
/// True if an extra newline should be inserted while the cursor is in the middle
|
||||||
|
/// of that bracket pair.
|
||||||
pub newline: bool,
|
pub newline: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1641,6 +1710,8 @@ impl LanguageScope {
|
|||||||
self.language.config.collapsed_placeholder.as_ref()
|
self.language.config.collapsed_placeholder.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns line prefix that is inserted in e.g. line continuations or
|
||||||
|
/// in `toggle comments` action.
|
||||||
pub fn line_comment_prefix(&self) -> Option<&Arc<str>> {
|
pub fn line_comment_prefix(&self) -> Option<&Arc<str>> {
|
||||||
Override::as_option(
|
Override::as_option(
|
||||||
self.config_override().map(|o| &o.line_comment),
|
self.config_override().map(|o| &o.line_comment),
|
||||||
@ -1656,6 +1727,11 @@ impl LanguageScope {
|
|||||||
.map(|e| (&e.0, &e.1))
|
.map(|e| (&e.0, &e.1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a list of language-specific word characters.
|
||||||
|
///
|
||||||
|
/// By default, Zed treats alphanumeric characters (and '_') as word characters for
|
||||||
|
/// the purpose of actions like 'move to next word end` or whole-word search.
|
||||||
|
/// It additionally accounts for language's additional word characters.
|
||||||
pub fn word_characters(&self) -> Option<&HashSet<char>> {
|
pub fn word_characters(&self) -> Option<&HashSet<char>> {
|
||||||
Override::as_option(
|
Override::as_option(
|
||||||
self.config_override().map(|o| &o.word_characters),
|
self.config_override().map(|o| &o.word_characters),
|
||||||
@ -1663,6 +1739,8 @@ impl LanguageScope {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a list of bracket pairs for a given language with an additional
|
||||||
|
/// piece of information about whether the particular bracket pair is currently active for a given language.
|
||||||
pub fn brackets(&self) -> impl Iterator<Item = (&BracketPair, bool)> {
|
pub fn brackets(&self) -> impl Iterator<Item = (&BracketPair, bool)> {
|
||||||
let mut disabled_ids = self
|
let mut disabled_ids = self
|
||||||
.config_override()
|
.config_override()
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! Provides `language`-related settings.
|
||||||
|
|
||||||
use crate::{File, Language};
|
use crate::{File, Language};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use collections::{HashMap, HashSet};
|
use collections::{HashMap, HashSet};
|
||||||
@ -11,10 +13,12 @@ use serde::{Deserialize, Serialize};
|
|||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use std::{num::NonZeroU32, path::Path, sync::Arc};
|
use std::{num::NonZeroU32, path::Path, sync::Arc};
|
||||||
|
|
||||||
|
/// Initializes the language settings.
|
||||||
pub fn init(cx: &mut AppContext) {
|
pub fn init(cx: &mut AppContext) {
|
||||||
AllLanguageSettings::register(cx);
|
AllLanguageSettings::register(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the settings for the specified language from the provided file.
|
||||||
pub fn language_settings<'a>(
|
pub fn language_settings<'a>(
|
||||||
language: Option<&Arc<Language>>,
|
language: Option<&Arc<Language>>,
|
||||||
file: Option<&Arc<dyn File>>,
|
file: Option<&Arc<dyn File>>,
|
||||||
@ -24,6 +28,7 @@ pub fn language_settings<'a>(
|
|||||||
all_language_settings(file, cx).language(language_name.as_deref())
|
all_language_settings(file, cx).language(language_name.as_deref())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the settings for all languages from the provided file.
|
||||||
pub fn all_language_settings<'a>(
|
pub fn all_language_settings<'a>(
|
||||||
file: Option<&Arc<dyn File>>,
|
file: Option<&Arc<dyn File>>,
|
||||||
cx: &'a AppContext,
|
cx: &'a AppContext,
|
||||||
@ -32,51 +37,89 @@ pub fn all_language_settings<'a>(
|
|||||||
AllLanguageSettings::get(location, cx)
|
AllLanguageSettings::get(location, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The settings for all languages.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct AllLanguageSettings {
|
pub struct AllLanguageSettings {
|
||||||
|
/// The settings for GitHub Copilot.
|
||||||
pub copilot: CopilotSettings,
|
pub copilot: CopilotSettings,
|
||||||
defaults: LanguageSettings,
|
defaults: LanguageSettings,
|
||||||
languages: HashMap<Arc<str>, LanguageSettings>,
|
languages: HashMap<Arc<str>, LanguageSettings>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The settings for a particular language.
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
pub struct LanguageSettings {
|
pub struct LanguageSettings {
|
||||||
|
/// How many columns a tab should occupy.
|
||||||
pub tab_size: NonZeroU32,
|
pub tab_size: NonZeroU32,
|
||||||
|
/// Whether to indent lines using tab characters, as opposed to multiple
|
||||||
|
/// spaces.
|
||||||
pub hard_tabs: bool,
|
pub hard_tabs: bool,
|
||||||
|
/// How to soft-wrap long lines of text.
|
||||||
pub soft_wrap: SoftWrap,
|
pub soft_wrap: SoftWrap,
|
||||||
|
/// The column at which to soft-wrap lines, for buffers where soft-wrap
|
||||||
|
/// is enabled.
|
||||||
pub preferred_line_length: u32,
|
pub preferred_line_length: u32,
|
||||||
|
/// Whether to show wrap guides in the editor. Setting this to true will
|
||||||
|
/// show a guide at the 'preferred_line_length' value if softwrap is set to
|
||||||
|
/// 'preferred_line_length', and will show any additional guides as specified
|
||||||
|
/// by the 'wrap_guides' setting.
|
||||||
pub show_wrap_guides: bool,
|
pub show_wrap_guides: bool,
|
||||||
|
/// Character counts at which to show wrap guides in the editor.
|
||||||
pub wrap_guides: Vec<usize>,
|
pub wrap_guides: Vec<usize>,
|
||||||
|
/// Whether or not to perform a buffer format before saving.
|
||||||
pub format_on_save: FormatOnSave,
|
pub format_on_save: FormatOnSave,
|
||||||
|
/// Whether or not to remove any trailing whitespace from lines of a buffer
|
||||||
|
/// before saving it.
|
||||||
pub remove_trailing_whitespace_on_save: bool,
|
pub remove_trailing_whitespace_on_save: bool,
|
||||||
|
/// Whether or not to ensure there's a single newline at the end of a buffer
|
||||||
|
/// when saving it.
|
||||||
pub ensure_final_newline_on_save: bool,
|
pub ensure_final_newline_on_save: bool,
|
||||||
|
/// How to perform a buffer format.
|
||||||
pub formatter: Formatter,
|
pub formatter: Formatter,
|
||||||
|
/// Zed's Prettier integration settings.
|
||||||
|
/// If Prettier is enabled, Zed will use this its Prettier instance for any applicable file, if
|
||||||
|
/// the project has no other Prettier installed.
|
||||||
pub prettier: HashMap<String, serde_json::Value>,
|
pub prettier: HashMap<String, serde_json::Value>,
|
||||||
|
/// Whether to use language servers to provide code intelligence.
|
||||||
pub enable_language_server: bool,
|
pub enable_language_server: bool,
|
||||||
|
/// Controls whether Copilot provides suggestion immediately (true)
|
||||||
|
/// or waits for a `copilot::Toggle` (false).
|
||||||
pub show_copilot_suggestions: bool,
|
pub show_copilot_suggestions: bool,
|
||||||
|
/// Whether to show tabs and spaces in the editor.
|
||||||
pub show_whitespaces: ShowWhitespaceSetting,
|
pub show_whitespaces: ShowWhitespaceSetting,
|
||||||
|
/// Whether to start a new line with a comment when a previous line is a comment as well.
|
||||||
pub extend_comment_on_newline: bool,
|
pub extend_comment_on_newline: bool,
|
||||||
|
/// Inlay hint related settings.
|
||||||
pub inlay_hints: InlayHintSettings,
|
pub inlay_hints: InlayHintSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The settings for [GitHub Copilot](https://github.com/features/copilot).
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct CopilotSettings {
|
pub struct CopilotSettings {
|
||||||
|
/// Whether Copilot is enabled.
|
||||||
pub feature_enabled: bool,
|
pub feature_enabled: bool,
|
||||||
|
/// A list of globs representing files that Copilot should be disabled for.
|
||||||
pub disabled_globs: Vec<GlobMatcher>,
|
pub disabled_globs: Vec<GlobMatcher>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The settings for all languages.
|
||||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct AllLanguageSettingsContent {
|
pub struct AllLanguageSettingsContent {
|
||||||
|
/// The settings for enabling/disabling features.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub features: Option<FeaturesContent>,
|
pub features: Option<FeaturesContent>,
|
||||||
|
/// The settings for GitHub Copilot.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub copilot: Option<CopilotSettingsContent>,
|
pub copilot: Option<CopilotSettingsContent>,
|
||||||
|
/// The default language settings.
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub defaults: LanguageSettingsContent,
|
pub defaults: LanguageSettingsContent,
|
||||||
|
/// The settings for individual languages.
|
||||||
#[serde(default, alias = "language_overrides")]
|
#[serde(default, alias = "language_overrides")]
|
||||||
pub languages: HashMap<Arc<str>, LanguageSettingsContent>,
|
pub languages: HashMap<Arc<str>, LanguageSettingsContent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The settings for a particular language.
|
||||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct LanguageSettingsContent {
|
pub struct LanguageSettingsContent {
|
||||||
/// How many columns a tab should occupy.
|
/// How many columns a tab should occupy.
|
||||||
@ -138,7 +181,7 @@ pub struct LanguageSettingsContent {
|
|||||||
pub formatter: Option<Formatter>,
|
pub formatter: Option<Formatter>,
|
||||||
/// Zed's Prettier integration settings.
|
/// Zed's Prettier integration settings.
|
||||||
/// If Prettier is enabled, Zed will use this its Prettier instance for any applicable file, if
|
/// If Prettier is enabled, Zed will use this its Prettier instance for any applicable file, if
|
||||||
/// project has no other Prettier installed.
|
/// the project has no other Prettier installed.
|
||||||
///
|
///
|
||||||
/// Default: {}
|
/// Default: {}
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@ -148,7 +191,7 @@ pub struct LanguageSettingsContent {
|
|||||||
/// Default: true
|
/// Default: true
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub enable_language_server: Option<bool>,
|
pub enable_language_server: Option<bool>,
|
||||||
/// Controls whether copilot provides suggestion immediately (true)
|
/// Controls whether Copilot provides suggestion immediately (true)
|
||||||
/// or waits for a `copilot::Toggle` (false).
|
/// or waits for a `copilot::Toggle` (false).
|
||||||
///
|
///
|
||||||
/// Default: true
|
/// Default: true
|
||||||
@ -167,18 +210,23 @@ pub struct LanguageSettingsContent {
|
|||||||
pub inlay_hints: Option<InlayHintSettings>,
|
pub inlay_hints: Option<InlayHintSettings>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The contents of the GitHub Copilot settings.
|
||||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct CopilotSettingsContent {
|
pub struct CopilotSettingsContent {
|
||||||
|
/// A list of globs representing files that Copilot should be disabled for.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub disabled_globs: Option<Vec<String>>,
|
pub disabled_globs: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The settings for enabling/disabling features.
|
||||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub struct FeaturesContent {
|
pub struct FeaturesContent {
|
||||||
|
/// Whether the GitHub Copilot feature is enabled.
|
||||||
pub copilot: Option<bool>,
|
pub copilot: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Controls the soft-wrapping behavior in the editor.
|
||||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum SoftWrap {
|
pub enum SoftWrap {
|
||||||
@ -190,29 +238,38 @@ pub enum SoftWrap {
|
|||||||
PreferredLineLength,
|
PreferredLineLength,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Controls the behavior of formatting files when they are saved.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum FormatOnSave {
|
pub enum FormatOnSave {
|
||||||
|
/// Files should be formatted on save.
|
||||||
On,
|
On,
|
||||||
|
/// Files should not be formatted on save.
|
||||||
Off,
|
Off,
|
||||||
|
/// Files should be formatted using the current language server.
|
||||||
LanguageServer,
|
LanguageServer,
|
||||||
|
/// The external program to use to format the files on save.
|
||||||
External {
|
External {
|
||||||
|
/// The external program to run.
|
||||||
command: Arc<str>,
|
command: Arc<str>,
|
||||||
|
/// The arguments to pass to the program.
|
||||||
arguments: Arc<[String]>,
|
arguments: Arc<[String]>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Controls how whitespace should be displayedin the editor.
|
||||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum ShowWhitespaceSetting {
|
pub enum ShowWhitespaceSetting {
|
||||||
/// Draw tabs and spaces only for the selected text.
|
/// Draw whitespace only for the selected text.
|
||||||
Selection,
|
Selection,
|
||||||
/// Do not draw any tabs or spaces
|
/// Do not draw any tabs or spaces.
|
||||||
None,
|
None,
|
||||||
/// Draw all invisible symbols
|
/// Draw all invisible symbols.
|
||||||
All,
|
All,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Controls which formatter should be used when formatting code.
|
||||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum Formatter {
|
pub enum Formatter {
|
||||||
@ -226,11 +283,14 @@ pub enum Formatter {
|
|||||||
Prettier,
|
Prettier,
|
||||||
/// Format code using an external command.
|
/// Format code using an external command.
|
||||||
External {
|
External {
|
||||||
|
/// The external program to run.
|
||||||
command: Arc<str>,
|
command: Arc<str>,
|
||||||
|
/// The arguments to pass to the program.
|
||||||
arguments: Arc<[String]>,
|
arguments: Arc<[String]>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The settings for inlay hints.
|
||||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||||
pub struct InlayHintSettings {
|
pub struct InlayHintSettings {
|
||||||
/// Global switch to toggle hints on and off.
|
/// Global switch to toggle hints on and off.
|
||||||
@ -238,10 +298,19 @@ pub struct InlayHintSettings {
|
|||||||
/// Default: false
|
/// Default: false
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
|
/// Whether type hints should be shown.
|
||||||
|
///
|
||||||
|
/// Default: true
|
||||||
#[serde(default = "default_true")]
|
#[serde(default = "default_true")]
|
||||||
pub show_type_hints: bool,
|
pub show_type_hints: bool,
|
||||||
|
/// Whether parameter hints should be shown.
|
||||||
|
///
|
||||||
|
/// Default: true
|
||||||
#[serde(default = "default_true")]
|
#[serde(default = "default_true")]
|
||||||
pub show_parameter_hints: bool,
|
pub show_parameter_hints: bool,
|
||||||
|
/// Whether other hints should be shown.
|
||||||
|
///
|
||||||
|
/// Default: true
|
||||||
#[serde(default = "default_true")]
|
#[serde(default = "default_true")]
|
||||||
pub show_other_hints: bool,
|
pub show_other_hints: bool,
|
||||||
}
|
}
|
||||||
@ -251,6 +320,7 @@ fn default_true() -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl InlayHintSettings {
|
impl InlayHintSettings {
|
||||||
|
/// Returns the kinds of inlay hints that are enabled based on the settings.
|
||||||
pub fn enabled_inlay_hint_kinds(&self) -> HashSet<Option<InlayHintKind>> {
|
pub fn enabled_inlay_hint_kinds(&self) -> HashSet<Option<InlayHintKind>> {
|
||||||
let mut kinds = HashSet::default();
|
let mut kinds = HashSet::default();
|
||||||
if self.show_type_hints {
|
if self.show_type_hints {
|
||||||
@ -267,6 +337,7 @@ impl InlayHintSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AllLanguageSettings {
|
impl AllLanguageSettings {
|
||||||
|
/// Returns the [`LanguageSettings`] for the language with the specified name.
|
||||||
pub fn language<'a>(&'a self, language_name: Option<&str>) -> &'a LanguageSettings {
|
pub fn language<'a>(&'a self, language_name: Option<&str>) -> &'a LanguageSettings {
|
||||||
if let Some(name) = language_name {
|
if let Some(name) = language_name {
|
||||||
if let Some(overrides) = self.languages.get(name) {
|
if let Some(overrides) = self.languages.get(name) {
|
||||||
@ -276,6 +347,7 @@ impl AllLanguageSettings {
|
|||||||
&self.defaults
|
&self.defaults
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether GitHub Copilot is enabled for the given path.
|
||||||
pub fn copilot_enabled_for_path(&self, path: &Path) -> bool {
|
pub fn copilot_enabled_for_path(&self, path: &Path) -> bool {
|
||||||
!self
|
!self
|
||||||
.copilot
|
.copilot
|
||||||
@ -284,6 +356,7 @@ impl AllLanguageSettings {
|
|||||||
.any(|glob| glob.is_match(path))
|
.any(|glob| glob.is_match(path))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether GitHub Copilot is enabled for the given language and path.
|
||||||
pub fn copilot_enabled(&self, language: Option<&Arc<Language>>, path: Option<&Path>) -> bool {
|
pub fn copilot_enabled(&self, language: Option<&Arc<Language>>, path: Option<&Path>) -> bool {
|
||||||
if !self.copilot.feature_enabled {
|
if !self.copilot.feature_enabled {
|
||||||
return false;
|
return false;
|
||||||
@ -300,13 +373,20 @@ impl AllLanguageSettings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The kind of an inlay hint.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum InlayHintKind {
|
pub enum InlayHintKind {
|
||||||
|
/// An inlay hint for a type.
|
||||||
Type,
|
Type,
|
||||||
|
/// An inlay hint for a parameter.
|
||||||
Parameter,
|
Parameter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InlayHintKind {
|
impl InlayHintKind {
|
||||||
|
/// Returns the [`InlayHintKind`] from the given name.
|
||||||
|
///
|
||||||
|
/// Returns `None` if `name` does not match any of the expected
|
||||||
|
/// string representations.
|
||||||
pub fn from_name(name: &str) -> Option<Self> {
|
pub fn from_name(name: &str) -> Option<Self> {
|
||||||
match name {
|
match name {
|
||||||
"type" => Some(InlayHintKind::Type),
|
"type" => Some(InlayHintKind::Type),
|
||||||
@ -315,6 +395,7 @@ impl InlayHintKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the name of this [`InlayHintKind`].
|
||||||
pub fn name(&self) -> &'static str {
|
pub fn name(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
InlayHintKind::Type => "type",
|
InlayHintKind::Type => "type",
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! Provides Markdown-related constructs.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{ops::Range, path::PathBuf};
|
use std::{ops::Range, path::PathBuf};
|
||||||
|
|
||||||
@ -5,21 +7,30 @@ use crate::{HighlightId, Language, LanguageRegistry};
|
|||||||
use gpui::{px, FontStyle, FontWeight, HighlightStyle, UnderlineStyle};
|
use gpui::{px, FontStyle, FontWeight, HighlightStyle, UnderlineStyle};
|
||||||
use pulldown_cmark::{CodeBlockKind, Event, Options, Parser, Tag};
|
use pulldown_cmark::{CodeBlockKind, Event, Options, Parser, Tag};
|
||||||
|
|
||||||
|
/// Parsed Markdown content.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ParsedMarkdown {
|
pub struct ParsedMarkdown {
|
||||||
|
/// The Markdown text.
|
||||||
pub text: String,
|
pub text: String,
|
||||||
|
/// The list of highlights contained in the Markdown document.
|
||||||
pub highlights: Vec<(Range<usize>, MarkdownHighlight)>,
|
pub highlights: Vec<(Range<usize>, MarkdownHighlight)>,
|
||||||
|
/// The regions of the various ranges in the Markdown document.
|
||||||
pub region_ranges: Vec<Range<usize>>,
|
pub region_ranges: Vec<Range<usize>>,
|
||||||
|
/// The regions of the Markdown document.
|
||||||
pub regions: Vec<ParsedRegion>,
|
pub regions: Vec<ParsedRegion>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A run of highlighted Markdown text.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum MarkdownHighlight {
|
pub enum MarkdownHighlight {
|
||||||
|
/// A styled Markdown highlight.
|
||||||
Style(MarkdownHighlightStyle),
|
Style(MarkdownHighlightStyle),
|
||||||
|
/// A highlighted code block.
|
||||||
Code(HighlightId),
|
Code(HighlightId),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MarkdownHighlight {
|
impl MarkdownHighlight {
|
||||||
|
/// Converts this [`MarkdownHighlight`] to a [`HighlightStyle`].
|
||||||
pub fn to_highlight_style(&self, theme: &theme::SyntaxTheme) -> Option<HighlightStyle> {
|
pub fn to_highlight_style(&self, theme: &theme::SyntaxTheme) -> Option<HighlightStyle> {
|
||||||
match self {
|
match self {
|
||||||
MarkdownHighlight::Style(style) => {
|
MarkdownHighlight::Style(style) => {
|
||||||
@ -48,23 +59,39 @@ impl MarkdownHighlight {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The style for a Markdown highlight.
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
||||||
pub struct MarkdownHighlightStyle {
|
pub struct MarkdownHighlightStyle {
|
||||||
|
/// Whether the text should be italicized.
|
||||||
pub italic: bool,
|
pub italic: bool,
|
||||||
|
/// Whether the text should be underlined.
|
||||||
pub underline: bool,
|
pub underline: bool,
|
||||||
|
/// The weight of the text.
|
||||||
pub weight: FontWeight,
|
pub weight: FontWeight,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A parsed region in a Markdown document.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ParsedRegion {
|
pub struct ParsedRegion {
|
||||||
|
/// Whether the region is a code block.
|
||||||
pub code: bool,
|
pub code: bool,
|
||||||
|
/// The link contained in this region, if it has one.
|
||||||
pub link: Option<Link>,
|
pub link: Option<Link>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A Markdown link.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Link {
|
pub enum Link {
|
||||||
Web { url: String },
|
/// A link to a webpage.
|
||||||
Path { path: PathBuf },
|
Web {
|
||||||
|
/// The URL of the webpage.
|
||||||
|
url: String,
|
||||||
|
},
|
||||||
|
/// A link to a path on the filesystem.
|
||||||
|
Path {
|
||||||
|
/// The path to the item.
|
||||||
|
path: PathBuf,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Link {
|
impl Link {
|
||||||
@ -82,6 +109,7 @@ impl Link {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses a string of Markdown.
|
||||||
pub async fn parse_markdown(
|
pub async fn parse_markdown(
|
||||||
markdown: &str,
|
markdown: &str,
|
||||||
language_registry: &Arc<LanguageRegistry>,
|
language_registry: &Arc<LanguageRegistry>,
|
||||||
@ -111,6 +139,7 @@ pub async fn parse_markdown(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses a Markdown block.
|
||||||
pub async fn parse_markdown_block(
|
pub async fn parse_markdown_block(
|
||||||
markdown: &str,
|
markdown: &str,
|
||||||
language_registry: &Arc<LanguageRegistry>,
|
language_registry: &Arc<LanguageRegistry>,
|
||||||
@ -261,6 +290,7 @@ pub async fn parse_markdown_block(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Appends a highlighted run of text to the provided `text` buffer.
|
||||||
pub fn highlight_code(
|
pub fn highlight_code(
|
||||||
text: &mut String,
|
text: &mut String,
|
||||||
highlights: &mut Vec<(Range<usize>, MarkdownHighlight)>,
|
highlights: &mut Vec<(Range<usize>, MarkdownHighlight)>,
|
||||||
@ -275,6 +305,7 @@ pub fn highlight_code(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Appends a new paragraph to the provided `text` buffer.
|
||||||
pub fn new_paragraph(text: &mut String, list_stack: &mut Vec<(Option<u64>, bool)>) {
|
pub fn new_paragraph(text: &mut String, list_stack: &mut Vec<(Option<u64>, bool)>) {
|
||||||
let mut is_subsequent_paragraph_of_list = false;
|
let mut is_subsequent_paragraph_of_list = false;
|
||||||
if let Some((_, has_content)) = list_stack.last_mut() {
|
if let Some((_, has_content)) = list_stack.last_mut() {
|
||||||
|
@ -2,6 +2,7 @@ use fuzzy::{StringMatch, StringMatchCandidate};
|
|||||||
use gpui::{BackgroundExecutor, HighlightStyle};
|
use gpui::{BackgroundExecutor, HighlightStyle};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
|
/// An outline of all the symbols contained in a buffer.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Outline<T> {
|
pub struct Outline<T> {
|
||||||
pub items: Vec<OutlineItem<T>>,
|
pub items: Vec<OutlineItem<T>>,
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! Handles conversions of `language` items to and from the [`rpc`] protocol.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
diagnostic_set::DiagnosticEntry, CodeAction, CodeLabel, Completion, CursorShape, Diagnostic,
|
diagnostic_set::DiagnosticEntry, CodeAction, CodeLabel, Completion, CursorShape, Diagnostic,
|
||||||
Language,
|
Language,
|
||||||
@ -11,15 +13,18 @@ use text::*;
|
|||||||
|
|
||||||
pub use proto::{BufferState, Operation};
|
pub use proto::{BufferState, Operation};
|
||||||
|
|
||||||
|
/// Serializes a [`RopeFingerprint`] to be sent over RPC.
|
||||||
pub fn serialize_fingerprint(fingerprint: RopeFingerprint) -> String {
|
pub fn serialize_fingerprint(fingerprint: RopeFingerprint) -> String {
|
||||||
fingerprint.to_hex()
|
fingerprint.to_hex()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserializes a [`RopeFingerprint`] from the RPC representation.
|
||||||
pub fn deserialize_fingerprint(fingerprint: &str) -> Result<RopeFingerprint> {
|
pub fn deserialize_fingerprint(fingerprint: &str) -> Result<RopeFingerprint> {
|
||||||
RopeFingerprint::from_hex(fingerprint)
|
RopeFingerprint::from_hex(fingerprint)
|
||||||
.map_err(|error| anyhow!("invalid fingerprint: {}", error))
|
.map_err(|error| anyhow!("invalid fingerprint: {}", error))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserializes a `[text::LineEnding]` from the RPC representation.
|
||||||
pub fn deserialize_line_ending(message: proto::LineEnding) -> text::LineEnding {
|
pub fn deserialize_line_ending(message: proto::LineEnding) -> text::LineEnding {
|
||||||
match message {
|
match message {
|
||||||
proto::LineEnding::Unix => text::LineEnding::Unix,
|
proto::LineEnding::Unix => text::LineEnding::Unix,
|
||||||
@ -27,6 +32,7 @@ pub fn deserialize_line_ending(message: proto::LineEnding) -> text::LineEnding {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes a [`text::LineEnding`] to be sent over RPC.
|
||||||
pub fn serialize_line_ending(message: text::LineEnding) -> proto::LineEnding {
|
pub fn serialize_line_ending(message: text::LineEnding) -> proto::LineEnding {
|
||||||
match message {
|
match message {
|
||||||
text::LineEnding::Unix => proto::LineEnding::Unix,
|
text::LineEnding::Unix => proto::LineEnding::Unix,
|
||||||
@ -34,6 +40,7 @@ pub fn serialize_line_ending(message: text::LineEnding) -> proto::LineEnding {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes a [`crate::Operation`] to be sent over RPC.
|
||||||
pub fn serialize_operation(operation: &crate::Operation) -> proto::Operation {
|
pub fn serialize_operation(operation: &crate::Operation) -> proto::Operation {
|
||||||
proto::Operation {
|
proto::Operation {
|
||||||
variant: Some(match operation {
|
variant: Some(match operation {
|
||||||
@ -96,6 +103,7 @@ pub fn serialize_operation(operation: &crate::Operation) -> proto::Operation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes an [`operation::EditOperation`] to be sent over RPC.
|
||||||
pub fn serialize_edit_operation(operation: &EditOperation) -> proto::operation::Edit {
|
pub fn serialize_edit_operation(operation: &EditOperation) -> proto::operation::Edit {
|
||||||
proto::operation::Edit {
|
proto::operation::Edit {
|
||||||
replica_id: operation.timestamp.replica_id as u32,
|
replica_id: operation.timestamp.replica_id as u32,
|
||||||
@ -110,6 +118,7 @@ pub fn serialize_edit_operation(operation: &EditOperation) -> proto::operation::
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes an entry in the undo map to be sent over RPC.
|
||||||
pub fn serialize_undo_map_entry(
|
pub fn serialize_undo_map_entry(
|
||||||
(edit_id, counts): (&clock::Lamport, &[(clock::Lamport, u32)]),
|
(edit_id, counts): (&clock::Lamport, &[(clock::Lamport, u32)]),
|
||||||
) -> proto::UndoMapEntry {
|
) -> proto::UndoMapEntry {
|
||||||
@ -127,6 +136,7 @@ pub fn serialize_undo_map_entry(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Splits the given list of operations into chunks.
|
||||||
pub fn split_operations(
|
pub fn split_operations(
|
||||||
mut operations: Vec<proto::Operation>,
|
mut operations: Vec<proto::Operation>,
|
||||||
) -> impl Iterator<Item = Vec<proto::Operation>> {
|
) -> impl Iterator<Item = Vec<proto::Operation>> {
|
||||||
@ -152,10 +162,12 @@ pub fn split_operations(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes selections to be sent over RPC.
|
||||||
pub fn serialize_selections(selections: &Arc<[Selection<Anchor>]>) -> Vec<proto::Selection> {
|
pub fn serialize_selections(selections: &Arc<[Selection<Anchor>]>) -> Vec<proto::Selection> {
|
||||||
selections.iter().map(serialize_selection).collect()
|
selections.iter().map(serialize_selection).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes a [`Selection`] to be sent over RPC.
|
||||||
pub fn serialize_selection(selection: &Selection<Anchor>) -> proto::Selection {
|
pub fn serialize_selection(selection: &Selection<Anchor>) -> proto::Selection {
|
||||||
proto::Selection {
|
proto::Selection {
|
||||||
id: selection.id as u64,
|
id: selection.id as u64,
|
||||||
@ -171,6 +183,7 @@ pub fn serialize_selection(selection: &Selection<Anchor>) -> proto::Selection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes a [`CursorShape`] to be sent over RPC.
|
||||||
pub fn serialize_cursor_shape(cursor_shape: &CursorShape) -> proto::CursorShape {
|
pub fn serialize_cursor_shape(cursor_shape: &CursorShape) -> proto::CursorShape {
|
||||||
match cursor_shape {
|
match cursor_shape {
|
||||||
CursorShape::Bar => proto::CursorShape::CursorBar,
|
CursorShape::Bar => proto::CursorShape::CursorBar,
|
||||||
@ -180,6 +193,7 @@ pub fn serialize_cursor_shape(cursor_shape: &CursorShape) -> proto::CursorShape
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserializes a [`CursorShape`] from the RPC representation.
|
||||||
pub fn deserialize_cursor_shape(cursor_shape: proto::CursorShape) -> CursorShape {
|
pub fn deserialize_cursor_shape(cursor_shape: proto::CursorShape) -> CursorShape {
|
||||||
match cursor_shape {
|
match cursor_shape {
|
||||||
proto::CursorShape::CursorBar => CursorShape::Bar,
|
proto::CursorShape::CursorBar => CursorShape::Bar,
|
||||||
@ -189,6 +203,7 @@ pub fn deserialize_cursor_shape(cursor_shape: proto::CursorShape) -> CursorShape
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes a list of diagnostics to be sent over RPC.
|
||||||
pub fn serialize_diagnostics<'a>(
|
pub fn serialize_diagnostics<'a>(
|
||||||
diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<Anchor>>,
|
diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<Anchor>>,
|
||||||
) -> Vec<proto::Diagnostic> {
|
) -> Vec<proto::Diagnostic> {
|
||||||
@ -208,7 +223,7 @@ pub fn serialize_diagnostics<'a>(
|
|||||||
} as i32,
|
} as i32,
|
||||||
group_id: entry.diagnostic.group_id as u64,
|
group_id: entry.diagnostic.group_id as u64,
|
||||||
is_primary: entry.diagnostic.is_primary,
|
is_primary: entry.diagnostic.is_primary,
|
||||||
is_valid: entry.diagnostic.is_valid,
|
is_valid: true,
|
||||||
code: entry.diagnostic.code.clone(),
|
code: entry.diagnostic.code.clone(),
|
||||||
is_disk_based: entry.diagnostic.is_disk_based,
|
is_disk_based: entry.diagnostic.is_disk_based,
|
||||||
is_unnecessary: entry.diagnostic.is_unnecessary,
|
is_unnecessary: entry.diagnostic.is_unnecessary,
|
||||||
@ -216,6 +231,7 @@ pub fn serialize_diagnostics<'a>(
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes an [`Anchor`] to be sent over RPC.
|
||||||
pub fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
|
pub fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
|
||||||
proto::Anchor {
|
proto::Anchor {
|
||||||
replica_id: anchor.timestamp.replica_id as u32,
|
replica_id: anchor.timestamp.replica_id as u32,
|
||||||
@ -230,6 +246,7 @@ pub fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This behavior is currently copied in the collab database, for snapshotting channel notes
|
// This behavior is currently copied in the collab database, for snapshotting channel notes
|
||||||
|
/// Deserializes an [`crate::Operation`] from the RPC representation.
|
||||||
pub fn deserialize_operation(message: proto::Operation) -> Result<crate::Operation> {
|
pub fn deserialize_operation(message: proto::Operation) -> Result<crate::Operation> {
|
||||||
Ok(
|
Ok(
|
||||||
match message
|
match message
|
||||||
@ -312,6 +329,7 @@ pub fn deserialize_operation(message: proto::Operation) -> Result<crate::Operati
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserializes an [`EditOperation`] from the RPC representation.
|
||||||
pub fn deserialize_edit_operation(edit: proto::operation::Edit) -> EditOperation {
|
pub fn deserialize_edit_operation(edit: proto::operation::Edit) -> EditOperation {
|
||||||
EditOperation {
|
EditOperation {
|
||||||
timestamp: clock::Lamport {
|
timestamp: clock::Lamport {
|
||||||
@ -324,6 +342,7 @@ pub fn deserialize_edit_operation(edit: proto::operation::Edit) -> EditOperation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserializes an entry in the undo map from the RPC representation.
|
||||||
pub fn deserialize_undo_map_entry(
|
pub fn deserialize_undo_map_entry(
|
||||||
entry: proto::UndoMapEntry,
|
entry: proto::UndoMapEntry,
|
||||||
) -> (clock::Lamport, Vec<(clock::Lamport, u32)>) {
|
) -> (clock::Lamport, Vec<(clock::Lamport, u32)>) {
|
||||||
@ -348,6 +367,7 @@ pub fn deserialize_undo_map_entry(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserializes selections from the RPC representation.
|
||||||
pub fn deserialize_selections(selections: Vec<proto::Selection>) -> Arc<[Selection<Anchor>]> {
|
pub fn deserialize_selections(selections: Vec<proto::Selection>) -> Arc<[Selection<Anchor>]> {
|
||||||
Arc::from(
|
Arc::from(
|
||||||
selections
|
selections
|
||||||
@ -357,6 +377,7 @@ pub fn deserialize_selections(selections: Vec<proto::Selection>) -> Arc<[Selecti
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserializes a [`Selection`] from the RPC representation.
|
||||||
pub fn deserialize_selection(selection: proto::Selection) -> Option<Selection<Anchor>> {
|
pub fn deserialize_selection(selection: proto::Selection) -> Option<Selection<Anchor>> {
|
||||||
Some(Selection {
|
Some(Selection {
|
||||||
id: selection.id as usize,
|
id: selection.id as usize,
|
||||||
@ -367,6 +388,7 @@ pub fn deserialize_selection(selection: proto::Selection) -> Option<Selection<An
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserializes a list of diagnostics from the RPC representation.
|
||||||
pub fn deserialize_diagnostics(
|
pub fn deserialize_diagnostics(
|
||||||
diagnostics: Vec<proto::Diagnostic>,
|
diagnostics: Vec<proto::Diagnostic>,
|
||||||
) -> Arc<[DiagnosticEntry<Anchor>]> {
|
) -> Arc<[DiagnosticEntry<Anchor>]> {
|
||||||
@ -387,7 +409,6 @@ pub fn deserialize_diagnostics(
|
|||||||
message: diagnostic.message,
|
message: diagnostic.message,
|
||||||
group_id: diagnostic.group_id as usize,
|
group_id: diagnostic.group_id as usize,
|
||||||
code: diagnostic.code,
|
code: diagnostic.code,
|
||||||
is_valid: diagnostic.is_valid,
|
|
||||||
is_primary: diagnostic.is_primary,
|
is_primary: diagnostic.is_primary,
|
||||||
is_disk_based: diagnostic.is_disk_based,
|
is_disk_based: diagnostic.is_disk_based,
|
||||||
is_unnecessary: diagnostic.is_unnecessary,
|
is_unnecessary: diagnostic.is_unnecessary,
|
||||||
@ -397,6 +418,7 @@ pub fn deserialize_diagnostics(
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserializes an [`Anchor`] from the RPC representation.
|
||||||
pub fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
|
pub fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
|
||||||
Some(Anchor {
|
Some(Anchor {
|
||||||
timestamp: clock::Lamport {
|
timestamp: clock::Lamport {
|
||||||
@ -412,6 +434,7 @@ pub fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a `[clock::Lamport`] timestamp for the given [`proto::Operation`].
|
||||||
pub fn lamport_timestamp_for_operation(operation: &proto::Operation) -> Option<clock::Lamport> {
|
pub fn lamport_timestamp_for_operation(operation: &proto::Operation) -> Option<clock::Lamport> {
|
||||||
let replica_id;
|
let replica_id;
|
||||||
let value;
|
let value;
|
||||||
@ -444,6 +467,7 @@ pub fn lamport_timestamp_for_operation(operation: &proto::Operation) -> Option<c
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes a [`Completion`] to be sent over RPC.
|
||||||
pub fn serialize_completion(completion: &Completion) -> proto::Completion {
|
pub fn serialize_completion(completion: &Completion) -> proto::Completion {
|
||||||
proto::Completion {
|
proto::Completion {
|
||||||
old_start: Some(serialize_anchor(&completion.old_range.start)),
|
old_start: Some(serialize_anchor(&completion.old_range.start)),
|
||||||
@ -454,6 +478,7 @@ pub fn serialize_completion(completion: &Completion) -> proto::Completion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserializes a [`Completion`] from the RPC representation.
|
||||||
pub async fn deserialize_completion(
|
pub async fn deserialize_completion(
|
||||||
completion: proto::Completion,
|
completion: proto::Completion,
|
||||||
language: Option<Arc<Language>>,
|
language: Option<Arc<Language>>,
|
||||||
@ -488,6 +513,7 @@ pub async fn deserialize_completion(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes a [`CodeAction`] to be sent over RPC.
|
||||||
pub fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
|
pub fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
|
||||||
proto::CodeAction {
|
proto::CodeAction {
|
||||||
server_id: action.server_id.0 as u64,
|
server_id: action.server_id.0 as u64,
|
||||||
@ -497,6 +523,7 @@ pub fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserializes a [`CodeAction`] from the RPC representation.
|
||||||
pub fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
|
pub fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
|
||||||
let start = action
|
let start = action
|
||||||
.start
|
.start
|
||||||
@ -514,6 +541,7 @@ pub fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes a [`Transaction`] to be sent over RPC.
|
||||||
pub fn serialize_transaction(transaction: &Transaction) -> proto::Transaction {
|
pub fn serialize_transaction(transaction: &Transaction) -> proto::Transaction {
|
||||||
proto::Transaction {
|
proto::Transaction {
|
||||||
id: Some(serialize_timestamp(transaction.id)),
|
id: Some(serialize_timestamp(transaction.id)),
|
||||||
@ -527,6 +555,7 @@ pub fn serialize_transaction(transaction: &Transaction) -> proto::Transaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserializes a [`Transaction`] from the RPC representation.
|
||||||
pub fn deserialize_transaction(transaction: proto::Transaction) -> Result<Transaction> {
|
pub fn deserialize_transaction(transaction: proto::Transaction) -> Result<Transaction> {
|
||||||
Ok(Transaction {
|
Ok(Transaction {
|
||||||
id: deserialize_timestamp(
|
id: deserialize_timestamp(
|
||||||
@ -543,6 +572,7 @@ pub fn deserialize_transaction(transaction: proto::Transaction) -> Result<Transa
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes a [`clock::Lamport`] timestamp to be sent over RPC.
|
||||||
pub fn serialize_timestamp(timestamp: clock::Lamport) -> proto::LamportTimestamp {
|
pub fn serialize_timestamp(timestamp: clock::Lamport) -> proto::LamportTimestamp {
|
||||||
proto::LamportTimestamp {
|
proto::LamportTimestamp {
|
||||||
replica_id: timestamp.replica_id as u32,
|
replica_id: timestamp.replica_id as u32,
|
||||||
@ -550,6 +580,7 @@ pub fn serialize_timestamp(timestamp: clock::Lamport) -> proto::LamportTimestamp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserializes a [`clock::Lamport`] timestamp from the RPC representation.
|
||||||
pub fn deserialize_timestamp(timestamp: proto::LamportTimestamp) -> clock::Lamport {
|
pub fn deserialize_timestamp(timestamp: proto::LamportTimestamp) -> clock::Lamport {
|
||||||
clock::Lamport {
|
clock::Lamport {
|
||||||
replica_id: timestamp.replica_id as ReplicaId,
|
replica_id: timestamp.replica_id as ReplicaId,
|
||||||
@ -557,6 +588,7 @@ pub fn deserialize_timestamp(timestamp: proto::LamportTimestamp) -> clock::Lampo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes a range of [`FullOffset`]s to be sent over RPC.
|
||||||
pub fn serialize_range(range: &Range<FullOffset>) -> proto::Range {
|
pub fn serialize_range(range: &Range<FullOffset>) -> proto::Range {
|
||||||
proto::Range {
|
proto::Range {
|
||||||
start: range.start.0 as u64,
|
start: range.start.0 as u64,
|
||||||
@ -564,10 +596,12 @@ pub fn serialize_range(range: &Range<FullOffset>) -> proto::Range {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserializes a range of [`FullOffset`]s from the RPC representation.
|
||||||
pub fn deserialize_range(range: proto::Range) -> Range<FullOffset> {
|
pub fn deserialize_range(range: proto::Range) -> Range<FullOffset> {
|
||||||
FullOffset(range.start as usize)..FullOffset(range.end as usize)
|
FullOffset(range.start as usize)..FullOffset(range.end as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserializes a clock version from the RPC representation.
|
||||||
pub fn deserialize_version(message: &[proto::VectorClockEntry]) -> clock::Global {
|
pub fn deserialize_version(message: &[proto::VectorClockEntry]) -> clock::Global {
|
||||||
let mut version = clock::Global::new();
|
let mut version = clock::Global::new();
|
||||||
for entry in message {
|
for entry in message {
|
||||||
@ -579,6 +613,7 @@ pub fn deserialize_version(message: &[proto::VectorClockEntry]) -> clock::Global
|
|||||||
version
|
version
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes a clock version to be sent over RPC.
|
||||||
pub fn serialize_version(version: &clock::Global) -> Vec<proto::VectorClockEntry> {
|
pub fn serialize_version(version: &clock::Global) -> Vec<proto::VectorClockEntry> {
|
||||||
version
|
version
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -29,7 +29,7 @@ pub struct SyntaxMap {
|
|||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct SyntaxSnapshot {
|
pub struct SyntaxSnapshot {
|
||||||
layers: SumTree<SyntaxLayer>,
|
layers: SumTree<SyntaxLayerEntry>,
|
||||||
parsed_version: clock::Global,
|
parsed_version: clock::Global,
|
||||||
interpolated_version: clock::Global,
|
interpolated_version: clock::Global,
|
||||||
language_registry_version: usize,
|
language_registry_version: usize,
|
||||||
@ -84,7 +84,7 @@ struct SyntaxMapMatchesLayer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct SyntaxLayer {
|
struct SyntaxLayerEntry {
|
||||||
depth: usize,
|
depth: usize,
|
||||||
range: Range<Anchor>,
|
range: Range<Anchor>,
|
||||||
content: SyntaxLayerContent,
|
content: SyntaxLayerContent,
|
||||||
@ -117,17 +117,22 @@ impl SyntaxLayerContent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A layer of syntax highlighting, corresponding to a single syntax
|
||||||
|
/// tree in a particular language.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SyntaxLayerInfo<'a> {
|
pub struct SyntaxLayer<'a> {
|
||||||
pub depth: usize,
|
/// The language for this layer.
|
||||||
pub language: &'a Arc<Language>,
|
pub language: &'a Arc<Language>,
|
||||||
|
depth: usize,
|
||||||
tree: &'a Tree,
|
tree: &'a Tree,
|
||||||
offset: (usize, tree_sitter::Point),
|
offset: (usize, tree_sitter::Point),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A layer of syntax highlighting. Like [SyntaxLayer], but holding
|
||||||
|
/// owned data instead of references.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct OwnedSyntaxLayerInfo {
|
pub struct OwnedSyntaxLayer {
|
||||||
pub depth: usize,
|
/// The language for this layer.
|
||||||
pub language: Arc<Language>,
|
pub language: Arc<Language>,
|
||||||
tree: tree_sitter::Tree,
|
tree: tree_sitter::Tree,
|
||||||
offset: (usize, tree_sitter::Point),
|
offset: (usize, tree_sitter::Point),
|
||||||
@ -691,7 +696,7 @@ impl SyntaxSnapshot {
|
|||||||
};
|
};
|
||||||
|
|
||||||
layers.push(
|
layers.push(
|
||||||
SyntaxLayer {
|
SyntaxLayerEntry {
|
||||||
depth: step.depth,
|
depth: step.depth,
|
||||||
range: step.range,
|
range: step.range,
|
||||||
content,
|
content,
|
||||||
@ -741,7 +746,7 @@ impl SyntaxSnapshot {
|
|||||||
SyntaxMapCaptures::new(
|
SyntaxMapCaptures::new(
|
||||||
range.clone(),
|
range.clone(),
|
||||||
text,
|
text,
|
||||||
[SyntaxLayerInfo {
|
[SyntaxLayer {
|
||||||
language,
|
language,
|
||||||
tree,
|
tree,
|
||||||
depth: 0,
|
depth: 0,
|
||||||
@ -781,7 +786,7 @@ impl SyntaxSnapshot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn layers<'a>(&'a self, buffer: &'a BufferSnapshot) -> Vec<SyntaxLayerInfo> {
|
pub fn layers<'a>(&'a self, buffer: &'a BufferSnapshot) -> Vec<SyntaxLayer> {
|
||||||
self.layers_for_range(0..buffer.len(), buffer).collect()
|
self.layers_for_range(0..buffer.len(), buffer).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -789,7 +794,7 @@ impl SyntaxSnapshot {
|
|||||||
&'a self,
|
&'a self,
|
||||||
range: Range<T>,
|
range: Range<T>,
|
||||||
buffer: &'a BufferSnapshot,
|
buffer: &'a BufferSnapshot,
|
||||||
) -> impl 'a + Iterator<Item = SyntaxLayerInfo> {
|
) -> impl 'a + Iterator<Item = SyntaxLayer> {
|
||||||
let start_offset = range.start.to_offset(buffer);
|
let start_offset = range.start.to_offset(buffer);
|
||||||
let end_offset = range.end.to_offset(buffer);
|
let end_offset = range.end.to_offset(buffer);
|
||||||
let start = buffer.anchor_before(start_offset);
|
let start = buffer.anchor_before(start_offset);
|
||||||
@ -813,7 +818,7 @@ impl SyntaxSnapshot {
|
|||||||
let layer_start_offset = layer.range.start.to_offset(buffer);
|
let layer_start_offset = layer.range.start.to_offset(buffer);
|
||||||
let layer_start_point = layer.range.start.to_point(buffer).to_ts_point();
|
let layer_start_point = layer.range.start.to_point(buffer).to_ts_point();
|
||||||
|
|
||||||
info = Some(SyntaxLayerInfo {
|
info = Some(SyntaxLayer {
|
||||||
tree,
|
tree,
|
||||||
language,
|
language,
|
||||||
depth: layer.depth,
|
depth: layer.depth,
|
||||||
@ -842,7 +847,7 @@ impl<'a> SyntaxMapCaptures<'a> {
|
|||||||
fn new(
|
fn new(
|
||||||
range: Range<usize>,
|
range: Range<usize>,
|
||||||
text: &'a Rope,
|
text: &'a Rope,
|
||||||
layers: impl Iterator<Item = SyntaxLayerInfo<'a>>,
|
layers: impl Iterator<Item = SyntaxLayer<'a>>,
|
||||||
query: fn(&Grammar) -> Option<&Query>,
|
query: fn(&Grammar) -> Option<&Query>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut result = Self {
|
let mut result = Self {
|
||||||
@ -964,7 +969,7 @@ impl<'a> SyntaxMapMatches<'a> {
|
|||||||
fn new(
|
fn new(
|
||||||
range: Range<usize>,
|
range: Range<usize>,
|
||||||
text: &'a Rope,
|
text: &'a Rope,
|
||||||
layers: impl Iterator<Item = SyntaxLayerInfo<'a>>,
|
layers: impl Iterator<Item = SyntaxLayer<'a>>,
|
||||||
query: fn(&Grammar) -> Option<&Query>,
|
query: fn(&Grammar) -> Option<&Query>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut result = Self::default();
|
let mut result = Self::default();
|
||||||
@ -1436,23 +1441,25 @@ fn insert_newlines_between_ranges(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OwnedSyntaxLayerInfo {
|
impl OwnedSyntaxLayer {
|
||||||
|
/// Returns the root syntax node for this layer.
|
||||||
pub fn node(&self) -> Node {
|
pub fn node(&self) -> Node {
|
||||||
self.tree
|
self.tree
|
||||||
.root_node_with_offset(self.offset.0, self.offset.1)
|
.root_node_with_offset(self.offset.0, self.offset.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SyntaxLayerInfo<'a> {
|
impl<'a> SyntaxLayer<'a> {
|
||||||
pub fn to_owned(&self) -> OwnedSyntaxLayerInfo {
|
/// Returns an owned version of this layer.
|
||||||
OwnedSyntaxLayerInfo {
|
pub fn to_owned(&self) -> OwnedSyntaxLayer {
|
||||||
|
OwnedSyntaxLayer {
|
||||||
tree: self.tree.clone(),
|
tree: self.tree.clone(),
|
||||||
offset: self.offset,
|
offset: self.offset,
|
||||||
depth: self.depth,
|
|
||||||
language: self.language.clone(),
|
language: self.language.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the root node for this layer.
|
||||||
pub fn node(&self) -> Node<'a> {
|
pub fn node(&self) -> Node<'a> {
|
||||||
self.tree
|
self.tree
|
||||||
.root_node_with_offset(self.offset.0, self.offset.1)
|
.root_node_with_offset(self.offset.0, self.offset.1)
|
||||||
@ -1564,7 +1571,7 @@ impl ChangeRegionSet {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn intersects(&self, layer: &SyntaxLayer, text: &BufferSnapshot) -> bool {
|
fn intersects(&self, layer: &SyntaxLayerEntry, text: &BufferSnapshot) -> bool {
|
||||||
for region in &self.0 {
|
for region in &self.0 {
|
||||||
if region.depth < layer.depth {
|
if region.depth < layer.depth {
|
||||||
continue;
|
continue;
|
||||||
@ -1675,7 +1682,7 @@ impl<'a> SeekTarget<'a, SyntaxLayerSummary, SyntaxLayerSummary>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl sum_tree::Item for SyntaxLayer {
|
impl sum_tree::Item for SyntaxLayerEntry {
|
||||||
type Summary = SyntaxLayerSummary;
|
type Summary = SyntaxLayerSummary;
|
||||||
|
|
||||||
fn summary(&self) -> Self::Summary {
|
fn summary(&self) -> Self::Summary {
|
||||||
@ -1690,7 +1697,7 @@ impl sum_tree::Item for SyntaxLayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for SyntaxLayer {
|
impl std::fmt::Debug for SyntaxLayerEntry {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_struct("SyntaxLayer")
|
f.debug_struct("SyntaxLayer")
|
||||||
.field("depth", &self.depth)
|
.field("depth", &self.depth)
|
||||||
|
@ -5,7 +5,7 @@ use gpui::{
|
|||||||
MouseButton, MouseDownEvent, MouseMoveEvent, ParentElement, Render, Styled,
|
MouseButton, MouseDownEvent, MouseMoveEvent, ParentElement, Render, Styled,
|
||||||
UniformListScrollHandle, View, ViewContext, VisualContext, WeakView, WindowContext,
|
UniformListScrollHandle, View, ViewContext, VisualContext, WeakView, WindowContext,
|
||||||
};
|
};
|
||||||
use language::{Buffer, OwnedSyntaxLayerInfo};
|
use language::{Buffer, OwnedSyntaxLayer};
|
||||||
use std::{mem, ops::Range};
|
use std::{mem, ops::Range};
|
||||||
use theme::ActiveTheme;
|
use theme::ActiveTheme;
|
||||||
use tree_sitter::{Node, TreeCursor};
|
use tree_sitter::{Node, TreeCursor};
|
||||||
@ -54,7 +54,7 @@ struct EditorState {
|
|||||||
struct BufferState {
|
struct BufferState {
|
||||||
buffer: Model<Buffer>,
|
buffer: Model<Buffer>,
|
||||||
excerpt_id: ExcerptId,
|
excerpt_id: ExcerptId,
|
||||||
active_layer: Option<OwnedSyntaxLayerInfo>,
|
active_layer: Option<OwnedSyntaxLayer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SyntaxTreeView {
|
impl SyntaxTreeView {
|
||||||
@ -477,7 +477,7 @@ impl SyntaxTreeToolbarItemView {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_header(active_layer: &OwnedSyntaxLayerInfo) -> ButtonLike {
|
fn render_header(active_layer: &OwnedSyntaxLayer) -> ButtonLike {
|
||||||
ButtonLike::new("syntax tree header")
|
ButtonLike::new("syntax tree header")
|
||||||
.child(Label::new(active_layer.language.name()))
|
.child(Label::new(active_layer.language.name()))
|
||||||
.child(Label::new(format_node_range(active_layer.node())))
|
.child(Label::new(format_node_range(active_layer.node())))
|
||||||
|
@ -3028,7 +3028,7 @@ impl MultiBufferSnapshot {
|
|||||||
|
|
||||||
pub fn has_git_diffs(&self) -> bool {
|
pub fn has_git_diffs(&self) -> bool {
|
||||||
for excerpt in self.excerpts.iter() {
|
for excerpt in self.excerpts.iter() {
|
||||||
if !excerpt.buffer.git_diff.is_empty() {
|
if excerpt.buffer.has_git_diff() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3910,7 +3910,6 @@ impl Project {
|
|||||||
message: diagnostic.message.clone(),
|
message: diagnostic.message.clone(),
|
||||||
group_id,
|
group_id,
|
||||||
is_primary: true,
|
is_primary: true,
|
||||||
is_valid: true,
|
|
||||||
is_disk_based,
|
is_disk_based,
|
||||||
is_unnecessary,
|
is_unnecessary,
|
||||||
},
|
},
|
||||||
@ -3928,7 +3927,6 @@ impl Project {
|
|||||||
message: info.message.clone(),
|
message: info.message.clone(),
|
||||||
group_id,
|
group_id,
|
||||||
is_primary: false,
|
is_primary: false,
|
||||||
is_valid: true,
|
|
||||||
is_disk_based,
|
is_disk_based,
|
||||||
is_unnecessary: false,
|
is_unnecessary: false,
|
||||||
},
|
},
|
||||||
|
@ -1472,7 +1472,10 @@ message Diagnostic {
|
|||||||
optional string code = 6;
|
optional string code = 6;
|
||||||
uint64 group_id = 7;
|
uint64 group_id = 7;
|
||||||
bool is_primary = 8;
|
bool is_primary = 8;
|
||||||
|
|
||||||
|
// TODO: remove this field
|
||||||
bool is_valid = 9;
|
bool is_valid = 9;
|
||||||
|
|
||||||
bool is_disk_based = 10;
|
bool is_disk_based = 10;
|
||||||
bool is_unnecessary = 11;
|
bool is_unnecessary = 11;
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ use workspace::Workspace;
|
|||||||
use crate::{
|
use crate::{
|
||||||
normal::normal_motion,
|
normal::normal_motion,
|
||||||
state::{Mode, Operator},
|
state::{Mode, Operator},
|
||||||
|
utils::coerce_punctuation,
|
||||||
visual::visual_motion,
|
visual::visual_motion,
|
||||||
Vim,
|
Vim,
|
||||||
};
|
};
|
||||||
@ -680,8 +681,8 @@ pub(crate) fn next_word_start(
|
|||||||
for _ in 0..times {
|
for _ in 0..times {
|
||||||
let mut crossed_newline = false;
|
let mut crossed_newline = false;
|
||||||
point = movement::find_boundary(map, point, FindRange::MultiLine, |left, right| {
|
point = movement::find_boundary(map, point, FindRange::MultiLine, |left, right| {
|
||||||
let left_kind = char_kind(&scope, left).coerce_punctuation(ignore_punctuation);
|
let left_kind = coerce_punctuation(char_kind(&scope, left), ignore_punctuation);
|
||||||
let right_kind = char_kind(&scope, right).coerce_punctuation(ignore_punctuation);
|
let right_kind = coerce_punctuation(char_kind(&scope, right), ignore_punctuation);
|
||||||
let at_newline = right == '\n';
|
let at_newline = right == '\n';
|
||||||
|
|
||||||
let found = (left_kind != right_kind && right_kind != CharKind::Whitespace)
|
let found = (left_kind != right_kind && right_kind != CharKind::Whitespace)
|
||||||
@ -710,8 +711,8 @@ fn next_word_end(
|
|||||||
*point.column_mut() = 0;
|
*point.column_mut() = 0;
|
||||||
}
|
}
|
||||||
point = movement::find_boundary(map, point, FindRange::MultiLine, |left, right| {
|
point = movement::find_boundary(map, point, FindRange::MultiLine, |left, right| {
|
||||||
let left_kind = char_kind(&scope, left).coerce_punctuation(ignore_punctuation);
|
let left_kind = coerce_punctuation(char_kind(&scope, left), ignore_punctuation);
|
||||||
let right_kind = char_kind(&scope, right).coerce_punctuation(ignore_punctuation);
|
let right_kind = coerce_punctuation(char_kind(&scope, right), ignore_punctuation);
|
||||||
|
|
||||||
left_kind != right_kind && left_kind != CharKind::Whitespace
|
left_kind != right_kind && left_kind != CharKind::Whitespace
|
||||||
});
|
});
|
||||||
@ -743,8 +744,8 @@ fn previous_word_start(
|
|||||||
// cursor because the newline is checked only once.
|
// cursor because the newline is checked only once.
|
||||||
point =
|
point =
|
||||||
movement::find_preceding_boundary(map, point, FindRange::MultiLine, |left, right| {
|
movement::find_preceding_boundary(map, point, FindRange::MultiLine, |left, right| {
|
||||||
let left_kind = char_kind(&scope, left).coerce_punctuation(ignore_punctuation);
|
let left_kind = coerce_punctuation(char_kind(&scope, left), ignore_punctuation);
|
||||||
let right_kind = char_kind(&scope, right).coerce_punctuation(ignore_punctuation);
|
let right_kind = coerce_punctuation(char_kind(&scope, right), ignore_punctuation);
|
||||||
|
|
||||||
(left_kind != right_kind && !right.is_whitespace()) || left == '\n'
|
(left_kind != right_kind && !right.is_whitespace()) || left == '\n'
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
use crate::{motion::Motion, object::Object, state::Mode, utils::copy_selections_content, Vim};
|
use crate::{
|
||||||
|
motion::Motion,
|
||||||
|
object::Object,
|
||||||
|
state::Mode,
|
||||||
|
utils::{coerce_punctuation, copy_selections_content},
|
||||||
|
Vim,
|
||||||
|
};
|
||||||
use editor::{
|
use editor::{
|
||||||
display_map::DisplaySnapshot,
|
display_map::DisplaySnapshot,
|
||||||
movement::{self, FindRange, TextLayoutDetails},
|
movement::{self, FindRange, TextLayoutDetails},
|
||||||
@ -102,9 +108,9 @@ fn expand_changed_word_selection(
|
|||||||
if in_word {
|
if in_word {
|
||||||
selection.end =
|
selection.end =
|
||||||
movement::find_boundary(map, selection.end, FindRange::MultiLine, |left, right| {
|
movement::find_boundary(map, selection.end, FindRange::MultiLine, |left, right| {
|
||||||
let left_kind = char_kind(&scope, left).coerce_punctuation(ignore_punctuation);
|
let left_kind = coerce_punctuation(char_kind(&scope, left), ignore_punctuation);
|
||||||
let right_kind =
|
let right_kind =
|
||||||
char_kind(&scope, right).coerce_punctuation(ignore_punctuation);
|
coerce_punctuation(char_kind(&scope, right), ignore_punctuation);
|
||||||
|
|
||||||
left_kind != right_kind && left_kind != CharKind::Whitespace
|
left_kind != right_kind && left_kind != CharKind::Whitespace
|
||||||
});
|
});
|
||||||
|
@ -10,7 +10,10 @@ use language::{char_kind, CharKind, Selection};
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use workspace::Workspace;
|
use workspace::Workspace;
|
||||||
|
|
||||||
use crate::{motion::right, normal::normal_object, state::Mode, visual::visual_object, Vim};
|
use crate::{
|
||||||
|
motion::right, normal::normal_object, state::Mode, utils::coerce_punctuation,
|
||||||
|
visual::visual_object, Vim,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub enum Object {
|
pub enum Object {
|
||||||
@ -213,14 +216,14 @@ fn in_word(
|
|||||||
right(map, relative_to, 1),
|
right(map, relative_to, 1),
|
||||||
movement::FindRange::SingleLine,
|
movement::FindRange::SingleLine,
|
||||||
|left, right| {
|
|left, right| {
|
||||||
char_kind(&scope, left).coerce_punctuation(ignore_punctuation)
|
coerce_punctuation(char_kind(&scope, left), ignore_punctuation)
|
||||||
!= char_kind(&scope, right).coerce_punctuation(ignore_punctuation)
|
!= coerce_punctuation(char_kind(&scope, right), ignore_punctuation)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let end = movement::find_boundary(map, relative_to, FindRange::SingleLine, |left, right| {
|
let end = movement::find_boundary(map, relative_to, FindRange::SingleLine, |left, right| {
|
||||||
char_kind(&scope, left).coerce_punctuation(ignore_punctuation)
|
coerce_punctuation(char_kind(&scope, left), ignore_punctuation)
|
||||||
!= char_kind(&scope, right).coerce_punctuation(ignore_punctuation)
|
!= coerce_punctuation(char_kind(&scope, right), ignore_punctuation)
|
||||||
});
|
});
|
||||||
|
|
||||||
Some(start..end)
|
Some(start..end)
|
||||||
@ -283,15 +286,15 @@ fn around_next_word(
|
|||||||
right(map, relative_to, 1),
|
right(map, relative_to, 1),
|
||||||
FindRange::SingleLine,
|
FindRange::SingleLine,
|
||||||
|left, right| {
|
|left, right| {
|
||||||
char_kind(&scope, left).coerce_punctuation(ignore_punctuation)
|
coerce_punctuation(char_kind(&scope, left), ignore_punctuation)
|
||||||
!= char_kind(&scope, right).coerce_punctuation(ignore_punctuation)
|
!= coerce_punctuation(char_kind(&scope, right), ignore_punctuation)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut word_found = false;
|
let mut word_found = false;
|
||||||
let end = movement::find_boundary(map, relative_to, FindRange::MultiLine, |left, right| {
|
let end = movement::find_boundary(map, relative_to, FindRange::MultiLine, |left, right| {
|
||||||
let left_kind = char_kind(&scope, left).coerce_punctuation(ignore_punctuation);
|
let left_kind = coerce_punctuation(char_kind(&scope, left), ignore_punctuation);
|
||||||
let right_kind = char_kind(&scope, right).coerce_punctuation(ignore_punctuation);
|
let right_kind = coerce_punctuation(char_kind(&scope, right), ignore_punctuation);
|
||||||
|
|
||||||
let found = (word_found && left_kind != right_kind) || right == '\n' && left == '\n';
|
let found = (word_found && left_kind != right_kind) || right == '\n' && left == '\n';
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use editor::{ClipboardSelection, Editor};
|
use editor::{ClipboardSelection, Editor};
|
||||||
use gpui::{AppContext, ClipboardItem};
|
use gpui::{AppContext, ClipboardItem};
|
||||||
use language::Point;
|
use language::{CharKind, Point};
|
||||||
|
|
||||||
pub fn copy_selections_content(editor: &mut Editor, linewise: bool, cx: &mut AppContext) {
|
pub fn copy_selections_content(editor: &mut Editor, linewise: bool, cx: &mut AppContext) {
|
||||||
let selections = editor.selections.all_adjusted(cx);
|
let selections = editor.selections.all_adjusted(cx);
|
||||||
@ -48,3 +48,11 @@ pub fn copy_selections_content(editor: &mut Editor, linewise: bool, cx: &mut App
|
|||||||
|
|
||||||
cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
|
cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn coerce_punctuation(kind: CharKind, treat_punctuation_as_word: bool) -> CharKind {
|
||||||
|
if treat_punctuation_as_word && kind == CharKind::Punctuation {
|
||||||
|
CharKind::Word
|
||||||
|
} else {
|
||||||
|
kind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user