Repository: rsteube/carapace
Pull request #249 (2021-03-10 23:38:35)

powershell reenable special characters
#215 

rsteube: still some issues with colon:
```sh
example multiparts DIRECTORY=example/`,<TAB>
```

Patch:
diff --git a/internal/common/value.go b/internal/common/value.go
index ee06fa3..cb7de5c 100644
--- a/internal/common/value.go
+++ b/internal/common/value.go
@@ -38,3 +38,15 @@ type ByDisplay []RawValue
 func (a ByDisplay) Len() int           { return len(a) }
 func (a ByDisplay) Less(i, j int) bool { return a[i].Display < a[j].Display }
 func (a ByDisplay) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+
+type ByValues []RawValue
+
+func (r ByValues) Filter(prefix string) []RawValue {
+	filtered := make([]RawValue, 0, len(r))
+	for _, v := range r {
+		if strings.HasPrefix(v.Value, prefix) {
+			filtered = append(filtered, v)
+		}
+	}
+	return filtered
+}
diff --git a/internal/powershell/action.go b/internal/powershell/action.go
index 7ed6d58..8ada722 100644
--- a/internal/powershell/action.go
+++ b/internal/powershell/action.go
@@ -2,28 +2,17 @@ package powershell
 
 import (
 	"encoding/json"
+	"fmt"
+	"sort"
 	"strings"
 
 	"github.com/rsteube/carapace/internal/common"
 )
 
 var sanitizer = strings.NewReplacer( // TODO
-	`$`, ``,
-	"`", ``,
 	"\n", ``,
-	`\`, ``,
-	`"`, ``,
-	`'`, ``,
-	`|`, ``,
-	`>`, ``,
-	`<`, ``,
-	`&`, ``,
-	`(`, ``,
-	`)`, ``,
-	`;`, ``,
-	`#`, ``,
-	`’`, ``,
-	`,`, "`,",
+	"\t", ``,
+	`'`, "``",
 )
 
 func Sanitize(values ...string) []string {
@@ -34,10 +23,6 @@ func Sanitize(values ...string) []string {
 	return sanitized
 }
 
-func EscapeSpace(value string) string {
-	return strings.Replace(value, " ", "` ", -1)
-}
-
 type completionResult struct {
 	CompletionText string
 	ListItemText   string
@@ -53,11 +38,20 @@ func ensureNotEmpty(s string) string {
 }
 
 func ActionRawValues(callbackValue string, values ...common.RawValue) string {
-	vals := make([]completionResult, 0, len(values))
-	for _, val := range values {
+	filtered := common.ByValues(values).Filter(callbackValue)
+	sort.Sort(common.ByDisplay(filtered))
+
+	vals := make([]completionResult, 0, len(filtered))
+	for _, val := range filtered {
 		if val.Value != "" { // must not be empty - any empty `''` parameter in CompletionResult causes an error
+			val.Value = sanitizer.Replace(val.Value)
+
+			if strings.ContainsAny(val.Value, ` {}()[]*$?\"|<>&(),;#`+"`") {
+				val.Value = fmt.Sprintf("'%v'", val.Value)
+			}
+
 			vals = append(vals, completionResult{
-				CompletionText: EscapeSpace(sanitizer.Replace(val.Value)),
+				CompletionText: val.Value,
 				ListItemText:   ensureNotEmpty(sanitizer.Replace(val.Display)),
 				ToolTip:        ensureNotEmpty(sanitizer.Replace(val.Description)),
 			})
diff --git a/internal/powershell/snippet.go b/internal/powershell/snippet.go
index aa37aa7..b4c90b1 100644
--- a/internal/powershell/snippet.go
+++ b/internal/powershell/snippet.go
@@ -15,12 +15,26 @@ Function _%v_completer {
     param($wordToComplete, $commandAst) #, $cursorPosition)
     $commandElements = $commandAst.CommandElements
 
+    # double quoted value works but seems single quoted needs some fixing (e.g. "example 'acti" -> "example acti")
+    $elems = $commandElements | ForEach-Object {
+       $t =$_.Extent.Text
+       if ($t.Substring(0,1) -eq "'"){
+         $t = $t.Substring(1)
+       }
+       if ($t.get_Length() -gt 0 -and $t.Substring($t.get_Length()-1) -eq "'"){
+         $t = $t.Substring(0,$t.get_Length()-1)
+       }
+       if ($t.get_Length() -eq 0){
+         $t = '""'
+       }
+       $t
+    }
 
     $completions = @(
       if (!$wordToComplete) {
-        %v _carapace powershell _ $($commandElements| ForEach-Object {$_.Extent}) '""' | ConvertFrom-Json | ForEach-Object { [CompletionResult]::new($_.CompletionText, $_.ListItemText, [CompletionResultType]::ParameterValue, $_.ToolTip) }
+        %v _carapace powershell _ $($elems| ForEach-Object {$_}) '""' | ConvertFrom-Json | ForEach-Object { [CompletionResult]::new($_.CompletionText, $_.ListItemText, [CompletionResultType]::ParameterValue, $_.ToolTip) }
       } else {
-        %v _carapace powershell _ $($commandElements| ForEach-Object {$_.Extent}) | ConvertFrom-Json | ForEach-Object { [CompletionResult]::new($_.CompletionText, $_.ListItemText, [CompletionResultType]::ParameterValue, $_.ToolTip) }
+        %v _carapace powershell _ $($elems| ForEach-Object {$_}) | ConvertFrom-Json | ForEach-Object { [CompletionResult]::new($_.CompletionText, $_.ListItemText, [CompletionResultType]::ParameterValue, $_.ToolTip) }
       }
     )
 
@@ -28,8 +42,7 @@ Function _%v_completer {
       return "" # prevent default file completion
     }
 
-    $completions.Where{ ($_.CompletionText -replace '`+"`"+`','') -like "$wordToComplete*" } |
-        Sort-Object -Property ListItemText
+    $completions
 }
 Register-ArgumentCompleter -Native -CommandName '%v' -ScriptBlock (Get-Item "Function:_%v_completer").ScriptBlock
 `, cmd.Name(), uid.Executable(), uid.Executable(), cmd.Name(), cmd.Name())


Test patch:
diff --git a/example/cmd/_test/powershell.ps1 b/example/cmd/_test/powershell.ps1
index c7fd8c1..a0981d2 100644
--- a/example/cmd/_test/powershell.ps1
+++ b/example/cmd/_test/powershell.ps1
@@ -5,12 +5,26 @@ Function _example_completer {
     param($wordToComplete, $commandAst) #, $cursorPosition)
     $commandElements = $commandAst.CommandElements
 
+    # double quoted value works but seems single quoted needs some fixing (e.g. "example 'acti" -> "example acti")
+    $elems = $commandElements | ForEach-Object {
+       $t =$_.Extent.Text
+       if ($t.Substring(0,1) -eq "'"){
+         $t = $t.Substring(1)
+       }
+       if ($t.get_Length() -gt 0 -and $t.Substring($t.get_Length()-1) -eq "'"){
+         $t = $t.Substring(0,$t.get_Length()-1)
+       }
+       if ($t.get_Length() -eq 0){
+         $t = '""'
+       }
+       $t
+    }
 
     $completions = @(
       if (!$wordToComplete) {
-        example _carapace powershell _ $($commandElements| ForEach-Object {$_.Extent}) '""' | ConvertFrom-Json | ForEach-Object { [CompletionResult]::new($_.CompletionText, $_.ListItemText, [CompletionResultType]::ParameterValue, $_.ToolTip) }
+        example _carapace powershell _ $($elems| ForEach-Object {$_}) '""' | ConvertFrom-Json | ForEach-Object { [CompletionResult]::new($_.CompletionText, $_.ListItemText, [CompletionResultType]::ParameterValue, $_.ToolTip) }
       } else {
-        example _carapace powershell _ $($commandElements| ForEach-Object {$_.Extent}) | ConvertFrom-Json | ForEach-Object { [CompletionResult]::new($_.CompletionText, $_.ListItemText, [CompletionResultType]::ParameterValue, $_.ToolTip) }
+        example _carapace powershell _ $($elems| ForEach-Object {$_}) | ConvertFrom-Json | ForEach-Object { [CompletionResult]::new($_.CompletionText, $_.ListItemText, [CompletionResultType]::ParameterValue, $_.ToolTip) }
       }
     )
 
@@ -18,8 +32,7 @@ Function _example_completer {
       return "" # prevent default file completion
     }
 
-    $completions.Where{ ($_.CompletionText -replace '`','') -like "$wordToComplete*" } |
-        Sort-Object -Property ListItemText
+    $completions
 }
 Register-ArgumentCompleter -Native -CommandName 'example' -ScriptBlock (Get-Item "Function:_example_completer").ScriptBlock