commit
5f43c1141b
@ -0,0 +1,2 @@
|
||||
uri_runner
|
||||
xdg_open
|
@ -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?
|
@ -0,0 +1,9 @@
|
||||
version 1 .
|
||||
|
||||
XdgOpen = <xdg-open @uris [string ...]> .
|
||||
|
||||
Action = [@pat string @cmd [string ...] ] .
|
||||
|
||||
Attrs = { actions: [Action ...] } .
|
||||
|
||||
UriRunnerConfig = <config @attrs Attrs> .
|
@ -0,0 +1,2 @@
|
||||
include_rules
|
||||
: foreach ../*.prs |> !preserves_schema_nim |> %B.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))
|
@ -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()
|
@ -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
|
@ -0,0 +1,17 @@
|
||||
<require-service <daemon uri_runner>>
|
||||
|
||||
<daemon uri_runner {
|
||||
argv: ["/home/repo/syndicate/xdg_open_ng/src/uri_runner"]
|
||||
dir: "/tmp"
|
||||
protocol: text/syndicate
|
||||
clearEnv: #f
|
||||
}>
|
||||
|
||||
? <service-object <daemon uri_runner> ?cap> [
|
||||
$cap <config { actions: [
|
||||
["gemini://.*|file:///.*.gmi", ["/run/current-system/sw/bin/kristall" "\\1"]]
|
||||
["http://.*|https://.*|.*html", ["/run/current-system/sw/bin/firefox" "\\1"]]
|
||||
["tox:.*|uri:tox:.*", ["/run/current-system/sw/bin/qtox" "\\1"]]
|
||||
[".*mkv", ["/run/current-system/sw/bin/mpv" "\\1"]]
|
||||
] } >
|
||||
]
|
@ -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"
|
Loading…
Reference in new issue