aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mingling_core/src/asset/comp/shell_ctx.rs19
-rw-r--r--mingling_core/tmpls/comps/pwsh.ps186
2 files changed, 73 insertions, 32 deletions
diff --git a/mingling_core/src/asset/comp/shell_ctx.rs b/mingling_core/src/asset/comp/shell_ctx.rs
index e5d095c..dd2aa86 100644
--- a/mingling_core/src/asset/comp/shell_ctx.rs
+++ b/mingling_core/src/asset/comp/shell_ctx.rs
@@ -175,8 +175,14 @@ impl ShellContext {
///
/// This method determines whether the current word being typed starts with
/// a dash (`-`), indicating that the user is likely in the process of
- /// entering a command-line flag. It returns `true` if the current word
- /// begins with a dash character.
+ /// entering a command-line flag. On Windows, an empty current word is also
+ /// considered as typing a flag to accommodate shell behavior differences.
+ /// It returns `true` if the current word begins with a dash character.
+ ///
+ /// # Platform-specific behavior
+ ///
+ /// - **Windows**: Returns `true` if `current_word` is empty or starts with `-`
+ /// - **Other platforms**: Returns `true` only if `current_word` starts with `-`
///
/// # Example
///
@@ -197,7 +203,14 @@ impl ShellContext {
/// }
/// ```
pub fn typing_argument(&self) -> bool {
- self.current_word.starts_with("-")
+ #[cfg(target_os = "windows")]
+ {
+ self.current_word.is_empty()
+ }
+ #[cfg(not(target_os = "windows"))]
+ {
+ self.current_word.starts_with("-")
+ }
}
/// Filters out already typed flag arguments from suggestion results.
diff --git a/mingling_core/tmpls/comps/pwsh.ps1 b/mingling_core/tmpls/comps/pwsh.ps1
index 6d7d91d..8a52a4f 100644
--- a/mingling_core/tmpls/comps/pwsh.ps1
+++ b/mingling_core/tmpls/comps/pwsh.ps1
@@ -1,43 +1,71 @@
-Register-ArgumentCompleter -CommandName <<<bin_name>>> -ScriptBlock {
+# PowerShell completion script for <<<bin_name>>>
+Register-ArgumentCompleter -Native -CommandName '<<<bin_name>>>' -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition)
- $line = $commandAst.ToString()
- $commandName = if ($commandAst.CommandElements.Count -gt 0) {
- $commandAst.CommandElements[0].Value
- } else { "" }
+ $words = $commandAst.ToString().Split(' ')
+ $currentIndex = $words.IndexOf($wordToComplete)
+ if ($currentIndex -eq -1) { $currentIndex = $words.Count }
- $words = @()
- $currentIndex = 0
- $parser = [System.Management.Automation.PSParser]
- $tokens = $parser::Tokenize($line, [ref]$null)
-
- foreach ($token in $tokens) {
- if ($token.Type -in 'CommandArgument', 'CommandParameter') {
- $words += $token.Content
- }
- }
+ $buffer = $commandAst.ToString()
+ $currentWord = $wordToComplete
+ $previousWord = if ($currentIndex -gt 1) { $words[$currentIndex - 2] } else { "" }
+ $commandName = if ($words.Count -gt 0) { $words[0] } else { "" }
+ $wordIndex = $currentIndex
$args = @(
- "-f", ($line -replace '-', '^')
- "-C", $cursorPosition.ToString()
- "-w", ($wordToComplete -replace '-', '^')
- "-p", (if ($words.Count -gt 1) { $words[-2] } else { "" }) -replace '-', '^'
+ "-f", $buffer.Replace('-', '^')
+ "-C", $cursorPosition
+ "-w", $currentWord.Replace('-', '^')
+ "-p", $previousWord.Replace('-', '^')
"-c", $commandName
- "-i", ($words.Count - 1).ToString()
- "-a", ($words | ForEach-Object { $_ -replace '-', '^' })
- "-F", "powershell"
+ "-i", $wordIndex
+ "-a", ($words | ForEach-Object { $_.Replace('-', '^') }) -join ' '
+ "-F", "pwsh"
)
- $suggestions = <<<bin_name>>> __comp $args 2>$null
+ $suggestions = & <<<bin_name>>> __comp $args 2>$null
- if ($suggestions) {
- $suggestions | ForEach-Object {
- if ($_ -eq "_file_") {
- $completionType = 'ProviderItem'
+ if ($LASTEXITCODE -eq 0 -and $suggestions) {
+ $completions = $suggestions -split "`n"
+
+ if ($completions[0].Trim() -eq "_file_") {
+ $completions = if ($completions.Count -gt 1) {
+ $completions[1..($completions.Count-1)]
} else {
- $completionType = 'ParameterValue'
+ @()
+ }
+
+ $completions | ForEach-Object {
+ $path = $_.Replace('^', '-')
+ $isDirectory = $path.EndsWith([System.IO.Path]::DirectorySeparatorChar) -or $path.EndsWith('/')
+ $completionType = if ($isDirectory) { 'ProviderContainer' } else { 'ProviderItem' }
+ [System.Management.Automation.CompletionResult]::new($path, $path, $completionType, $path)
+ }
+ }
+ else {
+ $parsedCompletions = @()
+ foreach ($item in $completions) {
+ if ($item -match '^([^$]+)\$\((.+)\)$') {
+ $parsedCompletions += "$($matches[1]):$($matches[2])"
+ }
+ else {
+ $parsedCompletions += $item
+ }
+ }
+
+ $simpleCompletions = @()
+ foreach ($item in $parsedCompletions) {
+ if ($item -match '^([^:]+):(.+)$') {
+ $simpleCompletions += $matches[1]
+ }
+ else {
+ $simpleCompletions += $item
+ }
+ }
+
+ return $simpleCompletions | ForEach-Object {
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
}
- [System.Management.Automation.CompletionResult]::new($_, $_, $completionType, $_)
}
}
}