Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T01:33:32.833Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

highlight_matching_bracket.rs

219 lines · 7.7 KB · rust
1use crate::{Editor, HighlightKey, RangeToAnchorExt, display_map::DisplaySnapshot};
2use gpui::{AppContext, Context, HighlightStyle};
3use language::CursorShape;
4use multi_buffer::MultiBufferOffset;
5use theme::ActiveTheme;
6
7impl Editor {
8    #[ztracing::instrument(skip_all)]
9    pub fn refresh_matching_bracket_highlights(
10        &mut self,
11        snapshot: &DisplaySnapshot,
12        cx: &mut Context<Editor>,
13    ) {
14        let newest_selection = self.selections.newest::<MultiBufferOffset>(&snapshot);
15        // Don't highlight brackets if the selection isn't empty
16        if !newest_selection.is_empty() {
17            self.clear_highlights(HighlightKey::MatchingBracket, cx);
18            return;
19        }
20
21        let buffer_snapshot = snapshot.buffer_snapshot();
22        let head = newest_selection.head();
23        if head > buffer_snapshot.len() {
24            log::error!("bug: cursor offset is out of range while refreshing bracket highlights");
25            return;
26        }
27
28        let mut tail = head;
29        if (self.cursor_shape == CursorShape::Block || self.cursor_shape == CursorShape::Hollow)
30            && head < buffer_snapshot.len()
31        {
32            if let Some(tail_ch) = buffer_snapshot.chars_at(tail).next() {
33                tail += tail_ch.len_utf8();
34            }
35        }
36        let task = cx.background_spawn({
37            let buffer_snapshot = buffer_snapshot.clone();
38            async move { buffer_snapshot.innermost_enclosing_bracket_ranges(head..tail, None) }
39        });
40        self.refresh_matching_bracket_highlights_task = cx.spawn({
41            let buffer_snapshot = buffer_snapshot.clone();
42            async move |this, cx| {
43                let bracket_ranges = task.await;
44                let current_ranges = this
45                    .read_with(cx, |editor, cx| {
46                        editor
47                            .display_map
48                            .read(cx)
49                            .text_highlights(HighlightKey::MatchingBracket)
50                            .map(|(_, ranges)| ranges.to_vec())
51                    })
52                    .ok()
53                    .flatten();
54                let new_ranges = bracket_ranges.map(|(opening_range, closing_range)| {
55                    vec![
56                        opening_range.to_anchors(&buffer_snapshot),
57                        closing_range.to_anchors(&buffer_snapshot),
58                    ]
59                });
60
61                if current_ranges != new_ranges {
62                    this.update(cx, |editor, cx| {
63                        editor.clear_highlights(HighlightKey::MatchingBracket, cx);
64                        if let Some(new_ranges) = new_ranges {
65                            editor.highlight_text(
66                                HighlightKey::MatchingBracket,
67                                new_ranges,
68                                HighlightStyle {
69                                    background_color: Some(
70                                        cx.theme()
71                                            .colors()
72                                            .editor_document_highlight_bracket_background,
73                                    ),
74                                    ..Default::default()
75                                },
76                                cx,
77                            )
78                        }
79                    })
80                    .ok();
81                }
82            }
83        });
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90    use crate::{editor_tests::init_test, test::editor_lsp_test_context::EditorLspTestContext};
91    use indoc::indoc;
92    use language::{BracketPair, BracketPairConfig, Language, LanguageConfig, LanguageMatcher};
93
94    #[gpui::test]
95    async fn test_matching_bracket_highlights(cx: &mut gpui::TestAppContext) {
96        init_test(cx, |_| {});
97
98        let mut cx = EditorLspTestContext::new(
99            Language::new(
100                LanguageConfig {
101                    name: "Rust".into(),
102                    matcher: (LanguageMatcher {
103                        path_suffixes: vec!["rs".to_string()],
104                        ..Default::default()
105                    })
106                    .into(),
107                    brackets: BracketPairConfig {
108                        pairs: vec![
109                            BracketPair {
110                                start: "{".to_string(),
111                                end: "}".to_string(),
112                                close: false,
113                                surround: false,
114                                newline: true,
115                            },
116                            BracketPair {
117                                start: "(".to_string(),
118                                end: ")".to_string(),
119                                close: false,
120                                surround: false,
121                                newline: true,
122                            },
123                        ],
124                        ..Default::default()
125                    },
126                    ..Default::default()
127                },
128                Some(tree_sitter_rust::LANGUAGE.into()),
129            )
130            .with_brackets_query(indoc! {r#"
131                ("{" @open "}" @close)
132                ("(" @open ")" @close)
133                "#})
134            .unwrap(),
135            Default::default(),
136            cx,
137        )
138        .await;
139
140        // positioning cursor inside bracket highlights both
141        cx.set_state(indoc! {r#"
142            pub fn test("Test ˇargument") {
143                another_test(1, 2, 3);
144            }
145        "#});
146        cx.run_until_parked();
147        cx.assert_editor_text_highlights(
148            HighlightKey::MatchingBracket,
149            indoc! {r#"
150            pub fn test«(»"Test argument"«)» {
151                another_test(1, 2, 3);
152            }
153        "#},
154        );
155
156        cx.set_state(indoc! {r#"
157            pub fn test("Test argument") {
158                another_test(1, ˇ2, 3);
159            }
160        "#});
161        cx.run_until_parked();
162        cx.assert_editor_text_highlights(
163            HighlightKey::MatchingBracket,
164            indoc! {r#"
165            pub fn test("Test argument") {
166                another_test«(»1, 2, 3«)»;
167            }
168        "#},
169        );
170
171        cx.set_state(indoc! {r#"
172            pub fn test("Test argument") {
173                anotherˇ_test(1, 2, 3);
174            }
175        "#});
176        cx.run_until_parked();
177        cx.assert_editor_text_highlights(
178            HighlightKey::MatchingBracket,
179            indoc! {r#"
180            pub fn test("Test argument") «{»
181                another_test(1, 2, 3);
182            «}»
183        "#},
184        );
185
186        // positioning outside of brackets removes highlight
187        cx.set_state(indoc! {r#"
188            pub fˇn test("Test argument") {
189                another_test(1, 2, 3);
190            }
191        "#});
192        cx.run_until_parked();
193        cx.assert_editor_text_highlights(
194            HighlightKey::MatchingBracket,
195            indoc! {r#"
196            pub fn test("Test argument") {
197                another_test(1, 2, 3);
198            }
199        "#},
200        );
201
202        // non empty selection dismisses highlight
203        cx.set_state(indoc! {r#"
204            pub fn test("Te«st argˇ»ument") {
205                another_test(1, 2, 3);
206            }
207        "#});
208        cx.run_until_parked();
209        cx.assert_editor_text_highlights(
210            HighlightKey::MatchingBracket,
211            indoc! {r#"
212            pub fn test«("Test argument") {
213                another_test(1, 2, 3);
214            }
215        "#},
216        );
217    }
218}
219
Served at tenant.openagents/omega Member data and write actions are omitted.