Highlight matching bracket when newest selection head is on a bracket
This commit is contained in:
parent
1572fef1c4
commit
9b36e3d009
4 changed files with 65 additions and 2 deletions
|
@ -37,6 +37,7 @@
|
||||||
"ignorePunctuation": true
|
"ignorePunctuation": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"shift-%": "vim::Matching",
|
||||||
"escape": "editor::Cancel"
|
"escape": "editor::Cancel"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
pub mod display_map;
|
pub mod display_map;
|
||||||
mod element;
|
mod element;
|
||||||
|
mod highlight_matching_bracket;
|
||||||
mod hover_popover;
|
mod hover_popover;
|
||||||
pub mod items;
|
pub mod items;
|
||||||
mod link_go_to_definition;
|
mod link_go_to_definition;
|
||||||
|
@ -31,6 +32,7 @@ use gpui::{
|
||||||
ModelHandle, MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle,
|
ModelHandle, MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle,
|
||||||
WeakViewHandle,
|
WeakViewHandle,
|
||||||
};
|
};
|
||||||
|
use highlight_matching_bracket::refresh_matching_bracket_highlights;
|
||||||
use hover_popover::{hide_hover, HoverState};
|
use hover_popover::{hide_hover, HoverState};
|
||||||
pub use language::{char_kind, CharKind};
|
pub use language::{char_kind, CharKind};
|
||||||
use language::{
|
use language::{
|
||||||
|
@ -1422,6 +1424,7 @@ impl Editor {
|
||||||
}
|
}
|
||||||
self.refresh_code_actions(cx);
|
self.refresh_code_actions(cx);
|
||||||
self.refresh_document_highlights(cx);
|
self.refresh_document_highlights(cx);
|
||||||
|
refresh_matching_bracket_highlights(self, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.pause_cursor_blinking(cx);
|
self.pause_cursor_blinking(cx);
|
||||||
|
|
40
crates/editor/src/highlight_matching_bracket.rs
Normal file
40
crates/editor/src/highlight_matching_bracket.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
use gpui::ViewContext;
|
||||||
|
|
||||||
|
use crate::Editor;
|
||||||
|
|
||||||
|
enum MatchingBracketHighlight {}
|
||||||
|
|
||||||
|
pub fn refresh_matching_bracket_highlights(editor: &mut Editor, cx: &mut ViewContext<Editor>) {
|
||||||
|
editor.clear_background_highlights::<MatchingBracketHighlight>(cx);
|
||||||
|
|
||||||
|
let newest_selection = editor.selections.newest::<usize>(cx);
|
||||||
|
let snapshot = editor.snapshot(cx);
|
||||||
|
if let Some((opening_range, closing_range)) = snapshot
|
||||||
|
.buffer_snapshot
|
||||||
|
.enclosing_bracket_ranges(newest_selection.range())
|
||||||
|
{
|
||||||
|
let head = newest_selection.head();
|
||||||
|
let range_to_highlight = if opening_range.contains(&head) {
|
||||||
|
Some(closing_range)
|
||||||
|
} else if closing_range.contains(&head) {
|
||||||
|
Some(opening_range)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(range_to_highlight) = range_to_highlight {
|
||||||
|
let anchor_range = snapshot
|
||||||
|
.buffer_snapshot
|
||||||
|
.anchor_before(range_to_highlight.start)
|
||||||
|
..snapshot
|
||||||
|
.buffer_snapshot
|
||||||
|
.anchor_after(range_to_highlight.end);
|
||||||
|
|
||||||
|
editor.highlight_background::<MatchingBracketHighlight>(
|
||||||
|
vec![anchor_range],
|
||||||
|
|theme| theme.editor.document_highlight_read_background,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,6 +30,7 @@ pub enum Motion {
|
||||||
EndOfLine,
|
EndOfLine,
|
||||||
StartOfDocument,
|
StartOfDocument,
|
||||||
EndOfDocument,
|
EndOfDocument,
|
||||||
|
Matching,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, PartialEq)]
|
#[derive(Clone, Deserialize, PartialEq)]
|
||||||
|
@ -65,7 +66,8 @@ actions!(
|
||||||
EndOfLine,
|
EndOfLine,
|
||||||
CurrentLine,
|
CurrentLine,
|
||||||
StartOfDocument,
|
StartOfDocument,
|
||||||
EndOfDocument
|
EndOfDocument,
|
||||||
|
Matching,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
impl_actions!(vim, [NextWordStart, NextWordEnd, PreviousWordStart]);
|
impl_actions!(vim, [NextWordStart, NextWordEnd, PreviousWordStart]);
|
||||||
|
@ -85,6 +87,7 @@ pub fn init(cx: &mut MutableAppContext) {
|
||||||
motion(Motion::StartOfDocument, cx)
|
motion(Motion::StartOfDocument, cx)
|
||||||
});
|
});
|
||||||
cx.add_action(|_: &mut Workspace, _: &EndOfDocument, cx: _| motion(Motion::EndOfDocument, cx));
|
cx.add_action(|_: &mut Workspace, _: &EndOfDocument, cx: _| motion(Motion::EndOfDocument, cx));
|
||||||
|
cx.add_action(|_: &mut Workspace, _: &Matching, cx: _| motion(Motion::Matching, cx));
|
||||||
|
|
||||||
cx.add_action(
|
cx.add_action(
|
||||||
|_: &mut Workspace, &NextWordStart { ignore_punctuation }: &NextWordStart, cx: _| {
|
|_: &mut Workspace, &NextWordStart { ignore_punctuation }: &NextWordStart, cx: _| {
|
||||||
|
@ -136,7 +139,7 @@ impl Motion {
|
||||||
}
|
}
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
EndOfLine | NextWordEnd { .. } => true,
|
EndOfLine | NextWordEnd { .. } | Matching => true,
|
||||||
Left | Right | StartOfLine | NextWordStart { .. } | PreviousWordStart { .. } => false,
|
Left | Right | StartOfLine | NextWordStart { .. } | PreviousWordStart { .. } => false,
|
||||||
_ => panic!("Exclusivity not defined for {self:?}"),
|
_ => panic!("Exclusivity not defined for {self:?}"),
|
||||||
}
|
}
|
||||||
|
@ -172,6 +175,7 @@ impl Motion {
|
||||||
CurrentLine => (end_of_line(map, point), SelectionGoal::None),
|
CurrentLine => (end_of_line(map, point), SelectionGoal::None),
|
||||||
StartOfDocument => (start_of_document(map, point), SelectionGoal::None),
|
StartOfDocument => (start_of_document(map, point), SelectionGoal::None),
|
||||||
EndOfDocument => (end_of_document(map, point), SelectionGoal::None),
|
EndOfDocument => (end_of_document(map, point), SelectionGoal::None),
|
||||||
|
Matching => (matching(map, point), SelectionGoal::None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,3 +345,18 @@ fn end_of_document(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPoint {
|
||||||
*new_point.column_mut() = point.column();
|
*new_point.column_mut() = point.column();
|
||||||
map.clip_point(new_point, Bias::Left)
|
map.clip_point(new_point, Bias::Left)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn matching(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPoint {
|
||||||
|
let offset = point.to_offset(map, Bias::Left);
|
||||||
|
if let Some((open_range, close_range)) =
|
||||||
|
map.buffer_snapshot.enclosing_bracket_ranges(offset..offset)
|
||||||
|
{
|
||||||
|
if open_range.contains(&offset) {
|
||||||
|
close_range.start.to_display_point(map)
|
||||||
|
} else {
|
||||||
|
open_range.start.to_display_point(map)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
point
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue