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:
Ben Kunkle 2025-03-06 08:36:10 -06:00 committed by GitHub
parent 05df3d1bd6
commit ff25fa24e7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 1207 additions and 149 deletions

View file

@ -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,