diff --git a/assets/beluga.txt b/assets/beluga.txt new file mode 100644 index 0000000..28fe0e0 --- /dev/null +++ b/assets/beluga.txt @@ -0,0 +1,44 @@ + **#%#*****###%** + *##+--------------------=##* + #*=----------------------------=*#* + #*------------------------------------*# + %+----------------------------------------=#* + #+---------------------------------------------## + *#-------------------------------------------------=## + *#----------------------------------------------------:-## + #----------------------------------------------------------## + #=-------------------------------------------------------------## + #----------------------------==----------------------------------=#* + +--------------------------+@#-%*-----------------------------------#* + +--------------------------%@@@@#-------------------------------------** + *-=-------------------------#@@*---------------------------------------=% + %*#==--------------------------------------------------------------------+# + *%%=-=--------------------------------------------------------------------=# + %=--------------------------------------------------------------------------#* + %-----------------------------------------------------------------------------** +*+--=---===----=---------------=*-----------------------------------------------** + #--=## *#%#*+==----==+**+----------------------= ***=---------------------% + *%**=-----------==== ==---------------------------------=+#+-----------------=# + *%=----------------------------------------------------------=#*---------------# + ##=----------------------------------=------------------------+%=------------+# + #%+---------------------------------=*------------------------+%------------# + *#%*=-------------=-----------------#-------------------------#+----------# + **#%#*******+=======-------------#=------------------------#----------# + #===#*=======------------------#*----=-----------=--=##*-----------# + -====##=------------------------*%+------------=*#+=====----------# + --=====+#*=----------------------=-=+*#####***+=======-----------=* + %------=====*%*=-------------------------========-----------------+* + *-=--------====%%###+=--------------------------=-----------------# + #-----------=% +*##%%%%%%@@%%%%####*==---------------------** + %=-------#* #%*=-----------------+# + *%+--=## ##=-----------------=#* + ** #+----=-------------------#* + %+----------------------------#* + *%-------------==----------------+# + ##--------------==------------------# + *#--------------===%-----------------=% + ##---------------=-##*-----------------+# + *#---------------==#+=#%-----------------% + *%---------------+# %*---------------#* + *#------------=+#* #%*=-----------#* + #****##****** *#%%##+=----% diff --git a/config/init.el b/config/init.el new file mode 100644 index 0000000..20546f6 --- /dev/null +++ b/config/init.el @@ -0,0 +1,13 @@ +(define TAB-LENGTH 2) +(define QUIT-TIMES 1) + +(map-key "CTRL-q" editor-quit) +(map-key "CTRL-s" editor-save) + +(map-key "ARROW-UP" '(move-cursor "up")) +(map-key "ARROW-DOWN" '(move-cursor "down")) +(map-key "ARROW-RIGHT" '(move-cursor "right")) +(map-key "ARROW-LEFT" '(move-cursor "left")) +(map-key "ENTER" editor-insert-new-line) +(map-key "CTRL-a" move-cursor-beg-line) +(map-key "CTRL-e" move-cursor-end-line) diff --git a/include/builtins.h b/include/builtins.h new file mode 100644 index 0000000..d5ba0f1 --- /dev/null +++ b/include/builtins.h @@ -0,0 +1,22 @@ +#ifndef BUILTINS_H_ +#define BUILTINS_H_ + +#include "../lisp-interpreter/dist/lisp.h" + +Lisp moveCursor(Lisp args, LispError *e, LispContext ctx); + +Lisp mapKey(Lisp args, LispError *e, LispContext ctx); + +void registerBuiltin(char * key_sequence, LispCFunc f); + +Lisp editorQuit(Lisp args, LispError *e, LispContext ctx); + +Lisp l_editorSave(Lisp args, LispError *e, LispContext ctx); + +Lisp l_editorInsertNewLine(Lisp args, LispError* e, LispContext ctx); + +Lisp moveCursorBeginLine(Lisp args, LispError *e, LispContext ctx); + +Lisp moveCursorEndLine(Lisp args, LispError* e, LispContext ctx); + +#endif diff --git a/include/data.h b/include/data.h index 0b82ea3..1d2e824 100644 --- a/include/data.h +++ b/include/data.h @@ -1,10 +1,12 @@ #ifndef DATA_H_ #define DATA_H_ -#include "../lisp-interpreter/dist/lisp.h" +#include #include #include +#include "../lisp-interpreter/dist/lisp.h" + /** * \struct erow * \brief Store one editor row @@ -18,6 +20,18 @@ typedef struct erow { char *render; /**< The actual line we will print */ } erow; + +struct const_t { + int TAB_LENGTH; + int QUIT_TIMES; +}; + +struct keyBind_t { + char *key_sequence; + Lisp command; + +}; + /** * \struct editorConfig * \brief Containing our editor state. @@ -36,9 +50,18 @@ struct editorConfig { char status_msg[80]; time_t status_msg_time; struct termios orig_termios; /**< Terminal communication interface */ - LispContext ctx; /** Lisp context */ - Lisp ctx_data; /** Lisp data context */ - LispError ctx_error; /** Lisp ctx error */ + + struct const_t constantes; + int quit_times_buffer; + + FILE *fd_init_file; + Lisp env; + LispContext ctx; /** Lisp context */ + Lisp ctx_data; /** Lisp data context */ + LispError ctx_error; /** Lisp ctx error */ + + struct keyBind_t* key_binds; + int number_of_keybinds; }; /** diff --git a/include/define.h b/include/define.h index 8af4442..c0f2fb3 100644 --- a/include/define.h +++ b/include/define.h @@ -25,7 +25,5 @@ enum editorKey { #define ABUF_INIT {NULL, 0} #define BELUGA_VERSION "1.0" -#define TAB_LENGTH 4 -#define QUIT_TIMES 1 #endif // DEFINE_H_ diff --git a/include/init.h b/include/init.h index f538d94..3e9e3c2 100644 --- a/include/init.h +++ b/include/init.h @@ -10,6 +10,8 @@ * \brief Job's function is to initialize all the fields of editorConfig. * */ +void initBuiltins(); + void initEditor(); #endif // INIT_H_ diff --git a/include/input.h b/include/input.h index 676be3d..aaf7a71 100644 --- a/include/input.h +++ b/include/input.h @@ -21,8 +21,12 @@ char *editorPrompt(char *prompt); +char *key_to_string(int key); + void editorMoveCursor(int key); +int executeKeyBind(char *key_sequence); + /** * \fn void editorProcessKeypress() * \brief Get the last key input and do the proper action. diff --git a/main.c b/main.c index dbc2bd5..b88fba8 100644 --- a/main.c +++ b/main.c @@ -5,6 +5,7 @@ * interactions. \version 0.1 \date 21 septembre 2024 */ +#include #define _DEFAULT_SOURCE #define _BSD_SOURCE #define _GNU_SOURCE diff --git a/meson.build b/meson.build index 239d64a..fdf2d2c 100644 --- a/meson.build +++ b/meson.build @@ -22,6 +22,7 @@ src_files = files( 'src/output.c', 'src/row_op.c', 'src/terminal.c', + 'src/builtins.c', ) # Executable diff --git a/src/builtins.c b/src/builtins.c new file mode 100644 index 0000000..a5b5d53 --- /dev/null +++ b/src/builtins.c @@ -0,0 +1,95 @@ +#include "../include/builtins.h" +#include "../include/define.h" +#include "../include/input.h" +#include "../include/file_io.h" +#include "../include/editor_op.h" +#include "../include/data.h" + +#include +#include + +Lisp mapKey(Lisp args, LispError *e, LispContext ctx) { + const char* key_sequence = lisp_string(lisp_car(args)); + args = lisp_cdr(args); + // second argument + Lisp func = lisp_car(args); + + E.key_binds = + (struct keyBind_t *)realloc(E.key_binds, ++E.number_of_keybinds * sizeof(struct keyBind_t)); + E.key_binds[E.number_of_keybinds - 1].key_sequence = (char *) malloc(50 * sizeof(char)); + + strncpy(E.key_binds[E.number_of_keybinds - 1].key_sequence, key_sequence, 50); + + E.key_binds[E.number_of_keybinds - 1].command = func; + + return lisp_null(); +} + +Lisp moveCursor(Lisp args, LispError* e, LispContext ctx) { + const char *direction = lisp_string(lisp_car(args)); + switch (direction[0]) { + case 'u': + editorMoveCursor(ARROW_UP); + break; + case 'd': + editorMoveCursor(ARROW_DOWN); + break; + case 'r': + editorMoveCursor(ARROW_RIGHT); + break; + case 'l': + editorMoveCursor(ARROW_LEFT); + break; + } + + + return lisp_null(); +} + +Lisp editorQuit(Lisp args, LispError* e, LispContext ctx) { + if (E.dirty && E.quit_times_buffer > 0) { + editorSetStatusMessage("WARNING! Changes hasn't been saved. Press Ctrl-Q " + "another time to quit."); + --E.quit_times_buffer; + return lisp_null(); + } + write(STDOUT_FILENO, "\x1b[2J", 4); + write(STDOUT_FILENO, CURSOR_TOP_LEFT, 3); + disableRawMode(); + exit(0); + + return lisp_null(); + + +} + + +Lisp l_editorSave(Lisp args, LispError* e, LispContext ctx) { + + editorSave(); + + return lisp_null(); + + +} + +Lisp l_editorInsertNewLine(Lisp args, LispError* e, LispContext ctx) { + + editorInsertNewLine(); + + return lisp_null(); + + +} + +Lisp moveCursorBeginLine(Lisp args, LispError *e, LispContext ctx) { + E.cursor_x = 0; + return lisp_null(); +} + +Lisp moveCursorEndLine(Lisp args, LispError* e, LispContext ctx) { + if (E.cursor_y < E.numrows) { + E.cursor_x = E.row[E.cursor_y].size; + } + return lisp_null(); +} diff --git a/src/editor_op.c b/src/editor_op.c index 258f197..91948e5 100644 --- a/src/editor_op.c +++ b/src/editor_op.c @@ -1,5 +1,6 @@ #include "../include/editor_op.h" #include "../include/row_op.h" +#include extern struct editorConfig E; diff --git a/src/file_io.c b/src/file_io.c index ac535ca..6a141ae 100644 --- a/src/file_io.c +++ b/src/file_io.c @@ -22,7 +22,7 @@ char *editorRowsToString(int *buffer_len) { for (j = 0; j < E.numrows; ++j) { tot_len += E.row[j].size + 1; - } + } *buffer_len = tot_len; buf = malloc(tot_len); p = buf; @@ -42,7 +42,7 @@ void editorOpen(char *filename) { free(E.filename); E.filename = strdup(filename); - fp = fopen(filename, "r"); + fp = fopen(filename, "a+"); if (!fp) die("fopen"); diff --git a/src/init.c b/src/init.c index db8627c..46f0e30 100644 --- a/src/init.c +++ b/src/init.c @@ -1,9 +1,35 @@ #include "../include/init.h" #include "../include/data.h" +#include "../include/terminal.h" +#include "../include/builtins.h" #include +#define LISP_IMPLEMENTATION +#include "../lisp-interpreter/dist/lisp.h" +#include "../lisp-interpreter/dist/lisp_lib.h" + extern struct editorConfig; + +void registerBuiltin(char *key_sequence, LispCFunc f) { + lisp_env_define(E.ctx.p->env, lisp_make_symbol(key_sequence, E.ctx), + lisp_make_func(f), E.ctx); + +} + +void initBuiltins() { + // move cursor + registerBuiltin("MOVE-CURSOR", moveCursor); + registerBuiltin("MAP-KEY", mapKey); + registerBuiltin("EDITOR-QUIT", editorQuit); + registerBuiltin("EDITOR-SAVE", l_editorSave); + registerBuiltin("EDITOR-INSERT-NEW-LINE", l_editorInsertNewLine); + registerBuiltin("MOVE-CURSOR-BEG-LINE", moveCursorBeginLine); + registerBuiltin("MOVE-CURSOR-END-LINE", moveCursorEndLine); + + +} + void initEditor() { E.cursor_x = 0; E.cursor_y = 0; @@ -21,9 +47,33 @@ void initEditor() { } E.screenrows -= 2; - // E.fd_init_file = fopen("../config/init.el", "r"); + E.number_of_keybinds = 0; - // E.ctx = lisp_init(); - // E.ctx_data = lisp_read_file(E.fd_init_file, &E.ctx_error, E.ctx); - // lisp_printf(stderr, E.ctx_data); + + E.fd_init_file = fopen("config/init.el", "r"); + E.ctx = lisp_init(); + E.env = lisp_env(E.ctx); + lisp_lib_load(E.ctx); + // Init builtins lisp functions + initBuiltins(); + + // Read config file + E.ctx_data = lisp_read_file(E.fd_init_file, &E.ctx_error, E.ctx); + if (E.ctx_error != LISP_ERROR_NONE) { + die("init failed"); + } + lisp_eval(E.ctx_data, &E.ctx_error, E.ctx); + + // To modify + + E.constantes.TAB_LENGTH = + (int)lisp_eval(lisp_read("TAB-LENGTH", &E.ctx_error, E.ctx), &E.ctx_error, + E.ctx) + .val.int_val; + E.constantes.QUIT_TIMES = + (int)lisp_eval(lisp_read("QUIT-TIMES", &E.ctx_error, E.ctx), &E.ctx_error, + E.ctx) + .val.int_val; + + E.quit_times_buffer = E.constantes.QUIT_TIMES; } diff --git a/src/input.c b/src/input.c index 57f749e..ed7e215 100644 --- a/src/input.c +++ b/src/input.c @@ -1,11 +1,13 @@ #include "../include/input.h" #include "../include/editor_op.h" -#include "../include/file_io.h" #include "../include/output.h" +#include "../include/define.h" +#include "data.h" #include #include #include #include +#include #include extern struct editorConfig E; @@ -30,7 +32,6 @@ char *editorPrompt(char *prompt) { buf[--buf_len] = '\0'; } } else if (c == ESCAPE) { - fprintf(stderr, "escape"); editorSetStatusMessage(""); free(buf); return NULL; @@ -50,6 +51,70 @@ char *editorPrompt(char *prompt) { } } +char *key_to_string(int key) { + static char key_str[32]; + + char tmp[10]; + sprintf(tmp, "%d", key); + + + // First test enter key + + if (key == '\r') { + strcpy(key_str, "ENTER"); + } else if (key >= 1 && key <= 26) { // CTRL keys + snprintf(key_str, sizeof(key_str), "CTRL-%c", 'a' + key - 1); + } else { + switch (key) { + case ARROW_UP: + strcpy(key_str, "ARROW-UP"); + break; + case ARROW_DOWN: + strcpy(key_str, "ARROW-DOWN"); + break; + case ARROW_LEFT: + strcpy(key_str, "ARROW-LEFT"); + break; + case ARROW_RIGHT: + strcpy(key_str, "ARROW-RIGHT"); + break; + case PAGE_UP: + strcpy(key_str, "PAGE-UP"); + break; + case PAGE_DOWN: + strcpy(key_str, "PAGE-DOWN"); + break; + case DEL_KEY: + strcpy(key_str, "DEL"); + break; + case BACKSPACE: + strcpy(key_str, "BACKSPACE"); + break; + case '\r': + strcpy(key_str, "ENTER"); + break; + case '\x1b': + strcpy(key_str, "ESCAPE"); + break; + case BEG_LINE: + strcpy(key_str, "HOME"); + break; + case END_LINE: + strcpy(key_str, "END"); + break; + default: + // For regular characters + if (isprint(key)) { + snprintf(key_str, sizeof(key_str), "%c", key); + } else { + snprintf(key_str, sizeof(key_str), "KEY-%d", key); + } + } + } + return key_str; +} + + void editorMoveCursor(int key) { erow *row = (E.cursor_y >= E.numrows) ? NULL : &E.row[E.cursor_y]; int row_len; @@ -89,81 +154,28 @@ void editorMoveCursor(int key) { } } -void editorProcessKeypress() { - static int quit_times = QUIT_TIMES; - int c = editorReadKey(); - int times; - - switch (c) { - - case '\r': - editorInsertNewLine(); - break; - case CTRL_KEY('q'): - if (E.dirty && quit_times > 0) { - editorSetStatusMessage("WARNING! Changes hasn't been saved. Press Ctrl-Q " - "another time to quit."); - --quit_times; - return; +int executeKeyBind(char *key_sequence) { + int i; + for (i = 0; i < E.number_of_keybinds; ++i) { + if (!strcmp(key_sequence, E.key_binds[i].key_sequence)) { + + fprintf(stderr, "lisp function %s\n", key_sequence); + // It's a symbol, create a function call + lisp_eval(lisp_cons(E.key_binds[i].command, lisp_null(), E.ctx), + &E.ctx_error, E.ctx); + return 1; } - write(STDOUT_FILENO, "\x1b[2J", 4); - write(STDOUT_FILENO, CURSOR_TOP_LEFT, 3); - disableRawMode(); - exit(0); - break; - - case CTRL_KEY('s'): - editorSave(); - break; - - case BEG_LINE: - E.cursor_x = 0; - break; - - case END_LINE: - if (E.cursor_y < E.numrows) { - E.cursor_x = E.row[E.cursor_y].size; - } - break; - - case BACKSPACE: - case CTRL_KEY('h'): - case DEL_KEY: - if (c == DEL_KEY) { - editorMoveCursor(ARROW_RIGHT); - } - editorDelChar(); - break; - - case PAGE_UP: - case PAGE_DOWN: { - if (c == PAGE_UP) { - E.cursor_y = E.row_offset; - } else if (c == PAGE_DOWN) { - E.cursor_y = E.row_offset + E.screenrows - 1; - if (E.cursor_y > E.numrows) { - E.cursor_y = E.numrows; - } - } - times = E.screenrows; - while (--times) { - editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN); - } - } break; - - case ARROW_UP: - case ARROW_DOWN: - case ARROW_LEFT: - case ARROW_RIGHT: - editorMoveCursor(c); - break; - - case CTRL_KEY('l'): - case '\x1b': - break; - default: - editorInsertChar(c); - break; } - quit_times = QUIT_TIMES; + return 0; +} + +void editorProcessKeypress() { + int c = editorReadKey(); + + if (executeKeyBind(key_to_string(c))) { + return; + } + editorInsertChar(c); + E.quit_times_buffer = E.constantes.QUIT_TIMES; + } diff --git a/src/row_op.c b/src/row_op.c index 97c22af..64515c5 100644 --- a/src/row_op.c +++ b/src/row_op.c @@ -1,4 +1,6 @@ #include "../include/row_op.h" +#include "data.h" +#include #include #include #include @@ -10,7 +12,7 @@ int editorRowCxToRx(erow *row, int cursor_x) { int i; for (i = 0; i < cursor_x; ++i) { if (row->chars[i] == '\t') { - render_x += (TAB_LENGTH - 1) - (render_x % TAB_LENGTH); + render_x += (E.constantes.TAB_LENGTH - 1) - (render_x % E.constantes.TAB_LENGTH); } render_x++; } @@ -34,8 +36,8 @@ void editorUpdateRow(erow *row) { } free(row->render); - row->render = malloc(row->size + tabs * (TAB_LENGTH - 1) + - 1); /**< Tabs needs TAB_LENGTH chars so TAB_LENGTH - 1 + row->render = malloc(row->size + tabs * (E.constantes.TAB_LENGTH - 1) + + 1); /**< Tabs needs E.constantes.TAB_LENGTH chars so E.constantes.TAB_LENGTH - 1 more than the first already counted. */ // end of counting @@ -43,7 +45,7 @@ void editorUpdateRow(erow *row) { for (i = 0; i < row->size; ++i) { if (row->chars[i] == '\t') { row->render[i_render++] = ' '; - while (i_render % TAB_LENGTH) { + while (i_render % E.constantes.TAB_LENGTH) { row->render[i_render++] = ' '; /**< Addind the right amount of spaces for tabs */ } @@ -57,10 +59,14 @@ void editorUpdateRow(erow *row) { void editorInsertRow(int at, char *s, size_t len) { if (at < 0 || at > E.numrows) { + return; } - - E.row = realloc(E.row, sizeof(erow) * (E.numrows + 1)); + erow *tmp = (erow *)realloc(E.row, sizeof(erow) * (E.numrows + 1)); + if (!tmp) { + return; + } + E.row = tmp; memmove(&E.row[at + 1], &E.row[at], sizeof(erow) * (E.numrows - at)); E.row[at].size = len; diff --git a/src/terminal.c b/src/terminal.c index 48dc20a..521958a 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -4,145 +4,146 @@ #include void die(const char *s) { - write(STDOUT_FILENO, "\x1b[2J", 4); - write(STDOUT_FILENO, CURSOR_TOP_LEFT, 3); - perror(s); - exit(1); + write(STDOUT_FILENO, "\x1b[2J", 4); + write(STDOUT_FILENO, CURSOR_TOP_LEFT, 3); + lisp_shutdown(E.ctx); + perror(s); + exit(1); } void disableRawMode() { - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &E.orig_termios) == -1) { - die("tcsetattr"); - } + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &E.orig_termios) == -1) { + die("tcsetattr"); + } } void enableRawMode() { - if (tcgetattr(STDIN_FILENO, &E.orig_termios) == -1) { - die("tcgetattr"); - } + if (tcgetattr(STDIN_FILENO, &E.orig_termios) == -1) { + die("tcgetattr"); + } - struct termios raw = E.orig_termios; - raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); - raw.c_oflag &= ~(OPOST); - raw.c_cflag |= (CS8); - raw.c_lflag &= ~(ECHO | ICANON | ISIG | IEXTEN); - raw.c_cc[VMIN] = 0; - raw.c_cc[VTIME] = 1; + struct termios raw = E.orig_termios; + raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + raw.c_oflag &= ~(OPOST); + raw.c_cflag |= (CS8); + raw.c_lflag &= ~(ECHO | ICANON | ISIG | IEXTEN); + raw.c_cc[VMIN] = 0; + raw.c_cc[VTIME] = 1; - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) { - die("tcgetattr"); - } + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) { + die("tcgetattr"); + } } int editorReadKey() { - int nread; - char c; - char seq[3]; - while ((nread = read(STDIN_FILENO, &c, 1)) != 1) { - if (nread == -1 && errno != EAGAIN) { - die("read"); - } + int nread; + char c; + char seq[3]; + while ((nread = read(STDIN_FILENO, &c, 1)) != 1) { + if (nread == -1 && errno != EAGAIN) { + die("read"); } + } - if (c == '\x1b') { - if (read(STDIN_FILENO, &seq[0], 1) != 1 || - read(STDIN_FILENO, &seq[1], 1) != 1) { - return '\x1b'; - } - if (seq[0] == '[') { - if (seq[1] >= '0' && seq[1] <= '9') { - if (read(STDIN_FILENO, &seq[2], 1) != 1) { - return '\x1b'; - } - if (seq[2] == '~') { - switch (seq[1]) { - case '1': - return BEG_LINE; - case '3': - return DEL_KEY; - case '4': - return END_LINE; - case '5': - return PAGE_UP; - case '6': - return PAGE_DOWN; - case '7': - return BEG_LINE; - case '8': - return END_LINE; - } - } - } else { - - switch (seq[1]) { - case 'A': - return ARROW_UP; - case 'B': - return ARROW_DOWN; - case 'C': - return ARROW_RIGHT; - case 'D': - return ARROW_LEFT; - case 'H': - return BEG_LINE; - case 'F': - return END_LINE; - } - } - } else if (seq[0] == 'O') { - switch (seq[1]) { - case 'H': - return BEG_LINE; - case 'F': - return END_LINE; - } - } - return '\x1b'; - } else { - return c; + if (c == '\x1b') { + if (read(STDIN_FILENO, &seq[0], 1) != 1 || + read(STDIN_FILENO, &seq[1], 1) != 1) { + return '\x1b'; } + if (seq[0] == '[') { + if (seq[1] >= '0' && seq[1] <= '9') { + if (read(STDIN_FILENO, &seq[2], 1) != 1) { + return '\x1b'; + } + if (seq[2] == '~') { + switch (seq[1]) { + case '1': + return BEG_LINE; + case '3': + return DEL_KEY; + case '4': + return END_LINE; + case '5': + return PAGE_UP; + case '6': + return PAGE_DOWN; + case '7': + return BEG_LINE; + case '8': + return END_LINE; + } + } + } else { + + switch (seq[1]) { + case 'A': + return ARROW_UP; + case 'B': + return ARROW_DOWN; + case 'C': + return ARROW_RIGHT; + case 'D': + return ARROW_LEFT; + case 'H': + return BEG_LINE; + case 'F': + return END_LINE; + } + } + } else if (seq[0] == 'O') { + switch (seq[1]) { + case 'H': + return BEG_LINE; + case 'F': + return END_LINE; + } + } + return '\x1b'; + } else { + return c; + } } int getCursorPosition(int *rows, int *cols) { - char buf[32]; - unsigned int i = 0; + char buf[32]; + unsigned int i = 0; - if (write(STDOUT_FILENO, "\x1b[6n", 4) != 4) { - return -1; - } + if (write(STDOUT_FILENO, "\x1b[6n", 4) != 4) { + return -1; + } - while (i < sizeof(buf) - 1) { - if (read(STDIN_FILENO, &buf[i], 1) != 1) { - break; - } - if (buf[i] == 'R') { - break; - } - ++i; + while (i < sizeof(buf) - 1) { + if (read(STDIN_FILENO, &buf[i], 1) != 1) { + break; } - buf[i] = '\0'; + if (buf[i] == 'R') { + break; + } + ++i; + } + buf[i] = '\0'; - if (buf[0] != '\x1b' || buf[1] != '[') { - return -1; - } - if (sscanf(&buf[2], "%d;%d", rows, cols) != 2) { - return -1; - } + if (buf[0] != '\x1b' || buf[1] != '[') { + return -1; + } + if (sscanf(&buf[2], "%d;%d", rows, cols) != 2) { + return -1; + } - return 0; + return 0; } int getWindowSize(int *rows, int *cols) { - struct winsize ws; + struct winsize ws; - if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) { - if (write(STDOUT_FILENO, "\x1b[999C\x1b[999B", 12) != 12) { - return -1; - } - return getCursorPosition(rows, cols); - } else { - *cols = ws.ws_col; - *rows = ws.ws_row; - return 0; + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) { + if (write(STDOUT_FILENO, "\x1b[999C\x1b[999B", 12) != 12) { + return -1; } + return getCursorPosition(rows, cols); + } else { + *cols = ws.ws_col; + *rows = ws.ws_row; + return 0; + } }