From 88f6815462c51a5d345389c0a50ac345083aa552 Mon Sep 17 00:00:00 2001 From: misson20000 Date: Sat, 27 Jul 2024 17:25:19 -0400 Subject: [PATCH] Vertical cursor movement based on logical (not visual) position in line --- src/model/listing/cursor.rs | 340 +++++++++++++++++++----- src/model/listing/cursor/hexdump.rs | 69 +++-- src/model/listing/cursor/punctuation.rs | 21 +- src/model/listing/cursor/title.rs | 20 +- src/view/crashreport.rs | 11 +- src/view/listing.rs | 11 +- src/view/listing/facet/cursor.rs | 4 +- src/view/listing/line.rs | 6 + 8 files changed, 363 insertions(+), 119 deletions(-) diff --git a/src/model/listing/cursor.rs b/src/model/listing/cursor.rs index c75b4fe..3d5cabc 100644 --- a/src/model/listing/cursor.rs +++ b/src/model/listing/cursor.rs @@ -3,6 +3,7 @@ use std::sync; use crate::model::addr; use crate::model::document; use crate::model::document::structure; +use crate::model::listing::line; use crate::model::listing::token; use crate::model::listing::token::TokenKind; use crate::model::versioned::Versioned; @@ -52,7 +53,7 @@ pub trait CursorClassExt { fn get_offset(&self) -> addr::Size; fn get_token(&self) -> token::TokenRef<'_>; fn get_placement_hint(&self) -> PlacementHint; - fn get_transition_hint(&self) -> TransitionHintClass; + fn get_horizontal_position_in_line(&self, line: &line::Line) -> HorizontalPosition; fn move_left(&mut self) -> MovementResult; fn move_right(&mut self) -> MovementResult; @@ -71,9 +72,20 @@ pub enum CursorClass { Punctuation(punctuation::Cursor), } +#[derive(Clone, Debug)] +pub enum HorizontalPosition { + Unspecified, + Title, + Hexdump(addr::Size, bool), +} + #[derive(Debug)] pub struct Cursor { tokenizer: tokenizer::Tokenizer, + line: line::Line, + line_begin: tokenizer::Tokenizer, + line_end: tokenizer::Tokenizer, + desired_horizontal_position: Option, pub class: CursorClass, document: sync::Arc, } @@ -90,19 +102,20 @@ enum UpdateMode { impl CursorClass { fn place_forward(tokenizer: &mut tokenizer::Tokenizer, offset: addr::Address, hint: &PlacementHint) -> Result { loop { - if !match tokenizer.gen_token() { + match tokenizer.gen_token() { tokenizer::TokenGenerationResult::Ok(token) => match CursorClass::new_placement(token, offset, hint) { Ok(cursor) => return Ok(cursor), /* failed to place on this token; try the next */ - Err(_) => tokenizer.move_next(), + Err(_) => {}, }, - tokenizer::TokenGenerationResult::Skip => tokenizer.move_next(), + tokenizer::TokenGenerationResult::Skip => {}, tokenizer::TokenGenerationResult::Boundary => return Err(PlacementFailure::HitBottomOfAddressSpace) - } { - /* move_next() returned false */ + }; + + if !tokenizer.move_next() { return Err(PlacementFailure::HitBottomOfAddressSpace) } - } + } } fn place_backward(tokenizer: &mut tokenizer::Tokenizer, offset: addr::Address, hint: &PlacementHint) -> Result { @@ -149,8 +162,17 @@ impl Cursor { Err(_) => panic!("unexpected error from CursorClass::place_forward") }; + let mut line_end = tokenizer.clone(); + let (line, mut line_begin, _) = line::Line::containing_tokenizer(&mut line_end); + line_begin.canonicalize_next(); + line_end.canonicalize_next(); + Cursor { tokenizer, + line, + line_begin, + line_end, + desired_horizontal_position: None, class, document, } @@ -202,15 +224,93 @@ impl Cursor { self.class.is_over(token) } - fn movement(&mut self, mov: F, op: TransitionOp) -> MovementResult where F: FnOnce(&mut CursorClass) -> MovementResult { + /// Finds the next token that the supplied function returns Ok(_) for, and mutates our state to account for being on a new token. If we hit the end of the token stream without seeing Ok(_), the state is not mutated. + fn next_token_matching Result>(&mut self, acceptor: F) -> Option { + let mut tokenizer = self.tokenizer.clone(); + let mut line = self.line.clone(); + let mut line_begin = self.line_begin.clone(); + let mut line_end = self.line_end.clone(); + + let obj = loop { + match tokenizer.next_preincrement() { + None => return None, + Some(token) => { + while tokenizer >= line_end { + line_begin = line_end.clone(); + line = line::Line::next_from_tokenizer(&mut line_end); + line_end.canonicalize_next(); + } + + line_begin.canonicalize_next(); + + assert!(line.iter_tokens().any(|t| t == token.as_ref())); + + match acceptor(token) { + Ok(obj) => break obj, + Err(_) => continue, + } + } + } + }; + + /* We only want to update these in the success case. */ + self.line = line; + self.line_begin = line_begin; + self.line_end = line_end; + self.tokenizer = tokenizer; + + Some(obj) + } + + /// See [next_token_matching]. + fn prev_token_matching Result>(&mut self, acceptor: F) -> Option { + let mut tokenizer = self.tokenizer.clone(); + let mut line = self.line.clone(); + let mut line_begin = self.line_begin.clone(); + let mut line_end = self.line_end.clone(); + + let obj = loop { + match tokenizer.prev() { + None => return None, + Some(token) => { + while tokenizer < line_begin { + line_end = line_begin.clone(); + line = line::Line::prev_from_tokenizer(&mut line_begin); + line_begin.canonicalize_next(); + } + + line_end.canonicalize_next(); + + assert!(line.iter_tokens().any(|t| t == token.as_ref())); + + match acceptor(token) { + Ok(obj) => break obj, + Err(_) => continue, + } + } + } + }; + + /* We only want to update these in the success case. */ + self.line = line; + self.line_begin = line_begin; + self.line_end = line_end; + self.tokenizer = tokenizer; + + Some(obj) + } + + fn movement(&mut self, mov: F, hint: TransitionHint) -> MovementResult where F: FnOnce(&mut CursorClass) -> MovementResult { + self.desired_horizontal_position = None; + match mov(&mut self.class) { /* If the movement hit a token boundary, try moving the cursor to another token. */ - MovementResult::HitStart => match self.class.try_move_prev_token(self.tokenizer.clone(), op) { - Some((cc, tokenizer)) => { (self.class, self.tokenizer) = (cc, tokenizer); MovementResult::Ok } + MovementResult::HitStart => match self.prev_token_matching(|tok| CursorClass::new_transition(tok, &hint)) { + Some(cc) => { self.class = cc; MovementResult::Ok } None => MovementResult::HitStart }, - MovementResult::HitEnd => match self.class.try_move_next_token(self.tokenizer.clone(), op) { - Some((cc, tokenizer)) => { (self.class, self.tokenizer) = (cc, tokenizer); MovementResult::Ok } + MovementResult::HitEnd => match self.next_token_matching(|tok| CursorClass::new_transition(tok, &hint)) { + Some(cc) => { self.class = cc; MovementResult::Ok } None => MovementResult::HitStart } /* Otherwise, it's a legitimate result. */ @@ -218,15 +318,107 @@ impl Cursor { } } - pub fn move_left(&mut self) -> MovementResult { self.movement(|c| c.move_left(), TransitionOp::UnspecifiedLeft) } - pub fn move_right(&mut self) -> MovementResult { self.movement(|c| c.move_right(), TransitionOp::UnspecifiedRight) } - //pub fn move_up(&mut self) -> MovementResult { self.movement(|c| c.move_up(), TransitionOp::UnspecifiedLeft) } - //pub fn move_down(&mut self) -> MovementResult { self.movement(|c| c.move_down(), TransitionOp::UnspecifiedRight) } - //pub fn move_to_start_of_line(&mut self) -> MovementResult { self.movement(|c| c.move_to_start_of_line(), TransitionOp::UnspecifiedLeft) } - //pub fn move_to_end_of_line(&mut self) -> MovementResult { self.movement(|c| c.move_to_end_of_line(), TransitionOp::UnspecifiedRight) } - pub fn move_left_large(&mut self) -> MovementResult { self.movement(|c| c.move_left_large(), TransitionOp::MoveLeftLarge) } - pub fn move_right_large(&mut self) -> MovementResult { self.movement(|c| c.move_right_large(), TransitionOp::UnspecifiedRight) } + pub fn move_left(&mut self) -> MovementResult { self.movement(|c| c.move_left(), TransitionHint::UnspecifiedLeft) } + pub fn move_right(&mut self) -> MovementResult { self.movement(|c| c.move_right(), TransitionHint::UnspecifiedRight) } + //pub fn move_up(&mut self) -> MovementResult { self.movement(|c| c.move_up(), TransitionHint::UnspecifiedLeft) } + //pub fn move_down(&mut self) -> MovementResult { self.movement(|c| c.move_down(), TransitionHint::UnspecifiedRight) } + //pub fn move_to_start_of_line(&mut self) -> MovementResult { self.movement(|c| c.move_to_start_of_line(), TransitionHint::UnspecifiedLeft) } + //pub fn move_to_end_of_line(&mut self) -> MovementResult { self.movement(|c| c.move_to_end_of_line(), TransitionHint::UnspecifiedRight) } + pub fn move_left_large(&mut self) -> MovementResult { self.movement(|c| c.move_left_large(), TransitionHint::MoveLeftLarge) } + pub fn move_right_large(&mut self) -> MovementResult { self.movement(|c| c.move_right_large(), TransitionHint::UnspecifiedRight) } + + fn move_vertically(&mut self, line: line::Line, line_begin: tokenizer::Tokenizer, line_end: tokenizer::Tokenizer) -> Result { + let dhp = match &self.desired_horizontal_position { + Some(x) => x.clone(), + None => self.class.get_horizontal_position_in_line(&self.line), + }; + + let mut tokenizer = line_begin.clone(); + + let hint = TransitionHint::MoveVertical { + horizontal_position: &dhp, + line: &line, + line_end: &line_end + }; + + self.class = loop { + match tokenizer.gen_token() { + tokenizer::TokenGenerationResult::Ok(token) => match CursorClass::new_transition(token, &hint) { + Ok(cc) => break cc, + Err(_tok) => {}, + }, + tokenizer::TokenGenerationResult::Skip => {}, + tokenizer::TokenGenerationResult::Boundary => return Ok(MovementResult::HitEnd), + }; + + if !tokenizer.move_next() { + return Ok(MovementResult::HitEnd); + } + + if tokenizer >= line_end { + break loop { + if let Some(token) = tokenizer.prev() { + if tokenizer < line_begin { + return Err((line_begin, line_end)); + } + match CursorClass::new_transition(token, &TransitionHint::EndOfLine) { + Ok(cc) => break cc, + Err(_tok) => {}, + } + } else { + return Ok(MovementResult::HitStart); + } + } + } + }; + + assert!(line.iter_tokens().any(|t| t == self.class.get_token())); + + self.tokenizer = tokenizer; + self.line = line; + self.line_begin = line_begin; + self.line_end = line_end; + + self.desired_horizontal_position = Some(dhp); + + Ok(MovementResult::Ok) + } + + pub fn move_up(&mut self) -> MovementResult { + let mut line_begin = self.line_begin.clone(); + + loop { + let line_end = line_begin.clone(); + let line = line::Line::prev_from_tokenizer(&mut line_begin); + if line.is_empty() { + return MovementResult::HitStart; + } + + line_begin = match self.move_vertically(line, line_begin, line_end) { + Ok(mr) => return mr, + Err((line_begin, _line_end)) => line_begin, + } + } + } + + pub fn move_down(&mut self) -> MovementResult { + let mut line_end = self.line_end.clone(); + + loop { + let line_begin = line_end.clone(); + let line = line::Line::next_from_tokenizer(&mut line_end); + if line.is_empty() { + return MovementResult::HitEnd; + } + + line_end = match self.move_vertically(line, line_begin, line_end) { + Ok(mr) => return mr, + Err((_line_begin, line_end)) => line_end, + } + } + } + /* previous node */ pub fn move_prev(&mut self) -> MovementResult { todo!(); @@ -239,11 +431,11 @@ impl Cursor { /* pub fn enter_standard(&mut self, document_host: &document::DocumentHost, insert: bool, key: &key::Key) -> Result { - self.class.enter_standard(document_host, insert, key).map(|mr| self.movement(|_| mr, TransitionOp::EntryStandard)) + self.class.enter_standard(document_host, insert, key).map(|mr| self.movement(|_| mr, TransitionHint::EntryStandard)) } pub fn enter_utf8(&mut self, document_host: &document::DocumentHost, insert: bool, key: &key::Key) -> Result { - self.class.enter_utf8(document_host, insert, key).map(|mr| self.movement(|_| mr, TransitionOp::EntryUTF8)) + self.class.enter_utf8(document_host, insert, key).map(|mr| self.movement(|_| mr, TransitionHint::EntryUTF8)) } */ @@ -306,12 +498,7 @@ impl CursorClass { } #[instrument] - fn try_move_prev_token(&self, mut tokenizer: tokenizer::Tokenizer, op: TransitionOp) -> Option<(CursorClass, tokenizer::Tokenizer)> { - let hint = TransitionHint { - op, - class: self.get_transition_hint(), - }; - + fn try_move_prev_token(&self, mut tokenizer: tokenizer::Tokenizer, hint: TransitionHint) -> Option<(CursorClass, tokenizer::Tokenizer)> { loop { match tokenizer.prev() { None => { @@ -332,12 +519,7 @@ impl CursorClass { } #[instrument] - fn try_move_next_token(&self, mut tokenizer: tokenizer::Tokenizer, op: TransitionOp) -> Option<(CursorClass, tokenizer::Tokenizer)> { - let hint = TransitionHint { - op, - class: self.get_transition_hint(), - }; - + fn try_move_next_token(&self, mut tokenizer: tokenizer::Tokenizer, hint: TransitionHint) -> Option<(CursorClass, tokenizer::Tokenizer)> { loop { match tokenizer.next_preincrement() { None => { @@ -370,65 +552,64 @@ pub enum PlacementHint { } impl std::default::Default for PlacementHint { - fn default() -> PlacementHint{ - PlacementHint::Unused + fn default() -> Self { + Self::Unused } } #[derive(Debug, Clone, Copy)] -pub enum TransitionOp { +pub enum TransitionHint<'a> { MoveLeftLarge, EntryStandard, EntryUTF8, UnspecifiedLeft, UnspecifiedRight, + MoveVertical { + horizontal_position: &'a HorizontalPosition, + line: &'a line::Line, + line_end: &'a tokenizer::Tokenizer, + }, + EndOfLine, } -impl TransitionOp { +impl<'a> TransitionHint<'a> { pub fn is_left(&self) -> bool { match self { - TransitionOp::MoveLeftLarge => true, - TransitionOp::EntryStandard => false, - TransitionOp::EntryUTF8 => false, - TransitionOp::UnspecifiedLeft => true, - TransitionOp::UnspecifiedRight => false, + TransitionHint::MoveLeftLarge => true, + TransitionHint::EntryStandard => false, + TransitionHint::EntryUTF8 => false, + TransitionHint::UnspecifiedLeft => true, + TransitionHint::UnspecifiedRight => false, + TransitionHint::MoveVertical { .. } => false, + TransitionHint::EndOfLine => true, } } pub fn is_right(&self) -> bool { match self { - TransitionOp::MoveLeftLarge => false, - TransitionOp::EntryStandard => true, - TransitionOp::EntryUTF8 => true, - TransitionOp::UnspecifiedLeft => false, - TransitionOp::UnspecifiedRight => true, + TransitionHint::MoveLeftLarge => false, + TransitionHint::EntryStandard => true, + TransitionHint::EntryUTF8 => true, + TransitionHint::UnspecifiedLeft => false, + TransitionHint::UnspecifiedRight => true, + TransitionHint::MoveVertical { .. } => false, + TransitionHint::EndOfLine => false, } } pub fn is_entry(&self) -> bool { match self { - TransitionOp::MoveLeftLarge => false, - TransitionOp::EntryStandard => true, - TransitionOp::EntryUTF8 => true, - TransitionOp::UnspecifiedLeft => false, - TransitionOp::UnspecifiedRight => false, + TransitionHint::MoveLeftLarge => false, + TransitionHint::EntryStandard => true, + TransitionHint::EntryUTF8 => true, + TransitionHint::UnspecifiedLeft => false, + TransitionHint::UnspecifiedRight => false, + TransitionHint::MoveVertical { .. } => false, + TransitionHint::EndOfLine => false, } } } -/// Used to hint at how to transition a cursor from one break to another. -#[derive(Debug, Clone)] -pub struct TransitionHint { - pub op: TransitionOp, - pub class: TransitionHintClass, -} - -#[derive(Debug, Clone)] -pub enum TransitionHintClass { - Hexdump(hexdump::HexdumpTransitionHint), - Unused -} - #[cfg(test)] mod tests { use super::*; @@ -731,4 +912,31 @@ mod tests { Cursor::place(document, &vec![], 0x0.into(), PlacementHint::Unused); } + + #[test] + fn vertical_and_horizontal_movement() { + let root = structure::Node::builder() + .name("root") + .size(0x40) + .child(0x0, |b| b + .name("child") + .size(0x10)) + .build(); + + let document = sync::Arc::new(document::Builder::new(root).build()); + + let mut cursor = Cursor::place(document, &vec![], 0x0.into(), PlacementHint::Unused); + println!("initial:"); + println!(" line: {:?}", cursor.line); + println!(" line tokenizers: {:?}-{:?}", cursor.line_begin, cursor.line_end); + cursor.move_up(); + println!("after move up 1:"); + println!(" line: {:?}", cursor.line); + println!(" line tokenizers: {:?}-{:?}", cursor.line_begin, cursor.line_end); + cursor.move_up(); + println!("after move up 2:"); + println!(" line: {:?}", cursor.line); + println!(" line tokenizers: {:?}-{:?}", cursor.line_begin, cursor.line_end); + cursor.move_right(); + } } diff --git a/src/model/listing/cursor/hexdump.rs b/src/model/listing/cursor/hexdump.rs index b69c4ce..f78b822 100644 --- a/src/model/listing/cursor/hexdump.rs +++ b/src/model/listing/cursor/hexdump.rs @@ -1,5 +1,6 @@ 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; @@ -15,38 +16,49 @@ impl Cursor { pub fn new_transition(token: token::HexdumpToken, hint: &cursor::TransitionHint) -> Result { 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, extent, - offset: match hint.op { - cursor::TransitionOp::MoveLeftLarge => addr::Size::from(limit.bytes & !7), - op if op.is_left() => limit, - op if op.is_right() => addr::unit::ZERO, - _ => match &hint.class { - cursor::TransitionHintClass::Hexdump(hth) => std::cmp::min(hth.offset, limit), - _ => addr::unit::ZERO, - }, - }, - low_nybble: match (&hint.class, hint.op) { - /* decide from op */ - (_, cursor::TransitionOp::MoveLeftLarge) => false, - (_, op) if op.is_left() => true, - (_, op) if op.is_right() => false, - /* if we have an intended offset and had to truncate it, we should place at the end of the line */ - (cursor::TransitionHintClass::Hexdump(hth), _) if hth.offset > limit => true, - /* if we have an intended offset and didn't have to truncate it, try to carry the low_nybble flag over from a previous HexCursor */ - (cursor::TransitionHintClass::Hexdump(hth), _) => hth.low_nybble, - /* last resort, if the op is seriously misbehaving and is neither left nor right */ - _ => false, - }, + offset, + low_nybble, }) } pub fn new_placement(token: token::HexdumpToken, offset: addr::Address, hint: &cursor::PlacementHint) -> Result { let extent = token.extent; let limit = (extent.length() - addr::unit::BIT).floor(); - + Ok(Cursor { token, extent, @@ -86,13 +98,14 @@ impl cursor::CursorClassExt for Cursor { }) } - fn get_transition_hint(&self) -> cursor::TransitionHintClass { - cursor::TransitionHintClass::Hexdump(HexdumpTransitionHint { - offset: self.offset, - low_nybble: self.low_nybble - }) + fn get_horizontal_position_in_line(&self, line: &line::Line) -> cursor::HorizontalPosition { + if let line::LineType::Hexdump { line_extent, .. } = &line.ty { + cursor::HorizontalPosition::Hexdump(self.extent.begin.to_size() + self.offset - line_extent.begin.to_size(), self.low_nybble) + } else { + panic!("attempted to get horizontal position of HexdumpCursor on a non-Hexdump line"); + } } - + fn move_left(&mut self) -> cursor::MovementResult { if self.low_nybble { self.low_nybble = false; diff --git a/src/model/listing/cursor/punctuation.rs b/src/model/listing/cursor/punctuation.rs index 82037e4..d1e7c58 100644 --- a/src/model/listing/cursor/punctuation.rs +++ b/src/model/listing/cursor/punctuation.rs @@ -1,5 +1,6 @@ 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; @@ -10,13 +11,15 @@ pub struct Cursor { impl Cursor { pub fn new_transition(token: token::Token, hint: &cursor::TransitionHint) -> Result { - if hint.op.is_entry() { - /* skip over punctuation tokens for entry */ - Err(token) + if match hint { + hint if hint.is_entry() => false, + cursor::TransitionHint::MoveVertical { horizontal_position: cursor::HorizontalPosition::Unspecified, .. } => true, + cursor::TransitionHint::MoveVertical { .. } => false, + _ => true, + } { + Ok(Cursor { token }) } else { - Ok(Cursor { - token - }) + Err(token) } } @@ -53,10 +56,10 @@ impl cursor::CursorClassExt for Cursor { cursor::PlacementHint::Punctuation } - fn get_transition_hint(&self) -> cursor::TransitionHintClass { - cursor::TransitionHintClass::Unused + fn get_horizontal_position_in_line(&self, _line: &line::Line) -> cursor::HorizontalPosition { + cursor::HorizontalPosition::Unspecified } - + fn move_left(&mut self) -> cursor::MovementResult { cursor::MovementResult::HitStart } diff --git a/src/model/listing/cursor/title.rs b/src/model/listing/cursor/title.rs index 3241207..af4301b 100644 --- a/src/model/listing/cursor/title.rs +++ b/src/model/listing/cursor/title.rs @@ -1,5 +1,6 @@ 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; @@ -12,13 +13,16 @@ pub struct Cursor { impl Cursor { pub fn new_transition(token: token::TitleToken, hint: &cursor::TransitionHint) -> Result { - if hint.op.is_entry() { - /* skip over title tokens for entry */ - Err(token) + 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 { - Ok(Cursor { - token - }) + Err(token) } } @@ -55,8 +59,8 @@ impl cursor::CursorClassExt for Cursor { cursor::PlacementHint::Title } - fn get_transition_hint(&self) -> cursor::TransitionHintClass { - cursor::TransitionHintClass::Unused + fn get_horizontal_position_in_line(&self, _line: &line::Line) -> cursor::HorizontalPosition { + cursor::HorizontalPosition::Title } #[instrument] diff --git a/src/view/crashreport.rs b/src/view/crashreport.rs index f113cb0..b1690a7 100644 --- a/src/view/crashreport.rs +++ b/src/view/crashreport.rs @@ -42,7 +42,12 @@ pub enum Circumstance { InWindow(u64), TreeSelectionUpdate(sync::Arc, sync::Arc), ListingSelectionUpdate(sync::Arc, sync::Arc), - Goto(sync::Arc, document::structure::Path, model::addr::Address, model::listing::cursor::PlacementHint), + Goto { + document: sync::Arc, + path: document::structure::Path, + offset: model::addr::Address, + hint: String, + }, LWDocumentUpdate(sync::Arc, sync::Arc), LWSelectionUpdate(sync::Arc, sync::Arc), } @@ -603,8 +608,8 @@ impl Circumstance { write!(d, " - {:?}\n", change).unwrap(); }); }, - Circumstance::Goto(_doc, path, addr, hint) => { - write!(d, "While performing goto({:?}, {}, {:?}).\n", path, addr, hint)?; + Circumstance::Goto { document: _, path, offset, hint } => { + write!(d, "While performing goto({:?}, {}, {}).\n", path, offset, hint)?; }, Circumstance::LWDocumentUpdate(old, new) => { write!(d, "While updating listing widget for new document.\n")?; diff --git a/src/view/listing.rs b/src/view/listing.rs index bd3a676..a0b0360 100644 --- a/src/view/listing.rs +++ b/src/view/listing.rs @@ -477,7 +477,12 @@ impl ListingWidget { let _circumstances = crashreport::circumstances([ crashreport::Circumstance::InWindow(interior.charm_window_id), - crashreport::Circumstance::Goto(document.clone(), path.clone(), offset, hint.clone()), + crashreport::Circumstance::Goto { + document: document.clone(), + path: path.clone(), + offset, + hint: format!("{:?}", hint), + }, ]); if interior.document.generation() != document.generation() { @@ -740,8 +745,8 @@ impl Interior { /* basic cursor key shift ctrl */ (gdk::Key::Left, false, false) => self.cursor_transaction(|c| c.move_left(), facet::scroll::EnsureCursorInViewDirection::Up), (gdk::Key::Right, false, false) => self.cursor_transaction(|c| c.move_right(), facet::scroll::EnsureCursorInViewDirection::Down), - //(gdk::keys::constants::Up, false, false) => self.cursor_transaction(|c| c.move_up(), facet::scroll::EnsureCursorInViewDirection::Up), - //(gdk::keys::constants::Down, false, false) => self.cursor_transaction(|c| c.move_down(), facet::scroll::EnsureCursorInViewDirection::Down), + (gdk::Key::Up, false, false) => self.cursor_transaction(|c| c.move_up(), facet::scroll::EnsureCursorInViewDirection::Up), + (gdk::Key::Down, false, false) => self.cursor_transaction(|c| c.move_down(), facet::scroll::EnsureCursorInViewDirection::Down), /* fast cursor key shift ctrl */ //(gdk::keys::constants::Left, false, true ) => self.cursor_transaction(|c| c.move_left_large(), facet::scroll::EnsureCursorInViewDirection::Up), diff --git a/src/view/listing/facet/cursor.rs b/src/view/listing/facet/cursor.rs index e1978a7..d1d2899 100644 --- a/src/view/listing/facet/cursor.rs +++ b/src/view/listing/facet/cursor.rs @@ -133,8 +133,8 @@ impl CursorView { pub fn move_left(&mut self) { self.movement(|c| c.move_left()); } pub fn move_right(&mut self) { self.movement(|c| c.move_right()); } - //pub fn move_up(&mut self) { self.movement(|c| c.move_up()); } - //pub fn move_down(&mut self) { self.movement(|c| c.move_down()); } + pub fn move_up(&mut self) { self.movement(|c| c.move_up()); } + pub fn move_down(&mut self) { self.movement(|c| c.move_down()); } //pub fn move_to_start_of_line(&mut self) { self.movement(|c| c.move_to_start_of_line()); } //pub fn move_to_end_of_line(&mut self) { self.movement(|c| c.move_to_end_of_line()); } pub fn move_left_large(&mut self) { self.movement(|c| c.move_left_large()); } diff --git a/src/view/listing/line.rs b/src/view/listing/line.rs index 848fbbe..e101c4d 100644 --- a/src/view/listing/line.rs +++ b/src/view/listing/line.rs @@ -42,6 +42,12 @@ enum LineViewType { }, } +impl std::fmt::Debug for LineViewType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("LineViewType").finish() + } +} + pub struct Line { ev_draw: facet::Event, ev_work: facet::Event,