mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-08 14:18:26 +02:00
rc protocol: Encode strings values in an escape code safe way
Go emits UTF-8 encoded JSON not ascii encoded JSON. Still need to fix lists and dicts of strings
This commit is contained in:
@@ -12,6 +12,7 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf16"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
@@ -27,6 +28,8 @@ import (
|
||||
"github.com/jamesruan/go-rfc1924/base85"
|
||||
)
|
||||
|
||||
const lowerhex = "0123456789abcdef"
|
||||
|
||||
var ProtocolVersion [3]int = [3]int{0, 26, 0}
|
||||
|
||||
type GlobalOptions struct {
|
||||
@@ -36,11 +39,11 @@ type GlobalOptions struct {
|
||||
|
||||
var global_options GlobalOptions
|
||||
|
||||
func expand_ansi_c_escapes_in_args(args ...string) (string, error) {
|
||||
func expand_ansi_c_escapes_in_args(args ...string) (escaped_string, error) {
|
||||
for i, x := range args {
|
||||
args[i] = shlex.ExpandANSICEscapes(x)
|
||||
}
|
||||
return strings.Join(args, " "), nil
|
||||
return escaped_string(strings.Join(args, " ")), nil
|
||||
}
|
||||
|
||||
func set_payload_string_field(io_data *rc_io_data, field, data string) {
|
||||
@@ -76,6 +79,48 @@ func get_pubkey(encoded_key string) (encryption_version string, pubkey []byte, e
|
||||
return
|
||||
}
|
||||
|
||||
type escaped_string string
|
||||
|
||||
func (s escaped_string) MarshalJSON() ([]byte, error) {
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON
|
||||
// we additionally escape all non-ascii chars so they can be safely transmitted inside an escape code
|
||||
src := utf16.Encode([]rune(s))
|
||||
buf := make([]byte, 0, len(src)+128)
|
||||
a := func(x ...byte) {
|
||||
buf = append(buf, x...)
|
||||
}
|
||||
a('"')
|
||||
for _, r := range src {
|
||||
if ' ' <= r && r <= 126 {
|
||||
buf = append(buf, byte(r))
|
||||
continue
|
||||
}
|
||||
switch r {
|
||||
case '\n':
|
||||
a('\\', 'n')
|
||||
case '\t':
|
||||
a('\\', 't')
|
||||
case '\r':
|
||||
a('\\', 'r')
|
||||
case '\f':
|
||||
a('\\', 'f')
|
||||
case '\b':
|
||||
a('\\', 'b')
|
||||
case '\\':
|
||||
a('\\', '\\')
|
||||
case '"':
|
||||
a('\\', '"')
|
||||
default:
|
||||
a('\\', 'u')
|
||||
for s := 12; s >= 0; s -= 4 {
|
||||
a(lowerhex[r>>uint(s)&0xF])
|
||||
}
|
||||
}
|
||||
}
|
||||
a('"')
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func simple_serializer(rc *utils.RemoteControlCmd) (ans []byte, err error) {
|
||||
return json.Marshal(rc)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,25 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEncodeJSON(t *testing.T) {
|
||||
tests := map[string]string{
|
||||
"a b\nc\td\a": `a b\nc\td\u0007`,
|
||||
"•": `\u2022`,
|
||||
"\U0001f123": `\ud83c\udd23`,
|
||||
}
|
||||
var s escaped_string
|
||||
for x, expected := range tests {
|
||||
s = escaped_string(x)
|
||||
expected = `"` + expected + `"`
|
||||
actualb, _ := s.MarshalJSON()
|
||||
actual := string(actualb)
|
||||
if expected != actual {
|
||||
t.Fatalf("Failed for %#v\n%#v != %#v", x, expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCommandToJSON(t *testing.T) {
|
||||
pv := fmt.Sprint(ProtocolVersion[0], ",", ProtocolVersion[1], ",", ProtocolVersion[2])
|
||||
rc, err := create_rc_ls([]string{})
|
||||
|
||||
Reference in New Issue
Block a user