Introduce modes - lchat - A line oriented chat front end for ii. | |
git clone git://git.suckless.org/lchat | |
Log | |
Files | |
Refs | |
README | |
--- | |
commit a2e85fdc57c1322c16d120d1865acc8f13f4c8bd | |
parent 19b4d99293ad470c98406b94935565750339b716 | |
Author: Tom Schwindl <[email protected]> | |
Date: Thu, 29 Dec 2022 13:17:48 +0100 | |
Introduce modes | |
A mode determines how keyborad input is interpreted and which keybindings | |
are available. Currently, there is a default- and an emacs-mode from which | |
the user can choose. | |
Diffstat: | |
M Makefile | 7 +++++-- | |
M lchat.c | 9 ++++++--- | |
M slackline.c | 112 +++++++++++++++++++++--------… | |
A slackline_emacs.c | 53 ++++++++++++++++++++++++++++++ | |
4 files changed, 139 insertions(+), 42 deletions(-) | |
--- | |
diff --git a/Makefile b/Makefile | |
@@ -22,8 +22,8 @@ dist: | |
tar -czf lchat-$(VERSION).tar.gz lchat-$(VERSION) | |
rm -fr lchat-$(VERSION) | |
-lchat: lchat.o slackline.o util.o | |
- $(CC) -o $@ lchat.o slackline.o util.o $(LIBS) | |
+lchat: lchat.o slackline.o util.o slackline_emacs.o | |
+ $(CC) -o $@ lchat.o slackline.o slackline_emacs.o util.o $(LIBS) | |
lchat.o: lchat.c | |
$(CC) -c $(CFLAGS) -D_BSD_SOURCE -D_XOPEN_SOURCE -D_GNU_SOURCE \ | |
@@ -42,5 +42,8 @@ sl_test: sl_test.o slackline.o slackline.h | |
slackline.o: slackline.c slackline.h | |
$(CC) -c $(CFLAGS) -o $@ slackline.c | |
+slackline_emacs.o: slackline_emacs.c slackline.h | |
+ $(CC) -c $(CFLAGS) -o $@ slackline_emacs.c | |
+ | |
util.o: util.c util.h | |
$(CC) -c $(CFLAGS) -D_BSD_SOURCE -o $@ util.c | |
diff --git a/lchat.c b/lchat.c | |
@@ -23,6 +23,7 @@ | |
#include <limits.h> | |
#include <poll.h> | |
#include <signal.h> | |
+#include <stdbool.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
@@ -183,7 +184,7 @@ main(int argc, char *argv[]) | |
char *in_file = NULL; | |
char *out_file = NULL; | |
- while ((ch = getopt(argc, argv, "an:i:eo:p:t:uh")) != -1) { | |
+ while ((ch = getopt(argc, argv, "an:i:eo:p:t:uhm:")) != -1) { | |
switch (ch) { | |
case 'a': | |
bell_flag = false; | |
@@ -217,6 +218,10 @@ main(int argc, char *argv[]) | |
case 'u': | |
ucspi = true; | |
break; | |
+ case 'm': | |
+ if (strcmp(optarg, "emacs") == 0) | |
+ sl_mode(sl, SL_EMACS); | |
+ break; | |
case 'h': | |
default: | |
usage(); | |
@@ -342,8 +347,6 @@ main(int argc, char *argv[]) | |
return EXIT_SUCCESS; | |
switch (c) { | |
- case 4: /* eot */ | |
- return EXIT_SUCCESS; | |
case 13: /* return */ | |
if (sl->rlen == 0 && empty_line == false) | |
goto out; | |
diff --git a/slackline.c b/slackline.c | |
@@ -22,13 +22,14 @@ | |
#include <grapheme.h> | |
+#include "slackline_internals.h" | |
#include "slackline.h" | |
- | |
-enum direction {LEFT, RIGHT, HOME, END}; | |
+#include "util.h" | |
struct slackline * | |
sl_init(void) | |
{ | |
+ char *mode = getenv("EDITOR"); | |
struct slackline *sl = malloc(sizeof *sl); | |
if (sl == NULL) | |
@@ -45,6 +46,14 @@ sl_init(void) | |
sl_reset(sl); | |
+ sl->mode = SL_DEFAULT; | |
+ if (mode != NULL) { | |
+ if (strcmp(mode, "emacs") == 0) | |
+ sl->mode = SL_EMACS; | |
+ else if (strcmp(mode, "vi") == 0) | |
+ sl->mode = SL_VI; | |
+ } | |
+ | |
return sl; | |
} | |
@@ -71,7 +80,13 @@ sl_reset(struct slackline *sl) | |
sl->ubuf_len = 0; | |
} | |
-static size_t | |
+void | |
+sl_mode(struct slackline *sl, enum mode mode) | |
+{ | |
+ sl->mode = mode; | |
+} | |
+ | |
+size_t | |
sl_postobyte(struct slackline *sl, size_t pos) | |
{ | |
char *ptr = &sl->buf[0]; | |
@@ -84,13 +99,13 @@ sl_postobyte(struct slackline *sl, size_t pos) | |
return byte; | |
} | |
-static char * | |
+char * | |
sl_postoptr(struct slackline *sl, size_t pos) | |
{ | |
return &sl->buf[sl_postobyte(sl, pos)]; | |
} | |
-static void | |
+void | |
sl_backspace(struct slackline *sl) | |
{ | |
char *ncur; | |
@@ -114,7 +129,7 @@ sl_backspace(struct slackline *sl) | |
sl->ptr = ncur; | |
} | |
-static void | |
+void | |
sl_move(struct slackline *sl, enum direction dir) | |
{ | |
switch (dir) { | |
@@ -139,21 +154,41 @@ sl_move(struct slackline *sl, enum direction dir) | |
sl->ptr = sl->buf + sl->bcur; | |
} | |
-int | |
-sl_keystroke(struct slackline *sl, int key) | |
+static void | |
+sl_default(struct slackline *sl, int key) | |
{ | |
- uint_least32_t cp; | |
- | |
- if (sl == NULL || sl->rlen < sl->rcur) | |
- return -1; | |
+ switch (key) { | |
+ case 27: /* Escape */ | |
+ sl->esc = ESC; | |
+ break; | |
+ case 21: | |
+ sl_reset(sl); | |
+ break; | |
+ case 23: /* ctrl+w -- erase previous word */ | |
+ while (sl->rcur != 0 && isspace((unsigned char) *(sl->ptr-1))) | |
+ sl_backspace(sl); | |
+ while (sl->rcur != 0 && !isspace((unsigned char) *(sl->ptr-1))) | |
+ sl_backspace(sl); | |
+ break; | |
+ case 127: /* backspace */ | |
+ case 8: /* backspace */ | |
+ sl_backspace(sl); | |
+ break; | |
+ default: | |
+ break; | |
+ } | |
+} | |
+static int | |
+sl_esc(struct slackline *sl, int key) | |
+{ | |
/* handle escape sequences */ | |
switch (sl->esc) { | |
case ESC_NONE: | |
break; | |
case ESC: | |
sl->esc = key == '[' ? ESC_BRACKET : ESC_NONE; | |
- return 0; | |
+ return 1; | |
case ESC_BRACKET: | |
switch (key) { | |
case 'A': /* up */ | |
@@ -189,10 +224,10 @@ sl_keystroke(struct slackline *sl, int key) | |
case '9': | |
sl->nummod = key; | |
sl->esc = ESC_BRACKET_NUM; | |
- return 0; | |
+ return 1; | |
} | |
sl->esc = ESC_NONE; | |
- return 0; | |
+ return 1; | |
case ESC_BRACKET_NUM: | |
switch(key) { | |
case '~': | |
@@ -213,35 +248,38 @@ sl_keystroke(struct slackline *sl, int key) | |
break; | |
} | |
sl->esc = ESC_NONE; | |
- return 0; | |
+ return 1; | |
} | |
} | |
- if (!iscntrl((unsigned char) key)) | |
- goto compose; | |
+ return 0; | |
+} | |
- /* handle ctl keys */ | |
- switch (key) { | |
- case 27: /* Escape */ | |
- sl->esc = ESC; | |
- return 0; | |
- case 127: /* backspace */ | |
- case 8: /* backspace */ | |
- sl_backspace(sl); | |
- return 0; | |
- case 21: /* ctrl+u -- clearline */ | |
- sl_reset(sl); | |
- return 0; | |
- case 23: /* ctrl+w -- erase previous word */ | |
- while (sl->rcur != 0 && isspace((unsigned char) *(sl->ptr-1))) | |
- sl_backspace(sl); | |
+int | |
+sl_keystroke(struct slackline *sl, int key) | |
+{ | |
+ uint_least32_t cp; | |
- while (sl->rcur != 0 && !isspace((unsigned char) *(sl->ptr-1))) | |
- sl_backspace(sl); | |
- return 0; | |
- default: | |
+ if (sl == NULL || sl->rlen < sl->rcur) | |
+ return -1; | |
+ if (sl_esc(sl, key)) | |
return 0; | |
+ if (!iscntrl((unsigned char) key)) | |
+ goto compose; | |
+ | |
+ switch (sl->mode) { | |
+ case SL_DEFAULT: | |
+ sl_default(sl, key); | |
+ break; | |
+ case SL_EMACS: | |
+ sl_default(sl, key); | |
+ sl_emacs(sl, key); | |
+ break; | |
+ case SL_VI: | |
+ /* TODO: implement vi-mode */ | |
+ break; | |
} | |
+ return 0; | |
compose: | |
/* byte-wise composing of UTF-8 runes */ | |
diff --git a/slackline_emacs.c b/slackline_emacs.c | |
@@ -0,0 +1,53 @@ | |
+#include <stdio.h> | |
+#include <ctype.h> | |
+#include <stddef.h> | |
+#include <stdlib.h> | |
+ | |
+#include "slackline_internals.h" | |
+ | |
+void | |
+sl_emacs(struct slackline *sl, int key) | |
+{ | |
+ char tmp; | |
+ | |
+ switch (key) { | |
+ case 27: /* Escape */ | |
+ sl->esc = ESC; | |
+ break; | |
+ case 1: /* ctrl+a -- start of line */ | |
+ sl_move(sl, HOME); | |
+ break; | |
+ case 2: /* ctrl+b -- previous char */ | |
+ sl_move(sl, LEFT); | |
+ break; | |
+ case 4: /* ctrl+d -- delete char in front of the cursor or exit */ | |
+ if (sl->rcur < sl->rlen) { | |
+ sl_move(sl, RIGHT); | |
+ sl_backspace(sl); | |
+ } else { | |
+ exit(EXIT_SUCCESS); | |
+ } | |
+ break; | |
+ case 5: /* ctrl+e -- end of line */ | |
+ sl_move(sl, END); | |
+ break; | |
+ case 6: /* ctrl+f -- next char */ | |
+ sl_move(sl, RIGHT); | |
+ break; | |
+ case 11: /* ctrl+k -- delete line from cursor to end */ | |
+ for (int i = sl->rlen - sl->rcur; i > 0; --i) { | |
+ sl_move(sl, RIGHT); | |
+ sl_backspace(sl); | |
+ } | |
+ break; | |
+ case 20: /* ctrl+t -- swap last two chars */ | |
+ if (sl->rcur >= 2) { | |
+ tmp = *sl_postoptr(sl, sl->rcur-1); | |
+ sl->buf[sl->rcur-1] = *sl_postoptr(sl, sl->rcur-2); | |
+ sl->buf[sl->rcur-2] = tmp; | |
+ } | |
+ break; | |
+ default: | |
+ break; | |
+ } | |
+} |