Add support for auto-closing of JSX tags (#25681)
Closes #4271 Implemented by kicking of a task on the main thread at the end of `Editor::handle_input` which waits for the buffer to be re-parsed before checking if JSX tag completion possible based on the recent edits, and if it is then it spawns a task on the background thread to generate the edits to be auto-applied to the buffer Release Notes: - Added support for auto-closing of JSX tags --------- Co-authored-by: Cole Miller <cole@zed.dev> Co-authored-by: Max Brunsfeld <max@zed.dev> Co-authored-by: Marshall Bowers <git@maxdeviant.com> Co-authored-by: Mikayla <mikayla@zed.dev> Co-authored-by: Peter Tripp <peter@zed.dev>
This commit is contained in:
parent
05df3d1bd6
commit
ff25fa24e7
15 changed files with 1207 additions and 149 deletions
|
@ -3080,6 +3080,25 @@ impl BufferSnapshot {
|
|||
.last()
|
||||
}
|
||||
|
||||
pub fn smallest_syntax_layer_containing<D: ToOffset>(
|
||||
&self,
|
||||
range: Range<D>,
|
||||
) -> Option<SyntaxLayer> {
|
||||
let range = range.to_offset(self);
|
||||
return self
|
||||
.syntax
|
||||
.layers_for_range(range, &self.text, false)
|
||||
.max_by(|a, b| {
|
||||
if a.depth != b.depth {
|
||||
a.depth.cmp(&b.depth)
|
||||
} else if a.offset.0 != b.offset.0 {
|
||||
a.offset.0.cmp(&b.offset.0)
|
||||
} else {
|
||||
a.node().end_byte().cmp(&b.node().end_byte()).reverse()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns the main [`Language`].
|
||||
pub fn language(&self) -> Option<&Arc<Language>> {
|
||||
self.language.as_ref()
|
||||
|
|
|
@ -680,6 +680,9 @@ pub struct LanguageConfig {
|
|||
/// languages, but should not appear to the user as a distinct language.
|
||||
#[serde(default)]
|
||||
pub hidden: bool,
|
||||
/// If configured, this language contains JSX style tags, and should support auto-closing of those tags.
|
||||
#[serde(default)]
|
||||
pub jsx_tag_auto_close: Option<JsxTagAutoCloseConfig>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Default, JsonSchema)]
|
||||
|
@ -697,6 +700,34 @@ pub struct LanguageMatcher {
|
|||
pub first_line_pattern: Option<Regex>,
|
||||
}
|
||||
|
||||
/// The configuration for JSX tag auto-closing.
|
||||
#[derive(Clone, Deserialize, JsonSchema)]
|
||||
pub struct JsxTagAutoCloseConfig {
|
||||
/// The name of the node for a opening tag
|
||||
pub open_tag_node_name: String,
|
||||
/// The name of the node for an closing tag
|
||||
pub close_tag_node_name: String,
|
||||
/// The name of the node for a complete element with children for open and close tags
|
||||
pub jsx_element_node_name: String,
|
||||
/// The name of the node found within both opening and closing
|
||||
/// tags that describes the tag name
|
||||
pub tag_name_node_name: String,
|
||||
/// Some grammars are smart enough to detect a closing tag
|
||||
/// that is not valid i.e. doesn't match it's corresponding
|
||||
/// opening tag or does not have a corresponding opening tag
|
||||
/// This should be set to the name of the node for invalid
|
||||
/// closing tags if the grammar contains such a node, otherwise
|
||||
/// detecting already closed tags will not work properly
|
||||
#[serde(default)]
|
||||
pub erroneous_close_tag_node_name: Option<String>,
|
||||
/// See above for erroneous_close_tag_node_name for details
|
||||
/// This should be set if the node used for the tag name
|
||||
/// within erroneous closing tags is different from the
|
||||
/// normal tag name node name
|
||||
#[serde(default)]
|
||||
pub erroneous_close_tag_name_node_name: Option<String>,
|
||||
}
|
||||
|
||||
/// 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.
|
||||
|
@ -767,6 +798,7 @@ impl Default for LanguageConfig {
|
|||
soft_wrap: None,
|
||||
prettier_parser_name: None,
|
||||
hidden: false,
|
||||
jsx_tag_auto_close: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -888,7 +920,7 @@ pub struct BracketPair {
|
|||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
||||
pub(crate) struct LanguageId(usize);
|
||||
pub struct LanguageId(usize);
|
||||
|
||||
impl LanguageId {
|
||||
pub(crate) fn new() -> Self {
|
||||
|
@ -1056,6 +1088,10 @@ impl Language {
|
|||
Self::new_with_id(LanguageId::new(), config, ts_language)
|
||||
}
|
||||
|
||||
pub fn id(&self) -> LanguageId {
|
||||
self.id
|
||||
}
|
||||
|
||||
fn new_with_id(
|
||||
id: LanguageId,
|
||||
config: LanguageConfig,
|
||||
|
|
|
@ -100,6 +100,8 @@ pub struct LanguageSettings {
|
|||
pub formatter: SelectedFormatter,
|
||||
/// Zed's Prettier integration settings.
|
||||
pub prettier: PrettierSettings,
|
||||
/// Whether to automatically close JSX tags.
|
||||
pub jsx_tag_auto_close: JsxTagAutoCloseSettings,
|
||||
/// Whether to use language servers to provide code intelligence.
|
||||
pub enable_language_server: bool,
|
||||
/// The list of language servers to use (or disable) for this language.
|
||||
|
@ -374,6 +376,9 @@ pub struct LanguageSettingsContent {
|
|||
/// Default: off
|
||||
#[serde(default)]
|
||||
pub prettier: Option<PrettierSettings>,
|
||||
/// Whether to automatically close JSX tags.
|
||||
#[serde(default)]
|
||||
pub jsx_tag_auto_close: Option<JsxTagAutoCloseSettings>,
|
||||
/// Whether to use language servers to provide code intelligence.
|
||||
///
|
||||
/// Default: true
|
||||
|
@ -1335,6 +1340,10 @@ fn merge_settings(settings: &mut LanguageSettings, src: &LanguageSettingsContent
|
|||
);
|
||||
merge(&mut settings.formatter, src.formatter.clone());
|
||||
merge(&mut settings.prettier, src.prettier.clone());
|
||||
merge(
|
||||
&mut settings.jsx_tag_auto_close,
|
||||
src.jsx_tag_auto_close.clone(),
|
||||
);
|
||||
merge(&mut settings.format_on_save, src.format_on_save.clone());
|
||||
merge(
|
||||
&mut settings.remove_trailing_whitespace_on_save,
|
||||
|
@ -1398,6 +1407,13 @@ pub struct PrettierSettings {
|
|||
pub options: HashMap<String, serde_json::Value>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct JsxTagAutoCloseSettings {
|
||||
/// Enables or disables auto-closing of JSX tags.
|
||||
#[serde(default)]
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use gpui::TestAppContext;
|
||||
|
|
|
@ -121,9 +121,9 @@ impl SyntaxLayerContent {
|
|||
pub struct SyntaxLayer<'a> {
|
||||
/// The language for this layer.
|
||||
pub language: &'a Arc<Language>,
|
||||
depth: usize,
|
||||
pub(crate) depth: usize,
|
||||
tree: &'a Tree,
|
||||
offset: (usize, tree_sitter::Point),
|
||||
pub(crate) offset: (usize, tree_sitter::Point),
|
||||
}
|
||||
|
||||
/// A layer of syntax highlighting. Like [SyntaxLayer], but holding
|
||||
|
@ -133,7 +133,7 @@ pub struct OwnedSyntaxLayer {
|
|||
/// The language for this layer.
|
||||
pub language: Arc<Language>,
|
||||
tree: tree_sitter::Tree,
|
||||
offset: (usize, tree_sitter::Point),
|
||||
pub offset: (usize, tree_sitter::Point),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue