From aa5dcb67efe78bd70f677beefbb323ab5838fe15 Mon Sep 17 00:00:00 2001 From: lilydjwg Date: Tue, 2 Jan 2024 21:22:44 +0800 Subject: [PATCH 1/2] 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 --- atuin-client/src/import/zsh.rs | 49 +++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/atuin-client/src/import/zsh.rs b/atuin-client/src/import/zsh.rs index a4b03f2d890..30c88c4d972 100644 --- a/atuin-client/src/import/zsh.rs +++ b/atuin-client/src/import/zsh.rs @@ -2,6 +2,7 @@ // automatically hoover up all that we can find use std::path::PathBuf; +use std::borrow::Cow; use async_trait::async_trait; use directories::UserDirs; @@ -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> { + 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,24 @@ 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 ~/音乐", + ], + ); + } } From eca76540911f45c0a68759ff79364167adaacd21 Mon Sep 17 00:00:00 2001 From: lilydjwg Date: Wed, 3 Jan 2024 09:18:25 +0800 Subject: [PATCH 2/2] fix code style --- atuin-client/src/import/zsh.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/atuin-client/src/import/zsh.rs b/atuin-client/src/import/zsh.rs index 30c88c4d972..5bc8fc16416 100644 --- a/atuin-client/src/import/zsh.rs +++ b/atuin-client/src/import/zsh.rs @@ -1,8 +1,8 @@ // import old shell history! // automatically hoover up all that we can find -use std::path::PathBuf; use std::borrow::Cow; +use std::path::PathBuf; use async_trait::async_trait; use directories::UserDirs; @@ -212,8 +212,8 @@ 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 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); @@ -223,10 +223,7 @@ cargo update assert_equal( loader.buf.iter().map(|h| h.command.as_str()), - [ - "echo 你好", - "ls ~/音乐", - ], + ["echo 你好", "ls ~/音乐"], ); } }