This diff gives mg the ability to have an interactive session with interpreter.c via the 'eval-current-buffer' command. With this diff the interactive mode is switched off by default of course. So if you are in the habit of evaluting startup files you won't see any difference. With this diff applied, you would need to give the 'M-x eval-interactive' command to toggle this functionality on. Even then you will only see a difference with 'eval-current-buffer' if there are commands with parenthesis* at the start of a line in the startup buffer you are evaluating. For example, having the following line in a buffer and executing 'eval-current-buffer' the behaviour is the same as previously:
column-number-mode The command will toggle whether the column number shows in the modeline. If you instead have the following in the buffer: (column-number-mode) And issue the 'eval-current-buffer' command, with this diff applied (and whilst previously having toggled 'M-x eval-interactive' to on). You will achieve the same effect as the 1st command of toggling the column number in the modeline to on, but a buffer called *display-output* will have opened since you have entered the interpreter.c code by having '(' as the first none white character of the line. The contents of the *display-output* buffer will be empty because 'column-number-mode' creates no output. However with commands like: (insert "abc") The text "abc" will show in the *display-output* buffer. My initial goal is to have an interpreter that allows mg to combine different mg commands together and have some form of user defined functions, but I am a long way from that. The interpreter functionaility is still in the PoC stage and I wouldn't use it without expecting to see bugs (lots of them), and I expect it will go through more rewrites as I learn and understand more things about what is required. The functionality in the diff bellow allows me to test quicker though. As an outline, currently the interpreter can do things like: (define avar(list "a" "b" "c")) (insert avar) (newline 4) (insert avar) The string "abc" will appear twice in *display-output*, with 4 newline characters between them. Its pretty basic at the moment, I must admit.... I'm not intending this to be a scheme interpreter, but am using scheme syntax and a similar behaviour to be the glue of different mg commands which hopefully together can create mg user defined functions. This interpreter kind of functionality will also help me with intergrating mg's regress tests with OpenBSD's regress framework. For example, I am hoping to have something like: (define curdir(shell-command "echo $CURDIR")) To be able to import an environment variable, then use 'curdir' where required in mg's regress tests. If you would like to test, that would be much appreciated, there are also notes at the top of interpreter.c. I have not included anything in the mg man page about the interactive mode since I don't think the code is ready for that. Comments/oks/criticisms? Mark *parenthesis have been ignored in mg evaluation routines since mg being imported into the OpenBSD tree 21 years ago - and probably way before that, so I reckoned that no-one would have parenthesis in their startup files, or if they did, my interpreter code wouldn't change the behaviour of those lines anyway. Index: buffer.c =================================================================== RCS file: /cvs/src/usr.bin/mg/buffer.c,v retrieving revision 1.111 diff -u -p -r1.111 buffer.c --- buffer.c 23 Mar 2021 18:40:29 -0000 1.111 +++ buffer.c 23 Mar 2021 22:58:45 -0000 @@ -128,8 +128,6 @@ usebuffer(int f, int n) int poptobuffer(int f, int n) { - struct buffer *bp; - struct mgwin *wp; char bufn[NBUFN], *bufp; /* Get buffer to use from user */ @@ -142,6 +140,16 @@ poptobuffer(int f, int n) bufn, NBUFN, EFNUL | EFNEW | EFBUF, curbp->b_altb->b_bname); if (bufp == NULL) return (ABORT); + + return (do_poptobuffer(f, n, bufp)); +} + +int +do_poptobuffer(int f, int n, char *bufp) +{ + struct buffer *bp; + struct mgwin *wp; + if (bufp[0] == '\0' && curbp->b_altb != NULL) bp = curbp->b_altb; else if ((bp = bfind(bufp, TRUE)) == NULL) Index: def.h =================================================================== RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.170 diff -u -p -r1.170 def.h --- def.h 21 Mar 2021 12:56:16 -0000 1.170 +++ def.h 23 Mar 2021 22:58:45 -0000 @@ -381,6 +381,7 @@ int writeout(FILE **, struct buffer *, void upmodes(struct buffer *); size_t xbasename(char *, const char *, size_t); int do_filevisitalt(char *); +int do_poptofile(int, int, char *); /* line.c X */ struct line *lalloc(int); @@ -444,6 +445,7 @@ int revertbuffer(int, int); int dorevert(void); int diffbuffer(int, int); struct buffer *findbuffer(char *); +int do_poptobuffer(int, int, char *); /* display.c */ int vtresize(int, int, int); @@ -581,6 +583,7 @@ int extend(int, int); int evalexpr(int, int); int evalbuffer(int, int); int evalfile(int, int); +int evalinteractive(int, int); int load(const char *); int excline(char *); char *skipwhite(char *); @@ -751,6 +754,7 @@ extern int dovisiblebell; extern int dblspace; extern int allbro; extern int batch; +extern int einteract; extern char cinfo[]; extern char *keystrings[]; extern char pat[NPAT]; Index: extend.c =================================================================== RCS file: /cvs/src/usr.bin/mg/extend.c,v retrieving revision 1.73 diff -u -p -r1.73 extend.c --- extend.c 21 Mar 2021 12:56:16 -0000 1.73 +++ extend.c 23 Mar 2021 22:58:46 -0000 @@ -593,11 +593,31 @@ evalexpr(int f, int n) int evalbuffer(int f, int n) { - struct line *lp; - struct buffer *bp = curbp; + struct line *lp; + struct buffer *bp = curbp; int s; static char excbuf[BUFSIZE]; + if (einteract) { /* Do we want an interactive session */ + char *dobp, *bnamep; + + dobp = "*display-output*"; + bnamep = curbp->b_bname; + + if (do_poptobuffer(FFRAND, 0, dobp) != TRUE) + return(dobeep_msg("Unable to open display output.")); + + curbp->b_flag &= BFREADONLY; + markbuffer(FFARG, 0); + killregion(FFARG, 1); + eerase(); + + if (do_poptobuffer(FFRAND, 0, bnamep) != TRUE) + return(dobeep_msgs("Unable to move to:", bnamep)); + + bp = curbp; + } + for (lp = bfirstlp(bp); lp != bp->b_headp; lp = lforw(lp)) { if (llength(lp) >= BUFSIZE) return (FALSE); @@ -630,6 +650,20 @@ evalfile(int f, int n) else if (bufp[0] == '\0') return (FALSE); return (load(fname)); +} + +/* + * evalinteractive - Toggle interacting with interpreter.c. + */ +int +evalinteractive(int f, int n) +{ + if (f & FFARG) + einteract = n > 0; + else + einteract = !einteract; + + return (TRUE); } /* Index: file.c =================================================================== RCS file: /cvs/src/usr.bin/mg/file.c,v retrieving revision 1.102 diff -u -p -r1.102 file.c --- file.c 22 Jun 2019 15:03:43 -0000 1.102 +++ file.c 23 Mar 2021 22:58:46 -0000 @@ -157,10 +157,7 @@ filevisitro(int f, int n) int poptofile(int f, int n) { - struct buffer *bp; - struct mgwin *wp; - char fname[NFILEN], *adjf, *bufp; - int status; + char fname[NFILEN], *bufp; if (getbufcwd(fname, sizeof(fname)) != TRUE) fname[0] = '\0'; @@ -169,7 +166,19 @@ poptofile(int f, int n) return (ABORT); else if (bufp[0] == '\0') return (FALSE); - adjf = adjustname(fname, TRUE); + + return (do_poptofile(f, n, bufp)); +} + +int +do_poptofile(int f, int n, char *fn) +{ + struct buffer *bp; + struct mgwin *wp; + char *adjf; + int status; + + adjf = adjustname(fn, TRUE); if (adjf == NULL) return (FALSE); if (fisdir(adjf) == TRUE) Index: funmap.c =================================================================== RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.60 diff -u -p -r1.60 funmap.c --- funmap.c 23 Mar 2021 18:33:05 -0000 1.60 +++ funmap.c 23 Mar 2021 22:58:46 -0000 @@ -108,6 +108,7 @@ static struct funmap functnames[] = { {NULL, "esc prefix", 0}, /* internal */ {evalbuffer, "eval-current-buffer", 0}, {evalexpr, "eval-expression", 0}, + {evalinteractive, "eval-interactive", 0}, {swapmark, "exchange-point-and-mark", 0}, {extend, "execute-extended-command", 1}, {fillpara, "fill-paragraph", 0}, Index: interpreter.c =================================================================== RCS file: /cvs/src/usr.bin/mg/interpreter.c,v retrieving revision 1.13 diff -u -p -r1.13 interpreter.c --- interpreter.c 23 Mar 2021 15:22:25 -0000 1.13 +++ interpreter.c 23 Mar 2021 22:58:46 -0000 @@ -111,7 +111,8 @@ int foundparen(char *funstr) { struct expentry *e1 = NULL, *e2 = NULL; - char *p, *valp, *endp = NULL, *regs; + struct buffer *bp; + char *p, *valp, *endp = NULL, *regs, *bnamep; char expbuf[BUFSIZE], tmpbuf[BUFSIZE]; int ret, pctr, fndstart, expctr, blkid, fndchr, fndend; int inquote; @@ -146,6 +147,23 @@ foundparen(char *funstr) */ TAILQ_INIT(&ehead); + if (!batch && einteract) { + /* + * Create display output buffer if it doesn't exist + * otherwise just move to it. + */ + char *dobp = "*display-output*"; + + bnamep = curbp->b_bname; /* come back to this buff */ + + if ((bp = bfind(dobp, TRUE)) != NULL) { + if (do_poptobuffer(FFRAND, 0, dobp) != TRUE) + return(dobeep_msg("Unable to open display "\ + "output.")); + } + curbp->b_flag &= BFREADONLY; + } + while (*p != '\0') { if (*p == '(') { if (fndstart == 1) { @@ -247,6 +265,12 @@ foundparen(char *funstr) cleanup(); else clearexp(); /* leave lists but remove expressions */ + + if (!batch && einteract) { + curbp->b_flag |= BFREADONLY; + curbp->b_flag &= BFIGNDIRTY; + do_poptobuffer(FFRAND, 0, bnamep); + } return (ret); } Index: main.c =================================================================== RCS file: /cvs/src/usr.bin/mg/main.c,v retrieving revision 1.89 diff -u -p -r1.89 main.c --- main.c 20 Mar 2021 09:00:49 -0000 1.89 +++ main.c 23 Mar 2021 22:58:46 -0000 @@ -36,6 +36,7 @@ int dovisiblebell; /* visible bell t int dblspace; /* sentence end #spaces */ int allbro; /* all buffs read-only */ int batch; /* for regress tests */ +int einteract; /* interactive eval buf */ struct buffer *curbp; /* current buffer */ struct buffer *bheadp; /* BUFFER list head */ struct mgwin *curwp; /* current window */ @@ -149,6 +150,7 @@ main(int argc, char **argv) ttykeymapinit(); /* Symbols, bindings. */ bellinit(); /* Audible and visible bell. */ dblspace = 1; /* two spaces for sentence end. */ + einteract = 0; /* * doing update() before reading files causes the error messages from