Updated wormhole.
This commit is contained in:
1 parent
e56771aa22
commit
48f7d5262c
4 files changed
+84
-4
No files matched your search
+10
-2
@@ -1,9 +1,17 @@
|
||||
# Wormhole
|
||||
|
||||
An experimental Magic Wormhole Tentacle for Cthulhu-Go. Suggested shortcut:
|
||||
**Cthulhu+Alt+Shift+W**, on desktop and laptop layouts. It opens the reader's
|
||||
**Cthulhu+Ctrl+Shift+W**, on desktop and laptop layouts. It opens the reader's
|
||||
internal **Wormhole menu**, preserving the underlying application's focus.
|
||||
|
||||
With a reader supporting Tentacle settings registration, global Preferences →
|
||||
Tentacles → select Wormhole → Settings opens **Wormhole preferences** directly.
|
||||
Save persists the two checkboxes and returns to reader preferences; Escape
|
||||
discards the form's edits. This entry point works without the Wormhole CLI.
|
||||
Rebuild both the reader and Tentacle to obtain settings registration and the
|
||||
Ctrl+Shift shortcut; the published 0.1.1 binary uses Alt+Shift and has no
|
||||
registered settings entry point.
|
||||
|
||||
Install the `magic-wormhole` CLI using your distribution's package manager.
|
||||
Clipboard operations require `xclip` on Xorg. Missing `wormhole` does not stop
|
||||
reader startup: the shortcut speaks and brailles **Magic wormhole is not
|
||||
@@ -117,7 +125,7 @@ After configuring the local entry:
|
||||
|
||||
1. Quit Cthulhu with Cthulhu+Q. Press Ctrl+Escape, then Shift+G. These are
|
||||
separate key presses. Shift+G rebuilds the reader and braille helper.
|
||||
2. Focus an ordinary multiline text field. Open Cthulhu+Alt+Shift+W. Expect
|
||||
2. Focus an ordinary multiline text field. Open Cthulhu+Ctrl+Shift+W. Expect
|
||||
“Wormhole menu. Send focused item” in speech and the menu option on braille.
|
||||
Native application focus must stay on the original field. Send it to a
|
||||
second Wormhole endpoint; the recipient must get exactly the current line.
|
||||
|
||||
+22
-1
@@ -90,6 +90,25 @@ func (w *wormhole) preferencesForm() tentacle.Interaction {
|
||||
{ID: "save", Label: "Save", Kind: tentacle.Button},
|
||||
}}, Next: "preferences"}
|
||||
}
|
||||
func (w *wormhole) openPreferences(ctx context.Context, _ json.RawMessage) (any, error) {
|
||||
w.mutex.Lock()
|
||||
defer w.mutex.Unlock()
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := w.preferencesForm()
|
||||
result.Next = "save-settings"
|
||||
return result, nil
|
||||
}
|
||||
func (w *wormhole) saveSettings(ctx context.Context, raw json.RawMessage) (any, error) {
|
||||
value, err := w.savePreferences(ctx, raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := value.(tentacle.Interaction)
|
||||
result.Form, result.Next, result.Done = nil, "", true
|
||||
return result, nil
|
||||
}
|
||||
func (w *wormhole) savePreferences(ctx context.Context, raw json.RawMessage) (any, error) {
|
||||
value, err := submission(raw)
|
||||
if err != nil {
|
||||
@@ -146,11 +165,13 @@ func (w *wormhole) commands() []tentacle.Command {
|
||||
{"wormhole", "Wormhole menu", w.open}, {"menu", "Wormhole menu selection", w.choose},
|
||||
{"send", "Send Wormhole item", w.send}, {"receive", "Receive Wormhole item", w.receive},
|
||||
{"preferences", "Save Wormhole preferences", w.savePreferences}, {"control", "Wormhole transfer controls", w.control}, {"poll", "Wormhole transfer status", w.poll},
|
||||
{"settings", "Wormhole preferences", w.openPreferences}, {"save-settings", "Save Wormhole settings", w.saveSettings},
|
||||
} {
|
||||
command := tentacle.Command{ID: entry.id, Title: entry.title, Description: entry.title, Presentation: true, Interaction: true, Handle: entry.handler}
|
||||
if entry.id == "wormhole" {
|
||||
command.Bindings = []tentacle.Binding{{Layout: "desktop", Scope: "global", Key: "Cthulhu+Alt+Shift+W"}, {Layout: "laptop", Scope: "global", Key: "Cthulhu+Alt+Shift+W"}}
|
||||
command.Bindings = []tentacle.Binding{{Layout: "desktop", Scope: "global", Key: "Cthulhu+Ctrl+Shift+W"}, {Layout: "laptop", Scope: "global", Key: "Cthulhu+Ctrl+Shift+W"}}
|
||||
}
|
||||
command.Settings = entry.id == "settings"
|
||||
commands = append(commands, command)
|
||||
}
|
||||
return commands
|
||||
|
||||
@@ -89,6 +89,57 @@ func TestMenuPreferencesAndMissingDependency(t *testing.T) {
|
||||
t.Fatal(result, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisteredSettingsAndDefaultShortcut(t *testing.T) {
|
||||
w := testWormhole(t, "exit 0\n")
|
||||
w.program = filepath.Join(t.TempDir(), "missing")
|
||||
settings := 0
|
||||
for _, command := range w.commands() {
|
||||
if command.ID == "wormhole" {
|
||||
if len(command.Bindings) != 2 {
|
||||
t.Fatal(command.Bindings)
|
||||
}
|
||||
for index, layout := range []string{"desktop", "laptop"} {
|
||||
binding := command.Bindings[index]
|
||||
if binding.Layout != layout || binding.Scope != "global" || binding.Key != "Cthulhu+Ctrl+Shift+W" {
|
||||
t.Fatal(binding)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !command.Settings {
|
||||
continue
|
||||
}
|
||||
settings++
|
||||
value, err := command.Handle(context.Background(), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
form := value.(tentacle.Interaction)
|
||||
if !command.Interaction || !command.Presentation || form.Form.Title != "Wormhole preferences" || form.Next != "save-settings" {
|
||||
t.Fatal(command, form)
|
||||
}
|
||||
}
|
||||
if settings != 1 {
|
||||
t.Fatalf("settings entry points: %d", settings)
|
||||
}
|
||||
value, err := w.saveSettings(context.Background(), arguments(tentacle.Submission{Activated: "save", Values: map[string]tentacle.Value{"copy-code": {Checked: true}}}))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
result := value.(tentacle.Interaction)
|
||||
if !result.Done || result.Form != nil || result.Next != "" || !w.preferences.CopySendCode {
|
||||
t.Fatal(result)
|
||||
}
|
||||
data, err := os.ReadFile(w.settingsPath)
|
||||
var saved preferences
|
||||
if err != nil || json.Unmarshal(data, &saved) != nil || !saved.CopySendCode {
|
||||
t.Fatal("settings did not persist", err)
|
||||
}
|
||||
_, err = w.saveSettings(context.Background(), arguments(tentacle.Submission{Cancelled: true}))
|
||||
if err != nil || !w.preferences.CopySendCode {
|
||||
t.Fatal("Cancel changed saved settings", err)
|
||||
}
|
||||
}
|
||||
func TestSendPreservesClipboardTextAndCodePreference(t *testing.T) {
|
||||
for _, copyCode := range []bool{false, true} {
|
||||
t.Run(map[bool]string{false: "read-only", true: "copy-code"}[copyCode], func(t *testing.T) {
|
||||
|
||||
@@ -18,6 +18,6 @@ major = 1
|
||||
minor = 0
|
||||
|
||||
[requirements]
|
||||
reader = "Cthulhu-Go with interactive Tentacle support"
|
||||
reader = "Cthulhu-Go with interactive Tentacle settings support"
|
||||
runtime = "Magic Wormhole CLI (wormhole); xclip for clipboard operations"
|
||||
build = "Go 1.24 or newer and the adjacent cthulhu-go source checkout"
|
||||
Reference in new issue
Block a user