@@ -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 ) ]
1010pub 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
7398impl 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