-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add hexdump and summary label cursors and better selection rendering …
…for summaries
- Loading branch information
1 parent
ae17064
commit 998e4b8
Showing
10 changed files
with
412 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,248 @@ | ||
use std::task; | ||
use std::vec; | ||
|
||
use crate::model::addr; | ||
use crate::model::datapath; | ||
use crate::model::datapath::DataPathExt; | ||
use crate::model::document; | ||
use crate::model::listing::cursor; | ||
use crate::model::listing::line; | ||
use crate::model::listing::token; | ||
use crate::model::listing::token::TokenKind; | ||
|
||
#[derive(Debug)] | ||
pub struct Cursor { | ||
pub token: token::HexstringToken, | ||
pub offset: addr::Size, | ||
pub low_nybble: bool, | ||
|
||
data_cache: vec::Vec<datapath::ByteRecord>, | ||
data_pending: bool, | ||
} | ||
|
||
impl Cursor { | ||
pub fn new_transition(token: token::HexstringToken, hint: &cursor::TransitionHint) -> Result<Cursor, token::Token> { | ||
let extent = token.extent; | ||
let limit = (extent.length() - addr::unit::BIT).floor(); | ||
|
||
let (offset, low_nybble) = match hint { | ||
cursor::TransitionHint::MoveLeftLarge => (addr::Size::from(limit.bytes & !7), false), | ||
|
||
/* | ||
cursor::TransitionHint::MoveVertical { | ||
horizontal_position: cursor::HorizontalPosition::Hexdump(offset_in_line, low_nybble), | ||
line, | ||
.. | ||
} => { | ||
let line_extent = match line.ty { | ||
line::LineType::Hexdump { line_extent, .. } => line_extent, | ||
_ => return Err(token::Token::Hexdump(token)), | ||
}; | ||
let offset = line_extent.begin + *offset_in_line; | ||
if offset >= extent.end { | ||
return Err(token::Token::Hexdump(token)); | ||
} else if offset < extent.begin { | ||
/* the first line after a child can have a first token that | ||
* starts in the middle of the line, and the horizontal | ||
* position can point before that token starts. */ | ||
(addr::unit::ZERO, false) | ||
} else { | ||
(offset - extent.begin, *low_nybble) | ||
} | ||
}, | ||
*/ | ||
|
||
op if op.is_left() => (limit, true), | ||
op if op.is_right() => (addr::unit::ZERO, false), | ||
_ => (addr::unit::ZERO, false) | ||
}; | ||
|
||
Ok(Cursor { | ||
token, | ||
offset, | ||
low_nybble, | ||
|
||
data_cache: vec::Vec::new(), | ||
data_pending: true, | ||
}) | ||
} | ||
|
||
pub fn new_placement(token: token::HexstringToken, offset: addr::Address, hint: &cursor::PlacementHint) -> Result<Cursor, token::Token> { | ||
let extent = token.extent; | ||
let limit = (extent.length() - addr::unit::BIT).floor(); | ||
|
||
Ok(Cursor { | ||
token, | ||
offset: match offset { | ||
offset if offset < extent.begin => addr::unit::ZERO, | ||
offset if offset >= extent.begin + limit => limit, | ||
offset => offset - extent.begin, | ||
}, | ||
low_nybble: match &hint { | ||
cursor::PlacementHint::Hexdump(hph) => hph.low_nybble, | ||
cursor::PlacementHint::Hexstring(hph) => hph.low_nybble, | ||
_ => false, | ||
}, | ||
|
||
data_cache: vec::Vec::new(), | ||
data_pending: true, | ||
}) | ||
} | ||
|
||
pub fn extent(&self) -> addr::Extent { | ||
self.token.extent | ||
} | ||
} | ||
|
||
impl cursor::CursorClassExt for Cursor { | ||
fn is_over(&self, token: token::TokenRef<'_>) -> bool { | ||
self.token.as_ref() == token | ||
} | ||
|
||
fn get_addr(&self) -> addr::Address { | ||
self.token.absolute_extent().begin + self.offset | ||
} | ||
|
||
fn get_offset(&self) -> addr::Size { | ||
self.offset | ||
} | ||
|
||
fn get_token(&self) -> token::TokenRef<'_> { | ||
self.token.as_ref() | ||
} | ||
|
||
fn get_placement_hint(&self) -> cursor::PlacementHint { | ||
cursor::PlacementHint::Hexstring(HexstringPlacementHint { | ||
low_nybble: self.low_nybble | ||
}) | ||
} | ||
|
||
fn get_horizontal_position_in_line(&self, _line: &line::Line) -> cursor::HorizontalPosition { | ||
cursor::HorizontalPosition::Unspecified | ||
} | ||
|
||
fn move_left(&mut self) -> cursor::MovementResult { | ||
if self.low_nybble { | ||
self.low_nybble = false; | ||
cursor::MovementResult::Ok | ||
} else if self.offset >= addr::unit::BYTE { | ||
self.offset-= addr::unit::BYTE; | ||
self.low_nybble = true; | ||
cursor::MovementResult::Ok | ||
} else { | ||
cursor::MovementResult::HitStart | ||
} | ||
} | ||
|
||
fn move_right(&mut self) -> cursor::MovementResult { | ||
if self.low_nybble { | ||
let offset = self.offset + addr::unit::BYTE; | ||
if offset >= self.extent().length() { | ||
cursor::MovementResult::HitEnd | ||
} else { | ||
self.offset = offset; | ||
self.low_nybble = false; | ||
cursor::MovementResult::Ok | ||
} | ||
} else { | ||
self.low_nybble = true; | ||
cursor::MovementResult::Ok | ||
} | ||
} | ||
|
||
fn move_left_large(&mut self) -> cursor::MovementResult { | ||
if self.offset == addr::unit::ZERO && !self.low_nybble { | ||
cursor::MovementResult::HitStart | ||
} else if self.low_nybble { | ||
self.offset = addr::Size::from(self.offset.bytes & !7); | ||
self.low_nybble = false; | ||
cursor::MovementResult::Ok | ||
} else { | ||
self.offset-= addr::unit::BIT; | ||
self.offset = addr::Size::from(self.offset.bytes & !7); | ||
cursor::MovementResult::Ok | ||
} | ||
} | ||
|
||
fn move_right_large(&mut self) -> cursor::MovementResult { | ||
let offset = addr::Size::from(self.offset.bytes & !7); | ||
let length = self.extent().length(); | ||
|
||
if offset + addr::unit::QWORD >= length { | ||
cursor::MovementResult::HitEnd | ||
} else { | ||
self.low_nybble = false; | ||
self.offset = offset + addr::unit::QWORD; | ||
cursor::MovementResult::Ok | ||
} | ||
} | ||
|
||
fn enter_hex(&mut self, document_host: &document::DocumentHost, document: &document::Document, nybble: u8) -> Result<cursor::MovementResult, cursor::EntryError> { | ||
let i = self.offset.bytes as usize; | ||
let loc = self.token.absolute_extent().begin.byte + self.offset.bytes; | ||
let shift = self.token.absolute_extent().begin.bit; | ||
let insert = false; // TODO | ||
|
||
/* | ||
* +-----------------+-----------------+ | ||
* | 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 6 7 | | ||
* +-----------------+-----------------+ | ||
* | ||
*/ | ||
|
||
let br = self.data_cache[i]; | ||
if br.pending { | ||
return Err(cursor::EntryError::DataPending); | ||
} | ||
let raw = br.value; | ||
|
||
let change = if self.low_nybble && shift <= 4 { | ||
let mask = 0xF << shift; | ||
|
||
document.patch_byte(loc, (raw & !mask) | (nybble << shift)) | ||
} else if !self.low_nybble && shift == 0 { | ||
let mask = 0xF << 4; | ||
|
||
if insert { | ||
document.insert_byte(loc, (raw & !mask) | (nybble << 4)) | ||
} else { | ||
document.patch_byte(loc, (raw & !mask) | (nybble << 4)) | ||
} | ||
} else { | ||
todo!(); // TODO | ||
}; | ||
|
||
document_host.change(change)?; | ||
|
||
Ok(self.move_right()) | ||
} | ||
|
||
fn invalidate_data(&mut self) { | ||
self.data_cache.clear(); | ||
self.data_pending = true; | ||
} | ||
|
||
fn work(&mut self, document: &document::Document, cx: &mut task::Context) -> bool { | ||
if self.data_pending { | ||
let (begin_byte, size) = self.token.absolute_extent().round_out(); | ||
|
||
self.data_cache.resize(size as usize, datapath::ByteRecord::default()); | ||
document.datapath.fetch(datapath::ByteRecordRange::new(begin_byte, &mut self.data_cache), cx); | ||
|
||
self.data_pending = self.data_cache.iter().any(|b| b.pending); | ||
} | ||
|
||
self.data_pending | ||
} | ||
} | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct HexstringPlacementHint { | ||
pub low_nybble: bool, | ||
} | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct HexstringTransitionHint { | ||
offset: addr::Size, | ||
low_nybble: bool, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
use crate::model::addr; | ||
use crate::model::listing::cursor; | ||
use crate::model::listing::line; | ||
use crate::model::listing::token; | ||
use crate::model::listing::token::TokenKind; | ||
|
||
use tracing::instrument; | ||
|
||
#[derive(Debug)] | ||
pub struct Cursor { | ||
token: token::SummaryLabelToken, | ||
} | ||
|
||
impl Cursor { | ||
pub fn new_transition(token: token::SummaryLabelToken, hint: &cursor::TransitionHint) -> Result<Cursor, token::SummaryLabelToken> { | ||
if match hint { | ||
hint if hint.is_entry() => false, | ||
cursor::TransitionHint::MoveVertical { horizontal_position: cursor::HorizontalPosition::Title, .. } => true, | ||
cursor::TransitionHint::MoveVertical { horizontal_position: cursor::HorizontalPosition::Unspecified, .. } => true, | ||
cursor::TransitionHint::MoveVertical { .. } => false, | ||
_ => true, | ||
} { | ||
Ok(Cursor { token }) | ||
} else { | ||
Err(token) | ||
} | ||
} | ||
|
||
pub fn new_placement(token: token::SummaryLabelToken, hint: &cursor::PlacementHint) -> Result<Cursor, token::SummaryLabelToken> { | ||
match hint { | ||
/* we only place the cursor on a summary label if explicitly requested or this is a last-ditch effort; | ||
* otherwise, we prefer to place it on a content token. */ | ||
cursor::PlacementHint::Title | cursor::PlacementHint::LastDitch => Ok(Cursor { | ||
token | ||
}), | ||
_ => Err(token) | ||
} | ||
} | ||
} | ||
|
||
impl cursor::CursorClassExt for Cursor { | ||
fn is_over(&self, token: token::TokenRef<'_>) -> bool { | ||
self.token.as_ref() == token | ||
} | ||
|
||
fn get_addr(&self) -> addr::Address { | ||
self.token.node_addr() | ||
} | ||
|
||
fn get_offset(&self) -> addr::Size { | ||
addr::unit::ZERO | ||
} | ||
|
||
fn get_token(&self) -> token::TokenRef<'_> { | ||
self.token.as_ref() | ||
} | ||
|
||
fn get_placement_hint(&self) -> cursor::PlacementHint { | ||
cursor::PlacementHint::Title | ||
} | ||
|
||
fn get_horizontal_position_in_line(&self, _line: &line::Line) -> cursor::HorizontalPosition { | ||
cursor::HorizontalPosition::Title | ||
} | ||
|
||
#[instrument] | ||
fn move_left(&mut self) -> cursor::MovementResult { | ||
cursor::MovementResult::HitStart | ||
} | ||
|
||
#[instrument] | ||
fn move_right(&mut self) -> cursor::MovementResult { | ||
cursor::MovementResult::HitEnd | ||
} | ||
|
||
fn move_left_large(&mut self) -> cursor::MovementResult { | ||
cursor::MovementResult::HitStart | ||
} | ||
|
||
fn move_right_large(&mut self) -> cursor::MovementResult { | ||
cursor::MovementResult::HitEnd | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.