Add a complete-command command to configure command completion
This makes it possible to change command completion in hooks and paves the way to more flexibility in how custom commands can be completed
This commit is contained in:
parent
b915e4e11b
commit
7061001728
|
@ -3,6 +3,10 @@
|
|||
This changelog contains major and/or breaking changes to Kakoune between
|
||||
released versions.
|
||||
|
||||
== Development version
|
||||
|
||||
* `complete-command` (See <<commands#configuring-command-completion,`:doc commands configuring-command-completion`>>
|
||||
|
||||
== Kakoune 2021.11.07
|
||||
|
||||
* Support for curly and separately colored underlines (undocumented in 2021.10.28)
|
||||
|
|
|
@ -180,6 +180,11 @@ of the file onto the filesystem
|
|||
define a new alias named *name* in *scope*
|
||||
(See <<aliases,Using aliases>> and <<scopes#,`:doc scopes`>>)
|
||||
|
||||
*complete-command* [<switches>] <name> <type> [<param>]::
|
||||
*alias* compl +
|
||||
configure how a command completion works
|
||||
(See <<configuring-command-completion,Configuring command completion>>)
|
||||
|
||||
*unalias* <scope> <name> [<command>]::
|
||||
remove an alias if its current value is the same as the one passed
|
||||
as an optional parameter, remove it unconditionally otherwise
|
||||
|
@ -473,25 +478,59 @@ New commands can be defined using the *define-command* command:
|
|||
define the documentation string for the command
|
||||
|
||||
*-menu*:::
|
||||
the suggestions generated by the completion options are the only
|
||||
permitted parameters.
|
||||
|
||||
*-file-completion*:::
|
||||
try file completion on any parameter passed to this command
|
||||
|
||||
*-client-completion*:::
|
||||
try client name completion on any parameter passed to this command
|
||||
|
||||
*-buffer-completion*:::
|
||||
try buffer name completion on any parameter passed to this command
|
||||
|
||||
*-command-completion*:::
|
||||
try command completion on any parameter passed to this command
|
||||
|
||||
*-shell-completion*:::
|
||||
try shell command completion on any parameter passed to this command
|
||||
|
||||
*-shell-script-completion*:::
|
||||
*-shell-script-candidates*:::
|
||||
old-style command completion specification, function as-if
|
||||
the switch and its eventual parameter was passed to the
|
||||
*complete-command* command
|
||||
(See <<configuring-command-completion,Configuring command completion>>)
|
||||
|
||||
The use of those switches is discouraged in favor of the
|
||||
*complete-command* command.
|
||||
|
||||
Using shell expansion allows defining complex commands or accessing
|
||||
Kakoune's state:
|
||||
|
||||
---------------------------------------------------------------------
|
||||
# create a directory for current buffer if it does not exist
|
||||
define-command mkdir %{ nop %sh{ mkdir -p $(dirname $kak_buffile) } }
|
||||
---------------------------------------------------------------------
|
||||
|
||||
== Configuring command completion
|
||||
|
||||
Command completion can be configured with the *complete-command* command:
|
||||
|
||||
*complete-command* [<switches>] <command_name> <completion_type> [<parameter>]::
|
||||
*switches* can be:
|
||||
|
||||
*-menu*:::
|
||||
the suggestions generated by the completion options are the only
|
||||
permitted parameters. Kakoune will autoselect the best completion
|
||||
candidate on command validation.
|
||||
|
||||
*completion_type* can be:
|
||||
|
||||
*file-completion*:::
|
||||
try file completion on any parameter passed to the command
|
||||
|
||||
*client-completion*:::
|
||||
try client name completion on any parameter passed to the command
|
||||
|
||||
*buffer-completion*:::
|
||||
try buffer name completion on any parameter passed to the command
|
||||
|
||||
*command-completion*:::
|
||||
try command completion on any parameter passed to the command
|
||||
|
||||
*shell-completion*:::
|
||||
try shell command completion on any parameter passed to the command
|
||||
|
||||
*shell-script-completion*:::
|
||||
following string is a shell command which takes parameters as
|
||||
positional params and outputs one completion candidate per line.
|
||||
The provided shell command will run after each keypress.
|
||||
|
@ -507,14 +546,14 @@ New commands can be defined using the *define-command* command:
|
|||
Position of the cursor inside the token being completed, in bytes
|
||||
from token start.
|
||||
|
||||
*-shell-script-candidates*:::
|
||||
following string is a shell command which takes parameters as
|
||||
*shell-script-candidates*:::
|
||||
following string is a shell script which takes parameters as
|
||||
positional params and outputs one completion candidate per line.
|
||||
The provided shell command will run once at the beginning of each
|
||||
The provided shell script will run once at the beginning of each
|
||||
completion session, candidates are cached and then used by kakoune
|
||||
internal fuzzy engine.
|
||||
|
||||
During the execution of the shell command, the following env vars are
|
||||
During the execution of the shell script, the following env vars are
|
||||
available:
|
||||
|
||||
*$kak_token_to_complete*::::
|
||||
|
@ -522,14 +561,6 @@ New commands can be defined using the *define-command* command:
|
|||
Note that unlike the Unix `argv` tradition,
|
||||
0 is the first argument, not the command name itself.
|
||||
|
||||
Using shell expansion allows defining complex commands or accessing
|
||||
Kakoune's state:
|
||||
|
||||
---------------------------------------------------------------------
|
||||
# create a directory for current buffer if it does not exist
|
||||
define-command mkdir %{ nop %sh{ mkdir -p $(dirname $kak_buffile) } }
|
||||
---------------------------------------------------------------------
|
||||
|
||||
== Aliases
|
||||
|
||||
With `:alias`, commands can be given additional names.
|
||||
|
|
|
@ -19,14 +19,14 @@ add-highlighter shared/diff/ regex "^\+[^\n]*\n" 0:green,default
|
|||
add-highlighter shared/diff/ regex "^-[^\n]*\n" 0:red,default
|
||||
add-highlighter shared/diff/ regex "^@@[^\n]*@@" 0:cyan,default
|
||||
|
||||
define-command diff-jump \
|
||||
-docstring %{diff-jump [<switches>] [<directory>]: edit the diff's source file at the cursor position.
|
||||
Paths are resolved relative to <directory>, or the current working directory if unspecified.
|
||||
define-command diff-jump -params .. -docstring %{
|
||||
diff-jump [<switches>] [<directory>]: edit the diff's source file at the cursor position.
|
||||
Paths are resolved relative to <directory>, or the current working directory if unspecified.
|
||||
|
||||
Switches:
|
||||
- jump to the old file instead of the new file
|
||||
-<num> strip <num> leading directory components, like -p<num> in patch(1). Defaults to 1 if there is a 'diff' line (as printed by 'diff -r'), or 0 otherwise.} \
|
||||
-params .. -file-completion %{
|
||||
Switches:
|
||||
- jump to the old file instead of the new file
|
||||
-<num> strip <num> leading directory components, like -p<num> in patch(1). Defaults to 1 if there is a 'diff' line (as printed by 'diff -r'), or 0 otherwise.
|
||||
} %{
|
||||
evaluate-commands -draft -save-regs c %{
|
||||
# Save the column because we will move the cursor.
|
||||
set-register c %val{cursor_column}
|
||||
|
@ -146,6 +146,7 @@ Switches:
|
|||
}
|
||||
}
|
||||
}
|
||||
complete-command diff-jump file
|
||||
|
||||
§
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ add-highlighter shared/kakrc/shell8 region -recurse '<' '(^|\h)\K-shell-script-
|
|||
evaluate-commands %sh{
|
||||
# Grammar
|
||||
keywords="add-highlighter alias arrange-buffers buffer buffer-next buffer-previous catch
|
||||
change-directory colorscheme debug declare-option declare-user-mode define-command
|
||||
change-directory colorscheme debug declare-option declare-user-mode define-command complete-command
|
||||
delete-buffer delete-buffer! echo edit edit! enter-user-mode evaluate-commands execute-keys
|
||||
fail hook info kill kill! map menu nop on-key prompt provide-module quit quit!
|
||||
remove-highlighter remove-hooks rename-buffer rename-client rename-session require-module
|
||||
|
|
|
@ -4,7 +4,7 @@ declare-option -docstring "name of the client in which utilities display informa
|
|||
str toolsclient
|
||||
declare-option -hidden int grep_current_line 0
|
||||
|
||||
define-command -params .. -file-completion -docstring %{
|
||||
define-command -params .. -docstring %{
|
||||
grep [<arguments>]: grep utility wrapper
|
||||
All optional arguments are forwarded to the grep utility
|
||||
} grep %{ evaluate-commands %sh{
|
||||
|
@ -23,6 +23,7 @@ define-command -params .. -file-completion -docstring %{
|
|||
hook -always -once buffer BufCloseFifo .* %{ nop %sh{ rm -r $(dirname ${output}) } }
|
||||
}"
|
||||
}}
|
||||
complete-command grep file
|
||||
|
||||
hook -group grep-highlight global WinSetOption filetype=grep %{
|
||||
add-highlighter window/grep group
|
||||
|
|
|
@ -36,22 +36,25 @@ define-command -hidden -params 2.. iterm-terminal-split-impl %{
|
|||
}
|
||||
}
|
||||
|
||||
define-command iterm-terminal-vertical -params 1.. -shell-completion -docstring '
|
||||
define-command iterm-terminal-vertical -params 1.. -docstring '
|
||||
iterm-terminal-vertical <program> [<arguments>]: create a new terminal as an iterm pane
|
||||
The current pane is split into two, left and right
|
||||
The program passed as argument will be executed in the new terminal'\
|
||||
%{
|
||||
iterm-terminal-split-impl 'vertically' %arg{@}
|
||||
}
|
||||
define-command iterm-terminal-horizontal -params 1.. -shell-completion -docstring '
|
||||
complete-command iterm-terminal-vertical shell
|
||||
|
||||
define-command iterm-terminal-horizontal -params 1.. -docstring '
|
||||
iterm-terminal-horizontal <program> [<arguments>]: create a new terminal as an iterm pane
|
||||
The current pane is split into two, top and bottom
|
||||
The program passed as argument will be executed in the new terminal'\
|
||||
%{
|
||||
iterm-terminal-split-impl 'horizontally' %arg{@}
|
||||
}
|
||||
complete-command iterm-terminal-horizontal shell
|
||||
|
||||
define-command iterm-terminal-tab -params 1.. -shell-completion -docstring '
|
||||
define-command iterm-terminal-tab -params 1.. -docstring '
|
||||
iterm-terminal-tab <program> [<arguments>]: create a new terminal as an iterm tab
|
||||
The program passed as argument will be executed in the new terminal'\
|
||||
%{
|
||||
|
@ -76,8 +79,9 @@ The program passed as argument will be executed in the new terminal'\
|
|||
-e "end tell" >/dev/null
|
||||
}
|
||||
}
|
||||
complete-command iterm-terminal-tab shell
|
||||
|
||||
define-command iterm-terminal-window -params 1.. -shell-completion -docstring '
|
||||
define-command iterm-terminal-window -params 1.. -docstring '
|
||||
iterm-terminal-window <program> [<arguments>]: create a new terminal as an iterm window
|
||||
The program passed as argument will be executed in the new terminal'\
|
||||
%{
|
||||
|
@ -100,8 +104,9 @@ The program passed as argument will be executed in the new terminal'\
|
|||
-e "end tell" >/dev/null
|
||||
}
|
||||
}
|
||||
complete-command iterm-terminal-window shell
|
||||
|
||||
define-command iterm-focus -params ..1 -client-completion -docstring '
|
||||
define-command iterm-focus -params ..1 -docstring '
|
||||
iterm-focus [<client>]: focus the given client
|
||||
If no client is passed then the current one is used' \
|
||||
%{
|
||||
|
@ -131,6 +136,7 @@ If no client is passed then the current one is used' \
|
|||
fi
|
||||
}
|
||||
}
|
||||
complete-command iterm-focus client
|
||||
|
||||
alias global focus iterm-focus
|
||||
alias global terminal iterm-terminal-vertical
|
||||
|
|
|
@ -10,7 +10,7 @@ evaluate-commands %sh{
|
|||
|
||||
declare-option -docstring %{window type that kitty creates on new and repl calls (window|os-window)} str kitty_window_type window
|
||||
|
||||
define-command kitty-terminal -params 1.. -shell-completion -docstring '
|
||||
define-command kitty-terminal -params 1.. -docstring '
|
||||
kitty-terminal <program> [<arguments>]: create a new terminal as a kitty window
|
||||
The program passed as argument will be executed in the new terminal' \
|
||||
%{
|
||||
|
@ -28,8 +28,9 @@ The program passed as argument will be executed in the new terminal' \
|
|||
kitty @ $listen launch --no-response --type="$kak_opt_kitty_window_type" --cwd="$PWD" $match "$@"
|
||||
}
|
||||
}
|
||||
complete-command kitty-terminal shell
|
||||
|
||||
define-command kitty-terminal-tab -params 1.. -shell-completion -docstring '
|
||||
define-command kitty-terminal-tab -params 1.. -docstring '
|
||||
kitty-terminal-tab <program> [<arguments>]: create a new terminal as kitty tab
|
||||
The program passed as argument will be executed in the new terminal' \
|
||||
%{
|
||||
|
@ -47,8 +48,9 @@ The program passed as argument will be executed in the new terminal' \
|
|||
kitty @ $listen launch --no-response --type=tab --cwd="$PWD" $match "$@"
|
||||
}
|
||||
}
|
||||
complete-command kitty-terminal-tab shell
|
||||
|
||||
define-command kitty-focus -params ..1 -client-completion -docstring '
|
||||
define-command kitty-focus -params ..1 -docstring '
|
||||
kitty-focus [<client>]: focus the given client
|
||||
If no client is passed then the current one is used' \
|
||||
%{
|
||||
|
@ -70,6 +72,7 @@ If no client is passed then the current one is used' \
|
|||
fi
|
||||
}
|
||||
}
|
||||
complete-command kitty-focus client
|
||||
|
||||
alias global terminal kitty-terminal
|
||||
alias global terminal-tab kitty-terminal-tab
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
define-command new -params .. -command-completion -docstring '
|
||||
define-command new -params .. -docstring '
|
||||
new [<commands>]: create a new Kakoune client
|
||||
The ''terminal'' alias is being used to determine the user''s preferred terminal emulator
|
||||
The optional arguments are passed as commands to the new client' \
|
||||
|
@ -6,3 +6,4 @@ The optional arguments are passed as commands to the new client' \
|
|||
terminal kak -c %val{session} -e "%arg{@}"
|
||||
}
|
||||
|
||||
complete-command new command
|
||||
|
|
|
@ -12,7 +12,6 @@ define-command -docstring %{
|
|||
All optional parameters are forwarded to the new terminal window
|
||||
} \
|
||||
-params .. \
|
||||
-shell-completion \
|
||||
dtach-repl %{ terminal sh -c %{
|
||||
file="$(mktemp -u -t kak_dtach_repl.XXXXX)"
|
||||
trap 'rm -f "${file}"' EXIT
|
||||
|
@ -22,6 +21,7 @@ define-command -docstring %{
|
|||
dtach -c "${file}" -E sh -c "${@:-$SHELL}" || "${@:-$SHELL}"
|
||||
} -- %val{client} %val{session} %arg{@}
|
||||
}
|
||||
complete-command dtach-repl shell
|
||||
|
||||
define-command dtach-send-text -params 0..1 -docstring %{
|
||||
dtach-send-text [text]: Send text to the REPL.
|
||||
|
|
|
@ -4,7 +4,7 @@ hook global ModuleLoaded kitty %{
|
|||
|
||||
provide-module kitty-repl %{
|
||||
|
||||
define-command -params .. -shell-completion \
|
||||
define-command -params .. \
|
||||
-docstring %{
|
||||
kitty-repl [<arguments>]: Create a new window for repl interaction.
|
||||
|
||||
|
@ -31,6 +31,7 @@ define-command -params .. -shell-completion \
|
|||
kitty @ $listen launch --no-response --keep-focus --type="$kak_opt_kitty_window_type" --title=kak_repl_window --cwd="$PWD" $match $cmd
|
||||
}
|
||||
}
|
||||
complete-command kitty-repl shell
|
||||
|
||||
define-command -hidden -params 0..1 \
|
||||
-docstring %{
|
||||
|
|
|
@ -23,17 +23,20 @@ define-command -hidden -params 1.. tmux-repl-impl %{
|
|||
}
|
||||
}
|
||||
|
||||
define-command tmux-repl-vertical -params 0.. -command-completion -docstring "Create a new vertical pane for repl interaction" %{
|
||||
define-command tmux-repl-vertical -params 0.. -docstring "Create a new vertical pane for repl interaction" %{
|
||||
tmux-repl-impl 'split-window -v' %arg{@}
|
||||
}
|
||||
complete-command tmux-repl-vertical command
|
||||
|
||||
define-command tmux-repl-horizontal -params 0.. -command-completion -docstring "Create a new horizontal pane for repl interaction" %{
|
||||
define-command tmux-repl-horizontal -params 0.. -docstring "Create a new horizontal pane for repl interaction" %{
|
||||
tmux-repl-impl 'split-window -h' %arg{@}
|
||||
}
|
||||
complete-command tmux-repl-horizontal command
|
||||
|
||||
define-command tmux-repl-window -params 0.. -command-completion -docstring "Create a new window for repl interaction" %{
|
||||
define-command tmux-repl-window -params 0.. -docstring "Create a new window for repl interaction" %{
|
||||
tmux-repl-impl 'new-window' %arg{@}
|
||||
}
|
||||
complete-command tmux-repl-window command
|
||||
|
||||
define-command -params 0..1 tmux-repl-set-pane -docstring %{
|
||||
tmux-repl-set-pane [pane number]: Set an existing tmux pane for repl interaction
|
||||
|
|
|
@ -11,7 +11,6 @@ define-command -docstring %{
|
|||
All optional parameters are forwarded to the new window
|
||||
} \
|
||||
-params .. \
|
||||
-shell-completion \
|
||||
x11-repl %{ x11-terminal sh -c %{
|
||||
winid="${WINDOWID:-$(xdotool search --pid ${PPID} | tail -1)}"
|
||||
printf "evaluate-commands -try-client $1 \
|
||||
|
@ -20,6 +19,7 @@ define-command -docstring %{
|
|||
[ "$1" ] && "$@" || "$SHELL"
|
||||
} -- %val{client} %val{session} %arg{@}
|
||||
}
|
||||
complete-command x11-repl shell
|
||||
|
||||
define-command x11-send-text -params 0..1 -docstring %{
|
||||
x11-send-text [text]: Send text to the REPL window.
|
||||
|
|
|
@ -28,21 +28,25 @@ define-command screen-terminal-impl -hidden -params 3.. %{
|
|||
}
|
||||
}
|
||||
|
||||
define-command screen-terminal-vertical -params 1.. -shell-completion -docstring '
|
||||
define-command screen-terminal-vertical -params 1.. -docstring '
|
||||
screen-terminal-vertical <program> [<arguments>] [<arguments>]: create a new terminal as a screen pane
|
||||
The current pane is split into two, left and right
|
||||
The program passed as argument will be executed in the new terminal' \
|
||||
%{
|
||||
screen-terminal-impl 'split -v' 'focus right' %arg{@}
|
||||
}
|
||||
define-command screen-terminal-horizontal -params 1.. -shell-completion -docstring '
|
||||
complete-command screen-terminal-vertical shell
|
||||
|
||||
define-command screen-terminal-horizontal -params 1.. -docstring '
|
||||
screen-terminal-horizontal <program> [<arguments>]: create a new terminal as a screen pane
|
||||
The current pane is split into two, top and bottom
|
||||
The program passed as argument will be executed in the new terminal' \
|
||||
%{
|
||||
screen-terminal-impl 'split -h' 'focus down' %arg{@}
|
||||
}
|
||||
define-command screen-terminal-window -params 1.. -shell-completion -docstring '
|
||||
complete-command screen-terminal-horizontal shell
|
||||
|
||||
define-command screen-terminal-window -params 1.. -docstring '
|
||||
screen-terminal-window <program> [<arguments>]: create a new terminal as a screen window
|
||||
The program passed as argument will be executed in the new terminal' \
|
||||
%{
|
||||
|
@ -51,8 +55,9 @@ The program passed as argument will be executed in the new terminal' \
|
|||
screen -X screen "$@" < "/dev/$tty"
|
||||
}
|
||||
}
|
||||
complete-command screen-terminal-window shell
|
||||
|
||||
define-command screen-focus -params ..1 -client-completion -docstring '
|
||||
define-command screen-focus -params ..1 -docstring '
|
||||
screen-focus [<client>]: focus the given client
|
||||
If no client is passed then the current one is used' \
|
||||
%{
|
||||
|
@ -67,6 +72,7 @@ If no client is passed then the current one is used' \
|
|||
fi
|
||||
}
|
||||
}
|
||||
complete-command screen-focus client
|
||||
|
||||
alias global focus screen-focus
|
||||
alias global terminal screen-terminal-vertical
|
||||
|
|
|
@ -30,28 +30,33 @@ define-command -hidden -params 2.. tmux-terminal-impl %{
|
|||
}
|
||||
}
|
||||
|
||||
define-command tmux-terminal-vertical -params 1.. -shell-completion -docstring '
|
||||
define-command tmux-terminal-vertical -params 1.. -docstring '
|
||||
tmux-terminal-vertical <program> [<arguments>]: create a new terminal as a tmux pane
|
||||
The current pane is split into two, top and bottom
|
||||
The program passed as argument will be executed in the new terminal' \
|
||||
%{
|
||||
tmux-terminal-impl 'split-window -v' %arg{@}
|
||||
}
|
||||
define-command tmux-terminal-horizontal -params 1.. -shell-completion -docstring '
|
||||
complete-command tmux-terminal-vertical shell
|
||||
|
||||
define-command tmux-terminal-horizontal -params 1.. -docstring '
|
||||
tmux-terminal-horizontal <program> [<arguments>]: create a new terminal as a tmux pane
|
||||
The current pane is split into two, left and right
|
||||
The program passed as argument will be executed in the new terminal' \
|
||||
%{
|
||||
tmux-terminal-impl 'split-window -h' %arg{@}
|
||||
}
|
||||
define-command tmux-terminal-window -params 1.. -shell-completion -docstring '
|
||||
complete-command tmux-terminal-horizontal shell
|
||||
|
||||
define-command tmux-terminal-window -params 1.. -docstring '
|
||||
tmux-terminal-window <program> [<arguments>] [<arguments>]: create a new terminal as a tmux window
|
||||
The program passed as argument will be executed in the new terminal' \
|
||||
%{
|
||||
tmux-terminal-impl 'new-window' %arg{@}
|
||||
}
|
||||
complete-command tmux-terminal-window shell
|
||||
|
||||
define-command tmux-focus -params ..1 -client-completion -docstring '
|
||||
define-command tmux-focus -params ..1 -docstring '
|
||||
tmux-focus [<client>]: focus the given client
|
||||
If no client is passed then the current one is used' \
|
||||
%{
|
||||
|
@ -66,6 +71,7 @@ If no client is passed then the current one is used' \
|
|||
fi
|
||||
}
|
||||
}
|
||||
complete-command tmux-focus client
|
||||
|
||||
## The default behaviour for the `new` command is to open an horizontal pane in a tmux session
|
||||
alias global focus tmux-focus
|
||||
|
|
|
@ -28,7 +28,7 @@ A shell command is appended to the one set in this option at runtime} \
|
|||
done
|
||||
}
|
||||
|
||||
define-command wayland-terminal -params 1.. -shell-completion -docstring '
|
||||
define-command wayland-terminal -params 1.. -docstring '
|
||||
wayland-terminal <program> [<arguments>]: create a new terminal as a Wayland window
|
||||
The program passed as argument will be executed in the new terminal' \
|
||||
%{
|
||||
|
@ -43,13 +43,15 @@ The program passed as argument will be executed in the new terminal' \
|
|||
}
|
||||
}
|
||||
}
|
||||
complete-command wayland-terminal shell
|
||||
|
||||
define-command wayland-focus -params ..1 -client-completion -docstring '
|
||||
define-command wayland-focus -params ..1 -docstring '
|
||||
wayland-focus [<kakoune_client>]: focus a given client''s window
|
||||
If no client is passed, then the current client is used' \
|
||||
%{
|
||||
fail There is no way to focus another window on Wayland
|
||||
}
|
||||
complete-command wayland-focus client
|
||||
|
||||
alias global focus wayland-focus
|
||||
alias global terminal wayland-terminal
|
||||
|
|
|
@ -33,7 +33,7 @@ A shell command is appended to the one set in this option at runtime} \
|
|||
done
|
||||
}
|
||||
|
||||
define-command x11-terminal -params 1.. -shell-completion -docstring '
|
||||
define-command x11-terminal -params 1.. -docstring '
|
||||
x11-terminal <program> [<arguments>]: create a new terminal as an X11 window
|
||||
The program passed as argument will be executed in the new terminal' \
|
||||
%{
|
||||
|
@ -48,8 +48,9 @@ The program passed as argument will be executed in the new terminal' \
|
|||
}
|
||||
}
|
||||
}
|
||||
complete-command x11-terminal shell
|
||||
|
||||
define-command x11-focus -params ..1 -client-completion -docstring '
|
||||
define-command x11-focus -params ..1 -docstring '
|
||||
x11-focus [<kakoune_client>]: focus a given client''s window
|
||||
If no client is passed, then the current client is used' \
|
||||
%{
|
||||
|
@ -62,6 +63,7 @@ If no client is passed, then the current client is used' \
|
|||
fi
|
||||
}
|
||||
}
|
||||
complete-command x11-focus client
|
||||
|
||||
alias global focus x11-focus
|
||||
alias global terminal x11-terminal
|
||||
|
|
|
@ -41,6 +41,15 @@ void CommandManager::register_command(String command_name,
|
|||
std::move(completer) };
|
||||
}
|
||||
|
||||
void CommandManager::set_command_completer(StringView command_name, CommandCompleter completer)
|
||||
{
|
||||
auto it = m_commands.find(command_name);
|
||||
if (it == m_commands.end())
|
||||
throw runtime_error(format("no such command '{}'", command_name));
|
||||
|
||||
it->value.completer = std::move(completer);
|
||||
}
|
||||
|
||||
bool CommandManager::module_defined(StringView module_name) const
|
||||
{
|
||||
return m_modules.find(module_name) != m_modules.end();
|
||||
|
|
|
@ -112,6 +112,8 @@ public:
|
|||
CommandHelper helper = CommandHelper(),
|
||||
CommandCompleter completer = CommandCompleter());
|
||||
|
||||
void set_command_completer(StringView command_name, CommandCompleter completer);
|
||||
|
||||
Completions complete_command_name(const Context& context, StringView query) const;
|
||||
|
||||
void clear_last_complete_command() { m_last_complete_command = String{}; }
|
||||
|
|
171
src/commands.cc
171
src/commands.cc
|
@ -1159,6 +1159,82 @@ Vector<String> params_to_shell(const ParametersParser& parser)
|
|||
return vars;
|
||||
}
|
||||
|
||||
CommandCompleter make_command_completer(StringView type, StringView param, Completions::Flags completions_flags)
|
||||
{
|
||||
if (type == "file")
|
||||
{
|
||||
return [=](const Context& context, CompletionFlags flags,
|
||||
CommandParameters params,
|
||||
size_t token_to_complete, ByteCount pos_in_token) {
|
||||
const String& prefix = params[token_to_complete];
|
||||
const auto& ignored_files = context.options()["ignored_files"].get<Regex>();
|
||||
return Completions{0_byte, pos_in_token,
|
||||
complete_filename(prefix, ignored_files,
|
||||
pos_in_token, FilenameFlags::Expand),
|
||||
completions_flags};
|
||||
};
|
||||
}
|
||||
else if (type == "client")
|
||||
{
|
||||
return [=](const Context& context, CompletionFlags flags,
|
||||
CommandParameters params,
|
||||
size_t token_to_complete, ByteCount pos_in_token)
|
||||
{
|
||||
const String& prefix = params[token_to_complete];
|
||||
auto& cm = ClientManager::instance();
|
||||
return Completions{0_byte, pos_in_token,
|
||||
cm.complete_client_name(prefix, pos_in_token),
|
||||
completions_flags};
|
||||
};
|
||||
}
|
||||
else if (type == "buffer")
|
||||
{
|
||||
return [=](const Context& context, CompletionFlags flags,
|
||||
CommandParameters params,
|
||||
size_t token_to_complete, ByteCount pos_in_token)
|
||||
{
|
||||
return add_flags(complete_buffer_name<false>, completions_flags)(
|
||||
context, flags, params[token_to_complete], pos_in_token);
|
||||
};
|
||||
}
|
||||
else if (type == "shell-script")
|
||||
{
|
||||
if (param.empty())
|
||||
throw runtime_error("shell-script requires a shell script parameter");
|
||||
|
||||
return ShellScriptCompleter{param.str(), completions_flags};
|
||||
}
|
||||
else if (type == "shell-script-candidates")
|
||||
{
|
||||
if (param.empty())
|
||||
throw runtime_error("shell-script-candidates requires a shell script parameter");
|
||||
|
||||
return ShellCandidatesCompleter{param.str(), completions_flags};
|
||||
}
|
||||
else if (type == "command")
|
||||
{
|
||||
return [](const Context& context, CompletionFlags flags,
|
||||
CommandParameters params,
|
||||
size_t token_to_complete, ByteCount pos_in_token)
|
||||
{
|
||||
return CommandManager::instance().complete(
|
||||
context, flags, params, token_to_complete, pos_in_token);
|
||||
};
|
||||
}
|
||||
else if (type == "shell")
|
||||
{
|
||||
return [=](const Context& context, CompletionFlags flags,
|
||||
CommandParameters params,
|
||||
size_t token_to_complete, ByteCount pos_in_token)
|
||||
{
|
||||
return add_flags(shell_complete, completions_flags)(
|
||||
context, flags, params[token_to_complete], pos_in_token);
|
||||
};
|
||||
}
|
||||
else
|
||||
throw runtime_error(format("invalid command completion type '{}'", type));
|
||||
}
|
||||
|
||||
void define_command(const ParametersParser& parser, Context& context, const ShellContext&)
|
||||
{
|
||||
const String& cmd_name = parser[0];
|
||||
|
@ -1211,75 +1287,22 @@ void define_command(const ParametersParser& parser, Context& context, const Shel
|
|||
}
|
||||
|
||||
CommandCompleter completer;
|
||||
if (parser.get_switch("file-completion"))
|
||||
for (StringView completion_switch : {"file-completion", "client-completion", "buffer-completion",
|
||||
"shell-script-completion", "shell-script-candidates",
|
||||
"command-completion", "shell-completion"})
|
||||
{
|
||||
completer = [=](const Context& context, CompletionFlags flags,
|
||||
CommandParameters params,
|
||||
size_t token_to_complete, ByteCount pos_in_token)
|
||||
if (auto param = parser.get_switch(completion_switch))
|
||||
{
|
||||
const String& prefix = params[token_to_complete];
|
||||
const auto& ignored_files = context.options()["ignored_files"].get<Regex>();
|
||||
return Completions{0_byte, pos_in_token,
|
||||
complete_filename(prefix, ignored_files,
|
||||
pos_in_token, FilenameFlags::Expand),
|
||||
completions_flags};
|
||||
};
|
||||
constexpr StringView suffix = "-completion";
|
||||
if (completion_switch.ends_with(suffix))
|
||||
completion_switch = completion_switch.substr(0, completion_switch.length() - suffix.length());
|
||||
completer = make_command_completer(completion_switch, *param, completions_flags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (parser.get_switch("client-completion"))
|
||||
{
|
||||
completer = [=](const Context& context, CompletionFlags flags,
|
||||
CommandParameters params,
|
||||
size_t token_to_complete, ByteCount pos_in_token)
|
||||
{
|
||||
const String& prefix = params[token_to_complete];
|
||||
auto& cm = ClientManager::instance();
|
||||
return Completions{0_byte, pos_in_token,
|
||||
cm.complete_client_name(prefix, pos_in_token),
|
||||
completions_flags};
|
||||
};
|
||||
}
|
||||
else if (parser.get_switch("buffer-completion"))
|
||||
{
|
||||
completer = [=](const Context& context, CompletionFlags flags,
|
||||
CommandParameters params,
|
||||
size_t token_to_complete, ByteCount pos_in_token)
|
||||
{
|
||||
return add_flags(complete_buffer_name<false>, completions_flags)(
|
||||
context, flags, params[token_to_complete], pos_in_token);
|
||||
};
|
||||
}
|
||||
else if (auto shell_script = parser.get_switch("shell-script-completion"))
|
||||
{
|
||||
completer = ShellScriptCompleter{shell_script->str(), completions_flags};
|
||||
}
|
||||
else if (auto shell_script = parser.get_switch("shell-script-candidates"))
|
||||
{
|
||||
completer = ShellCandidatesCompleter{shell_script->str(), completions_flags};
|
||||
}
|
||||
else if (parser.get_switch("command-completion"))
|
||||
{
|
||||
completer = [](const Context& context, CompletionFlags flags,
|
||||
CommandParameters params,
|
||||
size_t token_to_complete, ByteCount pos_in_token)
|
||||
{
|
||||
return CommandManager::instance().complete(
|
||||
context, flags, params, token_to_complete, pos_in_token);
|
||||
};
|
||||
}
|
||||
else if (parser.get_switch("shell-completion"))
|
||||
{
|
||||
completer = [=](const Context& context, CompletionFlags flags,
|
||||
CommandParameters params,
|
||||
size_t token_to_complete, ByteCount pos_in_token)
|
||||
{
|
||||
return add_flags(shell_complete, completions_flags)(
|
||||
context, flags, params[token_to_complete], pos_in_token);
|
||||
};
|
||||
}
|
||||
|
||||
auto docstring = trim_indent(parser.get_switch("docstring").value_or(StringView{}));
|
||||
|
||||
cm.register_command(cmd_name, cmd, docstring, desc, flags, CommandHelper{}, completer);
|
||||
cm.register_command(cmd_name, cmd, docstring, desc, flags, CommandHelper{}, std::move(completer));
|
||||
}
|
||||
|
||||
const CommandDesc define_command_cmd = {
|
||||
|
@ -1354,6 +1377,25 @@ const CommandDesc unalias_cmd = {
|
|||
}
|
||||
};
|
||||
|
||||
const CommandDesc complete_command_cmd = {
|
||||
"complete-command",
|
||||
"compl",
|
||||
"complete-command [<switches>] <name> <type> [<param>]\n"
|
||||
"define command completion",
|
||||
ParameterDesc{
|
||||
{ { "menu", { false, "treat completions as the only valid inputs" } }, },
|
||||
ParameterDesc::Flags::None, 2, 3},
|
||||
CommandFlags::None,
|
||||
CommandHelper{},
|
||||
make_completer(complete_command_name),
|
||||
[](const ParametersParser& parser, Context& context, const ShellContext&)
|
||||
{
|
||||
const Completions::Flags flags = parser.get_switch("menu") ? Completions::Flags::Menu : Completions::Flags::None;
|
||||
CommandCompleter completer = make_command_completer(parser[1], parser.positional_count() >= 3 ? parser[2] : StringView{}, flags);
|
||||
CommandManager::instance().set_command_completer(parser[0], std::move(completer));
|
||||
}
|
||||
};
|
||||
|
||||
const CommandDesc echo_cmd = {
|
||||
"echo",
|
||||
nullptr,
|
||||
|
@ -2719,6 +2761,7 @@ void register_commands()
|
|||
register_command(remove_hook_cmd);
|
||||
register_command(trigger_user_hook_cmd);
|
||||
register_command(define_command_cmd);
|
||||
register_command(complete_command_cmd);
|
||||
register_command(alias_cmd);
|
||||
register_command(unalias_cmd);
|
||||
register_command(echo_cmd);
|
||||
|
|
|
@ -46,6 +46,7 @@ struct {
|
|||
} constexpr version_notes[] = { {
|
||||
0,
|
||||
"» pipe commands do not append final end-of-lines anymore\n"
|
||||
"» {+u}complete-command{} to configure command completion\n"
|
||||
}, {
|
||||
20211107,
|
||||
"» colored and curly underlines support (undocumented in 20210828)\n"
|
||||
|
|
|
@ -67,6 +67,9 @@ public:
|
|||
[[gnu::always_inline]]
|
||||
bool empty() const { return type().length() == 0_byte; }
|
||||
|
||||
bool starts_with(StringView str) const;
|
||||
bool ends_with(StringView str) const;
|
||||
|
||||
ByteCount byte_count_to(CharCount count) const
|
||||
{ return utf8::advance(begin(), end(), count) - begin(); }
|
||||
|
||||
|
@ -306,6 +309,22 @@ inline StringView StringOps<Type, CharType>::substr(ColumnCount from, ColumnCoun
|
|||
return StringView{ beg, utf8::advance(beg, end(), length) };
|
||||
}
|
||||
|
||||
template<typename Type, typename CharType>
|
||||
inline bool StringOps<Type, CharType>::starts_with(StringView str) const
|
||||
{
|
||||
if (type().length() < str.length())
|
||||
return false;
|
||||
return substr(0, str.length()) == str;
|
||||
}
|
||||
|
||||
template<typename Type, typename CharType>
|
||||
inline bool StringOps<Type, CharType>::ends_with(StringView str) const
|
||||
{
|
||||
if (type().length() < str.length())
|
||||
return false;
|
||||
return substr(type().length() - str.length()) == str;
|
||||
}
|
||||
|
||||
inline String& operator+=(String& lhs, StringView rhs)
|
||||
{
|
||||
lhs.append(rhs.data(), rhs.length());
|
||||
|
|
|
@ -396,6 +396,16 @@ UnitTest test_string{[]()
|
|||
{
|
||||
kak_assert(String("youpi ") + "matin" == "youpi matin");
|
||||
|
||||
kak_assert(StringView{"youpi"}.starts_with(""));
|
||||
kak_assert(StringView{"youpi"}.starts_with("you"));
|
||||
kak_assert(StringView{"youpi"}.starts_with("youpi"));
|
||||
kak_assert(not StringView{"youpi"}.starts_with("youpi!"));
|
||||
|
||||
kak_assert(StringView{"youpi"}.ends_with(""));
|
||||
kak_assert(StringView{"youpi"}.ends_with("pi"));
|
||||
kak_assert(StringView{"youpi"}.ends_with("youpi"));
|
||||
kak_assert(not StringView{"youpi"}.ends_with("oup"));
|
||||
|
||||
auto wrapped = "wrap this paragraph\n respecting whitespaces and much_too_long_words" | wrap_at(16) | gather<Vector>();
|
||||
kak_assert(wrapped.size() == 6);
|
||||
kak_assert(wrapped[0] == "wrap this");
|
||||
|
|
Loading…
Reference in New Issue
Block a user