Download raw body.
electric-pair-mode for mg [was Re: mg: grep buffer improvements]
electric-pair-mode for mg [was Re: mg: grep buffer improvements]
That's really cool, thanks for sharing!
I don't have much experience with C and I've been exploring how mg
works and using it as a jumping off point for sending patches to
OpenBSD. I've been using the system for years and mg has always been a
fascinating tool to me since Emacs users generally don't get a good
option OOB on any other OS.
I'll try to keep improving the quality of my patches and submitting
fixes if I come across anything that looks like it needs work.
Best,
Dante
On Tue, 2024-06-04 at 18:47 +0200, Omar Polo wrote:
> 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]
electric-pair-mode for mg [was Re: mg: grep buffer improvements]