commit db30ac46bf4bd6ce42f8b08495cc5643446ae202
parent 2a3d0336ce771b0ea1a7581eb9d0e650649fc54a
Author: Byron Torres <b@torresjrjr.com>
Date: Sun, 14 Jan 2024 22:27:49 +0000
cmd_substitute(): handle flags
Diffstat:
M | command.ha | | | 9 | +++++++-- |
M | parse.ha | | | 76 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------- |
2 files changed, 62 insertions(+), 23 deletions(-)
diff --git a/command.ha b/command.ha
@@ -16,6 +16,8 @@ type Command = struct{
arg1: str,
arg2: str,
arg3: str,
+ count: size,
+ flag_global: bool,
textinput: []str,
subcmds: []Command,
};
@@ -472,10 +474,10 @@ fn cmd_substitute(s: *Session, cmd: *Command) (void | Error) = {
const re = newregex(s, cmd.arg1)?; defer regex::finish(&re);
const replacement = cmd.arg2;
- const flags = cmd.arg3;
// TODO: parse and use substitution flags `cmd.arg3`
// use regex::replace ?
// TODO: implement '&', '%'
+ let count = if (cmd.count == 0z) 0z else cmd.count - 1z;
for (let n = a; n <= b; n += 1) {
const old = s.buf.lines[n].text;
@@ -491,12 +493,15 @@ fn cmd_substitute(s: *Session, cmd: *Command) (void | Error) = {
let start = 0z;
let lbound = 0z;
let rbound = 0z;
- for (let i = 0z; i < len(results); i += 1) {
+ for (let i = count; i < len(results); i += 1) {
lbound = results[i][0].start;
rbound = results[i][0].end;
memio::concat(&new, strings::sub(old, start, lbound))!;
memio::concat(&new, replacement)!;
start = rbound;
+
+ if (!cmd.flag_global)
+ break;
};
memio::concat(&new, strings::sub(old, rbound, strings::end))!;
diff --git a/parse.ha b/parse.ha
@@ -141,19 +141,19 @@ fn parse_cmdargs(cmd: *Command, iter: *strings::iterator) (bool | ParseError) =
// .[s] where 's' is '(l|n|p)'
case 'd', 'h', 'H', 'j', 'l', 'n', 'p', 'P', 'u', '=' =>
- cmd.printmode = scan_suffix(iter);
+ cmd.printmode = scan_printmode(iter);
scan_end_assert(iter)?;
return true;
// .[s]
case 'a', 'c', 'i' =>
- cmd.printmode = scan_suffix(iter);
+ cmd.printmode = scan_printmode(iter);
scan_end_assert(iter)?;
return false;
// .[s][ ]<addr>
case 'm', 't' =>
- cmd.printmode = scan_suffix(iter);
+ cmd.printmode = scan_printmode(iter);
cmd.arg1 = scan_rest(iter);
return true;
@@ -218,7 +218,10 @@ fn parse_cmdargs(cmd: *Command, iter: *strings::iterator) (bool | ParseError) =
case void =>
return true;
};
- cmd.arg3 = scan_rest(iter); // TODO: scan properly here?
+ let (count, global, printmode) = scan_substitute_flags(iter);
+ cmd.count = count;
+ cmd.flag_global = global;
+ cmd.printmode = printmode;
return true;
case '&' =>
@@ -322,7 +325,7 @@ fn scan_addr(iter: *strings::iterator) (Address | void) = {
yield LastLine;
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' =>
strings::prev(iter);
- yield scan_uint(iter): size;
+ yield scan_size(iter): size;
case '\'' =>
yield scan_mark(iter);
case '/' =>
@@ -384,7 +387,7 @@ fn scan_offsets(iter: *strings::iterator) []int = {
append(offs, -scan_offset(iter));
} else if (ascii::isdigit(r)) {
strings::prev(iter);
- append(offs, scan_uint(iter): int);
+ append(offs, scan_size(iter): int);
} else {
strings::prev(iter);
break;
@@ -402,7 +405,7 @@ fn scan_offset(iter: *strings::iterator) int = {
case let r: rune =>
strings::prev(iter);
if (ascii::isdigit(r)) {
- return scan_uint(iter): int;
+ return scan_size(iter): int;
} else {
return 1;
};
@@ -430,7 +433,7 @@ fn scan_cmdname(iter: *strings::iterator) (rune | UnknownCommand) = {
};
};
-fn scan_suffix(iter: *strings::iterator) PrintMode = {
+fn scan_printmode(iter: *strings::iterator) PrintMode = {
let r = match (strings::next(iter)) {
case void =>
return PrintMode::NONE;
@@ -508,11 +511,42 @@ fn scan_mark(iter: *strings::iterator) rune = {
};
};
-// TODO: rename and appropriate to "scan_size()"?
-fn scan_uint(iter: *strings::iterator) uint = {
+fn scan_substitute_flags(iter: *strings::iterator) (size, bool, PrintMode) = {
+ let count = 0z;
+ let global = false;
+ let printmode = PrintMode::NONE;
+
+ for (true) {
+ let r = match (strings::next(iter)) {
+ case void =>
+ break;
+ case let r: rune =>
+ yield r;
+ };
+
+ switch (r) {
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' =>
+ strings::prev(iter);
+ count = scan_size(iter);
+ case 'g' =>
+ global = true;
+ case 'p' =>
+ printmode = PrintMode::PLAIN;
+ case 'n' =>
+ printmode = PrintMode::NUMBER;
+ case 'l' =>
+ printmode = PrintMode::LIST;
+ case =>
+ break;
+ };
+ };
+
+ return (count, global, printmode);
+};
+
+fn scan_size(iter: *strings::iterator) size = {
+ let begin = *iter;
// reimplement this function using another iterator
- let num: []rune = [];
- defer free(num);
for (true) {
let r = match (strings::next(iter)) {
case void =>
@@ -521,24 +555,24 @@ fn scan_uint(iter: *strings::iterator) uint = {
yield r;
};
- if (ascii::isdigit(r)) {
- append(num, r);
- } else {
+ if (!ascii::isdigit(r)) {
strings::prev(iter);
break;
};
};
+ let num = strings::slice(&begin, iter);
+
// TODO: return void instead?
- if (len(num) == 0) {
- return 0;
+ if (num == "") {
+ return 0z;
};
- match (strconv::stou(strings::fromrunes(num))) {
+ match (strconv::stoz(num)) {
case (strconv::invalid | strconv::overflow) =>
- abort("Invalid");
- case let u: uint =>
- return u;
+ abort("Invalid"); // TODO: propagate?
+ case let z: size =>
+ return z;
};
};