aboutsummaryrefslogtreecommitdiff
path: root/helix-term
diff options
context:
space:
mode:
authorJan Hrastnik2020-06-03 23:05:01 +0000
committerBlaž Hrastnik2020-06-16 08:42:32 +0000
commit19643446cd2d5911b56af6f52f0f40da39a14109 (patch)
treed06e1d6bbc6bb91996c182b5caa92d448268e540 /helix-term
parent073fe61264d5154eb0bd37be575ccc91e17b74d7 (diff)
editor.rs now uses crossterm
Diffstat (limited to 'helix-term')
-rw-r--r--helix-term/src/editor.rs318
-rw-r--r--helix-term/src/main.rs6
2 files changed, 53 insertions, 271 deletions
diff --git a/helix-term/src/editor.rs b/helix-term/src/editor.rs
index c4aa72e6..1ea37053 100644
--- a/helix-term/src/editor.rs
+++ b/helix-term/src/editor.rs
@@ -1,287 +1,69 @@
-use anyhow::Error;
-use termwiz::caps::Capabilities;
-use termwiz::cell::AttributeChange;
-use termwiz::color::{AnsiColor, ColorAttribute, RgbColor};
-use termwiz::input::*;
-use termwiz::surface::Change;
-use termwiz::terminal::{buffered::BufferedTerminal, SystemTerminal, Terminal};
-use termwiz::widgets::*;
+use std::io::{self, stdout, Write};
-use crate::Args;
+use crossterm::{
+ cursor,
+ cursor::position,
+ event::{self, read, Event, KeyCode, KeyEvent},
+ execute, style,
+ terminal::{self, disable_raw_mode, enable_raw_mode},
+ Result,
+};
-use std::{env, path::PathBuf};
+const HELP: &str = r#"
+ - Use q to quit
+ - Move cursor with h, j, k, l
+"#;
-use helix_core::Buffer;
+pub struct Editor {}
-/// This is a widget for our application
-pub struct MainScreen {}
-
-impl MainScreen {
- pub fn new() -> Self {
- Self {}
- }
-}
-
-impl Widget for MainScreen {
- fn process_event(&mut self, event: &WidgetEvent, _args: &mut UpdateArgs) -> bool {
- true // handled it all
- }
-
- /// Draw ourselves into the surface provided by RenderArgs
- fn render(&mut self, args: &mut RenderArgs) {
- // args.surface.add_change(Change::ClearScreen(
- // ColorAttribute::TrueColorWithPaletteFallback(
- // RgbColor::new(0x31, 0x1B, 0x92),
- // AnsiColor::Black.into(),
- // ),
- // ));
- // args.surface
- // .add_change(Change::Attribute(AttributeChange::Foreground(
- // ColorAttribute::TrueColorWithPaletteFallback(
- // RgbColor::new(0xB3, 0x88, 0xFF),
- // AnsiColor::Purple.into(),
- // ),
- // )));
- }
-
- fn get_size_constraints(&self) -> layout::Constraints {
- let mut constraints = layout::Constraints::default();
- constraints.child_orientation = layout::ChildOrientation::Vertical;
- constraints
- }
-}
-
-pub struct BufferComponent<'a> {
- text: String,
- buffer: &'a mut Buffer,
-
- first_line: usize,
-}
-
-impl<'a> BufferComponent<'a> {
- /// Initialize the widget with the input text
- pub fn new(buffer: &'a mut Buffer) -> Self {
- Self {
- buffer,
- text: String::new(),
-
- first_line: 0,
- }
- }
-}
-
-impl<'a> Widget for BufferComponent<'a> {
- fn process_event(&mut self, event: &WidgetEvent, _args: &mut UpdateArgs) -> bool {
- match event {
- WidgetEvent::Input(InputEvent::Key(KeyEvent {
- key: KeyCode::Char('k'),
- ..
- })) => {
- self.first_line = self.first_line.saturating_sub(1);
- }
- WidgetEvent::Input(InputEvent::Key(KeyEvent {
- key: KeyCode::Char('j'),
- ..
- })) => {
- self.first_line = self.first_line.saturating_add(1);
- }
- WidgetEvent::Input(InputEvent::Key(KeyEvent {
- key: KeyCode::Enter,
+impl Editor {
+ pub fn read_char() -> Result<char> {
+ loop {
+ if let Ok(Event::Key(KeyEvent {
+ code: KeyCode::Char(c),
..
- })) => {
- self.text.push_str("\r\n");
+ })) = event::read()
+ {
+ return Ok(c);
}
- WidgetEvent::Input(InputEvent::Paste(s)) => {
- self.text.push_str(&s);
- }
- _ => {}
}
-
- true // handled it all
}
- /// Draw ourselves into the surface provided by RenderArgs
- fn render(&mut self, args: &mut RenderArgs) {
- args.surface
- .add_change(Change::ClearScreen(ColorAttribute::Default));
-
- // args.surface
- // .add_change(Change::Attribute(AttributeChange::Foreground(
- // ColorAttribute::TrueColorWithPaletteFallback(
- // RgbColor::new(0x11, 0x00, 0xFF),
- // AnsiColor::Purple.into(),
- // ),
- // )));
- let (_width, height) = args.surface.dimensions();
-
- for line in self.buffer.contents.lines_at(self.first_line).take(height) {
- args.surface
- .add_change(unsafe { String::from_utf8_unchecked(line.bytes().collect()) });
- args.surface.add_change("\r");
- }
- // args.surface
- // .add_change(format!("🤷 surface size is {:?}\r\n", dims));
- // args.surface.add_change(self.text.clone());
-
- // Place the cursor at the end of the text.
- // A more advanced text editing widget would manage the
- // cursor position differently.
- *args.cursor = CursorShapeAndPosition {
- coords: args.surface.cursor_position().into(),
- shape: termwiz::surface::CursorShape::SteadyBar,
- ..Default::default()
- };
- }
-
- fn get_size_constraints(&self) -> layout::Constraints {
- let mut c = layout::Constraints::default();
- c.set_valign(layout::VerticalAlignment::Top);
- c
- }
-}
-
-pub struct StatusLine {}
-
-impl StatusLine {
- pub fn new() -> Self {
- StatusLine {}
- }
-}
-impl Widget for StatusLine {
- fn process_event(&mut self, event: &WidgetEvent, _args: &mut UpdateArgs) -> bool {
- true
- }
-
- fn render(&mut self, args: &mut RenderArgs) {
- args.surface.add_change(Change::ClearScreen(
- ColorAttribute::TrueColorWithPaletteFallback(
- RgbColor::new(0xFF, 0xFF, 0xFF),
- AnsiColor::Black.into(),
- ),
- ));
- args.surface
- .add_change(Change::Attribute(AttributeChange::Foreground(
- ColorAttribute::TrueColorWithPaletteFallback(
- RgbColor::new(0x00, 0x00, 0x00),
- AnsiColor::Black.into(),
- ),
- )));
-
- args.surface.add_change(" helix");
- }
-
- fn get_size_constraints(&self) -> layout::Constraints {
- *layout::Constraints::default()
- .set_fixed_height(1)
- .set_valign(layout::VerticalAlignment::Bottom)
- }
-}
-
-pub struct Editor {
- terminal: BufferedTerminal<SystemTerminal>,
-
- buffer: Option<Buffer>,
-}
-
-impl Editor {
- pub fn new(mut args: Args) -> Result<Self, Error> {
- // Create a terminal
- let caps = Capabilities::new_from_env()?;
- let mut terminal = BufferedTerminal::new(SystemTerminal::new(caps)?)?;
-
- let mut editor = Editor {
- terminal,
- buffer: None,
- };
-
- if let Some(file) = args.files.pop() {
- editor.open(file)?;
+ pub fn print_events() -> Result<()> {
+ loop {
+ // Handle key events
+ match Editor::read_char()? {
+ 'h' => execute!(io::stdout(), cursor::MoveLeft(1))?,
+ 'j' => execute!(io::stdout(), cursor::MoveDown(1))?,
+ 'k' => execute!(io::stdout(), cursor::MoveUp(1))?,
+ 'l' => execute!(io::stdout(), cursor::MoveRight(1))?,
+ 'q' => {
+ execute!(
+ io::stdout(),
+ style::ResetColor,
+ cursor::Show,
+ terminal::LeaveAlternateScreen
+ )?;
+ break;
+ }
+ _ => println!("use 'q' to quit."),
+ }
}
- Ok(editor)
- }
-
- pub fn open(&mut self, path: PathBuf) -> Result<(), Error> {
- let buffer = Buffer::load(path)?;
- self.buffer = Some(buffer);
Ok(())
}
- pub fn run(&mut self) -> Result<(), Error> {
- // Start with an empty string; typing into the app will
- // update this string.
- let mut typed_text = String::new();
-
- {
- let buf = &mut self.terminal;
- // Put the terminal in raw mode + alternate screen
- buf.terminal().enter_alternate_screen()?;
- buf.terminal().set_raw_mode()?;
-
- // Set up the UI
- let mut ui = Ui::new();
-
- let root_id = ui.set_root(MainScreen::new());
- let buffer_id =
- ui.add_child(root_id, BufferComponent::new(self.buffer.as_mut().unwrap()));
- // let root_id = ui.set_root(Buffer::new(&mut typed_text));
- ui.add_child(root_id, StatusLine::new());
- ui.set_focus(buffer_id);
+ pub fn run() -> Result<()> {
+ enable_raw_mode()?;
- loop {
- ui.process_event_queue()?;
-
- // After updating and processing all of the widgets, compose them
- // and render them to the screen.
- if ui.render_to_screen(buf)? {
- // We have more events to process immediately; don't block waiting
- // for input below, but jump to the top of the loop to re-run the
- // updates.
- continue;
- }
- // Compute an optimized delta to apply to the terminal and display it
- buf.flush()?;
-
- // Wait for user input
- match buf.terminal().poll_input(None) {
- Ok(Some(InputEvent::Resized { rows, cols })) => {
- // FIXME: this is working around a bug where we don't realize
- // that we should redraw everything on resize in BufferedTerminal.
- buf.add_change(Change::ClearScreen(Default::default()));
- buf.resize(cols, rows);
- }
- Ok(Some(input)) => match input {
- InputEvent::Key(KeyEvent {
- key: KeyCode::Escape,
- ..
- }) => {
- // Quit the app when escape is pressed
- break;
- }
- input @ _ => {
- // Feed input into the Ui
- ui.queue_event(WidgetEvent::Input(input));
- }
- },
- Ok(None) => {}
- Err(e) => {
- print!("{:?}\r\n", e);
- break;
- }
- }
- }
+ // used for clearing the screen
+ execute!(io::stdout(), terminal::EnterAlternateScreen)?;
+ println!("{}", HELP);
+ let mut stdout = stdout();
+ if let Err(e) = Editor::print_events() {
+ println!("Error: {:?}\r", e);
}
- // After we've stopped the full screen raw terminal,
- // print out the final edited value of the input text.
- println!("The text you entered: {}", typed_text);
- Ok(())
- }
-
- pub fn render(&self) {
- // create a new window sized surface
- // paint all components
- // diff vs last frame, swap
- // paint diff
+ disable_raw_mode()
}
}
diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs
index 6a04bdb7..11c700e7 100644
--- a/helix-term/src/main.rs
+++ b/helix-term/src/main.rs
@@ -1,9 +1,10 @@
#![allow(unused)]
// mod editor;
// mod component;
+mod editor;
mod keymap;
-// use editor::Editor;
+use editor::Editor;
use argh::FromArgs;
use std::path::PathBuf;
@@ -19,9 +20,8 @@ pub struct Args {
fn main() -> Result<(), Error> {
let args: Args = argh::from_env();
- // let mut editor = Editor::new(args)?;
- // editor.run()?;
+ editor::Editor::run()?;
Ok(())
}