Download raw body.
electric-pair-mode for mg [was Re: mg: grep buffer improvements]
sorry for the slighly OT, but thought this might interest you :)
(and maybe a few other readers)
many moons ago I wrote this to emulate GNU Emacs' electric-pair-mode,
i.e. to automatically close pairs. It's not in a state where it can be
committed, some keybindings conflict with other keymaps and care needs
to be used to enable electric-pair-mode *after* c-mode, epnewline is
also conflicting with auto-indent-mode and/or c-mode IIRC. I'd need to
understand better how keybindings are handled and what can be done for
conflicting ones and/or to "fallback". Still, it's something i keep in
my tree and use always :)
diff d784f91cfcb7086a5e38d59ae74fcadbcf1bb1af dfb48153daf1efa4cef5b96317016965cbee0176
commit - d784f91cfcb7086a5e38d59ae74fcadbcf1bb1af
commit + dfb48153daf1efa4cef5b96317016965cbee0176
blob - fc3899772ec9892528274d0f22f438cac31c24b0
blob + aff6a4016f5ca65616667786c9cc8288f2389ab4
--- usr.bin/mg/Makefile
+++ usr.bin/mg/Makefile
@@ -22,7 +22,7 @@ SRCS= autoexec.c basic.c bell.c buffer.c cinfo.c dir.c
#
# More or less standalone extensions.
#
-SRCS+= cmode.c cscope.c dired.c grep.c interpreter.c tags.c
+SRCS+= cmode.c cscope.c dired.c grep.c interpreter.c tags.c electric.c
#
# -DMGLOG source file.
blob - 403635036ceea9bcb7ca995a0c55b5ebe11e7372
blob + a1d50b94798aed6b5e2c2797fcb18a054cc096e7
--- usr.bin/mg/def.h
+++ usr.bin/mg/def.h
@@ -20,7 +20,7 @@ typedef int (*PF)(int, int); /* generally useful type
#define NFILEN 1024 /* Length, file name. */
#define NBUFN NFILEN /* Length, buffer name. */
#define NLINE 256 /* Length, line. */
-#define PBMODES 4 /* modes per buffer */
+#define PBMODES 8 /* modes per buffer */
#define NPAT 80 /* Length, pattern. */
#define HUGE 1000 /* A rather large number. */
#define NSRCH 128 /* Undoable search commands. */
@@ -722,6 +722,14 @@ int cc_tab(int, int);
int cc_indent(int, int);
int cc_lfindent(int, int);
+/* electric.c X */
+int epmode(int, int);
+int epinsert(int, int);
+int epskip(int, int);
+int epbdel(int, int);
+int epfdel(int, int);
+int epnewline(int, int);
+
/* grep.c X */
int next_error(int, int);
int globalwdtoggle(int, int);
blob - /dev/null
blob + 1a5e05464b74cbd477686bb4d4828bfa3a8c49ec (mode 644)
--- /dev/null
+++ usr.bin/mg/electric.c
@@ -0,0 +1,280 @@
+/* $OpenBSD$ */
+/*
+ * This file is in the public domain.
+ *
+ * Author: Omar Polo <op@openbsd.org>
+ */
+
+#include <sys/queue.h>
+#include <signal.h>
+#include <stdio.h>
+
+#include "def.h"
+#include "funmap.h"
+#include "kbd.h"
+#include "key.h"
+
+/* Pull in from modes.c */
+extern int changemode(int, int, char *);
+
+int pairp(int, int);
+int epclosep(void);
+
+/* Keymaps */
+
+static PF ele_cmap[] = {
+ epfdel, /* ^D */
+ rescan, /* ^E */
+ rescan, /* ^F */
+ rescan, /* ^G */
+ rescan, /* ^H */
+ rescan, /* ^I */
+ rescan, /* ^J */
+ rescan, /* ^K */
+ rescan, /* ^L */
+ rescan, /* ^M */
+ //epnewline, /* ^M */
+};
+
+static PF ele_quote[] = {
+ epinsert, /* " */
+};
+
+static PF ele_apostrophe[] = {
+ epinsert, /* ' */
+};
+
+static PF ele_paren[] = {
+ epinsert, /* ( */
+ epskip, /* ) */
+};
+
+static PF ele_bracket[] = {
+ epinsert, /* [ */
+ rescan, /* \ */
+ epskip, /* ] */
+};
+
+static PF ele_backtick[] = {
+ epinsert, /* ` */
+};
+
+static PF ele_high[] = {
+ epinsert, /* { */
+ rescan, /* | */
+ epskip, /* } */
+ rescan, /* ~ */
+ epbdel, /* DEL */
+};
+
+static struct KEYMAPE (7) epmodemap = {
+ 7,
+ 7,
+ rescan,
+ {
+ { CCHR('D'), CCHR('M'), ele_cmap, NULL },
+ { '"', '"', ele_quote, NULL },
+ { '\'', '\'', ele_apostrophe, NULL },
+ { '(', ')', ele_paren, NULL },
+ { '[', ']', ele_bracket, NULL },
+ { '`', '`', ele_backtick, NULL },
+ { '{', CCHR('?'), ele_high, NULL },
+ }
+};
+
+/* Function, Mode hooks */
+
+void
+epmode_init(void)
+{
+ funmap_add(epmode, "electric-pair-mode", 0);
+ maps_add((KEYMAP *)&epmodemap, "ep");
+}
+
+/*
+ * Enable/toggle electric-pair-mode.
+ */
+int
+epmode(int f, int n)
+{
+ return (changemode(f, n, "ep"));
+}
+
+/* Do o and c form a pair? */
+int
+pairp(int o, int c)
+{
+ switch (o) {
+ case '"':
+ case '\'':
+ case '`':
+ return (c == o);
+ case '(':
+ return (c == ')');
+ case '[':
+ return (c == ']');
+ case '{':
+ return (c == '}');
+ }
+ return (FALSE);
+}
+
+/* Can we skip over the character? */
+int
+epclosep(void)
+{
+ int c;
+
+ c = key.k_chars[key.k_count - 1];
+ if (curwp->w_doto < llength(curwp->w_dotp))
+ return (c == lgetc(curwp->w_dotp, curwp->w_doto));
+ return (FALSE);
+}
+
+/*
+ * Handle pair character - selfinsert then selfinsert.
+ */
+int
+epinsert(int f, int n)
+{
+ int s, c;
+
+ if (n < 0)
+ return (FALSE);
+
+ if (n == 0)
+ return (TRUE);
+
+ if (n == 1 && epclosep())
+ return (forwchar(FFRAND, 1));
+
+ c = key.k_chars[key.k_count - 1];
+ if ((s = selfinsert(FFRAND, n)) != TRUE)
+ return (s);
+
+ switch (c) {
+ case '"':
+ case '\'':
+ case '`':
+ s = linsert(n, c);
+ break;
+ case '(':
+ s = linsert(n, ')');
+ break;
+ case '[':
+ s = linsert(n, ']');
+ break;
+ case '{':
+ s = linsert(n, '}');
+ break;
+ }
+
+ if (s != TRUE)
+ return (s);
+
+ return (backchar(FFRAND, n));
+}
+
+/*
+ * Do forwchar if trying to insert a character equal to the next one.
+ */
+int
+epskip(int f, int n)
+{
+ if (n == 1 && epclosep())
+ return (forwchar(FFRAND, 1));
+ return (selfinsert(f, n));
+}
+
+/*
+ * Handle deletion of a character trying to keep pairs balanced.
+ */
+int
+epbdel(int f, int n)
+{
+ int s, o, c;
+
+ if (n < 0)
+ return (epfdel(f | FFRAND, -n));
+
+ while (n--) {
+ o = '\0';
+ c = '\0';
+
+ /* peek at the character to delete */
+ if (curwp->w_doto > 0)
+ o = lgetc(curwp->w_dotp, curwp->w_doto - 1);
+
+ /* do the delete */
+ if ((s = backdel(FFRAND, 1)) != TRUE)
+ return (s);
+
+ /* peek at the next character */
+ if (curwp->w_doto < llength(curwp->w_dotp))
+ c = lgetc(curwp->w_dotp, curwp->w_doto);
+
+ if (!pairp(o, c))
+ continue;
+ if ((s = forwdel(FFRAND, 1)) != TRUE)
+ return (s);
+ }
+
+ return (TRUE);
+}
+
+/*
+ * Handle deletion of a character trying to keep pairs balanced.
+ */
+int
+epfdel(int f, int n)
+{
+ int s, o, c;
+
+ if (n < 0)
+ return (epbdel(f | FFRAND, -n));
+
+ while (n--) {
+ o = '\0';
+ c = '\0';
+
+ /* peek at the character to delete */
+ if (curwp->w_doto < llength(curwp->w_dotp))
+ c = lgetc(curwp->w_dotp, curwp->w_doto);
+
+ /* do the delete */
+ if ((s = forwdel(FFRAND, 1)) != TRUE)
+ return (s);
+
+ /* peek at the prev character */
+ if (curwp->w_doto > 0)
+ o = lgetc(curwp->w_dotp, curwp->w_doto - 1);
+
+ if (!pairp(o, c))
+ continue;
+ if ((s = backdel(FFRAND, 1)) != TRUE)
+ return (s);
+ }
+
+ return (TRUE);
+}
+
+int
+epnewline(int f, int n)
+{
+ int s, o, c;
+
+ if (n != 1 || curwp->w_doto == 0 ||
+ curwp->w_doto == llength(curwp->w_dotp))
+ return (lfindent(f, n));
+
+ o = lgetc(curwp->w_dotp, curwp->w_doto - 1);
+ c = lgetc(curwp->w_dotp, curwp->w_doto);
+ if (!pairp(o, c))
+ return (lfindent(f, n));
+
+ if ((s = lfindent(FFRAND, 2)) != TRUE ||
+ (s = backline(FFRAND, 1)) != TRUE ||
+ (s = gotoeol(FFRAND, 1)) != TRUE)
+ return (s);
+ return (TRUE);
+}
blob - 56ef7d9a0429e15ac6af9645781f9e7f2042f16d
blob + 20f8ab03d4fb500e2944327bfeea1ec1f34adc5b
--- usr.bin/mg/main.c
+++ usr.bin/mg/main.c
@@ -137,10 +137,12 @@ main(int argc, char **argv)
extern void grep_init(void);
extern void cmode_init(void);
extern void dired_init(void);
+ extern void epmode_init(void);
dired_init();
grep_init();
cmode_init();
+ epmode_init();
}
if (init_fcn_name &&
electric-pair-mode for mg [was Re: mg: grep buffer improvements]