From 23b60dfb08e85f6e70b5ec17d4352eb5692a8853 Mon Sep 17 00:00:00 2001 From: Arijit Dey Date: Thu, 1 Feb 2024 01:58:29 +0530 Subject: [PATCH] Finalize moving with left, right, l and h keys --- src/core/ev_handler.rs | 8 ++++- src/core/utils/display/mod.rs | 57 +++++++++++++++++++++-------------- src/input/mod.rs | 15 +++++++-- src/screen.rs | 9 ++++++ 4 files changed, 64 insertions(+), 25 deletions(-) diff --git a/src/core/ev_handler.rs b/src/core/ev_handler.rs index 5f4b8a0..4f2b3a5 100644 --- a/src/core/ev_handler.rs +++ b/src/core/ev_handler.rs @@ -48,7 +48,13 @@ pub fn handle_event( display::draw_for_change(out, p, &mut um)?; p.upper_mark = um; } - Command::UserInput(InputEvent::UpdateLeftMark(lm)) => p.left_mark = lm, + Command::UserInput(InputEvent::UpdateLeftMark(lm)) if !p.line_wrapping => { + if lm.saturating_add(p.cols) > p.screen.max_line_length() { + return Ok(()); + } + p.left_mark = lm; + display::draw_full(out, p)? + } Command::UserInput(InputEvent::RestorePrompt) => { // Set the message to None and new messages to false as all messages have been shown p.message = None; diff --git a/src/core/utils/display/mod.rs b/src/core/utils/display/mod.rs index a8e5edf..ea0028e 100644 --- a/src/core/utils/display/mod.rs +++ b/src/core/utils/display/mod.rs @@ -9,7 +9,7 @@ use crossterm::{ use std::{cmp::Ordering, convert::TryInto, io::Write}; use super::{term, text::AppendStyle}; -use crate::{error::MinusError, PagerState}; +use crate::{error::MinusError, minus_core, LineNumbers, PagerState}; /// Handles drawing of screen based on movement /// @@ -107,6 +107,7 @@ pub fn draw_for_change( ps.line_wrapping, ps.left_mark, ps.line_numbers.is_on(), + ps.screen.line_count(), )?; ps.upper_mark = *new_upper_mark; @@ -271,7 +272,7 @@ pub fn write_from_pagerstate(out: &mut impl Write, ps: &mut PagerState) -> Resul let display_lines: &[String] = ps .screen .get_formatted_lines_with_bounds(ps.upper_mark, lower_mark); - let line_count = ps.screen.line_count(); + write_lines( out, display_lines, @@ -279,6 +280,7 @@ pub fn write_from_pagerstate(out: &mut impl Write, ps: &mut PagerState) -> Resul ps.line_wrapping, ps.left_mark, ps.line_numbers.is_on(), + ps.screen.line_count(), ) } @@ -289,10 +291,10 @@ pub fn write_lines( line_wrapping: bool, left_mark: usize, line_numbers: bool, + line_count: usize, ) -> crate::Result { if !line_wrapping { - let range = (left_mark, 0); - write_lines_in_horizontal_scroll(out, lines, cols, range, line_numbers) + write_lines_in_horizontal_scroll(out, lines, cols, left_mark, line_numbers, line_count) } else { write_raw_lines(out, lines, Some("\r")) } @@ -302,29 +304,40 @@ pub fn write_lines_in_horizontal_scroll( out: &mut impl Write, lines: &[String], cols: usize, - range: (usize, usize), + start: usize, line_numbers: bool, + line_count: usize, ) -> crate::Result { - let (start, _end) = range; - - // When line numbers are active, the bold and reset ascii sequences also appear in the line - // which also gets counted when end = (available no. of columns) and eventually results in - // less text being shown per line. - // - // To counter this, we add the length of these sequences to available no. of columns - // essentially doing this: - // - // crossterm::style::Attribute::Bold.to_string().len() - // + crossterm::style::Attribute::Reset.to_string().len() - // - // which is equal to 8 let line_number_ascii_seq_len = if line_numbers { 8 } else { 0 }; + let line_number_padding = if line_numbers { + minus_core::digits(line_count) + LineNumbers::EXTRA_PADDING + 3 + } else { + 0 + }; + let shifted_start = if line_numbers { + start + line_number_padding + line_number_ascii_seq_len + } else { + start + }; for line in lines { - let end = cols - .saturating_add(line_number_ascii_seq_len) - .min(line.len()); - writeln!(out, "\r{}", &line[start..end])?; + let end = shifted_start + cols.min(line.len().saturating_sub(shifted_start)) + - line_number_padding; + + if start < line.len() { + if line_numbers { + writeln!( + out, + "\r{}{}", + &line[0..line_number_padding + line_number_ascii_seq_len], + &line[shifted_start..end] + )?; + } else { + writeln!(out, "\r{}", &line[shifted_start..end])?; + } + } else { + writeln!(out, "\r")?; + } } Ok(()) } diff --git a/src/input/mod.rs b/src/input/mod.rs index 02a6e1c..056ed18 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -107,14 +107,17 @@ pub enum InputEvent { UpdateUpperMark(usize), /// `Ctrl+L`, inverts the line number display. Contains the new value. UpdateLineNumber(LineNumbers), - /// `Right`, `Left`, `h` or `l` was pressed - UpdateLeftMark(usize), /// A number key has been pressed. This inner value is stored as a `char`. /// The input loop will append this number to its `count` string variable Number(char), /// Restore the original prompt RestorePrompt, + /// Whether to allow Horizontal scrolling HorizontalScroll(bool), + /// Sets the left mark of Horizontal scrolling + /// + /// Sent by keys like `l`, `h`, `right`, `left` etc. + UpdateLeftMark(usize), /// Tells the event hadler to not do anything for this event /// /// This is extremely useful when you want to execute arbitrary code on events without @@ -265,6 +268,14 @@ where map.add_key_events(&["c-s-h"], |_, ps| { InputEvent::HorizontalScroll(!ps.line_wrapping) }); + map.add_key_events(&["h", "left"], |_, ps| { + let position = ps.prefix_num.parse::().unwrap_or(1); + InputEvent::UpdateLeftMark(ps.left_mark.saturating_sub(position)) + }); + map.add_key_events(&["l", "right"], |_, ps| { + let position = ps.prefix_num.parse::().unwrap_or(1); + InputEvent::UpdateLeftMark(ps.left_mark.saturating_add(position)) + }); // TODO: Add keybindings for left right scrolling map.add_resize_event(|ev, _| { diff --git a/src/screen.rs b/src/screen.rs index 9d4466f..40af09d 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -30,6 +30,15 @@ impl Screen { &self.formatted_lines[start..end] } } + + // TODO: Optimize this + pub(crate) fn max_line_length(&self) -> usize { + self.orig_text + .lines() + .max_by_key(|l| l.len()) + .unwrap() + .len() + } } impl Default for Screen {