boost command typing experience
This commit is contained in:
parent
e0ba4e0661
commit
c2a0942902
|
@ -1,7 +1,10 @@
|
|||
[colortheme]
|
||||
background = [26, 26, 28]
|
||||
command_bar = [20, 28, 20]
|
||||
background = [0x26, 0x26, 0x28]
|
||||
command-bar = [0x20, 0x28, 0x20]
|
||||
cmdbar-prompt = [0x40, 0x40, 0x40]
|
||||
cmdbar-cmdexist = [0x40, 0xff, 0x40]
|
||||
cmdbar-cmdunexist = [0xff, 0x40, 0x40]
|
||||
|
||||
[command]
|
||||
new_window = "n"
|
||||
new-window = "n"
|
||||
quit = "q"
|
||||
|
|
|
@ -15,7 +15,9 @@ use crossterm::{
|
|||
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use crate::{colortheme::ColorTheme, iterate_config, window::Window, Config};
|
||||
use crate::{
|
||||
colortheme::ColorTheme, command::CommandProcessor, iterate_config, window::Window, Config,
|
||||
};
|
||||
|
||||
pub struct Application {
|
||||
config: Config,
|
||||
|
@ -23,10 +25,7 @@ pub struct Application {
|
|||
stdout: Stdout,
|
||||
size: (u16, u16),
|
||||
windows: HashMap<usize, Window>,
|
||||
command_mode: bool,
|
||||
command: String,
|
||||
cmdbar_show: String,
|
||||
cmdbar_prompt: String,
|
||||
cmdprocessor: CommandProcessor,
|
||||
}
|
||||
|
||||
impl Application {
|
||||
|
@ -46,142 +45,84 @@ impl Application {
|
|||
stdout: stdout(),
|
||||
size: terminal::size()?,
|
||||
windows: HashMap::new(),
|
||||
command_mode: true,
|
||||
command: String::new(),
|
||||
cmdbar_show: String::new(),
|
||||
cmdbar_prompt: String::from("New workspace"),
|
||||
cmdprocessor: CommandProcessor::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn exec(&mut self) -> io::Result<()> {
|
||||
self.render()?;
|
||||
self.stdout.flush()?;
|
||||
loop {
|
||||
if event::poll(Duration::from_secs(5))? {
|
||||
match event::read()? {
|
||||
event::Event::FocusGained => queue!(self.stdout, cursor::Show)?,
|
||||
event::Event::FocusLost => queue!(self.stdout, cursor::Hide)?,
|
||||
event::Event::Key(key_event) => {
|
||||
let KeyEvent {
|
||||
code, modifiers, ..
|
||||
} = key_event;
|
||||
match code {
|
||||
event::KeyCode::Backspace => {
|
||||
if self.command_mode {
|
||||
self.command.pop();
|
||||
self.cmdbar_show.clone_from(&self.command);
|
||||
}
|
||||
}
|
||||
event::KeyCode::Enter => {
|
||||
if self.command_mode {
|
||||
self.command.clear();
|
||||
self.cmdbar_show.clear();
|
||||
}
|
||||
}
|
||||
event::KeyCode::Left => (),
|
||||
event::KeyCode::Right => (),
|
||||
event::KeyCode::Up => (),
|
||||
event::KeyCode::Down => (),
|
||||
event::KeyCode::Home => (),
|
||||
event::KeyCode::End => (),
|
||||
event::KeyCode::PageUp => (),
|
||||
event::KeyCode::PageDown => (),
|
||||
event::KeyCode::Tab => (),
|
||||
event::KeyCode::BackTab => (),
|
||||
event::KeyCode::Delete => (),
|
||||
event::KeyCode::Insert => (),
|
||||
event::KeyCode::F(_) => (),
|
||||
event::KeyCode::Char(c) => {
|
||||
if self.command_mode {
|
||||
let mut b = true;
|
||||
if modifiers.contains(KeyModifiers::CONTROL) {
|
||||
self.command += "C-";
|
||||
} else if modifiers.contains(KeyModifiers::ALT) {
|
||||
self.command += "A-";
|
||||
} else {
|
||||
b = false;
|
||||
}
|
||||
self.command.push(c);
|
||||
if b {
|
||||
self.command.push(' ');
|
||||
}
|
||||
self.cmdbar_show.clone_from(&self.command);
|
||||
}
|
||||
}
|
||||
event::KeyCode::Null => (),
|
||||
event::KeyCode::Esc => (),
|
||||
event::KeyCode::CapsLock => (),
|
||||
event::KeyCode::ScrollLock => (),
|
||||
event::KeyCode::NumLock => (),
|
||||
event::KeyCode::PrintScreen => (),
|
||||
event::KeyCode::Pause => (),
|
||||
event::KeyCode::Menu => (),
|
||||
event::KeyCode::KeypadBegin => (),
|
||||
event::KeyCode::Media(media) => (),
|
||||
event::KeyCode::Modifier(modifier) => (),
|
||||
if self.cmdprocessor.is_command_mode() {
|
||||
self.cmdprocessor.key_event(key_event);
|
||||
}
|
||||
}
|
||||
event::Event::Mouse(mouse_event) => (),
|
||||
event::Event::Paste(_) => (),
|
||||
event::Event::Resize(w, h) => self.size = (w, h),
|
||||
}
|
||||
if self.command_process() {
|
||||
break;
|
||||
}
|
||||
self.render()?;
|
||||
let f = |_, value| {
|
||||
if let &toml::Value::String(ref s) = value {
|
||||
s == &self.command
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
if let toml::Value::Table(map) = &self.config.get("command").unwrap() {
|
||||
if let Some((name, _)) = iterate_config(map, &f) {
|
||||
match name.as_str() {
|
||||
"quit" => break,
|
||||
_ => self.cmdbar_prompt = String::from("Unknown command"),
|
||||
}
|
||||
self.command.clear();
|
||||
}
|
||||
}
|
||||
self.stdout.flush()?;
|
||||
} else {
|
||||
}
|
||||
}
|
||||
self.render()?;
|
||||
self.stdout.flush()?;
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn command_process(&mut self) -> bool {
|
||||
if let toml::Value::Table(map) = &self.config.get("command").unwrap() {
|
||||
if self.cmdprocessor.process(map) {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&mut self) -> io::Result<()> {
|
||||
let mut show = String::new();
|
||||
for c in self.cmdbar_show.chars() {
|
||||
for c in self.cmdprocessor.get_show().chars() {
|
||||
show.push(c);
|
||||
if UnicodeWidthStr::width(show.as_str()) as u16 >= self.size.0 - 1 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let x = cursor::position().unwrap().0;
|
||||
let x = UnicodeWidthStr::width(show.as_str()) as u16;
|
||||
let mut prompt = String::new();
|
||||
for c in self.cmdbar_prompt.chars() {
|
||||
show.push(c);
|
||||
for c in self.cmdprocessor.get_prompt().chars() {
|
||||
prompt.push(c);
|
||||
if UnicodeWidthStr::width(prompt.as_str()) as u16 >= self.size.0 - 1 - x {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let x = x + UnicodeWidthStr::width(prompt.as_str()) as u16;
|
||||
queue!(
|
||||
self.stdout,
|
||||
style::SetBackgroundColor(self.colortheme.command_bar),
|
||||
cursor::MoveTo(0, self.size.1 - 1),
|
||||
style::SetForegroundColor(if self.cmdprocessor.unknown() {
|
||||
self.colortheme.cmdbar_cmdunexist
|
||||
} else {
|
||||
self.colortheme.cmdbar_cmdexist
|
||||
}),
|
||||
style::Print(show),
|
||||
style::SetForegroudColor(self.colortheme.cmdbar_prompt),
|
||||
cursor::SavePosition,
|
||||
style::SetForegroundColor(self.colortheme.cmdbar_prompt),
|
||||
style::Print(prompt),
|
||||
)?;
|
||||
let x = cursor::position().unwrap().0;
|
||||
queue!(
|
||||
self.stdout,
|
||||
style::Print(" ".repeat((self.size.0 - x) as usize)),
|
||||
cursor::MoveTo(x, self.size.1 - 1),
|
||||
cursor::RestorePosition,
|
||||
)?;
|
||||
self.stdout.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,9 @@ use toml::{Table, Value};
|
|||
pub struct ColorTheme {
|
||||
pub background: Color,
|
||||
pub command_bar: Color,
|
||||
pub cmdbar_prompt: Color,
|
||||
pub cmdbar_cmdexist: Color,
|
||||
pub cmdbar_cmdunexist: Color,
|
||||
}
|
||||
|
||||
impl From<&Table> for ColorTheme {
|
||||
|
@ -20,10 +23,16 @@ impl From<&Table> for ColorTheme {
|
|||
}
|
||||
};
|
||||
let background = f("background");
|
||||
let command_bar = f("command_bar");
|
||||
let command_bar = f("command-bar");
|
||||
let cmdbar_prompt = f("cmdbar-prompt");
|
||||
let cmdbar_cmdexist = f("cmdbar-cmdexist");
|
||||
let cmdbar_cmdunexist = f("cmdbar-cmdunexist");
|
||||
Self {
|
||||
background,
|
||||
command_bar,
|
||||
cmdbar_prompt,
|
||||
cmdbar_cmdexist,
|
||||
cmdbar_cmdunexist,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
use crossterm::event::{self, KeyEvent, KeyModifiers};
|
||||
|
||||
use crate::{iterate_config, Config};
|
||||
|
||||
pub struct CommandProcessor {
|
||||
command_mode: bool,
|
||||
command: String,
|
||||
unknown_cmd: bool,
|
||||
cmdbar_show: String,
|
||||
cmdbar_prompt: String,
|
||||
}
|
||||
|
||||
impl CommandProcessor {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
command_mode: true,
|
||||
command: String::new(),
|
||||
unknown_cmd: false,
|
||||
cmdbar_show: String::new(),
|
||||
cmdbar_prompt: String::from("New workspace"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_show(&self) -> &String {
|
||||
&self.cmdbar_show
|
||||
}
|
||||
|
||||
pub fn get_prompt(&self) -> &String {
|
||||
&self.cmdbar_prompt
|
||||
}
|
||||
|
||||
pub fn unknown(&self) -> bool {
|
||||
self.unknown_cmd
|
||||
}
|
||||
|
||||
pub fn is_command_mode(&self) -> bool {
|
||||
self.command_mode
|
||||
}
|
||||
|
||||
pub fn process(&mut self, map: &Config) -> bool {
|
||||
let f = |_, value| {
|
||||
if let &toml::Value::String(ref s) = value {
|
||||
s == &self.command
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
if let Some((name, _)) = iterate_config(map, &f) {
|
||||
self.command.clear();
|
||||
self.cmdbar_prompt = format!(" - {}", name);
|
||||
self.unknown_cmd = false;
|
||||
match name.as_str() {
|
||||
"quit" => return true,
|
||||
_ => (),
|
||||
}
|
||||
} else if !self.cmdbar_show.is_empty() {
|
||||
self.cmdbar_prompt = String::from(" | Unknown command");
|
||||
self.unknown_cmd = true;
|
||||
} else {
|
||||
self.cmdbar_prompt.clear();
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn key_event(&mut self, key: KeyEvent) {
|
||||
let KeyEvent {
|
||||
code, modifiers, ..
|
||||
} = key;
|
||||
match code {
|
||||
event::KeyCode::Backspace => {
|
||||
if self.command_mode {
|
||||
self.command.pop();
|
||||
self.cmdbar_show.clone_from(&self.command);
|
||||
}
|
||||
}
|
||||
event::KeyCode::Enter => {
|
||||
if self.command_mode {
|
||||
self.command.clear();
|
||||
self.cmdbar_show.clear();
|
||||
}
|
||||
}
|
||||
event::KeyCode::Left => (),
|
||||
event::KeyCode::Right => (),
|
||||
event::KeyCode::Up => (),
|
||||
event::KeyCode::Down => (),
|
||||
event::KeyCode::Home => (),
|
||||
event::KeyCode::End => (),
|
||||
event::KeyCode::PageUp => (),
|
||||
event::KeyCode::PageDown => (),
|
||||
event::KeyCode::Tab => (),
|
||||
event::KeyCode::BackTab => (),
|
||||
event::KeyCode::Delete => (),
|
||||
event::KeyCode::Insert => (),
|
||||
event::KeyCode::F(_) => (),
|
||||
event::KeyCode::Char(c) => {
|
||||
if self.command_mode {
|
||||
let mut b = true;
|
||||
if modifiers.contains(KeyModifiers::CONTROL) {
|
||||
self.command += "C-";
|
||||
} else if modifiers.contains(KeyModifiers::ALT) {
|
||||
self.command += "A-";
|
||||
} else {
|
||||
b = false;
|
||||
}
|
||||
self.command.push(c);
|
||||
if b {
|
||||
self.command.push(' ');
|
||||
}
|
||||
self.cmdbar_show.clone_from(&self.command);
|
||||
}
|
||||
}
|
||||
event::KeyCode::Null => (),
|
||||
event::KeyCode::Esc => (),
|
||||
event::KeyCode::CapsLock => (),
|
||||
event::KeyCode::ScrollLock => (),
|
||||
event::KeyCode::NumLock => (),
|
||||
event::KeyCode::PrintScreen => (),
|
||||
event::KeyCode::Pause => (),
|
||||
event::KeyCode::Menu => (),
|
||||
event::KeyCode::KeypadBegin => (),
|
||||
event::KeyCode::Media(media) => (),
|
||||
event::KeyCode::Modifier(modifier) => (),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
pub mod application;
|
||||
pub mod colortheme;
|
||||
pub mod window;
|
||||
pub mod command;
|
||||
|
||||
use std::io;
|
||||
|
||||
|
|
Loading…
Reference in New Issue