More vim fixes and move some more things out of app.rs
This commit is contained in:
parent
c1812ddc27
commit
3d53336916
19 changed files with 595 additions and 473 deletions
|
@ -1,4 +1,4 @@
|
|||
use editor::{EditorBlurred, EditorFocused, EditorMode, EditorReleased};
|
||||
use editor::{EditorBlurred, EditorFocused, EditorMode, EditorReleased, Event};
|
||||
use gpui::MutableAppContext;
|
||||
|
||||
use crate::{state::Mode, Vim};
|
||||
|
@ -20,14 +20,18 @@ fn focused(EditorFocused(editor): &EditorFocused, cx: &mut MutableAppContext) {
|
|||
}
|
||||
|
||||
vim.active_editor = Some(editor.downgrade());
|
||||
dbg!("Active editor changed", editor.read(cx).mode());
|
||||
vim.editor_subscription = Some(cx.subscribe(editor, |editor, event, cx| {
|
||||
if editor.read(cx).leader_replica_id().is_none() {
|
||||
if let editor::Event::SelectionsChanged { local: true } = event {
|
||||
let newest_empty = editor.read(cx).selections.newest::<usize>(cx).is_empty();
|
||||
vim.editor_subscription = Some(cx.subscribe(editor, |editor, event, cx| match event {
|
||||
Event::SelectionsChanged { local: true } => {
|
||||
let editor = editor.read(cx);
|
||||
if editor.leader_replica_id().is_none() {
|
||||
let newest_empty = editor.selections.newest::<usize>(cx).is_empty();
|
||||
local_selections_changed(newest_empty, cx);
|
||||
}
|
||||
}
|
||||
Event::InputIgnored { text } => {
|
||||
Vim::active_editor_input_ignored(text.clone(), cx);
|
||||
}
|
||||
_ => {}
|
||||
}));
|
||||
|
||||
if vim.enabled {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use editor::{
|
||||
char_kind,
|
||||
display_map::{DisplaySnapshot, ToDisplayPoint},
|
||||
|
@ -15,7 +17,7 @@ use crate::{
|
|||
Vim,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Motion {
|
||||
Left,
|
||||
Backspace,
|
||||
|
@ -32,8 +34,8 @@ pub enum Motion {
|
|||
StartOfDocument,
|
||||
EndOfDocument,
|
||||
Matching,
|
||||
FindForward { before: bool, character: char },
|
||||
FindBackward { after: bool, character: char },
|
||||
FindForward { before: bool, text: Arc<str> },
|
||||
FindBackward { after: bool, text: Arc<str> },
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, PartialEq)]
|
||||
|
@ -134,7 +136,7 @@ pub(crate) fn motion(motion: Motion, cx: &mut MutableAppContext) {
|
|||
// Motion handling is specified here:
|
||||
// https://github.com/vim/vim/blob/master/runtime/doc/motion.txt
|
||||
impl Motion {
|
||||
pub fn linewise(self) -> bool {
|
||||
pub fn linewise(&self) -> bool {
|
||||
use Motion::*;
|
||||
matches!(
|
||||
self,
|
||||
|
@ -142,12 +144,12 @@ impl Motion {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn infallible(self) -> bool {
|
||||
pub fn infallible(&self) -> bool {
|
||||
use Motion::*;
|
||||
matches!(self, StartOfDocument | CurrentLine | EndOfDocument)
|
||||
}
|
||||
|
||||
pub fn inclusive(self) -> bool {
|
||||
pub fn inclusive(&self) -> bool {
|
||||
use Motion::*;
|
||||
match self {
|
||||
Down
|
||||
|
@ -171,13 +173,14 @@ impl Motion {
|
|||
}
|
||||
|
||||
pub fn move_point(
|
||||
self,
|
||||
&self,
|
||||
map: &DisplaySnapshot,
|
||||
point: DisplayPoint,
|
||||
goal: SelectionGoal,
|
||||
times: usize,
|
||||
) -> Option<(DisplayPoint, SelectionGoal)> {
|
||||
use Motion::*;
|
||||
let infallible = self.infallible();
|
||||
let (new_point, goal) = match self {
|
||||
Left => (left(map, point, times), SelectionGoal::None),
|
||||
Backspace => (backspace(map, point, times), SelectionGoal::None),
|
||||
|
@ -185,15 +188,15 @@ impl Motion {
|
|||
Up => up(map, point, goal, times),
|
||||
Right => (right(map, point, times), SelectionGoal::None),
|
||||
NextWordStart { ignore_punctuation } => (
|
||||
next_word_start(map, point, ignore_punctuation, times),
|
||||
next_word_start(map, point, *ignore_punctuation, times),
|
||||
SelectionGoal::None,
|
||||
),
|
||||
NextWordEnd { ignore_punctuation } => (
|
||||
next_word_end(map, point, ignore_punctuation, times),
|
||||
next_word_end(map, point, *ignore_punctuation, times),
|
||||
SelectionGoal::None,
|
||||
),
|
||||
PreviousWordStart { ignore_punctuation } => (
|
||||
previous_word_start(map, point, ignore_punctuation, times),
|
||||
previous_word_start(map, point, *ignore_punctuation, times),
|
||||
SelectionGoal::None,
|
||||
),
|
||||
FirstNonWhitespace => (first_non_whitespace(map, point), SelectionGoal::None),
|
||||
|
@ -203,22 +206,22 @@ impl Motion {
|
|||
StartOfDocument => (start_of_document(map, point, times), SelectionGoal::None),
|
||||
EndOfDocument => (end_of_document(map, point, times), SelectionGoal::None),
|
||||
Matching => (matching(map, point), SelectionGoal::None),
|
||||
FindForward { before, character } => (
|
||||
find_forward(map, point, before, character, times),
|
||||
FindForward { before, text } => (
|
||||
find_forward(map, point, *before, text.clone(), times),
|
||||
SelectionGoal::None,
|
||||
),
|
||||
FindBackward { after, character } => (
|
||||
find_backward(map, point, after, character, times),
|
||||
FindBackward { after, text } => (
|
||||
find_backward(map, point, *after, text.clone(), times),
|
||||
SelectionGoal::None,
|
||||
),
|
||||
};
|
||||
|
||||
(new_point != point || self.infallible()).then_some((new_point, goal))
|
||||
(new_point != point || infallible).then_some((new_point, goal))
|
||||
}
|
||||
|
||||
// Expands a selection using self motion for an operator
|
||||
pub fn expand_selection(
|
||||
self,
|
||||
&self,
|
||||
map: &DisplaySnapshot,
|
||||
selection: &mut Selection<DisplayPoint>,
|
||||
times: usize,
|
||||
|
@ -254,7 +257,7 @@ impl Motion {
|
|||
// but "d}" will not include that line.
|
||||
let mut inclusive = self.inclusive();
|
||||
if !inclusive
|
||||
&& self != Motion::Backspace
|
||||
&& self != &Motion::Backspace
|
||||
&& selection.end.row() > selection.start.row()
|
||||
&& selection.end.column() == 0
|
||||
{
|
||||
|
@ -466,45 +469,42 @@ fn find_forward(
|
|||
map: &DisplaySnapshot,
|
||||
from: DisplayPoint,
|
||||
before: bool,
|
||||
target: char,
|
||||
mut times: usize,
|
||||
target: Arc<str>,
|
||||
times: usize,
|
||||
) -> DisplayPoint {
|
||||
let mut previous_point = from;
|
||||
|
||||
for (ch, point) in map.chars_at(from) {
|
||||
if ch == target && point != from {
|
||||
times -= 1;
|
||||
if times == 0 {
|
||||
return if before { previous_point } else { point };
|
||||
map.find_while(from, target.as_ref(), |ch, _| ch != '\n')
|
||||
.skip_while(|found_at| found_at == &from)
|
||||
.nth(times - 1)
|
||||
.map(|mut found| {
|
||||
if before {
|
||||
*found.column_mut() -= 1;
|
||||
found = map.clip_point(found, Bias::Right);
|
||||
found
|
||||
} else {
|
||||
found
|
||||
}
|
||||
} else if ch == '\n' {
|
||||
break;
|
||||
}
|
||||
previous_point = point;
|
||||
}
|
||||
|
||||
from
|
||||
})
|
||||
.unwrap_or(from)
|
||||
}
|
||||
|
||||
fn find_backward(
|
||||
map: &DisplaySnapshot,
|
||||
from: DisplayPoint,
|
||||
after: bool,
|
||||
target: char,
|
||||
mut times: usize,
|
||||
target: Arc<str>,
|
||||
times: usize,
|
||||
) -> DisplayPoint {
|
||||
let mut previous_point = from;
|
||||
for (ch, point) in map.reverse_chars_at(from) {
|
||||
if ch == target && point != from {
|
||||
times -= 1;
|
||||
if times == 0 {
|
||||
return if after { previous_point } else { point };
|
||||
map.reverse_find_while(from, target.as_ref(), |ch, _| ch != '\n')
|
||||
.skip_while(|found_at| found_at == &from)
|
||||
.nth(times - 1)
|
||||
.map(|mut found| {
|
||||
if after {
|
||||
*found.column_mut() += 1;
|
||||
found = map.clip_point(found, Bias::Left);
|
||||
found
|
||||
} else {
|
||||
found
|
||||
}
|
||||
} else if ch == '\n' {
|
||||
break;
|
||||
}
|
||||
previous_point = point;
|
||||
}
|
||||
|
||||
from
|
||||
})
|
||||
.unwrap_or(from)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ mod change;
|
|||
mod delete;
|
||||
mod yank;
|
||||
|
||||
use std::{borrow::Cow, cmp::Ordering};
|
||||
use std::{borrow::Cow, cmp::Ordering, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
motion::Motion,
|
||||
|
@ -424,7 +424,7 @@ fn scroll(editor: &mut Editor, amount: &ScrollAmount, cx: &mut ViewContext<Edito
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn normal_replace(text: &str, cx: &mut MutableAppContext) {
|
||||
pub(crate) fn normal_replace(text: Arc<str>, cx: &mut MutableAppContext) {
|
||||
Vim::update(cx, |vim, cx| {
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
editor.transact(cx, |editor, cx| {
|
||||
|
@ -453,7 +453,7 @@ pub(crate) fn normal_replace(text: &str, cx: &mut MutableAppContext) {
|
|||
(
|
||||
range.start.to_offset(&map, Bias::Left)
|
||||
..range.end.to_offset(&map, Bias::Left),
|
||||
text,
|
||||
text.clone(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
|
|
@ -53,7 +53,7 @@ impl<'a> VimTestContext<'a> {
|
|||
|
||||
// Setup search toolbars and keypress hook
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
observe_keypresses(window_id, cx);
|
||||
observe_keystrokes(window_id, cx);
|
||||
workspace.active_pane().update(cx, |pane, cx| {
|
||||
pane.toolbar().update(cx, |toolbar, cx| {
|
||||
let buffer_search_bar = cx.add_view(BufferSearchBar::new);
|
||||
|
|
|
@ -10,12 +10,12 @@ mod state;
|
|||
mod utils;
|
||||
mod visual;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use command_palette::CommandPaletteFilter;
|
||||
use editor::{Bias, Cancel, Editor, EditorMode};
|
||||
use gpui::{
|
||||
impl_actions,
|
||||
keymap_matcher::{KeyPressed, Keystroke},
|
||||
MutableAppContext, Subscription, ViewContext, ViewHandle, WeakViewHandle,
|
||||
impl_actions, MutableAppContext, Subscription, ViewContext, ViewHandle, WeakViewHandle,
|
||||
};
|
||||
use language::CursorShape;
|
||||
use motion::Motion;
|
||||
|
@ -57,11 +57,6 @@ pub fn init(cx: &mut MutableAppContext) {
|
|||
cx.add_action(|_: &mut Workspace, n: &Number, cx: _| {
|
||||
Vim::update(cx, |vim, cx| vim.push_number(n, cx));
|
||||
});
|
||||
cx.add_action(
|
||||
|_: &mut Workspace, KeyPressed { keystroke }: &KeyPressed, cx| {
|
||||
Vim::key_pressed(keystroke, cx);
|
||||
},
|
||||
);
|
||||
|
||||
// Editor Actions
|
||||
cx.add_action(|_: &mut Editor, _: &Cancel, cx| {
|
||||
|
@ -91,7 +86,7 @@ pub fn init(cx: &mut MutableAppContext) {
|
|||
.detach();
|
||||
}
|
||||
|
||||
pub fn observe_keypresses(window_id: usize, cx: &mut MutableAppContext) {
|
||||
pub fn observe_keystrokes(window_id: usize, cx: &mut MutableAppContext) {
|
||||
cx.observe_keystrokes(window_id, |_keystroke, _result, handled_by, cx| {
|
||||
if let Some(handled_by) = handled_by {
|
||||
// Keystroke is handled by the vim system, so continue forward
|
||||
|
@ -103,11 +98,12 @@ pub fn observe_keypresses(window_id: usize, cx: &mut MutableAppContext) {
|
|||
}
|
||||
}
|
||||
|
||||
Vim::update(cx, |vim, cx| {
|
||||
if vim.active_operator().is_some() {
|
||||
// If the keystroke is not handled by vim, we should clear the operator
|
||||
Vim::update(cx, |vim, cx| match vim.active_operator() {
|
||||
Some(Operator::FindForward { .. } | Operator::FindBackward { .. }) => {}
|
||||
Some(_) => {
|
||||
vim.clear_operator(cx);
|
||||
}
|
||||
_ => {}
|
||||
});
|
||||
true
|
||||
})
|
||||
|
@ -164,7 +160,6 @@ impl Vim {
|
|||
.and_then(|editor| editor.upgrade(cx))
|
||||
{
|
||||
editor.update(cx, |editor, cx| {
|
||||
dbg!(&mode, editor.mode());
|
||||
editor.change_selections(None, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
if self.state.empty_selections_only() {
|
||||
|
@ -221,24 +216,24 @@ impl Vim {
|
|||
self.state.operator_stack.last().copied()
|
||||
}
|
||||
|
||||
fn key_pressed(keystroke: &Keystroke, cx: &mut ViewContext<Workspace>) {
|
||||
fn active_editor_input_ignored(text: Arc<str>, cx: &mut MutableAppContext) {
|
||||
if text.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
match Vim::read(cx).active_operator() {
|
||||
Some(Operator::FindForward { before }) => {
|
||||
if let Some(character) = keystroke.key.chars().next() {
|
||||
motion::motion(Motion::FindForward { before, character }, cx)
|
||||
}
|
||||
motion::motion(Motion::FindForward { before, text }, cx)
|
||||
}
|
||||
Some(Operator::FindBackward { after }) => {
|
||||
if let Some(character) = keystroke.key.chars().next() {
|
||||
motion::motion(Motion::FindBackward { after, character }, cx)
|
||||
}
|
||||
motion::motion(Motion::FindBackward { after, text }, cx)
|
||||
}
|
||||
Some(Operator::Replace) => match Vim::read(cx).state.mode {
|
||||
Mode::Normal => normal_replace(&keystroke.key, cx),
|
||||
Mode::Visual { line } => visual_replace(&keystroke.key, line, cx),
|
||||
Mode::Normal => normal_replace(text, cx),
|
||||
Mode::Visual { line } => visual_replace(text, line, cx),
|
||||
_ => Vim::update(cx, |vim, cx| vim.clear_operator(cx)),
|
||||
},
|
||||
_ => cx.propagate_action(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::borrow::Cow;
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
|
||||
use collections::HashMap;
|
||||
use editor::{
|
||||
|
@ -313,7 +313,7 @@ pub fn paste(_: &mut Workspace, _: &VisualPaste, cx: &mut ViewContext<Workspace>
|
|||
});
|
||||
}
|
||||
|
||||
pub(crate) fn visual_replace(text: &str, line: bool, cx: &mut MutableAppContext) {
|
||||
pub(crate) fn visual_replace(text: Arc<str>, line: bool, cx: &mut MutableAppContext) {
|
||||
Vim::update(cx, |vim, cx| {
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
editor.transact(cx, |editor, cx| {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue