Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[PATCH] Re: Editing the history in the shell
- X-seq: zsh-workers 48710
- From: Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx>
- To: Zsh hackers list <zsh-workers@xxxxxxx>
- Subject: [PATCH] Re: Editing the history in the shell
- Date: Sun, 25 Apr 2021 14:56:14 -0700
- Archived-at: <https://zsh.org/workers/48710>
- In-reply-to: <CAH+w=7bXeQo8Uvz3fNpC3ruzFxKeDzO928VTGhJGH_24g+CxOg@mail.gmail.com>
- List-id: <zsh-workers.zsh.org>
- References: <CAH+w=7ZFt7jshjv1FCEbmP_PgADvdKwymRutrzwJAvzNpsfOmA@mail.gmail.com> <20200523022807.08f3ba45@tarpaulin.shahaf.local2> <CAH+w=7aWxdY3KuTaYym1GiAowRRHBc=2AJPPgqOmN8G6L0xT2A@mail.gmail.com> <20200525023515.7855610a@tarpaulin.shahaf.local2> <CAH+w=7bTCCC2XBr+_HCAPqXWuOV_YOrDv+36C6jJScKrxZjhLQ@mail.gmail.com> <CAH+w=7bXeQo8Uvz3fNpC3ruzFxKeDzO928VTGhJGH_24g+CxOg@mail.gmail.com>
Another one from last May.
On Fri, May 22, 2020 at 3:24 PM Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> wrote:
>
> The patch implements "zed -h" which loads the history into vared and
> arranges to replace the existing history with that before it exits.
> This does NOT solve Markus' complaint about the history numbers, they
> increase by the number of entries output by the editor. It makes no
> attempt to account for various history options, so those may change
> the final result if they affect "print -s".
>
> It also handles "zed -h filename" which loads that file and saves it
> back again rather than alter the current shell history.
On Tue, May 26, 2020 at 8:32 PM Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> wrote:
>
> I think zed has a long-standing problem with SH_WORD_SPLIT and
> probably some other SH_ options?
>
> % setopt shwordsplit
> % zed "/tmp/one two"
> Where does this go?
> % cat "/tmp/one two"
> cat: '/tmp/one two': No such file or directory
> % cat /tmp/one
> Where does this go?
> %
>
> So ... how far do we go to make "zed" compatible with nonstandard
> options, and how do we approach doing it? Try to use entirely
> portable syntax, or invoke "emulate -L", or something in between?
> Look at the handling of function names, too -- it creates the empty
> function definition with ${(q-)1} but makes no attempt to quote $1
> when calling "functions" or "autoload".
The attached patch both implements zed -h and fixes issues with
SH_WORD_SPLIT and NO_SHORT_LOOPS, but does not attempt a comprehensive
repair, so the "how far do we go?" question remains. Completion is
updated per Oliver's advice in the "_arguments optspecs" thread
(starts at workers/45909, messages from Oliver seem to have been
doubled up in the archives) but could use a once-over. Doc also
updated.
A minor head-scratcher for me (insufficient note-taking to return to
this a year later) is that at one time the code for zed -h was using
var=( "${(@Oav)history:gs/\\/\\\\}" )
before invoking vared. Now I can't figure out when or why I thought
that was necessary; I'm able to edit my existing 500 commands / 734
lines of history without seeing any garbled backslashes, using only
var=( "${(@Oav)history}" )
as in the patch. Can anyone jog my memory? Do backslashes ever need
double-escaping?
diff --git a/Completion/Zsh/Command/_zed b/Completion/Zsh/Command/_zed
index 6b68fadf0..f84993d73 100644
--- a/Completion/Zsh/Command/_zed
+++ b/Completion/Zsh/Command/_zed
@@ -1,10 +1,16 @@
-#compdef zed fned
+#compdef zed fned histed
case $service in
(fned) _arguments -S : ':shell function:_functions';;
+(histed) _arguments -S : \
+ '1:history file:_files' \
+ '2:history size: ';;
(zed) _arguments -S : \
- '(- 2):file:_files' \
- '(1):shell function:_functions' \
- '(1)-x+[specify spaces to use for indentation in function expansion]:spaces' \
- '(1)-f[edit function]';;
+ '(-h 1 3 4)-f[edit function]' \
+ '(-h 1 3 4)-x+[specify spaces to use for indentation in function expansion]:spaces' \
+ '(-f -x 1 2)-h[edit history]' \
+ '(- 2 3 4)1:file:_files' \
+ '(3 4)2:shell function:_functions' \
+ '3:history file:_files -g "*(D)"' \
+ '4:history size';;
esac
diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo
index 8bf1a208e..0f2d0664d 100644
--- a/Doc/Zsh/contrib.yo
+++ b/Doc/Zsh/contrib.yo
@@ -4295,6 +4295,12 @@ Same as tt(zed -f). This function does not appear in the zsh
distribution, but can be created by linking tt(zed) to the name tt(fned)
in some directory in your tt(fpath).
)
+findex(histed)
+item(tt(histed) [ [ var(name) ] var(size) ])(
+Same as tt(zed -h). This function does not appear in the zsh
+distribution, but can be created by linking tt(zed) to the name tt(histed)
+in some directory in your tt(fpath).
+)
findex(is-at-least)
item(tt(is-at-least) var(needed) [ var(present) ])(
Perform a greater-than-or-equal-to comparison of two strings having the
@@ -4504,6 +4510,7 @@ tt(zargs) with the tt(-)tt(-help) option.
)
findex(zed)
xitem(tt(zed) [ tt(-f) [ tt(-x) var(num) ] ] var(name))
+xitem(tt(zed) [ tt(-h) [ var(name) ] var(size) ])
item(tt(zed -b))(
This function uses the ZLE editor to edit a file or function.
@@ -4518,7 +4525,14 @@ the given number of spaces; `tt(-x 2)' is consistent with the layout
of functions distributed with the shell.
Without tt(-f), var(name) is the path name of the file to edit, which need
-not exist; it is created on write, if necessary.
+not exist; it is created on write, if necessary. With tt(-h), the file is
+presumed to contain history events.
+
+When no file name is provided for tt(-h) the current shell history is edited
+in place. The history is renumbered when zed exits successfully.
+
+When editing history, multi-line events must have a trailing backslash on
+every line before the last.
While editing, the function sets the main keymap to tt(zed) and the
vi command keymap to tt(zed-vicmd). These will be copied from the existing
@@ -4543,7 +4557,11 @@ of the return key), or can be bound to a key in either of the tt(zed) or
tt(zed-vicmd) keymaps after `tt(zed -b)' has been run. When the widget is
called, it prompts for a new name for the file being edited. When zed
exits the file will be written under that name and the original file will
-be left alone. The widget has no effect with `tt(zed -f)'.
+be left alone. The widget has no effect with `tt(zed -f)'. When editing
+the current history with `tt(zed -h)', the history is first updated and
+then the file is written, but the global setting of tt(HISTFILE) is not
+altered.
+
While tt(zed-set-file-name) is running, zed uses the keymap
tt(zed-normal-keymap), which is linked from the main keymap in effect
diff --git a/Functions/Misc/zed b/Functions/Misc/zed
index 9eb4b2d93..7d0d590db 100644
--- a/Functions/Misc/zed
+++ b/Functions/Misc/zed
@@ -5,16 +5,18 @@
# Edit small files with the command line editor.
# Use ^X^W to save (or ZZ in vicmd mode), ^C to abort.
# Option -f: edit shell functions. (Also if called as fned.)
+# Option -h: edit shell history. (Also if called as histed.)
setopt localoptions noksharrays
local var opts zed_file_name
# We do not want timeout while we are editing a file
-integer TMOUT=0 okargs=1 fun bind
+integer TMOUT=0 okargs=1 fun hist bind
local -a expand
-zparseopts -D -A opts f b x:
+zparseopts -D -A opts f h b x:
fun=$+opts[-f]
+hist=$+opts[-h]
bind=$+opts[-b]
if [[ $opts[-x] == <-> ]]; then
expand=(-x $opts[-x])
@@ -24,23 +26,28 @@ elif (( $+opts[-x] )); then
fi
[[ $0 = fned ]] && fun=1
+[[ $0 = histed ]] && hist=1
+(( hist && $# <= 2 )) && okargs=$#
(( bind )) && okargs=0
-if (( $# != okargs )); then
+if (( $# != okargs || bind + fun + hist > 1 )); then
echo 'Usage:
zed filename
zed -f [ -x N ] function
+zed -h [ filename [ size ] ]
zed -b' >&2
return 1
fi
local curcontext=zed:::
-# Matching used in zstyle -m: hide result from caller.
-# Variables not used directly here.
-local -a match mbegin mend
-zstyle -m ":completion:zed:*" insert-tab '*' ||
- zstyle ":completion:zed:*" insert-tab yes
+() {
+ # Matching used in zstyle -m: hide result from caller.
+ # Variables not used directly here.
+ local -a match mbegin mend
+ zstyle -m ":completion:zed:*" insert-tab '*' ||
+ zstyle ":completion:zed:*" insert-tab yes
+}
zmodload zsh/terminfo 2>/dev/null
@@ -124,22 +131,51 @@ fi
setopt localoptions nobanghist
if ((fun)) then
- var="$(functions $expand -- $1)"
+ var="$(functions $expand -- "$1")"
# If function is undefined but autoloadable, load it
if [[ $var = *\#\ undefined* ]] then
- var="$(autoload +X $1; functions -- $1)"
+ var="$(autoload +X "$1"; functions -- "$1")"
elif [[ -z $var ]] then
var="${(q-)1} () {
}"
fi
vared -M zed -m zed-vicmd -i __zed_init var && eval function "$var"
+elif ((hist)) then
+ if [[ -n $1 ]]; then
+ { fc -p -a "$1" ${2:-$({ wc -l <"$1" } 2>/dev/null)} || return }
+ let HISTSIZE++
+ print -s "" # Work around fc -p limitation
+ fi
+ # When editing the current shell history, the "zed -h" command is not
+ # itself included because the current event is not added to the ring
+ # until the next prompt is printed. This means "zed -h" is prepended
+ # to the result of the edit, because of the way "print -s" is defined.
+ var=( "${(@Oav)history}" )
+ IFS=$'\n' vared -M zed -m zed-vicmd -i __zed_init var
+ if (( ? )); then
+ [[ -n $1 ]] && unset HISTFILE
+ else
+ local HISTSIZE=0 savehist=$#var
+ fc -R /dev/null # Remove entries other than those added here
+ HISTSIZE=$savehist # Resets on function exit because local
+ [[ -n $1 ]] && SAVEHIST=$savehist # Resets via foregoing fc -a
+ for (( hist=1; hist <= savehist; hist++ ))
+ do print -rs -- "$var[hist]"
+ done
+ if [[ -n $zed_file_name ]]; then
+ fc -W "$zed_file_name"
+ [[ -n $1 ]] && unset HISTFILE
+ fi
+ # Note prepend effect when global HISTSIZE greater than $savehist.
+ # This does not affect file editing.
+ fi
else
- zed_file_name=$1
- [[ -f $1 ]] && var="$(<$1)"
+ zed_file_name="$1"
+ [[ -f $1 ]] && var="$(<"$1")"
while vared -M zed -m zed-vicmd -i __zed_init var
do
{
- print -r -- "$var" >| $zed_file_name
+ print -r -- "$var" >| "$zed_file_name"
} always {
(( TRY_BLOCK_ERROR = 0 ))
} && break
Messages sorted by:
Reverse Date,
Date,
Thread,
Author