Skip to content

Commit

Permalink
[v1.1] emacs ^X^E, vi v: avoid executing if command line not saved
Browse files Browse the repository at this point in the history
@pghvlaans reports:
> According to 'The New KornShell', the full editor history editing
> commands are only meant to execute command lines that have had
> saved changes:
>
> "The command is the ksh line that you were editing with the vi
> built-in editor if you omit n, or command n in the history file.
> When you exit the vi program, ksh displays and executes the
> command if you have changed it. Version: With some early releases
> of the 11/16/88 version of ksh, the file was executed even if you
> had not changed it." (Bolsky & Korn, pg. 116)
>
> There is no other evidence that this functionality was ever part
> of release ksh93, however. Neither bash nor any existing open
> source ksh88 derivative behaves in this manner. Nevertheless,
> some distributions of ksh88 (such as the one shipped with
> UnixWare 7) did attempt to avoid running unchanged command lines
> using timestamps.

POSIX does not allow this behaviour for the fc command, but says
nothing about the emacs ^X^E and vi v editor commands. I have
concluded from the resulting discussion is that it is best to make
the timestamp check on the temporary file subject to a new option
to the fc/hist command, let's say -E. The emacs and vi commands can
then invoke fc/hist with that new option.

src/cmd/ksh93/bltins/hist.c,
src/cmd/ksh93/data/builtins.c:
- Add new -E option to fc/hist, remembered by the checktime flag.
- When invoking the editor and checktime is set, use the libast
  tv(3) library to get the temporary file's timestamp before and
  after editing (with nanosecond granularity where available), and
  flag up an error if the timestamp has not changed. This has the
  effect of not executing the command line if a user quits the
  editor without saving.

src/cmd/ksh93/data/msg.c:
- Change e_runvi, the command used by ed_fulledit() (called by ^X^E
  in emacs and v in vi) to invoke a fullscreen editor, to invoke
  'fc' with the new -E option.
  - 'fc' is the same as 'hist' but is shorter and standard. :)
  - Add a 'command' prefix to bypass a possible fc shell function.

src/cmd/ksh93/sh.1:
- Document the changes.
- Remove mention of the specific shell command executed by the
  emacs and vi editor commands; that's an internal implementation
  detail.

Resolves: ksh93#748
  • Loading branch information
McDutchie committed Dec 24, 2024
1 parent 9b64328 commit bb83575
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 18 deletions.
17 changes: 17 additions & 0 deletions ANNOUNCE
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ New command line editor features:
- In the emacs line editor, pressing ^U (kill) twice no longer causes further
^U presses to start a new line (this was a feature for paper terminals).

- The ^X^E (emacs mode) and v (vi mode) commands will now only execute the
command line that was loaded into the editor if the temporary file is
saved before exiting the editor. This removes the need to empty the file
and save just to cancel execution.

New shell language features:

- The appending redirection operator &>>FILE is now available. It is a
Expand Down Expand Up @@ -44,6 +49,18 @@ New features in built-in commands:
command given that was not found on PATH, and return a non-zero exit
status if any of the commands given were not found.

- The 'fc'/'hist' command has a new -E option. If given and a full-screen
editor is launched, the command line that was loaded into the editor will
only be executed if the temporary file is saved before exiting the editor.
This removes the need to empty the file and save just to cancel execution.
People who want the new behaviour as a default for the fc/hist command
where available (i.e., for ksh 93u+m/1.1 and later) can add the following
to their ~/.kshrc or other profile script:
case ${KSH_VERSION-} in
*93u+m/1.0.*) ;;
*93u+m/*) alias fc='fc -E' hist='fc -E' ;;
esac

New features in shell options:

- A new --arrowkeysearch option, on by default, causes the up and down arrow
Expand Down
10 changes: 10 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@ This documents significant changes in the dev branch of ksh 93u+m.
For full details, see the git log at: https://github.com/ksh93/ksh
Uppercase BUG_* IDs are shell bug IDs as used by the Modernish shell library.

2024-12-24:

- [v1.1] The fc/hist command has a new -E option. If this option is given,
the command line that was loaded into the editor will only be executed if
the temp file is saved before exiting the editor.

- [v1.1] The ^X^E (emacs mode) and v (vi mode) commands will now only
execute the command line that was loaded into the full-screen editor if
the temp file is saved before exiting the editor.

2024-12-22:

- In the emacs/gmacs line editor, the ESC [ <letter> macro feature, which is
Expand Down
1 change: 1 addition & 0 deletions src/cmd/ksh93/Mamfile
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,7 @@ make install virtual
prev include/io.h
prev include/variables.h
prev %{INCLUDE_AST}/error.h
prev %{INCLUDE_AST}/tv.h
prev %{INCLUDE_AST}/ls.h
prev include/defs.h
prev shopt.h
Expand Down
21 changes: 20 additions & 1 deletion src/cmd/ksh93/bltins/hist.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "shopt.h"
#include "defs.h"
#include <ls.h>
#include <tv.h>
#include <error.h>
#include "variables.h"
#include "io.h"
Expand Down Expand Up @@ -52,6 +53,7 @@ int b_hist(int argc,char *argv[], Shbltin_t *context)
#if SHOPT_HISTEXPAND
int pflag = 0;
#endif
int checktime = 0;
Histloc_t location;
NOT_USED(argc);
NOT_USED(context);
Expand All @@ -63,6 +65,9 @@ int b_hist(int argc,char *argv[], Shbltin_t *context)
hp = sh.hist_ptr;
while((flag = optget(argv,sh_opthist))) switch(flag)
{
case 'E':
checktime = 1;
break;
case 'e':
edit = opt_info.arg;
break;
Expand Down Expand Up @@ -246,11 +251,25 @@ int b_hist(int argc,char *argv[], Shbltin_t *context)
}
if(*arg != '-')
{
int e = 0; /* error flag */
struct stat statb;
Tv_t before, after;
char *com[3];
com[0] = arg;
com[1] = fname;
com[2] = 0;
error_info.errors = sh_eval(sh_sfeval(com),0);
if (checktime && !(e = stat(fname,&statb)<0))
tvgetmtime(&before,&statb);
/* invoke the editor */
if (!e)
e = sh_eval(sh_sfeval(com),0);
if (checktime && !e && !(e = stat(fname,&statb)<0))
{
/* if the file's timestamp hasn't changed, treat this as an error */
tvgetmtime(&after,&statb);
e = before.tv_sec==after.tv_sec && before.tv_nsec==after.tv_nsec;
}
error_info.errors = e;
}
fdo = sh_chkopen(fname);
unlink(fname);
Expand Down
4 changes: 3 additions & 1 deletion src/cmd/ksh93/data/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -1017,7 +1017,7 @@ const char sh_opthash[] =

#if !SHOPT_SCRIPTONLY
const char sh_opthist[] =
"[-1cn?\n@(#)$Id: hist (AT&T Research) 2000-04-02 $\n]"
"[-1cn?\n@(#)$Id: hist (ksh 93u+m) 2024-12-23 $\n]"
"[--catalog?" SH_DICT "]"
"[+NAME?\f?\f - process command history list]"
"[+DESCRIPTION?\b\f?\f\b lists, edits, or re-executes, commands "
Expand Down Expand Up @@ -1055,6 +1055,8 @@ const char sh_opthist[] =
"[+?If no editor is specified, then the editor specified by the \bHISTEDIT\b "
"variable will be used if set, or the \bFCEDIT\b variable will be "
"used if set, otherwise, \bed\b will be used.]"
"[E?Only execute the edited command line if the file is saved before "
"exiting the editor.]"
"[e]:[editor?\aeditor\a specifies the editor to use to edit the history "
"command. A value of \b-\b for \aeditor\a is equivalent to "
"specifying the \b-s\b option.]"
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/ksh93/data/msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

/* error messages */
const char e_timewarn[] = "\r\n\ashell will timeout in 60 seconds due to inactivity";
const char e_runvi[] = "\\hist -e \"${VISUAL:-${EDITOR:-vi}}\" ";
const char e_runvi[] = "\\command fc -Ee\"${VISUAL:-${EDITOR:-vi}}\" ";
const char e_timeout[] = "timed out waiting for input";
const char e_mailmsg[] = "you have mail in $_";
const char e_query[] = "no query process";
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/ksh93/include/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#include <ast_release.h>
#include "git.h"

#define SH_RELEASE_DATE "2024-12-22" /* must be in this format for $((.sh.version)) */
#define SH_RELEASE_DATE "2024-12-24" /* must be in this format for $((.sh.version)) */
/*
* This comment keeps SH_RELEASE_DATE a few lines away from SH_RELEASE_SVER to avoid
* merge conflicts when cherry-picking dev branch commits onto a release branch.
Expand Down
43 changes: 29 additions & 14 deletions src/cmd/ksh93/sh.1
Original file line number Diff line number Diff line change
Expand Up @@ -5353,11 +5353,16 @@ Kill the entire current line.
Restore last item removed from line. (Yank item back to the line.)
.TP 10
.BI ^X^E
Return the command
.BI "hist \-e ${\s-1VISUAL\s+1:\-${\s-1EDITOR\s+1:\-vi}}"
in the input buffer to call a full editor \(em
.BI vi
by default \(em on the current command line.
Edit the current command line in a full editor (as set in the
.SM
.B VISUAL
or
.SM
.B EDITOR
variable, or
.IR vi (1),
in that order of preference).
The command line is executed if the file is saved before exiting the editor.
.TP 10
.BI ^L
Line feed and print current line.
Expand Down Expand Up @@ -6113,14 +6118,21 @@ Undo the last text modifying command.
Undo all the text modifying commands performed on the line.
.TP 10
[\f2count\fP]\f3v\fP
Returns the command
.BI "hist \-e ${\s-1VISUAL\s+1:\-${\s-1EDITOR\s+1:\-vi}}" " count"
in the input buffer to call a full editor \(em
.BI vi
by default \(em on a history entry.
Edit command line number
.I count\^
in a full editor (as set in the
.SM
.B VISUAL
or
.SM
.B EDITOR
variable, or
.IR vi (1),
in that order of preference).
If
.I count\^
is omitted, then the current line is used.
The command line is executed if the file is saved before exiting the editor.
.TP 10
.BI ^L
Line feed and print current line.
Expand Down Expand Up @@ -6783,7 +6795,7 @@ Does nothing, and exits 1. Used with
for infinite loops.
.TP
.PD 0
\f3fc\fP \*(OK \f3\-e\fP \f2ename\^\fP \ \*(CK \*(OK \f3\-N\fP \f2num\^\fP \*(CK \*(OK \f3\-nlr\^\fP \*(CK \*(OK \f2first\^\fP \*(OK \f2last\^\fP \*(CK \*(CK
\f3fc\fP \*(OK \f3\-e\fP \f2ename\^\fP \ \*(CK \*(OK \f3\-N\fP \f2num\^\fP \*(CK \*(OK \f3\-Enlr\^\fP \*(CK \*(OK \f2first\^\fP \*(OK \f2last\^\fP \*(CK \*(CK
.TP
\f3fc \-s \fP \*(OK \f2old\fP\f3\=\fP\f2new\^\fP \*(CK \*(OK \f2command\^\fP \*(CK
.PD
Expand Down Expand Up @@ -6952,7 +6964,7 @@ option empties the hash table. This can also be achieved by resetting
.BR PATH.
.TP
.PD 0
\f3hist\fP \*(OK \f3\-e\fP \f2ename\^\fP \ \*(CK \*(OK \f3\-N\fP \f2num\^\fP \*(CK \*(OK \f3\-nlr\^\fP \*(CK \*(OK \f2first\^\fP \*(OK \f2last\^\fP \*(CK \*(CK
\f3hist\fP \*(OK \f3\-e\fP \f2ename\^\fP \ \*(CK \*(OK \f3\-N\fP \f2num\^\fP \*(CK \*(OK \f3\-Enlr\^\fP \*(CK \*(OK \f2first\^\fP \*(OK \f2last\^\fP \*(CK \*(CK
.TP
\f3hist \-s\fP \*(OK \f2old\fP\f3\=\fP\f2new\^\fP \*(CK \*(OK \f2command\^\fP \*(CK
.PD
Expand Down Expand Up @@ -6997,8 +7009,11 @@ is not set, then
(default
.BR /bin/ed\^ )
is used as the editor.
When editing is complete, the edited command(s)
is executed if the changes have been saved.
When the editor exits, the contents of the file become
the new command line and it is either executed
regardless of any change, or if the
.B \-E
option is given, it is executed if the file has been saved.
If
.I last\^
is not specified,
Expand Down

0 comments on commit bb83575

Please sign in to comment.