mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-08 14:18:26 +02:00
More work on dnd kitten
This commit is contained in:
@@ -391,7 +391,7 @@ examine the :ref:`machine_id` sent with the enable drag offers
|
|||||||
from the URI list. To request data for a particular entry, terminals send an
|
from the URI list. To request data for a particular entry, terminals send an
|
||||||
escape code of the form::
|
escape code of the form::
|
||||||
|
|
||||||
OSC _dnd_code ; t=k:x=idx ; base64 encoded file data ST
|
OSC _dnd_code ; t=k:x=idx ST
|
||||||
|
|
||||||
Here ``idx`` is the one based index into the list of entries in the
|
Here ``idx`` is the one based index into the list of entries in the
|
||||||
``text/uri-list`` MIME type. Then the client can respond with the data
|
``text/uri-list`` MIME type. Then the client can respond with the data
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ var _ = fmt.Print
|
|||||||
|
|
||||||
type data_request struct {
|
type data_request struct {
|
||||||
drag_source *drag_source
|
drag_source *drag_source
|
||||||
send_remote_data bool
|
|
||||||
index int
|
index int
|
||||||
write_id loop.IdType
|
write_id loop.IdType
|
||||||
base64 streaming_base64.StreamingBase64Encoder
|
base64 streaming_base64.StreamingBase64Encoder
|
||||||
@@ -51,7 +50,7 @@ type drag_status struct {
|
|||||||
current_remote_file *remote_data_item
|
current_remote_file *remote_data_item
|
||||||
dir_handle_counter int
|
dir_handle_counter int
|
||||||
remote_item_write_id loop.IdType
|
remote_item_write_id loop.IdType
|
||||||
remote_data_was_sent bool
|
remote_data_requests []int
|
||||||
}
|
}
|
||||||
|
|
||||||
func find_drag_image(drag_sources map[string]*drag_source) image.Image {
|
func find_drag_image(drag_sources map[string]*drag_source) image.Image {
|
||||||
@@ -66,12 +65,10 @@ func find_drag_image(drag_sources map[string]*drag_source) image.Image {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var uri_list []string
|
var uri_list []string
|
||||||
if ds := drag_sources["text/uri-list"]; ds != nil && len(ds.data) > 0 {
|
if ds := drag_sources["text/uri-list"]; ds != nil {
|
||||||
if q, err := parse_uri_list(string(ds.data)); err == nil {
|
for _, e := range ds.uri_list {
|
||||||
for _, path := range q {
|
if e.path != "" {
|
||||||
if path != "" {
|
uri_list = append(uri_list, e.path)
|
||||||
uri_list = append(uri_list, path)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,16 +99,14 @@ func (dnd *dnd) set_drag_image_text() (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if icon == "" {
|
if icon == "" {
|
||||||
if ds := dnd.drag_sources["text/uri-list"]; ds != nil && len(ds.data) > 0 {
|
if ds := dnd.drag_sources["text/uri-list"]; ds != nil {
|
||||||
if q, err := parse_uri_list(string(ds.data)); err == nil {
|
for _, e := range ds.uri_list {
|
||||||
for _, path := range q {
|
if e.path != "" && from_path(e.path) {
|
||||||
if path != "" && from_path(path) {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if icon == "" {
|
if icon == "" {
|
||||||
icon = strings.TrimSpace(" ")
|
icon = strings.TrimSpace(" ")
|
||||||
}
|
}
|
||||||
@@ -219,7 +214,7 @@ func (dnd *dnd) reset_drag() {
|
|||||||
dnd.drag_status = drag_status{}
|
dnd.drag_status = drag_status{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dnd *dnd) on_drag_event(x, y, operation, Y int) (err error) {
|
func (dnd *dnd) on_drag_event(x, y, operation int) (err error) {
|
||||||
switch x {
|
switch x {
|
||||||
case 1:
|
case 1:
|
||||||
dnd.drag_status.accepted_mime = y
|
dnd.drag_status.accepted_mime = y
|
||||||
@@ -230,14 +225,14 @@ func (dnd *dnd) on_drag_event(x, y, operation, Y int) (err error) {
|
|||||||
case 4:
|
case 4:
|
||||||
was_dropped := dnd.drag_status.dropped
|
was_dropped := dnd.drag_status.dropped
|
||||||
was_move := dnd.drag_status.accepted_operation == 2
|
was_move := dnd.drag_status.accepted_operation == 2
|
||||||
was_remote := dnd.drag_status.remote_data_was_sent
|
|
||||||
dnd.reset_drag()
|
dnd.reset_drag()
|
||||||
if was_dropped && dnd.has_exit_on("drag-finish") {
|
if was_dropped && dnd.has_exit_on("drag-finish") {
|
||||||
dnd.lp.Quit(0)
|
dnd.lp.Quit(0)
|
||||||
}
|
}
|
||||||
if was_dropped && was_move && was_remote {
|
if was_dropped && was_move {
|
||||||
if ds := dnd.drag_sources["text/uri-list"]; ds != nil {
|
if ds := dnd.drag_sources["text/uri-list"]; ds != nil {
|
||||||
for _, item := range ds.uri_list {
|
for _, item := range ds.uri_list {
|
||||||
|
if item.was_sent {
|
||||||
if item.metadata.IsDir() {
|
if item.metadata.IsDir() {
|
||||||
err = os.RemoveAll(item.path)
|
err = os.RemoveAll(item.path)
|
||||||
} else {
|
} else {
|
||||||
@@ -248,6 +243,7 @@ func (dnd *dnd) on_drag_event(x, y, operation, Y int) (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
dnd.drag_sources = nil
|
dnd.drag_sources = nil
|
||||||
dnd.allow_drags = false
|
dnd.allow_drags = false
|
||||||
dnd.lp.StopOfferingDrags()
|
dnd.lp.StopOfferingDrags()
|
||||||
@@ -256,7 +252,7 @@ func (dnd *dnd) on_drag_event(x, y, operation, Y int) (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 5:
|
case 5:
|
||||||
if err = dnd.handle_data_request(y, Y == 1); err != nil {
|
if err = dnd.handle_data_request(y); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -272,28 +268,24 @@ func (dnd *dnd) finish_drag(errname string) {
|
|||||||
dnd.reset_drag()
|
dnd.reset_drag()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dnd *dnd) handle_data_request(idx int, send_remote_data bool) (err error) {
|
func (dnd *dnd) handle_data_request(idx int) (err error) {
|
||||||
if idx < 0 || idx >= len(dnd.drag_status.offered_mimes) {
|
if idx < 0 || idx >= len(dnd.drag_status.offered_mimes) {
|
||||||
dnd.finish_drag("EINVAL")
|
dnd.finish_drag("EINVAL")
|
||||||
return fmt.Errorf("terminal asked for drag data from MIME list with out of bounds index: %d", idx)
|
return fmt.Errorf("terminal asked for drag data from MIME list with out of bounds index: %d", idx)
|
||||||
}
|
}
|
||||||
mime := dnd.drag_status.offered_mimes[idx]
|
mime := dnd.drag_status.offered_mimes[idx]
|
||||||
ds := dnd.drag_sources[mime]
|
ds := dnd.drag_sources[mime]
|
||||||
send_remote_data = send_remote_data && mime == "text/uri-list" && len(ds.uri_list) > 0
|
|
||||||
for _, dr := range dnd.drag_status.data_requests {
|
for _, dr := range dnd.drag_status.data_requests {
|
||||||
if dr.index == idx {
|
if dr.index == idx {
|
||||||
dnd.finish_drag("EINVAL")
|
dnd.finish_drag("EINVAL")
|
||||||
return fmt.Errorf("terminal sent a duplicate drag data request")
|
return fmt.Errorf("terminal sent a duplicate drag data request")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dr := &data_request{drag_source: ds, send_remote_data: send_remote_data, index: idx}
|
dr := &data_request{drag_source: ds, index: idx}
|
||||||
if ds.path == "" {
|
if ds.path == "" {
|
||||||
dnd.lp.QueueDnDData(DC{Type: 'e', Y: idx, Payload: utils.UnsafeStringToBytes(base64.RawStdEncoding.EncodeToString(ds.data))})
|
dnd.lp.QueueDnDData(DC{Type: 'e', Y: idx, Payload: utils.UnsafeStringToBytes(base64.RawStdEncoding.EncodeToString(ds.data))})
|
||||||
dnd.lp.QueueDnDData(DC{Type: 'e', Y: idx}) // EOF
|
dnd.lp.QueueDnDData(DC{Type: 'e', Y: idx}) // EOF
|
||||||
if !dr.send_remote_data {
|
|
||||||
return
|
return
|
||||||
}
|
|
||||||
return dnd.start_remote_data_send(ds)
|
|
||||||
} else {
|
} else {
|
||||||
if ds.file != nil {
|
if ds.file != nil {
|
||||||
ds.file.Close()
|
ds.file.Close()
|
||||||
@@ -356,9 +348,7 @@ func (dnd *dnd) on_data_request_finished(i int) (err error) {
|
|||||||
dr.drag_source.file = nil
|
dr.drag_source.file = nil
|
||||||
}
|
}
|
||||||
dnd.drag_status.data_requests = slices.Delete(dnd.drag_status.data_requests, i, i+1)
|
dnd.drag_status.data_requests = slices.Delete(dnd.drag_status.data_requests, i, i+1)
|
||||||
if dr.send_remote_data {
|
if len(dnd.drag_status.data_requests) > 0 {
|
||||||
err = dnd.start_remote_data_send(dr.drag_source)
|
|
||||||
} else if len(dnd.drag_status.data_requests) > 0 {
|
|
||||||
err = dnd.send_data_for_data_request(0)
|
err = dnd.send_data_for_data_request(0)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -386,6 +376,9 @@ func (dnd *dnd) send_remote_dir(path string, idx_in_uri_list, parent_dir_handle,
|
|||||||
dnd.finish_drag("EIO")
|
dnd.finish_drag("EIO")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
for dnd.drag_status.dir_handle_counter < 2 {
|
||||||
|
dnd.drag_status.dir_handle_counter++
|
||||||
|
}
|
||||||
handle := dnd.drag_status.dir_handle_counter
|
handle := dnd.drag_status.dir_handle_counter
|
||||||
dnd.drag_status.dir_handle_counter++
|
dnd.drag_status.dir_handle_counter++
|
||||||
names := make([]string, 0, len(entries))
|
names := make([]string, 0, len(entries))
|
||||||
@@ -447,7 +440,11 @@ func (dnd *dnd) send_next_file_chunk() (err error) {
|
|||||||
|
|
||||||
func (dnd *dnd) next_remote_item() (err error) {
|
func (dnd *dnd) next_remote_item() (err error) {
|
||||||
if len(dnd.drag_status.remote_items) < 1 {
|
if len(dnd.drag_status.remote_items) < 1 {
|
||||||
dnd.lp.QueueDnDData(DC{Type: 'k'}) // inform terminal remote data is finished
|
// current remote data request finished
|
||||||
|
dnd.drag_status.remote_data_requests = dnd.drag_status.remote_data_requests[1:]
|
||||||
|
if len(dnd.drag_status.remote_data_requests) > 0 {
|
||||||
|
return dnd.send_next_remote_data_request()
|
||||||
|
}
|
||||||
if len(dnd.drag_status.data_requests) > 0 {
|
if len(dnd.drag_status.data_requests) > 0 {
|
||||||
err = dnd.send_data_for_data_request(0)
|
err = dnd.send_data_for_data_request(0)
|
||||||
}
|
}
|
||||||
@@ -478,12 +475,31 @@ func (dnd *dnd) next_remote_item() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dnd *dnd) start_remote_data_send(ds *drag_source) (err error) {
|
func (dnd *dnd) on_drag_remote_data_request(idx int) (err error) {
|
||||||
dnd.drag_status.dir_handle_counter = 2
|
ds := dnd.drag_sources["text/uri_list"]
|
||||||
dnd.drag_status.remote_item_write_id = 0
|
if ds == nil || len(ds.uri_list) < 1 {
|
||||||
dnd.drag_status.remote_data_was_sent = true
|
dnd.finish_drag("EINVAL")
|
||||||
|
return fmt.Errorf("terminal asked for drag data from URI list but no list present")
|
||||||
|
}
|
||||||
|
if idx < 0 || idx >= len(ds.uri_list) {
|
||||||
|
dnd.finish_drag("EINVAL")
|
||||||
|
return fmt.Errorf("terminal asked for drag data from URI list with out of bounds index: %d", idx)
|
||||||
|
}
|
||||||
|
ds.uri_list[idx].was_sent = true
|
||||||
|
dnd.drag_status.remote_data_requests = append(dnd.drag_status.remote_data_requests, idx)
|
||||||
|
if len(dnd.drag_status.remote_data_requests) == 1 {
|
||||||
|
err = dnd.send_next_remote_data_request()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dnd *dnd) send_next_remote_data_request() (err error) {
|
||||||
|
if len(dnd.drag_status.remote_data_requests) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
i := dnd.drag_status.remote_data_requests[0]
|
||||||
|
x := dnd.drag_sources["text/uri-list"].uri_list[i]
|
||||||
items := []*remote_data_item{}
|
items := []*remote_data_item{}
|
||||||
for i, x := range ds.uri_list {
|
|
||||||
if x.metadata.IsDir() {
|
if x.metadata.IsDir() {
|
||||||
if children, err := dnd.send_remote_dir(x.path, i, 0, i); err != nil {
|
if children, err := dnd.send_remote_dir(x.path, i, 0, i); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -498,7 +514,6 @@ func (dnd *dnd) start_remote_data_send(ds *drag_source) (err error) {
|
|||||||
f := remote_data_item{idx_in_parent: i, idx_in_uri_list: i, metadata: x.metadata, path: x.path}
|
f := remote_data_item{idx_in_parent: i, idx_in_uri_list: i, metadata: x.metadata, path: x.path}
|
||||||
dnd.drag_status.remote_items = append(dnd.drag_status.remote_items, &f)
|
dnd.drag_status.remote_items = append(dnd.drag_status.remote_items, &f)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
dnd.drag_status.remote_items = append(dnd.drag_status.remote_items, items...)
|
dnd.drag_status.remote_items = append(dnd.drag_status.remote_items, items...)
|
||||||
if dnd.drag_status.remote_item_write_id == 0 {
|
if dnd.drag_status.remote_item_write_id == 0 {
|
||||||
return dnd.next_remote_item()
|
return dnd.next_remote_item()
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ type uri_list_item struct {
|
|||||||
path, uri, human_name string
|
path, uri, human_name string
|
||||||
file *os.File
|
file *os.File
|
||||||
metadata os.FileInfo
|
metadata os.FileInfo
|
||||||
|
was_sent bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type drag_source struct {
|
type drag_source struct {
|
||||||
@@ -105,7 +106,7 @@ func (dnd *dnd) send_test_response(payload string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (dnd *dnd) has_exit_on(event string) bool {
|
func (dnd *dnd) has_exit_on(event string) bool {
|
||||||
for _, e := range strings.Split(dnd.opts.ExitOn, ",") {
|
for e := range strings.SplitSeq(dnd.opts.ExitOn, ",") {
|
||||||
if strings.TrimSpace(e) == event {
|
if strings.TrimSpace(e) == event {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -276,7 +277,9 @@ func (dnd *dnd) run_loop() (err error) {
|
|||||||
case 'E':
|
case 'E':
|
||||||
return dnd.on_drag_error(cmd)
|
return dnd.on_drag_error(cmd)
|
||||||
case 'e':
|
case 'e':
|
||||||
return dnd.on_drag_event(cmd.X, cmd.Y, cmd.Operation, cmd.Yp)
|
return dnd.on_drag_event(cmd.X, cmd.Y, cmd.Operation)
|
||||||
|
case 'k':
|
||||||
|
return dnd.on_drag_remote_data_request(cmd.X - 1)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -426,7 +426,7 @@ class PTY:
|
|||||||
if isinstance(data, str):
|
if isinstance(data, str):
|
||||||
data = data.encode('utf-8')
|
data = data.encode('utf-8')
|
||||||
if self.log_data_flow:
|
if self.log_data_flow:
|
||||||
print('t -> c:', data)
|
print('t -> c:', bytes(data))
|
||||||
self.write_buf += data
|
self.write_buf += data
|
||||||
if flush:
|
if flush:
|
||||||
self.process_input_from_child(0)
|
self.process_input_from_child(0)
|
||||||
|
|||||||
Reference in New Issue
Block a user