Replaces the AUR greenclip (declared absent) with the official clipmenu, started once from the session's xinitrc slot, its menu the launcher's dmenu command bound as an i3 drop-in, its history in the runtime directory. Go tools read and change clipmenu's own store under its lock.
91 lines
3.0 KiB
Go
91 lines
3.0 KiB
Go
// clipmenu's Go tools bundle (novox/hq ADR 0188, ADR 0193, ADR 0208): its implementation of
|
|
// node-clipboard's verbs `history` and `copy`, and its own tools, served by the node's runtime as the
|
|
// operator account. The history is read from clipmenu's own store in the account's runtime directory;
|
|
// the clipboard itself is the X session's.
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
|
|
stdio "git.novox.be/novox/mesh-sdk/go"
|
|
)
|
|
|
|
func main() {
|
|
if err := stdio.Serve("", tools()); err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func tools() []stdio.Tool {
|
|
return []stdio.Tool{
|
|
{
|
|
Name: "node-clipboard.history",
|
|
Description: "What the operator copied, newest first: each entry's id, its first line, when, its size " +
|
|
"and its text (each cut at max_bytes). Whether the clipboard daemon is collecting.",
|
|
Input: map[string]any{
|
|
"limit": map[string]any{"type": "integer", "description": "at most this many entries (default 20, at most 500)"},
|
|
"max_bytes": map[string]any{"type": "integer", "description": "cut each entry's text at this many bytes; 0 leaves the text out (default 4096, at most 65536)"},
|
|
},
|
|
Run: func(args map[string]any) (any, error) {
|
|
limit, err := whole(args, "limit", 20, 1, 500)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
most, err := whole(args, "max_bytes", 4096, 0, 65536)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return History(limit, most)
|
|
},
|
|
},
|
|
{
|
|
Name: "node-clipboard.copy",
|
|
Description: "Put text on the operator's clipboard, as if they had copied it; it enters the history " +
|
|
"like any copy. Answers how many bytes.",
|
|
Input: map[string]any{
|
|
"type": "object",
|
|
"properties": map[string]any{
|
|
"text": map[string]any{"type": "string", "description": fmt.Sprintf("the text (at most %d bytes)", mostCopy)},
|
|
},
|
|
"required": []string{"text"},
|
|
},
|
|
Run: func(args map[string]any) (any, error) {
|
|
t, ok := args["text"].(string)
|
|
if !ok {
|
|
return nil, fmt.Errorf("text is required, as a string")
|
|
}
|
|
return Copy(t)
|
|
},
|
|
},
|
|
{
|
|
Name: "clipmenu_paste",
|
|
Description: "What the operator's clipboard holds right now, as text (cut at 64 KiB, said in truncated).",
|
|
Run: func(map[string]any) (any, error) { return Paste() },
|
|
},
|
|
{
|
|
Name: "clipmenu_clear",
|
|
Description: "Forget the whole clipboard history. What is on the clipboard now stays there.",
|
|
Run: func(map[string]any) (any, error) { return Clear() },
|
|
},
|
|
{
|
|
Name: "clipmenu_delete",
|
|
Description: "Forget one entry of the clipboard history, by its id as the history answers it, or by " +
|
|
"its first line exactly.",
|
|
Input: map[string]any{
|
|
"id": map[string]any{"type": "string", "description": "the entry's id"},
|
|
"line": map[string]any{"type": "string", "description": "the entry's first line, exactly"},
|
|
},
|
|
Run: func(args map[string]any) (any, error) {
|
|
id, err := text(args, "id", false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
line, _ := args["line"].(string)
|
|
return Delete(id, line)
|
|
},
|
|
},
|
|
}
|
|
}
|