diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 8e6ab4b3..990a17e4 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -91,14 +91,10 @@ jobs: run: | rustup target add aarch64-pc-windows-msvc - - name: Generate Completion Scripts and Manpage + - name: Generate Manpage run: | set -euxo pipefail cargo build - mkdir -p completions - for shell in bash elvish fish nu powershell zsh; do - ./target/debug/just --completions $shell > completions/just.$shell - done mkdir -p man ./target/debug/just --man > man/just.1 diff --git a/Cargo.toml b/Cargo.toml index 6394169f..545a4c47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,6 @@ blake3 = { version = "1.5.0", features = ["rayon", "mmap"] } camino = "1.0.4" chrono = "0.4.38" clap = { version = "4.0.0", features = ["derive", "env", "wrap_help"] } -clap_complete = "=4.5.48" clap_mangen = "0.2.20" ctrlc = { version = "3.1.1", features = ["termination"] } derive-where = "1.2.7" @@ -61,6 +60,7 @@ nix = { version = "0.30.1", features = ["user"] } ctrlc = { version = "3.1.1", features = ["termination"] } [dev-dependencies] +clap_complete = "=4.5.48" executable-path = "1.0.0" pretty_assertions = "1.0.0" temptree = "0.2.0" diff --git a/completions/just.bash b/completions/just.bash new file mode 100644 index 00000000..51e630c8 --- /dev/null +++ b/completions/just.bash @@ -0,0 +1,185 @@ +_just() { + local i cur prev words cword opts cmd + COMPREPLY=() + + # Modules use "::" as the separator, which is considered a wordbreak character in bash. + # The _get_comp_words_by_ref function is a hack to allow for exceptions to this rule without + # modifying the global COMP_WORDBREAKS environment variable. + if type _get_comp_words_by_ref &>/dev/null; then + _get_comp_words_by_ref -n : cur prev words cword + else + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + words=$COMP_WORDS + cword=$COMP_CWORD + fi + + cmd="" + opts="" + + for i in ${words[@]} + do + case "${cmd},${i}" in + ",$1") + cmd="just" + ;; + *) + ;; + esac + done + + case "${cmd}" in + just) + opts="-E -n -g -f -q -u -v -d -c -e -l -s -h -V --alias-style --ceiling --check --chooser --clear-shell-args --color --command-color --cygpath --dotenv-filename --dotenv-path --dry-run --dump-format --explain --global-justfile --highlight --justfile --list-heading --list-prefix --list-submodules --no-aliases --no-deps --no-dotenv --no-highlight --one --quiet --allow-missing --set --shell --shell-arg --shell-command --tempdir --timestamp --timestamp-format --unsorted --unstable --verbose --working-directory --yes --changelog --choose --command --completions --dump --edit --evaluate --fmt --groups --init --list --man --request --show --summary --variables --help --version [ARGUMENTS]..." + if [[ ${cur} == -* ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + else + local recipes=$(just --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=$(printf "${path_prefix}%s\t" $recipes) + fi + + if [[ $? -eq 0 ]]; then + COMPREPLY=( $(compgen -W "${recipes}" -- "${cur}") ) + if type __ltrim_colon_completions &>/dev/null; then + __ltrim_colon_completions "$cur" + fi + return 0 + fi + fi + case "${prev}" in + --alias-style) + COMPREPLY=($(compgen -W "left right separate" -- "${cur}")) + return 0 + ;; + --ceiling) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --chooser) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always auto never" -- "${cur}")) + return 0 + ;; + --command-color) + COMPREPLY=($(compgen -W "black blue cyan green purple red yellow" -- "${cur}")) + return 0 + ;; + --cygpath) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --dotenv-filename) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --dotenv-path) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -E) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --dump-format) + COMPREPLY=($(compgen -W "json just" -- "${cur}")) + return 0 + ;; + --justfile) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -f) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --list-heading) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --list-prefix) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --set) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --shell) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --shell-arg) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --tempdir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --timestamp-format) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --working-directory) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -d) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --command) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -c) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --completions) + COMPREPLY=($(compgen -W "bash elvish fish nushell powershell zsh" -- "${cur}")) + return 0 + ;; + --list) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -l) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --request) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --show) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -s) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + esac +} + +if [[ "${BASH_VERSINFO[0]}" -eq 4 && "${BASH_VERSINFO[1]}" -ge 4 || "${BASH_VERSINFO[0]}" -gt 4 ]]; then + complete -F _just -o nosort -o bashdefault -o default just +else + complete -F _just -o bashdefault -o default just +fi diff --git a/completions/just.elvish b/completions/just.elvish new file mode 100644 index 00000000..b2efa8ed --- /dev/null +++ b/completions/just.elvish @@ -0,0 +1,93 @@ +use builtin; +use str; + +set edit:completion:arg-completer[just] = {|@words| + fn spaces {|n| + builtin:repeat $n ' ' | str:join '' + } + fn cand {|text desc| + edit:complex-candidate $text &display=$text' '(spaces (- 14 (wcswidth $text)))$desc + } + var command = 'just' + for word $words[1..-1] { + if (str:has-prefix $word '-') { + break + } + set command = $command';'$word + } + var completions = [ + &'just'= { + cand --alias-style 'Set list command alias display style' + cand --ceiling 'Do not ascend above directory when searching for a justfile.' + cand --chooser 'Override binary invoked by `--choose`' + cand --color 'Print colorful output' + cand --command-color 'Echo recipe lines in ' + cand --cygpath 'Use binary at to convert between unix and Windows paths.' + cand --dotenv-filename 'Search for environment file named instead of `.env`' + cand -E 'Load as environment file instead of searching for one' + cand --dotenv-path 'Load as environment file instead of searching for one' + cand --dump-format 'Dump justfile as ' + cand -f 'Use as justfile' + cand --justfile 'Use as justfile' + cand --list-heading 'Print before list' + cand --list-prefix 'Print before each list item' + cand --set 'Override with ' + cand --shell 'Invoke to run recipes' + cand --shell-arg 'Invoke shell with as an argument' + cand --tempdir 'Save temporary files to .' + cand --timestamp-format 'Timestamp format string' + cand -d 'Use as working directory. --justfile must also be set' + cand --working-directory 'Use as working directory. --justfile must also be set' + cand -c 'Run an arbitrary command with the working directory, `.env`, overrides, and exports set' + cand --command 'Run an arbitrary command with the working directory, `.env`, overrides, and exports set' + cand --completions 'Print shell completion script for ' + cand -l 'List available recipes in or root if omitted' + cand --list 'List available recipes in or root if omitted' + cand --request 'Execute . For internal testing purposes only. May be changed or removed at any time.' + cand -s 'Show recipe at ' + cand --show 'Show recipe at ' + cand --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.' + cand --clear-shell-args 'Clear shell arguments' + cand -n 'Print what just would do without doing it' + cand --dry-run 'Print what just would do without doing it' + cand --explain 'Print recipe doc comment before running it' + cand -g 'Use global justfile' + cand --global-justfile 'Use global justfile' + cand --highlight 'Highlight echoed recipe lines in bold' + cand --list-submodules 'List recipes in submodules' + cand --no-aliases 'Don''t show aliases in list' + cand --no-deps 'Don''t run recipe dependencies' + cand --no-dotenv 'Don''t load `.env` file' + cand --no-highlight 'Don''t highlight echoed recipe lines in bold' + cand --one 'Forbid multiple recipes from being invoked on the command line' + cand -q 'Suppress all output' + cand --quiet 'Suppress all output' + cand --allow-missing 'Ignore missing recipe and module errors' + cand --shell-command 'Invoke with the shell used to run recipe lines and backticks' + cand --timestamp 'Print recipe command timestamps' + cand -u 'Return list and summary entries in source order' + cand --unsorted 'Return list and summary entries in source order' + cand --unstable 'Enable unstable features' + cand -v 'Use verbose output' + cand --verbose 'Use verbose output' + cand --yes 'Automatically confirm all recipes.' + cand --changelog 'Print changelog' + cand --choose 'Select one or more recipes to run using a binary chooser. If `--chooser` is not passed the chooser defaults to the value of $JUST_CHOOSER, falling back to `fzf`' + cand --dump 'Print justfile' + cand -e 'Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`' + cand --edit 'Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`' + cand --evaluate 'Evaluate and print all variables. If a variable name is given as an argument, only print that variable''s value.' + cand --fmt 'Format and overwrite justfile' + cand --groups 'List recipe groups' + cand --init 'Initialize new justfile in project root' + cand --man 'Print man page' + cand --summary 'List names of available recipes' + cand --variables 'List names of variables' + cand -h 'Print help' + cand --help 'Print help' + cand -V 'Print version' + cand --version 'Print version' + } + ] + $completions[$command] +} diff --git a/completions/just.fish b/completions/just.fish new file mode 100644 index 00000000..f1202115 --- /dev/null +++ b/completions/just.fish @@ -0,0 +1,86 @@ +function __fish_just_complete_recipes + if string match -rq '(-f|--justfile)\s*=?(?[^\s]+)' -- (string split -- ' -- ' (commandline -pc))[1] + set -fx JUST_JUSTFILE "$justfile" + end + printf "%s\n" (string split " " (just --summary)) +end + +# don't suggest files right off +complete -c just -n "__fish_is_first_arg" --no-files + +# complete recipes +complete -c just -a '(__fish_just_complete_recipes)' + +# autogenerated completions +complete -c just -l alias-style -d 'Set list command alias display style' -r -f -a "left\t'' +right\t'' +separate\t''" +complete -c just -l ceiling -d 'Do not ascend above directory when searching for a justfile.' -r -F +complete -c just -l chooser -d 'Override binary invoked by `--choose`' -r +complete -c just -l color -d 'Print colorful output' -r -f -a "always\t'' +auto\t'' +never\t''" +complete -c just -l command-color -d 'Echo recipe lines in ' -r -f -a "black\t'' +blue\t'' +cyan\t'' +green\t'' +purple\t'' +red\t'' +yellow\t''" +complete -c just -l cygpath -d 'Use binary at to convert between unix and Windows paths.' -r -F +complete -c just -l dotenv-filename -d 'Search for environment file named instead of `.env`' -r +complete -c just -s E -l dotenv-path -d 'Load as environment file instead of searching for one' -r -F +complete -c just -l dump-format -d 'Dump justfile as ' -r -f -a "json\t'' +just\t''" +complete -c just -s f -l justfile -d 'Use as justfile' -r -F +complete -c just -l list-heading -d 'Print before list' -r +complete -c just -l list-prefix -d 'Print before each list item' -r +complete -c just -l set -d 'Override with ' -r +complete -c just -l shell -d 'Invoke to run recipes' -r +complete -c just -l shell-arg -d 'Invoke shell with as an argument' -r +complete -c just -l tempdir -d 'Save temporary files to .' -r -F +complete -c just -l timestamp-format -d 'Timestamp format string' -r +complete -c just -s d -l working-directory -d 'Use as working directory. --justfile must also be set' -r -F +complete -c just -s c -l command -d 'Run an arbitrary command with the working directory, `.env`, overrides, and exports set' -r +complete -c just -l completions -d 'Print shell completion script for ' -r -f -a "bash\t'' +elvish\t'' +fish\t'' +nushell\t'' +powershell\t'' +zsh\t''" +complete -c just -s l -l list -d 'List available recipes in or root if omitted' -r +complete -c just -l request -d 'Execute . For internal testing purposes only. May be changed or removed at any time.' -r +complete -c just -s s -l show -d 'Show recipe at ' -r +complete -c just -l check -d 'Run `--fmt` in \'check\' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required.' +complete -c just -l clear-shell-args -d 'Clear shell arguments' +complete -c just -s n -l dry-run -d 'Print what just would do without doing it' +complete -c just -l explain -d 'Print recipe doc comment before running it' +complete -c just -s g -l global-justfile -d 'Use global justfile' +complete -c just -l highlight -d 'Highlight echoed recipe lines in bold' +complete -c just -l list-submodules -d 'List recipes in submodules' +complete -c just -l no-aliases -d 'Don\'t show aliases in list' +complete -c just -l no-deps -d 'Don\'t run recipe dependencies' +complete -c just -l no-dotenv -d 'Don\'t load `.env` file' +complete -c just -l no-highlight -d 'Don\'t highlight echoed recipe lines in bold' +complete -c just -l one -d 'Forbid multiple recipes from being invoked on the command line' +complete -c just -s q -l quiet -d 'Suppress all output' +complete -c just -l allow-missing -d 'Ignore missing recipe and module errors' +complete -c just -l shell-command -d 'Invoke with the shell used to run recipe lines and backticks' +complete -c just -l timestamp -d 'Print recipe command timestamps' +complete -c just -s u -l unsorted -d 'Return list and summary entries in source order' +complete -c just -l unstable -d 'Enable unstable features' +complete -c just -s v -l verbose -d 'Use verbose output' +complete -c just -l yes -d 'Automatically confirm all recipes.' +complete -c just -l changelog -d 'Print changelog' +complete -c just -l choose -d 'Select one or more recipes to run using a binary chooser. If `--chooser` is not passed the chooser defaults to the value of $JUST_CHOOSER, falling back to `fzf`' +complete -c just -l dump -d 'Print justfile' +complete -c just -s e -l edit -d 'Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`' +complete -c just -l evaluate -d 'Evaluate and print all variables. If a variable name is given as an argument, only print that variable\'s value.' +complete -c just -l fmt -d 'Format and overwrite justfile' +complete -c just -l groups -d 'List recipe groups' +complete -c just -l init -d 'Initialize new justfile in project root' +complete -c just -l man -d 'Print man page' +complete -c just -l summary -d 'List names of available recipes' +complete -c just -l variables -d 'List names of variables' +complete -c just -s h -l help -d 'Print help' +complete -c just -s V -l version -d 'Print version' diff --git a/completions/just.nu b/completions/just.nu new file mode 100644 index 00000000..ab109108 --- /dev/null +++ b/completions/just.nu @@ -0,0 +1,8 @@ +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 +} + +# Just: A Command Runner +export extern "just" [ + ...recipe: string@"nu-complete just", # Recipe(s) to run, may be with argument(s) +] diff --git a/completions/just.powershell b/completions/just.powershell new file mode 100644 index 00000000..93455524 --- /dev/null +++ b/completions/just.powershell @@ -0,0 +1,119 @@ +using namespace System.Management.Automation +using namespace System.Management.Automation.Language + +Register-ArgumentCompleter -Native -CommandName 'just' -ScriptBlock { + param($wordToComplete, $commandAst, $cursorPosition) + + $commandElements = $commandAst.CommandElements + $command = @( + 'just' + for ($i = 1; $i -lt $commandElements.Count; $i++) { + $element = $commandElements[$i] + if ($element -isnot [StringConstantExpressionAst] -or + $element.StringConstantType -ne [StringConstantType]::BareWord -or + $element.Value.StartsWith('-') -or + $element.Value -eq $wordToComplete) { + break + } + $element.Value + }) -join ';' + + $completions = @(switch ($command) { + 'just' { + [CompletionResult]::new('--alias-style', '--alias-style', [CompletionResultType]::ParameterName, 'Set list command alias display style') + [CompletionResult]::new('--ceiling', '--ceiling', [CompletionResultType]::ParameterName, 'Do not ascend above directory when searching for a justfile.') + [CompletionResult]::new('--chooser', '--chooser', [CompletionResultType]::ParameterName, 'Override binary invoked by `--choose`') + [CompletionResult]::new('--color', '--color', [CompletionResultType]::ParameterName, 'Print colorful output') + [CompletionResult]::new('--command-color', '--command-color', [CompletionResultType]::ParameterName, 'Echo recipe lines in ') + [CompletionResult]::new('--cygpath', '--cygpath', [CompletionResultType]::ParameterName, 'Use binary at to convert between unix and Windows paths.') + [CompletionResult]::new('--dotenv-filename', '--dotenv-filename', [CompletionResultType]::ParameterName, 'Search for environment file named instead of `.env`') + [CompletionResult]::new('-E', '-E ', [CompletionResultType]::ParameterName, 'Load as environment file instead of searching for one') + [CompletionResult]::new('--dotenv-path', '--dotenv-path', [CompletionResultType]::ParameterName, 'Load as environment file instead of searching for one') + [CompletionResult]::new('--dump-format', '--dump-format', [CompletionResultType]::ParameterName, 'Dump justfile as ') + [CompletionResult]::new('-f', '-f', [CompletionResultType]::ParameterName, 'Use as justfile') + [CompletionResult]::new('--justfile', '--justfile', [CompletionResultType]::ParameterName, 'Use as justfile') + [CompletionResult]::new('--list-heading', '--list-heading', [CompletionResultType]::ParameterName, 'Print before list') + [CompletionResult]::new('--list-prefix', '--list-prefix', [CompletionResultType]::ParameterName, 'Print before each list item') + [CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'Override with ') + [CompletionResult]::new('--shell', '--shell', [CompletionResultType]::ParameterName, 'Invoke to run recipes') + [CompletionResult]::new('--shell-arg', '--shell-arg', [CompletionResultType]::ParameterName, 'Invoke shell with as an argument') + [CompletionResult]::new('--tempdir', '--tempdir', [CompletionResultType]::ParameterName, 'Save temporary files to .') + [CompletionResult]::new('--timestamp-format', '--timestamp-format', [CompletionResultType]::ParameterName, 'Timestamp format string') + [CompletionResult]::new('-d', '-d', [CompletionResultType]::ParameterName, 'Use as working directory. --justfile must also be set') + [CompletionResult]::new('--working-directory', '--working-directory', [CompletionResultType]::ParameterName, 'Use as working directory. --justfile must also be set') + [CompletionResult]::new('-c', '-c', [CompletionResultType]::ParameterName, 'Run an arbitrary command with the working directory, `.env`, overrides, and exports set') + [CompletionResult]::new('--command', '--command', [CompletionResultType]::ParameterName, 'Run an arbitrary command with the working directory, `.env`, overrides, and exports set') + [CompletionResult]::new('--completions', '--completions', [CompletionResultType]::ParameterName, 'Print shell completion script for ') + [CompletionResult]::new('-l', '-l', [CompletionResultType]::ParameterName, 'List available recipes in or root if omitted') + [CompletionResult]::new('--list', '--list', [CompletionResultType]::ParameterName, 'List available recipes in or root if omitted') + [CompletionResult]::new('--request', '--request', [CompletionResultType]::ParameterName, 'Execute . For internal testing purposes only. May be changed or removed at any time.') + [CompletionResult]::new('-s', '-s', [CompletionResultType]::ParameterName, 'Show recipe at ') + [CompletionResult]::new('--show', '--show', [CompletionResultType]::ParameterName, 'Show recipe at ') + [CompletionResult]::new('--check', '--check', [CompletionResultType]::ParameterName, 'Run `--fmt` in ''check'' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required.') + [CompletionResult]::new('--clear-shell-args', '--clear-shell-args', [CompletionResultType]::ParameterName, 'Clear shell arguments') + [CompletionResult]::new('-n', '-n', [CompletionResultType]::ParameterName, 'Print what just would do without doing it') + [CompletionResult]::new('--dry-run', '--dry-run', [CompletionResultType]::ParameterName, 'Print what just would do without doing it') + [CompletionResult]::new('--explain', '--explain', [CompletionResultType]::ParameterName, 'Print recipe doc comment before running it') + [CompletionResult]::new('-g', '-g', [CompletionResultType]::ParameterName, 'Use global justfile') + [CompletionResult]::new('--global-justfile', '--global-justfile', [CompletionResultType]::ParameterName, 'Use global justfile') + [CompletionResult]::new('--highlight', '--highlight', [CompletionResultType]::ParameterName, 'Highlight echoed recipe lines in bold') + [CompletionResult]::new('--list-submodules', '--list-submodules', [CompletionResultType]::ParameterName, 'List recipes in submodules') + [CompletionResult]::new('--no-aliases', '--no-aliases', [CompletionResultType]::ParameterName, 'Don''t show aliases in list') + [CompletionResult]::new('--no-deps', '--no-deps', [CompletionResultType]::ParameterName, 'Don''t run recipe dependencies') + [CompletionResult]::new('--no-dotenv', '--no-dotenv', [CompletionResultType]::ParameterName, 'Don''t load `.env` file') + [CompletionResult]::new('--no-highlight', '--no-highlight', [CompletionResultType]::ParameterName, 'Don''t highlight echoed recipe lines in bold') + [CompletionResult]::new('--one', '--one', [CompletionResultType]::ParameterName, 'Forbid multiple recipes from being invoked on the command line') + [CompletionResult]::new('-q', '-q', [CompletionResultType]::ParameterName, 'Suppress all output') + [CompletionResult]::new('--quiet', '--quiet', [CompletionResultType]::ParameterName, 'Suppress all output') + [CompletionResult]::new('--allow-missing', '--allow-missing', [CompletionResultType]::ParameterName, 'Ignore missing recipe and module errors') + [CompletionResult]::new('--shell-command', '--shell-command', [CompletionResultType]::ParameterName, 'Invoke with the shell used to run recipe lines and backticks') + [CompletionResult]::new('--timestamp', '--timestamp', [CompletionResultType]::ParameterName, 'Print recipe command timestamps') + [CompletionResult]::new('-u', '-u', [CompletionResultType]::ParameterName, 'Return list and summary entries in source order') + [CompletionResult]::new('--unsorted', '--unsorted', [CompletionResultType]::ParameterName, 'Return list and summary entries in source order') + [CompletionResult]::new('--unstable', '--unstable', [CompletionResultType]::ParameterName, 'Enable unstable features') + [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'Use verbose output') + [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'Use verbose output') + [CompletionResult]::new('--yes', '--yes', [CompletionResultType]::ParameterName, 'Automatically confirm all recipes.') + [CompletionResult]::new('--changelog', '--changelog', [CompletionResultType]::ParameterName, 'Print changelog') + [CompletionResult]::new('--choose', '--choose', [CompletionResultType]::ParameterName, 'Select one or more recipes to run using a binary chooser. If `--chooser` is not passed the chooser defaults to the value of $JUST_CHOOSER, falling back to `fzf`') + [CompletionResult]::new('--dump', '--dump', [CompletionResultType]::ParameterName, 'Print justfile') + [CompletionResult]::new('-e', '-e', [CompletionResultType]::ParameterName, 'Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`') + [CompletionResult]::new('--edit', '--edit', [CompletionResultType]::ParameterName, 'Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`') + [CompletionResult]::new('--evaluate', '--evaluate', [CompletionResultType]::ParameterName, 'Evaluate and print all variables. If a variable name is given as an argument, only print that variable''s value.') + [CompletionResult]::new('--fmt', '--fmt', [CompletionResultType]::ParameterName, 'Format and overwrite justfile') + [CompletionResult]::new('--groups', '--groups', [CompletionResultType]::ParameterName, 'List recipe groups') + [CompletionResult]::new('--init', '--init', [CompletionResultType]::ParameterName, 'Initialize new justfile in project root') + [CompletionResult]::new('--man', '--man', [CompletionResultType]::ParameterName, 'Print man page') + [CompletionResult]::new('--summary', '--summary', [CompletionResultType]::ParameterName, 'List names of available recipes') + [CompletionResult]::new('--variables', '--variables', [CompletionResultType]::ParameterName, 'List names of variables') + [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') + [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') + [CompletionResult]::new('-V', '-V ', [CompletionResultType]::ParameterName, 'Print version') + [CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version') + break + } + }) + + function Get-JustFileRecipes([string[]]$CommandElements) { + $justFileIndex = $commandElements.IndexOf("--justfile"); + + if ($justFileIndex -ne -1 -and $justFileIndex + 1 -le $commandElements.Length) { + $justFileLocation = $commandElements[$justFileIndex + 1] + } + + $justArgs = @("--summary") + + if (Test-Path $justFileLocation) { + $justArgs += @("--justfile", $justFileLocation) + } + + $recipes = $(just @justArgs) -split ' ' + return $recipes | ForEach-Object { [CompletionResult]::new($_) } + } + + $elementValues = $commandElements | Select-Object -ExpandProperty Value + $recipes = Get-JustFileRecipes -CommandElements $elementValues + $completions += $recipes + $completions.Where{ $_.CompletionText -like "$wordToComplete*" } | + Sort-Object -Property ListItemText +} diff --git a/completions/just.zsh b/completions/just.zsh new file mode 100644 index 00000000..103362c6 --- /dev/null +++ b/completions/just.zsh @@ -0,0 +1,180 @@ +#compdef just + +autoload -U is-at-least + +_just() { + typeset -A opt_args + typeset -a _arguments_options + local ret=1 + + if is-at-least 5.2; then + _arguments_options=(-s -S -C) + else + _arguments_options=(-s -C) + fi + + local context curcontext="$curcontext" state line + local common=( +'(--no-aliases)--alias-style=[Set list command alias display style]: :(left right separate)' \ +'--ceiling=[Do not ascend above directory when searching for a justfile.]: :_files' \ +'--chooser=[Override binary invoked by \`--choose\`]: :_default' \ +'--color=[Print colorful output]: :(always auto never)' \ +'--command-color=[Echo recipe lines in ]: :(black blue cyan green purple red yellow)' \ +'--cygpath=[Use binary at to convert between unix and Windows paths.]: :_files' \ +'(-E --dotenv-path)--dotenv-filename=[Search for environment file named instead of \`.env\`]: :_default' \ +'-E+[Load as environment file instead of searching for one]: :_files' \ +'--dotenv-path=[Load as environment file instead of searching for one]: :_files' \ +'--dump-format=[Dump justfile as ]:FORMAT:(json just)' \ +'-f+[Use as justfile]: :_files' \ +'--justfile=[Use as justfile]: :_files' \ +'--list-heading=[Print before list]:TEXT:_default' \ +'--list-prefix=[Print before each list item]:TEXT:_default' \ +'*--set=[Override with ]: :(_just_variables)' \ +'--shell=[Invoke to run recipes]: :_default' \ +'*--shell-arg=[Invoke shell with as an argument]: :_default' \ +'--tempdir=[Save temporary files to .]: :_files' \ +'--timestamp-format=[Timestamp format string]: :_default' \ +'-d+[Use as working directory. --justfile must also be set]: :_files' \ +'--working-directory=[Use as working directory. --justfile must also be set]: :_files' \ +'*-c+[Run an arbitrary command with the working directory, \`.env\`, overrides, and exports set]: :_default' \ +'*--command=[Run an arbitrary command with the working directory, \`.env\`, overrides, and exports set]: :_default' \ +'--completions=[Print shell completion script for ]:SHELL:(bash elvish fish nushell powershell zsh)' \ +'()-l+[List available recipes in or root if omitted]' \ +'()--list=[List available recipes in or root if omitted]' \ +'--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)' \ +'--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]' \ +'(-q --quiet)--dry-run[Print what just would do without doing it]' \ +'--explain[Print recipe doc comment before running it]' \ +'(-f --justfile -d --working-directory)-g[Use global justfile]' \ +'(-f --justfile -d --working-directory)--global-justfile[Use global justfile]' \ +'--highlight[Highlight echoed recipe lines in bold]' \ +'--list-submodules[List recipes in submodules]' \ +'--no-aliases[Don'\''t show aliases in list]' \ +'--no-deps[Don'\''t run recipe dependencies]' \ +'--no-dotenv[Don'\''t load \`.env\` file]' \ +'--no-highlight[Don'\''t highlight echoed recipe lines in bold]' \ +'--one[Forbid multiple recipes from being invoked on the command line]' \ +'(-n --dry-run)-q[Suppress all output]' \ +'(-n --dry-run)--quiet[Suppress all output]' \ +'--allow-missing[Ignore missing recipe and module errors]' \ +'--shell-command[Invoke with the shell used to run recipe lines and backticks]' \ +'--timestamp[Print recipe command timestamps]' \ +'-u[Return list and summary entries in source order]' \ +'--unsorted[Return list and summary entries in source order]' \ +'--unstable[Enable unstable features]' \ +'*-v[Use verbose output]' \ +'*--verbose[Use verbose output]' \ +'--yes[Automatically confirm all recipes.]' \ +'--changelog[Print changelog]' \ +'--choose[Select one or more recipes to run using a binary chooser. If \`--chooser\` is not passed the chooser defaults to the value of \$JUST_CHOOSER, falling back to \`fzf\`]' \ +'--dump[Print justfile]' \ +'-e[Edit justfile with editor given by \$VISUAL or \$EDITOR, falling back to \`vim\`]' \ +'--edit[Edit justfile with editor given by \$VISUAL or \$EDITOR, falling back to \`vim\`]' \ +'--evaluate[Evaluate and print all variables. If a variable name is given as an argument, only print that variable'\''s value.]' \ +'--fmt[Format and overwrite justfile]' \ +'--groups[List recipe groups]' \ +'--init[Initialize new justfile in project root]' \ +'--man[Print man page]' \ +'--summary[List names of available recipes]' \ +'--variables[List names of variables]' \ +'-h[Print help]' \ +'--help[Print help]' \ +'-V[Print version]' \ +'--version[Print version]' \ +) + + _arguments "${_arguments_options[@]}" $common \ + '1: :_just_commands' \ + '*: :->args' \ + && ret=0 + + case $state in + args) + curcontext="${curcontext%:*}-${words[2]}:" + + local lastarg=${words[${#words}]} + local recipe + + local cmds; cmds=( + ${(s: :)$(_call_program commands just --summary)} + ) + + # Find first recipe name + for ((i = 2; i < $#words; i++ )) do + if [[ ${cmds[(I)${words[i]}]} -gt 0 ]]; then + recipe=${words[i]} + break + fi + done + + if [[ $lastarg = */* ]]; then + # Arguments contain slash would be recognised as a file + _arguments -s -S $common '*:: :_files' + elif [[ $lastarg = *=* ]]; then + # Arguments contain equal would be recognised as a variable + _message "value" + elif [[ $recipe ]]; then + # Show usage message + _message "`just --show $recipe`" + # Or complete with other commands + #_arguments -s -S $common '*:: :_just_commands' + else + _arguments -s -S $common '*:: :_just_commands' + fi + ;; + esac + + return ret + +} + +(( $+functions[_just_commands] )) || +_just_commands() { + [[ $PREFIX = -* ]] && return 1 + integer ret=1 + local variables; variables=( + ${(s: :)$(_call_program commands just --variables)} + ) + local commands; commands=( + ${${${(M)"${(f)$(_call_program commands just --list)}":# *}/ ##/}/ ##/:Args: } + ) + + 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 + +} + +if [ "$funcstack[1]" = "_just" ]; then + (( $+functions[_just_variables] )) || +_just_variables() { + [[ $PREFIX = -* ]] && return 1 + integer ret=1 + local variables; variables=( + ${(s: :)$(_call_program commands just --variables)} + ) + + if compset -P '*='; then + case "${${words[-1]%=*}#*=}" in + *) _message 'value' && ret=0 ;; + esac + else + _describe -t variables 'variables' variables && ret=0 + fi + + return ret +} + +_just "$@" +else + compdef _just just +fi diff --git a/src/completions.rs b/src/completions.rs index 5cc8c242..97eda5b4 100644 --- a/src/completions.rs +++ b/src/completions.rs @@ -12,88 +12,95 @@ pub(crate) enum Shell { } impl Shell { - pub(crate) fn script(self) -> RunResult<'static, String> { + pub(crate) fn script(self) -> &'static str { match self { - Self::Bash => completions::clap(clap_complete::Shell::Bash), - Self::Elvish => completions::clap(clap_complete::Shell::Elvish), - Self::Fish => completions::clap(clap_complete::Shell::Fish), - Self::Nushell => Ok(completions::NUSHELL_COMPLETION_SCRIPT.into()), - Self::Powershell => completions::clap(clap_complete::Shell::PowerShell), - Self::Zsh => completions::clap(clap_complete::Shell::Zsh), + Self::Bash => include_str!("../completions/just.bash"), + Self::Elvish => include_str!("../completions/just.elvish"), + Self::Fish => include_str!("../completions/just.fish"), + Self::Nushell => include_str!("../completions/just.nu"), + Self::Powershell => include_str!("../completions/just.powershell"), + Self::Zsh => include_str!("../completions/just.zsh"), } } } -fn clap(shell: clap_complete::Shell) -> RunResult<'static, String> { - fn replace(haystack: &mut String, needle: &str, replacement: &str) -> RunResult<'static, ()> { - if let Some(index) = haystack.find(needle) { - haystack.replace_range(index..index + needle.len(), replacement); - Ok(()) - } else { - Err(Error::internal(format!( - "Failed to find text:\n{needle}\n…in completion script:\n{haystack}" - ))) - } - } - - let mut script = { - let mut tempfile = tempfile().map_err(|io_error| Error::TempfileIo { io_error })?; - - clap_complete::generate( - shell, - &mut crate::config::Config::app(), - env!("CARGO_PKG_NAME"), - &mut tempfile, - ); - - tempfile - .rewind() - .map_err(|io_error| Error::TempfileIo { io_error })?; - - let mut buffer = String::new(); - - tempfile - .read_to_string(&mut buffer) - .map_err(|io_error| Error::TempfileIo { io_error })?; - - buffer +#[cfg(test)] +mod tests { + use { + super::*, + pretty_assertions::assert_eq, + std::io::{Read, Seek}, + tempfile::tempfile, }; - match shell { - clap_complete::Shell::Bash => { - for (needle, replacement) in completions::BASH_COMPLETION_REPLACEMENTS { - replace(&mut script, needle, replacement)?; - } - } - clap_complete::Shell::Fish => { - script.insert_str(0, completions::FISH_RECIPE_COMPLETIONS); - } - clap_complete::Shell::PowerShell => { - for (needle, replacement) in completions::POWERSHELL_COMPLETION_REPLACEMENTS { - replace(&mut script, needle, replacement)?; - } - } - clap_complete::Shell::Zsh => { - for (needle, replacement) in completions::ZSH_COMPLETION_REPLACEMENTS { - replace(&mut script, needle, replacement)?; - } - } - _ => {} + #[test] + fn scripts() { + assert_eq!(Shell::Bash.script(), clap(clap_complete::Shell::Bash)); + assert_eq!(Shell::Elvish.script(), clap(clap_complete::Shell::Elvish)); + assert_eq!(Shell::Fish.script(), clap(clap_complete::Shell::Fish)); + assert_eq!( + Shell::Powershell.script(), + clap(clap_complete::Shell::PowerShell) + ); + assert_eq!(Shell::Zsh.script(), clap(clap_complete::Shell::Zsh)); } - Ok(script.trim().into()) -} + fn clap(shell: clap_complete::Shell) -> String { + fn replace(haystack: &mut String, needle: &str, replacement: &str) { + if let Some(index) = haystack.find(needle) { + haystack.replace_range(index..index + needle.len(), replacement); + } else { + panic!("Failed to find text:\n{needle}\n…in completion script:\n{haystack}") + } + } -const NUSHELL_COMPLETION_SCRIPT: &str = r#"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 -} + let mut script = { + let mut tempfile = tempfile().unwrap(); -# Just: A Command Runner -export extern "just" [ - ...recipe: string@"nu-complete just", # Recipe(s) to run, may be with argument(s) -]"#; + clap_complete::generate( + shell, + &mut crate::config::Config::app(), + env!("CARGO_PKG_NAME"), + &mut tempfile, + ); -const FISH_RECIPE_COMPLETIONS: &str = r#"function __fish_just_complete_recipes + tempfile.rewind().unwrap(); + + let mut buffer = String::new(); + + tempfile.read_to_string(&mut buffer).unwrap(); + + buffer + }; + + match shell { + clap_complete::Shell::Bash => { + for (needle, replacement) in BASH_COMPLETION_REPLACEMENTS { + replace(&mut script, needle, replacement); + } + } + clap_complete::Shell::Fish => { + script.insert_str(0, FISH_RECIPE_COMPLETIONS); + } + clap_complete::Shell::PowerShell => { + for (needle, replacement) in POWERSHELL_COMPLETION_REPLACEMENTS { + replace(&mut script, needle, replacement); + } + } + clap_complete::Shell::Zsh => { + for (needle, replacement) in ZSH_COMPLETION_REPLACEMENTS { + replace(&mut script, needle, replacement); + } + } + _ => {} + } + + let mut script = script.trim().to_string(); + script.push('\n'); + script + } + + 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 -fx JUST_JUSTFILE "$justfile" end @@ -109,26 +116,26 @@ complete -c just -a '(__fish_just_complete_recipes)' # autogenerated completions "#; -const ZSH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[ - ( - r#" _arguments "${_arguments_options[@]}" : \"#, - r" local common=(", - ), - ( - r"'*--set=[Override with ]:VARIABLE:_default:VARIABLE:_default' \", - r"'*--set=[Override with ]: :(_just_variables)' \", - ), - ( - r"'()-s+[Show recipe at ]:PATH:_default' \ + const ZSH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[ + ( + r#" _arguments "${_arguments_options[@]}" : \"#, + r" local common=(", + ), + ( + r"'*--set=[Override with ]:VARIABLE:_default:VARIABLE:_default' \", + r"'*--set=[Override with ]: :(_just_variables)' \", + ), + ( + r"'()-s+[Show recipe at ]:PATH:_default' \ '()--show=[Show recipe at ]:PATH:_default' \", - r"'-s+[Show recipe at ]: :(_just_commands)' \ + r"'-s+[Show recipe at ]: :(_just_commands)' \ '--show=[Show recipe at ]: :(_just_commands)' \", - ), - ( - "'*::ARGUMENTS -- Overrides and recipe(s) to run, defaulting to the first recipe in the \ + ), + ( + "'*::ARGUMENTS -- Overrides and recipe(s) to run, defaulting to the first recipe in the \ justfile:_default' \\ && ret=0", - r#") + r#") _arguments "${_arguments_options[@]}" $common \ '1: :_just_commands' \ @@ -173,10 +180,10 @@ const ZSH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[ return ret "#, - ), - ( - " local commands; commands=()", - r#" [[ $PREFIX = -* ]] && return 1 + ), + ( + " local commands; commands=()", + r#" [[ $PREFIX = -* ]] && return 1 integer ret=1 local variables; variables=( ${(s: :)$(_call_program commands just --variables)} @@ -185,10 +192,10 @@ const ZSH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[ ${${${(M)"${(f)$(_call_program commands just --list)}":# *}/ ##/}/ ##/:Args: } ) "#, - ), - ( - r#" _describe -t commands 'just commands' commands "$@""#, - r#" if compset -P '*='; then + ), + ( + r#" _describe -t commands 'just commands' commands "$@""#, + r#" if compset -P '*='; then case "${${words[-1]%=*}#*=}" in *) _message 'value' && ret=0 ;; esac @@ -197,10 +204,10 @@ const ZSH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[ _describe -t commands 'just commands' commands "$@" fi "#, - ), - ( - r#"_just "$@""#, - r#"(( $+functions[_just_variables] )) || + ), + ( + r#"_just "$@""#, + r#"(( $+functions[_just_variables] )) || _just_variables() { [[ $PREFIX = -* ]] && return 1 integer ret=1 @@ -220,13 +227,13 @@ _just_variables() { } _just "$@""#, - ), -]; + ), + ]; -const POWERSHELL_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[( - r#"$completions.Where{ $_.CompletionText -like "$wordToComplete*" } | + const POWERSHELL_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[( + r#"$completions.Where{ $_.CompletionText -like "$wordToComplete*" } | Sort-Object -Property ListItemText"#, - r#"function Get-JustFileRecipes([string[]]$CommandElements) { + r#"function Get-JustFileRecipes([string[]]$CommandElements) { $justFileIndex = $commandElements.IndexOf("--justfile"); if ($justFileIndex -ne -1 -and $justFileIndex + 1 -le $commandElements.Length) { @@ -248,15 +255,15 @@ const POWERSHELL_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[( $completions += $recipes $completions.Where{ $_.CompletionText -like "$wordToComplete*" } | Sort-Object -Property ListItemText"#, -)]; + )]; -const BASH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[ - ( - r#" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then + const BASH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[ + ( + r#" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi"#, - r#" if [[ ${cur} == -* ]] ; then + r#" if [[ ${cur} == -* ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 elif [[ ${COMP_CWORD} -eq 1 ]]; then @@ -273,15 +280,15 @@ const BASH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[ return 0 fi fi"#, - ), - ( - r"local i cur prev opts cmd", - r"local i cur prev words cword opts cmd", - ), - ( - r#" cur="${COMP_WORDS[COMP_CWORD]}" + ), + ( + r"local i cur prev opts cmd", + r"local i cur prev words cword opts cmd", + ), + ( + r#" cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}""#, - r#" + r#" # Modules use "::" as the separator, which is considered a wordbreak character in bash. # The _get_comp_words_by_ref function is a hack to allow for exceptions to this rule without # modifying the global COMP_WORDBREAKS environment variable. @@ -294,14 +301,15 @@ const BASH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[ cword=$COMP_CWORD fi "#, - ), - (r"for i in ${COMP_WORDS[@]}", r"for i in ${words[@]}"), - (r"elif [[ ${COMP_CWORD} -eq 1 ]]; then", r"else"), - ( - r#"COMPREPLY=( $(compgen -W "${recipes}" -- "${cur}") )"#, - r#"COMPREPLY=( $(compgen -W "${recipes}" -- "${cur}") ) + ), + (r"for i in ${COMP_WORDS[@]}", r"for i in ${words[@]}"), + (r"elif [[ ${COMP_CWORD} -eq 1 ]]; then", r"else"), + ( + r#"COMPREPLY=( $(compgen -W "${recipes}" -- "${cur}") )"#, + r#"COMPREPLY=( $(compgen -W "${recipes}" -- "${cur}") ) if type __ltrim_colon_completions &>/dev/null; then __ltrim_colon_completions "$cur" fi"#, - ), -]; + ), + ]; +} diff --git a/src/error.rs b/src/error.rs index 142f1814..6e1106ad 100644 --- a/src/error.rs +++ b/src/error.rs @@ -185,9 +185,6 @@ pub(crate) enum Error<'src> { recipe: &'src str, io_error: io::Error, }, - TempfileIo { - io_error: io::Error, - }, Unknown { recipe: &'src str, line_number: Option, @@ -501,9 +498,6 @@ impl ColorDisplay for Error<'_> { write!(f, "Recipe `{recipe}` could not be run because of an IO error while trying to create a temporary \ directory or write a file to that directory: {io_error}")?; } - TempfileIo { io_error } => { - write!(f, "Tempfile I/O error: {io_error}")?; - } Unknown { recipe, line_number} => { if let Some(n) = line_number { write!(f, "Recipe `{recipe}` failed on line {n} for an unknown reason")?; diff --git a/src/lib.rs b/src/lib.rs index 695a5eee..08eda196 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -120,7 +120,7 @@ pub(crate) use { ffi::OsString, fmt::{self, Debug, Display, Formatter}, fs, - io::{self, Read, Seek, Write}, + io::{self, Write}, iter::{self, FromIterator}, mem, ops::Deref, @@ -132,7 +132,7 @@ pub(crate) use { thread, vec, }, strum::{Display, EnumDiscriminants, EnumString, IntoStaticStr}, - tempfile::{tempfile, TempDir}, + tempfile::TempDir, typed_arena::Arena, unicode_width::{UnicodeWidthChar, UnicodeWidthStr}, }; diff --git a/src/signals.rs b/src/signals.rs index 23f2477e..a1c12a11 100644 --- a/src/signals.rs +++ b/src/signals.rs @@ -6,6 +6,7 @@ use { }, std::{ fs::File, + io::Read, os::fd::{BorrowedFd, IntoRawFd}, sync::atomic::{self, AtomicI32}, }, diff --git a/src/subcommand.rs b/src/subcommand.rs index 72c7907a..ffb5f5f1 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -63,7 +63,10 @@ impl Subcommand { Self::changelog(); return Ok(()); } - Completions { shell } => return Self::completions(*shell), + Completions { shell } => { + Self::completions(*shell); + return Ok(()); + } Init => return Self::init(config), Man => return Self::man(), Request { request } => return Self::request(request), @@ -283,9 +286,8 @@ impl Subcommand { justfile.run(config, search, overrides, &recipes) } - fn completions(shell: completions::Shell) -> RunResult<'static, ()> { - println!("{}", shell.script()?); - Ok(()) + fn completions(shell: completions::Shell) { + print!("{}", shell.script()); } fn dump(config: &Config, compilation: Compilation) -> RunResult<'static> {