use escriba_buffer::BufferSet;
use escriba_core::Mode;
use escriba_keymap::Key;
use escriba_runtime::EditorState;
fn editor_with(path: &str, text: &str) -> EditorState {
use std::sync::atomic::{AtomicUsize, Ordering};
static N: AtomicUsize = AtomicUsize::new(0);
let dir = std::env::temp_dir()
.join("escriba-comment-toggle")
.join(N.fetch_add(1, Ordering::Relaxed).to_string());
std::fs::create_dir_all(&dir).expect("scratch dir");
let file = dir.join(path);
std::fs::write(&file, text).expect("fixture");
let mut bufs = BufferSet::new();
let id = bufs.open(&file).expect("open");
let mut st = EditorState::new_with_buffer(bufs, id);
let plan = escriba_lisp::apply_source(
r#"
(defmode :name "rust" :extensions ("rs") :commentstring "// %s")
(defmode :name "lisp" :extensions ("lisp") :commentstring ";; %s")
(defmode :name "html" :extensions ("html") :commentstring "<!-- %s -->")
(defmode :name "plain" :extensions ("txt"))
"#,
)
.expect("modes parse");
escriba_lisp::apply_plan_to_filetypes(&plan, &mut st.filetypes);
escriba_lisp::apply_plan_to_commands(&plan, &mut st.commands);
st
}
fn ex(st: &mut EditorState, line: &str) {
st.on_key(&Key::Char(':'));
for c in line.chars() {
st.on_key(&Key::Char(c));
}
st.on_key(&Key::Enter);
if st.modal.mode() == Mode::Command {
st.on_key(&Key::Esc);
}
}
fn text(st: &EditorState) -> String {
st.buffers
.get(st.active)
.map(escriba_buffer::Buffer::to_string)
.unwrap_or_default()
}
#[test]
fn commenting_a_line_uses_the_filetypes_own_syntax() {
let mut st = editor_with("a.rs", "let x = 1;\n");
ex(&mut st, "comment.toggle-line");
assert_eq!(text(&st), "// let x = 1;\n");
}
#[test]
fn toggling_twice_returns_the_original_exactly() {
for (file, body) in [
("a.rs", "let x = 1;\n"),
("a.lisp", "(defun f ())\n"),
("a.html", "<p>hi</p>\n"),
] {
let mut st = editor_with(file, body);
let before = text(&st);
ex(&mut st, "comment.toggle-line");
assert_ne!(text(&st), before, "{file}: first toggle must comment");
ex(&mut st, "comment.toggle-line");
assert_eq!(text(&st), before, "{file}: second toggle must restore");
}
}
#[test]
fn indentation_survives_the_round_trip() {
let mut st = editor_with("a.rs", " deeply.indented();\n");
ex(&mut st, "comment.toggle-line");
assert_eq!(
text(&st),
" // deeply.indented();\n",
"the marker goes after the indent, not before it",
);
ex(&mut st, "comment.toggle-line");
assert_eq!(text(&st), " deeply.indented();\n");
}
#[test]
fn a_block_syntax_wraps_on_both_sides() {
let mut st = editor_with("a.html", "<p>hi</p>\n");
ex(&mut st, "comment.toggle-line");
assert_eq!(text(&st), "<!-- <p>hi</p> -->\n");
ex(&mut st, "comment.toggle-line");
assert_eq!(text(&st), "<p>hi</p>\n");
}
#[test]
fn a_filetype_with_no_comment_syntax_declines() {
let mut st = editor_with("a.txt", "words\n");
ex(&mut st, "comment.toggle-line");
assert_eq!(text(&st), "words\n", "the buffer is untouched");
assert!(
st.messages.iter().any(|m| m.contains("no comment syntax")),
"and it must say why: {:?}",
st.messages,
);
}
#[test]
fn an_unknown_filetype_declines() {
let mut st = editor_with("a.zzz", "stuff\n");
ex(&mut st, "comment.toggle-line");
assert_eq!(text(&st), "stuff\n");
assert!(
st.messages.iter().any(|m| m.contains("no filetype")),
"{:?}",
st.messages,
);
}
#[test]
fn an_empty_line_declines_rather_than_leaving_a_bare_marker() {
let mut st = editor_with("a.rs", "\nlet x = 1;\n");
ex(&mut st, "comment.toggle-line");
assert_eq!(text(&st), "\nlet x = 1;\n", "untouched");
assert!(
st.messages
.iter()
.any(|m| m.contains("nothing on this line")),
"{:?}",
st.messages,
);
}
#[test]
fn an_already_commented_line_written_by_a_human_is_recognised() {
let mut st = editor_with("a.rs", "//x\n");
ex(&mut st, "comment.toggle-line");
assert_eq!(
text(&st),
"x\n",
"uncommenting must tolerate the missing space"
);
}
#[test]
fn a_scratch_buffer_has_no_path_and_therefore_no_filetype() {
let mut bufs = BufferSet::new();
let id = bufs.scratch("let x = 1;\n");
let mut st = EditorState::new_with_buffer(bufs, id);
let plan = escriba_lisp::apply_source(
r#"(defmode :name "rust" :extensions ("rs") :commentstring "// %s")"#,
)
.expect("parses");
escriba_lisp::apply_plan_to_filetypes(&plan, &mut st.filetypes);
ex(&mut st, "comment.toggle-line");
assert_eq!(text(&st), "let x = 1;\n");
}