use super::*;
#[test]
fn new_registry_has_fundamental_mode() {
crate::test_utils::init_test_tracing();
let reg = ModeRegistry::new();
assert!(reg.major_modes.contains_key("fundamental-mode"));
}
#[test]
fn default_major_mode_is_fundamental() {
crate::test_utils::init_test_tracing();
let reg = ModeRegistry::new();
assert_eq!(reg.get_major_mode(1), "fundamental-mode");
}
#[test]
fn register_and_set_major_mode() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_major_mode(MajorMode {
name: "rust-mode".to_string(),
pretty_name: "Rust".to_string(),
parent: Some("prog-mode".to_string()),
mode_hook: "rust-mode-hook".to_string(),
keymap_name: Some("rust-mode-map".to_string()),
syntax_table_name: None,
abbrev_table_name: None,
font_lock: None,
body: None,
});
assert!(reg.set_major_mode(1, "rust-mode").is_ok());
assert_eq!(reg.get_major_mode(1), "rust-mode");
}
#[test]
fn set_unknown_major_mode_fails() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
let result = reg.set_major_mode(1, "nonexistent-mode");
assert!(result.is_err());
}
#[test]
fn set_major_mode_replaces_previous() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_major_mode(MajorMode {
name: "text-mode".to_string(),
pretty_name: "Text".to_string(),
parent: None,
mode_hook: "text-mode-hook".to_string(),
keymap_name: None,
syntax_table_name: None,
abbrev_table_name: None,
font_lock: None,
body: None,
});
reg.register_major_mode(MajorMode {
name: "org-mode".to_string(),
pretty_name: "Org".to_string(),
parent: Some("text-mode".to_string()),
mode_hook: "org-mode-hook".to_string(),
keymap_name: None,
syntax_table_name: None,
abbrev_table_name: None,
font_lock: None,
body: None,
});
reg.set_major_mode(1, "text-mode").unwrap();
assert_eq!(reg.get_major_mode(1), "text-mode");
reg.set_major_mode(1, "org-mode").unwrap();
assert_eq!(reg.get_major_mode(1), "org-mode");
}
#[test]
fn register_and_enable_minor_mode() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_minor_mode(MinorMode {
name: "auto-fill-mode".to_string(),
lighter: Some(" Fill".to_string()),
keymap_name: None,
global: false,
body: None,
});
assert!(reg.enable_minor_mode(1, "auto-fill-mode").is_ok());
assert!(reg.is_minor_mode_active(1, "auto-fill-mode"));
}
#[test]
fn enable_unknown_minor_mode_fails() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
let result = reg.enable_minor_mode(1, "nonexistent-mode");
assert!(result.is_err());
}
#[test]
fn disable_minor_mode() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_minor_mode(MinorMode {
name: "flycheck-mode".to_string(),
lighter: Some(" FlyC".to_string()),
keymap_name: None,
global: false,
body: None,
});
reg.enable_minor_mode(1, "flycheck-mode").unwrap();
assert!(reg.is_minor_mode_active(1, "flycheck-mode"));
reg.disable_minor_mode(1, "flycheck-mode");
assert!(!reg.is_minor_mode_active(1, "flycheck-mode"));
}
#[test]
fn toggle_minor_mode() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_minor_mode(MinorMode {
name: "linum-mode".to_string(),
lighter: Some(" Ln".to_string()),
keymap_name: None,
global: false,
body: None,
});
let active = reg.toggle_minor_mode(1, "linum-mode").unwrap();
assert!(active);
assert!(reg.is_minor_mode_active(1, "linum-mode"));
let active = reg.toggle_minor_mode(1, "linum-mode").unwrap();
assert!(!active);
assert!(!reg.is_minor_mode_active(1, "linum-mode"));
}
#[test]
fn toggle_unknown_minor_mode_fails() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
let result = reg.toggle_minor_mode(1, "nonexistent");
assert!(result.is_err());
}
#[test]
fn active_minor_modes_lists_all() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_minor_mode(MinorMode {
name: "mode-a".to_string(),
lighter: Some(" A".to_string()),
keymap_name: None,
global: false,
body: None,
});
reg.register_minor_mode(MinorMode {
name: "mode-b".to_string(),
lighter: Some(" B".to_string()),
keymap_name: None,
global: false,
body: None,
});
reg.enable_minor_mode(1, "mode-a").unwrap();
reg.enable_minor_mode(1, "mode-b").unwrap();
let active = reg.active_minor_modes(1);
assert_eq!(active.len(), 2);
assert!(active.contains(&"mode-a"));
assert!(active.contains(&"mode-b"));
}
#[test]
fn enable_minor_mode_idempotent() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_minor_mode(MinorMode {
name: "hl-line-mode".to_string(),
lighter: None,
keymap_name: None,
global: false,
body: None,
});
reg.enable_minor_mode(1, "hl-line-mode").unwrap();
reg.enable_minor_mode(1, "hl-line-mode").unwrap();
let active = reg.active_minor_modes(1);
assert_eq!(active.len(), 1);
}
#[test]
fn global_minor_mode_active_in_all_buffers() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_minor_mode(MinorMode {
name: "global-hl-line-mode".to_string(),
lighter: Some(" HL".to_string()),
keymap_name: None,
global: true,
body: None,
});
reg.enable_global_minor_mode("global-hl-line-mode").unwrap();
assert!(reg.is_minor_mode_active(1, "global-hl-line-mode"));
assert!(reg.is_minor_mode_active(99, "global-hl-line-mode"));
}
#[test]
fn disable_global_minor_mode() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_minor_mode(MinorMode {
name: "global-mode".to_string(),
lighter: None,
keymap_name: None,
global: true,
body: None,
});
reg.enable_global_minor_mode("global-mode").unwrap();
assert!(reg.is_minor_mode_active(1, "global-mode"));
reg.disable_global_minor_mode("global-mode");
assert!(!reg.is_minor_mode_active(1, "global-mode"));
}
#[test]
fn global_and_buffer_local_no_duplicates() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_minor_mode(MinorMode {
name: "shared-mode".to_string(),
lighter: Some(" S".to_string()),
keymap_name: None,
global: false,
body: None,
});
reg.enable_global_minor_mode("shared-mode").unwrap();
reg.enable_minor_mode(1, "shared-mode").unwrap();
let active = reg.active_minor_modes(1);
assert_eq!(active.iter().filter(|&&m| m == "shared-mode").count(), 1);
}
#[test]
fn auto_mode_alist_suffix_match() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_major_mode(MajorMode {
name: "rust-mode".to_string(),
pretty_name: "Rust".to_string(),
parent: None,
mode_hook: "rust-mode-hook".to_string(),
keymap_name: None,
syntax_table_name: None,
abbrev_table_name: None,
font_lock: None,
body: None,
});
reg.add_auto_mode(".rs".to_string(), "rust-mode".to_string());
assert_eq!(reg.mode_for_file("main.rs"), Some("rust-mode"));
assert_eq!(reg.mode_for_file("lib.rs"), Some("rust-mode"));
assert_eq!(reg.mode_for_file("main.py"), None);
}
#[test]
fn auto_mode_alist_first_match_wins() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_major_mode(MajorMode {
name: "mode-a".to_string(),
pretty_name: "A".to_string(),
parent: None,
mode_hook: "mode-a-hook".to_string(),
keymap_name: None,
syntax_table_name: None,
abbrev_table_name: None,
font_lock: None,
body: None,
});
reg.register_major_mode(MajorMode {
name: "mode-b".to_string(),
pretty_name: "B".to_string(),
parent: None,
mode_hook: "mode-b-hook".to_string(),
keymap_name: None,
syntax_table_name: None,
abbrev_table_name: None,
font_lock: None,
body: None,
});
reg.add_auto_mode(".txt".to_string(), "mode-a".to_string());
reg.add_auto_mode(".txt".to_string(), "mode-b".to_string());
assert_eq!(reg.mode_for_file("file.txt"), Some("mode-a"));
}
#[test]
fn mode_line_string_fundamental() {
crate::test_utils::init_test_tracing();
let reg = ModeRegistry::new();
let s = reg.mode_line_string(1);
assert_eq!(s, "(Fundamental)");
}
#[test]
fn mode_line_string_with_minor_modes() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_minor_mode(MinorMode {
name: "auto-fill-mode".to_string(),
lighter: Some(" Fill".to_string()),
keymap_name: None,
global: false,
body: None,
});
reg.enable_minor_mode(1, "auto-fill-mode").unwrap();
let s = reg.mode_line_string(1);
assert_eq!(s, "(Fundamental Fill)");
}
#[test]
fn mode_line_format_render() {
crate::test_utils::init_test_tracing();
let reg = ModeRegistry::new();
let fmt = ModeLineFormat::default_format();
let rendered = fmt.render(1, ®, "*scratch*", false, false, 1, 0, 0);
assert!(rendered.contains("*scratch*"));
assert!(rendered.contains("Fundamental"));
assert!(rendered.contains("Top"));
assert!(rendered.contains("--"));
}
#[test]
fn mode_line_format_modified_and_readonly() {
crate::test_utils::init_test_tracing();
let reg = ModeRegistry::new();
let fmt = ModeLineFormat::default_format();
let rendered_mod = fmt.render(1, ®, "buf", true, false, 10, 5, 50);
assert!(rendered_mod.contains("**"));
assert!(rendered_mod.contains("50%"));
assert!(rendered_mod.contains("10:5"));
let rendered_ro = fmt.render(1, ®, "buf", false, true, 1, 0, 100);
assert!(rendered_ro.contains("%%"));
assert!(rendered_ro.contains("Bot"));
}
#[test]
fn font_lock_keywords_basic() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_major_mode(MajorMode {
name: "lisp-mode".to_string(),
pretty_name: "Lisp".to_string(),
parent: None,
mode_hook: "lisp-mode-hook".to_string(),
keymap_name: None,
syntax_table_name: None,
abbrev_table_name: None,
font_lock: Some(FontLockDefaults {
keywords: vec![FontLockKeyword {
pattern: r"\b(defun|defvar)\b".to_string(),
face: "font-lock-keyword-face".to_string(),
group: 1,
override_: false,
laxmatch: false,
}],
case_fold: false,
syntax_table: None,
}),
body: None,
});
let kws = reg.font_lock_keywords("lisp-mode").unwrap();
assert_eq!(kws.len(), 1);
assert_eq!(kws[0].face, "font-lock-keyword-face");
}
#[test]
fn font_lock_keywords_inherit_from_parent() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_major_mode(MajorMode {
name: "prog-mode".to_string(),
pretty_name: "Prog".to_string(),
parent: None,
mode_hook: "prog-mode-hook".to_string(),
keymap_name: None,
syntax_table_name: None,
abbrev_table_name: None,
font_lock: Some(FontLockDefaults {
keywords: vec![FontLockKeyword {
pattern: r"TODO".to_string(),
face: "font-lock-warning-face".to_string(),
group: 0,
override_: true,
laxmatch: false,
}],
case_fold: false,
syntax_table: None,
}),
body: None,
});
reg.register_major_mode(MajorMode {
name: "rust-mode".to_string(),
pretty_name: "Rust".to_string(),
parent: Some("prog-mode".to_string()),
mode_hook: "rust-mode-hook".to_string(),
keymap_name: None,
syntax_table_name: None,
abbrev_table_name: None,
font_lock: None,
body: None,
});
let kws = reg.font_lock_keywords("rust-mode").unwrap();
assert_eq!(kws.len(), 1);
assert_eq!(kws[0].pattern, "TODO");
}
#[test]
fn font_lock_keywords_none() {
crate::test_utils::init_test_tracing();
let reg = ModeRegistry::new();
assert!(reg.font_lock_keywords("fundamental-mode").is_none());
}
#[test]
fn register_custom_variable() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_custom_variable(CustomVariable {
name: "indent-tabs-mode".to_string(),
default_value: Value::T,
doc: Some("Use tabs for indentation.".to_string()),
type_: CustomType::Boolean,
group: None,
set_function: None,
get_function: None,
tag: None,
});
let var = reg.get_custom_variable("indent-tabs-mode").unwrap();
assert_eq!(var.name, "indent-tabs-mode");
assert!(var.default_value.is_truthy());
}
#[test]
fn custom_variable_in_group() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_custom_group(CustomGroup {
name: "editing".to_string(),
doc: Some("Editing options.".to_string()),
parent: None,
members: vec![],
});
reg.register_custom_variable(CustomVariable {
name: "fill-column".to_string(),
default_value: Value::fixnum(70),
doc: None,
type_: CustomType::Integer,
group: Some("editing".to_string()),
set_function: None,
get_function: None,
tag: None,
});
let group = reg.get_custom_group("editing").unwrap();
assert!(group.members.contains(&"fill-column".to_string()));
}
#[test]
fn derived_mode_p_self() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_major_mode(MajorMode {
name: "text-mode".to_string(),
pretty_name: "Text".to_string(),
parent: None,
mode_hook: "text-mode-hook".to_string(),
keymap_name: None,
syntax_table_name: None,
abbrev_table_name: None,
font_lock: None,
body: None,
});
assert!(reg.derived_mode_p("text-mode", "text-mode"));
}
#[test]
fn derived_mode_p_parent_chain() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_major_mode(MajorMode {
name: "text-mode".to_string(),
pretty_name: "Text".to_string(),
parent: None,
mode_hook: "text-mode-hook".to_string(),
keymap_name: None,
syntax_table_name: None,
abbrev_table_name: None,
font_lock: None,
body: None,
});
reg.register_major_mode(MajorMode {
name: "org-mode".to_string(),
pretty_name: "Org".to_string(),
parent: Some("text-mode".to_string()),
mode_hook: "org-mode-hook".to_string(),
keymap_name: None,
syntax_table_name: None,
abbrev_table_name: None,
font_lock: None,
body: None,
});
reg.register_major_mode(MajorMode {
name: "org-journal-mode".to_string(),
pretty_name: "Org-Journal".to_string(),
parent: Some("org-mode".to_string()),
mode_hook: "org-journal-mode-hook".to_string(),
keymap_name: None,
syntax_table_name: None,
abbrev_table_name: None,
font_lock: None,
body: None,
});
assert!(reg.derived_mode_p("org-journal-mode", "text-mode"));
assert!(reg.derived_mode_p("org-journal-mode", "org-mode"));
assert!(reg.derived_mode_p("org-mode", "text-mode"));
assert!(!reg.derived_mode_p("text-mode", "org-mode"));
}
#[test]
fn derived_mode_p_unrelated() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_major_mode(MajorMode {
name: "text-mode".to_string(),
pretty_name: "Text".to_string(),
parent: None,
mode_hook: "text-mode-hook".to_string(),
keymap_name: None,
syntax_table_name: None,
abbrev_table_name: None,
font_lock: None,
body: None,
});
reg.register_major_mode(MajorMode {
name: "prog-mode".to_string(),
pretty_name: "Prog".to_string(),
parent: None,
mode_hook: "prog-mode-hook".to_string(),
keymap_name: None,
syntax_table_name: None,
abbrev_table_name: None,
font_lock: None,
body: None,
});
assert!(!reg.derived_mode_p("text-mode", "prog-mode"));
assert!(!reg.derived_mode_p("prog-mode", "text-mode"));
}
#[test]
fn remove_buffer_cleans_up() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_minor_mode(MinorMode {
name: "test-mode".to_string(),
lighter: None,
keymap_name: None,
global: false,
body: None,
});
reg.set_major_mode(1, "fundamental-mode").unwrap();
reg.enable_minor_mode(1, "test-mode").unwrap();
reg.remove_buffer(1);
assert_eq!(reg.get_major_mode(1), "fundamental-mode");
assert!(
reg.active_minor_modes(1).is_empty()
|| reg
.active_minor_modes(1)
.iter()
.all(|m| { reg.global_minor_modes.contains(&m.to_string()) })
);
}
#[test]
fn font_lock_level_default_is_level3() {
crate::test_utils::init_test_tracing();
let level = FontLockLevel::default();
assert_eq!(level, FontLockLevel::Level3);
}
#[test]
fn mode_line_format_default_has_elements() {
crate::test_utils::init_test_tracing();
let fmt = ModeLineFormat::default_format();
assert!(!fmt.elements.is_empty());
}
#[test]
fn custom_type_choice() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_custom_variable(CustomVariable {
name: "my-choice".to_string(),
default_value: Value::symbol("fast"),
doc: None,
type_: CustomType::Choice(vec![
("fast".to_string(), Value::symbol("fast")),
("slow".to_string(), Value::symbol("slow")),
]),
group: None,
set_function: None,
get_function: None,
tag: None,
});
let var = reg.get_custom_variable("my-choice").unwrap();
assert!(matches!(var.type_, CustomType::Choice(_)));
}
#[test]
fn custom_type_nested_list() {
crate::test_utils::init_test_tracing();
let mut reg = ModeRegistry::new();
reg.register_custom_variable(CustomVariable {
name: "my-list".to_string(),
default_value: Value::NIL,
doc: None,
type_: CustomType::List(Box::new(CustomType::String)),
group: None,
set_function: None,
get_function: None,
tag: None,
});
let var = reg.get_custom_variable("my-list").unwrap();
assert!(matches!(var.type_, CustomType::List(_)));
}