@optique/core 1.0.15-dev.2824 → 1.0.15-dev.2835
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 +46 -16
- package/dist/completion.js +46 -16
- package/package.json +1 -1
package/dist/completion.cjs
CHANGED
|
@@ -62,6 +62,17 @@ function sanitizeForTransport(text) {
|
|
|
62
62
|
return text.replace(/[\t\n\r\0]/g, " ");
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
|
+
* Escapes literal values that would otherwise be interpreted as transport
|
|
66
|
+
* directives. Escape the escape prefix itself so decoding is unambiguous.
|
|
67
|
+
* @param text The literal suggestion text.
|
|
68
|
+
* @returns The sanitized and, if necessary, escaped literal text.
|
|
69
|
+
* @internal
|
|
70
|
+
*/
|
|
71
|
+
function encodeLiteral(text) {
|
|
72
|
+
const sanitized = sanitizeForTransport(text);
|
|
73
|
+
return sanitized.startsWith("__FILE__:") || sanitized.startsWith("__LITERAL__:") ? `__LITERAL__:${sanitized}` : sanitized;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
65
76
|
* The Bash shell completion generator.
|
|
66
77
|
* @since 0.6.0
|
|
67
78
|
*/
|
|
@@ -308,10 +319,11 @@ function _${programName} () {
|
|
|
308
319
|
__reply_prefix=""
|
|
309
320
|
__file_current="$current"
|
|
310
321
|
__literal=0
|
|
311
|
-
|
|
322
|
+
# Protocol tags are case-sensitive even when nocasematch is enabled.
|
|
323
|
+
if [ "\${line:0:12}" = '__LITERAL__:' ]; then
|
|
312
324
|
line="\${line#__LITERAL__:}"
|
|
313
325
|
__literal=1
|
|
314
|
-
elif [
|
|
326
|
+
elif [ "\${line:0:16}" = '__JOINED_FILE__:' ]; then
|
|
315
327
|
line="\${line#__JOINED_FILE__:}"
|
|
316
328
|
__reply_prefix="\${line%%:*}"
|
|
317
329
|
__reply_prefix="\${__reply_prefix//%3A/:}"
|
|
@@ -332,7 +344,7 @@ function _${programName} () {
|
|
|
332
344
|
__file_quote_offset=$((__file_quote_offset - \${#__reply_prefix}))
|
|
333
345
|
fi
|
|
334
346
|
fi
|
|
335
|
-
if [
|
|
347
|
+
if [ "$__literal" = 0 ] && [ "\${line:0:9}" = '__FILE__:' ]; then
|
|
336
348
|
# Parse file completion directive: __FILE__:type:extensions:pattern:hidden
|
|
337
349
|
IFS=':' read -r _ type extensions pattern hidden <<< "$line"
|
|
338
350
|
extensions="\${extensions//,\\./,}"; extensions="\${extensions#.}"
|
|
@@ -700,7 +712,12 @@ function _${programName.replace(/[^a-zA-Z0-9]/g, "_")} () {
|
|
|
700
712
|
desc=\${line#*\$'\\0'}
|
|
701
713
|
desc=\${desc%%\$'\\0'*}
|
|
702
714
|
|
|
703
|
-
|
|
715
|
+
local __literal=0
|
|
716
|
+
if [[ "\$value" == __LITERAL__:* ]]; then
|
|
717
|
+
value="\${value#__LITERAL__:}"
|
|
718
|
+
__literal=1
|
|
719
|
+
fi
|
|
720
|
+
if [[ \$__literal == 0 && "\$value" == __FILE__:* ]]; then
|
|
704
721
|
# Parse file completion directive: __FILE__:type:extensions:pattern:hidden
|
|
705
722
|
local type extensions pattern hidden
|
|
706
723
|
IFS=':' read -r _ type extensions pattern hidden <<< "\$value"
|
|
@@ -816,7 +833,7 @@ fi
|
|
|
816
833
|
*encodeSuggestions(suggestions) {
|
|
817
834
|
for (const suggestion of suggestions) if (suggestion.kind === "literal") {
|
|
818
835
|
const description = suggestion.description == null ? "" : sanitizeForTransport(require_message.formatMessage(suggestion.description, { colors: false }));
|
|
819
|
-
yield `${
|
|
836
|
+
yield `${encodeLiteral(suggestion.text)}\0${description}\0`;
|
|
820
837
|
} else {
|
|
821
838
|
const extensions = encodeExtensions(suggestion.extensions);
|
|
822
839
|
const hidden = suggestion.includeHidden ? "1" : "0";
|
|
@@ -875,7 +892,12 @@ function ${functionName}
|
|
|
875
892
|
${escapedArgs ? ` set -l output (${programName} ${escapedArgs} $prev $current 2>/dev/null)\n` : ` set -l output (${programName} $prev $current 2>/dev/null)\n`}
|
|
876
893
|
# Process each line of output
|
|
877
894
|
for line in $output
|
|
878
|
-
|
|
895
|
+
set -l literal 0
|
|
896
|
+
if string match -q '__LITERAL__:*' -- $line
|
|
897
|
+
set line (string sub -s 13 -- $line)
|
|
898
|
+
set literal 1
|
|
899
|
+
end
|
|
900
|
+
if test $literal -eq 0; and string match -q '__FILE__:*' -- $line
|
|
879
901
|
# Parse file completion directive: __FILE__:type:extensions:pattern:hidden
|
|
880
902
|
set -l directive (string split \\t -- $line)[1]
|
|
881
903
|
set -l parts (string split ':' -- $directive)
|
|
@@ -1166,7 +1188,7 @@ complete -c ${programName} -f -a '(${functionName})'
|
|
|
1166
1188
|
if (i > 0) yield "\n";
|
|
1167
1189
|
if (suggestion.kind === "literal") {
|
|
1168
1190
|
const description = suggestion.description == null ? "" : sanitizeForTransport(require_message.formatMessage(suggestion.description, { colors: false }));
|
|
1169
|
-
yield `${
|
|
1191
|
+
yield `${encodeLiteral(suggestion.text)}\t${description}`;
|
|
1170
1192
|
} else {
|
|
1171
1193
|
const extensions = encodeExtensions(suggestion.extensions);
|
|
1172
1194
|
const hidden = suggestion.includeHidden ? "1" : "0";
|
|
@@ -1405,8 +1427,10 @@ ${escapedArgs ? ` ^${programName} ${escapedArgs} ...$final_args | complete |
|
|
|
1405
1427
|
}
|
|
1406
1428
|
|
|
1407
1429
|
# Process each line of output
|
|
1408
|
-
$output | lines | each {|
|
|
1409
|
-
|
|
1430
|
+
$output | lines | each {|raw_line|
|
|
1431
|
+
let literal = ($raw_line | str starts-with '__LITERAL__:')
|
|
1432
|
+
let line = if $literal { $raw_line | str substring 12.. } else { $raw_line }
|
|
1433
|
+
if (not $literal) and ($line | str starts-with '__FILE__:') {
|
|
1410
1434
|
# Parse file completion directive: __FILE__:type:extensions:pattern:hidden
|
|
1411
1435
|
let directive = ($line | split row "\t" | first)
|
|
1412
1436
|
let parts = ($directive | split row ':')
|
|
@@ -1466,22 +1490,26 @@ ${escapedArgs ? ` ^${programName} ${escapedArgs} ...$final_args | complete |
|
|
|
1466
1490
|
# Generate file completions based on type.
|
|
1467
1491
|
# When the glob base contains wildcard characters, use it as-is;
|
|
1468
1492
|
# otherwise append * to treat it as a prefix.
|
|
1469
|
-
# Note: into glob is required so that ls expands wildcards from a variable
|
|
1493
|
+
# Note: into glob is required so that ls expands wildcards from a variable.
|
|
1494
|
+
# A literal prefix has its brackets wrapped as [[] and []] so that path
|
|
1495
|
+
# text like "report[1]" is not parsed as a glob character class; a
|
|
1496
|
+
# wildcard pattern is a glob as a whole, so its brackets stay classes.
|
|
1470
1497
|
let has_glob = ($glob_base =~ '[*?]')
|
|
1471
1498
|
let ls_pattern = if ($glob_base | is-empty) {
|
|
1472
1499
|
"."
|
|
1473
1500
|
} else if $has_glob {
|
|
1474
1501
|
($glob_base | into glob)
|
|
1475
1502
|
} else {
|
|
1476
|
-
($glob_base + "*" | into glob)
|
|
1503
|
+
(($glob_base | str replace -a -r '([\\[\\]])' '[$1]') + "*" | into glob)
|
|
1477
1504
|
}
|
|
1478
1505
|
|
|
1479
1506
|
# When using a glob pattern, also compute a directory listing pattern
|
|
1480
|
-
# so that file/any modes can include directories for navigation
|
|
1507
|
+
# so that file/any modes can include directories for navigation; its
|
|
1508
|
+
# directory part is a literal path
|
|
1481
1509
|
let glob_dir_pattern = if $has_glob {
|
|
1482
1510
|
let dir_part = ($glob_base | path dirname)
|
|
1483
1511
|
let dir = if ($dir_part | is-empty) or ($dir_part == $glob_base) { "." } else { $dir_part }
|
|
1484
|
-
($dir + "/*" | into glob)
|
|
1512
|
+
(($dir | str replace -a -r '([\\[\\]])' '[$1]') + "/*" | into glob)
|
|
1485
1513
|
} else {
|
|
1486
1514
|
null
|
|
1487
1515
|
}
|
|
@@ -1674,7 +1702,7 @@ ${functionName}-external
|
|
|
1674
1702
|
if (i > 0) yield "\n";
|
|
1675
1703
|
if (suggestion.kind === "literal") {
|
|
1676
1704
|
const description = suggestion.description == null ? "" : sanitizeForTransport(require_message.formatMessage(suggestion.description, { colors: false }));
|
|
1677
|
-
yield `${
|
|
1705
|
+
yield `${encodeLiteral(suggestion.text)}\t${description}`;
|
|
1678
1706
|
} else {
|
|
1679
1707
|
const extensions = encodeExtensions(suggestion.extensions);
|
|
1680
1708
|
const hidden = suggestion.includeHidden ? "1" : "0";
|
|
@@ -1729,10 +1757,12 @@ ${escapedArgs ? ` \$completionArgs += @(${escapedArgs})
|
|
|
1729
1757
|
|
|
1730
1758
|
# Parse tab-separated output and create CompletionResult objects
|
|
1731
1759
|
\$output -split "\`n" | ForEach-Object {
|
|
1760
|
+
\$literal = \$_.StartsWith('__LITERAL__:', [System.StringComparison]::Ordinal)
|
|
1732
1761
|
\$line = \$_.Trim()
|
|
1733
1762
|
if (-not \$line) { return }
|
|
1763
|
+
if (\$literal) { \$line = \$line.Substring(12) }
|
|
1734
1764
|
|
|
1735
|
-
if (\$
|
|
1765
|
+
if (-not \$literal -and \$_.StartsWith('__FILE__:', [System.StringComparison]::Ordinal)) {
|
|
1736
1766
|
# Parse file completion directive: __FILE__:type:extensions:pattern:hidden
|
|
1737
1767
|
\$directive = (\$line -split "\`t")[0]
|
|
1738
1768
|
\$parts = \$directive -split ':', 5
|
|
@@ -1874,7 +1904,7 @@ ${escapedArgs ? ` \$completionArgs += @(${escapedArgs})
|
|
|
1874
1904
|
if (suggestion.kind === "literal") {
|
|
1875
1905
|
const description = suggestion.description == null ? "" : sanitizeForTransport(require_message.formatMessage(suggestion.description, { colors: false }));
|
|
1876
1906
|
const text = sanitizeForTransport(suggestion.text);
|
|
1877
|
-
yield `${text}\t${text}\t${description}`;
|
|
1907
|
+
yield `${encodeLiteral(suggestion.text)}\t${text}\t${description}`;
|
|
1878
1908
|
} else {
|
|
1879
1909
|
const extensions = encodeExtensions(suggestion.extensions);
|
|
1880
1910
|
const hidden = suggestion.includeHidden ? "1" : "0";
|
package/dist/completion.js
CHANGED
|
@@ -62,6 +62,17 @@ function sanitizeForTransport(text) {
|
|
|
62
62
|
return text.replace(/[\t\n\r\0]/g, " ");
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
|
+
* Escapes literal values that would otherwise be interpreted as transport
|
|
66
|
+
* directives. Escape the escape prefix itself so decoding is unambiguous.
|
|
67
|
+
* @param text The literal suggestion text.
|
|
68
|
+
* @returns The sanitized and, if necessary, escaped literal text.
|
|
69
|
+
* @internal
|
|
70
|
+
*/
|
|
71
|
+
function encodeLiteral(text) {
|
|
72
|
+
const sanitized = sanitizeForTransport(text);
|
|
73
|
+
return sanitized.startsWith("__FILE__:") || sanitized.startsWith("__LITERAL__:") ? `__LITERAL__:${sanitized}` : sanitized;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
65
76
|
* The Bash shell completion generator.
|
|
66
77
|
* @since 0.6.0
|
|
67
78
|
*/
|
|
@@ -308,10 +319,11 @@ function _${programName} () {
|
|
|
308
319
|
__reply_prefix=""
|
|
309
320
|
__file_current="$current"
|
|
310
321
|
__literal=0
|
|
311
|
-
|
|
322
|
+
# Protocol tags are case-sensitive even when nocasematch is enabled.
|
|
323
|
+
if [ "\${line:0:12}" = '__LITERAL__:' ]; then
|
|
312
324
|
line="\${line#__LITERAL__:}"
|
|
313
325
|
__literal=1
|
|
314
|
-
elif [
|
|
326
|
+
elif [ "\${line:0:16}" = '__JOINED_FILE__:' ]; then
|
|
315
327
|
line="\${line#__JOINED_FILE__:}"
|
|
316
328
|
__reply_prefix="\${line%%:*}"
|
|
317
329
|
__reply_prefix="\${__reply_prefix//%3A/:}"
|
|
@@ -332,7 +344,7 @@ function _${programName} () {
|
|
|
332
344
|
__file_quote_offset=$((__file_quote_offset - \${#__reply_prefix}))
|
|
333
345
|
fi
|
|
334
346
|
fi
|
|
335
|
-
if [
|
|
347
|
+
if [ "$__literal" = 0 ] && [ "\${line:0:9}" = '__FILE__:' ]; then
|
|
336
348
|
# Parse file completion directive: __FILE__:type:extensions:pattern:hidden
|
|
337
349
|
IFS=':' read -r _ type extensions pattern hidden <<< "$line"
|
|
338
350
|
extensions="\${extensions//,\\./,}"; extensions="\${extensions#.}"
|
|
@@ -700,7 +712,12 @@ function _${programName.replace(/[^a-zA-Z0-9]/g, "_")} () {
|
|
|
700
712
|
desc=\${line#*\$'\\0'}
|
|
701
713
|
desc=\${desc%%\$'\\0'*}
|
|
702
714
|
|
|
703
|
-
|
|
715
|
+
local __literal=0
|
|
716
|
+
if [[ "\$value" == __LITERAL__:* ]]; then
|
|
717
|
+
value="\${value#__LITERAL__:}"
|
|
718
|
+
__literal=1
|
|
719
|
+
fi
|
|
720
|
+
if [[ \$__literal == 0 && "\$value" == __FILE__:* ]]; then
|
|
704
721
|
# Parse file completion directive: __FILE__:type:extensions:pattern:hidden
|
|
705
722
|
local type extensions pattern hidden
|
|
706
723
|
IFS=':' read -r _ type extensions pattern hidden <<< "\$value"
|
|
@@ -816,7 +833,7 @@ fi
|
|
|
816
833
|
*encodeSuggestions(suggestions) {
|
|
817
834
|
for (const suggestion of suggestions) if (suggestion.kind === "literal") {
|
|
818
835
|
const description = suggestion.description == null ? "" : sanitizeForTransport(formatMessage(suggestion.description, { colors: false }));
|
|
819
|
-
yield `${
|
|
836
|
+
yield `${encodeLiteral(suggestion.text)}\0${description}\0`;
|
|
820
837
|
} else {
|
|
821
838
|
const extensions = encodeExtensions(suggestion.extensions);
|
|
822
839
|
const hidden = suggestion.includeHidden ? "1" : "0";
|
|
@@ -875,7 +892,12 @@ function ${functionName}
|
|
|
875
892
|
${escapedArgs ? ` set -l output (${programName} ${escapedArgs} $prev $current 2>/dev/null)\n` : ` set -l output (${programName} $prev $current 2>/dev/null)\n`}
|
|
876
893
|
# Process each line of output
|
|
877
894
|
for line in $output
|
|
878
|
-
|
|
895
|
+
set -l literal 0
|
|
896
|
+
if string match -q '__LITERAL__:*' -- $line
|
|
897
|
+
set line (string sub -s 13 -- $line)
|
|
898
|
+
set literal 1
|
|
899
|
+
end
|
|
900
|
+
if test $literal -eq 0; and string match -q '__FILE__:*' -- $line
|
|
879
901
|
# Parse file completion directive: __FILE__:type:extensions:pattern:hidden
|
|
880
902
|
set -l directive (string split \\t -- $line)[1]
|
|
881
903
|
set -l parts (string split ':' -- $directive)
|
|
@@ -1166,7 +1188,7 @@ complete -c ${programName} -f -a '(${functionName})'
|
|
|
1166
1188
|
if (i > 0) yield "\n";
|
|
1167
1189
|
if (suggestion.kind === "literal") {
|
|
1168
1190
|
const description = suggestion.description == null ? "" : sanitizeForTransport(formatMessage(suggestion.description, { colors: false }));
|
|
1169
|
-
yield `${
|
|
1191
|
+
yield `${encodeLiteral(suggestion.text)}\t${description}`;
|
|
1170
1192
|
} else {
|
|
1171
1193
|
const extensions = encodeExtensions(suggestion.extensions);
|
|
1172
1194
|
const hidden = suggestion.includeHidden ? "1" : "0";
|
|
@@ -1405,8 +1427,10 @@ ${escapedArgs ? ` ^${programName} ${escapedArgs} ...$final_args | complete |
|
|
|
1405
1427
|
}
|
|
1406
1428
|
|
|
1407
1429
|
# Process each line of output
|
|
1408
|
-
$output | lines | each {|
|
|
1409
|
-
|
|
1430
|
+
$output | lines | each {|raw_line|
|
|
1431
|
+
let literal = ($raw_line | str starts-with '__LITERAL__:')
|
|
1432
|
+
let line = if $literal { $raw_line | str substring 12.. } else { $raw_line }
|
|
1433
|
+
if (not $literal) and ($line | str starts-with '__FILE__:') {
|
|
1410
1434
|
# Parse file completion directive: __FILE__:type:extensions:pattern:hidden
|
|
1411
1435
|
let directive = ($line | split row "\t" | first)
|
|
1412
1436
|
let parts = ($directive | split row ':')
|
|
@@ -1466,22 +1490,26 @@ ${escapedArgs ? ` ^${programName} ${escapedArgs} ...$final_args | complete |
|
|
|
1466
1490
|
# Generate file completions based on type.
|
|
1467
1491
|
# When the glob base contains wildcard characters, use it as-is;
|
|
1468
1492
|
# otherwise append * to treat it as a prefix.
|
|
1469
|
-
# Note: into glob is required so that ls expands wildcards from a variable
|
|
1493
|
+
# Note: into glob is required so that ls expands wildcards from a variable.
|
|
1494
|
+
# A literal prefix has its brackets wrapped as [[] and []] so that path
|
|
1495
|
+
# text like "report[1]" is not parsed as a glob character class; a
|
|
1496
|
+
# wildcard pattern is a glob as a whole, so its brackets stay classes.
|
|
1470
1497
|
let has_glob = ($glob_base =~ '[*?]')
|
|
1471
1498
|
let ls_pattern = if ($glob_base | is-empty) {
|
|
1472
1499
|
"."
|
|
1473
1500
|
} else if $has_glob {
|
|
1474
1501
|
($glob_base | into glob)
|
|
1475
1502
|
} else {
|
|
1476
|
-
($glob_base + "*" | into glob)
|
|
1503
|
+
(($glob_base | str replace -a -r '([\\[\\]])' '[$1]') + "*" | into glob)
|
|
1477
1504
|
}
|
|
1478
1505
|
|
|
1479
1506
|
# When using a glob pattern, also compute a directory listing pattern
|
|
1480
|
-
# so that file/any modes can include directories for navigation
|
|
1507
|
+
# so that file/any modes can include directories for navigation; its
|
|
1508
|
+
# directory part is a literal path
|
|
1481
1509
|
let glob_dir_pattern = if $has_glob {
|
|
1482
1510
|
let dir_part = ($glob_base | path dirname)
|
|
1483
1511
|
let dir = if ($dir_part | is-empty) or ($dir_part == $glob_base) { "." } else { $dir_part }
|
|
1484
|
-
($dir + "/*" | into glob)
|
|
1512
|
+
(($dir | str replace -a -r '([\\[\\]])' '[$1]') + "/*" | into glob)
|
|
1485
1513
|
} else {
|
|
1486
1514
|
null
|
|
1487
1515
|
}
|
|
@@ -1674,7 +1702,7 @@ ${functionName}-external
|
|
|
1674
1702
|
if (i > 0) yield "\n";
|
|
1675
1703
|
if (suggestion.kind === "literal") {
|
|
1676
1704
|
const description = suggestion.description == null ? "" : sanitizeForTransport(formatMessage(suggestion.description, { colors: false }));
|
|
1677
|
-
yield `${
|
|
1705
|
+
yield `${encodeLiteral(suggestion.text)}\t${description}`;
|
|
1678
1706
|
} else {
|
|
1679
1707
|
const extensions = encodeExtensions(suggestion.extensions);
|
|
1680
1708
|
const hidden = suggestion.includeHidden ? "1" : "0";
|
|
@@ -1729,10 +1757,12 @@ ${escapedArgs ? ` \$completionArgs += @(${escapedArgs})
|
|
|
1729
1757
|
|
|
1730
1758
|
# Parse tab-separated output and create CompletionResult objects
|
|
1731
1759
|
\$output -split "\`n" | ForEach-Object {
|
|
1760
|
+
\$literal = \$_.StartsWith('__LITERAL__:', [System.StringComparison]::Ordinal)
|
|
1732
1761
|
\$line = \$_.Trim()
|
|
1733
1762
|
if (-not \$line) { return }
|
|
1763
|
+
if (\$literal) { \$line = \$line.Substring(12) }
|
|
1734
1764
|
|
|
1735
|
-
if (\$
|
|
1765
|
+
if (-not \$literal -and \$_.StartsWith('__FILE__:', [System.StringComparison]::Ordinal)) {
|
|
1736
1766
|
# Parse file completion directive: __FILE__:type:extensions:pattern:hidden
|
|
1737
1767
|
\$directive = (\$line -split "\`t")[0]
|
|
1738
1768
|
\$parts = \$directive -split ':', 5
|
|
@@ -1874,7 +1904,7 @@ ${escapedArgs ? ` \$completionArgs += @(${escapedArgs})
|
|
|
1874
1904
|
if (suggestion.kind === "literal") {
|
|
1875
1905
|
const description = suggestion.description == null ? "" : sanitizeForTransport(formatMessage(suggestion.description, { colors: false }));
|
|
1876
1906
|
const text = sanitizeForTransport(suggestion.text);
|
|
1877
|
-
yield `${text}\t${text}\t${description}`;
|
|
1907
|
+
yield `${encodeLiteral(suggestion.text)}\t${text}\t${description}`;
|
|
1878
1908
|
} else {
|
|
1879
1909
|
const extensions = encodeExtensions(suggestion.extensions);
|
|
1880
1910
|
const hidden = suggestion.includeHidden ? "1" : "0";
|