From 39004180141983cf3a678a8df31924ee82435d6c Mon Sep 17 00:00:00 2001 From: savalet Date: Fri, 9 May 2025 00:28:10 +0200 Subject: [PATCH] Setup special key handler --- .clang-tidy | 1 + Makefile | 1 + src/readline.c | 37 +++++++++++++++---------------- src/readline.h | 5 +++-- src/repl.h | 14 ++++++++++-- src/repl/key_arrow.c | 32 +++++++++++++++++++++++++++ src/repl/key_control.c | 33 ++++++++++++++++++++++++++++ src/repl/key_handler.h | 28 ++++++++++++++++++++++++ src/{ => repl}/repl.c | 49 ++++++++++++++++++++++-------------------- 9 files changed, 155 insertions(+), 45 deletions(-) create mode 100644 src/repl/key_arrow.c create mode 100644 src/repl/key_control.c create mode 100644 src/repl/key_handler.h rename src/{ => repl}/repl.c (66%) diff --git a/.clang-tidy b/.clang-tidy index 01f59e4..e30e021 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -12,6 +12,7 @@ Checks: "-*, -readability-braces-around-statements, -readability-identifier-length, -readability-implicit-bool-conversion, + -readability-named-parameter, clang-analyzer-*, modernize-*, llvm-*, diff --git a/Makefile b/Makefile index adc1ee6..56b2873 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ SRC += $(wildcard src/builtins/expr/*.c) SRC += $(wildcard src/ast/*.c) SRC += $(wildcard src/utils/*.c) SRC += $(wildcard src/local/*.c) +SRC += $(wildcard src/repl/*.c) LIB_SRC := $(wildcard ulib/*.c) LIB_SRC += $(wildcard ulib/write/printf/*.c) diff --git a/src/readline.c b/src/readline.c index 467de90..ca10361 100644 --- a/src/readline.c +++ b/src/readline.c @@ -61,7 +61,7 @@ bool append_null_terminator(buff_t *out) } static -bool populate_single_char( +bool copy_single_char( exec_ctx_t *exec_ctx, buff_t *out, char *cpy, @@ -69,7 +69,7 @@ bool populate_single_char( { if (in == '\r') in = '\n'; - if (in == '\0') + if (in == '\0' || in == '\f') return false; if (isspace(in) || isprint(in) || !exec_ctx->isatty) { *cpy = in; @@ -82,34 +82,34 @@ bool populate_single_char( static bool populate_copy_buff( - exec_ctx_t *exec_ctx, readline_helper_t *rh, ssize_t rd, + exec_ctx_t *ec, readline_helper_t *rh, ssize_t rd, text_parse_info_t *tpi) { - size_t w = 0; ssize_t i = 0; + ssize_t skip; for (bool done = false; !done && i < rd; i++) { - if (populate_single_char(exec_ctx, rh->out, &rh->cpy[w], rh->in[i])) { - done = rh->cpy[w] == '\n'; - w++; + if (copy_single_char(ec, rh->out, &rh->cpy[tpi->written], rh->in[i])) { + done = rh->cpy[tpi->written] == '\n'; + tpi->written++; continue; } - if (handle_keys(exec_ctx, rh->out, &rh->in[i])) { + skip = handle_keys(ec, rh->out, &rh->in[i], BULK_READ_BUFF_SZ - i); + if (skip < 0) { tpi->used = i; - tpi->written = w; return false; } + i += skip - 1; } - if (exec_ctx->isatty) - write(STDOUT_FILENO, rh->cpy, w); + if (ec->isatty) + write(STDOUT_FILENO, rh->cpy, tpi->written); tpi->used = i; - tpi->written = w; return true; } static bool read_until_line_ending( - exec_ctx_t *exec_ctx, readline_helper_t *rh, ssize_t rd) + exec_ctx_t *ec, readline_helper_t *rh, ssize_t rd) { text_parse_info_t tpi; @@ -117,13 +117,14 @@ bool read_until_line_ending( memset(&tpi, '\0', sizeof tpi); if (!ensure_buff_av_capacity(rh->out, BULK_READ_BUFF_SZ)) return false; - populate_copy_buff(exec_ctx, rh, rd, &tpi); + if (!populate_copy_buff(ec, rh, rd, &tpi)) + return true; U_DEBUG("copied %zu chars to cpy (%zu used)\n", tpi.written, tpi.used); memmove(rh->in, &rh->in[tpi.used], BULK_READ_BUFF_SZ - tpi.used); memset(&rh->in[BULK_READ_BUFF_SZ - tpi.used], '\0', tpi.used); if (rh->cpy[tpi.written - 1] == '\n') break; - rd = read(exec_ctx->read_fd, rh->in, BULK_READ_BUFF_SZ); + rd = read(ec->read_fd, rh->in, BULK_READ_BUFF_SZ); if (rd <= 0) return (rd == 0); U_DEBUG("read %zu characters\n", rd); @@ -131,7 +132,7 @@ bool read_until_line_ending( return true; } -bool readline(exec_ctx_t *exec_ctx, buff_t *out) +bool readline(exec_ctx_t *ec, buff_t *out) { static char read_buff[BULK_READ_BUFF_SZ] = {0}; readline_helper_t rh = { out, read_buff, { 0 } }; @@ -142,12 +143,12 @@ bool readline(exec_ctx_t *exec_ctx, buff_t *out) is_empty &= read_buff[i] == '\0'; U_DEBUG("readline buff is empty? %d\n", is_empty); if (is_empty) { - rd = read(exec_ctx->read_fd, read_buff, sizeof read_buff); + rd = read(ec->read_fd, read_buff, sizeof read_buff); if (rd < 0) return (rd == 0); } else rd = BULK_READ_BUFF_SZ; - if (!read_until_line_ending(exec_ctx, &rh, rd)) + if (!read_until_line_ending(ec, &rh, rd)) return false; return append_null_terminator(out); } diff --git a/src/readline.h b/src/readline.h index 507a0dc..81d13dc 100644 --- a/src/readline.h +++ b/src/readline.h @@ -7,15 +7,16 @@ #ifndef READLINE #define READLINE + #define BUFF_INIT_SZ 16 #include - #include "exec.h" + #include "builtins_handler.h" #include "u_str.h" #define BULK_READ_BUFF_SZ 32 -bool readline(exec_ctx_t *exec_ctx, buff_t *out); +bool readline(exec_ctx_t *ec, buff_t *out); typedef struct { buff_t *out; diff --git a/src/repl.h b/src/repl.h index d046ee7..9510443 100644 --- a/src/repl.h +++ b/src/repl.h @@ -7,11 +7,21 @@ #ifndef REPL_H #define REPL_H - #include "exec.h" + + #include + + #include "builtins_handler.h" #include "u_str.h" void init_shell_repl(exec_ctx_t *exec_ctx); + void restore_term_flags(exec_ctx_t *exec_ctx); -bool handle_keys(exec_ctx_t *exec_ctx, buff_t *buff, char const *read_buff); + +ssize_t handle_keys( + exec_ctx_t *ec, + buff_t *buff, + char const *read_buff, + size_t len); + void print_shell_prompt(exec_ctx_t *exec_ctx); #endif /* REPL_H */ diff --git a/src/repl/key_arrow.c b/src/repl/key_arrow.c new file mode 100644 index 0000000..940c630 --- /dev/null +++ b/src/repl/key_arrow.c @@ -0,0 +1,32 @@ +/* +** EPITECH PROJECT, 2025 +** __ +** File description: +** _ +*/ + +#include + +#include "key_handler.h" +#include "repl.h" +#include "vt100_esc_codes.h" + +bool handle_key_arrow_up(exec_ctx_t *ec, buff_t *buff) +{ + return true; +} + +bool handle_key_arrow_left(exec_ctx_t *ec, buff_t *buff) +{ + return true; +} + +bool handle_key_arrow_right(exec_ctx_t *ec, buff_t *buff) +{ + return true; +} + +bool handle_key_arrow_down(exec_ctx_t *ec, buff_t *buff) +{ + return true; +} diff --git a/src/repl/key_control.c b/src/repl/key_control.c new file mode 100644 index 0000000..77f64a7 --- /dev/null +++ b/src/repl/key_control.c @@ -0,0 +1,33 @@ +/* +** EPITECH PROJECT, 2025 +** __ +** File description: +** _ +*/ + +#include + +#include "key_handler.h" +#include "repl.h" +#include "vt100_esc_codes.h" + +bool handle_key_ctrl_c(exec_ctx_t *ec, buff_t *buff) +{ + WRITE_CONST(ec->read_fd, "\n"); + print_shell_prompt(ec); + return true; +} + +bool handle_key_ctrl_d(exec_ctx_t *ec, buff_t *buff) +{ + buff->sz = 0; + return false; +} + +bool handle_key_ctrl_l(exec_ctx_t *ec, buff_t *buff) +{ + WRITE_CONST(STDOUT_FILENO, ESC "[2J"); + WRITE_CONST(STDOUT_FILENO, ESC "[H"); + print_shell_prompt(ec); + return false; +} diff --git a/src/repl/key_handler.h b/src/repl/key_handler.h new file mode 100644 index 0000000..004527a --- /dev/null +++ b/src/repl/key_handler.h @@ -0,0 +1,28 @@ +/* +** EPITECH PROJECT, 2025 +** __ +** File description: +** _ +*/ + +#ifndef KEY_HANDLER_H + #define KEY_HANDLER_H + + #include "builtins_handler.h" + #include "u_str.h" + +typedef struct { + const char *name; + bool (*exec)(exec_ctx_t *ec, buff_t *buff); +} key_handler_t; + +bool handle_key_ctrl_c(exec_ctx_t *ec, buff_t *buff); +bool handle_key_ctrl_d(exec_ctx_t *ec, buff_t *buff); +bool handle_key_ctrl_l(exec_ctx_t *ec, buff_t *buff); + +bool handle_key_arrow_up(exec_ctx_t *ec, buff_t *buff); +bool handle_key_arrow_left(exec_ctx_t *ec, buff_t *buff); +bool handle_key_arrow_right(exec_ctx_t *ec, buff_t *buff); +bool handle_key_arrow_down(exec_ctx_t *ec, buff_t *buff); + +#endif diff --git a/src/repl.c b/src/repl/repl.c similarity index 66% rename from src/repl.c rename to src/repl/repl.c index b782bd2..f78592d 100644 --- a/src/repl.c +++ b/src/repl/repl.c @@ -7,15 +7,26 @@ #include #include +#include #include #include #include "common.h" -#include "repl.h" #include "debug.h" +#include "repl.h" +#include "repl/key_handler.h" #include "u_str.h" #include "vt100_esc_codes.h" +const key_handler_t KEY_HANDLERS[] = { + {"\03", handle_key_ctrl_c}, // ^C + {"\04", handle_key_ctrl_d}, // ^D + {"\014", handle_key_ctrl_l}, // ^L + {"]A", handle_key_arrow_up}, + {"]B", handle_key_arrow_down}, + {"]D", handle_key_arrow_left}, + {"]C", handle_key_arrow_right}, +}; void print_shell_prompt(exec_ctx_t *exec_ctx) { @@ -58,29 +69,21 @@ void restore_term_flags(exec_ctx_t *exec_ctx) tcsetattr(exec_ctx->read_fd, TCSANOW, &exec_ctx->saved_term_settings); } -static -void ignore_sigint(exec_ctx_t *exec_ctx) -{ - WRITE_CONST(exec_ctx->read_fd, "\n"); - print_shell_prompt(exec_ctx); -} - -bool handle_keys(exec_ctx_t *exec_ctx, buff_t *buff, char const *read_buff) +ssize_t handle_keys( + exec_ctx_t *ec, + buff_t *buff, + char const *read_buff, + size_t len) { U_DEBUG("Found special char, [%hhx]\n", *read_buff); - switch (*read_buff) { - case CTRL('d'): - buff->sz = 0; - return true; - case CTRL('c'): - ignore_sigint(exec_ctx); - return false; - case CTRL('l'): - WRITE_CONST(STDOUT_FILENO, ESC "[2J"); - WRITE_CONST(STDOUT_FILENO, ESC "[H"); - print_shell_prompt(exec_ctx); - return false; - default: - return false; + for (size_t i = 0; i < sizeof KEY_HANDLERS / sizeof *KEY_HANDLERS; i++) { + if (strncmp(read_buff, KEY_HANDLERS[i].name, len) == 0) + continue; + if (!KEY_HANDLERS[i].exec(ec, buff)) + return strlen(KEY_HANDLERS[i].name); + return -1; } + for (size_t i = 0; i < len; i++) + U_DEBUG("<- [%d]\n", read_buff[i]); + return 0; }