]> git.mdlowis.com Git - projs/tide.git/commitdiff
added rctags, tsed, updated TODO, added loading message to pick
authorMichael D. Lowis <mike.lowis@gentex.com>
Fri, 26 Apr 2019 20:06:34 +0000 (16:06 -0400)
committerMichael D. Lowis <mike.lowis@gentex.com>
Fri, 26 Apr 2019 20:06:34 +0000 (16:06 -0400)
Makefile
TODO.md
bin/rctags [new file with mode: 0755]
foo.md [deleted file]
src/pick.c
src/tsed.c [new file with mode: 0644]

index 5be212d533c42303bae09f78a90a688ac874a2b4..756b79e47f74932fd15196a9a9ec34fb8a19ece4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 CC = ./acc
 INCS = -Iinc/
-BINS = bin/tide bin/registrar bin/edit bin/fetch bin/pick
+BINS = bin/tide bin/registrar bin/edit bin/fetch bin/pick bin/tsed
 TEST_BINS =  tests/libedit
 MAN1 = docs/tide.1
 
diff --git a/TODO.md b/TODO.md
index a325c5315cfdc3d68bc4a4d493096e1b0d0d0174..fcfe8a5ad82e7d7a5b0e79381ae0ec2bc776f4c7 100644 (file)
--- a/TODO.md
+++ b/TODO.md
@@ -7,6 +7,7 @@
 ## STAGING
 
 * tide: gap buffer does not handle UTF-8 currently
+* tide: arrow keys on reverse selection shrink the wrong way
 
 ## BACKLOG
 
diff --git a/bin/rctags b/bin/rctags
new file mode 100755 (executable)
index 0000000..73709a7
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/sh
+ctags -R --exclude="mock*" --exclude="test_*"
diff --git a/foo.md b/foo.md
deleted file mode 100644 (file)
index 06c59fc..0000000
--- a/foo.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# Ctrl+D
-
-1) Tag: "Get", Edit: nil
-2) Tag: "Get", Edit: "Makefile"
-3) Tag: "Get Makefile", Edit: nil
-4) Tag: nil, Edit: "Get"
-5) Tag: "Makefile", Edit: "Get"
-6) Tag: nil, Edit: "Get Makefile"
-
-# Tag Execution
\ No newline at end of file
index 4dd6de80643fc46692f93e76bc46e9acb685c32e..9c525cd0d5ff14f4fb4d2f423d2a8d235ef71800 100644 (file)
@@ -240,10 +240,14 @@ static void redraw(XConf* x) {
     x11_draw_string(x, x->font, offset + 2, fheight, Palette[TagsFg], Query);
 
     /* draw the scored and sorted results */
-    for (int i = Offset, y = 2 * fheight + 4; ((size_t)i < vec_size(&Choices)) && ((size_t)i <= Offset+nlines); i++, y += fheight) {
-        if ((size_t)i == ChoiceIdx)
-            x11_draw_rect(x, Palette[EditSel], ScrollWidth+3, y - x->font->ascent, x->width, fheight);
-        x11_draw_string(x, x->font, ScrollWidth+3, y, Palette[TagsFg], ((Choice*)vec_at(&Choices, i))->string);
+    if (vec_size(&Choices)) {
+        for (int i = Offset, y = 2 * fheight + 4; ((size_t)i < vec_size(&Choices)) && ((size_t)i <= Offset+nlines); i++, y += fheight) {
+            if ((size_t)i == ChoiceIdx)
+                x11_draw_rect(x, Palette[EditSel], ScrollWidth+3, y - x->font->ascent, x->width, fheight);
+            x11_draw_string(x, x->font, ScrollWidth+3, y, Palette[TagsFg], ((Choice*)vec_at(&Choices, i))->string);
+        }
+    } else {
+        x11_draw_string(x, x->font, ScrollWidth+3, 2 * fheight + 4, Palette[TagsFg], "Loading...");
     }
     x11_flip(x);
 }
diff --git a/src/tsed.c b/src/tsed.c
new file mode 100644 (file)
index 0000000..457f04f
--- /dev/null
@@ -0,0 +1,236 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <regex.h>
+
+/* Line buffer flags */
+enum {
+    LB_NEWLINE = (1 << 0),
+    LB_DELETE = (1 << 1)
+};
+
+typedef struct {
+    int flags;
+    size_t capacity;
+    ssize_t length;
+    char* buffer;
+} LineBuf;
+
+/* Command flags */
+enum {
+    SUB_GLOBAL = (1 << 0),
+    SUB_PRINT  = (1 << 1),
+    IN_RANGE = (1 << 2),
+};
+
+typedef struct {
+    enum { NONE, LINE, REGEX } type;
+    union {
+        regex_t* regex;
+        size_t line;
+    } u;
+} Addr;
+
+typedef struct {
+    int type;
+    int flags;
+    Addr addr[2];
+    regex_t* regex;
+    char* text;
+} Cmd;
+
+typedef struct {
+    size_t ncmds;
+    size_t line;
+    Cmd cmds[];
+} Prog;
+
+typedef void (*CmdFn)(Cmd* cmd, LineBuf* buf);
+
+static void cmd_d(Cmd* cmd, LineBuf* lbuf) {
+    (void)cmd;
+    lbuf->flags |= LB_DELETE;
+}
+
+static void cmd_s(Cmd* cmd, LineBuf* lbuf) {
+    regmatch_t match[10] = {0};
+    if (!regexec(cmd->regex, lbuf->buffer, 10, match, 0)) {
+//        lbuf->flags |= LB_DELETE;
+    }
+}
+
+static const CmdFn Commands[] = {
+    ['d'] = cmd_d,
+    ['s'] = cmd_s
+};
+
+static int match_addr(Prog* prog, Addr* addr, LineBuf* lbuf) {
+    if (addr->type == NONE)
+        return 1;
+    else if (addr->type == LINE)
+        return (addr->u.line == prog->line);
+    else if (addr->type == REGEX)
+        return (regexec(addr->u.regex, lbuf->buffer, 0, 0, 0) == 0);
+    else
+        return 0;
+}
+
+static char* rdline(LineBuf* buf, FILE* file) {
+    buf->length = getline(&(buf->buffer), &(buf->capacity), file);
+    buf->flags = 0;
+    if (buf->length <= 0) {
+        free(buf->buffer);
+        buf->buffer = NULL;
+    } else if (buf->buffer[buf->length-1] == '\n') {
+        buf->flags |= LB_NEWLINE;
+        buf->buffer[buf->length-1] = '\0';
+    }
+    return buf->buffer;
+}
+
+static void parse_fail(char* msg) {
+    printf("parse error: %s\n", msg);
+    exit(1);
+}
+
+static char* parse_till(char* script, int term, char** str) {
+    if (!*script) return script;
+    char *sbeg = script, *send = script;
+    for (; *send && *send != term; send++)
+        if (*send == '\\')  send++;
+    *str = strndup(sbeg, send - sbeg);
+    return (*send ? send+1 : send);
+}
+
+static char* parse_addr(char* script, Addr* addr) {
+    if (isdigit(*script)) {
+        addr->type = LINE;
+        for (; *script && isdigit(*script); script++)
+            addr->u.line = (addr->u.line * 10) + (*script - '0');
+    } else if (*script == '/') {
+        addr->type = REGEX;
+        char* rstr = NULL;
+        script = parse_till(++script, '/', &rstr);
+        addr->u.regex = calloc(1, sizeof(regex_t));
+        if (regcomp(addr->u.regex, rstr, REG_EXTENDED|REG_NOSUB) != 0)
+            parse_fail("failed to compile regex");
+    }
+    return script;
+}
+
+static char* parse_sub(char* script, Cmd* cmd) {
+    int sep = *script++;
+    if (!sep) return (script-1);
+
+    /* parse out the regex and template */
+    char *rstr = NULL, *tstr = NULL;
+    script = parse_till(script, sep, &rstr);
+    script = parse_till(script, sep, &tstr);
+
+    /* parse the flags */
+    for (;*script && !isspace(*script); script++) {
+        switch (*script) {
+            case 'g': cmd->flags |= SUB_GLOBAL; break;
+            case 'p': cmd->flags |= SUB_PRINT;  break;
+            default:  parse_fail("bad substitute flag");
+        }
+    }
+
+    /* compile the regex and setup the command */
+    cmd->text = tstr;
+    cmd->regex = calloc(1, sizeof(regex_t));
+    if (regcomp(cmd->regex, rstr, REG_EXTENDED|REG_NEWLINE) < 0)
+        parse_fail("failed to compile regex");
+    free(rstr);
+
+    return script;
+}
+
+static Prog* prog_grow(Prog* prog, Cmd** lastcmd) {
+    prog = realloc(prog, sizeof(Prog) + ((prog->ncmds + 1) * sizeof(Cmd)));
+    *lastcmd = &(prog->cmds[prog->ncmds]);
+    prog->ncmds++;
+    memset(*lastcmd, 0, sizeof(Cmd));
+    return prog;
+}
+
+Prog* prog_parse(char* script) {
+    Cmd* cmd = NULL;
+    Prog* prog = calloc(1, sizeof(Prog));
+    while (*script) {
+        while (isspace(*script)) script++;
+        if (!*script) break;
+
+        /* allocate a new command */
+        prog = prog_grow(prog, &cmd);
+
+        /* parse the addresses */
+        script = parse_addr(script, &(cmd->addr[0]));
+        if (*script == ',')
+            script = parse_addr(++script, &(cmd->addr[1]));
+
+        /* parse the command */
+        cmd->type = *script;
+        switch (*script++) {
+            case 'd':
+                /* handled above */
+                break;
+            case 's':
+                script = parse_sub(script, cmd);
+                break;
+            case '\0':
+                parse_fail("unexpected end of string");
+                break;
+            default:
+                parse_fail("unexpected char");
+                exit(1);
+                break;
+        }
+    }
+    return prog;
+}
+
+void prog_free(Prog* prog) {
+#define FREE_REGEX(regex) do { regfree(regex); free(regex); } while(0)
+    for (size_t i = 0; i < prog->ncmds; i++) {
+        if (prog->cmds[i].addr[0].type == REGEX) FREE_REGEX(prog->cmds[i].addr[0].u.regex);
+        if (prog->cmds[i].addr[1].type == REGEX) FREE_REGEX(prog->cmds[i].addr[1].u.regex);
+        if (prog->cmds[i].regex) FREE_REGEX(prog->cmds[i].regex);
+        if (prog->cmds[i].text) free(prog->cmds[i].text);
+    }
+#undef FREE_REGEX
+    free(prog);
+}
+
+void prog_exec(Prog* prog, LineBuf* lbuf) {
+    prog->line++;
+    for (size_t i = 0; i < prog->ncmds; i++) {
+        Cmd* cmd = &(prog->cmds[i]);
+        if ((cmd->flags & IN_RANGE) ||match_addr(prog, &(cmd->addr[0]), lbuf)) {
+            if (cmd->addr[1].type != NONE) {
+                cmd->flags |= IN_RANGE;
+                if (match_addr(prog, &(cmd->addr[1]), lbuf))
+                    cmd->flags &= ~IN_RANGE;
+            }
+            Commands[cmd->type](cmd, lbuf);
+        }
+    }
+}
+
+int main(int argc, char** argv) {
+    if (argc < 2) return 1;
+
+    LineBuf buf = {0};
+    Prog* prog = prog_parse(argv[1]);
+    while (rdline(&buf, stdin)) {
+        prog_exec(prog, &buf);
+        if (buf.flags & LB_DELETE) continue;
+        fwrite(buf.buffer, 1u, buf.length, stdout);
+        if (buf.flags & LB_NEWLINE)
+            fwrite("\n", 1u, 1u, stdout);
+    }
+    prog_free(prog);
+
+    return 0;
+}