language: Update block_comment and documentation comment (#34861)
As suggested in https://github.com/zed-industries/zed/pull/34418, this proposes various changes to language configs to make block comments and doc-block-style comments more similar. In doing so, it introduces some breaking changes into the extension schema. This change is needed to support the changes I'm working on in #34418, to be able to support `rewrap` in block comments like `/* really long comment ... */`. As is, we can do this in C-style doc-block comments (eg `/** ... */`) because of the config in `documentation`, but we can't do this in regular block comments because we lack the info about what the line prefix and indentation should be. And while I was here, I did various other clean-ups, many of which feel nice but are optional. I would love special attention on the changes to the schema, version and related changes; I'm totally unfamiliar with that part of Zed. **Summary of changes** - break: changes type of `block_comment` to same type as `documentation_comment` (**this is the important change**) - break: rename `documentation` to `documentation_comment` (optional, but improves consistency w/ `line_comments` and `block_comment`) - break/refactor?: removes some whitespace in the declaration of `block_comment` delimiters (optional, may break things, need input; some langs had no spaces, others did) - refactor: change `tab_size` from `NonZeroU32` to just a `u32` (some block comments don't seem to need/want indent past the initial delimiter, so we need this be 0 sometimes) - refactor: moves the `documentation_comment` declarations to appear next to `block_comment`, rearranges the order of the fields in the TOML for `documentation_comment`, rename backing `struct` (all optional) **Future scope** I believe that this will also allow us to extend regular block comments on newline – as we do doc-block comments – but I haven't looked into this yet. (eg, in JS try pressing enter in both of these: `/* */` and `/** */`; the latter should extend w/ a `*` prefixed line, while the former does not.) Release Notes: - BREAKING CHANGE: update extension schema version from 1 to 2, change format of `block_comment` and rename `documentation_comment` /cc @smitbarmase
This commit is contained in:
parent
14171e0721
commit
1f4c9b9427
18 changed files with 249 additions and 74 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -9018,6 +9018,7 @@ dependencies = [
|
||||||
"task",
|
"task",
|
||||||
"text",
|
"text",
|
||||||
"theme",
|
"theme",
|
||||||
|
"toml 0.8.20",
|
||||||
"tree-sitter",
|
"tree-sitter",
|
||||||
"tree-sitter-elixir",
|
"tree-sitter-elixir",
|
||||||
"tree-sitter-embedded-template",
|
"tree-sitter-embedded-template",
|
||||||
|
|
|
@ -109,10 +109,10 @@ use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
|
||||||
pub use items::MAX_TAB_TITLE_LEN;
|
pub use items::MAX_TAB_TITLE_LEN;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use language::{
|
use language::{
|
||||||
AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
|
AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, Capability, CharKind,
|
||||||
CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
|
CodeLabel, CursorShape, DiagnosticEntry, DiffOptions, EditPredictionsMode, EditPreview,
|
||||||
EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
|
HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point, Selection,
|
||||||
Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
|
SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
|
||||||
language_settings::{
|
language_settings::{
|
||||||
self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
|
self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
|
||||||
all_language_settings, language_settings,
|
all_language_settings, language_settings,
|
||||||
|
@ -4408,7 +4408,9 @@ impl Editor {
|
||||||
})
|
})
|
||||||
.max_by_key(|(_, len)| *len)?;
|
.max_by_key(|(_, len)| *len)?;
|
||||||
|
|
||||||
if let Some((block_start, _)) = language.block_comment_delimiters()
|
if let Some(BlockCommentConfig {
|
||||||
|
start: block_start, ..
|
||||||
|
}) = language.block_comment()
|
||||||
{
|
{
|
||||||
let block_start_trimmed = block_start.trim_end();
|
let block_start_trimmed = block_start.trim_end();
|
||||||
if block_start_trimmed.starts_with(delimiter.trim_end()) {
|
if block_start_trimmed.starts_with(delimiter.trim_end()) {
|
||||||
|
@ -4445,13 +4447,12 @@ impl Editor {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let DocumentationConfig {
|
let BlockCommentConfig {
|
||||||
start: start_tag,
|
start: start_tag,
|
||||||
end: end_tag,
|
end: end_tag,
|
||||||
prefix: delimiter,
|
prefix: delimiter,
|
||||||
tab_size: len,
|
tab_size: len,
|
||||||
} = language.documentation()?;
|
} = language.documentation_comment()?;
|
||||||
|
|
||||||
let is_within_block_comment = buffer
|
let is_within_block_comment = buffer
|
||||||
.language_scope_at(start_point)
|
.language_scope_at(start_point)
|
||||||
.is_some_and(|scope| scope.override_name() == Some("comment"));
|
.is_some_and(|scope| scope.override_name() == Some("comment"));
|
||||||
|
@ -4521,7 +4522,7 @@ impl Editor {
|
||||||
let cursor_is_at_start_of_end_tag =
|
let cursor_is_at_start_of_end_tag =
|
||||||
column == end_tag_offset;
|
column == end_tag_offset;
|
||||||
if cursor_is_at_start_of_end_tag {
|
if cursor_is_at_start_of_end_tag {
|
||||||
indent_on_extra_newline.len = (*len).into();
|
indent_on_extra_newline.len = *len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cursor_is_before_end_tag
|
cursor_is_before_end_tag
|
||||||
|
@ -4534,7 +4535,7 @@ impl Editor {
|
||||||
&& cursor_is_before_end_tag_if_exists
|
&& cursor_is_before_end_tag_if_exists
|
||||||
{
|
{
|
||||||
if cursor_is_after_start_tag {
|
if cursor_is_after_start_tag {
|
||||||
indent_on_newline.len = (*len).into();
|
indent_on_newline.len = *len;
|
||||||
}
|
}
|
||||||
Some(delimiter.clone())
|
Some(delimiter.clone())
|
||||||
} else {
|
} else {
|
||||||
|
@ -14349,8 +14350,11 @@ impl Editor {
|
||||||
(position..position, first_prefix.clone())
|
(position..position, first_prefix.clone())
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
} else if let Some((full_comment_prefix, comment_suffix)) =
|
} else if let Some(BlockCommentConfig {
|
||||||
language.block_comment_delimiters()
|
start: full_comment_prefix,
|
||||||
|
end: comment_suffix,
|
||||||
|
..
|
||||||
|
}) = language.block_comment()
|
||||||
{
|
{
|
||||||
let comment_prefix = full_comment_prefix.trim_end_matches(' ');
|
let comment_prefix = full_comment_prefix.trim_end_matches(' ');
|
||||||
let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
|
let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
|
||||||
|
|
|
@ -2875,11 +2875,11 @@ async fn test_newline_documentation_comments(cx: &mut TestAppContext) {
|
||||||
let language = Arc::new(
|
let language = Arc::new(
|
||||||
Language::new(
|
Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
documentation: Some(language::DocumentationConfig {
|
documentation_comment: Some(language::BlockCommentConfig {
|
||||||
start: "/**".into(),
|
start: "/**".into(),
|
||||||
end: "*/".into(),
|
end: "*/".into(),
|
||||||
prefix: "* ".into(),
|
prefix: "* ".into(),
|
||||||
tab_size: NonZeroU32::new(1).unwrap(),
|
tab_size: 1,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
..LanguageConfig::default()
|
..LanguageConfig::default()
|
||||||
|
@ -3089,7 +3089,12 @@ async fn test_newline_comments_with_block_comment(cx: &mut TestAppContext) {
|
||||||
let lua_language = Arc::new(Language::new(
|
let lua_language = Arc::new(Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
line_comments: vec!["--".into()],
|
line_comments: vec!["--".into()],
|
||||||
block_comment: Some(("--[[".into(), "]]".into())),
|
block_comment: Some(language::BlockCommentConfig {
|
||||||
|
start: "--[[".into(),
|
||||||
|
prefix: "".into(),
|
||||||
|
end: "]]".into(),
|
||||||
|
tab_size: 0,
|
||||||
|
}),
|
||||||
..LanguageConfig::default()
|
..LanguageConfig::default()
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
|
@ -13806,7 +13811,12 @@ async fn test_toggle_block_comment(cx: &mut TestAppContext) {
|
||||||
Language::new(
|
Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: "HTML".into(),
|
name: "HTML".into(),
|
||||||
block_comment: Some(("<!-- ".into(), " -->".into())),
|
block_comment: Some(BlockCommentConfig {
|
||||||
|
start: "<!-- ".into(),
|
||||||
|
prefix: "".into(),
|
||||||
|
end: " -->".into(),
|
||||||
|
tab_size: 0,
|
||||||
|
}),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Some(tree_sitter_html::LANGUAGE.into()),
|
Some(tree_sitter_html::LANGUAGE.into()),
|
||||||
|
|
|
@ -14,7 +14,8 @@ use futures::Future;
|
||||||
use gpui::{Context, Entity, Focusable as _, VisualTestContext, Window};
|
use gpui::{Context, Entity, Focusable as _, VisualTestContext, Window};
|
||||||
use indoc::indoc;
|
use indoc::indoc;
|
||||||
use language::{
|
use language::{
|
||||||
FakeLspAdapter, Language, LanguageConfig, LanguageMatcher, LanguageQueries, point_to_lsp,
|
BlockCommentConfig, FakeLspAdapter, Language, LanguageConfig, LanguageMatcher, LanguageQueries,
|
||||||
|
point_to_lsp,
|
||||||
};
|
};
|
||||||
use lsp::{notification, request};
|
use lsp::{notification, request};
|
||||||
use multi_buffer::ToPointUtf16;
|
use multi_buffer::ToPointUtf16;
|
||||||
|
@ -269,7 +270,12 @@ impl EditorLspTestContext {
|
||||||
path_suffixes: vec!["html".into()],
|
path_suffixes: vec!["html".into()],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
block_comment: Some(("<!-- ".into(), " -->".into())),
|
block_comment: Some(BlockCommentConfig {
|
||||||
|
start: "<!--".into(),
|
||||||
|
prefix: "".into(),
|
||||||
|
end: "-->".into(),
|
||||||
|
tab_size: 0,
|
||||||
|
}),
|
||||||
completion_query_characters: ['-'].into_iter().collect(),
|
completion_query_characters: ['-'].into_iter().collect(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
|
|
@ -92,6 +92,7 @@ tree-sitter-python.workspace = true
|
||||||
tree-sitter-ruby.workspace = true
|
tree-sitter-ruby.workspace = true
|
||||||
tree-sitter-rust.workspace = true
|
tree-sitter-rust.workspace = true
|
||||||
tree-sitter-typescript.workspace = true
|
tree-sitter-typescript.workspace = true
|
||||||
|
toml.workspace = true
|
||||||
unindent.workspace = true
|
unindent.workspace = true
|
||||||
util = { workspace = true, features = ["test-support"] }
|
util = { workspace = true, features = ["test-support"] }
|
||||||
zlog.workspace = true
|
zlog.workspace = true
|
||||||
|
|
|
@ -2273,7 +2273,12 @@ fn test_language_scope_at_with_javascript(cx: &mut App) {
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: "JavaScript".into(),
|
name: "JavaScript".into(),
|
||||||
line_comments: vec!["// ".into()],
|
line_comments: vec!["// ".into()],
|
||||||
block_comment: Some(("/*".into(), "*/".into())),
|
block_comment: Some(BlockCommentConfig {
|
||||||
|
start: "/*".into(),
|
||||||
|
end: "*/".into(),
|
||||||
|
prefix: "* ".into(),
|
||||||
|
tab_size: 1,
|
||||||
|
}),
|
||||||
brackets: BracketPairConfig {
|
brackets: BracketPairConfig {
|
||||||
pairs: vec![
|
pairs: vec![
|
||||||
BracketPair {
|
BracketPair {
|
||||||
|
@ -2300,7 +2305,12 @@ fn test_language_scope_at_with_javascript(cx: &mut App) {
|
||||||
"element".into(),
|
"element".into(),
|
||||||
LanguageConfigOverride {
|
LanguageConfigOverride {
|
||||||
line_comments: Override::Remove { remove: true },
|
line_comments: Override::Remove { remove: true },
|
||||||
block_comment: Override::Set(("{/*".into(), "*/}".into())),
|
block_comment: Override::Set(BlockCommentConfig {
|
||||||
|
start: "{/*".into(),
|
||||||
|
prefix: "".into(),
|
||||||
|
end: "*/}".into(),
|
||||||
|
tab_size: 0,
|
||||||
|
}),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
|
@ -2338,9 +2348,15 @@ fn test_language_scope_at_with_javascript(cx: &mut App) {
|
||||||
let config = snapshot.language_scope_at(0).unwrap();
|
let config = snapshot.language_scope_at(0).unwrap();
|
||||||
assert_eq!(config.line_comment_prefixes(), &[Arc::from("// ")]);
|
assert_eq!(config.line_comment_prefixes(), &[Arc::from("// ")]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.block_comment_delimiters(),
|
config.block_comment(),
|
||||||
Some((&"/*".into(), &"*/".into()))
|
Some(&BlockCommentConfig {
|
||||||
|
start: "/*".into(),
|
||||||
|
prefix: "* ".into(),
|
||||||
|
end: "*/".into(),
|
||||||
|
tab_size: 1,
|
||||||
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// Both bracket pairs are enabled
|
// Both bracket pairs are enabled
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.brackets().map(|e| e.1).collect::<Vec<_>>(),
|
config.brackets().map(|e| e.1).collect::<Vec<_>>(),
|
||||||
|
@ -2360,8 +2376,13 @@ fn test_language_scope_at_with_javascript(cx: &mut App) {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(string_config.line_comment_prefixes(), &[Arc::from("// ")]);
|
assert_eq!(string_config.line_comment_prefixes(), &[Arc::from("// ")]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
string_config.block_comment_delimiters(),
|
string_config.block_comment(),
|
||||||
Some((&"/*".into(), &"*/".into()))
|
Some(&BlockCommentConfig {
|
||||||
|
start: "/*".into(),
|
||||||
|
prefix: "* ".into(),
|
||||||
|
end: "*/".into(),
|
||||||
|
tab_size: 1,
|
||||||
|
})
|
||||||
);
|
);
|
||||||
// Second bracket pair is disabled
|
// Second bracket pair is disabled
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -2391,8 +2412,13 @@ fn test_language_scope_at_with_javascript(cx: &mut App) {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(tag_config.line_comment_prefixes(), &[Arc::from("// ")]);
|
assert_eq!(tag_config.line_comment_prefixes(), &[Arc::from("// ")]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tag_config.block_comment_delimiters(),
|
tag_config.block_comment(),
|
||||||
Some((&"/*".into(), &"*/".into()))
|
Some(&BlockCommentConfig {
|
||||||
|
start: "/*".into(),
|
||||||
|
prefix: "* ".into(),
|
||||||
|
end: "*/".into(),
|
||||||
|
tab_size: 1,
|
||||||
|
})
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tag_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
|
tag_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
|
||||||
|
@ -2408,8 +2434,13 @@ fn test_language_scope_at_with_javascript(cx: &mut App) {
|
||||||
&[Arc::from("// ")]
|
&[Arc::from("// ")]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
expression_in_element_config.block_comment_delimiters(),
|
expression_in_element_config.block_comment(),
|
||||||
Some((&"/*".into(), &"*/".into()))
|
Some(&BlockCommentConfig {
|
||||||
|
start: "/*".into(),
|
||||||
|
prefix: "* ".into(),
|
||||||
|
end: "*/".into(),
|
||||||
|
tab_size: 1,
|
||||||
|
})
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
expression_in_element_config
|
expression_in_element_config
|
||||||
|
@ -2528,13 +2559,18 @@ fn test_language_scope_at_with_combined_injections(cx: &mut App) {
|
||||||
let html_config = snapshot.language_scope_at(Point::new(2, 4)).unwrap();
|
let html_config = snapshot.language_scope_at(Point::new(2, 4)).unwrap();
|
||||||
assert_eq!(html_config.line_comment_prefixes(), &[]);
|
assert_eq!(html_config.line_comment_prefixes(), &[]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
html_config.block_comment_delimiters(),
|
html_config.block_comment(),
|
||||||
Some((&"<!--".into(), &"-->".into()))
|
Some(&BlockCommentConfig {
|
||||||
|
start: "<!--".into(),
|
||||||
|
end: "-->".into(),
|
||||||
|
prefix: "".into(),
|
||||||
|
tab_size: 0,
|
||||||
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
let ruby_config = snapshot.language_scope_at(Point::new(3, 12)).unwrap();
|
let ruby_config = snapshot.language_scope_at(Point::new(3, 12)).unwrap();
|
||||||
assert_eq!(ruby_config.line_comment_prefixes(), &[Arc::from("# ")]);
|
assert_eq!(ruby_config.line_comment_prefixes(), &[Arc::from("# ")]);
|
||||||
assert_eq!(ruby_config.block_comment_delimiters(), None);
|
assert_eq!(ruby_config.block_comment(), None);
|
||||||
|
|
||||||
buffer
|
buffer
|
||||||
});
|
});
|
||||||
|
@ -3490,7 +3526,12 @@ fn html_lang() -> Language {
|
||||||
Language::new(
|
Language::new(
|
||||||
LanguageConfig {
|
LanguageConfig {
|
||||||
name: LanguageName::new("HTML"),
|
name: LanguageName::new("HTML"),
|
||||||
block_comment: Some(("<!--".into(), "-->".into())),
|
block_comment: Some(BlockCommentConfig {
|
||||||
|
start: "<!--".into(),
|
||||||
|
prefix: "".into(),
|
||||||
|
end: "-->".into(),
|
||||||
|
tab_size: 0,
|
||||||
|
}),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Some(tree_sitter_html::LANGUAGE.into()),
|
Some(tree_sitter_html::LANGUAGE.into()),
|
||||||
|
@ -3521,7 +3562,12 @@ fn erb_lang() -> Language {
|
||||||
path_suffixes: vec!["erb".to_string()],
|
path_suffixes: vec!["erb".to_string()],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
block_comment: Some(("<%#".into(), "%>".into())),
|
block_comment: Some(BlockCommentConfig {
|
||||||
|
start: "<%#".into(),
|
||||||
|
prefix: "".into(),
|
||||||
|
end: "%>".into(),
|
||||||
|
tab_size: 0,
|
||||||
|
}),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Some(tree_sitter_embedded_template::LANGUAGE.into()),
|
Some(tree_sitter_embedded_template::LANGUAGE.into()),
|
||||||
|
|
|
@ -727,9 +727,12 @@ pub struct LanguageConfig {
|
||||||
/// used for comment continuations on the next line, but only the first one is used for Editor::ToggleComments.
|
/// used for comment continuations on the next line, but only the first one is used for Editor::ToggleComments.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub line_comments: Vec<Arc<str>>,
|
pub line_comments: Vec<Arc<str>>,
|
||||||
/// Starting and closing characters of a block comment.
|
/// Delimiters and configuration for recognizing and formatting block comments.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub block_comment: Option<(Arc<str>, Arc<str>)>,
|
pub block_comment: Option<BlockCommentConfig>,
|
||||||
|
/// Delimiters and configuration for recognizing and formatting documentation comments.
|
||||||
|
#[serde(default, alias = "documentation")]
|
||||||
|
pub documentation_comment: Option<BlockCommentConfig>,
|
||||||
/// A list of additional regex patterns that should be treated as prefixes
|
/// A list of additional regex patterns that should be treated as prefixes
|
||||||
/// for creating boundaries during rewrapping, ensuring content from one
|
/// for creating boundaries during rewrapping, ensuring content from one
|
||||||
/// prefixed section doesn't merge with another (e.g., markdown list items).
|
/// prefixed section doesn't merge with another (e.g., markdown list items).
|
||||||
|
@ -774,10 +777,6 @@ pub struct LanguageConfig {
|
||||||
/// A list of preferred debuggers for this language.
|
/// A list of preferred debuggers for this language.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub debuggers: IndexSet<SharedString>,
|
pub debuggers: IndexSet<SharedString>,
|
||||||
/// Whether to treat documentation comment of this language differently by
|
|
||||||
/// auto adding prefix on new line, adjusting the indenting , etc.
|
|
||||||
#[serde(default)]
|
|
||||||
pub documentation: Option<DocumentationConfig>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Default, JsonSchema)]
|
#[derive(Clone, Debug, Deserialize, Default, JsonSchema)]
|
||||||
|
@ -837,17 +836,56 @@ pub struct JsxTagAutoCloseConfig {
|
||||||
pub erroneous_close_tag_name_node_name: Option<String>,
|
pub erroneous_close_tag_name_node_name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The configuration for documentation block for this language.
|
/// The configuration for block comments for this language.
|
||||||
#[derive(Clone, Deserialize, JsonSchema)]
|
#[derive(Clone, Debug, JsonSchema, PartialEq)]
|
||||||
pub struct DocumentationConfig {
|
pub struct BlockCommentConfig {
|
||||||
/// A start tag of documentation block.
|
/// A start tag of block comment.
|
||||||
pub start: Arc<str>,
|
pub start: Arc<str>,
|
||||||
/// A end tag of documentation block.
|
/// A end tag of block comment.
|
||||||
pub end: Arc<str>,
|
pub end: Arc<str>,
|
||||||
/// A character to add as a prefix when a new line is added to a documentation block.
|
/// A character to add as a prefix when a new line is added to a block comment.
|
||||||
pub prefix: Arc<str>,
|
pub prefix: Arc<str>,
|
||||||
/// A indent to add for prefix and end line upon new line.
|
/// A indent to add for prefix and end line upon new line.
|
||||||
pub tab_size: NonZeroU32,
|
pub tab_size: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for BlockCommentConfig {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum BlockCommentConfigHelper {
|
||||||
|
New {
|
||||||
|
start: Arc<str>,
|
||||||
|
end: Arc<str>,
|
||||||
|
prefix: Arc<str>,
|
||||||
|
tab_size: u32,
|
||||||
|
},
|
||||||
|
Old([Arc<str>; 2]),
|
||||||
|
}
|
||||||
|
|
||||||
|
match BlockCommentConfigHelper::deserialize(deserializer)? {
|
||||||
|
BlockCommentConfigHelper::New {
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
prefix,
|
||||||
|
tab_size,
|
||||||
|
} => Ok(BlockCommentConfig {
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
prefix,
|
||||||
|
tab_size,
|
||||||
|
}),
|
||||||
|
BlockCommentConfigHelper::Old([start, end]) => Ok(BlockCommentConfig {
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
prefix: "".into(),
|
||||||
|
tab_size: 0,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a language for the given range. Some languages (e.g. HTML)
|
/// Represents a language for the given range. Some languages (e.g. HTML)
|
||||||
|
@ -864,7 +902,7 @@ pub struct LanguageConfigOverride {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub line_comments: Override<Vec<Arc<str>>>,
|
pub line_comments: Override<Vec<Arc<str>>>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub block_comment: Override<(Arc<str>, Arc<str>)>,
|
pub block_comment: Override<BlockCommentConfig>,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub disabled_bracket_ixs: Vec<u16>,
|
pub disabled_bracket_ixs: Vec<u16>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
@ -916,6 +954,7 @@ impl Default for LanguageConfig {
|
||||||
autoclose_before: Default::default(),
|
autoclose_before: Default::default(),
|
||||||
line_comments: Default::default(),
|
line_comments: Default::default(),
|
||||||
block_comment: Default::default(),
|
block_comment: Default::default(),
|
||||||
|
documentation_comment: Default::default(),
|
||||||
rewrap_prefixes: Default::default(),
|
rewrap_prefixes: Default::default(),
|
||||||
scope_opt_in_language_servers: Default::default(),
|
scope_opt_in_language_servers: Default::default(),
|
||||||
overrides: Default::default(),
|
overrides: Default::default(),
|
||||||
|
@ -929,7 +968,6 @@ impl Default for LanguageConfig {
|
||||||
jsx_tag_auto_close: None,
|
jsx_tag_auto_close: None,
|
||||||
completion_query_characters: Default::default(),
|
completion_query_characters: Default::default(),
|
||||||
debuggers: Default::default(),
|
debuggers: Default::default(),
|
||||||
documentation: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1847,12 +1885,17 @@ impl LanguageScope {
|
||||||
.map_or([].as_slice(), |e| e.as_slice())
|
.map_or([].as_slice(), |e| e.as_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn block_comment_delimiters(&self) -> Option<(&Arc<str>, &Arc<str>)> {
|
/// Config for block comments for this language.
|
||||||
|
pub fn block_comment(&self) -> Option<&BlockCommentConfig> {
|
||||||
Override::as_option(
|
Override::as_option(
|
||||||
self.config_override().map(|o| &o.block_comment),
|
self.config_override().map(|o| &o.block_comment),
|
||||||
self.language.config.block_comment.as_ref(),
|
self.language.config.block_comment.as_ref(),
|
||||||
)
|
)
|
||||||
.map(|e| (&e.0, &e.1))
|
}
|
||||||
|
|
||||||
|
/// Config for documentation-style block comments for this language.
|
||||||
|
pub fn documentation_comment(&self) -> Option<&BlockCommentConfig> {
|
||||||
|
self.language.config.documentation_comment.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns additional regex patterns that act as prefix markers for creating
|
/// Returns additional regex patterns that act as prefix markers for creating
|
||||||
|
@ -1897,14 +1940,6 @@ impl LanguageScope {
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns config to documentation block for this language.
|
|
||||||
///
|
|
||||||
/// Used for documentation styles that require a leading character on each line,
|
|
||||||
/// such as the asterisk in JSDoc, Javadoc, etc.
|
|
||||||
pub fn documentation(&self) -> Option<&DocumentationConfig> {
|
|
||||||
self.language.config.documentation.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a list of bracket pairs for a given language with an additional
|
/// 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.
|
/// 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)> {
|
||||||
|
@ -2299,6 +2334,7 @@ pub fn range_from_lsp(range: lsp::Range) -> Range<Unclipped<PointUtf16>> {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use gpui::TestAppContext;
|
use gpui::TestAppContext;
|
||||||
|
use pretty_assertions::assert_matches;
|
||||||
|
|
||||||
#[gpui::test(iterations = 10)]
|
#[gpui::test(iterations = 10)]
|
||||||
async fn test_language_loading(cx: &mut TestAppContext) {
|
async fn test_language_loading(cx: &mut TestAppContext) {
|
||||||
|
@ -2460,4 +2496,75 @@ mod tests {
|
||||||
"LSP completion items with duplicate label and detail, should omit the detail"
|
"LSP completion items with duplicate label and detail, should omit the detail"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deserializing_comments_backwards_compat() {
|
||||||
|
// current version of `block_comment` and `documentation_comment` work
|
||||||
|
{
|
||||||
|
let config: LanguageConfig = ::toml::from_str(
|
||||||
|
r#"
|
||||||
|
name = "Foo"
|
||||||
|
block_comment = { start = "a", end = "b", prefix = "c", tab_size = 1 }
|
||||||
|
documentation_comment = { start = "d", end = "e", prefix = "f", tab_size = 2 }
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_matches!(config.block_comment, Some(BlockCommentConfig { .. }));
|
||||||
|
assert_matches!(
|
||||||
|
config.documentation_comment,
|
||||||
|
Some(BlockCommentConfig { .. })
|
||||||
|
);
|
||||||
|
|
||||||
|
let block_config = config.block_comment.unwrap();
|
||||||
|
assert_eq!(block_config.start.as_ref(), "a");
|
||||||
|
assert_eq!(block_config.end.as_ref(), "b");
|
||||||
|
assert_eq!(block_config.prefix.as_ref(), "c");
|
||||||
|
assert_eq!(block_config.tab_size, 1);
|
||||||
|
|
||||||
|
let doc_config = config.documentation_comment.unwrap();
|
||||||
|
assert_eq!(doc_config.start.as_ref(), "d");
|
||||||
|
assert_eq!(doc_config.end.as_ref(), "e");
|
||||||
|
assert_eq!(doc_config.prefix.as_ref(), "f");
|
||||||
|
assert_eq!(doc_config.tab_size, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// former `documentation` setting is read into `documentation_comment`
|
||||||
|
{
|
||||||
|
let config: LanguageConfig = ::toml::from_str(
|
||||||
|
r#"
|
||||||
|
name = "Foo"
|
||||||
|
documentation = { start = "a", end = "b", prefix = "c", tab_size = 1}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_matches!(
|
||||||
|
config.documentation_comment,
|
||||||
|
Some(BlockCommentConfig { .. })
|
||||||
|
);
|
||||||
|
|
||||||
|
let config = config.documentation_comment.unwrap();
|
||||||
|
assert_eq!(config.start.as_ref(), "a");
|
||||||
|
assert_eq!(config.end.as_ref(), "b");
|
||||||
|
assert_eq!(config.prefix.as_ref(), "c");
|
||||||
|
assert_eq!(config.tab_size, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// old block_comment format is read into BlockCommentConfig
|
||||||
|
{
|
||||||
|
let config: LanguageConfig = ::toml::from_str(
|
||||||
|
r#"
|
||||||
|
name = "Foo"
|
||||||
|
block_comment = ["a", "b"]
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_matches!(config.block_comment, Some(BlockCommentConfig { .. }));
|
||||||
|
|
||||||
|
let config = config.block_comment.unwrap();
|
||||||
|
assert_eq!(config.start.as_ref(), "a");
|
||||||
|
assert_eq!(config.end.as_ref(), "b");
|
||||||
|
assert_eq!(config.prefix.as_ref(), "");
|
||||||
|
assert_eq!(config.tab_size, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,4 +16,4 @@ brackets = [
|
||||||
{ start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] },
|
{ start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] },
|
||||||
]
|
]
|
||||||
debuggers = ["CodeLLDB", "GDB"]
|
debuggers = ["CodeLLDB", "GDB"]
|
||||||
documentation = { start = "/*", end = "*/", prefix = "* ", tab_size = 1 }
|
documentation_comment = { start = "/*", prefix = "* ", end = "*/", tab_size = 1 }
|
||||||
|
|
|
@ -16,4 +16,4 @@ brackets = [
|
||||||
{ start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] },
|
{ start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] },
|
||||||
]
|
]
|
||||||
debuggers = ["CodeLLDB", "GDB"]
|
debuggers = ["CodeLLDB", "GDB"]
|
||||||
documentation = { start = "/*", end = "*/", prefix = "* ", tab_size = 1 }
|
documentation_comment = { start = "/*", prefix = "* ", end = "*/", tab_size = 1 }
|
||||||
|
|
|
@ -10,5 +10,5 @@ brackets = [
|
||||||
{ start = "'", end = "'", close = true, newline = false, not_in = ["string", "comment"] },
|
{ start = "'", end = "'", close = true, newline = false, not_in = ["string", "comment"] },
|
||||||
]
|
]
|
||||||
completion_query_characters = ["-"]
|
completion_query_characters = ["-"]
|
||||||
block_comment = ["/* ", " */"]
|
block_comment = { start = "/*", prefix = "* ", end = "*/", tab_size = 1 }
|
||||||
prettier_parser_name = "css"
|
prettier_parser_name = "css"
|
||||||
|
|
|
@ -15,4 +15,4 @@ brackets = [
|
||||||
tab_size = 4
|
tab_size = 4
|
||||||
hard_tabs = true
|
hard_tabs = true
|
||||||
debuggers = ["Delve"]
|
debuggers = ["Delve"]
|
||||||
documentation = { start = "/*", end = "*/", prefix = "* ", tab_size = 1 }
|
documentation_comment = { start = "/*", prefix = "* ", end = "*/", tab_size = 1 }
|
||||||
|
|
|
@ -4,7 +4,8 @@ path_suffixes = ["js", "jsx", "mjs", "cjs"]
|
||||||
# [/ ] is so we match "env node" or "/node" but not "ts-node"
|
# [/ ] is so we match "env node" or "/node" but not "ts-node"
|
||||||
first_line_pattern = '^#!.*\b(?:[/ ]node|deno run.*--ext[= ]js)\b'
|
first_line_pattern = '^#!.*\b(?:[/ ]node|deno run.*--ext[= ]js)\b'
|
||||||
line_comments = ["// "]
|
line_comments = ["// "]
|
||||||
block_comment = ["/*", "*/"]
|
block_comment = { start = "/*", prefix = "* ", end = "*/", tab_size = 1 }
|
||||||
|
documentation_comment = { start = "/**", prefix = "* ", end = "*/", tab_size = 1 }
|
||||||
autoclose_before = ";:.,=}])>"
|
autoclose_before = ";:.,=}])>"
|
||||||
brackets = [
|
brackets = [
|
||||||
{ start = "{", end = "}", close = true, newline = true },
|
{ start = "{", end = "}", close = true, newline = true },
|
||||||
|
@ -21,7 +22,6 @@ tab_size = 2
|
||||||
scope_opt_in_language_servers = ["tailwindcss-language-server", "emmet-language-server"]
|
scope_opt_in_language_servers = ["tailwindcss-language-server", "emmet-language-server"]
|
||||||
prettier_parser_name = "babel"
|
prettier_parser_name = "babel"
|
||||||
debuggers = ["JavaScript"]
|
debuggers = ["JavaScript"]
|
||||||
documentation = { start = "/**", end = "*/", prefix = "* ", tab_size = 1 }
|
|
||||||
|
|
||||||
[jsx_tag_auto_close]
|
[jsx_tag_auto_close]
|
||||||
open_tag_node_name = "jsx_opening_element"
|
open_tag_node_name = "jsx_opening_element"
|
||||||
|
@ -31,7 +31,7 @@ tag_name_node_name = "identifier"
|
||||||
|
|
||||||
[overrides.element]
|
[overrides.element]
|
||||||
line_comments = { remove = true }
|
line_comments = { remove = true }
|
||||||
block_comment = ["{/* ", " */}"]
|
block_comment = { start = "{/* ", prefix = "", end = "*/}", tab_size = 0 }
|
||||||
opt_into_language_servers = ["emmet-language-server"]
|
opt_into_language_servers = ["emmet-language-server"]
|
||||||
|
|
||||||
[overrides.string]
|
[overrides.string]
|
||||||
|
|
|
@ -2,7 +2,7 @@ name = "Markdown"
|
||||||
grammar = "markdown"
|
grammar = "markdown"
|
||||||
path_suffixes = ["md", "mdx", "mdwn", "markdown", "MD"]
|
path_suffixes = ["md", "mdx", "mdwn", "markdown", "MD"]
|
||||||
completion_query_characters = ["-"]
|
completion_query_characters = ["-"]
|
||||||
block_comment = ["<!-- ", " -->"]
|
block_comment = { start = "<!--", prefix = "", end = "-->", tab_size = 0 }
|
||||||
autoclose_before = ";:.,=}])>"
|
autoclose_before = ";:.,=}])>"
|
||||||
brackets = [
|
brackets = [
|
||||||
{ start = "{", end = "}", close = true, newline = true },
|
{ start = "{", end = "}", close = true, newline = true },
|
||||||
|
|
|
@ -16,4 +16,4 @@ brackets = [
|
||||||
]
|
]
|
||||||
collapsed_placeholder = " /* ... */ "
|
collapsed_placeholder = " /* ... */ "
|
||||||
debuggers = ["CodeLLDB", "GDB"]
|
debuggers = ["CodeLLDB", "GDB"]
|
||||||
documentation = { start = "/*", end = "*/", prefix = "* ", tab_size = 1 }
|
documentation_comment = { start = "/*", prefix = "* ", end = "*/", tab_size = 1 }
|
||||||
|
|
|
@ -2,7 +2,8 @@ name = "TSX"
|
||||||
grammar = "tsx"
|
grammar = "tsx"
|
||||||
path_suffixes = ["tsx"]
|
path_suffixes = ["tsx"]
|
||||||
line_comments = ["// "]
|
line_comments = ["// "]
|
||||||
block_comment = ["/*", "*/"]
|
block_comment = { start = "/*", prefix = "* ", end = "*/", tab_size = 1 }
|
||||||
|
documentation_comment = { start = "/**", prefix = "* ", end = "*/", tab_size = 1 }
|
||||||
autoclose_before = ";:.,=}])>"
|
autoclose_before = ";:.,=}])>"
|
||||||
brackets = [
|
brackets = [
|
||||||
{ start = "{", end = "}", close = true, newline = true },
|
{ start = "{", end = "}", close = true, newline = true },
|
||||||
|
@ -19,7 +20,6 @@ scope_opt_in_language_servers = ["tailwindcss-language-server", "emmet-language-
|
||||||
prettier_parser_name = "typescript"
|
prettier_parser_name = "typescript"
|
||||||
tab_size = 2
|
tab_size = 2
|
||||||
debuggers = ["JavaScript"]
|
debuggers = ["JavaScript"]
|
||||||
documentation = { start = "/**", end = "*/", prefix = "* ", tab_size = 1 }
|
|
||||||
|
|
||||||
[jsx_tag_auto_close]
|
[jsx_tag_auto_close]
|
||||||
open_tag_node_name = "jsx_opening_element"
|
open_tag_node_name = "jsx_opening_element"
|
||||||
|
@ -30,7 +30,7 @@ tag_name_node_name_alternates = ["member_expression"]
|
||||||
|
|
||||||
[overrides.element]
|
[overrides.element]
|
||||||
line_comments = { remove = true }
|
line_comments = { remove = true }
|
||||||
block_comment = ["{/* ", " */}"]
|
block_comment = { start = "{/*", prefix = "", end = "*/}", tab_size = 0 }
|
||||||
opt_into_language_servers = ["emmet-language-server"]
|
opt_into_language_servers = ["emmet-language-server"]
|
||||||
|
|
||||||
[overrides.string]
|
[overrides.string]
|
||||||
|
|
|
@ -3,7 +3,8 @@ grammar = "typescript"
|
||||||
path_suffixes = ["ts", "cts", "mts"]
|
path_suffixes = ["ts", "cts", "mts"]
|
||||||
first_line_pattern = '^#!.*\b(?:deno run|ts-node|bun|tsx|[/ ]node)\b'
|
first_line_pattern = '^#!.*\b(?:deno run|ts-node|bun|tsx|[/ ]node)\b'
|
||||||
line_comments = ["// "]
|
line_comments = ["// "]
|
||||||
block_comment = ["/*", "*/"]
|
block_comment = { start = "/*", prefix = "* ", end = "*/", tab_size = 1 }
|
||||||
|
documentation_comment = { start = "/**", prefix = "* ", end = "*/", tab_size = 1 }
|
||||||
autoclose_before = ";:.,=}])>"
|
autoclose_before = ";:.,=}])>"
|
||||||
brackets = [
|
brackets = [
|
||||||
{ start = "{", end = "}", close = true, newline = true },
|
{ start = "{", end = "}", close = true, newline = true },
|
||||||
|
@ -19,7 +20,6 @@ word_characters = ["#", "$"]
|
||||||
prettier_parser_name = "typescript"
|
prettier_parser_name = "typescript"
|
||||||
tab_size = 2
|
tab_size = 2
|
||||||
debuggers = ["JavaScript"]
|
debuggers = ["JavaScript"]
|
||||||
documentation = { start = "/**", end = "*/", prefix = "* ", tab_size = 1 }
|
|
||||||
|
|
||||||
[overrides.string]
|
[overrides.string]
|
||||||
completion_query_characters = ["."]
|
completion_query_characters = ["."]
|
||||||
|
|
|
@ -12,7 +12,7 @@ path_suffixes = [
|
||||||
]
|
]
|
||||||
first_line_pattern = '^#version \d+'
|
first_line_pattern = '^#version \d+'
|
||||||
line_comments = ["// "]
|
line_comments = ["// "]
|
||||||
block_comment = ["/* ", " */"]
|
block_comment = { start = "/* ", prefix = "* ", end = "*/", tab_size = 1 }
|
||||||
brackets = [
|
brackets = [
|
||||||
{ start = "{", end = "}", close = true, newline = true },
|
{ start = "{", end = "}", close = true, newline = true },
|
||||||
{ start = "[", end = "]", close = true, newline = true },
|
{ start = "[", end = "]", close = true, newline = true },
|
||||||
|
|
|
@ -2,7 +2,7 @@ name = "HTML"
|
||||||
grammar = "html"
|
grammar = "html"
|
||||||
path_suffixes = ["html", "htm", "shtml"]
|
path_suffixes = ["html", "htm", "shtml"]
|
||||||
autoclose_before = ">})"
|
autoclose_before = ">})"
|
||||||
block_comment = ["<!-- ", " -->"]
|
block_comment = { start = "<!--", prefix = "", end = "-->", tab_size = 0 }
|
||||||
brackets = [
|
brackets = [
|
||||||
{ start = "{", end = "}", close = true, newline = true },
|
{ start = "{", end = "}", close = true, newline = true },
|
||||||
{ start = "[", end = "]", close = true, newline = true },
|
{ start = "[", end = "]", close = true, newline = true },
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue