Compare commits
5 Commits
performanc
...
40727-push
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
727bce98cd | ||
|
|
40a2f1e458 | ||
|
|
613e851df9 | ||
|
|
56bd762ac7 | ||
|
|
562b8589e7 |
@@ -47,7 +47,7 @@ use crate::{
|
||||
search::{FindCommand, ReplaceCommand, Replacement},
|
||||
},
|
||||
object::Object,
|
||||
state::{Mark, Mode},
|
||||
state::{Mark, Mode, ObjectScope},
|
||||
visual::VisualDeleteLine,
|
||||
};
|
||||
|
||||
@@ -2043,7 +2043,7 @@ impl Vim {
|
||||
pub fn shell_command_object(
|
||||
&mut self,
|
||||
object: Object,
|
||||
around: bool,
|
||||
scope: ObjectScope,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Vim>,
|
||||
) {
|
||||
@@ -2057,7 +2057,7 @@ impl Vim {
|
||||
.selections
|
||||
.newest_display(&editor.display_snapshot(cx));
|
||||
let range = object
|
||||
.range(&snapshot, start.clone(), around, None)
|
||||
.range(&snapshot, start.clone(), &scope, None)
|
||||
.unwrap_or(start.range());
|
||||
if range.start != start.start {
|
||||
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
|
||||
|
||||
@@ -10,6 +10,7 @@ use text::Selection;
|
||||
use crate::{
|
||||
helix::boundary::{FuzzyBoundary, ImmediateBoundary},
|
||||
object::Object as VimObject,
|
||||
state::ObjectScope,
|
||||
};
|
||||
|
||||
/// A text object from helix or an extra one
|
||||
@@ -43,11 +44,17 @@ impl VimObject {
|
||||
self,
|
||||
map: &DisplaySnapshot,
|
||||
selection: Selection<DisplayPoint>,
|
||||
around: bool,
|
||||
scope: &ObjectScope,
|
||||
) -> Result<Option<Range<DisplayPoint>>, VimToHelixError> {
|
||||
let cursor = cursor_range(&selection, map);
|
||||
if let Some(helix_object) = self.to_helix_object() {
|
||||
Ok(helix_object.range(map, cursor, around))
|
||||
// TODO!: Does it make sense to update the trait so as to work on
|
||||
// `ObjectScope` instead of the `around` bool?
|
||||
Ok(helix_object.range(
|
||||
map,
|
||||
cursor,
|
||||
matches!(scope, ObjectScope::Around | ObjectScope::AroundTrimmed),
|
||||
))
|
||||
} else {
|
||||
Err(VimToHelixError)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use text::SelectionGoal;
|
||||
use ui::{Context, Window};
|
||||
|
||||
use crate::{Vim, helix::object::cursor_range, object::Object};
|
||||
use crate::{Vim, helix::object::cursor_range, object::Object, state::ObjectScope};
|
||||
|
||||
impl Vim {
|
||||
/// Selects the object each cursor is over.
|
||||
@@ -9,7 +9,7 @@ impl Vim {
|
||||
pub fn select_current_object(
|
||||
&mut self,
|
||||
object: Object,
|
||||
around: bool,
|
||||
scope: ObjectScope,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
@@ -18,9 +18,9 @@ impl Vim {
|
||||
editor.change_selections(Default::default(), window, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
let Some(range) = object
|
||||
.helix_range(map, selection.clone(), around)
|
||||
.helix_range(map, selection.clone(), &scope)
|
||||
.unwrap_or({
|
||||
let vim_range = object.range(map, selection.clone(), around, None);
|
||||
let vim_range = object.range(map, selection.clone(), &scope, None);
|
||||
vim_range.filter(|r| r.start <= cursor_range(selection, map).start)
|
||||
})
|
||||
else {
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
use crate::{Vim, motion::Motion, object::Object, state::Mode};
|
||||
use crate::{
|
||||
Vim,
|
||||
motion::Motion,
|
||||
object::Object,
|
||||
state::{Mode, ObjectScope},
|
||||
};
|
||||
use collections::HashMap;
|
||||
use editor::SelectionEffects;
|
||||
use editor::{Bias, Editor, display_map::ToDisplayPoint};
|
||||
@@ -136,7 +141,7 @@ impl Vim {
|
||||
pub(crate) fn indent_object(
|
||||
&mut self,
|
||||
object: Object,
|
||||
around: bool,
|
||||
scope: ObjectScope,
|
||||
dir: IndentDirection,
|
||||
times: Option<usize>,
|
||||
window: &mut Window,
|
||||
@@ -150,7 +155,7 @@ impl Vim {
|
||||
s.move_with(|map, selection| {
|
||||
let anchor = map.display_point_to_anchor(selection.head(), Bias::Right);
|
||||
original_positions.insert(selection.id, anchor);
|
||||
object.expand_selection(map, selection, around, times);
|
||||
object.expand_selection(map, selection, &scope, times);
|
||||
});
|
||||
});
|
||||
match dir {
|
||||
|
||||
@@ -16,7 +16,7 @@ use workspace::searchable::Direction;
|
||||
use crate::{
|
||||
Vim,
|
||||
normal::mark,
|
||||
state::{Mode, Operator},
|
||||
state::{Mode, ObjectScope, Operator},
|
||||
surrounds::SurroundsType,
|
||||
};
|
||||
|
||||
@@ -2336,8 +2336,8 @@ fn end_of_document(
|
||||
}
|
||||
|
||||
fn matching_tag(map: &DisplaySnapshot, head: DisplayPoint) -> Option<DisplayPoint> {
|
||||
let inner = crate::object::surrounding_html_tag(map, head, head..head, false)?;
|
||||
let outer = crate::object::surrounding_html_tag(map, head, head..head, true)?;
|
||||
let inner = crate::object::surrounding_html_tag(map, head, head..head, &ObjectScope::Inside)?;
|
||||
let outer = crate::object::surrounding_html_tag(map, head, head..head, &ObjectScope::Around)?;
|
||||
|
||||
if head > outer.start && head < inner.start {
|
||||
let mut offset = inner.end.to_offset(map, Bias::Left);
|
||||
|
||||
@@ -19,7 +19,7 @@ use crate::{
|
||||
indent::IndentDirection,
|
||||
motion::{self, Motion, first_non_whitespace, next_line_end, right},
|
||||
object::Object,
|
||||
state::{Mark, Mode, Operator},
|
||||
state::{Mark, Mode, ObjectScope, Operator},
|
||||
surrounds::SurroundsType,
|
||||
};
|
||||
use collections::BTreeSet;
|
||||
@@ -454,62 +454,80 @@ impl Vim {
|
||||
) {
|
||||
let mut waiting_operator: Option<Operator> = None;
|
||||
match self.maybe_pop_operator() {
|
||||
Some(Operator::Object { around }) => match self.maybe_pop_operator() {
|
||||
Some(Operator::Change) => self.change_object(object, around, times, window, cx),
|
||||
Some(Operator::Delete) => self.delete_object(object, around, times, window, cx),
|
||||
Some(Operator::Yank) => self.yank_object(object, around, times, window, cx),
|
||||
Some(Operator::Indent) => {
|
||||
self.indent_object(object, around, IndentDirection::In, times, window, cx)
|
||||
Some(Operator::Object { scope }) => {
|
||||
let (around, _whitespace) = match scope {
|
||||
ObjectScope::Inside => (false, false),
|
||||
ObjectScope::Around => (true, true),
|
||||
ObjectScope::AroundTrimmed => (true, false),
|
||||
};
|
||||
|
||||
match self.maybe_pop_operator() {
|
||||
Some(Operator::Change) => self.change_object(object, scope, times, window, cx),
|
||||
Some(Operator::Delete) => self.delete_object(object, scope, times, window, cx),
|
||||
Some(Operator::Yank) => self.yank_object(object, scope, times, window, cx),
|
||||
Some(Operator::Indent) => {
|
||||
self.indent_object(object, scope, IndentDirection::In, times, window, cx)
|
||||
}
|
||||
Some(Operator::Outdent) => {
|
||||
self.indent_object(object, scope, IndentDirection::Out, times, window, cx)
|
||||
}
|
||||
Some(Operator::AutoIndent) => {
|
||||
self.indent_object(object, scope, IndentDirection::Auto, times, window, cx)
|
||||
}
|
||||
Some(Operator::ShellCommand) => {
|
||||
self.shell_command_object(object, scope, window, cx);
|
||||
}
|
||||
Some(Operator::Rewrap) => self.rewrap_object(object, scope, times, window, cx),
|
||||
Some(Operator::Lowercase) => self.convert_object(
|
||||
object,
|
||||
scope,
|
||||
ConvertTarget::LowerCase,
|
||||
times,
|
||||
window,
|
||||
cx,
|
||||
),
|
||||
Some(Operator::Uppercase) => self.convert_object(
|
||||
object,
|
||||
scope,
|
||||
ConvertTarget::UpperCase,
|
||||
times,
|
||||
window,
|
||||
cx,
|
||||
),
|
||||
Some(Operator::OppositeCase) => self.convert_object(
|
||||
object,
|
||||
scope,
|
||||
ConvertTarget::OppositeCase,
|
||||
times,
|
||||
window,
|
||||
cx,
|
||||
),
|
||||
Some(Operator::Rot13) => {
|
||||
self.convert_object(object, scope, ConvertTarget::Rot13, times, window, cx)
|
||||
}
|
||||
Some(Operator::Rot47) => {
|
||||
self.convert_object(object, scope, ConvertTarget::Rot47, times, window, cx)
|
||||
}
|
||||
Some(Operator::AddSurrounds { target: None }) => {
|
||||
waiting_operator = Some(Operator::AddSurrounds {
|
||||
target: Some(SurroundsType::Object(object, around)),
|
||||
});
|
||||
}
|
||||
Some(Operator::ToggleComments) => {
|
||||
self.toggle_comments_object(object, scope, times, window, cx)
|
||||
}
|
||||
Some(Operator::ReplaceWithRegister) => {
|
||||
self.replace_with_register_object(object, scope, window, cx)
|
||||
}
|
||||
Some(Operator::Exchange) => self.exchange_object(object, scope, window, cx),
|
||||
Some(Operator::HelixMatch) => {
|
||||
self.select_current_object(object, scope, window, cx)
|
||||
}
|
||||
_ => {
|
||||
// Can't do anything for namespace operators. Ignoring
|
||||
}
|
||||
}
|
||||
Some(Operator::Outdent) => {
|
||||
self.indent_object(object, around, IndentDirection::Out, times, window, cx)
|
||||
}
|
||||
Some(Operator::AutoIndent) => {
|
||||
self.indent_object(object, around, IndentDirection::Auto, times, window, cx)
|
||||
}
|
||||
Some(Operator::ShellCommand) => {
|
||||
self.shell_command_object(object, around, window, cx);
|
||||
}
|
||||
Some(Operator::Rewrap) => self.rewrap_object(object, around, times, window, cx),
|
||||
Some(Operator::Lowercase) => {
|
||||
self.convert_object(object, around, ConvertTarget::LowerCase, times, window, cx)
|
||||
}
|
||||
Some(Operator::Uppercase) => {
|
||||
self.convert_object(object, around, ConvertTarget::UpperCase, times, window, cx)
|
||||
}
|
||||
Some(Operator::OppositeCase) => self.convert_object(
|
||||
object,
|
||||
around,
|
||||
ConvertTarget::OppositeCase,
|
||||
times,
|
||||
window,
|
||||
cx,
|
||||
),
|
||||
Some(Operator::Rot13) => {
|
||||
self.convert_object(object, around, ConvertTarget::Rot13, times, window, cx)
|
||||
}
|
||||
Some(Operator::Rot47) => {
|
||||
self.convert_object(object, around, ConvertTarget::Rot47, times, window, cx)
|
||||
}
|
||||
Some(Operator::AddSurrounds { target: None }) => {
|
||||
waiting_operator = Some(Operator::AddSurrounds {
|
||||
target: Some(SurroundsType::Object(object, around)),
|
||||
});
|
||||
}
|
||||
Some(Operator::ToggleComments) => {
|
||||
self.toggle_comments_object(object, around, times, window, cx)
|
||||
}
|
||||
Some(Operator::ReplaceWithRegister) => {
|
||||
self.replace_with_register_object(object, around, window, cx)
|
||||
}
|
||||
Some(Operator::Exchange) => self.exchange_object(object, around, window, cx),
|
||||
Some(Operator::HelixMatch) => {
|
||||
self.select_current_object(object, around, window, cx)
|
||||
}
|
||||
_ => {
|
||||
// Can't do anything for namespace operators. Ignoring
|
||||
}
|
||||
},
|
||||
}
|
||||
Some(Operator::HelixNext { around }) => {
|
||||
self.select_next_object(object, around, window, cx);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::{
|
||||
Vim,
|
||||
motion::{self, Motion, MotionKind},
|
||||
object::Object,
|
||||
state::Mode,
|
||||
state::{Mode, ObjectScope},
|
||||
};
|
||||
use editor::{
|
||||
Bias, DisplayPoint,
|
||||
@@ -105,7 +105,7 @@ impl Vim {
|
||||
pub fn change_object(
|
||||
&mut self,
|
||||
object: Object,
|
||||
around: bool,
|
||||
scope: ObjectScope,
|
||||
times: Option<usize>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
@@ -117,7 +117,7 @@ impl Vim {
|
||||
editor.transact(window, cx, |editor, window, cx| {
|
||||
editor.change_selections(Default::default(), window, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
objects_found |= object.expand_selection(map, selection, around, times);
|
||||
objects_found |= object.expand_selection(map, selection, &scope, times);
|
||||
});
|
||||
});
|
||||
if objects_found {
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::{
|
||||
motion::Motion,
|
||||
normal::{ChangeCase, ConvertToLowerCase, ConvertToRot13, ConvertToRot47, ConvertToUpperCase},
|
||||
object::Object,
|
||||
state::Mode,
|
||||
state::{Mode, ObjectScope},
|
||||
};
|
||||
|
||||
pub enum ConvertTarget {
|
||||
@@ -80,7 +80,7 @@ impl Vim {
|
||||
pub fn convert_object(
|
||||
&mut self,
|
||||
object: Object,
|
||||
around: bool,
|
||||
scope: ObjectScope,
|
||||
mode: ConvertTarget,
|
||||
times: Option<usize>,
|
||||
window: &mut Window,
|
||||
@@ -93,7 +93,7 @@ impl Vim {
|
||||
let mut original_positions: HashMap<_, _> = Default::default();
|
||||
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
object.expand_selection(map, selection, around, times);
|
||||
object.expand_selection(map, selection, &scope, times);
|
||||
original_positions.insert(
|
||||
selection.id,
|
||||
map.display_point_to_anchor(selection.start, Bias::Left),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
Vim,
|
||||
ObjectScope, Vim,
|
||||
motion::{Motion, MotionKind},
|
||||
object::Object,
|
||||
state::Mode,
|
||||
@@ -92,7 +92,7 @@ impl Vim {
|
||||
pub fn delete_object(
|
||||
&mut self,
|
||||
object: Object,
|
||||
around: bool,
|
||||
scope: ObjectScope,
|
||||
times: Option<usize>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
@@ -109,7 +109,7 @@ impl Vim {
|
||||
// to the same column it was before deletion if the line is not empty or only
|
||||
// contains whitespace
|
||||
let mut column_before_move: HashMap<_, _> = Default::default();
|
||||
let target_mode = object.target_visual_mode(vim.mode, around);
|
||||
let target_mode = object.target_visual_mode(vim.mode, &scope);
|
||||
|
||||
editor.change_selections(Default::default(), window, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
@@ -118,7 +118,7 @@ impl Vim {
|
||||
column_before_move.insert(selection.id, cursor_point.column);
|
||||
}
|
||||
|
||||
object.expand_selection(map, selection, around, times);
|
||||
object.expand_selection(map, selection, &scope, times);
|
||||
let offset_range = selection.map(|p| p.to_offset(map, Bias::Left)).range();
|
||||
let mut move_selection_start_to_previous_line =
|
||||
|map: &DisplaySnapshot, selection: &mut Selection<DisplayPoint>| {
|
||||
@@ -145,7 +145,10 @@ impl Vim {
|
||||
// If expanded range contains only newlines and
|
||||
// the object is around or sentence, expand to include a newline
|
||||
// at the end or start
|
||||
if (around || object == Object::Sentence) && contains_only_newlines {
|
||||
if (matches!(scope, ObjectScope::AroundTrimmed | ObjectScope::Around)
|
||||
|| object == Object::Sentence)
|
||||
&& contains_only_newlines
|
||||
{
|
||||
if end_at_newline {
|
||||
move_selection_end_to_next_line(map, selection);
|
||||
} else {
|
||||
@@ -155,7 +158,9 @@ impl Vim {
|
||||
|
||||
// Does post-processing for the trailing newline and EOF
|
||||
// when not cancelled.
|
||||
let cancelled = around && selection.start == selection.end;
|
||||
let cancelled =
|
||||
matches!(scope, ObjectScope::AroundTrimmed | ObjectScope::Around)
|
||||
&& selection.start == selection.end;
|
||||
if object == Object::Paragraph && !cancelled {
|
||||
// EOF check should be done before including a trailing newline.
|
||||
if ends_at_eof(map, selection) {
|
||||
@@ -209,9 +214,11 @@ fn ends_at_eof(map: &DisplaySnapshot, selection: &mut Selection<DisplayPoint>) -
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use gpui::KeyBinding;
|
||||
use indoc::indoc;
|
||||
|
||||
use crate::{
|
||||
PushObject,
|
||||
state::Mode,
|
||||
test::{NeovimBackedTestContext, VimTestContext},
|
||||
};
|
||||
@@ -760,4 +767,24 @@ mod test {
|
||||
.await
|
||||
.assert_matches();
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_delete_object_scope(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
|
||||
cx.update(|_, cx| {
|
||||
cx.bind_keys([KeyBinding::new(
|
||||
"a",
|
||||
PushObject {
|
||||
around: true,
|
||||
whitespace: false,
|
||||
},
|
||||
Some("VimControl && !menu"),
|
||||
)]);
|
||||
});
|
||||
|
||||
cx.set_state("some 'ˇquotes' here", Mode::Normal);
|
||||
cx.simulate_keystrokes("d a '");
|
||||
cx.assert_editor_state("some ˇ here");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::{
|
||||
Vim,
|
||||
motion::{Motion, MotionKind},
|
||||
object::Object,
|
||||
state::{Mode, Register},
|
||||
state::{Mode, ObjectScope, Register},
|
||||
};
|
||||
|
||||
/// Pastes text from the specified register at the cursor position.
|
||||
@@ -233,7 +233,7 @@ impl Vim {
|
||||
pub fn replace_with_register_object(
|
||||
&mut self,
|
||||
object: Object,
|
||||
around: bool,
|
||||
scope: ObjectScope,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
@@ -244,7 +244,7 @@ impl Vim {
|
||||
editor.set_clip_at_line_ends(false, cx);
|
||||
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
object.expand_selection(map, selection, around, None);
|
||||
object.expand_selection(map, selection, &scope, None);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{Vim, motion::Motion, object::Object};
|
||||
use crate::{ObjectScope, Vim, motion::Motion, object::Object};
|
||||
use collections::HashMap;
|
||||
use editor::{Bias, SelectionEffects, display_map::ToDisplayPoint};
|
||||
use gpui::{Context, Window};
|
||||
@@ -45,7 +45,7 @@ impl Vim {
|
||||
pub fn toggle_comments_object(
|
||||
&mut self,
|
||||
object: Object,
|
||||
around: bool,
|
||||
scope: ObjectScope,
|
||||
times: Option<usize>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
@@ -58,7 +58,7 @@ impl Vim {
|
||||
s.move_with(|map, selection| {
|
||||
let anchor = map.display_point_to_anchor(selection.head(), Bias::Right);
|
||||
original_positions.insert(selection.id, anchor);
|
||||
object.expand_selection(map, selection, around, times);
|
||||
object.expand_selection(map, selection, &scope, times);
|
||||
});
|
||||
});
|
||||
editor.toggle_comments(&Default::default(), window, cx);
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::{
|
||||
Vim, VimSettings,
|
||||
motion::{Motion, MotionKind},
|
||||
object::Object,
|
||||
state::{Mode, Register},
|
||||
state::{Mode, ObjectScope, Register},
|
||||
};
|
||||
use collections::HashMap;
|
||||
use editor::{ClipboardSelection, Editor, SelectionEffects};
|
||||
@@ -65,7 +65,7 @@ impl Vim {
|
||||
pub fn yank_object(
|
||||
&mut self,
|
||||
object: Object,
|
||||
around: bool,
|
||||
scope: ObjectScope,
|
||||
times: Option<usize>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
@@ -76,7 +76,7 @@ impl Vim {
|
||||
let mut start_positions: HashMap<_, _> = Default::default();
|
||||
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
object.expand_selection(map, selection, around, times);
|
||||
object.expand_selection(map, selection, &scope, times);
|
||||
let start_position = (selection.start, selection.goal);
|
||||
start_positions.insert(selection.id, start_position);
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::ops::Range;
|
||||
use crate::{
|
||||
Vim,
|
||||
motion::right,
|
||||
state::{Mode, Operator},
|
||||
state::{Mode, ObjectScope, Operator},
|
||||
};
|
||||
use editor::{
|
||||
Bias, DisplayPoint, Editor, ToOffset,
|
||||
@@ -204,9 +204,10 @@ impl DelimiterRange {
|
||||
fn find_mini_delimiters(
|
||||
map: &DisplaySnapshot,
|
||||
display_point: DisplayPoint,
|
||||
around: bool,
|
||||
scope: &ObjectScope,
|
||||
is_valid_delimiter: &DelimiterPredicate,
|
||||
) -> Option<Range<DisplayPoint>> {
|
||||
let around = matches!(scope, ObjectScope::Around | ObjectScope::AroundTrimmed);
|
||||
let point = map.clip_at_line_end(display_point).to_point(map);
|
||||
let offset = point.to_offset(&map.buffer_snapshot());
|
||||
|
||||
@@ -278,17 +279,17 @@ fn is_bracket_delimiter(buffer: &BufferSnapshot, start: usize, _end: usize) -> b
|
||||
fn find_mini_quotes(
|
||||
map: &DisplaySnapshot,
|
||||
display_point: DisplayPoint,
|
||||
around: bool,
|
||||
scope: &ObjectScope,
|
||||
) -> Option<Range<DisplayPoint>> {
|
||||
find_mini_delimiters(map, display_point, around, &is_quote_delimiter)
|
||||
find_mini_delimiters(map, display_point, scope, &is_quote_delimiter)
|
||||
}
|
||||
|
||||
fn find_mini_brackets(
|
||||
map: &DisplaySnapshot,
|
||||
display_point: DisplayPoint,
|
||||
around: bool,
|
||||
scope: &ObjectScope,
|
||||
) -> Option<Range<DisplayPoint>> {
|
||||
find_mini_delimiters(map, display_point, around, &is_bracket_delimiter)
|
||||
find_mini_delimiters(map, display_point, scope, &is_bracket_delimiter)
|
||||
}
|
||||
|
||||
actions!(
|
||||
@@ -406,7 +407,13 @@ pub fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
|
||||
});
|
||||
Vim::action(editor, cx, |vim, _: &Comment, window, cx| {
|
||||
if !matches!(vim.active_operator(), Some(Operator::Object { .. })) {
|
||||
vim.push_operator(Operator::Object { around: true }, window, cx);
|
||||
vim.push_operator(
|
||||
Operator::Object {
|
||||
scope: ObjectScope::Around,
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
vim.object(Object::Comment, window, cx)
|
||||
});
|
||||
@@ -504,7 +511,7 @@ impl Object {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn target_visual_mode(self, current_mode: Mode, around: bool) -> Mode {
|
||||
pub fn target_visual_mode(self, current_mode: Mode, scope: &ObjectScope) -> Mode {
|
||||
match self {
|
||||
Object::Word { .. }
|
||||
| Object::Subword { .. }
|
||||
@@ -531,13 +538,10 @@ impl Object {
|
||||
| Object::Comment
|
||||
| Object::Argument
|
||||
| Object::IndentObj { .. } => Mode::Visual,
|
||||
Object::Method | Object::Class => {
|
||||
if around {
|
||||
Mode::VisualLine
|
||||
} else {
|
||||
Mode::Visual
|
||||
}
|
||||
}
|
||||
Object::Method | Object::Class => match scope {
|
||||
ObjectScope::Around | ObjectScope::AroundTrimmed => Mode::VisualLine,
|
||||
ObjectScope::Inside => Mode::Visual,
|
||||
},
|
||||
Object::Paragraph | Object::EntireFile => Mode::VisualLine,
|
||||
}
|
||||
}
|
||||
@@ -546,33 +550,31 @@ impl Object {
|
||||
self,
|
||||
map: &DisplaySnapshot,
|
||||
selection: Selection<DisplayPoint>,
|
||||
around: bool,
|
||||
scope: &ObjectScope,
|
||||
times: Option<usize>,
|
||||
) -> Option<Range<DisplayPoint>> {
|
||||
let relative_to = selection.head();
|
||||
match self {
|
||||
Object::Word { ignore_punctuation } => {
|
||||
if around {
|
||||
Object::Word { ignore_punctuation } => match scope {
|
||||
ObjectScope::Around | ObjectScope::AroundTrimmed => {
|
||||
around_word(map, relative_to, ignore_punctuation)
|
||||
} else {
|
||||
in_word(map, relative_to, ignore_punctuation)
|
||||
}
|
||||
}
|
||||
Object::Subword { ignore_punctuation } => {
|
||||
if around {
|
||||
ObjectScope::Inside => in_word(map, relative_to, ignore_punctuation),
|
||||
},
|
||||
Object::Subword { ignore_punctuation } => match scope {
|
||||
ObjectScope::Around | ObjectScope::AroundTrimmed => {
|
||||
around_subword(map, relative_to, ignore_punctuation)
|
||||
} else {
|
||||
in_subword(map, relative_to, ignore_punctuation)
|
||||
}
|
||||
}
|
||||
Object::Sentence => sentence(map, relative_to, around),
|
||||
ObjectScope::Inside => in_subword(map, relative_to, ignore_punctuation),
|
||||
},
|
||||
Object::Sentence => sentence(map, relative_to, scope),
|
||||
//change others later
|
||||
Object::Paragraph => paragraph(map, relative_to, around, times.unwrap_or(1)),
|
||||
Object::Paragraph => paragraph(map, relative_to, scope, times.unwrap_or(1)),
|
||||
Object::Quotes => {
|
||||
surrounding_markers(map, relative_to, around, self.is_multiline(), '\'', '\'')
|
||||
surrounding_markers(map, relative_to, scope, self.is_multiline(), '\'', '\'')
|
||||
}
|
||||
Object::BackQuotes => {
|
||||
surrounding_markers(map, relative_to, around, self.is_multiline(), '`', '`')
|
||||
surrounding_markers(map, relative_to, scope, self.is_multiline(), '`', '`')
|
||||
}
|
||||
Object::AnyQuotes => {
|
||||
let quote_types = ['\'', '"', '`'];
|
||||
@@ -587,7 +589,7 @@ impl Object {
|
||||
if let Some(range) = surrounding_markers(
|
||||
map,
|
||||
relative_to,
|
||||
around,
|
||||
scope,
|
||||
self.is_multiline(),
|
||||
quote,
|
||||
quote,
|
||||
@@ -616,7 +618,7 @@ impl Object {
|
||||
surrounding_markers(
|
||||
map,
|
||||
relative_to,
|
||||
around,
|
||||
scope,
|
||||
self.is_multiline(),
|
||||
quote,
|
||||
quote,
|
||||
@@ -634,20 +636,20 @@ impl Object {
|
||||
}
|
||||
})
|
||||
}
|
||||
Object::MiniQuotes => find_mini_quotes(map, relative_to, around),
|
||||
Object::MiniQuotes => find_mini_quotes(map, relative_to, scope),
|
||||
Object::DoubleQuotes => {
|
||||
surrounding_markers(map, relative_to, around, self.is_multiline(), '"', '"')
|
||||
surrounding_markers(map, relative_to, scope, self.is_multiline(), '"', '"')
|
||||
}
|
||||
Object::VerticalBars => {
|
||||
surrounding_markers(map, relative_to, around, self.is_multiline(), '|', '|')
|
||||
surrounding_markers(map, relative_to, scope, self.is_multiline(), '|', '|')
|
||||
}
|
||||
Object::Parentheses => {
|
||||
surrounding_markers(map, relative_to, around, self.is_multiline(), '(', ')')
|
||||
surrounding_markers(map, relative_to, scope, self.is_multiline(), '(', ')')
|
||||
}
|
||||
Object::Tag => {
|
||||
let head = selection.head();
|
||||
let range = selection.range();
|
||||
surrounding_html_tag(map, head, range, around)
|
||||
surrounding_html_tag(map, head, range, scope)
|
||||
}
|
||||
Object::AnyBrackets => {
|
||||
let bracket_pairs = [('(', ')'), ('[', ']'), ('{', '}'), ('<', '>')];
|
||||
@@ -661,7 +663,7 @@ impl Object {
|
||||
if let Some(range) = surrounding_markers(
|
||||
map,
|
||||
relative_to,
|
||||
around,
|
||||
scope,
|
||||
self.is_multiline(),
|
||||
open,
|
||||
close,
|
||||
@@ -690,7 +692,7 @@ impl Object {
|
||||
surrounding_markers(
|
||||
map,
|
||||
relative_to,
|
||||
around,
|
||||
scope,
|
||||
self.is_multiline(),
|
||||
open,
|
||||
close,
|
||||
@@ -708,45 +710,42 @@ impl Object {
|
||||
}
|
||||
})
|
||||
}
|
||||
Object::MiniBrackets => find_mini_brackets(map, relative_to, around),
|
||||
Object::MiniBrackets => find_mini_brackets(map, relative_to, scope),
|
||||
Object::SquareBrackets => {
|
||||
surrounding_markers(map, relative_to, around, self.is_multiline(), '[', ']')
|
||||
surrounding_markers(map, relative_to, scope, self.is_multiline(), '[', ']')
|
||||
}
|
||||
Object::CurlyBrackets => {
|
||||
surrounding_markers(map, relative_to, around, self.is_multiline(), '{', '}')
|
||||
surrounding_markers(map, relative_to, scope, self.is_multiline(), '{', '}')
|
||||
}
|
||||
Object::AngleBrackets => {
|
||||
surrounding_markers(map, relative_to, around, self.is_multiline(), '<', '>')
|
||||
surrounding_markers(map, relative_to, scope, self.is_multiline(), '<', '>')
|
||||
}
|
||||
Object::Method => text_object(
|
||||
map,
|
||||
relative_to,
|
||||
if around {
|
||||
TextObject::AroundFunction
|
||||
} else {
|
||||
TextObject::InsideFunction
|
||||
match scope {
|
||||
ObjectScope::Around | ObjectScope::AroundTrimmed => TextObject::AroundFunction,
|
||||
ObjectScope::Inside => TextObject::InsideFunction,
|
||||
},
|
||||
),
|
||||
Object::Comment => text_object(
|
||||
map,
|
||||
relative_to,
|
||||
if around {
|
||||
TextObject::AroundComment
|
||||
} else {
|
||||
TextObject::InsideComment
|
||||
match scope {
|
||||
ObjectScope::Around | ObjectScope::AroundTrimmed => TextObject::AroundComment,
|
||||
ObjectScope::Inside => TextObject::InsideComment,
|
||||
},
|
||||
),
|
||||
Object::Class => text_object(
|
||||
map,
|
||||
relative_to,
|
||||
if around {
|
||||
TextObject::AroundClass
|
||||
} else {
|
||||
TextObject::InsideClass
|
||||
match scope {
|
||||
ObjectScope::Around | ObjectScope::AroundTrimmed => TextObject::AroundClass,
|
||||
ObjectScope::Inside => TextObject::InsideClass,
|
||||
},
|
||||
),
|
||||
Object::Argument => argument(map, relative_to, around),
|
||||
Object::IndentObj { include_below } => indent(map, relative_to, around, include_below),
|
||||
Object::Argument => argument(map, relative_to, scope),
|
||||
Object::IndentObj { include_below } => indent(map, relative_to, scope, include_below),
|
||||
Object::EntireFile => entire_file(map),
|
||||
}
|
||||
}
|
||||
@@ -755,10 +754,10 @@ impl Object {
|
||||
self,
|
||||
map: &DisplaySnapshot,
|
||||
selection: &mut Selection<DisplayPoint>,
|
||||
around: bool,
|
||||
scope: &ObjectScope,
|
||||
times: Option<usize>,
|
||||
) -> bool {
|
||||
if let Some(range) = self.range(map, selection.clone(), around, times) {
|
||||
if let Some(range) = self.range(map, selection.clone(), scope, times) {
|
||||
selection.start = range.start;
|
||||
selection.end = range.end;
|
||||
true
|
||||
@@ -857,7 +856,7 @@ pub fn surrounding_html_tag(
|
||||
map: &DisplaySnapshot,
|
||||
head: DisplayPoint,
|
||||
range: Range<DisplayPoint>,
|
||||
around: bool,
|
||||
scope: &ObjectScope,
|
||||
) -> Option<Range<DisplayPoint>> {
|
||||
fn read_tag(chars: impl Iterator<Item = char>) -> String {
|
||||
chars
|
||||
@@ -909,7 +908,8 @@ pub fn surrounding_html_tag(
|
||||
&& range.end.to_offset(map, Bias::Left) <= last_child.start_byte() + 1
|
||||
};
|
||||
if open_tag.is_some() && open_tag == close_tag && is_valid {
|
||||
let range = if around {
|
||||
let range = if matches!(scope, ObjectScope::Around | ObjectScope::AroundTrimmed)
|
||||
{
|
||||
first_child.byte_range().start..last_child.byte_range().end
|
||||
} else {
|
||||
first_child.byte_range().end..last_child.byte_range().start
|
||||
@@ -1110,7 +1110,7 @@ fn text_object(
|
||||
fn argument(
|
||||
map: &DisplaySnapshot,
|
||||
relative_to: DisplayPoint,
|
||||
around: bool,
|
||||
scope: &ObjectScope,
|
||||
) -> Option<Range<DisplayPoint>> {
|
||||
let snapshot = &map.buffer_snapshot();
|
||||
let offset = relative_to.to_offset(map, Bias::Left);
|
||||
@@ -1246,7 +1246,9 @@ fn argument(
|
||||
Some(start..end)
|
||||
}
|
||||
|
||||
let result = comma_delimited_range_at(buffer, excerpt.map_offset_to_buffer(offset), around)?;
|
||||
let include_comma = matches!(scope, ObjectScope::Around | ObjectScope::AroundTrimmed);
|
||||
let result =
|
||||
comma_delimited_range_at(buffer, excerpt.map_offset_to_buffer(offset), include_comma)?;
|
||||
|
||||
if excerpt.contains_buffer_range(result.clone()) {
|
||||
let result = excerpt.map_range_from_buffer(result);
|
||||
@@ -1259,9 +1261,10 @@ fn argument(
|
||||
fn indent(
|
||||
map: &DisplaySnapshot,
|
||||
relative_to: DisplayPoint,
|
||||
around: bool,
|
||||
scope: &ObjectScope,
|
||||
include_below: bool,
|
||||
) -> Option<Range<DisplayPoint>> {
|
||||
let around = matches!(scope, ObjectScope::Around | ObjectScope::AroundTrimmed);
|
||||
let point = relative_to.to_point(map);
|
||||
let row = point.row;
|
||||
|
||||
@@ -1311,13 +1314,13 @@ fn indent(
|
||||
fn sentence(
|
||||
map: &DisplaySnapshot,
|
||||
relative_to: DisplayPoint,
|
||||
around: bool,
|
||||
scope: &ObjectScope,
|
||||
) -> Option<Range<DisplayPoint>> {
|
||||
let mut start = None;
|
||||
let relative_offset = relative_to.to_offset(map, Bias::Left);
|
||||
let mut previous_end = relative_offset;
|
||||
|
||||
let mut chars = map.buffer_chars_at(previous_end).peekable();
|
||||
let around = matches!(scope, ObjectScope::Around | ObjectScope::AroundTrimmed);
|
||||
|
||||
// Search backwards for the previous sentence end or current sentence start. Include the character under relative_to
|
||||
for (char, offset) in chars
|
||||
@@ -1463,7 +1466,7 @@ pub fn expand_to_include_whitespace(
|
||||
fn paragraph(
|
||||
map: &DisplaySnapshot,
|
||||
relative_to: DisplayPoint,
|
||||
around: bool,
|
||||
scope: &ObjectScope,
|
||||
times: usize,
|
||||
) -> Option<Range<DisplayPoint>> {
|
||||
let mut paragraph_start = start_of_paragraph(map, relative_to);
|
||||
@@ -1477,7 +1480,7 @@ fn paragraph(
|
||||
.buffer_snapshot()
|
||||
.is_line_blank(MultiBufferRow(point.row));
|
||||
|
||||
if around {
|
||||
if matches!(scope, ObjectScope::Around | ObjectScope::AroundTrimmed) {
|
||||
if paragraph_ends_with_eof {
|
||||
if current_line_is_empty {
|
||||
return None;
|
||||
@@ -1558,12 +1561,13 @@ pub fn end_of_paragraph(map: &DisplaySnapshot, display_point: DisplayPoint) -> D
|
||||
pub fn surrounding_markers(
|
||||
map: &DisplaySnapshot,
|
||||
relative_to: DisplayPoint,
|
||||
around: bool,
|
||||
scope: &ObjectScope,
|
||||
search_across_lines: bool,
|
||||
open_marker: char,
|
||||
close_marker: char,
|
||||
) -> Option<Range<DisplayPoint>> {
|
||||
let point = relative_to.to_offset(map, Bias::Left);
|
||||
let around = matches!(scope, ObjectScope::Around | ObjectScope::AroundTrimmed);
|
||||
|
||||
let mut matched_closes = 0;
|
||||
let mut opening = None;
|
||||
@@ -1669,7 +1673,12 @@ pub fn surrounding_markers(
|
||||
for (ch, range) in movement::chars_after(map, closing.end) {
|
||||
if ch.is_whitespace() && ch != '\n' {
|
||||
found = true;
|
||||
closing.end = range.end;
|
||||
|
||||
// Only update closing range's `end` value if whitespace is
|
||||
// meant to be included.
|
||||
if *scope == ObjectScope::Around {
|
||||
closing.end = range.end;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -1678,7 +1687,11 @@ pub fn surrounding_markers(
|
||||
if !found {
|
||||
for (ch, range) in movement::chars_before(map, opening.start) {
|
||||
if ch.is_whitespace() && ch != '\n' {
|
||||
opening.start = range.start
|
||||
// Only update closing range's `start` value if whitespace
|
||||
// is meant to be included.
|
||||
if *scope == ObjectScope::Around {
|
||||
opening.start = range.start
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::{
|
||||
Vim,
|
||||
motion::{self, Motion},
|
||||
object::Object,
|
||||
state::Mode,
|
||||
state::{Mode, ObjectScope},
|
||||
};
|
||||
use editor::{
|
||||
Anchor, Bias, Editor, EditorSnapshot, SelectionEffects, ToOffset, ToPoint,
|
||||
@@ -143,7 +143,7 @@ impl Vim {
|
||||
pub fn exchange_object(
|
||||
&mut self,
|
||||
object: Object,
|
||||
around: bool,
|
||||
scope: ObjectScope,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
@@ -154,7 +154,7 @@ impl Vim {
|
||||
.selections
|
||||
.newest_display(&editor.display_snapshot(cx));
|
||||
let snapshot = editor.snapshot(window, cx);
|
||||
object.expand_selection(&snapshot, &mut selection, around, None);
|
||||
object.expand_selection(&snapshot, &mut selection, &scope, None);
|
||||
let start = snapshot
|
||||
.buffer_snapshot()
|
||||
.anchor_before(selection.start.to_point(&snapshot));
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
use crate::{Vim, motion::Motion, object::Object, state::Mode};
|
||||
use crate::{
|
||||
Vim,
|
||||
motion::Motion,
|
||||
object::Object,
|
||||
state::{Mode, ObjectScope},
|
||||
};
|
||||
use collections::HashMap;
|
||||
use editor::{Bias, Editor, RewrapOptions, SelectionEffects, display_map::ToDisplayPoint};
|
||||
use gpui::{Context, Window, actions};
|
||||
@@ -94,7 +99,7 @@ impl Vim {
|
||||
pub(crate) fn rewrap_object(
|
||||
&mut self,
|
||||
object: Object,
|
||||
around: bool,
|
||||
scope: ObjectScope,
|
||||
times: Option<usize>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
@@ -107,7 +112,7 @@ impl Vim {
|
||||
s.move_with(|map, selection| {
|
||||
let anchor = map.display_point_to_anchor(selection.head(), Bias::Right);
|
||||
original_positions.insert(selection.id, anchor);
|
||||
object.expand_selection(map, selection, around, times);
|
||||
object.expand_selection(map, selection, &scope, times);
|
||||
});
|
||||
});
|
||||
editor.rewrap_impl(
|
||||
|
||||
@@ -2,7 +2,10 @@ use crate::command::command_interceptor;
|
||||
use crate::motion::MotionKind;
|
||||
use crate::normal::repeat::Replayer;
|
||||
use crate::surrounds::SurroundsType;
|
||||
use crate::{ToggleMarksView, ToggleRegistersView, UseSystemClipboard, Vim, VimAddon, VimSettings};
|
||||
use crate::{
|
||||
PushObject, ToggleMarksView, ToggleRegistersView, UseSystemClipboard, Vim, VimAddon,
|
||||
VimSettings,
|
||||
};
|
||||
use crate::{motion::Motion, object::Object};
|
||||
use anyhow::Result;
|
||||
use collections::HashMap;
|
||||
@@ -87,7 +90,7 @@ pub enum Operator {
|
||||
Yank,
|
||||
Replace,
|
||||
Object {
|
||||
around: bool,
|
||||
scope: ObjectScope,
|
||||
},
|
||||
FindForward {
|
||||
before: bool,
|
||||
@@ -149,6 +152,40 @@ pub enum Operator {
|
||||
},
|
||||
}
|
||||
|
||||
/// Controls how the object interacts with its delimiters and the surrounding
|
||||
/// whitespace.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub(crate) enum ObjectScope {
|
||||
/// Inside the delimiters, excluding whitespace.
|
||||
///
|
||||
/// Used by the `i` operator (e.g., `diw` for "delete inner word").
|
||||
/// Selects only the content between delimiters without including
|
||||
/// the delimiters themselves or surrounding whitespace.
|
||||
Inside,
|
||||
/// Around the delimiters, including surrounding whitespace.
|
||||
///
|
||||
/// Used by the `a` operator (e.g., `daw` for "delete a word").
|
||||
/// Selects the content, the delimiters, and any surrounding whitespace.
|
||||
Around,
|
||||
/// Around the delimiters, excluding surrounding whitespace.
|
||||
///
|
||||
/// Similar to `Around`, but does not include whitespace adjacent to
|
||||
/// the delimiters.
|
||||
AroundTrimmed,
|
||||
}
|
||||
|
||||
impl ObjectScope {
|
||||
/// Create the `ObjectScope` from a `PushObject` action, taking into account
|
||||
/// its `around` and `whitespace` values.
|
||||
pub(crate) fn from_action(action: &PushObject) -> Self {
|
||||
match (action.around, action.whitespace) {
|
||||
(false, _) => ObjectScope::Inside,
|
||||
(true, true) => ObjectScope::Around,
|
||||
(true, false) => ObjectScope::AroundTrimmed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub enum RecordedSelection {
|
||||
#[default]
|
||||
@@ -996,8 +1033,12 @@ pub struct SearchState {
|
||||
impl Operator {
|
||||
pub fn id(&self) -> &'static str {
|
||||
match self {
|
||||
Operator::Object { around: false } => "i",
|
||||
Operator::Object { around: true } => "a",
|
||||
Operator::Object {
|
||||
scope: ObjectScope::Inside,
|
||||
} => "i",
|
||||
Operator::Object {
|
||||
scope: ObjectScope::Around | ObjectScope::AroundTrimmed,
|
||||
} => "a",
|
||||
Operator::Change => "c",
|
||||
Operator::Delete => "d",
|
||||
Operator::Yank => "y",
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::{
|
||||
Vim,
|
||||
motion::{self, Motion},
|
||||
object::{Object, surrounding_markers},
|
||||
state::Mode,
|
||||
state::{Mode, ObjectScope},
|
||||
};
|
||||
use editor::{Bias, movement};
|
||||
use gpui::{Context, Window};
|
||||
@@ -53,7 +53,13 @@ impl Vim {
|
||||
for selection in &display_selections {
|
||||
let range = match &target {
|
||||
SurroundsType::Object(object, around) => {
|
||||
object.range(&display_map, selection.clone(), *around, None)
|
||||
// TODO!: Should `SurroundsType::Object` be updated to also leverage `ObjectScope`?
|
||||
let scope = match around {
|
||||
true => ObjectScope::Around,
|
||||
false => ObjectScope::Inside,
|
||||
};
|
||||
|
||||
object.range(&display_map, selection.clone(), &scope, None)
|
||||
}
|
||||
SurroundsType::Motion(motion) => {
|
||||
motion
|
||||
@@ -152,8 +158,9 @@ impl Vim {
|
||||
|
||||
for selection in &display_selections {
|
||||
let start = selection.start.to_offset(&display_map, Bias::Left);
|
||||
let scope = ObjectScope::Around;
|
||||
if let Some(range) =
|
||||
pair_object.range(&display_map, selection.clone(), true, None)
|
||||
pair_object.range(&display_map, selection.clone(), &scope, None)
|
||||
{
|
||||
// If the current parenthesis object is single-line,
|
||||
// then we need to filter whether it is the current line or not
|
||||
@@ -265,8 +272,9 @@ impl Vim {
|
||||
|
||||
for selection in &selections {
|
||||
let start = selection.start.to_offset(&display_map, Bias::Left);
|
||||
let scope = ObjectScope::Around;
|
||||
if let Some(range) =
|
||||
target.range(&display_map, selection.clone(), true, None)
|
||||
target.range(&display_map, selection.clone(), &scope, None)
|
||||
{
|
||||
if !target.is_multiline() {
|
||||
let is_same_row = selection.start.row() == range.start.row()
|
||||
@@ -391,8 +399,9 @@ impl Vim {
|
||||
|
||||
for selection in &selections {
|
||||
let start = selection.start.to_offset(&display_map, Bias::Left);
|
||||
let scope = ObjectScope::Around;
|
||||
if let Some(range) =
|
||||
object.range(&display_map, selection.clone(), true, None)
|
||||
object.range(&display_map, selection.clone(), &scope, None)
|
||||
{
|
||||
// If the current parenthesis object is single-line,
|
||||
// then we need to filter whether it is the current line or not
|
||||
@@ -533,7 +542,7 @@ impl Vim {
|
||||
if let Some(range) = surrounding_markers(
|
||||
&display_map,
|
||||
relative_to,
|
||||
true,
|
||||
&ObjectScope::Around,
|
||||
false,
|
||||
open,
|
||||
close,
|
||||
|
||||
@@ -42,11 +42,12 @@ use serde::Deserialize;
|
||||
pub use settings::{
|
||||
ModeContent, Settings, SettingsStore, UseSystemClipboard, update_settings_file,
|
||||
};
|
||||
use state::{Mode, Operator, RecordedSelection, SearchState, VimGlobals};
|
||||
use state::{Mode, ObjectScope, Operator, RecordedSelection, SearchState, VimGlobals};
|
||||
use std::{mem, ops::Range, sync::Arc};
|
||||
use surrounds::SurroundsType;
|
||||
use theme::ThemeSettings;
|
||||
use ui::{IntoElement, SharedString, px};
|
||||
use util::serde::default_true;
|
||||
use vim_mode_setting::HelixModeSetting;
|
||||
use vim_mode_setting::VimModeSetting;
|
||||
use workspace::{self, Pane, Workspace};
|
||||
@@ -71,6 +72,8 @@ struct SelectRegister(String);
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct PushObject {
|
||||
around: bool,
|
||||
#[serde(default = "default_true")]
|
||||
whitespace: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)]
|
||||
@@ -659,13 +662,8 @@ impl Vim {
|
||||
Vim::globals(cx).forced_motion = true;
|
||||
});
|
||||
Vim::action(editor, cx, |vim, action: &PushObject, window, cx| {
|
||||
vim.push_operator(
|
||||
Operator::Object {
|
||||
around: action.around,
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
let scope = ObjectScope::from_action(action);
|
||||
vim.push_operator(Operator::Object { scope }, window, cx)
|
||||
});
|
||||
|
||||
Vim::action(editor, cx, |vim, action: &PushFindForward, window, cx| {
|
||||
|
||||
@@ -426,10 +426,10 @@ impl Vim {
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Vim>,
|
||||
) {
|
||||
if let Some(Operator::Object { around }) = self.active_operator() {
|
||||
if let Some(Operator::Object { scope }) = self.active_operator() {
|
||||
self.pop_operator(window, cx);
|
||||
let current_mode = self.mode;
|
||||
let target_mode = object.target_visual_mode(current_mode, around);
|
||||
let target_mode = object.target_visual_mode(current_mode, &scope);
|
||||
if target_mode != current_mode {
|
||||
self.switch_mode(target_mode, true, window, cx);
|
||||
}
|
||||
@@ -453,7 +453,7 @@ impl Vim {
|
||||
|
||||
let original_point = selection.tail().to_point(map);
|
||||
|
||||
if let Some(range) = object.range(map, mut_selection, around, count) {
|
||||
if let Some(range) = object.range(map, mut_selection, &scope, count) {
|
||||
if !range.is_empty() {
|
||||
let expand_both_ways = object.always_expands_both_ways()
|
||||
|| selection.is_empty()
|
||||
@@ -465,7 +465,7 @@ impl Vim {
|
||||
&& object.always_expands_both_ways()
|
||||
{
|
||||
if let Some(range) =
|
||||
object.range(map, selection.clone(), around, count)
|
||||
object.range(map, selection.clone(), &scope, count)
|
||||
{
|
||||
selection.start = range.start;
|
||||
selection.end = range.end;
|
||||
|
||||
Reference in New Issue
Block a user