address.ha (2132B)
1 use regex; 2 use strings; 3 4 type Address = struct{ 5 addrform: AddressForm, 6 lineoffset: int, 7 setcurrentline: bool, 8 }; 9 10 type AddressForm = (size | CurrentLine | LastLine | rune | RegexAddr); 11 12 // The dot '.' address. 13 type CurrentLine = void; 14 15 // The dollar '$' address. 16 type LastLine = void; 17 18 // Regular expression search. /forward/ is true, ?backward? is false. 19 type RegexAddr = struct{ 20 expr: str, 21 direction: bool, 22 }; 23 24 // The address was invalid. 25 type InvalidAddress = !void; 26 27 // A regular expression search found no match. 28 type NoMatch = !void; 29 30 // There is no previously used regex search pattern. 31 type NoPrevRegex = !void; 32 33 fn addr_nextline(buf: *Buffer, n: size) size = { 34 if (len(buf.lines) - 1 == n) 35 return n; 36 37 return n + 1; 38 }; 39 40 fn addr_prevline(buf: *Buffer, n: size) size = { 41 if (n == 0 || n == 1) 42 return n; 43 44 return n - 1; 45 }; 46 47 fn addr_linenum(buf: *Buffer, n: size) (size | InvalidAddress) = { 48 if (n >= len(buf.lines)) 49 return InvalidAddress; 50 51 return n; 52 }; 53 54 fn addr_lastline(buf: *Buffer) size = { 55 return len(buf.lines) - 1z; 56 }; 57 58 fn addr_mark(buf: *Buffer, mark: rune) (size | InvalidAddress) = { 59 for (let n = 1z; n < len(buf.lines); n += 1) { 60 const line = buf.lines[n]; 61 if (line.mark == mark) 62 return n; 63 }; 64 65 return InvalidAddress; 66 }; 67 68 fn addr_regex( 69 buf: *Buffer, 70 rad: RegexAddr, 71 start: size, 72 s: *Session, 73 ) (size | NoPrevRegex | NoMatch | regex::error) = { 74 const length = len(buf.lines); 75 const re = newregex(s, rad.expr)?; defer regex::finish(&re); 76 77 for (let x = 1z; x <= length; x += 1) { 78 const n = 79 if (rad.direction) 80 (start + x) % length 81 else 82 (start - x) % length; 83 84 if (n == 0) 85 continue; 86 87 if (regex::test(&re, buf.lines[n].text)) 88 return n; 89 }; 90 91 return NoMatch; 92 }; 93 94 fn newregex(s: *Session, expr: str) (regex::regex | NoPrevRegex | regex::error) = { 95 //debug("expr=<{}>", expr); 96 //debug("s.lastregex=<{}>", s.lastregex); 97 98 const newexpr = 99 if (expr != "") 100 expr 101 else if (s.lastregex is str) 102 s.lastregex as str 103 else 104 return NoPrevRegex; 105 106 // TODO: use BRE, not ERE. 107 const re = regex::compile(newexpr)?; 108 s.lastregex = strings::dup(newexpr); 109 yield re; 110 };