Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

[RFC][PATCH] Add change-directory() widget function

Attached is the widget that was discussed in workers/48408 and ancestors (Re: Rewrite of zsh-newuser-install).

There was some discussion as to whether this should or shouldn’t leave the executed commands visible in the terminal and/or history. I tried a version of it that doesn’t put the commands in the buffer but executes them directly and then does zle .reset-prompt, but this can leave the prompt in an incorrect state if the prompt uses precmd hooks. I also tried “manually” running precmd_functions before zle .reset-prompt, but this causes problems when any precmd hook contains code that doesn’t work when executed inside a widget (for example, echoing an escape code that result in a response from the terminal). Therefore, I instead settled on pushing the current line, setting the buffer, and then accepting the line. This seems to me the least likely to break anything, but I’m open to alternatives.

From 7cf2d34d4066a5979d47256865680b36ea08d0c0 Mon Sep 17 00:00:00 2001
From: Marlon Richert <marlon.richert@xxxxxxxxx>
Date: Tue, 20 Apr 2021 16:25:07 +0300
Subject: [PATCH] Add change-directory() widget function

 Doc/Zsh/contrib.yo             | 73 ++++++++++++++++++++--------------
 Functions/Zle/change-directory | 29 ++++++++++++++
 2 files changed, 73 insertions(+), 29 deletions(-)
 create mode 100644 Functions/Zle/change-directory

diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo
index 3c4fdded0..519f0db43 100644
--- a/Doc/Zsh/contrib.yo
+++ b/Doc/Zsh/contrib.yo
@@ -123,9 +123,9 @@ If the tt(-p) option is given, the var(arg)s are interpreted as one
 or more sets of arguments for tt(zcompile), separated by `tt(-)tt(-)'.
 For example:
-example(zrecompile -p \ 
-           -R ~/.zshrc -- \ 
-           -M ~/.zcompdump -- \ 
+example(zrecompile -p \
+           -R ~/.zshrc -- \
+           -M ~/.zcompdump -- \
            ~/zsh/comp.zwc ~/zsh/Completion/*/_*)
 This compiles tt(~/.zshrc) into tt(~/.zshrc.zwc) if that doesn't exist or
@@ -529,7 +529,7 @@ are shown first.  The special value tt(+) can appear in the list to
 indicate the default file should be read at that point.  This allows
 effects like the following:
-example(zstyle ':chpwd:*' recent-dirs-file \ 
+example(zstyle ':chpwd:*' recent-dirs-file \
 ~/.chpwd-recent-dirs-${TTY##*/} +)
 Recent directories are read from a file numbered according to
@@ -890,9 +890,9 @@ subsect(Quickstart)
 To get this feature working quickly (including colors), you can do the
 following (assuming, you loaded tt(vcs_info) properly - see above):
-example(zstyle ':vcs_info:*' actionformats \ 
+example(zstyle ':vcs_info:*' actionformats \
     '%F{5}(%f%s%F{5})%F{3}-%F{5}[%F{2}%b%F{3}|%F{1}%a%F{5}]%f '
-zstyle ':vcs_info:*' formats       \ 
+zstyle ':vcs_info:*' formats       \
     '%F{5}(%f%s%F{5})%F{3}-%F{5}[%F{2}%b%F{5}]%f '
 zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat '%b%F{1}:%F{3}%r'
 precmd () { vcs_info }
@@ -1418,7 +1418,7 @@ to know which patches of a series are not yet applied, you need to activate
 the tt(get-unapplied) style in the appropriate context.
 tt(vcs_info) allows for very detailed control over how the gathered
-information is presented (see 
+information is presented (see
 ifzman(the bf(Configuration) and bf(Hooks in vcs_info) sections)\
 ifnzman(noderef(vcs_info Configuration) and noderef(vcs_info Hooks))),
 all of which are documented below. Note there are a number of
@@ -1826,7 +1826,7 @@ example(zstyle ':vcs_info:bzr:*' use-simple true)
 If you do use tt(use-simple), please report if it does `the-right-thing[tm]'.
 Display the revision number in yellow for tt(bzr) and tt(svn):
-example(zstyle ':vcs_info:(svn|bzr):*' \ 
+example(zstyle ':vcs_info:(svn|bzr):*' \
        branchformat '%b%%F{yellow}:%r')
 The doubled percent sign is explained in
@@ -1834,7 +1834,7 @@ ifzman(the bf(Oddities) section)ifnzman(noderef(vcs_info Oddities)).
 Alternatively, one can use the raw colour codes directly:
-example(zstyle ':vcs_info:(svn|bzr):*' \ 
+example(zstyle ':vcs_info:(svn|bzr):*' \
        branchformat '%b%{'${fg[yellow]}'%}:%r')
 Normally when a variable is interpolated into a format string, the variable
@@ -2273,7 +2273,7 @@ Neither of the styles tt(word-chars) nor tt(word-class) is used in this case.
 Here are some examples of use of the tt(word-context) style to extend
 the context.
-example(zstyle ':zle:*' word-context \ 
+example(zstyle ':zle:*' word-context \
        "*/*" filename "[[:space:]]" whitespace
 zstyle ':zle:transpose-words:whitespace' word-style shell
 zstyle ':zle:transpose-words:filename' word-style normal
@@ -2383,7 +2383,7 @@ paste itself from proceeding.
 Loading tt(bracketed-paste-magic) defines tt(backward-extend-paste), a
 helper function for use in tt(paste-init).
-example(zstyle :bracketed-paste-magic paste-init \ 
+example(zstyle :bracketed-paste-magic paste-init \
 When a paste would insert into the middle of a word or append text to a
@@ -2403,16 +2403,16 @@ the paste itself from proceeding.
 Loading tt(bracketed-paste-magic) also defines tt(quote-paste), a helper
 function for use in tt(paste-finish).
-example(zstyle :bracketed-paste-magic paste-finish \ 
+example(zstyle :bracketed-paste-magic paste-finish \
-zstyle :bracketed-paste-magic:finish quote-style \ 
+zstyle :bracketed-paste-magic:finish quote-style \
 When the pasted text is inserted into tt(BUFFER), it is quoted per the
 tt(quote-style) value.  To forcibly turn off the built-in numeric prefix
 quoting of tt(bracketed-paste), use:
-example(zstyle :bracketed-paste-magic:finish quote-style \ 
+example(zstyle :bracketed-paste-magic:finish quote-style \
@@ -2423,6 +2423,21 @@ history is restricted, so cursor motions, etc., may not pass outside of
 the pasted content.  Text assigned to tt(BUFFER) by the active widgets
 is copied back into tt(PASTED) before tt(paste-finish).
+This function implements the widgets tt(cd-upward), tt(cd-backward) and
+tt(cd-forward).  They can be used, respectively, to change to the current
+directory's parent or the previous/next entry in the directory stack. They
+should be initialized as follows:
+example(autoload -Uz change-directory
+zle -N cd-upward   change-directory
+zle -N cd-backward change-directory
+zle -N cd-forward  change-directory
+bindkey '^[^[OA' cd-upward    # Alt-Up
+bindkey '^[^[OD' cd-backward  # Alt-Left
+bindkey '^[^[OC' cd-forward   # Alt-Right
 This widget works like a combination of tt(insert-last-word) and
@@ -2447,7 +2462,7 @@ function based completion system may know about multiple places in
 this string where characters are missing or differ from at least one
 of the possible matches.  It will then place the cursor on the
 position it considers to be the most interesting one, i.e. the one
-where one can disambiguate between as many matches as possible with as 
+where one can disambiguate between as many matches as possible with as
 little typing as possible.
 This widget allows the cursor to be easily moved to the other interesting
@@ -2516,9 +2531,9 @@ the history.
 Although you tt(autoload) only one function, the commands to use it are
 slightly different because it implements two widgets.
-example(zle -N history-beginning-search-backward-end \ 
+example(zle -N history-beginning-search-backward-end \
-zle -N history-beginning-search-forward-end \ 
+zle -N history-beginning-search-forward-end \
 bindkey '\e^P' history-beginning-search-backward-end
 bindkey '\e^N' history-beginning-search-forward-end)
@@ -2543,7 +2558,7 @@ in the text typed is treated as a wildcard and can match anything (hence
 a leading space is equivalent to giving a numeric argument).  Both
 forms can be combined, for example:
-example(zle -N history-beginning-search-menu-space-end \ 
+example(zle -N history-beginning-search-menu-space-end \
@@ -2865,7 +2880,7 @@ non-zero.
 Here is a trivial example of a widget using this feature.
 example(local state
-narrow-to-region -p $'Editing restricted region\n' \ 
+narrow-to-region -p $'Editing restricted region\n' \
   -P '' -S state
 zle recursive-edit
 narrow-to-region -R state)
@@ -3300,11 +3315,11 @@ and for these widgets.  For example, to use completion, approximation and
 correction for normal completion, completion and correction for
 incremental completion and only completion for prediction one could use:
-example(zstyle ':completion:*' completer \ 
+example(zstyle ':completion:*' completer \
         _complete _correct _approximate
-zstyle ':completion:incremental:*' completer \ 
+zstyle ':completion:incremental:*' completer \
         _complete _correct
-zstyle ':completion:predict:*' completer \ 
+zstyle ':completion:predict:*' completer \
 It is a good idea to restrict the completers used in prediction, because
@@ -3324,7 +3339,7 @@ been tried.  Values are:
 The cursor is left where it was when completion finished, but only if
-it is after a character equal to the one just inserted by the user.  If 
+it is after a character equal to the one just inserted by the user.  If
 it is after another character, this value is the same as `tt(key)'.
@@ -3333,7 +3348,7 @@ after the var(n)th occurrence of the character just inserted, where
 var(n) is the number of times that character appeared in the word
 before completion was attempted.  In short, this has the effect of
 leaving the cursor after the character just typed even if the
-completion code found out that no other characters need to be inserted 
+completion code found out that no other characters need to be inserted
 at that position.
@@ -3344,7 +3359,7 @@ position where the completion code left it.
 kindex(list, widget style)
 When using the tt(incremental-complete-word) widget, this style says
-if the matches should be listed on every key press (if they fit on the 
+if the matches should be listed on every key press (if they fit on the
 screen).  Use the context prefix `tt(:completion:incremental)'.
 The tt(insert-and-predict) widget uses this style to decide if the
@@ -3410,7 +3425,7 @@ Like `tt(break-keys)', this uses the `tt(:incremental)' context.
 kindex(stop-keys, widget style)
 This style is used by the tt(incremental-complete-word) widget.  Its value
-is treated similarly to the one for the tt(break-keys) style (and uses 
+is treated similarly to the one for the tt(break-keys) style (and uses
 the same context: `tt(:incremental)').  However, in
 this case all keys matching the pattern given as its value will stop
 incremental completion and will then execute their usual function.
@@ -4401,7 +4416,7 @@ tt(openssl),
@@ -4646,8 +4661,8 @@ This makes defining styles a bit simpler by using a single `tt(+)' as a
 special token that allows you to append a context name to the previously
 used context name.  Like this:
-example(zstyle+ ':foo:bar' var(style1) var(value1) \ 
-      + ':baz'     var(style2) var(value2) \ 
+example(zstyle+ ':foo:bar' var(style1) var(value1) \
+      + ':baz'     var(style2) var(value2) \
       + ':frob'    var(style3) var(value3))
 This defines var(style1) with var(value1) for the context tt(:foo:bar) as usual,
diff --git a/Functions/Zle/change-directory b/Functions/Zle/change-directory
new file mode 100644
index 000000000..376e4414c
--- /dev/null
+++ b/Functions/Zle/change-directory
@@ -0,0 +1,29 @@
+zle .push-line-or-edit
+case $WIDGET in
+  *-upward )
+    if [[ -o autocd ]]; then
+      BUFFER='..'
+    else
+      BUFFER='cd ..'
+    fi
+    ;;
+  *-backward )
+    if [[ -o pushdminus ]]; then
+      BUFFER='pushd -1'
+    else
+      BUFFER='pushd +1'
+    fi
+    ;;
+  *-forward )
+    if [[ -o pushdminus ]]; then
+      BUFFER='pushd +0'
+    else
+      BUFFER='pushd -0'
+    fi
+    ;;
+  * )
+    print -u2 'change-directory: widget name should end in -(up|back|for)ward'
+    return 1
+    ;;
+zle .accept-line

Messages sorted by: Reverse Date, Date, Thread, Author