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

Reply via email to