forked from mars/breed
Compare commits
8 Commits
5c3a21e35e
...
64249e0f67
Author | SHA1 | Date |
---|---|---|
Emma Tebibyte | 64249e0f67 | |
mars | d68a719a90 | |
mars | da33dcce1d | |
mars | 1496a39a1a | |
mars | 7f46721caf | |
mars | c03991f110 | |
mars | 3020d14081 | |
mars | 9f6eecfa26 |
|
@ -50,7 +50,12 @@ impl Default for Keybinds {
|
|||
(End, goto_line_end_newline),
|
||||
];
|
||||
|
||||
let normalish_keys = &[
|
||||
let goto_keys = &[
|
||||
(Char('h'), goto_line_start as Action),
|
||||
(Char('l'), goto_line_end_newline),
|
||||
];
|
||||
|
||||
let normalish_keys = [
|
||||
(Char(':'), command_mode as Action),
|
||||
(Char('h'), move_char_left),
|
||||
(Char('j'), move_line_down),
|
||||
|
@ -68,7 +73,10 @@ impl Default for Keybinds {
|
|||
.iter()
|
||||
.chain(basic_nav);
|
||||
|
||||
let insert_keys = &[
|
||||
let normalish_submodes: HashMap<Key, KeyMap> =
|
||||
[(Char('g'), key_map_from_iter(goto_keys))].into();
|
||||
|
||||
let insert_keys = [
|
||||
(Backspace, delete_char_backward as Action),
|
||||
(Delete, delete_char_forward),
|
||||
(Enter, insert_newline),
|
||||
|
@ -77,34 +85,28 @@ impl Default for Keybinds {
|
|||
.chain(basic_nav);
|
||||
|
||||
Self {
|
||||
normal: normalish_keys.clone().into(),
|
||||
insert: insert_keys.clone().into(),
|
||||
visual: normalish_keys.clone().into(),
|
||||
normal: ModeKeys {
|
||||
submodes: normalish_submodes.clone(),
|
||||
map: key_map_from_iter(normalish_keys.clone()),
|
||||
},
|
||||
insert: ModeKeys {
|
||||
submodes: [].into(),
|
||||
map: key_map_from_iter(insert_keys),
|
||||
},
|
||||
visual: ModeKeys {
|
||||
submodes: normalish_submodes,
|
||||
map: key_map_from_iter(normalish_keys.clone()),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct ModeKeys {
|
||||
pub minor_modes: HashMap<Key, KeyMap>,
|
||||
pub submodes: HashMap<Key, KeyMap>,
|
||||
pub map: KeyMap,
|
||||
}
|
||||
|
||||
impl<'a, T> From<T> for ModeKeys
|
||||
where
|
||||
T: IntoIterator<Item = &'a (Key, Action)>,
|
||||
{
|
||||
fn from(iter: T) -> Self {
|
||||
let minor_modes = HashMap::new();
|
||||
let mut map = KeyMap::new();
|
||||
for (key, action) in iter {
|
||||
map.insert(*key, Keybind::Action(*action));
|
||||
}
|
||||
|
||||
Self { minor_modes, map }
|
||||
}
|
||||
}
|
||||
|
||||
impl ModeKeys {
|
||||
pub fn apply_table(values: Table) -> Result<Self, String> {
|
||||
let mut keys = Self::default();
|
||||
|
@ -114,7 +116,7 @@ impl ModeKeys {
|
|||
match value {
|
||||
Value::Table(table) => {
|
||||
let map = parse_key_map(table)?;
|
||||
keys.minor_modes.insert(key, map);
|
||||
keys.submodes.insert(key, map);
|
||||
}
|
||||
Value::String(keybind) => {
|
||||
let bind = Keybind::try_from(keybind.as_str())?;
|
||||
|
@ -162,6 +164,18 @@ impl TryFrom<&str> for Keybind {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn key_map_from_iter<'a, T>(iter: T) -> KeyMap
|
||||
where
|
||||
T: IntoIterator<Item = &'a (Key, Action)>,
|
||||
{
|
||||
let mut map = KeyMap::new();
|
||||
for (key, action) in iter {
|
||||
map.insert(*key, Keybind::Action(*action));
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
pub fn parse_key_map(values: Table) -> Result<KeyMap, String> {
|
||||
let mut map = KeyMap::with_capacity(values.len());
|
||||
|
||||
|
|
67
src/main.rs
67
src/main.rs
|
@ -33,7 +33,6 @@ use crossterm::{
|
|||
event::{Event, KeyCode, KeyEvent},
|
||||
terminal, QueueableCommand, Result,
|
||||
};
|
||||
use keybinds::Keybind;
|
||||
use parking_lot::Mutex;
|
||||
use ropey::Rope;
|
||||
use yacexits::{exit, EX_DATAERR, EX_UNAVAILABLE};
|
||||
|
@ -46,6 +45,7 @@ mod theme;
|
|||
|
||||
use buffer::Buffer;
|
||||
use config::Config;
|
||||
use keybinds::{Key, Keybind};
|
||||
use theme::StyleStore;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
|
@ -111,6 +111,7 @@ pub struct State {
|
|||
pub cursor: Cursor,
|
||||
pub file: Option<OsString>,
|
||||
pub mode: Mode,
|
||||
pub submode: Option<Key>,
|
||||
pub last_saved: Rope,
|
||||
pub scroll: Cursor,
|
||||
pub size: (usize, usize),
|
||||
|
@ -133,6 +134,7 @@ impl State {
|
|||
cursor: Cursor::default(),
|
||||
file: file_name,
|
||||
mode: Mode::default(),
|
||||
submode: None,
|
||||
last_saved,
|
||||
scroll: Cursor::default(),
|
||||
size: (cols as usize, rows as usize),
|
||||
|
@ -179,6 +181,12 @@ impl State {
|
|||
.buffer
|
||||
.draw(cols, buffer_rows, self.scroll, self.cursor, out)?;
|
||||
|
||||
// draw submode
|
||||
if let Some(submode) = self.submode {
|
||||
out.queue(cursor::MoveTo(cols - 10, rows - 1))?;
|
||||
write!(out, "{:?}", submode)?;
|
||||
}
|
||||
|
||||
// draw cursor
|
||||
let cursor_pos = set_cursor_pos.unwrap_or_else(|| {
|
||||
// calculate cursor position on buffer
|
||||
|
@ -222,9 +230,7 @@ impl State {
|
|||
|
||||
match event {
|
||||
Event::Key(KeyEvent { code, .. }) => {
|
||||
if let Some(keybind) = self.config.keybinds.visual.map.get(&code) {
|
||||
self.execute_keybind(keybind.clone());
|
||||
}
|
||||
self.on_key(code);
|
||||
}
|
||||
event => self.on_any_event(event),
|
||||
}
|
||||
|
@ -274,9 +280,7 @@ impl State {
|
|||
fn on_visual_event(&mut self, event: Event) {
|
||||
match event {
|
||||
Event::Key(KeyEvent { code, .. }) => {
|
||||
if let Some(keybind) = self.config.keybinds.visual.map.get(&code) {
|
||||
self.execute_keybind(keybind.clone());
|
||||
}
|
||||
self.on_key(code);
|
||||
}
|
||||
event => self.on_any_event(event),
|
||||
}
|
||||
|
@ -284,19 +288,53 @@ impl State {
|
|||
|
||||
fn on_insert_event(&mut self, event: Event, _state: InsertState) {
|
||||
match event {
|
||||
Event::Key(KeyEvent { code, .. }) => match self.config.keybinds.insert.map.get(&code) {
|
||||
Some(keybind) => self.execute_keybind(keybind.clone()),
|
||||
None => {
|
||||
Event::Key(KeyEvent { code, .. }) => {
|
||||
if !self.on_key(code) {
|
||||
if let KeyCode::Char(c) = code {
|
||||
self.buffer.insert_char(self.cursor, c);
|
||||
self.move_cursor(Direction::Right);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
event => self.on_any_event(event),
|
||||
}
|
||||
}
|
||||
|
||||
/// Processes a key press event.
|
||||
///
|
||||
/// Returns `true` if the key was handled by a keybind, `false` otherwise.
|
||||
fn on_key(&mut self, key: Key) -> bool {
|
||||
let keybinds = match &self.mode {
|
||||
Mode::Normal(_) => &self.config.keybinds.normal,
|
||||
Mode::Insert(_) => &self.config.keybinds.insert,
|
||||
Mode::Visual => &self.config.keybinds.visual,
|
||||
Mode::Command(_) => return false, // command mode is handled in [on_command_event]
|
||||
};
|
||||
|
||||
if let Some(submode) = self.submode {
|
||||
// if we're currently in a submode, try to run this submode's keybind
|
||||
keybinds
|
||||
.submodes
|
||||
.get(&submode)
|
||||
.and_then(|submode| submode.get(&key))
|
||||
.cloned()
|
||||
.map(|keybind| self.execute_keybind(keybind));
|
||||
// whether or not there is a keybind we exit the submode
|
||||
self.submode = None;
|
||||
} else if keybinds.submodes.contains_key(&key) {
|
||||
// enter a submode if available
|
||||
self.submode = Some(key);
|
||||
} else if let Some(keybind) = keybinds.map.get(&key) {
|
||||
// run the keybind if available
|
||||
self.execute_keybind(keybind.clone());
|
||||
} else {
|
||||
// key is not bound; don't handle
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn on_any_event(&mut self, event: Event) {
|
||||
match event {
|
||||
Event::Resize(cols, rows) => {
|
||||
|
@ -434,12 +472,12 @@ fn main() -> Result<()> {
|
|||
if unsafe { libc::isatty(stdin) } == 0 {
|
||||
unsafe { File::from_raw_fd(stdin) }
|
||||
} else {
|
||||
File::open("/dev/null").unwrap()
|
||||
File::open("/dev/null")?
|
||||
}
|
||||
}
|
||||
Some(path) => {
|
||||
let input_file = Path::new(path);
|
||||
file_name = Some(OsString::from(input_file.clone().display().to_string()));
|
||||
file_name = Some(OsString::from(&path));
|
||||
|
||||
File::open(input_file).unwrap_or_else(|_| {
|
||||
let mut err = String::new();
|
||||
|
@ -453,8 +491,7 @@ fn main() -> Result<()> {
|
|||
})
|
||||
}
|
||||
}
|
||||
.read_to_end(&mut buf)
|
||||
.unwrap();
|
||||
.read_to_end(&mut buf)?;
|
||||
|
||||
let text = String::from_utf8(buf).unwrap_or_else(|_| {
|
||||
eprintln!(
|
||||
|
|
Reference in New Issue