Skip to content

Commit

Permalink
Implement functional horizontal scrolling.
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulJuliusMartinez committed Jan 17, 2022
1 parent 7f9166f commit 655c538
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 16 deletions.
3 changes: 2 additions & 1 deletion src/jless.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,8 @@ impl JLess {
None
}
Key::Char(';') => {
self.screen_writer.scroll_focused_line_to_an_end(&self.viewer);
self.screen_writer
.scroll_focused_line_to_an_end(&self.viewer);
None
}
Key::Char(':') => {
Expand Down
24 changes: 21 additions & 3 deletions src/lineprinter.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::fmt;
use std::fmt::Write;

Expand Down Expand Up @@ -180,6 +182,7 @@ impl LabelStyle {
}
}

#[derive(Debug)]
pub enum LineValue<'a> {
Container {
flatjson: &'a FlatJson,
Expand Down Expand Up @@ -210,10 +213,12 @@ pub struct LinePrinter<'a, TUI: TUIControl> {
// Stuff to actually print out
pub label: Option<LineLabel<'a>>,
pub value: LineValue<'a>,

pub cached_formatted_value: Option<Entry<'a, usize, TruncatedStrView>>,
}

impl<'a, TUI: TUIControl> LinePrinter<'a, TUI> {
pub fn print_line<W: Write>(&self, buf: &mut W) -> fmt::Result {
pub fn print_line<W: Write>(&mut self, buf: &mut W) -> fmt::Result {
self.tui.reset_style(buf)?;

self.print_focus_and_container_indicators(buf)?;
Expand Down Expand Up @@ -380,7 +385,7 @@ impl<'a, TUI: TUIControl> LinePrinter<'a, TUI> {
}

fn fill_in_value<W: Write>(
&self,
&mut self,
buf: &mut W,
mut available_space: isize,
) -> Result<isize, fmt::Error> {
Expand Down Expand Up @@ -417,7 +422,19 @@ impl<'a, TUI: TUIControl> LinePrinter<'a, TUI> {
available_space -= 1;
}

let truncated_view = TruncatedStrView::init_start(value_ref, available_space);
// Option<Entry<>>
// - if no entry, then init_start
// - if entry, but vacant, then init_start
// - if entry with value, then value
let truncated_view = self
.cached_formatted_value
.take()
.map(|entry| {
entry
.or_insert_with(|| TruncatedStrView::init_start(value_ref, available_space))
.clone()
})
.unwrap_or_else(|| TruncatedStrView::init_start(value_ref, available_space));
let space_used_for_value = truncated_view.used_space();
if space_used_for_value.is_none() {
return Ok(0);
Expand Down Expand Up @@ -879,6 +896,7 @@ mod tests {
quotes: true,
color: Color::White,
},
cached_formatted_value: None,
}
}
}
Expand Down
78 changes: 70 additions & 8 deletions src/screenwriter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::lineprinter::JS_IDENTIFIER;
use crate::search::SearchState;
use crate::truncate::TruncationResult::{DoesntFit, NoTruncation, Truncated};
use crate::truncate::{truncate_left_to_fit, truncate_right_to_fit};
use crate::truncatedstrview::TruncatedStrView;
use crate::truncatedstrview::{TruncatedStrSlice, TruncatedStrView};
use crate::tuicontrol::{Color as TUIColor, ColorControl};
use crate::types::TTYDimensions;
use crate::viewer::{JsonViewer, Mode};
Expand Down Expand Up @@ -116,8 +116,7 @@ impl ScreenWriter {
write!(self.tty_writer, "~")?;
}
OptionIndex::Index(index) => {
let row = &viewer.flatjson[index];
self.print_line(viewer, row_index, row, index == viewer.focused_row)?;
self.print_line(viewer, row_index, index, index == viewer.focused_row)?;
line = match viewer.mode {
Mode::Line => viewer.flatjson.next_visible_row(index),
Mode::Data => viewer.flatjson.next_item(index),
Expand Down Expand Up @@ -164,10 +163,11 @@ impl ScreenWriter {
&mut self,
viewer: &JsonViewer,
screen_index: u16,
row: &Row,
index: Index,
is_focused: bool,
) -> std::io::Result<()> {
self.tty_writer.position_cursor(1, screen_index + 1)?;
let row = &viewer.flatjson[index];

let depth = row
.depth
Expand Down Expand Up @@ -255,7 +255,7 @@ impl ScreenWriter {
}
}

let line = lp::LinePrinter {
let mut line = lp::LinePrinter {
mode: viewer.mode,
tui: ColorControl {},

Expand All @@ -269,6 +269,8 @@ impl ScreenWriter {

label,
value,

cached_formatted_value: Some(self.truncated_row_value_views.entry(index)),
};

let mut buf = String::new();
Expand All @@ -278,6 +280,24 @@ impl ScreenWriter {
write!(self.tty_writer, "{}", buf)
}

fn line_primitive_value_ref<'a, 'b>(
&'a self,
row: &'a Row,
viewer: &'b JsonViewer,
) -> Option<&'b str> {
match &row.value {
Value::OpenContainer { .. } | Value::CloseContainer { .. } => None,
_ => {
let range = row.range.clone();
if let Value::String = &row.value {
Some(&viewer.flatjson.1[range.start + 1..range.end - 1])
} else {
Some(&viewer.flatjson.1[range])
}
}
}
}

// input.data.viewer.gameDetail.plays[3].playStats[0].gsisPlayer.id filename.>
// input.data.viewer.gameDetail.plays[3].playStats[0].gsisPlayer.id fi>
// // Path also shrinks if needed
Expand Down Expand Up @@ -489,15 +509,57 @@ impl ScreenWriter {
}

pub fn scroll_focused_line_right(&mut self, viewer: &JsonViewer, count: usize) {
unimplemented!();
self.scroll_focused_line(viewer, count, true);
}

pub fn scroll_focused_line_left(&mut self, viewer: &JsonViewer, count: usize) {
unimplemented!();
self.scroll_focused_line(viewer, count, false);
}

pub fn scroll_focused_line(&mut self, viewer: &JsonViewer, count: usize, to_right: bool) {
let row = viewer.focused_row;
let tsv = self.truncated_row_value_views.get(&row);
if let Some(tsv) = tsv {
// Make tsv not a reference.
let mut tsv = *tsv;
let value_ref = self
.line_primitive_value_ref(&viewer.flatjson[row], &viewer)
.unwrap();
if tsv.range.is_none() {
return;
}
for _ in 0..count {
if to_right {
tsv = tsv.scroll_right(value_ref);
} else {
tsv = tsv.scroll_left(value_ref);
}
}
self.truncated_row_value_views
.insert(viewer.focused_row, tsv);
} else {
return;
}
}

pub fn scroll_focused_line_to_an_end(&mut self, viewer: &JsonViewer) {
unimplemented!();
let row = viewer.focused_row;
let tsv = self.truncated_row_value_views.get(&row);
if let Some(tsv) = tsv {
// Make tsv not a reference.
let mut tsv = *tsv;
let value_ref = self
.line_primitive_value_ref(&viewer.flatjson[row], &viewer)
.unwrap();
if tsv.range.is_none() {
return;
}
tsv = tsv.jump_to_an_end(value_ref);
self.truncated_row_value_views
.insert(viewer.focused_row, tsv);
} else {
return;
}
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/truncatedstrview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use unicode_width::UnicodeWidthStr;
/// much space the view takes up, including ellipses.
#[derive(Debug, Copy, Clone)]
pub struct TruncatedStrView {
range: Option<TruncatedRange>,
pub range: Option<TruncatedRange>,
available_space: isize,
}

Expand Down Expand Up @@ -54,7 +54,7 @@ pub struct TruncatedStrView {
///
/// This range also keeps track of how much space it takes up.
#[derive(Debug, Copy, Clone)]
struct TruncatedRange {
pub struct TruncatedRange {
start: usize,
end: usize,
showing_replacement_character: bool,
Expand Down Expand Up @@ -223,7 +223,7 @@ impl TruncatedStrView {
}

/// Scrolls a string view to the left by at least one character.
fn scroll_left(&self, s: &str) -> TruncatedStrView {
pub fn scroll_left(&self, s: &str) -> TruncatedStrView {
if self.range.is_none() {
return self.clone();
}
Expand Down Expand Up @@ -261,7 +261,7 @@ impl TruncatedStrView {
/// Normally we will always jump to the back of the string, unless
/// we are already showing the back of the string, in which case we
/// will jump to the front.
fn jump_to_an_end(&self, s: &str) -> TruncatedStrView {
pub fn jump_to_an_end(&self, s: &str) -> TruncatedStrView {
match self.range {
None => self.clone(),
Some(range) => {
Expand Down

0 comments on commit 655c538

Please sign in to comment.