diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index b232c0246002..98d10ef965cb 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -5978,9 +5978,15 @@ fn record_macro(cx: &mut Context) { keys.pop(); let s = keys .into_iter() - .map(|key| key.to_string()) - .collect::>() - .join(" "); + .map(|key| { + let s = key.to_string(); + if s.chars().count() == 1 { + s + } else { + format!("<{}>", s) + } + }) + .collect::(); cx.editor.registers.get_mut(reg).write(vec![s]); cx.editor .set_status(format!("Recorded to register [{}]", reg)); @@ -5995,8 +6001,38 @@ fn record_macro(cx: &mut Context) { fn replay_macro(cx: &mut Context) { let reg = cx.register.unwrap_or('@'); // TODO: macro keys should be parsed one by one and not space delimited (see kak) - let keys: Vec = if let Some([keys]) = cx.editor.registers.read(reg) { - match keys.split_whitespace().map(str::parse).collect() { + let keys: Vec = if let Some([keys_str]) = cx.editor.registers.read(reg) { + let mut keys_res: anyhow::Result<_> = Ok(Vec::new()); + let mut i = 0; + while let Ok(keys) = &mut keys_res { + if i >= keys_str.len() { + break; + } + if !keys_str.is_char_boundary(i) { + i += 1; + continue; + } + + let s = &keys_str[i..]; + let mut end_i = 1; + while !s.is_char_boundary(end_i) { + end_i += 1; + } + let c = &s[..end_i]; + if c != "<" { + keys.push(c); + i += end_i; + } else { + match s.find('>').context("'>' expected") { + Ok(end_i) => { + keys.push(&s[1..end_i]); + i += end_i + 1; + } + Err(err) => keys_res = Err(err), + } + } + } + match keys_res.and_then(|keys| keys.into_iter().map(str::parse).collect()) { Ok(keys) => keys, Err(err) => { cx.editor.set_error(format!("Invalid macro: {}", err));