Skip to content

Commit 025c1ac

Browse files
committed
fix: handle zsh's escaped history
1 parent 75d10ed commit 025c1ac

1 file changed

Lines changed: 29 additions & 1 deletion

File tree

src/history.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::{
66
str::FromStr,
77
};
88

9-
#[derive(Debug, Clone, strum::Display, strum::EnumString)]
9+
#[derive(Debug, Clone, strum::Display, strum::EnumString, Eq, PartialEq)]
1010
pub enum HistoryProvider {
1111
#[strum(serialize = "zsh")]
1212
Zsh,
@@ -68,6 +68,31 @@ impl History {
6868
buff_reader: BufReader::new(provider.history_stream()?),
6969
})
7070
}
71+
72+
/// Remove metadata from Zsh's escaped history for non-ASCII.
73+
///
74+
/// Reference code: https://www.zsh.org/mla/users/2011/msg00154.html
75+
///
76+
/// Note: this will mutate `line` in-place.
77+
fn zsh_unmetafy(line: &mut [u8]) -> usize {
78+
const ZSH_META: u8 = 0x83;
79+
80+
let Some(mut p) = line.iter().position(|&x| x == ZSH_META) else {
81+
return line.len();
82+
};
83+
let mut t = p;
84+
while p < line.len() {
85+
line[t] = line[p];
86+
p += 1;
87+
88+
if line[t] == ZSH_META {
89+
line[t] = line[p] ^ 32;
90+
p += 1;
91+
}
92+
t += 1;
93+
}
94+
t
95+
}
7196
}
7297

7398
impl Iterator for History {
@@ -83,6 +108,9 @@ impl Iterator for History {
83108
if buf.is_empty() {
84109
return if block.is_empty() { None } else { Some(block) };
85110
}
111+
if self.provider == HistoryProvider::Zsh {
112+
Self::zsh_unmetafy(&mut buf);
113+
}
86114
let str = String::from_utf8_lossy(&buf).trim_end().to_owned();
87115
block += &str;
88116
if str.is_empty() {

0 commit comments

Comments
 (0)