WIP line mode operations

This commit is contained in:
Keith Simmons 2022-05-18 11:10:24 -07:00
parent 8044586296
commit d7d17b2148
15 changed files with 166 additions and 30 deletions

View file

@ -18,22 +18,29 @@ fn editor_created(EditorCreated(editor): &EditorCreated, cx: &mut MutableAppCont
}
fn editor_focused(EditorFocused(editor): &EditorFocused, cx: &mut MutableAppContext) {
Vim::update(cx, |state, cx| {
state.active_editor = Some(editor.downgrade());
Vim::update(cx, |vim, cx| {
vim.active_editor = Some(editor.downgrade());
vim.selection_subscription = Some(cx.subscribe(editor, |editor, event, cx| {
if let editor::Event::SelectionsChanged { local: true } = event {
let newest_empty = !editor.read(cx).selections.newest::<usize>(cx).is_empty();
editor_local_selections_changed(newest_empty, cx);
}
}));
if editor.read(cx).mode() != EditorMode::Full {
state.switch_mode(Mode::Insert, cx);
vim.switch_mode(Mode::Insert, cx);
}
});
}
fn editor_blurred(EditorBlurred(editor): &EditorBlurred, cx: &mut MutableAppContext) {
Vim::update(cx, |state, cx| {
if let Some(previous_editor) = state.active_editor.clone() {
Vim::update(cx, |vim, cx| {
if let Some(previous_editor) = vim.active_editor.clone() {
if previous_editor == editor.clone() {
state.active_editor = None;
vim.active_editor = None;
}
}
state.sync_editor_options(cx);
vim.sync_editor_options(cx);
})
}
@ -47,3 +54,11 @@ fn editor_released(EditorReleased(editor): &EditorReleased, cx: &mut MutableAppC
}
});
}
fn editor_local_selections_changed(newest_empty: bool, cx: &mut MutableAppContext) {
Vim::update(cx, |vim, cx| {
if vim.state.mode == Mode::Normal && !newest_empty {
vim.switch_mode(Mode::Visual, cx)
}
})
}

View file

@ -112,6 +112,7 @@ fn motion(motion: Motion, cx: &mut MutableAppContext) {
match Vim::read(cx).state.mode {
Mode::Normal => normal_motion(motion, cx),
Mode::Visual => visual_motion(motion, cx),
Mode::VisualLine => visual_motion(motion, cx),
Mode::Insert => {
// Shouldn't execute a motion in insert mode. Ignoring
}

View file

@ -7,6 +7,7 @@ pub enum Mode {
Normal,
Insert,
Visual,
VisualLine,
}
impl Default for Mode {
@ -36,8 +37,7 @@ pub struct VimState {
impl VimState {
pub fn cursor_shape(&self) -> CursorShape {
match self.mode {
Mode::Normal => CursorShape::Block,
Mode::Visual => CursorShape::Block,
Mode::Normal | Mode::Visual | Mode::VisualLine => CursorShape::Block,
Mode::Insert => CursorShape::Bar,
}
}
@ -53,6 +53,7 @@ impl VimState {
match self.mode {
Mode::Normal => "normal",
Mode::Visual => "visual",
Mode::VisualLine => "visual_line",
Mode::Insert => "insert",
}
.to_string(),

View file

@ -10,7 +10,7 @@ mod visual;
use collections::HashMap;
use editor::{CursorShape, Editor};
use gpui::{impl_actions, MutableAppContext, ViewContext, WeakViewHandle};
use gpui::{impl_actions, MutableAppContext, Subscription, ViewContext, WeakViewHandle};
use serde::Deserialize;
use settings::Settings;
@ -51,6 +51,7 @@ pub fn init(cx: &mut MutableAppContext) {
pub struct Vim {
editors: HashMap<usize, WeakViewHandle<Editor>>,
active_editor: Option<WeakViewHandle<Editor>>,
selection_subscription: Option<Subscription>,
enabled: bool,
state: VimState,

View file

@ -4,11 +4,21 @@ use workspace::Workspace;
use crate::{motion::Motion, state::Mode, Vim};
actions!(vim, [VisualDelete, VisualChange]);
actions!(
vim,
[
VisualDelete,
VisualChange,
VisualLineDelete,
VisualLineChange
]
);
pub fn init(cx: &mut MutableAppContext) {
cx.add_action(change);
cx.add_action(change_line);
cx.add_action(delete);
cx.add_action(delete_line);
}
pub fn visual_motion(motion: Motion, cx: &mut MutableAppContext) {
@ -58,6 +68,22 @@ pub fn change(_: &mut Workspace, _: &VisualChange, cx: &mut ViewContext<Workspac
});
}
pub fn change_line(_: &mut Workspace, _: &VisualChange, cx: &mut ViewContext<Workspace>) {
Vim::update(cx, |vim, cx| {
vim.update_active_editor(cx, |editor, cx| {
editor.set_clip_at_line_ends(false, cx);
editor.change_selections(Some(Autoscroll::Fit), cx, |s| {
s.move_with(|map, selection| {
selection.start = map.prev_line_boundary(selection.start.to_point(map)).1;
selection.end = map.next_line_boundary(selection.end.to_point(map)).1;
});
});
editor.insert("", cx);
});
vim.switch_mode(Mode::Insert, cx);
});
}
pub fn delete(_: &mut Workspace, _: &VisualDelete, cx: &mut ViewContext<Workspace>) {
Vim::update(cx, |vim, cx| {
vim.switch_mode(Mode::Normal, cx);
@ -88,6 +114,43 @@ pub fn delete(_: &mut Workspace, _: &VisualDelete, cx: &mut ViewContext<Workspac
});
}
pub fn delete_line(_: &mut Workspace, _: &VisualChange, cx: &mut ViewContext<Workspace>) {
Vim::update(cx, |vim, cx| {
vim.switch_mode(Mode::Normal, cx);
vim.update_active_editor(cx, |editor, cx| {
editor.set_clip_at_line_ends(false, cx);
editor.change_selections(Some(Autoscroll::Fit), cx, |s| {
s.move_with(|map, selection| {
selection.start = map.prev_line_boundary(selection.start.to_point(map)).1;
if selection.end.row() < map.max_point().row() {
*selection.end.row_mut() += 1;
*selection.end.column_mut() = 0;
// Don't reset the end here
return;
} else if selection.start.row() > 0 {
*selection.start.row_mut() -= 1;
*selection.start.column_mut() = map.line_len(selection.start.row());
}
selection.end = map.next_line_boundary(selection.end.to_point(map)).1;
});
});
editor.insert("", cx);
// Fixup cursor position after the deletion
editor.set_clip_at_line_ends(true, cx);
editor.change_selections(Some(Autoscroll::Fit), cx, |s| {
s.move_with(|map, selection| {
let mut cursor = selection.head();
cursor = map.clip_point(cursor, Bias::Left);
selection.collapse_to(cursor, selection.goal)
});
});
});
});
}
#[cfg(test)]
mod test {
use indoc::indoc;