12345678module cli910import os11import src.fmt12import src.view1314const manual = $embed_file('../../docs/koh3-man.txt').to_string()1516pub fn cmd_man(raw []string) int {17 args := parse('man', raw, Options{}) or { return usage_error(err.msg()) }18 mut text := manual19 if args.positional.len > 0 {20 name := args.positional_at(0)21 text = section_of(name) or {22 eprintln(' ${fmt.red(fmt.glyph_fail)} the manual has no "${name}" — try "koh man" for the whole page')23 return 224 }25 }26 page(text)27 return 028}29303132fn section_of(name string) ?string {33 lines := manual.split_into_lines()34 mut start := -135 mut in_commands := false36 for i, line in lines {37 if line == 'COMMANDS' {38 in_commands = true39 } else if in_commands && is_synopsis(line)40 && (line.starts_with(' koh ${name} ') || line == ' koh ${name}') {41 start = i42 break43 }44 }45 if start < 0 {46 return none47 }48 for start > 0 && is_synopsis(lines[start - 1]) {49 start--50 }51 mut end := start52 for end < lines.len && is_synopsis(lines[end]) {53 end++54 }55 56 57 for end < lines.len && (lines[end] == '' || lines[end].starts_with(' ')) {58 end++59 }60 return lines[start..end].join('\n').trim_right('\n ')61}6263fn is_synopsis(line string) bool {64 return line.starts_with(' koh ')65}6667686970fn page(text string) {71 lines := text.trim_right('\n').split_into_lines().map(manual_line(it))72 rows, _ := view.terminal_size()73 if os.is_atty(1) != 0 && os.is_atty(0) != 0 && lines.len >= rows {74 view.page_manual(lines)75 return76 }77 for line in lines {78 println(line.text)79 }80}8182838485fn manual_line(line string) view.ManualLine {86 trimmed := line.trim_left(' ')87 if line != '' && !line.starts_with(' ') && line == line.to_upper() {88 return view.ManualLine{89 text: if fmt.colour_enabled() { fmt.blue('◆ ${line}') } else { line }90 section: line91 }92 }93 if trimmed.starts_with('koh ') {94 return view.ManualLine{95 text: fmt.gold(line)96 }97 }98 if trimmed != line && trimmed.ends_with(':') {99 return view.ManualLine{100 text: fmt.warning(line)101 }102 }103 return view.ManualLine{104 text: line[..line.len - trimmed.len] + body_text(trimmed)105 }106}107108109fn body_text(text string) string {110 mut out := ''111 mut rest := text112 for {113 at := rest.index('--') or { break }114 mut end := at + 2115 for end < rest.len && rest[end] !in [` `, `,`, `)`, `.`, `\``] {116 end++117 }118 if end == at + 2 {119 out += fmt.light(rest[..end])120 } else {121 out += fmt.light(rest[..at]) + fmt.gold(rest[at..end])122 }123 rest = rest[end..]124 }125 return out + fmt.light(rest)126}