This commit is contained in:
Blaž Hrastnik 2020-10-16 16:58:26 +09:00
parent 49b4cdb566
commit bc2c652fe8
4 changed files with 68 additions and 36 deletions

View file

@ -10,7 +10,6 @@ pub enum Mode {
Normal,
Insert,
Goto,
Command,
}
/// A state represents the current editor state of a single buffer.

View file

@ -225,7 +225,6 @@ impl Renderer {
Mode::Insert => "INS",
Mode::Normal => "NOR",
Mode::Goto => "GOTO",
Mode::Command => "COM", // command?
};
// statusline
self.surface.set_style(
@ -237,13 +236,15 @@ impl Renderer {
}
pub fn render_prompt(&mut self, prompt: &Prompt) {
use tui::backend::Backend;
// render buffer text
self.surface
.set_string(1, self.size.1 - 1, String::from(":"), self.text_color);
.set_string(1, self.size.1 - 1, &prompt.prompt, self.text_color);
self.surface
.set_string(2, self.size.1 - 1, &prompt.buffer, self.text_color);
.set_string(2, self.size.1 - 1, &prompt.line, self.text_color);
}
pub fn draw(&mut self) {
use tui::backend::Backend;
// TODO: theres probably a better place for this
self.terminal
.backend_mut()
@ -259,7 +260,7 @@ impl Renderer {
mode => write!(stdout, "\x1B[2 q"),
};
let pos = if let Some(prompt) = prompt {
Position::new(self.size.0 as usize, 2 + prompt.cursor_loc)
Position::new(self.size.0 as usize, 2 + prompt.cursor)
} else {
if let Some(path) = view.state.path() {
self.surface.set_string(
@ -303,15 +304,6 @@ impl Application {
Ok(app)
}
pub fn set_prompt(&mut self) {
let commands = |editor: &mut Editor, input: &str| match input {
"q" => editor.should_close = true,
_ => (),
};
let prompt = Prompt::new(|input| None, commands);
self.prompt = Some(prompt);
}
fn render(&mut self) {
let viewport = Rect::new(OFFSET, 0, self.terminal.size.0, self.terminal.size.1 - 2); // - 2 for statusline and prompt
@ -323,6 +315,8 @@ impl Application {
self.terminal.render_prompt(prompt);
}
self.terminal.draw();
// TODO: drop unwrap
self.terminal.render_cursor(
self.editor.view.as_ref().unwrap(),
@ -335,7 +329,6 @@ impl Application {
let mut reader = EventStream::new();
let keymap = keymap::default();
self.set_prompt();
self.render();
loop {
@ -363,6 +356,8 @@ impl Application {
.as_mut()
.unwrap()
.handle_input(event, &mut self.editor);
self.render();
} else if let Some(view) = &mut self.editor.view {
let keys = vec![event];
// TODO: sequences (`gg`)
@ -380,7 +375,31 @@ impl Application {
}
view.ensure_cursor_in_view();
}
Mode::Command => unreachable!(),
Mode::Normal => {
if let &[KeyEvent {
code: KeyCode::Char(':'),
..
}] = keys.as_slice()
{
let prompt = Prompt::new(
":".to_owned(),
|_input: &str| None, // completion
|editor: &mut Editor, input: &str| match input {
"q" => editor.should_close = true,
_ => (),
},
);
self.prompt = Some(prompt);
// HAXX: special casing for command mode
} else if let Some(command) = keymap[&Mode::Normal].get(&keys) {
command(view, 1);
// TODO: simplistic ensure cursor in view for now
view.ensure_cursor_in_view();
}
}
mode => {
if let Some(command) = keymap[&mode].get(&keys) {
command(view, 1);

View file

@ -307,8 +307,19 @@ pub fn append_mode(view: &mut View, _count: usize) {
})
}
pub fn command_mode(view: &mut View, _count: usize) {
view.state.mode = Mode::Command;
pub fn command_mode(_view: &mut View, _count: usize) {
use crate::Editor;
let prompt = Prompt::new(
":".to_owned(),
|_input: &str| None, // completion
|editor: &mut Editor, input: &str| match input {
"q" => editor.should_close = true,
_ => (),
},
);
// set_prompt(prompt)
}
// TODO: I, A, o and O can share a lot of the primitives.
@ -627,7 +638,7 @@ pub fn unindent(view: &mut View, _count: usize) {
append_changes_to_history(view);
}
pub fn indent_selection(view: &mut View, _count: usize) {
pub fn indent_selection(_view: &mut View, _count: usize) {
// loop over each line and recompute proper indentation
unimplemented!()
}

View file

@ -4,54 +4,57 @@ use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use std::string::String;
pub struct Prompt {
pub buffer: String,
pub cursor_loc: usize,
pub prompt: String,
pub line: String,
pub cursor: usize,
completion_fn: Box<dyn FnMut(&str) -> Option<Vec<&str>>>,
callback_fn: Box<dyn FnMut(&mut Editor, &str)>,
}
impl Prompt {
pub fn new(
prompt: String,
completion_fn: impl FnMut(&str) -> Option<Vec<&str>> + 'static,
callback_fn: impl FnMut(&mut Editor, &str) + 'static,
) -> Prompt {
Prompt {
buffer: String::from(""),
cursor_loc: 0,
prompt,
line: String::new(),
cursor: 0,
completion_fn: Box::new(completion_fn),
callback_fn: Box::new(callback_fn),
}
}
pub fn insert_char(&mut self, c: char) {
self.buffer.insert(self.cursor_loc, c);
self.cursor_loc += 1;
self.line.insert(self.cursor, c);
self.cursor += 1;
}
pub fn move_char_left(&mut self) {
if self.cursor_loc > 1 {
self.cursor_loc -= 1;
if self.cursor > 1 {
self.cursor -= 1;
}
}
pub fn move_char_right(&mut self) {
if self.cursor_loc < self.buffer.len() {
self.cursor_loc += 1;
if self.cursor < self.line.len() {
self.cursor += 1;
}
}
pub fn move_start(&mut self) {
self.cursor_loc = 0;
self.cursor = 0;
}
pub fn move_end(&mut self) {
self.cursor_loc = self.buffer.len();
self.cursor = self.line.len();
}
pub fn delete_char_backwards(&mut self) {
if self.cursor_loc > 0 {
self.buffer.remove(self.cursor_loc - 1);
self.cursor_loc -= 1;
if self.cursor > 0 {
self.line.remove(self.cursor - 1);
self.cursor -= 1;
}
}
@ -87,7 +90,7 @@ impl Prompt {
KeyEvent {
code: KeyCode::Enter,
..
} => (self.callback_fn)(editor, &self.buffer),
} => (self.callback_fn)(editor, &self.line),
_ => (),
}
}