Added runtime rcfile parsing. - sam - An updated version of the sam text editor.
(HTM) git clone git://vernunftzentrum.de/sam.git
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) LICENSE
---
(DIR) commit 071c95698bc28739fb0289c84ff46a2278d1270c
(DIR) parent 140ba1042462570fc3c966652ea1d6e79cd3ae93
(HTM) Author: Rob King <jking@deadpixi.com>
Date: Fri, 9 Sep 2016 13:07:48 -0500
Added runtime rcfile parsing.
Diffstat:
include/libg.h | 2 ++
libXg/gwin.c | 121 ++++++++++++++++++++++---------
libXg/libgint.h | 4 ++++
libXg/xtbinit.c | 2 ++
samterm/Makefile | 2 +-
samterm/main.c | 12 ++++++++++++
samterm/samrc.c | 255 +++++++++++++++++++++++++++++++
samterm/samterm.h | 3 +++
8 files changed, 365 insertions(+), 36 deletions(-)
---
(DIR) diff --git a/include/libg.h b/include/libg.h
@@ -230,4 +230,6 @@ extern XftColor bgcolor;
#define BPSHORT(p, v) ((p)[0]=(v), (p)[1]=((v)>>8))
#define BPLONG(p, v) (BPSHORT(p, (v)), BPSHORT(p+2, (v)>>16))
+extern int installbinding(int, KeySym, int, int);
+extern int installchord(int, int, int, int);
#endif
(DIR) diff --git a/libXg/gwin.c b/libXg/gwin.c
@@ -160,19 +160,6 @@ Mappingaction(Widget w, XEvent *e, String *p, Cardinal *np)
for (c = 0; c < composing; c++) \
(*f)(compose[c], 0, Tcurrent, 0, 0)
-typedef struct Keymapping Keymapping;
-struct Keymapping{
- int mask;
- int sym;
- int kind;
- int result;
-};
-
-Keymapping keymappings[] ={
- #include "../commands.h"
- {0, 0, Kend, 0}
-};
-
typedef struct Unikeysym Unikeysym;
struct Unikeysym{
KeySym keysym;
@@ -195,6 +182,49 @@ keysymtoshort(KeySym k)
return k;
}
+typedef struct Keymapping Keymapping;
+struct Keymapping{
+ Keymapping *next;
+ int m;
+ KeySym s;
+ int k;
+ int c;
+};
+
+static Keymapping *keymappings = NULL;
+
+int
+installbinding(int m, KeySym s, int k, int c)
+{
+ if (m < 0 || s == NoSymbol || k < 0 || c < 0)
+ return -1;
+
+ Keymapping *km = calloc(1, sizeof(Keymapping));
+ if (!km)
+ return -1;
+
+ km->m = m;
+ km->s = s;
+ km->k = k;
+ km->c = c;
+
+ km->next = keymappings;
+ keymappings = km;
+
+ return 0;
+}
+
+void
+freebindings(void)
+{
+ Keymapping *m = keymappings;
+ while (m){
+ Keymapping *n = m->next;
+ free(m);
+ m = n;
+ }
+}
+
static void
Keyaction(Widget w, XEvent *e, String *p, Cardinal *np)
{
@@ -220,12 +250,12 @@ Keyaction(Widget w, XEvent *e, String *p, Cardinal *np)
XtTranslateKeycode(e->xany.display, (KeyCode)e->xkey.keycode, e->xkey.state, &md, &k);
/* Check to see if it's a specially-handled key first. */
- for (Keymapping *m = keymappings; m && m->kind != Kend; m++){
- if (k == m->sym && m->kind != Kdefault){
- if ((e->xkey.state & m->mask) || m->mask == 0){
+ for (Keymapping *m = keymappings; m; m = m->next){
+ if (k == m->s){
+ if ((e->xkey.state & m->m) || m->m == 0){
f = ((GwinWidget)w)->gwin.gotchar;
if (f)
- (*f)(m->result, m->kind, Tcurrent, 0, 0);
+ (*f)(m->c, m->k, Tcurrent, 0, 0);
return;
}
}
@@ -308,24 +338,45 @@ Keyaction(Widget w, XEvent *e, String *p, Cardinal *np)
typedef struct Chordmapping Chordmapping;
struct Chordmapping{
- int start;
- int end;
- int kind;
- int result;
- int target;
+ Chordmapping *next;
+ int s1;
+ int s2;
+ int c;
+ int t;
};
-#define Bnone 0
-#define B1 1
-#define B2 2
-#define B3 4
-#define B4 8
-#define B5 16
+static Chordmapping *chordmap = NULL;
-Chordmapping chordmappings[] ={
- #include "../chords.h"
- {0, 0, Kend, 0, 0}
-};
+int
+installchord(int s1, int s2, int c, int t)
+{
+ if (s1 < 0 || s2 < 0 || c < 0 || (t != Tmouse && t != Tcurrent))
+ return -1;
+
+ Chordmapping *m = calloc(1, sizeof(Chordmapping));
+ if (!m)
+ return -1;
+
+ m->s1 = s1;
+ m->s2 = s2;
+ m->c = c;
+ m->t = t;
+
+ m->next = chordmap;
+ chordmap = m;
+ return 0;
+}
+
+void
+freechords(void)
+{
+ Chordmapping *m = chordmap;
+ while (m){
+ Chordmapping *n = m->next;
+ free(m);
+ m = n;
+ }
+}
static void
Mouseaction(Widget w, XEvent *e, String *p, Cardinal *np)
@@ -391,11 +442,11 @@ Mouseaction(Widget w, XEvent *e, String *p, Cardinal *np)
if(s & Button5Mask) m.buttons |= 16;
/* Check to see if it's a chord first. */
- for (Chordmapping *cm = chordmappings; cm && cm->kind != Kend; cm++){
- if (ob == cm->start && m.buttons == cm->end){
+ for (Chordmapping *cm = chordmap; cm; cm = cm->next){
+ if (ob == cm->s1 && m.buttons == cm->s2){
Charfunc kf = ((GwinWidget)w)->gwin.gotchar;
if (kf)
- (*kf)(cm->result, cm->kind, cm->target, m.xy.x, m.xy.y);
+ (*kf)(cm->c, Kcommand, cm->t, m.xy.x, m.xy.y);
m.buttons = 0;
}
(DIR) diff --git a/libXg/libgint.h b/libXg/libgint.h
@@ -29,6 +29,10 @@ typedef char* caddr_t;
#undef Font
#undef Event
+/* binding and chord management */
+void freechords(void);
+void freebindings(void);
+
/* Cursor initialization */
void initcursors(void);
(DIR) diff --git a/libXg/xtbinit.c b/libXg/xtbinit.c
@@ -209,6 +209,8 @@ xtbinit(Errfunc f, char *class, int *pargc, char **argv, char **fallbacks)
}
initcursors();
+ atexit(freebindings);
+ atexit(freechords);
font = XftFontOpenName(_dpy, DefaultScreen(_dpy), getenv("FONT") ? getenv("FONT") : "monospace");
screen.id = 0;
(DIR) diff --git a/samterm/Makefile b/samterm/Makefile
@@ -22,7 +22,7 @@ CFLAGS=$(INCS) $(STANDARDS) $(INCLUDES)
LIBS=../libframe/libframe.a ../libXg/libXg.a
CC?=c99
-OBJ=main.o flayer.o icons.o io.o menu.o mesg.o rasp.o scroll.o unix.o
+OBJ=main.o flayer.o icons.o io.o menu.o mesg.o rasp.o samrc.o scroll.o unix.o
all: samterm
(DIR) diff --git a/samterm/main.c b/samterm/main.c
@@ -47,6 +47,18 @@ main(int argc, char *argv[])
Rectangle r;
Flayer *nwhich;
int fwdbut;
+ char rcpath[PATH_MAX + 1] = {0};
+ FILE *rc = NULL;
+
+ installdefaultbindings();
+ installdefaultchords();
+
+ snprintf(rcpath, PATH_MAX, "%s/.samrc", getenv("HOME") ? getenv("HOME") : ".");
+ rc = fopen(rcpath, "r");
+ if (rc){
+ loadrcfile(rc);
+ fclose(rc);
+ }
while ((opt = getopt(argc, argv, "efr:")) != -1){
switch (opt){
(DIR) diff --git a/samterm/samrc.c b/samterm/samrc.c
@@ -0,0 +1,255 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+
+#include <commands.h>
+#include <u.h>
+#include <libg.h>
+
+typedef struct Namemapping Namemapping;
+struct Namemapping{
+ const char *name;
+ int value;
+};
+
+static Namemapping commandmapping[] ={
+ {"escape", Cescape},
+ {"scrolldown", Cscrolldown},
+ {"scrollup", Cscrollup},
+ {"scrolldownline", Cscrolldownline},
+ {"scrollupline", Cscrollupline},
+ {"jump", Cjump},
+ {"charright", Ccharright},
+ {"charleft", Ccharleft},
+ {"linedown", Clinedown},
+ {"lineup", Clineup},
+ {"delword", Cdelword},
+ {"delbol", Cdelbol},
+ {"del", Cdel},
+ {"snarf", Csnarf},
+ {"cut", Ccut},
+ {"paste", Cpaste},
+ {"exchange", Cexchange},
+ {"write", Cwrite},
+ {"eol", Ceol},
+ {"bol", Cbol},
+ {NULL, 0}
+};
+
+static Namemapping targetmapping[] ={
+ {"current", Tcurrent},
+ {"mouse", Tmouse},
+ {NULL, 0}
+};
+
+static Namemapping buttonmapping[] ={
+ {"0", 0},
+ {"n", 0},
+#define B1 1
+ {"1", 1},
+#define B2 2
+ {"2", 2},
+#define B3 4
+ {"3", 4},
+#define B4 8
+ {"4", 8},
+#define B5 16
+ {"5", 16},
+ {NULL, 0}
+};
+
+static Namemapping modmapping[] ={
+ {"n", 0},
+ {"c", ControlMask},
+ {"a", Mod1Mask},
+ {"m", Mod1Mask},
+ {"s", Mod2Mask},
+ {"h", Mod3Mask},
+ {"1", Mod1Mask},
+ {"2", Mod2Mask},
+ {"3", Mod3Mask},
+ {"4", Mod4Mask},
+ {"5", Mod5Mask},
+ {NULL, 0}
+};
+
+static int
+lookupmapping(const char *n, Namemapping *m)
+{
+ for (Namemapping *k = m; k->name != NULL; k++){
+ if (strcasecmp(k->name, n) == 0)
+ return k->value;
+ }
+
+ return -1;
+}
+
+static int
+nametocommand(const char *n)
+{
+ return lookupmapping(n, commandmapping);
+}
+
+static int
+nametotarget(const char *n)
+{
+ return lookupmapping(n, targetmapping);
+}
+
+typedef struct Defaultbinding Defaultbinding;
+struct Defaultbinding{
+ int modifiers;
+ KeySym keysym;
+ int kind;
+ int command;
+};
+
+static Defaultbinding defaultbindings[] ={
+ /* Motion commands. */
+ {ControlMask, XK_e, Kcommand, Clineup},
+ {ControlMask, XK_x, Kcommand, Clinedown},
+ {ControlMask, XK_d, Kcommand, Ccharright},
+ {ControlMask, XK_s, Kcommand, Ccharleft},
+ {ControlMask, XK_u, Kcommand, Cdelbol},
+ {ControlMask, XK_w, Kcommand, Cdelword},
+ {ControlMask, XK_k, Kcommand, Cjump},
+ {ControlMask, XK_BackSpace, Kcommand, Cdelword},
+ {ControlMask, XK_y, Kcommand, Ccut},
+ {ControlMask, XK_c, Kcommand, Csnarf},
+ {ControlMask, XK_v, Kcommand, Cpaste},
+ {ControlMask, XK_q, Kcommand, Cexchange},
+
+ /* Use Control-Tab to insert a literal tab when tab expansion is enabled. */
+ {ControlMask, XK_Tab, Kcomposed, '\t'},
+
+ /* Handle arrow keys, page up/down, and escape. */
+ {0, XK_Up, Kcommand, Cscrollup},
+ {0, XK_Prior, Kcommand, Cscrollup},
+ {0, XK_Left, Kcommand, Cscrollup},
+ {0, XK_Down, Kcommand, Cscrolldown},
+ {0, XK_Next, Kcommand, Cscrolldown},
+ {0, XK_Right, Kcommand, Cscrolldown},
+ {0, XK_Escape, Kcommand, Cescape},
+
+ /* More fundamental stuff: backspace, delete, etc. */
+ {0, XK_BackSpace, Kcommand, Cdel},
+ {0, XK_Delete, Kcommand, Cdel},
+ {0, XK_Return, Kraw, '\n'},
+ {0, XK_KP_Enter, Kraw, '\n'},
+ {0, XK_Linefeed, Kraw, '\r'},
+ {0, XK_Tab, Kraw, '\t'},
+ {0, XK_KP_0, Kraw, '0'},
+ {0, XK_KP_1, Kraw, '1'},
+ {0, XK_KP_2, Kraw, '2'},
+ {0, XK_KP_3, Kraw, '3'},
+ {0, XK_KP_4, Kraw, '4'},
+ {0, XK_KP_5, Kraw, '5'},
+ {0, XK_KP_6, Kraw, '6'},
+ {0, XK_KP_7, Kraw, '7'},
+ {0, XK_KP_8, Kraw, '8'},
+ {0, XK_KP_9, Kraw, '9'},
+ {0, XK_KP_Divide, Kraw, '/'},
+ {0, XK_KP_Multiply, Kraw, '*'},
+ {0, XK_KP_Subtract, Kraw, '-'},
+ {0, XK_KP_Add, Kraw, '+'},
+ {0, XK_KP_Decimal, Kraw, '.'},
+ {0, XK_hyphen, Kraw, '-'},
+ {0, 0, Kend, 0}
+};
+
+void
+installdefaultbindings(void)
+{
+ for (Defaultbinding *b = defaultbindings; b->kind != Kend; b++)
+ installbinding(b->modifiers, b->keysym, b->kind, b->command);
+}
+
+typedef struct Defaultchord Defaultchord;
+struct Defaultchord{
+ int state1;
+ int state2;
+ int command;
+ int target;
+};
+
+static Defaultchord defaultchords[] ={
+ {B1, B1|B2, Ccut, Tcurrent},
+ {B1, B1|B3, Cpaste, Tcurrent},
+ {B1|B2, B1, Cnone, Tcurrent},
+ {B1|B3, B1, Cnone, Tcurrent},
+
+ {B4, 0, Cscrollupline, Tmouse},
+ {B5, 0, Cscrolldownline, Tmouse},
+
+ {0, 0, Kend, 0}
+};
+
+void
+installdefaultchords(void)
+{
+ for (Defaultchord *c = defaultchords; c->state1 != 0; c++)
+ installchord(c->state1, c->state2, c->command, c->target);
+}
+
+static int
+statetomask(const char *n, Namemapping *m)
+{
+ int r = 0;
+ for (int i = 0; n[i] != 0; i++){
+ char s[2] = {n[i], 0};
+ int v = lookupmapping(s, m);
+ if (v < 0)
+ return -1;
+ r |= v;
+ }
+
+ return r;
+}
+
+void
+loadrcfile(FILE *f)
+{
+ char *l = NULL;
+ size_t n = 0;
+ ssize_t r = 0;
+ size_t ln = 0;
+
+ while ((r = getline(&l, &n, f)) >= 0){
+ char s1[6] = {0};
+ char s2[6] = {0};
+ char cname[100] = {0};
+ char tname[100] = {0};
+ char c = 0;
+ unsigned short i = 0;
+ int rc = 0;
+
+ ln++;
+ if (r == 0 || l[0] == '\n' || l[0] == 0)
+ continue;
+
+ if (sscanf(l, " chord %5[Nn12345] %5[Nn12345] %99s %99s", s1, s2, cname, tname) == 4)
+ rc = installchord(statetomask(s1, buttonmapping), statetomask(s2, buttonmapping), nametocommand(cname), nametotarget(tname));
+ else if (sscanf(l, " bind %5[ncamshNCAMSH12345] %99s raw %hx", s1, s2, &i) == 3)
+ rc = installbinding(statetomask(s1, modmapping), XStringToKeysym(s2), Kraw, i);
+ else if (sscanf(l, " bind %5[ncamshNCAMSH12345] %99s composed %hx", s1, s2, &i) == 3)
+ rc = installbinding(statetomask(s1, modmapping), XStringToKeysym(s2), Kcomposed, i);
+ else if (sscanf(l, " bind %5[ncamshNCAMSH12345] %99s raw %c", s1, s2, &c) == 3)
+ rc = installbinding(statetomask(s1, modmapping), XStringToKeysym(s2), Kraw, c);
+ else if (sscanf(l, " bind %5[ncamshNCAMSH12345] %99s composed %c", s1, s2, &c) == 3)
+ rc = installbinding(statetomask(s1, modmapping), XStringToKeysym(s2), Kcomposed, c);
+ else if (sscanf(l, " bind %5[ncamshNCAMSH12345] %99s command %99s", s1, s2, cname) == 3)
+ rc = installbinding(statetomask(s1, modmapping), XStringToKeysym(s2), Kcommand, nametocommand(cname));
+ else if (sscanf(l, " %[#]", &c) == 1)
+ continue;
+ else
+ fprintf(stderr, "invalid rc line %zd\n", ln);
+
+ if (rc != 0)
+ fprintf(stderr, "invalid chord/binding on rc line %zd\n", ln);
+ }
+
+ free(l);
+}
(DIR) diff --git a/samterm/samterm.h b/samterm/samterm.h
@@ -157,3 +157,6 @@ void outlong(long);
void outvlong(void*);
void outsend(void);
int getlayer(const Flayer *l, const Text *t);
+void loadrcfile(FILE *);
+void installdefaultbindings(void);
+void installdefaultchords(void);