URI:
       tAdd basic support for commands - ledit - Text editor (WIP)
  HTML git clone git://lumidify.org/ledit.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/git/ledit.git (encrypted, but very slow)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 36a12616e748e39265af475dbaee5e8356cc984a
   DIR parent 5d691e9f97b979d571d38c101554d72e91cb7db5
  HTML Author: lumidify <nobody@lumidify.org>
       Date:   Sun, 19 Sep 2021 19:27:06 +0200
       
       Add basic support for commands
       
       Diffstat:
         A BUG                                 |       9 +++++++++
         M Makefile                            |       4 ++--
         M buffer.c                            |       2 +-
         M commands.c                          |     159 ++++++++++++++++++++++++-------
         A commands.h                          |       1 +
         M ledit.c                             |       2 ++
       
       6 files changed, 142 insertions(+), 35 deletions(-)
       ---
   DIR diff --git a/BUG b/BUG
       t@@ -0,0 +1,9 @@
       +Random bugs noted down so I remember them; you are not expected to understand this
       +deleting two lines in middle: leaves stray empty line without cursor; undo not right order;
       +#0  0x00000d017890ccef in memcpy (dst0=0xd01adb5cf00, src0=0xd01c90a610b, length=18446744073709551566) at /usr/src/lib/libc/string/memcpy.c:97
       +#1  0x00000cff1763be78 in ledit_insert_text_base (buffer=0xd01adb67300, line_index=6, index=0, text=0xd01c90a610b "\001\r", len=-50) at buffer.c:322
       +#2  0x00000cff1763c516 in ledit_insert_text_with_newlines_base (buffer=0xd01adb67300, line_index=4, index=0,
       +    text=0xd01c90a6080 "اسجد\233ا\204کسجدا\233س\204کجاس\233\204دکاج\233د\204کسادجا\233سداکج\204د\233ا\n", len=89, end_line_ret=0x0,
       +    end_char_ret=0x0) at buffer.c:391
       +#3  0x00000cff17640058 in ledit_undo (buffer=0xd01adb67300) at undo.c:172
       +#4  0x00000cff17639d8a in undo () at ledit.c:1774
   DIR diff --git a/Makefile b/Makefile
       t@@ -9,8 +9,8 @@ MANPREFIX = ${PREFIX}/man
        BIN = ${NAME}
        MAN1 = ${BIN:=.1}
        
       -OBJ = ${BIN:=.o} cache.o buffer.o memory.o util.o search.o lbuf.o undo.o
       -HDR = cache.h buffer.h memory.h common.h util.h search.h lbuf.h undo.h
       +OBJ = ${BIN:=.o} cache.o buffer.o memory.o util.o search.o lbuf.o undo.o commands.o
       +HDR = cache.h buffer.h memory.h common.h util.h search.h lbuf.h undo.h commands.h
        
        CFLAGS_LEDIT = -g -Wall -Wextra -D_POSIX_C_SOURCE=200809L `pkg-config --cflags x11 xkbfile pangoxft xext`
        LDFLAGS_LEDIT = ${LDFLAGS} `pkg-config --libs x11 xkbfile pangoxft xext` -lm
   DIR diff --git a/buffer.c b/buffer.c
       t@@ -1035,7 +1035,7 @@ ledit_delete_range_base(
                                                        rgl1 = l1;
                                                        rgb1 = 0;
                                                        rgl2 = l2 + 1;
       -                                                rgb2 = nextline->len;
       +                                                rgb2 = 0;
                                                }
                                                if (text_ret) {
                                                        ledit_copy_text_to_lbuf(
   DIR diff --git a/commands.c b/commands.c
       t@@ -1,12 +1,52 @@
        /* FIXME: Parse commands properly and allow combinations of commands */
       +#include <ctype.h>
       +#include <X11/Xlib.h>
       +#include <X11/Xutil.h>
       +#include <pango/pangoxft.h>
       +#include <X11/extensions/Xdbe.h>
       +
       +#include "memory.h"
       +#include "common.h"
       +#include "lbuf.h"
       +#include "buffer.h"
       +
       +static int
       +handle_write(ledit_buffer *buffer, char *cmd, int l1, int l2) {
       +        (void)buffer;
       +        (void)cmd;
       +        (void)l1;
       +        (void)l2;
       +        printf("write\n");
       +        return 0;
       +}
       +
       +static int
       +handle_quit(ledit_buffer *buffer, char *cmd, int l1, int l2) {
       +        (void)buffer;
       +        (void)cmd;
       +        (void)l1;
       +        (void)l2;
       +        printf("quit\n");
       +        return 0;
       +}
        
        static int
        handle_write_quit(ledit_buffer *buffer, char *cmd, int l1, int l2) {
       +        (void)buffer;
       +        (void)cmd;
       +        (void)l1;
       +        (void)l2;
       +        printf("write quit\n");
                return 0;
        }
        
        static int
        handle_substitute(ledit_buffer *buffer, char *cmd, int l1, int l2) {
       +        (void)buffer;
       +        (void)cmd;
       +        (void)l1;
       +        (void)l2;
       +        printf("substitute\n");
                return 0;
        }
        
       t@@ -20,48 +60,103 @@ static const struct {
                enum cmd_type type;
                int (*handler)(ledit_buffer *buffer, char *cmd, int l1, int l2);
        } cmds[] = {
       -        {"w", CMD_NORMAL, &handle_write_quit},
       -        {"q", CMD_NORMAL, &handle_write_quit},
       +        {"wq", CMD_OPTIONAL_RANGE, &handle_write_quit},
       +        {"w", CMD_OPTIONAL_RANGE, &handle_write},
       +        {"q", CMD_NORMAL, &handle_quit},
                {"s", CMD_OPTIONAL_RANGE, &handle_substitute}
        };
        
        #define LENGTH(X) (sizeof(X) / sizeof(X[0]))
        
       +/*
       +. current line - FIXME: implement
       +$ last line
       +% all lines
       +*/
       +
       +/* FIXME: ACTUALLY USE LEN!!! */
       +static int
       +parse_range(ledit_buffer *buffer, char *cmd, int len, char **cmd_ret, int *line1_ret, int *line2_ret) {
       +        (void)len;
       +        enum {
       +                START_LINENO = 1,
       +                START_RANGE = 2,
       +                IN_RANGE = 4,
       +                IN_LINENO = 8
       +        } s = START_LINENO | START_RANGE;
       +        int l1 = -1, l2 = -1;
       +        char *c = cmd;
       +        for (; *c != '\0'; c++) {
       +                if (isdigit(*c)) {
       +                        /* FIXME: integer overflow */
       +                        if (s & IN_LINENO) {
       +                                if (l2 != -1)
       +                                        l2 = l2 * 10 + (*c - '0');
       +                                else
       +                                        l1 = l1 * 10 + (*c - '0');
       +                        } else if ((s & START_LINENO) && (s & START_RANGE)) {
       +                                l1 = *c - '0';
       +                                s &= ~START_RANGE;
       +                                s &= ~START_LINENO;
       +                                s |= IN_RANGE | IN_LINENO;
       +                        } else if ((s & START_LINENO)) {
       +                                l2 = *c - '0';
       +                                s &= ~START_LINENO;
       +                                s |= IN_LINENO;
       +                        }
       +                } else if (*c == ',' && !(s & START_RANGE)) {
       +                        if (l1 != -1 && l2 != -1) {
       +                                return 1;
       +                        } else {
       +                                s |= START_LINENO;
       +                                s &= ~IN_LINENO;
       +                        }
       +                } else if (*c == '%') {
       +                        if (s & START_RANGE) {
       +                                l1 = 1;
       +                                l2 = buffer->lines_num;
       +                                break;
       +                        } else {
       +                                return 1;
       +                        }
       +                } else if (*c == '$') {
       +                        if (s & START_LINENO) {
       +                                if (l1 == -1)
       +                                        l1 = buffer->lines_num;
       +                                else
       +                                        l2 = buffer->lines_num;
       +                                s &= ~START_LINENO;
       +                                s &= ~IN_LINENO;
       +                        } else {
       +                                return 1;
       +                        }
       +                } else {
       +                        break;
       +                }
       +        }
       +        if ((l1 == -1 || l2 == -1) && !(s & START_RANGE))
       +                return 1;
       +        *cmd_ret = c;
       +        *line1_ret = l1;
       +        *line2_ret = l2;
       +        return 0;
       +}
       +
        int
        ledit_handle_cmd(ledit_buffer *buffer, char *cmd, int len) {
                if (len < 0)
                        len = strlen(cmd);
                if (len < 1)
       -                return;
       -        char *cur_pos = cmd;
       -        int l1 = buffer->cur_line;
       -        int l2 = buffer->cur_line;
       -        int range_given = 0;
       -        switch (cur_pos[0]) {
       -        case '%':
       -                l1 = 0;
       -                l2 = buffer->lines_num - 1;
       -                range_given = 1;
       -                cur_pos++;
       -                break;
       -        case '&'
       -                l1 = buffer->sel.line1;
       -                l2 = buffer->sel.line2;
       -                if (l1 < 0 || l2 < 0)
       -                        return 1;
       -                if (l1 < l2) {
       -                        int tmp = l1;
       -                        l1 = l2;
       -                        l2 = tmp;
       -                }
       -                range_given = 1;
       -                cur_pos++;
       -                break
       -        }
       -        for (int i = 0; i < LENGTH(cmds); i++) {
       -                if (!strncmp(cmds[i].cmd, cur_pos, strlen(cmds[i].cmd)) &&
       -                    (!range_given || cmds[i].type == CMD_NORMAL)) {
       -                        return cmds[i].handler(buffer, cur_pos, l1, l2);
       +                return 1;
       +        char *c;
       +        int l1, l2;
       +        if (parse_range(buffer, cmd, len, &c, &l1, &l2))
       +                return 1;
       +        int range_given = l1 != -1 && l2 != -1;
       +        for (size_t i = 0; i < LENGTH(cmds); i++) {
       +                if (!strncmp(cmds[i].cmd, c, strlen(cmds[i].cmd)) &&
       +                    (!range_given || cmds[i].type == CMD_OPTIONAL_RANGE)) {
       +                        return cmds[i].handler(buffer, c, l1, l2);
                        }
                }
                return 1;
   DIR diff --git a/commands.h b/commands.h
       t@@ -0,0 +1 @@
       +int ledit_handle_cmd(ledit_buffer *buffer, char *cmd, int len);
   DIR diff --git a/ledit.c b/ledit.c
       t@@ -1755,6 +1755,8 @@ end_lineedit(void) {
                        else
                                ledit_set_search_backward(bottom_bar.line_text + 1);
                        search_next();
       +        } else if (old_mode == COMMANDEDIT) {
       +                ledit_handle_cmd(buffer, bottom_bar.line_text + 1, -1);
                }
        }