port to crossterm
This commit is contained in:
parent
f3f1c4de94
commit
f5da786053
5 changed files with 315 additions and 115 deletions
|
@ -1,15 +1,16 @@
|
|||
use crossterm::{
|
||||
cursor::{self, MoveTo},
|
||||
event::{self, Event, KeyCode, KeyModifiers},
|
||||
queue,
|
||||
style::{Color, Colors, ResetColor, SetColors},
|
||||
terminal::{self, Clear, ClearType},
|
||||
};
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
io::{stdin, stdout, Write},
|
||||
io::{stdout, Write},
|
||||
ops::Range,
|
||||
vec,
|
||||
};
|
||||
use termion::{
|
||||
clear, color, cursor,
|
||||
event::{Event, Key},
|
||||
input::TermRead,
|
||||
terminal_size,
|
||||
};
|
||||
|
||||
use crate::util::read_line;
|
||||
use crate::{clipboard::Clipboard, util::RangeConverter};
|
||||
|
@ -87,34 +88,39 @@ impl Editor {
|
|||
}
|
||||
|
||||
fn input(&mut self) {
|
||||
for event in stdin().events().take(1).flatten() {
|
||||
if let Event::Key(key) = event {
|
||||
match key {
|
||||
Key::Esc => self.active = false,
|
||||
Key::Char(char) => self.insert_char(char),
|
||||
Key::Backspace => self.backspace(),
|
||||
Key::Delete => self.delete(),
|
||||
Key::Left => self.move_left(),
|
||||
Key::Right => self.move_right(),
|
||||
Key::Up => self.move_up(),
|
||||
Key::Down => self.move_down(),
|
||||
Key::Home => self.move_home(),
|
||||
Key::End => self.move_end(),
|
||||
Key::Ctrl('s') => self.save(),
|
||||
Key::Ctrl('p') => self.toggle_marker(),
|
||||
Key::Ctrl('c') => self.copy(),
|
||||
Key::Ctrl('x') => self.cut(),
|
||||
Key::Ctrl('v') => self.paste(),
|
||||
match event::read() {
|
||||
Ok(Event::Key(event)) => match event.modifiers {
|
||||
KeyModifiers::NONE => match event.code {
|
||||
KeyCode::Esc => self.active = false,
|
||||
KeyCode::Char(ch) => self.insert_char(ch),
|
||||
KeyCode::Backspace => self.backspace(),
|
||||
KeyCode::Delete => self.delete(),
|
||||
KeyCode::Left => self.move_left(),
|
||||
KeyCode::Right => self.move_right(),
|
||||
KeyCode::Up => self.move_up(),
|
||||
KeyCode::Down => self.move_down(),
|
||||
KeyCode::Home => self.move_home(),
|
||||
KeyCode::End => self.move_end(),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
},
|
||||
KeyModifiers::CONTROL => match event.code {
|
||||
KeyCode::Char('s') => self.save(),
|
||||
KeyCode::Char('p') => self.toggle_marker(),
|
||||
KeyCode::Char('c') => self.copy(),
|
||||
KeyCode::Char('x') => self.cut(),
|
||||
KeyCode::Char('v') => self.paste(),
|
||||
_ => (),
|
||||
},
|
||||
_ => (),
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(&self) {
|
||||
print!("{}", clear::All);
|
||||
queue!(stdout(), Clear(ClearType::All)).unwrap();
|
||||
|
||||
let max_rows = terminal_size().unwrap().1 as usize - 1;
|
||||
let max_rows = terminal::size().unwrap().1 as usize - 1;
|
||||
let end = (self.scroll + max_rows).min(self.lines.len());
|
||||
let visible_rows = self.scroll..end;
|
||||
|
||||
|
@ -125,7 +131,7 @@ impl Editor {
|
|||
for (line_index, line) in self.lines[visible_rows].iter().enumerate() {
|
||||
let text = &self.text[line.clone()];
|
||||
|
||||
print!("{}", cursor::Goto(1, line_index as u16 + 1));
|
||||
queue!(stdout(), MoveTo(0, line_index as u16)).unwrap();
|
||||
|
||||
if self.marker.is_none() {
|
||||
print!("{}", text.replace('\t', &" ".repeat(TAB_SIZE)));
|
||||
|
@ -150,21 +156,22 @@ impl Editor {
|
|||
}
|
||||
}
|
||||
self.status_line();
|
||||
print!(
|
||||
"{}{}",
|
||||
cursor::Goto(
|
||||
self.physical_column() as u16 + 1,
|
||||
(self.cursor.line - self.scroll) as u16 + 1
|
||||
queue!(
|
||||
stdout(),
|
||||
MoveTo(
|
||||
self.physical_column() as u16,
|
||||
(self.cursor.line - self.scroll) as u16
|
||||
),
|
||||
cursor::Show
|
||||
);
|
||||
)
|
||||
.unwrap();
|
||||
stdout().flush().unwrap();
|
||||
}
|
||||
|
||||
fn status_line(&self) {
|
||||
queue!(stdout(), MoveTo(0, terminal::size().unwrap().1)).unwrap();
|
||||
print!(
|
||||
"{}({}, {}) {}",
|
||||
cursor::Goto(1, terminal_size().unwrap().1),
|
||||
"({},{}) {}",
|
||||
self.cursor.line,
|
||||
self.physical_column(),
|
||||
self.name(),
|
||||
|
@ -213,7 +220,7 @@ impl Editor {
|
|||
self.cursor.line += 1;
|
||||
self.cursor.column = physical_column.min(self.current_line().len());
|
||||
self.ensure_char_boundary();
|
||||
if self.cursor.line > (self.scroll + terminal_size().unwrap().1 as usize - 2) {
|
||||
if self.cursor.line > (self.scroll + terminal::size().unwrap().1 as usize - 2) {
|
||||
self.scroll += 1;
|
||||
}
|
||||
}
|
||||
|
@ -379,13 +386,9 @@ impl Editor {
|
|||
}
|
||||
|
||||
fn color_selection() {
|
||||
print!(
|
||||
"{}{}",
|
||||
color::Fg(color::Black),
|
||||
color::Bg(color::LightBlack)
|
||||
);
|
||||
queue!(stdout(), SetColors(Colors::new(Color::Black, Color::White))).unwrap();
|
||||
}
|
||||
|
||||
fn color_reset() {
|
||||
print!("{}{}", color::Fg(color::Reset), color::Bg(color::Reset));
|
||||
queue!(stdout(), ResetColor).unwrap();
|
||||
}
|
||||
|
|
66
src/main.rs
66
src/main.rs
|
@ -1,15 +1,18 @@
|
|||
use crossterm::{
|
||||
cursor::{self, MoveTo},
|
||||
event::{self, Event, KeyCode, KeyModifiers},
|
||||
execute, queue,
|
||||
style::{Color, Colors, ResetColor, SetColors},
|
||||
terminal::{
|
||||
disable_raw_mode, enable_raw_mode, Clear, ClearType, EnterAlternateScreen,
|
||||
LeaveAlternateScreen,
|
||||
},
|
||||
};
|
||||
use std::{
|
||||
env,
|
||||
io::{stdin, stdout, Stdout, Write},
|
||||
io::{stdout, Write},
|
||||
process::exit,
|
||||
};
|
||||
use termion::{
|
||||
clear, color,
|
||||
cursor::{self, Goto},
|
||||
event::{Event, Key},
|
||||
input::TermRead,
|
||||
raw::{IntoRawMode, RawTerminal},
|
||||
};
|
||||
|
||||
mod clipboard;
|
||||
mod editor;
|
||||
|
@ -25,12 +28,10 @@ struct Navigator {
|
|||
editors: Vec<Editor>,
|
||||
selected: Option<usize>,
|
||||
clipboard: Clipboard,
|
||||
_term: RawTerminal<Stdout>,
|
||||
}
|
||||
|
||||
impl Navigator {
|
||||
fn new() -> Self {
|
||||
let term = stdout().into_raw_mode().unwrap();
|
||||
let clipboard = Clipboard::new();
|
||||
let mut editors: Vec<Editor> = env::args()
|
||||
.skip(1)
|
||||
|
@ -43,13 +44,12 @@ impl Navigator {
|
|||
editors,
|
||||
selected: Some(0),
|
||||
clipboard,
|
||||
_term: term,
|
||||
}
|
||||
}
|
||||
|
||||
fn run(mut self) {
|
||||
print!("{}", clear::All);
|
||||
stdout().flush().unwrap();
|
||||
execute!(stdout(), EnterAlternateScreen, Clear(ClearType::All)).unwrap();
|
||||
enable_raw_mode().unwrap();
|
||||
|
||||
loop {
|
||||
self.draw();
|
||||
|
@ -58,41 +58,38 @@ impl Navigator {
|
|||
}
|
||||
|
||||
fn draw(&self) {
|
||||
print!(
|
||||
"{}{}{}Open editors: {}",
|
||||
clear::All,
|
||||
cursor::Hide,
|
||||
Goto(1, 1),
|
||||
self.editors.len()
|
||||
);
|
||||
queue!(stdout(), Clear(ClearType::All), cursor::Hide, MoveTo(0, 0)).unwrap();
|
||||
print!("Open editors: {}", self.editors.len());
|
||||
|
||||
for (index, editor) in self.editors.iter().enumerate() {
|
||||
if Some(index) == self.selected {
|
||||
print!("{}{}", color::Fg(color::Black), color::Bg(color::White));
|
||||
queue!(stdout(), SetColors(Colors::new(Color::Black, Color::White))).unwrap();
|
||||
}
|
||||
queue!(stdout(), MoveTo(1, index as u16 + 1)).unwrap();
|
||||
print!(
|
||||
"{}{}{}",
|
||||
Goto(2, index as u16 + 2),
|
||||
"{}{}",
|
||||
editor.has_unsaved_changes().then_some("*").unwrap_or(" "),
|
||||
editor.name()
|
||||
);
|
||||
print!("{}{}", color::Fg(color::Reset), color::Bg(color::Reset));
|
||||
queue!(stdout(), ResetColor).unwrap();
|
||||
}
|
||||
|
||||
stdout().flush().unwrap();
|
||||
}
|
||||
|
||||
fn input(&mut self) {
|
||||
for event in stdin().events().take(1).flatten() {
|
||||
if let Event::Key(key) = event {
|
||||
match key {
|
||||
Key::Char('q') => self.quit(),
|
||||
Key::Char('\n') => self.open_selected(),
|
||||
Key::Ctrl('n') => self.new_editor(),
|
||||
Key::Up => self.nav_up(),
|
||||
Key::Down => self.nav_down(),
|
||||
_ => (),
|
||||
if let Ok(Event::Key(event)) = event::read() {
|
||||
match event.code {
|
||||
KeyCode::Char('q') => self.quit(),
|
||||
KeyCode::Up => self.nav_up(),
|
||||
KeyCode::Down => self.nav_down(),
|
||||
KeyCode::Enter => self.open_selected(),
|
||||
KeyCode::Char('n') => {
|
||||
if event.modifiers == KeyModifiers::CONTROL {
|
||||
self.new_editor();
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +121,8 @@ impl Navigator {
|
|||
}
|
||||
|
||||
fn quit(&self) {
|
||||
print!("{}{}", clear::All, cursor::Show);
|
||||
disable_raw_mode().unwrap();
|
||||
execute!(stdout(), LeaveAlternateScreen, cursor::Show).unwrap();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
|
41
src/util.rs
41
src/util.rs
|
@ -1,37 +1,36 @@
|
|||
use std::{
|
||||
io::{stdin, stdout, Write},
|
||||
ops::Range,
|
||||
};
|
||||
use termion::{
|
||||
use crossterm::{
|
||||
cursor,
|
||||
event::{Event, Key},
|
||||
input::TermRead,
|
||||
terminal_size,
|
||||
event::{self, Event, KeyCode},
|
||||
queue, terminal,
|
||||
};
|
||||
use std::{
|
||||
io::{stdout, Write},
|
||||
ops::Range,
|
||||
};
|
||||
|
||||
pub fn read_line(prompt: &str) -> Option<String> {
|
||||
let mut response = String::new();
|
||||
let size = terminal_size().unwrap();
|
||||
let start_pos = cursor::Goto(1, size.1);
|
||||
let width = size.0 as usize;
|
||||
let size = terminal::size().unwrap();
|
||||
let start_pos = cursor::MoveTo(0, size.1);
|
||||
|
||||
print!("{start_pos}{prompt}{response}",);
|
||||
queue!(stdout(), start_pos).unwrap();
|
||||
print!("{prompt}");
|
||||
stdout().flush().unwrap();
|
||||
|
||||
for event in stdin().events() {
|
||||
if let Ok(Event::Key(key)) = event {
|
||||
match key {
|
||||
Key::Char('\n') => break,
|
||||
Key::Char(ch) => response.push(ch),
|
||||
Key::Backspace => {
|
||||
loop {
|
||||
if let Ok(Event::Key(event)) = event::read() {
|
||||
match event.code {
|
||||
KeyCode::Enter => break,
|
||||
KeyCode::Char(ch) => response.push(ch),
|
||||
KeyCode::Backspace => {
|
||||
response.pop();
|
||||
print!("{start_pos}{:width$}", " ");
|
||||
}
|
||||
Key::Esc => return None,
|
||||
KeyCode::Esc => return None,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
print!("{start_pos}{prompt}{response}",);
|
||||
queue!(stdout(), start_pos).unwrap();
|
||||
print!("{prompt}{response} ");
|
||||
stdout().flush().unwrap();
|
||||
}
|
||||
Some(response.trim().into())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue