@optique/core 0.5.1 → 0.6.0-dev.103
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/completion.cjs +513 -0
- package/dist/completion.d.cts +51 -0
- package/dist/completion.d.ts +51 -0
- package/dist/completion.js +510 -0
- package/dist/constructs.cjs +140 -0
- package/dist/constructs.js +140 -0
- package/dist/facade.cjs +119 -37
- package/dist/facade.d.cts +35 -0
- package/dist/facade.d.ts +35 -0
- package/dist/facade.js +121 -39
- package/dist/index.cjs +7 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/modifiers.cjs +24 -0
- package/dist/modifiers.js +24 -0
- package/dist/parser.cjs +46 -0
- package/dist/parser.d.cts +88 -1
- package/dist/parser.d.ts +88 -1
- package/dist/parser.js +46 -1
- package/dist/primitives.cjs +92 -0
- package/dist/primitives.js +92 -0
- package/dist/valueparser.cjs +249 -0
- package/dist/valueparser.d.cts +10 -0
- package/dist/valueparser.d.ts +10 -0
- package/dist/valueparser.js +249 -0
- package/package.json +9 -1
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
const require_message = require('./message.cjs');
|
|
2
|
+
|
|
3
|
+
//#region src/completion.ts
|
|
4
|
+
/**
|
|
5
|
+
* The Bash shell completion generator.
|
|
6
|
+
* @since 0.6.0
|
|
7
|
+
*/
|
|
8
|
+
const bash = {
|
|
9
|
+
name: "bash",
|
|
10
|
+
generateScript(programName, args = []) {
|
|
11
|
+
const escapedArgs = args.map((arg) => `'${arg.replace(/'/g, "'\\''")}'`).join(" ");
|
|
12
|
+
return `
|
|
13
|
+
function _${programName} () {
|
|
14
|
+
COMPREPLY=()
|
|
15
|
+
local current="\${COMP_WORDS[COMP_CWORD]}"
|
|
16
|
+
local prev=("\${COMP_WORDS[@]:1:COMP_CWORD-1}")
|
|
17
|
+
while IFS= read -r line; do
|
|
18
|
+
if [[ "$line" == __FILE__:* ]]; then
|
|
19
|
+
# Parse file completion directive: __FILE__:type:extensions:pattern:hidden
|
|
20
|
+
IFS=':' read -r _ type extensions pattern hidden <<< "$line"
|
|
21
|
+
|
|
22
|
+
# Generate file completions based on type
|
|
23
|
+
case "$type" in
|
|
24
|
+
file)
|
|
25
|
+
# Complete files only
|
|
26
|
+
if [[ -n "$extensions" ]]; then
|
|
27
|
+
# Complete with extension filtering
|
|
28
|
+
local ext_pattern="\${extensions//,/|}"
|
|
29
|
+
for file in "$current"*; do
|
|
30
|
+
[[ -e "$file" && "$file" =~ \\.($ext_pattern)$ ]] && COMPREPLY+=("$file")
|
|
31
|
+
done
|
|
32
|
+
else
|
|
33
|
+
# Complete files only, exclude directories
|
|
34
|
+
while IFS= read -r -d '' item; do
|
|
35
|
+
[[ -f "$item" ]] && COMPREPLY+=("$item")
|
|
36
|
+
done < <(compgen -f -z -- "$current")
|
|
37
|
+
fi
|
|
38
|
+
;;
|
|
39
|
+
directory)
|
|
40
|
+
# Complete directories only
|
|
41
|
+
while IFS= read -r -d '' dir; do
|
|
42
|
+
COMPREPLY+=("$dir/")
|
|
43
|
+
done < <(compgen -d -z -- "$current")
|
|
44
|
+
;;
|
|
45
|
+
any)
|
|
46
|
+
# Complete both files and directories
|
|
47
|
+
if [[ -n "$extensions" ]]; then
|
|
48
|
+
# Files with extension filtering + directories
|
|
49
|
+
# Files with extension filtering
|
|
50
|
+
local ext_pattern="\${extensions//,/|}"
|
|
51
|
+
for item in "$current"*; do
|
|
52
|
+
if [[ -d "$item" ]]; then
|
|
53
|
+
COMPREPLY+=("$item/")
|
|
54
|
+
elif [[ -f "$item" && "$item" =~ \\.($ext_pattern)$ ]]; then
|
|
55
|
+
COMPREPLY+=("$item")
|
|
56
|
+
fi
|
|
57
|
+
done
|
|
58
|
+
else
|
|
59
|
+
# Complete files and directories, add slash to directories
|
|
60
|
+
while IFS= read -r -d '' item; do
|
|
61
|
+
if [[ -d "$item" ]]; then
|
|
62
|
+
COMPREPLY+=("$item/")
|
|
63
|
+
else
|
|
64
|
+
COMPREPLY+=("$item")
|
|
65
|
+
fi
|
|
66
|
+
done < <(compgen -f -z -- "$current")
|
|
67
|
+
fi
|
|
68
|
+
;;
|
|
69
|
+
esac
|
|
70
|
+
|
|
71
|
+
# Filter out hidden files unless requested
|
|
72
|
+
if [[ "$hidden" != "1" && "$current" != .* ]]; then
|
|
73
|
+
local filtered=()
|
|
74
|
+
for item in "\${COMPREPLY[@]}"; do
|
|
75
|
+
[[ "$(basename "$item")" != .* ]] && filtered+=("$item")
|
|
76
|
+
done
|
|
77
|
+
COMPREPLY=("\${filtered[@]}")
|
|
78
|
+
fi
|
|
79
|
+
else
|
|
80
|
+
# Regular literal completion
|
|
81
|
+
COMPREPLY+=("$line")
|
|
82
|
+
fi
|
|
83
|
+
done < <(${programName} ${escapedArgs} "\${prev[@]}" "$current" 2>/dev/null)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
complete -F _${programName} ${programName}
|
|
87
|
+
`;
|
|
88
|
+
},
|
|
89
|
+
*encodeSuggestions(suggestions) {
|
|
90
|
+
let i = 0;
|
|
91
|
+
for (const suggestion of suggestions) {
|
|
92
|
+
if (i > 0) yield "\n";
|
|
93
|
+
if (suggestion.kind === "literal") yield `${suggestion.text}`;
|
|
94
|
+
else {
|
|
95
|
+
const extensions = suggestion.extensions?.join(",") || "";
|
|
96
|
+
const hidden = suggestion.includeHidden ? "1" : "0";
|
|
97
|
+
yield `__FILE__:${suggestion.type}:${extensions}:${suggestion.pattern || ""}:${hidden}`;
|
|
98
|
+
}
|
|
99
|
+
i++;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* The Zsh shell completion generator.
|
|
105
|
+
* @since 0.6.0
|
|
106
|
+
*/
|
|
107
|
+
const zsh = {
|
|
108
|
+
name: "zsh",
|
|
109
|
+
generateScript(programName, args = []) {
|
|
110
|
+
const escapedArgs = args.map((arg) => `'${arg.replace(/'/g, "'\\''")}'`).join(" ");
|
|
111
|
+
return `
|
|
112
|
+
function _${programName.replace(/[^a-zA-Z0-9]/g, "_")} () {
|
|
113
|
+
local current="\$words[CURRENT]"
|
|
114
|
+
local -a prev
|
|
115
|
+
# Extract previous arguments, skipping empty ones
|
|
116
|
+
prev=()
|
|
117
|
+
local i
|
|
118
|
+
for (( i=2; i < CURRENT; i++ )); do
|
|
119
|
+
if [[ -n "\$words[i]" ]]; then
|
|
120
|
+
prev+=("\$words[i]")
|
|
121
|
+
fi
|
|
122
|
+
done
|
|
123
|
+
|
|
124
|
+
# Call the completion function and capture output
|
|
125
|
+
local output
|
|
126
|
+
if (( \${#prev[@]} == 0 )); then
|
|
127
|
+
output=\$(${programName} ${escapedArgs} "\$current" 2>/dev/null)
|
|
128
|
+
else
|
|
129
|
+
output=\$(${programName} ${escapedArgs} "\${prev[@]}" "\$current" 2>/dev/null)
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
# Split output into lines and process each line
|
|
133
|
+
local -a completions descriptions
|
|
134
|
+
local line value desc
|
|
135
|
+
local has_file_completion=0
|
|
136
|
+
|
|
137
|
+
while IFS= read -r line; do
|
|
138
|
+
if [[ -n "\$line" ]]; then
|
|
139
|
+
# Split by null character - first part is value, second is description
|
|
140
|
+
value=\${line%%\$'\\0'*}
|
|
141
|
+
desc=\${line#*\$'\\0'}
|
|
142
|
+
desc=\${desc%%\$'\\0'*}
|
|
143
|
+
|
|
144
|
+
if [[ "\$value" == __FILE__:* ]]; then
|
|
145
|
+
# Parse file completion directive: __FILE__:type:extensions:pattern:hidden
|
|
146
|
+
local type extensions pattern hidden
|
|
147
|
+
IFS=':' read -r _ type extensions pattern hidden <<< "\$value"
|
|
148
|
+
has_file_completion=1
|
|
149
|
+
|
|
150
|
+
# Use zsh's native file completion
|
|
151
|
+
case "\$type" in
|
|
152
|
+
file)
|
|
153
|
+
if [[ -n "\$extensions" ]]; then
|
|
154
|
+
# Complete files with extension filtering
|
|
155
|
+
local ext_pattern="*.(\\$\{extensions//,/|\})"
|
|
156
|
+
_files -g "\\$ext_pattern"
|
|
157
|
+
else
|
|
158
|
+
_files -g "*"
|
|
159
|
+
fi
|
|
160
|
+
;;
|
|
161
|
+
directory)
|
|
162
|
+
_directories
|
|
163
|
+
;;
|
|
164
|
+
any)
|
|
165
|
+
if [[ -n "\$extensions" ]]; then
|
|
166
|
+
# Complete both files and directories, with extension filtering for files
|
|
167
|
+
local ext_pattern="*.(\\$\{extensions//,/|\})"
|
|
168
|
+
_files -g "\\$ext_pattern" && _directories
|
|
169
|
+
else
|
|
170
|
+
_files
|
|
171
|
+
fi
|
|
172
|
+
;;
|
|
173
|
+
esac
|
|
174
|
+
|
|
175
|
+
# Note: zsh's _files and _directories handle hidden file filtering automatically
|
|
176
|
+
# based on the completion context and user settings
|
|
177
|
+
else
|
|
178
|
+
# Regular literal completion
|
|
179
|
+
if [[ -n "\$value" ]]; then
|
|
180
|
+
completions+=("\$value")
|
|
181
|
+
descriptions+=("\$desc")
|
|
182
|
+
fi
|
|
183
|
+
fi
|
|
184
|
+
fi
|
|
185
|
+
done <<< "\$output"
|
|
186
|
+
|
|
187
|
+
# Add literal completions with descriptions if we have any
|
|
188
|
+
if (( \${#completions[@]} > 0 )); then
|
|
189
|
+
# Prepare completion with descriptions for _describe
|
|
190
|
+
local -a matches
|
|
191
|
+
local -i i
|
|
192
|
+
for (( i=1; i <= \${#completions[@]}; i++ )); do
|
|
193
|
+
if [[ -n "\${descriptions[i]}" ]]; then
|
|
194
|
+
matches+=("\${completions[i]}:\${descriptions[i]}")
|
|
195
|
+
else
|
|
196
|
+
matches+=("\${completions[i]}")
|
|
197
|
+
fi
|
|
198
|
+
done
|
|
199
|
+
_describe 'commands' matches
|
|
200
|
+
fi
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
compdef _${programName.replace(/[^a-zA-Z0-9]/g, "_")} ${programName}
|
|
204
|
+
`;
|
|
205
|
+
},
|
|
206
|
+
*encodeSuggestions(suggestions) {
|
|
207
|
+
for (const suggestion of suggestions) if (suggestion.kind === "literal") {
|
|
208
|
+
const description = suggestion.description == null ? "" : require_message.formatMessage(suggestion.description, { colors: false });
|
|
209
|
+
yield `${suggestion.text}\0${description}\0`;
|
|
210
|
+
} else {
|
|
211
|
+
const extensions = suggestion.extensions?.join(",") || "";
|
|
212
|
+
const hidden = suggestion.includeHidden ? "1" : "0";
|
|
213
|
+
const description = suggestion.description == null ? "" : require_message.formatMessage(suggestion.description, { colors: false });
|
|
214
|
+
yield `__FILE__:${suggestion.type}:${extensions}:${suggestion.pattern || ""}:${hidden}\0${description}\0`;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
/**
|
|
219
|
+
* The fish shell completion generator.
|
|
220
|
+
* @since 0.6.0
|
|
221
|
+
*/
|
|
222
|
+
const fish = {
|
|
223
|
+
name: "fish",
|
|
224
|
+
generateScript(programName, args = []) {
|
|
225
|
+
const escapedArgs = args.map((arg) => `'${arg.replace(/'/g, "\\'")}'`).join(" ");
|
|
226
|
+
const functionName = `__${programName.replace(/[^a-zA-Z0-9]/g, "_")}_complete`;
|
|
227
|
+
return `
|
|
228
|
+
function ${functionName}
|
|
229
|
+
set -l tokens (commandline -poc)
|
|
230
|
+
set -l current (commandline -ct)
|
|
231
|
+
|
|
232
|
+
# Extract previous arguments (skip the command name)
|
|
233
|
+
set -l prev
|
|
234
|
+
set -l count (count $tokens)
|
|
235
|
+
if test $count -gt 1
|
|
236
|
+
set prev $tokens[2..$count]
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Call completion command and capture output
|
|
240
|
+
${escapedArgs ? ` set -l output (${programName} ${escapedArgs} $prev $current 2>/dev/null)\n` : ` set -l output (${programName} $prev $current 2>/dev/null)\n`}
|
|
241
|
+
# Process each line of output
|
|
242
|
+
for line in $output
|
|
243
|
+
if string match -q '__FILE__:*' -- $line
|
|
244
|
+
# Parse file completion directive: __FILE__:type:extensions:pattern:hidden
|
|
245
|
+
set -l parts (string split ':' -- $line)
|
|
246
|
+
set -l type $parts[2]
|
|
247
|
+
set -l extensions $parts[3]
|
|
248
|
+
set -l pattern $parts[4]
|
|
249
|
+
set -l hidden $parts[5]
|
|
250
|
+
|
|
251
|
+
# Generate file completions based on type
|
|
252
|
+
set -l items
|
|
253
|
+
switch $type
|
|
254
|
+
case file
|
|
255
|
+
# Complete files only
|
|
256
|
+
for item in $current*
|
|
257
|
+
if test -f $item
|
|
258
|
+
set -a items $item
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
case directory
|
|
262
|
+
# Complete directories only
|
|
263
|
+
for item in $current*
|
|
264
|
+
if test -d $item
|
|
265
|
+
set -a items $item/
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
case any
|
|
269
|
+
# Complete both files and directories
|
|
270
|
+
for item in $current*
|
|
271
|
+
if test -d $item
|
|
272
|
+
set -a items $item/
|
|
273
|
+
else if test -f $item
|
|
274
|
+
set -a items $item
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# Filter by extensions if specified
|
|
280
|
+
if test -n "$extensions" -a "$type" != directory
|
|
281
|
+
set -l filtered
|
|
282
|
+
set -l ext_list (string split ',' -- $extensions)
|
|
283
|
+
for item in $items
|
|
284
|
+
# Skip directories, they don't have extensions
|
|
285
|
+
if string match -q '*/' -- $item
|
|
286
|
+
set -a filtered $item
|
|
287
|
+
continue
|
|
288
|
+
end
|
|
289
|
+
# Check if file matches any extension
|
|
290
|
+
for ext in $ext_list
|
|
291
|
+
if string match -q "*.$ext" -- $item
|
|
292
|
+
set -a filtered $item
|
|
293
|
+
break
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
set items $filtered
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Filter out hidden files unless requested
|
|
301
|
+
if test "$hidden" != "1" -a (string sub -l 1 -- $current) != "."
|
|
302
|
+
set -l filtered
|
|
303
|
+
for item in $items
|
|
304
|
+
set -l basename (basename $item)
|
|
305
|
+
if not string match -q '.*' -- $basename
|
|
306
|
+
set -a filtered $item
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
set items $filtered
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Output file completions
|
|
313
|
+
for item in $items
|
|
314
|
+
echo $item
|
|
315
|
+
end
|
|
316
|
+
else
|
|
317
|
+
# Regular literal completion - split by tab
|
|
318
|
+
set -l parts (string split \\t -- $line)
|
|
319
|
+
if test (count $parts) -ge 2
|
|
320
|
+
# value\tdescription format
|
|
321
|
+
echo $parts[1]\\t$parts[2]
|
|
322
|
+
else
|
|
323
|
+
# Just value
|
|
324
|
+
echo $line
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
complete -c ${programName} -f -a '(${functionName})'
|
|
331
|
+
`;
|
|
332
|
+
},
|
|
333
|
+
*encodeSuggestions(suggestions) {
|
|
334
|
+
let i = 0;
|
|
335
|
+
for (const suggestion of suggestions) {
|
|
336
|
+
if (i > 0) yield "\n";
|
|
337
|
+
if (suggestion.kind === "literal") {
|
|
338
|
+
const description = suggestion.description == null ? "" : require_message.formatMessage(suggestion.description, { colors: false });
|
|
339
|
+
yield `${suggestion.text}\t${description}`;
|
|
340
|
+
} else {
|
|
341
|
+
const extensions = suggestion.extensions?.join(",") || "";
|
|
342
|
+
const hidden = suggestion.includeHidden ? "1" : "0";
|
|
343
|
+
const description = suggestion.description == null ? "" : require_message.formatMessage(suggestion.description, { colors: false });
|
|
344
|
+
yield `__FILE__:${suggestion.type}:${extensions}:${suggestion.pattern || ""}:${hidden}\t${description}`;
|
|
345
|
+
}
|
|
346
|
+
i++;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
/**
|
|
351
|
+
* The PowerShell completion generator.
|
|
352
|
+
* @since 0.6.0
|
|
353
|
+
*/
|
|
354
|
+
const pwsh = {
|
|
355
|
+
name: "pwsh",
|
|
356
|
+
generateScript(programName, args = []) {
|
|
357
|
+
const escapedArgs = args.map((arg) => `'${arg.replace(/'/g, "''")}'`).join(", ");
|
|
358
|
+
return `
|
|
359
|
+
Register-ArgumentCompleter -Native -CommandName ${programName} -ScriptBlock {
|
|
360
|
+
param(\$wordToComplete, \$commandAst, \$cursorPosition)
|
|
361
|
+
|
|
362
|
+
# Extract arguments from AST (handles quoted strings properly)
|
|
363
|
+
\$arguments = @()
|
|
364
|
+
\$commandElements = \$commandAst.CommandElements
|
|
365
|
+
|
|
366
|
+
# Determine the range of elements to extract
|
|
367
|
+
# Exclude the last element if it matches wordToComplete (partial input case)
|
|
368
|
+
\$maxIndex = \$commandElements.Count - 1
|
|
369
|
+
if (\$commandElements.Count -gt 1) {
|
|
370
|
+
\$lastElement = \$commandElements[\$commandElements.Count - 1]
|
|
371
|
+
\$lastText = if (\$lastElement -is [System.Management.Automation.Language.StringConstantExpressionAst]) {
|
|
372
|
+
\$lastElement.Value
|
|
373
|
+
} else {
|
|
374
|
+
\$lastElement.Extent.Text
|
|
375
|
+
}
|
|
376
|
+
if (\$lastText -eq \$wordToComplete) {
|
|
377
|
+
\$maxIndex = \$commandElements.Count - 2
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
for (\$i = 1; \$i -le \$maxIndex; \$i++) {
|
|
382
|
+
\$element = \$commandElements[\$i]
|
|
383
|
+
|
|
384
|
+
if (\$element -is [System.Management.Automation.Language.StringConstantExpressionAst]) {
|
|
385
|
+
\$arguments += \$element.Value
|
|
386
|
+
} else {
|
|
387
|
+
\$arguments += \$element.Extent.Text
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
# Build arguments array for completion command
|
|
392
|
+
\$completionArgs = @()
|
|
393
|
+
${escapedArgs ? ` \$completionArgs += @(${escapedArgs})
|
|
394
|
+
` : ""} \$completionArgs += \$arguments
|
|
395
|
+
\$completionArgs += \$wordToComplete
|
|
396
|
+
|
|
397
|
+
# Call completion command and capture output
|
|
398
|
+
try {
|
|
399
|
+
\$output = & ${programName} \$completionArgs 2>\$null
|
|
400
|
+
if (-not \$output) { return }
|
|
401
|
+
|
|
402
|
+
# Parse tab-separated output and create CompletionResult objects
|
|
403
|
+
\$output -split "\`n" | ForEach-Object {
|
|
404
|
+
\$line = \$_.Trim()
|
|
405
|
+
if (-not \$line) { return }
|
|
406
|
+
|
|
407
|
+
if (\$line -match '^__FILE__:') {
|
|
408
|
+
# Parse file completion directive: __FILE__:type:extensions:pattern:hidden
|
|
409
|
+
\$parts = \$line -split ':', 5
|
|
410
|
+
\$type = \$parts[1]
|
|
411
|
+
\$extensions = \$parts[2]
|
|
412
|
+
\$pattern = \$parts[3]
|
|
413
|
+
\$hidden = \$parts[4] -eq '1'
|
|
414
|
+
|
|
415
|
+
# Determine current prefix for file matching
|
|
416
|
+
\$prefix = if (\$wordToComplete) { \$wordToComplete } else { '' }
|
|
417
|
+
|
|
418
|
+
# Get file system items based on type
|
|
419
|
+
\$items = @()
|
|
420
|
+
switch (\$type) {
|
|
421
|
+
'file' {
|
|
422
|
+
if (\$extensions) {
|
|
423
|
+
# Filter by extensions
|
|
424
|
+
\$extList = \$extensions -split ','
|
|
425
|
+
\$items = Get-ChildItem -File -Path "\${prefix}*" -ErrorAction SilentlyContinue |
|
|
426
|
+
Where-Object {
|
|
427
|
+
\$ext = \$_.Extension
|
|
428
|
+
\$extList | ForEach-Object { if (\$ext -eq ".\$_") { return \$true } }
|
|
429
|
+
}
|
|
430
|
+
} else {
|
|
431
|
+
\$items = Get-ChildItem -File -Path "\${prefix}*" -ErrorAction SilentlyContinue
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
'directory' {
|
|
435
|
+
\$items = Get-ChildItem -Directory -Path "\${prefix}*" -ErrorAction SilentlyContinue
|
|
436
|
+
}
|
|
437
|
+
'any' {
|
|
438
|
+
if (\$extensions) {
|
|
439
|
+
# Get directories and filtered files
|
|
440
|
+
\$dirs = Get-ChildItem -Directory -Path "\${prefix}*" -ErrorAction SilentlyContinue
|
|
441
|
+
\$extList = \$extensions -split ','
|
|
442
|
+
\$files = Get-ChildItem -File -Path "\${prefix}*" -ErrorAction SilentlyContinue |
|
|
443
|
+
Where-Object {
|
|
444
|
+
\$ext = \$_.Extension
|
|
445
|
+
\$extList | ForEach-Object { if (\$ext -eq ".\$_") { return \$true } }
|
|
446
|
+
}
|
|
447
|
+
\$items = \$dirs + \$files
|
|
448
|
+
} else {
|
|
449
|
+
\$items = Get-ChildItem -Path "\${prefix}*" -ErrorAction SilentlyContinue
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
# Filter hidden files unless requested
|
|
455
|
+
if (-not \$hidden) {
|
|
456
|
+
\$items = \$items | Where-Object { -not \$_.Attributes.HasFlag([System.IO.FileAttributes]::Hidden) }
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
# Create completion results for files
|
|
460
|
+
\$items | ForEach-Object {
|
|
461
|
+
\$completionText = if (\$_.PSIsContainer) { "\$(\$_.Name)/" } else { \$_.Name }
|
|
462
|
+
\$itemType = if (\$_.PSIsContainer) { 'Directory' } else { 'File' }
|
|
463
|
+
[System.Management.Automation.CompletionResult]::new(
|
|
464
|
+
\$completionText,
|
|
465
|
+
\$completionText,
|
|
466
|
+
'ParameterValue',
|
|
467
|
+
\$itemType
|
|
468
|
+
)
|
|
469
|
+
}
|
|
470
|
+
} else {
|
|
471
|
+
# Parse literal completion: text\\tlistItemText\\tdescription
|
|
472
|
+
\$parts = \$line -split "\`t", 3
|
|
473
|
+
\$completionText = \$parts[0]
|
|
474
|
+
\$listItemText = if (\$parts.Length -gt 1 -and \$parts[1]) { \$parts[1] } else { \$completionText }
|
|
475
|
+
\$toolTip = if (\$parts.Length -gt 2 -and \$parts[2]) { \$parts[2] } else { \$completionText }
|
|
476
|
+
|
|
477
|
+
[System.Management.Automation.CompletionResult]::new(
|
|
478
|
+
\$completionText,
|
|
479
|
+
\$listItemText,
|
|
480
|
+
'ParameterValue',
|
|
481
|
+
\$toolTip
|
|
482
|
+
)
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
} catch {
|
|
486
|
+
# Silently ignore errors
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
`;
|
|
490
|
+
},
|
|
491
|
+
*encodeSuggestions(suggestions) {
|
|
492
|
+
let i = 0;
|
|
493
|
+
for (const suggestion of suggestions) {
|
|
494
|
+
if (i > 0) yield "\n";
|
|
495
|
+
if (suggestion.kind === "literal") {
|
|
496
|
+
const description = suggestion.description == null ? "" : require_message.formatMessage(suggestion.description, { colors: false });
|
|
497
|
+
yield `${suggestion.text}\t${suggestion.text}\t${description}`;
|
|
498
|
+
} else {
|
|
499
|
+
const extensions = suggestion.extensions?.join(",") || "";
|
|
500
|
+
const hidden = suggestion.includeHidden ? "1" : "0";
|
|
501
|
+
const description = suggestion.description == null ? "" : require_message.formatMessage(suggestion.description, { colors: false });
|
|
502
|
+
yield `__FILE__:${suggestion.type}:${extensions}:${suggestion.pattern || ""}:${hidden}\t[file]\t${description}`;
|
|
503
|
+
}
|
|
504
|
+
i++;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
//#endregion
|
|
510
|
+
exports.bash = bash;
|
|
511
|
+
exports.fish = fish;
|
|
512
|
+
exports.pwsh = pwsh;
|
|
513
|
+
exports.zsh = zsh;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Suggestion } from "./parser.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/completion.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A shell completion generator.
|
|
7
|
+
* @since 0.6.0
|
|
8
|
+
*/
|
|
9
|
+
interface ShellCompletion {
|
|
10
|
+
/**
|
|
11
|
+
* The name of the shell.
|
|
12
|
+
*/
|
|
13
|
+
readonly name: string;
|
|
14
|
+
/**
|
|
15
|
+
* Generates a shell completion script for the given program name.
|
|
16
|
+
* @param programName The name of the program.
|
|
17
|
+
* @param args The arguments passed to the program. If omitted, an empty
|
|
18
|
+
* array is used.
|
|
19
|
+
* @returns The shell completion script.
|
|
20
|
+
*/
|
|
21
|
+
generateScript(programName: string, args?: readonly string[]): string;
|
|
22
|
+
/**
|
|
23
|
+
* Encodes {@link Suggestion}s into chunks of strings suitable for the shell.
|
|
24
|
+
* All chunks will be joined without any separator.
|
|
25
|
+
* @param suggestions The suggestions to encode.
|
|
26
|
+
* @returns The encoded suggestions.
|
|
27
|
+
*/
|
|
28
|
+
encodeSuggestions(suggestions: readonly Suggestion[]): Iterable<string>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The Bash shell completion generator.
|
|
32
|
+
* @since 0.6.0
|
|
33
|
+
*/
|
|
34
|
+
declare const bash: ShellCompletion;
|
|
35
|
+
/**
|
|
36
|
+
* The Zsh shell completion generator.
|
|
37
|
+
* @since 0.6.0
|
|
38
|
+
*/
|
|
39
|
+
declare const zsh: ShellCompletion;
|
|
40
|
+
/**
|
|
41
|
+
* The fish shell completion generator.
|
|
42
|
+
* @since 0.6.0
|
|
43
|
+
*/
|
|
44
|
+
declare const fish: ShellCompletion;
|
|
45
|
+
/**
|
|
46
|
+
* The PowerShell completion generator.
|
|
47
|
+
* @since 0.6.0
|
|
48
|
+
*/
|
|
49
|
+
declare const pwsh: ShellCompletion;
|
|
50
|
+
//#endregion
|
|
51
|
+
export { ShellCompletion, bash, fish, pwsh, zsh };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Suggestion } from "./parser.js";
|
|
2
|
+
|
|
3
|
+
//#region src/completion.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A shell completion generator.
|
|
7
|
+
* @since 0.6.0
|
|
8
|
+
*/
|
|
9
|
+
interface ShellCompletion {
|
|
10
|
+
/**
|
|
11
|
+
* The name of the shell.
|
|
12
|
+
*/
|
|
13
|
+
readonly name: string;
|
|
14
|
+
/**
|
|
15
|
+
* Generates a shell completion script for the given program name.
|
|
16
|
+
* @param programName The name of the program.
|
|
17
|
+
* @param args The arguments passed to the program. If omitted, an empty
|
|
18
|
+
* array is used.
|
|
19
|
+
* @returns The shell completion script.
|
|
20
|
+
*/
|
|
21
|
+
generateScript(programName: string, args?: readonly string[]): string;
|
|
22
|
+
/**
|
|
23
|
+
* Encodes {@link Suggestion}s into chunks of strings suitable for the shell.
|
|
24
|
+
* All chunks will be joined without any separator.
|
|
25
|
+
* @param suggestions The suggestions to encode.
|
|
26
|
+
* @returns The encoded suggestions.
|
|
27
|
+
*/
|
|
28
|
+
encodeSuggestions(suggestions: readonly Suggestion[]): Iterable<string>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The Bash shell completion generator.
|
|
32
|
+
* @since 0.6.0
|
|
33
|
+
*/
|
|
34
|
+
declare const bash: ShellCompletion;
|
|
35
|
+
/**
|
|
36
|
+
* The Zsh shell completion generator.
|
|
37
|
+
* @since 0.6.0
|
|
38
|
+
*/
|
|
39
|
+
declare const zsh: ShellCompletion;
|
|
40
|
+
/**
|
|
41
|
+
* The fish shell completion generator.
|
|
42
|
+
* @since 0.6.0
|
|
43
|
+
*/
|
|
44
|
+
declare const fish: ShellCompletion;
|
|
45
|
+
/**
|
|
46
|
+
* The PowerShell completion generator.
|
|
47
|
+
* @since 0.6.0
|
|
48
|
+
*/
|
|
49
|
+
declare const pwsh: ShellCompletion;
|
|
50
|
+
//#endregion
|
|
51
|
+
export { ShellCompletion, bash, fish, pwsh, zsh };
|