diff --git a/Makefile b/Makefile index b7eb58e..2ba4963 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,8 @@ SRC = src/shell.c \ src/key_bindings/move_commands.c \ src/my_ncurses/my_ncurses.c \ src/my_ncurses/string_utils.c \ - src/my_ncurses/pause_utils.c + src/my_ncurses/pause_utils.c \ + src/key_bindings/autocompletion.c OBJ = $(SRC:%.c=%.o) OBJ += src/main.o diff --git a/include/key_functions.h b/include/key_functions.h index ff31335..467eb43 100644 --- a/include/key_functions.h +++ b/include/key_functions.h @@ -41,3 +41,5 @@ int end_of_line_command(int key, buffer_t *buffer, env_t *env); int up_history_command(int key, buffer_t *buffer, env_t *env); int down_history_command(int key, buffer_t *buffer, env_t *env); + +int complete_command(int key, buffer_t *buffer, env_t *env); \ No newline at end of file diff --git a/include/utility.h b/include/utility.h index acba45c..4541e4d 100644 --- a/include/utility.h +++ b/include/utility.h @@ -27,4 +27,6 @@ int split_is_invalid(char **cmds, int *return_values, int i); int count_char(const char *str, char c); int ncount_char(const char *str, int end, char c); int get_max_eof(char *ignoreeof); -int skip_eof(buffer_t *buffer, env_t *env); \ No newline at end of file +int skip_eof(buffer_t *buffer, env_t *env); + +#define MAX(x, y) ((x) < (y) ? (y) : (x)) \ No newline at end of file diff --git a/src/glob.c b/src/glob.c index 8a7e113..6113b24 100644 --- a/src/glob.c +++ b/src/glob.c @@ -26,7 +26,7 @@ char **glob_error(char **argv, int err) char **globbing(char **argv) { static glob_t results; - int flags = GLOB_DOOFFS | GLOB_NOMAGIC; + int flags = GLOB_DOOFFS | GLOB_NOMAGIC | GLOB_TILDE; int ret = 0; for (int i = 0; argv[i] && ret == 0; i++) { diff --git a/src/key_bindings/autocompletion.c b/src/key_bindings/autocompletion.c new file mode 100644 index 0000000..d53e156 --- /dev/null +++ b/src/key_bindings/autocompletion.c @@ -0,0 +1,105 @@ +/* +** EPITECH PROJECT, 2020 +** ash +** File description: +** autocompletion +*/ + +#define _GNU_SOURCE +#include "shell.h" +#include "utility.h" +#include +#include +#include +#include + +char *get_start_of_current_arg(buffer_t *buffer) +{ + char *p; + + if (!buffer->buffer) + return (NULL); + p = memrchr(buffer->buffer, ' ', buffer->pos); + if (!p) + return (NULL); + return (p + 1); +} + +void print_results(my_window *window, unsigned count, char **results) +{ + unsigned size = 0; + int per_line; + int prefix_length = 0; + char *p = memrchr(results[0], '/', strlen(results[0]) - 1); + + if (p) + prefix_length = p - results[0] + 1; + putchar('\n'); + my_clrtobot(); + for (unsigned i = 0; i < count; i++) + size = MAX(size, strlen(results[i]) - prefix_length); + size++; + per_line = window->w / size; + for (unsigned i = 0; i < count; i += per_line) { + for (int j = 0; j < per_line && i + j < count; j++) + printf("%-*s", size, results[i + j] + prefix_length); + putchar('\n'); + } + window->y -= MAX(0, (window->y + ((int)count / per_line) + 3 - window->h)); +} + +void buffer_replace(buffer_t *buffer, char *to_replace, int start, int end) +{ + int len = strlen(to_replace); + int total = len + (buffer->buffer ? strlen(buffer->buffer) : 0); + + if (buffer->size < total) { + buffer->buffer = realloc(buffer->buffer, total + 50); + buffer->size = total + 50; + } + if (!buffer->buffer) + return; + for (int i = strlen(buffer->buffer); i >= end; i--) + buffer->buffer[i + len - 1] = buffer->buffer[i]; + memcpy(buffer->buffer + start, to_replace, len); + buffer->buffer[total - (end - start)] = '\0'; +} + +void complete_current(buffer_t *buffer, char *cmd) +{ + char *start = get_start_of_current_arg(buffer); + char *end; + + if (!start) + return; + end = strchr(start, ' '); + if (!end) + end = buffer->buffer + strlen(buffer->buffer); + buffer_replace(buffer, cmd, start - buffer->buffer, end - buffer->buffer); + buffer->pos = start - buffer->buffer + strlen(cmd); +} + +int complete_command(int key, buffer_t *buffer, env_t *env) +{ + char *str; + char *p = get_start_of_current_arg(buffer); + glob_t result; + + if (!buffer->buffer || !p) + return (0); + str = malloc(buffer->pos - (p - buffer->buffer) + 2); + if (!str) + return (0); + strncpy(str, p, buffer->pos - (p - buffer->buffer)); + str[buffer->pos - (p - buffer->buffer)] = '\0'; + strcat(str, "*"); + if (!glob(str, GLOB_MARK | GLOB_BRACE, NULL, &result)) { + if (result.gl_pathc == 1) + complete_current(buffer, result.gl_pathv[0]); + else + print_results(env->window, result.gl_pathc, result.gl_pathv); + } + globfree(&result); + free(str); + return (0); +} \ No newline at end of file diff --git a/src/key_bindings/default_bindings.c b/src/key_bindings/default_bindings.c index 91595af..406c350 100644 --- a/src/key_bindings/default_bindings.c +++ b/src/key_bindings/default_bindings.c @@ -20,6 +20,8 @@ const key_function_t key_functions[] = { {"forward-char", &forward_char_command}, {"beginning-of-line", &beginning_of_line_command}, {"end-of-line", &end_of_line_command}, + {"up-history", &up_history_command}, + {"down-history", &down_history_command}, {NULL, NULL} }; @@ -35,5 +37,6 @@ const binding_t emacs_bindings[] = { {KEY_END, &end_of_line_command}, {KEY_UP, &up_history_command}, {KEY_DOWN, &down_history_command}, + {'\t', &complete_command}, {0, NULL} }; \ No newline at end of file diff --git a/src/my_ncurses/my_ncurses.c b/src/my_ncurses/my_ncurses.c index bc13b0c..9a9ede8 100644 --- a/src/my_ncurses/my_ncurses.c +++ b/src/my_ncurses/my_ncurses.c @@ -19,6 +19,7 @@ void on_resize(int sig, siginfo_t *info, void *context) { my_getmaxyx(&stdwin->h, &stdwin->w); my_getcuryx(&stdwin->y, &stdwin->x); + my_clrtobot(); } my_window *my_initwin(void) diff --git a/src/shell.c b/src/shell.c index bb722c6..8f77e8f 100644 --- a/src/shell.c +++ b/src/shell.c @@ -23,6 +23,7 @@ int process_key(int key, buffer_t *buffer, env_t *env) { if (key <= 0) return (0); + my_clrtobot(); for (int i = 0; env->bindings[i].func; i++) if (key == env->bindings[i].key) return (env->bindings[i].func(key, buffer, env)); @@ -57,7 +58,7 @@ void shell_refresh(buffer_t *buffer, env_t *env) if (buffer->buffer) my_mvaddstr(env->window, y, buffer->startx, buffer->buffer); - my_clrtobot(); + my_clrtoeol(); my_move(env->window, newy, buf_getx(buffer, env)); my_refresh(); oldbuffer_pos = buffer->pos;