global.ha (4117B)
1 use bufio; 2 use fmt; 3 use io; 4 use memio; 5 use regex; 6 use strings; 7 use types; 8 9 fn global(s: *Session, cmd: *Command, matched: bool) (void | Error) = { 10 s.warned = false; 11 12 const (a, b) = get_range( 13 s, 14 &cmd.linenums, 15 addr_linenum(s.buf, 1)?, 16 addr_lastline(s.buf), 17 )?; 18 assert_nonzero(s, a)?; 19 20 const re = newregex(s, cmd.arg1)?; defer regex::finish(&re); 21 22 for (let i = a; i <= b; i += 1) { 23 const line = s.buf.lines[i]; 24 line.globalmark = false; // TODO: is this necessary? 25 if (matched == regex::test(&re, line.text)) 26 line.globalmark = true; 27 }; 28 29 let subcmds: []Command = []; 30 31 let inputtext = strings::join("\n", cmd.textinput...); 32 let inputbytes = strings::toutf8(inputtext); 33 let inputstream = memio::dynamic_from(inputbytes); 34 defer io::close(&inputstream)!; 35 let input = bufio::newscanner(&inputstream, types::SIZE_MAX); 36 defer bufio::finish(&input); 37 // TODO: could be less than types::SIZE_MAX ^ ? 38 39 for (true) { 40 // TODO: handle mem 41 // TODO: just use 'parse()?' when compiler allows 42 //let subcmd = parse(s.input)?; 43 let subcmd = match (parse(&input)) { 44 case let c: Command => 45 yield c; 46 case io::EOF => 47 break; 48 case let e: ParseError => 49 return e; 50 case let e: InteractionError => 51 return e; 52 }; 53 54 debug("cmd_global() for subcmd.name=<{}>", subcmd.name); 55 56 // TODO: write new parse_global() function instead 57 // as to avoid reading multiple lines in the case of 58 // 'a', 'c', 'i' ? 59 switch (subcmd.name) { 60 case 'g', 'G', 'v', 'V', '!' => 61 // TODO: undefined specification. implement? 62 errormsg(s, subcmd.name: InvalidGlobalSubCmd); 63 continue; 64 case '&' => 65 errormsg(s, '&': UnknownCommand); 66 continue; 67 case 'u' => 68 // TODO: undo behaviour 69 continue; 70 case => 71 void; 72 }; 73 74 append(subcmds, subcmd); 75 }; 76 77 debug("cmd_global() len(subcmds)={}", len(subcmds)); 78 79 if (len(subcmds) == 0) 80 append(subcmds, Command{ name = 'p', ... }); 81 82 for :marks (true) { 83 // find next global-marked line 84 let n = 1z; 85 for :lines (true; n += 1) { 86 if (n >= len(s.buf.lines)) { 87 break :marks; 88 }; 89 if (s.buf.lines[n].globalmark) { 90 break :lines; 91 }; 92 }; 93 s.buf.cursor = n; 94 let line = s.buf.lines[n]; 95 96 for (let i = 0z; i < len(subcmds); i += 1) { 97 let subcmd = subcmds[i]; 98 //debug("cmd_global() for :marks execute()ing"); 99 execute(s, &subcmd)?; 100 }; 101 102 line.globalmark = false; 103 }; 104 }; 105 106 fn global_ia(s: *Session, cmd: *Command, matched: bool) (void | Error) = { 107 s.warned = false; 108 109 const (a, b) = get_range( 110 s, 111 &cmd.linenums, 112 addr_linenum(s.buf, 1)?, 113 addr_lastline(s.buf), 114 )?; 115 assert_nonzero(s, a)?; 116 117 const re = newregex(s, cmd.arg1)?; defer regex::finish(&re); 118 119 for (let i = a; i <= b; i += 1) { 120 const line = s.buf.lines[i]; 121 line.globalmark = false; // TODO: is this necessary? 122 if (matched == regex::test(&re, line.text)) 123 line.globalmark = true; 124 }; 125 126 let prevsubcmd: (void | Command) = void; // TODO: handle mem 127 128 for :marks (true) { 129 // find next global-marked line 130 let n = 1z; 131 for :lines (true; n += 1) { 132 if (n >= len(s.buf.lines)) { 133 break :marks; 134 }; 135 if (s.buf.lines[n].globalmark) { 136 break :lines; 137 }; 138 }; 139 s.buf.cursor = n; 140 let line = s.buf.lines[n]; 141 142 fmt::println(line.text)!; 143 144 // TODO: handle mem 145 // TODO: just use 'parse()?' when compiler allows 146 //let subcmd = parse(s.input)?; 147 let subcmd = match (parse(s.input)) { 148 case let c: Command => 149 yield c; 150 case let e: ParseError => 151 return e; 152 case let e: InteractionError => 153 return e; 154 }; 155 156 // TODO: write new parse_global_ia() function instead 157 // as to avoid reading multiple lines in the case of 158 // 'a', 'c', 'i' ? 159 switch (subcmd.name) { 160 case 'a', 'c', 'i', 'g', 'G', 'v', 'V' => 161 errormsg(s, subcmd.name: InvalidGlobalSubCmd); 162 continue; 163 case NUL => 164 line.globalmark = false; 165 continue; 166 case '&' => 167 match (prevsubcmd) { 168 case void => 169 return NoPrevGlobalSubCmd; 170 case let prevsubcmd: Command => 171 subcmd = prevsubcmd; 172 }; 173 case 'u' => 174 // TODO: undo behaviour 175 continue; 176 case => 177 prevsubcmd = subcmd; 178 }; 179 180 execute(s, &subcmd)?; 181 182 line.globalmark = false; 183 }; 184 };