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 for i, line in lines {36 if line.starts_with(' koh ') && line.contains(' ${name}') {37 start = i38 break39 }40 }41 if start < 0 {42 return none43 }44 mut end := lines.len45 for i := start + 1; i < lines.len; i++ {46 trimmed := lines[i].trim_space()47 if trimmed.starts_with('koh ') && lines[i].starts_with(' ') {48 end = i49 break50 }51 if lines[i].starts_with('OPTIONS') || lines[i].starts_with('ENVIRONMENT') {52 end = i53 break54 }55 }56 return lines[start..end].join('\n')57}5859606162fn page(text string) {63 lines := text.trim_right('\n').split_into_lines().map(manual_line(it))64 rows, _ := view.terminal_size()65 if os.is_atty(1) != 0 && os.is_atty(0) != 0 && lines.len >= rows {66 view.page_manual(lines)67 return68 }69 for line in lines {70 println(line.text)71 }72}7374757677fn manual_line(line string) view.ManualLine {78 trimmed := line.trim_left(' ')79 if line != '' && !line.starts_with(' ') && line == line.to_upper() {80 return view.ManualLine{81 text: if fmt.colour_enabled() { fmt.blue('◆ ${line}') } else { line }82 section: line83 }84 }85 if trimmed.starts_with('koh ') {86 return view.ManualLine{87 text: fmt.gold(line)88 }89 }90 if trimmed != line && trimmed.ends_with(':') {91 return view.ManualLine{92 text: fmt.warning(line)93 }94 }95 return view.ManualLine{96 text: line[..line.len - trimmed.len] + body_text(trimmed)97 }98}99100101fn body_text(text string) string {102 mut out := ''103 mut rest := text104 for {105 at := rest.index('--') or { break }106 mut end := at + 2107 for end < rest.len && rest[end] !in [` `, `,`, `)`, `.`, `\``] {108 end++109 }110 if end == at + 2 {111 out += fmt.light(rest[..end])112 } else {113 out += fmt.light(rest[..at]) + fmt.gold(rest[at..end])114 }115 rest = rest[end..]116 }117 return out + fmt.light(rest)118}