From d61b0d251044344cfad5fd51fec881e75d50854f Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Thu, 12 Jun 2025 14:11:01 +0800 Subject: [PATCH] highlighter: Fix highlight offset and reset highlight when replace all text. (#950) - Improve JSON highlights. image --- crates/story/examples/code-editor.rs | 6 ++++- crates/story/examples/fixtures/test.json | 11 +++++++++ crates/ui/src/highlighter/highlighter.rs | 20 ++++++++++++---- crates/ui/src/highlighter/languages.rs | 2 +- .../highlighter/languages/json/highlights.scm | 24 +++++++++++++++++++ crates/ui/src/highlighter/themes/dark.json | 7 +++++- crates/ui/src/input/state.rs | 11 +++++++++ 7 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 crates/story/examples/fixtures/test.json create mode 100644 crates/ui/src/highlighter/languages/json/highlights.scm diff --git a/crates/story/examples/code-editor.rs b/crates/story/examples/code-editor.rs index 7b5a48e7..4f60daff 100644 --- a/crates/story/examples/code-editor.rs +++ b/crates/story/examples/code-editor.rs @@ -47,7 +47,7 @@ impl Lang { } } -const LANGUAGES: [(Lang, &'static str); 9] = [ +const LANGUAGES: [(Lang, &'static str); 10] = [ ( Lang::BuiltIn(Language::Rust), include_str!("./fixtures/test.rs"), @@ -80,6 +80,10 @@ const LANGUAGES: [(Lang, &'static str); 9] = [ Lang::BuiltIn(Language::Sql), include_str!("./fixtures/test.sql"), ), + ( + Lang::BuiltIn(Language::Json), + include_str!("./fixtures/test.json"), + ), (Lang::External("navi"), include_str!("./fixtures/test.nv")), ]; diff --git a/crates/story/examples/fixtures/test.json b/crates/story/examples/fixtures/test.json new file mode 100644 index 00000000..41f175bc --- /dev/null +++ b/crates/story/examples/fixtures/test.json @@ -0,0 +1,11 @@ +[ + { + "name": "GPUI Component", + "description": "UI components for building fantastic desktop application by using GPUI.", + "license": "Apache-2.0", + "keywords": ["UI", "desktop", "application"], + "stars": 3000, + "public": true, + "repository": "https://github.com/longbridge/gpui-component" + } +] diff --git a/crates/ui/src/highlighter/highlighter.rs b/crates/ui/src/highlighter/highlighter.rs index 9bf3573c..b4898523 100644 --- a/crates/ui/src/highlighter/highlighter.rs +++ b/crates/ui/src/highlighter/highlighter.rs @@ -308,12 +308,14 @@ impl SyntaxHighlighter { for (start, (old_range, highlight_name)) in old_cache.into_iter() { if old_range.end >= byte_range.start { let new_range = Range { - start: (old_range.start as isize + changed_len) as usize, - end: (old_range.end as isize + changed_len) as usize, + start: (old_range.start as isize + changed_len).max(0) as usize, + end: (old_range.end as isize + changed_len).max(0) as usize, }; - self.cache - .insert(new_range.start, (new_range, highlight_name)); + if new_range.len() > 0 { + self.cache + .insert(new_range.start, (new_range, highlight_name)); + } } else { self.cache.insert(start, (old_range, highlight_name)); } @@ -365,6 +367,14 @@ impl SyntaxHighlighter { last_range.start, (last_range.start..node_range.end, highlight_name.clone()), ); + } else if last_range == &node_range { + // case: + // last_range: 213..220, last_highlight_name: Some("property") + // last_range: 213..220, last_highlight_name: Some("string") + self.cache.insert( + node_range.start, + (node_range, last_highlight_name.unwrap_or(highlight_name)), + ); } else { self.cache .insert(node_range.start, (node_range, highlight_name.clone())); @@ -581,7 +591,7 @@ impl SyntaxHighlighter { let styles = unique_styles(styles); // NOTE: DO NOT remove this comment, it is used for debugging. - // for style in &result { + // for style in &styles { // println!("---- style: {:?} - {:?}", style.0, style.1.color); // } // println!("--------------------------------"); diff --git a/crates/ui/src/highlighter/languages.rs b/crates/ui/src/highlighter/languages.rs index 0b9c3d3e..5d24ebdd 100644 --- a/crates/ui/src/highlighter/languages.rs +++ b/crates/ui/src/highlighter/languages.rs @@ -184,7 +184,7 @@ impl Language { let (language, query, injection, locals) = match self { Self::Json => ( tree_sitter_json::LANGUAGE, - tree_sitter_json::HIGHLIGHTS_QUERY, + include_str!("languages/json/highlights.scm"), "", "", ), diff --git a/crates/ui/src/highlighter/languages/json/highlights.scm b/crates/ui/src/highlighter/languages/json/highlights.scm new file mode 100644 index 00000000..a31adfab --- /dev/null +++ b/crates/ui/src/highlighter/languages/json/highlights.scm @@ -0,0 +1,24 @@ +(comment) @comment + +(string) @string +(escape_sequence) @string.escape + +(number) @number + +(pair key: (string) @property) + +[ + (true) + (false) +] @boolean + +(null) @constant.builtin + +[ + "," + ":" + "{" + "}" + "[" + "]" +] @punctuation diff --git a/crates/ui/src/highlighter/themes/dark.json b/crates/ui/src/highlighter/themes/dark.json index 7b7c0427..26080874 100644 --- a/crates/ui/src/highlighter/themes/dark.json +++ b/crates/ui/src/highlighter/themes/dark.json @@ -155,6 +155,11 @@ "font_style": null, "font_weight": null }, + "property": { + "color": "#CACCCA", + "font_style": null, + "font_weight": null + }, "variable.special": { "color": "#E19773", "font_style": null, @@ -162,4 +167,4 @@ } } } -} \ No newline at end of file +} diff --git a/crates/ui/src/input/state.rs b/crates/ui/src/input/state.rs index 407f7e7f..65733dca 100644 --- a/crates/ui/src/input/state.rs +++ b/crates/ui/src/input/state.rs @@ -477,6 +477,16 @@ impl InputState { cx.notify(); } + fn reset_highlighter(&mut self, cx: &mut Context) { + match &mut self.mode { + InputMode::CodeEditor { highlighter, .. } => { + *highlighter.borrow_mut() = None; + } + _ => {} + } + cx.notify(); + } + /// Set markers, only for [`InputMode::CodeEditor`] mode. /// /// For example to set the diagnostic markers in the code editor. @@ -715,6 +725,7 @@ impl InputState { let text: SharedString = text.into(); let range = 0..self.text.chars().map(|c| c.len_utf16()).sum(); self.replace_text_in_range(Some(range), &text, window, cx); + self.reset_highlighter(cx); } /// Set with disabled mode.