1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-27 12:23:46 +03:00

termwiz: add very basic line editor

This commit is contained in:
Wez Furlong 2019-05-26 21:10:37 -07:00
parent cc0d2e5493
commit 6d243ec1f1
7 changed files with 101 additions and 2 deletions

View File

@ -0,0 +1,15 @@
use failure::Fallible;
use termwiz::caps::Capabilities;
use termwiz::lineedit::LineEditor;
use termwiz::terminal::new_terminal;
fn main() -> Fallible<()> {
let caps = Capabilities::new_from_env()?;
let terminal = new_terminal(caps)?;
let mut editor = LineEditor::new(terminal);
let line = editor.read_line()?;
println!("read line: {}", line);
Ok(())
}

View File

@ -43,6 +43,7 @@ pub mod image;
pub mod input;
pub mod istty;
pub mod keymap;
pub mod lineedit;
mod readbuf;
pub mod render;
pub mod surface;

View File

@ -0,0 +1,62 @@
use crate::input::{InputEvent, KeyCode, KeyEvent, Modifiers};
use crate::surface::{Change, Position};
use crate::terminal::Terminal;
use failure::Fallible;
pub struct LineEditor<T: Terminal> {
terminal: T,
line: String,
}
impl<T: Terminal> LineEditor<T> {
pub fn new(terminal: T) -> Self {
Self {
terminal,
line: String::new(),
}
}
fn render(&mut self) -> Fallible<()> {
self.terminal.render(&[
Change::CursorPosition {
x: Position::Absolute(0),
y: Position::NoChange,
},
Change::ClearToEndOfScreen(Default::default()),
Change::Text(self.line.clone()),
])?;
Ok(())
}
pub fn read_line(&mut self) -> Fallible<String> {
self.terminal.set_raw_mode()?;
let res = self.read_line_impl();
self.terminal.set_cooked_mode()?;
println!();
res
}
fn read_line_impl(&mut self) -> Fallible<String> {
self.line.clear();
self.render()?;
while let Some(event) = self.terminal.poll_input(None)? {
match event {
InputEvent::Key(KeyEvent {
key: KeyCode::Enter,
modifiers: Modifiers::NONE,
}) => {
break;
}
InputEvent::Key(KeyEvent {
key: KeyCode::Char(c),
modifiers: Modifiers::NONE,
}) => {
self.line.push(c);
}
_ => {}
}
self.render()?;
}
Ok(self.line.clone())
}
}

View File

@ -452,6 +452,10 @@ impl TerminfoRenderer {
out.by_ref().write_all(b"\r\n")?;
}
Change::CursorPosition {
x: Position::Absolute(0),
y: Position::NoChange,
}
| Change::CursorPosition {
x: Position::Absolute(0),
y: Position::Relative(0),
} => {

View File

@ -3,7 +3,7 @@
use crate::caps::Capabilities;
use crate::input::InputEvent;
use crate::surface::Change;
use failure::{format_err, Error};
use failure::{format_err, Error, Fallible};
use num::{self, NumCast};
use std::fmt::Display;
use std::time::Duration;
@ -56,6 +56,7 @@ pub trait Terminal {
/// pressed by the user do not implicitly render to the terminal
/// output, and disables canonicalization of unix newlines to CRLF.
fn set_raw_mode(&mut self) -> Result<(), Error>;
fn set_cooked_mode(&mut self) -> Fallible<()>;
/// Enter the alternate screen. The alternate screen will be left
/// automatically when the `Terminal` is dropped.

View File

@ -1,5 +1,5 @@
use crate::istty::IsTty;
use failure::{bail, ensure, format_err, Error};
use failure::{bail, ensure, format_err, Error, Fallible};
use libc::{self, poll, pollfd, winsize, POLLIN};
use signal_hook::{self, SigId};
use std::collections::VecDeque;
@ -357,6 +357,11 @@ impl Terminal for UnixTerminal {
Ok(())
}
fn set_cooked_mode(&mut self) -> Fallible<()> {
self.write
.set_termios(&self.saved_termios, SetAttributeWhen::Now)
}
fn enter_alternate_screen(&mut self) -> Result<(), Error> {
if !self.in_alternate_screen {
write!(

View File

@ -521,6 +521,17 @@ impl Terminal for WindowsTerminal {
)
}
fn set_cooked_mode(&mut self) -> Fallible<()> {
let mode = self.input_handle.get_input_mode()?;
self.input_handle.set_input_mode(
(mode & !(ENABLE_WINDOW_INPUT | ENABLE_WINDOW_INPUT))
| ENABLE_ECHO_INPUT
| ENABLE_LINE_INPUT
| ENABLE_PROCESSED_INPUT,
)
}
fn enter_alternate_screen(&mut self) -> Result<(), Error> {
// TODO: Implement using CreateConsoleScreenBuffer and
// SetConsoleActiveScreenBuffer.