commit 75577de0f5b81b5225c671403b12ea690a830346
parent 97ceeeaf3ef19e9c6481438f0eece7fbf645fee8
Author: Byron Torres <b@torresjrjr.com>
Date: Sun, 19 Feb 2023 23:46:13 +0000
complete cmd_shellescape()
Diffstat:
M | command.ha | | | 53 | ++++++++++++++++++++++++++++++++++++++++++++++++++++- |
M | main.ha | | | 4 | ++++ |
2 files changed, 56 insertions(+), 1 deletion(-)
diff --git a/command.ha b/command.ha
@@ -6,6 +6,7 @@ use os;
use os::exec;
use regex;
use strings;
+use strio;
type command = struct {
addrs: []address,
@@ -35,6 +36,7 @@ type error = !(
| nofilename
| buffermodified
| nomatch
+ | noprevshcmd
| regex::error
| fs::error
);
@@ -47,6 +49,8 @@ type nofilename = !void;
type buffermodified = !void;
+type noprevshcmd = !void;
+
fn lookupcmd(name: rune) commandfn = {
switch (name) {
case 'a' => return &cmd_append;
@@ -536,7 +540,49 @@ fn cmd_linenumber(s: *session, cmd: *command) (void | error) = {
};
fn cmd_shellescape(s: *session, cmd: *command) (void | error) = {
- let shcmd = exec::cmd("sh", "-c", cmd.arg)!;
+ let iter = strings::iter(cmd.arg);
+ let new = strio::dynamic(); defer io::close(&new)!;
+ let preview = false;
+
+ // handling '!!'
+ if (strings::next(&iter) == '!') {
+ match (s.prev_shcmd) {
+ case void =>
+ return noprevshcmd;
+ case let s: str =>
+ strio::concat(&new, s)!;
+ };
+ preview = true;
+ } else {
+ strings::prev(&iter);
+ };
+
+ // handling '%' and '\%'
+ for (true) {
+ match (strings::next(&iter)) {
+ case void =>
+ break;
+ case let r: rune =>
+ switch (r) {
+ case '\\' =>
+ match (strings::next(&iter)) {
+ case void =>
+ break;
+ case let r: rune =>
+ strio::appendrune(&new, r)!;
+ };
+ case '%' =>
+ strio::concat(&new, s.buf.filename)!;
+ preview = true;
+ case =>
+ strio::appendrune(&new, r)!;
+ };
+ };
+ };
+
+ let shcmdline = strings::dup(strio::string(&new));
+
+ let shcmd = exec::cmd("sh", "-c", shcmdline)!;
let pipe = exec::pipe();
exec::addfile(&shcmd, os::stdout_file, pipe.1);
let proc = exec::start(&shcmd)!;
@@ -546,10 +592,15 @@ fn cmd_shellescape(s: *session, cmd: *command) (void | error) = {
io::close(pipe.0)!;
exec::wait(&proc)!;
+ if (preview) {
+ fmt::println(shcmdline)!;
+ };
fmt::print(strings::fromutf8(data)!)!;
if (!s.suppressmode) {
fmt::println("!")!;
};
+
+ s.prev_shcmd = shcmdline;
};
fn cmd_null(s: *session, cmd: *command) (void | error) = {
diff --git a/main.ha b/main.ha
@@ -17,6 +17,7 @@ type session = struct {
promptmode: bool,
prompt: str,
warned: bool,
+ prev_shcmd: (str | void),
};
type mode = enum {
@@ -41,6 +42,7 @@ export fn main() void = {
...
},
prompt = "*",
+ prev_shcmd = void,
...
};
@@ -148,6 +150,8 @@ fn errormsg(s: *session, err: error) error = {
yield "Invalid destination";
case nomatch =>
yield "No match";
+ case noprevshcmd =>
+ yield "No previous shell command";
case let e: regex::error =>
yield regex::strerror(e);
case let e: fs::error =>