Get transmission medium detection working

This commit is contained in:
Kovid Goyal 2022-12-22 11:42:14 +05:30
parent 2d1a2c30bf
commit ea756db544
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -3,6 +3,7 @@
package icat package icat
import ( import (
"errors"
"fmt" "fmt"
"os" "os"
@ -11,6 +12,7 @@ import (
"kitty/tools/tui/graphics" "kitty/tools/tui/graphics"
"kitty/tools/tui/loop" "kitty/tools/tui/loop"
"kitty/tools/utils" "kitty/tools/utils"
"kitty/tools/utils/shm"
) )
var _ = fmt.Print var _ = fmt.Print
@ -29,8 +31,11 @@ const (
var transfer_by_file, transfer_by_memory, transfer_by_stream transfer_mode var transfer_by_file, transfer_by_memory, transfer_by_stream transfer_mode
var temp_files_to_delete []string var temp_files_to_delete []string
var shm_files_to_delete []shm.MMap
var direct_query_id, file_query_id, memory_query_id uint32 var direct_query_id, file_query_id, memory_query_id uint32
var stderr_is_tty bool var stderr_is_tty bool
var query_in_flight bool
var stream_response string
func print_error(format string, args ...any) { func print_error(format string, args ...any) {
if lp == nil || !stderr_is_tty { if lp == nil || !stderr_is_tty {
@ -44,10 +49,12 @@ func print_error(format string, args ...any) {
func on_initialize() (string, error) { func on_initialize() (string, error) {
var iid uint32 var iid uint32
query_in_flight = true
g := func(t graphics.GRT_t, payload string) uint32 { g := func(t graphics.GRT_t, payload string) uint32 {
iid += 1 iid += 1
g1 := &graphics.GraphicsCommand{} g1 := &graphics.GraphicsCommand{}
g1.SetTransmission(t).SetAction(graphics.GRT_action_query).SetImageId(iid).SetDataWidth(1).SetDataHeight(1).SetFormat(graphics.GRT_format_rgb) g1.SetTransmission(t).SetAction(graphics.GRT_action_query).SetImageId(iid).SetDataWidth(1).SetDataHeight(1).SetFormat(
graphics.GRT_format_rgb).SetDataSize(uint64(len(payload)))
g1.WriteWithPayloadToLoop(lp, utils.UnsafeStringToBytes(payload)) g1.WriteWithPayloadToLoop(lp, utils.UnsafeStringToBytes(payload))
return iid return iid
} }
@ -69,16 +76,90 @@ func on_initialize() (string, error) {
transfer_by_file = unsupported transfer_by_file = unsupported
print_error("Failed to create temporary file for data transfer, file based transfer is disabled. Error: %v", err) print_error("Failed to create temporary file for data transfer, file based transfer is disabled. Error: %v", err)
} }
sf, err := shm.CreateTemp("icat-", 3)
if err == nil {
memory_query_id = g(graphics.GRT_transmission_sharedmem, sf.Name())
shm_files_to_delete = append(shm_files_to_delete, sf)
copy(sf.Slice(), []byte{1, 2, 3})
sf.Close()
} else {
transfer_by_memory = unsupported
var ens *shm.ErrNotSupported
if !errors.As(err, &ens) {
print_error("Failed to create SHM for data transfer, memory based transfer is disabled. Error: %v", err)
}
}
lp.QueueWriteString("\x1b[c")
return "", nil return "", nil
} }
func on_query_finished() (err error) {
query_in_flight = false
if transfer_by_stream != supported {
return fmt.Errorf("This terminal emulator does not support the graphics protocol, use a terminal emulator such as kitty that does support it")
}
if opts.DetectSupport {
switch {
case transfer_by_memory == supported:
print_error("memory")
case transfer_by_file == supported:
print_error("file")
default:
print_error("stream")
}
lp.Quit(0)
return
}
return
}
func on_query_response(g *graphics.GraphicsCommand) (err error) {
var tm *transfer_mode
switch g.ImageId() {
case direct_query_id:
tm = &transfer_by_stream
case file_query_id:
tm = &transfer_by_file
case memory_query_id:
tm = &transfer_by_memory
}
if g.ResponseMessage() == "OK" {
*tm = supported
} else {
*tm = unsupported
}
return
}
func on_escape_code(etype loop.EscapeCodeType, payload []byte) (err error) {
switch etype {
case loop.CSI:
if len(payload) > 3 && payload[0] == '?' && payload[len(payload)-1] == 'c' {
return on_query_finished()
}
case loop.APC:
g := graphics.GraphicsCommandFromAPC(payload)
if g != nil {
if query_in_flight {
return on_query_response(g)
}
}
}
return
}
func on_finalize() string { func on_finalize() string {
if len(temp_files_to_delete) > 0 { if len(temp_files_to_delete) > 0 && transfer_by_file != supported {
for _, name := range temp_files_to_delete { for _, name := range temp_files_to_delete {
os.Remove(name) os.Remove(name)
} }
} }
if len(shm_files_to_delete) > 0 && transfer_by_memory != supported {
for _, name := range shm_files_to_delete {
name.Unlink()
}
}
return "" return ""
} }
@ -98,13 +179,25 @@ func main(cmd *cli.Command, o *Options, args []string) (rc int, err error) {
return 0, nil return 0, nil
} }
temp_files_to_delete = make([]string, 0, 8) temp_files_to_delete = make([]string, 0, 8)
shm_files_to_delete = make([]shm.MMap, 0, 8)
lp, err = loop.New(loop.NoAlternateScreen, loop.NoRestoreColors, loop.NoMouseTracking) lp, err = loop.New(loop.NoAlternateScreen, loop.NoRestoreColors, loop.NoMouseTracking)
if err != nil { if err != nil {
return return
} }
lp.OnInitialize = on_initialize lp.OnInitialize = on_initialize
lp.OnFinalize = on_finalize lp.OnFinalize = on_finalize
lp.OnEscapeCode = on_escape_code
err = lp.Run()
if err != nil {
return
}
ds := lp.DeathSignalName()
if ds != "" {
fmt.Println("Killed by signal: ", ds)
lp.KillIfSignalled()
return
}
return 0, nil return 0, nil
} }