lattice_mode/modes/text.rs
1//! `text-mode` -- the default major mode for plain-text content.
2//!
3//! Catch-all major mode that any buffer falls back to when no
4//! more-specific major mode applies. Provides:
5//!
6//! - No tree-sitter parser.
7//! - No LSP attachment.
8//! - The default keymap layer (vim grammar).
9//! - No mode-scoped option overrides (all options take their
10//! global / default values).
11//!
12//! Per `mode-architecture.md` ยง4.1, this is the foundation
13//! catch-all. Buffer content with no language detection lands
14//! here. Buffer kinds with their own behavior (Help, FileTree,
15//! Oil, language-specific Documents) declare their own majors;
16//! those modes can `implies` text-mode if they want the
17//! default keymap, or specify their own from scratch.
18
19use crate::{
20 CapabilitySet, LifecycleFuture, Mode, ModeContext, ModeId, ModeKind, OptionOverrideSet,
21};
22
23/// Catch-all major mode for plain-text content.
24pub struct TextMode;
25
26impl TextMode {
27 /// Canonical id for this mode. Used for `:enable text-mode`,
28 /// `:customize text-mode` (if it ever has options), etc.
29 pub fn mode_id() -> ModeId {
30 ModeId::new("text-mode")
31 }
32}
33
34impl Mode for TextMode {
35 type Guard = ();
36
37 fn id(&self) -> ModeId {
38 Self::mode_id()
39 }
40
41 fn kind(&self) -> ModeKind {
42 ModeKind::Major
43 }
44
45 fn required_capabilities(&self) -> CapabilitySet {
46 // text-mode imposes no requirements -- it activates on
47 // any buffer.
48 CapabilitySet::empty()
49 }
50
51 /// Plain text is prose, so `autowrap` covers every line (RF.4).
52 ///
53 /// The one override this mode carries, and it does not contradict
54 /// the module docs above ("no mode-scoped option overrides"): that
55 /// described a mode with nothing to say, and prose-versus-code IS
56 /// something a catch-all text major can say. A `.txt` buffer that
57 /// does not wrap while a `.md` one does would be an arbitrary split.
58 fn options(&self) -> OptionOverrideSet {
59 lattice_config::overrides! {
60 lattice_config::AutoWrapOption = lattice_core::AutoWrap::All,
61 }
62 }
63
64 fn on_activate(&self, _ctx: ModeContext) -> LifecycleFuture<'_, ()> {
65 // No setup work; text-mode is content-free.
66 Box::pin(async { Ok(()) })
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn id_and_kind() {
76 let m = TextMode;
77 assert_eq!(m.id(), TextMode::mode_id());
78 assert_eq!(m.id().as_str(), "text-mode");
79 assert_eq!(m.kind(), ModeKind::Major);
80 }
81
82 /// RF.4: plain text is prose. A `.txt` buffer that does not wrap
83 /// while a `.md` one does would be an arbitrary split.
84 #[test]
85 fn text_mode_wraps_prose() {
86 let opts = TextMode.options();
87 assert!(
88 opts.iter()
89 .any(|o| o.option_type_id
90 == std::any::TypeId::of::<lattice_config::AutoWrapOption>()),
91 "text-mode must override autowrap to `all`"
92 );
93 }
94
95 #[test]
96 fn no_capability_requirements() {
97 let m = TextMode;
98 assert_eq!(m.required_capabilities(), CapabilitySet::empty());
99 }
100}