1
use crate::utils;
2
use std::collections::HashMap;
3

            
4
pub struct Section {
5
    pub title: String,
6
    pub entries: HashMap<&'static str, &'static str>,
7
}
8

            
9
impl Section {
10
    /// Returns the size of the biggest entry key in the section
11
147
    fn max_entry_key_size(&self) -> usize {
12
1977
        if let Some(key) = self.entries.keys().max_by_key(|k| k.len()) {
13
147
            key.len()
14
        } else {
15
            0
16
        }
17
147
    }
18

            
19
    #[must_use]
20
147
    pub fn format(&self) -> String {
21
147
        let title_str = utils::as_bold(self.title.as_str());
22
147
        let mut body: Vec<String> = Vec::new();
23
147
        let whitespace_offset = self.max_entry_key_size();
24
1977
        for (cmd, cmd_help_msg) in &self.entries {
25
3660
            let whitespace = " ".repeat(whitespace_offset - cmd.len() + 1);
26
1830
            body.push(format!("{cmd}{whitespace}=> {cmd_help_msg}"));
27
1830
        }
28
147
        body.sort();
29
147
        let body_str = body.join("\n  ");
30
147
        format!("{title_str}\n  {body_str}")
31
147
    }
32
}
33
pub struct Help {
34
    pub sections: Vec<Section>,
35
}
36

            
37
impl Help {
38
    #[must_use]
39
48
    pub fn new() -> Help {
40
48
        Help {
41
96
            sections: vec![
42
48
                Section {
43
48
                    title: String::from("Normal commands"),
44
48
                    entries: HashMap::from([
45
48
                        ("j", "move cursor down one row (<n>j moves it by n rows)"),
46
48
                        ("k", "move cursor up one row (<n>k moves it by n rows)"),
47
48
                        ("h", "move cursor left (<n>h moves it n times)"),
48
48
                        ("l", "move cursor right (<n>l moves it n times)"),
49
48
                        (
50
                            "}",
51
                            "move to the end of the current paragraph (<n>} moves n times)",
52
                        ),
53
48
                        (
54
                            "{",
55
                            "move to the start of the current paragraph (<n>{ moves n times)",
56
                        ),
57
48
                        (
58
                            "w",
59
                            "move to the end of the current word (<n>w moves n times)",
60
                        ),
61
48
                        (
62
                            "b",
63
                            "move to the start of the current word (<n>b moves n times)",
64
                        ),
65
48
                        ("i", "switch to insert mode"),
66
48
                        ("g", "go to beginining of document"),
67
48
                        ("G", "go to end of document"),
68
48
                        ("0", "go to first character in line"),
69
48
                        ("^", "go to first non-whitespace character in line"),
70
48
                        ("$", "go to end of line"),
71
48
                        ("H", "go to first line in screen"),
72
48
                        ("M", "go to line in the middle of the screen"),
73
48
                        ("L", "go to last line in screen"),
74
48
                        ("n%", "move to n% in the file"),
75
48
                        ("/", "open search prompt"),
76
48
                        ("n", "go to next search match"),
77
48
                        ("N", "go to previous search match"),
78
48
                        ("d", "delete current line"),
79
48
                        ("x", "delete current character"),
80
48
                        ("o", "insert newline after current line & enter insert mode"),
81
48
                        (
82
                            "O",
83
                            "insert newline before current line & enter insert mode",
84
                        ),
85
48
                        ("A", "go to end of line & enter insert mode"),
86
48
                        ("J", "join the current line with the next one"),
87
48
                        (":", "open command prompt"),
88
48
                        ("u", "undo last operation"),
89
                    ]),
90
                },
91
48
                Section {
92
48
                    title: String::from("Prompt commands"),
93
48
                    entries: HashMap::from([
94
48
                        ("help", "display this help screen"),
95
48
                        ("ln", "toggle line numbers"),
96
48
                        ("new <filename>", "open a new file"),
97
48
                        ("open/o <filename>", "open a file"),
98
48
                        ("q", "quit bo"),
99
48
                        ("stats", "toggle line/word stats"),
100
48
                        ("w <new_name>", "save"),
101
48
                        ("wq", "save and quit"),
102
                    ]),
103
                },
104
48
                Section {
105
48
                    title: String::from("Insert commands"),
106
48
                    entries: HashMap::from([("Esc", "go back to normal mode")]),
107
                },
108
            ],
109
        }
110
48
    }
111

            
112
    #[must_use]
113
49
    pub fn format(&self) -> String {
114
49
        let mut out: Vec<String> = Vec::new();
115
195
        for section in &self.sections {
116
292
            let section_format = section.format();
117
146
            out.push(section_format);
118
        }
119
49
        out.join("\n\n")
120
49
    }
121
}
122

            
123
impl Default for Help {
124
48
    fn default() -> Self {
125
48
        Self::new()
126
48
    }
127
}
128

            
129
#[cfg(test)]
130
#[path = "./help_test.rs"]
131
mod help_test;