commit 68d687a913ca150afed7877b26343356b1dc87dc
parent 3d06a08091e0de7e3e156e0d359eb3cf7e0a695b
Author: Byron Torres <b@torresjrjr.com>
Date: Sat, 6 Jan 2024 16:19:41 +0000
impl & repeat command
Diffstat:
3 files changed, 41 insertions(+), 11 deletions(-)
diff --git a/command.ha b/command.ha
@@ -99,7 +99,7 @@ fn lookupcmd(name: rune) CommandFn = {
case 'w' => return &cmd_write;
case '=' => return &cmd_linenumber;
case '!' => return &cmd_shellescape;
- case '\x00' => return &cmd_null;
+ case NUL => return &cmd_null;
case => abort();
};
};
@@ -279,6 +279,8 @@ fn cmd_global_interative(s: *Session, cmd: *Command) (void | Error) = {
};
};
+ let prevcmd: (void | Command) = void;
+
for :marks (true) {
// find next global-marked line
let n = 1z;
@@ -302,9 +304,22 @@ fn cmd_global_interative(s: *Session, cmd: *Command) (void | Error) = {
// 'a', 'c', 'i' ?
switch (cmd.cmdname) {
case 'a', 'c', 'i', 'g', 'G', 'v', 'V' =>
- // return new type 'InvalidGlobalInteractiveSubcmd' ?
+ // TODO: how to handle?
+ // return !InvalidGlobalInteractiveSubcmd; ?
+ continue;
+ case NUL =>
+ line.globalmark = false;
continue;
- case => void;
+ case '&' =>
+ match (prevcmd) {
+ case void =>
+ // TODO: return NoPrevGlobalCmd;
+ abort("global interactive: &: no previous command");
+ case let prevcmd: Command =>
+ cmd = prevcmd;
+ };
+ case =>
+ prevcmd = cmd;
};
execute(s, &cmd)?;
@@ -370,11 +385,11 @@ fn cmd_join(s: *Session, cmd: *Command) (void | Error) = {
};
let ls: []str = [];
- let mark = '\x00';
+ let mark = NUL;
for (let n = a; n <= b; n += 1) {
const l = s.buf.lines[n];
append(ls, l.text);
- if (mark == '\x00') {
+ if (mark == NUL) {
mark = l.mark;
};
};
@@ -408,7 +423,7 @@ fn cmd_mark(s: *Session, cmd: *Command) (void | Error) = {
debug("cmd_mark(): search A i={}", i);
if (s.buf.trash[i].mark == mark) {
debug("cmd_mark(): search A i={} true", i);
- s.buf.trash[i].mark = '\x00';
+ s.buf.trash[i].mark = NUL;
yield :search;
};
};
@@ -417,7 +432,7 @@ fn cmd_mark(s: *Session, cmd: *Command) (void | Error) = {
debug("cmd_mark(): search B i={}", i);
if (s.buf.lines[i].mark == mark) {
debug("cmd_mark(): search B i={} true", i);
- s.buf.lines[i].mark = '\x00';
+ s.buf.lines[i].mark = NUL;
yield :search;
};
};
@@ -578,8 +593,11 @@ fn cmd_substitute(s: *Session, cmd: *Command) (void | Error) = {
)?;
assert_nonzero(s, a)?;
- const replacement = cmd.arg2;
const regex = regex::compile(cmd.arg1)?; defer regex::finish(®ex);
+ const replacement = cmd.arg2;
+ // TODO: parse and use substitution flags `cmd.arg3`
+ // use regex::replace ?
+ // TODO: implement '&', '%'
for (let i = a; i <= b; i += 1) {
const old = s.buf.lines[i].text;
diff --git a/main.ha b/main.ha
@@ -98,6 +98,11 @@ export fn main() void = {
};
defer command_finish(&cmd);
+ if (cmd.cmdname == '&') {
+ errormsg(&s, strerror('&': UnknownCommand));
+ continue;
+ };
+
match (execute(&s, &cmd)) {
case Quit =>
debug("main() for match (exec) case Quit");
diff --git a/parse.ha b/parse.ha
@@ -34,6 +34,8 @@ type InvalidDelimiter = !void;
type ExpectedDelimiter = !void;
+def NUL = '\x00';
+
// Parses inputted commands. Returns true when command is ready.
fn parse(input: *bufio::scanner) (Command | ParseError | InteractionError) = {
let inputline = match (bufio::scan_line(input)?) {
@@ -86,10 +88,11 @@ fn parse(input: *bufio::scanner) (Command | ParseError | InteractionError) = {
return cmd;
};
+// TODO: remove 'bool' returns
fn parse_cmdargs(cmd: *Command, iter: *strings::iterator) (bool | ParseError) = {
switch (cmd.cmdname) {
// [ ]
- case '\x00' =>
+ case NUL =>
return true;
// (q|Q)
@@ -209,6 +212,10 @@ fn parse_cmdargs(cmd: *Command, iter: *strings::iterator) (bool | ParseError) =
cmd.arg3 = scan_rest(iter); // TODO: scan properly here?
return true;
+ case '&' =>
+ scan_end_assert(iter)?;
+ return true;
+
case =>
abort();
};
@@ -399,7 +406,7 @@ fn scan_cmdname(iter: *strings::iterator) (rune | UnknownCommand) = {
scan_blanks(iter);
let r = match (strings::next(iter)) {
case void =>
- return '\x00';
+ return NUL;
case let r: rune =>
yield r;
};
@@ -408,7 +415,7 @@ fn scan_cmdname(iter: *strings::iterator) (rune | UnknownCommand) = {
case
'a', 'c', 'd', 'e', 'E', 'f', 'g', 'G', 'h', 'H',
'i', 'j', 'k', 'l', 'm', 'n', 'p', 'P', 'q', 'Q',
- 'r', 's', 't', 'u', 'v', 'V', 'w', '=', '!',
+ 'r', 's', 't', 'u', 'v', 'V', 'w', '=', '!', '&',
=>
return r;
case =>