Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/app/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,9 @@ pub enum Action {
EndLine,
MoveNext,
MovePrev,
MoveToWord,
MoveToPrevWordEnd,
MoveToStart,
MoveToEnd,
Quit,
}
122 changes: 122 additions & 0 deletions src/editor/movement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,128 @@ pub fn move_toprev(buffer: &mut Buffer) {
}
}

pub fn move_to_next_word(buffer: &mut Buffer) {
if buffer.lines.is_empty() {
return;
}

if buffer.column >= buffer.lines.len() {
return;
}

let mut col = buffer.column;
let mut pos = buffer.row;

while col < buffer.lines.len() {
let line: Vec<char> = buffer.lines[col].chars().collect();

if line.is_empty() || pos >= line.len() {
col += 1;
pos = 0;
continue;
}

if char_type(line[pos]) == CharType::Word {
let mut end = pos;

while end + 1 < line.len() && char_type(line[end + 1]) == CharType::Word {
end += 1;
}

if end > pos {
buffer.column = col;
buffer.row = end;
return;
}

pos += 1;
}

while pos < line.len() && char_type(line[pos]) != CharType::Word {
pos += 1;
}

if pos < line.len() {
while pos + 1 < line.len() && char_type(line[pos + 1]) == CharType::Word {
pos += 1;
}

buffer.column = col;
buffer.row = pos;
return;
}

col += 1;
pos = 0;
}
}

pub fn moveto_prev_word_end(buffer: &mut Buffer) {
if buffer.lines.is_empty() || buffer.column >= buffer.lines.len() {
return;
}

let original_row = buffer.row;
let original_col = buffer.column;

let mut col = original_col;
let mut pos = original_row;

let current_line: Vec<char> = buffer.lines[col].chars().collect();

if pos < current_line.len() && char_type(current_line[pos]) == CharType::Word {
while pos > 0 && char_type(current_line[pos - 1]) == CharType::Word {
pos -= 1;
}
}

loop {
if pos == 0 {
if col == 0 {
break;
}

col -= 1;

let line: Vec<char> = buffer.lines[col].chars().collect();
pos = line.len();

if pos == 0 {
continue;
}
}

let line: Vec<char> = buffer.lines[col].chars().collect();

while pos > 0 && char_type(line[pos - 1]) != CharType::Word {
pos -= 1;
}

if pos > 0 {
buffer.column = col;
buffer.row = pos - 1;
return;
}
}

buffer.column = original_col;
buffer.row = original_row;
}

pub fn move_to_start(buffer: &mut Buffer) {
buffer.row = 0;
buffer.column = 0;
}

pub fn move_to_end(buffer: &mut Buffer) {
if buffer.lines.is_empty() {
return;
} else {
buffer.row = 0;
buffer.column = buffer.lines.len().saturating_sub(1);
}
}

fn char_type(c: char) -> CharType {
if c.is_whitespace() {
CharType::Whitespace
Expand Down
107 changes: 58 additions & 49 deletions src/input/keyboard.rs
Original file line number Diff line number Diff line change
@@ -1,73 +1,82 @@
use crate::app::actions::{Action};
use crate::app::actions::Action;
use crate::app::mode::Mode;

use crossterm::{
event::{KeyCode, KeyEvent},
};


use crossterm::event::{KeyCode, KeyEvent};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PendingKey {
None,
Space
Space,
G,
}

pub fn keybinding(key: KeyEvent, mode: &Mode, pending_key: &mut PendingKey) -> Option<Action> {
match mode {
Mode::Normal => {
match key.code {
KeyCode::Char('h') => Some(Action::MoveLeft),
KeyCode::Char('l') => Some(Action::MoveRight),
KeyCode::Char('j') => Some(Action::MoveDown),
KeyCode::Char('k') => Some(Action::MoveUp),
KeyCode::Char('a') => Some(Action::InsertForward),
KeyCode::Char('i') => Some(Action::InserBackward),
KeyCode::Char(':') => Some(Action::SetCommand),
KeyCode::Char('0') => Some(Action::StartLine),
KeyCode::Char('$') => Some(Action::EndLine),
KeyCode::Char('w') => Some(Action::MoveNext),
KeyCode::Char('b') => Some(Action::MovePrev),
KeyCode::Char(' ') => {
*pending_key = PendingKey::Space;
None
}
KeyCode::Char('e') if *pending_key == PendingKey::Space => {
if *pending_key != PendingKey::None {
let pending = *pending_key;
*pending_key = PendingKey::None;
Some(Action::SetExplorer)

match (pending, key.code) {
(PendingKey::G, KeyCode::Char('e')) => {
return Some(Action::MoveToPrevWordEnd);
}
(PendingKey::G, KeyCode::Char('g')) => {
return Some(Action::MoveToStart);
}
(PendingKey::Space, KeyCode::Char('e')) => {
return Some(Action::SetExplorer);
}
_ => {}
}
}
_ => None,
}
}
Mode::Insert => {
match key.code {
KeyCode::Esc => Some(Action::SetNormal),
KeyCode::Char(c) => Some(Action::InsertChar(c)),
KeyCode::Backspace => Some(Action::RemoveChar),
KeyCode::Enter => Some(Action::InserNewLine),
_ => None
KeyCode::Char('h') => Some(Action::MoveLeft),
KeyCode::Char('l') => Some(Action::MoveRight),
KeyCode::Char('j') => Some(Action::MoveDown),
KeyCode::Char('k') => Some(Action::MoveUp),
KeyCode::Char('a') => Some(Action::InsertForward),
KeyCode::Char('i') => Some(Action::InserBackward),
KeyCode::Char(':') => Some(Action::SetCommand),
KeyCode::Char('0') => Some(Action::StartLine),
KeyCode::Char('$') => Some(Action::EndLine),
KeyCode::Char('w') => Some(Action::MoveNext),
KeyCode::Char('b') => Some(Action::MovePrev),
KeyCode::Char('e') => Some(Action::MoveToWord),
KeyCode::Char('G') => Some(Action::MoveToEnd),
KeyCode::Char(' ') => {
*pending_key = PendingKey::Space;
None
}
KeyCode::Char('g') => {
*pending_key = PendingKey::G;
None
},
_ => None,
}
}
Mode::Command => {
match key.code {
KeyCode::Esc => Some(Action::EscCommand),
KeyCode::Char(char) => Some(Action::InsertChar(char)),
KeyCode::Backspace => Some(Action::RemoveChar),
KeyCode::Enter => Some(Action::SendCommand),
_ => None
}
}
Mode::Explorer => {
match key.code {
Mode::Insert => match key.code {
KeyCode::Esc => Some(Action::SetNormal),
KeyCode::Char(c) => Some(Action::InsertChar(c)),
KeyCode::Backspace => Some(Action::RemoveChar),
KeyCode::Enter => Some(Action::InserNewLine),
_ => None,
},
Mode::Command => match key.code {
KeyCode::Esc => Some(Action::EscCommand),
KeyCode::Char(char) => Some(Action::InsertChar(char)),
KeyCode::Backspace => Some(Action::RemoveChar),
KeyCode::Enter => Some(Action::SendCommand),
_ => None,
},
Mode::Explorer => match key.code {
KeyCode::Up => Some(Action::ExplorerUp),
KeyCode::Down => Some(Action::ExplorerDown),
KeyCode::Enter => Some(Action::EnterFile),
KeyCode::Esc => Some(Action::SetNormal),
KeyCode::Char('j') => Some(Action::ExplorerDown),
KeyCode::Char('k') => Some(Action::ExplorerUp),
_ => None
}
}
_ => None,
},
}

}
23 changes: 9 additions & 14 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,14 @@
use std::{io::stdout, path::PathBuf, time::Instant};

use crate::{
Status::Continue,
app::{
Status::Continue, app::{
messages::MessageLevel,
mode::{Mode, set_command, set_normal},
},
commands::{executor, parser},
editor::{
editing::{insert_backward, insert_newline, remove_char},
movement::{
move_down, move_left, move_right, move_toend, move_tonext, move_toprev, move_tostart,
move_up,
}, commands::{executor, parser}, editor::{
editing::{insert_backward, insert_newline, remove_char}, movement::{
move_down, move_left, move_right, move_to_end, move_to_next_word, move_to_start, move_toend, move_tonext, move_toprev, move_tostart, move_up, moveto_prev_word_end,
},
},
explorer::tree::{Explorer, read_dir},
gui::{display::Display, status_bar::send_message},
input::keyboard::{PendingKey, keybinding},
io::save::save,
}, explorer::tree::{Explorer, read_dir}, gui::{display::Display, status_bar::send_message}, input::keyboard::{PendingKey, keybinding}, io::save::save,
};
use crossterm::{
event::{
Expand Down Expand Up @@ -215,9 +206,13 @@ fn manager(
Action::EndLine => move_toend(lines),
Action::MoveNext => move_tonext(lines),
Action::MovePrev => move_toprev(lines),
Action::MoveToPrevWordEnd => moveto_prev_word_end(lines),
Action::SetExplorer => {
return Ok(Status::OpenExplorer);
}
Action::MoveToWord => move_to_next_word(lines),
Action::MoveToStart => move_to_start(lines),
Action::MoveToEnd => move_to_end(lines),
_ => {}
},
Mode::Insert => match first {
Expand Down
Loading