Repository: rsteube/carapace
Pull request #223 (2021-01-13 15:11:55)

xonsh: remove eval
related #3
related #192
related #194
related #215


Patch:
diff --git a/internal/xonsh/action.go b/internal/xonsh/action.go
index d68047a..8529809 100644
--- a/internal/xonsh/action.go
+++ b/internal/xonsh/action.go
@@ -1,7 +1,7 @@
 package xonsh
 
 import (
-	"fmt"
+	"encoding/json"
 	"strings"
 
 	"github.com/rsteube/carapace/internal/common"
@@ -32,6 +32,12 @@ func Sanitize(values ...string) []string {
 	return sanitized
 }
 
+type richCompletion struct {
+	Value       string
+	Display     string
+	Description string
+}
+
 func ActionRawValues(callbackValue string, values ...common.RawValue) string {
 	filtered := make([]common.RawValue, 0)
 
@@ -41,9 +47,10 @@ func ActionRawValues(callbackValue string, values ...common.RawValue) string {
 		}
 	}
 
-	vals := make([]string, len(filtered))
+	vals := make([]richCompletion, len(filtered))
 	for index, val := range filtered {
-		vals[index] = fmt.Sprintf(`  RichCompletion('%v', display='%v', description='%v', prefix_len=0),`, sanitizer.Replace(val.Value), sanitizer.Replace(val.Display), sanitizer.Replace(val.Description))
+		vals[index] = richCompletion{Value: sanitizer.Replace(val.Value), Display: sanitizer.Replace(val.Display), Description: sanitizer.Replace(val.Description)}
 	}
-	return fmt.Sprintf("{\n%v\n}", strings.Join(vals, "\n"))
+	m, _ := json.Marshal(vals)
+	return string(m)
 }
diff --git a/internal/xonsh/snippet.go b/internal/xonsh/snippet.go
index f3be550..382f16c 100644
--- a/internal/xonsh/snippet.go
+++ b/internal/xonsh/snippet.go
@@ -47,17 +47,14 @@ func Snippet(cmd *cobra.Command, actions map[string]string) string {
     result = {}
 
     def _%v_callback():
+        from json import loads
         from subprocess import Popen, PIPE
         from xonsh.completers.tools import RichCompletion
-        cb, _ = Popen(['%v', '_carapace', 'xonsh', '_', *words],
-                                     stdout=PIPE,
-                                     stderr=PIPE).communicate()
-        cb = cb.decode('utf-8')
-        if cb == "":
-            return {}
-        else:
-            nonlocal prefix, line, begidx, endidx, ctx
-            return eval(cb)
+        cb, _ = Popen(['%v', '_carapace', 'xonsh', '_', *words], stdout=PIPE, stderr=PIPE).communicate()
+        try:
+          return {RichCompletion(c["Value"], display=c["Display"], description=c["Description"], prefix_len=0) for c in loads(cb)}
+        except:
+          return {}
   
     result = _%v_callback()
 


Test patch:
diff --git a/example/cmd/_test/xonsh.py b/example/cmd/_test/xonsh.py
index 92969ae..347ad6e 100644
--- a/example/cmd/_test/xonsh.py
+++ b/example/cmd/_test/xonsh.py
@@ -35,17 +35,14 @@ def _example_completer(prefix, line, begidx, endidx, ctx):
     result = {}
 
     def _example_callback():
+        from json import loads
         from subprocess import Popen, PIPE
         from xonsh.completers.tools import RichCompletion
-        cb, _ = Popen(['example', '_carapace', 'xonsh', '_', *words],
-                                     stdout=PIPE,
-                                     stderr=PIPE).communicate()
-        cb = cb.decode('utf-8')
-        if cb == "":
-            return {}
-        else:
-            nonlocal prefix, line, begidx, endidx, ctx
-            return eval(cb)
+        cb, _ = Popen(['example', '_carapace', 'xonsh', '_', *words], stdout=PIPE, stderr=PIPE).communicate()
+        try:
+          return {RichCompletion(c["Value"], display=c["Display"], description=c["Description"], prefix_len=0) for c in loads(cb)}
+        except:
+          return {}
   
     result = _example_callback()