partial line rendering
This commit is contained in:
+84
-8
@@ -13,16 +13,24 @@ impl Widget for &App {
|
|||||||
let (chunks, remainder) = bytes_to_render
|
let (chunks, remainder) = bytes_to_render
|
||||||
.as_chunks::<BYTES_PER_LINE>();
|
.as_chunks::<BYTES_PER_LINE>();
|
||||||
|
|
||||||
assert!(remainder.is_empty());
|
|
||||||
|
|
||||||
let hex_lines = chunks
|
let hex_lines = chunks
|
||||||
.iter()
|
.iter()
|
||||||
.zip((self.scroll_position..).step_by(BYTES_PER_LINE))
|
.zip((self.scroll_position..).step_by(BYTES_PER_LINE))
|
||||||
.map(|(bytes, address)| self.render_line(address, bytes));
|
.map(|(bytes, address)| self.render_line(address, bytes));
|
||||||
|
|
||||||
let hex_area_text: Text = hex_lines.collect();
|
let remainder_address = bytes_end - remainder.len();
|
||||||
|
let remainder_line = if !remainder.is_empty() {
|
||||||
|
Some(self.render_partial_line(remainder_address, remainder))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let hex_text: Text = hex_lines
|
||||||
|
.chain(remainder_line)
|
||||||
|
.collect();
|
||||||
|
|
||||||
let hex_area = Rect::new(area.x, area.y, area.width, area.height - 1);
|
let hex_area = Rect::new(area.x, area.y, area.width, area.height - 1);
|
||||||
hex_area_text.render(hex_area, buf);
|
hex_text.render(hex_area, buf);
|
||||||
|
|
||||||
let status_line_area = Rect::new(area.x, area.bottom() - 1, area.width, 1);
|
let status_line_area = Rect::new(area.x, area.bottom() - 1, area.width, 1);
|
||||||
self.render_status_line().render(status_line_area, buf);
|
self.render_status_line().render(status_line_area, buf);
|
||||||
@@ -42,6 +50,15 @@ impl App {
|
|||||||
.chain(character_panel::render_character_panel(bytes))
|
.chain(character_panel::render_character_panel(bytes))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(mismatched_lifetime_syntaxes)]
|
||||||
|
fn render_partial_line(&self, address: usize, bytes: &[u8]) -> Line {
|
||||||
|
iter::once(address::render_address(address))
|
||||||
|
.chain(self.render_partial_chunks(address, bytes))
|
||||||
|
.chain(iter::once(" ".into()))
|
||||||
|
.chain(character_panel::render_character_panel(bytes))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod address {
|
mod address {
|
||||||
@@ -57,7 +74,7 @@ mod address {
|
|||||||
|
|
||||||
mod hex {
|
mod hex {
|
||||||
use std::{borrow::Cow, mem};
|
use std::{borrow::Cow, mem};
|
||||||
use itertools::Itertools;
|
use itertools::{Itertools, repeat_n};
|
||||||
use ratatui::{style::{Color, Style, Stylize}, text::Span};
|
use ratatui::{style::{Color, Style, Stylize}, text::Span};
|
||||||
|
|
||||||
use crate::{BYTES_PER_CHUNK, BYTES_PER_LINE, CHUNKS_PER_LINE, app::App, cardinality::HasCardinality, cursor::InCursor, empty_span::empty_span, custom_greys::CustomGreys};
|
use crate::{BYTES_PER_CHUNK, BYTES_PER_LINE, CHUNKS_PER_LINE, app::App, cardinality::HasCardinality, cursor::InCursor, empty_span::empty_span, custom_greys::CustomGreys};
|
||||||
@@ -70,7 +87,7 @@ mod hex {
|
|||||||
) -> impl Iterator<Item=Span<'static>> {
|
) -> impl Iterator<Item=Span<'static>> {
|
||||||
let (chunks, remainder) = bytes.as_chunks::<BYTES_PER_CHUNK>();
|
let (chunks, remainder) = bytes.as_chunks::<BYTES_PER_CHUNK>();
|
||||||
|
|
||||||
assert!(remainder.is_empty());
|
assert!(remainder.is_empty(), "BYTES_PER_LINE should be a multiple of BYTES_PER_CHUNK");
|
||||||
|
|
||||||
#[allow(unstable_name_collisions)]
|
#[allow(unstable_name_collisions)]
|
||||||
chunks
|
chunks
|
||||||
@@ -88,6 +105,46 @@ mod hex {
|
|||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn render_partial_chunks(
|
||||||
|
&self,
|
||||||
|
address: usize,
|
||||||
|
bytes: &[u8]
|
||||||
|
) -> impl Iterator<Item=Span<'static>> {
|
||||||
|
let (chunks, remainder) = bytes.as_chunks::<BYTES_PER_CHUNK>();
|
||||||
|
|
||||||
|
let remainder_address = address + chunks.len() * BYTES_PER_CHUNK;
|
||||||
|
let remainder_chunks: Option<Vec<_>> = if !remainder.is_empty() {
|
||||||
|
Some(self.render_partial_chunk(remainder_address, remainder).collect())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let chunks_rendered = chunks.len() + remainder_chunks.iter().len();
|
||||||
|
let chunks_not_rendered = CHUNKS_PER_LINE - chunks_rendered;
|
||||||
|
let spaces_per_chunk = BYTES_PER_CHUNK - 1;
|
||||||
|
let bytes_not_rendered = BYTES_PER_LINE - bytes.len();
|
||||||
|
|
||||||
|
let padding_width = 2 * bytes_not_rendered +
|
||||||
|
spaces_per_chunk * chunks_not_rendered;
|
||||||
|
|
||||||
|
#[allow(unstable_name_collisions)]
|
||||||
|
chunks
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.zip((address..).step_by(BYTES_PER_CHUNK))
|
||||||
|
.map(|(chunk, address)| self.render_chunk(address, &chunk).collect())
|
||||||
|
.chain(remainder_chunks)
|
||||||
|
.interleave(
|
||||||
|
(address..)
|
||||||
|
.step_by(BYTES_PER_CHUNK)
|
||||||
|
.take(CHUNKS_PER_LINE)
|
||||||
|
.skip(1)
|
||||||
|
.map(|address| vec![self.render_large_space_before(address)])
|
||||||
|
)
|
||||||
|
.flatten()
|
||||||
|
.chain(repeat_n(" ".into(), padding_width))
|
||||||
|
}
|
||||||
|
|
||||||
fn render_chunk(
|
fn render_chunk(
|
||||||
&self,
|
&self,
|
||||||
address: usize,
|
address: usize,
|
||||||
@@ -107,6 +164,25 @@ mod hex {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_partial_chunk(
|
||||||
|
&self,
|
||||||
|
address: usize,
|
||||||
|
bytes: &[u8]
|
||||||
|
) -> impl Iterator<Item=Span<'static>> {
|
||||||
|
#[allow(unstable_name_collisions)]
|
||||||
|
bytes
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.zip(address..)
|
||||||
|
.map(|(byte, address)| self.render_byte_at(address, byte))
|
||||||
|
.interleave(
|
||||||
|
(address..)
|
||||||
|
.take(BYTES_PER_CHUNK)
|
||||||
|
.skip(1)
|
||||||
|
.map(|address| self.render_space_before(address))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn render_byte_at(
|
fn render_byte_at(
|
||||||
&self,
|
&self,
|
||||||
address: usize,
|
address: usize,
|
||||||
@@ -201,10 +277,10 @@ mod character_panel {
|
|||||||
use std::{borrow::Cow, mem};
|
use std::{borrow::Cow, mem};
|
||||||
use ratatui::{style::{Color, Style}, text::Span};
|
use ratatui::{style::{Color, Style}, text::Span};
|
||||||
|
|
||||||
use crate::{BYTES_PER_LINE, cardinality::HasCardinality, empty_span::empty_span};
|
use crate::{cardinality::HasCardinality, empty_span::empty_span};
|
||||||
|
|
||||||
pub fn render_character_panel(
|
pub fn render_character_panel(
|
||||||
bytes: &[u8; BYTES_PER_LINE]
|
bytes: &[u8]
|
||||||
) -> impl Iterator<Item=Span<'static>> {
|
) -> impl Iterator<Item=Span<'static>> {
|
||||||
bytes
|
bytes
|
||||||
.iter()
|
.iter()
|
||||||
|
|||||||
+24
-2
@@ -14,12 +14,13 @@ const BYTES_PER_CHUNK: usize = 4;
|
|||||||
const CHUNKS_PER_LINE: usize = BYTES_PER_LINE / BYTES_PER_CHUNK;
|
const CHUNKS_PER_LINE: usize = BYTES_PER_LINE / BYTES_PER_CHUNK;
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
|
// - refactor input system
|
||||||
|
// - undo/redo
|
||||||
|
// - x/X
|
||||||
// - modes
|
// - modes
|
||||||
// - select
|
// - select
|
||||||
// - insert
|
// - insert
|
||||||
// - zz/zt/zb
|
// - zz/zt/zb
|
||||||
// - search
|
|
||||||
// - jumplist
|
|
||||||
// - modifications
|
// - modifications
|
||||||
// - insert/append
|
// - insert/append
|
||||||
// - mode
|
// - mode
|
||||||
@@ -29,6 +30,27 @@ const CHUNKS_PER_LINE: usize = BYTES_PER_LINE / BYTES_PER_CHUNK;
|
|||||||
// - mode
|
// - mode
|
||||||
// - delete
|
// - delete
|
||||||
// - change
|
// - change
|
||||||
|
// - highlight cursor in character panel too (but lighter?)
|
||||||
|
// - edit too
|
||||||
|
// - modifier on existing keys like teehee? or jump to panel?
|
||||||
|
// - search
|
||||||
|
// - jumplist
|
||||||
|
// - f/t
|
||||||
|
// - ascii?
|
||||||
|
// - [/] to cycle view offset?
|
||||||
|
// - J jump to offset
|
||||||
|
|
||||||
|
// future directions
|
||||||
|
// - switch between cursor size u8s/u16s/u32s/u64s?
|
||||||
|
// - +/-
|
||||||
|
// - multi-cursor
|
||||||
|
// - s/C
|
||||||
|
// - split selection by u8/16/32/etc
|
||||||
|
// - 'views' for bytes (i8/16/etc u8/16/etc 20.12/8.4/etc)
|
||||||
|
// - how to fit??! `-128` longer than `80`
|
||||||
|
// - mark offsets?
|
||||||
|
// - utf8?
|
||||||
|
// - diffing
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut app = App::init();
|
let mut app = App::init();
|
||||||
|
|||||||
Reference in New Issue
Block a user