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 22, 2024
1 parent 1f0d873 commit b57b14c
Show file tree
Hide file tree
Showing 25 changed files with 1,302 additions and 12 deletions.
8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ members = [
"rair",
"test_file",
"trees",
"visual",
]

[workspace.dependencies]
base64 = "0.22.1"
bitflags = "2.6.0"
clap = "4.5.17"
cli-clipboard = "0.4.0"
copypasta = "0.10.1"
directories = "5.0.1"
err-derive = "0.3.1"
flate2 = "1.0.33"
Expand All @@ -24,22 +27,25 @@ 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"
serde_cbor = "0.11.2"
serde_json = "1.0"
tempfile = "3.12.0"
winit = "0.30.5"
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: 0 additions & 1 deletion core/src/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ pub struct CmdFunctions {
}

#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub enum AddrMode {
Vir,
Phy,
Expand Down
4 changes: 2 additions & 2 deletions core/src/hex/hex_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{is_color, Core, Writer};
use std::io::Write;
use yansi::Paint;

#[derive(Clone)]
#[derive(Clone, Default)]
pub struct HexEnv {
// color for banner and offsets
pub banner: (u8, u8, u8),
Expand Down Expand Up @@ -89,7 +89,7 @@ impl HexEnv {
separator: String::new(),
}
}
pub(super) fn get_env(&mut self, core: &mut Core) -> &Self {
pub fn get_env(&mut self, core: &mut Core) -> &Self {
let env = core.env.read();
let color = env.get_str("hex.headerColor").unwrap();
self.banner = env.get_color(color).unwrap();
Expand Down
1 change: 1 addition & 0 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ pub use self::commands::*;
pub use self::core::*;
pub use self::diff::*;
pub use self::helper::*;
pub use self::hex::*;
pub use self::io::*;
pub use self::writer::*;
23 changes: 15 additions & 8 deletions eval/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use core::mem;
use core::mem::{replace, swap, take};
use rair_cmd::{Argument, Cmd, ParseTree, RedPipe};
use rair_core::{Core, Writer};
use std::{
Expand All @@ -7,6 +7,13 @@ use std::{
process::{Child, Command, Stdio},
};

pub fn rair_eval_no_out(core: &mut Core, line: &str) {
let stdout = take(&mut core.stdout);
let stderr = take(&mut core.stderr);
rair_eval(core, line);
core.stdout = stdout;
core.stderr = stderr;

Check warning on line 15 in eval/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

eval/src/lib.rs#L10-L15

Added lines #L10 - L15 were not covered by tests
}
pub fn rair_eval(core: &mut Core, line: &str) {
match ParseTree::construct(line) {
Ok(tree) => evaluate(core, tree),
Expand Down Expand Up @@ -37,17 +44,17 @@ fn run_cmd(core: &mut Core, cmd: Cmd) {
let mut child: Option<Child> = None;
match *cmd.red_pipe {
RedPipe::Redirect(arg) => match create_redirect(core, *arg) {
Ok(out) => stdout = Some(mem::replace(&mut core.stdout, out)),
Ok(out) => stdout = Some(replace(&mut core.stdout, out)),

Check warning on line 47 in eval/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

eval/src/lib.rs#L47

Added line #L47 was not covered by tests
Err(e) => return writeln!(core.stderr, "{e}").unwrap(),
},
RedPipe::RedirectCat(arg) => match create_redirect_cat(core, *arg) {
Ok(out) => stdout = Some(mem::replace(&mut core.stdout, out)),
Ok(out) => stdout = Some(replace(&mut core.stdout, out)),

Check warning on line 51 in eval/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

eval/src/lib.rs#L51

Added line #L51 was not covered by tests
Err(e) => return writeln!(core.stderr, "{e}").unwrap(),
},
RedPipe::Pipe(arg) => match create_pipe(core, arg) {
Ok((process, writer)) => {
child = Some(process);
stdout = Some(mem::replace(&mut core.stdout, writer));
stdout = Some(replace(&mut core.stdout, writer));

Check warning on line 57 in eval/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

eval/src/lib.rs#L57

Added line #L57 was not covered by tests
}
Err(e) => return writeln!(core.stderr, "{e}").unwrap(),
},
Expand Down Expand Up @@ -123,13 +130,13 @@ fn eval_non_literal_arg(core: &mut Core, cmd: Cmd) -> Result<String, String> {
// change stderr and stdout
let mut stderr = Writer::new_buf();
let mut stdout = Writer::new_buf();
mem::swap(&mut core.stderr, &mut stderr);
mem::swap(&mut core.stdout, &mut stdout);
swap(&mut core.stderr, &mut stderr);
swap(&mut core.stdout, &mut stdout);

Check warning on line 134 in eval/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

eval/src/lib.rs#L133-L134

Added lines #L133 - L134 were not covered by tests
// run command
run_cmd(core, cmd);
// restore stderr and stdout
mem::swap(&mut core.stderr, &mut stderr);
mem::swap(&mut core.stdout, &mut stdout);
swap(&mut core.stderr, &mut stderr);
swap(&mut core.stdout, &mut stdout);

Check warning on line 139 in eval/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

eval/src/lib.rs#L138-L139

Added lines #L138 - L139 were not covered by tests

let err = stderr.utf8_string().unwrap();
if err.is_empty() {
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_commands;
use rpel::prompt_read_parse_evaluate_loop;

fn main() {
let mut core = Core::new();
register_commands(&mut core);

Check warning on line 19 in rair/src/rair.rs

View check run for this annotation

Codecov / codecov/patch

rair/src/rair.rs#L19

Added line #L19 was not covered by tests
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
13 changes: 13 additions & 0 deletions visual/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "rair-visual"
version = "0.1.0"
edition = "2021"

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

use rair_core::Core;
use visual_hex::VisualHex;

pub fn register_commands(core: &mut Core) {
let vx = VisualHex::new(core);
core.add_command(vx);

Check warning on line 8 in visual/src/commands/mod.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/mod.rs#L6-L8

Added lines #L6 - L8 were not covered by tests
}
35 changes: 35 additions & 0 deletions visual/src/commands/visual_hex/addresses.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use crate::visual_hex::VisualHexEnv;

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);

Check warning on line 12 in visual/src/commands/visual_hex/addresses.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/addresses.rs#L10-L12

Added lines #L10 - L12 were not covered by tests
// 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

Check warning on line 16 in visual/src/commands/visual_hex/addresses.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/addresses.rs#L15-L16

Added lines #L15 - L16 were not covered by tests
}
/// renders the column of all addresses + header
pub(super) fn render_addresses(

Check warning on line 19 in visual/src/commands/visual_hex/addresses.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/addresses.rs#L19

Added line #L19 was not covered by tests
&mut self,
f: &mut Frame,
chunk: Rect,
core: &mut Core,
env: &VisualHexEnv,
) {
// TODO center the header
let banner = env.render_addresses_banner(core);
let loc = core.get_loc();

Check warning on line 28 in visual/src/commands/visual_hex/addresses.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/addresses.rs#L27-L28

Added lines #L27 - L28 were not covered by tests
// TODO overflow here
let addresses = (1..chunk.height as u64).map(|i| env.render_addresses(loc + 16 * (i - 1)));
let lines: Vec<_> = once(banner).chain(addresses).collect();
let text = Text::from(lines);
f.render_widget(text, chunk);

Check warning on line 33 in visual/src/commands/visual_hex/addresses.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/addresses.rs#L30-L33

Added lines #L30 - L33 were not covered by tests
}
}
47 changes: 47 additions & 0 deletions visual/src/commands/visual_hex/ascii.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use crate::visual_hex::VisualHexEnv;

use super::{mode::Mode, VisualHex};
use rair_core::Core;
use ratatui::prelude::*;
use std::collections::BTreeMap;

impl VisualHex {
fn ascii_line<'a>(

Check warning on line 9 in visual/src/commands/visual_hex/ascii.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/ascii.rs#L9

Added line #L9 was not covered by tests
&self,
loc: u64,
data: &BTreeMap<u64, u8>,
env: &'a VisualHexEnv,
) -> Line<'a> {
let mut spans = Vec::with_capacity(16);
for j in 0..16 {
let byte = data.get(&(j + loc)).copied();
let span = env.render_ascii(byte);
let span = match &self.mode {
Mode::Edit(editor) => editor.span_ascii(span, loc + j),
Mode::Select(selector) => selector.span_ascii(span, loc + j),
_ => span,

Check warning on line 22 in visual/src/commands/visual_hex/ascii.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/ascii.rs#L15-L22

Added lines #L15 - L22 were not covered by tests
};
spans.push(span);

Check warning on line 24 in visual/src/commands/visual_hex/ascii.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/ascii.rs#L24

Added line #L24 was not covered by tests
}
Line::default().spans(spans)

Check warning on line 26 in visual/src/commands/visual_hex/ascii.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/ascii.rs#L26

Added line #L26 was not covered by tests
}
pub(super) fn render_ascii(

Check warning on line 28 in visual/src/commands/visual_hex/ascii.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/ascii.rs#L28

Added line #L28 was not covered by tests
&self,
f: &mut Frame,
chunk: Rect,
core: &Core,
data: &BTreeMap<u64, u8>,
env: &VisualHexEnv,
) {
let mut lines: Vec<Line<'_>> = Vec::with_capacity(chunk.height as usize + 1);
lines.push(env.render_ascii_banner());

Check warning on line 37 in visual/src/commands/visual_hex/ascii.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/ascii.rs#L36-L37

Added lines #L36 - L37 were not covered by tests

let loc = core.get_loc();

Check warning on line 39 in visual/src/commands/visual_hex/ascii.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/ascii.rs#L39

Added line #L39 was not covered by tests

for i in 0..chunk.height as u64 {
lines.push(self.ascii_line(loc + i * 16, data, env));

Check warning on line 42 in visual/src/commands/visual_hex/ascii.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/ascii.rs#L41-L42

Added lines #L41 - L42 were not covered by tests
}
let txt = Text::from(lines);
f.render_widget(txt, chunk);

Check warning on line 45 in visual/src/commands/visual_hex/ascii.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/ascii.rs#L44-L45

Added lines #L44 - L45 were not covered by tests
}
}
51 changes: 51 additions & 0 deletions visual/src/commands/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);

Check warning on line 16 in visual/src/commands/visual_hex/command.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/command.rs#L15-L16

Added lines #L15 - L16 were not covered by tests
}
pub fn move_cursor_right(&mut self) {
self.cursor = max(self.cursor.saturating_add(1), self.input.len())

Check warning on line 19 in visual/src/commands/visual_hex/command.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/command.rs#L18-L19

Added lines #L18 - L19 were not covered by tests
}
pub fn delete_char(&mut self) {
if self.cursor == 0 {

Check warning on line 22 in visual/src/commands/visual_hex/command.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/command.rs#L21-L22

Added lines #L21 - L22 were not covered by tests
return;
}
let from_left_to_custor = self.cursor - 1;

Check warning on line 25 in visual/src/commands/visual_hex/command.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/command.rs#L25

Added line #L25 was not covered by tests
// Getting all characters before the selected character.
let before_char_to_delete = self.input.chars().take(from_left_to_custor);

Check warning on line 27 in visual/src/commands/visual_hex/command.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/command.rs#L27

Added line #L27 was not covered by tests
// 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();

Check warning on line 31 in visual/src/commands/visual_hex/command.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/command.rs#L29-L31

Added lines #L29 - L31 were not covered by tests
}
pub fn enter_char(&mut self, c: char) {
let index = self

Check warning on line 34 in visual/src/commands/visual_hex/command.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/command.rs#L33-L34

Added lines #L33 - L34 were not covered by tests
.input
.char_indices()
.map(|(i, _)| i)
.nth(self.cursor)
.unwrap_or(self.input.len());
self.input.insert(index, c);
self.move_cursor_right();

Check warning on line 41 in visual/src/commands/visual_hex/command.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/command.rs#L37-L41

Added lines #L37 - L41 were not covered by tests
}
pub fn get_str(&self) -> &str {
&self.input

Check warning on line 44 in visual/src/commands/visual_hex/command.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/command.rs#L43-L44

Added lines #L43 - L44 were not covered by tests
}
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));

Check warning on line 49 in visual/src/commands/visual_hex/command.rs

View check run for this annotation

Codecov / codecov/patch

visual/src/commands/visual_hex/command.rs#L46-L49

Added lines #L46 - L49 were not covered by tests
}
}
Loading

0 comments on commit b57b14c

Please sign in to comment.