Skip to content

Commit

Permalink
Additional polish to the hex editor and segment views
Browse files Browse the repository at this point in the history
  • Loading branch information
cayb0rg committed Feb 5, 2024
1 parent 539903a commit d206069
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 243 deletions.
275 changes: 83 additions & 192 deletions src/bin/main.rs

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions src/parser/parser_assembler_main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub fn parser(file_string: String) -> (ProgramInfo, Vec<u32>) {
&mut program_info.monaco_line_info,
);

let binary = create_binary_vec(program_info.instructions.clone(), vec_of_data);
let (binary, data_starting_point) = create_binary_vec(program_info.instructions.clone(), vec_of_data);

for entry in &program_info.monaco_line_info {
program_info
Expand All @@ -65,6 +65,7 @@ pub fn parser(file_string: String) -> (ProgramInfo, Vec<u32>) {
}

program_info.pc_starting_point = determine_pc_starting_point(labels);
program_info.data_starting_point = data_starting_point;

(program_info.clone(), binary)
}
Expand Down Expand Up @@ -1531,13 +1532,15 @@ pub fn determine_pc_starting_point(labels: HashMap<String, usize>) -> usize {
}

///Creates a vector of u32 from the data found in the parser / assembler to put into memory.
pub fn create_binary_vec(instructions: Vec<Instruction>, mut vec_of_data: Vec<u8>) -> Vec<u32> {
pub fn create_binary_vec(instructions: Vec<Instruction>, mut vec_of_data: Vec<u8>) -> (Vec<u32>, usize) {
//push all instructions
let mut binary: Vec<u32> = Vec::new();
for instruction in instructions {
binary.push(instruction.binary);
}

let data_starting_point = binary.len();

//makes sure the byte array length is a multiple of 4
let mut mod4 = 4 - (vec_of_data.len() % 4);
if mod4 == 4 {
Expand All @@ -1563,5 +1566,5 @@ pub fn create_binary_vec(instructions: Vec<Instruction>, mut vec_of_data: Vec<u8
i += 1;
}

binary
(binary, data_starting_point)
}
1 change: 1 addition & 0 deletions src/parser/parser_structs_and_enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub struct ProgramInfo {
pub instructions: Vec<Instruction>,
pub data: Vec<Data>,
pub pc_starting_point: usize,
pub data_starting_point: usize,
}

#[derive(Clone, Debug, Default, Eq, PartialEq)]
Expand Down
2 changes: 1 addition & 1 deletion src/tests/parser/parser_assembler_main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -886,7 +886,7 @@ fn create_binary_vec_works_with_data() {
&mut program_info.monaco_line_info,
);

let result = create_binary_vec(program_info.instructions.clone(), vec_of_data);
let (result, _) = create_binary_vec(program_info.instructions.clone(), vec_of_data);

assert_eq!(result[3], 0b01110100011010000110100101110011);
assert_eq!(result[4], 0b00100000011010010111001100100000);
Expand Down
70 changes: 43 additions & 27 deletions src/ui/assembled_view/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ pub struct DataSegmentProps {
pub program_info: ProgramInfo,
pub binary: Vec<u32>,
pub lines_content: Rc<RefCell<Vec<String>>>,
pub memory_curr_instr: UseStateHandle<u64>,
pub editor_curr_line: UseStateHandle<f64>,
pub editor_active_tab: UseStateHandle<EditorTabState>,
pub console_active_tab: UseStateHandle<ConsoleTabState>,
pub pc_limit: usize
}

#[function_component]
Expand All @@ -40,7 +45,7 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html {
let executed_ref = use_node_ref();

{
// Always scroll to the executed row on re-render
// Always scroll to the executed row on execution
let executed_row = executed_ref.cast::<HtmlElement>();
if let Some(executed_row) = executed_row {
let mut options = web_sys::ScrollIntoViewOptions::new();
Expand All @@ -60,16 +65,18 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html {

});

// Go to the memory address in hex editor
let on_address_click = {
let memory_curr_instr = memory_curr_instr.clone();
let console_active_tab = console_active_tab.clone();
use_callback(move |args: (MouseEvent, i64), memory_curr_instr| {
use_callback(move |args: (MouseEvent, usize), memory_curr_instr| {
let (_e, address) = args;
memory_curr_instr.set(address as u64);
console_active_tab.set(ConsoleTabState::HexEditor);
}, memory_curr_instr)
};

// Go to the line in code editor
let on_assembled_click = {
let editor_curr_line = editor_curr_line.clone();
let editor_active_tab = editor_active_tab.clone();
Expand Down Expand Up @@ -104,15 +111,15 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html {
let line_number = instruction.line_number.clone();

let mut conditional_class = "";
if props.pc as i64 == address {
if props.pc as i64 == address + 4 {
conditional_class = "executedLine";
html!{
<tr ref={executed_ref} key={index} class={classes!("row", conditional_class)}>
<td class={classes!("bkpt")}>
<input type="checkbox" onclick={move |e: MouseEvent| {on_check.emit((e, address))}}/>
<div class="circle"></div>
</td>
<td class="address" title={format!("Go to address {:08x}", address)} onclick={move |e: MouseEvent| {on_address_click.emit((e, address))}}>
<td class="address" title={format!("Go to address in memory {:08x}", address)} onclick={move |e: MouseEvent| {on_address_click.emit((e, address as usize))}}>
{format!("0x{:08x}", address as u64)}
</td>
<td>
Expand All @@ -121,7 +128,7 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html {
<td>
{format!("0x{:08x}", instruction.binary)}
</td>
<td class="assembled-string" title="Go to line" onclick={move |e: MouseEvent| {on_assembled_click.emit((e, line_number))}}>
<td class="assembled-string" title="Go to line in editor" onclick={move |e: MouseEvent| {on_assembled_click.emit((e, line_number))}}>
{recreated_string}
</td>
<td>
Expand All @@ -137,7 +144,7 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html {
<input type="checkbox" onclick={move |e: MouseEvent| {on_check.emit((e, address))}}/>
<div class="circle"></div>
</td>
<td class="address" title={format!("Go to address {:08x}", address)} onclick={move |e: MouseEvent| {on_address_click.emit((e, address))}}>
<td class="address" title={format!("Go to address in memory {:08x}", address)} onclick={move |e: MouseEvent| {on_address_click.emit((e, address as usize))}}>
{format!("0x{:08x}", address as u64)}
</td>
<td>
Expand All @@ -146,11 +153,11 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html {
<td>
{format!("0x{:08x}", instruction.binary)}
</td>
<td class="assembled-string" title="Go to line" onclick={move |e: MouseEvent| {on_assembled_click.emit((e, line_number))}}>
<td class="assembled-string" title="Go to line in editor" onclick={move |e: MouseEvent| {on_assembled_click.emit((e, line_number))}}>
{recreated_string}
</td>
<td>
{format!("{}: {:?}", line_number, lines_content.get(line_number).unwrap_or(&String::from("")))}
{format!("{}: {:?}", line_number + 1, lines_content.get(line_number).unwrap_or(&String::from("")))}
</td>
</tr>
}
Expand All @@ -166,25 +173,32 @@ pub fn DataSegment(props: &DataSegmentProps) -> Html {
let program_info = &props.program_info;
let binary = &props.binary;
let lines_content = props.lines_content.borrow_mut().clone();
let memory_curr_instr = &props.memory_curr_instr;
let editor_curr_line = &props.editor_curr_line;
let editor_active_tab = &props.editor_active_tab;
let console_active_tab = &props.console_active_tab;

let on_address_click = Callback::from(move |args: (MouseEvent, usize)| {
let (_e, address) = args;
// let target = e.target();
// let input = target.unwrap().unchecked_into::<HtmlInputElement>();

debug!("Go to address {:08x}", address);
debug!("Go to line {:?}", (address / 4) as f64);

});

let on_assembled_click = Callback::from(move |args: (MouseEvent, usize)| {
let (_e, line_number) = args;
// let target = e.target();
// let input = target.unwrap().unchecked_into::<HtmlInputElement>();

debug!("Go to line number {:08x}", line_number);
// Go to the memory address in hex editor
let on_address_click = {
let memory_curr_instr = memory_curr_instr.clone();
let console_active_tab = console_active_tab.clone();
use_callback(move |args: (MouseEvent, usize), memory_curr_instr| {
let (_e, address) = args;
memory_curr_instr.set(address as u64);
console_active_tab.set(ConsoleTabState::HexEditor);
}, memory_curr_instr)
};

});
// Go to the line in code editor
let on_assembled_click = {
let editor_curr_line = editor_curr_line.clone();
let editor_active_tab = editor_active_tab.clone();
use_callback(move |args: (MouseEvent, usize), _| {
let (_e, line_number) = args;
editor_curr_line.set(line_number as f64);
editor_active_tab.set(EditorTabState::Editor);
}, ())
};

html! {
<table class={classes!("memory_segment")}>
Expand All @@ -198,25 +212,27 @@ pub fn DataSegment(props: &DataSegmentProps) -> Html {
{
if program_info.instructions.len() > 0 && binary.len() > 0 {
let mut address = program_info.instructions.len() * 4 - 4;
let mut data_binary_index = program_info.data_starting_point - 1;
program_info.data.iter().enumerate().map(|(index, data)| {
let recreated_string = data.recreate_string();
let on_address_click = Callback::clone(&on_address_click);
let on_assembled_click = Callback::clone(&on_assembled_click);
address += 4;
data_binary_index += 1;
html!{

<tr key={index} class={classes!("row")}>
<td class="address" title={format!("Go to address {:08x}", address)} onclick={move |e: MouseEvent| {on_address_click.emit((e, address))}}>
{format!("0x{:08x}", address as u64)}
</td>
<td>
{format!("0x{:08x}", binary[data.line_number])}
{format!("0x{:08x}", binary[data_binary_index])}
</td>
<td class="assembled-string" title="Go to line" onclick={move |e: MouseEvent| {on_assembled_click.emit((e, address))}}>
{recreated_string}
</td>
<td>
{format!("{}: {:?}", data.line_number, lines_content.get(data.line_number).unwrap_or(&String::from("")))}
{format!("{}: {:?}", data.line_number + 1, lines_content.get(data.line_number).unwrap_or(&String::from("")))}
</td>
</tr>
}
Expand Down
97 changes: 84 additions & 13 deletions src/ui/swim_editor/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ use std::{cell::RefCell, rc::Rc};

use monaco::{api::TextModel, sys::{editor::{
IEditorMinimapOptions, IEditorScrollbarOptions, IModelDecorationOptions, IModelDeltaDecoration, IStandaloneEditorConstructionOptions, ISuggestOptions, ScrollType
}, Range}, yew::{CodeEditor, CodeEditorLink}};
use yew::{Callback, Properties};
}, IMarkdownString, Range}, yew::{CodeEditor, CodeEditorLink}};
use yew::{html, Callback, Properties};
use yew_hooks::prelude::*;
use yew::prelude::*;
use wasm_bindgen::{JsCast, JsValue};

Expand All @@ -16,6 +17,7 @@ pub struct SwimEditorProps {
pub program_info: ProgramInfo,
pub binary: Vec<u32>,
pub pc: u64,
pub pc_limit: usize,
pub memory_curr_instr: UseStateHandle<u64>,
pub editor_curr_line: UseStateHandle<f64>,
pub editor_active_tab: UseStateHandle<EditorTabState>,
Expand Down Expand Up @@ -63,6 +65,11 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html {
let editor_active_tab = &props.editor_active_tab;
let console_active_tab = &props.console_active_tab;

// Setup the array that would store hover decorations applied to the
// text model and initialize the options for it.
let hover_jsarray = js_sys::Array::new();
let hover_decor_array = use_mut_ref(js_sys::Array::new);

let on_editor_created = {
let curr_line = props.editor_curr_line.clone();
let lines_content = Rc::clone(&props.lines_content);
Expand All @@ -73,16 +80,14 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html {
let raw_editor = editor.as_ref();
let model = raw_editor.get_model().unwrap();
// store each line from the original code editor's contents for assembled view
let js_lines = model.get_lines_content();
let mut string_lines = lines_content.borrow_mut();
for js_string in js_lines.into_iter() {
let string_value = match js_string.as_string() {
Some(string) => string,
None => String::from("")
};
string_lines.push(string_value);

};
let line_count = model.get_line_count() as usize;
let mut lines_content = lines_content.borrow_mut();
let mut lines = Vec::new();
for i in 1..line_count {
log::debug!("line {}: {}", i, model.get_line_content(i as f64));
lines.push(model.get_line_content(i as f64));
}
*lines_content = lines;
// Scroll to current line
raw_editor.reveal_line_in_center(**curr_line, Some(ScrollType::Smooth));
// Highlight current line using delta decorations
Expand Down Expand Up @@ -133,6 +138,72 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html {
editor_active_tab.set(new_tab);
})
};


// We'll have the Mouse Hover event running at all times.
{
let text_model = text_model.clone();
let program_info = props.program_info.clone();
use_event_with_window("mouseover", move |_: MouseEvent| {
let hover_jsarray = hover_jsarray.clone();
let hover_decor_array = hover_decor_array.clone();
let text_model = text_model.clone();
let curr_model = text_model.as_ref();

// Parse output from parser and create an instance of IModelDeltaDecoration for each line.
for (line_number, line_information) in program_info.monaco_line_info.iter().enumerate()
{
let decoration: IModelDeltaDecoration = js_sys::Object::new().unchecked_into();

let hover_range = monaco::sys::Range::new(
(line_number + 1) as f64,
0.0,
(line_number + 1) as f64,
0.0,
);
let hover_range_js = hover_range
.dyn_into::<JsValue>()
.expect("Range is not found.");
decoration.set_range(&monaco::sys::IRange::from(hover_range_js));

let hover_opts: IModelDecorationOptions = js_sys::Object::new().unchecked_into();
hover_opts.set_is_whole_line(true.into());
let hover_message: IMarkdownString = js_sys::Object::new().unchecked_into();
js_sys::Reflect::set(
&hover_message,
&JsValue::from_str("value"),
&JsValue::from_str(&line_information.mouse_hover_string),
)
.unwrap();
hover_opts.set_hover_message(&hover_message);
decoration.set_options(&hover_opts);
let hover_js = decoration
.dyn_into::<JsValue>()
.expect("Hover is not found.");
hover_jsarray.push(&hover_js);
}

// log!("This is the array after the push");
// log!(hover_jsarray.clone());

// properly pass the handlers onto the array
let new_hover_decor_array =
curr_model.delta_decorations(&hover_decor_array.borrow_mut(), &hover_jsarray, None);
*hover_decor_array.borrow_mut() = new_hover_decor_array;

// log!("These are the arrays after calling Delta Decorations");
// log!(hover_jsarray.clone());
// log!(hover_decor_array.borrow_mut().clone());

// empty out the array that hold the decorations
hover_jsarray.set_length(0);

// log!("These are the arrays after calling popping the hover_jsarray");
// log!(hover_jsarray.clone());
// log!(hover_decor_array.borrow_mut().clone());
});
};

html! {
<>
// Editor buttons
Expand Down Expand Up @@ -160,7 +231,7 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html {
} else if **editor_active_tab == EditorTabState::TextSegment {
<TextSegment lines_content={props.lines_content.clone()} program_info={props.program_info.clone()} pc={props.pc.clone()} editor_active_tab={editor_active_tab.clone()} console_active_tab={console_active_tab.clone()} memory_curr_instr={props.memory_curr_instr.clone()} editor_curr_line={props.editor_curr_line.clone()}/>
} else if **editor_active_tab == EditorTabState::DataSegment {
<DataSegment lines_content={props.lines_content.clone()} program_info={props.program_info.clone()} binary={props.binary.clone()}/>
<DataSegment lines_content={props.lines_content.clone()} program_info={props.program_info.clone()} binary={props.binary.clone()} editor_active_tab={editor_active_tab.clone()} console_active_tab={console_active_tab.clone()} memory_curr_instr={props.memory_curr_instr.clone()} editor_curr_line={props.editor_curr_line.clone()} pc_limit={props.pc_limit}/>
}
</>
}
Expand Down
Loading

0 comments on commit d206069

Please sign in to comment.