From 5f43c1141b2b173ede1e5cd9f0fd27207b2e3a5c Mon Sep 17 00:00:00 2001 From: Emery Date: Sat, 26 Feb 2022 17:39:22 -0600 Subject: [PATCH] Initial commit --- .gitignore | 2 ++ README.md | 9 ++++++++ protocol.prs | 9 ++++++++ src/Tupfile | 2 ++ src/protocol.nim | 29 +++++++++++++++++++++++ src/uri_runner.nim | 57 ++++++++++++++++++++++++++++++++++++++++++++++ src/xdg_open.nim | 28 +++++++++++++++++++++++ uri_runner.pr | 17 ++++++++++++++ xdg_open_ng.nimble | 13 +++++++++++ 9 files changed, 166 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 protocol.prs create mode 100644 src/Tupfile create mode 100644 src/protocol.nim create mode 100644 src/uri_runner.nim create mode 100644 src/xdg_open.nim create mode 100644 uri_runner.pr create mode 100644 xdg_open_ng.nimble diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eebcf05 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +uri_runner +xdg_open diff --git a/README.md b/README.md new file mode 100644 index 0000000..9769226 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# xd-open-ng + +An `xdg-open` replacement that uses Syndicate and PCRE pattern matching to open URIs. + +There are two utilites, `uri_runner` and `xdg-open`; both expect to be able to connect to a shared Syndicate dataspace via a UNIX socket at `$SYNDICATE_SOCK` otherwise `$XDG_RUNTIME_DIR/dataspace`. The `xdg-open` component has no other configuration. The `uri_runner` component is intended to be managed by the [Syndicate server](https://git.syndicate-lang.org/syndicate-lang/syndicate-rs) thru which it receives configuration, see [uri_runner.pr](./uri_runner.pr) as an example. + +## TODO +- Pattern back-references in commands +- Fallback commands? diff --git a/protocol.prs b/protocol.prs new file mode 100644 index 0000000..6ef2e2f --- /dev/null +++ b/protocol.prs @@ -0,0 +1,9 @@ +version 1 . + +XdgOpen = . + +Action = [@pat string @cmd [string ...] ] . + +Attrs = { actions: [Action ...] } . + +UriRunnerConfig = . diff --git a/src/Tupfile b/src/Tupfile new file mode 100644 index 0000000..e5ee95f --- /dev/null +++ b/src/Tupfile @@ -0,0 +1,2 @@ +include_rules +: foreach ../*.prs |> !preserves_schema_nim |> %B.nim diff --git a/src/protocol.nim b/src/protocol.nim new file mode 100644 index 0000000..cba88b3 --- /dev/null +++ b/src/protocol.nim @@ -0,0 +1,29 @@ + +import + std/typetraits, preserves + +type + XdgOpen* {.preservesRecord: "xdg-open".} = object + `data`*: seq[string] + + Attrs*[E] {.preservesDictionary.} = ref object + `actions`*: seq[Action] + + UriRunnerConfig*[E] {.preservesRecord: "config".} = ref object + `attrs`*: Attrs[E] + + Action* {.preservesTuple.} = object + `pat`*: string + `cmd`*: seq[string] + +proc `$`*[E](x: Attrs[E] | UriRunnerConfig[E]): string = + `$`(toPreserve(x, E)) + +proc encode*[E](x: Attrs[E] | UriRunnerConfig[E]): seq[byte] = + encode(toPreserve(x, E)) + +proc `$`*(x: XdgOpen | Action): string = + `$`(toPreserve(x)) + +proc encode*(x: XdgOpen | Action): seq[byte] = + encode(toPreserve(x)) diff --git a/src/uri_runner.nim b/src/uri_runner.nim new file mode 100644 index 0000000..5c835b1 --- /dev/null +++ b/src/uri_runner.nim @@ -0,0 +1,57 @@ +# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway +# SPDX-License-Identifier: Unlicense + +import std/[asyncdispatch, deques, re, streams, strutils, os, osproc] +import preserves +import syndicate, syndicate/capabilities +import ./protocol + +proc unixSocketPath: string = + result = getEnv("SYNDICATE_SOCK") + if result == "": + result = getEnv("XDG_RUNTIME_DIR", "/run/user/1000") / "dataspace" + +proc mintCap: SturdyRef = + var key: array[16, byte] + mint(key, "syndicate") + +bootDataspace("main") do (ds: Ref; turn: var Turn): + var + actions: seq[tuple[regex: Regex; cmd: string; args: seq[string]]] + children: Deque[Process] + + connectStdio(ds, turn) + + onPublish(turn, ds, ?UriRunnerConfig[Ref]) do (cfg: seq[Action]): + actions.setLen 0 + for act in cfg: + if act.cmd.len < 2: + stderr.writeLine "ignoring ", act + else: + actions.add (re(act.pat, {reIgnoreCase, reStudy}), act.cmd[0], act.cmd[1..act.cmd.high]) + stderr.writeLine "actions updated" + + connectUnix(turn, unixSocketPath(), mintCap()) do (turn: var Turn; a: Assertion) -> TurnAction: + let ds = unembed a + onMessage(turn, ds, ?XdgOpen) do (uris: seq[string]): + while children.len > 0 and not children.peekFirst.running: + var child = children.popFirst() + if child.peekExitCode != 0: + stderr.writeLine child.errorStream.readAll + close child + # TODO check children on a timer? + for uri in uris: + var matched: bool + for act in actions: + if match(uri, act.regex): + matched = true + var args = newSeq[string](act.args.len) + for i, arg in act.args: + args[i] = replace(arg, "\\1", uri) + var child = startProcess( + command = act.cmd, args = args, options = {}) + children.addLast child + if not matched: + stderr.writeLine "no patterns matched for ", uri + +runForever() diff --git a/src/xdg_open.nim b/src/xdg_open.nim new file mode 100644 index 0000000..61210df --- /dev/null +++ b/src/xdg_open.nim @@ -0,0 +1,28 @@ +# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway +# SPDX-License-Identifier: Unlicense + +import std/[asyncdispatch, os] +import preserves +import syndicate, syndicate/capabilities +import ./protocol + +proc unixSocketPath: string = + result = getEnv("SYNDICATE_SOCK") + if result == "": + result = getEnv("XDG_RUNTIME_DIR", "/run/user/1000") / "dataspace" + +proc mintCap: SturdyRef = + var key: array[16, byte] + mint(key, "syndicate") + +type XdgOpen {.preservesRecord: "xdg-open".} = object + args: seq[string] + +bootDataspace("main") do (ds: Ref; turn: var Turn): + let mainFacet = turn.facet + connectUnix(turn, unixSocketPath(), mintCap()) do (turn: var Turn; a: Assertion) -> TurnAction: + let ds = unembed a + message(turn, ds, XdgOpen(args: commandLineParams())) + +for i in 0..7: poll(20) + # A hack to exit diff --git a/uri_runner.pr b/uri_runner.pr new file mode 100644 index 0000000..a07e033 --- /dev/null +++ b/uri_runner.pr @@ -0,0 +1,17 @@ +> + + + +? ?cap> [ + $cap +] diff --git a/xdg_open_ng.nimble b/xdg_open_ng.nimble new file mode 100644 index 0000000..bdb346a --- /dev/null +++ b/xdg_open_ng.nimble @@ -0,0 +1,13 @@ +# Package + +version = "0.1.0" +author = "Emery" +description = "A better xdg-open" +license = "Unlicense" +srcDir = "src" +bin = @[ "uri_runner", "xdg_open"] + + +# Dependencies + +requires "nim >= 1.6.4", "syndicate"