waveterm/pkg/wshutil/wshutil.go
Mike Sawka 01b5d71709
new wshrpc mechanism (#112)
lots of changes. new wshrpc implementation. unify websocket, web,
blockcontroller, domain sockets, and terminal inputs to all use the new
rpc system.

lots of moving files around to deal with circular dependencies

use new wshrpc as a client in wsh cmd
2024-07-17 15:24:43 -07:00

97 lines
2.3 KiB
Go

// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
package wshutil
import (
"bytes"
"encoding/json"
"fmt"
)
// these should both be 5 characters
const WaveOSC = "23198"
const WaveServerOSC = "23199"
const WaveOSCPrefixLen = 5 + 3 // \x1b] + WaveOSC + ; + \x07
const WaveOSCPrefix = "\x1b]" + WaveOSC + ";"
const WaveServerOSCPrefix = "\x1b]" + WaveServerOSC + ";"
const HexChars = "0123456789ABCDEF"
const BEL = 0x07
const ST = 0x9c
const ESC = 0x1b
// OSC escape types
// OSC 23198 ; (JSON | base64-JSON) ST
// JSON = must escape all ASCII control characters ([\x00-\x1F\x7F])
// we can tell the difference between JSON and base64-JSON by the first character: '{' or not
// for responses (terminal -> program), we'll use OSC 23199
// same json format
func copyOscPrefix(dst []byte, oscNum string) {
dst[0] = ESC
dst[1] = ']'
copy(dst[2:], oscNum)
dst[len(oscNum)+2] = ';'
}
func oscPrefixLen(oscNum string) int {
return 3 + len(oscNum)
}
func makeOscPrefix(oscNum string) []byte {
output := make([]byte, oscPrefixLen(oscNum))
copyOscPrefix(output, oscNum)
return output
}
func EncodeWaveOSCBytes(oscNum string, barr []byte) []byte {
if len(oscNum) != 5 {
panic("oscNum must be 5 characters")
}
hasControlChars := false
for _, b := range barr {
if b < 0x20 || b == 0x7F {
hasControlChars = true
break
}
}
if !hasControlChars {
// If no control characters, directly construct the output
// \x1b] (2) + WaveOSC + ; (1) + message + \x07 (1)
output := make([]byte, oscPrefixLen(oscNum)+len(barr)+1)
copyOscPrefix(output, oscNum)
copy(output[oscPrefixLen(oscNum):], barr)
output[len(output)-1] = BEL
return output
}
var buf bytes.Buffer
buf.Write(makeOscPrefix(oscNum))
escSeq := [6]byte{'\\', 'u', '0', '0', '0', '0'}
for _, b := range barr {
if b < 0x20 || b == 0x7f {
escSeq[4] = HexChars[b>>4]
escSeq[5] = HexChars[b&0x0f]
buf.Write(escSeq[:])
} else {
buf.WriteByte(b)
}
}
buf.WriteByte(BEL)
return buf.Bytes()
}
func EncodeWaveOSCMessageEx(oscNum string, msg *RpcMessage) ([]byte, error) {
if msg == nil {
return nil, fmt.Errorf("nil message")
}
barr, err := json.Marshal(msg)
if err != nil {
return nil, fmt.Errorf("error marshalling message to json: %w", err)
}
return EncodeWaveOSCBytes(oscNum, barr), nil
}