tSet editor mode, improve cursor navigation - ve - a minimal text editor (work in progress)
 (HTM) git clone git://src.adamsgaard.dk/ve
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 812ddc49f3f4312a59bf50452a2b5384160dd415
 (DIR) parent b8e623a52f0e936fd1a85796f6ab7af8d030fac7
 (HTM) Author: Anders Damsgaard <anders@adamsgaard.dk>
       Date:   Tue,  6 Aug 2019 11:11:16 +0200
       
       Set editor mode, improve cursor navigation
       
       Diffstat:
         M byote.h                             |      11 +++++++++++
         M input.c                             |      65 +++++++++++++++++++++++++++----
         M output.c                            |      42 +++++++++++++++++++++-----------
         M terminal.c                          |       7 +++++--
         M terminal.h                          |      10 ----------
       
       5 files changed, 102 insertions(+), 33 deletions(-)
       ---
 (DIR) diff --git a/byote.h b/byote.h
       t@@ -1,7 +1,18 @@
        #ifndef BYOTE_H_
        #define BYOTE_H_
        
       +#include <termios.h>
       +
        #define PROGNAME "byote"
        #define VERSION "0.0.1"
        
       +struct editor_config {
       +        int cursor_x, cursor_y;
       +        int screen_rows, screen_cols;
       +        struct termios orig_termios;
       +        int status_height;
       +        int mode; /* 0: normal, 1: insert, 2: visual */
       +};
       +
       +extern struct editor_config E;
        #endif
 (DIR) diff --git a/input.c b/input.c
       t@@ -1,18 +1,69 @@
        #include <unistd.h>
        #include <stdlib.h>
       +#include "byote.h"
        #include "terminal.h"
        
        #define CTRL_KEY(k) ((k) & 0x1f)
        
        void
       -editor_process_keypress()
       +editor_move_cursor(char key)
        {
       -        char c = editor_read_key();
       -        switch (c) {
       -                case CTRL_KEY('q'):
       -                        write(STDOUT_FILENO, "\x1b[2J", 4);
       -                        write(STDOUT_FILENO, "\x1b[H", 3);
       -                        exit(0);
       +        switch(key) {
       +                case 'h':
       +                        if (E.cursor_x > 0)
       +                                E.cursor_x--;
       +                        break;
       +                case 'j':
       +                        if (E.cursor_y < E.screen_rows - 1 - E.status_height)
       +                                E.cursor_y++;
       +                        break;
       +                case 'k':
       +                        if (E.cursor_y > 0)
       +                                E.cursor_y--;
       +                        break;
       +                case 'l':
       +                        if (E.cursor_x < E.screen_cols - 1)
       +                                E.cursor_x++;
                                break;
                }
        }
       +
       +void
       +editor_process_keypress()
       +{
       +        char c;
       +        int i;
       +        
       +        c = editor_read_key();
       +
       +        if (E.mode == 0) {  /* normal mode */
       +                switch (c) {
       +                        case CTRL_KEY('q'):
       +                                write(STDOUT_FILENO, "\x1b[2J", 4);
       +                                write(STDOUT_FILENO, "\x1b[H", 3);
       +                                exit(0);
       +                                break;
       +                        case 'h':
       +                        case 'j':
       +                        case 'k':
       +                        case 'l':
       +                                editor_move_cursor(c);
       +                                break;
       +
       +                        case CTRL_KEY('d'):
       +                                i = E.screen_rows/2;
       +                                while (i--)
       +                                        editor_move_cursor('j');
       +                                break;
       +                        case CTRL_KEY('u'):
       +                                i = E.screen_rows/2;
       +                                while (i--)
       +                                        editor_move_cursor('k');
       +                                break;
       +
       +                        case '0':
       +                                E.cursor_x = 0;
       +                                break;
       +                }
       +        }
       +}
 (DIR) diff --git a/output.c b/output.c
       t@@ -31,24 +31,35 @@ ab_free(struct abuf *ab) {
        void
        draw_status(struct abuf *ab)
        {
       -        char left_status[80], right_status[80];
       +        E.status_height = 1;
       +        char left_status[512], right_status[512];
                int left_status_len, right_status_len, padding;
       -        left_status_len = snprintf(left_status, sizeof(left_status),
       -                                   "%s editor -- version %s",
       -                                   PROGNAME, VERSION);
       +
       +        left_status_len = 0;
       +        switch (E.mode) {
       +                case 1:
       +                        left_status_len = snprintf(left_status, sizeof(left_status),
       +                                                   "INSERT");
       +                        break;
       +                case 2:
       +                        left_status_len = snprintf(left_status, sizeof(left_status),
       +                                                   "VISUAL");
       +                        break;
       +        }
       +
                right_status_len = snprintf(right_status, sizeof(right_status),
                                            "%s editor -- version %s",
                                            PROGNAME, VERSION);
        
       -        if (left_status_len > E.screencols)
       -                left_status_len = E.screencols;
       +        if (left_status_len > E.screen_cols)
       +                left_status_len = E.screen_cols;
        
       -        padding = E.screencols - left_status_len - right_status_len;
       +        padding = E.screen_cols - left_status_len - right_status_len;
                if (padding < 0) {
       -                if (left_status_len < E.screencols)
       +                if (left_status_len < E.screen_cols)
                                ab_append(ab, left_status, left_status_len);
                        else
       -                        ab_append(ab, left_status, E.screencols);
       +                        ab_append(ab, left_status, E.screen_cols);
                } else {
                        ab_append(ab, left_status, left_status_len);
                        while (padding--)
       t@@ -63,21 +74,21 @@ void
        editor_draw_rows(struct abuf *ab)
        {
                int y;
       -        for (y = -1; y < E.screenrows; ++y) {
       +        for (y = -1; y < E.screen_rows; ++y) {
        
       -                if (y == E.screenrows-1)
       +                if (y == E.screen_rows-1)
                                draw_status(ab);
                        else
                                ab_append(ab, "~", 1);
        
                        ab_append(ab, "\x1b[K", 3); /* erase to end of line */
       -                if (y < E.screenrows - 1)
       +                if (y < E.screen_rows - 1)
                                ab_append(ab, "\r\n", 2);
                }
        }
        
        /* fill output append buffer and write to terminal.
       - * move cursor to top left before and after repaint.
       + * move cursor to left before repaint, and to cursor position after.
         * hide the cursor when repainting.
         * VT100 escape sequences:
         * - http://vt100.net/docs/vt100-ug/chapter3.html
       t@@ -91,7 +102,10 @@ editor_refresh_screen()
                
                editor_draw_rows(&ab);
        
       -        ab_append(&ab, "\x1b[H", 3);    /* cursor to home */
       +        char buf[32];
       +        snprintf(buf, sizeof(buf), "\x1b[%d;%dH", E.cursor_y+1, E.cursor_x+1);
       +        ab_append(&ab, buf, strlen(buf));
       +
                ab_append(&ab, "\x1b[?25h", 6); /* show cursor */
        
                write(STDOUT_FILENO, ab.b, ab.len);
 (DIR) diff --git a/terminal.c b/terminal.c
       t@@ -5,7 +5,7 @@
        #include <termios.h>
        #include <unistd.h>
        #include <sys/ioctl.h>
       -#include "terminal.h"
       +#include "byote.h"
        
        struct editor_config E;
        
       t@@ -108,6 +108,9 @@ get_window_size(int *rows, int *cols)
        
        void
        init_editor() {
       -        if (get_window_size(&E.screenrows, &E.screencols) == -1)
       +        E.cursor_x = 0;
       +        E.cursor_y = 0;
       +        E.mode = 0;
       +        if (get_window_size(&E.screen_rows, &E.screen_cols) == -1)
                        die("get_window_size");
        }
 (DIR) diff --git a/terminal.h b/terminal.h
       t@@ -1,16 +1,6 @@
        #ifndef TERMINAL_H_
        #define TERMINAL_H_
        
       -#include <termios.h>
       -
       -struct editor_config {
       -        int screenrows;
       -        int screencols;
       -        struct termios orig_termios;
       -};
       -
       -extern struct editor_config E;
       -
        void die(const char *s);
        void disable_raw_mode();
        void enable_raw_mode();