Add shell aliases via lush.aliases table (issue #28)
Aliases rewrite the command string before pipeline splitting, so alias values may contain pipes (e.g. lush.aliases.foo = "echo hi |"). Expansion happens once per dispatch to prevent recursion.
This commit is contained in:
70
lcmd.c
70
lcmd.c
@@ -897,6 +897,67 @@ static int try_builtin (lua_State *L, ParsedArgs *pa) {
|
||||
}
|
||||
|
||||
|
||||
/* ===== alias expansion ===== */
|
||||
|
||||
/*
|
||||
** Extract the first whitespace-delimited word from cmd, look it up in
|
||||
** lush.aliases. If found, replace the command string on the Lua stack
|
||||
** (position 1) with alias_value + remaining_text, and update *cmd.
|
||||
** Expansion happens on the raw string, before pipeline splitting,
|
||||
** so alias values may contain pipes.
|
||||
** Returns 1 if expanded, 0 if no alias.
|
||||
*/
|
||||
static int expand_alias (lua_State *L, const char **cmd) {
|
||||
const char *s = *cmd;
|
||||
const char *rest;
|
||||
size_t wordlen;
|
||||
const char *alias;
|
||||
size_t alias_len, rest_len, total;
|
||||
char *expanded;
|
||||
|
||||
/* skip leading whitespace */
|
||||
while (*s == ' ' || *s == '\t') s++;
|
||||
if (*s == '\0') return 0;
|
||||
|
||||
/* find end of first word */
|
||||
rest = s;
|
||||
while (*rest && *rest != ' ' && *rest != '\t') rest++;
|
||||
wordlen = (size_t)(rest - s);
|
||||
|
||||
/* look up in lush.aliases */
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_LUSH);
|
||||
lua_getfield(L, -1, "aliases");
|
||||
lua_pushlstring(L, s, wordlen);
|
||||
lua_gettable(L, -2);
|
||||
|
||||
if (!lua_isstring(L, -1)) {
|
||||
lua_pop(L, 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
alias = lua_tolstring(L, -1, &alias_len);
|
||||
rest_len = strlen(rest); /* includes leading space if any */
|
||||
|
||||
total = alias_len + rest_len;
|
||||
expanded = (char *)malloc(total + 1);
|
||||
if (expanded == NULL) {
|
||||
lua_pop(L, 3);
|
||||
return 0;
|
||||
}
|
||||
memcpy(expanded, alias, alias_len);
|
||||
memcpy(expanded + alias_len, rest, rest_len);
|
||||
expanded[total] = '\0';
|
||||
lua_pop(L, 3);
|
||||
|
||||
/* replace command on Lua stack */
|
||||
lua_pushstring(L, expanded);
|
||||
lua_replace(L, 1);
|
||||
free(expanded);
|
||||
*cmd = lua_tostring(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ===== lushCmd_command ===== */
|
||||
|
||||
int lushCmd_command (lua_State *L) {
|
||||
@@ -910,6 +971,9 @@ int lushCmd_command (lua_State *L) {
|
||||
DynBuf buf_out, buf_err;
|
||||
struct sigaction sa_old, sa_new;
|
||||
|
||||
/* expand alias before pipeline splitting */
|
||||
expand_alias(L, &cmd);
|
||||
|
||||
/* try to split into pipeline stages */
|
||||
if (split_pipeline(cmd, stages, &nstages) != 0)
|
||||
return luaL_error(L, "invalid pipeline syntax in command");
|
||||
@@ -1076,6 +1140,9 @@ int lushCmd_interactive (lua_State *L) {
|
||||
struct sigaction sa_old_pipe, sa_old_int, sa_old_quit, sa_new;
|
||||
DynBuf buf_out, buf_err;
|
||||
|
||||
/* expand alias before pipeline splitting */
|
||||
expand_alias(L, &cmd);
|
||||
|
||||
/* try to split into pipeline stages */
|
||||
if (split_pipeline(cmd, stages, &nstages) != 0)
|
||||
return luaL_error(L, "invalid pipeline syntax in command");
|
||||
@@ -1217,6 +1284,9 @@ static const luaL_Reg lushlib[] = {
|
||||
|
||||
LUAMOD_API int luaopen_lush (lua_State *L) {
|
||||
luaL_newlib(L, lushlib);
|
||||
/* create aliases subtable */
|
||||
lua_createtable(L, 0, 4);
|
||||
lua_setfield(L, -2, "aliases");
|
||||
/* intern function name strings for OP_LUSH VM access */
|
||||
lushname[LUSH_OP_COMMAND] = luaS_new(L, "command");
|
||||
lushname[LUSH_OP_INTERACTIVE] = luaS_new(L, "interactive");
|
||||
|
||||
Reference in New Issue
Block a user