1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
use tui;
use tui::widget::list;
use tui::layout;
use bufio;
use os;
use strings;
use fmt;
use io;
export fn main() void = {
const scanner = bufio::newscanner(os::stdin);
defer bufio::finish(&scanner);
let items: []str = [];
for (let line: const str => bufio::scan_line(&scanner)!) {
append(items, strings::dup(line));
};
defer strings::freeall(items);
const state = tui::init()!;
defer tui::finish(&state);
let li = list::newscrolllist(
&state,
(1, 1),
void,
void,
items...
)!;
let vl = layout::newvlayout(&li);
defer layout::finishvlayout(&vl);
vl.layout.print(&vl);
let term: (str | void) = void;
defer if (term is str) free(term as str) else void;
let revsearch = false;
for (true) {
const r = tui::read(&state)!;
if (r == 'j') {
list::down(&li);
};
if (r == 'k') {
list::up(&li);
};
if (r == 'J') {
list::framedown(&li);
};
if (r == 'K') {
list::frameup(&li);
};
if (r == 'g') {
list::top(&li);
};
if (r == 'G') {
list::bottom(&li);
};
if (r == 'q') {
break;
};
if (r == 'l') {
fmt::println(li.items[li.cursor])!;
break;
};
if (r == '/' || r == '?') {
revsearch = r == '?';
term = search(&state, &li, r as rune);
if (revsearch) prevsearch(&li, term) else nextsearch(&li, term);
};
if (r == 'n') {
if (revsearch) prevsearch(&li, term) else nextsearch(&li, term);
};
if (r == 'N') {
if (!revsearch) prevsearch(&li, term) else nextsearch(&li, term);
};
vl.layout.print(&vl);
};
};
fn search(state: *tui::tui, li: *list::scrolllist, prefix: (str | rune) = '/') (str | void) = {
tui::unraw(state);
defer tui::raw(state)!;
fmt::fprint(state.out, prefix)!;
const uline = match (bufio::read_line(state.out)!) {
case let u: []u8 =>
yield u;
case io::EOF =>
return;
};
defer free(uline);
return strings::dup(strings::fromutf8(uline)!);
};
fn nextsearch(li: *list::scrolllist, term: (str | void)) void = {
const term = match (term) {
case let term: str =>
yield term;
case void =>
return;
};
for (let i = li.cursor + 1; i < len(li.items): int; i += 1) {
if (strings::contains(li.items[i], term)) {
list::setcursor(li, i);
return;
};
};
};
fn prevsearch(li: *list::scrolllist, term: (str | void)) void = {
const term = match (term) {
case let term: str =>
yield term;
case void =>
return;
};
for (let i: int = li.cursor: int - 1; i >= 0; i -= 1) {
if (strings::contains(li.items[i], term)) {
list::setcursor(li, i);
return;
};
};
};
|