Repository: rsteube/carapace
Pull request #222 (2021-01-13 13:52:45)

powershell: removed invoke-expression
related #3
related #192
related #194
related #215


Patch:
diff --git a/internal/powershell/action.go b/internal/powershell/action.go
index a9953e1..7ed6d58 100644
--- a/internal/powershell/action.go
+++ b/internal/powershell/action.go
@@ -1,7 +1,7 @@
 package powershell
 
 import (
-	"fmt"
+	"encoding/json"
 	"strings"
 
 	"github.com/rsteube/carapace/internal/common"
@@ -38,12 +38,31 @@ func EscapeSpace(value string) string {
 	return strings.Replace(value, " ", "` ", -1)
 }
 
+type completionResult struct {
+	CompletionText string
+	ListItemText   string
+	ToolTip        string
+}
+
+// CompletionResult doesn't like empty parameters, so just replace with space if needed
+func ensureNotEmpty(s string) string {
+	if s == "" {
+		return " "
+	}
+	return s
+}
+
 func ActionRawValues(callbackValue string, values ...common.RawValue) string {
-	vals := make([]string, len(values))
-	for index, val := range values {
+	vals := make([]completionResult, 0, len(values))
+	for _, val := range values {
 		if val.Value != "" { // must not be empty - any empty `''` parameter in CompletionResult causes an error
-			vals[index] = fmt.Sprintf(`[CompletionResult]::new('%v', '%v ', [CompletionResultType]::ParameterValue, '%v ')`, EscapeSpace(sanitizer.Replace(val.Value)), sanitizer.Replace(val.Display), sanitizer.Replace(val.Description))
+			vals = append(vals, completionResult{
+				CompletionText: EscapeSpace(sanitizer.Replace(val.Value)),
+				ListItemText:   ensureNotEmpty(sanitizer.Replace(val.Display)),
+				ToolTip:        ensureNotEmpty(sanitizer.Replace(val.Description)),
+			})
 		}
 	}
-	return strings.Join(vals, "\n")
+	m, _ := json.Marshal(vals)
+	return string(m)
 }
diff --git a/internal/powershell/snippet.go b/internal/powershell/snippet.go
index fdca021..a8ea3a0 100644
--- a/internal/powershell/snippet.go
+++ b/internal/powershell/snippet.go
@@ -18,9 +18,9 @@ Function _%v_completer {
 
     $completions = @(
       if (!$wordToComplete) {
-        %v _carapace powershell _ $($commandElements| ForEach-Object {$_.Extent}) '""' | Out-String | Invoke-Expression
+        %v _carapace powershell _ $($commandElements| ForEach-Object {$_.Extent}) '""' | ConvertFrom-Json | ForEach-Object { [CompletionResult]::new($_.CompletionText, $_.ListItemText, [CompletionResultType]::ParameterValue, $_.ToolTip) }
       } else {
-        %v _carapace powershell _ $($commandElements| ForEach-Object {$_.Extent}) | Out-String | Invoke-Expression
+        %v _carapace powershell _ $($commandElements| ForEach-Object {$_.Extent}) | ConvertFrom-Json | ForEach-Object { [CompletionResult]::new($_.CompletionText, $_.ListItemText, [CompletionResultType]::ParameterValue, $_.ToolTip) }
       }
     )
 


Test patch:
diff --git a/example/cmd/_test/powershell.ps1 b/example/cmd/_test/powershell.ps1
index 6395e64..c7fd8c1 100644
--- a/example/cmd/_test/powershell.ps1
+++ b/example/cmd/_test/powershell.ps1
@@ -8,9 +8,9 @@ Function _example_completer {
 
     $completions = @(
       if (!$wordToComplete) {
-        example _carapace powershell _ $($commandElements| ForEach-Object {$_.Extent}) '""' | Out-String | Invoke-Expression
+        example _carapace powershell _ $($commandElements| ForEach-Object {$_.Extent}) '""' | ConvertFrom-Json | ForEach-Object { [CompletionResult]::new($_.CompletionText, $_.ListItemText, [CompletionResultType]::ParameterValue, $_.ToolTip) }
       } else {
-        example _carapace powershell _ $($commandElements| ForEach-Object {$_.Extent}) | Out-String | Invoke-Expression
+        example _carapace powershell _ $($commandElements| ForEach-Object {$_.Extent}) | ConvertFrom-Json | ForEach-Object { [CompletionResult]::new($_.CompletionText, $_.ListItemText, [CompletionResultType]::ParameterValue, $_.ToolTip) }
       }
     )