Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 68 additions & 1 deletion src/cli.toit
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,10 @@ class Command:
result := complete_ this completion-args
result.candidates.do: | candidate/CompletionCandidate_ |
print candidate.to-string
print ":$result.directive"
if result.extensions and not result.extensions.is-empty:
print ":$result.directive:$(result.extensions.join ",")"
else:
print ":$result.directive"
return

if not cli:
Expand Down Expand Up @@ -779,6 +782,16 @@ abstract class Option:
completion-directive -> int?:
return null

/**
Returns file extensions to filter completions by, or null.

When non-null, the shell only shows files matching these extensions
(plus directories for navigation). Extensions include the leading
dot, e.g. [".txt", ".json"].
*/
completion-extensions -> List?:
return null

/**
Returns completion candidates for this option's value.

Expand Down Expand Up @@ -1055,6 +1068,15 @@ class OptionPath extends Option:
*/
is-directory/bool

/**
File extensions to filter completions by, or null.

When non-null, the shell only shows files matching these extensions
(plus directories for navigation). Extensions include the leading
dot, e.g. [".txt", ".json"].
*/
extensions/List?

/**
Creates a new path option.

Expand All @@ -1063,11 +1085,17 @@ class OptionPath extends Option:

If $directory is true, the shell only completes directories.

If $extensions is non-null, the shell only completes files matching
the given extensions (plus directories for navigation). Extensions
must include the leading dot, e.g. `[".txt", ".json"]`. Cannot be
combined with $directory.

See $Option.constructor for the other parameters.
*/
constructor name/string
--.default=null
--directory/bool=false
--.extensions/List?=null
--.type=(directory ? "directory" : "path")
--short-name/string?=null
--help/string?=null
Expand All @@ -1077,6 +1105,8 @@ class OptionPath extends Option:
--split-commas/bool=false
--completion/Lambda?=null:
is-directory = directory
if directory and extensions and not extensions.is-empty:
throw "OptionPath can't have both --directory and --extensions."
if multi and default: throw "Multi option can't have default value."
if required and default: throw "Option can't have default value and be required."
super.from-subclass name --short-name=short-name --help=help \
Expand All @@ -1091,6 +1121,9 @@ class OptionPath extends Option:
if is-directory: return DIRECTIVE-DIRECTORY-COMPLETION_
return DIRECTIVE-FILE-COMPLETION_

completion-extensions -> List?:
return extensions

parse str/string [--if-error] --for-help-example/bool=false -> string:
return str

Expand Down Expand Up @@ -1119,6 +1152,15 @@ class OptionInFile extends Option:
*/
check-exists/bool

/**
File extensions to filter completions by, or null.

When non-null, the shell only shows files matching these extensions
(plus directories for navigation). Extensions include the leading
dot, e.g. [".txt", ".json"].
*/
extensions/List?

/**
Creates a new input file option.

Expand All @@ -1131,13 +1173,18 @@ class OptionInFile extends Option:
If $check-exists is true (the default), the file must exist at parse
time. This check is skipped for "-" (stdin) and for help examples.

If $extensions is non-null, the shell only completes files matching
the given extensions (plus directories for navigation). Extensions
must include the leading dot, e.g. `[".txt", ".json"]`.

See $Option.constructor for the other parameters.
*/
constructor name/string
--.default=null
--.type="file"
--.allow-dash=true
--.check-exists=true
--.extensions/List?=null
--short-name/string?=null
--help/string?=null
--required/bool=false
Expand All @@ -1157,6 +1204,9 @@ class OptionInFile extends Option:

completion-directive -> int?: return DIRECTIVE-FILE-COMPLETION_

completion-extensions -> List?:
return extensions

parse str/string [--if-error] --for-help-example/bool=false -> any:
if allow-dash and str == "-":
return InFile.stdin_ --option-name=name
Expand Down Expand Up @@ -1190,6 +1240,15 @@ class OptionOutFile extends Option:
*/
create-directories/bool

/**
File extensions to filter completions by, or null.

When non-null, the shell only shows files matching these extensions
(plus directories for navigation). Extensions include the leading
dot, e.g. [".txt", ".json"].
*/
extensions/List?

/**
Creates a new output file option.

Expand All @@ -1202,13 +1261,18 @@ class OptionOutFile extends Option:
If $create-directories is true, parent directories are created
automatically when opening the file for writing. Defaults to false.

If $extensions is non-null, the shell only completes files matching
the given extensions (plus directories for navigation). Extensions
must include the leading dot, e.g. `[".txt", ".json"]`.

See $Option.constructor for the other parameters.
*/
constructor name/string
--.default=null
--.type="file"
--.allow-dash=true
--.create-directories=false
--.extensions/List?=null
--short-name/string?=null
--help/string?=null
--required/bool=false
Expand All @@ -1228,6 +1292,9 @@ class OptionOutFile extends Option:

completion-directive -> int?: return DIRECTIVE-FILE-COMPLETION_

completion-extensions -> List?:
return extensions

parse str/string [--if-error] --for-help-example/bool=false -> any:
if allow-dash and str == "-":
return OutFile.stdout_ --create-directories=create-directories --option-name=name
Expand Down
125 changes: 105 additions & 20 deletions src/completion-scripts_.toit
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,27 @@ bash-completion-script_ --program-path/string -> string:
return """
_$(func-name)_completions() {
local IFS=\$'\\n'
shopt -s extglob 2>/dev/null

local completions
completions=\$("$program-path" __complete -- "\${COMP_WORDS[@]:1:\$COMP_CWORD}")
if [ \$? -ne 0 ]; then
return
fi

local directive
directive=\$(echo "\$completions" | tail -n 1)
local directive_line
directive_line=\$(echo "\$completions" | tail -n 1)
completions=\$(echo "\$completions" | sed '\$d')

directive="\${directive#:}"
directive_line="\${directive_line#:}"

local directive extensions=""
if [[ "\$directive_line" == *:* ]]; then
directive="\${directive_line%%:*}"
extensions="\${directive_line#*:}"
else
directive="\$directive_line"
fi

local candidates=()
while IFS='' read -r line; do
Expand All @@ -70,7 +79,24 @@ bash-completion-script_ --program-path/string -> string:
compopt +o default 2>/dev/null
elif [[ \$directive -eq 4 ]]; then
if [[ \${#COMPREPLY[@]} -eq 0 ]]; then
compopt -o default 2>/dev/null
if [[ -n "\$extensions" ]]; then
local ext_pattern=""
IFS=',' read -ra exts <<< "\$extensions"
for ext in "\${exts[@]}"; do
ext="\${ext#.}"
if [[ -n "\$ext_pattern" ]]; then
ext_pattern="\$ext_pattern|\$ext"
else
ext_pattern="\$ext"
fi
done
COMPREPLY=(\$(compgen -f -X "!*.@(\$ext_pattern)" -- "\$cur_word"))
COMPREPLY+=(\$(compgen -d -- "\$cur_word"))
# Remove duplicate directory entries.
COMPREPLY=(\$(printf '%s\\n' "\${COMPREPLY[@]}" | sort -u))
else
compopt -o default 2>/dev/null
fi
fi
elif [[ \$directive -eq 8 ]]; then
if [[ \${#COMPREPLY[@]} -eq 0 ]]; then
Expand All @@ -91,16 +117,23 @@ zsh-completion-script_ --program-path/string -> string:

_$(func-name)() {
local -a completions
local directive
local directive_line directive extensions=""

local output
output=\$("$program-path" __complete -- "\${words[@]:1:\$((CURRENT-1))}" 2>/dev/null)
if [ \$? -ne 0 ]; then
return
fi

directive=\$(echo "\$output" | tail -n 1)
directive="\${directive#:}"
directive_line=\$(echo "\$output" | tail -n 1)
directive_line="\${directive_line#:}"

if [[ "\$directive_line" == *:* ]]; then
directive="\${directive_line%%:*}"
extensions="\${directive_line#*:}"
else
directive="\$directive_line"
fi

local -a lines
lines=("\${(@f)\$(echo "\$output" | sed '\$d')}")
Expand All @@ -123,7 +156,21 @@ zsh-completion-script_ --program-path/string -> string:
fi

if [[ \$directive -eq 4 ]]; then
_files
if [[ -n "\$extensions" ]]; then
local -a ext_array
ext_array=(\${(s:,:)extensions})
local glob_parts=""
for ext in "\${ext_array[@]}"; do
if [[ -n "\$glob_parts" ]]; then
glob_parts="\$glob_parts|*\$ext"
else
glob_parts="*\$ext"
fi
done
_files -g "(\$glob_parts)"
else
_files
fi
elif [[ \$directive -eq 8 ]]; then
_directories
fi
Expand All @@ -147,9 +194,16 @@ fish-completion-script_ --program-path/string -> string:
return
end

set -l directive (string replace -r '^:(.*)' '\$1' \$output[-1])
set -l directive_line (string replace -r '^:(.*)' '\$1' \$output[-1])
set -e output[-1]

set -l directive \$directive_line
set -l extensions ""
if string match -q '*:*' \$directive_line
set directive (string split ':' \$directive_line)[1]
set extensions (string split ':' \$directive_line)[2]
end

for line in \$output
set -l parts (string split \\t \$line)
if test (count \$parts) -gt 1
Expand All @@ -162,7 +216,24 @@ fish-completion-script_ --program-path/string -> string:
end

if test "\$directive" = "4"
__fish_complete_path (commandline -ct)
if test -n "\$extensions"
set -l cur (commandline -ct)
set -l ext_list (string split ',' \$extensions)
for f in \$cur*
if test -d "\$f"
echo \$f
continue
end
for ext in \$ext_list
if string match -q "*\$ext" \$f
echo \$f
break
end
end
end
else
__fish_complete_path (commandline -ct)
end
else if test "\$directive" = "8"
__fish_complete_directories (commandline -ct)
end
Expand Down Expand Up @@ -193,9 +264,16 @@ powershell-completion-script_ --program-path/string -> string:
if (\$LASTEXITCODE -ne 0 -or -not \$output) { return }

\$lines = \$output -split '\\r?\\n'
\$directive = (\$lines[-1] -replace '^:', '')
\$directiveLine = (\$lines[-1] -replace '^:', '')
\$lines = \$lines[0..(\$lines.Length - 2)]

\$directive = \$directiveLine
\$extensions = ''
if (\$directiveLine -match '^(\\d+):(.+)\$') {
\$directive = \$Matches[1]
\$extensions = \$Matches[2]
}

foreach (\$line in \$lines) {
if (-not \$line) { continue }
if (\$line -match '^([^\\t]+)\\t(.+)\$') {
Expand All @@ -216,15 +294,22 @@ powershell-completion-script_ --program-path/string -> string:

if (\$directive -eq '4' -or \$directive -eq '8') {
\$completionType = if (\$directive -eq '8') { 'ProviderContainer' } else { 'ProviderItem' }
Get-ChildItem -Path "\$wordToComplete*" -ErrorAction SilentlyContinue |
Where-Object { \$directive -ne '8' -or \$_.PSIsContainer } |
ForEach-Object {
[System.Management.Automation.CompletionResult]::new(
\$_.FullName,
\$_.Name,
\$completionType,
\$_.FullName
)
\$items = Get-ChildItem -Path "\$wordToComplete*" -ErrorAction SilentlyContinue
if (\$directive -eq '8') {
\$items = \$items | Where-Object { \$_.PSIsContainer }
} elseif (\$extensions) {
\$extArray = \$extensions -split ','
\$items = \$items | Where-Object {
\$_.PSIsContainer -or (\$extArray -contains \$_.Extension)
}
}
\$items | ForEach-Object {
[System.Management.Automation.CompletionResult]::new(
\$_.FullName,
\$_.Name,
\$completionType,
\$_.FullName
)
}
}
}"""
Loading