Skip to content

Commit

Permalink
Add multi-cursor support! Find current selection and add cursors on e…
Browse files Browse the repository at this point in the history
…ach occurence, as well as line-wise.
  • Loading branch information
msirringhaus committed Jun 26, 2019
1 parent 1c11099 commit db5488b
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 28 deletions.
6 changes: 3 additions & 3 deletions configs/Default (Linux).sublime-keymap
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@
{ "keys": ["ctrl+u"], "command": "soft_undo" },
{ "keys": ["ctrl+shift+u"], "command": "soft_redo" },

{ "keys": ["shift+delete"], "command": "cut" },
{ "keys": ["ctrl+insert"], "command": "copy" },
{ "keys": ["shift+insert"], "command": "paste" },
//{ "keys": ["shift+delete"], "command": "cut" },
//{ "keys": ["ctrl+insert"], "command": "copy" },
//{ "keys": ["shift+insert"], "command": "paste" },

// These two key bindings should replace the above three if you'd prefer
// the traditional X11 behavior of shift+insert pasting from the primary
Expand Down
17 changes: 14 additions & 3 deletions src/core/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ pub struct AbsoluteMove {
pub extend: bool
}

#[allow(non_camel_case_types)]
#[derive(Debug, Deserialize, Serialize, PartialEq, Clone)]
pub struct ExpandLinesDirection {
pub forward: bool
}

#[derive(Debug, PartialEq, Clone)]
pub enum Command {
/// Close the CommandPrompt.
Expand Down Expand Up @@ -89,10 +95,14 @@ pub enum Command {
OpenPrompt,
/// Insert a character
Insert(char),
// Undo last action
/// Undo last action
Undo,
// Redo last undone action
Redo
/// Redo last undone action
Redo,
/// Find word and set another cursor there
FindUnderExpand,
/// Set a new cursor below or above current position
CursorExpandLines(ExpandLinesDirection),
}

#[derive(Debug)]
Expand Down Expand Up @@ -120,6 +130,7 @@ impl FromStr for Command {

fn from_str(s: &str) -> Result<Command, Self::Err> {
match &s[..] {
"fue" | "find_under_expand" => Ok(Command::FindUnderExpand),
"hide_overlay" => Ok(Command::Cancel),
"s" | "save" => Ok(Command::Save(None)),
"q" | "quit" | "exit" => Ok(Command::Quit),
Expand Down
25 changes: 20 additions & 5 deletions src/core/config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::core::{Command, RelativeMove, AbsoluteMove};
use crate::core::{Command, RelativeMove, AbsoluteMove, ExpandLinesDirection};
use termion::event::{Event, Key};

use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -48,6 +48,11 @@ impl KeybindingConfig {
let cmd : AbsoluteMove = serde_json::from_value(args)?;
Command::AbsoluteMove(cmd)
},
"select_lines" => {
let args = binding.args.ok_or("select_lines binding incomplete! Missing \"args\"")?;
let cmd : ExpandLinesDirection = serde_json::from_value(args)?;
Command::CursorExpandLines(cmd)
}
x => match Command::from_str(x) {
Ok(cmd) => cmd,
// unimplemented command for now
Expand All @@ -62,7 +67,7 @@ impl KeybindingConfig {
keymap.insert(binding, cmd.clone());
found_cmds.push(cmd);
} else {
warn!("Skipping failed binding");
// warn!("Skipping failed binding");
continue;
}
}
Expand Down Expand Up @@ -91,12 +96,22 @@ impl KeybindingConfig {
"delete" => Some(Event::Key(Key::Delete)),
"insert" => Some(Event::Key(Key::Insert)),
"escape" => Some(Event::Key(Key::Esc)),
"ctrl+right" => Some(Event::Unsupported(vec![27, 91, 49, 59, 53, 67])),
"ctrl+left" => Some(Event::Unsupported(vec![27, 91, 49, 59, 53, 68])),
"ctrl+shift+right" => Some(Event::Unsupported(vec![27, 91, 49, 59, 54, 67])),
"ctrl+shift+left" => Some(Event::Unsupported(vec![27, 91, 49, 59, 54, 68])),
"ctrl+shift+up" => Some(Event::Unsupported(vec![27, 91, 49, 59, 54, 65])),
"ctrl+shift+down" => Some(Event::Unsupported(vec![27, 91, 49, 59, 54, 66])),
"alt+shift+up" => Some(Event::Unsupported(vec![27, 91, 49, 59, 52, 65])),
"alt+shift+down" => Some(Event::Unsupported(vec![27, 91, 49, 59, 52, 66])),
// Not yet released
// "shift+tab" => Some(Event::Key(Key::Backtab)),

x if x.starts_with("f") => {
match x[1..].parse::<u8>() {
Ok(val) => Some(Event::Key(Key::F(val))),
Err(_) => {
warn!("Cannot parse {}", x);
// warn!("Cannot parse {}", x);
None
}
}
Expand All @@ -109,7 +124,7 @@ impl KeybindingConfig {
let character;
// start_length + "shift+x".len() || start_length + "x".len()
if x.len() != start_length + 7 && x.len() != start_length + 1 {
warn!("Cannot parse {}. Length is = {}, which is neither {} nor {} ", x, x.len(), start_length + 1, start_length + 7);
// warn!("Cannot parse {}. Length is = {}, which is neither {} nor {} ", x, x.len(), start_length + 1, start_length + 7);
return None
} else {
if x.len() == start_length + 7 {
Expand All @@ -128,7 +143,7 @@ impl KeybindingConfig {
}

x => {
warn!("Completely unknown argument {}", x);
// warn!("Completely unknown argument {}", x);
None
},
}
Expand Down
2 changes: 1 addition & 1 deletion src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod tui;
pub use self::tui::{CoreEvent, Tui, TuiService, TuiServiceBuilder};

mod cmd;
pub use self::cmd::{Command, ParseCommandError, RelativeMove, AbsoluteMove, RelativeMoveDistance, AbsoluteMovePoint};
pub use self::cmd::{Command, ParseCommandError, RelativeMove, AbsoluteMove, RelativeMoveDistance, AbsoluteMovePoint, ExpandLinesDirection};

mod config;
pub use self::config::{KeybindingConfig, Keymap};
2 changes: 1 addition & 1 deletion src/core/tui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ impl Tui {
}
return; },
Command::Quit => { self.exit = true; return; },
Command::Cancel => { self.prompt = None; return; },
Command::Cancel if !self.prompt.is_none() => { self.prompt = None; return; },
_ => {/* Somebody else has to deal with these commands */},
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ extern crate clap;
#[macro_use]
extern crate log;

#[macro_use]
extern crate serde_json;

use log4rs;
use tokio;
use xrl;
Expand Down
12 changes: 5 additions & 7 deletions src/widgets/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,21 +123,20 @@ impl Editor {
pub fn handle_input(&mut self, event: Event) {
// We have to remove and insert again, to beat the borrow-checker
match event {
Event::Key(key) => {
match self.keybindings.keymap.get(&event).cloned() {
Event::Mouse(mouse_event) => self.views.get_mut(&self.current_view).unwrap().handle_mouse_event(mouse_event),
ev => {
match self.keybindings.keymap.get(&ev).cloned() {
Some(cmd) => self.handle_command(cmd),
None => {
if let Some(view) = self.views.get_mut(&self.current_view) {
match key {
Key::Char(c) => view.handle_command(Command::Insert(c)),
match ev {
Event::Key(Key::Char(c)) => view.handle_command(Command::Insert(c)),
k => error!("un-handled key {:?}", k)
}
}
}
}
},
Event::Mouse(mouse_event) => self.views.get_mut(&self.current_view).unwrap().handle_mouse_event(mouse_event),
ev => error!("un-handled event {:?}", ev),
}
}

Expand All @@ -148,7 +147,6 @@ impl Editor {
Command::PrevBuffer => self.prev_buffer(),
Command::Save(view_id) => self.save(view_id),
Command::Open(file) => self.new_view(file),

view_command => {
if let Some(view) = self.views.get_mut(&self.current_view) {
view.handle_command(view_command)
Expand Down
81 changes: 73 additions & 8 deletions src/widgets/view/client.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use futures::Future;
use tokio::spawn;
use xrl;
use serde_json::Value;

use crate::core::{Command, RelativeMoveDistance, AbsoluteMovePoint};

Expand Down Expand Up @@ -28,20 +29,29 @@ impl Client {
Command::Save(_view_id) => { /* Handled by Editor */ },
Command::Open(_file) => { /* Handled by Editor */ },
Command::ToggleLineNumbers => { /* Handled by View */ },
Command::FindUnderExpand => { /* Handled by View */ },
Command::Back => self.back(),
Command::Delete => self.delete(),
Command::Insert('\n') => self.insert_newline(),
Command::Insert('\t') => self.insert_tab(),
Command::Insert(c) => self.insert(c),
Command::Undo => self.undo(),
Command::Redo => self.redo(),
Command::CursorExpandLines(dir) => self.cursor_expand_line(dir.forward),
Command::RelativeMove(x) => {
match x.by {
RelativeMoveDistance::characters => {
if x.forward {
self.right()
self.right(x.extend)
} else {
self.left()
self.left(x.extend)
}
},
RelativeMoveDistance::words | RelativeMoveDistance::word_ends => {
if x.forward {
self.word_right(x.extend)
} else {
self.word_left(x.extend)
}
},
RelativeMoveDistance::pages => {
Expand Down Expand Up @@ -71,6 +81,19 @@ impl Client {
}
}

pub fn find_under_expand_next(&mut self) {
let f = self.inner
.find_next(self.view_id, true, false, xrl::ModifySelection::Add)
.map_err(|_| ());
spawn(f);
}

pub fn find_under_expand(&mut self) {
let f = self.inner.edit_notify(self.view_id, "selection_for_find", Some(json!({"case_sensitive": true})))
.map_err(|_| ());
spawn(f);
}

pub fn undo(&mut self) {
let f = self.inner.undo(self.view_id).map_err(|_| ());
spawn(f);
Expand Down Expand Up @@ -111,14 +134,44 @@ impl Client {
spawn(f);
}

pub fn right(&mut self) {
let f = self.inner.right(self.view_id).map_err(|_| ());
spawn(f);
pub fn right(&mut self, extend: bool) {
if extend {
let f = self.inner.right_sel(self.view_id).map_err(|_| ());
spawn(f);
} else {
let f = self.inner.right(self.view_id).map_err(|_| ());
spawn(f);
}
}

pub fn left(&mut self) {
let f = self.inner.left(self.view_id).map_err(|_| ());
spawn(f);
pub fn left(&mut self, extend: bool) {
if extend {
let f = self.inner.left_sel(self.view_id).map_err(|_| ());
spawn(f);
} else {
let f = self.inner.left(self.view_id).map_err(|_| ());
spawn(f);
}
}

pub fn word_right(&mut self, extend: bool) {
if extend {
let f = self.inner.move_word_right_sel(self.view_id).map_err(|_| ());
spawn(f);
} else {
let f = self.inner.move_word_right(self.view_id).map_err(|_| ());
spawn(f);
}
}

pub fn word_left(&mut self, extend: bool) {
if extend {
let f = self.inner.move_word_left_sel(self.view_id).map_err(|_| ());
spawn(f);
} else {
let f = self.inner.move_word_left(self.view_id).map_err(|_| ());
spawn(f);
}
}

pub fn page_down(&mut self) {
Expand Down Expand Up @@ -168,4 +221,16 @@ impl Client {
let f = self.inner.drag(self.view_id, line, column).map_err(|_| ());
spawn(f);
}

pub fn collapse_selections(&mut self) {
let f = self.inner.collapse_selections(self.view_id).map_err(|_| ());
spawn(f);
}

pub fn cursor_expand_line(&mut self, forward: bool) {
let command = if forward { "add_selection_below" } else { "add_selection_above" };
let f = self.inner.edit_notify(self.view_id, command, None as Option<Value>)
.map_err(|_| ());
spawn(f);
}
}
14 changes: 14 additions & 0 deletions src/widgets/view/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ pub struct View {
file: Option<String>,
client: Client,
cfg: ViewConfig,

search_in_progress: bool
}

impl View {
Expand All @@ -39,6 +41,7 @@ impl View {
cfg: ViewConfig::default(),
client,
file,
search_in_progress: false
}
}

Expand Down Expand Up @@ -145,9 +148,20 @@ impl View {
self.client.drag(line, column);
}

fn find_under_expand(&mut self) {
if self.search_in_progress {
self.client.find_under_expand_next()
} else {
self.search_in_progress = true;
self.client.find_under_expand()
}
}

pub fn handle_command(&mut self, cmd: Command) {
match cmd {
Command::ToggleLineNumbers => self.toggle_line_numbers(),
Command::FindUnderExpand => self.find_under_expand(),
Command::Cancel => { self.search_in_progress = false; self.client.collapse_selections() },
client_command => self.client.handle_command(client_command),
}
}
Expand Down

0 comments on commit db5488b

Please sign in to comment.