on f224d6c help sign in
55 files changed+638−3384
since splitsnapshots
unifiedsplit
.gitignore−1 LICENSE−7 README.md−43 dev/sink-elm-live.sh → dev/elm-live.sh+1−1 dev/vanilla-elm-live.sh−7 docs/sink.md−101 elm.json+2−11 example/script.js+1−16 example/src/Vanilla.elm → example/src/Main.elm+24−36 example/src/Sink.elm−199 example/urbit/app/journal.hoon−133 example/urbit/desk.bill−2 example/urbit/desk.docket-0−12 example/urbit/gen/journal/add.hoon−37 example/urbit/lib/agentio.hoon−139 example/urbit/lib/dbug.hoon−155 example/urbit/lib/default-agent.hoon−69 example/urbit/lib/docket.hoon−223 example/urbit/lib/journal.hoon−66 example/urbit/lib/noun-diff.hoon−227 example/urbit/lib/sink.hoon−26 example/urbit/lib/skeleton.hoon−51 example/urbit/mar/bill.hoon−34 example/urbit/mar/docket-0.hoon−25 example/urbit/mar/hoon.hoon−49 example/urbit/mar/jam.hoon−17 example/urbit/mar/journal/action.hoon−14 example/urbit/mar/journal/update.hoon−16 example/urbit/mar/json.hoon−26 example/urbit/mar/kelvin.hoon−28 example/urbit/mar/mime.hoon−32 example/urbit/mar/noun.hoon−19 example/urbit/mar/txt-diff.hoon−16 example/urbit/mar/txt.hoon−275 example/urbit/sur/docket.hoon−82 example/urbit/sur/journal.hoon−19 example/urbit/sys.kelvin−1 res/airlock.jpeg src/BitWriter.elm+5−5 src/Ur.elm+207−94 src/Ur/Cmd.elm+10−27 src/Ur/Cmd/Internal.elm+2−1 src/Ur/Constructor.elm+16−65 src/Ur/Da.elm+1−11 src/Ur/Deconstructor.elm+198−293 src/Ur/Jam.elm−193 src/Ur/NounDiff.elm−115 src/Ur/Phonemic.elm+12−9 src/Ur/Requests.elm+53−7 src/Ur/Run.elm+81−216 src/Ur/Sub.elm+4−41 src/Ur/Sub/Internal.elm+3−4 src/Ur/Types.elm−60 src/Ur/Uw.elm+7−15 tests/Test/Urbit.elm+11−13
.gitignore−1
@@ -1,3 +1,2 @@
11elm-stuff
22elm.js
3−zod
LICENSEdeleted−7
@@ -1,7 +0,0 @@
1−Copyright 2023 Ilia Kostiuchenko
2−
3−Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4−
5−The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6−
7−THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
README.mddeleted−43
@@ -1,43 +0,0 @@
1−# Airlock
2−
3−![](res/airlock.jpeg)
4−
5−## Usage
6−
7−### Demo
8−
9−[![DEMO](https://img.youtube.com/vi/tynCzifvIzE/0.jpg)](https://www.youtube.com/watch?v=tynCzifvIzE)
10−
11−
12−## Getting started
13−
14−The easiest way of using this library is by using the [airlock template](https://github.com/ilyakooo0/airlock-template).
15−
16−### FFI
17−
18−This is for setting up this library from scratch.
19−
20−Urbit subscriptions require [server-side event (SSE)](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events).
21−Unfortunately, Elm does not provide a native implementation.
22−This means that we will need to use [JS FFI (aka ports)](https://guide.elm-lang.org/interop/ports.html).
23−
24−#### Setting up the Elm side
25−
26−You would need to declare two ports for Airlock to use:
27−
28−1. `port createEventSource : String -> Cmd msg`
29−
30− This sets up the SSE channel.
31−2. `port onEventSourceMessage : (JD.Value -> msg) -> Sub msg`
32− This recieves the actual messages from the SSE channel.
33−
34−These two functions need to be passed to one of the functions from `Ur.Run` module.
35−The functions in `Ur.Run` are the same as functions from `Browser`, but have a couple of extra urbit-specific fields.
36−
37−#### Setting up the JS side
38−
39−The SSE JS code is neatly packed into [example/fetch-event-source.js](example/fetch-event-source.js).
40−All you need to do is pass them to Elm ports like in [example/script.js](example/script.js).
41−
42−You can see a full working example in [example](example).
43−
dev/sink-elm-live.sh → dev/elm-live.shrenamed+1−1
@@ -4,4 +4,4 @@ set -e
44
55cd "$(dirname "$0")/../example"
66
7−nix run nixpkgs#elmPackages.elm-live -- src/Sink.elm --start-page=index.html -- --output=elm.js --debug "$@"
7+nix run nixpkgs#elmPackages.elm-live -- src/Main.elm --start-page=index.html -- --output=elm.js --debug "$@"
dev/vanilla-elm-live.shdeleted−7
@@ -1,7 +0,0 @@
1−#!/bin/sh
2−
3−set -e
4−
5−cd "$(dirname "$0")/../example"
6−
7−nix run nixpkgs#elmPackages.elm-live -- src/Vanilla.elm --start-page=index.html -- --output=elm.js --debug "$@"
docs/sink.mddeleted−101
@@ -1,101 +0,0 @@
1−# %sink
2−
3−%sink is a state replication system between your %gall agent and your Elm airlock.
4−
5−%sink allows you to avoid having to manually write subscriptions which send semantic diffs between your %gall agent and the frontend.
6−
7−## How it works
8−
9−%sink consists of two parts:
10−1. The %sink library you import into your %gall agent and call appropriate functions at the right points in your agent lifecycle. More on this in a bit.
11−2. The `Ur.Sub.sink` urbit subscription which reconciles the state and hands you the latest version of %gall agent state that you can then `Deconstruct` into Elm data structures.
12−
13−The whole system works by saving the previous version your %gall agent state and diffing the raw nouns that compose your old state and your new state.
14−On first initialization of the %sink system the whole state you supplied is sent to the frontend. Any subsequent changes are sent as a diff between your old state and your new state.
15−
16−## How to use it
17−
18−### The %gall agent part
19−
20−#### Copying library files
21−
22−In order to use %sink you have to copy the following two files into your agent desk into the `lib` directory:
23−1. [example/urbit/lib/noun-diff.hoon](../example/urbit/lib/noun-diff.hoon) -- contains the algorithm for diffing raw nouns.
24−2. [example/urbit/lib/sink.hoon](../example/urbit/lib/sink.hoon) -- contains the logic of syncing the state between your agent and your frontend.
25−
26−#### Adding sync points into your agent
27−
28−First you need to import the %sink library into your agent:
29−
30−```hoon
31−/+ *sink
32−```
33−
34−Next you need to initialize the sink. Put the following declaration somewhere before your agent door:
35−
36−```hoon
37−::
38−:: A deferred expression of the state you want to sync to the frontend.
39−=* entries (tap:j-orm journal.stat)
40−::
41−:: Replace /sync with whatever path you want to use for syncing your state.
42−=/ snik (sink ~[/sync])
43−::
44−:: Next you initialize your sink with your initial agent state.
45−=/ sink (snik entries)
46−```
47−
48−You can have multiple sinks in the same application to sync different parts of your state on different paths.
49−
50−Don't forget to reinitialize your `sink` when your restore your agent state in the `++on-load` arm:
51−
52−```hoon
53−++ on-load
54− |= old-vase=vase
55− ^- (quip card _this)
56− =/ state !<(versioned-state old-vase)
57− ::
58− :: the `sink (snik entries)` is the important bit.
59− `this(state state, sink (snik entries))
60−```
61−
62−Lastly, you need to send sink updates whenever you change your state. Most likely this will be in your `++on-poke` arm:
63−
64−```hoon
65−::
66−:: This line generates a `card` that you need to pass to arvo and updates
67−:: the `sink` to reference the latest state of your agent.
68−=^ card sink (sync:sink entries)
69−```
70−
71−You can look at the [journal.hoon](../example/urbit/app/journal.hoon) for a full example.
72−
73−#### Adding sink the the frontend
74−
75−For your frontend to recieve %sink updates you need to pass the result of calling `Ur.Sub.sink` to the `urbitSubscriptions` field of `Ur.Run.application` or similar function from `Ur.Run`:
76−
77−```elm
78−main : Ur.Run.Program Model Msg
79−main =
80− Ur.Run.application
81− {
82− -- ...
83− urbitSubscriptions =
84− -- ...
85− Ur.Sub.sink
86− { ship = ship
87− , app = "journal"
88− , path = [ "sync" ]
89− , deconstructor =
90− D.list (D.cell D.bigint D.cord |> D.map (\a b -> ( a, b )))
91− |> D.map GotListings
92− }
93− -- ...
94− }
95−```
96−
97−In the `deconstructor` field you specify a `Deconstructor` the deconstructs _the whole_ state that is being synced form the %gall agent.
98−
99−You do not have to deal with diffs. It is handled automatically
100−
101−You can look at [example/src/Sink.elm](../example/src/Sink.elm) for a full example.
elm.json+2−11
@@ -3,18 +3,9 @@
33 "name": "ilyakooo0/airlock",
44 "summary": "Urbit airlock",
55 "license": "MIT",
6− "version": "1.1.1",
6+ "version": "1.0.0",
77 "exposed-modules": [
8− "Ur",
9− "Ur.Cmd",
10− "Ur.Sub",
11− "Ur.Constructor",
12− "Ur.Deconstructor",
13− "Ur.Phonemic",
14− "Ur.Da",
15− "Ur.Uw",
16− "Ur.Run",
17− "Ur.Types"
8+ "Ur", "Ur.Cmd", "Ur.Sub", "Ur.Constructor", "Ur.Deconstructor", "Ur.Phonemic", "Ur.Da", "Ur.Uw", "Ur.Run"
189 ],
1910 "elm-version": "0.19.0 <= v < 0.20.0",
2011 "dependencies": {
example/script.js+1−16
@@ -2,22 +2,7 @@ import { fetchEventSource } from "/fetch-event-source.js"
22
33const uid = `${Math.floor(Date.now() / 1000)}-${Math.random()}`;
44
5−function searchForInit(obj) {
6− if (obj.init) {
7− return obj.init;
8− } else {
9− for (let key in obj) {
10− if (obj.hasOwnProperty(key)) {
11− const result = searchForInit(obj[key]);
12− if (result) {
13− return result;
14− }
15− }
16− }
17− }
18−}
19−
20−let app = searchForInit(Elm)({ node: document.getElementById("elm"), flags: { uid } });
5+let app = Elm.Main.init({ node: document.getElementById("elm"), flags: { uid } });
216
227app.ports.createEventSource.subscribe((url) => {
238 fetchEventSource(url, {
example/src/Vanilla.elm → example/src/Main.elmrenamed+24−36
@@ -1,4 +1,4 @@
1−port module Vanilla exposing (main)
1+port module Main exposing (main)
22
33import BigInt exposing (BigInt)
44import Browser exposing (Document)
@@ -11,7 +11,9 @@ import Time
1111import Ur
1212import Ur.Cmd
1313import Ur.Constructor as C
14+import Ur.Da
1415import Ur.Deconstructor as D
16+import Ur.Requests
1517import Ur.Run
1618import Ur.Sub
1719import Widget
@@ -19,12 +21,6 @@ import Widget.Icon as Icon
1921import Widget.Material as Material
2022
2123
22−url : String
23−url =
24− "http://localhost:8080"
25−
26−
27−main : Ur.Run.Program Model Msg
2824main =
2925 Ur.Run.application
3026 { init =
@@ -32,23 +28,21 @@ main =
3228 ( { error = ""
3329 , entries = Nothing
3430 , newEntry = ""
35− , shipName = Nothing
3631 }
3732 , Cmd.batch
38− [ Ur.logIn url "lidlut-tabwed-pillex-ridrup"
33+ [ Ur.logIn "http://localhost:8080" "lidlut-tabwed-pillex-ridrup"
3934 |> Cmd.map (result (Debug.toString >> Error) (always Noop))
40− , Ur.getShipName url |> Cmd.map (result (always Noop) GotShipName)
41− , Ur.scry
42− { url = url
35+ , Ur.Requests.scry
36+ { url = "http://localhost:8080"
4337 , agent = "journal"
4438 , path = [ "entries", "all" ]
4539 , error = Noop
4640 , success =
4741 D.cell D.ignore
4842 (D.cell (D.const D.cord "jrnl")
49− (D.list (D.cell D.bigint D.cord))
43+ (D.list (D.cell D.bigint D.cord |> D.map (\a b -> ( a, b ))))
44+ |> D.map GotListings
5045 )
51− |> D.map (\( (), ( (), listings ) ) -> GotListings listings)
5246 }
5347 ]
5448 |> Ur.Cmd.cmd
@@ -58,22 +52,22 @@ main =
5852 , subscriptions = always Sub.none
5953 , createEventSource = createEventSource
6054 , urbitSubscriptions =
61− \{ entries, shipName } ->
62− case ( entries, shipName ) of
63− ( Just _, Just ship ) ->
55+ \{ entries } ->
56+ case entries of
57+ Nothing ->
58+ Ur.Sub.none
59+
60+ Just _ ->
6461 Ur.Sub.subscribe
65− { ship = ship
62+ { ship = "~zod"
6663 , app = "journal"
6764 , path = [ "updates" ]
6865 , deconstructor = decodeJournalUpdate |> D.map GotUpdate
6966 }
70−
71− _ ->
72− Ur.Sub.none
7367 , onEventSourceMsg = onEventSourceMessage
7468 , onUrlChange = \_ -> Noop
7569 , onUrlRequest = \_ -> Noop
76− , urbitUrl = \_ -> url
70+ , urbitUrl = \_ -> "http://localhost:8080"
7771 }
7872
7973
@@ -81,7 +75,6 @@ type alias Model =
8175 { error : String
8276 , entries : Maybe (List ( BigInt, String ))
8377 , newEntry : String
84− , shipName : Maybe String
8578 }
8679
8780
@@ -94,7 +87,6 @@ type Msg
9487 | DeleteEntry BigInt
9588 | AddEntry String
9689 | RunCmd (Ur.Cmd.Cmd Msg)
97− | GotShipName String
9890
9991
10092update : Msg -> Model -> ( Model, Ur.Cmd.Cmd Msg )
@@ -157,7 +149,7 @@ update msg model =
157149 { ship = "~zod"
158150 , agent = "journal"
159151 , mark = "journal-action"
160− , noun = C.cell (C.cord "add") (C.cell (time |> Time.posixToMillis |> BigInt.fromInt |> C.bigint) (C.cord txt))
152+ , noun = C.cell (C.cord "add") (C.cell (Ur.Da.posixToDa time |> C.bigint) (C.cord txt))
161153 }
162154 |> RunCmd
163155 )
@@ -167,9 +159,6 @@ update msg model =
167159 RunCmd cmd ->
168160 ( model, cmd )
169161
170− GotShipName name ->
171− ( { model | shipName = Just name }, Ur.Cmd.none )
172−
173162
174163type JournalUpdate
175164 = Add BigInt String
@@ -177,15 +166,14 @@ type JournalUpdate
177166 | Delete BigInt
178167
179168
180−decodeJournalUpdate : D.Deconstructor JournalUpdate
169+decodeJournalUpdate : D.Deconstructor (JournalUpdate -> a) a
181170decodeJournalUpdate =
182− D.oneOf
183− [ (D.cell (D.const D.cord "add") <| D.cell D.bigint D.cord) |> D.map (\( (), ( id, txt ) ) -> Add id txt)
184− , D.cell (D.const D.cord "edit") (D.cell D.bigint D.cord) |> D.map (\( (), ( id, txt ) ) -> Edit id txt)
185− , D.cell (D.const D.cord "del") D.bigint |> D.map (\( (), id ) -> Delete id)
186− ]
187− |> D.cell D.ignore
188− |> D.map (\( (), upd ) -> upd)
171+ D.cell D.ignore <|
172+ D.oneOf
173+ [ (D.cell (D.const D.cord "add") <| D.cell D.bigint D.cord) |> D.map Add
174+ , (D.cell (D.const D.cord "edit") <| D.cell D.bigint D.cord) |> D.map Edit
175+ , D.cell (D.const D.cord "del") D.bigint |> D.map Delete
176+ ]
189177
190178
191179view : Model -> Document Msg
example/src/Sink.elmdeleted−199
@@ -1,199 +0,0 @@
1−port module Sink exposing (main)
2−
3−import BigInt exposing (BigInt)
4−import Browser exposing (Document)
5−import Element exposing (..)
6−import Element.Border as Border
7−import Heroicons.Outline
8−import Json.Decode as JD
9−import Task
10−import Time
11−import Ur
12−import Ur.Cmd
13−import Ur.Constructor as C
14−import Ur.Deconstructor as D
15−import Ur.Run
16−import Ur.Sub
17−import Widget
18−import Widget.Icon as Icon
19−import Widget.Material as Material
20−
21−
22−url : String
23−url =
24− "http://localhost:8080"
25−
26−
27−main : Ur.Run.Program Model Msg
28−main =
29− Ur.Run.application
30− { init =
31− \_ _ ->
32− ( { error = ""
33− , entries = Nothing
34− , newEntry = ""
35− , shipName = Nothing
36− }
37− , Cmd.batch
38− [ Ur.logIn url "lidlut-tabwed-pillex-ridrup"
39− |> Cmd.map (result (Debug.toString >> Error) (always Noop))
40− , Ur.getShipName url |> Cmd.map (result (always Noop) GotShipName)
41− ]
42− |> Ur.Cmd.cmd
43− )
44− , update = update
45− , view = view
46− , subscriptions = always Sub.none
47− , createEventSource = createEventSource
48− , urbitSubscriptions =
49− \{ shipName } ->
50− case shipName of
51− Just ship ->
52− Ur.Sub.batch
53− [ Ur.Sub.sink
54− { ship = ship
55− , app = "journal"
56− , path = [ "sync" ]
57− , deconstructor =
58− D.list (D.cell D.bigint D.cord)
59− |> D.map GotListings
60− }
61− ]
62−
63− _ ->
64− Ur.Sub.none
65− , onEventSourceMsg = onEventSourceMessage
66− , onUrlChange = \_ -> Noop
67− , onUrlRequest = \_ -> Noop
68− , urbitUrl = \_ -> url
69− }
70−
71−
72−type alias Model =
73− { error : String
74− , entries : Maybe (List ( BigInt, String ))
75− , newEntry : String
76− , shipName : Maybe String
77− }
78−
79−
80−type Msg
81− = Noop
82− | Error String
83− | GotListings (List ( BigInt, String ))
84− | UpdateNewEntry String
85− | DeleteEntry BigInt
86− | AddEntry String
87− | RunCmd (Ur.Cmd.Cmd Msg)
88− | GotShipName String
89−
90−
91−update : Msg -> Model -> ( Model, Ur.Cmd.Cmd Msg )
92−update msg model =
93− case msg of
94− Noop ->
95− ( model, Ur.Cmd.none )
96−
97− Error err ->
98− ( { model | error = err }, Ur.Cmd.none )
99−
100− GotListings entries ->
101− ( { model | entries = Just entries }, Ur.Cmd.none )
102−
103− UpdateNewEntry txt ->
104− ( { model | newEntry = txt }, Ur.Cmd.none )
105−
106− DeleteEntry id ->
107− ( model
108− , Ur.Cmd.poke
109− { ship = "~zod"
110− , agent = "journal"
111− , mark = "journal-action"
112− , noun = C.cell (C.cord "del") (C.bigint id)
113− }
114− )
115−
116− AddEntry txt ->
117− ( { model | newEntry = "" }
118− , Time.now
119− |> Task.perform
120− (\time ->
121− Ur.Cmd.poke
122− { ship = "~zod"
123− , agent = "journal"
124− , mark = "journal-action"
125− , noun = C.cell (C.cord "add") (C.cell (time |> Time.posixToMillis |> BigInt.fromInt |> C.bigint) (C.cord txt))
126− }
127− |> RunCmd
128− )
129− |> Ur.Cmd.cmd
130− )
131−
132− RunCmd cmd ->
133− ( model, cmd )
134−
135− GotShipName name ->
136− ( { model | shipName = Just name }, Ur.Cmd.none )
137−
138−
139−view : Model -> Document Msg
140−view model =
141− { body =
142− [ layout []
143− ([ el [ alignTop ] (text model.error)
144− , row [ spacing 8 ]
145− [ Widget.textInput (Material.textInput Material.defaultPalette)
146− { chips = []
147− , text = model.newEntry
148− , placeholder = Nothing
149− , label = "New entry"
150− , onChange = UpdateNewEntry
151− }
152− , Widget.iconButton (Material.containedButton Material.defaultPalette)
153− { text = "submit"
154− , icon = Icon.elmHeroicons Heroicons.Outline.check
155− , onPress = AddEntry model.newEntry |> Just
156− }
157− ]
158− , model.entries
159− |> Maybe.withDefault []
160− |> List.map
161− (\( id, txt ) ->
162− row
163− [ Border.rounded 10
164− , Border.shadow { offset = ( 0, 5 ), size = 1, blur = 10, color = rgba 0 0 0 0.3 }
165− , centerX
166− , padding 10
167− , spacing 12
168− ]
169− [ paragraph [] [ text txt ]
170− , Widget.iconButton (Material.containedButton Material.defaultPalette)
171− { text = "delete"
172− , icon = Icon.elmHeroicons Heroicons.Outline.trash
173− , onPress = DeleteEntry id |> Just
174− }
175− ]
176− )
177− |> column [ spacing 10, centerX ]
178− ]
179− |> column [ spacing 18, centerX ]
180− )
181− ]
182− , title = "Airlock"
183− }
184−
185−
186−result : (a -> c) -> (b -> c) -> Result a b -> c
187−result f g res =
188− case res of
189− Ok b ->
190− g b
191−
192− Err a ->
193− f a
194−
195−
196−port createEventSource : String -> Cmd msg
197−
198−
199−port onEventSourceMessage : (JD.Value -> msg) -> Sub msg
example/urbit/app/journal.hoondeleted−133
@@ -1,133 +0,0 @@
1−/- *journal
2−/+ default-agent, dbug, agentio, *sink
3−|%
4−+$ versioned-state
5− $% state-0
6− ==
7−+$ state-0 [%0 =journal =log]
8−+$ card card:agent:gall
9−++ j-orm ((on id txt) gth)
10−++ log-orm ((on @ action) lth)
11−++ unique-time
12− |= [=time =log]
13− ^- @
14− =/ unix-ms=@
15− (unm:chrono:userlib time)
16− |-
17− ?. (has:log-orm log unix-ms)
18− unix-ms
19− $(time (add unix-ms 1))
20−--
21−
22−%- agent:dbug
23−=/ state *state-0
24−=* entries (tap:j-orm journal.state)
25−=/ snik (sink ~[/sync])
26−=/ sink (snik entries)
27−^- agent:gall
28−::
29−|_ =bowl:gall
30−+* this .
31− def ~(. (default-agent this %|) bowl)
32− io ~(. agentio bowl)
33−++ on-init on-init:def
34−++ on-save
35− ^- vase
36− !>(state)
37−::
38−++ on-load
39− |= old-vase=vase
40− ^- (quip card _this)
41− =/ state !<(versioned-state old-vase)
42− `this(state state, sink (snik entries))
43−::
44−++ on-poke
45− |= [=mark =vase]
46− ^- (quip card _this)
47− |^
48− ?> (team:title our.bowl src.bowl)
49− ?. ?=(%journal-action mark) (on-poke:def mark vase)
50− =/ now=@ (unique-time now.bowl log.state)
51− =/ act !<(action vase)
52− =. state (poke-action act)
53− =^ card sink (sync:sink entries)
54− :_ this(log.state (put:log-orm log.state now act))
55− ~[(fact:io journal-update+!>(`update`[now act]) ~[/updates]) card]
56− ::
57− ++ poke-action
58− |= act=action
59− ^- _state
60− ?- -.act
61− %add
62− ?< (has:j-orm journal.state id.act)
63− state(journal (put:j-orm journal.state id.act txt.act))
64− ::
65− %edit
66− ?> (has:j-orm journal.state id.act)
67− state(journal (put:j-orm journal.state id.act txt.act))
68− ::
69− %del
70− ?> (has:j-orm journal.state id.act)
71− state(journal +:(del:j-orm journal.state id.act))
72− ==
73− --
74−::
75−++ on-watch
76− |= =path
77− ^- (quip card _this)
78− ?> (team:title our.bowl src.bowl)
79− ?+ path (on-watch:def path)
80− [%updates ~] `this
81− [%sync ~] [~[flush:sink] this]
82− ==
83−::
84−++ on-peek
85− |= =path
86− ^- (unit (unit cage))
87− ?> (team:title our.bowl src.bowl)
88− =/ now=@ (unm:chrono:userlib now.bowl)
89− ?+ path (on-peek:def path)
90− [%x %entries *]
91− ?+ t.t.path (on-peek:def path)
92− [%all ~]
93− :^ ~ ~ %journal-update
94− !> ^- update
95− [now %jrnl entries]
96− ::
97− [%before @ @ ~]
98− =/ before=@ (rash i.t.t.t.path dem)
99− =/ max=@ (rash i.t.t.t.t.path dem)
100− :^ ~ ~ %journal-update
101− !> ^- update
102− [now %jrnl (tab:j-orm journal.state `before max)]
103− ::
104− [%between @ @ ~]
105− =/ start=@
106− =+ (rash i.t.t.t.path dem)
107− ?:(=(0 -) - (sub - 1))
108− =/ end=@ (add 1 (rash i.t.t.t.t.path dem))
109− :^ ~ ~ %journal-update
110− !> ^- update
111− [now %jrnl (tap:j-orm (lot:j-orm journal.state `end `start))]
112− ==
113− ::
114− [%x %updates *]
115− ?+ t.t.path (on-peek:def path)
116− [%all ~]
117− :^ ~ ~ %journal-update
118− !> ^- update
119− [now %logs (tap:log-orm log.state)]
120− ::
121− [%since @ ~]
122− =/ since=@ (rash i.t.t.t.path dem)
123− :^ ~ ~ %journal-update
124− !> ^- update
125− [now %logs (tap:log-orm (lot:log-orm log.state `since ~))]
126− ==
127− ==
128−::
129−++ on-leave on-leave:def
130−++ on-agent on-agent:def
131−++ on-arvo on-arvo:def
132−++ on-fail on-fail:def
133−--
example/urbit/desk.billdeleted−2
@@ -1,2 +0,0 @@
1−:~ %journal
2−==
example/urbit/desk.docket-0deleted−12
@@ -1,12 +0,0 @@
1−:~
2− title+'Journal'
3− info+'Dear diary...'
4− color+0xd9.b06d
5− version+[0 1 1]
6− website+'https://urbit.org'
7− license+'MIT'
8− base+'journal'
9− :+ %glob-http
10− 'https://m.tinnus-napbus.xyz/pub/journal-glob-0v3.gjphm.jp4u3.59f0f.a67bf.446k4.glob'
11− 0v3.gjphm.jp4u3.59f0f.a67bf.446k4
12−==
example/urbit/gen/journal/add.hoondeleted−37
@@ -1,37 +0,0 @@
1−/- *journal, *sole
2−/+ *generators
3−:- %ask
4−|= [[now=@da * bek=beak] *]
5−^- (sole-product (cask action))
6−=| acc=wain
7−=/ off=tape
8− =/ blit
9− =+ [our=(scot %p p.bek) now=(scot %da p.r.bek)]
10− .^(blit:dill %dx /[our]//[now]/sessions//line)
11− ?. ?=(%lin -.blit) !!
12− %+ scan (tufa p.blit)
13− ;~ sfix
14− %+ cook
15− |=(t=tape (reap (add 2 (lent t)) ' '))
16− (star ;~(less gar next))
17− (star next)
18− ==
19−|^
20−%+ print leaf+"{off}-------------------------------------\0a"
21−%+ print leaf+"{off}| |"
22−%+ print leaf+"{off}| (\\\\\\ to submit, <BKSP> to cancel) |"
23−%+ print leaf+"{off}| New Journal Entry |"
24−%+ print leaf+"{off}| |"
25−%+ print leaf+"\0a{off}-------------------------------------"
26−line
27−++ line
28− %+ prompt [%& %prompt ""]
29− |= t=tape
30− ?: =(t "\\\\\\")
31− %+ produce %journal-action
32− :+ %add
33− (unm:chrono:userlib now)
34− (of-wain:format (flop acc))
35− %+ print leaf+"{off}{t}"
36− line(acc [(crip t) acc])
37−--
example/urbit/lib/agentio.hoondeleted−139
@@ -1,139 +0,0 @@
1−=>
2− |%
3− ++ card card:agent:gall
4− --
5−::
6−|_ =bowl:gall
7−++ scry
8− |= [desk=@tas =path]
9− %+ weld
10− /(scot %p our.bowl)/[desk]/(scot %da now.bowl)
11− path
12−::
13−++ pass
14− |_ =wire
15− ++ poke
16− |= [=dock =cage]
17− [%pass wire %agent dock %poke cage]
18− ::
19− ++ poke-our
20− |= [app=term =cage]
21− ^- card
22− (poke [our.bowl app] cage)
23− ::
24− ++ poke-self
25− |= =cage
26− ^- card
27− (poke-our dap.bowl cage)
28− ::
29− ++ arvo
30− |= =note-arvo
31− ^- card
32− [%pass wire %arvo note-arvo]
33− ::
34− ++ watch
35− |= [=dock =path]
36− [%pass (watch-wire path) %agent dock %watch path]
37− ::
38− ++ watch-our
39− |= [app=term =path]
40− (watch [our.bowl app] path)
41− ::
42− ++ watch-wire
43− |= =path
44− ^+ wire
45− ?. ?=(~ wire)
46− wire
47− agentio-watch+path
48− ::
49− ++ leave
50− |= =dock
51− [%pass wire %agent dock %leave ~]
52− ::
53− ++ leave-our
54− |= app=term
55− (leave our.bowl app)
56− ::
57− ++ leave-path
58− |= [=dock =path]
59− =. wire
60− (watch-wire path)
61− (leave dock)
62− ::
63− ++ wait
64− |= p=@da
65− (arvo %b %wait p)
66− ::
67− ++ rest
68− |= p=@da
69− (arvo %b %wait p)
70− ::
71− ++ warp
72− |= [wer=ship =riff:clay]
73− (arvo %c %warp wer riff)
74− ::
75− ++ warp-our
76− |= =riff:clay
77− (warp our.bowl riff)
78− ::
79− :: right here, right now
80− ++ warp-slim
81− |= [genre=?(%sing %next) =care:clay =path]
82− =/ =mood:clay
83− [care r.byk.bowl path]
84− =/ =rave:clay
85− ?:(?=(%sing genre) [genre mood] [genre mood])
86− (warp-our q.byk.bowl `rave)
87− ::
88− ++ connect
89− |= [=binding:eyre app=term]
90− (arvo %e %connect binding app)
91− --
92−::
93−++ fact-curry
94− |* [=mark =mold]
95− |= [paths=(list path) fac=mold]
96− (fact mark^!>(fac) paths)
97−::
98−++ fact-kick
99− |= [=path =cage]
100− ^- (list card)
101− :~ (fact cage ~[path])
102− (kick ~[path])
103− ==
104−::
105−++ fact-init
106− |= =cage
107− ^- card
108− [%give %fact ~ cage]
109−::
110−++ fact-init-kick
111− |= =cage
112− ^- (list card)
113− :~ (fact cage ~)
114− (kick ~)
115− ==
116−::
117−++ fact
118− |= [=cage paths=(list path)]
119− ^- card
120− [%give %fact paths cage]
121−::
122−++ fact-all
123− |= =cage
124− ^- (unit card)
125− =/ paths=(set path)
126− %- ~(gas in *(set path))
127− %+ turn ~(tap by sup.bowl)
128− |=([duct ship =path] path)
129− ?: =(~ paths) ~
130− `(fact cage ~(tap in paths))
131−::
132−++ kick
133− |= paths=(list path)
134− [%give %kick paths ~]
135−::
136−++ kick-only
137− |= [=ship paths=(list path)]
138− [%give %kick paths `ship]
139−--
example/urbit/lib/dbug.hoondeleted−155
@@ -1,155 +0,0 @@
1−:: dbug: agent wrapper for generic debugging tools
2−::
3−:: usage: %-(agent:dbug your-agent)
4−::
5−|%
6−+$ poke
7− $% [%bowl ~]
8− [%state grab=cord]
9− [%incoming =about]
10− [%outgoing =about]
11− ==
12−::
13−+$ about
14− $@ ~
15− $% [%ship =ship]
16− [%path =path]
17− [%wire =wire]
18− [%term =term]
19− ==
20−::
21−++ agent
22− |= =agent:gall
23− ^- agent:gall
24− !.
25− |_ =bowl:gall
26− +* this .
27− ag ~(. agent bowl)
28− ::
29− ++ on-poke
30− |= [=mark =vase]
31− ^- (quip card:agent:gall agent:gall)
32− ?. ?=(%dbug mark)
33− =^ cards agent (on-poke:ag mark vase)
34− [cards this]
35− =/ dbug
36− !<(poke vase)
37− =; =tang
38− ((%*(. slog pri 1) tang) [~ this])
39− ?- -.dbug
40− %bowl [(sell !>(bowl))]~
41− ::
42− %state
43− =? grab.dbug =('' grab.dbug) '-'
44− =; product=^vase
45− [(sell product)]~
46− =/ state=^vase
47− :: if the underlying app has implemented a /dbug/state scry endpoint,
48− :: use that vase in place of +on-save's.
49− ::
50− =/ result=(each ^vase tang)
51− (mule |.(q:(need (need (on-peek:ag /x/dbug/state)))))
52− ?:(?=(%& -.result) p.result on-save:ag)
53− %+ slap
54− (slop state !>([bowl=bowl ..zuse]))
55− (ream grab.dbug)
56− ::
57− %incoming
58− =; =tang
59− ?^ tang tang
60− [%leaf "no matching subscriptions"]~
61− %+ murn
62− %+ sort ~(tap by sup.bowl)
63− |= [[* a=[=ship =path]] [* b=[=ship =path]]]
64− (aor [path ship]:a [path ship]:b)
65− |= [=duct [=ship =path]]
66− ^- (unit tank)
67− =; relevant=?
68− ?. relevant ~
69− `>[path=path from=ship duct=duct]<
70− ?: ?=(~ about.dbug) &
71− ?- -.about.dbug
72− %ship =(ship ship.about.dbug)
73− %path ?=(^ (find path.about.dbug path))
74− %wire %+ lien duct
75− |=(=wire ?=(^ (find wire.about.dbug wire)))
76− %term !!
77− ==
78− ::
79− %outgoing
80− =; =tang
81− ?^ tang tang
82− [%leaf "no matching subscriptions"]~
83− %+ murn
84− %+ sort ~(tap by wex.bowl)
85− |= [[[a=wire *] *] [[b=wire *] *]]
86− (aor a b)
87− |= [[=wire =ship =term] [acked=? =path]]
88− ^- (unit tank)
89− =; relevant=?
90− ?. relevant ~
91− `>[wire=wire agnt=[ship term] path=path ackd=acked]<
92− ?: ?=(~ about.dbug) &
93− ?- -.about.dbug
94− %ship =(ship ship.about.dbug)
95− %path ?=(^ (find path.about.dbug path))
96− %wire ?=(^ (find wire.about.dbug wire))
97− %term =(term term.about.dbug)
98− ==
99− ==
100− ::
101− ++ on-peek
102− |= =path
103− ^- (unit (unit cage))
104− ?. ?=([@ %dbug *] path)
105− (on-peek:ag path)
106− ?+ path [~ ~]
107− [%u %dbug ~] ``noun+!>(&)
108− [%x %dbug %state ~] ``noun+!>(on-save:ag)
109− [%x %dbug %subscriptions ~] ``noun+!>([wex sup]:bowl)
110− ==
111− ::
112− ++ on-init
113− ^- (quip card:agent:gall agent:gall)
114− =^ cards agent on-init:ag
115− [cards this]
116− ::
117− ++ on-save on-save:ag
118− ::
119− ++ on-load
120− |= old-state=vase
121− ^- (quip card:agent:gall agent:gall)
122− =^ cards agent (on-load:ag old-state)
123− [cards this]
124− ::
125− ++ on-watch
126− |= =path
127− ^- (quip card:agent:gall agent:gall)
128− =^ cards agent (on-watch:ag path)
129− [cards this]
130− ::
131− ++ on-leave
132− |= =path
133− ^- (quip card:agent:gall agent:gall)
134− =^ cards agent (on-leave:ag path)
135− [cards this]
136− ::
137− ++ on-agent
138− |= [=wire =sign:agent:gall]
139− ^- (quip card:agent:gall agent:gall)
140− =^ cards agent (on-agent:ag wire sign)
141− [cards this]
142− ::
143− ++ on-arvo
144− |= [=wire =sign-arvo]
145− ^- (quip card:agent:gall agent:gall)
146− =^ cards agent (on-arvo:ag wire sign-arvo)
147− [cards this]
148− ::
149− ++ on-fail
150− |= [=term =tang]
151− ^- (quip card:agent:gall agent:gall)
152− =^ cards agent (on-fail:ag term tang)
153− [cards this]
154− --
155−--
example/urbit/lib/default-agent.hoondeleted−69
@@ -1,69 +0,0 @@
1−/+ skeleton
2−|* [agent=* help=*]
3−?: ?=(%& help)
4− ~| %default-agent-helpfully-crashing
5− skeleton
6−|_ =bowl:gall
7−++ on-init
8− `agent
9−::
10−++ on-save
11− !>(~)
12−::
13−++ on-load
14− |= old-state=vase
15− `agent
16−::
17−++ on-poke
18− |= =cage
19− ~| "unexpected poke to {<dap.bowl>} with mark {<p.cage>}"
20− !!
21−::
22−++ on-watch
23− |= =path
24− ~| "unexpected subscription to {<dap.bowl>} on path {<path>}"
25− !!
26−::
27−++ on-leave
28− |= path
29− `agent
30−::
31−++ on-peek
32− |= =path
33− ~| "unexpected scry into {<dap.bowl>} on path {<path>}"
34− !!
35−::
36−++ on-agent
37− |= [=wire =sign:agent:gall]
38− ^- (quip card:agent:gall _agent)
39− ?- -.sign
40− %poke-ack
41− ?~ p.sign
42− `agent
43− %- (slog leaf+"poke failed from {<dap.bowl>} on wire {<wire>}" u.p.sign)
44− `agent
45− ::
46− %watch-ack
47− ?~ p.sign
48− `agent
49− =/ =tank leaf+"subscribe failed from {<dap.bowl>} on wire {<wire>}"
50− %- (slog tank u.p.sign)
51− `agent
52− ::
53− %kick `agent
54− %fact
55− ~| "unexpected subscription update to {<dap.bowl>} on wire {<wire>}"
56− ~| "with mark {<p.cage.sign>}"
57− !!
58− ==
59−::
60−++ on-arvo
61− |= [=wire =sign-arvo]
62− ~| "unexpected system response {<-.sign-arvo>} to {<dap.bowl>} on wire {<wire>}"
63− !!
64−::
65−++ on-fail
66− |= [=term =tang]
67− %- (slog leaf+"error in {<dap.bowl>}" >term< tang)
68− `agent
69−--
example/urbit/lib/docket.hoondeleted−223
@@ -1,223 +0,0 @@
1−/- *docket
2−|%
3−::
4−++ mime
5− |%
6− +$ draft
7− $: title=(unit @t)
8− info=(unit @t)
9− color=(unit @ux)
10− glob-http=(unit [=url hash=@uvH])
11− glob-ames=(unit [=ship hash=@uvH])
12− base=(unit term)
13− site=(unit path)
14− image=(unit url)
15− version=(unit version)
16− website=(unit url)
17− license=(unit cord)
18− ==
19− ::
20− ++ finalize
21− |= =draft
22− ^- (unit docket)
23− ?~ title.draft ~
24− ?~ info.draft ~
25− ?~ color.draft ~
26− ?~ version.draft ~
27− ?~ website.draft ~
28− ?~ license.draft ~
29− =/ href=(unit href)
30− ?^ site.draft `[%site u.site.draft]
31− ?~ base.draft ~
32− ?^ glob-http.draft
33− `[%glob u.base hash.u.glob-http %http url.u.glob-http]:draft
34− ?~ glob-ames.draft
35− ~
36− `[%glob u.base hash.u.glob-ames %ames ship.u.glob-ames]:draft
37− ?~ href ~
38− =, draft
39− :- ~
40− :* %1
41− u.title
42− u.info
43− u.color
44− u.href
45− image
46− u.version
47− u.website
48− u.license
49− ==
50− ::
51− ++ from-clauses
52− =| =draft
53− |= cls=(list clause)
54− ^- (unit docket)
55− =* loop $
56− ?~ cls (finalize draft)
57− =* clause i.cls
58− =. draft
59− ?- -.clause
60− %title draft(title `title.clause)
61− %info draft(info `info.clause)
62− %color draft(color `color.clause)
63− %glob-http draft(glob-http `[url hash]:clause)
64− %glob-ames draft(glob-ames `[ship hash]:clause)
65− %base draft(base `base.clause)
66− %site draft(site `path.clause)
67− %image draft(image `url.clause)
68− %version draft(version `version.clause)
69− %website draft(website `website.clause)
70− %license draft(license `license.clause)
71− ==
72− loop(cls t.cls)
73− ::
74− ++ to-clauses
75− |= d=docket
76− ^- (list clause)
77− %- zing
78− :~ :~ title+title.d
79− info+info.d
80− color+color.d
81− version+version.d
82− website+website.d
83− license+license.d
84− ==
85− ?~ image.d ~ ~[image+u.image.d]
86− ?: ?=(%site -.href.d) ~[site+path.href.d]
87− =/ ref=glob-reference glob-reference.href.d
88− :~ base+base.href.d
89− ?- -.location.ref
90− %http [%glob-http url.location.ref hash.ref]
91− %ames [%glob-ames ship.location.ref hash.ref]
92− == == ==
93− ::
94− ++ spit-clause
95− |= =clause
96− ^- tape
97− %+ weld " {(trip -.clause)}+"
98− ?+ -.clause "'{(trip +.clause)}'"
99− %color (scow %ux color.clause)
100− %site (spud path.clause)
101− ::
102− %glob-http
103− "['{(trip url.clause)}' {(scow %uv hash.clause)}]"
104− ::
105− %glob-ames
106− "[{(scow %p ship.clause)} {(scow %uv hash.clause)}]"
107− ::
108− %version
109− =, version.clause
110− "[{(scow %ud major)} {(scow %ud minor)} {(scow %ud patch)}]"
111− ==
112− ::
113− ++ spit-docket
114− |= dock=docket
115− ^- tape
116− ;: welp
117− ":~\0a"
118− `tape`(zing (join "\0a" (turn (to-clauses dock) spit-clause)))
119− "\0a=="
120− ==
121− --
122−::
123−++ enjs
124− =, enjs:format
125− |%
126− ::
127− ++ charge-update
128− |= u=^charge-update
129− ^- json
130− %+ frond -.u
131− ^- json
132− ?- -.u
133− %del-charge s+desk.u
134− ::
135− %initial
136− %- pairs
137− %+ turn ~(tap by initial.u)
138− |=([=desk c=^charge] [desk (charge c)])
139− ::
140− %add-charge
141− %- pairs
142− :~ desk+s+desk.u
143− charge+(charge charge.u)
144− ==
145− ==
146− ::
147− ++ num
148− |= a=@u
149− ^- ^tape
150− =/ p=json (numb a)
151− ?> ?=(%n -.p)
152− (trip p.p)
153− ::
154− ++ version
155− |= v=^version
156− ^- json
157− :- %s
158− %- crip
159− "{(num major.v)}.{(num minor.v)}.{(num patch.v)}"
160− ::
161− ++ merge
162− |= [a=json b=json]
163− ^- json
164− ?> &(?=(%o -.a) ?=(%o -.b))
165− [%o (~(uni by p.a) p.b)]
166− ::
167− ++ href
168− |= h=^href
169− %+ frond -.h
170− ?- -.h
171− %site s+(spat path.h)
172− %glob
173− %- pairs
174− :~ base+s+base.h
175− glob-reference+(glob-reference glob-reference.h)
176− ==
177− ==
178− ::
179− ++ glob-reference
180− |= ref=^glob-reference
181− %- pairs
182− :~ hash+s+(scot %uv hash.ref)
183− location+(glob-location location.ref)
184− ==
185− ::
186− ++ glob-location
187− |= loc=^glob-location
188− ^- json
189− %+ frond -.loc
190− ?- -.loc
191− %http s+url.loc
192− %ames s+(scot %p ship.loc)
193− ==
194− ::
195− ++ charge
196− |= c=^charge
197− %+ merge (docket docket.c)
198− %- pairs
199− :~ chad+(chad chad.c)
200− ==
201− ::
202− ++ docket
203− |= d=^docket
204− ^- json
205− %- pairs
206− :~ title+s+title.d
207− info+s+info.d
208− color+s+(scot %ux color.d)
209− href+(href href.d)
210− image+?~(image.d ~ s+u.image.d)
211− version+(version version.d)
212− license+s+license.d
213− website+s+website.d
214− ==
215− ::
216− ++ chad
217− |= c=^chad
218− %+ frond -.c
219− ?+ -.c ~
220− %hung s+err.c
221− ==
222− --
223−--
example/urbit/lib/journal.hoondeleted−66
@@ -1,66 +0,0 @@
1−/- *journal
2−|%
3−++ dejs-action
4− =, dejs:format
5− |= jon=json
6− ^- action
7− %. jon
8− %- of
9− :~ [%add (ot ~[id+ni txt+so])]
10− [%edit (ot ~[id+ni txt+so])]
11− [%del (ot ~[id+ni])]
12− ==
13−++ enjs-update
14− =, enjs:format
15− |= upd=update
16− ^- json
17− |^
18− ?+ -.q.upd (logged upd)
19− %jrnl
20− %- pairs
21− :~ ['time' (numb p.upd)]
22− ['entries' a+(turn list.q.upd entry)]
23− ==
24− ::
25− %logs
26− %- pairs
27− :~ ['time' (numb p.upd)]
28− ['logs' a+(turn list.q.upd logged)]
29− ==
30− ==
31− ++ entry
32− |= ent=^entry
33− ^- json
34− %- pairs
35− :~ ['id' (numb id.ent)]
36− ['txt' s+txt.ent]
37− ==
38− ++ logged
39− |= lgd=^logged
40− ^- json
41− ?- -.q.lgd
42− %add
43− %- pairs
44− :~ ['time' (numb p.lgd)]
45− :- 'add'
46− %- pairs
47− :~ ['id' (numb id.q.lgd)]
48− ['txt' s+txt.q.lgd]
49− == ==
50− %edit
51− %- pairs
52− :~ ['time' (numb p.lgd)]
53− :- 'edit'
54− %- pairs
55− :~ ['id' (numb id.q.lgd)]
56− ['txt' s+txt.q.lgd]
57− == ==
58− %del
59− %- pairs
60− :~ ['time' (numb p.lgd)]
61− :- 'del'
62− (frond 'id' (numb id.q.lgd))
63− ==
64− ==
65− --
66−--
example/urbit/lib/noun-diff.hoondeleted−227
@@ -1,227 +0,0 @@
1−=<
2−|%
3− ++ diff
4− |= [old=* new=*]
5− ^- patch
6− =/ del (extract-del (oracle old new) old)
7− =/ ins (extract-ins (oracle old new) new)
8− =/ allowed-holes (~(int in (find-del-holes del)) (find-ins-holes ins))
9− =. del (filter-del-holes allowed-holes del)
10− =/ ins (filter-ins-holes allowed-holes ins)
11− =/ closed-patch (closure (gcp [del ins]))
12− ?> =(& +.closed-patch)
13− -.closed-patch
14− ++ apply
15− |= [patch=_id noun=*]
16− ?- -.patch
17− %diff
18− =/ var-map (del del.patch noun)
19− (ins ins.patch var-map)
20− %cell
21− ?> ?=(^ noun)
22− [$(patch lhs.patch, noun -.noun) $(patch rhs.patch, noun +.noun)]
23− ==
24− ++ id
25− ^- patch
26− [%diff [%hole ~] [%hole ~]]
27− +$ patch
28− $%
29− [%cell lhs=patch rhs=patch]
30− [%diff ^diff]
31− ==
32−--
33−::
34−|%
35− +$ del-diff
36− $%
37− [%hole @]
38− [%cell lhs=del-diff rhs=del-diff]
39− [%ignore ~]
40− ==
41− +$ ins-diff
42− $%
43− [%hole @ original=*]
44− [%cell lhs=ins-diff rhs=ins-diff]
45− [%atom @]
46− ==
47− +$ final-ins-diff
48− $%
49− [%hole @]
50− [%cell lhs=final-ins-diff rhs=final-ins-diff]
51− [%atom @]
52− ==
53− +$ diff [del=del-diff ins=final-ins-diff]
54− +$ patch
55− $%
56− [%cell lhs=patch rhs=patch]
57− [%diff diff]
58− ==
59− ++ insify-noun
60− |= noun=*
61− ^- final-ins-diff
62− ?- noun
63− ^ [%cell $(noun -.noun) $(noun +.noun)]
64− @ [%atom noun]
65− ==
66− ++ empty-set (silt `(list @)`~)
67− ++ find-del-holes
68− |= diff=del-diff
69− ~+
70− ^- (set @)
71− ?- -.diff
72− %hole (silt ~[+.diff])
73− %cell
74− (~(uni in $(diff lhs.diff)) $(diff rhs.diff))
75− %ignore empty-set
76− ==
77− ++ find-final-ins-holes
78− |= diff=final-ins-diff
79− ~+
80− ^- (set @)
81− ?- -.diff
82− %hole (silt ~[+.diff])
83− %cell
84− (~(uni in $(diff lhs.diff)) $(diff rhs.diff))
85− %atom empty-set
86− ==
87− ++ find-ins-holes
88− |= diff=ins-diff
89− ~+
90− ^- (set @)
91− ?- -.diff
92− %hole (silt ~[+<.diff])
93− %cell
94− (~(uni in $(diff lhs.diff)) $(diff rhs.diff))
95− %atom empty-set
96− ==
97− ++ filter-del-holes
98− |= [allowed-holes=(set @) diff=del-diff]
99− ^- del-diff
100− ?: ?=(%ignore -.diff) diff
101− ?- -.diff
102− %hole
103− ?: (~(has in allowed-holes) +.diff) diff
104− [%ignore ~]
105− %cell [%cell $(diff +<.diff) $(diff +>.diff)]
106− ==
107− ++ filter-ins-holes
108− |= [allowed-holes=(set @) diff=ins-diff]
109− ^- final-ins-diff
110− ?- -.diff
111− %hole
112− ?: (~(has in allowed-holes) +<.diff) [%hole +<.diff]
113− (insify-noun original:diff)
114− %cell [%cell $(diff +<.diff) $(diff +>.diff)]
115− %atom diff
116− ==
117− ++ gcp
118− |= diff=diff
119− ^- patch
120− ?- -.ins.diff
121− %atom
122− [%diff diff]
123− %cell
124− ?: ?=(%cell -.del.diff)
125− [%cell $(diff [+<.del.diff +<.ins.diff]) $(diff [+>.del.diff +>.ins.diff])]
126− [%diff diff]
127− %hole
128− [%diff diff]
129− ==
130− ++ closure
131− |= =patch
132− ^- [^patch ?]
133− ?- -.patch
134− %diff
135− =/ del-holes (find-del-holes del:patch)
136− =/ ins-holes (find-final-ins-holes ins:patch)
137− =/ difference (~(dif in ins-holes) del-holes)
138− [patch =(difference empty-set)]
139− %cell
140− =/ lhs $(patch lhs:patch)
141− =/ rhs $(patch rhs:patch)
142− ?: ?&(+.lhs +.rhs) [[%cell -.lhs -.rhs] &]
143− $(patch (pull-diff [%cell -.lhs -.rhs]))
144− ==
145− ++ pull-diff
146− |= =patch
147− ^- [%diff del=del-diff ins=final-ins-diff]
148− ?- -.patch
149− %diff patch
150− %cell
151− =/ pulled-lhs $(patch lhs:patch)
152− =/ pulled-rhs $(patch rhs:patch)
153− :+
154− %diff
155− [%cell del:pulled-lhs del:pulled-rhs]
156− [%cell ins:pulled-lhs ins:pulled-rhs]
157− ==
158− ++ is-subtree
159− |= [tree=* subtree=*]
160− ~+
161− ^- ?
162− ?: =(tree subtree) &
163− ?@ tree |
164− ?|
165− (is-subtree -.tree subtree)
166− (is-subtree +.tree subtree)
167− ==
168− ++ oracle
169− |= [a=* b=*]
170− |= subtree=*
171− ^- (unit @)
172− ?:
173− ?&
174− (is-subtree a subtree)
175− (is-subtree b subtree)
176− ==
177− `(mug subtree)
178− ~
179− ++ extract-del
180− |= [oracle=$-(* (unit @)) subtree=*]
181− ~+
182− ^- del-diff
183− =/ hash (oracle subtree)
184− ?^ hash [%hole +.hash]
185− ?@ subtree [%ignore ~]
186− [%cell (extract-del oracle -.subtree) (extract-del oracle +.subtree)]
187− ++ extract-ins
188− |= [oracle=$-(* (unit @)) subtree=*]
189− ~+
190− ^- ins-diff
191− =/ hash (oracle subtree)
192− ?^ hash [%hole +.hash subtree]
193− ?@ subtree [%atom subtree]
194− [%cell (extract-ins oracle -.subtree) (extract-ins oracle +.subtree)]
195− ++ ins
196− |= [diff=final-ins-diff var-map=(map @ *)]
197− ^- *
198− ?- -.diff
199− %atom
200− +.diff
201− %cell
202− [$(diff +<.diff) $(diff +>.diff)]
203− %hole
204− (~(got by var-map) +.diff)
205− ==
206− ++ del
207− |= [diff=del-diff noun=*]
208− ^- (map @ *)
209− |^ (go diff noun ((map @ *) ~))
210− ++ go
211− |= [diff=del-diff noun=* var-map=(map @ *)]
212− ^- (map @ *)
213− ?- -.diff
214− %ignore var-map
215− %hole
216− =/ subtree (~(get by var-map) +.diff)
217− ?~ subtree (~(put by var-map) +.diff noun)
218− ?> =(+.subtree noun)
219− var-map
220− %cell
221− ?> ?=(^ noun)
222− =/ lhs-var-map $(diff +<.diff, noun -.noun)
223− =/ rhs-var-map $(diff +>.diff, noun +.noun, var-map lhs-var-map)
224− rhs-var-map
225− ==
226− --
227−--
example/urbit/lib/sink.hoondeleted−26
@@ -1,26 +0,0 @@
1−/+ noun-diff
2−|%
3−++ clog
4− |$ [stut]
5− $%
6− [%flush stut]
7− [%drain patch:noun-diff]
8− ==
9−++ sink
10− |* pats=(list path)
11− |* stat=*
12− |@
13− ++ sync
14− |= [stat=_stat]
15− ^- [card:agent:gall _..sync]
16− =/ dif
17− %+ diff:noun-diff ^stat stat
18− :-
19− [%give %fact pats %noun !>(^-((clog) [%drain dif]))]
20− ..sync(stat stat)
21− ++ paths pats
22− ++ flush
23− ^- card:agent:gall
24− [%give %fact pats %noun !>(^-((clog) [%flush stat]))]
25− --
26−--
example/urbit/lib/skeleton.hoondeleted−51
@@ -1,51 +0,0 @@
1−:: Similar to default-agent except crashes everywhere
2−^- agent:gall
3−|_ bowl:gall
4−++ on-init
5− ^- (quip card:agent:gall agent:gall)
6− !!
7−::
8−++ on-save
9− ^- vase
10− !!
11−::
12−++ on-load
13− |~ old-state=vase
14− ^- (quip card:agent:gall agent:gall)
15− !!
16−::
17−++ on-poke
18− |~ in-poke-data=cage
19− ^- (quip card:agent:gall agent:gall)
20− !!
21−::
22−++ on-watch
23− |~ path
24− ^- (quip card:agent:gall agent:gall)
25− !!
26−::
27−++ on-leave
28− |~ path
29− ^- (quip card:agent:gall agent:gall)
30− !!
31−::
32−++ on-peek
33− |~ path
34− ^- (unit (unit cage))
35− !!
36−::
37−++ on-agent
38− |~ [wire sign:agent:gall]
39− ^- (quip card:agent:gall agent:gall)
40− !!
41−::
42−++ on-arvo
43− |~ [wire =sign-arvo]
44− ^- (quip card:agent:gall agent:gall)
45− !!
46−::
47−++ on-fail
48− |~ [term tang]
49− ^- (quip card:agent:gall agent:gall)
50− !!
51−--
example/urbit/mar/bill.hoondeleted−34
@@ -1,34 +0,0 @@
1−|_ bil=(list dude:gall)
2−++ grow
3− |%
4− ++ mime `^mime`[/text/x-bill (as-octs:mimes:html hoon)]
5− ++ noun bil
6− ++ hoon
7− ^- @t
8− |^ (crip (of-wall:format (wrap-lines (spit-duz bil))))
9− ::
10− ++ wrap-lines
11− |= taz=wall
12− ^- wall
13− ?~ taz ["~"]~
14− :- (weld ":~ " i.taz)
15− %- snoc :_ "=="
16− (turn t.taz |=(t=tape (weld " " t)))
17− ::
18− ++ spit-duz
19− |= duz=(list dude:gall)
20− ^- wall
21− (turn duz |=(=dude:gall ['%' (trip dude)]))
22− --
23− ++ txt (to-wain:format hoon)
24− --
25−++ grab
26− |%
27− ++ noun (list dude:gall)
28− ++ mime
29− |= [=mite len=@ud tex=@]
30− ~_ tex
31− !<((list dude:gall) (slap !>(~) (ream tex)))
32− --
33−++ grad %noun
34−--
example/urbit/mar/docket-0.hoondeleted−25
@@ -1,25 +0,0 @@
1−/+ dock=docket
2−|_ =docket:dock
3−++ grow
4− |%
5− ++ mime
6− ^- ^mime
7− [/text/x-docket (as-octt:mimes:html (spit-docket:mime:dock docket))]
8− ++ noun docket
9− ++ json (docket:enjs:dock docket)
10− --
11−++ grab
12− |%
13− ::
14− ++ mime
15− |= [=mite len=@ud tex=@]
16− ^- docket:dock
17− %- need
18− %- from-clauses:mime:dock
19− !<((list clause:dock) (slap !>(~) (ream tex)))
20−
21− ::
22− ++ noun docket:dock
23− --
24−++ grad %noun
25−--
example/urbit/mar/hoon.hoondeleted−49
@@ -1,49 +0,0 @@
1−:::: /hoon/hoon/mar
2− ::
3−/? 310
4−::
5−=, eyre
6−|_ own=@t
7−::
8−++ grow :: convert to
9− |%
10− ++ mime `^mime`[/text/x-hoon (as-octs:mimes:html own)] :: convert to %mime
11− ++ elem :: convert to %html
12− ;div:pre(urb_codemirror "", mode "hoon"):"{(trip own)}"
13− :: =+ gen-id="src-{<`@ui`(mug own)>}"
14− :: ;div
15− :: ;textarea(id "{gen-id}"):"{(trip own)}"
16− :: ;script:"""
17− :: CodeMirror.fromTextArea(
18− :: window[{<gen-id>}],
19− :: \{lineNumbers:true, readOnly:true}
20− :: )
21− :: """
22− :: ==
23− ++ hymn
24− :: ;html:(head:title:"Source" "+{elem}")
25− ;html
26− ;head
27− ;title:"Source"
28− ;script@"//cdnjs.cloudflare.com/ajax/libs/codemirror/4.3.0/codemirror.js";
29− ;script@"/lib/syntax/hoon.js";
30− ;link(rel "stylesheet", href "//cdnjs.cloudflare.com/ajax/libs/".
31− "codemirror/4.3.0/codemirror.min.css");
32− ;link/"/lib/syntax/codemirror.css"(rel "stylesheet");
33− ==
34− ;body
35− ;textarea#src:"{(trip own)}"
36− ;script:'CodeMirror.fromTextArea(src, {lineNumbers:true, readOnly:true})'
37− ==
38− ==
39− ++ txt
40− (to-wain:format own)
41− --
42−++ grab
43− |% :: convert from
44− ++ mime |=([p=mite q=octs] q.q)
45− ++ noun @t :: clam from %noun
46− ++ txt of-wain:format
47− --
48−++ grad %txt
49−--
example/urbit/mar/jam.hoondeleted−17
@@ -1,17 +0,0 @@
1−::
2−:::: /hoon/jam/mar
3− ::
4−/? 310
5−::
6−=, mimes:html
7−|_ mud=@
8−++ grow
9− |%
10− ++ mime [/application/octet-stream (as-octs mud)]
11− --
12−++ grab
13− |% :: convert from
14− ++ noun @ :: clam from %noun
15− --
16−++ grad %mime
17−--
example/urbit/mar/journal/action.hoondeleted−14
@@ -1,14 +0,0 @@
1−/- *journal
2−/+ *journal
3−|_ act=action
4−++ grow
5− |%
6− ++ noun act
7− --
8−++ grab
9− |%
10− ++ noun action
11− ++ json dejs-action
12− --
13−++ grad %noun
14−--
example/urbit/mar/journal/update.hoondeleted−16
@@ -1,16 +0,0 @@
1−/- *journal
2−/+ *journal
3−|_ upd=update
4−++ grow
5− |%
6− ++ noun upd
7− ++ json (enjs-update upd)
8− ++ jam (^jam upd)
9− --
10−++ grab
11− |%
12− ++ noun update
13− ++ jam cue
14− --
15−++ grad %noun
16−--
example/urbit/mar/json.hoondeleted−26
@@ -1,26 +0,0 @@
1−::
2−:::: /hoon/json/mar
3− ::
4−/? 310
5− ::
6−:::: compute
7− ::
8−=, eyre
9−=, format
10−=, html
11−|_ jon=^json
12−::
13−++ grow :: convert to
14− |%
15− ++ mime [/application/json (as-octs:mimes -:txt)] :: convert to %mime
16− ++ txt [(en:json jon)]~
17− --
18−++ grab
19− |% :: convert from
20− ++ mime |=([p=mite q=octs] (fall (de:json (@t q.q)) *^json))
21− ++ noun ^json :: clam from %noun
22− ++ numb numb:enjs
23− ++ time time:enjs
24− --
25−++ grad %mime
26−--
example/urbit/mar/kelvin.hoondeleted−28
@@ -1,28 +0,0 @@
1−|_ kal=waft:clay
2−++ grow
3− |%
4− ++ mime `^mime`[/text/x-kelvin (as-octs:mimes:html hoon)]
5− ++ noun kal
6− ++ hoon
7− %+ rap 3
8− %+ turn
9− %+ sort
10− ~(tap in (waft-to-wefts:clay kal))
11− |= [a=weft b=weft]
12− ?: =(lal.a lal.b)
13− (gte num.a num.b)
14− (gte lal.a lal.b)
15− |= =weft
16− (rap 3 '[%' (scot %tas lal.weft) ' ' (scot %ud num.weft) ']\0a' ~)
17− ::
18− ++ txt (to-wain:format hoon)
19− --
20−++ grab
21− |%
22− ++ noun waft:clay
23− ++ mime
24− |= [=mite len=@ud tex=@]
25− (cord-to-waft:clay tex)
26− --
27−++ grad %noun
28−--
example/urbit/mar/mime.hoondeleted−32
@@ -1,32 +0,0 @@
1−::
2−:::: /hoon/mime/mar
3− ::
4−/? 310
5−::
6−|_ own=mime
7−++ grow
8− ^?
9− |%
10− ++ jam `@`q.q.own
11− --
12−::
13−++ grab :: convert from
14− ^?
15− |%
16− ++ noun mime :: clam from %noun
17− ++ tape
18− |=(a=_"" [/application/x-urb-unknown (as-octt:mimes:html a)])
19− --
20−++ grad
21− ^?
22− |%
23− ++ form %mime
24− ++ diff |=(mime +<)
25− ++ pact |=(mime +<)
26− ++ join |=([mime mime] `(unit mime)`~)
27− ++ mash
28− |= [[ship desk mime] [ship desk mime]]
29− ^- mime
30− ~|(%mime-mash !!)
31− --
32−--
example/urbit/mar/noun.hoondeleted−19
@@ -1,19 +0,0 @@
1−::
2−:::: /hoon/noun/mar
3− ::
4−/? 310
5−!:
6−:::: A minimal noun mark
7−|_ non=*
8−++ grab |%
9− ++ noun *
10− --
11−++ grad
12− |%
13− ++ form %noun
14− ++ diff |=(* +<)
15− ++ pact |=(* +<)
16− ++ join |=([* *] *(unit *))
17− ++ mash |=([[ship desk *] [ship desk *]] `*`~|(%noun-mash !!))
18− --
19−--
example/urbit/mar/txt-diff.hoondeleted−16
@@ -1,16 +0,0 @@
1−::
2−:::: /hoon/txt-diff/mar
3− ::
4−/? 310
5−|_ txt-diff=(urge:clay cord)
6−::
7−++ grad %noun
8−++ grow
9− |%
10− ++ noun txt-diff
11− --
12−++ grab :: convert from
13− |%
14− ++ noun (urge:clay cord) :: make from %noun
15− --
16−--
example/urbit/mar/txt.hoondeleted−275
@@ -1,275 +0,0 @@
1−::
2−:::: /hoon/txt/mar
3− ::
4−/? 310
5−::
6−=, clay
7−=, differ
8−=, format
9−=, mimes:html
10−|_ txt=wain
11−::
12−++ grab :: convert from
13− |%
14− ++ mime |=((pair mite octs) (to-wain q.q))
15− ++ noun wain :: clam from %noun
16− --
17−++ grow
18− => v=.
19− |%
20− ++ mime => v [/text/plain (as-octs (of-wain txt))]
21− ++ elem => v ;pre: {(trip (of-wain txt))}
22− --
23−++ grad
24− |%
25− ++ form %txt-diff
26− ++ diff
27− |= tyt=wain
28− ^- (urge cord)
29− (lusk txt tyt (loss txt tyt))
30− ::
31− ++ pact
32− |= dif=(urge cord)
33− ~| [%pacting dif]
34− ^- wain
35− (lurk txt dif)
36− ::
37− ++ join
38− |= [ali=(urge cord) bob=(urge cord)]
39− ^- (unit (urge cord))
40− |^
41− =. ali (clean ali)
42− =. bob (clean bob)
43− |- ^- (unit (urge cord))
44− ?~ ali `bob
45− ?~ bob `ali
46− ?- -.i.ali
47− %&
48− ?- -.i.bob
49− %&
50− ?: =(p.i.ali p.i.bob)
51− %+ bind $(ali t.ali, bob t.bob)
52− |=(cud=(urge cord) [i.ali cud])
53− ?: (gth p.i.ali p.i.bob)
54− %+ bind $(p.i.ali (sub p.i.ali p.i.bob), bob t.bob)
55− |=(cud=(urge cord) [i.bob cud])
56− %+ bind $(ali t.ali, p.i.bob (sub p.i.bob p.i.ali))
57− |=(cud=(urge cord) [i.ali cud])
58− ::
59− %|
60− ?: =(p.i.ali (lent p.i.bob))
61− %+ bind $(ali t.ali, bob t.bob)
62− |=(cud=(urge cord) [i.bob cud])
63− ?: (gth p.i.ali (lent p.i.bob))
64− %+ bind $(p.i.ali (sub p.i.ali (lent p.i.bob)), bob t.bob)
65− |=(cud=(urge cord) [i.bob cud])
66− ~
67− ==
68− ::
69− %|
70− ?- -.i.bob
71− %|
72− ?. =(i.ali i.bob)
73− ~
74− %+ bind $(ali t.ali, bob t.bob)
75− |=(cud=(urge cord) [i.ali cud])
76− ::
77− %&
78− ?: =(p.i.bob (lent p.i.ali))
79− %+ bind $(ali t.ali, bob t.bob)
80− |=(cud=(urge cord) [i.ali cud])
81− ?: (gth p.i.bob (lent p.i.ali))
82− %+ bind $(ali t.ali, p.i.bob (sub p.i.bob (lent p.i.ali)))
83− |=(cud=(urge cord) [i.ali cud])
84− ~
85− ==
86− ==
87− ++ clean :: clean
88− |= wig=(urge cord)
89− ^- (urge cord)
90− ?~ wig ~
91− ?~ t.wig wig
92− ?: ?=(%& -.i.wig)
93− ?: ?=(%& -.i.t.wig)
94− $(wig [[%& (add p.i.wig p.i.t.wig)] t.t.wig])
95− [i.wig $(wig t.wig)]
96− ?: ?=(%| -.i.t.wig)
97− $(wig [[%| (welp p.i.wig p.i.t.wig) (welp q.i.wig q.i.t.wig)] t.t.wig])
98− [i.wig $(wig t.wig)]
99− --
100− ::
101− ++ mash
102− |= $: [als=ship ald=desk ali=(urge cord)]
103− [bos=ship bod=desk bob=(urge cord)]
104− ==
105− ^- (urge cord)
106− |^
107− =. ali (clean ali)
108− =. bob (clean bob)
109− |- ^- (urge cord)
110− ?~ ali bob
111− ?~ bob ali
112− ?- -.i.ali
113− %&
114− ?- -.i.bob
115− %&
116− ?: =(p.i.ali p.i.bob)
117− [i.ali $(ali t.ali, bob t.bob)]
118− ?: (gth p.i.ali p.i.bob)
119− [i.bob $(p.i.ali (sub p.i.ali p.i.bob), bob t.bob)]
120− [i.ali $(ali t.ali, p.i.bob (sub p.i.bob p.i.ali))]
121− ::
122− %|
123− ?: =(p.i.ali (lent p.i.bob))
124− [i.bob $(ali t.ali, bob t.bob)]
125− ?: (gth p.i.ali (lent p.i.bob))
126− [i.bob $(p.i.ali (sub p.i.ali (lent p.i.bob)), bob t.bob)]
127− =/ [fic=(unce cord) ali=(urge cord) bob=(urge cord)]
128− (resolve ali bob)
129− [fic $(ali ali, bob bob)]
130− :: ~ :: here, alice is good for a while, but not for the whole
131− == :: length of bob's changes
132− ::
133− %|
134− ?- -.i.bob
135− %|
136− =/ [fic=(unce cord) ali=(urge cord) bob=(urge cord)]
137− (resolve ali bob)
138− [fic $(ali ali, bob bob)]
139− ::
140− %&
141− ?: =(p.i.bob (lent p.i.ali))
142− [i.ali $(ali t.ali, bob t.bob)]
143− ?: (gth p.i.bob (lent p.i.ali))
144− [i.ali $(ali t.ali, p.i.bob (sub p.i.bob (lent p.i.ali)))]
145− =/ [fic=(unce cord) ali=(urge cord) bob=(urge cord)]
146− (resolve ali bob)
147− [fic $(ali ali, bob bob)]
148− ==
149− ==
150− ::
151− ++ annotate :: annotate conflict
152− |= $: ali=(list @t)
153− bob=(list @t)
154− bas=(list @t)
155− ==
156− ^- (list @t)
157− %- zing
158− ^- (list (list @t))
159− %- flop
160− ^- (list (list @t))
161− :- :_ ~
162− %^ cat 3 '<<<<<<<<<<<<'
163− %^ cat 3 ' '
164− %^ cat 3 `@t`(scot %p bos)
165− %^ cat 3 '/'
166− bod
167−
168− :- bob
169− :- ~['------------']
170− :- bas
171− :- ~['++++++++++++']
172− :- ali
173− :- :_ ~
174− %^ cat 3 '>>>>>>>>>>>>'
175− %^ cat 3 ' '
176− %^ cat 3 `@t`(scot %p als)
177− %^ cat 3 '/'
178− ald
179− ~
180− ::
181− ++ clean :: clean
182− |= wig=(urge cord)
183− ^- (urge cord)
184− ?~ wig ~
185− ?~ t.wig wig
186− ?: ?=(%& -.i.wig)
187− ?: ?=(%& -.i.t.wig)
188− $(wig [[%& (add p.i.wig p.i.t.wig)] t.t.wig])
189− [i.wig $(wig t.wig)]
190− ?: ?=(%| -.i.t.wig)
191− $(wig [[%| (welp p.i.wig p.i.t.wig) (welp q.i.wig q.i.t.wig)] t.t.wig])
192− [i.wig $(wig t.wig)]
193− ::
194− ++ resolve
195− |= [ali=(urge cord) bob=(urge cord)]
196− ^- [fic=[%| p=(list cord) q=(list cord)] ali=(urge cord) bob=(urge cord)]
197− =- [[%| bac (annotate alc boc bac)] ali bob]
198− |- ^- $: $: bac=(list cord)
199− alc=(list cord)
200− boc=(list cord)
201− ==
202− ali=(urge cord)
203− bob=(urge cord)
204− ==
205− ?~ ali [[~ ~ ~] ali bob]
206− ?~ bob [[~ ~ ~] ali bob]
207− ?- -.i.ali
208− %&
209− ?- -.i.bob
210− %& [[~ ~ ~] ali bob] :: no conflict
211− %|
212− =+ lob=(lent p.i.bob)
213− ?: =(lob p.i.ali)
214− [[p.i.bob p.i.bob q.i.bob] t.ali t.bob]
215− ?: (lth lob p.i.ali)
216− [[p.i.bob p.i.bob q.i.bob] [[%& (sub p.i.ali lob)] t.ali] t.bob]
217− =+ wat=(scag (sub lob p.i.ali) p.i.bob)
218− =+ ^= res
219− %= $
220− ali t.ali
221− bob [[%| (scag (sub lob p.i.ali) p.i.bob) ~] t.bob]
222− ==
223− :* :* (welp bac.res wat)
224− (welp alc.res wat)
225− (welp boc.res q.i.bob)
226− ==
227− ali.res
228− bob.res
229− ==
230− ==
231− ::
232− %|
233− ?- -.i.bob
234− %&
235− =+ loa=(lent p.i.ali)
236− ?: =(loa p.i.bob)
237− [[p.i.ali q.i.ali p.i.ali] t.ali t.bob]
238− ?: (lth loa p.i.bob)
239− [[p.i.ali q.i.ali p.i.ali] t.ali [[%& (sub p.i.bob loa)] t.bob]]
240− =+ wat=(slag (sub loa p.i.bob) p.i.ali)
241− =+ ^= res
242− %= $
243− ali [[%| (scag (sub loa p.i.bob) p.i.ali) ~] t.ali]
244− bob t.bob
245− ==
246− :* :* (welp bac.res wat)
247− (welp alc.res q.i.ali)
248− (welp boc.res wat)
249− ==
250− ali.res
251− bob.res
252− ==
253− ::
254− %|
255− =+ loa=(lent p.i.ali)
256− =+ lob=(lent p.i.bob)
257− ?: =(loa lob)
258− [[p.i.ali q.i.ali q.i.bob] t.ali t.bob]
259− =+ ^= res
260− ?: (gth loa lob)
261− $(ali [[%| (scag (sub loa lob) p.i.ali) ~] t.ali], bob t.bob)
262− ~& [%scagging loa=loa pibob=p.i.bob slag=(scag loa p.i.bob)]
263− $(ali t.ali, bob [[%| (scag (sub lob loa) p.i.bob) ~] t.bob])
264− :* :* (welp bac.res ?:((gth loa lob) p.i.bob p.i.ali))
265− (welp alc.res q.i.ali)
266− (welp boc.res q.i.bob)
267− ==
268− ali.res
269− bob.res
270− ==
271− ==
272− ==
273− --
274− --
275−--
example/urbit/sur/docket.hoondeleted−82
@@ -1,82 +0,0 @@
1−|%
2−::
3−+$ version
4− [major=@ud minor=@ud patch=@ud]
5−::
6−+$ glob (map path mime)
7−::
8−+$ url cord
9−:: $glob-location: How to retrieve a glob
10−::
11−+$ glob-reference
12− [hash=@uvH location=glob-location]
13−::
14−+$ glob-location
15− $% [%http =url]
16− [%ames =ship]
17− ==
18−:: $href: Where a tile links to
19−::
20−+$ href
21− $% [%glob base=term =glob-reference]
22− [%site =path]
23− ==
24−:: $chad: State of a docket
25−::
26−+$ chad
27− $~ [%install ~]
28− $% :: Done
29− [%glob =glob]
30− [%site ~]
31− :: Waiting
32− [%install ~]
33− [%suspend glob=(unit glob)]
34− :: Error
35− [%hung err=cord]
36− ==
37−::
38−:: $charge: A realized $docket
39−::
40−+$ charge
41− $: =docket
42− =chad
43− ==
44−::
45−:: $clause: A key and value, as part of a docket
46−::
47−:: Only used to parse $docket
48−::
49−+$ clause
50− $% [%title title=@t]
51− [%info info=@t]
52− [%color color=@ux]
53− [%glob-http url=cord hash=@uvH]
54− [%glob-ames =ship hash=@uvH]
55− [%image =url]
56− [%site =path]
57− [%base base=term]
58− [%version =version]
59− [%website website=url]
60− [%license license=cord]
61− ==
62−::
63−:: $docket: A description of JS bundles for a desk
64−::
65−+$ docket
66− $: %1
67− title=@t
68− info=@t
69− color=@ux
70− =href
71− image=(unit url)
72− =version
73− website=url
74− license=cord
75− ==
76−::
77−+$ charge-update
78− $% [%initial initial=(map desk charge)]
79− [%add-charge =desk =charge]
80− [%del-charge =desk]
81− ==
82−--
example/urbit/sur/journal.hoondeleted−19
@@ -1,19 +0,0 @@
1−|%
2−+$ id @
3−+$ txt @t
4−+$ action
5− $% [%add =id =txt]
6− [%edit =id =txt]
7− [%del =id]
8− ==
9−+$ entry [=id =txt]
10−+$ logged (pair @ action)
11−+$ update
12− %+ pair @
13− $% action
14− [%jrnl list=(list entry)]
15− [%logs list=(list logged)]
16− ==
17−+$ journal ((mop id txt) gth)
18−+$ log ((mop @ action) lth)
19−--
example/urbit/sys.kelvindeleted−1
@@ -1 +0,0 @@
1−[%zuse 413]
res/airlock.jpegdeleted

Binary file not shown.

src/BitWriter.elm+5−5
@@ -14,17 +14,17 @@ import Bytes.Encode as BE
1414
1515empty : BitWriter
1616empty =
17− BitWriter { running = Nothing, collected = [], offset = 0 }
17+ BitWriter { running = Nothing, collected = BE.sequence [], offset = 0 }
1818
1919
2020run : BitWriter -> Bytes
2121run (BitWriter { running, collected }) =
2222 case running of
2323 Nothing ->
24− BE.encode (collected |> List.reverse |> BE.sequence)
24+ BE.encode collected
2525
2626 Just { value } ->
27− BE.sequence (BE.unsignedInt8 value :: collected |> List.reverse) |> BE.encode
27+ BE.sequence [ collected, BE.unsignedInt8 value ] |> BE.encode
2828
2929
3030type BitWriter
@@ -35,7 +35,7 @@ type BitWriter
3535 , length : Int
3636 }
3737 , offset : Int
38− , collected : List BE.Encoder
38+ , collected : BE.Encoder
3939 }
4040
4141
@@ -68,7 +68,7 @@ bit b (BitWriter { running, collected, offset }) =
6868 if length == 7 then
6969 BitWriter
7070 { running = Nothing
71− , collected = BE.unsignedInt8 newValue :: collected
71+ , collected = BE.sequence [ collected, BE.unsignedInt8 newValue ]
7272 , offset = newOffset
7373 }
7474
src/Ur.elm+207−94
@@ -1,26 +1,42 @@
1−module Ur exposing (logIn, getShipName, scry, scryTask)
2−
3−{-|
1+module Ur exposing
2+ ( Agent
3+ , Atom
4+ , Mark
5+ , Noun(..)
6+ , Path
7+ , cue
8+ , jam
9+ , logIn
10+ , mat
11+ , rub
12+ )
13+
14+import BitParser as BP exposing (BitParser)
15+import BitWriter as BW exposing (BitWriter)
16+import Bitwise
17+import Bytes exposing (Bytes)
18+import Bytes.Extra as Bytes
19+import Dict exposing (Dict)
20+import Http
21+import List.Extra as List
422
523
6−# Simple requests
24+{-| An Urbit agent (app) name like `journal` or 'groups'.
25+-}
26+type alias Agent =
27+ String
728
8−@docs logIn, getShipName, scry, scryTask
929
30+{-| An Urbit subscription path.
1031-}
11−
12−import Http
13−import Platform exposing (Task)
14−import Task
15−import Ur.Deconstructor as D
16−import Ur.Types exposing (..)
32+type alias Path =
33+ List String
1734
1835
19−{-| Logs into your Urbit at the given root path and password.
36+type alias Mark =
37+ String
2038
21− logIn "http://localhost:8080" "lidlut-tabwed-pillex-ridrup"
2239
23−-}
2440logIn : String -> String -> Cmd (Result Http.Error ())
2541logIn root password =
2642 Http.riskyRequest
@@ -37,83 +53,180 @@ logIn root password =
3753 }
3854
3955
40−{-| Queries the name of the current ship.
41−Return strings like `~zod` or `~racfer-hattes`.
42−
43− getShipName "http://localhost:8080"
44−
45−-}
46−getShipName : String -> Cmd (Result Http.Error Ship)
47−getShipName root =
48− Http.riskyRequest
49− { url = root ++ "/~/name"
50− , method = "GET"
51− , headers = []
52− , timeout = Nothing
53− , tracker = Nothing
54− , body = Http.emptyBody
55− , expect = Http.expectString identity
56− }
57−
58−
59−{-| Scry an agent at some path
60−
61− scry
62− { url = "http://localhost:8080"
63− , agent = "journal"
64− , path = [ "entries", "all" ]
65− , error = Noop
66− , success =
67− D.cell D.ignore
68− (D.cell (D.const D.cord "jrnl")
69− (D.list (D.cell D.bigint D.cord |> D.map (\a b -> ( a, b ))))
70− |> D.map GotListings
71− )
72− }
73−
74−-}
75−scry :
76− { url : String
77− , agent : Agent
78− , path : Path
79− , error : msg
80− , success : D.Deconstructor msg
81− }
82− -> Cmd msg
83−scry args =
84− scryTask args |> Task.perform identity
85−
86−
87−{-| Same as `scry` but returns a `Task` instead of a `Cmd`.
88−-}
89−scryTask :
90− { url : String
91− , agent : Agent
92− , path : Path
93− , error : msg
94− , success : D.Deconstructor msg
95− }
96− -> Task a msg
97−scryTask { url, agent, path, error, success } =
98− Http.riskyTask
99− { method = "GET"
100− , headers = []
101− , url = url ++ "/~/scry/" ++ agent ++ "/" ++ String.join "/" path ++ ".jam"
102− , body = Http.emptyBody
103− , resolver =
104− Http.bytesResolver
105− (\resp ->
106− case resp of
107− Http.GoodStatus_ _ bytes ->
108− case D.runBytes success bytes of
109− Just msg ->
110− Ok msg
111−
112− Nothing ->
113− Ok error
114−
115− _ ->
116− Ok error
117− )
118− , timeout = Nothing
119− }
56+type Noun
57+ = Cell ( Noun, Noun )
58+ | Atom Atom
59+
60+
61+type alias Atom =
62+ Bytes
63+
64+
65+jam : Noun -> Bytes
66+jam n =
67+ BW.run (jamWriter n BW.empty)
68+
69+
70+
71+-- Does not use references because it is complex to implement in Elm and would probably lead
72+-- to poor performance
73+
74+
75+jamWriter : Noun -> BitWriter -> BitWriter
76+jamWriter noun writer =
77+ case noun of
78+ Atom atom ->
79+ writer
80+ |> BW.bit 0
81+ |> mat atom
82+
83+ Cell ( a, b ) ->
84+ writer
85+ |> BW.bit 1
86+ |> BW.bit 0
87+ |> jamWriter a
88+ |> jamWriter b
89+
90+
91+cue : Bytes -> Maybe Noun
92+cue =
93+ BP.run (cueParser Dict.empty) >> Maybe.map Tuple.second
94+
95+
96+cueParser : Dict Int Noun -> BitParser ( Dict Int Noun, Noun )
97+cueParser refs =
98+ BP.getOffset
99+ |> BP.andThen
100+ (\offset ->
101+ BP.bit
102+ |> BP.andThen
103+ (\isAtom ->
104+ if isAtom == 0 then
105+ rub |> BP.map (\a -> ( Dict.insert offset (Atom a) refs, Atom a ))
106+
107+ else
108+ BP.bit
109+ |> BP.andThen
110+ (\isRef ->
111+ if isRef == 0 then
112+ cueParser refs
113+ |> BP.andThen
114+ (\( refs_, a ) ->
115+ cueParser refs_
116+ |> BP.andThen
117+ (\( refs__, b ) ->
118+ let
119+ c =
120+ Cell ( a, b )
121+ in
122+ ( Dict.insert offset c refs__, c )
123+ |> BP.succeed
124+ )
125+ )
126+
127+ else
128+ rub
129+ |> BP.andThen
130+ (\ref ->
131+ case
132+ Dict.get
133+ (Bytes.toByteValues ref
134+ |> List.foldr
135+ (\b acc -> Bitwise.shiftLeftBy 8 acc |> Bitwise.or b)
136+ 0
137+ )
138+ refs
139+ of
140+ Just n ->
141+ BP.succeed ( refs, n )
142+
143+ _ ->
144+ BP.fail
145+ )
146+ )
147+ )
148+ )
149+
150+
151+isSig : Bytes -> Bool
152+isSig bytes =
153+ Bytes.toByteValues bytes |> List.all (\x -> x == 0)
154+
155+
156+mat : Bytes -> BitWriter -> BitWriter
157+mat bytes writer =
158+ if isSig bytes then
159+ writer |> BW.bit 1
160+
161+ else
162+ let
163+ bits =
164+ bytesToBits bytes |> List.dropWhileRight (\x -> x == 0)
165+
166+ lengthBits =
167+ bits |> List.length |> intToBits |> List.reverse |> List.drop 1 |> List.reverse
168+ in
169+ writer
170+ |> BW.bit 0
171+ |> BW.bits (List.repeat (List.length lengthBits) 0)
172+ |> BW.bit 1
173+ |> BW.bits lengthBits
174+ |> BW.bits bits
175+
176+
177+rub : BitParser Bytes
178+rub =
179+ BP.bit
180+ |> BP.andThen
181+ (\zeroBit ->
182+ if zeroBit == 1 then
183+ BP.succeed Bytes.empty
184+
185+ else
186+ let
187+ countZeros n =
188+ BP.bit
189+ |> BP.andThen
190+ (\b ->
191+ if b == 0 then
192+ countZeros (n + 1)
193+
194+ else
195+ BP.succeed n
196+ )
197+ in
198+ countZeros 0
199+ |> BP.andThen
200+ (\lengthOfLength ->
201+ BP.rawBits lengthOfLength
202+ |> BP.andThen
203+ (\preLengthRawBits ->
204+ let
205+ length =
206+ BP.bitsToInt (preLengthRawBits ++ [ 1 ])
207+ in
208+ BP.bits length
209+ )
210+ )
211+ )
212+
213+
214+bytesToBits : Bytes -> List Int
215+bytesToBits bytes =
216+ case
217+ BP.run (BP.rawBits (Bytes.width bytes * 8)) bytes
218+ of
219+ Nothing ->
220+ []
221+
222+ Just bits ->
223+ bits
224+
225+
226+intToBits : Int -> List Int
227+intToBits n =
228+ if n <= 0 then
229+ []
230+
231+ else
232+ Bitwise.and 1 n :: intToBits (Bitwise.shiftRightBy 1 n)
src/Ur/Cmd.elm+10−27
@@ -1,52 +1,35 @@
1−module Ur.Cmd exposing (Cmd, poke, cmd, none, batch)
2−
3−{-| This module is conceptually similar to `Platform.Cmd`, but also allows you to send Urbit requests.
4−
5−@docs Cmd, poke, cmd, none, batch
6−
7−-}
8−
1+module Ur.Cmd exposing
2+ ( Cmd
3+ , batch
4+ , cmd
5+ , none
6+ , poke
7+ )
8+
9+import Ur exposing (Agent, Mark, Noun)
910import Ur.Cmd.Internal
10−import Ur.Types exposing (Agent, Mark, Noun, Ship)
11+import Ur.Phonemic exposing (Ship)
1112
1213
13−{-| Like `Cmd` from `Platform.Cmd`, but for Urbit commands.
14−-}
1514type alias Cmd msg =
1615 List (Ur.Cmd.Internal.Cmd msg)
1716
1817
19−{-| A command that does exactly nothing.
20−-}
2118none : Cmd msg
2219none =
2320 []
2421
2522
26−{-| Sends a %poke to a Gall Agent.
27−
28− poke
29− { ship = "~zod"
30− , agent = "journal"
31− , mark = "journal-action"
32− , noun = C.cell (C.cord "del") (C.bigint id)
33− }
34−
35−-}
3623poke : { ship : Ship, agent : Agent, mark : Mark, noun : Noun } -> Cmd msg
3724poke p =
3825 [ Ur.Cmd.Internal.Poke p ]
3926
4027
41−{-| Turns a `Platform.Cmd` command into a `Ur.Cmd` command.
42−-}
4328cmd : Cmd.Cmd msg -> Cmd msg
4429cmd c =
4530 [ Ur.Cmd.Internal.Cmd c ]
4631
4732
48−{-| Batches multiple commands into one. Similar to `Platform.Cmd.batch`.
49−-}
5033batch : List (Cmd msg) -> Cmd msg
5134batch =
5235 List.concat
src/Ur/Cmd/Internal.elm+2−1
@@ -1,6 +1,7 @@
11module Ur.Cmd.Internal exposing (Cmd(..))
22
3−import Ur.Types exposing (Agent, Mark, Noun, Ship)
3+import Ur exposing (Agent, Mark, Noun)
4+import Ur.Phonemic exposing (Ship)
45
56
67type Cmd msg
src/Ur/Constructor.elm+16−65
@@ -1,58 +1,35 @@
11module Ur.Constructor exposing
2− ( cell, sig, bytes
3− , int, signedInt, bigint
4− , float32, float64
5− , cord, tape
2+ ( Constructor
3+ , bigint
4+ , bytes
5+ , cell
6+ , cord
7+ , float32
8+ , float64
9+ , int
610 , listOf
11+ , sig
12+ , signedInt
13+ , tape
714 )
815
9−{-| Different ways of constructing `Noun` from Elm types.
10−
11−
12−# Primitive constructors
13−
14−@docs cell, sig, bytes
15−
16−
17−# Integers
18−
19−@docs int, signedInt, bigint
20−
21−
22−# Floats
23−
24−@docs float32, float64
25−
26−
27−# String
28−
29−@docs cord, tape
30−
31−
32−# Higher-order constructors
33−
34−@docs listOf
35−
36−-}
37−
3816import BigInt exposing (BigInt)
3917import BigInt.Bytes
4018import Bitwise
4119import Bytes exposing (Bytes, Endianness(..))
4220import Bytes.Encode as BE
43−import Ur.Types exposing (..)
21+import Ur exposing (..)
22+
23+
24+type alias Constructor a =
25+ a -> Noun
4426
4527
46−{-| Constructs a [Cell](https://developers.urbit.org/reference/glossary/cell) from two Nouns.
47−-}
4828cell : Noun -> Noun -> Noun
4929cell a b =
5030 Cell ( a, b )
5131
5232
53−{-| Constructs an `Atom` from an unsigned 32-bit `Int`.
54−If you pass something other than an unsigned 32-bit integer the behaviour is undefined.
55−-}
5633int : Int -> Noun
5734int i =
5835 Atom
@@ -69,15 +46,11 @@ int i =
6946 )
7047
7148
72−{-| Constructs an `Atom` from a `BigInt`.
73−-}
7449bigint : BigInt -> Noun
7550bigint x =
7651 Atom (BigInt.Bytes.encode x)
7752
7853
79−{-| Constructs an `Atom` from a signed `Int`.
80−-}
8154signedInt : Int -> Noun
8255signedInt i =
8356 int
@@ -89,34 +62,21 @@ signedInt i =
8962 )
9063
9164
92−{-| Constructs an `Atom` from `Bytes`.
93−-}
9465bytes : Bytes -> Noun
9566bytes =
9667 Atom
9768
9869
99−{-| Constructs a [`cord`](https://developers.urbit.org/reference/glossary/cord), [`knot`](https://developers.urbit.org/guides/additional/strings#knot) or a [`term`](https://developers.urbit.org/guides/additional/strings#term) from a String.
100−-}
10170cord : String -> Noun
10271cord s =
10372 Atom (BE.encode (BE.string s))
10473
10574
106−{-| Constructs a [`tape`](https://developers.urbit.org/reference/glossary/tape) from a `String`.
107−-}
10875tape : String -> Noun
10976tape s =
11077 String.toList s |> List.map String.fromChar |> listOf cord
11178
11279
113−{-| Constructs a `sig`-terminated list.
114−
115−The first argument is a constructor for the elements of the list.
116−
117−The second argument is the list of values to encode.
118−
119−-}
12080listOf : (a -> Noun) -> List a -> Noun
12181listOf encEl list =
12282 case list of
@@ -127,25 +87,16 @@ listOf encEl list =
12787 cell (encEl x) (listOf encEl xs)
12888
12989
130−{-| The [`sig`](https://developers.urbit.org/reference/glossary/tape) value. Also known as `~`.
131−
132−It is equivalent to `0`.
133−
134−-}
13590sig : Noun
13691sig =
13792 Atom (BE.encode (BE.sequence []))
13893
13994
140−{-| Constructs an `Atom` from a 32-bit float.
141−-}
14295float32 : Float -> Noun
14396float32 f =
14497 Atom (BE.encode (BE.float32 LE f))
14598
14699
147−{-| Constructs an `Atom` from a 64-bit float.
148−-}
149100float64 : Float -> Noun
150101float64 f =
151102 Atom (BE.encode (BE.float64 LE f))
src/Ur/Da.elm+1−11
@@ -1,17 +1,9 @@
11module Ur.Da exposing (Da, posixToDa)
22
3−{-|
4−
5−@docs Da, posixToDa
6−
7−-}
8−
93import BigInt exposing (BigInt)
104import Time exposing (Posix)
115
126
13−{-| Represents a `@da`.
14−-}
157type alias Da =
168 BigInt
179
@@ -26,8 +18,6 @@ second =
2618 BigInt.fromIntString "18446744073709551616" |> Maybe.withDefault (BigInt.fromInt 0)
2719
2820
29−{-| Converts `Posix` to a `@da`.
30−-}
3121posixToDa : Posix -> Da
3222posixToDa p =
33− BigInt.add (BigInt.div (BigInt.mul (BigInt.fromInt (Time.posixToMillis p)) second) (BigInt.fromInt 1000000)) unixEpochStart
23+ BigInt.add (BigInt.div (BigInt.mul (BigInt.fromInt (Time.posixToMillis p)) second) (BigInt.fromInt 1000)) unixEpochStart
src/Ur/Deconstructor.elm+198−293
@@ -1,64 +1,27 @@
11module Ur.Deconstructor exposing
22 ( Deconstructor
3− , run, runBytes
4− , cell, list, oneOf, const
3+ , alt
4+ , bigint
5+ , bytes
6+ , cell
7+ , const
8+ , cord
9+ , float32
10+ , float64
11+ , ignore
12+ , int
13+ , list
14+ , llec
515 , map
6− , int, signedInt, bigint
7− , float32, float64
8− , cord, tape
9− , bytes, sig, ignore, tar, lazy, debug
16+ , oneOf
17+ , run
18+ , runBytes
19+ , sig
20+ , signedInt
21+ , tape
22+ , tar
1023 )
1124
12−{-| This module provides an API to deconstruct `Noun`s into arbitrary Elm data structures.
13−
14−You would parse a `[%edit @ cord]` like this:
15−
16− type alias Edit = {id: Int, text : String}
17−
18− (D.cell (D.const D.cord "edit") (D.cell D.bigint D.cord)) |> D.map (\( (), ( id, txt ) ) -> Edit id txt)
19−
20−@docs Deconstructor
21−
22−
23−# Running a `Deconstructor`
24−
25−@docs run, runBytes
26−
27−
28−# Higher-order `Deconstructor`s
29−
30−@docs cell, list, oneOf, const
31−
32−
33−# Mapping a `Deconstructor`
34−
35−@docs map
36−
37−
38−# Numbers
39−
40−
41−## `Int`a
42−
43−@docs int, signedInt, bigint
44−
45−
46−## `Float`s
47−
48−@docs float32, float64
49−
50−
51−# `String`s
52−
53−@docs cord, tape
54−
55−
56−# Miscellaneous
57−
58−@docs bytes, sig, ignore, tar, lazy, debug
59−
60−-}
61−
6225import BigInt exposing (BigInt)
6326import BigInt.Bytes
6427import Bitwise
@@ -66,74 +29,107 @@ import Bytes exposing (Bytes, Endianness(..))
6629import Bytes.Decode as BD
6730import Bytes.Encode as BE
6831import Bytes.Extra
69−import Ur.Jam exposing (cue, isSig)
70−import Ur.Types exposing (..)
32+import Ur exposing (..)
33+
7134
35+type Deconstructor a b
36+ = Deconstructor (Noun -> a -> Maybe b)
7237
73−{-| A `Noun` deconstructor.
74−-}
75−type alias Deconstructor a =
76− Noun -> Maybe a
7738
39+run : Deconstructor (a -> a) a -> Noun -> Maybe a
40+run (Deconstructor f) noun =
41+ f noun identity
42+
43+
44+runBytes : Deconstructor (a -> a) a -> Bytes -> Maybe a
45+runBytes (Deconstructor f) bs =
46+ cue bs
47+ |> Maybe.andThen
48+ (\noun -> f noun identity)
49+
50+
51+const : Deconstructor (a -> a) a -> a -> Deconstructor c c
52+const (Deconstructor f) value =
53+ Deconstructor
54+ (\noun c ->
55+ case f noun identity of
56+ Just a ->
57+ if a == value then
58+ Just c
59+
60+ else
61+ Nothing
7862
79−{-| Executes a `Deconstructor` on a `Noun`.
80−-}
81−run : Deconstructor a -> Noun -> Maybe a
82−run f noun =
83− f noun
63+ Nothing ->
64+ Nothing
65+ )
8466
8567
86−{-| Executes a deconstructor on a `jam`med `Noun`.
87−-}
88−runBytes : Deconstructor a -> Bytes -> Maybe a
89−runBytes f bs =
90− cue bs |> Maybe.andThen f
68+cord : Deconstructor (String -> a) a
69+cord =
70+ Deconstructor
71+ (\x f ->
72+ case x of
73+ Atom bs ->
74+ BD.decode (BD.string (Bytes.width bs)) bs
75+ |> Maybe.map f
9176
77+ Cell _ ->
78+ Nothing
79+ )
9280
93−{-| Asserts that the value should be exactly equal to the second argument.
9481
95−The first argument is a `Deconstructor` for the given type.
82+tape : Deconstructor (String -> a) a
83+tape =
84+ list cord |> fmap String.concat
9685
97−The second argument is the value to compare with.
9886
99−This is useful to match on `term`s when there are multiple possible cases in a head-tagged union.
87+int : Deconstructor (Int -> a) a
88+int =
89+ Deconstructor
90+ (\x f ->
91+ case x of
92+ Atom bs ->
93+ (case Bytes.width bs of
94+ 1 ->
95+ BD.decode BD.unsignedInt8 bs
10096
101−-}
102−const : Deconstructor a -> a -> Deconstructor ()
103−const f value noun =
104− case f noun of
105− Just a ->
106− if a == value then
107− Just ()
97+ 2 ->
98+ BD.decode (BD.unsignedInt16 LE) bs
10899
109− else
110− Nothing
100+ 3 ->
101+ BD.decode (BD.unsignedInt32 LE) (BE.encode (BE.sequence [ BE.bytes bs, BE.unsignedInt8 0 ]))
111102
112− Nothing ->
113− Nothing
103+ 4 ->
104+ BD.decode (BD.unsignedInt32 LE) bs
114105
106+ _ ->
107+ Nothing
108+ )
109+ |> Maybe.map f
115110
116−{-| Extracts a `BigInt`.
117−-}
118−bigint : Deconstructor BigInt
119−bigint x =
120− case x of
121− Atom bs ->
122− BigInt.Bytes.decode bs |> Just
111+ Cell _ ->
112+ Nothing
113+ )
123114
124− Cell _ ->
125− Nothing
126115
116+bigint : Deconstructor (BigInt -> a) a
117+bigint =
118+ Deconstructor
119+ (\x f ->
120+ case x of
121+ Atom bs ->
122+ BigInt.Bytes.decode bs |> f |> Just
127123
128−{-| Extracts a 32-bit signed `Int`.
124+ Cell _ ->
125+ Nothing
126+ )
129127
130−If the `Atom` is larger than 32 bits the the behaviour is undefined.
131128
132−-}
133−signedInt : Deconstructor Int
129+signedInt : Deconstructor (Int -> a) a
134130signedInt =
135131 int
136− |> map
132+ |> fmap
137133 (\i ->
138134 if Bitwise.and 1 i == 1 then
139135 -(Bitwise.shiftRightBy 1 (1 + i))
@@ -143,236 +139,145 @@ signedInt =
143139 )
144140
145141
146−{-| Extracts a 32-bit `Float`.
147−-}
148−float32 : Deconstructor Float
149−float32 x =
150− case x of
151− Atom bs ->
152− BD.decode (BD.float32 LE) bs
153−
154− Cell _ ->
155− Nothing
156−
157−
158−{-| Extracts a 64-bit `Float`.
159−-}
160−float64 : Deconstructor Float
161−float64 x =
162− case x of
163− Atom bs ->
164− BD.decode (BD.float64 LE) bs
165−
166− Cell _ ->
167− Nothing
142+float32 : Deconstructor (Float -> a) a
143+float32 =
144+ Deconstructor
145+ (\x f ->
146+ case x of
147+ Atom bs ->
148+ BD.decode (BD.float32 LE) bs
149+ |> Maybe.map f
168150
151+ Cell _ ->
152+ Nothing
153+ )
169154
170−{-| Extracts the raw `Byte`s of an `Atom`.
171−-}
172−bytes : Deconstructor Bytes
173−bytes n =
174− case n of
175− Atom bs ->
176− Just bs
177155
178− Cell _ ->
179− Nothing
156+float64 : Deconstructor (Float -> a) a
157+float64 =
158+ Deconstructor
159+ (\x f ->
160+ case x of
161+ Atom bs ->
162+ BD.decode (BD.float64 LE) bs
163+ |> Maybe.map f
180164
165+ Cell _ ->
166+ Nothing
167+ )
181168
182−{-| Asserts the the `Atom` should be exactly `sig` (`~`).
183−-}
184−sig : Deconstructor ()
185−sig n =
186− case n of
187− Atom b ->
188− if (Bytes.Extra.toByteValues b |> List.filter (\x -> x /= 0)) == [] then
189− Just ()
190169
191− else
192− Nothing
170+bytes : Deconstructor (Bytes -> a) a
171+bytes =
172+ Deconstructor
173+ (\n f ->
174+ case n of
175+ Atom bs ->
176+ f bs |> Just
193177
194− Cell _ ->
195− Nothing
178+ Cell _ ->
179+ Nothing
180+ )
196181
197182
198−{-| Extracts a sig-terminated list of arbitrary elements.
183+sig : Deconstructor a a
184+sig =
185+ Deconstructor
186+ (\n a ->
187+ case n of
188+ Atom b ->
189+ if (Bytes.Extra.toByteValues b |> List.filter (\x -> x /= 0)) == [] then
190+ Just a
199191
200−The first argument is a `Deconstructor` of the elements of the list.
192+ else
193+ Nothing
201194
202−-}
203−list : Deconstructor a -> Deconstructor (List a)
204−list f n =
205− let
206− go n_ =
207− case n_ of
208− Atom _ ->
209− Just []
195+ Cell _ ->
196+ Nothing
197+ )
210198
211− Cell ( el, tail ) ->
212− Maybe.map2 (\a b -> a :: b) (f el) (go tail)
213− in
214− go n
215199
200+list : Deconstructor (a -> a) a -> Deconstructor (List a -> b) b
201+list (Deconstructor f) =
202+ Deconstructor
203+ (\n g ->
204+ let
205+ go n_ =
206+ case n_ of
207+ Atom _ ->
208+ Just []
216209
217−alt : Deconstructor a -> Deconstructor a -> Deconstructor a
218−alt f g n =
219− case f n of
220− Just x ->
221− Just x
210+ Cell ( el, tail ) ->
211+ Maybe.map2 (\a b -> a :: b) (f el identity) (go tail)
212+ in
213+ go n |> Maybe.map g
214+ )
222215
223− Nothing ->
224− g n
225216
217+alt : Deconstructor a b -> Deconstructor a b -> Deconstructor a b
218+alt (Deconstructor f) (Deconstructor g) =
219+ Deconstructor
220+ (\n a ->
221+ case f n a of
222+ Just x ->
223+ Just x
226224
227−{-| Try to execute all of the `Deconstructor`s in order until one succeeds.
225+ Nothing ->
226+ g n a
227+ )
228228
229−This is especially useful for deconstructing head-tagged unions from Hoon.
230229
231−-}
232−oneOf : List (Deconstructor a) -> Deconstructor a
230+oneOf : List (Deconstructor a b) -> Deconstructor a b
233231oneOf l =
234232 case l of
235233 [] ->
236− always Nothing
234+ Deconstructor (\_ _ -> Nothing)
237235
238236 x :: xs ->
239237 alt x (oneOf xs)
240238
241239
242−{-| Ignore any value.
240+tar : Deconstructor (Noun -> a) a
241+tar =
242+ Deconstructor (\noun f -> Just (f noun))
243243
244−This is useful when you have a value you don't care about. `ignore` allows you to just skip the value.
245244
246−-}
247−ignore : Deconstructor ()
245+ignore : Deconstructor a a
248246ignore =
249− always (Just ())
250−
251−
252−{-| Extracts a [`Cell`](https://developers.urbit.org/reference/glossary/cell) (pair) of two arbitrary values.
253−
254−Accepts two arbitrary `Deconstructor`s that form a Cell.
255−
256−-}
257−cell : Deconstructor a -> Deconstructor b -> Deconstructor ( a, b )
258−cell l r noun =
259− case noun of
260− Cell ( lhs, rhs ) ->
261− l lhs |> Maybe.andThen (\a -> r rhs |> Maybe.map (\b -> ( a, b )))
262−
263− Atom _ ->
264− Nothing
265−
266−
267−{-| Maps (applies) a function to all of the values deconstructed.
268−
269−This is useful when you want to create a data type with extracted values as fields.
270−
271−-}
272−lazy : (() -> Deconstructor a) -> Deconstructor a
273−lazy f noun =
274− f () noun
275−
276−
277−{-| Maps over the result of the deconstructor.
278−-}
279−map : (a -> b) -> Deconstructor a -> Deconstructor b
280−map g f noun =
281− f noun |> Maybe.map g
282−
283−
284−{-| Extracts a `cord`.
285−-}
286−cord : Deconstructor String
287−cord x =
288− case x of
289− Atom bs ->
290− BD.decode (BD.string (Bytes.width bs)) bs
291−
292− Cell _ ->
293− Nothing
294−
295−
296−{-| Extracts a `tape`.
297−-}
298−tape : Deconstructor String
299−tape =
300− list cord |> map String.concat
301−
302−
303−{-| Extracts a 32-bit unsigned `Int`.
304−
305−If the `Atom` is larger than 32 bits the the behaviour is undefined.
306−
307−-}
308−int : Deconstructor Int
309−int x =
310− case x of
311− Atom bs ->
312− case Bytes.width bs of
313− 1 ->
314− BD.decode BD.unsignedInt8 bs
315−
316− 2 ->
317− BD.decode (BD.unsignedInt16 LE) bs
247+ Deconstructor (\_ f -> Just f)
318248
319− 3 ->
320− BD.decode (BD.unsignedInt32 LE) (BE.encode (BE.sequence [ BE.bytes bs, BE.unsignedInt8 0 ]))
321249
322− 4 ->
323− BD.decode (BD.unsignedInt32 LE) bs
250+llec : Deconstructor a b -> Deconstructor b c -> Deconstructor a c
251+llec (Deconstructor r) (Deconstructor l) =
252+ Deconstructor
253+ (\noun a ->
254+ case noun of
255+ Cell ( lhs, rhs ) ->
256+ r rhs a |> Maybe.andThen (\b -> l lhs b)
324257
325− _ ->
258+ Atom _ ->
326259 Nothing
260+ )
327261
328− Cell _ ->
329− Nothing
330−
331−
332−{-| Extract the raw `Noun`.
333−
334−Always succeeds.
335−
336−-}
337−tar : Deconstructor Noun
338−tar =
339− Just
340−
341−
342−{-| Debug a deconstructor.
343−If the deconstructor from the second argument fails then the failed nock will be printed to the console.
344−-}
345−debug : (String -> String) -> Deconstructor a -> Deconstructor a
346−debug log f noun =
347− case f noun of
348− Just x ->
349− Just x
350262
351− Nothing ->
352− let
353− _ =
354− log (prettyNoun noun)
355− in
356− Nothing
263+cell : Deconstructor a b -> Deconstructor b c -> Deconstructor a c
264+cell (Deconstructor l) (Deconstructor r) =
265+ Deconstructor
266+ (\noun a ->
267+ case noun of
268+ Cell ( lhs, rhs ) ->
269+ l lhs a |> Maybe.andThen (\b -> r rhs b)
357270
271+ Atom _ ->
272+ Nothing
273+ )
358274
359−prettyNoun : Noun -> String
360−prettyNoun noun =
361− let
362− go isRhs n =
363− case n of
364− Atom a ->
365− if isSig a then
366− "~"
367275
368− else
369− "@"
276+map : a -> Deconstructor a b -> Deconstructor (b -> c) c
277+map a (Deconstructor f) =
278+ Deconstructor (\noun g -> f noun a |> Maybe.map g)
370279
371− Cell ( lhs, rhs ) ->
372− if isRhs then
373− go False lhs ++ " " ++ go True rhs
374280
375− else
376− "[" ++ go False lhs ++ " " ++ go True rhs ++ "]"
377− in
378− go False noun
281+fmap : (a -> b) -> Deconstructor (a -> c) c -> Deconstructor (b -> c) c
282+fmap f (Deconstructor g) =
283+ Deconstructor (\noun h -> g noun (f >> h))
src/Ur/Jam.elmdeleted−193
@@ -1,193 +0,0 @@
1−module Ur.Jam exposing (..)
2−
3−{-|
4−
5−
6−# Encoding and decoding Nouns
7−
8−@docs jam, cue
9−
10−-}
11−
12−import BitParser as BP exposing (BitParser)
13−import BitWriter as BW exposing (BitWriter)
14−import Bitwise
15−import Bytes exposing (Bytes)
16−import Bytes.Extra as Bytes
17−import Dict exposing (Dict)
18−import List.Extra as List
19−import Ur.Types exposing (..)
20−
21−
22−{-| `jam` encodes arbitrary Nouns into an Atom.
23−-}
24−jam : Noun -> Bytes
25−jam n =
26− BW.run (jamWriter n BW.empty)
27−
28−
29−
30−-- Does not use references because it is complex to implement in Elm and would probably lead
31−-- to poor performance
32−
33−
34−jamWriter : Noun -> BitWriter -> BitWriter
35−jamWriter noun writer =
36− case noun of
37− Atom atom ->
38− writer
39− |> BW.bit 0
40− |> mat atom
41−
42− Cell ( a, b ) ->
43− writer
44− |> BW.bit 1
45− |> BW.bit 0
46− |> jamWriter a
47− |> jamWriter b
48−
49−
50−{-| Decodes a `jam`med Noun (Atom) into the original Noun.
51−-}
52−cue : Bytes -> Maybe Noun
53−cue =
54− BP.run (cueParser Dict.empty) >> Maybe.map Tuple.second
55−
56−
57−cueParser : Dict Int Noun -> BitParser ( Dict Int Noun, Noun )
58−cueParser refs =
59− BP.getOffset
60− |> BP.andThen
61− (\offset ->
62− BP.bit
63− |> BP.andThen
64− (\isAtom ->
65− if isAtom == 0 then
66− rub |> BP.map (\a -> ( Dict.insert offset (Atom a) refs, Atom a ))
67−
68− else
69− BP.bit
70− |> BP.andThen
71− (\isRef ->
72− if isRef == 0 then
73− cueParser refs
74− |> BP.andThen
75− (\( refs_, a ) ->
76− cueParser refs_
77− |> BP.andThen
78− (\( refs__, b ) ->
79− let
80− c =
81− Cell ( a, b )
82− in
83− ( Dict.insert offset c refs__, c )
84− |> BP.succeed
85− )
86− )
87−
88− else
89− rub
90− |> BP.andThen
91− (\ref ->
92− case
93− Dict.get
94− (Bytes.toByteValues ref
95− |> List.foldr
96− (\b acc -> Bitwise.shiftLeftBy 8 acc |> Bitwise.or b)
97− 0
98− )
99− refs
100− of
101− Just n ->
102− BP.succeed ( refs, n )
103−
104− _ ->
105− BP.fail
106− )
107− )
108− )
109− )
110−
111−
112−isSig : Bytes -> Bool
113−isSig bytes =
114− Bytes.toByteValues bytes |> List.all (\x -> x == 0)
115−
116−
117−mat : Bytes -> BitWriter -> BitWriter
118−mat bytes writer =
119− if isSig bytes then
120− writer |> BW.bit 1
121−
122− else
123− let
124− bits =
125− bytesToBits bytes |> List.dropWhileRight (\x -> x == 0)
126−
127− lengthBits =
128− bits |> List.length |> intToBits |> List.reverse |> List.drop 1 |> List.reverse
129− in
130− writer
131− |> BW.bit 0
132− |> BW.bits (List.repeat (List.length lengthBits) 0)
133− |> BW.bit 1
134− |> BW.bits lengthBits
135− |> BW.bits bits
136−
137−
138−rub : BitParser Bytes
139−rub =
140− BP.bit
141− |> BP.andThen
142− (\zeroBit ->
143− if zeroBit == 1 then
144− BP.succeed Bytes.empty
145−
146− else
147− let
148− countZeros n =
149− BP.bit
150− |> BP.andThen
151− (\b ->
152− if b == 0 then
153− countZeros (n + 1)
154−
155− else
156− BP.succeed n
157− )
158− in
159− countZeros 0
160− |> BP.andThen
161− (\lengthOfLength ->
162− BP.rawBits lengthOfLength
163− |> BP.andThen
164− (\preLengthRawBits ->
165− let
166− length =
167− BP.bitsToInt (preLengthRawBits ++ [ 1 ])
168− in
169− BP.bits length
170− )
171− )
172− )
173−
174−
175−bytesToBits : Bytes -> List Int
176−bytesToBits bytes =
177− case
178− BP.run (BP.rawBits (Bytes.width bytes * 8)) bytes
179− of
180− Nothing ->
181− []
182−
183− Just bits ->
184− bits
185−
186−
187−intToBits : Int -> List Int
188−intToBits n =
189− if n <= 0 then
190− []
191−
192− else
193− Bitwise.and 1 n :: intToBits (Bitwise.shiftRightBy 1 n)
src/Ur/NounDiff.elmdeleted−115
@@ -1,115 +0,0 @@
1−module Ur.NounDiff exposing (Patch, apply, deconstructPatch)
2−
3−import Bytes.Extra
4−import Dict exposing (Dict)
5−import Ur.Deconstructor as D
6−import Ur.Types exposing (..)
7−
8−
9−type Patch
10− = PatchCell Patch Patch
11− | Diff DelDiff InsDiff
12−
13−
14−deconstructPatch : () -> D.Deconstructor Patch
15−deconstructPatch () =
16− D.oneOf
17− [ D.cell (D.const D.cord "cell")
18− (D.cell
19− (D.lazy deconstructPatch)
20− (D.lazy deconstructPatch)
21− )
22− |> D.map (\( (), ( a, b ) ) -> PatchCell a b)
23− , D.cell (D.const D.cord "diff") (D.cell (D.lazy deconstructDel) (D.lazy deconstructIns))
24− |> D.map (\( (), ( a, b ) ) -> Diff a b)
25− ]
26−
27−
28−apply : Patch -> Noun -> Noun
29−apply patch noun =
30− case ( patch, noun ) of
31− ( PatchCell lhs rhs, Cell ( lhs_, rhs_ ) ) ->
32− Cell ( apply lhs lhs_, apply rhs rhs_ )
33−
34− ( Diff delDiff insDiff, _ ) ->
35− ins insDiff (del delDiff noun)
36−
37− _ ->
38− noun
39−
40−
41−del : DelDiff -> Noun -> Dict Int Noun
42−del diff noun =
43− let
44− go : DelDiff -> Noun -> Dict Int Noun -> Dict Int Noun
45− go diff_ noun_ dict =
46− case ( diff_, noun_ ) of
47− ( Ignore, _ ) ->
48− dict
49−
50− ( DelCell lhsDiff rhsDiff, Cell ( lhs, rhs ) ) ->
51− go lhsDiff lhs (go rhsDiff rhs dict)
52−
53− ( DelHole hole, _ ) ->
54− -- There should be a continuity check here.
55− -- Check that the noun_ is equal to whatever the hole maps to in dict.
56− -- I don't include it for speed and laziness reasons.
57− Dict.insert hole noun_ dict
58−
59− _ ->
60− dict
61− in
62− go diff noun Dict.empty
63−
64−
65−ins : InsDiff -> Dict Int Noun -> Noun
66−ins diff dict =
67− case diff of
68− InsAtom a ->
69− Atom a
70−
71− InsHole hole ->
72− Dict.get hole dict |> Maybe.withDefault (Atom Bytes.Extra.empty)
73−
74− InsCell lhs rhs ->
75− Cell ( ins lhs dict, ins rhs dict )
76−
77−
78−type DelDiff
79− = Ignore
80− | DelHole Int
81− | DelCell DelDiff DelDiff
82−
83−
84−deconstructDel : () -> D.Deconstructor DelDiff
85−deconstructDel () =
86− D.oneOf
87− [ D.cell (D.const D.cord "ignore") D.ignore |> D.map (\( (), () ) -> Ignore)
88− , D.cell (D.const D.cord "hole") D.int |> D.map (\( (), x ) -> DelHole x)
89− , D.cell (D.const D.cord "cell")
90− (D.cell
91− (D.lazy deconstructDel)
92− (D.lazy deconstructDel)
93− )
94− |> D.map (\( (), ( lhs, rhs ) ) -> DelCell lhs rhs)
95− ]
96−
97−
98−type InsDiff
99− = InsAtom Atom
100− | InsHole Int
101− | InsCell InsDiff InsDiff
102−
103−
104−deconstructIns : () -> D.Deconstructor InsDiff
105−deconstructIns () =
106− D.oneOf
107− [ D.cell (D.const D.cord "hole") D.int |> D.map (\( (), x ) -> InsHole x)
108− , D.cell (D.const D.cord "atom") D.bytes |> D.map (\( (), bs ) -> InsAtom bs)
109− , D.cell (D.const D.cord "cell")
110− (D.cell
111− (D.lazy deconstructIns)
112− (D.lazy deconstructIns)
113− )
114− |> D.map (\( (), ( a, b ) ) -> InsCell a b)
115− ]
src/Ur/Phonemic.elm+12−9
@@ -1,19 +1,22 @@
1−module Ur.Phonemic exposing (fromString)
2−
3−{-|
4−
5−@docs fromString
6−
7−-}
1+module Ur.Phonemic exposing (Ship, fromString)
82
93import BigInt.Bytes
104import Bytes.Extra
11−import Ur.Types exposing (Atom, Noun(..), Ship)
5+import Ur exposing (Atom, Noun(..))
126import Urbit.Encoding.Atom exposing (toBigInt)
137import Urbit.Encoding.Phonemic exposing (..)
148
159
16−{-| Converts a ship name like `~zod` into an `Atom`.
10+{-| A ship name like `~zod` or `~racfer-hattes`.
11+
12+Also know as `@p`.
13+
14+-}
15+type alias Ship =
16+ String
17+
18+
19+{-| Converts a string like '~zod' into an Atom.
1720-}
1821fromString : Ship -> Atom
1922fromString s =
src/Ur/Requests.elm+53−7
@@ -1,6 +1,8 @@
11module Ur.Requests exposing
22 ( EventId
33 , UrbitRequest(..)
4+ , scry
5+ , scryTask
46 , send
57 , sendTask
68 , tag
@@ -11,9 +13,8 @@ import Http
1113import Task exposing (Task)
1214import Ur exposing (..)
1315import Ur.Constructor as C
14−import Ur.Jam exposing (jam)
15−import Ur.Phonemic
16−import Ur.Types exposing (..)
16+import Ur.Deconstructor as D
17+import Ur.Phonemic exposing (Ship)
1718import Ur.Uw
1819
1920
@@ -67,7 +68,7 @@ sendTask { url, error, success, requests } =
6768 requests
6869 |> List.map (uncurry toNoun)
6970 |> C.listOf identity
70− |> jam
71+ |> Ur.jam
7172 |> Ur.Uw.encode
7273 |> Http.stringBody "application/x-urb-jam"
7374 , resolver =
@@ -88,23 +89,68 @@ type alias EventId =
8889 Int
8990
9091
92+scry :
93+ { url : String
94+ , agent : Agent
95+ , path : Path
96+ , error : msg
97+ , success : D.Deconstructor (msg -> msg) msg
98+ }
99+ -> Cmd msg
100+scry args =
101+ scryTask args |> Task.perform identity
102+
103+
104+scryTask :
105+ { url : String
106+ , agent : Agent
107+ , path : Path
108+ , error : msg
109+ , success : D.Deconstructor (msg -> msg) msg
110+ }
111+ -> Task a msg
112+scryTask { url, agent, path, error, success } =
113+ Http.riskyTask
114+ { method = "GET"
115+ , headers = []
116+ , url = url ++ "/~/scry/" ++ agent ++ "/" ++ String.join "/" path ++ ".jam"
117+ , body = Http.emptyBody
118+ , resolver =
119+ Http.bytesResolver
120+ (\resp ->
121+ case resp of
122+ Http.GoodStatus_ _ bytes ->
123+ case D.runBytes success bytes of
124+ Just msg ->
125+ Ok msg
126+
127+ Nothing ->
128+ Ok error
129+
130+ _ ->
131+ Ok error
132+ )
133+ , timeout = Nothing
134+ }
135+
136+
91137toNoun : EventId -> UrbitRequest -> Noun
92138toNoun eventId req =
93139 case req of
94140 Subscribe ( ship, app, path ) ->
95141 C.cell (C.cord "subscribe") <|
96142 C.cell (C.int eventId) <|
97− C.cell (Atom (Ur.Phonemic.fromString ship)) <|
143+ C.cell (Ur.Atom (Ur.Phonemic.fromString ship)) <|
98144 C.cell (C.cord app) (C.listOf C.cord path)
99145
100146 Unsubscribe subId ->
101− C.cell (C.cord "unsubscribe") <|
147+ C.cell (C.cord "usubscribe") <|
102148 C.cell (C.int eventId) (C.int subId)
103149
104150 Poke { ship, agent, mark, noun } ->
105151 C.cell (C.cord "poke") <|
106152 C.cell (C.int eventId) <|
107− C.cell (Atom (Ur.Phonemic.fromString ship)) <|
153+ C.cell (Ur.Atom (Ur.Phonemic.fromString ship)) <|
108154 C.cell (C.cord agent) <|
109155 C.cell (C.cord mark) <|
110156 noun
src/Ur/Run.elm+81−216
@@ -1,28 +1,22 @@
1−module Ur.Run exposing (element, document, application, Program, Model, Msg)
2−
3−{-| This module contains functions to run your application with Urbit integration.
4−
5−@docs element, document, application, Program, Model, Msg
6−
7−-}
1+module Ur.Run exposing (Model, Msg, application)
82
93import Browser exposing (Document, UrlRequest)
104import Browser.Navigation as Nav
115import Dict exposing (Dict)
126import Either exposing (Either(..))
13−import Html exposing (Html)
7+import Html
148import Json.Decode as JD
159import Task
1610import Time
11+import Ur exposing (Agent, Path)
1712import Ur.Cmd
1813import Ur.Cmd.Internal
1914import Ur.Constructor as C
2015import Ur.Deconstructor as D
21−import Ur.NounDiff exposing (Patch, deconstructPatch)
16+import Ur.Phonemic exposing (Ship)
2217import Ur.Requests exposing (..)
2318import Ur.Sub
2419import Ur.Sub.Internal
25−import Ur.Types exposing (..)
2620import Ur.Uw
2721import Url exposing (Url)
2822
@@ -31,9 +25,8 @@ type alias SubDict msg =
3125 Dict
3226 -- (ship, agent, path)
3327 ( String, String, List String )
34− { deconstructor : D.Deconstructor msg
28+ { deconstructor : D.Deconstructor (msg -> msg) msg
3529 , number : Int
36− , sink : Bool
3730 }
3831
3932
@@ -41,8 +34,6 @@ type alias Flags =
4134 { uid : String }
4235
4336
44−{-| An Urbit wrapper around your application model.
45−-}
4637type alias Model app msg =
4738 { subscriptions : SubDict msg
4839 , subscriptionIntMapping : Dict Int ( String, String, List String )
@@ -51,12 +42,9 @@ type alias Model app msg =
5142 , eventId : Int
5243 , flags : Flags
5344 , requestsToRetry : List UrbitRequest
54− , sinks : Dict Int Noun
5545 }
5646
5747
58−{-| An Urbit wrapper around your application messages.
59−-}
6048type Msg msg
6149 = AppMsg msg
6250 | EventSourceMsg JD.Value
@@ -67,61 +55,6 @@ type Msg msg
6755 | RetryRequests
6856
6957
70−{-| A wrapper around your application `Program`.
71−-}
72−type alias Program model msg =
73− Platform.Program Flags (Model model msg) (Msg msg)
74−
75−
76−{-| The same as `Browser.element` but with urbit stuff added around it.
77−-}
78−element :
79− { init : ( model, Ur.Cmd.Cmd msg )
80− , view : model -> Html msg
81− , update : msg -> model -> ( model, Ur.Cmd.Cmd msg )
82− , subscriptions : model -> Sub msg
83− , urbitSubscriptions : model -> Ur.Sub.Sub msg
84− , createEventSource : String -> Cmd (Msg msg)
85− , onEventSourceMsg : (JD.Value -> Msg msg) -> Sub (Msg msg)
86− , urbitUrl : model -> String
87− }
88− -> Program model msg
89−element inp =
90− Browser.element
91− { init = init inp inp.init
92− , view = \model -> inp.view model.app |> Html.map AppMsg
93− , update = update inp
94− , subscriptions = subscriptions inp
95− }
96−
97−
98−{-| The same as `Browser.element` but with urbit stuff added around it.
99−-}
100−document :
101− { init : ( model, Ur.Cmd.Cmd msg )
102− , view : model -> Document msg
103− , update : msg -> model -> ( model, Ur.Cmd.Cmd msg )
104− , subscriptions : model -> Sub msg
105− , urbitSubscriptions : model -> Ur.Sub.Sub msg
106− , createEventSource : String -> Cmd (Msg msg)
107− , onEventSourceMsg : (JD.Value -> Msg msg) -> Sub (Msg msg)
108− , urbitUrl : model -> String
109− }
110− -> Program model msg
111−document inp =
112− Browser.document
113− { init = init inp inp.init
114− , view =
115− \model ->
116− inp.view model.app
117− |> (\{ body, title } -> { title = title, body = body |> List.map (Html.map AppMsg) })
118− , update = update inp
119− , subscriptions = subscriptions inp
120− }
121−
122−
123−{-| The same as `Browser.element` but with urbit stuff added around it.
124−-}
12558application :
12659 { init : Url -> Nav.Key -> ( model, Ur.Cmd.Cmd msg )
12760 , view : model -> Document msg
@@ -134,20 +67,66 @@ application :
13467 , onEventSourceMsg : (JD.Value -> Msg msg) -> Sub (Msg msg)
13568 , urbitUrl : model -> String
13669 }
137− -> Program model msg
70+ -> Program Flags (Model model msg) (Msg msg)
13871application inp =
13972 let
140− { view, onUrlRequest, onUrlChange } =
73+ { init, view, onUrlRequest, onUrlChange, onEventSourceMsg } =
14174 inp
14275 in
14376 Browser.application
144− { init = \flags url key -> init inp (inp.init url key) flags
77+ { init =
78+ \flags u key ->
79+ let
80+ ( app, appCmds ) =
81+ init u key
82+
83+ { subscriptions, eventId, subscriptionRequests, subscriptionIntMapping } =
84+ processUrSubs
85+ 0
86+ Dict.empty
87+ (inp.urbitSubscriptions app |> (\(Ur.Sub.Internal.Sub x) -> x))
88+
89+ ( eventId_, cmds, urReqs ) =
90+ processCmd eventId appCmds
91+
92+ url =
93+ inp.urbitUrl app ++ "/~/channel/" ++ flags.uid
94+ in
95+ ( { subscriptions = subscriptions
96+ , subscriptionIntMapping = subscriptionIntMapping
97+ , app = app
98+ , connected = False
99+ , eventId = eventId_
100+ , flags = flags
101+ , requestsToRetry = []
102+ }
103+ , [ cmds
104+ , pureCmd NeedsActivation
105+ , send
106+ { requests = urReqs ++ subscriptionRequests
107+ , url = url
108+ , error = Noop
109+ , success = Noop
110+ }
111+ ]
112+ |> Cmd.batch
113+ )
145114 , view =
146115 \model ->
147116 view model.app
148117 |> (\{ body, title } -> { title = title, body = body |> List.map (Html.map AppMsg) })
149118 , update = update inp
150− , subscriptions = subscriptions inp
119+ , subscriptions =
120+ \model ->
121+ Sub.batch
122+ [ inp.subscriptions model.app |> Sub.map AppMsg
123+ , onEventSourceMsg EventSourceMsg
124+ , if List.isEmpty model.requestsToRetry then
125+ Sub.none
126+
127+ else
128+ Time.every 1000 (always RetryRequests)
129+ ]
151130 , onUrlRequest = \req -> onUrlRequest req |> AppMsg
152131 , onUrlChange = \url -> onUrlChange url |> AppMsg
153132 }
@@ -174,20 +153,20 @@ update inp msg model =
174153 ( appModel, appCmds ) =
175154 inp.update msg_ model.app
176155
177− subsResult =
156+ { subscriptions, eventId, subscriptionRequests, subscriptionIntMapping } =
178157 processUrSubs
179158 model.eventId
180159 model.subscriptions
181− (inp.urbitSubscriptions appModel |> (\(Ur.Sub.Internal.Sub x) -> x))
160+ (inp.urbitSubscriptions model.app |> (\(Ur.Sub.Internal.Sub x) -> x))
182161
183162 ( eventId_, cmds, urReqs ) =
184− processCmd subsResult.eventId appCmds
163+ processCmd eventId appCmds
185164 in
186165 ( { model
187166 | app = appModel
188167 , eventId = eventId_
189− , subscriptions = subsResult.subscriptions
190− , subscriptionIntMapping = model.subscriptionIntMapping |> Dict.union subsResult.subscriptionIntMapping
168+ , subscriptions = subscriptions
169+ , subscriptionIntMapping = model.subscriptionIntMapping |> Dict.union subscriptionIntMapping
191170 }
192171 , Cmd.batch
193172 [ cmds
@@ -198,9 +177,9 @@ update inp msg model =
198177 , requests = urReqs
199178 }
200179 , send
201− { requests = subsResult.subscriptionRequests
180+ { requests = subscriptionRequests
202181 , url = url
203− , error = subsResult.subscriptionRequests |> List.map (\( _, x ) -> x) |> FailedRequest
182+ , error = subscriptionRequests |> List.map (\( _, x ) -> x) |> FailedRequest
204183 , success = Noop
205184 }
206185 ]
@@ -211,10 +190,12 @@ update inp msg model =
211190 Ok string ->
212191 case
213192 D.runBytes
214− (D.cell D.int (D.cell D.cord D.tar))
193+ (D.cell D.int (D.cell D.cord D.tar)
194+ |> D.map (\a b c -> ( a, b, c ))
195+ )
215196 (Ur.Uw.decode string)
216197 of
217− Just ( messageId, ( messageType, rest ) ) ->
198+ Just ( messageId, messageType, rest ) ->
218199 let
219200 ( eventId, ackReqs ) =
220201 tag model.eventId [ Ack messageId ]
@@ -244,51 +225,14 @@ update inp msg model =
244225 Dict.get messageId model.subscriptionIntMapping
245226 |> Maybe.andThen (\key -> Dict.get key model.subscriptions)
246227 of
247− Just { deconstructor, sink } ->
248− if sink then
249− case D.run (D.cell D.ignore (D.cell D.ignore deconstructSink) |> D.map (\( (), ( (), s ) ) -> s)) rest of
250− Just (Flush noun) ->
251− ( { model | sinks = Dict.insert messageId noun model.sinks }
252− , case D.run deconstructor noun of
253− Just subMsg ->
254− pureCmd (AppMsg subMsg)
255−
256− -- Got garbage
257− Nothing ->
258− Cmd.none
259− )
260−
261− Just (Drain patch) ->
262− case Dict.get messageId model.sinks of
263− Just oldNoun ->
264− let
265− newNoun =
266− Ur.NounDiff.apply patch oldNoun
267− in
268− ( { model | sinks = Dict.insert messageId newNoun model.sinks }
269− , case D.run deconstructor newNoun of
270− Just subMsg ->
271− pureCmd (AppMsg subMsg)
272−
273− Nothing ->
274− Cmd.none
275− )
276−
277− Nothing ->
278− ( model, Cmd.none )
279−
280− -- Got garbage
281− Nothing ->
282− ( model, Cmd.none )
283−
284− else
285− case D.run (D.cell D.ignore (D.cell D.ignore deconstructor) |> D.map (\( (), ( (), m ) ) -> m)) rest of
286− Just subMsg ->
287− ( model_, pureCmd (AppMsg subMsg) )
288−
289− -- Got gargbage
290− Nothing ->
291− ( model_, ackCmd )
228+ Just { deconstructor } ->
229+ case D.run (D.cell D.ignore (D.cell D.ignore deconstructor)) rest of
230+ Just subMsg ->
231+ ( model_, pureCmd (AppMsg subMsg) )
232+
233+ -- Got gargbage
234+ Nothing ->
235+ ( model_, ackCmd )
292236
293237 -- Got a fact for a subscription we do not hold
294238 Nothing ->
@@ -313,11 +257,11 @@ update inp msg model =
313257 NeedsActivation ->
314258 let
315259 ( eventId, reqs ) =
316− [ Poke { ship = "", agent = "hood", mark = "helm-hi", noun = C.cord "Opening airlock!" } ]
260+ [ Poke { ship = "~zod", agent = "hood", mark = "helm-hi", noun = C.cord "Opening airlock!" } ]
317261 |> tag model.eventId
318262 in
319263 ( { model | eventId = eventId }
320− , send { url = url, requests = reqs, success = OpenConnection, error = Noop }
264+ , send { url = url, requests = reqs, success = OpenConnection, error = NeedsActivation }
321265 )
322266
323267 Noop ->
@@ -344,19 +288,6 @@ update inp msg model =
344288 )
345289
346290
347−type Sink
348− = Flush Noun
349− | Drain Patch
350−
351−
352−deconstructSink : D.Deconstructor Sink
353−deconstructSink =
354− D.oneOf
355− [ D.cell (D.const D.cord "flush") D.tar |> D.map (\( (), n ) -> Flush n)
356− , D.cell (D.const D.cord "drain") (D.lazy deconstructPatch) |> D.map (\( (), patch ) -> Drain patch)
357− ]
358−
359−
360291processCmd : EventId -> Ur.Cmd.Cmd msg -> ( EventId, Cmd (Msg msg), List ( EventId, UrbitRequest ) )
361292processCmd eventId urCmds =
362293 let
@@ -386,10 +317,10 @@ pureCmd msg =
386317
387318processUrSubs :
388319 EventId
389− -> Dict ( Ship, Agent, Path ) { deconstructor : d, number : EventId, sink : Bool }
390− -> Dict ( Ship, Agent, Path ) { deconstructor : d, sink : Bool }
320+ -> Dict ( Ship, Agent, Path ) { deconstructor : d, number : EventId }
321+ -> Dict ( Ship, Agent, Path ) d
391322 ->
392− { subscriptions : Dict ( Ship, Agent, Path ) { deconstructor : d, number : EventId, sink : Bool }
323+ { subscriptions : Dict ( Ship, Agent, Path ) { deconstructor : d, number : EventId }
393324 , eventId : EventId
394325 , subscriptionRequests : List ( EventId, UrbitRequest )
395326 , subscriptionIntMapping : Dict EventId ( Ship, Agent, Path )
@@ -398,7 +329,7 @@ processUrSubs eventId existingSubscriptions urbitSubs_ =
398329 let
399330 urbitSubs =
400331 urbitSubs_
401− |> Dict.map (\_ { deconstructor, sink } -> { deconstructor = deconstructor, sink = sink })
332+ |> Dict.map (\_ deconstructor -> { deconstructor = deconstructor })
402333
403334 ( eventId_, newSubscriptionActions ) =
404335 Dict.diff urbitSubs existingSubscriptions
@@ -421,11 +352,10 @@ processUrSubs eventId existingSubscriptions urbitSubs_ =
421352 newSubscriptions =
422353 Dict.merge
423354 (\_ _ x -> x)
424− (\key number { deconstructor, sink } ->
355+ (\key number { deconstructor } ->
425356 Dict.insert key
426357 { deconstructor = deconstructor
427358 , number = number
428− , sink = sink
429359 }
430360 )
431361 (\_ _ x -> x)
@@ -443,68 +373,3 @@ processUrSubs eventId existingSubscriptions urbitSubs_ =
443373 , subscriptionRequests =
444374 removedSubscriptionActions ++ (newSubscriptionActions |> List.map (\( id, ( req, _ ) ) -> ( id, req )))
445375 }
446−
447−
448−init :
449− { a | urbitSubscriptions : model -> Ur.Sub.Sub msg, urbitUrl : model -> String }
450− -> ( model, Ur.Cmd.Cmd msg )
451− -> Flags
452− ->
453− ( Model model msg
454− , Cmd (Msg msg)
455− )
456−init inp ( app, appCmds ) flags =
457− let
458− subsResult =
459− processUrSubs
460− 0
461− Dict.empty
462− (inp.urbitSubscriptions app |> (\(Ur.Sub.Internal.Sub x) -> x))
463−
464− ( eventId_, cmds, urReqs ) =
465− processCmd subsResult.eventId appCmds
466−
467− url =
468− inp.urbitUrl app ++ "/~/channel/" ++ flags.uid
469− in
470− ( { subscriptions = subsResult.subscriptions
471− , sinks = Dict.empty
472− , subscriptionIntMapping = subsResult.subscriptionIntMapping
473− , app = app
474− , connected = False
475− , eventId = eventId_
476− , flags = flags
477− , requestsToRetry = []
478− }
479− , [ cmds
480− , pureCmd NeedsActivation
481− , send
482− { requests = urReqs ++ subsResult.subscriptionRequests
483− , url = url
484− , error = Noop
485− , success = Noop
486− }
487− ]
488− |> Cmd.batch
489− )
490−
491−
492−subscriptions :
493− { a | subscriptions : b -> Sub msg, onEventSourceMsg : (JD.Value -> Msg c) -> Sub (Msg msg) }
494− -> { d | app : b, requestsToRetry : List e, connected : Bool }
495− -> Sub (Msg msg)
496−subscriptions inp model =
497− Sub.batch
498− [ inp.subscriptions model.app |> Sub.map AppMsg
499− , inp.onEventSourceMsg EventSourceMsg
500− , if List.isEmpty model.requestsToRetry then
501− Sub.none
502−
503− else
504− Time.every 1000 (always RetryRequests)
505− , if not model.connected then
506− Time.every 10000 (always NeedsActivation)
507−
508− else
509− Sub.none
510− ]
src/Ur/Sub.elm+4−41
@@ -1,61 +1,24 @@
1−module Ur.Sub exposing (Sub, subscribe, none, batch, sink)
2−
3−{-| This module is conceptually similar to `Platform.Sub`, but allows you to subscribe to Urbit channels.
4−
5−@docs Sub, subscribe, none, batch, sink
6−
7−-}
1+module Ur.Sub exposing (Sub, batch, none, subscribe)
82
93import Dict
104import Ur.Deconstructor as D
115import Ur.Sub.Internal
126
137
14−{-| Like `Sub` from `Platform.Sub` but for Urbit subscriptions.
15−-}
168type alias Sub msg =
179 Ur.Sub.Internal.Sub msg
1810
1911
20−{-| Creates an Urbit subscription.
12+subscribe : { ship : String, app : String, path : List String, deconstructor : D.Deconstructor (msg -> msg) msg } -> Sub msg
13+subscribe { ship, app, path, deconstructor } =
14+ Dict.singleton ( ship, app, path ) deconstructor |> Ur.Sub.Internal.Sub
2115
22− subscribe
23− { ship = ship
24− , app = "journal"
25− , path = [ "updates" ]
26− , deconstructor = decodeJournalUpdate |> D.map GotUpdate
27− }
2816
29−-}
30−subscribe : { ship : String, app : String, path : List String, deconstructor : D.Deconstructor msg } -> Sub msg
31−subscribe { ship, app, path, deconstructor } =
32− Dict.singleton ( ship, app, path )
33− { deconstructor = deconstructor
34− , sink = False
35− }
36− |> Ur.Sub.Internal.Sub
37−
38−
39−{-| Creates a %sink subscription.
40−-}
41−sink : { ship : String, app : String, path : List String, deconstructor : D.Deconstructor msg } -> Sub msg
42−sink { ship, app, path, deconstructor } =
43− Dict.singleton ( ship, app, path )
44− { deconstructor = deconstructor
45− , sink = True
46− }
47− |> Ur.Sub.Internal.Sub
48−
49−
50−{-| A subscription that does exactly nothing. (Does not subscribe to anything)
51−-}
5217none : Sub msg
5318none =
5419 Ur.Sub.Internal.Sub Dict.empty
5520
5621
57−{-| Batch multiple subscriptions into one.
58−-}
5922batch : List (Sub msg) -> Sub msg
6023batch subs =
6124 subs |> List.map (\(Ur.Sub.Internal.Sub dict) -> dict) |> List.foldl Dict.union Dict.empty |> Ur.Sub.Internal.Sub
src/Ur/Sub/Internal.elm+3−4
@@ -1,8 +1,9 @@
11module Ur.Sub.Internal exposing (Sub(..))
22
33import Dict exposing (Dict)
4+import Ur exposing (Agent, Path)
45import Ur.Deconstructor as D
5−import Ur.Types exposing (Agent, Path, Ship)
6+import Ur.Phonemic exposing (Ship)
67
78
89type Sub msg
@@ -10,7 +11,5 @@ type Sub msg
1011 (Dict
1112 -- key is (ship, app, path)
1213 ( Ship, Agent, Path )
13− { deconstructor : D.Deconstructor msg
14− , sink : Bool
15− }
14+ (D.Deconstructor (msg -> msg) msg)
1615 )
src/Ur/Types.elmdeleted−60
@@ -1,60 +0,0 @@
1−module Ur.Types exposing
2− ( Noun(..), Atom
3− , Agent, Mark, Path, Ship
4− )
5−
6−{-|
7−
8−
9−# Nouns
10−
11−@docs Noun, Atom
12−
13−
14−# Types
15−
16−@docs Agent, Mark, Path, Ship
17−
18−-}
19−
20−import Bytes exposing (Bytes)
21−
22−
23−{-| An [Urbit agent](https://developers.urbit.org/reference/glossary/agent) (app) name like `journal` or `groups`.
24−-}
25−type alias Agent =
26− String
27−
28−
29−{-| An [Urbit subscription path](https://developers.urbit.org/reference/glossary/path).
30−-}
31−type alias Path =
32− List String
33−
34−
35−{-| An [Urbit mark](https://developers.urbit.org/reference/arvo/clay/marks/marks)
36−-}
37−type alias Mark =
38− String
39−
40−
41−{-| A ship name like `~zod` or `~racfer-hattes`.
42−
43−Also know as `@p`.
44−
45−-}
46−type alias Ship =
47− String
48−
49−
50−{-| An [Urbit Noun](https://developers.urbit.org/reference/glossary/noun).
51−-}
52−type Noun
53− = Cell ( Noun, Noun )
54− | Atom Atom
55−
56−
57−{-| An [Urbit Atom](https://developers.urbit.org/reference/glossary/atom)
58−-}
59−type alias Atom =
60− Bytes
src/Ur/Uw.elm+7−15
@@ -1,11 +1,5 @@
11module Ur.Uw exposing (decode, encode)
22
3−{-| This module works with Urbit base-64 encoded strings aka `@uw`.
4−
5−@docs decode, encode
6−
7−-}
8−
93import BitParser as BP
104import BitWriter as BW
115import Bitwise
@@ -15,7 +9,6 @@ import Dict
159import List.Extra
1610
1711
18−{-| -}
1912decode : String -> Bytes
2013decode string =
2114 if string == "0w0" then
@@ -29,27 +22,26 @@ decode string =
2922 -- 0w
3023 |> List.drop 2
3124
32− go : List Char -> List Int -> BW.BitWriter -> BW.BitWriter
33− go cs append writer =
25+ go : List Char -> BW.BitWriter -> BW.BitWriter
26+ go cs writer =
3427 case cs of
3528 [] ->
36− BW.bits append writer
29+ writer
3730
3831 '.' :: rest ->
39− go rest append writer
32+ go rest writer
4033
4134 c :: rest ->
4235 case Dict.get c charToBits of
4336 Just bits ->
44− go rest (bits ++ append) writer
37+ go rest writer |> BW.bits bits
4538
4639 Nothing ->
47− go rest [] writer
40+ go rest writer
4841 in
49− BW.run (go chars [] BW.empty)
42+ BW.run (go chars BW.empty)
5043
5144
52−{-| -}
5345encode : Bytes -> String
5446encode bytes =
5547 let
tests/Test/Urbit.elm+11−13
@@ -14,8 +14,6 @@ import Test.Utils exposing (..)
1414import Ur exposing (..)
1515import Ur.Constructor as C
1616import Ur.Deconstructor as D
17−import Ur.Jam exposing (cue, jam, mat, rub)
18−import Ur.Types exposing (..)
1917import Ur.Uw
2018
2119
@@ -77,7 +75,7 @@ tests =
7775 Expect.equal
7876 (Just ( 1, 2 ))
7977 (D.runBytes
80− (D.cell D.int D.int)
78+ (D.cell D.int D.int |> D.map Tuple.pair)
8179 (Bytes.fromByteValues [ 0x31, 0x12 ])
8280 )
8381 )
@@ -96,7 +94,7 @@ tests =
9694 Expect.equal
9795 (Just ( 4, [ 1, 2, 3 ] ))
9896 (D.runBytes
99− (D.cell D.int (D.list D.int))
97+ (D.cell D.int (D.list D.int) |> D.map Tuple.pair)
10098 (Bytes.fromByteValues [ 0x61, 0xC6, 0x21, 0x43, 0x0B ])
10199 )
102100 )
@@ -105,7 +103,7 @@ tests =
105103 Expect.equal
106104 (Just ( 8, 11 ))
107105 (D.runBytes
108− (D.cell D.float32 D.float32)
106+ (D.cell D.float32 D.float32 |> D.map Tuple.pair)
109107 (Bytes.fromByteValues [ 0x01, 0x1F, 0x00, 0x00, 0x20, 0x08, 0x7C, 0x00, 0x00, 0x98, 0x20 ])
110108 )
111109 )
@@ -114,7 +112,7 @@ tests =
114112 Expect.equal
115113 (Just ( 8, "hi" ))
116114 (D.runBytes
117− (D.cell D.int D.cord)
115+ (D.cell D.int D.cord |> D.map Tuple.pair)
118116 (Bytes.fromByteValues [ 0x41, 0x10, 0x3C, 0x5A, 0x1A ])
119117 )
120118 )
@@ -123,7 +121,7 @@ tests =
123121 Expect.equal
124122 (Just ( 8, "hi" ))
125123 (D.runBytes
126− (D.cell D.int D.tape)
124+ (D.cell D.int D.tape |> D.map Tuple.pair)
127125 (Bytes.fromByteValues [ 0x41, 0x30, 0x38, 0x3A, 0x78, 0x5A ])
128126 )
129127 )
@@ -134,8 +132,8 @@ tests =
134132 (Just "hi")
135133 (D.runBytes
136134 (D.oneOf
137− [ D.cell (D.const D.cord "tape") D.tape |> D.map (\((), t) -> t)
138− , D.cell (D.const D.cord "cord") D.cord |> D.map (\((), c) -> c)
135+ [ D.cell (D.const D.cord "tape") D.tape
136+ , D.cell (D.const D.cord "cord") D.cord
139137 ]
140138 )
141139 (Bytes.fromByteValues [ 0x01, 0x9F, 0x2E, 0x0C, 0xAE, 0x1C, 0x1C, 0x1D, 0x3C, 0x2D ])
@@ -147,8 +145,8 @@ tests =
147145 (Just "hi")
148146 (D.runBytes
149147 (D.oneOf
150− [ D.cell (D.const D.cord "tape") D.tape |> D.map (\((), t) -> t)
151− , D.cell (D.const D.cord "cord") D.cord |> D.map (\((), c) -> c)
148+ [ D.cell (D.const D.cord "tape") D.tape
149+ , D.cell (D.const D.cord "cord") D.cord
152150 ]
153151 )
154152 (Bytes.fromByteValues [ 0x01, 0x7F, 0xEC, 0x4D, 0x8E, 0x0C, 0x1E, 0x2D, 0x0D ])
@@ -160,7 +158,7 @@ tests =
160158 Expect.equal
161159 (Just ( 8, -8 ))
162160 (D.runBytes
163− (D.cell D.signedInt D.signedInt)
161+ (D.cell D.signedInt D.signedInt |> D.map Tuple.pair)
164162 (Bytes.fromByteValues [ 0xC1, 0x20, 0xE4, 0x01 ])
165163 )
166164 )
@@ -190,7 +188,7 @@ tests =
190188 (\( f, i, ui ) ->
191189 Expect.equal (Just ( f, i, ui ))
192190 (D.run
193− (D.cell D.float64 (D.cell D.signedInt D.int) |> D.map (\(a, (b, c)) -> ( a, b, c )))
191+ (D.cell D.float64 (D.cell D.signedInt D.int) |> D.map (\a b c -> ( a, b, c )))
194192 (C.cell (C.float64 f) (C.cell (C.signedInt i) (C.int ui)))
195193 )
196194 )