aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar BanceDev 2024-09-09 10:22:06 -0400
committerGravatar BanceDev 2024-09-09 10:22:06 -0400
commit49de8d30345020c046d125c39bdf2a177b4f9e94 (patch)
treee2c03299979ff3e455739a371088d764bb770cc5
parentadded getenv and putenv to Lua API (diff)
added support for init.lua for configuring shell
-rw-r--r--.lush/init.lua35
-rw-r--r--.lush/scripts/example.lua5
-rw-r--r--install.sh7
-rw-r--r--src/lua_api.c51
-rw-r--r--src/lua_api.h1
-rw-r--r--src/lush.c114
-rw-r--r--src/lush.h5
-rw-r--r--vgcore.250513bin0 -> 7970816 bytes
8 files changed, 180 insertions, 38 deletions
diff --git a/.lush/init.lua b/.lush/init.lua
new file mode 100644
index 0000000..26fe71e
--- /dev/null
+++ b/.lush/init.lua
@@ -0,0 +1,35 @@
+--[[
+Copyright (c) 2024, Lance Borden
+All rights reserved.
+
+This software is licensed under the BSD 3-Clause License.
+You may obtain a copy of the license at:
+https://opensource.org/licenses/BSD-3-Clause
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted under the conditions stated in the BSD 3-Clause
+License.
+
+THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+]]
+
+-- This file is your init.lua. It will be automatically executed each time you open
+-- a new session of Lunar Shell.
+
+-- Setting environment variables
+local path = lush.getenv("HOME") .. "/bin:" .. lush.getenv("PATH")
+lush.setenv("PATH", path)
+
+-- the prompt can be customized here too
+-- %u is username, %h is hostname, %w is current working directory
+lush.setPrompt("[%u@%h: %w]")
+-- any global functions that accept either no parameters or just an array of args
+-- will be read in and stored as built in commands for the shell
+function my_command(args)
+ print("my custom command")
+end
+
+-- all functions from the Lunar Shell Lua API are available to you to
+-- customize your startup however you want
diff --git a/.lush/scripts/example.lua b/.lush/scripts/example.lua
index 4d0b8fa..c60f99b 100644
--- a/.lush/scripts/example.lua
+++ b/.lush/scripts/example.lua
@@ -84,7 +84,10 @@ print("Most recent history: " .. lush.lastHistory())
print("Most recent history indexed: " .. lush.getHistory(1))
-- you can set environment variables using putenv
-lush.putenv("EXAMPLE=Lunar Shell Example")
+lush.setenv("EXAMPLE", "Lunar Shell Example")
-- you can get an environment variable using getenv
print("Value of EXAMPLE: " .. lush.getenv("EXAMPLE"))
+
+-- you can unset an environment variable with unsetenv
+lush.unsetenv("EXAMPLE")
diff --git a/install.sh b/install.sh
index bdcfe2e..ebdbaeb 100644
--- a/install.sh
+++ b/install.sh
@@ -51,7 +51,12 @@ rm premake.tar.gz
premake5 gmake
make
-cp -rf ./.lush ~/
+if [ ! -d ~/.lush ]; then
+ cp -rf ./.lush ~/
+fi
+
+# always update example
+cp -f ./.lush/scripts/example.lua ~/.lush/scripts/example.lua
# Install the new shell binary to a temporary location
sudo cp ./bin/Debug/lush/lush /usr/bin/lush.new
diff --git a/src/lua_api.c b/src/lua_api.c
index e28d7c1..2f967e6 100644
--- a/src/lua_api.c
+++ b/src/lua_api.c
@@ -29,7 +29,7 @@ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#include <sys/stat.h>
#include <unistd.h>
-// global for checking if debug_mode is toggled
+// globals
static bool debug_mode = false;
// -- script execution --
@@ -56,7 +56,7 @@ void lua_load_script(lua_State *L, const char *script, char **args) {
}
}
// add args global if args were passed
- if (args[0] != NULL) {
+ if (args != NULL && args[0] != NULL) {
lua_newtable(L);
for (int i = 0; args[i]; i++) {
lua_pushstring(L, args[i]);
@@ -79,6 +79,12 @@ void lua_load_script(lua_State *L, const char *script, char **args) {
}
}
+void lua_run_init(lua_State *L) {
+ char script_path[64];
+ snprintf(script_path, sizeof(script_path), ".lush/%s", "init.lua");
+ lua_load_script(L, script_path, NULL);
+}
+
// -- C funtions --
static int execute_command(lua_State *L, const char *line) {
int status = 0;
@@ -284,9 +290,38 @@ static int l_get_env(lua_State *L) {
return 1;
}
-static int l_put_env(lua_State *L) {
+static int l_set_env(lua_State *L) {
+ const char *env_name = luaL_checkstring(L, 1);
+ const char *env_value = luaL_checkstring(L, 2);
+ setenv(env_name, env_value, 1);
+ return 0;
+}
+
+static int l_unset_env(lua_State *L) {
const char *env = luaL_checkstring(L, 1);
- putenv((char *)env);
+ unsetenv(env);
+ return 0;
+}
+
+static int l_set_prompt(lua_State *L) {
+ const char *format = luaL_checkstring(L, 1);
+ if (format == NULL) {
+ perror("string format not passed");
+ return 0;
+ }
+
+ // free old prompt format if necessary
+ if (prompt_format) {
+ free(prompt_format);
+ }
+
+ prompt_format = malloc(strlen(format) + 1);
+
+ if (prompt_format) {
+ strcpy(prompt_format, format);
+ } else {
+ perror("malloc failed");
+ }
return 0;
}
@@ -320,8 +355,12 @@ void lua_register_api(lua_State *L) {
lua_setfield(L, -2, "getHistory");
lua_pushcfunction(L, l_get_env);
lua_setfield(L, -2, "getenv");
- lua_pushcfunction(L, l_put_env);
- lua_setfield(L, -2, "putenv");
+ lua_pushcfunction(L, l_set_env);
+ lua_setfield(L, -2, "setenv");
+ lua_pushcfunction(L, l_unset_env);
+ lua_setfield(L, -2, "unsetenv");
+ lua_pushcfunction(L, l_set_prompt);
+ lua_setfield(L, -2, "setPrompt");
// set the table as global
lua_setglobal(L, "lush");
}
diff --git a/src/lua_api.h b/src/lua_api.h
index c9f61ab..9027040 100644
--- a/src/lua_api.h
+++ b/src/lua_api.h
@@ -21,6 +21,7 @@ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#include <lua.h>
void lua_load_script(lua_State *L, const char *script, char **args);
+void lua_run_init(lua_State *L);
void lua_register_api(lua_State *L);
#endif
diff --git a/src/lush.c b/src/lush.c
index a3fbb93..8e5bb6f 100644
--- a/src/lush.c
+++ b/src/lush.c
@@ -40,6 +40,9 @@ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#define BUFFER_SIZE 1024
+// initialize prompt format
+char *prompt_format = NULL;
+
// -- builtin functions --
char *builtin_strs[] = {"cd", "help", "exit", "time"};
@@ -163,10 +166,67 @@ static int get_terminal_width() {
return w.ws_col;
}
+static size_t get_prompt_len(const char *format, const char *username,
+ const char *hostname, const char *cwd) {
+ size_t prompt_len = 0;
+
+ while (*format) {
+ if (strncmp(format, "%u", 2) == 0) {
+ prompt_len += strlen(username);
+ format += 2;
+ } else if (strncmp(format, "%h", 2) == 0) {
+ prompt_len += strlen(hostname);
+ format += 2;
+ } else if (strncmp(format, "%w", 2) == 0) {
+ prompt_len += strlen(cwd);
+ format += 2;
+ } else {
+ prompt_len++;
+ format++;
+ }
+ }
+ return prompt_len;
+}
+
+static char *format_prompt_string(const char *input, const char *username,
+ const char *hostname, const char *cwd) {
+ // Calculate the size of the new string
+ size_t new_size = get_prompt_len(input, username, hostname, cwd) + 1;
+
+ // Allocate memory for the new string
+ char *result = (char *)malloc(new_size);
+ if (!result) {
+ return NULL; // Handle memory allocation failure
+ }
+
+ // Replace placeholders in the input string and build the result string
+ char *dest = result;
+ while (*input) {
+ if (strncmp(input, "%u", 2) == 0) {
+ strcpy(dest, username);
+ dest += strlen(username);
+ input += 2;
+ } else if (strncmp(input, "%h", 2) == 0) {
+ strcpy(dest, hostname);
+ dest += strlen(hostname);
+ input += 2;
+ } else if (strncmp(input, "%w", 2) == 0) {
+ strcpy(dest, cwd);
+ dest += strlen(cwd);
+ input += 2;
+ } else {
+ *dest++ = *input++;
+ }
+ }
+
+ *dest = '\0'; // Null-terminate the result string
+ return result;
+}
+
static char *get_prompt() {
char *username = getenv("USER");
- char device_name[256];
- gethostname(device_name, sizeof(device_name));
+ char hostname[256];
+ gethostname(hostname, sizeof(hostname));
char *cwd = getcwd(NULL, 0);
// Replace /home/<user> with ~
@@ -182,12 +242,20 @@ static char *get_prompt() {
prompt_cwd = strdup(cwd);
}
- // Print the prompt
- size_t prompt_len =
- strlen(prompt_cwd) + strlen(username) + strlen(device_name) + 6;
- char *prompt = (char *)malloc(prompt_len);
- snprintf(prompt, prompt_len, "[%s@%s:%s]", username, device_name,
- prompt_cwd);
+ // get the prompt if no format in init.lua
+ if (prompt_format == NULL) {
+ size_t prompt_len =
+ strlen(prompt_cwd) + strlen(username) + strlen(hostname) + 6;
+ char *prompt = (char *)malloc(prompt_len);
+ snprintf(prompt, prompt_len, "[%s@%s:%s]", username, hostname,
+ prompt_cwd);
+ free(cwd);
+ return prompt;
+ }
+
+ // get formatted prompt
+ char *prompt =
+ format_prompt_string(prompt_format, username, hostname, prompt_cwd);
free(cwd);
return prompt;
@@ -581,9 +649,11 @@ int main(int argc, char *argv[]) {
#endif
return 0;
}
+ // init lua state
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_register_api(L);
+ lua_run_init(L);
// eat ^C in main
struct sigaction sa;
sa.sa_handler = SIG_IGN;
@@ -594,28 +664,9 @@ int main(int argc, char *argv[]) {
int status = 0;
while (true) {
// Prompt
- char *username = getenv("USER");
- char device_name[256];
- gethostname(device_name, sizeof(device_name));
- char *cwd = getcwd(NULL, 0);
-
- // Replace /home/<user> with ~
- char *home_prefix = "/home/";
- size_t home_len = strlen(home_prefix) + strlen(username);
- char *prompt_cwd;
- if (strncmp(cwd, home_prefix, strlen(home_prefix)) == 0 &&
- strncmp(cwd + strlen(home_prefix), username, strlen(username)) ==
- 0) {
- prompt_cwd = malloc(strlen(cwd) - home_len +
- 2); // 1 for ~ and 1 for null terminator
- snprintf(prompt_cwd, strlen(cwd) - home_len + 2, "~%s",
- cwd + home_len);
- } else {
- prompt_cwd = strdup(cwd);
- }
+ char *prompt = get_prompt();
- // Print the prompt
- printf("[%s@%s:%s] ", username, device_name, prompt_cwd);
+ printf("%s ", prompt);
char *line = lush_read_line();
lush_push_history(line);
printf("\n");
@@ -635,11 +686,14 @@ int main(int argc, char *argv[]) {
free(args[i]);
}
// add last line to history
- free(cwd);
+ free(prompt);
free(args);
free(commands);
free(line);
}
lua_close(L);
+ if (prompt_format != NULL)
+ free(prompt_format);
+
return 0;
}
diff --git a/src/lush.h b/src/lush.h
index bc8dc3c..ea575c7 100644
--- a/src/lush.h
+++ b/src/lush.h
@@ -37,4 +37,9 @@ char ***lush_split_args(char **commands, int *status);
void lush_execute_command(char **args, int input_fd, int output_fd);
int lush_execute_pipeline(char ***commands, int num_commands);
+void lush_format_prompt(const char *prompt_format);
+
+// format spec for the prompt
+extern char *prompt_format;
+
#endif // LUSH_H
diff --git a/vgcore.250513 b/vgcore.250513
new file mode 100644
index 0000000..85ad236
--- /dev/null
+++ b/vgcore.250513
Binary files differ