fix(import/zsh): zsh use a special format to escape some characters (#1490)

* fix(import/zsh): zsh use a special format to escape some characters

unescape those correctly rather than throw them away.

zsh side code:
9f57ca4ac8/Src/utils.c (L4889-L4900)

* fix code style
This commit is contained in:
依云 2024-01-03 16:46:59 +08:00 committed by GitHub
parent 434e8238d8
commit c37147d619
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,6 +1,7 @@
// import old shell history!
// automatically hoover up all that we can find
use std::borrow::Cow;
use std::path::PathBuf;
use async_trait::async_trait;
@ -61,16 +62,16 @@ impl Importer for Zsh {
let mut counter = 0;
for b in unix_byte_lines(&self.bytes) {
let s = match std::str::from_utf8(b) {
Ok(s) => s,
Err(_) => continue, // we can skip past things like invalid utf8
let s = match unmetafy(b) {
Some(s) => s,
_ => continue, // we can skip past things like invalid utf8
};
if let Some(s) = s.strip_suffix('\\') {
line.push_str(s);
line.push_str("\\\n");
} else {
line.push_str(s);
line.push_str(&s);
let command = std::mem::take(&mut line);
if let Some(command) = command.strip_prefix(": ") {
@ -116,6 +117,26 @@ fn parse_extended(line: &str, counter: i64) -> History {
imported.build().into()
}
fn unmetafy(line: &[u8]) -> Option<Cow<str>> {
if line.contains(&0x83) {
let mut s = Vec::with_capacity(line.len());
let mut is_meta = false;
for ch in line {
if *ch == 0x83 {
is_meta = true;
} else if is_meta {
is_meta = false;
s.push(*ch ^ 32);
} else {
s.push(*ch)
}
}
String::from_utf8(s).ok().map(Cow::Owned)
} else {
std::str::from_utf8(line).ok().map(Cow::Borrowed)
}
}
#[cfg(test)]
mod test {
use itertools::assert_equal;
@ -188,4 +209,21 @@ cargo update
],
);
}
#[tokio::test]
async fn test_parse_metafied() {
let bytes =
b"echo \xe4\xbd\x83\x80\xe5\xa5\xbd\nls ~/\xe9\x83\xbf\xb3\xe4\xb9\x83\xb0\n".to_vec();
let mut zsh = Zsh { bytes };
assert_eq!(zsh.entries().await.unwrap(), 2);
let mut loader = TestLoader::default();
zsh.load(&mut loader).await.unwrap();
assert_equal(
loader.buf.iter().map(|h| h.command.as_str()),
["echo 你好", "ls ~/音乐"],
);
}
}