summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
author依云 <lilydjwg@gmail.com>2024-01-03 16:46:59 +0800
committerGitHub <noreply@github.com>2024-01-03 08:46:59 +0000
commitc37147d619a3d8d30897db8c5cb6dddb9276e310 (patch)
tree8d05c8e173a7441a946cae23469b1cf1ae86df6b
parent434e8238d8604dd1efcf601867b73ef17d912490 (diff)
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: https://github.com/zsh-users/zsh/blob/9f57ca4ac8ae071727b1d77cbb8c4c0d893b9099/Src/utils.c#L4889-L4900 * fix code style
-rw-r--r--atuin-client/src/import/zsh.rs46
1 files changed, 42 insertions, 4 deletions
diff --git a/atuin-client/src/import/zsh.rs b/atuin-client/src/import/zsh.rs
index a4b03f2d..5bc8fc16 100644
--- a/atuin-client/src/import/zsh.rs
+++ b/atuin-client/src/import/zsh.rs
@@ -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 ~/音乐"],
+ );
+ }
}