Rename to "open", decompose URIs in assertions
This commit is contained in:
parent
bcc1870176
commit
509970a2d2
|
@ -1,8 +1,8 @@
|
||||||
# xdg-open-ng
|
# Syndicated Open
|
||||||
|
|
||||||
An [xdg-open](https://portland.freedesktop.org/doc/xdg-open.html) replacement that uses [Syndicate](http://syndicate-lang.org/) and PCRE pattern matching to open URIs.
|
An [open command](https://en.wikipedia.org/wiki/Open_(process)) implementation that uses [Syndicate](http://syndicate-lang.org/) and PCRE pattern matching to open URIs.
|
||||||
|
|
||||||
There are two utilites, `xdg-open` and `uri_runner`. The former connects to a shared Syndicate dataspace via a UNIX socket at `$SYNDICATE_SOCK` otherwise `$XDG_RUNTIME_DIR/dataspace` and 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.
|
There are two utilites, `open` and `uri_runner`. The former connects to a shared Syndicate dataspace via a UNIX socket at `$SYNDICATE_SOCK` otherwise `$XDG_RUNTIME_DIR/dataspace` and 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.
|
||||||
|
|
||||||
Matching patterns to actions is done with `action-handler` records:
|
Matching patterns to actions is done with `action-handler` records:
|
||||||
```preserves
|
```preserves
|
||||||
|
|
|
@ -16,9 +16,11 @@
|
||||||
<action-handler "https://twitter.com/(.*)" $execspace
|
<action-handler "https://twitter.com/(.*)" $execspace
|
||||||
<exec ["/run/current-system/sw/bin/firefox" "--new-tab" "https://nitter.net/$1"]>>
|
<exec ["/run/current-system/sw/bin/firefox" "--new-tab" "https://nitter.net/$1"]>>
|
||||||
|
|
||||||
<action-handler "(http://.*)|(https://.*)" $execspace
|
<action-handler "(file:///.*.html|http://.*|https://.*)" $execspace
|
||||||
<exec ["/run/current-system/sw/bin/firefox" "$1"]>>
|
<exec ["/run/current-system/sw/bin/firefox" "$#"]>>
|
||||||
|
|
||||||
|
<action-handler "mailto:(.*)" $execspace
|
||||||
|
<exec ["/run/current-system/sw/bin/astroid" "--mailto" "$#"]>>
|
||||||
]
|
]
|
||||||
|
|
||||||
; when mpv is available send it commands directly
|
; when mpv is available send it commands directly
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
version 1 .
|
version 1 .
|
||||||
|
|
||||||
XdgOpen = <xdg-open @uri string> .
|
Authority = [ @username any @password any @host any @port any ] .
|
||||||
|
|
||||||
|
; Uniform Resource Identifier https://datatracker.ietf.org/doc/html/rfc3986
|
||||||
|
Uri = <uri @scheme string @auth Authority @path any @query any @fragment any> .
|
||||||
|
|
||||||
|
; Broadcast this to open a URI.
|
||||||
|
Open = <open @uri Uri>.
|
||||||
|
|
||||||
UriRunnerConfig = {
|
UriRunnerConfig = {
|
||||||
handlerspace: #!any
|
handlerspace: #!any
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
include_rules
|
include_rules
|
||||||
: foreach ../*.prs |> !preserves_schema_nim |> | {schema}
|
: foreach ../*.prs |> !preserves_schema_nim |> | {common}
|
||||||
: uri_runner.nim | $(SYNDICATE_PROTOCOL) {schema} |> !nim_bin |> {bin}
|
: common.nim |> !nim_check |> {common}
|
||||||
: xdg_open.nim | $(SYNDICATE_PROTOCOL) {schema} |> !nim_bin |> $(BIN_DIR)/xdg-open {bin}
|
: uri_runner.nim | $(SYNDICATE_PROTOCOL) {common} |> !nim_bin |> {bin}
|
||||||
|
: open.nim | $(SYNDICATE_PROTOCOL) {common} |> !nim_bin |> {bin}
|
||||||
: foreach {bin} |> !assert_built |>
|
: foreach {bin} |> !assert_built |>
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
||||||
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
|
import std/uri
|
||||||
|
import preserves
|
||||||
|
|
||||||
|
proc toPreserveOrNull(s: string; E: typedesc): Preserve[E] =
|
||||||
|
if s != "": result = toPreserve(s, E)
|
||||||
|
|
||||||
|
proc toPreserveHook*(u: Uri; E: typedesc): Preserve[E] =
|
||||||
|
## Best-effort preservation of the `Uri` type.
|
||||||
|
runnableExamples:
|
||||||
|
from std/unittest import check
|
||||||
|
import std/uri
|
||||||
|
import preserves
|
||||||
|
var u = parseUri"https://bidstonobservatory.org"
|
||||||
|
check $(u.toPreserve) == """<uri "https" [#f #f "bidstonobservatory.org" #f] #f #f #f>"""
|
||||||
|
initRecord("uri",
|
||||||
|
u.scheme.toPreserve(E),
|
||||||
|
toPreserve([
|
||||||
|
u.username.toPreserveOrNull(E),
|
||||||
|
u.password.toPreserveOrNull(E),
|
||||||
|
u.hostname.toPreserveOrNull(E),
|
||||||
|
u.port.toPreserveOrNull(E),
|
||||||
|
]),
|
||||||
|
u.path.toPreserveOrNull(E),
|
||||||
|
u.query.toPreserveOrNull(E),
|
||||||
|
u.anchor.toPreserveOrNull(E),
|
||||||
|
)
|
||||||
|
|
||||||
|
proc fromPreserveHook*[E](u: var Uri; pr: Preserve[E]): bool =
|
||||||
|
## Best-effort preservation of the `Uri` type.
|
||||||
|
runnableExamples:
|
||||||
|
import std/uri
|
||||||
|
import preserves
|
||||||
|
var u: Uri
|
||||||
|
doAssert fromPreserveHook(u, parsePreserves"""<uri "https" [#f #f "bidstonobservatory.org" #f] #f #f #f>""")
|
||||||
|
if pr.isRecord("uri", 5):
|
||||||
|
result = fromPreserve(u.scheme, pr[0])
|
||||||
|
if result:
|
||||||
|
if pr[1].isSequence and pr[1].sequence.len == 4:
|
||||||
|
discard fromPreserve(u.username, pr[1][0])
|
||||||
|
discard fromPreserve(u.password, pr[1][1])
|
||||||
|
discard fromPreserve(u.hostname, pr[1][2])
|
||||||
|
discard fromPreserve(u.port, pr[1][3])
|
||||||
|
discard fromPreserve(u.path, pr[2])
|
||||||
|
discard fromPreserve(u.query, pr[3])
|
||||||
|
discard fromPreserve(u.anchor, pr[4])
|
|
@ -1,19 +1,17 @@
|
||||||
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
||||||
# SPDX-License-Identifier: Unlicense
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
## Facsimile of xdg-open from xdg-utils.
|
import std/[asyncdispatch, os, uri]
|
||||||
## https://portland.freedesktop.org/doc/xdg-open.html
|
|
||||||
|
|
||||||
import std/[asyncdispatch, os]
|
|
||||||
import preserves, syndicate, syndicate/capabilities
|
import preserves, syndicate, syndicate/capabilities
|
||||||
import ./protocol
|
import ./protocol, ./common
|
||||||
|
|
||||||
proc publishUri(turn: var Turn; ds: Ref) =
|
proc publishUri(turn: var Turn; ds: Ref) =
|
||||||
for arg in commandLineParams():
|
for arg in commandLineParams():
|
||||||
var xo = XdgOpen(uri: arg)
|
if fileExists(arg):
|
||||||
if fileExists(xo.uri):
|
message(turn, ds, Open(uri: protocol.Uri(
|
||||||
xo.uri = "file://" & absolutePath(arg)
|
scheme: "file", path: arg.absolutePath.toPreserve)))
|
||||||
message(turn, ds, xo)
|
else:
|
||||||
|
message(turn, ds, initRecord("open", arg.parseUri.toPreserve))
|
||||||
stop(turn)
|
stop(turn)
|
||||||
|
|
||||||
proc unixSocketPath: Unix =
|
proc unixSocketPath: Unix =
|
||||||
|
@ -21,7 +19,7 @@ proc unixSocketPath: Unix =
|
||||||
if result.path == "":
|
if result.path == "":
|
||||||
result.path = getEnv("XDG_RUNTIME_DIR", "/run/user/1000") / "dataspace"
|
result.path = getEnv("XDG_RUNTIME_DIR", "/run/user/1000") / "dataspace"
|
||||||
|
|
||||||
discard bootDataspace("xdg-open") do (root: Ref; turn: var Turn):
|
discard bootDataspace("open") do (root: Ref; turn: var Turn):
|
||||||
let cap = mint().toPreserve(Ref)
|
let cap = mint().toPreserve(Ref)
|
||||||
connect(turn, unixSocketPath(), cap, publishUri)
|
connect(turn, unixSocketPath(), cap, publishUri)
|
||||||
|
|
|
@ -3,20 +3,34 @@ import
|
||||||
preserves
|
preserves
|
||||||
|
|
||||||
type
|
type
|
||||||
XdgOpen* {.preservesRecord: "xdg-open".} = object
|
Open* {.preservesRecord: "open".} = object
|
||||||
`uri`*: string
|
`uri`*: Uri
|
||||||
|
|
||||||
UriRunnerConfig* {.preservesDictionary.} = object
|
UriRunnerConfig* {.preservesDictionary.} = object
|
||||||
`handlerspace`* {.preservesEmbedded.}: Preserve[void]
|
`handlerspace`* {.preservesEmbedded.}: Preserve[void]
|
||||||
`urispace`* {.preservesEmbedded.}: Preserve[void]
|
`urispace`* {.preservesEmbedded.}: Preserve[void]
|
||||||
|
|
||||||
|
Authority* {.preservesTuple.} = object
|
||||||
|
`username`*: Preserve[void]
|
||||||
|
`password`*: Preserve[void]
|
||||||
|
`host`*: Preserve[void]
|
||||||
|
`port`*: Preserve[void]
|
||||||
|
|
||||||
|
Uri* {.preservesRecord: "uri".} = object
|
||||||
|
`scheme`*: string
|
||||||
|
`auth`*: Authority
|
||||||
|
`path`*: Preserve[void]
|
||||||
|
`query`*: Preserve[void]
|
||||||
|
`fragment`*: Preserve[void]
|
||||||
|
|
||||||
ActionHandler* {.preservesRecord: "action-handler".} = object
|
ActionHandler* {.preservesRecord: "action-handler".} = object
|
||||||
`pat`*: string
|
`pat`*: string
|
||||||
`entity`* {.preservesEmbedded.}: Preserve[void]
|
`entity`* {.preservesEmbedded.}: Preserve[void]
|
||||||
`action`*: Preserve[void]
|
`action`*: Preserve[void]
|
||||||
|
|
||||||
proc `$`*(x: XdgOpen | UriRunnerConfig | ActionHandler): string =
|
proc `$`*(x: Open | UriRunnerConfig | Authority | Uri | ActionHandler): string =
|
||||||
`$`(toPreserve(x))
|
`$`(toPreserve(x))
|
||||||
|
|
||||||
proc encode*(x: XdgOpen | UriRunnerConfig | ActionHandler): seq[byte] =
|
proc encode*(x: Open | UriRunnerConfig | Authority | Uri | ActionHandler): seq[
|
||||||
|
byte] =
|
||||||
encode(toPreserve(x))
|
encode(toPreserve(x))
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
||||||
# SPDX-License-Identifier: Unlicense
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
import std/[re, tables]
|
import std/[re, tables, uri]
|
||||||
import preserves, syndicate, syndicate/patterns
|
import preserves, syndicate, syndicate/patterns
|
||||||
import ./protocol
|
import ./protocol, ./common
|
||||||
|
|
||||||
# importing std/re doesn't actually link against PCRE
|
# importing std/re doesn't actually link against PCRE
|
||||||
{.passC: staticExec("pkg-config --cflags libpcre").}
|
{.passC: staticExec("pkg-config --cflags libpcre").}
|
||||||
|
@ -22,12 +22,6 @@ runActor("main") do (root: Ref; turn: var Turn):
|
||||||
var handlers: Table[Handle, RegexAction]
|
var handlers: Table[Handle, RegexAction]
|
||||||
during(turn, root, ?UriRunnerConfig) do (handlerspace: Ref, urispace: Ref):
|
during(turn, root, ?UriRunnerConfig) do (handlerspace: Ref, urispace: Ref):
|
||||||
|
|
||||||
# sanity chek
|
|
||||||
onMessage(turn, handlerspace, ?XdgOpen) do (uri: string):
|
|
||||||
raiseAssert "got a message in the wrong dataspace!"
|
|
||||||
onPublish(turn, urispace, ?ActionHandler) do (pat: string; entity: Ref; act: Assertion):
|
|
||||||
raiseAssert "got an assertion in the wrong dataspace!"
|
|
||||||
|
|
||||||
during(turn, handlerspace, dropType(ActionHandler)) do:
|
during(turn, handlerspace, dropType(ActionHandler)) do:
|
||||||
|
|
||||||
during(turn, handlerspace, ?ActionHandler) do (pat: string; entity: Ref; act: Assertion):
|
during(turn, handlerspace, ?ActionHandler) do (pat: string; entity: Ref; act: Assertion):
|
||||||
|
@ -36,7 +30,8 @@ runActor("main") do (root: Ref; turn: var Turn):
|
||||||
do:
|
do:
|
||||||
del(handlers, duringHandle)
|
del(handlers, duringHandle)
|
||||||
|
|
||||||
onMessage(turn, urispace, ?XdgOpen) do (uri: string):
|
onMessage(turn, urispace, Open ? {0:grab()}) do (u: uri.Uri):
|
||||||
|
let uri = $u
|
||||||
assert len(handlers) > 0
|
assert len(handlers) > 0
|
||||||
var matched = false
|
var matched = false
|
||||||
for handler in handlers.values:
|
for handler in handlers.values:
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Package
|
||||||
|
|
||||||
|
version = "20230630"
|
||||||
|
author = "Emery"
|
||||||
|
description = "Syndicated open command"
|
||||||
|
license = "Unlicense"
|
||||||
|
srcDir = "src"
|
||||||
|
bin = @[ "open", "uri_runner"]
|
||||||
|
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
|
||||||
|
requires "nim >= 1.6.4", "syndicate >= 20230630"
|
|
@ -10,12 +10,12 @@
|
||||||
}>
|
}>
|
||||||
]
|
]
|
||||||
|
|
||||||
; grab a dataspace for observing <xdg-open …> messages
|
; grab a dataspace for observing <open …> messages
|
||||||
? <socketspace ?socketspace> [
|
? <socketspace ?socketspace> [
|
||||||
|
|
||||||
; log xdg-open messages
|
; log open messages
|
||||||
$socketspace ?? <xdg-open ?stuff> [
|
$socketspace ?? <open ?stuff> [
|
||||||
$log ! <log "-" { line: <xdg-open $stuff> }>
|
$log ! <log "-" { line: <open $stuff> }>
|
||||||
]
|
]
|
||||||
|
|
||||||
; configure the uri_runner
|
; configure the uri_runner
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
# Package
|
|
||||||
|
|
||||||
version = "20230630"
|
|
||||||
author = "Emery"
|
|
||||||
description = "A better xdg-open"
|
|
||||||
license = "Unlicense"
|
|
||||||
srcDir = "src"
|
|
||||||
bin = @[ "uri_runner", "xdg_open"]
|
|
||||||
|
|
||||||
|
|
||||||
# Dependencies
|
|
||||||
|
|
||||||
requires "nim >= 1.6.4", "syndicate >= 20230518"
|
|
Loading…
Reference in New Issue