Discussion:
[Bug-apl] Yet another editor thingy.
Chris Moller
2018-07-15 20:47:14 UTC
Permalink
After battling for decades with the ancient nabla editor, I finally did
something I should have done years ago and write a simple native
function that let's you use emacs or vi from inside an APL session. 
It's not even close to Elias MÃ¥rtenson's cool emacs APL mode--it's just
a quick thing to bring up a friendlier editor.  It's alpha-level
code--if it melts your computer, it's not my fault--and there are a few
things on the TODO list, but I thought I'd put it out there and get some
feedback if anyone's interested.

Here's the README:

edif is a GNU APL native function that allows the use of external
editors
from within an APL session.

Usage:

        edif 'function_name'

This will open an editor, typically vi or emacs, containing the present
definition of the specified function, or, if the function doesn't exist,
a boilerplate function header consisting of the function name. 
After saving
the edited definition and exiting the editor, the function will
appear in
the APL workspace.  While the editor is open, APL is suspended.

edif will look for the environment variable EDIF and will use the string
specified by that variable as the command line to invoke the chosen
editor.
For example:

   export EDIF="emacs --geometry=40x20  -background '#ffffcc' -font
'DejaVu Sans Mono-10'"

will invoke emacs with a fairly small window, a light yellow
background, and
using the DejaVu Sans Mono-10 font.  (That's also the default if no EDIF
variable is found.)

edif has only been tested with emacs and vi.


Future work may also allow edif to edit APL variables and operators,
but no
guarantees I'll ever get around to it.

edif may be included in the workspace with:

        'libedif.so' ⎕fx 'edif'



Implimentation note:

edif works by storing an editable version of the specified function in:

/var/run/user/<uid>/<pid>/<name>.apl

where <uid> is the user's userid, <pid> is the process id of the APL
session, and <name> is the function name.  This allows multiple users
each to have multiple simultaneous APL sessions with workspaces with
identical names.  No locking is done by edif and I've no idea if APL
itself has any protection against a writable workspace being open in
multiple simultaneous sessions, but it opens up the possibility that
you can hose the workspace.  So while, as far as edif is concerned
you can have multiple simultaneous sessions aimed at the same lib0
workspace, you probably shouldn't do it.

Also, I've no idea if Windows or any Linux distribution other than
Fedora has a /var directory, so using this directory may be
non-portable.

So far as I can tell, edif doesn't interfere with Elias MÃ¥rtenson's
emacs APL mode, but I haven't thoroughly tested that.


It's at https://github.com/ChrisMoller/edif

(BTW, "edif" is short for "editor interface.")
Juergen Sauermann
2018-07-18 09:36:09 UTC
Permalink
Chris Moller
2018-07-20 19:33:47 UTC
Permalink
Hi, JÃŒrgen,
Hi Chris,
thank you for contributing this. I have added a link on our community page
http://www.gnu.org/software/apl/Community.html.
I believe the function would be even more useful it could create or modify
an APL function in a running workspace rather than writing the
function to a file.
It already does that--even in the current version, once the editor
closes and the system() call that started it returns, the file is read
and fixed back into the workspace.  (I guess I need to make that clearer
in the README.)

But version 2.0 takes it even farther--I fork()/exec() to start the
editor, along with a fork()-ed inotify waitspin that listens for changes
in the working file. When the editor writes to the file, the change is
caught and the function is fixed into the workspace, but the editor
stays open until you explicitly kill it.  The effects of this are that
APL keeps running even while the editor is open--you can real-time run
the function after every save and see if it's doing the right thing--and
you can have any number of editor sessions running simultaneously.  (I
don't know how useful that will be, but it was easy to make happen...) 
All this works even now, but somewhere in all these spawned processes I
seem to be firing off a wild signal and not catching it so it winds up
interrupting the main APL readline loop resulting in either a null input
or a spurious ctrl-d.  I'm working on that now.

--Chris
/// JÃŒrgen
Post by Chris Moller
After battling for decades with the ancient nabla editor, I finally
did something I should have done years ago and write a simple native
function that let's you use emacs or vi from inside an APL session. 
It's not even close to Elias MÃ¥rtenson's cool emacs APL mode--it's
just a quick thing to bring up a friendlier editor.  It's alpha-level
code--if it melts your computer, it's not my fault--and there are a
few things on the TODO list, but I thought I'd put it out there and
get some feedback if anyone's interested.
edif is a GNU APL native function that allows the use of external
editors
from within an APL session.
        edif 'function_name'
This will open an editor, typically vi or emacs, containing the present
definition of the specified function, or, if the function doesn't exist,
a boilerplate function header consisting of the function name. 
After saving
the edited definition and exiting the editor, the function will
appear in
the APL workspace.  While the editor is open, APL is suspended.
edif will look for the environment variable EDIF and will use the string
specified by that variable as the command line to invoke the
chosen editor.
   export EDIF="emacs --geometry=40x20  -background '#ffffcc'
-font 'DejaVu Sans Mono-10'"
will invoke emacs with a fairly small window, a light yellow
background, and
using the DejaVu Sans Mono-10 font.  (That's also the default if no EDIF
variable is found.)
edif has only been tested with emacs and vi.
Future work may also allow edif to edit APL variables and
operators, but no
guarantees I'll ever get around to it.
        'libedif.so' ⎕fx 'edif'
/var/run/user/<uid>/<pid>/<name>.apl
where <uid> is the user's userid, <pid> is the process id of the APL
session, and <name> is the function name.  This allows multiple users
each to have multiple simultaneous APL sessions with workspaces with
identical names.  No locking is done by edif and I've no idea if APL
itself has any protection against a writable workspace being open in
multiple simultaneous sessions, but it opens up the possibility that
you can hose the workspace.  So while, as far as edif is concerned
you can have multiple simultaneous sessions aimed at the same lib0
workspace, you probably shouldn't do it.
Also, I've no idea if Windows or any Linux distribution other than
Fedora has a /var directory, so using this directory may be
non-portable.
So far as I can tell, edif doesn't interfere with Elias MÃ¥rtenson's
emacs APL mode, but I haven't thoroughly tested that.
It's at https://github.com/ChrisMoller/edif
(BTW, "edif" is short for "editor interface.")
Chris Moller
2018-07-29 21:10:07 UTC
Permalink
Hi, JÃŒrgen,

So far as I  can tell, after all the testing I can throw at it, my
editor interface function is ready for the world. Unfortunately, it
needs a small patch to APL itself:

Index: LineInput.cc
===================================================================
--- LineInput.cc        (revision 1054)
+++ LineInput.cc        (working copy)
@@ -966,6 +966,12 @@
 const int b0 = fgetc(stdin);
    if (b0 == EOF)
       {
+       if (errno == EINTR) {
+         clearerr (stdin);
+         CIN.unsetf( std::ios_base::unitbuf );
+         CERR.unsetf( std::ios_base::unitbuf );
+         return UNI_ASCII_CR;
+       }
        if (got_WINCH)
           {
             got_WINCH = false;

The usual state of APL is blocking on the fgetc, waiting for user
keystrokes.  But my new edif2 function fork()s to open editor windows
and when those processes are killed they emit SIGCHLD signals which also
unblock the fgetc, resulting in an invalid unicode being returned.  The
patch catches these signals, clears the error on stdin, and returns a
harmless CR.  Somehow, though, and I don't really understand it, the
signals were causing CIN to block on echoing to the screen.  Unsetting
the unitbuf bit fixes this, though I don't have any idea why.  (I'm
unsetting it on CERR too, just in case, but I don't know if it's really
necessary.)

I've run apl -T and haven't hit  any unexpected failures, so I'm pretty
sure this patch won't break anything, at least under Fedora 28 Linux,
kernel 4.16.13.

--Chris
Post by Chris Moller
Hi, JÃŒrgen,
Hi Chris,
thank you for contributing this. I have added a link on our community page
http://www.gnu.org/software/apl/Community.html.
I believe the function would be even more useful it could create or modify
an APL function in a running workspace rather than writing the
function to a file.
It already does that--even in the current version, once the editor
closes and the system() call that started it returns, the file is read
and fixed back into the workspace.  (I guess I need to make that
clearer in the README.)
But version 2.0 takes it even farther--I fork()/exec() to start the
editor, along with a fork()-ed inotify waitspin that listens for
changes in the working file. When the editor writes to the file, the
change is caught and the function is fixed into the workspace, but the
editor stays open until you explicitly kill it.  The effects of this
are that APL keeps running even while the editor is open--you can
real-time run the function after every save and see if it's doing the
right thing--and you can have any number of editor sessions running
simultaneously.  (I don't know how useful that will be, but it was
easy to make happen...)  All this works even now, but somewhere in all
these spawned processes I seem to be firing off a wild signal and not
catching it so it winds up interrupting the main APL readline loop
resulting in either a null input or a spurious ctrl-d.  I'm working on
that now.
--Chris
/// JÃŒrgen
Post by Chris Moller
After battling for decades with the ancient nabla editor, I finally
did something I should have done years ago and write a simple native
function that let's you use emacs or vi from inside an APL session. 
It's not even close to Elias MÃ¥rtenson's cool emacs APL mode--it's
just a quick thing to bring up a friendlier editor.  It's
alpha-level code--if it melts your computer, it's not my fault--and
there are a few things on the TODO list, but I thought I'd put it
out there and get some feedback if anyone's interested.
edif is a GNU APL native function that allows the use of
external editors
from within an APL session.
        edif 'function_name'
This will open an editor, typically vi or emacs, containing the present
definition of the specified function, or, if the function doesn't exist,
a boilerplate function header consisting of the function name. 
After saving
the edited definition and exiting the editor, the function will
appear in
the APL workspace.  While the editor is open, APL is suspended.
edif will look for the environment variable EDIF and will use the string
specified by that variable as the command line to invoke the
chosen editor.
   export EDIF="emacs --geometry=40x20  -background '#ffffcc'
-font 'DejaVu Sans Mono-10'"
will invoke emacs with a fairly small window, a light yellow
background, and
using the DejaVu Sans Mono-10 font.  (That's also the default if no EDIF
variable is found.)
edif has only been tested with emacs and vi.
Future work may also allow edif to edit APL variables and
operators, but no
guarantees I'll ever get around to it.
        'libedif.so' ⎕fx 'edif'
/var/run/user/<uid>/<pid>/<name>.apl
where <uid> is the user's userid, <pid> is the process id of the APL
session, and <name> is the function name.  This allows multiple users
each to have multiple simultaneous APL sessions with workspaces with
identical names.  No locking is done by edif and I've no idea if APL
itself has any protection against a writable workspace being open in
multiple simultaneous sessions, but it opens up the possibility that
you can hose the workspace.  So while, as far as edif is concerned
you can have multiple simultaneous sessions aimed at the same lib0
workspace, you probably shouldn't do it.
Also, I've no idea if Windows or any Linux distribution other than
Fedora has a /var directory, so using this directory may be
non-portable.
So far as I can tell, edif doesn't interfere with Elias MÃ¥rtenson's
emacs APL mode, but I haven't thoroughly tested that.
It's at https://github.com/ChrisMoller/edif
(BTW, "edif" is short for "editor interface.")
Xiao-Yong Jin
2018-07-30 01:19:47 UTC
Permalink
EINTR could happen in many situations.
The usual resolution for EINTR is to retry whatever system call that failed because of EINTR.
Here, we should call fgetc again.

Best,
Xiao-Yong
Hi, Jürgen,
Index: LineInput.cc
===================================================================
--- LineInput.cc (revision 1054)
+++ LineInput.cc (working copy)
@@ -966,6 +966,12 @@
const int b0 = fgetc(stdin);
if (b0 == EOF)
{
+ if (errno == EINTR) {
+ clearerr (stdin);
+ CIN.unsetf( std::ios_base::unitbuf );
+ CERR.unsetf( std::ios_base::unitbuf );
+ return UNI_ASCII_CR;
+ }
if (got_WINCH)
{
got_WINCH = false;
The usual state of APL is blocking on the fgetc, waiting for user keystrokes. But my new edif2 function fork()s to open editor windows and when those processes are killed they emit SIGCHLD signals which also unblock the fgetc, resulting in an invalid unicode being returned. The patch catches these signals, clears the error on stdin, and returns a harmless CR. Somehow, though, and I don't really understand it, the signals were causing CIN to block on echoing to the screen. Unsetting the unitbuf bit fixes this, though I don't have any idea why. (I'm unsetting it on CERR too, just in case, but I don't know if it's really necessary.)
I've run apl -T and haven't hit any unexpected failures, so I'm pretty sure this patch won't break anything, at least under Fedora 28 Linux, kernel 4.16.13.
--Chris
Hi, Jürgen,
Hi Chris,
thank you for contributing this. I have added a link on our community page
http://www.gnu.org/software/apl/Community.html.
I believe the function would be even more useful it could create or modify
an APL function in a running workspace rather than writing the function to a file.
It already does that--even in the current version, once the editor closes and the system() call that started it returns, the file is read and fixed back into the workspace. (I guess I need to make that clearer in the README.)
But version 2.0 takes it even farther--I fork()/exec() to start the editor, along with a fork()-ed inotify waitspin that listens for changes in the working file. When the editor writes to the file, the change is caught and the function is fixed into the workspace, but the editor stays open until you explicitly kill it. The effects of this are that APL keeps running even while the editor is open--you can real-time run the function after every save and see if it's doing the right thing--and you can have any number of editor sessions running simultaneously. (I don't know how useful that will be, but it was easy to make happen...) All this works even now, but somewhere in all these spawned processes I seem to be firing off a wild signal and not catching it so it winds up interrupting the main APL readline loop resulting in either a null input or a spurious ctrl-d. I'm working on that now.
--Chris
/// Jürgen
After battling for decades with the ancient nabla editor, I finally did something I should have done years ago and write a simple native function that let's you use emacs or vi from inside an APL session. It's not even close to Elias Mårtenson's cool emacs APL mode--it's just a quick thing to bring up a friendlier editor. It's alpha-level code--if it melts your computer, it's not my fault--and there are a few things on the TODO list, but I thought I'd put it out there and get some feedback if anyone's interested.
edif is a GNU APL native function that allows the use of external editors
from within an APL session.
edif 'function_name'
This will open an editor, typically vi or emacs, containing the present
definition of the specified function, or, if the function doesn't exist,
a boilerplate function header consisting of the function name. After saving
the edited definition and exiting the editor, the function will appear in
the APL workspace. While the editor is open, APL is suspended.
edif will look for the environment variable EDIF and will use the string
specified by that variable as the command line to invoke the chosen editor.
export EDIF="emacs --geometry=40x20 -background '#ffffcc' -font 'DejaVu Sans Mono-10'"
will invoke emacs with a fairly small window, a light yellow background, and
using the DejaVu Sans Mono-10 font. (That's also the default if no EDIF
variable is found.)
edif has only been tested with emacs and vi.
Future work may also allow edif to edit APL variables and operators, but no
guarantees I'll ever get around to it.
'libedif.so' ⎕fx 'edif'
/var/run/user/<uid>/<pid>/<name>.apl
where <uid> is the user's userid, <pid> is the process id of the APL
session, and <name> is the function name. This allows multiple users
each to have multiple simultaneous APL sessions with workspaces with
identical names. No locking is done by edif and I've no idea if APL
itself has any protection against a writable workspace being open in
multiple simultaneous sessions, but it opens up the possibility that
you can hose the workspace. So while, as far as edif is concerned
you can have multiple simultaneous sessions aimed at the same lib0
workspace, you probably shouldn't do it.
Also, I've no idea if Windows or any Linux distribution other than
Fedora has a /var directory, so using this directory may be non-portable.
So far as I can tell, edif doesn't interfere with Elias Mårtenson's
emacs APL mode, but I haven't thoroughly tested that.
It's at https://github.com/ChrisMoller/edif
(BTW, "edif" is short for "editor interface.")
Chris Moller
2018-07-30 02:00:20 UTC
Permalink
Ultimately, that's exactly what happens, but "goto again;" didn't work

Though I just thought of something I'll try in the morning...
Post by Xiao-Yong Jin
EINTR could happen in many situations.
The usual resolution for EINTR is to retry whatever system call that failed because of EINTR.
Here, we should call fgetc again.
Best,
Xiao-Yong
Post by Chris Moller
Hi, JÃŒrgen,
Index: LineInput.cc
===================================================================
--- LineInput.cc (revision 1054)
+++ LineInput.cc (working copy)
@@ -966,6 +966,12 @@
const int b0 = fgetc(stdin);
if (b0 == EOF)
{
+ if (errno == EINTR) {
+ clearerr (stdin);
+ CIN.unsetf( std::ios_base::unitbuf );
+ CERR.unsetf( std::ios_base::unitbuf );
+ return UNI_ASCII_CR;
+ }
if (got_WINCH)
{
got_WINCH = false;
The usual state of APL is blocking on the fgetc, waiting for user keystrokes. But my new edif2 function fork()s to open editor windows and when those processes are killed they emit SIGCHLD signals which also unblock the fgetc, resulting in an invalid unicode being returned. The patch catches these signals, clears the error on stdin, and returns a harmless CR. Somehow, though, and I don't really understand it, the signals were causing CIN to block on echoing to the screen. Unsetting the unitbuf bit fixes this, though I don't have any idea why. (I'm unsetting it on CERR too, just in case, but I don't know if it's really necessary.)
I've run apl -T and haven't hit any unexpected failures, so I'm pretty sure this patch won't break anything, at least under Fedora 28 Linux, kernel 4.16.13.
--Chris
Post by Chris Moller
Hi, JÃŒrgen,
Hi Chris,
thank you for contributing this. I have added a link on our community page
http://www.gnu.org/software/apl/Community.html.
I believe the function would be even more useful it could create or modify
an APL function in a running workspace rather than writing the function to a file.
It already does that--even in the current version, once the editor closes and the system() call that started it returns, the file is read and fixed back into the workspace. (I guess I need to make that clearer in the README.)
But version 2.0 takes it even farther--I fork()/exec() to start the editor, along with a fork()-ed inotify waitspin that listens for changes in the working file. When the editor writes to the file, the change is caught and the function is fixed into the workspace, but the editor stays open until you explicitly kill it. The effects of this are that APL keeps running even while the editor is open--you can real-time run the function after every save and see if it's doing the right thing--and you can have any number of editor sessions running simultaneously. (I don't know how useful that will be, but it was easy to make happen...) All this works even now, but somewhere in all these spawned processes I seem to be firing off a wild signal and not catching it so it winds up interrupting the main APL readline loop resulting in either a null input or a spurious ctrl-d. I'm working on that now.
--Chris
/// JÃŒrgen
After battling for decades with the ancient nabla editor, I finally did something I should have done years ago and write a simple native function that let's you use emacs or vi from inside an APL session. It's not even close to Elias MÃ¥rtenson's cool emacs APL mode--it's just a quick thing to bring up a friendlier editor. It's alpha-level code--if it melts your computer, it's not my fault--and there are a few things on the TODO list, but I thought I'd put it out there and get some feedback if anyone's interested.
edif is a GNU APL native function that allows the use of external editors
from within an APL session.
edif 'function_name'
This will open an editor, typically vi or emacs, containing the present
definition of the specified function, or, if the function doesn't exist,
a boilerplate function header consisting of the function name. After saving
the edited definition and exiting the editor, the function will appear in
the APL workspace. While the editor is open, APL is suspended.
edif will look for the environment variable EDIF and will use the string
specified by that variable as the command line to invoke the chosen editor.
export EDIF="emacs --geometry=40x20 -background '#ffffcc' -font 'DejaVu Sans Mono-10'"
will invoke emacs with a fairly small window, a light yellow background, and
using the DejaVu Sans Mono-10 font. (That's also the default if no EDIF
variable is found.)
edif has only been tested with emacs and vi.
Future work may also allow edif to edit APL variables and operators, but no
guarantees I'll ever get around to it.
'libedif.so' ⎕fx 'edif'
/var/run/user/<uid>/<pid>/<name>.apl
where <uid> is the user's userid, <pid> is the process id of the APL
session, and <name> is the function name. This allows multiple users
each to have multiple simultaneous APL sessions with workspaces with
identical names. No locking is done by edif and I've no idea if APL
itself has any protection against a writable workspace being open in
multiple simultaneous sessions, but it opens up the possibility that
you can hose the workspace. So while, as far as edif is concerned
you can have multiple simultaneous sessions aimed at the same lib0
workspace, you probably shouldn't do it.
Also, I've no idea if Windows or any Linux distribution other than
Fedora has a /var directory, so using this directory may be non-portable.
So far as I can tell, edif doesn't interfere with Elias MÃ¥rtenson's
emacs APL mode, but I haven't thoroughly tested that.
It's at https://github.com/ChrisMoller/edif
(BTW, "edif" is short for "editor interface.")
Chris Moller
2018-07-30 13:59:31 UTC
Permalink
Here's an even simpler, more direct, patch:

Index: LineInput.cc
===================================================================
--- LineInput.cc        (revision 1054)
+++ LineInput.cc        (working copy)
@@ -966,6 +966,11 @@
 const int b0 = fgetc(stdin);
    if (b0 == EOF)
       {
+       if (errno == EINTR) {
+         clearerr (stdin);
+         CIN.unsetf( std::ios_base::unitbuf );
+         goto again;
+       }
        if (got_WINCH)
           {
             got_WINCH = false;
Post by Chris Moller
Ultimately, that's exactly what happens, but "goto again;" didn't work
Though I just thought of something I'll try in the morning...
Post by Xiao-Yong Jin
EINTR could happen in many situations.
The usual resolution for EINTR is to retry whatever system call that failed because of EINTR.
Here, we should call fgetc again.
Best,
Xiao-Yong
Post by Chris Moller
Hi, JÃŒrgen,
Juergen Sauermann
2018-07-30 14:52:47 UTC
Permalink
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body text="#000000" bgcolor="#FFFFFF">
<font face="Helvetica, Arial, sans-serif">Hi Chris,<br>
<br>
thanks, done in <b>SVN 1060</b>.<br>
<br>
/// Jürgen<br>
<br>
</font><br>
<div class="moz-cite-prefix">On 07/30/2018 03:59 PM, Chris Moller
wrote:<br>
</div>
<blockquote type="cite"
cite="mid:b7728d88-2d28-2bab-d8c5-***@mollerware.com">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<p><font size="-1">Here's an even simpler, more direct, patch:</font></p>
<blockquote>
<p><tt>Index: LineInput.cc</tt><tt><br>
</tt><tt>===================================================================</tt><tt><br>
</tt><tt>--- LineInput.cc        (revision 1054)</tt><tt><br>
</tt><tt>+++ LineInput.cc        (working copy)</tt><tt><br>
</tt><tt>@@ -966,6 +966,11 @@</tt><tt><br>
</tt><tt> const int b0 = fgetc(stdin);</tt><tt><br>
</tt><tt>    if (b0 == EOF)</tt><tt><br>
</tt><tt>       {</tt><tt><br>
</tt><tt>+       if (errno == EINTR) {</tt><tt><br>
</tt><tt>+         clearerr (stdin);</tt><tt><br>
</tt><tt>+         CIN.unsetf( std::ios_base::unitbuf );</tt><tt><br>
</tt><tt>+         goto again;</tt><tt><br>
</tt><tt>+       }</tt><tt><br>
</tt><tt>        if (got_WINCH)</tt><tt><br>
</tt><tt>           {</tt><tt><br>
</tt><tt>             got_WINCH = false;</tt><br>
</p>
</blockquote>
<br>
<div class="moz-cite-prefix">On 29/07/18 22:00, Chris Moller
wrote:<br>
</div>
<blockquote type="cite"
cite="mid:0d77d857-0ef7-ebfc-ef31-***@mollerware.com">
<meta http-equiv="Content-Type" content="text/html;
charset=utf-8">
<p><font size="-1">Ultimately, that's exactly what happens, but
"goto again;" didn't work</font></p>
<p><font size="-1">Though I just thought of something I'll try
in the morning...</font><br>
</p>
<br>
<div class="moz-cite-prefix">On 29/07/18 21:19, Xiao-Yong Jin
wrote:<br>
</div>
<blockquote type="cite"
cite="mid:534D32CA-3F3B-4D82-89C1-***@gmail.com">
<pre wrap="">EINTR could happen in many situations.
The usual resolution for EINTR is to retry whatever system call that failed because of EINTR.
Here, we should call fgetc again.

Best,
Xiao-Yong </pre> <blockquote type="cite"> <pre wrap="">On Jul 29, 2018, at 4:10 PM, Chris Moller <a class="moz-txt-link-rfc2396E" href="mailto:***@mollerware.com" moz-do-not-send="true">&lt;***@mollerware.com&gt;</a> wrote:

Hi, Jürgen,

So far as I can tell, after all the testing I can throw at it, my editor interface function is ready for the world. Unfortunately, it needs a small patch to APL itself:
</pre>
</blockquote>
</blockquote>
<br>
</blockquote>
<br>
</blockquote>
<br>
</body>
</html>
Chris Moller
2018-07-30 18:52:22 UTC
Permalink
Thanks, JÃŒrgen.

And for anyone interested, my editor interface native function is
available at https://github.com/ChrisMoller/edif.git

Basically, what it does is allow users to invoke external editors from
within APL sessions, i.e., while running APL, you can edit functions
using vi, emacs, gvim, nano, and probably other editors (those are the
ones I've tested) and when the function is saved it will fixed in APL. 
Two versions are included, libedif and libedif2, the former, which I
usually ⎕fx as 'edif', runs in the APL process and defaults to opening
the function in vi.  libedif2, which I usually ⎕fx as 'edif2', spawns
separate processes for the editors (defaulting to emacs) it opens,
allowing the user to go on using APL while the editor is open--including
testing saved functions real-time without having to close the
editor--and allowing any number of edit windows to be open
simultaneously on different functions.

Feedback welcome, and here's the README:





edif is a GNU APL native function that allows the use of external editors
from within an APL session.

Usage:

    edif 'function_name'
    or
    edif2 'function_name'

Both of these will open an editor, typically vi or emacs, containing the
present definition of the specified function, or, if the function doesn't
exist, a boilerplate function header consisting of the function name.
After saving the edited definition and exiting the editor, the function
will appear in the APL workspace..  (In the case of a new function, the
boilerplate name can be edited as necessary:

    fubar

can be edited to

    z←x fubar y

and the right thing will be fixed in APL.  (Even existing functions can be
modified this way.))

The two versions of the function differ in that the first version, edif,
suspends the current APL session until the editor is closed, while the
second version, edif2, opens the editor in a separate process, in a
separate window, while the APL session remains active.  This allows
functions to be edited and tested concurrently without having to go
into and out of the editor.  edif2 also allows multiple editor windows
to be open simultaneously on different functions.

Both versions have a dyadic form:

    'editor' edif 'function_name'
    or
    'editor' edif2 'function_name'

where 'editor' is the editor to be invoked.  For example:

    'vi' edif 'fubar'

would open function fubar using the vi editor.

    'emacs' edif2 'fu'
    'emacs' edif2 'bar'

would open functions fu and bar in separate emacs windows.

edif will look for the environment variable EDIF and will use the string
specified by that variable as the command line to invoke the chosen editor.
For example:

   export EDIF="nano"

will cause edif to default to using the nano editor.  Similarly, the EDIF2
variable affects the default edif2 editor.

edif has been tested with emacs, vi, and nano; edif2 with emacs and gvim.
The default editor for edif is vi; the default for edif2 is

   "emacs --geometry=40x20  -background '#ffffcc' -font 'DejaVu Sans
Mono-10'"

The dyadic form is a one-shot thing--edif doesn't remember editors
specified this way and the monadic form will go back to using the
default or environment-specified editor.

edif may be included in the workspace with:

    'libedif.so' ⎕fx 'edif'

and edif2 with:

    'libedif2.so' ⎕fx 'edif2'

Of course, you can use any function names you like and, as long as you use
different names, both versions can be used at the same time.

So far as I can tell, edif doesn't interfere with Elias MÃ¥rtenson's
emacs APL mode, but I haven't thoroughly tested that.

By the way, "edif" is short for "editor interface."



Implimentation note:

edif and edif2 work by storing an editable version of the specified
function in:

/var/run/user/<uid>/<pid>/<name>.apl

where <uid> is the user's userid, <pid> is the process id of the APL
session, and <name> is the function name.  This allows multiple users
each to have multiple simultaneous APL sessions with workspaces with
identical names.  No locking is done by edif and I've no idea if APL
itself has any protection against a writable workspace being open in
multiple simultaneous sessions, but it opens up the possibility that
you can hose the workspace.  So while, as far as edif is concerned
you can have multiple simultaneous sessions aimed at the same lib0
workspace, you probably shouldn't do it.

Also, I've no idea if Windows or any Linux distribution other than
Fedora has a /var directory, so using this directory may be non-portable.
Hi Chris,
thanks, done in *SVN 1060*.
/// JÃŒrgen
Post by Chris Moller
Index: LineInput.cc
===================================================================
--- LineInput.cc        (revision 1054)
+++ LineInput.cc        (working copy)
@@ -966,6 +966,11 @@
 const int b0 = fgetc(stdin);
    if (b0 == EOF)
       {
+       if (errno == EINTR) {
+         clearerr (stdin);
+         CIN.unsetf( std::ios_base::unitbuf );
+         goto again;
+       }
        if (got_WINCH)
           {
             got_WINCH = false;
Hans-Peter Sorge
2018-08-02 11:12:12 UTC
Permalink
Hello Chris,

thank you for this master piece. The line editing in GNU APL is a bit
cumbersome.

But the apl session gets blocked during editing (edif2).

Currently I have no clue, how to analyze it.

Thank you again.

Hans-Peter
Post by Chris Moller
Thanks, JÃŒrgen.
And for anyone interested, my editor interface native function is
available at https://github.com/ChrisMoller/edif.git
Basically, what it does is allow users to invoke external editors from
within APL sessions, i.e., while running APL, you can edit functions
using vi, emacs, gvim, nano, and probably other editors (those are the
ones I've tested) and when the function is saved it will fixed in
APL.  Two versions are included, libedif and libedif2, the former,
which I usually ⎕fx as 'edif', runs in the APL process and defaults to
opening the function in vi.  libedif2, which I usually ⎕fx as 'edif2',
spawns separate processes for the editors (defaulting to emacs) it
opens, allowing the user to go on using APL while the editor is
open--including testing saved functions real-time without having to
close the editor--and allowing any number of edit windows to be open
simultaneously on different functions. 
edif is a GNU APL native function that allows the use of external editors
from within an APL session.
    edif 'function_name'
    or
    edif2 'function_name'
Both of these will open an editor, typically vi or emacs, containing the
present definition of the specified function, or, if the function doesn't
exist, a boilerplate function header consisting of the function name.
After saving the edited definition and exiting the editor, the function
will appear in the APL workspace..  (In the case of a new function, the
    fubar
can be edited to
    z←x fubar y
and the right thing will be fixed in APL.  (Even existing functions can be
modified this way.))
The two versions of the function differ in that the first version, edif,
suspends the current APL session until the editor is closed, while the
second version, edif2, opens the editor in a separate process, in a
separate window, while the APL session remains active.  This allows
functions to be edited and tested concurrently without having to go
into and out of the editor.  edif2 also allows multiple editor windows
to be open simultaneously on different functions.
    'editor' edif 'function_name'
    or
    'editor' edif2 'function_name'
    'vi' edif 'fubar'
would open function fubar using the vi editor.
    'emacs' edif2 'fu'
    'emacs' edif2 'bar'
would open functions fu and bar in separate emacs windows.
edif will look for the environment variable EDIF and will use the string
specified by that variable as the command line to invoke the chosen editor.
   export EDIF="nano"
will cause edif to default to using the nano editor.  Similarly, the EDIF2
variable affects the default edif2 editor.
edif has been tested with emacs, vi, and nano; edif2 with emacs and gvim.
The default editor for edif is vi; the default for edif2 is
   "emacs --geometry=40x20  -background '#ffffcc' -font 'DejaVu Sans
Mono-10'"
The dyadic form is a one-shot thing--edif doesn't remember editors
specified this way and the monadic form will go back to using the
default or environment-specified editor.
    'libedif.so' ⎕fx 'edif'
   
    'libedif2.so' ⎕fx 'edif2'
Of course, you can use any function names you like and, as long as you use
different names, both versions can be used at the same time.
So far as I can tell, edif doesn't interfere with Elias MÃ¥rtenson's
emacs APL mode, but I haven't thoroughly tested that.
By the way, "edif" is short for "editor interface."
edif and edif2 work by storing an editable version of the specified
/var/run/user/<uid>/<pid>/<name>.apl 
where <uid> is the user's userid, <pid> is the process id of the APL
session, and <name> is the function name.  This allows multiple users
each to have multiple simultaneous APL sessions with workspaces with
identical names.  No locking is done by edif and I've no idea if APL
itself has any protection against a writable workspace being open in
multiple simultaneous sessions, but it opens up the possibility that
you can hose the workspace.  So while, as far as edif is concerned
you can have multiple simultaneous sessions aimed at the same lib0
workspace, you probably shouldn't do it.
Also, I've no idea if Windows or any Linux distribution other than
Fedora has a /var directory, so using this directory may be non-portable.
Hi Chris,
thanks, done in *SVN 1060*.
/// JÃŒrgen
Post by Chris Moller
Index: LineInput.cc
===================================================================
--- LineInput.cc        (revision 1054)
+++ LineInput.cc        (working copy)
@@ -966,6 +966,11 @@
 const int b0 = fgetc(stdin);
    if (b0 == EOF)
       {
+       if (errno == EINTR) {
+         clearerr (stdin);
+         CIN.unsetf( std::ios_base::unitbuf );
+         goto again;
+       }
        if (got_WINCH)
           {
             got_WINCH = false;
Chris Moller
2018-08-02 13:14:09 UTC
Permalink
I thought I'd fixed the echo blocking!

Actually, what seems to be happening is that APL is still running--you
can enter an APL expression, press enter, and the result will show up on
your screen--but keystroke echoing is somehow inhibited.

There was a patch for this JÃŒrgenput in for me that showed up in SVN
1060, but that seems to be not quite right. That patch was an
alternative to a slightly clumsier patch I'd tried earlier, somaybe
reverting to the original patch would help:


Index: LineInput.cc
===================================================================
--- LineInput.cc        (revision 1060)
+++ LineInput.cc        (working copy)
@@ -968,9 +968,10 @@
       {
         if (errno == EINTR)
            {
-             clearerr(stdin);
-             CIN.unsetf(ios_base::unitbuf);
-             goto again;
+            clearerr (stdin);
+            CIN.unsetf( std::ios_base::unitbuf );
+            CERR.unsetf( std::ios_base::unitbuf );
+            return UNI_ASCII_CR;
            }

        if (got_WINCH)

If you could give that a try and let me know if it fixes things in your
environment, I'd appreciate it.


Thanks,

Chris
Post by Hans-Peter Sorge
Hello Chris,
thank you for this master piece. The line editing in GNU APL is a bit
cumbersome.
But the apl session gets blocked during editing (edif2).
Currently I have no clue, how to analyze it.
Thank you again.
Hans-Peter
Post by Chris Moller
Thanks, JÃŒrgen.
And for anyone interested, my editor interface native function is
available at https://github.com/ChrisMoller/edif.git
Basically, what it does is allow users to invoke external editors
from within APL sessions, i.e., while running APL, you can edit
functions using vi, emacs, gvim, nano, and probably other editors
(those are the ones I've tested) and when the function is saved it
will fixed in APL.  Two versions are included, libedif and libedif2,
the former, which I usually ⎕fx as 'edif', runs in the APL process
and defaults to opening the function in vi.  libedif2, which I
usually ⎕fx as 'edif2', spawns separate processes for the editors
(defaulting to emacs) it opens, allowing the user to go on using APL
while the editor is open--including testing saved functions real-time
without having to close the editor--and allowing any number of edit
windows to be open simultaneously on different functions.
edif is a GNU APL native function that allows the use of external editors
from within an APL session.
    edif 'function_name'
    or
    edif2 'function_name'
Both of these will open an editor, typically vi or emacs, containing the
present definition of the specified function, or, if the function doesn't
exist, a boilerplate function header consisting of the function name.
After saving the edited definition and exiting the editor, the function
will appear in the APL workspace..  (In the case of a new function, the
    fubar
can be edited to
    z←x fubar y
and the right thing will be fixed in APL.  (Even existing functions can be
modified this way.))
The two versions of the function differ in that the first version, edif,
suspends the current APL session until the editor is closed, while the
second version, edif2, opens the editor in a separate process, in a
separate window, while the APL session remains active.  This allows
functions to be edited and tested concurrently without having to go
into and out of the editor.  edif2 also allows multiple editor windows
to be open simultaneously on different functions.
    'editor' edif 'function_name'
    or
    'editor' edif2 'function_name'
    'vi' edif 'fubar'
would open function fubar using the vi editor.
    'emacs' edif2 'fu'
    'emacs' edif2 'bar'
would open functions fu and bar in separate emacs windows.
edif will look for the environment variable EDIF and will use the string
specified by that variable as the command line to invoke the chosen editor.
   export EDIF="nano"
will cause edif to default to using the nano editor. Similarly, the EDIF2
variable affects the default edif2 editor.
edif has been tested with emacs, vi, and nano; edif2 with emacs and gvim.
The default editor for edif is vi; the default for edif2 is
   "emacs --geometry=40x20  -background '#ffffcc' -font 'DejaVu Sans
Mono-10'"
The dyadic form is a one-shot thing--edif doesn't remember editors
specified this way and the monadic form will go back to using the
default or environment-specified editor.
    'libedif.so' ⎕fx 'edif'
    'libedif2.so' ⎕fx 'edif2'
Of course, you can use any function names you like and, as long as you use
different names, both versions can be used at the same time.
So far as I can tell, edif doesn't interfere with Elias MÃ¥rtenson's
emacs APL mode, but I haven't thoroughly tested that.
By the way, "edif" is short for "editor interface."
edif and edif2 work by storing an editable version of the specified
/var/run/user/<uid>/<pid>/<name>.apl
where <uid> is the user's userid, <pid> is the process id of the APL
session, and <name> is the function name.  This allows multiple users
each to have multiple simultaneous APL sessions with workspaces with
identical names.  No locking is done by edif and I've no idea if APL
itself has any protection against a writable workspace being open in
multiple simultaneous sessions, but it opens up the possibility that
you can hose the workspace.  So while, as far as edif is concerned
you can have multiple simultaneous sessions aimed at the same lib0
workspace, you probably shouldn't do it.
Also, I've no idea if Windows or any Linux distribution other than
Fedora has a /var directory, so using this directory may be non-portable.
Hi Chris,
thanks, done in *SVN 1060*.
/// JÃŒrgen
Post by Chris Moller
Index: LineInput.cc
===================================================================
--- LineInput.cc        (revision 1054)
+++ LineInput.cc        (working copy)
@@ -966,6 +966,11 @@
 const int b0 = fgetc(stdin);
    if (b0 == EOF)
       {
+       if (errno == EINTR) {
+         clearerr (stdin);
+         CIN.unsetf( std::ios_base::unitbuf );
+         goto again;
+       }
        if (got_WINCH)
           {
             got_WINCH = false;
Juergen Sauermann
2018-08-02 15:40:51 UTC
Permalink
Hi Chris,

I am not entirely happy with your patch, in particular because I cannot
judge which other effects it may have
and which problem it actually solves.

What I can see is that:

You disable automatic flushing when you are waiting for an input
character and get a ^C interrupt or so,

What I do not understand is:

1. according to https://en.cppreference.com/w/cpp/io/manip/unitbuf, the
unitbuf bit
changes only the timing of the output but not the output itself. So it
buys you some
time but is not guaranteed to do that. My concern is that you may
introduce some
unpredictable behaviour into the main input loop of the GNU interpreter.

2. Wouldn't it be cleaner if you save the state of CIN and CERR when you
enter your editor
and restore it when leaving it? Right now the state of CIN and CERR
seems to change after
hitting ^C for the first time.

/// Jürgen
Post by Chris Moller
I thought I'd fixed the echo blocking!
Actually, what seems to be happening is that APL is still running--you
can enter an APL expression, press enter, and the result will show up
on your screen--but keystroke echoing is somehow inhibited.
There was a patch for this Jürgenput in for me that showed up in SVN
1060, but that seems to be not quite right.  That patch was an
alternative to a slightly clumsier patch I'd tried earlier, somaybe
Index: LineInput.cc
===================================================================
--- LineInput.cc        (revision 1060)
+++ LineInput.cc        (working copy)
@@ -968,9 +968,10 @@
       {
         if (errno == EINTR)
            {
-             clearerr(stdin);
-             CIN.unsetf(ios_base::unitbuf);
-             goto again;
+            clearerr (stdin);
+            CIN.unsetf( std::ios_base::unitbuf );
+            CERR.unsetf( std::ios_base::unitbuf );
+            return UNI_ASCII_CR;
            }
 
        if (got_WINCH)
If you could give that a try and let me know if it fixes things in
your environment, I'd appreciate it.
Thanks,
Chris
Post by Hans-Peter Sorge
Hello Chris,
thank you for this master piece. The line editing in GNU APL is a bit
cumbersome.
But the apl session gets blocked during editing (edif2).
Currently I have no clue, how to analyze it.
Thank you again.
Hans-Peter
Thanks, Jürgen.
And for anyone interested, my editor interface native function is
available at https://github.com/ChrisMoller/edif.git
Basically, what it does is allow users to invoke external editors
from within APL sessions, i.e., while running APL, you can edit
functions using vi, emacs, gvim, nano, and probably other editors
(those are the ones I've tested) and when the function is saved it
will fixed in APL.  Two versions are included, libedif and libedif2,
the former, which I usually ⎕fx as 'edif', runs in the APL process
and defaults to opening the function in vi.  libedif2, which I
usually ⎕fx as 'edif2', spawns separate processes for the editors
(defaulting to emacs) it opens, allowing the user to go on using APL
while the editor is open--including testing saved functions
real-time without having to close the editor--and allowing any
number of edit windows to be open simultaneously on different
functions. 
edif is a GNU APL native function that allows the use of external editors
from within an APL session.
    edif 'function_name'
    or
    edif2 'function_name'
Both of these will open an editor, typically vi or emacs, containing the
present definition of the specified function, or, if the function doesn't
exist, a boilerplate function header consisting of the function name.
After saving the edited definition and exiting the editor, the function
will appear in the APL workspace..  (In the case of a new function, the
    fubar
can be edited to
    z←x fubar y
and the right thing will be fixed in APL.  (Even existing functions
can be
modified this way.))
The two versions of the function differ in that the first version, edif,
suspends the current APL session until the editor is closed, while the
second version, edif2, opens the editor in a separate process, in a
separate window, while the APL session remains active.  This allows
functions to be edited and tested concurrently without having to go
into and out of the editor.  edif2 also allows multiple editor windows
to be open simultaneously on different functions.
    'editor' edif 'function_name'
    or
    'editor' edif2 'function_name'
    'vi' edif 'fubar'
would open function fubar using the vi editor.
    'emacs' edif2 'fu'
    'emacs' edif2 'bar'
would open functions fu and bar in separate emacs windows.
edif will look for the environment variable EDIF and will use the string
specified by that variable as the command line to invoke the chosen editor.
   export EDIF="nano"
will cause edif to default to using the nano editor.  Similarly, the
EDIF2
variable affects the default edif2 editor.
edif has been tested with emacs, vi, and nano; edif2 with emacs and gvim.
The default editor for edif is vi; the default for edif2 is
   "emacs --geometry=40x20  -background '#ffffcc' -font 'DejaVu Sans
Mono-10'"
The dyadic form is a one-shot thing--edif doesn't remember editors
specified this way and the monadic form will go back to using the
default or environment-specified editor.
    'libedif.so' ⎕fx 'edif'
   
    'libedif2.so' ⎕fx 'edif2'
Of course, you can use any function names you like and, as long as you use
different names, both versions can be used at the same time.
So far as I can tell, edif doesn't interfere with Elias Mårtenson's
emacs APL mode, but I haven't thoroughly tested that.
By the way, "edif" is short for "editor interface."
edif and edif2 work by storing an editable version of the specified
/var/run/user/<uid>/<pid>/<name>.apl 
where <uid> is the user's userid, <pid> is the process id of the APL
session, and <name> is the function name.  This allows multiple users
each to have multiple simultaneous APL sessions with workspaces with
identical names.  No locking is done by edif and I've no idea if APL
itself has any protection against a writable workspace being open in
multiple simultaneous sessions, but it opens up the possibility that
you can hose the workspace.  So while, as far as edif is concerned
you can have multiple simultaneous sessions aimed at the same lib0
workspace, you probably shouldn't do it.
Also, I've no idea if Windows or any Linux distribution other than
Fedora has a /var directory, so using this directory may be
non-portable.
Hi Chris,
thanks, done in *SVN 1060*.
/// Jürgen
Post by Chris Moller
Index: LineInput.cc
===================================================================
--- LineInput.cc        (revision 1054)
+++ LineInput.cc        (working copy)
@@ -966,6 +966,11 @@
 const int b0 = fgetc(stdin);
    if (b0 == EOF)
       {
+       if (errno == EINTR) {
+         clearerr (stdin);
+         CIN.unsetf( std::ios_base::unitbuf );
+         goto again;
+       }
        if (got_WINCH)
           {
             got_WINCH = false;
Chris Moller
2018-08-02 17:12:56 UTC
Permalink
I agree with you.  I'm not all that pleased with it either, mostly
because I don't understand why it works--it was something suggested by
someone on StackOverflow.

Whatever is going on seems to be the result of the EINTR out of the
fgetc()--I'll try to look more closely at that.  I'll also try your
save-state suggestion.  It seems to be a highly intermittent thing,
which, in combination with fork()/exec()/terminate, possibly suggests a
race condition somewhere.

--Chris
Hi Chris,
I am not entirely happy with your patch, in particular because I cannot
judge which other effects it may have
and which problem it actually solves.
You disable automatic flushing when you are waiting for an input
character and get a ^C interrupt or so,
1. according to https://en.cppreference.com/w/cpp/io/manip/unitbuf, the
unitbuf bit
changes only the timing of the output but not the output itself. So it
buys you some
time but is not guaranteed to do that. My concern is that you may
introduce some
unpredictable behaviour into the main input loop of the GNU interpreter.
2. Wouldn't it be cleaner if you save the state of CIN and CERR when you
enter your editor
and restore it when leaving it? Right now the state of CIN and CERR
seems to change after
hitting ^C for the first time.
/// JÃŒrgen
Post by Chris Moller
I thought I'd fixed the echo blocking!
Actually, what seems to be happening is that APL is still running--you
can enter an APL expression, press enter, and the result will show up
on your screen--but keystroke echoing is somehow inhibited.
There was a patch for this JÃŒrgenput in for me that showed up in SVN
1060, but that seems to be not quite right.  That patch was an
alternative to a slightly clumsier patch I'd tried earlier, somaybe
Index: LineInput.cc
===================================================================
--- LineInput.cc        (revision 1060)
+++ LineInput.cc        (working copy)
@@ -968,9 +968,10 @@
       {
         if (errno == EINTR)
            {
-             clearerr(stdin);
-             CIN.unsetf(ios_base::unitbuf);
-             goto again;
+            clearerr (stdin);
+            CIN.unsetf( std::ios_base::unitbuf );
+            CERR.unsetf( std::ios_base::unitbuf );
+            return UNI_ASCII_CR;
            }
        if (got_WINCH)
If you could give that a try and let me know if it fixes things in
your environment, I'd appreciate it.
Thanks,
Chris
Post by Hans-Peter Sorge
Hello Chris,
thank you for this master piece. The line editing in GNU APL is a bit
cumbersome.
But the apl session gets blocked during editing (edif2).
Currently I have no clue, how to analyze it.
Thank you again.
Hans-Peter
Post by Chris Moller
Thanks, JÃŒrgen.
And for anyone interested, my editor interface native function is
available at https://github.com/ChrisMoller/edif.git
Basically, what it does is allow users to invoke external editors
from within APL sessions, i.e., while running APL, you can edit
functions using vi, emacs, gvim, nano, and probably other editors
(those are the ones I've tested) and when the function is saved it
will fixed in APL.  Two versions are included, libedif and libedif2,
the former, which I usually ⎕fx as 'edif', runs in the APL process
and defaults to opening the function in vi.  libedif2, which I
usually ⎕fx as 'edif2', spawns separate processes for the editors
(defaulting to emacs) it opens, allowing the user to go on using APL
while the editor is open--including testing saved functions
real-time without having to close the editor--and allowing any
number of edit windows to be open simultaneously on different
functions.
edif is a GNU APL native function that allows the use of external editors
from within an APL session.
    edif 'function_name'
    or
    edif2 'function_name'
Both of these will open an editor, typically vi or emacs, containing the
present definition of the specified function, or, if the function doesn't
exist, a boilerplate function header consisting of the function name.
After saving the edited definition and exiting the editor, the function
will appear in the APL workspace..  (In the case of a new function, the
    fubar
can be edited to
    z←x fubar y
and the right thing will be fixed in APL.  (Even existing functions can be
modified this way.))
The two versions of the function differ in that the first version, edif,
suspends the current APL session until the editor is closed, while the
second version, edif2, opens the editor in a separate process, in a
separate window, while the APL session remains active.  This allows
functions to be edited and tested concurrently without having to go
into and out of the editor.  edif2 also allows multiple editor windows
to be open simultaneously on different functions.
    'editor' edif 'function_name'
    or
    'editor' edif2 'function_name'
    'vi' edif 'fubar'
would open function fubar using the vi editor.
    'emacs' edif2 'fu'
    'emacs' edif2 'bar'
would open functions fu and bar in separate emacs windows.
edif will look for the environment variable EDIF and will use the string
specified by that variable as the command line to invoke the chosen editor.
   export EDIF="nano"
will cause edif to default to using the nano editor.  Similarly, the EDIF2
variable affects the default edif2 editor.
edif has been tested with emacs, vi, and nano; edif2 with emacs and gvim.
The default editor for edif is vi; the default for edif2 is
   "emacs --geometry=40x20  -background '#ffffcc' -font 'DejaVu Sans
Mono-10'"
The dyadic form is a one-shot thing--edif doesn't remember editors
specified this way and the monadic form will go back to using the
default or environment-specified editor.
    'libedif.so' ⎕fx 'edif'
    'libedif2.so' ⎕fx 'edif2'
Of course, you can use any function names you like and, as long as you use
different names, both versions can be used at the same time.
So far as I can tell, edif doesn't interfere with Elias MÃ¥rtenson's
emacs APL mode, but I haven't thoroughly tested that.
By the way, "edif" is short for "editor interface."
edif and edif2 work by storing an editable version of the specified
/var/run/user/<uid>/<pid>/<name>.apl
where <uid> is the user's userid, <pid> is the process id of the APL
session, and <name> is the function name.  This allows multiple users
each to have multiple simultaneous APL sessions with workspaces with
identical names.  No locking is done by edif and I've no idea if APL
itself has any protection against a writable workspace being open in
multiple simultaneous sessions, but it opens up the possibility that
you can hose the workspace.  So while, as far as edif is concerned
you can have multiple simultaneous sessions aimed at the same lib0
workspace, you probably shouldn't do it.
Also, I've no idea if Windows or any Linux distribution other than
Fedora has a /var directory, so using this directory may be
non-portable.
Hi Chris,
thanks, done in *SVN 1060*.
/// JÃŒrgen
Post by Chris Moller
Index: LineInput.cc
===================================================================
--- LineInput.cc        (revision 1054)
+++ LineInput.cc        (working copy)
@@ -966,6 +966,11 @@
 const int b0 = fgetc(stdin);
    if (b0 == EOF)
       {
+       if (errno == EINTR) {
+         clearerr (stdin);
+         CIN.unsetf( std::ios_base::unitbuf );
+         goto again;
+       }
        if (got_WINCH)
           {
             got_WINCH = false;
Chris Moller
2018-08-03 20:34:11 UTC
Permalink
Hi, JÃŒrgen,

Just to keep you updated, what seems to be happening is that after a few rounds opening and closing external editor processes, the

CIN << uni;

in LineEditContext::insert_char(Unicode uni) isn't getting the character to the screen. I still haven't figured out why, but I'm still hacking at it. It doesn't appear to be directly related to the EINTR patch in LineInput::get_uni(), though at least stdin has to be cleared when errno == EINTR.

-- Chris
Post by Chris Moller
I agree with you.  I'm not all that pleased with it either, mostly
because I don't understand why it works--it was something suggested by
someone on StackOverflow.
Whatever is going on seems to be the result of the EINTR out of the
fgetc()--I'll try to look more closely at that.  I'll also try your
save-state suggestion.  It seems to be a highly intermittent thing,
which, in combination with fork()/exec()/terminate, possibly suggests
a race condition somewhere.
--Chris
Chris Moller
2018-08-07 17:01:18 UTC
Permalink
Hi, JÃŒrgen,


I finally got lucky using strace--using it affected the timing so much
that at first I couldn't reproduce the failure under strace, but finally
got it.  What was happening was that once in a rare while, an IPC
message queue in edif2 popped a signal while a character was being
written to the screen by CIN, resulting in a ERESTARTSYS.  I don't know
if that resulted in an EINTR after the first fgetc() in
LineInput::get_uni(), but it doesn't matter--LineInput::get_uni() has no
way to retry the CIN write. What does cause a retry is setting
SA_RESTART in my signal handlers.  So far as I can tell, that fixes the
problem.

LineInput.cc needs one more tiny patch to remove an unnecessary step:

Index: LineInput.cc
===================================================================
--- LineInput.cc        (revision 1061)
+++ LineInput.cc        (working copy)
@@ -969,7 +969,6 @@
         if (errno == EINTR)
            {
              clearerr(stdin);
-             CIN.unsetf(ios_base::unitbuf);
              goto again;
            }

In addition to that first fgetc() in LineInput::get_uni(), there are two
more.  So far as I know, edif2 hasn't caused any signal problems with
those fgetc()s, but it's not impossible.  It might be worthwhile putting
in some code to catch EOF/EINTR conditions on them too.

--Chris
Post by Chris Moller
Hi, JÃŒrgen,
Just to keep you updated, what seems to be happening is that after a few rounds opening and closing external editor processes, the
CIN << uni;
in LineEditContext::insert_char(Unicode uni) isn't getting the character to the screen. I still haven't figured out why, but I'm still hacking at it. It doesn't appear to be directly related to the EINTR patch in LineInput::get_uni(), though at least stdin has to be cleared when errno == EINTR.
-- Chris
Post by Chris Moller
I agree with you.  I'm not all that pleased with it either, mostly
because I don't understand why it works--it was something suggested
by someone on StackOverflow.
Whatever is going on seems to be the result of the EINTR out of the
fgetc()--I'll try to look more closely at that.  I'll also try your
save-state suggestion. It seems to be a highly intermittent thing,
which, in combination with fork()/exec()/terminate, possibly suggests
a race condition somewhere.
--Chris
Chris Moller
2018-08-07 17:09:16 UTC
Permalink
Hans-Peter,

If you want to try it again, I'm pretty sure I've fixed that bug in
edif2--I just committed the update to https://github.com/ChrisMoller/edif

--Chris
Post by Hans-Peter Sorge
Hello Chris,
thank you for this master piece. The line editing in GNU APL is a bit
cumbersome.
But the apl session gets blocked during editing (edif2).
Currently I have no clue, how to analyze it.
Thank you again.
Hans-Peter
Hans-Peter Sorge
2018-08-07 20:22:19 UTC
Permalink
Hello Chris,

thank you (Really  a  lot:-). Works like a charm.

Feels like OS/2-times :_))

Greetings

Hans-Peter
Post by Chris Moller
Hans-Peter,
If you want to try it again, I'm pretty sure I've fixed that bug in
edif2--I just committed the update to https://github.com/ChrisMoller/edif
--Chris
Post by Hans-Peter Sorge
Hello Chris,
thank you for this master piece. The line editing in GNU APL is a bit
cumbersome.
But the apl session gets blocked during editing (edif2).
Currently I have no clue, how to analyze it.
Thank you again.
Hans-Peter
Chris Moller
2018-08-07 21:35:02 UTC
Permalink
OS/2?  Now /that/ was a lot of years ago... :-)
Post by Hans-Peter Sorge
Hello Chris,
thank you (Really  a  lot:-). Works like a charm.
Feels like OS/2-times :_))
Greetings
Hans-Peter
Post by Chris Moller
Hans-Peter,
If you want to try it again, I'm pretty sure I've fixed that bug in
edif2--I just committed the update to https://github.com/ChrisMoller/edif
--Chris
Post by Hans-Peter Sorge
Hello Chris,
thank you for this master piece. The line editing in GNU APL is a bit
cumbersome.
But the apl session gets blocked during editing (edif2).
Currently I have no clue, how to analyze it.
Thank you again.
Hans-Peter
Juergen Sauermann
2018-08-10 13:11:10 UTC
Permalink
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body text="#000000" bgcolor="#FFFFFF">
<font face="Helvetica, Arial, sans-serif">Hi Chris,<br>
<br>
does that mean that I can revert the patch that I have put in for
edif recently?<br>
<br>
Best Regards,<br>
/// Jürgen<br>
<br>
</font><br>
<div class="moz-cite-prefix">On 08/07/2018 07:09 PM, Chris Moller
wrote:<br>
</div>
<blockquote type="cite"
cite="mid:c938d3d5-27a5-b5d1-d80d-***@mollerware.com">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<p>Hans-Peter,</p>
<p>If you want to try it again, I'm pretty sure I've fixed that
bug in edif2--I just committed the update to <a
class="moz-txt-link-freetext"
href="https://github.com/ChrisMoller/edif"
moz-do-not-send="true">https://github.com/ChrisMoller/edif</a><br>
</p>
<p>--Chris<br>
</p>
<br>
<div class="moz-cite-prefix">On 02/08/18 07:12, Hans-Peter Sorge
wrote:<br>
</div>
<blockquote type="cite"
cite="mid:2783228c-e578-b612-f538-***@netscape.net">
<meta http-equiv="Content-Type" content="text/html;
charset=utf-8">
<p>Hello Chris, <br>
</p>
<p>thank you for this master piece. The line editing in GNU APL
is a bit cumbersome. <br>
</p>
<p>But the apl session gets blocked during editing (edif2).</p>
<p>Currently I have no clue, how to analyze it.<br>
</p>
<p>Thank you again.</p>
<p>Hans-Peter<br>
</p>
<br>
</blockquote>
<br>
</blockquote>
<br>
</body>
</html>
Chris Moller
2018-08-10 13:35:23 UTC
Permalink
I'm not sure how much the reversion would revert.  If it was the patch I
sent you on 2 August:

Index: LineInput.cc
===================================================================
--- LineInput.cc        (revision 1060)
+++ LineInput.cc        (working copy)
@@ -968,9 +968,10 @@
       {
         if (errno == EINTR)
            {
-             clearerr(stdin);
-             CIN.unsetf(ios_base::unitbuf);
-             goto again;
+            clearerr (stdin);
+            CIN.unsetf( std::ios_base::unitbuf );
+            CERR.unsetf( std::ios_base::unitbuf );
+            return UNI_ASCII_CR;
            }

I think it's still a good idea to catch EINTR just to avoid having nulls
returned:


Index: LineInput.cc
===================================================================
--- LineInput.cc        (revision 1061)
+++ LineInput.cc        (working copy)
@@ -969,7 +969,6 @@
         if (errno == EINTR)
            {
              clearerr(stdin);
-             CIN.unsetf(ios_base::unitbuf);
              goto again;
            }


I.e., getting rid of the CIN.unsetf(ios_base::unitbuf), making the code
look like:


const int b0 = fgetc(stdin);
   if (b0 == EOF)
      {
        if (errno == EINTR)
           {
             clearerr(stdin);
             goto again;
           }

       if (got_WINCH)



Thanks,

Chris
Hi Chris,
does that mean that I can revert the patch that I have put in for edif
recently?
Best Regards,
/// JÃŒrgen
Post by Chris Moller
Hans-Peter,
If you want to try it again, I'm pretty sure I've fixed that bug in
edif2--I just committed the update to https://github.com/ChrisMoller/edif
--Chris
Post by Hans-Peter Sorge
Hello Chris,
thank you for this master piece. The line editing in GNU APL is a
bit cumbersome.
But the apl session gets blocked during editing (edif2).
Currently I have no clue, how to analyze it.
Thank you again.
Hans-Peter
Juergen Sauermann
2018-08-11 15:00:39 UTC
Permalink
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body text="#000000" bgcolor="#FFFFFF">
<font face="Helvetica, Arial, sans-serif">Hi Chris,<br>
<br>
it would remove the <b>clearerr() </b>and <b>unsetf()</b>
calls.<br>
<b>clearerr()</b> has probably no effect at all because the next <b>fgetc()</b><br>
will do the same. And <b>CIN.unsetf(ios_base::unitbuf)</b> - if
at all needed -<br>
should go to a different place.<br>
<br>
The new code would be this:<br>
<br>
<font face="Courier New, Courier, monospace"><b>//-----------------------------------------------------------------------------</b><b><br>
</b><b>Unicode</b><b><br>
</b><b>LineInput::get_uni()</b><b><br>
</b><b>{</b><b><br>
</b><b>again:</b><b><br>
</b><b><br>
</b><b>const int b0 = fgetc(stdin);</b><b><br>
</b><b>   if (b0 == EOF)</b><b><br>
</b><b>      {</b><b><br>
</b><b>        if (errno == EINTR)   goto again;<br>
      }<br>
</b><b></b><b><br>
</b><b>   ...</b></font><br>
<br>
Could you please check if your editor still works with that?<br>
<br>
I also noticed another <b>fgetc() </b>below the one shown above.
I suppose that<br>
I should check for EINTR .in that one as well.<br>
<br>
Best Regards,<br>
/// Jürgen<br>
<br>
<br>
</font><br>
<div class="moz-cite-prefix">On 08/10/2018 03:35 PM, Chris Moller
wrote:<br>
</div>
<blockquote type="cite"
cite="mid:ad71630b-ea90-15fb-ed42-***@mollerware.com">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<p><font size="-1">I'm not sure how much the reversion would
revert.  If it was the patch I sent you on 2 August:</font></p>
<p><font size="-1"><tt>Index: LineInput.cc</tt></font><br>
<font size="-1"><tt>===================================================================</tt></font><br>
<font size="-1"><tt>--- LineInput.cc        (revision 1060)</tt></font><br>
<font size="-1"><tt>+++ LineInput.cc        (working copy)</tt></font><br>
<font size="-1"><tt>@@ -968,9 +968,10 @@</tt></font><br>
<font size="-1"><tt>       {</tt></font><br>
<font size="-1"><tt>         if (errno == EINTR)</tt></font><br>
<font size="-1"><tt>            {</tt></font><br>
<font size="-1"><tt>-             clearerr(stdin);</tt></font><br>
<font size="-1"><tt>-             CIN.unsetf(ios_base::unitbuf);</tt></font><br>
<font size="-1"><tt>-             goto again;</tt></font><br>
<font size="-1"><tt>+            clearerr (stdin);</tt></font><br>
<font size="-1"><tt>+            CIN.unsetf(
std::ios_base::unitbuf );</tt></font><br>
<font size="-1"><tt>+            CERR.unsetf(
std::ios_base::unitbuf );</tt></font><br>
<font size="-1"><tt>+            return UNI_ASCII_CR;</tt></font><br>
<font size="-1"><tt>            }</tt></font><br>
  <font size="-1"><tt><br>
</tt></font></p>
<p><font size="-1"><tt>I think it's still a good idea to catch
EINTR just to avoid having nulls returned:</tt></font></p>
<p><font size="-1"><tt><br>
</tt></font></p>
<p><font size="-1"><tt>Index: LineInput.cc<br>
===================================================================<br>
--- LineInput.cc        (revision 1061)<br>
+++ LineInput.cc        (working copy)<br>
@@ -969,7 +969,6 @@<br>
         if (errno == EINTR)<br>
            {<br>
              clearerr(stdin);<br>
-             CIN.unsetf(ios_base::unitbuf);<br>
              goto again;<br>
            }</tt></font></p>
<p><font size="-1"><tt><br>
</tt></font></p>
<p><font size="-1"><tt>I.e., getting rid of the </tt></font><font
size="-1"><tt><font size="-1"><tt>CIN.unsetf(ios_base::unitbuf),
making the code look like:</tt></font></tt></font></p>
<p><font size="-1"><tt><font size="-1"><tt><br>
</tt></font></tt></font></p>
<p><font size="-1"><tt><font size="-1"><tt>const int b0 =
fgetc(stdin);<br>
   if (b0 == EOF)<br>
      {<br>
        if (errno == EINTR)<br>
           {<br>
             clearerr(stdin);<br>
             goto again;<br>
           }<br>
<br>
       if (got_WINCH)<br>
</tt></font></tt></font></p>
<p><font size="-1"><tt><font size="-1"><tt><br>
<br>
</tt></font></tt></font></p>
<p><font size="-1"><tt><font size="-1"><tt>Thanks,</tt></font></tt></font></p>
<p><font size="-1"><tt><font size="-1"><tt>Chris<br>
</tt></font></tt></font></p>
<br>
<div class="moz-cite-prefix">On 10/08/18 09:11, Juergen Sauermann
wrote:<br>
</div>
<blockquote type="cite"
cite="mid:ce108859-b4d0-2544-b0dd-***@t-online.de">
<meta http-equiv="Content-Type" content="text/html;
charset=utf-8">
<font face="Helvetica, Arial, sans-serif">Hi Chris,<br>
<br>
does that mean that I can revert the patch that I have put in
for edif recently?<br>
<br>
Best Regards,<br>
/// Jürgen<br>
<br>
</font><br>
<div class="moz-cite-prefix">On 08/07/2018 07:09 PM, Chris
Moller wrote:<br>
</div>
<blockquote type="cite"
cite="mid:c938d3d5-27a5-b5d1-d80d-***@mollerware.com">
<meta http-equiv="Content-Type" content="text/html;
charset=utf-8">
<p>Hans-Peter,</p>
<p>If you want to try it again, I'm pretty sure I've fixed
that bug in edif2--I just committed the update to <a
class="moz-txt-link-freetext"
href="https://github.com/ChrisMoller/edif"
moz-do-not-send="true">https://github.com/ChrisMoller/edif</a><br>
</p>
<p>--Chris<br>
</p>
<br>
<div class="moz-cite-prefix">On 02/08/18 07:12, Hans-Peter
Sorge wrote:<br>
</div>
<blockquote type="cite"
cite="mid:2783228c-e578-b612-f538-***@netscape.net">
<meta http-equiv="Content-Type" content="text/html;
charset=utf-8">
<p>Hello Chris, <br>
</p>
<p>thank you for this master piece. The line editing in GNU
APL is a bit cumbersome. <br>
</p>
<p>But the apl session gets blocked during editing (edif2).</p>
<p>Currently I have no clue, how to analyze it.<br>
</p>
<p>Thank you again.</p>
<p>Hans-Peter<br>
</p>
<br>
</blockquote>
<br>
</blockquote>
<br>
</blockquote>
<br>
</blockquote>
<br>
</body>
</html>
Chris Moller
2018-08-11 16:02:52 UTC
Permalink
Hi, JÃŒrgen,

Yes, it works fine with just goto agin.

--Chris
Hi Chris,
it would remove the *clearerr() *and *unsetf()* calls.
*clearerr()* has probably no effect at all because the next *fgetc()*
will do the same. And *CIN.unsetf(ios_base::unitbuf)* - if at all needed -
should go to a different place.
*//-----------------------------------------------------------------------------**
**Unicode**
**LineInput::get_uni()**
**{**
**again:**
**
**const int b0 = fgetc(stdin);**
**   if (b0 == EOF)**
**      {**
**        if (errno == EINTR)   goto again;
      }
**
**   ...*
Could you please check if your editor still works with that?
I also noticed another *fgetc() *below the one shown above. I suppose that
I should check for EINTR .in that one as well.
Best Regards,
/// JÃŒrgen
Post by Chris Moller
I'm not sure how much the reversion would revert.  If it was the
Index: LineInput.cc
===================================================================
--- LineInput.cc        (revision 1060)
+++ LineInput.cc        (working copy)
@@ -968,9 +968,10 @@
       {
         if (errno == EINTR)
            {
-             clearerr(stdin);
- CIN.unsetf(ios_base::unitbuf);
-             goto again;
+            clearerr (stdin);
+            CIN.unsetf( std::ios_base::unitbuf );
+            CERR.unsetf( std::ios_base::unitbuf );
+            return UNI_ASCII_CR;
            }
I think it's still a good idea to catch EINTR just to avoid having
Index: LineInput.cc
===================================================================
--- LineInput.cc        (revision 1061)
+++ LineInput.cc        (working copy)
@@ -969,7 +969,6 @@
         if (errno == EINTR)
            {
              clearerr(stdin);
-             CIN.unsetf(ios_base::unitbuf);
              goto again;
            }
I.e., getting rid of the CIN.unsetf(ios_base::unitbuf), making the
const int b0 = fgetc(stdin);
   if (b0 == EOF)
      {
        if (errno == EINTR)
           {
             clearerr(stdin);
             goto again;
           }
       if (got_WINCH)
Thanks,
Chris
Hi Chris,
does that mean that I can revert the patch that I have put in for
edif recently?
Best Regards,
/// JÃŒrgen
Post by Chris Moller
Hans-Peter,
If you want to try it again, I'm pretty sure I've fixed that bug in
edif2--I just committed the update to
https://github.com/ChrisMoller/edif
--Chris
Post by Hans-Peter Sorge
Hello Chris,
thank you for this master piece. The line editing in GNU APL is a
bit cumbersome.
But the apl session gets blocked during editing (edif2).
Currently I have no clue, how to analyze it.
Thank you again.
Hans-Peter
Chris Moller
2018-08-11 16:12:24 UTC
Permalink
PS, the unitbuf thing was just the result of some bad advice I got when
asking around about the way C++ handles streams--the last time I  used
C++ for anything significant was in about 1990 and I've forgotten just
about everything I knew about it from back then.  Just about everything
I do these days is in boring old C.

So, yeah, I think it's safe to say that any and all references to
unitbuf should go in a different place: the bit bucket.

--CM
Hi Chris,
it would remove the *clearerr() *and *unsetf()* calls.
*clearerr()* has probably no effect at all because the next *fgetc()*
will do the same. And *CIN.unsetf(ios_base::unitbuf)* - if at all needed -
should go to a different place.
*//-----------------------------------------------------------------------------**
**Unicode**
**LineInput::get_uni()**
**{**
**again:**
**
**const int b0 = fgetc(stdin);**
**   if (b0 == EOF)**
**      {**
**        if (errno == EINTR)   goto again;
      }
**
**   ...*
Could you please check if your editor still works with that?
I also noticed another *fgetc() *below the one shown above. I suppose that
I should check for EINTR .in that one as well.
Best Regards,
/// JÃŒrgen
Post by Chris Moller
I'm not sure how much the reversion would revert.  If it was the
Index: LineInput.cc
===================================================================
--- LineInput.cc        (revision 1060)
+++ LineInput.cc        (working copy)
@@ -968,9 +968,10 @@
       {
         if (errno == EINTR)
            {
-             clearerr(stdin);
- CIN.unsetf(ios_base::unitbuf);
-             goto again;
+            clearerr (stdin);
+            CIN.unsetf( std::ios_base::unitbuf );
+            CERR.unsetf( std::ios_base::unitbuf );
+            return UNI_ASCII_CR;
            }
I think it's still a good idea to catch EINTR just to avoid having
Index: LineInput.cc
===================================================================
--- LineInput.cc        (revision 1061)
+++ LineInput.cc        (working copy)
@@ -969,7 +969,6 @@
         if (errno == EINTR)
            {
              clearerr(stdin);
-             CIN.unsetf(ios_base::unitbuf);
              goto again;
            }
I.e., getting rid of the CIN.unsetf(ios_base::unitbuf), making the
const int b0 = fgetc(stdin);
   if (b0 == EOF)
      {
        if (errno == EINTR)
           {
             clearerr(stdin);
             goto again;
           }
       if (got_WINCH)
Thanks,
Chris
Hi Chris,
does that mean that I can revert the patch that I have put in for
edif recently?
Best Regards,
/// JÃŒrgen
Post by Chris Moller
Hans-Peter,
If you want to try it again, I'm pretty sure I've fixed that bug in
edif2--I just committed the update to
https://github.com/ChrisMoller/edif
--Chris
Post by Hans-Peter Sorge
Hello Chris,
thank you for this master piece. The line editing in GNU APL is a
bit cumbersome.
But the apl session gets blocked during editing (edif2).
Currently I have no clue, how to analyze it.
Thank you again.
Hans-Peter
Loading...