12345module view67import fmt891011pub struct ManualLine {12pub:13 text string14 section string15}161718pub fn page_manual(lines []ManualLine) {19 enter_screen()20 defer {21 leave_screen()22 }23 mut page := 024 for {25 rows, cols := terminal_size()26 size := if rows > 2 { rows - 1 } else { 1 }27 last := last_page(lines.len, size)28 if page > last {29 page = last30 }31 paint(render(manual_frame(lines, page, size, cols)))32 key := read_key()33 match key.kind {34 .interrupt, .eof, .escape, .enter {35 return36 }37 .down, .page_down {38 page = if page < last { page + 1 } else { page }39 }40 .up, .page_up {41 page = if page > 0 { page - 1 } else { 0 }42 }43 .home {44 page = 045 }46 .end {47 page = last48 }49 .tab {50 page = section_page(lines, page, size, true)51 }52 .backtab {53 page = section_page(lines, page, size, false)54 }55 .rune {56 match key.text {57 'q' { return }58 'j', ' ' { page = if page < last { page + 1 } else { page } }59 'k' { page = if page > 0 { page - 1 } else { 0 } }60 'g' { page = 0 }61 'G' { page = last }62 else {}63 }64 }65 else {}66 }67 }68}6970fn last_page(count int, size int) int {71 return if count == 0 { 0 } else { (count - 1) / size }72}737475pub fn manual_frame(lines []ManualLine, page int, size int, cols int) []string {76 start := page * size77 end := if start + size < lines.len { start + size } else { lines.len }78 mut frame := []string{}79 for line in lines[start..end] {80 frame << fmt.fit(line.text, cols)81 }82 for frame.len < size {83 frame << ''84 }85 bar := '${fmt.blue(section_at(lines, start))} · ' +86 fmt.muted('page ${page + 1} of ${last_page(lines.len, size) + 1} · tab: next section · ↑↓ j/k · q quit')87 frame << fmt.fit(bar, cols)88 return frame89}90919293fn section_at(lines []ManualLine, index int) string {94 for i := index; i >= 0; i-- {95 if i < lines.len && lines[i].section != '' {96 return lines[i].section97 }98 }99 return 'KOH'100}101102103104pub fn section_page(lines []ManualLine, page int, size int, forward bool) int {105 if forward {106 for i := (page + 1) * size; i < lines.len; i++ {107 if lines[i].section != '' {108 return i / size109 }110 }111 return page112 }113 for i := page * size - 1; i >= 0; i-- {114 if lines[i].section != '' {115 return i / size116 }117 }118 return page119}