Skip to content

Commit

Permalink
Initial Support for Visual mode
Browse files Browse the repository at this point in the history
Signed-off-by: Ahmed <>
  • Loading branch information
Ahmed committed Sep 15, 2024
1 parent 296bf2d commit 13e411a
Show file tree
Hide file tree
Showing 15 changed files with 717 additions and 1 deletion.
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ members = [
"rair",
"test_file",
"trees",
"visual",
]

[workspace.dependencies]
Expand All @@ -24,6 +25,7 @@ nom = "7.1.3"
parking_lot="0.12.3"
pest = "2.7.12"
pest_derive = "2.7.12"
ratatui = "0.28.1"
rustyline = "14.0.0"
rustyline-derive = "0.10.0"
serde = "1.0"
Expand All @@ -32,14 +34,15 @@ serde_json = "1.0"
tempfile = "3.12.0"
yansi = "1.0.1"

rair = {path = "./rair"}
rair-cmd = {path = "./cmd"}
rair-core = {path = "./core"}
rair-env = {path = "./env"}
rair-eval = {path = "./eval"}
test_file = {path = "./test_file"}
rair-io = {path = "./io"}
rair-trees = {path = "./trees"}

rair-visual = {path = "./visual"}
[profile.release]
codegen-units = 1
lto = "fat"
Expand Down
1 change: 1 addition & 0 deletions rair/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ rair-core = {workspace = true}
rair-eval = {workspace = true}
rair-io = {workspace = true}
rair-trees = {workspace = true}
rair-visual = {workspace = true}
rustyline = {workspace = true}
rustyline-derive = {workspace = true}
yansi = {workspace = true}
Expand Down
2 changes: 2 additions & 0 deletions rair/src/rair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ use cli::Args;
use core::mem;
use init::init_editor_from_core;
use rair_core::{panic_msg, Core, Writer};
use rair_visual::register_visual;
use rpel::prompt_read_parse_evaluate_loop;

fn main() {
let mut core = Core::new();
register_visual(&mut core);
let editor = init_editor_from_core(&mut core);
let args = Args::parse().unwrap_or_else(|e| panic_msg(&mut core, &e, ""));
match args {
Expand Down
11 changes: 11 additions & 0 deletions visual/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "rair-visual"
version = "0.1.0"
edition = "2021"

[dependencies]
parking_lot = {workspace = true}
rair-core ={workspace = true}
rair-eval = {workspace = true}
rair-io = {workspace = true}
ratatui = {workspace = true}
14 changes: 14 additions & 0 deletions visual/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
mod visual_hex;

use parking_lot::Mutex;
use rair_core::Core;
use std::sync::Arc;
use visual_hex::VisualHex;

pub fn register_visual(core: &mut Core) {
core.add_command(
"visualHex",
"vx",
Arc::new(Mutex::new(VisualHex::default())),
);
}
33 changes: 33 additions & 0 deletions visual/src/visual_hex/addresses.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use super::VisualHex;
use rair_core::Core;
use ratatui::prelude::*;
use std::iter::once;

impl VisualHex {
/// Finds the maximum width of any address that will be currently rendered
pub(super) fn max_address_str_width(&mut self, core: &mut Core, chunk: &Rect) -> u16 {
let loc = core.get_loc();
let size = self.calculate_bytes_to_render(chunk);
// we don't put the address of the last bytes, but we put the address
// and then the last byte is 16 + that address.
let max_loc = loc.saturating_add(size).saturating_sub(16);
format!("0x{:08x} ", max_loc).len() as u16
}
/// renders the column of all addresses + header
pub(super) fn render_addresses(&mut self, f: &mut Frame, chunk: Rect, core: &mut Core) {
// TODO center the header
let header = format!("{}", core.mode);
let loc = core.get_loc();
// TODO overflow here
let addresses = (1..chunk.height as u64).map(|i| format!("0x{:08x} ", loc + 16 * (i - 1)));
let env = core.env.read();
let color = env.get_str("printHex.headerColor").unwrap();
let (r, g, b) = env.get_color(color).unwrap();
let lines: Vec<_> = once(header)
.chain(addresses)
.map(|s| Line::from(Span::styled(s, Style::default().fg(Color::Rgb(r, g, b)))))
.collect();
let text = Text::from(lines);
f.render_widget(text, chunk);
}
}
70 changes: 70 additions & 0 deletions visual/src/visual_hex/ascii.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use super::{mode::Mode, VisualHex};
use rair_core::Core;
use ratatui::prelude::*;
use std::collections::BTreeMap;

type Rgb = (u8, u8, u8);

impl VisualHex {
fn ascii_banner<'a>(&self, core: &Core) -> Line<'a> {
let env = core.env.read();
let color = env.get_str("printHex.headerColor").unwrap();
let (r, g, b) = env.get_color(color).unwrap();
Line::from(Span::styled(
"0123456789ABCDEF",
Style::default().fg(Color::Rgb(r, g, b)),
))
}
fn ascii_line<'a>(
&self,
loc: u64,
data: &BTreeMap<u64, u8>,
gap: &'a str,
no_print: &'a str,
na: Rgb,
) -> Line<'a> {
let mut spans = Vec::with_capacity(16);
for j in 0..16 {
let span = if let Some(c) = data.get(&(j + loc)) {
if *c >= 0x21 && *c <= 0x7E {
Span::from(format!("{}", *c as char))
} else {
Span::styled(no_print, Style::default().fg(Color::Rgb(na.0, na.1, na.2)))
}
} else {
Span::from(gap)
};
let span = if let Mode::Edit(editor) = &self.mode {
editor.span_ascii(span, loc + j)
} else {
span
};
spans.push(span);
}
Line::default().spans(spans)
}
pub(super) fn render_ascii(
&self,
f: &mut Frame,
chunk: Rect,
core: &Core,
data: &BTreeMap<u64, u8>,
) {
let mut lines: Vec<Line<'_>> = Vec::with_capacity(chunk.height as usize + 1);
lines.push(self.ascii_banner(core));

let env = core.env.read();
let gap: &str = env.get_str("printHex.gapReplace").unwrap();
let color = env.get_str("printHex.nonPrintColor").unwrap();
let na = core.env.read().get_color(color).unwrap();
let no_print = env.get_str("printHex.nonPrintReplace").unwrap();

let loc = core.get_loc();

for i in 0..chunk.height as u64 {
lines.push(self.ascii_line(loc + i * 16, data, gap, no_print, na));
}
let txt = Text::from(lines);
f.render_widget(txt, chunk);
}
}
51 changes: 51 additions & 0 deletions visual/src/visual_hex/command.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use ratatui::{
layout::{Position, Rect},
text::Line,
Frame,
};
use std::cmp::max;

#[derive(Default)]
pub struct Command {
input: String,
cursor: usize,
}

impl Command {
pub fn move_cursor_left(&mut self) {
self.cursor = self.cursor.saturating_sub(1);
}
pub fn move_cursor_right(&mut self) {
self.cursor = max(self.cursor.saturating_add(1), self.input.len())
}
pub fn delete_char(&mut self) {
if self.cursor == 0 {
return;
}
let from_left_to_custor = self.cursor - 1;
// Getting all characters before the selected character.
let before_char_to_delete = self.input.chars().take(from_left_to_custor);
// Getting all characters after selected character.
let after_char_to_delete = self.input.chars().skip(self.cursor);
self.input = before_char_to_delete.chain(after_char_to_delete).collect();
self.move_cursor_left();
}
pub fn enter_char(&mut self, c: char) {
let index = self
.input
.char_indices()
.map(|(i, _)| i)
.nth(self.cursor)
.unwrap_or(self.input.len());
self.input.insert(index, c);
self.move_cursor_right();
}
pub fn get_str(&self) -> &str {
&self.input
}
pub fn render(&self, f: &mut Frame, chunk: Rect) {
let input = Line::from(format!(":{}", self.input));
f.render_widget(input, chunk);
f.set_cursor_position(Position::new(chunk.x + self.cursor as u16 + 1, chunk.y));
}
}
Loading

0 comments on commit 13e411a

Please sign in to comment.