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
141
    fn max_entry_key_size(&self) -> usize {
12
1895
        if let Some(key) = self.entries.keys().max_by_key(|k| k.len()) {
13
141
            key.len()
14
        } else {
15
            0
16
        }
17
141
    }
18

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

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

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

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

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