From f597038a40fcd9df6515a4e8d2007c59ac881500 Mon Sep 17 00:00:00 2001 From: mars Date: Tue, 11 Apr 2023 17:20:12 -0400 Subject: [PATCH 1/2] rustfmt --- src/main.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index c16747c..e69b521 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,12 @@ -/* +/* * Copyright (c) 2023 Marceline Cramer * SPDX-License-Identifier: AGPL-3.0-or-later * * This program is free software: you can redistribute it and/or modify it under - * the terms of the GNU Affero General Public License as published by the Free + * the terms of the GNU Affero General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. - * + * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more @@ -21,9 +21,7 @@ use std::io::{stdout, Stdout, Write}; use crossterm::{ cursor, event::{Event, KeyCode, KeyEvent}, - terminal, - ExecutableCommand, - Result + terminal, ExecutableCommand, Result, }; use ropey::Rope; From d1693de12b302c85cff81e5ebd50d1209c7b5b9a Mon Sep 17 00:00:00 2001 From: mars Date: Tue, 11 Apr 2023 17:29:52 -0400 Subject: [PATCH 2/2] Autoscrolling + on_any_event() --- src/main.rs | 73 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 18 deletions(-) diff --git a/src/main.rs b/src/main.rs index e69b521..27ffff7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,18 +36,26 @@ impl Buffer { } } - pub fn draw(&self, out: &mut (impl ExecutableCommand + Write)) -> Result { + pub fn draw(&self, scroll: Cursor, out: &mut (impl ExecutableCommand + Write)) -> Result { let (cols, rows) = terminal::size()?; let lr_width = self.text.len_lines().ilog10() + 1; let gutter_width = lr_width + 1; + let text_width = cols as usize - gutter_width as usize; out.execute(cursor::MoveTo(0, 0))?; - for (row, line) in (0..rows).zip(self.text.lines()) { + for (row, line) in (0..rows).zip(self.text.lines_at(scroll.line)) { + let row = row as usize + scroll.line; write!(out, "{:width$} ", row, width = lr_width as usize)?; + + let lhs = scroll.column; let width = line.len_chars().saturating_sub(1); // lop off whitespace - let rhs = width.min(cols as usize - gutter_width as usize); - write!(out, "{}", line.slice(0..rhs))?; + if lhs < width { + let window = text_width.min(width - lhs); + let rhs = lhs + window; + write!(out, "{}", line.slice(lhs..rhs))?; + } + out.execute(cursor::MoveToNextLine(1))?; } @@ -143,26 +151,33 @@ enum Direction { struct State { pub buffer: Buffer, pub cursor: Cursor, + pub scroll: Cursor, + pub size: (usize, usize), pub mode: Mode, pub quit: bool, } impl State { - pub fn from_str(text: &str) -> Self { - Self { + pub fn from_str(text: &str) -> Result { + let (cols, rows) = terminal::size()?; + + Ok(Self { buffer: Buffer::from_str(text), cursor: Cursor::default(), + scroll: Cursor::default(), + size: (cols as usize, rows as usize), mode: Mode::default(), quit: false, - } + }) } pub fn draw(&self, out: &mut impl Write) -> Result<()> { out.execute(terminal::BeginSynchronizedUpdate)?; out.execute(terminal::Clear(terminal::ClearType::All))?; - let lr_width = self.buffer.draw(out)?; + let lr_width = self.buffer.draw(self.scroll, out)?; let cursor = self.buffer.clamped_cursor(self.cursor); - let (col, row) = (cursor.column as u16, cursor.line as u16); + let col = cursor.column.saturating_sub(self.scroll.column) as u16; + let row = cursor.line.saturating_sub(self.scroll.line) as u16; let col = col + lr_width as u16; out.execute(cursor::MoveTo(col, row))?; out.execute(self.mode.cursor_style())?; @@ -194,9 +209,9 @@ impl State { KeyCode::Esc => { self.quit = true; } - code => self.match_any_key(code), + code => self.on_any_key(code), }, - _ => {} + event => self.on_any_event(event), } } @@ -206,9 +221,9 @@ impl State { KeyCode::Esc => { self.mode = Mode::Normal; } - code => self.match_any_key(code), + code => self.on_any_key(code), }, - _ => {} + event => self.on_any_event(event), } } @@ -218,9 +233,9 @@ impl State { KeyCode::Esc => { self.mode = Mode::Normal; } - code => self.match_any_key(code), + code => self.on_any_key(code), }, - _ => {} + event => self.on_any_event(event), } } @@ -250,13 +265,23 @@ impl State { KeyCode::Esc => { self.mode = Mode::Normal; } - code => self.match_any_key(code), + code => self.on_any_key(code), }, + event => self.on_any_event(event), + } + } + + fn on_any_event(&mut self, event: Event) { + match event { + Event::Resize(cols, rows) => { + self.size = (cols as usize, rows as usize); + } + Event::Key(KeyEvent { code, .. }) => self.on_any_key(code), _ => {} } } - fn match_any_key(&mut self, code: KeyCode) { + fn on_any_key(&mut self, code: KeyCode) { match code { KeyCode::Esc => self.mode = Mode::Normal, KeyCode::Char('h') | KeyCode::Left => self.move_cursor(Direction::Left), @@ -269,6 +294,18 @@ impl State { fn move_cursor(&mut self, direction: Direction) { self.buffer.move_cursor(&mut self.cursor, direction, true); + + if self.cursor.column < self.scroll.column + 3 { + self.scroll.column = self.cursor.column.saturating_sub(3); + } else if self.cursor.column + 6 >= self.scroll.column + self.size.0 { + self.scroll.column = self.cursor.column.saturating_sub(self.size.0 - 6); + } + + if self.cursor.line < self.scroll.line { + self.scroll.line = self.cursor.line; + } else if self.cursor.line + 3 >= self.scroll.line + self.size.1 { + self.scroll.line = self.cursor.line + 3 - self.size.1; + } } } @@ -284,7 +321,7 @@ fn screen_main(stdout: &mut Stdout, mut state: State) -> Result<()> { fn main() -> Result<()> { let text = include_str!("main.rs"); - let state = State::from_str(text); + let state = State::from_str(text)?; let mut stdout = stdout(); terminal::enable_raw_mode()?; stdout.execute(terminal::EnterAlternateScreen)?;