main.ha (2066B)
1 use fmt; 2 use io; 3 use bufio; 4 use strings; 5 use fs; 6 use os; 7 use ascii; 8 use strconv; 9 10 use util; 11 12 type command = struct { 13 c: rune, 14 range: (size, size), 15 args: []str 16 }; 17 18 let file: nullable *lines = null; 19 let pos: size = 0; 20 21 fn loadfile(h: io::handle) nullable *lines = { 22 let ls: nullable *lines = null; 23 let sc = bufio::newscanner(h); 24 defer bufio::finish(&sc); 25 26 for (true) { 27 match (bufio::scan_line(&sc)) { 28 case let s: str => 29 match (ls) { 30 case let ls: *lines => 31 ls.next = newline(strings::dup(s)!); 32 (ls.next as *lines).prev = ls; 33 case null => ls = newline(strings::dup(s)!); 34 }; 35 case io::EOF => break; 36 case => abort(); 37 }; 38 }; 39 40 return ls; 41 }; 42 43 fn openfile(name: str) nullable *lines = { 44 let h = match(os::open(name)) { 45 case let h: io::file => yield h; 46 case let e: fs::error => util::die(fs::strerror(e)); 47 }; 48 defer io::close(h)!; 49 50 return loadfile(h); 51 }; 52 53 fn parsenum(runes: []rune) (size, []rune) = { 54 let digits: []rune = []; 55 defer free(digits); 56 57 let i = 0z; 58 59 for (ascii::isdigit(runes[i])) { 60 append(digits, runes[i])!; 61 i += 1; 62 }; 63 64 let num = strings::fromrunes(digits)!; 65 defer free(num); 66 67 return (strconv::stoz(num)!, runes[i..]); 68 }; 69 70 fn parsecmd(s: str) command = { 71 let c: command = command{c = ' ', range = (-1, -1), args = []}; 72 73 let runes = strings::torunes(s)!; 74 let sav = runes; 75 defer free(sav); 76 77 if (ascii::isdigit(runes[0])) { 78 let res = parsenum(runes); 79 c.range.0 = res.0; runes = res.1; 80 if (runes[0] == ',') { 81 res = parsenum(runes[1..]); 82 c.range.0 = res.0; runes = res.1; 83 } else c.range.1 = -1; 84 } else c.range = (-1, -1); 85 86 c.c = runes[0]; 87 88 return c; 89 }; 90 91 fn runcmd() void = { 92 let sc = bufio::newscanner(os::stdin); 93 defer bufio::finish(&sc); 94 95 let in = parsecmd(bufio::scan_line(&sc) as str); 96 97 for (let c .. cmds) { 98 if (c.cmd == in.c) { 99 c.f(&(file as *lines), &pos, in.range, in.args); 100 break; 101 }; 102 }; 103 }; 104 105 export fn main() void = { 106 if (len(os::args) < 2) { 107 util::die("", "needs a file!"); 108 }; 109 let f = os::open(os::args[1])!; 110 file = loadfile(f); 111 112 for (true) { 113 runcmd(); 114 }; 115 };