use hjkl_engine::Host;
pub(crate) fn format_registers<H: Host>(
editor: &hjkl_engine::Editor<hjkl_buffer::Buffer, H>,
) -> String {
let r = editor.registers();
let mut lines = vec!["--- Registers ---".to_string()];
let mut push = |sel: &str, text: &str, linewise: bool| {
if text.is_empty() {
return;
}
let marker = if linewise { "L" } else { " " };
lines.push(format!("{sel:<3} {marker} {}", display_register(text)));
};
push("\"\"", &r.unnamed.text, r.unnamed.linewise);
push("\"0", &r.yank_zero.text, r.yank_zero.linewise);
for (i, slot) in r.delete_ring.iter().enumerate() {
let sel = format!("\"{}", i + 1);
push(&sel, &slot.text, slot.linewise);
}
for (i, slot) in r.named.iter().enumerate() {
let sel = format!("\"{}", (b'a' + i as u8) as char);
push(&sel, &slot.text, slot.linewise);
}
if lines.len() == 1 {
lines.push("(no registers set)".to_string());
}
lines.join("\n")
}
fn display_register(text: &str) -> String {
let escaped: String = text
.chars()
.map(|c| match c {
'\n' => "\\n".to_string(),
'\t' => "\\t".to_string(),
'\r' => "\\r".to_string(),
c => c.to_string(),
})
.collect();
const MAX: usize = 60;
if escaped.chars().count() > MAX {
let head: String = escaped.chars().take(MAX - 3).collect();
format!("{head}...")
} else {
escaped
}
}
pub(crate) fn format_marks<H: Host>(
editor: &hjkl_engine::Editor<hjkl_buffer::Buffer, H>,
) -> String {
let mut lines = vec!["--- Marks ---".to_string(), "mark line col".to_string()];
let entries: Vec<(char, usize, usize)> =
editor.marks().map(|(c, (r, col))| (c, r, col)).collect();
for (c, r, col) in entries {
lines.push(format!(" {c} {:>4} {col:>3}", r + 1));
}
if let Some((r, col)) = editor.last_jump_back() {
lines.push(format!(" ' {:>4} {col:>3}", r + 1));
}
if let Some((r, col)) = editor.last_edit_pos() {
lines.push(format!(" . {:>4} {col:>3}", r + 1));
}
if lines.len() == 2 {
lines.push("(no marks set)".to_string());
}
lines.join("\n")
}
pub(crate) fn format_jumps<H: Host>(
editor: &hjkl_engine::Editor<hjkl_buffer::Buffer, H>,
) -> String {
let (back, fwd) = editor.jump_list();
if back.is_empty() && fwd.is_empty() {
return "(no jumps recorded)".to_string();
}
let mut lines = vec![
"--- Jump list ---".to_string(),
" jump line col".to_string(),
];
let back_len = back.len();
for (i, &(row, col)) in back.iter().rev().enumerate() {
let jump_num = i + 1;
lines.push(format!("{jump_num:>5} {:>4} {:>4}", row + 1, col));
}
lines.push(format!("{:>5} (current position)", 0));
for (i, &(row, col)) in fwd.iter().enumerate() {
let jump_num = -(i as isize + 1);
lines.push(format!("{jump_num:>5} {:>4} {:>4}", row + 1, col));
}
let _ = back_len; lines.join("\n")
}
pub(crate) fn format_changes<H: Host>(
editor: &hjkl_engine::Editor<hjkl_buffer::Buffer, H>,
) -> String {
let (list, cursor) = editor.change_list();
if list.is_empty() {
return "(no changes recorded)".to_string();
}
let mut lines = vec![
"--- Change list ---".to_string(),
"change line col".to_string(),
];
let len = list.len();
for (display_idx, &(row, col)) in list.iter().rev().enumerate() {
let change_num = display_idx + 1;
let marker = match cursor {
Some(c) if c == len - 1 - display_idx => " <",
_ => "",
};
lines.push(format!(
"{change_num:>6} {:>4} {:>4}{marker}",
row + 1,
col
));
}
lines.join("\n")
}
#[cfg(test)]
mod tests {
use super::*;
use hjkl_engine::{DefaultHost, Editor, Options};
fn make_editor() -> Editor<hjkl_buffer::Buffer, DefaultHost> {
let buf = hjkl_buffer::Buffer::new();
let host = DefaultHost::new();
Editor::new(buf, host, Options::default())
}
#[test]
fn format_registers_empty() {
let editor = make_editor();
let out = format_registers(&editor);
assert_eq!(out, "--- Registers ---\n(no registers set)");
}
#[test]
fn format_registers_after_yank() {
let mut editor = make_editor();
editor
.registers_mut()
.record_yank("hello".into(), false, None);
let out = format_registers(&editor);
assert!(out.contains("hello"), "expected 'hello' in: {out}");
assert!(out.starts_with("--- Registers ---"));
}
#[test]
fn format_marks_empty() {
let editor = make_editor();
let out = format_marks(&editor);
assert_eq!(out, "--- Marks ---\nmark line col\n(no marks set)");
}
#[test]
fn format_marks_after_set_mark() {
let mut editor = make_editor();
editor.set_mark_at_cursor('a');
let out = format_marks(&editor);
assert!(out.contains("a"), "expected mark 'a' in: {out}");
assert!(out.starts_with("--- Marks ---"));
}
#[test]
fn format_jumps_empty() {
let editor = make_editor();
let out = format_jumps(&editor);
assert_eq!(out, "(no jumps recorded)");
}
#[test]
fn format_changes_empty() {
let editor = make_editor();
let out = format_changes(&editor);
assert_eq!(out, "(no changes recorded)");
}
}