aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar BanceDev 2024-09-02 21:30:22 -0400
committerGravatar BanceDev 2024-09-02 21:30:22 -0400
commit8ddcd6bdc678538c507c3012abe9346186cc20d0 (patch)
treeb5b49fb6e3ff3dce27c57ee7872b1c0718f7e3d5
parentupdated help and fixed SIGINT (diff)
added arrow key movement
-rw-r--r--src/help.h24
-rw-r--r--src/lush.c156
2 files changed, 122 insertions, 58 deletions
diff --git a/src/help.h b/src/help.h
index 80c9bb3..3f7b705 100644
--- a/src/help.h
+++ b/src/help.h
@@ -2,29 +2,7 @@
#define HELP_H
char *lush_get_help_text() {
- return "    ..,;;;;;::::::::cccccclllllooooddddxxxdoc,    \n"
-"  .,;;,,'',,,,,,,,,,,;;;;;;;:::::::cccccllloxkxc  \n"
-" ,,,.                                        'oOk.\n"
-".,,               ......                       dOx\n"
-",;'       .:c.   ;::::::                       cOO\n"
-";;'         :Nl  ;::::::                       :O0\n"
-";;'          KN: ;::::::                       :00\n"
-";;'         :NNl ;::::::                       :00\n"
-";;' l:....;kNNk. ;::::::                       :00\n"
-"::'  ;x0XNX0d,   ;::::::                       :00\n"
-"::'              '''''''                       :00\n"
-"::'                                            :00\n"
-"::'                                            :00\n"
-"::'                                            :00\n"
-"cc,                                            :00\n"
-"cc,                                            :00\n"
-"cc,                                            :00\n"
-":c;                                            c00\n"
-".lc                                            k0;\n"
-" .lc.                                       .,x0; [0\n"
-"    oollccccllllllllooooooodddddddxxxxxxxxxk00.   \n"
-"       .dddddxxxxxxkkkkkkOOOOOO00000000000        \n"
-".____ _________.__ .__ .__ \n"
+ return ".____ _________.__ .__ .__ \n"
"| | __ __ ____ _____ _______ / _____/| |__ ____ | | | | \n"
"| | | | \\/ \\\\__ \\\\_ __ \\ \\_____ \\ | | \\_/ __ \\| | | | \n"
"| |___| | / | \\/ __ \\| | \\/ / \\| Y \\ ___/| |_| |__\n"
diff --git a/src/lush.c b/src/lush.c
index 846ce20..542aaf4 100644
--- a/src/lush.c
+++ b/src/lush.c
@@ -27,9 +27,12 @@ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <termios.h>
#include <time.h>
#include <unistd.h>
+#define BUFFER_SIZE 1024
+
// -- builtin functions --
char *builtin_strs[] = {"cd", "help", "exit", "time"};
@@ -116,18 +119,115 @@ int lush_time(char ***args) {
}
// -- shell utility --
+
+// -- static helpers for input --
+
+static void set_raw_mode(struct termios *orig_termios) {
+ struct termios raw;
+ tcgetattr(STDIN_FILENO, orig_termios);
+ raw = *orig_termios;
+ raw.c_lflag &= ~(ICANON | ECHO);
+ tcsetattr(STDIN_FILENO, TCSANOW, &raw);
+}
+
+static void reset_terminal_mode(struct termios *orig_termios) {
+ tcsetattr(STDIN_FILENO, TCSANOW, orig_termios);
+}
+
+static void print_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);
+ }
+
+ // Print the prompt
+ printf("[%s@%s:%s] ", username, device_name, prompt_cwd);
+ free(cwd);
+}
+
+static void reprint_buffer(const char *buffer, int pos) {
+ printf("\r\033[K");
+ print_prompt();
+ printf("%s ", buffer);
+ printf("\033[%ldD", strlen(buffer) - pos + 1);
+}
+
char *lush_read_line() {
- char *line = NULL;
- size_t bufsize = 0;
- if (getline(&line, &bufsize, stdin) == -1) {
- if (feof(stdin)) {
- exit(EXIT_SUCCESS);
+ struct termios orig_termios;
+ char *buffer = (char *)calloc(BUFFER_SIZE, sizeof(char));
+ int pos = 0;
+ int c;
+
+ // init buffer and make raw mode
+ set_raw_mode(&orig_termios);
+
+ while (true) {
+ c = getchar();
+
+ if (c == '\033') { // escape sequence
+ getchar(); // skip [
+ switch (getchar()) {
+ case 'C': // right arrow
+ if (pos < strlen(buffer)) {
+ pos++;
+ reprint_buffer(buffer, pos);
+ }
+ break;
+ case 'D': // left arrow
+ if (pos > 0) {
+ pos--;
+ reprint_buffer(buffer, pos);
+ }
+ break;
+ case '3': // delete
+ if (getchar() == '~') {
+ if (pos < strlen(buffer)) {
+ memmove(&buffer[pos], &buffer[pos + 1],
+ strlen(&buffer[pos + 1]) + 1);
+ reprint_buffer(buffer, pos);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ } else if (c == '\177') { // backspace
+ if (pos > 0) {
+ memmove(&buffer[pos - 1], &buffer[pos],
+ strlen(&buffer[pos]) + 1);
+ pos--;
+ reprint_buffer(buffer, pos);
+ }
+ } else if (c == '\n') {
+ break; // submit the command
} else {
- perror("readline");
- exit(EXIT_FAILURE);
+ if (pos < BUFFER_SIZE - 1) {
+ // insert text into buffer
+ memmove(&buffer[pos + 1], &buffer[pos],
+ strlen(&buffer[pos]) + 1);
+ buffer[pos] = c;
+ pos++;
+
+ reprint_buffer(buffer, pos);
+ }
}
}
- return line;
+
+ reset_terminal_mode(&orig_termios);
+ return buffer;
}
char **lush_split_pipes(char *line) {
@@ -286,10 +386,7 @@ void lush_execute_command(char **args, int input_fd, int output_fd) {
pid_t pid;
int status;
- // ignore SIGINT in the parent process
struct sigaction sa;
- sa.sa_handler = SIG_IGN;
- sigaction(SIGINT, &sa, NULL);
if ((pid = fork()) == 0) {
// child process content
@@ -343,33 +440,23 @@ int lush_run(char ***commands, int num_commands) {
}
int main() {
+ // eat ^C in main
+ struct sigaction sa;
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGINT, &sa, NULL);
+
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);
- }
-
- // Print the prompt
- printf("[%s@%s:%s] ", username, device_name, prompt_cwd);
-
+ print_prompt();
char *line = lush_read_line();
+ if (line == NULL || strlen(line) == 0) {
+ free(line);
+ continue;
+ }
+ printf("\n");
char **commands = lush_split_pipes(line);
char ***args = lush_split_args(commands, &status);
if (status == -1) {
@@ -384,6 +471,5 @@ int main() {
free(args);
free(commands);
free(line);
- free(cwd);
}
}