Skip to content

Commit

Permalink
Move recent paths completion to a keybinding
Browse files Browse the repository at this point in the history
Resolves #640.
  • Loading branch information
marlonrichert committed Apr 3, 2024
1 parent 2912c97 commit a8fdd21
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 71 deletions.
8 changes: 3 additions & 5 deletions Completions/_autocomplete__recent_paths
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
#autoload
zmodload -F zsh/parameter p:functions
zmodload -Fa zsh/parameter p:functions

local -aU files=()
local -a expl=() displ=()
local -Pi ret=1 i=0
local -P singular= plural=

for singular plural in directory directories file files; do
if [[ -v functions[+autocomplete:recent-$plural] &&
$_comp_tags == (|* )(|(all|local|globbed)-)$plural(| *) ]] &&
if [[ -v functions[+autocomplete:recent-$plural] ]] &&
+autocomplete:recent-$plural "$PREFIX$SUFFIX"; then
files=( "$reply[@]" )
_description -V recent-$plural expl "recent $singular"
compadd "$expl[@]" -D files -- "${files[@]:t}"

for i in {1..$#files}; do
displ=( "${${(D)files[i]:h}%/}/$files[i]:t" )
compadd "$expl[@]" -d displ -P "${${displ[1]:h}%/}/" -fW "${${files[i]:h}%/}/" \
compadd -U "$expl[@]" -d displ -P "${${displ[1]:h}%/}/" -fW "${${files[i]:h}%/}/" \
-- "$files[i]:t" &&
ret=0
done
Expand Down
26 changes: 18 additions & 8 deletions Functions/Init/.autocomplete__async
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ ${0}:precmd() {
[[ -v ZSH_AUTOSUGGEST_IGNORE_WIDGETS ]] &&
ZSH_AUTOSUGGEST_IGNORE_WIDGETS+=(
history-incremental-search-backward
recent-paths
.autocomplete:async:complete:fd-widget
)

Expand All @@ -27,7 +28,8 @@ ${0}:precmd() {

builtin zle -C ._list_choices list-choices .autocomplete:async:list-choices:completion-widget

builtin zle -N history-incremental-search-backward .autocomplete:async:history-incremental-search
builtin zle -N history-incremental-search-backward .autocomplete:async:toggle-context
builtin zle -N recent-paths .autocomplete:async:toggle-context

add-zle-hook-widget line-init .autocomplete:async:reset-context
add-zle-hook-widget line-pre-redraw .autocomplete:async:complete
Expand All @@ -37,13 +39,13 @@ ${0}:precmd() {
add-zle-hook-widget isearch-exit .autocomplete:async:isearch-exit
}

.autocomplete:async:history-incremental-search() {
.autocomplete:async:toggle-context() {
if [[ $curcontext == $WIDGET* ]]; then
unset curcontext
else
typeset -g curcontext=${WIDGET}:::
fi
.autocomplete:async:complete
zle .autocomplete:async:complete -w
}

.autocomplete:async:reset-context() {
Expand Down Expand Up @@ -349,7 +351,7 @@ ${0}:precmd() {
.autocomplete:async:sufficient-input() {
local min_input=
if ! builtin zstyle -s ":autocomplete:${curcontext}:" min-input min_input; then
if [[ $curcontext == *history-* ]]; then
if [[ -n $curcontext ]]; then
min_input=0
else
min_input=1
Expand Down Expand Up @@ -404,11 +406,18 @@ ${0}:precmd() {
}

.autocomplete:async:list-choices:main-complete() {
local -i _autocomplete__max_lines=0
if [[ $curcontext == *history-* ]]; then
local -i _autocomplete__max_lines

case $curcontext in
*history-* )
setopt $_autocomplete__func_opts[@]
autocomplete:_main_complete:new - history-lines _autocomplete__history_lines
else
;;
recent-paths:* )
setopt $_autocomplete__func_opts[@]
autocomplete:_main_complete:new - recent-paths _autocomplete__recent_paths
;;
* )
{
() {
emulate -L zsh
Expand All @@ -431,7 +440,8 @@ ${0}:precmd() {
.autocomplete:async:unshadow compadd
.autocomplete:async:unshadow _describe
}
fi
;;
esac
}

.autocomplete:async:shadow() {
Expand Down
4 changes: 2 additions & 2 deletions Functions/Init/.autocomplete__compinit
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ EOF

PREFIX=$PREFIX$SUFFIX
SUFFIX=
autocomplete:_complete:old "$@" ||
_autocomplete__recent_paths "$@"
autocomplete:_complete:old "$@"

# WORKAROUND: Some completion functions mistakenly don't return 0 when they have succeeded.
(( compstate[nmatches] > nmatches ))
}
Expand Down
1 change: 1 addition & 0 deletions Functions/Init/.autocomplete__key-bindings
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ local backtab=$terminfo[kcbt]
main+=(
'\t' complete-word
"$backtab" insert-unambiguous-or-complete
'^X/' recent-paths
)

${0}:bind history-search-backward vi-backward-blank-word '\ep' '^P' $key_alt_up[@]
Expand Down
64 changes: 33 additions & 31 deletions Functions/Init/.autocomplete__recent-dirs
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,38 @@ zmodload -Fa zsh/files b:zf_mv b:zf_mkdir
zmodload -F zsh/parameter p:commands p:dirstack p:functions

${0}:precmd() {
if [[ ! -v functions[+autocomplete:recent-directories] ]]; then
setopt autopushd pushdignoredups # Set *global* shell options.
builtin autoload -RUz chpwd_recent_filehandler

local __=''
builtin zstyle -s :chpwd: recent-dirs-file __ ||
builtin zstyle ':chpwd:*' recent-dirs-file ${XDG_DATA_HOME:-$HOME/.local/share}/zsh/chpwd-recent-dirs
builtin zstyle -s :chpwd: recent-dirs-max __ ||
builtin zstyle ':chpwd:*' recent-dirs-max 0

if ! (( $#dirstack[@] )); then
local -aU reply=()
chpwd_recent_filehandler
dirstack=( ${^reply[@]:#$PWD}(N-/) )
fi

+autocomplete:recent-directories:save() {
chpwd_recent_filehandler $PWD $dirstack[@]
}
add-zsh-hook chpwd +autocomplete:recent-directories:save

+autocomplete:recent-directories() {
# Don't complete current dir, its children, or nonexistent ones.
typeset -ga reply=( ${^dirstack[@]:#$PWD(|/[^/]#)}(N) )

local -i exact=$reply[(I)*/$PREFIX$SUFFIX]
(( exact )) &&
reply=( $reply[exact] $reply[1,exact-1] $reply[exact+1,-1] )

(( $#reply[@] ))
}
[[ -v functions[+autocomplete:recent-directories] ]] &&
return

setopt autopushd pushdignoredups # Set *global* shell options.
builtin autoload -RUz chpwd_recent_filehandler

local __=''
builtin zstyle -s :chpwd: recent-dirs-file __ ||
builtin zstyle ':chpwd:*' recent-dirs-file ${XDG_DATA_HOME:-$HOME/.local/share}/zsh/chpwd-recent-dirs
builtin zstyle -s :chpwd: recent-dirs-max __ ||
builtin zstyle ':chpwd:*' recent-dirs-max 0

if ! (( $#dirstack[@] )); then
local -aU reply=()
chpwd_recent_filehandler
dirstack=( ${^reply[@]:#$PWD}(N-/) )
fi

+autocomplete:recent-directories:save() {
chpwd_recent_filehandler $PWD $dirstack[@]
}
add-zsh-hook chpwd +autocomplete:recent-directories:save

+autocomplete:recent-directories() {
typeset -ga reply

# Don't complete /, ~, $PWD or its children, or nonexistent dirs.
reply=( ${^dirstack[@]:#([/~]|$PWD(|/[^/]#))}(N) )

[[ -n $1 ]] &&
reply=( ${(M)reply:#*${(~j:*:)${(s::)1}}*} )

(( $#reply[@] ))
}
}
54 changes: 29 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,15 @@ Otherwise, simply use your package manager or plugin manager's update mechanisms
| ---: | ---: | ---: | :--- | :---
| <kbd>Enter</kbd><br><kbd>Return</kbd> | | | | Exit menu text search or exit menu
| <kbd>Tab</kbd> | | | Insert first listed menu item | Exit menu text search or exit menu
| <kbd>Shift</kbd><kbd>Tab</kbd> | | | Insert substring occuring in all listed completions | Exit menu text search or exit menu
| <kbd>Shift</kbd><kbd>Tab</kbd> | | | Insert substring occurring in all listed completions | Exit menu text search or exit menu
| <kbd></kbd> | <kbd>Ctrl</kbd><kbd>N</kbd> | <kbd>J</kbd> | Cursor down or enter completion menu | Change selection
| <kbd></kbd> | <kbd>Ctrl</kbd><kbd>P</kbd> | <kbd>K</kbd> | Cursor up or enter [history menu](#history-menu) | Change selection
| <kbd>Alt</kbd><kbd></kbd> | <kbd>Alt</kbd><kbd>N</kbd> | <kbd>Ctrl</kbd><kbd>N</kbd> | Enter completion menu | Next section
| <kbd>Alt</kbd><kbd></kbd> | <kbd>Alt</kbd><kbd>P</kbd> | <kbd>Ctrl</kbd><kbd>P</kbd> | Enter history menu | Previous section
| <kbd>PgDn</kbd> | | | | Page down
| <kbd>PgUp</kbd> | | | | Page up
| | <kbd>Ctrl</kbd><kbd>R</kbd> | <kbd>/</kbd> | Toggle history search mode | Start menu text search or go to previous match
| | <kbd>Ctrl</kbd><kbd>X</kbd> <kbd>/</kbd> | | Toggle recent path search |
| | <kbd>Ctrl</kbd><kbd>R</kbd> | <kbd>/</kbd> | Toggle history search | Start menu text search or go to previous match
| | <kbd>Ctrl</kbd><kbd>S</kbd> | <kbd>?</kbd> | Start menu text search | Start menu text search or go to next match
| | <kbd>Ctrl</kbd><kbd>Space</kbd> | <kbd>V</kbd> | Toggle selection mode | Add another item
| | <kbd>Ctrl</kbd><kbd>-</kbd><br><kbd>Ctrl</kbd><kbd>/</kbd> | <kbd>U</kbd> | | Undo last item
Expand Down Expand Up @@ -208,29 +209,7 @@ Modifying this list will change when a space is inserted. If you change the
list to `'*'`, a space is always inserted. If you put no elements in the list,
then a space is never inserted.

### Use a custom backend for recent directories
Autocomplete comes with its own backend for keeping track of and listing recent
directories (which uses part of
[`cdr`](https://zsh.sourceforge.io/Doc/Release/User-Contributions.html#Recent-Directories)
under the hood). However, you can override this and supply Autocomplete with
recent directories from any source that you like. To do so, define a function
like this:
```zsh
+autocomplete:recent-directories() {
typeset -ga reply=( [code that generates an array of absolute paths] )
}
```

### Add a backend for recent files
Out of the box, Autocomplete doesn't track or offer recent files. However, it
will do so if you add a backend for it:
```zsh
+autocomplete:recent-files() {
typeset -ga reply=( [code that generates an array of absolute paths] )
}
```
### Start each new line in history search mode
### Start each command line in history search mode
This will make Autocomplete behave as if you pressed <kbd>Ctrl</kbd><kbd>R</kbd> at the start of each new command line:
```zsh
zstyle ':autocomplete:*' default-context history-incremental-search-backward
Expand Down Expand Up @@ -273,6 +252,31 @@ Note that for autocompletion and history search, the maximum number of lines is
lines that fit on screen. However, there is no such limit for the history menu. If that generates more lines than fit
on screen, you can simply scroll upwards to see more.

### Use a custom backend for recent directories
Autocomplete comes with its own backend for keeping track of and listing recent directories (which
uses part of
[`cdr`](https://zsh.sourceforge.io/Doc/Release/User-Contributions.html#Recent-Directories) under the
hood). However, you can override this and supply Autocomplete with recent directories from any
source that you like. To do so, define a function like this:

```sh
+autocomplete:recent-directories() {
<code>
typeset -ga reply=( <any number of absolute paths> )
}
```

#### Add a backend for recent files
Out of the box, Autocomplete doesn't track or offer recent files. However, it will do so if you add
a backend for it:
```sh
+autocomplete:recent-files() {
<code>
typeset -ga reply=( <any number of absolute paths> )
}
```
## Troubleshooting
Try the steps in the
[bug report template](.github/ISSUE_TEMPLATE/bug-report.md).
Expand Down

0 comments on commit a8fdd21

Please sign in to comment.