Skip to content

Commit

Permalink
Try ugly approach
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisduerr committed Jan 2, 2025
1 parent be6c1f5 commit 32ea120
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 29 deletions.
16 changes: 14 additions & 2 deletions examples/parselog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,18 @@ impl Perform for Log {
println!("[osc_dispatch] params={:?} bell_terminated={}", params, bell_terminated);
}

fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) {
fn csi_dispatch(
&mut self,
params: &Params,
intermediates: &[u8],
ignore: bool,
c: char,
) -> bool {
println!(
"[csi_dispatch] params={:#?}, intermediates={:?}, ignore={:?}, char={:?}",
params, intermediates, ignore, c
);
false
}

fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) {
Expand All @@ -61,7 +68,12 @@ fn main() {
loop {
match handle.read(&mut buf) {
Ok(0) => break,
Ok(n) => statemachine.advance(&mut performer, &buf[..n]),
Ok(n) => {
let mut processed = 0;
while processed < n {
processed += statemachine.advance(&mut performer, &buf[processed..n]);
}
},
Err(err) => {
println!("err: {}", err);
break;
Expand Down
77 changes: 55 additions & 22 deletions src/ansi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,23 +299,27 @@ impl<T: Timeout> Processor<T> {
where
H: Handler,
{
if self.state.sync_state.timeout.pending_timeout() {
self.advance_sync(handler, bytes);
} else {
let mut performer = Performer::new(&mut self.state, handler);
self.parser.advance(&mut performer, bytes);
let mut processed = 0;
while processed < bytes.len() {
let bytes = &bytes[processed..];
if self.state.sync_state.timeout.pending_timeout() {
processed += self.advance_sync(handler, bytes);
} else {
let mut performer = Performer::new(&mut self.state, handler);
processed += self.parser.advance(&mut performer, bytes);
}
}
}

/// End a synchronized update.
pub fn stop_sync<H>(&mut self, handler: &mut H)
pub fn stop_sync<H>(&mut self, handler: &mut H) -> usize
where
H: Handler,
{
// Process all synchronized bytes.
let buffer = mem::take(&mut self.state.sync_state.buffer);
let mut performer = Performer::new(&mut self.state, handler);
self.parser.advance(&mut performer, &buffer);
let processed = self.parser.advance(&mut performer, &buffer);
self.state.sync_state.buffer = buffer;

// Report that update ended, since we could end due to timeout.
Expand All @@ -324,6 +328,8 @@ impl<T: Timeout> Processor<T> {
// escapes.
self.state.sync_state.buffer.clear();
self.state.sync_state.timeout.clear_timeout();

processed
}

/// Number of bytes in the synchronization buffer.
Expand All @@ -334,7 +340,7 @@ impl<T: Timeout> Processor<T> {

/// Process a new byte during a synchronized update.
#[cold]
fn advance_sync<H>(&mut self, handler: &mut H, bytes: &[u8])
fn advance_sync<H>(&mut self, handler: &mut H, bytes: &[u8]) -> usize
where
H: Handler,
{
Expand All @@ -345,15 +351,15 @@ impl<T: Timeout> Processor<T> {

// Just parse the bytes normally.
let mut performer = Performer::new(&mut self.state, handler);
self.parser.advance(&mut performer, bytes);
self.parser.advance(&mut performer, bytes)
} else {
self.state.sync_state.buffer.extend(bytes);
self.advance_sync_csi(handler, bytes.len());
self.advance_sync_csi(handler, bytes.len())
}
}

/// Handle BSU/ESU CSI sequences during synchronized update.
fn advance_sync_csi<H>(&mut self, handler: &mut H, new_bytes: usize)
fn advance_sync_csi<H>(&mut self, handler: &mut H, new_bytes: usize) -> usize
where
H: Handler,
{
Expand All @@ -375,10 +381,11 @@ impl<T: Timeout> Processor<T> {
if escape == BSU_CSI {
self.state.sync_state.timeout.set_timeout(SYNC_UPDATE_TIMEOUT);
} else if escape == ESU_CSI {
self.stop_sync(handler);
break;
return self.stop_sync(handler);
}
}

new_bytes
}
}

Expand Down Expand Up @@ -1490,7 +1497,7 @@ where
intermediates: &[u8],
has_ignored_intermediates: bool,
action: char,
) {
) -> bool {
macro_rules! unhandled {
() => {{
debug!(
Expand All @@ -1502,7 +1509,7 @@ where

if has_ignored_intermediates || intermediates.len() > 2 {
unhandled!();
return;
return false;
}

let mut params_iter = params.iter();
Expand Down Expand Up @@ -1541,7 +1548,7 @@ where
3 => TabulationClearMode::All,
_ => {
unhandled!();
return;
return false;
},
};

Expand All @@ -1562,6 +1569,8 @@ where
// Handle sync updates opaquely.
if param == NamedPrivateMode::SyncUpdate as u16 {
self.state.sync_state.timeout.set_timeout(SYNC_UPDATE_TIMEOUT);
handler.set_private_mode(PrivateMode::new(param));
return true;
}

handler.set_private_mode(PrivateMode::new(param))
Expand All @@ -1576,7 +1585,7 @@ where
3 => ClearMode::Saved,
_ => {
unhandled!();
return;
return false;
},
};

Expand All @@ -1589,7 +1598,7 @@ where
2 => LineClearMode::All,
_ => {
unhandled!();
return;
return false;
},
};

Expand All @@ -1603,7 +1612,7 @@ where
2 => ScpCharPath::RTL,
_ => {
unhandled!();
return;
return false;
},
};

Expand All @@ -1613,7 +1622,7 @@ where
2 => ScpUpdateMode::PresentationToData,
_ => {
unhandled!();
return;
return false;
},
};

Expand Down Expand Up @@ -1643,7 +1652,10 @@ where
Some(0) => ModifyOtherKeys::Reset,
Some(1) => ModifyOtherKeys::EnableExceptWellDefined,
Some(2) => ModifyOtherKeys::EnableAll,
_ => return unhandled!(),
_ => {
unhandled!();
return false;
},
};
handler.set_modify_other_keys(mode);
},
Expand Down Expand Up @@ -1674,7 +1686,7 @@ where
5 | 6 => Some(CursorShape::Beam),
_ => {
unhandled!();
return;
return false;
},
};
let cursor_style =
Expand Down Expand Up @@ -1723,6 +1735,8 @@ where
('Z', []) => handler.move_backward_tabs(next_param_or(1)),
_ => unhandled!(),
}

false
}

#[inline]
Expand Down Expand Up @@ -2345,6 +2359,25 @@ mod tests {
}
}

#[test]
fn mixed_sync_escape() {
let mut parser = Processor::<TestSyncHandler>::new();
let mut handler = MockHandler::default();

assert_eq!(parser.state.sync_state.timeout.is_sync, 0);
assert!(handler.attr.is_none());

// Start synchronized update with immediate SGR.
parser.advance(&mut handler, b"\x1b[?2026h\x1b[31m");
assert_eq!(parser.state.sync_state.timeout.is_sync, 1);
assert!(handler.attr.is_none());

// Terminate synchronized update and check for SGR.
parser.advance(&mut handler, b"\x1b[?2026l");
assert_eq!(parser.state.sync_state.timeout.is_sync, 0);
assert!(handler.attr.is_some());
}

#[test]
#[cfg(not(feature = "no_std"))]
fn contrast() {
Expand Down
17 changes: 12 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ pub struct Parser<const OSC_RAW_BUF_SIZE: usize = MAX_OSC_RAW> {
ignoring: bool,
partial_utf8: [u8; 4],
partial_utf8_len: usize,
terminated: bool,
}

impl Parser {
Expand Down Expand Up @@ -109,15 +110,17 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> {
///
/// [`Perform`]: trait.Perform.html
#[inline]
pub fn advance<P: Perform>(&mut self, performer: &mut P, bytes: &[u8]) {
pub fn advance<P: Perform>(&mut self, performer: &mut P, bytes: &[u8]) -> usize {
self.terminated = false;

let mut i = 0;

// Handle partial codepoints from previous calls to `advance`.
if self.partial_utf8_len > 0 {
i += self.advance_partial_utf8(performer, bytes);
}

while i < bytes.len() {
while i < bytes.len() && !self.terminated {
match self.state {
State::Ground => i += self.advance_ground(performer, &bytes[i..]),
_ => {
Expand All @@ -131,6 +134,8 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> {
},
}
}

i
}

#[inline]
Expand Down Expand Up @@ -249,7 +254,7 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> {
self.params.push(self.param);
}

performer.csi_dispatch(
self.terminated |= performer.csi_dispatch(
self.params(),
self.intermediates(),
self.ignoring,
Expand Down Expand Up @@ -521,7 +526,8 @@ pub trait Perform {
_intermediates: &[u8],
_ignore: bool,
_action: char,
) {
) -> bool {
false
}

/// The final character of an escape sequence has arrived.
Expand Down Expand Up @@ -571,10 +577,11 @@ mod tests {
self.dispatched.push(Sequence::Osc(params, bell_terminated));
}

fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) {
fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) -> bool {
let params = params.iter().map(|subparam| subparam.to_vec()).collect();
let intermediates = intermediates.to_vec();
self.dispatched.push(Sequence::Csi(params, intermediates, ignore, c));
false
}

fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) {
Expand Down

0 comments on commit 32ea120

Please sign in to comment.