From 843b1318adc7a5d48114bfc340805413932ea79d Mon Sep 17 00:00:00 2001 From: "Sean P. Kane" Date: Mon, 22 Dec 2025 11:53:59 -0800 Subject: [PATCH 1/3] Add support for global justfile completions --- completions/just.bash | 13 +++++++++++-- completions/just.elvish | 23 +++++++++++++++++++++++ completions/just.fish | 12 ++++++++++-- completions/just.nu | 10 ++++++++-- completions/just.powershell | 6 +++++- completions/just.zsh | 37 +++++++++++++++++++++++++++++++++---- 6 files changed, 90 insertions(+), 11 deletions(-) diff --git a/completions/just.bash b/completions/just.bash index 51e630c86e..11a686cf8a 100644 --- a/completions/just.bash +++ b/completions/just.bash @@ -35,11 +35,20 @@ _just() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 else - local recipes=$(just --summary 2> /dev/null) + # Check if --global-justfile or -g flag is present + local use_global="" + for word in "${words[@]}"; do + if [[ "$word" == "-g" || "$word" == "--global-justfile" ]]; then + use_global="--global-justfile" + break + fi + done + + local recipes=$(just $use_global --summary 2> /dev/null) if echo "${cur}" | \grep -qF '/'; then local path_prefix=$(echo "${cur}" | sed 's/[/][^/]*$/\//') - local recipes=$(just --summary 2> /dev/null -- "${path_prefix}") + local recipes=$(just $use_global --summary 2> /dev/null -- "${path_prefix}") local recipes=$(printf "${path_prefix}%s\t" $recipes) fi diff --git a/completions/just.elvish b/completions/just.elvish index b2efa8edd5..9010e7d9bb 100644 --- a/completions/just.elvish +++ b/completions/just.elvish @@ -8,6 +8,16 @@ set edit:completion:arg-completer[just] = {|@words| fn cand {|text desc| edit:complex-candidate $text &display=$text' '(spaces (- 14 (wcswidth $text)))$desc } + + # Check if --global-justfile or -g flag is present + var use-global = [] + for word $words[1..-1] { + if (or (eq $word '-g') (eq $word '--global-justfile')) { + set use-global = ['--global-justfile'] + break + } + } + var command = 'just' for word $words[1..-1] { if (str:has-prefix $word '-') { @@ -90,4 +100,17 @@ set edit:completion:arg-completer[just] = {|@words| } ] $completions[$command] + + # Complete recipes if not completing an option + var current = $words[-1] + if (not (str:has-prefix $current '-')) { + try { + var recipes = [(just $@use-global --summary 2>/dev/null | str:split ' ')] + for recipe $recipes { + if (not (eq $recipe '')) { + cand $recipe '' + } + } + } catch { } + } } diff --git a/completions/just.fish b/completions/just.fish index f1202115b6..0430ece507 100644 --- a/completions/just.fish +++ b/completions/just.fish @@ -1,8 +1,16 @@ function __fish_just_complete_recipes - if string match -rq '(-f|--justfile)\s*=?(?[^\s]+)' -- (string split -- ' -- ' (commandline -pc))[1] + set -l cmdline (string split -- ' -- ' (commandline -pc))[1] + if string match -rq '(-f|--justfile)\s*=?(?[^\s]+)' -- $cmdline set -fx JUST_JUSTFILE "$justfile" end - printf "%s\n" (string split " " (just --summary)) + + # Check if --global-justfile or -g flag is present + set -l use_global + if string match -rq '(^|\s)(-g|--global-justfile)(\s|$)' -- $cmdline + set use_global --global-justfile + end + + printf "%s\n" (string split " " (just $use_global --summary)) end # don't suggest files right off diff --git a/completions/just.nu b/completions/just.nu index ab109108c7..a9b311593d 100644 --- a/completions/just.nu +++ b/completions/just.nu @@ -1,5 +1,11 @@ -def "nu-complete just" [] { - (^just --dump --unstable --dump-format json | from json).recipes | transpose recipe data | flatten | where {|row| $row.private == false } | select recipe doc parameters | rename value description +def "nu-complete just" [context: string] { + # Check if --global-justfile or -g flag is present + let use_global = if ($context | str contains " -g ") or ($context | str contains " --global-justfile ") or ($context | str ends-with " -g") or ($context | str ends-with " --global-justfile") { + ["--global-justfile"] + } else { + [] + } + (^just ...$use_global --dump --unstable --dump-format json | from json).recipes | transpose recipe data | flatten | where {|row| $row.private == false } | select recipe doc parameters | rename value description } # Just: A Command Runner diff --git a/completions/just.powershell b/completions/just.powershell index 934555242e..90a0cfcaec 100644 --- a/completions/just.powershell +++ b/completions/just.powershell @@ -103,7 +103,11 @@ Register-ArgumentCompleter -Native -CommandName 'just' -ScriptBlock { $justArgs = @("--summary") - if (Test-Path $justFileLocation) { + # Check if --global-justfile or -g flag is present + if ($commandElements -contains "-g" -or $commandElements -contains "--global-justfile") { + $justArgs += @("--global-justfile") + } + elseif (Test-Path $justFileLocation) { $justArgs += @("--justfile", $justFileLocation) } diff --git a/completions/just.zsh b/completions/just.zsh index 103362c68d..a69f7c4dcf 100644 --- a/completions/just.zsh +++ b/completions/just.zsh @@ -99,8 +99,17 @@ _just() { local lastarg=${words[${#words}]} local recipe + # Check if --global-justfile or -g flag is present + local use_global="" + for word in ${words[@]}; do + if [[ "$word" == "-g" || "$word" == "--global-justfile" ]]; then + use_global="--global-justfile" + break + fi + done + local cmds; cmds=( - ${(s: :)$(_call_program commands just --summary)} + ${(s: :)$(_call_program commands just $use_global --summary)} ) # Find first recipe name @@ -136,11 +145,21 @@ _just() { _just_commands() { [[ $PREFIX = -* ]] && return 1 integer ret=1 + + # Check if --global-justfile or -g flag is present + local use_global="" + for word in ${words[@]}; do + if [[ "$word" == "-g" || "$word" == "--global-justfile" ]]; then + use_global="--global-justfile" + break + fi + done + local variables; variables=( - ${(s: :)$(_call_program commands just --variables)} + ${(s: :)$(_call_program commands just $use_global --variables)} ) local commands; commands=( - ${${${(M)"${(f)$(_call_program commands just --list)}":# *}/ ##/}/ ##/:Args: } + ${${${(M)"${(f)$(_call_program commands just $use_global --list)}":# *}/ ##/}/ ##/:Args: } ) if compset -P '*='; then @@ -159,8 +178,18 @@ if [ "$funcstack[1]" = "_just" ]; then _just_variables() { [[ $PREFIX = -* ]] && return 1 integer ret=1 + + # Check if --global-justfile or -g flag is present + local use_global="" + for word in ${words[@]}; do + if [[ "$word" == "-g" || "$word" == "--global-justfile" ]]; then + use_global="--global-justfile" + break + fi + done + local variables; variables=( - ${(s: :)$(_call_program commands just --variables)} + ${(s: :)$(_call_program commands just $use_global --variables)} ) if compset -P '*='; then From d3ab90760cbd5afd2a2ecac87d0e442a73908806 Mon Sep 17 00:00:00 2001 From: "Sean P. Kane" Date: Mon, 22 Dec 2025 12:39:59 -0800 Subject: [PATCH 2/3] Update src/completions.rs to add global Justfile support --- src/completions.rs | 117 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 108 insertions(+), 9 deletions(-) diff --git a/src/completions.rs b/src/completions.rs index 97eda5b4c1..ad2907a5b0 100644 --- a/src/completions.rs +++ b/src/completions.rs @@ -79,6 +79,11 @@ mod tests { replace(&mut script, needle, replacement); } } + clap_complete::Shell::Elvish => { + for (needle, replacement) in ELVISH_COMPLETION_REPLACEMENTS { + replace(&mut script, needle, replacement); + } + } clap_complete::Shell::Fish => { script.insert_str(0, FISH_RECIPE_COMPLETIONS); } @@ -101,10 +106,18 @@ mod tests { } const FISH_RECIPE_COMPLETIONS: &str = r#"function __fish_just_complete_recipes - if string match -rq '(-f|--justfile)\s*=?(?[^\s]+)' -- (string split -- ' -- ' (commandline -pc))[1] + set -l cmdline (string split -- ' -- ' (commandline -pc))[1] + if string match -rq '(-f|--justfile)\s*=?(?[^\s]+)' -- $cmdline set -fx JUST_JUSTFILE "$justfile" end - printf "%s\n" (string split " " (just --summary)) + + # Check if --global-justfile or -g flag is present + set -l use_global + if string match -rq '(^|\s)(-g|--global-justfile)(\s|$)' -- $cmdline + set use_global --global-justfile + end + + printf "%s\n" (string split " " (just $use_global --summary)) end # don't suggest files right off @@ -116,6 +129,50 @@ complete -c just -a '(__fish_just_complete_recipes)' # autogenerated completions "#; + const ELVISH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[ + ( + r#" fn cand {|text desc| + edit:complex-candidate $text &display=$text' '(spaces (- 14 (wcswidth $text)))$desc + } + var command = 'just'"#, + r#" fn cand {|text desc| + edit:complex-candidate $text &display=$text' '(spaces (- 14 (wcswidth $text)))$desc + } + + # Check if --global-justfile or -g flag is present + var use-global = [] + for word $words[1..-1] { + if (or (eq $word '-g') (eq $word '--global-justfile')) { + set use-global = ['--global-justfile'] + break + } + } + + var command = 'just'"#, + ), + ( + r#" ] + $completions[$command] +}"#, + r#" ] + $completions[$command] + + # Complete recipes if not completing an option + var current = $words[-1] + if (not (str:has-prefix $current '-')) { + try { + var recipes = [(just $@use-global --summary 2>/dev/null | str:split ' ')] + for recipe $recipes { + if (not (eq $recipe '')) { + cand $recipe '' + } + } + } catch { } + } +}"#, + ), + ]; + const ZSH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[ ( r#" _arguments "${_arguments_options[@]}" : \"#, @@ -149,8 +206,17 @@ complete -c just -a '(__fish_just_complete_recipes)' local lastarg=${words[${#words}]} local recipe + # Check if --global-justfile or -g flag is present + local use_global="" + for word in ${words[@]}; do + if [[ "$word" == "-g" || "$word" == "--global-justfile" ]]; then + use_global="--global-justfile" + break + fi + done + local cmds; cmds=( - ${(s: :)$(_call_program commands just --summary)} + ${(s: :)$(_call_program commands just $use_global --summary)} ) # Find first recipe name @@ -185,11 +251,21 @@ complete -c just -a '(__fish_just_complete_recipes)' " local commands; commands=()", r#" [[ $PREFIX = -* ]] && return 1 integer ret=1 + + # Check if --global-justfile or -g flag is present + local use_global="" + for word in ${words[@]}; do + if [[ "$word" == "-g" || "$word" == "--global-justfile" ]]; then + use_global="--global-justfile" + break + fi + done + local variables; variables=( - ${(s: :)$(_call_program commands just --variables)} + ${(s: :)$(_call_program commands just $use_global --variables)} ) local commands; commands=( - ${${${(M)"${(f)$(_call_program commands just --list)}":# *}/ ##/}/ ##/:Args: } + ${${${(M)"${(f)$(_call_program commands just $use_global --list)}":# *}/ ##/}/ ##/:Args: } ) "#, ), @@ -211,8 +287,18 @@ complete -c just -a '(__fish_just_complete_recipes)' _just_variables() { [[ $PREFIX = -* ]] && return 1 integer ret=1 + + # Check if --global-justfile or -g flag is present + local use_global="" + for word in ${words[@]}; do + if [[ "$word" == "-g" || "$word" == "--global-justfile" ]]; then + use_global="--global-justfile" + break + fi + done + local variables; variables=( - ${(s: :)$(_call_program commands just --variables)} + ${(s: :)$(_call_program commands just $use_global --variables)} ) if compset -P '*='; then @@ -242,7 +328,11 @@ _just "$@""#, $justArgs = @("--summary") - if (Test-Path $justFileLocation) { + # Check if --global-justfile or -g flag is present + if ($commandElements -contains "-g" -or $commandElements -contains "--global-justfile") { + $justArgs += @("--global-justfile") + } + elseif (Test-Path $justFileLocation) { $justArgs += @("--justfile", $justFileLocation) } @@ -267,11 +357,20 @@ _just "$@""#, COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 elif [[ ${COMP_CWORD} -eq 1 ]]; then - local recipes=$(just --summary 2> /dev/null) + # Check if --global-justfile or -g flag is present + local use_global="" + for word in "${words[@]}"; do + if [[ "$word" == "-g" || "$word" == "--global-justfile" ]]; then + use_global="--global-justfile" + break + fi + done + + local recipes=$(just $use_global --summary 2> /dev/null) if echo "${cur}" | \grep -qF '/'; then local path_prefix=$(echo "${cur}" | sed 's/[/][^/]*$/\//') - local recipes=$(just --summary 2> /dev/null -- "${path_prefix}") + local recipes=$(just $use_global --summary 2> /dev/null -- "${path_prefix}") local recipes=$(printf "${path_prefix}%s\t" $recipes) fi From 16caec66c9059c29b027784121563a4f9ca3f092 Mon Sep 17 00:00:00 2001 From: Hugo Posca Date: Mon, 5 Jan 2026 14:31:02 -0800 Subject: [PATCH 3/3] Working autocomplete for ZSH With the help of ClaudeAI (and lots of patience) Now `just -g ` is working as expected including for modules, so one can run `just -g mod` and it will be autocompleted to `just -g module::` and you can then `just -g module::` to see all the available recipes. --- completions/just.zsh | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/completions/just.zsh b/completions/just.zsh index a69f7c4dcf..69e40ef441 100644 --- a/completions/just.zsh +++ b/completions/just.zsh @@ -44,6 +44,7 @@ _just() { '--request=[Execute . For internal testing purposes only. May be changed or removed at any time.]: :_default' \ '-s+[Show recipe at ]: :(_just_commands)' \ '--show=[Show recipe at ]: :(_just_commands)' \ +'()--usage=[Print recipe usage information]:PATH:_default' \ '--check[Run \`--fmt\` in '\''check'\'' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required.]' \ '--clear-shell-args[Clear shell arguments]' \ '(-q --quiet)-n[Print what just would do without doing it]' \ @@ -101,7 +102,7 @@ _just() { # Check if --global-justfile or -g flag is present local use_global="" - for word in ${words[@]}; do + for word in "${words[@]}"; do if [[ "$word" == "-g" || "$word" == "--global-justfile" ]]; then use_global="--global-justfile" break @@ -128,7 +129,7 @@ _just() { _message "value" elif [[ $recipe ]]; then # Show usage message - _message "`just --show $recipe`" + _message "`just $use_global --show $recipe`" # Or complete with other commands #_arguments -s -S $common '*:: :_just_commands' else @@ -148,29 +149,24 @@ _just_commands() { # Check if --global-justfile or -g flag is present local use_global="" - for word in ${words[@]}; do + for word in "${words[@]}"; do if [[ "$word" == "-g" || "$word" == "--global-justfile" ]]; then use_global="--global-justfile" break fi done - local variables; variables=( - ${(s: :)$(_call_program commands just $use_global --variables)} - ) - local commands; commands=( - ${${${(M)"${(f)$(_call_program commands just $use_global --list)}":# *}/ ##/}/ ##/:Args: } - ) + # Get recipes from --summary (includes full module::recipe paths) + local summary_output=$(_call_program commands just $use_global --summary) - if compset -P '*='; then - case "${${words[-1]%=*}#*=}" in - *) _message 'value' && ret=0 ;; - esac - else - _describe -t variables 'variables' variables -qS "=" && ret=0 - _describe -t commands 'just commands' commands "$@" - fi + # Split into array properly + local -a recipes + recipes=("${(@s: :)summary_output}") + # Add recipes directly to completion + compadd -a recipes + + return 0 } if [ "$funcstack[1]" = "_just" ]; then @@ -178,16 +174,14 @@ if [ "$funcstack[1]" = "_just" ]; then _just_variables() { [[ $PREFIX = -* ]] && return 1 integer ret=1 - # Check if --global-justfile or -g flag is present local use_global="" - for word in ${words[@]}; do + for word in "${words[@]}"; do if [[ "$word" == "-g" || "$word" == "--global-justfile" ]]; then use_global="--global-justfile" break fi done - local variables; variables=( ${(s: :)$(_call_program commands just $use_global --variables)} )