Implement prefix-based interactive commands via ! (issue #14)
Add !command syntax that runs commands with inherited terminal (no
capture). The lexer treats ! as a statement-starting token, reading
to end-of-line with the same interpolation/escape/pipe support as
backtick commands. The C function sets _ = {code=N, stdout="", stderr=""}.
This commit is contained in:
36
llex.c
36
llex.c
@@ -50,7 +50,8 @@ static const char *const luaX_tokens [] = {
|
||||
"//", "..", "...", "==", ">=", "<=", "~=",
|
||||
"<<", ">>", "::", "<eof>",
|
||||
"<number>", "<integer>", "<name>", "<string>",
|
||||
"<command>", "<command_interp>", "<envvar>"
|
||||
"<command>", "<command_interp>", "<envvar>",
|
||||
"<interactive>", "<interactive_interp>"
|
||||
};
|
||||
|
||||
|
||||
@@ -190,7 +191,7 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
|
||||
ls->source = source;
|
||||
/* all three strings here ("_ENV", "break", "global") were fixed,
|
||||
so they cannot be collected */
|
||||
ls->in_command = 0;
|
||||
ls->cmd_mode = 0;
|
||||
ls->envn = luaS_newliteral(L, LUA_ENV); /* get env string */
|
||||
ls->brkn = luaS_newliteral(L, "break"); /* get "break" string */
|
||||
#if defined(LUA_COMPAT_GLOBAL)
|
||||
@@ -478,14 +479,29 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) {
|
||||
** or TK_COMMAND_INTERP if an interpolation ${...} was found.
|
||||
*/
|
||||
static int read_command_body (LexState *ls, SemInfo *seminfo) {
|
||||
int interactive = (ls->cmd_mode == 2);
|
||||
luaZ_resetbuffer(ls->buff);
|
||||
for (;;) {
|
||||
switch (ls->current) {
|
||||
case EOZ:
|
||||
if (interactive) {
|
||||
seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
|
||||
luaZ_bufflen(ls->buff));
|
||||
ls->cmd_mode = 0;
|
||||
return TK_INTERACTIVE;
|
||||
}
|
||||
lexerror(ls, "unfinished command", TK_EOS);
|
||||
break; /* to avoid warnings */
|
||||
case '\n':
|
||||
case '\r':
|
||||
if (interactive) {
|
||||
/* newline terminates interactive command (don't consume it —
|
||||
leave for inclinenumber on next llex() call) */
|
||||
seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
|
||||
luaZ_bufflen(ls->buff));
|
||||
ls->cmd_mode = 0;
|
||||
return TK_INTERACTIVE;
|
||||
}
|
||||
save(ls, '\n');
|
||||
inclinenumber(ls);
|
||||
break;
|
||||
@@ -496,8 +512,7 @@ static int read_command_body (LexState *ls, SemInfo *seminfo) {
|
||||
/* store fragment so far */
|
||||
seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
|
||||
luaZ_bufflen(ls->buff));
|
||||
ls->in_command = 1;
|
||||
return TK_COMMAND_INTERP;
|
||||
return interactive ? TK_INTERACTIVE_INTERP : TK_COMMAND_INTERP;
|
||||
}
|
||||
else {
|
||||
save(ls, '$'); /* not an interpolation, keep literal '$' */
|
||||
@@ -505,10 +520,15 @@ static int read_command_body (LexState *ls, SemInfo *seminfo) {
|
||||
break;
|
||||
}
|
||||
case '`': {
|
||||
if (interactive) {
|
||||
/* backtick is literal in interactive mode */
|
||||
save_and_next(ls);
|
||||
break;
|
||||
}
|
||||
next(ls); /* skip closing '`' */
|
||||
seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
|
||||
luaZ_bufflen(ls->buff));
|
||||
ls->in_command = 0;
|
||||
ls->cmd_mode = 0;
|
||||
return TK_COMMAND;
|
||||
}
|
||||
case '\\': { /* escape sequences */
|
||||
@@ -541,6 +561,7 @@ static int read_command_body (LexState *ls, SemInfo *seminfo) {
|
||||
|
||||
static int read_command (LexState *ls, SemInfo *seminfo) {
|
||||
next(ls); /* skip opening '`' */
|
||||
ls->cmd_mode = 1;
|
||||
return read_command_body(ls, seminfo);
|
||||
}
|
||||
|
||||
@@ -636,6 +657,11 @@ static int llex (LexState *ls, SemInfo *seminfo) {
|
||||
case '`': { /* explicit command `ls -l` with ${} interpolation */
|
||||
return read_command(ls, seminfo);
|
||||
}
|
||||
case '!': { /* interactive command !ls -l */
|
||||
next(ls); /* skip '!' */
|
||||
ls->cmd_mode = 2;
|
||||
return read_command_body(ls, seminfo);
|
||||
}
|
||||
case '$': { /* environment variable $NAME */
|
||||
next(ls);
|
||||
if (lislalpha(ls->current)) { /* $NAME */
|
||||
|
||||
Reference in New Issue
Block a user