Merge pull request #64 from urbit/dev-summit

Dev summit
This commit is contained in:
Liam Fitzgerald 2024-06-25 14:25:52 -04:00 committed by GitHub
commit 622eee6a66
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
359 changed files with 13044 additions and 92401 deletions

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:feaae0eece54db3e92122263706c283674af581d14ffde8a29fb24e1873a35b1 oid sha256:c2ab6607450382e0ec80c7264dad2c72d69672eaf861eb1c24cde5a76921c6a3
size 6453015 size 9972490

View File

@ -3,7 +3,7 @@
flake-utils.url = "github:numtide/flake-utils"; flake-utils.url = "github:numtide/flake-utils";
tools = { tools = {
flake = false; flake = false;
url = "github:urbit/tools"; url = "github:urbit/tools/d454e2482c3d4820d37db6d5625a6d40db975864";
}; };
}; };

View File

@ -28,17 +28,6 @@ let
-- --
''; '';
testThread = dojoCommand:
pkgs.writeTextFile {
name = "${dojoCommand}.hoon";
text = ''
${poke}
=/ m (strand ,vase)
;< [=ship =desk =case] bind:m get-beak
;< ok=? bind:m (poke [ship %dojo] %lens-command !>([%$ [%dojo '${dojoCommand}'] [%stdout ~]]))
(pure:m !>(ok))
'';
};
appThread = generator: app: appThread = generator: app:
pkgs.writeTextFile { pkgs.writeTextFile {
name = ":${app}|${generator}.hoon"; name = ":${app}|${generator}.hoon";
@ -87,11 +76,12 @@ in pkgs.stdenvNoCC.mkDerivation {
sleep 2 sleep 2
${click} -k -p -i ${testThread "-test %/tests ~"} ./pier ${click} -c ./pier "[0 %fyrd [%base %test %noun %noun 0]]"
${click} -k -p -i ${pokeApp "%agents" "noun" "test"} ./pier ${click} -k -p -i ${pokeApp "%agents" "noun" "test"} ./pier
${click} -k -p -i ${pokeApp "%generators" "noun" "test"} ./pier ${click} -k -p -i ${pokeApp "%generators" "noun" "test"} ./pier
${click} -k -p -i ${pokeApp "%marks" "noun" "test"} ./pier ${click} -k -p -i ${pokeApp "%marks" "noun" "test"} ./pier
${click} -k -p -i ${pokeApp "%threads" "noun" "test"} ./pier
${click} -k -p -i ${appThread "mass" "hood"} ./pier ${click} -k -p -i ${appThread "mass" "hood"} ./pier
sleep 2 sleep 2
@ -112,7 +102,7 @@ in pkgs.stdenvNoCC.mkDerivation {
''; '';
checkPhase = '' checkPhase = ''
if egrep "((FAILED|CRASHED|Failed)|warn:)" $out >/dev/null; then if egrep "((FAILED|CRASHED|Failed|\[0 %avow 0 %noun 1\])|warn:)" $out >/dev/null; then
exit 1 exit 1
fi fi
''; '';

View File

@ -85,7 +85,7 @@
=^ cards state =^ cards state
?+ mark ~|([%aqua-bad-mark mark] !!) ?+ mark ~|([%aqua-bad-mark mark] !!)
%aqua-events (poke-aqua-events:ac !<((list aqua-event) vase)) %aqua-events (poke-aqua-events:ac !<((list aqua-event) vase))
%pill (poke-pill:ac !<(pill vase)) %pill (poke-pill:ac !<(pill vase))
%noun (poke-noun:ac !<(* vase)) %noun (poke-noun:ac !<(* vase))
%azimuth-action (poke-azimuth-action:ac !<(azimuth-action vase)) %azimuth-action (poke-azimuth-action:ac !<(azimuth-action vase))
== ==
@ -663,34 +663,55 @@
(pe ~bud) :: XX why ~bud? need an example (pe ~bud) :: XX why ~bud? need an example
:: ::
%read %read
?~ pier=(~(get by ships.piers) from.ae) ?~ pier=(~(get by ships.piers) ship.from.ae)
(pe from.ae) (pe ship.from.ae)
=/ cash (~(get by namespace.u.pier) path.ae) =/ cash (~(get by namespace.u.pier) path.ae)
|- |-
?^ cash ?^ cash
?: (gth num.ae (lent u.cash)) ?: (gth num.ae (lent u.cash))
(pe from.ae) (pe ship.from.ae)
::TODO depends on /ted/aqua/ames behavior in a weird indirect way ::TODO depends on /ted/aqua/ames behavior in a weird indirect way
=/ for=@p `@`(tail for.ae) ::NOTE moons & comets not supported =/ for=@p `@`(tail lane.for.ae) ::NOTE moons & comets not supported
=; task=task-arvo %- push-events:(pe for)
^$(ae [%event for /a/aqua/fine-response task], thus this) %- flop =< events
:+ %hear `lane:ames`[%| `@`from.ae] %+ roll u.cash
|= [=yowl:ames i=@ud events=(list unix-event)]
:- +(i)
:_ events
:- /a/aqua/fine-response/[(scot %ud i)]
^- task-arvo
:+ %hear `lane:ames`[%| `@`ship.from.ae]
^- blob:ames ^- blob:ames
=/ =shot:ames %- etch-shot:ames
::NOTE dec is important! so dumb!! :* [sndr=ship.from.ae rcvr=for]
(sift-shot:ames `@`(snag (dec num.ae) u.cash)) req=| sam=|
::TODO runtime needs to update rcvr field also sndr-tick=life.from.ae
::NOTE rcvr life is allowed to be wrong rcvr-tick=life.for.ae
(etch-shot:ames shot(sndr from.ae, rcvr for)) origin=~
content=`@ux`yowl
==
::
=/ pacs=(unit (list yowl:ames)) =/ pacs=(unit (list yowl:ames))
=/ =path [%fine %hunk (scot %ud num.ae) '512' path.ae]
%+ biff %+ biff
(peek-once:(pe from.ae) %ax %$ [%fine %message path.ae]) (peek-once:(pe ship.from.ae) %ax %$ path)
(soft (list yowl:ames)) (soft (list yowl:ames))
?~ pacs (pe from.ae) ?~ pacs (pe ship.from.ae)
=. u.pacs
:: add request to each response packet payload
::
=+ pat=(spat path.ae)
=+ wid=(met 3 pat)
%- flop =< blobs
%+ roll u.pacs
|= [=yowl:ames num=_1 blobs=(list @ux)]
:- +(num)
:_ blobs
(can 3 4^num 2^wid wid^`@`pat (met 3 yowl)^yowl ~)
=. namespace.u.pier =. namespace.u.pier
(~(put by namespace.u.pier) path.ae u.pacs) (~(put by namespace.u.pier) path.ae u.pacs)
=. ships.piers =. ships.piers
(~(put by ships.piers) from.ae u.pier) (~(put by ships.piers) ship.from.ae u.pier)
$(cash pacs, thus this) $(cash pacs, thus this)
:: ::
%event %event

View File

@ -42,8 +42,8 @@
++ on-poke ++ on-poke
|= [=mark =vase] |= [=mark =vase]
^- (quip card _this) ^- (quip card _this)
?> =(our src):bowl
?: ?=(%noun mark) ?: ?=(%noun mark)
?> (team:title [our src]:bowl)
=/ code !<((unit @t) vase) =/ code !<((unit @t) vase)
=/ msg=tape =/ msg=tape
?~ code ?~ code
@ -55,6 +55,13 @@
""" """
%- (slog leaf+msg ~) %- (slog leaf+msg ~)
[~ this(passcode code)] [~ this(passcode code)]
?: ?=(%json mark)
=/ jon=json !<(json vase)
=, dejs:format
=/ cmd
((of clear-eyre-cache+(ot url+so ~) ~) jon)
?> ?=(%clear-eyre-cache -.cmd)
[[%pass /cmd %arvo %e %set-response +.cmd ~]~ this]
?. ?=(%handle-http-request mark) ?. ?=(%handle-http-request mark)
(on-poke:def mark vase) (on-poke:def mark vase)
=+ !<([eyre-id=@ta =inbound-request:eyre] vase) =+ !<([eyre-id=@ta =inbound-request:eyre] vase)
@ -315,6 +322,19 @@
:~ 'location'^s+(cat 3 (fall site '*') (spat path)) :~ 'location'^s+(cat 3 (fall site '*') (spat path))
'action'^(render-action:v-eyre action) 'action'^(render-action:v-eyre action)
== ==
::
:: /eyre/cache.json
::
[%eyre %cache ~]
%- some
:- %a
%+ turn (sort ~(tap by cache:v-eyre) aor)
|= [url=@t aeon=@ud val=(unit cache-entry:eyre)]
%- pairs
:~ 'url'^s+url
'aeon'^(numb aeon)
'val'^?~(val ~ (render-cache-entry:v-eyre u.val))
==
:: ::
:: /eyre/connections.json :: /eyre/connections.json
:: ::
@ -566,7 +586,6 @@
%- pairs %- pairs
:~ 'messages'^(numb (lent messages)) :~ 'messages'^(numb (lent messages))
'packets'^(numb ~(wyt in packets)) 'packets'^(numb ~(wyt in packets))
'heeds'^(set-array heeds from-duct)
'keens'^(set-array ~(key by keens) path) 'keens'^(set-array ~(key by keens) path)
== ==
:: ::
@ -630,7 +649,6 @@
:: }, ...], :: }, ...],
:: closing: [bone, ..., bone], :: closing: [bone, ..., bone],
:: corked: [bone, ..., bone], :: corked: [bone, ..., bone],
:: heeds: [['/paths', ...] ...]
:: scries: :: scries:
:: -> { =path :: -> { =path
:: keen-state: { :: keen-state: {
@ -757,8 +775,6 @@
'closing'^(set-array closing numb) 'closing'^(set-array closing numb)
:: ::
'corked'^(set-array corked numb) 'corked'^(set-array corked numb)
::
'heeds'^(set-array heeds from-duct)
:: ::
'scries'^(scries ~(tap by keens)) 'scries'^(scries ~(tap by keens))
== ==
@ -773,7 +789,7 @@
'next'^(numb next) 'next'^(numb next)
:: ::
:- 'unsent-messages' :: as byte sizes :- 'unsent-messages' :: as byte sizes
(set-array unsent-messages (cork (cury met 3) numb)) (set-array unsent-messages (cork jam (cork (cury met 3) numb)))
:: ::
'unsent-fragments'^(numb (lent unsent-fragments)) :: as lent 'unsent-fragments'^(numb (lent unsent-fragments)) :: as lent
:: ::
@ -1038,6 +1054,9 @@
++ bindings ++ bindings
(scry ,(list [=binding =duct =action]) %e %bindings ~) (scry ,(list [=binding =duct =action]) %e %bindings ~)
:: ::
++ cache
(scry ,(map url=@t [aeon=@ud (unit cache-entry)]) %e %cache ~)
::
++ connections ++ connections
(scry ,(map duct outstanding-connection) %e %connections ~) (scry ,(map duct outstanding-connection) %e %connections ~)
:: ::
@ -1065,6 +1084,27 @@
%gen :((cury cat 3) '+' (spat [desk path]:generator.action)) %gen :((cury cat 3) '+' (spat [desk path]:generator.action))
%app (cat 3 ':' app.action) %app (cat 3 ':' app.action)
== ==
::
++ render-cache-entry
|= cache-entry
^- json
%- pairs:enjs:format
:~ 'auth'^b+auth
'payload'^(render-simple-payload simple-payload.body)
==
::
++ render-simple-payload
|= simple-payload:http
^- json
=, enjs:format
%- pairs
:~ 'status'^(numb status-code.response-header)
'data'^?~(data ~ (numb p.u.data))
::
:+ 'headers' %a
%+ turn headers.response-header
|=([k=@t v=@t] (pairs 'key'^s+k 'value'^s+v ~))
==
-- --
:: ::
:: helpers :: helpers

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,20 +1,16 @@
<!doctype html> <!doctype html>
<html> <html lang="en">
<head>
<head> <meta charset="UTF-8" />
<title>Debug Dashboard</title> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta charset="utf-8" /> <title>Debug Dashboard</title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <style type="text/css" src="/src/index.css"></style>
<link rel="stylesheet" href="/~debug/css/index.css" /> <script type="module" crossorigin src="/~debug/index.js"></script>
<link rel="icon" type="image/png" href="/~launch/img/Favicon.png"> <link rel="stylesheet" crossorigin href="/~debug/index.css">
</head> </head>
<body>
<body class="w-100 h-100"> <div id="root"></div>
<div id="root" class="w-100 h-100"> <script src="/~debug/channel.js"></script>
</div> <script src="/~debug/js/session.js"></script>
<script src="/~debug/js/channel.js"></script> </body>
<script src="/~debug/js/session.js"></script>
<script src="/~debug/js/index.js"></script>
</body>
</html> </html>

125
pkg/arvo/app/debug/index.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
import{errors as c,isChunkObject as y}from"./util.js";import"./index.js";let n=globalThis.File,p=globalThis.Blob;const m=o=>{n=o},g=o=>{p=o},{INVALID:z,GONE:s,MISMATCH:w,MOD_ERR:E,SYNTAX:l,DISALLOWED:O}=c;class D{constructor(e,i){this.fileHandle=e,this.file=i?e.file:new n([],e.file.name,e.file),this.size=i?e.file.size:0,this.position=0}async write(e){if(!this.fileHandle.file)throw new DOMException(...s);let i=this.file;if(y(e)){if(e.type==="write"){if(typeof e.position=="number"&&e.position>=0&&(this.position=e.position,this.size<e.position&&(this.file=new n([this.file,new ArrayBuffer(e.position-this.size)],this.file.name,this.file))),!("data"in e))throw new DOMException(...l("write requires a data argument"));e=e.data}else if(e.type==="seek")if(Number.isInteger(e.position)&&e.position>=0){if(this.size<e.position)throw new DOMException(...z);this.position=e.position;return}else throw new DOMException(...l("seek requires a position argument"));else if(e.type==="truncate")if(Number.isInteger(e.size)&&e.size>=0){i=e.size<this.size?new n([i.slice(0,e.size)],i.name,i):new n([i,new Uint8Array(e.size-this.size)],i.name,i),this.size=i.size,this.position>i.size&&(this.position=i.size),this.file=i;return}else throw new DOMException(...l("truncate requires a size argument"))}e=new p([e]);let t=this.file;const a=t.slice(0,this.position),d=t.slice(this.position+e.size);let r=this.position-a.size;r<0&&(r=0),t=new n([a,new Uint8Array(r),e,d],t.name),this.size=t.size,this.position+=e.size,this.file=t}async close(){if(!this.fileHandle.file)throw new DOMException(...s);this.fileHandle.file=this.file,this.file=this.position=this.size=null,this.fileHandle.onclose&&this.fileHandle.onclose(this.fileHandle)}}class f{constructor(e="",i=new n([],e),t=!0){this.kind="file",this.deleted=!1,this.file=i,this.name=e,this.writable=t}async getFile(){if(this.deleted||this.file===null)throw new DOMException(...s);return this.file}async createWritable(e){if(!this.writable)throw new DOMException(...O);if(this.deleted)throw new DOMException(...s);return new D(this,!!(e!=null&&e.keepExistingData))}async isSameEntry(e){return this===e}destroy(){this.deleted=!0,this.file=null}}class h{constructor(e,i=!0){this.kind="directory",this.deleted=!1,this._entries={},this.name=e,this.writable=i}async*entries(){if(this.deleted)throw new DOMException(...s);yield*Object.entries(this._entries)}async isSameEntry(e){return this===e}async getDirectoryHandle(e,i={}){if(this.deleted)throw new DOMException(...s);const t=this._entries[e];if(t){if(t instanceof f)throw new DOMException(...w);return t}else{if(i.create)return this._entries[e]=new h(e);throw new DOMException(...s)}}async getFileHandle(e,i={}){const t=this._entries[e];if(t){if(t instanceof f)return t;throw new DOMException(...w)}else{if(i.create)return this._entries[e]=new f(e);throw new DOMException(...s)}}async removeEntry(e,i={}){const t=this._entries[e];if(!t)throw new DOMException(...s);t.destroy(i.recursive),delete this._entries[e]}destroy(e){for(let i of Object.values(this._entries)){if(!e)throw new DOMException(...E);i.destroy(e)}this._entries={},this.deleted=!0}}const M=new h(""),u=()=>M;export{f as FileHandle,h as FolderHandle,u as default,g as setBlobImpl,m as setFileImpl};

View File

@ -0,0 +1,7 @@
function __vite__mapDeps(indexes) {
if (!__vite__mapDeps.viteFileDeps) {
__vite__mapDeps.viteFileDeps = ["memory.js","index.js","index.css"]
}
return indexes.map((i) => __vite__mapDeps.viteFileDeps[i])
}
import{_ as l}from"./index.js";const E={INVALID:["seeking position failed.","InvalidStateError"],GONE:["A requested file or directory could not be found at the time an operation was processed.","NotFoundError"],MISMATCH:["The path supplied exists, but was not an entry of requested type.","TypeMismatchError"],MOD_ERR:["The object can not be modified in this way.","InvalidModificationError"],SYNTAX:e=>[`Failed to execute 'write' on 'UnderlyingSinkBase': Invalid params passed. ${e}`,"SyntaxError"],ABORT:["The operation was aborted","AbortError"],SECURITY:["It was determined that certain files are unsafe for access within a Web application, or that too many calls are being made on file resources.","SecurityError"],DISALLOWED:["The request is not allowed by the user agent or the platform in the current context.","NotAllowedError"]},y=e=>typeof e=="object"&&typeof e.type<"u";async function v(e){var o,r,a;const{FolderHandle:t,FileHandle:u}=await l(()=>import("./memory.js"),__vite__mapDeps([0,1,2])),{FileSystemDirectoryHandle:m}=await l(()=>import("./index.js").then(n=>n.a),__vite__mapDeps([1,2])),p=(r=(o=e[0].webkitRelativePath)===null||o===void 0?void 0:o.split("/",1)[0])!==null&&r!==void 0?r:"",_=new t(p,!1);for(let n=0;n<e.length;n++){const i=e[n],d=!((a=i.webkitRelativePath)===null||a===void 0)&&a.length?i.webkitRelativePath.split("/"):["",i.name];d.shift();const f=d.pop(),w=d.reduce((c,s)=>(c._entries[s]||(c._entries[s]=new t(s,!1)),c._entries[s]),_);w._entries[f]=new u(i.name,i,!1)}return new m(_)}async function b(e){const{FileHandle:o}=await l(()=>import("./memory.js"),__vite__mapDeps([0,1,2])),{FileSystemFileHandle:r}=await l(()=>import("./index.js").then(t=>t.F),__vite__mapDeps([1,2]));return Array.from(e).map(t=>new r(new o(t.name,t,!1)))}export{E as errors,y as isChunkObject,v as makeDirHandleFromFileList,b as makeFileHandlesFromFileList};

View File

@ -168,7 +168,7 @@
:: ::
;~ pfix tis ;~ pfix tis
;~ pose ;~ pose
(parse-variable (jest %dir) ;~(pfix ace :(stag 0 %ex parse-rood))) (parse-variable (cold %dir (jest 'dir ')) :(stag 0 %ex parse-rood))
(parse-variable sym ;~(pfix ace parse-source)) (parse-variable sym ;~(pfix ace parse-source))
== ==
== ==

View File

@ -5,7 +5,6 @@
:: keep relevant mark conversions in cache for performance :: keep relevant mark conversions in cache for performance
:: ::
/$ blit-to-json %blit %json /$ blit-to-json %blit %json
/$ json-to-blit %json %blit
/$ json-to-task %json %herm-task /$ json-to-task %json %herm-task
:: ::
=, jael =, jael

View File

@ -2,8 +2,8 @@
/+ drum=hood-drum, helm=hood-helm, kiln=hood-kiln /+ drum=hood-drum, helm=hood-helm, kiln=hood-kiln
|% |%
+$ state +$ state
$~ [%26 *state:drum *state:helm *state:kiln] $~ [%27 *state:drum *state:helm *state:kiln]
$>(%26 any-state) $>(%27 any-state)
:: ::
+$ any-state +$ any-state
$% [ver=?(%1 %2 %3 %4 %5 %6) lac=(map @tas fin-any-state)] $% [ver=?(%1 %2 %3 %4 %5 %6) lac=(map @tas fin-any-state)]
@ -27,6 +27,7 @@
[%24 drum=state-4:drum helm=state-2:helm kiln=state-10:kiln] [%24 drum=state-4:drum helm=state-2:helm kiln=state-10:kiln]
[%25 drum=state-5:drum helm=state-2:helm kiln=state-10:kiln] [%25 drum=state-5:drum helm=state-2:helm kiln=state-10:kiln]
[%26 drum=state-6:drum helm=state-2:helm kiln=state-10:kiln] [%26 drum=state-6:drum helm=state-2:helm kiln=state-10:kiln]
[%27 drum=state-6:drum helm=state-2:helm kiln=state-11:kiln]
== ==
+$ any-state-tuple +$ any-state-tuple
$: drum=any-state:drum $: drum=any-state:drum

View File

@ -26,7 +26,7 @@
+$ card $+(card card:agent:gall) +$ card $+(card card:agent:gall)
+$ state-0 +$ state-0
$+ state-0 $+ state-0
$: =loam:dirt:neo :: layer 1 $: =loam:dirt:neo :: layer 1
=farm:neo :: layer 2 =farm:neo :: layer 2
:: ::
=town:neo :: subscription =town:neo :: subscription
@ -75,7 +75,7 @@
=| state-0 =| state-0
=* state - =* state -
=< =<
%- mute !.
%+ libverb | %+ libverb |
%- agent:dbug %- agent:dbug
^- agent:gall ^- agent:gall
@ -83,7 +83,7 @@
+* this . +* this .
run ~(. +> [bowl ~]) run ~(. +> [bowl ~])
def ~(. (default-agent this %|) bowl) def ~(. (default-agent this %|) bowl)
++ on-init ++ on-init
^- (quip card _this) ^- (quip card _this)
=^ cards state =^ cards state
abet:boot:run abet:boot:run
@ -131,7 +131,8 @@
[cards this] [cards this]
++ on-peek on-peek:run ++ on-peek on-peek:run
-- --
:: %- mute :: %- mute
!.
|_ [=bowl:gall cards=(list card)] |_ [=bowl:gall cards=(list card)]
:: |aux: auxilliary helpers :: |aux: auxilliary helpers
+| %aux +| %aux
@ -150,7 +151,7 @@
:- p/our.bowl :- p/our.bowl
~[n/~ %sys] ~[n/~ %sys]
:: |do: effect creation :: |do: effect creation
+| %do +| %do
++ do-watch ++ do-watch
|= [=wire =dock =path] |= [=wire =dock =path]
(pass wire %agent dock watch/path) (pass wire %agent dock watch/path)
@ -197,6 +198,7 @@
++ do-ack ++ do-ack
|= =ack:neo |= =ack:neo
^- (list card) ^- (list card)
:: %- (slog leaf/"do from: {<p.p.ack>} to: {<q.p.ack>}" ~)
?: =(p.ack sys-pith) ?: =(p.ack sys-pith)
%. *(list card) %. *(list card)
?~ q.ack ?~ q.ack
@ -228,23 +230,22 @@
=/ =name:neo (de-pith:name:neo pith) =/ =name:neo (de-pith:name:neo pith)
=/ nonce (scot %uv run-nonce:(~(got by mate) ship.name)) =/ nonce (scot %uv run-nonce:(~(got by mate) ship.name))
=/ =spar:ames [ship.name [nonce (pout pith)]] =/ =spar:ames [ship.name [nonce (pout pith)]]
~& fetching/spar
!! :: (pass wire %keen spar) !! :: (pass wire %keen spar)
++ do-gall-grow ++ do-gall-grow
|= [=pith:neo sag=(unit saga:neo)] |= [=pith:neo sag=(unit saga:neo)]
^- card ^- card
=/ =wire gall-grow/(pout pith) =/ =wire gall-grow/(pout pith)
=/ =page =/ =page
?~ sag none/~ ?~ sag none/~
neo-feat/(saga:soften u.sag) neo-feat/(saga:soften u.sag)
(pass wire %grow (pout pith) page) (pass wire %grow (pout pith) page)
:: ::
:: ?: =(p.flow :: ?: =(p.flow
:: |on: event handlers :: |on: event handlers
+| %on +| %on
:: ::
++ on-poke ++ on-poke
|= [=mark =vase] |= [=mark =vase]
^+ run ^+ run
?+ mark ~|(bad-poke-mark/mark !!) ?+ mark ~|(bad-poke-mark/mark !!)
%neo-move =;(f (f !<(_+<.f vase)) on-move) %neo-move =;(f (f !<(_+<.f vase)) on-move)
@ -272,7 +273,7 @@
++ on-move ++ on-move
|= =move:neo |= =move:neo
^+ run ^+ run
%- (slog leaf/"{(en-tape:pith:neo p.move)} -> {(en-tape:pith:neo p.q.move)}: {<-.q.q.move>}" ~) :: %- (slog leaf/"{(en-tape:pith:neo p.move)} -> {(en-tape:pith:neo p.q.move)}: {<-.q.q.move>}" ~)
=/ src=name:neo (de-pith:name:neo p.move) =/ src=name:neo (de-pith:name:neo p.move)
=/ dst=name:neo (de-pith:name:neo p.q.move) =/ dst=name:neo (de-pith:name:neo p.q.move)
?> =(src.bowl ship.src) ?> =(src.bowl ship.src)
@ -282,7 +283,7 @@
++ on-ack ++ on-ack
|= =ack:neo |= =ack:neo
=/ dst=name:neo (de-pith:name:neo p.p.ack) =/ dst=name:neo (de-pith:name:neo p.p.ack)
?> =(src.bowl ship.dst) :: ?> =(src.bowl ship.dst)
?: =(sys-pith p.p.ack) ?: =(sys-pith p.p.ack)
%. run %. run
?~ q.ack ?~ q.ack
@ -291,6 +292,7 @@
%gone (slog leaf/"Missing dep: {<term.u.q.ack>}" ~) %gone (slog leaf/"Missing dep: {<term.u.q.ack>}" ~)
%goof (slog leaf/"nacked on flow {<p.ack>}" tang.u.q.ack) %goof (slog leaf/"nacked on flow {<p.ack>}" tang.u.q.ack)
== ==
:: %- (slog leaf/"on-ack from: {<p.p.ack>} to: {<q.p.ack>}" ~)
(on-move q.p.ack p.p.ack %poke ack/!>(q.ack)) (on-move q.p.ack p.p.ack %poke ack/!>(q.ack))
:: ::
++ on-dirt-card ++ on-dirt-card
@ -328,6 +330,8 @@
=/ sag (need (peek-x:till pith)) =/ sag (need (peek-x:till pith))
=/ =feat:neo =/ =feat:neo
?~ sag [*aeon:neo sig/~] ?~ sag [*aeon:neo sig/~]
?: =(%vase p.q.u.sag)
[*aeon:neo sig/~]
(saga:soften u.sag) (saga:soften u.sag)
=. run (emit %give %fact ~ neo-feat+!>(feat)) =. run (emit %give %fact ~ neo-feat+!>(feat))
(emit %give %kick ~ ~) (emit %give %kick ~ ~)
@ -396,7 +400,7 @@
|= =poem:neo |= =poem:neo
neo-poem+!>(poem) neo-poem+!>(poem)
:: ::
++ tell ++ tell
%- raise %- raise
|= =myth:neo |= =myth:neo
neo-myth+!>(myth) neo-myth+!>(myth)
@ -417,12 +421,11 @@
^+ run ^+ run
=/ [gis=(list gift:dirt:neo) lom=loam:dirt:neo fam=farm:neo] =/ [gis=(list gift:dirt:neo) lom=loam:dirt:neo fam=farm:neo]
(tell:till epic) (tell:till epic)
=. loam lom =. loam lom
=. farm fam =. farm fam
=. run (lazarus gis) =. run (lazarus gis)
=. run (take:rage gis) =. run (take:rage gis)
=. run (collect-rent gis) =. run (collect-rent gis)
~& gifs/gis
run run
:: ::
++ plow ~(. plow:aux loam) ++ plow ~(. plow:aux loam)
@ -482,7 +485,7 @@
=. mart.u.mal (~(put in mart.u.mal) [care src]) =. mart.u.mal (~(put in mart.u.mal) [care src])
=. town (~(put of:neo town) pith u.mal) =. town (~(put of:neo town) pith u.mal)
sale sale
:: XX: search upwards for :: XX: search upwards for
=| =mall:neo =| =mall:neo
=. mart.mall (~(put in mart.mall) [care src]) =. mart.mall (~(put in mart.mall) [care src])
?. =(~ find-deli) ?. =(~ find-deli)
@ -522,13 +525,12 @@
++ take-fetch ++ take-fetch
|= syn=sign-arvo |= syn=sign-arvo
^+ sale ^+ sale
~& got-fetch/pith
?> ?=([%ames %tune *] syn) ?> ?=([%ames %tune *] syn)
?~ roar.syn ?~ roar.syn
~& missing-roar/pith ~& missing-roar/pith
sale sale
=/ [=path dat=(unit page)] dat.u.roar.syn =/ [=path dat=(unit page)] dat.u.roar.syn
?~ dat ?~ dat
~& missing-page/pith ~& missing-page/pith
sale sale
%- on-saga %- on-saga
@ -543,16 +545,14 @@
mismatch-saga-sale/[exe.p.u.shop.mall exe.p.p.res] mismatch-saga-sale/[exe.p.u.shop.mall exe.p.p.res]
~ ~
=. sale (put-mall mall) =. sale (put-mall mall)
=/ del =/ del
~| town/town ~| town/town
~| mall/mall ~| mall/mall
~| pith/pith ~| pith/pith
(need find-deli) (need find-deli)
~& del/del
=/ kid (dif:pith:neo pith del) =/ kid (dif:pith:neo pith del)
~& kid/kid
abet:(fetched:~(meat sale del) (dif:pith:neo pith del) res) abet:(fetched:~(meat sale del) (dif:pith:neo pith del) res)
:: XX: possibly check that :: XX: possibly check that
++ find-deli ++ find-deli
=| res=(unit pith:neo) =| res=(unit pith:neo)
=/ at=pith:neo pith =/ at=pith:neo pith
@ -577,18 +577,26 @@
++ meat . ++ meat .
++ new ++ new
|= =yuga:neo |= =yuga:neo
=. yuga.deli yuga =. yuga.deli
~& new-yuga/yuga %- gas-yuga
%+ murn ~(tap by ~(tar of:neo yuga))
|= [=pith:neo =aeon:neo]
=/ res (look %x pith)
?: ?=(?(~ [~ ~]) res)
`[pith aeon]
?~ rot=(~(get of:neo u.u.res) ~)
`[pith aeon]
?: =(p.exe.p.p.u.rot p.exe.p.aeon)
~
`[pith aeon]
meat meat
++ fetched ++ fetched
|= [kid=pith:neo =saga:neo] |= [kid=pith:neo =saga:neo]
=. yuga.deli (~(del of:neo yuga.deli) kid) =. yuga.deli (~(del of:neo yuga.deli) kid)
=. epic.deli (~(put of:neo epic.deli) kid saga) =. epic.deli (~(put of:neo epic.deli) kid saga)
~& fetched/deli
?. =(~ ~(tap of:neo yuga.deli)) ?. =(~ ~(tap of:neo yuga.deli))
meat meat
=/ =epic:neo epic.deli =/ =epic:neo epic.deli
~& finalizing/[pith epic]
=. epic.deli *epic:neo =. epic.deli *epic:neo
=. run (tell pith (~(rep of:neo *epic:neo) pith epic)) =. run (tell pith (~(rep of:neo *epic:neo) pith epic))
meat meat
@ -613,7 +621,6 @@
:: ::
++ on-sync-sign ++ on-sync-sign
|= =sign:agent:gall |= =sign:agent:gall
~& town/town
^+ sale ^+ sale
?+ -.sign ~|(bad-sign/-.sign !!) ?+ -.sign ~|(bad-sign/-.sign !!)
%watch-ack %watch-ack
@ -624,7 +631,6 @@
:: ::
%fact %fact
?. =(%neo-yuga p.cage.sign) ?. =(%neo-yuga p.cage.sign)
~& weird-mall-fact/p.cage.sign
sale sale
(on-yuga !<(yuga:neo q.cage.sign)) (on-yuga !<(yuga:neo q.cage.sign))
:: ::
@ -661,9 +667,8 @@
^+ sale ^+ sale
:: =. sale abet:(new:meat yuga) :: =. sale abet:(new:meat yuga)
=/ lis ~(tap of:neo yuga) =/ lis ~(tap of:neo yuga)
|- |-
?~ lis ?~ lis
~& done-yuga-town/town
abet:(new:meat yuga) abet:(new:meat yuga)
=/ [kid=pith:neo =aeon:neo] i.lis =/ [kid=pith:neo =aeon:neo] i.lis
=/ pit (welp pith kid) =/ pit (welp pith kid)
@ -674,12 +679,9 @@
~& nothing/pit ~& nothing/pit
$(lis t.lis) $(lis t.lis)
?~ u.res ?~ u.res
~& dead/pit
:: XX: what means?? :: XX: what means??
$(lis t.lis) $(lis t.lis)
~& alive/pit
?: =(p.u.u.res aeon) ?: =(p.u.u.res aeon)
~& clone/pit
$(lis t.lis, yuga (~(del of:neo yuga) kid)) $(lis t.lis, yuga (~(del of:neo yuga) kid))
~& fresh/pit ~& fresh/pit
=. run abet:(~(fresh sale pit) aeon) =. run abet:(~(fresh sale pit) aeon)
@ -689,7 +691,7 @@
=/ wir (wire %fetch) =/ wir (wire %fetch)
=. run (emit (do-watch-her wir get-ship fetch-path)) =. run (emit (do-watch-her wir get-ship fetch-path))
sale sale
++ watch-sync ++ watch-sync
=/ wir (wire %sync) =/ wir (wire %sync)
=. run (emit (do-watch-her (wire %sync) get-ship peer-path)) =. run (emit (do-watch-her (wire %sync) get-ship peer-path))
sale sale
@ -718,6 +720,7 @@
++ abet run ++ abet run
++ rent . ++ rent .
++ get-ward (~(gut of:neo city) pith *ward:neo) ++ get-ward (~(gut of:neo city) pith *ward:neo)
++ has-kid !=(~ kid:(~(dip of:neo city) pith))
++ put-ward |=(=ward:neo rent(city (~(put of:neo city) pith ward))) ++ put-ward |=(=ward:neo rent(city (~(put of:neo city) pith ward)))
++ fact ++ fact
|= [=care:neo paxs=(set pith:neo)] |= [=care:neo paxs=(set pith:neo)]
@ -738,7 +741,6 @@
^- yuga:neo ^- yuga:neo
?~ pic=(need (look care p/our.bowl pith)) ?~ pic=(need (look care p/our.bowl pith))
*yuga:neo *yuga:neo
~& epic/u.pic
(epic-to-yuga u.pic) (epic-to-yuga u.pic)
:: ::
++ stop ++ stop
@ -774,7 +776,7 @@
?: =(until pith) ?: =(until pith)
%self %self
=/ left (dif:pith:neo pith until) =/ left (dif:pith:neo pith until)
?: (~(has by (~(kid of:neo tide) pith)) left) ?: (~(has by (~(kid of:neo tide) pith)) left)
%par %par
%anc %anc
:: ::
@ -791,10 +793,12 @@
=. rent (fact %z zed.war) =. rent (fact %z zed.war)
?~ nex=(dif:pith:neo pith until) ?~ nex=(dif:pith:neo pith until)
rent rent
?. has-kid
rent
$(pith (snoc pith i.nex)) $(pith (snoc pith i.nex))
-- --
++ rage ++ rage
|% |%
++ stalk ++ stalk
|= [=hunt:neo =howl:neo] |= [=hunt:neo =howl:neo]
^+ run ^+ run
@ -802,6 +806,50 @@
=. rav (fume-add rav care.hunt howl) =. rav (fume-add rav care.hunt howl)
=. riot (~(put of:neo riot) pith.hunt rav) =. riot (~(put of:neo riot) pith.hunt rav)
run run
++ heal
|= [dead=hunt:neo how=(set howl:neo)]
^+ run
=/ how ~(tap in how)
|-
?~ how
run
=/ =howl:neo i.how
?. ?=(%rely -.howl) :: XX: handle %halt %sell
$(how t.how)
=/ [=term =pith:neo] +.howl
=/ =move:neo
[pith.dead [p/our.bowl pith] %poke %dead !>(term)]
=. run
abet:(arvo move)
$(how t.how)
++ ease
|= [=pith:neo how=(set howl:neo)]
%- ~(gas in *(set howl:neo))
%+ skip ~(tap in how)
|= =howl:neo
?. ?=(%rely -.howl)
|
=(pith pith.howl)
++ cure
|= dead=pith:neo
=. riot
%- gas-riot
%+ turn ~(tap by ~(tar of:neo riot))
|= [=pith:neo =rave:neo]
=. exe.rave (ease dead exe.rave)
=. why.rave (ease dead why.rave)
=. zed.rave (ease dead zed.rave)
[pith rave]
run
++ reap
|= [change=pith:neo =loot:neo]
=/ =name:neo (de-pith:name:neo change)
=? run =(our.bowl ship.name)
(cure pith.name)
=/ =rave:neo (~(gut of:neo riot) change *rave:neo)
=. run (heal:rage:(heal:rage:(heal x/change exe.rave) y/change why.rave) z/change zed.rave)
run(riot (~(del of:neo riot) change))
::
++ fury ++ fury
|= gis=(list gift:dirt:neo) |= gis=(list gift:dirt:neo)
%- gas-leaf %- gas-leaf
@ -825,7 +873,8 @@
=/ =rave:neo (~(gut of:neo riot) here *rave:neo) =/ =rave:neo (~(gut of:neo riot) here *rave:neo)
=? run =(here change) =? run =(here change)
(spaz exe.rave %x change) (spaz exe.rave %x change)
=? run =(here (~(parent of:neo tide) change)) =/ par (~(parent of:neo loam) change)
=? run =(`here par)
(spaz why.rave %y change) (spaz why.rave %y change)
=. run =. run
(spaz zed.rave %z change) (spaz zed.rave %z change)
@ -842,6 +891,8 @@
run run
=/ [=pith:neo =loot:neo] i.gis =/ [=pith:neo =loot:neo] i.gis
=. run (sweep i.gis) =. run (sweep i.gis)
=? run =(%del mode.loot)
(reap pith loot)
$(gis t.gis) $(gis t.gis)
:: ::
++ fume-add ++ fume-add
@ -867,7 +918,7 @@
^+ run ^+ run
:: XX: weird shadowing, be careful :: XX: weird shadowing, be careful
=/ =rave:neo (~(gut of:neo riot) pith.hunt *rave:neo) =/ =rave:neo (~(gut of:neo riot) pith.hunt *rave:neo)
=. rave =. rave
(fume-del rave care.hunt halt/~) (fume-del rave care.hunt halt/~)
=. riot (~(put of:neo riot) pith.hunt rave) =. riot (~(put of:neo riot) pith.hunt rave)
(resolved:stop hunt) (resolved:stop hunt)
@ -883,7 +934,7 @@
[pith.from [p/our.bowl pith] %poke %rely !>(rely)] [pith.from [p/our.bowl pith] %poke %rely !>(rely)]
abet:(arvo move) abet:(arvo move)
-- --
:: ::
++ lazarus ++ lazarus
|= git=grit:neo |= git=grit:neo
^+ run ^+ run
@ -896,8 +947,8 @@
=/ res (need (look-x:till case.loot pith)) =/ res (need (look-x:till case.loot pith))
?: &(?=(^ res) =(%vase p.q.u.res)) ?: &(?=(^ res) =(%vase p.q.u.res))
$(git t.git) $(git t.git)
=. run :: =. run
(emit (do-gall-grow pith (need (look-x:till case.loot pith)))) :: (emit (do-gall-grow pith (need (look-x:till case.loot pith))))
$(git t.git) $(git t.git)
++ take-dirt-card ++ take-dirt-card
@ -951,7 +1002,6 @@
run run
++ resolved ++ resolved
|= =hunt:neo |= =hunt:neo
~& resolved/hunt
=/ fow=(unit flow:neo) (~(get by by-hunt.halt) hunt) =/ fow=(unit flow:neo) (~(get by by-hunt.halt) hunt)
?~ fow ?~ fow
run run
@ -963,7 +1013,7 @@
run run
=/ q (~(got by clog.halt) u.fow) =/ q (~(got by clog.halt) u.fow)
|- |-
?: =(~ q) ?: =(~ q)
=. clog.halt (~(del by clog.halt) u.fow) =. clog.halt (~(del by clog.halt) u.fow)
run run
=^ nex=move:neo q ~(get to q) =^ nex=move:neo q ~(get to q)
@ -984,7 +1034,7 @@
:: ::
++ pith ++ pith
^- pith:neo ^- pith:neo
:- p/our.bowl :- p/our.bowl
(~(pith press imp/stud) %out) (~(pith press imp/stud) %out)
++ vase ++ vase
^- ^vase ^- ^vase
@ -1060,12 +1110,12 @@
!, *hoon !, *hoon
|= [to=stud:neo in=in] |= [to=stud:neo in=in]
^- vase ^- vase
=/ =stud:neo =/ =stud:neo
~| missing-con/[grab to] ~| missing-con/[grab to]
(~(got by con.dive) [grab %$ to]) (~(got by con.dive) [grab %$ to])
=/ conv ~(do con stud) =/ conv ~(do con stud)
(slym run:conv in) (slym run:conv in)
:: ::
++ all-grow ++ all-grow
|= grow=stud:neo |= grow=stud:neo
^- vase :: of $-(pail grow-type) ^- vase :: of $-(pail grow-type)
@ -1084,17 +1134,17 @@
^- out ^- out
~! p.pail ~! p.pail
~! grow ~! grow
=/ =stud:neo =/ =stud:neo
~| missing-con/[p.pail grow] ~| missing-con/[p.pail grow]
(~(got by con.dive) [p.pail %$ grow]) (~(got by con.dive) [p.pail %$ grow])
=/ conv ~(do con stud) =/ conv ~(do con stud)
!<(out (slam run:conv q.pail)) !<(out (slam run:conv q.pail))
:: ::
:: ::
++ con ++ con
|_ =stud:neo |_ =stud:neo
++ do ++ do
=/ vax=vase =/ vax=vase
q.q:(need fil:(need (need (~(peek till:aux [loam farm]) %x [p/our.bowl pith])))) q.q:(need fil:(need (need (~(peek till:aux [loam farm]) %x [p/our.bowl pith]))))
~| con-pith/pith ~| con-pith/pith
|% |%
@ -1121,7 +1171,7 @@
|. ^- ? |. ^- ?
=/ src=vase ~(get pro grab) =/ src=vase ~(get pro grab)
=/ dst=vase ~(get pro grow) =/ dst=vase ~(get pro grow)
=/ need=type =/ need=type
=< p =< p
%+ slap (with-faces:ford:neo get-reef src/src dst/dst ~) %+ slap (with-faces:ford:neo get-reef src/src dst/dst ~)
!,(*hoon *$-(src dst)) !,(*hoon *$-(src dst))
@ -1143,7 +1193,7 @@
!=(~ (~(peek plow:aux loam) p/our.bowl pith)) !=(~ (~(peek plow:aux loam) p/our.bowl pith))
++ pith (~(pith press pro/stud) %out) ++ pith (~(pith press pro/stud) %out)
++ exists (exists-file (~(path press pro/stud) %src)) ++ exists (exists-file (~(path press pro/stud) %src))
-- --
:: ::
++ press ++ press
|_ =post:neo |_ =post:neo
@ -1153,7 +1203,7 @@
|= =pith:neo |= =pith:neo
^- [kind:ford:neo post:neo pith:neo] ^- [kind:ford:neo post:neo pith:neo]
~| ejecting/pith ~| ejecting/pith
=^ =disk:neo pith =^ =disk:neo pith
?> ?=([%cod *] pith) ?> ?=([%cod *] pith)
(eject:floppy t.pith) (eject:floppy t.pith)
?> ?=([kind:ford:neo tack:neo @ *] pith) ?> ?=([kind:ford:neo tack:neo @ *] pith)
@ -1161,7 +1211,7 @@
=/ =tack:neo i.t.pith =/ =tack:neo i.t.pith
:+ kind [tack ?@(disk i.t.t.pith [i.t.t.pith ship.disk term.disk])] :+ kind [tack ?@(disk i.t.t.pith [i.t.t.pith ship.disk term.disk])]
t.t.t.pith t.t.t.pith
++ slip ++ slip
|= [=kind:ford:neo pax=pith:neo] |= [=kind:ford:neo pax=pith:neo]
=/ [@ p=post:neo =pith:neo] =/ [@ p=post:neo =pith:neo]
@ -1230,9 +1280,9 @@
++ finalize ++ finalize
=. ripe & =. ripe &
=/ base=pith:neo /cod/std/out/con =/ base=pith:neo /cod/std/out/con
=/ cons =/ cons
~(tap by ~(tar of:neo ~(snip of:neo (~(dip of:neo tide) base)))) ~(tap by ~(tar of:neo ~(snip of:neo (~(dip of:neo tide) base))))
|- |-
?~ cons ?~ cons
=. run gen-grab =. run gen-grab
gen-grow gen-grow
@ -1246,7 +1296,7 @@
++ gen-grab ++ gen-grab
=/ grabs ~(tap in ~(key by by-grab.dive)) =/ grabs ~(tap in ~(key by by-grab.dive))
~& genning/grabs ~& genning/grabs
|- |-
?~ grabs ?~ grabs
run run
=/ =vase (all-grab i.grabs) =/ =vase (all-grab i.grabs)
@ -1256,7 +1306,7 @@
++ gen-grow ++ gen-grow
=/ grows ~(tap in ~(key by by-grow.dive)) =/ grows ~(tap in ~(key by by-grow.dive))
~& genning-grows/grows ~& genning-grows/grows
|- |-
?~ grows ?~ grows
run run
=/ =vase (all-grow i.grows) =/ =vase (all-grow i.grows)
@ -1272,7 +1322,6 @@
!=(txt q.q.u.pal) !=(txt q.q.u.pal)
++ read-txt ++ read-txt
|= pax=path |= pax=path
~& reading-txt/pax
=+ .^(src=@t %cx `path`(welp root pax)) =+ .^(src=@t %cx `path`(welp root pax))
=. pax (snip pax) =. pax (snip pax)
=. run (write-txt pax src) =. run (write-txt pax src)
@ -1282,7 +1331,6 @@
++ read-file ++ read-file
|= pax=path |= pax=path
^+ run ^+ run
~& reading/pax
?. =((rear pax) %hoon) ?. =((rear pax) %hoon)
(read-txt pax) (read-txt pax)
=+ .^(src=@t %cx `path`(welp root pax)) =+ .^(src=@t %cx `path`(welp root pax))
@ -1298,7 +1346,6 @@
(mean p.res) (mean p.res)
%- mule |. %- mule |.
(scan (trip src) (rein:ford:neo [our.bowl (pave:neo (snip pax))])) (scan (trip src) (rein:ford:neo [our.bowl (pave:neo (snip pax))]))
~& [lib=lib pro=pro]:file
=/ has-imports=? =/ has-imports=?
?& (levy pro.file |=(pro:ford:neo ~(exists pro stud))) ?& (levy pro.file |=(pro:ford:neo ~(exists pro stud)))
(levy lib.file |=(lib:ford:neo ~(exists lib stud))) (levy lib.file |=(lib:ford:neo ~(exists lib stud)))
@ -1321,7 +1368,7 @@
~| ~(key by ~(tar of:neo loam)) ~| ~(key by ~(tar of:neo loam))
~| imports/file(hoon *hoon) ~| imports/file(hoon *hoon)
?> built-imports ?> built-imports
=^ pre=pith run =^ pre=pith run
(make-prelude (snip pax) file) (make-prelude (snip pax) file)
=/ =conf:neo =/ =conf:neo
(~(gas by *conf:neo) [%sut (ours pre)] ~) (~(gas by *conf:neo) [%sut (ours pre)] ~)
@ -1333,7 +1380,7 @@
^+ run ^+ run
?~ pos ?~ pos
run run
=/ pat =/ pat
(~(path press fil/i.pos) %src) (~(path press fil/i.pos) %src)
?: ~(built pro i.pos) ?: ~(built pro i.pos)
$(pos t.pos) $(pos t.pos)
@ -1348,7 +1395,7 @@
^+ run ^+ run
?~ pos ?~ pos
run run
=/ pat =/ pat
(~(path press pro/i.pos) %src) (~(path press pro/i.pos) %src)
?: ~(built pro i.pos) ?: ~(built pro i.pos)
$(pos t.pos) $(pos t.pos)
@ -1360,7 +1407,7 @@
^+ run ^+ run
?~ pos ?~ pos
run run
=/ pat =/ pat
(welp #/cod/grab (stud-to-pith:neo i.pos)) (welp #/cod/grab (stud-to-pith:neo i.pos))
?: !=(~ (~(peek plow:aux loam) p/our.bowl pat)) ?: !=(~ (~(peek plow:aux loam) p/our.bowl pat))
$(pos t.pos) $(pos t.pos)
@ -1372,7 +1419,7 @@
^+ run ^+ run
?~ pos ?~ pos
run run
=/ pat =/ pat
(welp #/cod/grow (stud-to-pith:neo i.pos)) (welp #/cod/grow (stud-to-pith:neo i.pos))
?: !=(~ (~(peek plow:aux loam) p/our.bowl pat)) ?: !=(~ (~(peek plow:aux loam) p/our.bowl pat))
$(pos t.pos) $(pos t.pos)
@ -1388,7 +1435,7 @@
^+ run ^+ run
?~ lis ?~ lis
run run
=/ pat =/ pat
(~(path press lib/i.lis) %src) (~(path press lib/i.lis) %src)
?: ~(built lib i.lis) ?: ~(built lib i.lis)
$(lis t.lis) $(lis t.lis)
@ -1465,7 +1512,7 @@
++ make-prelude ++ make-prelude
|= [pax=pith =file:ford:neo] |= [pax=pith =file:ford:neo]
^- [pith _run] ^- [pith _run]
=/ pre-path=pith =/ pre-path=pith
(slip:press %pre pax) (slip:press %pre pax)
[pre-path (make-deps pre-path (file-to-deps file))] [pre-path (make-deps pre-path (file-to-deps file))]
++ write-hoon ++ write-hoon
@ -1508,11 +1555,13 @@
=. run copy-clay =. run copy-clay
:: =. run (emit %pass /bind-site %arvo %e %connect [~ dap.bowl ~] dap.bowl) :: =. run (emit %pass /bind-site %arvo %e %connect [~ dap.bowl ~] dap.bowl)
=. run (emit do-std-warp) =. run (emit do-std-warp)
=. run =. run
(emit (do-card #/[p/our.bowl]/sky %make %sky `sky/!>([%system [~[%home] ~] 1]) ~)) (emit (do-card #/[p/our.bowl] %make %root ~ ~))
=. run =. run
(emit (do-card #/[p/our.bowl]/sky %make %sky ~ ~))
=. run
(emit (do-card #/[p/our.bowl]/srv/hawk %make %hawk-eyre ~ ~)) (emit (do-card #/[p/our.bowl]/srv/hawk %make %hawk-eyre ~ ~))
=. run =. run
(emit (do-card #/[p/our.bowl]/srv/sky %make %sky-eyre ~ ~)) (emit (do-card #/[p/our.bowl]/srv/sky %make %sky-eyre ~ ~))
run run
++ pess |=(=post:neo (~(pith press post) %out)) ++ pess |=(=post:neo (~(pith press post) %out))
@ -1543,7 +1592,7 @@
^- form:neo ^- form:neo
|_ [=bowl:neo =aeon:neo =pail:neo] |_ [=bowl:neo =aeon:neo =pail:neo]
++ poke ++ poke
|= pok=pail:neo |= pok=pail:neo
^- (quip card:neo pail:neo) ^- (quip card:neo pail:neo)
`pail `pail
:: ::
@ -1623,7 +1672,7 @@
:: ::
:: +arvo: local callstack :: +arvo: local callstack
++ arvo ++ arvo
=+ verb=& =+ verb=|
=/ old state =/ old state
:: data for blocking semantics :: data for blocking semantics
=| =block:neo =| =block:neo
@ -1651,10 +1700,10 @@
|% |%
++ can-ack ++ can-ack
^- ? ^- ?
!?=([%poke %ack *] q.q.init-move) !?=([%poke ?(%ack %rely %dead) *] q.q.init-move)
++ abet ++ abet
^+ run ^+ run
?: =([~ ~] block) ?: =([~ ~] block)
=? run can-ack =? run can-ack
(emil `(list card)`(do-ack [p p.q]:init-move err.block)) (emil `(list card)`(do-ack [p p.q]:init-move err.block))
=. run (emil (turn up do-move)) =. run (emil (turn up do-move))
@ -1714,9 +1763,17 @@
:: ::
++ trace-card ++ trace-card
|= =move:neo |= =move:neo
^- tank ::?: =((snag 1 p.q.move) %srv)
:: same
%- trace
^- tang
:_ ~
:- %leaf :- %leaf
"{(en-tape:pith:neo p.move)} -> {(en-tape:pith:neo p.q.move)}: {<-.q.q.move>}" %+ welp
"{(en-tape:pith:neo p.move)} -> {(en-tape:pith:neo p.q.move)}: "
?+ -.q.q.move (trip -.q.q.move)
%poke "%poke {<p.pail.q.q.move>}"
==
++ trace ++ trace
|= =tang |= =tang
?. verb same ?. verb same
@ -1752,7 +1809,7 @@
$(arvo new-arvo, done (snoc done nex)) $(arvo new-arvo, done (snoc done nex))
++ poke ++ poke
|= =pail:neo |= =pail:neo
^+ arvo :: ^+ arvo ::
=^ cards=(list card:neo) arvo =^ cards=(list card:neo) arvo
(soft-surf |.(su-abet:(su-poke:surf pail))) (soft-surf |.(su-abet:(su-poke:surf pail)))
(ingest cards) (ingest cards)
@ -1760,7 +1817,7 @@
:: XX: a hack :: XX: a hack
:: ::
:: this is implicity recursive, and all external dependencies of :: this is implicity recursive, and all external dependencies of
:: the children need to be woken up. this also breaks referential :: the children need to be woken up. this also breaks referential
:: transparency :: transparency
++ tomb ++ tomb
|= * |= *
@ -1770,6 +1827,7 @@
++ apply ++ apply
|= =move:neo |= =move:neo
^+ arvo ^+ arvo
%- (trace-card move)
?. =(~ err.block) ?. =(~ err.block)
:: skip if we have errored :: skip if we have errored
arvo arvo
@ -1777,7 +1835,6 @@
=. src (de-pith:name:neo p.move) =. src (de-pith:name:neo p.move)
=/ =name:neo (de-pith:name:neo p.q.move) =/ =name:neo (de-pith:name:neo p.q.move)
=. here +:p.q.move =. here +:p.q.move
%- (trace leaf/"{<-.q.q.move>} {(spud (pout here))}" ~)
?- -.q.q.move ?- -.q.q.move
%make (make +.q.q:move) %make (make +.q.q:move)
%poke (poke +.q.q:move) %poke (poke +.q.q:move)
@ -1811,28 +1868,47 @@
work work
:: ::
++ jazz ++ jazz
=| bad=(set term)
|= [=conf:neo =deps:neo] |= [=conf:neo =deps:neo]
^- [bad=(set term) block=(set tour:neo)] ^+ [bad arvo]
%+ roll ~(tap by deps) =/ deps ~(tap by deps)
|= [[=term required=? =quay:neo] bad=(set term) block=(set hunt:neo)] |- ^+ [bad arvo]
?~ deps
[bad arvo]
=/ [=term =deed:neo =quay:neo] i.deps
=/ req=?
?@(deed deed req.deed)
=/ timeout=(unit @dr)
?@(deed ~ time.deed)
=/ =care:neo (get-care:quay:neo quay) =/ =care:neo (get-care:quay:neo quay)
?: &(required !(~(has by conf) term)) ?: &(req !(~(has by conf) term))
:_(block (~(put in bad) term)) =. bad (~(put in bad) term)
?: &(!required !(~(has by conf) term)) $(deps t.deps)
[bad block] ?: &(!req !(~(has by conf) term))
$(deps t.deps)
=/ pit=pith:neo (~(got by conf) term) =/ pit=pith:neo (~(got by conf) term)
=/ res (look care pit) =/ res (look care pit)
=/ nam=name:neo (de-pith:name:neo pit) =/ nam=name:neo (de-pith:name:neo pit)
?~ res ?~ res
?: =(our.bowl ship.nam) ?: =(our.bowl ship.nam)
?. required ?. req
[bad block] $(deps t.deps)
:_(block (~(put in bad) term)) =. bad (~(put in bad) term)
[bad (~(put in block) care pit)] $(deps t.deps)
?~ u.res ?: &(=(timeout `0) req)
:_(block (~(put in bad) term)) =. bad (~(put in bad) term)
[bad block] :: $(deps t.deps)
:: =? get.block req
(~(put in get.block) care pit)
=. run abet:(~(start sale pit) [p/our.bowl here] care)
=? run !req
(stalk:rage care^pit %rely term here)
$(deps t.deps)
?^ u.res
$(deps t.deps)
=. bad (~(put in bad) term)
$(deps t.deps)
::
++ dance ++ dance
|= [=crew:neo =band:neo] |= [=crew:neo =band:neo]
^+ arvo ^+ arvo
@ -1841,11 +1917,13 @@
?~ cew ?~ cew
arvo arvo
=/ [=term =pith:neo] i.cew =/ [=term =pith:neo] i.cew
=/ d=(unit [req=? =quay:neo]) (~(get by band) term) =/ d=(unit [=deed:neo =quay:neo]) (~(get by band) term)
:: skip extraneous, XX: is correct? :: skip extraneous, XX: is correct?
?~ d ?~ d
$(cew t.cew) $(cew t.cew)
=/ [req=? =quay:neo] u.d =/ [=deed:neo =quay:neo] u.d
=/ req=?
?@(deed deed req.deed)
=/ =hunt:neo [(get-care:quay:neo quay) pith] =/ =hunt:neo [(get-care:quay:neo quay) pith]
=/ =name:neo (de-pith:name:neo pith) =/ =name:neo (de-pith:name:neo pith)
?: &(req =(~ (moor quay name))) ?: &(req =(~ (moor quay name)))
@ -1873,9 +1951,9 @@
:: ::
++ make ++ make
|= [src=stud:neo init=(unit pail:neo) =crew:neo] |= [src=stud:neo init=(unit pail:neo) =crew:neo]
=/ =wave:neo [src ~(dock husk src) crew] =/ =wave:neo [src ~(dock husk src) crew &]
=. tide (~(put of:neo tide) here wave) =. tide (~(put of:neo tide) here wave)
=^ bad=(set term) get.block =^ bad=(set term) arvo
(jazz crew deps:~(kook husk src)) (jazz crew deps:~(kook husk src))
?. =(~ get.block) ?. =(~ get.block)
arvo arvo
@ -1913,19 +1991,22 @@
=| cards=(list card:neo) =| cards=(list card:neo)
=/ =kook:neo ~(kook husk code.wave) =/ =kook:neo ~(kook husk code.wave)
=. dock.wave ~(dock husk code.wave) =. dock.wave ~(dock husk code.wave)
?. live.wave
~| dead-wave/here
!!
|% |%
++ su-core . ++ su-core .
++ su-emil |=(caz=(list card:neo) su-core(cards (welp cards caz))) ++ su-emil |=(caz=(list card:neo) su-core(cards (welp cards caz)))
++ su-bowl ++ su-bowl
=/ hare [p/our.bowl here] =/ hare [p/our.bowl here]
^- bowl:neo ^- bowl:neo
:* src :* src
our.bowl our.bowl
hare hare
hare hare
now.bowl now.bowl
eny.bowl eny.bowl
su-deps su-deps
su-kids su-kids
== ==
++ su-icon ++ su-icon
@ -1950,18 +2031,19 @@
%- ~(gas by *(map term [pith lore:neo])) %- ~(gas by *(map term [pith lore:neo]))
^- (list [term pith lore:neo]) ^- (list [term pith lore:neo])
%+ murn ~(tap by deps:kook) %+ murn ~(tap by deps:kook)
|= [=term required=? =quay:neo] |= [=term =deed:neo =quay:neo]
^- (unit [^term pith:neo lore:neo]) ^- (unit [^term pith:neo lore:neo])
=/ dep=(unit pith) (~(get by crew.wave) term) =/ dep=(unit pith) (~(get by crew.wave) term)
=/ req ?@(deed deed req.deed)
?~ dep ?~ dep
~| invariant-missing-required-conf/term ~| invariant-missing-required-conf/term
?< required ?< req
~ ~
=/ =name:neo (de-pith:name:neo u.dep) =/ =name:neo (de-pith:name:neo u.dep)
=/ =care:neo (get-care:quay:neo quay) =/ =care:neo (get-care:quay:neo quay)
?~ lor=(moor quay name) ?~ lor=(moor quay name)
?< required ?< req
~ `[term u.dep *lore:neo]
:: %- (slog term (epic:dbug:neo epic) ~) :: %- (slog term (epic:dbug:neo epic) ~)
`[term u.dep u.lor] `[term u.dep u.lor]
:: ::
@ -1986,13 +2068,20 @@
++ su-give ++ su-give
|= =gift:neo |= =gift:neo
?. (~(has in poke.dock.wave) %gift) ?. (~(has in poke.dock.wave) %gift)
~& skipping-give/here :: ~& skipping-give/here
su-core su-core
(su-poke gift/!>(gift)) (su-poke gift/!>(gift))
:: ::
++ su-poke ++ su-poke
|= =pail:neo |= =pail:neo
^+ su-core ^+ su-core
=? live.wave =(p.pail %dead)
=+ !<(dead=term q.pail)
?~ dep=(~(get by deps:kook) dead)
&
=/ [=deed:neo =quay:neo] u.dep
?@ deed !deed
!req.deed
?. (~(has in poke.dock.wave) p.pail) ?. (~(has in poke.dock.wave) p.pail)
?: ?=(%ack p.pail) ?: ?=(%ack p.pail)
%. su-core %. su-core
@ -2000,6 +2089,8 @@
?~ ack ?~ ack
same same
(slog (print-quit:neo u.ack)) (slog (print-quit:neo u.ack))
?: |(=(%dead p.pail) =(%rely p.pail))
su-core
(mean leaf/"no support for {<p.pail>}" ~) (mean leaf/"no support for {<p.pail>}" ~)
=/ [caz=(list card:neo) new=pail:neo] =/ [caz=(list card:neo) new=pail:neo]
(poke:su-form pail) (poke:su-form pail)
@ -2091,9 +2182,7 @@
^- $-(vase vase) ^- $-(vase vase)
?~ as.peer |=(=vase vase) ?~ as.peer |=(=vase vase)
.^(tube:clay %cc (welp /(scot %p our.bowl)/[r.p.u.p.syn]/(scot %da now.bowl) /(rear kid)/[u.as.peer])) .^(tube:clay %cc (welp /(scot %p our.bowl)/[r.p.u.p.syn]/(scot %da now.bowl) /(rear kid)/[u.as.peer]))
~& res/~(key by ~(tar of res))
=. res (~(dip of res) path.peer) =. res (~(dip of res) path.peer)
~& res/~(key by ~(tar of res))
=/ =note:neo [%poke %clay-res !>(`res:clay:neo`[hand case res])] =/ =note:neo [%poke %clay-res !>(`res:clay:neo`[hand case res])]
~& sending-to/src ~& sending-to/src
=/ =move:neo [[p/our.bowl #/$/clay] src note] =/ =move:neo [[p/our.bowl #/$/clay] src note]
@ -2120,7 +2209,7 @@
++ on-start-peek ++ on-start-peek
|= [src=pith:neo freq=@dr] |= [src=pith:neo freq=@dr]
^+ run ^+ run
=/ =peek:gall:neo =/ =peek:gall:neo
(~(gut by peek.gall.unix) pith [~ ~h24]) (~(gut by peek.gall.unix) pith [~ ~h24])
=. refresh.peek (min freq refresh.peek) =. refresh.peek (min freq refresh.peek)
=/ new=? =(~ src.peek) =/ new=? =(~ src.peek)
@ -2133,7 +2222,7 @@
++ on-stop-peek ++ on-stop-peek
|= src=pith:neo |= src=pith:neo
^+ run ^+ run
=/ =peek:gall:neo =/ =peek:gall:neo
(~(gut by peek.gall.unix) pith [~ ~h24]) (~(gut by peek.gall.unix) pith [~ ~h24])
=. src.peek (~(del in src.peek) src) =. src.peek (~(del in src.peek) src)
=. peek.gall.unix =. peek.gall.unix
@ -2150,7 +2239,7 @@
++ on-read-peek ++ on-read-peek
=/ =road:neo pith =/ =road:neo pith
?> ?=([dude=@ rest=*] road) ?> ?=([dude=@ rest=*] road)
=/ pax =/ pax
%+ welp /(scot %p our.bowl)/[dude.road]/(scot %da now.bowl) %+ welp /(scot %p our.bowl)/[dude.road]/(scot %da now.bowl)
(pout rest.road) (pout rest.road)
=/ =pail:neo noun/!>(.^(* %gx pax)) =/ =pail:neo noun/!>(.^(* %gx pax))
@ -2206,7 +2295,7 @@
?> ?=([%behn %wake *] syn) ?> ?=([%behn %wake *] syn)
=/ =time (slav %da da.wir) =/ =time (slav %da da.wir)
=/ timers ~(tap in (~(get ju behn.unix) time)) =/ timers ~(tap in (~(get ju behn.unix) time))
|- |-
?~ timers ?~ timers
=. behn.unix (~(del by behn.unix) time) =. behn.unix (~(del by behn.unix) time)
run run
@ -2331,7 +2420,7 @@
=/ rol=stud:neo =/ rol=stud:neo
(fall role %$) (fall role %$)
?~ can=(~(get by con.dive) [p.q.have rol want]) ?~ can=(~(get by con.dive) [p.q.have rol want])
~& missing-can/[p.q.have rol want] :: ~& missing-can/[p.q.have rol want]
~ ~
=/ conv run:~(do con u.can) =/ conv run:~(do con u.can)
~| dead-horse/[p.q.have rol want u.can] ~| dead-horse/[p.q.have rol want u.can]
@ -2348,7 +2437,7 @@
=* loop $ =* loop $
=/ =stud:neo p.q.have =/ =stud:neo p.q.have
?- -.want ?- -.want
%pro %pro
(puff p.want rol have) (puff p.want rol have)
:: ::
%rol %rol
@ -2384,7 +2473,7 @@
:: ::
::?. (~(has by con.fiesta) [p.have want]) ::?. (~(has by con.fiesta) [p.have want])
:: ~ :: ~
:: ::
::=/ conv run:~(do con (~(got by con.fiesta) [p.have want])) ::=/ conv run:~(do con (~(got by con.fiesta) [p.have want]))
::`[want (slam conv q.have)] ::`[want (slam conv q.have)]
:: ::
@ -2432,7 +2521,16 @@
leaf leaf
=. leaf (~(put of:neo leaf) i.lst) =. leaf (~(put of:neo leaf) i.lst)
$(lst t.lst) $(lst t.lst)
::
++ gas-riot
=| =riot:neo
|= lst=(list [pith:neo rave:neo])
^+ riot
?~ lst
riot
=. riot (~(put of:neo riot) i.lst)
$(lst t.lst)
:: ::
++ gas-epic ++ gas-epic
=| =epic:neo =| =epic:neo
@ -2533,13 +2631,22 @@
=/ lom (~(dip of:neo loam) prefix) =/ lom (~(dip of:neo loam) prefix)
=/ fam (~(dip of:neo farm) prefix) =/ fam (~(dip of:neo farm) prefix)
=/ rav (~(dip of:neo riot) prefix) =/ rav (~(dip of:neo riot) prefix)
=/ ton (~(dip of:neo town) prefix)
=/ cit (~(dip of:neo city) (tail prefix))
:- >fam< :- >fam<
:- >rav< :- >rav<
:- >ton<
:- >cit<
%- zing %- zing
%+ turn ~(tap by ~(tar of:neo lom)) %+ turn ~(tap by ~(tar of:neo lom))
|= [=pith:neo =soil:neo] |= [=pith:neo =soil:neo]
:~ >pith< :~ >pith<
>~(key by soil)< >~(key by soil)<
?~ val=(ram:on:soil:neo soil)
leaf/"No data"
?~ q.val.u.val
leaf/"~"
(sell q.u.q.val.u.val)
== ==
:: ::
++ print-dbug ++ print-dbug
@ -2562,4 +2669,3 @@
leaf/"{<p.pail>}" leaf/"{<p.pail>}"
== ==
-- --

View File

@ -20,257 +20,42 @@
:: ::
++ nat-timeout ~s25 ++ nat-timeout ~s25
:: ::
:: How often to check our IP when we know we're not behind a NAT.
::
++ ip-timeout ~m5
::
:: Chosen because it's run by Cloudflare, and others I tried were
:: inconsistently slow.
::
++ ip-reflector 'https://icanhazip.com'
::
+$ card card:agent:gall +$ card card:agent:gall
+$ ship-state ::
$% [%idle ~] +$ state-3
[%poking ~] $: %3
[%http until=@da] mode=?(%formal %informal)
[%waiting until=@da] pokes=@ud
== timer=(unit [=wire date=@da])
+$ state-1 galaxy=@p
$: %1
ships=(set ship)
nonce=@ud
$= plan
$~ [%nat ~]
$% [%nat ~]
[%pub ip=(unit @t)]
==
== ==
-- --
:: ::
%- agent:dbug %- agent:dbug
:: ::
=| state=state-1 =| state=state-3
=> |% => |%
:: Bind for the the writer monad on (quip effect state) ++ galaxy-for
:: |= [=ship =bowl:gall]
++ rind ^- @p
|* [effect=mold state=*] =/ next (sein:title our.bowl now.bowl ship)
|* state-type=mold ?: ?=(%czar (clan:title next))
|= $: m-b=(quip effect state-type) next
fun=$-(state-type (quip effect state-type)) $(ship next)
== ::
^- (quip effect state-type) ++ wait-card
=^ effects-1=(list effect) state m-b |= [=wire now=@da]
=^ effects-2=(list effect) state (fun state) ^- card
[(weld effects-1 effects-2) state] [%pass wire %arvo %b %wait (add nat-timeout now)]
:: ::
++ once ++ ping
|= =cord |= [=ship force=?]
=(cord (scot %uw nonce.state)) ^- (quip card _state)
:: ?: &(!force (gth pokes.state 0) =(ship galaxy.state))
:: Subsystem to keep track of which ships to ping across breaches [~ state]
:: and sponsorship changes :_ state(pokes +(pokes.state), galaxy ship)
:: [%pass /ping %agent [ship %ping] %poke %noun !>(~)]~
++ ships --
|%
++ rind (^rind card state)
++ kick
|= [our=@p now=@da]
^- (quip card _state)
:: ?: =(%czar (clan:title our))
:: `state
::
:: NB: !! This includes our own ship, and for moons, this is
:: what has caused Jael to fetch our own rift from our parent.
:: This role may be taken by Ames's subscription to
:: %public-keys, but this must be tested before changing the
:: behavior here.
::
=/ new-ships (~(gas in *(set ship)) (saxo:title our now our))
=/ removed (~(dif in ships.state) new-ships)
=/ added (~(dif in new-ships) ships.state)
;< new-state=_state rind
?~ removed `state
[[%pass /jael %arvo %j %nuke removed]~ state]
=. state new-state
::
;< new-state=_state rind
?~ added `state
[[%pass /jael %arvo %j %public-keys added]~ state]
=. state new-state
::
:: Kick even if ships weren't added or removed
::
(kick-pings our now new-ships)
::
:: Kick whenever we get a response. We really care about
:: breaches and sponsorship changes.
::
:: Delay until next event in case of breach, so that ames can
:: clear its state.
::
++ take-jael
|= now=@da
^- (quip card _state)
[[%pass /jael/delay %arvo %b %wait now]~ state]
::
++ take-delay kick
--
::
:: Starts pinging a new set of `ships`.
::
++ kick-pings
|= [our=@p now=@da ships=(set ship)]
^- (quip card _state)
=: nonce.state +(nonce.state)
ships.state ships
==
::
?: ?=(%nat -.plan.state)
(kick:nat our)
(kick:pub our now)
::
:: Subsystem for pinging our sponsors when we might be behind a NAT
::
:: Ping each ship every 25 seconds to keep the pinhole open.
:: This is expensive, but if you don't do it and you are behind a
:: NAT, you will stop receiving packets from other ships except
:: during the 30 seconds following each packet you send.
::
++ nat
?> ?=(%nat -.plan.state)
|%
++ rind (^rind card state)
++ kick
|= our=@p
^- (quip card _state)
=/ ships ~(tap in ships.state)
|- ^- (quip card _state)
?~ ships `state
?: =(our i.ships) $(ships t.ships)
;< new-state=_state rind (send-ping i.ships)
=. state new-state
$(ships t.ships)
::
++ send-ping
|= =ship
^- (quip card _state)
:_ state
=/ wire /nat/(scot %uw nonce.state)/ping/(scot %p ship)
[%pass wire %agent [ship %ping] %poke %noun !>(~)]~
::
++ take-ping
|= [now=@da =wire error=(unit tang)]
^- (quip card _state)
?. ?=([%nat @ %ping @ ~] wire) `state
?. (once i.t.wire) `state
=/ ship (slav %p i.t.t.t.wire)
%- (slog ?~(error ~ ['ping: got nack' >ship< u.error]))
:_ state
=/ wire /nat/(scot %uw nonce.state)/wait/(scot %p ship)
[%pass wire %arvo %b %wait (add nat-timeout now)]~
::
++ take-wait
|= =wire
^- (quip card _state)
?. ?=([%nat @ %wait @ ~] wire) `state
?. (once i.t.wire) `state
=/ ship (slav %p i.t.t.t.wire)
(send-ping ship)
--
::
:: Subsystem for pinging our sponsors when we know we're not behind a NAT
::
:: Check our IP address every minute, and only if it changes,
:: ping all our sponsors.
::
++ pub
?> ?=(%pub -.plan.state)
|%
++ rind (^rind card state)
++ kick
|= [our=@p now=@da]
^- (quip card _state)
;< new-state=_state rind (send-pings our)
=. state new-state
::
;< new-state=_state rind check-ip
=. state new-state
::
(set-timer now)
::
++ send-pings
|= our=@p
^- (quip card _state)
:_ state
%+ murn ~(tap in ships.state)
|= =ship
?: =(our ship)
~
=/ wire /pub/(scot %uw nonce.state)/ping/(scot %p ship)
`u=[%pass wire %agent [ship %ping] %poke %noun !>(~)]
::
++ take-pings
|= [=wire error=(unit tang)]
^- (quip card _state)
?. ?=([%pub @ %ping @ ~] wire) `state
?. (once i.t.wire) `state
=/ ship (slav %p i.t.t.t.wire)
%- (slog ?~(error ~ ['ping: got nack' >ship< u.error]))
`state
::
++ check-ip
^- (quip card _state)
:_ state
=/ wire /pub/(scot %uw nonce.state)/ip
=/ =request:http [%'GET' ip-reflector ~ ~]
[%pass wire %arvo %i %request request *outbound-config:iris]~
::
++ take-ip
|= [our=@p =wire resp=client-response:iris]
^- (quip card _state)
?. ?=([%pub @ %ip ~] wire) `state
?. (once i.t.wire) `state
::
?. ?=(%finished -.resp) `state :: will retry in a minute
?. ?=(%200 status-code.response-header.resp)
=* s status-code.response-header.resp
%- (slog leaf+"ping: ip check failed: {<s>}" ~)
`state
::
?~ full-file.resp
%- (slog 'ping: ip check body empty' ~)
`state
::
=* body q.data.u.full-file.resp
?~ body
%- (slog 'ping: ip check body empty' ~)
`state
::
=/ ip (end [3 (dec (met 3 body))] body)
?: =(ip.plan.state `ip) `state
::
=. ip.plan.state `ip
(send-pings our)
::
++ set-timer
|= now=@da
^- (quip card _state)
=/ =wire /pub/(scot %uw nonce.state)/wait
[[%pass wire %arvo %b %wait (add ip-timeout now)]~ state]
::
++ take-wait
|= [our=@p now=@da =wire]
^- (quip card _state)
?. ?=([%pub @ %wait ~] wire) `state
?. (once i.t.wire) `state
;< new-state=_state rind check-ip
=. state new-state
::
(set-timer now)
--
--
%+ verb | %+ verb |
^- agent:gall ^- agent:gall
|_ =bowl:gall |_ =bowl:gall
@ -281,28 +66,73 @@
:: ::
++ on-init ++ on-init
^- [(list card) _this] ^- [(list card) _this]
=. plan.state [%nat ~] =. mode.state %formal
=^ cards state (kick:ships our.bowl now.bowl) =. pokes.state 0
[cards this] =. galaxy.state (galaxy-for our.bowl bowl)
[~ this]
:: ::
++ on-save !>(state)
++ on-load ++ on-load
|= old-vase=vase |= old-vase=vase
|^ |^
=/ old !<(state-any old-vase) =/ old !<(state-any old-vase)
=? old ?=(%0 -.old) (state-0-to-1 old) =? old ?=(%0 -.old) (state-0-to-1 old)
?> ?=(%1 -.old) =? old ?=(%1 -.old) (state-1-to-2 old)
=? old ?=(%2 -.old) (state-2-to-3 old)
?> ?=(%3 -.old)
=. state old =. state old
=^ cards state (kick:ships our.bowl now.bowl) [~ this]
[cards this]
:: ::
+$ state-any $%(state-0 state-1) +$ ship-state
+$ state-0 [%0 ships=(map ship [=rift =ship-state])] $% [%idle ~]
[%poking ~]
[%http until=@da]
[%waiting until=@da]
==
+$ state-any $%(state-0 state-1 state-2 state-3)
+$ state-0 [%0 ships=(map ship [=rift =ship-state])]
+$ state-1
$: %1
ships=(set ship)
nonce=@ud
$= plan
$~ [%nat ~]
$% [%nat ~]
[%pub ip=(unit @t)]
== ==
+$ state-2
$: %2
ships=(set ship)
nonce=@ud
$= plan
$~ [%nat ~]
$% [%nat ~]
[%pub ip=(unit @t)]
[%off ~]
[%one ~]
==
==
:: ::
++ state-0-to-1 ++ state-0-to-1
|= old=state-0 |= old=state-0
^- state-1 ^- state-1
[%1 ~ 0 %nat ~] [%1 ~ 0 %nat ~]
::
++ state-1-to-2
|= old=state-1
^- state-2
old(- %2)
::
++ state-2-to-3
|= old=state-2
^- state-3
:* %3 %formal 0 ~
=/ galaxy=(list @p)
%+ skim ~(tap in ships.old)
|=(p=@p ?=(%czar (clan:title p)))
?: =(1 (lent galaxy))
-.galaxy
(head (flop (^saxo:title our.bowl)))
==
-- --
:: +on-poke: positively acknowledge pokes :: +on-poke: positively acknowledge pokes
:: ::
@ -311,20 +141,21 @@
?. =(our src):bowl :: don't crash, this is where pings are handled ?. =(our src):bowl :: don't crash, this is where pings are handled
`this `this
:: ::
?: ?=(%czar (clan:title our.bowl))
`this
::
=^ cards state =^ cards state
?: =(q.vase %kick) :: NB: ames calls this on %born ?: ?=([%kick ?] q.vase)
(kick:ships our.bowl now.bowl) =? mode.state =(+.q.vase %.y)
?: =(q.vase %nat) %formal
=. plan.state [%nat ~] (ping (galaxy-for our.bowl bowl) %.n)
(kick:ships our.bowl now.bowl) ::
?: =(q.vase %no-nat) ?: |(=(q.vase %once) =(q.vase %stop)) :: NB: ames calls this on %once
=. plan.state [%pub ~] =. mode.state %informal
(kick:ships our.bowl now.bowl) (ping (galaxy-for our.bowl bowl) %.y)
`state `state
[cards this] [cards this]
:: ::
++ on-watch on-watch:def
++ on-leave on-leave:def
++ on-peek ++ on-peek
|= =path |= =path
^- (unit (unit cage)) ^- (unit (unit cage))
@ -334,19 +165,18 @@
++ on-agent ++ on-agent
|= [=wire =sign:agent:gall] |= [=wire =sign:agent:gall]
^- [(list card) _this] ^- [(list card) _this]
=^ cards state ?. ?=([%ping *] wire)
?+ wire `state `this
[%nat *] ?. ?=(%poke-ack -.sign)
?. ?=(%nat -.plan.state) `state `this
?. ?=(%poke-ack -.sign) `state =. pokes.state (dec pokes.state)
(take-ping:nat now.bowl wire p.sign) ?. =(pokes.state 0)
:: `this
[%pub *] ?. |(?=(%formal mode.state) ?=(^ p.sign))
?. ?=(%pub -.plan.state) `state `this
?. ?=(%poke-ack -.sign) `state =/ wir /wait
(take-pings:pub wire p.sign) =. timer.state `[wir now.bowl]
== [[(wait-card wir now.bowl)]~ this]
[cards this]
:: +on-arvo: handle timer firing :: +on-arvo: handle timer firing
:: ::
++ on-arvo ++ on-arvo
@ -354,36 +184,22 @@
^- [(list card) _this] ^- [(list card) _this]
=^ cards state =^ cards state
?+ wire `state ?+ wire `state
[%jael %delay ~] [%wait *]
?: ?=(%czar (clan:title our.bowl))
`state
?. ?=(%formal mode.state) `state
?> ?=(%wake +<.sign-arvo) ?> ?=(%wake +<.sign-arvo)
?^ error.sign-arvo ?^ error.sign-arvo
%- (slog 'ping: strange jael wake fail!' u.error.sign-arvo) %- (slog 'ping: strange wake fail!' u.error.sign-arvo)
`state `state
(take-delay:ships our.bowl now.bowl) =. timer.state ~
(ping (galaxy-for our.bowl bowl) %.n)
:: ::
[%jael ~]
?> ?=(%public-keys +<.sign-arvo)
(take-jael:ships now.bowl)
::
[%nat *]
?. ?=(%nat -.plan.state) `state
?> ?=(%wake +<.sign-arvo)
?^ error.sign-arvo
%- (slog 'ping: strange nat wake fail!' u.error.sign-arvo)
`state
(take-wait:nat wire)
::
[%pub @ %ip *]
?. ?=(%pub -.plan.state) `state
?> ?=(%http-response +<.sign-arvo)
(take-ip:pub our.bowl wire client-response.sign-arvo)
::
[%pub @ %wait *]
?. ?=(%pub -.plan.state) `state
?> ?=(%wake +<.sign-arvo)
(take-wait:pub our.bowl now.bowl wire)
== ==
[cards this] [cards this]
:: ::
++ on-save !>(state)
++ on-fail on-fail:def ++ on-fail on-fail:def
++ on-watch on-watch:def
++ on-leave on-leave:def
-- --

View File

@ -14,7 +14,7 @@
$: starting=(map yarn [=trying =vase]) $: starting=(map yarn [=trying =vase])
running=(axal thread-form) running=(axal thread-form)
tid=(map tid yarn) tid=(map tid yarn)
serving=(map tid [(unit @ta) =mark =desk]) serving=(map tid [(unit [rid=@ta take=?(%json %noun)]) =mark =desk])
scrying=(jug tid [=wire =ship =path]) scrying=(jug tid [=wire =ship =path])
== ==
:: ::
@ -26,10 +26,20 @@
clean-slate-3 clean-slate-3
clean-slate-4 clean-slate-4
clean-slate-5 clean-slate-5
clean-slate-6
clean-slate clean-slate
== ==
:: ::
+$ clean-slate +$ clean-slate
$: %7
starting=(map yarn [=trying =vase])
running=(list yarn)
tid=(map tid yarn)
serving=(map tid [(unit [rid=@ta take=?(%json %noun)]) =mark =desk])
scrying=(jug tid [wire ship path])
==
::
+$ clean-slate-6
$: %6 $: %6
starting=(map yarn [=trying =vase]) starting=(map yarn [=trying =vase])
running=(list yarn) running=(list yarn)
@ -121,7 +131,8 @@
=. any (old-to-4 any) =. any (old-to-4 any)
=. any (old-to-5 any) =. any (old-to-5 any)
=. any (old-to-6 any) =. any (old-to-6 any)
?> ?=(%6 -.any) =. any (old-to-7 any)
?> ?=(%7 -.any)
:: ::
=. tid.state tid.any =. tid.state tid.any
=/ yarns=(list yarn) =/ yarns=(list yarn)
@ -148,8 +159,8 @@
++ old-to-2 ++ old-to-2
|= old=clean-slate-any |= old=clean-slate-any
^- (quip card clean-slate-any) ^- (quip card clean-slate-any)
?> ?=(?(%1 %2 %3 %4 %5 %6) -.old) ?> ?=(?(%1 %2 %3 %4 %5 %6 %7) -.old)
?: ?=(?(%2 %3 %4 %5 %6) -.old) ?: ?=(?(%2 %3 %4 %5 %6 %7) -.old)
`old `old
:- ~[bind-eyre:sc] :- ~[bind-eyre:sc]
:* %2 :* %2
@ -162,8 +173,8 @@
++ old-to-3 ++ old-to-3
|= old=clean-slate-any |= old=clean-slate-any
^- clean-slate-any ^- clean-slate-any
?> ?=(?(%2 %3 %4 %5 %6) -.old) ?> ?=(?(%2 %3 %4 %5 %6 %7) -.old)
?: ?=(?(%3 %4 %5 %6) -.old) ?: ?=(?(%3 %4 %5 %6 %7) -.old)
old old
:* %3 :* %3
starting.old starting.old
@ -175,8 +186,8 @@
++ old-to-4 ++ old-to-4
|= old=clean-slate-any |= old=clean-slate-any
^- clean-slate-any ^- clean-slate-any
?> ?=(?(%3 %4 %5 %6) -.old) ?> ?=(?(%3 %4 %5 %6 %7) -.old)
?: ?=(?(%4 %5 %6) -.old) ?: ?=(?(%4 %5 %6 %7) -.old)
old old
:* %4 :* %4
starting.old starting.old
@ -188,15 +199,15 @@
++ old-to-5 ++ old-to-5
|= old=clean-slate-any |= old=clean-slate-any
^- clean-slate-any ^- clean-slate-any
?> ?=(?(%4 %5 %6) -.old) ?> ?=(?(%4 %5 %6 %7) -.old)
?: ?=(?(%5 %6) -.old) old ?: ?=(?(%5 %6 %7) -.old) old
[%5 +.old(serving [serving.old ~])] [%5 +.old(serving [serving.old ~])]
:: ::
++ old-to-6 ++ old-to-6
|= old=clean-slate-any |= old=clean-slate-any
^- clean-slate ^- clean-slate-any
?> ?=(?(%5 %6) -.old) ?> ?=(?(%5 %6 %7) -.old)
?: ?=(%6 -.old) old ?: ?=(?(%6 %7) -.old) old
:- %6 :- %6
%= +.old %= +.old
scrying scrying
@ -208,6 +219,16 @@
:: ::
[/keen ship path]~ [/keen ship path]~
== ==
::
++ old-to-7
|= old=clean-slate-any
^- clean-slate-any
?> ?=(?(%6 %7) -.old)
?: ?=(%7 -.old) old
=- old(- %7, serving -)
%- ~(run by serving.old)
|= [request=(unit @ta) =mark =desk]
[(bind request (late %json)) mark desk]
-- --
:: ::
++ on-poke ++ on-poke
@ -309,15 +330,36 @@
=* input-mark i.t.t.site.url =* input-mark i.t.t.site.url
=* thread i.t.t.t.site.url =* thread i.t.t.t.site.url
=* output-mark i.t.t.t.t.site.url =* output-mark i.t.t.t.t.site.url
=/ =tid (new-thread-id thread)
=. serving.state
(~(put by serving.state) tid [`eyre-id output-mark desk])
:: TODO: speed this up somehow. we spend about 15ms in this arm alone :: TODO: speed this up somehow. we spend about 15ms in this arm alone
:: ::
=/ tube (convert-tube %json input-mark desk bowl)
?> ?=(^ body.request.inbound-request) ?> ?=(^ body.request.inbound-request)
=/ body=json (need (de:json:html q.u.body.request.inbound-request)) =/ test=$-(@t ?(%json %noun))
=/ input=vase (slop !>(~) (tube !>(body))) |= head=@t
=; type=(unit @t)
?:(=(`'application/x-urb-jam' type) %noun %json)
%+ bind
(get-header:http head header-list.request.inbound-request)
:(cork trip cass crip)
=/ give (test 'content-type')
=/ take (test 'accept')
::
=/ =tid (new-thread-id thread)
=. serving.state
(~(put by serving.state) tid [`[eyre-id take] output-mark desk])
::
=/ input=vase
%+ slop !>(~)
?- give
%json
=/ tube (convert-tube %json input-mark desk bowl)
=/ body=json (need (de:json:html q.u.body.request.inbound-request))
(tube !>(body))
::
%noun
=/ tube (convert-tube %noun input-mark desk bowl)
=/ body=noun (cue q.u.body.request.inbound-request)
(tube !>(body))
==
=/ boc bec =/ boc bec
=/ =start-args:spider [~ `tid boc(q desk, r da+now.bowl) thread input] =/ =start-args:spider [~ `tid boc(q desk, r da+now.bowl) thread input]
(handle-start-thread start-args) (handle-start-thread start-args)
@ -490,8 +532,9 @@
^- [(list card) _state] ^- [(list card) _state]
%+ roll cards.r %+ roll cards.r
|= [=card cards=(list card) s=_state] |= [=card cards=(list card) s=_state]
:_ =? scrying.s ?=([%pass ^ %arvo %a %keen @ *] card) :_ =? scrying.s ?=([%pass ^ %arvo %a %keen ?(~ ^) @ *] card)
(~(put ju scrying.s) tid [&2 &6 |6]:card) :: &2=wire &7=ship 7|=path
(~(put ju scrying.s) tid [&2 &7 |7]:card)
s s
:_ cards :_ cards
^- ^card ^- ^card
@ -549,18 +592,25 @@
=- (fall - `state) =- (fall - `state)
%+ bind %+ bind
(~(get by serving.state) tid) (~(get by serving.state) tid)
|= [eyre-id=(unit @ta) output=mark =desk] |= [request=(unit [rid=@ta take=?(%json %noun)]) output=mark =desk]
:_ state(serving (~(del by serving.state) tid)) :_ state(serving (~(del by serving.state) tid))
?~ eyre-id ?~ request
~ ~
%+ give-simple-payload:app:server u.eyre-id %+ give-simple-payload:app:server rid.u.request
^- simple-payload:http ^- simple-payload:http
?. ?=(http-error:spider term) ?. ?=(http-error:spider term)
%- (slog tang) %- (slog tang)
=/ tube (convert-tube %tang %json desk bowl) ?- take.u.request
:- [500 [['content-type' 'application/json'] ~]] %json
=- `(as-octs:mimes:html (en:json:html -)) =/ tube (convert-tube %tang %json desk bowl)
o/(malt `(list [key=@t json])`[term+s/term tang+!<(json (tube !>(tang))) ~]) :- [500 [['content-type' 'application/json'] ~]]
=- `(as-octs:mimes:html (en:json:html -))
o/(malt `(list [key=@t json])`[term+s/term tang+!<(json (tube !>(tang))) ~])
::
%noun
:- [500 [['content-type' 'application/x-urb-jam'] ~]]
`(as-octs:mimes:html (jam [term tang]))
==
:_ ~ :_ ~ :_ ~ :_ ~
?- term ?- term
%bad-request 400 %bad-request 400
@ -587,13 +637,22 @@
=- (fall - `state) =- (fall - `state)
%+ bind %+ bind
(~(get by serving.state) tid) (~(get by serving.state) tid)
|= [eyre-id=(unit @ta) output=mark =desk] |= [request=(unit [rid=@ta take=?(%json %noun)]) output=mark =desk]
?~ eyre-id ?~ request
`state `state
=/ tube (convert-tube output %json desk bowl) ?- take.u.request
:_ state(serving (~(del by serving.state) tid)) %json
%+ give-simple-payload:app:server u.eyre-id =/ tube (convert-tube output %json desk bowl)
(json-response:gen:server !<(json (tube vase))) :_ state(serving (~(del by serving.state) tid))
%+ give-simple-payload:app:server rid.u.request
(json-response:gen:server !<(json (tube vase)))
::
%noun
:_ state(serving (~(del by serving.state) tid))
%+ give-simple-payload:app:server rid.u.request
:- [200 ['content-type' 'application/x-urb-jam']~]
`(as-octs:mimes:html (jam q.vase))
==
:: ::
++ thread-done ++ thread-done
|= [=yarn =vase silent=?] |= [=yarn =vase silent=?]
@ -680,7 +739,7 @@
:: ::
++ clean-state ++ clean-state
!> ^- clean-slate !> ^- clean-slate
6+state(running (turn ~(tap of running.state) head)) 7+state(running (turn ~(tap of running.state) head))
:: ::
++ convert-tube ++ convert-tube
|= [from=mark to=mark =desk =bowl:gall] |= [from=mark to=mark =desk =bowl:gall]

View File

@ -2,7 +2,8 @@
!: !:
|% |%
+$ card card:agent:gall +$ card card:agent:gall
+$ test ?(%agents %marks %generators) +$ command $@(=test [=desk =test])
+$ test ?(%agents %marks %generators %threads)
+$ state +$ state
$: app=(set path) $: app=(set path)
app-ok=? app-ok=?
@ -10,9 +11,10 @@
mar-ok=? mar-ok=?
gen=(set path) gen=(set path)
gen-ok=? gen-ok=?
ted=(set path)
ted-ok=?
== ==
-- --
=, format
^- agent:gall ^- agent:gall
=| =state =| =state
|_ =bowl:gall |_ =bowl:gall
@ -26,12 +28,16 @@
|= [=mark =vase] |= [=mark =vase]
^- [(list card) _this] ^- [(list card) _this]
?> (team:title [our src]:bowl) ?> (team:title [our src]:bowl)
=+ !<(cmd=command vase)
=? cmd ?=(@ cmd)
[q.byk.bowl test.cmd]
?> ?=(^ cmd)
|^ |^
=+ !<(=test vase) ?- test.cmd
?- test %marks test-marks
%marks test-marks %agents test-agents
%agents test-agents
%generators test-generators %generators test-generators
%threads test-threads
== ==
:: ::
++ test-marks ++ test-marks
@ -51,7 +57,7 @@
|=(c=@tD `@tD`?:(=('/' c) '-' c)) |=(c=@tD `@tD`?:(=('/' c) '-' c))
=/ sing=card =/ sing=card
:+ %pass /build/mar/[mak] :+ %pass /build/mar/[mak]
[%arvo %c %warp our.bowl q.byk.bowl ~ %sing %b da+now.bowl /[mak]] [%arvo %c %warp our.bowl desk.cmd ~ %sing %b da+now.bowl /[mak]]
%_ $ %_ $
paz t.paz paz t.paz
fex [sing fex] fex [sing fex]
@ -73,7 +79,7 @@
$(daz t.daz) $(daz t.daz)
=/ sing=card =/ sing=card
:+ %pass /build/app/[i.daz] :+ %pass /build/app/[i.daz]
[%arvo %c %warp our.bowl q.byk.bowl ~ %sing %a da+now.bowl dap-pax] [%arvo %c %warp our.bowl desk.cmd ~ %sing %a da+now.bowl dap-pax]
%_ $ %_ $
daz t.daz daz t.daz
fex [sing fex] fex [sing fex]
@ -93,14 +99,33 @@
$(paz t.paz) $(paz t.paz)
=/ sing=card =/ sing=card
:+ %pass build+i.paz :+ %pass build+i.paz
[%arvo %c %warp our.bowl q.byk.bowl ~ %sing %a da+now.bowl i.paz] [%arvo %c %warp our.bowl desk.cmd ~ %sing %a da+now.bowl i.paz]
%_ $ %_ $
paz t.paz paz t.paz
fex [sing fex] fex [sing fex]
gen.state (~(put in gen.state) i.paz) gen.state (~(put in gen.state) i.paz)
== ==
:: ::
++ now-beak %_(byk.bowl r [%da now.bowl]) ++ test-threads
=| fex=(list card)
^+ [fex this]
?> =(~ ted.state)
=. ted-ok.state %.y
=+ .^(paz=(list path) ct+(en-beam now-beak /ted))
|- ^+ [fex this]
?~ paz [(flop fex) this]
=/ xap=path (flop i.paz)
?. ?=([%hoon *] xap)
$(paz t.paz)
=/ sing=card
:+ %pass build+i.paz
[%arvo %c %warp our.bowl desk.cmd ~ %sing %a da+now.bowl i.paz]
%_ $
paz t.paz
fex [sing fex]
ted.state (~(put in ted.state) i.paz)
==
++ now-beak [our.bowl desk.cmd da+now.bowl]
-- --
++ on-watch on-watch:def ++ on-watch on-watch:def
++ on-leave on-leave:def ++ on-leave on-leave:def
@ -150,6 +175,15 @@
~? =(~ gen.state) ~? =(~ gen.state)
?:(gen-ok.state %all-generators-built %some-generators-failed) ?:(gen-ok.state %all-generators-built %some-generators-failed)
[~ this] [~ this]
::
[%ted *]
=/ ok ?=(^ p.sign-arvo)
%- (report path ok)
=? ted-ok.state !ok %.n
=. ted.state (~(del in ted.state) path)
~? =(~ ted.state)
?:(ted-ok.state %all-threads-built %some-threads-failed)
[~ this]
== ==
++ on-fail on-fail:def ++ on-fail on-fail:def
-- --

View File

@ -0,0 +1,161 @@
:: verb-logger: serializes verb-plus events to unix-side json
::
:: watches specified agents for "verb plus" events, buffers those, and
:: periodically (+write-interval) flushes them out to unix, under the
:: .urb/put/verb-logger/[agent] directory of the pier.
::
/+ verb, dbug, verb-json
::
|%
+$ state-0
$: %0
events=(jar dude:gall event-plus:verb)
==
::
+$ card card:agent:gall
::
++ write-interval ~h1
::
++ write-events
|= [our=ship =dude:gall events=(list event-plus:verb)]
^- (list card)
?: =(~ events) ~ ::NOTE tmi
=/ first=event-plus:verb
(rear events)
=/ pax=path
/verb-logger/[dude]/(crip (a-co:co (unm:chrono:userlib now.first)))/json
=/ vex=@
(en:json:html (events:enjs our dude events))
[%pass /write/[dude] %agent [our %hood] %poke %drum-put !>([pax vex])]~
::
++ ingest-event
|= $: our=ship
events=(jar dude:gall event-plus:verb)
[=dude:gall event=event-plus:verb]
==
^- (quip card _events)
?~ ves=(~(get ja events) dude)
:- ~
(~(put by events) dude [event ~])
?: .= (sub now.i.ves (mod now.i.ves write-interval))
(sub now.event (mod now.event write-interval))
:- ~
(~(put by events) dude [event ves])
:- (write-events our dude ves)
(~(put by events) dude [event ~])
::
++ enjs
=, enjs:format
|%
++ events
|= [our=@p =dude:gall events=(list event-plus:verb)] :: latest-first
=/ first=event-plus:verb (rear events)
%- pairs
:~ 'ship'^s+(scot %p our)
'dude'^s+dude
'from'^(time now.first)
::
:- 'events'
:- %a
%+ roll events ::NOTE we +roll to +turn & +flop simultaneously
|= [event=event-plus:verb out=(list json)]
[(event:enjs:verb-json event) out]
==
--
--
::
=| state-0
=* state -
::
%+ verb |
%- agent:dbug
|_ =bowl:gall
+* this .
::
++ on-init
^- (quip card _this)
[~ this]
::
++ on-save
!>(state)
::
++ on-load
|= ole=vase
^- (quip card _this)
[~ this(state !<(state-0 ole))]
::
++ on-poke
|= [=mark =vase]
^- (quip card _this)
?> =(%noun mark)
?+ q.vase !!
[%watch =dude:gall]
=* dude dude.q.vase
:_ this
[%pass /log/[dude] %agent [our.bowl dude] %watch /verb/events-plus]~
::
[%leave =dude:gall]
=* dude dude.q.vase
:- :- [%pass /log/[dude] %agent [our.bowl dude] %leave ~]
(write-events our.bowl dude (~(get ja events) dude))
this(events (~(del by events) dude))
::
[%flush =dude:gall]
|-
=* dude dude.q.vase
?. =(%$ dude)
:- (write-events our.bowl dude (~(get ja events) dude))
this(events (~(del by events) dude))
=| cards=(list card)
=/ dudes=(list dude:gall) ~(tap in ~(key by events))
|- ^- (quip card _this)
?~ dudes [cards this]
=^ caz this ^$(dude.q.vase i.dudes)
=. cards (weld cards caz)
$(dudes t.dudes)
==
::
++ on-agent
|= [=wire =sign:agent:gall]
^- (quip card _this)
~| wire
?+ wire !!
[%write @ ~]
=* dude i.t.wire
?> ?=(%poke-ack -.sign)
?~ p.sign [~ this]
%. [~ this]
%- %*(. slog pri 3)
[(cat 3 'verb-logger: lost export for %' dude) u.p.sign]
::
[%log @ ~]
=* dude i.t.wire
?- -.sign
%poke-ack !!
%kick =- [[-]~ this]
[%pass /log/[dude] %agent [our.bowl dude] %watch /verb/events-plus]
%watch-ack ?~ p.sign [~ this]
%. [~ this]
%- %*(. slog pri 2)
[(cat 3 'verb-logger: failed verb watch for %' dude) u.p.sign]
%fact ?> =(%verb-event-plus p.cage.sign)
=^ caz events
%- ingest-event
[our.bowl events dude !<(event-plus:verb q.cage.sign)]
[caz this]
==
==
::
++ on-fail
|= [=term =tang]
^- (quip card _this)
%. [~ this]
%- %*(. slog pri 3)
:_ tang
(cat 3 'verb-logger: dropping the ball: ' term)
::
++ on-watch |=(* !!)
++ on-leave |=(* !!)
++ on-arvo |=(* !!)
++ on-peek |=(* ~)
--

View File

@ -0,0 +1,16 @@
:: make a unix commit event
::
:: call as > .event/jam +commit-event /path/to/file
:: to be used with ./urbit-binary -I event.jam pier
::
:: XX expand with arbitrary user-defined events?
:: XX only supports files in which +noun:grab in the mark file returns a @t
:: (e.g. hoon files)
::
:- %say
|= [[now=@da eny=@uvJ bec=beak] [=path ~] ~]
:- %noun
?~ beam=(de-beam path)
~|(%path-not-beam !!)
=+ .^(file=@t %cx path)
[/c/sync %info desk=q.u.beam & [s.u.beam %ins %mime !>([/ (as-octs:mimes:html file)])]~]

View File

@ -0,0 +1,6 @@
:- %say
|= $: [now=@da eny=@uvJ bec=beak]
[syd=desk her=ship sud=desk approve=? ~]
~
==
kiln-approve-merge+[[syd her sud] approve]

View File

@ -2,16 +2,36 @@
:: ::
:::: /hoon/cp/hood/gen :::: /hoon/cp/hood/gen
:: ::
:: XX clay discards the type, so %noun is used
:: copy by lobe should be used, if implemented
::
/? 310 /? 310
:- %say :- %say
=, space:userlib =, space:userlib
|= [^ [input=path output=path ~] ~] |= [^ [input=path output=path ~] r=_|]
:- %kiln-info :- %kiln-info
?. =(-:(flop input) -:(flop output)) ^- [mez=tape tor=(unit toro:clay)]
["Can't move to a different mark" ~] ?. r
=+ dir=.^(arch %cy input) ?. =(-:(flop input) -:(flop output))
?~ fil.dir ["Can't move to a different mark" ~]
~& "No such file:" ?~ =<(fil .^(arch %cy input))
[<input> ~] ~& "No such file:"
:- "copied" [<input> ~]
`(foal output -:(flop input) [%atom %t ~] .^(* %cx input)) :: XX type :- "copied"
`(foal output -:(flop input) [%noun .^(* %cx input)])
?~ in-beam=(de-beam input) ["bad input path" ~]
?~ =<(dir .^(arch %cy input)) ["input path isn't a directory" ~]
?~ out-beam=(de-beam output) ["bad output path" ~]
=/ in-beak=beak [p q r]:u.in-beam
=/ out-beak=beak [p q r]:u.out-beam
=/ =soba:clay
%+ murn .^((list path) %ct input)
|= pax=path
?: =(1 (sub (lent pax) (lent s.u.in-beam))) ~
=/ =cage
:- -:(flop pax)
[%noun .^(* %cx (en-beam in-beak pax))]
=/ =spur (weld s.u.out-beam (slag (lent s.u.in-beam) pax))
`[spur (feel (en-beam out-beak spur) cage)]
?~ soba ["nothing to copy" ~]
["copied" `[q.out-beak [%& soba]]]

View File

@ -0,0 +1,6 @@
:- %say
|= $: [now=@da eny=@uvJ bec=beak]
[auto=? ~]
~
==
kiln-global-automerge+auto

View File

@ -0,0 +1,6 @@
:- %say
|= $: [now=@da eny=@uvJ bec=beak]
[old=dock new=dock ~]
~
==
kiln-jump-opt+[old new &]

View File

@ -0,0 +1,16 @@
/+ *generators
:- %ask
|= $: [now=@da eny=@uvJ bec=beak]
[syd=desk her=ship sud=desk ~]
hard=_|
==
?: hard (produce %kiln-jump-propose syd her sud)
=/ msg
leaf+"Are you sure you want to tell subscribers to get ".
"updates for {<syd>} from {<her>}/{(trip sud)}?"
%+ print msg
%+ prompt [%& %prompt "(y/N) "]
|= in=tape
?. |(=("y" in) =("Y" in) =("yes" in))
no-product
(produce %kiln-jump-propose syd her sud)

View File

@ -0,0 +1,6 @@
:- %say
|= $: [now=@da eny=@uvJ bec=beak]
[old=dock new=dock ~]
~
==
kiln-jump-opt+[old new |]

View File

@ -24,6 +24,14 @@
?^ arg ?^ arg
mon.arg mon.arg
(add our (lsh 5 (end 5 (shaz eny)))) (add our (lsh 5 (end 5 (shaz eny))))
=/ ryf=(unit rift)
.^((unit rift) %j /(scot %p p.bec)/ryft/(scot %da now)/(scot %p mon))
?^ ryf
%. ~
%- slog
:~ leaf+"can't create {(scow %p mon)}, it already exists."
'use |moon-breach and/or |moon-cycle-keys instead.'
==
=/ seg=ship (sein:title our now mon) =/ seg=ship (sein:title our now mon)
?. =(our seg) ?. =(our seg)
%- %- slog :_ ~ %- %- slog :_ ~

View File

@ -0,0 +1,6 @@
:- %say
|= $: [now=@da eny=@uvJ bec=beak]
[syd=desk her=ship sud=desk auto=(unit ?) ~]
~
==
kiln-sync-automerge+[[syd her sud] auto]

16
pkg/arvo/gen/jumps.hoon Normal file
View File

@ -0,0 +1,16 @@
/- h=hood
:- %say
|= [[now=@da eny=@uvJ bec=beak] ~ ~]
:- %tang
^- tang
=+ .^ hop=jump:h
%gx
(scot %p p.bec)
%hood
(scot %da now)
/kiln/jumps/noun
==
?> ?=(%all -.hop)
%+ turn ~(tap by all.hop)
|= [old=dock new=dock]
leaf+"{<p.old>}/{(trip q.old)} -> {<p.new>}/{(trip q.new)}"

16
pkg/arvo/gen/updates.hoon Normal file
View File

@ -0,0 +1,16 @@
/- h=hood
:- %say
|= [[now=@da eny=@uvJ bec=beak] ~ ~]
:- %tang
^- tang
=+ .^ upd=sync-update:h
%gx
(scot %p p.bec)
%hood
(scot %da now)
/kiln/pending/noun
==
?> ?=(%pending -.upd)
%+ turn ~(tap in pending.upd)
|= [sync-record:h rev=@ud]
leaf+"{<syd>} <- {<her>}/{(trip sud)}/{<rev>}"

View File

@ -2,6 +2,6 @@
:- %say :- %say
|= [[now=@da eny=@uvJ bec=beak] [syd=desk ~] verb=_&] |= [[now=@da eny=@uvJ bec=beak] [syd=desk ~] verb=_&]
:* %tang :* %tang
leaf+"Notice: +vat is deprecated. use +vats which now takes one or more desks as arguments. e.g. '+vats %base %garden'" leaf+"Notice: +vat is deprecated. use +vats which now takes one or more desks as arguments. e.g. '+vats %base %landscape'"
(report-vat (report-prep p.bec now) p.bec now syd verb) (report-vat (report-prep p.bec now) p.bec now syd verb)
== ==

View File

@ -17,12 +17,4 @@
[filt=@tas verb=_|] [filt=@tas verb=_|]
== ==
:- %tang ^- tang :- %tang ^- tang
?. &(=(~ deks) =(%$ filt)) (report-vats p.bec now deks filt verb)
(report-vats p.bec now deks filt verb)
%- zing
%+ turn
%+ sort
=/ sed .^((set desk) %cd /(scot %p p.bec)//(scot %da now))
(sort ~(tap in sed) |=([a=@ b=@] !(aor a b)))
|=([a=desk b=desk] ?|(=(a %kids) =(b %base)))
|=(syd=desk (report-vat (report-prep p.bec now) p.bec now syd verb))

View File

@ -1070,8 +1070,9 @@
++ wrd :: next or current word ++ wrd :: next or current word
|= a=(list @) |= a=(list @)
=| i=@ud =| i=@ud
?~ a i
|- ^- @ud |- ^- @ud
?: |(?=(~ a) (alnm i.a)) i ?: |(?=(~ t.a) (alnm i.a)) i
$(i +(i), a t.a) $(i +(i), a t.a)
-- --
-- --

View File

@ -5,7 +5,8 @@
=, format =, format
=* dude dude:gall =* dude dude:gall
|% |%
+$ state state-10 +$ state state-11
+$ state-11 [%11 pith-11]
+$ state-10 [%10 pith-10] +$ state-10 [%10 pith-10]
+$ state-9 [%9 pith-9] +$ state-9 [%9 pith-9]
+$ state-8 [%8 pith-9] +$ state-8 [%8 pith-9]
@ -19,7 +20,8 @@
+$ state-0 [%0 pith-0] +$ state-0 [%0 pith-0]
+$ any-state +$ any-state
$~ *state $~ *state
$% state-10 $% state-11
state-10
state-9 state-9
state-8 state-8
state-7 state-7
@ -32,10 +34,32 @@
state-0 state-0
== ==
:: ::
+$ pith-11
$: rem=(map desk per-desk)
nyz=@ud
zyn=(map sync-record sync-state)
:: requests from publishers to switch sync source
hop=(map dock dock)
:: toggle global update auto-merge
mer=?
::
commit-timer=[way=wire nex=@da tim=@dr mon=term]
:: map desk to the currently ongoing fuse request
:: and the latest version numbers for beaks to
fus=(map desk per-fuse)
:: used for fuses - every time we get a fuse we
:: bump this. used when calculating hashes to
:: ensure they're unique even when the same
:: request is made multiple times.
hxs=(map desk @ud)
==
::
+$ sync-state-10 [nun=@ta kid=(unit desk) let=@ud]
::
+$ pith-10 +$ pith-10
$: rem=(map desk per-desk) $: rem=(map desk per-desk)
nyz=@ud nyz=@ud
zyn=(map kiln-sync sync-state) zyn=(map sync-record sync-state-10)
commit-timer=[way=wire nex=@da tim=@dr mon=term] commit-timer=[way=wire nex=@da tim=@dr mon=term]
:: map desk to the currently ongoing fuse request :: map desk to the currently ongoing fuse request
:: and the latest version numbers for beaks to :: and the latest version numbers for beaks to
@ -50,7 +74,7 @@
+$ pith-9 +$ pith-9
$: wef=(unit weft) $: wef=(unit weft)
rem=(map desk per-desk) rem=(map desk per-desk)
syn=(map kiln-sync let=@ud) syn=(map sync-record let=@ud)
ark=(map desk arak-9) ark=(map desk arak-9)
commit-timer=[way=wire nex=@da tim=@dr mon=term] commit-timer=[way=wire nex=@da tim=@dr mon=term]
:: map desk to the currently ongoing fuse request :: map desk to the currently ongoing fuse request
@ -78,7 +102,7 @@
+$ pith-7 +$ pith-7
$: wef=(unit weft) $: wef=(unit weft)
rem=(map desk per-desk) rem=(map desk per-desk)
syn=(map kiln-sync let=@ud) syn=(map sync-record let=@ud)
ark=(map desk arak-7) ark=(map desk arak-7)
commit-timer=[way=wire nex=@da tim=@dr mon=term] commit-timer=[way=wire nex=@da tim=@dr mon=term]
:: map desk to the currently ongoing fuse request :: map desk to the currently ongoing fuse request
@ -121,7 +145,7 @@
+$ pith-6 +$ pith-6
$: wef=(unit weft) $: wef=(unit weft)
rem=(map desk per-desk) :: rem=(map desk per-desk) ::
syn=(map kiln-sync let=@ud) :: syn=(map sync-record let=@ud) ::
ark=(map desk arak-6) :: ark=(map desk arak-6) ::
commit-timer=[way=wire nex=@da tim=@dr mon=term] :: commit-timer=[way=wire nex=@da tim=@dr mon=term] ::
:: map desk to the currently ongoing fuse request :: map desk to the currently ongoing fuse request
@ -139,7 +163,7 @@
:: ::
+$ pith-5 +$ pith-5
$: rem=(map desk per-desk) :: $: rem=(map desk per-desk) ::
syn=(map kiln-sync let=@ud) :: syn=(map sync-record let=@ud) ::
ark=(map desk arak-6) :: ark=(map desk arak-6) ::
commit-timer=[way=wire nex=@da tim=@dr mon=term] :: commit-timer=[way=wire nex=@da tim=@dr mon=term] ::
:: map desk to the currently ongoing fuse request :: map desk to the currently ongoing fuse request
@ -154,7 +178,7 @@
:: ::
+$ pith-4 :: +$ pith-4 ::
$: rem=(map desk per-desk) :: $: rem=(map desk per-desk) ::
syn=(map kiln-sync let=@ud) :: syn=(map sync-record let=@ud) ::
ark=(map desk arak-4) :: ark=(map desk arak-4) ::
commit-timer=[way=wire nex=@da tim=@dr mon=term] :: commit-timer=[way=wire nex=@da tim=@dr mon=term] ::
:: map desk to the currently ongoing fuse request :: map desk to the currently ongoing fuse request
@ -175,7 +199,7 @@
== ==
+$ pith-3 :: +$ pith-3 ::
$: rem=(map desk per-desk) :: $: rem=(map desk per-desk) ::
syn=(map kiln-sync let=@ud) :: syn=(map sync-record let=@ud) ::
ark=(map desk arak-3) :: ark=(map desk arak-3) ::
commit-timer=[way=wire nex=@da tim=@dr mon=term] :: commit-timer=[way=wire nex=@da tim=@dr mon=term] ::
:: map desk to the currently ongoing fuse request :: map desk to the currently ongoing fuse request
@ -201,7 +225,7 @@
:: ::
+$ pith-2 :: +$ pith-2 ::
$: rem=(map desk per-desk) :: $: rem=(map desk per-desk) ::
syn=(map kiln-sync let=@ud) :: syn=(map sync-record let=@ud) ::
ota=(unit [=ship =desk =aeon]) :: ota=(unit [=ship =desk =aeon]) ::
commit-timer=[way=wire nex=@da tim=@dr mon=term] :: commit-timer=[way=wire nex=@da tim=@dr mon=term] ::
fus=(map desk per-fuse) fus=(map desk per-fuse)
@ -209,13 +233,13 @@
== :: == ::
+$ pith-1 :: +$ pith-1 ::
$: rem=(map desk per-desk) :: $: rem=(map desk per-desk) ::
syn=(map kiln-sync let=@ud) :: syn=(map sync-record let=@ud) ::
ota=(unit [=ship =desk =aeon]) :: ota=(unit [=ship =desk =aeon]) ::
commit-timer=[way=wire nex=@da tim=@dr mon=term] :: commit-timer=[way=wire nex=@da tim=@dr mon=term] ::
== :: == ::
+$ pith-0 :: +$ pith-0 ::
$: rem=(map desk per-desk) :: $: rem=(map desk per-desk) ::
syn=(map kiln-sync let=@ud) :: syn=(map sync-record let=@ud) ::
autoload-on=? :: autoload-on=? ::
cur-hoon=@uvI :: cur-hoon=@uvI ::
cur-arvo=@uvI :: cur-arvo=@uvI ::
@ -245,16 +269,6 @@
pot=term :: pot=term ::
== ==
+$ kiln-unmount $@(term [knot path]) :: +$ kiln-unmount $@(term [knot path]) ::
+$ kiln-sync ::
$: syd=desk :: local desk
her=ship :: foreign ship
sud=desk :: foreign desk
==
+$ kiln-unsync ::
$: syd=desk :: local desk
her=ship :: foreign ship
sud=desk :: foreign desk
==
+$ kiln-merge :: +$ kiln-merge ::
$@ ~ $@ ~
$: syd=desk :: $: syd=desk ::
@ -285,7 +299,6 @@
+$ kiln-fuse-list (unit desk) +$ kiln-fuse-list (unit desk)
-- --
|= [bowl:gall state] |= [bowl:gall state]
?> =(src our)
=| moz=(list card:agent:gall) =| moz=(list card:agent:gall)
|% |%
++ kiln . ++ kiln .
@ -440,7 +453,7 @@
=^ cards-9=(list card:agent:gall) old =^ cards-9=(list card:agent:gall) old
?. ?=(%9 -.old) ?. ?=(%9 -.old)
`old `old
=/ syn=(set kiln-sync) =/ syn=(set sync-record)
%- ~(gas in ~(key by syn.old)) %- ~(gas in ~(key by syn.old))
%+ murn ~(tap by ark.old) %+ murn ~(tap by ark.old)
|= [=desk =arak-9] |= [=desk =arak-9]
@ -468,8 +481,8 @@
[%pass /kiln/load-zest %arvo %c %zest desk zest] [%pass /kiln/load-zest %arvo %c %zest desk zest]
:: ::
%+ turn ~(tap in syn) %+ turn ~(tap in syn)
|= k=kiln-sync |= r=sync-record
[%pass /kiln/load-sync %agent [our %hood] %poke %kiln-sync !>(k)] [%pass /kiln/load-sync %agent [our %hood] %poke %kiln-sync !>(r)]
:: ::
=/ ks ~(tap in syn) =/ ks ~(tap in syn)
|- ^- (list card:agent:gall) |- ^- (list card:agent:gall)
@ -483,7 +496,17 @@
$(ks t.ks) $(ks t.ks)
== ==
:: ::
?> ?=(%10 -.old) =? old ?=(%10 -.old)
%= old
- %11
|4 [hop=~ mer=& |4.old]
zyn %- ~(run by zyn.old)
|= sync-state-10
^- sync-state
[nun kid let ~ ~ |]
==
::
?> ?=(%11 -.old)
=. state old =. state old
abet:(emil cards-9) abet:(emil cards-9)
:: ::
@ -499,18 +522,31 @@
=/ ver (mergebase-hashes our %base now (~(got by sources) %base)) =/ ver (mergebase-hashes our %base now (~(got by sources) %base))
``noun+!>(?~(ver 0v0 i.ver)) ``noun+!>(?~(ver 0v0 i.ver))
:: ::
[%x %kiln %syncs ~] ``noun+!>(zyn) [%x %kiln %jumps ~] ``kiln-jump+!>([%all hop])
[%x %kiln %sources ~] ``noun+!>(sources) [%x %kiln %syncs ~] ``noun+!>(zyn)
[%x %kiln %sources ~] ``noun+!>(sources)
[%x %kiln %automerge ~] ``loob+!>(mer)
[%x %kiln %pikes ~] [%x %kiln %pikes ~]
=+ .^(=rock:tire %cx /(scot %p our)//(scot %da now)/tire) =+ .^(=rock:tire %cx /(scot %p our)//(scot %da now)/tire)
:^ ~ ~ %kiln-pikes :^ ~ ~ %kiln-pikes
!> ^- pikes !> ^- pikes
%- ~(rut by rock) %- ~(urn by rock)
|= [=desk =zest wic=(set weft)] |= [=desk =zest wic=(set weft)]
^- pike ^- pike
=+ .^(hash=@uv %cz /(scot %p our)/[desk]/(scot %da now)) =+ .^(hash=@uv %cz /(scot %p our)/[desk]/(scot %da now))
=/ sync (~(get by sources) desk) =/ sync (~(get by sources) desk)
[sync hash zest wic] [sync hash zest wic]
::
[%x %kiln %pending ~]
:^ ~ ~ %kiln-sync-update
!> ^- sync-update
:- %pending
%- ~(gas by *(set [sync-record @ud]))
^- (list [sync-record @ud])
%+ murn ~(tap by zyn)
|= [sync-record sync-state]
?~ hav ~
(some [syd her sud] u.hav)
== ==
:: ::
:: +get-germ: select merge strategy into local desk :: +get-germ: select merge strategy into local desk
@ -528,12 +564,15 @@
:: ::
++ poke ++ poke
|= [=mark =vase] |= [=mark =vase]
?> |(=(src our) =(%kiln-jump-ask mark))
?+ mark ~|([%poke-kiln-bad-mark mark] !!) ?+ mark ~|([%poke-kiln-bad-mark mark] !!)
%kiln-approve-merge =;(f (f !<(_+<.f vase)) poke-approve-merge)
%kiln-autocommit =;(f (f !<(_+<.f vase)) poke-autocommit) %kiln-autocommit =;(f (f !<(_+<.f vase)) poke-autocommit)
%kiln-bump =;(f (f !<(_+<.f vase)) poke-bump) %kiln-bump =;(f (f !<(_+<.f vase)) poke-bump)
%kiln-cancel =;(f (f !<(_+<.f vase)) poke-cancel) %kiln-cancel =;(f (f !<(_+<.f vase)) poke-cancel)
%kiln-cancel-autocommit =;(f (f !<(_+<.f vase)) poke-cancel-autocommit) %kiln-cancel-autocommit =;(f (f !<(_+<.f vase)) poke-cancel-autocommit)
%kiln-commit =;(f (f !<(_+<.f vase)) poke-commit) %kiln-commit =;(f (f !<(_+<.f vase)) poke-commit)
%kiln-sync-automerge =;(f (f !<(_+<.f vase)) poke-sync-automerge)
%kiln-fuse =;(f (f !<(_+<.f vase)) poke-fuse) %kiln-fuse =;(f (f !<(_+<.f vase)) poke-fuse)
%kiln-fuse-list =;(f (f !<(_+<.f vase)) poke-fuse-list) %kiln-fuse-list =;(f (f !<(_+<.f vase)) poke-fuse-list)
%kiln-gall-sear =;(f (f !<(_+<.f vase)) poke-gall-sear) %kiln-gall-sear =;(f (f !<(_+<.f vase)) poke-gall-sear)
@ -543,12 +582,16 @@
%kiln-label =;(f (f !<(_+<.f vase)) poke-label) %kiln-label =;(f (f !<(_+<.f vase)) poke-label)
%kiln-merge =;(f (f !<(_+<.f vase)) poke-merge) %kiln-merge =;(f (f !<(_+<.f vase)) poke-merge)
%kiln-mount =;(f (f !<(_+<.f vase)) poke-mount) %kiln-mount =;(f (f !<(_+<.f vase)) poke-mount)
%kiln-jump-ask =;(f (f !<(_+<.f vase)) poke-jump-ask)
%kiln-jump-opt =;(f (f !<(_+<.f vase)) poke-jump-opt)
%kiln-jump-propose =;(f (f !<(_+<.f vase)) poke-jump-propose)
%kiln-nuke =;(f (f !<(_+<.f vase)) poke-nuke) %kiln-nuke =;(f (f !<(_+<.f vase)) poke-nuke)
%kiln-pause =;(f (f !<(_+<.f vase)) poke-pause) %kiln-pause =;(f (f !<(_+<.f vase)) poke-pause)
%kiln-permission =;(f (f !<(_+<.f vase)) poke-permission) %kiln-permission =;(f (f !<(_+<.f vase)) poke-permission)
%kiln-revive =;(f (f !<(_+<.f vase)) poke-revive) %kiln-revive =;(f (f !<(_+<.f vase)) poke-revive)
%kiln-rein =;(f (f !<(_+<.f vase)) poke-rein) %kiln-rein =;(f (f !<(_+<.f vase)) poke-rein)
%kiln-rm =;(f (f !<(_+<.f vase)) poke-rm) %kiln-rm =;(f (f !<(_+<.f vase)) poke-rm)
%kiln-global-automerge =;(f (f !<(_+<.f vase)) poke-global-automerge)
%kiln-schedule =;(f (f !<(_+<.f vase)) poke-schedule) %kiln-schedule =;(f (f !<(_+<.f vase)) poke-schedule)
%kiln-suspend =;(f (f !<(_+<.f vase)) poke-suspend) %kiln-suspend =;(f (f !<(_+<.f vase)) poke-suspend)
%kiln-suspend-many =;(f (f !<(_+<.f vase)) poke-suspend-many) %kiln-suspend-many =;(f (f !<(_+<.f vase)) poke-suspend-many)
@ -559,6 +602,19 @@
%kiln-unsync =;(f (f !<(_+<.f vase)) poke-unsync) %kiln-unsync =;(f (f !<(_+<.f vase)) poke-unsync)
== ==
:: ::
++ poke-approve-merge
|= [sync-record approve=?]
?~ got=(~(get by zyn) syd her sud)
=+ msg="kiln: no syncs from {(scow %p her)}/{(trip sud)} to {<syd>}"
((slog leaf+msg ~) abet)
?~ hav.u.got
=+ msg="kiln: no updates from {(scow %p her)}/{(trip sud)} for {<syd>}"
((slog leaf+msg ~) abet)
=< abet
?. approve
abet:drop:(sync syd her sud)
abet:(merg /main syd):(sync syd her sud)
::
++ poke-autocommit ++ poke-autocommit
|= [mon=kiln-commit auto=?] |= [mon=kiln-commit auto=?]
=< abet =< abet
@ -679,6 +735,23 @@
|= =ship |= =ship
abet:(emit %pass /kiln %arvo %g %sear ship) abet:(emit %pass /kiln %arvo %g %sear ship)
:: ::
++ poke-global-automerge
|= auto=?
=. mer auto
?. mer abet
=/ zyns=(list [sync-record sync-state]) ~(tap by zyn)
=< abet
|-
?~ zyns ..abet
?. ?& ?=(^ hav.i.zyns)
!?=([~ %.n] nit.i.zyns)
==
$(zyns t.zyns)
%= $
zyns t.zyns
..abet abet:(merg /main syd):(sync -.i.zyns)
==
::
++ poke-info ++ poke-info
|= [mez=tape tor=(unit toro)] |= [mez=tape tor=(unit toro)]
?~ tor ?~ tor
@ -692,17 +765,20 @@
?~ got=(~(get by rock) loc) ?~ got=(~(get by rock) loc)
%dead %dead
zest.u.got zest.u.got
=. zyn =. ..abet
?~ got=(~(get by sources) loc) ?~ got=(~(get by sources) loc)
zyn ..abet
(~(del by zyn) loc u.got) ?: =([her rem] u.got)
..abet
=. ..abet abet:drop:(sync loc u.got)
..abet(zyn (~(del by zyn) loc u.got))
=? ..abet ?=(%dead zest) =? ..abet ?=(%dead zest)
(emit %pass /kiln/install %arvo %c %zest loc ?:(=(our her) %live %held)) (emit %pass /kiln/install %arvo %c %zest loc ?:(=(our her) %live %held))
?: (~(has by zyn) loc her rem) ?: (~(has by zyn) loc her rem)
abet:(spam (render "already syncing" loc her rem ~) ~) abet:(spam (render "already syncing" loc her rem ~) ~)
?: =([our loc] [her rem]) ?: =([our loc] [her rem])
abet abet
=/ sun (sync loc her rem) =/ sun okay:(sync loc her rem)
~> %slog.(fmt "beginning install into {here:sun}") ~> %slog.(fmt "beginning install into {here:sun}")
=< abet:abet:init =< abet:abet:init
?: =(%base loc) ?: =(%base loc)
@ -710,7 +786,7 @@
sun sun
:: ::
++ poke-kids ++ poke-kids
|= [hos=kiln-sync nex=(unit desk)] |= [hos=sync-record nex=(unit desk)]
abet:abet:(apex:(sync hos) nex) abet:abet:(apex:(sync hos) nex)
:: ::
++ poke-label ++ poke-label
@ -731,6 +807,84 @@
abet:(spam leaf+- ~) abet:(spam leaf+- ~)
abet:(emit %pass /mount %arvo %c [%mont pot u.bem]) abet:(emit %pass /mount %arvo %c [%mont pot u.bem])
:: ::
++ poke-jump-propose
|= [syd=desk her=ship sud=desk]
?: =([our syd] [her sud])
abet
=/ let=@ud ud:.^(cass:clay %cw /(scot %p our)/[syd]/(scot %da now))
=/ subs=(set [@p rave:clay])
.^((set [@p rave:clay]) %cx /(scot %p our)//(scot %da now)/cult/[syd])
=/ ships=(set @p)
%+ roll ~(tap in subs)
|= [[=ship =rave:clay] ships=(set @p)]
?: =(our ship) ships
?. ?=([%sing %w [%ud @] ~] rave) ships
?. =(+(let) p.case.mood.rave) ships
(~(put in ships) ship)
=< abet
%- emil
%+ turn ~(tap in ships)
|= =ship
:* %pass /kiln/jump-propose %agent [ship %hood]
%poke %kiln-jump-ask !>([[our syd] [her sud]])
==
::
++ poke-jump-ask
|= [old=dock new=dock]
?> |(=(src p.old) =(src our))
?: =(old new)
?~ had=(~(get by hop) old)
abet
=. hop (~(del by hop) old)
abet:(emit %give %fact ~[/jumps] %kiln-jump !>([%nay old u.had]))
?~ (skim ~(tap by sources) |=(sync-record =(old [her sud])))
~> %slog.(fmt "no syncs from {(scow %p p.old)}/{(trip q.old)}")
abet
=. hop (~(put by hop) old new)
abet:(emit %give %fact ~[/jumps] %kiln-jump !>([%add old new]))
::
++ poke-jump-opt
|= [old=dock new=dock yea=?]
?~ got=(~(get by hop) old)
~> %slog.(fmt "no jump request for {(scow %p p.old)}/{(trip q.old)}")
abet
?. =(new u.got)
=/ txt-old "{(scow %p p.old)}/{(trip q.old)}"
=/ txt-new "{(scow %p p.new)}/{(trip q.new)}"
~> %slog.(fmt "no jump request from {txt-old} to {txt-new}")
abet
?. yea
=/ txt-old "{(scow %p p.old)}/{(trip q.old)}"
=/ txt-new "{(scow %p p.new)}/{(trip q.new)}"
~> %slog.(fmt "denied jump from {txt-old} to {txt-new}")
=. hop (~(del by hop) old)
abet:(emit %give %fact ~[/jumps] %kiln-jump !>([%nay old new]))
=/ old-sources=(list sync-record)
(skim ~(tap by sources) |=(sync-record =(old [her sud])))
=/ new-sources=(list sync-record)
(turn old-sources |=(sync-record [syd new]))
=. ..abet
(emit %give %fact ~[/jumps] %kiln-jump !>([%yea old new]))
=. ..abet
|-
?~ old-sources
..abet
=. ..abet abet:drop:(sync i.old-sources)
=. zyn (~(del by zyn) i.old-sources)
$(old-sources t.old-sources, ..abet ..abet)
=. hop (~(del by hop) old)
=< abet
|- ^+ ..abet
?~ new-sources ..abet
%= $
new-sources t.new-sources
..abet =/ sun (sync i.new-sources)
=< abet:init
?: =(%base syd.i.new-sources)
(apex:sun `%kids)
sun
==
::
++ poke-nuke ++ poke-nuke
|= [=term desk=?] |= [=term desk=?]
=< abet =< abet
@ -801,11 +955,28 @@
|=(=desk [%pass /kiln/suspend %arvo %c %zest desk %dead]) |=(=desk [%pass /kiln/suspend %arvo %c %zest desk %dead])
:: ::
++ poke-sync ++ poke-sync
|= hos=kiln-sync |= sync-record
?: (~(has by zyn) hos) ?: (~(has by zyn) sud her syd)
abet:(spam (render "already syncing" [sud her syd ~]:hos) ~) abet:(spam (render "already syncing" [sud her syd ~]) ~)
~> %slog.(fmt "beginning sync into {<syd.hos>} from {<her.hos>}/{<sud.hos>}") =. ..abet
abet:abet:init:(sync hos) ?~ got=(~(get by sources) syd)
..abet
=. ..abet abet:drop:(sync syd u.got)
..abet(zyn (~(del by zyn) syd u.got))
~> %slog.(fmt "beginning sync into {<syd>} from {<her>}/{<sud>}")
abet:abet:init:(sync syd her sud)
::
++ poke-sync-automerge
|= [sync-record auto=(unit ?)]
?~ got=(~(get by zyn) syd her sud)
=+ msg="kiln: no syncs from {(scow %p her)}/{(trip sud)} to {<syd>}"
((slog leaf+msg ~) abet)
=. zyn (~(put by zyn) [syd her sud] u.got(nit auto))
?~ hav.u.got
abet
?. |(?=([~ %.y] auto) &(mer ?=(~ auto)))
abet
abet:abet:(merg /main syd):(sync [syd her sud])
:: ::
++ poke-syncs :: print sync config ++ poke-syncs :: print sync config
|= ~ |= ~
@ -813,7 +984,7 @@
?: =(0 ~(wyt by zyn)) ?: =(0 ~(wyt by zyn))
[%leaf "no syncs configured"]~ [%leaf "no syncs configured"]~
%+ turn ~(tap by zyn) %+ turn ~(tap by zyn)
|= [kiln-sync sync-state] |= [sync-record sync-state]
(render "sync configured" sud her syd kid) (render "sync configured" sud her syd kid)
:: ::
++ poke-uninstall ++ poke-uninstall
@ -841,9 +1012,10 @@
:: Don't need to cancel anything because new syncs will get a new nonce :: Don't need to cancel anything because new syncs will get a new nonce
:: ::
++ poke-unsync ++ poke-unsync
|= hus=kiln-unsync |= hus=sync-record
?~ got=(~(get by zyn) hus) ?~ got=(~(get by zyn) hus)
abet:(spam (render "not syncing" [sud her syd ~]:hus) ~) abet:(spam (render "not syncing" [sud her syd ~]:hus) ~)
=. ..abet abet:drop:(sync hus)
=. zyn (~(del by zyn) hus) =. zyn (~(del by zyn) hus)
abet:(spam (render "cancelling sync" sud.hus her.hus syd.hus kid.u.got) ~) abet:(spam (render "cancelling sync" sud.hus her.hus syd.hus kid.u.got) ~)
:: +peer: handle %watch :: +peer: handle %watch
@ -851,10 +1023,26 @@
++ peer ++ peer
|= =path |= =path
?> (team:title our src) ?> (team:title our src)
?: =(0 1) abet :: avoid mint-vain
?+ path ~|(kiln-path/path !!) ?+ path ~|(kiln-path/path !!)
[%vats ~] [%vats ~]
(mean leaf+"kiln: old subscription to /kiln/vats failed" ~) (mean leaf+"kiln: old subscription to /kiln/vats failed" ~)
::
[%jumps ~]
abet:(emit %give %fact ~ %kiln-jump !>([%all hop]))
::
[%updates ~]
=< abet
%- emit
:^ %give %fact ~
:- %kiln-sync-update
!> ^- sync-update
:- %pending
%- ~(gas by *(set [sync-record @ud]))
^- (list [sync-record @ud])
%+ murn ~(tap by zyn)
|= [sync-record sync-state]
?~ hav ~
(some [syd her sud] u.hav)
== ==
:: ::
++ take-agent ++ take-agent
@ -864,6 +1052,8 @@
~? ?=(^ p.sign) [%kiln-poke-nack u.p.sign] ~? ?=(^ p.sign) [%kiln-poke-nack u.p.sign]
abet abet
~|([%kiln-bad-take-agent wire -.sign] !!) ~|([%kiln-bad-take-agent wire -.sign] !!)
::
[%change-publisher ~] abet
:: ::
[%fancy *] [%fancy *]
?> ?=(%poke-ack -.sign) ?> ?=(%poke-ack -.sign)
@ -1078,15 +1268,30 @@
abet:abet:(take:(sync syd her sud) t.t.t.wire sign-arvo) abet:abet:(take:(sync syd her sud) t.t.t.wire sign-arvo)
:: ::
++ sync ++ sync
|= kiln-sync |= sync-record
=/ got (~(get by zyn) syd her sud) =/ got (~(get by zyn) syd her sud)
=+ `sync-state`(fall got [(scot %uv nyz) ~ *@ud]) =+ `sync-state`(fall got [(scot %uv nyz) ~ *@ud ~ ~ |])
=? nyz ?=(~ got) +(nyz) =? nyz ?=(~ got) +(nyz)
|% |%
++ abet ..sync(zyn (~(put by zyn) [syd her sud] nun kid let)) ++ abet ..sync(zyn (~(put by zyn) [syd her sud] nun kid let nit hav yea))
++ apex |=(nex=(unit desk) ..abet(kid nex)) ++ apex |=(nex=(unit desk) ..abet(kid nex))
++ emit |=(card:agent:gall ..abet(kiln (^emit +<))) ++ emit |=(card:agent:gall ..abet(kiln (^emit +<)))
++ emil |=((list card:agent:gall) ..abet(kiln (^emil +<))) ++ emil |=((list card:agent:gall) ..abet(kiln (^emil +<)))
++ okay ..abet(yea &)
++ gain
=. hav `(dec let)
=/ upd=sync-update [%new [syd her sud] (dec let)]
(emit %give %fact ~[/update] %kiln-sync-update !>(upd))
++ drop
=? ..abet ?=(^ hav)
=/ upd=sync-update [%drop [syd her sud] u.hav]
(emit %give %fact ~[/updates] %kiln-sync-update !>(upd))
..abet(hav ~, yea |)
++ tada
=? ..abet ?=(^ hav)
=/ upd=sync-update [%done [syd her sud] u.hav]
(emit %give %fact ~[/updates] %kiln-sync-update !>(upd))
..abet(hav ~, yea |)
++ here "{<syd>} from {<her>}/{<sud>}" ++ here "{<syd>} from {<her>}/{<sud>}"
++ ware ++ ware
|= =wire |= =wire
@ -1101,7 +1306,6 @@
%merg desk her sud %merg desk her sud
ud+(dec let) (get-germ desk) ud+(dec let) (get-germ desk)
== ==
::
:: (re)Start a sync from scratch by finding what version the source :: (re)Start a sync from scratch by finding what version the source
:: desk is at :: desk is at
:: ::
@ -1129,8 +1333,8 @@
?> ?=(^ riot) ?> ?=(^ riot)
:: The syncs may have changed, so get the latest :: The syncs may have changed, so get the latest
:: ::
;< zyx=(map kiln-sync sync-state) bind:m ;< zyx=(map sync-record sync-state) bind:m
(scry:strandio (map kiln-sync sync-state) /gx/hood/kiln/syncs/noun) (scry:strandio (map sync-record sync-state) /gx/hood/kiln/syncs/noun)
?. (~(has by zyx) syd her sud) ?. (~(has by zyx) syd her sud)
(pure:m !>(%done)) (pure:m !>(%done))
~> %slog.(fmt "downloading update for {here}") ~> %slog.(fmt "downloading update for {here}")
@ -1175,6 +1379,7 @@
?: ?=(%| -.p.sign-arvo) ?: ?=(%| -.p.sign-arvo)
:: ~> %slog.(fmt "download failed into {here}; retrying sync") :: ~> %slog.(fmt "download failed into {here}; retrying sync")
:: %- (slog p.p.sign-arvo) :: %- (slog p.p.sign-arvo)
=. ..abet drop
init init
:: ::
~> %slog.(fmt "finished downloading update for {here}") ~> %slog.(fmt "finished downloading update for {here}")
@ -1182,7 +1387,7 @@
:: If nothing changed, just ensure %kids is up-to-date and advance :: If nothing changed, just ensure %kids is up-to-date and advance
:: ::
?. (get-remote-diff our syd now [her sud (dec let)]) ?. (get-remote-diff our syd now [her sud (dec let)])
=< next =< next:drop
?~ kid ?~ kid
~> %slog.(fmt "remote is identical to {here}, skipping") ~> %slog.(fmt "remote is identical to {here}, skipping")
..abet ..abet
@ -1191,15 +1396,22 @@
..abet ..abet
~> %slog.(fmt "remote is identical to {here}, merging into {<u.kid>}") ~> %slog.(fmt "remote is identical to {here}, merging into {<u.kid>}")
(merg /kids u.kid) (merg /kids u.kid)
:: wait for approval if can't automerge & signal available update
::
?. |(=(our her) yea =([~ &] nit) &(=(~ nit) mer))
=. ..abet gain
next
:: Else start merging, but also immediately start listening to :: Else start merging, but also immediately start listening to
:: the next revision. Now, all errors should no-op -- we're :: the next revision. Now, all errors should no-op -- we're
:: already waiting for the next revision. :: already waiting for the next revision.
:: ::
=. yea |
=. ..abet (merg /main syd) =. ..abet (merg /main syd)
next next
:: ::
%main %main
?> ?=(%mere +<.sign-arvo) ?> ?=(%mere +<.sign-arvo)
=< tada
?: ?=(%| -.p.sign-arvo) ?: ?=(%| -.p.sign-arvo)
=+ "kiln: merge into {here} failed, waiting for next revision" =+ "kiln: merge into {here} failed, waiting for next revision"
%- (slog leaf/- p.p.sign-arvo) %- (slog leaf/- p.p.sign-arvo)

View File

@ -0,0 +1,54 @@
/- neo
|%
:: ++ dyad (pair @ @)
++ scam
=< scam
|%
++ on ((^on case:neo case:neo) lte)
+$ scam ((mop case:neo case:neo) lte)
--
:: ++ push
++ scum
=< scum
|%
++ on ((^on case:neo (map pith:neo case:neo)) lte)
+$ scum ((mop case:neo (map pith:neo case:neo)) lte)
--
+$ muck
$: =soil
=scum
why=scam
zed=scam
==
++ soil
=< a
^~
|%
++ on ((^on case:neo muck:neo) lte)
+$ a ((mop case:neo muck:neo) lte)
--
++ plot
:: $dirt: Layer 1 of the namespace
++ dirt
|%
+$ card (pair pith note)
+$ note
$% [%grow =pail case=(unit case) =oath]
[%cull ~]
==
+$ loam (axal soil)
+$ gift dust
--
++ frog
[=pail =
++ till
|_ =loam
++ plow
|=
++ grew
|= [=pail:neo case=@ud]
++ grow
|= [=pail:neo

View File

@ -220,10 +220,14 @@
`[pith key.u.lat] `[pith key.u.lat]
:: ::
++ grow ++ grow
|= [=pail:neo cas=(unit case:neo) =oath:neo] |= [=pith:neo =pail:neo cas=(unit case:neo) =oath:neo]
^- (quip loot:neo loam:dirt:neo) ^- (quip dust:neo loam:dirt:neo)
=/ =poem:neo [[(fall cas +(case)) oath] `pail] =/ l=loam:dirt:neo (~(dip of:neo loam) pith)
(make poem) =/ =poem:neo [[(fall cas +(~(case plow l))) oath] `pail]
=^ loot=(list loot:neo) l
(~(make plow l) poem)
:- (turn loot (lead pith))
(~(rep of:neo loam) pith l)
++ make ++ make
|= =poem:neo |= =poem:neo
^- (quip loot:neo loam:dirt:neo) ^- (quip loot:neo loam:dirt:neo)
@ -244,7 +248,7 @@
%add %add
%dif %dif
?: &(=(%dif mode) =(q.q:(need old) q.poem)) ?: &(=(%dif mode) =(q.q:(need old) q.poem))
~& %dupe-skipping :: ~& %dupe-skipping
`loam `loam
~| overwrite-soil/p.p.poem ~| overwrite-soil/p.p.poem
?> !(has:on:soil:neo u.fil.loam p.p.poem) ?> !(has:on:soil:neo u.fil.loam p.p.poem)
@ -252,22 +256,36 @@
loam(fil `(put:on:soil:neo u.fil.loam [p.p .]:poem)) loam(fil `(put:on:soil:neo u.fil.loam [p.p .]:poem))
:: ::
++ cull ++ cull
?~ fil.loam =| =grit:neo
[~ loam] |= =pith:neo
(make [[+(case) *oath:neo] ~]) ^+ [grit loam]
=/ [loot=(list loot:neo) l=loam:dirt:neo]
=/ lom (~(dip of:neo loam) pith)
?: =(~ fil.lom)
`lom
(~(make plow lom) [[+(~(case plow lom)) *oath:neo] ~])
=. grit (welp grit (turn loot (lead pith)))
=/ kids ~(tap by kid.l)
|-
?~ kids
=. loam (~(rep of:neo loam) pith l)
[grit loam]
=/ [iot=iota lo=loam:dirt:neo] i.kids
=/ pit=pith:neo (snoc pith iot)
=/ [loot=(list loot:neo) lom=loam:dirt:neo]
(make(loam lo) [[+(case) *oath:neo] ~])
=. grit (welp grit (turn loot (lead pit)))
=. kid.l (~(put by kid.l) iot lom)
$(kids t.kids) ::
:: ::
++ call ++ call
|= =card:dirt:neo |= =card:dirt:neo
^- (quip gift:dirt:neo _loam) ^- (quip gift:dirt:neo _loam)
=/ lom (~(dip of:neo loam) p.card)
%- (trace "call" (print-card card)) %- (trace "call" (print-card card))
=^ gifts=(list loot:neo) lom ?- -.q.card
?- -.q.card %grow (~(grow plow loam) p.card +.q.card)
%grow (~(grow plow lom) +.q.card) %cull (~(cull plow loam) p.card)
%cull ~(cull plow lom) ==
==
:_ (~(rep of:neo loam) p.card lom)
(turn gifts |=(loot:neo `gift:dirt:neo`[p.card +<]))
:: ::
++ look ++ look
|= =pith:neo |= =pith:neo
@ -395,7 +413,9 @@
=| gifts=(list gift:dirt:neo) =| gifts=(list gift:dirt:neo)
|= =epic:neo |= =epic:neo
^+ [gifts loam farm] ^+ [gifts loam farm]
=/ pic ~(tap of:neo epic) =/ pic
%+ sort ~(tap of:neo epic)
|=([[a=pith:neo *] [b=pith:neo *]] (lte-pith:neo a b))
|- |-
?~ pic ?~ pic
:+ gifts loam :+ gifts loam
@ -453,11 +473,64 @@
~ ~
`[pit %dif] `[pit %dif]
== ==
++ fallback-peek-kids
|= [=care:neo =pith:neo fam=farm:neo]
^- (list pith:neo)
?: ?=(%x care) ~
?^ fil.fam
=/ [=land:neo =plot:neo] u.fil.fam
?~ kid=(ram:on:plan:neo ?:(?=(%y care) by-kids-mut.plot by-desc-mut.plot))
~
~(tap in val.u.kid)
%- zing
%+ turn ~(tap by kid.fam)
|= [=iota f=farm:neo]
^- (list pith:neo)
(fallback-peek-kids care (snoc pith iota) f)
++ fallback-peek-x
|= =pith:neo
^- (unit saga:neo)
=/ sol (~(gut of:neo loam) pith *soil:neo)
?~ val=(ram:on:soil:neo sol)
~
?~ q.val.u.val
~
`[*aeon:neo u.q.val.u.val]
::
++ fallback-peek
|= [=care:neo =pith:neo]
^- (axal:neo saga:neo)
%- gas
%+ welp
?~ rot=(fallback-peek-x pith)
~
[pith u.rot]^~
%+ murn (fallback-peek-kids care pith (~(dip of:neo farm) pith))
|= p=pith:neo
^- (unit [pith:neo saga:neo])
=/ kid (welp pith p)
?~ sag=(fallback-peek-x kid)
~
`[kid u.sag]
++ piek
|= [=care:neo =pith:neo]
^- (unit (unit (axal:neo saga:neo)))
:: ~& peek-no-once/[care pith]
``(fallback-peek care pith)
::
++ peek ++ peek
|= [=care:neo =pith:neo] |= [=care:neo =pith:neo]
^- (unit (unit (axal:neo saga:neo))) ^- (unit (unit (axal:neo saga:neo)))
?~ nce=(now-once care pith) ?~ nce=(now-once care pith)
:: ~& peek-no-once/[care pith]
~ ~
:: =/ res
:: (fallback-peek care pith)
:: ~? !=(res [~ ~])
:: res/res
:: ``(fallback-peek care pith)
(look care u.nce pith) (look care u.nce pith)
++ look-x ++ look-x
|= [=case:neo =pith:neo] |= [=case:neo =pith:neo]
@ -467,6 +540,14 @@
?: ?=($@(~ [~ ~]) res) ?: ?=($@(~ [~ ~]) res)
res res
`(~(get of:neo u.u.res) ~) `(~(get of:neo u.u.res) ~)
++ gas
=| axe=(axal:neo saga:neo)
|= res=(list (pair pith:neo saga:neo))
^+ axe
?~ res
axe
$(axe (~(put of:neo axe) p.i.res q.i.res), res t.res)
:: ::
++ look ++ look
|= [=care:neo =once:neo =pith:neo] |= [=care:neo =once:neo =pith:neo]
@ -485,12 +566,6 @@
%y read-y %y read-y
%z read-z %z read-z
== ==
++ gas
|= res=(list (pair pith:neo saga:neo))
^+ axe
?~ res
axe
$(axe (~(put of:neo axe) p.i.res q.i.res), res t.res)
++ read-x (gas read-x-raw) ++ read-x (gas read-x-raw)
++ read-x-raw ++ read-x-raw
^- (list (pair pith:neo saga:neo)) ^- (list (pair pith:neo saga:neo))

View File

@ -213,7 +213,7 @@
=< q =< q
%- need %- need %- need %- need
%- scry:(ames-gate now eny roof) %- scry:(ames-gate now eny roof)
[~ / %x [[our %$ da+now] /peers/(scot %p her)]] [[~ ~] / %x [[our %$ da+now] /peers/(scot %p her)]]
:: ::
++ gall-scry-nonce ++ gall-scry-nonce
|= $: =gall-gate |= $: =gall-gate
@ -227,7 +227,7 @@
=< q =< q
%- need %- need %- need %- need
%- scry:(gall-gate now eny roof) %- scry:(gall-gate now eny roof)
[~ / %n [[our dude da+now] [%$ (scot %p ship.sub) [term wire]:sub]]] [[~ ~] / %n [[our dude da+now] [%$ (scot %p ship.sub) [term wire]:sub]]]
:: ::
++ load-agent ++ load-agent
|= [=ship =gall-gate =dude:gall =agent:gall] |= [=ship =gall-gate =dude:gall =agent:gall]

1
pkg/arvo/lib/verb Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/lib/verb

View File

@ -0,0 +1 @@
../../../base-dev/mar/kiln/approve-merge.hoon

View File

@ -0,0 +1 @@
../../../base-dev/mar/kiln/jump-ask.hoon

View File

@ -0,0 +1 @@
../../../base-dev/mar/kiln/jump-opt.hoon

1
pkg/arvo/mar/kiln/jump.hoon Symbolic link
View File

@ -0,0 +1 @@
../../../base-dev/mar/kiln/jump.hoon

View File

@ -0,0 +1 @@
../../../base-dev/mar/kiln/sync-update.hoon

View File

@ -1,20 +1,18 @@
:: ::
:::: /hoon/md/mar :::: /hoon/atom/mar
:: ::
/? 310 /? 310
:: ::
=, format :::: A minimal atom mark
::
=, mimes:html =, mimes:html
|_ txt=wain |_ ato=@
:: ++ grab |%
++ grab :: convert from ++ noun @
|% ++ mime |=([* p=octs] q.p)
++ mime |=((pair mite octs) (to-wain q.q)) --
++ noun wain :: clam from %noun ++ grow |%
-- ++ mime [/application/x-urb-unknown (as-octs ato)]
++ grow --
|%
++ mime [/text/plain (as-octs (of-wain txt))]
--
++ grad %mime ++ grad %mime
-- --

View File

@ -1,14 +1,14 @@
:: ::
/- neo /- neo
|_ =slip:neo |_ =ack:neo
:: ::
++ grad %noun ++ grad %noun
++ grab :: convert from ++ grab :: convert from
|% |%
++ noun slip:neo ++ noun ack:neo
-- --
++ grow ++ grow
|% |%
++ noun slip ++ noun ack
-- --
-- --

View File

@ -1 +0,0 @@
../../base-dev/mar/txt.hoon

18
pkg/arvo/mar/txt.hoon Normal file
View File

@ -0,0 +1,18 @@
::
:::: /hoon/atom/mar
::
/? 310
::
:::: A minimal atom mark
::
=, mimes:html
|_ ato=@
++ grab |%
++ noun @
++ mime |=([* p=octs] q.p)
--
++ grow |%
++ mime [/application/x-urb-unknown (as-octs ato)]
--
++ grad %mime
--

1
pkg/arvo/mar/verb Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/verb

View File

@ -1,168 +1,232 @@
/@ accel-conf /@ accel-conf
/@ htmx /@ htmx
/- feather-icons
:- [%accel-conf %$ %htmx] :- [%accel-conf %$ %htmx]
|= conf=accel-conf |= conf=accel-conf
|= =bowl:neo |= =bowl:neo
|^ ^- manx |^
;div.accel-cell.wf.hf.fc
;+ controls
;div.tabs.fc.grow.scroll-y
;div.tab.in.p2.fc.grow
=morph-retain "class"
;+ in
==
;div.tab.ref.p2.hidden.hf
=morph-retain "class"
;+ ref
==
;div.tab.poke.p2.hidden.hf
=morph-retain "class"
;+ poke
==
==
;+ script
==
:: ::
;div.fc.trans-root.grow ++ out-path (snoc (snip here.bowl) %out)
++ print-iota
|= =iota
?@(iota (trip iota) (scow iota))
++ controls
;div.p-1.fr.g2.ac.je
;button.p-1.br1.bd1.b1.hover.toggled
=onclick "accelSwitchTab(this, 'in');"
=morph-retain "class"
; in
==
;button.p-1.br1.bd1.b1.hover
=onclick "accelSwitchTab(this, 'ref');"
=morph-retain "class"
; ref
==
;button.p-1.br1.bd1.b1.hover
=onclick "accelSwitchTab(this, 'poke');"
=morph-retain "class"
; poke
==
==
++ in
;form.fc.grow ;form.fc.grow
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=hoon" =hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=hoon"
=hx-trigger "input changed delay:0.4s from:[name='text'], input changed delay:0.4s from:[name='a']" =hx-trigger "input changed delay:0.4s from:find textarea"
=hx-on-htmx-after-request "$(this).closest('.top').find('.refresher').emit('accel-refresh');"
=hx-swap "none" =hx-swap "none"
=hx-target "#code-spinner .loading" ;textarea
=hx-target-400 "#error-code-{id}" =class "p2 bd1 br1 scroll-x pre mono wf grow"
=hx-indicator "#code-spinner" =name "text"
=row (scow %ud +:x) =placeholder "code"
=col (scow %ud +:y) =spellcheck "false"
;div.fc.border.grow.basis-half.wf =autocomplete "off"
;+ code-input =value (trip hoon.conf)
;+ (spinner "code") =oninput "this.setAttribute('value', this.value);"
; {(trip hoon.conf)}
== ==
== ==
;div.fc.border ++ poke
;+ conf-header ;div
;div.fr ;+ add-poke
;div.fc.p2 ;+ pokes
;form.fr.js.hf
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=add-poke"
=hx-swap "none"
=hx-indicator "#code-spinner"
=hx-target "#code-spinner .loading"
;input
=type "text"
=placeholder "/{(scow %p our.bowl)}/shrub/to/poke"
=name "pith"
=autocomplete "off"
=oninput "this.setAttribute('value', this.value);"
;
==
;input
=type "text"
=placeholder "%some-type"
=name "stud"
=autocomplete "off"
=oninput "this.setAttribute('value', this.value);"
;
==
;button
=type "submit"
; Route poke
==
==
==
;div.fc.p2
::
;+ deps
;form.fr.js.hf
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=add-dep"
=hx-swap "none"
=hx-target "#conf-spinner .loading"
=hx-target-400 "#error-add-{id}"
=hx-indicator "#conf-spinner"
=row (scow %ud +:x)
=col (scow %ud +:y)
;div.fc.grow.basis-half.wf
;div.fr
;input
=type "text"
=placeholder "name"
=autocomplete "off"
=oninput "this.setAttribute('value', this.value);"
=name "name"
;
==
;input
=type "text"
=placeholder "/{(scow %p our.bowl)}/demo/cell/5"
=autocomplete "off"
=oninput "this.setAttribute('value', this.value);"
=name "pith"
;
==
==
;button
=type "submit"
; Add dep
==
;+ (spinner "conf")
==
==
==
==
== ==
== ++ ref
++ id ;div
^- tape ;+ add-dep
%- zing ;+ deps
%+ turn (pout (tail here.bowl))
|= smeg=@ta
%+ weld "--"
(trip smeg)
::
++ x (rear (snip (snip here.bowl)))
++ y (rear (snip here.bowl))
++ spinner
|= =tape
;div.b1.loader.p1.s-2.f2
=id (welp tape "-spinner")
;span.loaded: saved
;span.loading: ---
==
++ conf-header
=/ pit=tape (en-tape:pith:neo (snoc (snip here.bowl) %out))
;div.b1.border.fr.jb
;span.p1.mono.s-1: {pit}
;button.br1.border.b1.hover
=style "padding: 4px 8px;"
=type "button"
=pith pit
=onclick "navigator.clipboard.writeText(this.getAttribute('pith'));"
; copy path
==
==
++ code-input
;textarea#input.wf.p2.pre.mono.grow
=name "text"
=placeholder "code"
=spellcheck "false"
=value (trip hoon.conf)
=oninput "this.setAttribute('value', this.value);"
; {(trip hoon.conf)}
== ==
++ x (rear `pith`(snip (snip here.bowl)))
++ y (rear `pith`(snip here.bowl))
++ deps ++ deps
^- manx ^- manx
?: =(~ crew.conf) ?: =(~ crew.conf)
;div.fr: No dependencies ;div.fr.p2.f3: no deps
;div.fc ;div.fc.g2.p2.scroll-y
;div.s1.p1: Dependencies
;* ;*
%+ turn ~(tap by crew.conf) %+ turn ~(tap by crew.conf)
|= [=term =pith:neo] |= [=term =pith:neo]
=/ tap (trip term) =/ tap (trip term)
;label.fr.p1 ;div.fr.g3.ac
;div.border.wf =id "conf-dep-{tap}"
=name "name" ;button.bd1.br1.p-1.b1.hover.loader
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=del-dep"
=hx-swap "outerHTML"
=hx-target "find .loading"
=tap tap
;span.loaded: delete
;span.loading
;+ loading.feather-icons
==
==
;div.f3
; {tap} ; {tap}
== ==
;label.border.wf: {(en-tape:pith:neo pith)} ;div.mono: {(en-tape:pith:neo pith)}
;button.border ==
=hx-post "/neo/sky{(en-tape:pith:neo here.bowl)}?stud=del-dep" ==
; Delete ++ add-dep
;label.hidden ;form.frw.js.g2
=name "name" =hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=add-dep"
=value tap =hx-swap "outerHTML"
; =hx-target "find .loading"
== =hx-on-htmx-after-request "$(this).find('input').attr('value', '');this.reset();"
=row (scow %ud +:x)
=col (scow %ud +:y)
;input.p-1.br1.bd1.fr.wfc
=style "min-width: 0; flex: 1;"
=type "text"
=placeholder "name"
=autocomplete "off"
=oninput "this.setAttribute('value', this.value);"
=morph-no-swap ""
=name "name"
=required ""
;
==
;input.p-1.br1.bd1.fr.grow.wfc
=style "min-width: 0; flex: 1;"
=type "text"
=placeholder "/{(scow %p our.bowl)}/demo/cell/5"
=autocomplete "off"
=oninput "this.setAttribute('value', this.value);"
=required ""
=morph-no-swap ""
=name "pith"
;
==
;button.br1.bd1.b1.hover.p-1.loader
=type "submit"
;span.loaded: add dep
;span.loading
;+ loading.feather-icons
== ==
== ==
== ==
++ error ++ pokes
|= =tang ^- manx
;div.pre.mono.p2 ?: =(0 ~(wyt by poke.conf))
;div.fr.p2.f3: no pokes
;div.fc.g2.p2.scroll-y
;* ;*
%+ turn (scag 25 tang) %+ turn ~(tap by poke.conf)
|= =tank |= [=pith:neo =stud:neo]
;span: {(of-wall:format (~(win re tank) 0 80))} =/ pit (en-tape:pith:neo pith)
=/ tap (en-tape:pith:neo (snip (snip (snip here.bowl))))
;div.frw.g2.ac
;button.bd1.br1.p-1.b1.hover.loader
=hx-post "/neo/hawk{tap}?stud=send-poke"
=hx-swap "none"
=pith pit
=x (scow %ud +:x)
=y (scow %ud +:y)
;span.loaded: send
;span.loading
;+ loading.feather-icons
==
==
;button.bd1.br1.p-1.b1.hover.loader
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=del-poke"
=hx-swap "outerHTML"
=hx-target "find .loading"
=pith pit
;span.loaded: delete
;span.loading
;+ loading.feather-icons
==
==
;div.f3
; {<stud>}
==
;div.mono: {pit}
==
==
++ add-poke
;form.fr.js.hf.g2
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=add-poke"
=hx-swap "outerHTML"
=hx-target "find .loading"
=hx-on-htmx-after-request "$(this).find('input').attr('value', '');this.reset();"
=row (scow %ud +:x)
=col (scow %ud +:y)
;input.p-1.br1.bd1
=style "min-width: 0; flex: 1;"
=type "text"
=placeholder "%stud"
=autocomplete "off"
=oninput "this.setAttribute('value', this.value);"
=morph-no-swap ""
=name "stud"
=required ""
;
==
;input.p-1.br1.bd1.grow
=style "min-width: 0; flex: 1;"
=type "text"
=placeholder "/{(scow %p our.bowl)}/poke/target"
=autocomplete "off"
=oninput "this.setAttribute('value', this.value);"
=required ""
=morph-no-swap ""
=name "pith"
;
==
;button.br1.bd1.b1.hover.p-1.loader
=type "submit"
;span.loaded: add poke
;span.loading
;+ loading.feather-icons
==
==
==
++ script
;script
;+ ;/ %- trip
'''
function accelSwitchTab(el, name) {
$(el).siblings().removeClass('toggled');
$(el).addClass('toggled');
let tabs = $(el).closest('.accel-cell').find('.tab');
tabs.addClass('hidden');
tabs.filter('.'+name).removeClass('hidden');
}
'''
== ==
-- --

View File

@ -2,118 +2,219 @@
/@ accel-cell /@ accel-cell
/@ accel-conf /@ accel-conf
/@ htmx /@ htmx
/- feather-icons
:- [%accel %$ %htmx] :- [%accel %$ %htmx]
|= =accel |= =accel
|= =bowl:neo |= =bowl:neo
|^ |^
;div.accel-top.wf.hf ;div.top.wf.hf
=style
"""
display: grid;
grid-template-rows: 1fr 200px;
grid-template-columns: 1fr;
overflow: hidden;
grid-template-areas:
"table"
"dashboards";
"""
;+ table ;+ table
;+ dashboard-stub ;+ dashboards
;+ refresher ;+ script
;+ style
== ==
++ id ++ resizer
^- tape ;form.fr.ac.je.g1.p2
%- zing =hx-post "/neo/sky"
%+ turn (pout (tail here.bowl)) =hx-confirm "not yet implemented. bother ~migrev about this"
|= smeg=@ta ;input.p-1.br1.bd1.b0
%+ weld "--" =style "width: 80px;"
(trip smeg) =type "number"
:: =min "2"
++ table =max "20"
;div =step "1"
;table =value "10"
=id "table-{id}" ;
;tbody ==
;tr ;div: x
;th.mono; ;input.p-1.br1.bd1.b0
;* =style "width: 80px;"
%+ turn (gulf 1 10) =type "number"
|= n=@ =min "2"
;th.mono.f2.tc: {<n>} =max "20"
== =step "1"
;* =value "10"
%+ turn (gulf 1 10) ;
|= x=@ ==
;tr ;button.loader.p-1.br1.bd1.b1.hover
;td.mono.tr.f2(style "width: 1px;"): {<x>} ;span.loaded: resize
;* ;span.loading
%+ turn (gulf 1 10) ;+ loading.feather-icons
|= y=@
^- manx
=/ pax=pith:neo #/[ud/x]/[ud/y]
=/ kid=bowl:neo bowl
=. kids.kid [~ ~]
=. here.kid :(welp here.bowl pax)
=. deps.kid ~
=/ in=manx
?~ res=(~(get of:neo kids.bowl) (snoc pax %in))
*manx
=. here.kid (snoc here.kid %in)
(!<(htmx q.pail.u.res) kid)
=/ out=manx
?~ res=(~(get of:neo kids.bowl) (snoc pax %out))
*manx
=. here.kid (snoc here.kid %out)
(!<(htmx q.pail.u.res) kid)
;td.border
;+
;button.b1.scroll-none.hover.cell-btn.p2.wf.hf
=id "cell-{id}-{<x>}-{<y>}"
=hx-get "/neo/hawk{(en-tape:pith:neo here.bowl)}/{<x>}/{<y>}/in"
=hx-target "#dashboard-{id}"
=hx-select ".trans-root"
=hx-swap "innerHTML"
=morph-retain "class"
=onclick "$('.cell-btn').removeClass('toggled');$(this).addClass('toggled');"
;div.mono
;+ out
==
==
==
== ==
== ==
== ==
++ table
;div.scroll-x.scroll-y
=style "grid-area: table"
::;+ resizer
;+ grid
== ==
++ dashboard-stub ++ rows 5
;div.b0.fr ++ cols 5
=id "dashboard-{id}" ++ grid
; ;div
=style
"""
width: max-content;
display: grid;
grid-template-rows: repeat({<+(rows)>}, auto);
grid-template-columns: repeat({<+(cols)>}, fit-content(220px));
"""
;*
%+ turn (gulf 0 cols)
|= n=@
(index n)
;*
%+ turn (gulf 0 (dec (mul rows +(cols))))
|= i=@
?: =(0 (~(sit fo +(cols)) i))
(index +((div i +(cols))))
=/ d (dvr i +(cols))
=/ x q.d
=/ y +(p.d)
(cell x y)
==
++ out-preview
:: XX cool kids would use a role conversion...
:: YY or maybe cool kids prefer locality of behaviour
:: ZZ SOMEONE EXPLAIN ME POLYMORPHISM NOW!
|= =pail:neo
^- manx
?+ p.pail
;div: bruh, how did that a {<p.pail>} stud even get in here?
%vase
=/ vax q.pail
?: =(->-:vax %n) ;/("") :: empty if cell is null
;/((of-wall:format (~(win re (sell vax)) 0 50)))
::
%tang
;div.f-3: ERROR
==
++ cell
|= [x=@ y=@]
=/ pix=pith:neo #/[ud/x]/[ud/y]/out
;button.p-1.bd1.b0.hover.tl.mono.cell-btn
=morph-retain "class"
=onclick "accelRevealDashboard(this, '{<x>}', '{<y>}')"
=style
"""
min-height: 30px;
max-height: 100px;
min-width: 50px;
max-width: 400px;
box-sizing: border-box;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
"""
;+
?~ res=(~(get of:neo kids.bowl) pix)
;div.f-2: EMPTY
(out-preview q.saga.u.res)
==
++ index
|= n=@
?: =(0 n) ;div;
;div.fc.jc.ac.b0.p2.f3.s-2: {<n>}
++ dashboards
;div.b0.fc.relative.scroll-x.scroll-y
=style "grid-area: dashboards; border-top: 1px solid var(--f2); max-height: 200px;"
;+ refresher
;*
%+ turn (gulf 0 (dec (mul rows cols)))
|= i=@
=/ d (dvr i cols)
=/ x +(q.d)
=/ y +(p.d)
(dashboard x y)
::
;div.grow.fc.jc.ac.f3
=cell "empty"
=morph-retain "class"
; select a cell
==
==
++ dashboard
|= [x=@ y=@]
;div.grow.frw.af.js.hidden
=style ""
=cell "{<x>}-{<y>}"
=morph-retain "class"
;+ (in x y)
;+ (out x y)
==
++ in
|= [x=@ y=@]
=/ pax=pith:neo #/[ud/x]/[ud/y]
=/ kid=bowl:neo bowl
=. kids.kid [~ ~]
=. here.kid :(welp here.bowl pax /in)
=. deps.kid ~
;div.basis-half.shrink-0.grow.bd1
=style "min-width: 350px; min-height: 150px;"
;+
?~ res=(~(get of:neo kids.bowl) (snoc pax %in))
;div: none - in {<[x y]>}
(!<(htmx q.pail.u.res) kid)
==
++ out
|= [x=@ y=@]
=/ pax=pith:neo #/[ud/x]/[ud/y]/out
=/ kid=bowl:neo bowl
=. kids.kid [~ ~]
=. here.kid (welp here.bowl pax)
=. deps.kid ~
;div.basis-half.shrink-0.bd1.fc.g2.grow
=style "min-width: 350px; min-height: 150px;"
;div.b0.fr.g2.ac.je.p-1.bd1
;div.s-1: {(en-tape:pith:neo (snip pax))}
;button.p-1.b1.hover.br1.bd1.s-2
=onclick "navigator.clipboard.writeText('{(en-tape:pith:neo here.kid)}');"
; copy full path
==
==
;div.p2.pre.grow.mono.scroll-y.scroll-x
;+
?~ res=(~(get of:neo kids.bowl) pax)
;div: none out - {<[x y]>}
(!<(htmx q.pail.u.res) kid)
==
== ==
++ refresher ++ refresher
;div.hidden ;div.absolute
=hx-get "{(en-tape:pith:neo :(weld /neo/hawk here.bowl))}" =style "top: 1em; left: 1em;"
=hx-trigger "every 3s" ;div.loader.refresher
=hx-target "table" =hx-get "{(en-tape:pith:neo :(weld /neo/hawk here.bowl))}?no-save"
=hx-select "table" =hx-trigger "every 7s, accel-refresh"
=hx-swap "morph" =hx-target "closest .top"
; =hx-select ".top"
=hx-swap "morph"
;span.loaded;
;span.loading
;+ loading.feather-icons
==
==
== ==
++ style ++ script
;style.hidden ;script
;+ ;/ %- trip ;+ ;/ %- trip
''' '''
table { function accelRevealDashboard(el, x, y) {
border-collapse: collapse; let top = $(el).closest('.top');
width: 100%; top.find('.cell-btn').removeClass('toggled');
grid-area: table; $(el).addClass('toggled');
overflow-y: auto; let dashboards = top.find('[cell]');
} dashboards.addClass('hidden');
.scroll-none { dashboards.filter(`[cell='${x}-${y}']`).removeClass('hidden');
overflow-x: auto;
}
td, tr {
margin: 0;
padding: 0;
height: fit-content;
}
.accel-top {
display: grid;
grid-template-rows: 1fr 1fr;
grid-template-columns: 1fr;
grid-template-areas:
"table"
"dashboard";
} }
''' '''
== ==

View File

@ -0,0 +1,13 @@
/@ add-dep
/- feather-icons
:- [%add-dep %$ %htmx]
|= dep=add-dep
|= =bowl:neo
;div.loading
=hx-get "/neo/hawk{(en-tape:pith:neo here.bowl)}?no-save"
=hx-trigger "load"
=hx-swap "morph"
=hx-target "closest .accel-cell"
=hx-select ".accel-cell"
;+ loading.feather-icons
==

View File

@ -0,0 +1,13 @@
/@ add-poke
/- feather-icons
:- [%add-poke %$ %htmx]
|= add=add-poke
|= =bowl:neo
;div.loading
=hx-get "/neo/hawk{(en-tape:pith:neo here.bowl)}?no-save"
=hx-trigger "load"
=hx-swap "morph"
=hx-target "closest .accel-cell"
=hx-select ".accel-cell"
;+ loading.feather-icons
==

View File

@ -0,0 +1,13 @@
/@ del-dep
/- feather-icons
:- [%del-dep %$ %htmx]
|= dep=del-dep
|= =bowl:neo
;div.loading
=hx-get "/neo/hawk{(en-tape:pith:neo here.bowl)}?no-save"
=hx-trigger "load"
=hx-swap "morph"
=hx-target "closest .accel-cell"
=hx-select ".accel-cell"
;+ loading.feather-icons
==

View File

@ -0,0 +1,13 @@
/@ del-poke
/- feather-icons
:- [%del-poke %$ %htmx]
|= del=del-poke
|= =bowl:neo
;div.loading
=hx-get "/neo/hawk{(en-tape:pith:neo here.bowl)}?no-save"
=hx-trigger "load"
=hx-swap "morph"
=hx-target "closest .accel-cell"
=hx-select ".accel-cell"
;+ loading.feather-icons
==

View File

@ -1,14 +1,24 @@
/@ diary /@ diary :: name=@t
:: import /lib/feather-icons
/- feather-icons /- feather-icons
:: declare that this is a conversion from diary to HTMX
:- [%diary %$ %htmx] :- [%diary %$ %htmx]
:: gate takes a diary and a bowl:neo,
:: so we can access here.bowl
|= dia=diary |= dia=diary
|= =bowl:neo |= =bowl:neo
:: returns a manx, in this case HTMX
^- manx ^- manx
:: construct Sail using helper arms
|^ |^
;div.p2 :: <div class="p2" label="Diary">
=label "Diary" ;div.p-page
:: <div class="ma fc g2 mw-page">
;div.ma.fc.g2.mw-page ;div.ma.fc.g2.mw-page
:: render the text input for new entries
;+ form-put-entry ;+ form-put-entry
:: compose several link-entry elements generated
:: by the +turn gate into one HTMX node
;* ;*
%+ turn %+ turn
%+ sort %+ sort
@ -20,18 +30,38 @@
|= [a=[=pith *] b=[=pith *]] |= [a=[=pith *] b=[=pith *]]
(gth ->.pith.a ->.pith.b) (gth ->.pith.a ->.pith.b)
link-entry link-entry
== == :: </div>
== == :: </div>
::
:: text input for new entries
++ form-put-entry ++ form-put-entry
:: :: <form
:: class="fc g2"
:: style="margin-bottom: 30px"
:: head="put-entry"
:: hx-post="/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=diary-diff"
:: hx-on-submit="this.reset()"
:: hx-target="find .loading"
:: hx-swap="outerHTML"
:: >
;form.fc.g2 ;form.fc.g2
=style "margin-bottom: 30px;" =style "margin-bottom: 30px;"
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=diary-diff" =hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=diary-diff"
=hx-on-submit "this.reset()" =hx-on-submit "this.reset()"
=hx-target "find .loading" =hx-target "find .loading"
=hx-swap "outerHTML" =hx-swap "outerHTML"
=head "put-entry" =head "put-entry"
;date-now(name "id"); :: <date-now name="now" />
;date-now(name "now");
:: <textarea
:: class="p2 bd1 br1"
:: name="text"
:: placeholder="today, i ..."
:: oninput="this.setAttribute('value', this.value)"
:: rows="5"
:: required=""
:: autocomplete=""
:: />
;textarea.p2.bd1.br1 ;textarea.p2.bd1.br1
=name "text" =name "text"
=placeholder "today, i ..." =placeholder "today, i ..."
@ -40,35 +70,55 @@
=required "" =required ""
=autocomplete "off" =autocomplete "off"
; ;
== == :: </textarea>
:: <button class="p2 b1 br1 bd1 wfc hover loader">
;button.p2.b1.br1.bd1.wfc.hover.loader ;button.p2.b1.br1.bd1.wfc.hover.loader
:: <span class="loaded s2">create</span>
;span.loaded.s2: create ;span.loaded.s2: create
:: <span>
;span.loading ;span.loading
;+ loading.feather-icons ;+ loading.feather-icons
== == :: </span>
== == :: </button>
== == :: </form>
:: ::
:: entry box
++ link-entry ++ link-entry
::
|= [pax=pith =idea:neo] |= [pax=pith =idea:neo]
=/ tape (trip !<(@t q.pail.idea)) :: make sure the pail does in fact contain %txt
?. =(%txt p.q.saga.idea)
;div: error
:: extract information from the given pith and pail:neo
=/ tape (trip !<(@t q.q.saga.idea))
=/ subject-end (fall (find [10]~ tape) 56) =/ subject-end (fall (find [10]~ tape) 56)
=/ subject (scag subject-end tape) =/ subject (scag subject-end tape)
=/ id (trip (snag 0 (pout pax))) =/ id (trip (snag 0 (pout pax)))
:: <div class="fr g2">
;div.fr.g2 ;div.fr.g2
:: <a
:: class="p2 br1 grow b1 hover loader"
:: href="{(en-tape:pith:neo (weld /neo/hawk here.bowl))}/{id}"
:: >
;a.p2.br1.grow.b1.hover.loader ;a.p2.br1.grow.b1.hover.loader
=href "{(en-tape:pith:neo (weld /neo/hawk here.bowl))}/{id}" =href "{(en-tape:pith:neo (weld /neo/hawk here.bowl))}/{id}"
:: <div class="loaded fc g1 js as g2">
;div.loaded.fc.g1.js.as.g2 ;div.loaded.fc.g1.js.as.g2
:: <span class="f3">{YYYY-MM-DD}</span>
;span.f3: {(pretty-date `@da`->:pax)} ;span.f3: {(pretty-date `@da`->:pax)}
:: <span class="bold">{subject}</span>
;span.bold: {subject} ;span.bold: {subject}
== == :: </div>
:: <span class="loading">
;span.loading ;span.loading
;+ loading.feather-icons ;+ loading.feather-icons
== == :: </span>
== == :: </a>
;button.p2.br1.fr.g2.b1.hover.fc.ac.jc.loader ;button.p2.br1.fr.g2.b1.hover.fc.ac.jc.loader
=onclick "alert('not yet implemented. no tombstoning?')" =hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=diary-diff"
=head "del-entry"
=hx-target "find .loading"
=hx-swap "outerHTML"
=diary-id id
;span.loaded ;span.loaded
;+ close.feather-icons ;+ close.feather-icons
== ==
@ -77,6 +127,8 @@
== ==
== ==
== ==
::
:: styled date string
++ pretty-date ++ pretty-date
|= date=@da |= date=@da
^- tape ^- tape

View File

@ -0,0 +1,25 @@
/@ message
/- feather-icons
/- messages
:- [%ship %$ %htmx]
|= =ship
|= =bowl:neo
^- manx
;div.p2.wf.hf
=hx-on-message-sent "$(this).find('.refresher').emit('refresh');"
;div.mw-page.ma.wf.hf
=style
"""
display: grid;
grid-template-rows: 1fr auto;
grid-template-columns: auto;
grid-template-areas:
"messages"
"sender"
"""
;+ script:messages
;+ style:messages
;+ (render-messages:messages bowl)
;+ (render-sender:messages [bowl /pub])
==
==

View File

@ -44,8 +44,11 @@
%diary %diary
%iframe %iframe
%task %task
%todos
%txt %txt
%hoon
%sail %sail
%slideshow
== ==
|= t=@tas |= t=@tas
^- manx ^- manx
@ -71,7 +74,9 @@
%+ turn folder %+ turn folder
|= name=@tas |= name=@tas
=/ pith ~[name] =/ pith ~[name]
=/ =pail:neo pail:(~(got of:neo kids.bowl) pith) ?~ suga=(~(get of:neo kids.bowl) pith)
;div.p3.br1.bd1: no file called {<name>}
=/ =pail:neo q.saga.u.suga
=/ =stud:neo p.pail =/ =stud:neo p.pail
=/ =path (pout (welp here.bowl pith)) =/ =path (pout (welp here.bowl pith))
=/ label =/ label

View File

@ -0,0 +1,21 @@
/@ message
/@ groupchat
/- feather-icons
/- messages
:- [%groupchat %$ %htmx]
|= =groupchat
|= =bowl:neo
^- manx
;div.p2
=label "Chat"
;+ script:messages
;+ style:messages
;div.ma.fe.g2.wf
=style "max-width: 650px;"
;div.fc.g2.wf
=id "children"
;+ (render-messages:messages bowl)
==
;+ (render-sender:messages [bowl /pub])
==
==

View File

@ -55,22 +55,29 @@
=hx-indicator "#indicator-{id}" =hx-indicator "#indicator-{id}"
;* ;*
=/ apps =/ apps
%+ welp apps.home %+ welp
apps.home
%- skip
:_ |= =pith
(gth (lent pith) 1)
%~ tap in %~ tap in
(~(dif in ~(key by ~(tar of:neo kids.bowl))) `(set pith)`(silt apps.home)) %- %~ dif in
%~ key by
%~ tar of:neo
kids.bowl
`(set pith)`(silt apps.home)
%+ murn apps %+ murn apps
|= =pith |= =pith
^- (unit manx) ^- (unit manx)
?~ pith ~ ?~ pith ~
=/ =path (pout (welp here.bowl pith)) =/ =path (pout (welp here.bowl pith))
?: (gth (lent path) 3) ~ :: /our/home/whatever
:- ~ :- ~
;div.relative.br2 ;div.relative.br2
=pith (en-tape:pith:neo pith) =pith (en-tape:pith:neo pith)
;a.b1.br2.block.fc.as.js.hover.p3.s1.border-2.loader ;a.b1.br2.block.fc.as.js.hover.p3.s1.border-2.loader
=style "width: 160px; height: 160px;" =style "width: 160px; height: 160px;"
=hx-target "closest .hawk" =hx-target "closest .hawk"
=hx-swap "innerHTML" =hx-swap "outerHTML"
=hx-indicator "this" =hx-indicator "this"
=href (trip (spat ['neo' 'hawk' path])) =href (trip (spat ['neo' 'hawk' path]))
;span.loaded: {(trip (snag 0 (pout:neo pith)))} ;span.loaded: {(trip (snag 0 (pout:neo pith)))}
@ -86,24 +93,24 @@
; • • • ; • • •
== ==
;div.fr.hidden.g1.p1 ;div.fr.hidden.g1.p1
;button.grow.tc.s-2.b0.br2.p1 ;button.grow.fr.jc.b0.br2.p1
=hx-trigger "click" =hx-trigger "click"
=onclick "let t = $(this).closest('.relative'); t.parent().prepend(t);" =onclick "let t = $(this).closest('.relative'); t.parent().prepend(t);"
; |< ;+ chevron-first.feather-icons
== ==
;button.grow.tc.s-2.b0.br2.p1 ;button.grow.fr.jc.b0.br2.p1
=onclick "let t = $(this).closest('.relative'); t.insertBefore(t.prev());" =onclick "let t = $(this).closest('.relative'); t.insertBefore(t.prev());"
=hx-trigger "click" =hx-trigger "click"
; < ;+ chevron-left.feather-icons
== ==
;button.grow.tc.s-2.b0.br2.p1 ;button.grow.fr.jc.b0.br2.p1
=hx-trigger "click" =hx-trigger "click"
=onclick "let t = $(this).closest('.relative'); t.insertAfter(t.next());" =onclick "let t = $(this).closest('.relative'); t.insertAfter(t.next());"
; > ;+ chevron-right.feather-icons
== ==
;button.grow.tc.s-2.b0.br2.p1 ;button.grow.fr.jc.b0.br2.p1
=onclick "let t = $(this).closest('.relative'); t.parent().append(t);" =onclick "let t = $(this).closest('.relative'); t.parent().append(t);"
; >| ;+ chevron-last.feather-icons
== ==
== ==
== ==

View File

@ -1,10 +1,13 @@
/@ htmx /@ htmx
/- feather-icons
:- [%hoon %$ %htmx] :- [%hoon %$ %htmx]
|= hon=@t |= hon=@t
|= =bowl:neo |= =bowl:neo
=/ =name:neo =/ =name:neo
[our here]:bowl [our here]:bowl
=/ =file:ford:neo =/ fool=(each file:ford:neo tang)
%- mule
|.
(scan (trip hon) (rein:ford:neo name)) (scan (trip hon) (rein:ford:neo name))
=/ src=wain =/ src=wain
(to-wain:format hon) (to-wain:format hon)
@ -23,57 +26,77 @@
:: ::
++ apex ++ apex
^- manx ^- manx
;div.wf.hf.p3.hoon.fc.g2 ;form.wf.hf.hoon.fc
;+ imports
;+ contents
;+ style
==
++ imports
;div.frw.g2
;*
%+ turn pro.file
|= =pro:ford:neo
^- manx
;a.p2.br1.b1.hover.s-1
=href (spud (post-href %pro stud.pro))
=hx-target "closest .hawk"
=hx-swap "innerHTML"
; {<stud.pro>}
==
==
++ error
;details.error-parent.wf.br1.bd1(open "")
=style "max-height: 220px;"
;summary.p2.br1.b-3.f-3: error
;div.p3
;div.error.empty;
==
==
++ contents
;form.fc.g2.wf.relative.grow.scroll-y
=hx-put "{(en-tape:pith:neo (welp /neo/hawk here.bowl))}?stud=hoon" =hx-put "{(en-tape:pith:neo (welp /neo/hawk here.bowl))}?stud=hoon"
=hx-trigger "click from:find button, keydown[metaKey&&key=='Enter']" =hx-trigger "click from:find button, keydown[metaKey&&key=='Enter']"
=hx-target "closest .hoon" =hx-target "closest .hoon"
=hx-target-error "find .error"
=hx-swap "morph" =hx-swap "morph"
;div.relative.grow.fc ;+ imports
;div.wfc.z1.absolute ;+ contents
=style "top: 15px; right: 15px;" ;+ script
;button.p2.br2.b1.bd1.hover.loader ==
;span.loaded.fr.ac.g1 ++ imports
;span.bold: save ;div.frw.jb.ac.g2.p1
;span.f2.s-2: cmd+enter ;+
== ?- -.fool
;span.loading: ... %.n
(error p.fool)
::
%.y
;div.frw.g2.p1.wfc
;*
%+ turn pro.p.fool
|= =pro:ford:neo
^- manx
;a.p2.br1.bd1.b1.hover.s-1
=href (spud (post-href %pro stud.pro))
=hx-target "closest .hawk"
=hx-swap "innerHTML"
; {<stud.pro>}
== ==
== ==
;textarea.p2.bd1.br1.scroll-x.pre.mono.wf.grow ==
=style "outline:none;" ;+ saver
==
++ error
|= =tang
=/ =wall (zing (turn tang |=(t=tank (~(win re t) [0 80]))))
=/ =tape (zing (join "\0a" wall))
;details.wf.br1.bd1(open "")
=style "max-height: 220px;"
;summary.p2.br1.b-3.f0: error
;div.pre.mono.p2.wf.scroll-y
;+ ;/ tape
==
==
++ saver
;button.p2.br2.b1.bd1.hover.loader
;span.loaded.fr.ac.g1
;span.bold: save
;span.f2.s-2: cmd+enter
==
;span.loading
;+ loading.feather-icons
==
==
++ contents
;div.fc.g2.wf.relative.grow.scroll-y
=style "border-top: 1px solid var(--b3); padding-bottom: 250px;"
;div.fr.grow
;div.hf.f3.numbered
=style "min-width: 10px; padding: 8px 5px; border-right: 1px solid var(--b3);"
;*
%+ turn (gulf 1 (lent src))
|= n=@
;div.mono(style "line-height: 1.1;");
==
;textarea.p2.pre.mono.wf.grow.scroll-hidden
=style "outline:none; line-height: 1.1;"
=autocomplete "off" =autocomplete "off"
=rows "1" =rows "1"
=spellcheck "false" =spellcheck "false"
=name "text" =name "text"
=oninput "this.setAttribute('value', this.value);" =oninput "this.setAttribute('value', this.value); skyHoonRenumber(this);"
=value (trip hon) =value (trip hon)
;* ;*
%+ turn src %+ turn src
@ -81,14 +104,27 @@
;/ "{(trip lin)}\0a" ;/ "{(trip lin)}\0a"
== ==
== ==
;+ error
== ==
++ style ++ script
;style ;script
;+ ;/ %- trip ;+ ;/ %- trip
''' '''
details.error-parent:has(.error:empty) { function skyHoonRenumber(el) {
display: none; // corrects the line numbers
let lines = 1 + el.value.split('\n').length;
let nums = $(el).parent().find('.numbered').get()[0];
let kids = nums.children.length + 1;
while (kids < lines) {
let div = document.createElement('div');
div.classList.add('mono');
div.style = 'line-height: 1.1;';
nums.appendChild(div);
kids = kids + 1;
}
while (kids > lines) {
nums.children[0].remove();
kids = kids - 1;
}
} }
''' '''
== ==

View File

@ -0,0 +1,23 @@
/@ sky-diff
/@ http-request
/- serv=sky-server
:- [%http-request %$ %sky-diff]
|= =http-request
=/ pam (~(uni by pam:(parse-url:serv http-request)) (parse-form-body:serv http-request))
=/ bod ~(. by pam)
=/ head (@tas (got:bod 'head'))
^- sky-diff
?+ head ~|(bad-head/head !!)
%new-hawk
[head (slav %da (got:bod 'now'))]
%close
[head (slav %ud (got:bod 'slot'))]
%maximize
[head (slav %ud (got:bod 'slot'))]
%slide-up
[head (slav %ud (got:bod 'slot'))]
%slide-down
[head (slav %ud (got:bod 'slot'))]
%minimize
[head (slav %ud (got:bod 'slot'))]
==

View File

@ -0,0 +1,136 @@
/@ groupchat
/@ ship
/- feather-icons
/- messages
:- [%messenger %$ %htmx]
|= ~
|= =bowl:neo
|^
view
::
++ view
^- manx
;div.p2.fc.ac.view.g2.ma
;style: {style}
;+ make-chat
;+ all-chats
==
::
++ pith-tape
|= =pith
^- tape
(en-tape:pith:neo pith)
::
++ style
^~
%- trip
'''
.view {
max-width: 650px;
padding-bottom: 50vh;
padding-top: 30px;
}
input[type="text"]:hover {
cursor: text;
}
input:focus {
outline: none;
}
.w70{
width: 70%;
}
.bc1{
border: solid 1px var(--b2);
}
'''
::
++ make-chat
=/ oninput
"""
this.setAttribute("value", this.value); this.nextElementSibling.nextElementSibling.setAttribute('hx-get', '/neo/hawk{(pith-tape here.bowl)}/dms/' + this.value); htmx.process(document.body);
"""
;form.fr.jc.g1.w70
=hx-post "/neo/hawk{(pith-tape here.bowl)}?stud=messenger-diff"
=head "new-dm"
=hx-swap "none"
=hx-on-htmx-after-request "$(this).find('.redirect').emit('messenger-created')"
;input.grow.bc1.p2.br1
=name "invites"
=type "text"
=required ""
=placeholder "Start chat (e.g. ~sampel-palnet)"
=oninput oninput
=autocomplete "off"
;
==
;input.hidden.grow.bc1.p2.br1
=type "text"
=name "name"
=placeholder "chat name"
=oninput (trip 'this.setAttribute("value", this.value);')
;
==
;div.redirect.hidden
=hx-target "closest .hawk"
=hx-swap "outerHTML"
=hx-trigger "messenger-created"
;
==
;button.loader.br1.hover.p2.b0.bc1
;span.loaded; >
;span.loading
;+ loading.feather-icons
==
==
==
::
++ all-chats
=/ kids
%+ skid ~(tap of:neo kids.bowl)
|= [=pith =idea:neo]
=(p.q.saga.idea %groupchat)
^- manx
;div.fc.as.g1.w70
;div.fc.ac.g1.wf
;* %+ turn q.kids
|= [=pith =idea:neo]
?~ pith
;span.hidden: no dms
?: (lte 3 (lent pith))
;h1.hidden: {<pith>}
=/ ship
?. ?=([%p @p] (rear pith)) *@p
+:;;([%p @p] (rear pith))
^- manx
;a.br1.hover.b0.fr.jb.wf.bc1
=href "/neo/hawk{(pith-tape here.bowl)}{(pith-tape pith)}"
=hx-swap "innerHTML"
;h3.s-1.p2: {<ship>}
==
==
;div.fc.ac.g1.wf
;* %+ turn p.kids
|= [=pith =idea:neo]
?~ pith ;span.hidden: no groupchats
(chat pith idea)
==
==
::
++ chat
|= [=pith =idea:neo]
=/ org=@p +:;;([%p @p] (snag 1 `(list iota)`pith))
=/ members=(list ship) ~(tap in members:!<(groupchat q.q.saga.idea))
=/ chat +:;;([%t @t] (rear pith))
^- manx
;div.wf.br1.fc.g1
;div.fr.g1
;a.br1.hover.fr.jb.g2.wf.bc1.b0
=href "/neo/hawk{(pith-tape here.bowl)}{(pith-tape pith)}"
=hx-swap "innerHTML"
;h3.s-1.p2: {(trip chat)}
;h3.s-1.p2: {<org>}
==
==
==
--

View File

@ -10,4 +10,3 @@
=/ name=term (vol:mu "name") =/ name=term (vol:mu "name")
?> ((sane %tas) name) ?> ((sane %tas) name)
[name pith] [name pith]

View File

@ -3,10 +3,7 @@
/- manx-utils /- manx-utils
:- [%node %$ %add-poke] :- [%node %$ %add-poke]
|= nod=node |= nod=node
~& nod/nod
^- add-poke ^- add-poke
=/ mu ~(. manx-utils nod) =/ mu ~(. manx-utils nod)
:- (pave:neo (rash (vol:mu "pith") stap)) :- (pave:neo (rash (vol:mu "pith") stap))
`@tas`(rash (vol:mu "stud") ;~(pfix cen sym)) :: XX fix `@tas`(rash (vol:mu "stud") ;~(pfix cen sym)) :: XX fix

View File

@ -0,0 +1,21 @@
/@ node :: manx
/@ counter-diff :: [%inc ~]
:: import /lib/manx-utils, which helps us work with XML
/- manx-utils
:: declare this is a conversion from node to counter-diff
:- [%node %$ %counter-diff]
|= =node
^- counter-diff
:: initiate the manx-utils door with node
=/ mu ~(. manx-utils node)
::
:: got:mu gets an attribute from the manx by its name
:: in this case, the =head specified in /con/number-htmx
:: we expect the head from the manx to be %inc,
:: but we could add more terms to that type union...
=/ head (?(%inc) (got:mu %head))
::
:: return the [%inc ~] poke
:: if we wanted to handle multiple pokes,
:: we'd switch on the type of head here
[head ~]

View File

@ -5,7 +5,6 @@
|= nod=node |= nod=node
^- del-dep ^- del-dep
=/ mu ~(. manx-utils nod) =/ mu ~(. manx-utils nod)
=/ name=term (vol:mu "name") =/ name=term (got:mu %tap)
?> ((sane %tas) name) ?> ((sane %tas) name)
name name

View File

@ -5,5 +5,4 @@
|= nod=node |= nod=node
^- del-poke ^- del-poke
=/ mu ~(. manx-utils nod) =/ mu ~(. manx-utils nod)
(pave:neo (rash (vol:mu "pith") stap)) (pave:neo (rash (got:mu %pith) stap))

View File

@ -1,11 +1,22 @@
/@ node /@ node :: manx
/@ diary-diff /@ diary-diff :: ?([%put-entry id=@da txt=@t] [%del-entry id=@da])
:: import /lib/manx-utils
/- manx-utils /- manx-utils
:: declare that this is a conversion from a
:: dynamic XML node to diary-diff
:- [%node %$ %diary-diff] :- [%node %$ %diary-diff]
|= nod=node |= nod=node
^- diary-diff ^- diary-diff
=/ mu ~(. manx-utils nod) =/ mu ~(. manx-utils nod)
:: extract head, id, and text atttributes from XML node
=/ head (@tas (got:mu %head)) =/ head (@tas (got:mu %head))
=/ id (slav %da (vol:mu "id")) ?+ head !!
=/ text (vol:mu "text") %put-entry
[%put-entry id text] =/ id (slav %da (vol:mu "now"))
=/ text (vol:mu "text")
:: construct the diary-diff
[%put-entry id text]
::
%del-entry
[%del-entry (slav %da (got:mu %diary-id))]
==

View File

@ -0,0 +1,17 @@
/@ node
/@ groupchat-diff
/- manx-utils
:- [%node %$ %groupchat-diff]
|= nod=node
^- groupchat-diff
=/ mu ~(. manx-utils nod)
=/ head (@tas (got:mu %head))
~& >>> head
%- groupchat-diff
?+ head
~| [%unknown-head head]
!!
%remove
=/ =ship `@p`(slav %p (got:mu %pith))
[head ship]
==

View File

@ -4,4 +4,10 @@
:- [%node %$ %hoon] :- [%node %$ %hoon]
|= nod=node |= nod=node
^- hoon ^- hoon
(~(vol manx-utils nod) "text") =* mu ~(. manx-utils nod)
=/ raw=tape (need (val:mu "text"))
%- crip
?: =(0 (lent raw)) raw
?. =((rear raw) '\0a') raw
:: remove newline added by html encoding nonsense
(snip raw)

View File

@ -0,0 +1,10 @@
/@ node
/@ message
/- manx-utils
:- [%node %$ %message]
|= nod=node
^- message
=/ text (~(vol manx-utils nod) "text")
=/ ship (slav %p (~(vol manx-utils nod) "ship"))
=/ date (slav %da (~(vol manx-utils nod) "date"))
[ship date text]

View File

@ -0,0 +1,45 @@
/@ node
/@ messenger-diff
/- manx-utils
:- [%node %$ %messenger-diff]
|= nod=node
^- messenger-diff
=/ mu ~(. manx-utils nod)
=/ head (@tas (got:mu %head))
~& >>> head
%- messenger-diff
?+ head
~| [%unknown-head head]
!!
%new-dm
=/ partner `@p`(slav %p (vol:mu "invites"))
[head partner]
::
%new-groupchat
=/ invites=tape (need (val:mu "invites"))
=/ parsed-invites=(set @p)
%- silt
%+ scan (weld " " invites)
%- star
;~ pose
;~ pfix (jest ' ~')
fed:ag
==
;~ pfix (jest ', ~')
fed:ag
==
==
~& > parsed-invites
=/ value (val:mu "name")
=/ name=cord
:: TODO: if invites are longer than some amount of character
?~ value (crip invites)
(crip (need value))
~& > name
[head name parsed-invites]
::
%invite-to-groupchat
~& > (vol:mu "name")
=/ name (vol:mu "name")
[head name ~]
==

View File

@ -1,41 +1,15 @@
/@ node /@ node
/@ sail
/- manx-utils /- manx-utils
/- sail
:- [%node %$ %sail] :- [%node %$ %sail]
|= nod=node |= nod=node
|^ =/ mu ~(. manx-utils nod)
^- sail =/ code
=/ mu ~(. manx-utils nod) =/ raw=tape (need (val:mu "code"))
=/ code %- crip
=/ raw=tape (need (val:mu "code")) ?: =(0 (lent raw)) raw
?: =(0 (lent raw)) (crip raw) ?. =((rear raw) '\0a') raw
?. =((rear raw) '\0a') (crip raw) :: remove newline by html encoding nonsense
(crip (snip raw)) (snip raw)
=/ class (vol:mu "classes") =/ class (vol:mu "classes")
[code class `(render-udon code)] [code class `(render-udon:sail code)]
++ render-udon
|= code=@t
^- (each manx tang)
=/ newline (trip 10)
=/ udon
:: format as udon document
%- crip
;: welp
";>" newline newline
(trip code) newline
==
=/ mul
%- mule
|.
!< manx
%+ slap
;: slop
!>(..zuse)
!>(manx-utils=manx-utils)
==
(ream udon)
?- -.mul
%.y [%.y (manx p.mul)]
%.n [%.n (tang p.mul)]
==
--

View File

@ -0,0 +1,10 @@
/@ node
/@ send-poke
/- manx-utils
:- [%node %$ %send-poke]
|= nod=node
^- send-poke
=/ mu ~(. manx-utils nod)
:+ (slav %ud (got:mu %x))
(slav %ud (got:mu %y))
(pave:neo (rash (got:mu %pith) stap))

View File

@ -7,17 +7,8 @@
=* mu ~(. manx-utils nod) =* mu ~(. manx-utils nod)
=/ head (@tas (got:mu %head)) =/ head (@tas (got:mu %head))
?+ head !! ?+ head !!
%new-tab %menu
[%new-tab ~] =/ c ?~((get:mu %closed) %.y %.n)
%minimize [%menu c]
[%minimize (slav %ud (got:mu %hawk-slot))]
%slide-up
[%slide-up (slav %ud (got:mu %hawk-slot))]
%slide-down
[%slide-down (slav %ud (got:mu %hawk-slot))]
%maximize
[%maximize (slav %ud (got:mu %hawk-slot))]
%close
[%close (slav %ud (got:mu %hawk-slot))]
:: ::
== ==

View File

@ -4,9 +4,14 @@
:- [%node %$ %sky] :- [%node %$ %sky]
|= nod=node |= nod=node
^- sky ^- sky
:_ (slav %ud (~(got manx-utils nod) %slots)) :*
%+ murn c.nod %+ murn c.nod
|= =manx |= =manx
=/ here (rush (~(got manx-utils manx) %here) stap) =/ here (rush (~(got manx-utils manx) %here) stap)
?~ here ~ ?~ here ~
`[*@da (pave:neo u.here)] `[*@da (pave:neo u.here)]
::
(slav %ud (~(got manx-utils nod) %slots))
::
%.n
==

View File

@ -0,0 +1,24 @@
/@ node
/@ slideshow-diff
/- manx-utils
:- [%node %$ %slideshow-diff]
|= nod=node
^- slideshow-diff
=* mu ~(. manx-utils nod)
=/ head (got:mu %head)
?+ head !!
%mode
:- %mode
%+ snag 0
%+ murn c.nod
|= =manx
=/ ribs (malt a.g.manx)
=/ cls (fall (~(get by ribs) %class) "")
?~ x=(find "toggled" cls) ~
:- ~
%- ?(%edit %both %preview %present)
(crip (~(got by ribs) %mode))
::
%slide
[%slide (slav %ud (got:mu %current))]
==

View File

@ -0,0 +1,18 @@
/@ node
/@ slideshow
/- manx-utils
/- sh=slideshow
:- [%node %$ %slideshow]
|= nod=node
|^
^- slideshow
=/ mu ~(. manx-utils nod)
=/ code
=/ raw=tape (need (val:mu "code"))
%- crip
?: =((lent raw) 0) raw
?. =((rear raw) '\0a') raw
(snip raw)
=/ class (vol:mu "classes")
[code class `(render-slideshow:sh code) %both 0]
--

View File

@ -1,49 +1,64 @@
/@ node /@ node :: manx
::
:: $task-diff
:: $% [%new =task prepend=?]
:: [%edit text=cord done=?]
:: [%oust =pith]
:: [%reorder order=(list pith)]
:: ==
/@ task-diff /@ task-diff
:: import lib/manx-utils
/- manx-utils /- manx-utils
::
:: declare that this is a conversion from a
:: dynamic XML node to task-diff
:- [%node %$ %task-diff] :- [%node %$ %task-diff]
|= nod=node |= nod=node
^- task-diff ^- task-diff
=/ mu ~(. manx-utils nod) =/ mu ~(. manx-utils nod)
:: extract head attribute from XML node
=/ head (@tas (got:mu %head)) =/ head (@tas (got:mu %head))
%- task-diff %- task-diff
?+ head ?+ head
~| [%unknown-head head] ~| [%unknown-head head]
!! !!
%become %new
=/ path (stab (vol:mu "path")) :: extract text and prepend attributes from XML node
[head (pave:neo path)] =/ text (vol:mu "text")
:: =/ prepend (vol:mu "prepend")
%nest ?: =(prepend 'prepend')
=/ name (vol:mu "name") :: construct the task-diff
[head name '' | ~] [head [text | & ~] &]
:: [head [text | & ~] |]
%prep
=/ name (vol:mu "name")
[head name '' | ~]
::
%oust
=/ path (stab (got:mu %pith))
[head (pave:neo path)]
:: ::
%edit %edit
=/ text (vol:mu "text") :: extract text attribute from XML node
=/ text (vol:mu "text")
:: extract checked attribute from done element in XML node
=/ done-el (need (named:mu "done")) =/ done-el (need (named:mu "done"))
=/ done (~(has by (malt a.g.done-el)) %checked) =/ done (~(has by (malt a.g.done-el)) %checked)
:: construct the task-diff
[head text done] [head text done]
:: ::
%kid-done %oust
:: extract pith attribute from XML node
=/ path (stab (got:mu %pith)) =/ path (stab (got:mu %pith))
:: construct the task-diff
[head (pave:neo path)] [head (pave:neo path)]
:: ::
%reorder %reorder
=/ piths =/ piths
::
:: extracting here attribute from each node in XML
:: list and return as last element of here path
%+ turn c.nod %+ turn c.nod
|= =manx |= =manx
=/ here (get:mu %here) =/ mu-reorder ~(. manx-utils manx)
=/ here (get:mu-reorder %here)
?~ here ?~ here
~& >>> [%bad-here manx] ~& >>> [%bad-here manx]
!! !!
(pave:neo /[(rear (stab (crip (need here))))]) (pave:neo /[(rear (stab (crip (need here))))])
:: construct the task-diff
[head piths] [head piths]
== ==

View File

@ -0,0 +1,21 @@
/@ todos
/@ node
/- manx-utils
/- html-utils
:- [%node %$ %todos]
|= nod=node
^- todos
|^
=* mu ~(. manx-utils nod)
=* hu ~(. mx.html-utils nod)
:- (is-checked (need (named:mu "show-done")))
%+ turn c.q:(need (gen:hu "todos"))
|= =manx
^- [done=? name=@t]
=. nod manx
:- (is-checked (need (named:mu "done")))
(vol:mu "todo-name")
++ is-checked
|= =manx
(~(has by (malt a.g.manx)) %checked)
--

View File

@ -4,5 +4,4 @@
:- [%node %$ %txt] :- [%node %$ %txt]
|= nod=node |= nod=node
^- txt ^- txt
(~(vol manx-utils nod) "text") (~(vol manx-utils nod) "text")

View File

@ -0,0 +1,62 @@
/@ number :: @ud
:: import /lib/feather-icons
/- feather-icons
:: declare that this is a conversion from number to HTMX
:- [%number %$ %htmx]
::
:: this gate accepts a number and a bowl:neo;
:: we'll access bowl:neo in the UI to access the
:: here.bowl of the shrub that's using this /con file
|= =number
|= =bowl:neo
::
:: this gate returns a manx, which is what Hoon uses
:: to store dynamic XML nodes; in this case we'll use
:: Sail to specify a manx that expects the HTMX library
:: to be available on the frontend
^- manx
::
:: open a <div class="p3 fc g2 ac br2">
:: these utility classes are specified in feather.css,
:: which this /con file expects on the frontend
;div.p3.fc.g2.ac.br2
:: <h1>Counter</h1>
;h1: Counter
:: <p>{number}</p>
;p: {<number>}
:: open a <form> with HTMX attributes
;form
::
:: hx-post will issue a POST request to the provided
:: url and swap response into the DOM
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=counter-diff"
::
:: hx-target specifies the target for hx-post's DOM
:: swap: the element with class "loading"
=hx-target "find .loading"
::
:: hx-swap specifies how the response to hx-post's
:: request will be swapped in relative to the target
=hx-swap "outerHTML"
::
:: here, the head attribute specifies the poke that
:: hx-post will send to the target shrub; look at
:: /con/node-counter-diff.hoon for more on =head
=head "inc"
::
:: below, the classes "loaded", "loader", and
:: "loading" provide loading spinner behavior on
:: sending and receiving this form's POST request
::
:: <button class="bd1 br1 pr b1 hover loader">
;button.bd1.br1.p2.b1.hover.loader
:: <span class="loaded">Increment</span>
;span.loaded: Increment
:: <span class="loading">
;span.loading
:: import +loading sail from /lib/feather-icons
;+ loading.feather-icons
== :: </span>
== :: </button>
== :: </form>
== :: </div>

View File

@ -120,7 +120,7 @@
|= [=pith =idea:neo] |= [=pith =idea:neo]
^- (unit pent) ^- (unit pent)
?~ pith ~ ?~ pith ~
=/ entry !<(planner-entry q.pail.idea) =/ entry !<(planner-entry q.q.saga.idea)
?. ?& ?. ?&
(gte when.entry d) (gte when.entry d)
(lth when.entry (add d ~d1)) (lth when.entry (add d ~d1))
@ -141,7 +141,7 @@
%+ murn ~(tap of:neo kids.bowl) %+ murn ~(tap of:neo kids.bowl)
|= [=pith =idea:neo] |= [=pith =idea:neo]
^- (unit pent) ^- (unit pent)
=/ entry !<(planner-entry q.pail.idea) =/ entry !<(planner-entry q.q.saga.idea)
?. ?& ?. ?&
(gte d when.entry) (gte d when.entry)
(lte d (add when.entry length.entry)) (lte d (add when.entry length.entry))

View File

@ -10,7 +10,6 @@
=id "tabs-{id}" =id "tabs-{id}"
;+ editor ;+ editor
;+ viewer ;+ viewer
;+ docs
== ==
== ==
++ id ++ id
@ -58,15 +57,6 @@
; ;
; view ; view
== ==
;label.fr.je.g1.grow.hidden
;input
=name "view"
=type "radio"
=oninput "$('#tabs-{id}').children().addClass('hidden');$('#docs-{id}').removeClass('hidden');"
;
==
;span: docs
==
== ==
++ editor ++ editor
;form.fc.p1.g1.hidden.grow.basis-half.scroll-y.relative ;form.fc.p1.g1.hidden.grow.basis-half.scroll-y.relative
@ -141,716 +131,4 @@
+.res +.res
== ==
== ==
:: XX import from source file instead of copying
++ docs
;div.grow.border.basis-half.scroll-x.scroll-y.hidden
=id "docs-{id}"
=style "min-width: 300px; height: 100%;"
;div.prose.p3
# Intro to Feather
Feather is a _Design System_ which gives
Sail developers easy access to a small set of
predefined styles.
Feather is implemented as a library of CSS classes,
and is bundled with Sky and Hawk.
Benefits of opting into
Feather's constraints:
- Feather uses CSS variables that...
- the user can override
- respect OS light/dark theme
- UIs styled with Feather fit in
with the style of Sky and Hawk
- "birds of a feather flock together"
-----------------------------------------------
## The `prose` Class
the `.prose` class adds blog-like spacing,
sizing, and readability styling to semantic
children such as `p`
`li` `h1` `h2` `a` etc.
This document uses it.
```
;article.prose
# cool
- neat
- fine
==
```
-----------------------------------------------
## Flexbox
;*
%+ turn
:~
"fr jb"
"fr ja"
"fr jc"
"fr js"
"fr je"
"fc ac"
"fc as"
"fc ae"
"fc af"
==
|= =tape
;div.fc.g1.br1(style "margin-top: 20px;")
;code: {tape}
;div
=class "bd1 br1 p3 g1 {tape}"
;* %+ turn (gulf 1 3)
|= n=@
;b.b1.f3.p1.br1: X
==
==
;div.fc.g3(style "margin-top: 50px;")
;*
%+ turn
:~
"fr g0"
"fr g1"
"fr g2"
"fr g3"
"fr g4"
"fr g5"
"fr g6"
"fr g7"
"fr g8"
==
|= =tape
;div
=class "s-2 mono {tape}"
;div.bd1.p2: {tape}
;* %+ turn (gulf 1 3)
|= n=@
;div.bd1.p2;
==
==
;div.fr.g2(style "margin-top: 50px;")
;*
%+ turn
:~
"fc g0"
"fc g1"
"fc g2"
"fc g3"
"fc g4"
"fc g5"
"fc g6"
"fc g7"
"fc g8"
==
|= =tape
;div
=class "s-2 mono {tape}"
;div.bd1.p1(style "width: min-content;"): {tape}
;* %+ turn (gulf 1 3)
|= n=@
;div.bd1.p2;
==
==
;div.frw.g2(style "margin-top: 50px;")
;*
%+ turn (gulf 1 10)
|= n=@
;div.p2.bd1.mono: frw g2
==
;div.f2.mono
;div.fr.g4.p2.bd1.br1(style "margin-top: 50px;")
;div.p2.br1.b1;
;div.p2.br1.b1.tc.grow: grow
;div.p2.br1.b1;
==
;div.fr.g4.p2.bd1.br1(style "margin-top: 20px;")
;div.p2.br1.b1;
;div.p2.br1.b1;
;div.p2.br1.b1.tc.grow: grow
==
;div.fr.g4.p2.bd1.br1(style "margin-top: 20px;")
;div.p2.br1.b1.tc.grow: grow
;div.p2.br1.b1;
;div.p2.br1.b1.tc.grow: grow
==
==
-----------------------------------------------
## Typography
;div.frw.g1.br1.ac.jc
;*
%+ turn
:~
"s-2"
"s-1"
"s0"
"s2"
"s3"
"s4"
"s5"
"s6"
==
|= =tape
;span
=class "p2 {tape}"
; {tape}
==
==
;div.frw.g1.br1.ac.jc
;*
%+ turn
:~
"mono"
"bold"
"italic"
"underline"
"strike"
==
|= =tape
;span
=class "p2 {tape}"
; {tape}
==
==
-----------------------------------------------
## Text Alignment
;*
%+ turn
:~
"tl"
"tc"
"tr"
==
|= =tape
;div
=class "mono {tape}"
; {tape}
==
-----------------------------------------------
## Foreground & Background Colors
;div.frw.g1.br1.ac.jc.mono
;*
%+ turn
:~
"f-3"
"f-2"
"f-1"
"f0"
"f1"
"f2"
"f3"
"f4"
==
|= =tape
;span
=class "p2 bold {tape}"
; {tape}
==
==
;div.frw.g1.br1.ac.jc.mono
;*
%+ turn
:~
"b-3"
"b-2"
"b-1"
"b0"
"b1"
"b2"
"b3"
"b4"
==
|= =tape
;span
=class "p2 {tape}"
; {tape}
==
==
-----------------------------------------------
## Padding
;div.fc.ac.g2
;*
%+ turn
:~
"p-8"
"p-7"
"p-6"
"p-5"
"p-4"
"p-3"
"p-2"
"p-1"
"p0"
"p1"
"p2"
"p3"
"p4"
"p5"
"p6"
"p7"
"p8"
"p-page"
==
|= =tape
;div
=class "wfc mono f2 b1 {tape}"
; {tape}
==
==
-----------------------------------------------
## Margin
;div
;*
%+ turn
:~
"m0"
"ma"
"mt1"
"mt2"
"mt3"
==
|= =tape
;div
=class "mono f2 b2 br1 wfc p2 {tape}"
; {tape}
==
==
-----------------------------------------------
## Opacity
;div.frw.g2.ac.jc
;*
%+ turn
:~
"o0"
"o1"
"o2"
"o3"
"o4"
"o5"
"o6"
"o7"
"o8"
"o9"
"o10"
==
|= =tape
;div.fc.g1.ac.jc
;span.mono.s-1.f2: {tape}
;div
=class "wfc mono f0 b1 p4 bd1 {tape}"
;
==
==
==
-----------------------------------------------
## Borders
;div.frw.ac.g2(style "margin-top: 20px;")
;*
%+ turn
:~
"bd0"
"bd1"
"bd2"
"bd3"
==
|= =tape
;div
=class "wfc mono f2 p2 {tape}"
; {tape}
==
==
;div.frw.ac.g2(style "margin-top: 20px;")
;*
%+ turn
:~
"br0"
"br1"
"br2"
"br3"
==
|= =tape
;div
=class "wfc mono f2 p2 bd1 {tape}"
; {tape}
==
==
-----------------------------------------------
## Dimensions
- `wf` width: full
- `wfc` width: fit-content
- `mw-page` max-width: page (650px)
- `hf` height: full
- `hfc` height: fit-content
-----------------------------------------------
## Special
;*
%+ turn
:~
"toggled"
"hover"
==
|= =tape
;button(style "margin: 5px;")
=class "wfc mono f0 b0 p2 bd1 {tape}"
; {tape}
==
the `hidden` class hides the element.
-----------------------------------------------
## Request indicators
`loader` indicator parent
`loading` loading state
`loaded` loaded state
;details.mt1
;summary: Example
;button.mt1.b1.p1.hover.br1.bd1.f1.loader
=onclick "$(this).toggleClass('htmx-request')"
;span.loaded: toggle load state
;span.loading.f1: ...loading
==
```
;button.loader
=onclick "$(this).toggleClass('htmx-request')"
;span.loaded: toggle load state
;span.loading: ...loading
==
```
==
-----------------------------------------------
## Misc
`scroll-y`\
scroll-y: auto
`scroll-x`\
scroll-x: auto
`relative`\
position: relative
`sticky`\
position: sticky
`absolute`\
position: absolute
`fixed`\
postion: fixed
`block`\
display: block
`inline`\
display: inline-block
`pre`\
white-space: pre
`pre-line`\
white-space: pre-line
`break`\
word-break: break-word
`action`\
touch-action: manipulation
-----------------------------------------------
## Feather Sutra
> Order requires constraints.
### Primary Constraint
Interfaces must work on a mobile web browser.
### Consequent Constraints
- no element should need to be wider than 350px
- avoid horizontal scrolling
- left-click is the only mouse event
### Locality of Behavior
- co-locate actionable elements with the elements on which they act
- put styling inline
- put javascript inline
### Mechanical Simplicity
- don't fight the browser
- avoid animations
- prefer [bubbling-event](https://htmx.org/attributes/hx-on/)
architectures
- store state as text attributes in the DOM, not javascript state
### UX low-hanging fruit
- network requests should always have indicators
- prefer autosave to manually saving
- be semantic with your tags
-----------------------------------------------
## Feather Tantra
> Life evolves through a vital chaos.
```
;div.any.class(style "any: css;");
;div
=class "any class"
=style
"""
any: "css";
that-you: "want;
"""
;
==
;style
;+ ;/ %- trip
'''
.any-css {
that-you: "want";
}
'''
==
;script
;+ ;/ %- trip
'''
// any javascript you want
'''
==
```
;div.end;
;style
;+ ;/ %- trip
'''
details {
display: flex !important;
flex-direction: column;
padding: 12px;
background: var(--b1);
box-sizing: border-box;
}
.end {
margin-bottom: 450px;
}
hr {
margin: 100px 0;
}
'''
==
==
==
-- --

View File

@ -1,26 +1,65 @@
/@ sky /@ sky
/@ sky-settings /@ sky-settings
/- feather-icons /- feather-icons
/* date-now
/* a-i-r
/* feather
/* reset
/* hawk-icon
/* jquery
/* htmx-js
/* htmx-response-targets
/* htmx-idiomorph
:- [%sky %$ %htmx] :- [%sky %$ %htmx]
|= =sky |= =sky
|= =bowl:neo |= =bowl:neo
^- manx ^- manx
|^ |^
;div.wf.hf.relative =; m
;a-i-r.wf.hf.relative %- lift
=style "opacity: var(--sky-opacity); padding: var(--sky-outer-gap);" ?: menu.sky m
=id "air" m(a.g [[%closed ""] a.g.m])
=hawks "{<open.sky>}" ^- manx
=morph-retain "closed" ;a-i-r.wf.hf.relative
;+ menu-btn =style "opacity: var(--sky-opacity); padding: var(--sky-outer-gap);"
;+ menu-btn-style =id "air"
;+ theme-style =hawks "{<open.sky>}"
;+ nav =morph-retain "closed"
;* p:(spin (scag open.sky hawks.sky) 0 ha-wk) =hx-on-hawks-moved hawks-moved-js
== =hx-on-htmx-after-request
;+ eye """
let verb = event.detail.requestConfig.verb;
let url = new URL(event.detail.xhr.responseURL);
let pams = new URLSearchParams(url.search);
if (verb === 'get' &&
url.pathname.startsWith('/neo/hawk/~') &&
!pams.has('no-save')
) \{
$('.nav-refresher').emit('refresh');
}
"""
;* p:(spin (scag open.sky hawks.sky) 0 ha-wk)
;+ menu-btn
;+ nav
== ==
:: ::
++ hawks-moved-js
:: js to run whenever the order or number of hawks changed.
:: it will:
:: - trigger a refresh of the nav
:: - loop through any slotted hawks and reslot them starting from 0
%- trip
'''
let air = $(this);
let num = parseInt(air.attr('hawks'));
let hawks = air.children('[slot]').filter('.hawk').get();
hawks.sort((a, b) => {
return (a.getAttribute('slot') < b.getAttribute('slot')) ? -1 : 1;
}).forEach((h, i) => {
h.setAttribute('slot', `s${i}`);
});
air.find('.nav-refresher').emit('refresh');
'''
++ map-to-css-tape ++ map-to-css-tape
|= m=(map @t @t) |= m=(map @t @t)
^- tape ^- tape
@ -37,7 +76,7 @@
?~ s ~ ?~ s ~
:- ~ :- ~
!< sky-settings !< sky-settings
q.pail.u.s q.q.saga.u.s
;style ;style
;+ ;/ ;+ ;/
?~ settings ?~ settings
@ -49,9 +88,17 @@
""" """
== ==
++ menu-btn ++ menu-btn
=; m
?: menu.sky m
m(a.g [[%closed ""] a.g.m])
^- manx
;button.hover.f2.b2.fc.ac.jc.air-btn.wf ;button.hover.f2.b2.fc.ac.jc.air-btn.wf
=slot "button" =slot "button"
=onclick "$(this).closest('a-i-r').attr('closed', !$(this).parent().attr('closed'))" =onclick "this.parentNode.toggleAttribute('closed'); this.toggleAttribute('closed');"
=hx-post "/neo/hawk/{<our.bowl>}/sky?stud=sky-diff"
=head "menu"
=hx-target "this"
=hx-swap "none"
;div.fc.ac.jc.bold.s3.f3(style "height: 2rem;"): ~ ;div.fc.ac.jc.bold.s3.f3(style "height: 2rem;"): ~
== ==
++ menu-btn-style ++ menu-btn-style
@ -67,8 +114,8 @@
@media(max-width: 900px) { @media(max-width: 900px) {
.air-btn { .air-btn {
position: absolute; position: absolute;
bottom: 25px; bottom: 45px;
right: 25px; left: 25px;
padding: 30px; padding: 30px;
width: 70px; width: 70px;
height: 70px; height: 70px;
@ -89,26 +136,30 @@
?: =(pith /) "" ?: =(pith /) ""
(en-tape:pith:neo pith) (en-tape:pith:neo pith)
=/ idt `tape`(zing (scan +:(scow %da id) (most dot (star ;~(less dot prn))))) =/ idt `tape`(zing (scan +:(scow %da id) (most dot (star ;~(less dot prn)))))
;div.wf.hf.br1 ;div.wf.hf.fc.jc.ac.f2.s3.spinner
=slot "s{<a>}" =slot "s{<a>}"
=id "hawk-windshield-{idt}" =id "hawk-{idt}"
;div.wf.hf.fc.jc.ac.f2.s3.spinner =hx-get "/neo/hawk{ext}?slot={<a>}&hawk-id={<id>}&no-save"
=id "hawk-{idt}" =morph-retain "slot"
=morph-if-class "spinner" =hx-trigger "load"
;+ loading.feather-icons =hx-target "this"
== =hx-swap "morph"
;div.hidden ;+ loading.feather-icons
=hx-get "/neo/hawk{ext}?slot={<a>}&id={<id>}&no-save"
=hx-trigger "load"
=hx-target "#hawk-{idt}"
=hx-swap "morph"
;
==
== ==
++ nav ++ nav
;nav.wf.hf.p2.fc.g2 ;nav.wf.hf.p2.fc.g2.sky-nav
=slot "nav" =slot "nav"
;div.mt2.o0; ;div.nav-refresher.loader.p3
=hx-get "/neo/sky"
=hx-swap "outerHTML"
=hx-target "closest nav"
=hx-select "nav.sky-nav"
=hx-trigger "refresh"
;span.loaded;
;span.loading
;+ loading.feather-icons
==
==
;+ new-tab ;+ new-tab
;* ;*
=< p =< p
@ -119,16 +170,46 @@
:_ +(a) :_ +(a)
=/ idt `tape`(zing (scan +:(scow %da id) (most dot (star ;~(less dot prn))))) =/ idt `tape`(zing (scan +:(scow %da id) (most dot (star ;~(less dot prn)))))
=/ color (trip ?:((lth a open.sky) 'b2' 'b1')) =/ color (trip ?:((lth a open.sky) 'b2' 'b1'))
=/ close-hawk-js
%- trip
'''
let toClose = parseInt(this.getAttribute('close'));
let air = $('a-i-r');
let num = parseInt(air.attr('hawks'));
let hawks = air.children('[slot]').filter('.hawk');
if (toClose < num) {
air.attr('hawks', hawks.length-1);
}
hawks.each(function() {
let slot = parseInt($(this).attr('slot').slice(1));
if (slot == toClose) {
$(this).remove();
}
});
$(this).emit('hawks-moved');
'''
:: =/ maximize-hawk-js
:: %- trip
:: '''
:: let air = $('a-i-r');
:: let num = parseInt(air.attr('hawks'));
:: air.attr('hawks', num+1);
:: let toMax = '#hawk-' + this.getAttribute('hawk');
:: $(toMax).attr('slot', 's-1');
:: $(this).emit('hawks-moved');
:: '''
;div ;div
=id "hawk-tab-{idt}" =id "hawk-tab-{idt}"
=hx-ext "ignore:html-enc"
=class "fr ac br1 {color}" =class "fr ac br1 {color}"
;button ;button
=class "loader p2 tl br1 hover grow {color}" =class "loader p2 tl br1 hover grow {color}"
=hx-post "/neo/hawk/{<our.bowl>}/sky?stud=sky-diff" =hx-post "/neo/hawk/{<our.bowl>}/sky?stud=sky-diff&head=maximize&slot={<a>}"
:: XX optimistically render
::=hx-on-htmx-after-request maximize-hawk-js
=hawk idt
=hx-target "find .loading" =hx-target "find .loading"
=hx-swap "outerHTML" =hx-swap "outerHTML"
=head "maximize"
=hawk-slot "{<a>}"
;span.loaded: {(en-tape:pith:neo pith)} ;span.loaded: {(en-tape:pith:neo pith)}
;span.loading ;span.loading
;+ loading.feather-icons ;+ loading.feather-icons
@ -136,11 +217,10 @@
== ==
;button ;button
=class "loader p2 tl br1 hover {color}" =class "loader p2 tl br1 hover {color}"
=hx-post "/neo/hawk/{<our.bowl>}/sky?stud=sky-diff" =close "{<a>}"
=hx-target "find .loading" =hx-post "/neo/hawk/{<our.bowl>}/sky?stud=sky-diff&head=close&slot={<a>}"
=hx-swap "outerHTML" =hx-swap "none"
=head "close" =hx-on-htmx-after-request close-hawk-js
=hawk-slot "{<a>}"
;span.loaded.f3 ;span.loaded.f3
;+ close.feather-icons ;+ close.feather-icons
== ==
@ -151,15 +231,18 @@
== ==
== ==
++ new-tab ++ new-tab
:: XX optimistically render
;button.loader.b2.p2.tc.br1.hover.wfc.s-1 ;button.loader.b2.p2.tc.br1.hover.wfc.s-1
=hx-post "/neo/hawk/{<our.bowl>}/sky?stud=sky-diff" =hx-ext "ignore:html-enc"
=hx-post "/neo/hawk/{<our.bowl>}/sky?stud=sky-diff&head=new-hawk"
=hx-target "find .loading" =hx-target "find .loading"
=hx-swap "outerHTML" =hx-swap "outerHTML"
=hx-on-htmx-after-request "$(this).emit('hawks-moved')"
=type "button" =type "button"
=head "new-tab" =hx-vals (trip 'js:{now: urbitTimestamp()}')
;span.loaded.fr.ac.js.g2 ;span.loaded.fr.ac.js.g2
;+ add.feather-icons ;+ add.feather-icons
;span.f3: new tab ;span.f3: new window
== ==
;span.loading ;span.loading
;+ loading:feather-icons ;+ loading:feather-icons
@ -175,15 +258,18 @@
function handleKey(e) { function handleKey(e) {
let focused = document.activeElement; let focused = document.activeElement;
let textarea = ['TEXTAREA'].includes(focused.nodeName) let textarea = ['TEXTAREA'].includes(focused.nodeName)
let textinput = ['text', 'number', 'email', 'password'].includes(focused.getAttribute('type')); let textinput = ['text', 'number', 'email', 'password'].includes(focused.type);
if (textarea || textinput) { if (textarea || textinput) {
if (e.key === 'Escape') { if (e.key === 'Escape') {
closeEye();
document.activeElement.blur(); document.activeElement.blur();
} }
return; return;
} }
if (e.key === ' ') { else if (e.key === 'Escape') {
closeEye();
document.activeElement.blur();
}
else if (e.key === ' ') {
e.preventDefault(); e.preventDefault();
if (window.eye.open) { if (window.eye.open) {
closeEye(); closeEye();
@ -256,4 +342,204 @@
''' '''
== ==
== ==
++ icon-url
^~
%- trip
%^ cat
3
'data:image/png;base64,'
%- ~(en base64:mimes:html & |)
(as-octs:mimes:html hawk-icon)
++ favicon
^~
=; m m(a.g [[%href icon-url] a.g.m])
^- manx
;link
=rel "icon"
=type "image/png"
;
==
++ manifest-url
^~
%- trip
%^ cat
3
'data:application/json;utf-8,'
%- en:json:html
%- pairs:enjs:format
:~
['name' s+'sky']
['description' s+'an urbit namespace viewer']
['start_url' s+'http://localhost/neo/sky'] :: XX
['display' s+'standalone']
['background_color' s+'black']
:+ 'icons' %a
:~
%- pairs:enjs:format
:~
['src' s+(crip icon-url)]
['sizes' s+'196x196']
['type' s+'image/png']
==
==
==
++ manifest
^~
=; m m(a.g [[%href manifest-url] a.g.m])
^- manx
;link
=rel "manifest"
;
==
++ htmx-extensions
:: htmx extension which encodes the request
:: as the serialized HTML of the calling element
::
:: XX usage of this should be optional.
:: requests should default to form-encoded.
%- trip
'''
htmx.defineExtension('html-enc', {
onEvent: function (name, evt) {
if (name === "htmx:configRequest") {
evt.detail.headers['Content-Type'] = "text/html";
}
},
encodeParameters : function(xhr, parameters, elt) {
xhr.overrideMimeType('text/html');
let xmls = new XMLSerializer();
return (xmls.serializeToString(elt));
}
});
Idiomorph.defaults.ignoreActive = true;
Idiomorph.defaults.callbacks.beforeAttributeUpdated = (name, node, type) => {
if (node.hasAttribute('morph-retain')) {
let ribs = node.getAttribute('morph-retain').split(',').map(t => t.trim());
if (ribs.includes(name)) {
return false;
}
}
}
Idiomorph.defaults.callbacks.beforeNodeMorphed = (oldNode, newNode) => {
if (oldNode?.nodeName !== "#text") {
if (oldNode.hasAttribute('morph-no-swap') && oldNode.id === newNode.id) {
return false;
}
else if (
newNode.hasAttribute('morph-if-class') &&
!oldNode.classList.contains(newNode.getAttribute('morph-if-class'))
) {
return false;
}
}
}
'''
::
++ lift
|= in=manx
^- manx
;html
;head
;meta(charset "UTF-8");
;title: s k y
;script: {(trip jquery)}
;script: {(trip htmx-js)}
;script: {(trip htmx-response-targets)}
;script: {(trip htmx-idiomorph)}
;script: {htmx-extensions}
;link
=rel "stylesheet"
=href "https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.15.1/cdn/themes/light.css"
;
==
;script
=type "module"
=src "https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.15.1/cdn/shoelace.js"
;
==
;meta
=name "viewport"
=content
"""
width=device-width,
initial-scale=1.0,
maximum-scale=1.0
"""
;
==
;meta
=name "htmx-config"
=content (trip '{"ignoreTitle":"true"}')
;
==
::;style
:: ;+ ;/ %- trip
:: '''
:: @font-face {
:: font-family: 'Urbit Sans';
:: src: url("https://media.urbit.org/fonts/UrbitSans/UrbitSansVFWeb-Regular.woff2") format("woff2");
:: font-style: normal;
:: font-weight: 100 700;
:: }
:: '''
::==
;style: {(trip reset)}
;style: {(trip feather)}
;script
;+ ;/ %- trip
'''
window.log = function() {
if (this.console) {
console.log(Array.prototype.slice.call(arguments));
}
};
jQuery.fn.log = function (msg) {
console.log(msg, this);
return this;
};
jQuery.fn.emit = function (name) {
(this[0]).dispatchEvent(
new Event(
name,
{ bubbles: true, cancelable: true, composed: true }
)
);
return this;
};
function urbitTimestamp() {
let now = new Date();
let year = now.getFullYear();
let month = now.getMonth() + 1;
let date = now.getDate();
let hour = String(now.getHours()).padStart(2, '0');
let min = String(now.getMinutes()).padStart(2, '0');
let sec = String(now.getSeconds()).padStart(2, '0');
return `~${year}.${month}.${date}..${hour}.${min}.${sec}`;
}
'''
==
;script: {(trip a-i-r)}
;script: {(trip date-now)}
;+ favicon
;+ manifest
==
;body
=hx-ext "html-enc,response-targets,morph"
=hx-swap "outerHTML"
=hx-boost "true"
=hx-history "false"
=hx-replace-url "/neo/sky"
=style
"""
background-color: var(--b1);
background-image: var(--sky-bg-url);
background-size: var(--sky-bg-size);
background-repeat: var(--sky-bg-repeat);
"""
;+ in
;+ eye
;+ menu-btn-style
;+ theme-style
==
==
-- --

View File

@ -39,7 +39,7 @@
== ==
++ home-button ++ home-button
;a.p2.br1.bd1.b1.hover.loader.wfc.block ;a.p2.br1.bd1.b1.hover.loader.wfc.block
=href "/neo/hawk/home" =href "/neo/hawk/{(scow %p our.bowl)}/home"
=hx-swap "innerHTML" =hx-swap "innerHTML"
=hx-target "closest .hawk" =hx-target "closest .hawk"
=hx-select ".hawk" =hx-select ".hawk"

View File

@ -0,0 +1,293 @@
/@ slideshow
/- feather-icons
:- [%slideshow %$ %htmx]
|= =slideshow
|= =bowl:neo
|^
;div.slideshow.fc.relative.wf.hf
;+ controls
;div.frw.js.af.scroll-y.hf
;+ editor
;+ previewer
;+ deck
==
;+ script
;+ style
==
++ controls
=/ cls "p-1 br1 b1 hover"
;form.p2.frw.js.ac.g3.sticky.wf
=style "top:0; left: 0;"
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=slideshow-diff"
=hx-swap "none"
=head "mode"
;button
=class "{cls} {(trip ?:(=(%edit mode.slideshow) 'toggled' ''))}"
=morph-retain "class"
=type "submit"
=onclick "shChangeMode(this, ['.sh-editor'])"
=mode "edit"
; edit
==
;button
=class "{cls} {(trip ?:(=(%both mode.slideshow) 'toggled' ''))}"
=morph-retain "class"
=type "submit"
=onclick "shChangeMode(this, ['.sh-editor', '.sh-previewer'])"
=mode "both"
; both
==
;button
=class "{cls} {(trip ?:(=(%preview mode.slideshow) 'toggled' ''))}"
=morph-retain "class"
=type "submit"
=onclick "shChangeMode(this, ['.sh-previewer'])"
=mode "preview"
; preview
==
;div.grow;
;button
=class "{cls} {(trip ?:(=(%present mode.slideshow) 'toggled' ''))}"
=morph-retain "class"
=type "submit"
=onclick "shChangeMode(this, ['.deck'])"
=mode "present"
; present
==
==
++ editor
=/ open ?|(=(%edit mode.slideshow) =(%both mode.slideshow))
=/ hid ?:(open "" "hidden")
;div
=class "sh-editor sh-tab {hid} basis-half grow fc"
=morph-retain "class"
;form
=class "fc p1 g1 scroll-y relative grow"
=style "min-width: 300px; height: 100%;"
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=slideshow"
=hx-swap "morph"
=hx-target "closest .slideshow"
=hx-select ".slideshow"
=hx-trigger "input changed delay:0.4s from:find textarea, input changed delay:0.4s from:find input"
;input.p2.mono.bd1.br1
=name "classes"
=placeholder "prose p3"
=type "text"
=autocomplete "off"
=value (trip class.slideshow)
=oninput "$(this).attr('value', this.value);"
;
==
;textarea.p-page.pre.mono.scroll-x.grow.bd1.m0.br1
=name "code"
=morph-no-swap ""
=oninput "this.setAttribute('value', this.value);"
=spellcheck "false"
=value (trip code.slideshow)
=placeholder "# new slideshow"
; {(trip code.slideshow)}
==
;div.absolute
=style "top: 11px; right: 11px;"
;div.loader
;span.loaded(style "opacity: 0;"): ---
;span.loading
;+ loading.feather-icons
==
==
==
==
==
++ error
|= =tang
;div.fc.g3.p3.s0
;div.pre.mono
;*
%+ turn (scag 25 tang)
|= =tank
;span: {(of-wall:format (~(win re tank) 0 80))}
==
;div.pre.numbered.mono
;span: ;>
;span;
;*
%+ turn (to-wain:format code.slideshow)
|= t=@t
;span: {(trip t)}
==
==
++ previewer
=/ open ?|(=(%preview mode.slideshow) =(%both mode.slideshow))
=/ hid ?:(open "" "hidden")
;main
=class "sh-previewer sh-tab grow hf basis-half scroll-x scroll-y br1 {hid}"
=style "min-width: 300px;"
=morph-retain "class"
;+
?~ result.slideshow
;div.prose.p3
;h1: empty slideshow
==
=/ res u.result.slideshow
?- -.res
%.n (error +.res)
%.y
;div.p-page
;*
=< p
%^ spin
`(list manx)`+.res
0
|= [m=manx a=@ud]
:_ +(a)
=/ bdr ?:(=(slide.slideshow a) "bd2" "bd1")
;div.mw-page.ma.mt3.p1.bd1
;p.f3: {<+(a)>}
;div
=style "container-type: inline-size;"
;+ m(a.g [[%class (trip class.slideshow)] a.g.m])
==
==
==
==
==
++ deck
=/ hid ?:(=(%present mode.slideshow) "" "hidden")
;form
=class "deck b0 sh-tab grow basis-half scroll-x scroll-y wf hf {hid}"
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=slideshow-diff"
=hx-trigger "sh-change-slide"
=hx-swap "none"
=head "slide"
=current (scow %ud slide.slideshow)
=tabindex "0"
=onkeydown "shHandleKey(event, $(this))"
=style "min-width: 300px; height: 100%;"
=morph-retain "class"
;+
?~ result.slideshow
;div.prose.p3
;h1: empty slideshow
==
=/ res u.result.slideshow
?- -.res
%.n (error +.res)
%.y
=/ slides `(list manx)`+.res
=/ prev-t (scow %ud ?~(slide.slideshow 0 (dec slide.slideshow)))
=/ next-t (scow %ud (min (dec (lent slides)) +(slide.slideshow)))
;div.relative.wf.hf
;div.present-controls.fr.g1.ac.js.absolute.p2.o7.z1
=style "top: 0; right: 0;"
;button.p2.b1.br1.bd1.hover
=type "button"
=onclick "shPrevious($(this).closest('.deck'))"
;+ chevron-left.feather-icons
==
;span.sh-counter.f3.p2.b1.br1: {<+(slide.slideshow)>}/{<(lent slides)>}
;button.p2.b1.br1.bd1.hover
=type "button"
=onclick "shNext($(this).closest('.deck'))"
;+ chevron-right.feather-icons
==
;button.sh-fs-tog.p2.b1.br1.bd1.hover
=type "button"
=onclick "shToggleFullscreen($(this).closest('.deck'));"
; ⛶
==
==
;*
=< p
%^ spin
slides
0
|= [m=manx a=@ud]
:_ +(a)
=/ hid ?:(=(slide.slideshow a) "" "hidden")
=/ extra "wf hf"
=/ cls "{(trip class.slideshow)} {extra}"
;div
=class "wf hf {hid}"
=sh-slide (scow %ud a)
;div.wf.hf
=style "container-type: inline-size;"
;+ m(a.g [[%class cls] a.g.m])
==
==
==
==
==
++ script
;script
;+ ;/ %- trip
'''
function shPrevious(deck) {
let current = deck.attr('current');
let i = parseInt(current);
let slides = deck.find('[sh-slide]');
let n = Math.max(0, i-1)
slides.addClass('hidden');
slides.filter(`[sh-slide='${n}']`).removeClass('hidden');
deck.attr('current', n);
deck.find('.sh-counter').text((n + 1)+`/${slides.length}`);
triggerSlideSave(deck[0]);
}
function shNext(deck) {
let current = deck.attr('current');
let i = parseInt(current);
let slides = deck.find('[sh-slide]');
let n = Math.min(slides.length-1, i+1)
slides.addClass('hidden');
slides.filter(`[sh-slide='${n}']`).removeClass('hidden');
deck.attr('current', n);
deck.find('.sh-counter').text((n + 1)+`/${slides.length}`);
triggerSlideSave(deck[0]);
}
function triggerSlideSave(that) {
const evt = new Event("sh-change-slide");
that.dispatchEvent(evt);
}
function shToggleFullscreen(deck) {
if (!!deck.attr('full')) {
deck.removeAttr('full');
document.exitFullscreen();
} else {
deck.attr('full', 'true');
deck[0]?.requestFullscreen();
}
}
function shHandleKey(ev, deck) {
let key = ev.key;
if (['ArrowLeft'].includes(key)) {
ev.preventDefault();
ev.stopPropagation();
shPrevious(deck);
} else if (['ArrowRight', ' '].includes(key)) {
ev.preventDefault();
ev.stopPropagation();
shNext(deck);
}
}
function shChangeMode(that, tabs) {
$(that).siblings().removeClass('toggled');
$(that).addClass('toggled');
$(that).closest('.slideshow').find('.sh-tab').addClass('hidden');
tabs.forEach(t => {
$(that).closest('.slideshow').find(t).removeClass('hidden');
$(that).closest('.slideshow').find(t)[0]?.focus();
})
}
'''
==
++ style
;style
;+ ;/ %- trip
'''
.slide {
overflow-y: auto;
padding: 4cqw 6cqw;
font-size: 2.4cqw;
}
'''
==
--

View File

@ -4,11 +4,4 @@
|= =bowl:neo |= =bowl:neo
=/ =wall (zing (turn tan |=(t=tank (~(win re t) [0 80])))) =/ =wall (zing (turn tan |=(t=tank (~(win re t) [0 80]))))
=/ =tape (zing (join "\0a" wall)) =/ =tape (zing (join "\0a" wall))
;textarea#input.wf.p2.pre.mono.grow ;/(tape)
=name "text"
=placeholder "code"
=spellcheck "false"
=value tape
=oninput "this.setAttribute('value', this.value);"
; {tape}
==

View File

@ -1,12 +1,16 @@
/@ task-diff /@ task-diff
/- feather-icons
:- [%task-diff %$ %htmx] :- [%task-diff %$ %htmx]
|= t=task-diff |= t=task-diff
|= =bowl:neo |= =bowl:neo
^- manx
;div.loading ;div.loading
=hx-get "/neo/hawk{(en-tape:pith:neo here.bowl)}" =hx-get "/neo/hawk{(en-tape:pith:neo here.bowl)}"
=hx-target "closest .hawk" =hx-target "closest .hawk"
=hx-indicator "closest .loader" =hx-indicator "closest .loader"
=hx-swap "innerHTML" =hx-swap "innerHTML"
=hx-trigger "load" =hx-trigger "load"
; +++ ;span.loading
;+ loading.feather-icons
==
== ==

View File

@ -1,276 +1,364 @@
/@ task /@ task :: [text=cord done=? kids-done=? order=(list pith)]
:: import /lib/feather-icons
/- feather-icons
:: declare that this is a conversion from task to HTMX
:- [%task %$ %htmx] :- [%task %$ %htmx]
:: outer gate takes a task, inner gate takes a bowl:neo,
:: so we can access here.bowl and kids.bowl in the ui
|= t=task |= t=task
|= =bowl:neo |= =bowl:neo
::
:: in this case, all sail rendering
:: happens in helper arms
|^ |^
shell shell
++ kids ~(tap of:neo kids.bowl) ::
++ id ++ pith-tape
:: pith to tape conversion
|= =pith
^- tape ^- tape
%- zing (en-tape:pith:neo pith)
%+ turn (pout here.bowl) ::
|= smeg=@ta ++ shell
%+ weld "--"
(trip smeg)
++ form-edit
^- manx
;form.fc.g2.br1
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=task-diff"
=hx-trigger "input changed delay:0.4s from:find textarea, input from:find input"
=hx-swap "none"
=head "edit"
;label.fr.g2.ac.js
;+ =- ?. done.t:+ -
-(a.g [[%checked ""] a.g.-])
^- manx
;input
=type "checkbox"
=name "done"
=onclick (trip 'if (this.checked) { this.setAttribute("checked", "")} else {this.removeAttribute("checked")}')
;
==
;span.grow: Done
;div.htmx-indicator
; ---
==
==
;textarea.wf.p2.border.br1.ma.mono
=name "text"
=autocomplete "off"
=spellcheck "false"
=rows "{<(add 2 (lent (fand ~[10] (trip text.t))))>}"
=oninput "this.setAttribute('value', this.value); this.rows = this.value.split('\\n').length"
=value (trip (@t text.t))
; {(trip (@t text.t))}
==
==
++ form-create
|= [head=@tas label=tape]
^- manx
;div.fc.g1
;button.b0.br1.hover.p2.wfc.mono.f3
=onclick
"""
this.classList.toggle('toggled');
this.nextElementSibling.classList.toggle('hidden');
this.nextElementSibling.firstChild.focus();
"""
; {label}
==
;form.fr.g1.hidden
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=task-diff"
=head (trip head)
=hx-swap "outerHTML"
=hx-target "find button .loading"
;input.wf.p1.border.br1.grow
=name "name"
=autocomplete "off"
=type "text"
=pattern (trip '[a-z]{1}[a-z0-9\\-]+')
=title "lowercase and heps"
=required ""
=placeholder "name"
=oninput "this.setAttribute('value', this.value);"
;
==
;button.b1.br1.hover.p1.wfc.loader
;span.loaded: create
;span.loading: ---
==
==
==
++ part-kid
|= [=pith =idea:neo]
=/ =pail:neo pail.idea
=/ t=task !<(task q.pail)
=- ?. done.t -
-(a.g [[%done ""] a.g.-])
^- manx
;div.fc.g1
=here (en-tape:pith:neo (welp here.bowl pith))
;div.fr.g1
;button
=class "b0 br1 hover p1 tl action mono fr g3 f2"
=style "padding: 4px 9px;"
=type "button"
=onclick
"""
this.textContent = this.textContent === "=" ? "|" : "="; toggleChildren(this);
"""
;span.bold: =
==
;+ =-
=/ that -
=/ classes
%+ weld
"b0 br1 hover p1 grow tl action mono fr g3"
?:(done.t " strike f3" "")
that(a.g [[%class classes] a.g.that])
^- manx
;button
=type "button"
=onclick
"""
this.classList.toggle('toggled'); this.parentNode.nextElementSibling.classList.toggle('hidden');
"""
;span.bold: {(trip -:(pout pith))}
;span.break.f2: {(scag (fall (find [10 ~] (trip text.t)) 30) (trip text.t))}
==
;a
=class "b0 br1 hover p1 loader f3"
=hx-indicator "this"
=href "/neo/hawk{(en-tape:pith:neo here.bowl)}{(en-tape:pith:neo pith)}"
=hx-swap "innerHTML"
;span.loaded: →
;span.loading: .
==
==
;div.border.p2.br1.frw.g2.hidden
=hx-disinherit "hx-indicator"
=style "margin-left: 20px;"
;button.b1.br1.p2.hover
=onclick "this.parentNode.parentNode.parentNode?.insertAdjacentElement('beforeend', this.parentNode.parentNode); center(this);"
; ↧
==
;button.b1.br1.p2.hover
=onclick "this.parentNode.parentNode.nextElementSibling?.insertAdjacentElement('afterend', this.parentNode.parentNode); center(this);"
; ↓
==
;button.b1.br1.p2.hover
=onclick "this.parentNode.parentNode.previousElementSibling?.insertAdjacentElement('beforebegin', this.parentNode.parentNode); center(this);"
; ↑
==
;button.b1.br1.p2.hover
=onclick "this.parentNode.parentNode.parentNode?.insertAdjacentElement('afterbegin', this.parentNode.parentNode); center(this);"
; ↥
==
;div.htmx-indicator.reorder-indicator.p2.f2
; ---
==
;div.basis-full;
;button.b1.br1.p2.hover.loader
=type "button"
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=task-diff"
=hx-swap "outerHTML"
=hx-target "find .loading"
=head "kid-done"
=pith (en-tape:pith:neo pith)
;span.loaded: toggle
;span.loading: ---
==
;button.b1.br1.p2.hover.loader
=type "button"
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=task-diff"
=hx-swap "none"
=hx-on--after-request "this.parentNode.parentNode.remove();"
=head "oust"
=pith (en-tape:pith:neo pith)
;span.loaded: delete
;span.loading: ---
==
;button.b1.br1.p2.hover
=type "button"
=onclick "this.nextElementSibling.classList.toggle('hidden'); this.classList.toggle('toggled');"
; become
==
;div.basis-full.hidden.fr.g1
=hx-post "/neo/hawk{(en-tape:pith:neo (welp here.bowl pith))}?stud=task-diff"
=hx-trigger "become"
=hx-target "find .loading"
=hx-swap "outerHTML"
=head "become"
;input.grow.p2.br1.border
=type "text"
=name "path"
=value (en-tape:pith:neo (welp here.bowl pith))
=oninput "this.setAttribute('value', this.value);"
;
==
;button.p2.b1.hover.br1.loader
=type "button"
=onclick "this.dispatchEvent(new CustomEvent('become', \{composed:true, bubbles: true}))"
;span.loaded: become
;span.loading: ---
==
==
;div.basis-full.p2.pre.mono.scroll-x
; {(trip text.t)}
==
==
;div.fc.g2.hidden
=hx-disinherit "hx-indicator"
=style "margin-left: 20px;"
;
==
==
:: ::
:: this "shell" div is a wrapper for the whole interface
:: <div class="shell fc js af p2 wf p1 g5 ma" here="{<(pith-tape here.bowl)>}">
;div.shell.fc.js.af.p2.wf.p1.g5.ma
=here (pith-tape here.bowl)
::
:: return a <style> element with
:: the styling in the +css arm
;style: {style}
::
:: embed JavaScript code from +script for
:: a more responsive frontend experience
;+ script
::
:: render from the +task-title arm, which
:: returns a header with the task's title
;+ task-title
:: <div class="fc g1 kids">
;div.fc.g1.kids
::
:: render a <form> element with an ordered list of
:: the child shrubs, which are all the top-level tasks
;+ form-ordered-kids
:: render the <form> that sends a
:: poke to create a new task
;+ form-create
== :: </div>
== :: </div>
::
++ style
^~
%- trip
'''
.shell {
max-width: 650px;
padding-bottom: 50vh;
padding-top: 30px;
}
input[type="text"]:hover {
cursor: text;
}
input:focus {
outline: none;
}
input:checked {
outline: none;
accent-color: black;
}
'''
::
++ script ++ script
:: <script>
;script ;script
;+ ;/ %- trip ;+ ;/ %- trip
''' '''
// applies scrollIntoView() methods to the provided
// to display it as specified
function center(el) { function center(el) {
el.scrollIntoView({ el.scrollIntoView({
block: "center", block: "center",
inline: "start", inline: "start",
behavior: "instant" behavior: "instant"
}) })
} };
function toggleChildren(el) {
let kidsDiv = el.parentNode.nextElementSibling.nextElementSibling; // tell the user why a clicked checkbox
if (!kidsDiv.children.length) { // can't be marked as checked
let here = el.parentNode.parentNode.getAttribute('here'); document.querySelectorAll(".alert").forEach(function(element) {
let stub = document.createElement("div"); element.addEventListener('click', function(e) {
stub.setAttribute("hx-get", `/neo/hawk${here}`); if (element.hasAttribute("readonly")){
stub.setAttribute("hx-trigger", 'load'); e.preventDefault();
stub.setAttribute("hx-target", 'this'); alert("Subtasks are not completed");
stub.setAttribute("hx-select", '.kids'); }
stub.textContent = "+ + +" })
stub.className = "fc as jc" })
stub.style = "padding:10px; padding-left: 20px;"
stub.setAttribute("hx-swap", "outerHTML");
kidsDiv.appendChild(stub);
htmx.process(kidsDiv);
}
kidsDiv.classList.toggle('hidden');
}
''' '''
== == :: </script>
::
++ task-title
^- manx
:: <div class="fc g2 br1">
;div.fc.g2.br1
:: <h2 class="bold.s2.tc">
;h2.bold.s2.tc
; {(trip (@t text.t))}
== :: </h2>
== :: </div>
::
++ kids-check
::
:: check if all subtasks are completed
|= =pith
~& > pith
^- ?
=/ t
!< task
q.q.saga:(~(got of:neo kids.bowl) pith)
~& >> t
kids-done.t
::
::
++ form-ordered-kids ++ form-ordered-kids
::
:: <form> that keeps track of tasks order, sends %reorder
:: poke if tasks are manually reordered by the user
;form.fc.g1 ;form.fc.g1
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=task-diff" =hx-post "/neo/hawk{(pith-tape here.bowl)}?stud=task-diff"
=head "reorder" =head "reorder"
=hx-indicator ".reorder-indicator" =hx-indicator ".reorder-indicator"
=hx-swap "none" =hx-swap "none"
;* ;*
%+ turn order.t ::
|= =pith :: iterates over the list of piths in order.task
=/ kid (~(get of:neo kids.bowl) pith) %+ turn
?~ kid order.t
;div: does not exist {(en-tape:pith:neo pith)} |= =pith
(part-kid [pith (need kid)]) :: extract kid information at pith from kids.bowl
::;* :: and runs +part-kid on pith and kid data
::=/ orphans =/ kid (~(get of:neo kids.bowl) pith)
:: %+ skim kids ?~ kid
:: |= [=pith *] ;div: does not exist {(pith-tape pith)}
:: =(~ (find [pith ~] order.t)) (part-kid [pith (need kid)])
::%+ turn
:: %+ sort orphans
:: |= [a=[=pith *] b=[=pith *]]
:: (lth ->.pith.a ->.pith.b)
::part-kid
== ==
++ shell ::
;div.fc.js.af.p2.wf.p1.g5.ma ++ part-kid
=here (en-tape:pith:neo here.bowl) ::
=style "max-width: 650px; padding-bottom: 50vh; padding-top: 30px;" :: sends %edit poke on input change
;+ script |= [=pith =idea:neo]
;+ form-edit :: extracts information from idea:neo to task
;div.fc.g1.kids =/ =pail:neo q.saga.idea
::;+ ?~ (lent order.t) ;/("") (form-create %prep "+") =/ t=task !<(task q.pail)
::;+ ?~ (lent order.t) (form-create %nest "+") ;/("") :: converts pith to tape
;+ form-ordered-kids =/ pt (pith-tape (welp here.bowl pith))
::;+ ?~ (lent order.t) ;/("") (form-create %nest "+") :: checks if task is done; if so, assigns
;+ (form-create %nest "+") :: attribute "done" to the manx created below
=- ?. done.t -
-(a.g [[%done ""] a.g.-])
^- manx
:: <div class="fc g1" here="{<pt>}" done="" ...>
:: toggle hidden attribute on buttons-menu div
;div.fr.g1.p1
=here pt
=onmouseover "this.childNodes[1].classList.remove('hidden');$(this).addClass('b1 br2');"
=onmouseout "this.childNodes[1].classList.add('hidden');$(this).removeClass('b1 br2');"
::
:: div with %edit poke functionality
:: div that sends %edit poke when input with class="text"
:: or input with class "done" are being changed
;div.fr.ac.g1.grow
=hx-post "/neo/hawk{pt}?stud=task-diff"
=hx-trigger "input changed delay:0.4s from:find .text, input from:find .done"
=hx-swap "none"
=head "edit"
;+
:: defines class attribute with class names
=/ class [%class "p2 br1 border done s3"]
=/ class-alert [%class "p2 br1 border done s3 alert"]
::
:: checkbox logic:
:: - if task is toggled, checkbox will
:: appear as checked
:: - if task has kids and all kids are done,
:: user will be free to toggle the task
:: - if task have kids and they are not done,
:: checkbox will have readonly attribute and
:: will show alert onclick
:: - even though we have logic for handling
:: toggling of a parent task, we prevent
:: a task from being marked as done if it
:: has untoggled kids
::
:: combining attribute logic with manx below
=; m
:: checks if the task toggled as done
?. done.t
:: if it's not done, does it have kids?
?~ order.t
::
:: a.g.m is a part of the manx that
:: contains input checkbox attributes;
:: we assign the class attribute to
:: the rest of its data
m(a.g [class a.g.m])
=/ kc
(kids-check pith)
~& >>> kc
?: kc
:: assigning class attribute to
:: the rest of manx data
m(a.g [class a.g.m])
::
:: assigns readonly and class
:: attributes to checkbox; 'alert' class will trigger
:: alert script functionality
m(a.g [[%readonly ""] class-alert a.g.m])
::
:: assigning checked and class attributes
:: to the rest of manx data
m(a.g [[%checked ""] class a.g.m])
^- manx
::
:: onclick logic depending if input
:: has been checked or unchecked:
:: - if checked and doesn't have attribute
:: readonly, adds attribute checked="" to
:: local input and assigns classes "strike f3"
:: to sibling input text
:: - if it's been undone removes attribute checked=""
:: and removes "strike f3" classes from sibling input
::
;input
=type "checkbox"
=name "done"
=onclick (trip 'if (this.checked && !this.hasAttribute("readonly")){ this.setAttribute("checked", "");$(this.nextElementSibling).addClass("strike f3")} else {this.removeAttribute("checked");$(this.nextElementSibling).removeClass("strike f3")}')
;
==
::
:: combining class logic with
:: manx below and make it in to an XML node
;+ =; that
=/ classes
%+ weld
"grow p2 br2 text bold"
?:(done.t " strike f3" "")
:: assigning classes attribute to the manx below
that(a.g [[%class classes] a.g.that])
^- manx
::
:: input has a task text value
:: on input change, it will change the value
:: attribute to update the div's POST request form
;input
=type "text"
=name "text"
=value (trip text.t)
=onclick "$(this).addClass('border br2');$(this).removeClass('bold')"
=onblur "$(this).addClass('bold');$(this).removeClass('border')"
=oninput "this.setAttribute('value', this.value);"
=onmouseover "$(this).addClass('b2 br2');"
=onmouseout "$(this).removeClass('b2');"
;
==
==
:: buttons menu arm is called with pith as input
;+ (buttons-menu pith)
:: a-tag, opens subtask view with spinner logic on loading
;a.p2.br1.hover.action.mono.fr.g2.loader
=hx-indicator "this"
=href "/neo/hawk{(pith-tape here.bowl)}{(pith-tape pith)}"
=hx-swap "innerHTML"
;span.b1.br1.p2.hfc.loaded: →
;span.b1.br1.p2.hfc.loading
;+ loading.feather-icons
==
==
==
::
++ buttons-menu
:: dropdown-menu arm provides reorder
:: and oust(delete) logic for kids
|= =pith
^- manx
::
;div.p2.br1.fr.g2.hidden
=hx-disinherit "hx-indicator"
=style "padding-right:0px;"
::
:: indicator that %reorder POST request is in progress
;div.reorder-indicator.p2.loader
;span.loading.p1
;+ loading.feather-icons
==
==
:: moves kid div one task down and centers view
:: and uses script logic to center user view on moved task
;button.b1.br1.p2.hover.hfc
=onclick "this.parentNode.parentNode.nextElementSibling?.insertAdjacentElement('afterend', this.parentNode.parentNode); center(this);"
; ↓
==
:: moves kid div one task up and centers view
;button.b1.br1.p2.hover.hfc
=onclick "this.parentNode.parentNode.previousElementSibling?.insertAdjacentElement('beforebegin', this.parentNode.parentNode); center(this);"
; ↑
==
:: delete button that sends POST request with %oust poke to parent task
:: and after request been sent removes subtask div from DOM
;button.b1.br1.p2.hover.loader.hfc
=type "button"
=hx-post "/neo/hawk{(pith-tape here.bowl)}?stud=task-diff"
=hx-target "find .loading"
=hx-swap "outerHTML"
=hx-on--after-request "this.parentNode.parentNode.remove();"
=head "oust"
=pith (pith-tape pith)
;span.loaded: delete
;span.loading
;+ loading.feather-icons
==
==
==
::
++ form-create
::
:: form-create arm send POST request with data for %new poke
:: depending on whether it's a parent task or a kid,
:: it specifies a placeholder accordingly
=/ placeholder ?:(?=([%ud @ud] (rear here.bowl)) "subtask" "task")
^- manx
;div.fc.g1.p4r
=style "padding-top:8px;"
:: form for %new poke POST request
;form.fr.g1
=hx-post "/neo/hawk{(pith-tape here.bowl)}?stud=task-diff"
=head "new"
=hx-swap "outerHTML"
=hx-target "find button .loading"
:: by default will append new task to the ordered kid list
;input.hidden
=name "prepend"
=value "no"
;
==
:: input for task text data
;input.wf.p2.border.br2.grow
=name "text"
=autocomplete "off"
=type "text"
=required ""
=placeholder placeholder
=oninput "this.setAttribute('value', this.value);"
;
==
:: button that triggers form to send request
;button.b1.br1.hover.p1.wfc.loader
;span.loaded: create
;span.loading
;+ loading.feather-icons
==
==
== ==
== ==
-- --

View File

@ -0,0 +1,243 @@
/@ todos
/- feather-icons
:- [%todos %$ %htmx]
|= todo=todos
|= =bowl:neo
|^
=/ hide-hid ?:(show-done.todo "" "hide-hidden")
;div
=class "p-page todo-top mw-page ma {hide-hid}"
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=todos"
=hx-swap "none"
=hx-target "this"
=hx-trigger "todo-save, todo-save-name delay:0.4s"
;div.fr.ac.jb.p2.sticky.z1.b0
=style "top: 0;"
;+ indicator
;+ (show-done-toggle show-done.todo)
==
;div.fc.mt1.todo-list(name "todos")
;* (turn todos.todo render-todo)
==
;+ form-new
;div.hidden.template
;+ (render-todo [%.n ''])
==
;+ style
==
++ form-new
%^ add-attr %onsubmit
"""
event.preventDefault();
let template = $(this).closest('.todo-top').find('.template');
let list = $(this).closest('.todo-top').find('.todo-list');
let dolly = template.clone().children().first();
let input = $(this).find('input');
let name = input.val();
input.val('');
dolly.find('.todo-name').text(name);
dolly.find('.edit').val(name);
dolly.find('.edit').attr('value', name);
dolly.appendTo(list);
$(this).emit('todo-save');
"""
;form.fr.g1.mt1.p2
;input.grow.br1.bd1.p2
=required ""
=placeholder "new task"
;
==
;button.p2.b1.br1.bd1.hover
;+ add.feather-icons
==
==
++ indicator
;div.loader.p2
;span.loaded;
;span.loading
;+ loading.feather-icons
==
==
++ show-done-toggle
|= =flag
;label.fr.g2.ac.je.f3.p2
;span.s-1: show done
;+
=; m
?. flag m
m(a.g [[%checked ""] a.g.m])
%^ add-attr %onclick
"""
if($(this).is(':checked')) \{ this.setAttribute('checked', '') } else \{ this.removeAttribute('checked') }
$(this).closest('.todo-top').toggleClass('hide-hidden');
$(this).emit('todo-save');
"""
;input
=type "checkbox"
=name "show-done"
;
==
==
::
++ render-todo
|= [done=? name=@t]
=/ dun ?:(done "done" "")
;div
=class "fc p2 g2 todo {dun}"
;div.fr.ac.jb.g1
;label.fr.g2.ac.js
;+ (checkbox done)
;div.p2.todo-name: {(trip name)}
==
;+ %^ add-attr %oninput
"""
$(this).closest('.todo').find('.todo-name').text(this.value);
$(this).attr('value', this.value);
$(this).emit('todo-save-name');
"""
;input.edit.p2.br1.bd1.grow.hidden
=name "todo-name"
=value (trip name)
;
==
;+ %^ add-attr %onclick
"""
$(this).closest('.todo').find('.tray').toggleClass('hidden');
$(this).closest('.todo').find('.edit').toggleClass('hidden');
$(this).closest('.todo').find('label').toggleClass('hidden');
$(this).toggleClass('toggled');
"""
;button.p2.b0.br1.hover
=type "button"
; ⋮
==
==
;div.fr.ac.je.g2.tray.hidden
;+ %^ add-attr %onclick
"""
let todo = $(this).closest('.todo');
let par = todo.parent();
todo.remove();
par.emit('todo-save');
"""
;button.p-1.b1.br1.bd1.hover
=onclick
; delete
==
;div.grow;
;+ %^ add-attr %onclick
"""
let todo = $(this).closest('.todo');
todo.parent().prepend(todo);
$(this).emit('todo-save');
"""
;button.p-1.b1.br1.bd1.hover
; ⇈
==
;+ %^ add-attr %onclick
"""
let todo = $(this).closest('.todo');
let top = $(this).closest('.todo-top');
if (top.hasClass('hide-hidden')) \{
todo.prevAll(':not(.done)').first().before(todo);
} else \{
todo.prevAll().first().before(todo);
}
$(this).emit('todo-save');
"""
;button.p-1.b1.br1.bd1.hover
; ↑
==
;+ %^ add-attr %onclick
"""
let todo = $(this).closest('.todo');
let top = $(this).closest('.todo-top');
if (top.hasClass('hide-hidden')) \{
todo.nextAll(':not(.done)').first().after(todo);
} else \{
todo.nextAll().first().after(todo);
}
$(this).emit('todo-save');
"""
;button.p-1.b1.br1.bd1.hover
; ↓
==
;+ %^ add-attr %onclick
"""
let todo = $(this).closest('.todo');
todo.parent().append(todo);
$(this).emit('todo-save');
"""
;button.p-1.b1.br1.bd1.hover
; ⇊
==
==
==
::
++ checkbox
|= =flag
=; m
?. flag m
m(a.g [[%checked ""] a.g.m])
%^ add-attr %onclick
"""
if($(this).is(':checked')) \{ this.setAttribute('checked', '') } else \{ this.removeAttribute('checked') };
$(this).closest('.todo').toggleClass('done');
$(this).emit('todo-save');
"""
;input.checkbox-round
=type "checkbox"
=name "done"
;
==
++ style
;style
;+ ;/ %- trip
'''
.checkbox-round {
width: 1.1em;
height: 1.1em;
background-color: var(--b0);
border-radius: 50%;
vertical-align: middle;
border: 1px solid var(--b1);
appearance: none;
-webkit-appearance: none;
outline: none;
cursor: pointer;
}
label {
cursor: pointer;
}
.todo {
border-bottom: 1px solid var(--b1);
}
.todo:last-child {
border: none;
}
.checkbox-round:checked {
background-color: var(--f2);
}
.hide-hidden .done {
display: none;
}
.done .todo-name {
color: var(--f4);
}
'''
==
:: collapses newlines to spaces
++ unline
|= =tape
%+ turn tape
|= =cord
?:(=(cord '\0a') ' ' cord)
++ add-attr
|= [=term =tape =manx]
^- ^manx
%= manx
a.g
:- [term (unline tape)]
a.g.manx
==
--

View File

@ -1,7 +1,8 @@
=/ prelude !>(.)
:- [%vase %$ %htmx] :- [%vase %$ %htmx]
|= vax=vase |= vax=vase
|= =bowl:neo |= =bowl:neo
;div.pre.mono.p2 ^- manx
;+ ;pre
;/ (of-wall:format (~(win re (sell vax)) 0 80)) ; {(of-wall:format (~(win re (sell vax)) 0 80))}
== ==

View File

@ -0,0 +1,423 @@
# Chapter 1: Counter
One of the simplest shrubs imaginable is a counter that stores one number and takes one poke: make the number go up.
By the end of this chapter you'll understand the structure of a shrub, and how to write a trivial one of your own. This won't explain Shrubbery from first principles — you don't neeed to understand it from first principles to work with it — but you'll see how similar a shrub is to a Gall agent, and where they differ.
You'll also get a glimpse of how one shrub can accomodate various frontend interfaces. We'll make a simple HTMX frontend for Sky, a namespace browser and dev environment.
This chapter is the only real "tutorial" in that Counter doesn't currently exist on your ship. You can build Counter yourself following along this guide. The remaining three chapters will discuss shrubs that already exists in your `%neo` desk: Diary, Messenger, and Tasks.
In the Diary tutorial, you'll see how to write and read data to and from the namepsace. In Messenger, you'll see how shrubs can interact via the dependencies system. In the Tasks chapter, we'll look at how a full-featured UI works in the current system.
This chapter is focused on pattern-matching what you know about Gall to the new system.
## Counter in Gall and Shrubbery
Here's the Gall agent you'll reimplement in Shrubbery. It stores one number and takes one poke, `%inc`, to increment the number.
```
/+ dbug, default-agent, verb
|%
+$ versioned-state
$% state-0
==
+$ state-0
$: %0
value=@ud
==
+$ counter-action
$% [%inc ~]
==
+$ card card:agent:gall
--
::
%+ verb &
%- agent:dbug
=| state-0
=* state -
^- agent:gall
|_ =bowl:gall
+* this .
def ~(. (default-agent this %|) bowl)
::
++ on-init on-init:def
++ on-peek on-peek:def
++ on-watch on-watch:def
++ on-arvo on-arvo:def
++ on-leave on-leave:def
++ on-agent on-agent:def
++ on-fail on-fail:def
++ on-save
!>(state)
::
++ on-load
|= old=vase
^- (quip card _this)
:- ~
%= this
state !<(state-0 old)
==
::
++ on-poke
|= [=mark =vase]
^- (quip card _this)
?+ mark
(on-poke:def mark vase)
::
%noun
=/ act
!<(counter-action vase)
?- -.act
%inc
:- ~
%= this
value +(value)
==
==
==
--
```
Here's the same thing in Shrubery.
```
/@ number
/@ counter-diff
^- kook:neo
|%
++ state
^- curb:neo
[%pro %number]
++ poke
^- (set stud:neo)
(sy %counter-diff ~)
++ deps
^- deps:neo
*deps:neo
++ form
^- form:neo
|_ [=bowl:neo =aeon:neo =stud:neo state-vase=vase]
+* state !<(number state-vase)
++ init
|= old=(unit pail:neo)
^- ((list card:neo) pail:neo)
[~ (need old)]
++ poke
|= [=stud:neo vaz=vase]
^- ((list card:neo) pail:neo)
=/ act
!<(counter-diff vaz)
?> =(-.act %inc)
[~ [%number !>(+(state))]]
--
--
```
## Shrub structure
Let's look at the structure of `/imp/counter`.
```
/@ number
/@ counter-diff
```
These lines import two types from our `/pro` folder: `number` and `counter-diff`. To import from `/pro` we use `/@` as a new Ford-style rune.
A shrub is a five-arm `|%` core — called a `kook:neo` — with an inner two-arm core called a `form:neo`. The `kook` defines type information about the shrub, and the inner `form` contains business logic.
At first glance the `kook` might look familiar to Gall developers, but this is all new logic defining 1) what's stored at this node in the namespace 2) what can be stored below this node, and 3) what we expect to be stored at existing nodes we declare as dependencies.
```
:: $kook:neo
|%
::
:: type this value in the namespace
++ state
!!
::
:: type acceptable requests to
:: change this value in the namespace
++ poke
!!
::
:: constrain the state/pokes of the shrubs that
:: can be created under this shrub in the namespace
++ kids
!!
::
:: declare the state/pokes we expect for existing shrubs
:: whose state we will track, and whose state changes we
:: will react to
++ deps
!!
::
:: handle state changes in this shrub,
:: its kids, and its dependencies
++ form
!!
--
```
The `form` is where the Gall agent-like application logic lives. We only need two arms, which are slightly modified versions of `+on-init` and `+on-poke`.
```
:: $form:neo
|_ [=bowl:neo =aeon:neo =stud:neo state-vase=vase]
::
:: like +on-init, run some logic when this shrub is created
:: unlike +on-init, potentially accept some injected initial state
++ init
|= old=(unit pail:neo)
^- ((list card:neo) pail:neo)
!!
::
:: like +on-poke, run some logic when this shrub is poked
++ poke
|= [=stud:neo vaz=vase]
^- ((list card:neo) pail:neo)
!!
--
```
## Counter logic
Now that we understand the shape of a shrub, let's look at the application logic of the Counter shrub. You can copy the following into the relevant files or type it out for yourself.
There are lots of new types here which are flagged with the `:neo` suffix in code and documentation. We'll cover those in detail in the following chapters.
### /pro/number.hoon
```
,@ud
```
### /pro/counter-diff.hoon
```
,[%inc ~]
```
### /imp/counter.hoon
```
/@ number :: import number type
/@ counter-diff :: import counter-diff type
::
:: outer core
^- kook:neo
|%
::
:: the state of counter is a number
++ state
^- curb:neo
[%pro %number]
::
:: the set of pokes counter takes only contains %counter-diff
:: a stud:neo is like a mark
++ poke
^- (set stud:neo)
(sy %counter-diff ~)
::
:: counter has no dependencies
++ deps
^- deps:neo
*deps:neo
::
:: inner core
++ form
^- form:neo
::
:: the sample is populated with context like bowl, version number, and
:: counter's current state
|_ [=bowl:neo =aeon:neo =stud:neo state-vase=vase]
::
:: de-vase counter's state
+* state !<(number state-vase)
::
:: +init, like +on-init
++ init
::
:: return no cards and the initial given state
:: pail:neo is a (pair stud:neo vase),
:: like a cell of a mark and data
|= old=(unit pail:neo)
^- ((list card:neo) pail:neo)
[~ (need old)]
::
:: +poke, like +on-poke
++ poke
|= [=stud:neo vaz=vase]
^- ((list card:neo) pail:neo)
::
:: de-vase the poke
=/ act
!<(counter-diff vaz)
::
:: crash if we're not incrementing
?> =(-.act %inc)
::
:: return no cards, return a (pair stud:neo vase)
:: where the vase contains the incremented state
[~ [%number !>(+(state))]]
--
--
```
Once you've saved `/imp/counter.hoon` and the `/pro` files, run `|commit %base` and %neo will add it to its state. We can now interact with this shrub in the Dojo.
## Poking the shrub
A `card:neo` is a `(pair pith note)`.
A `pith` is a `(list iota)`, and an `iota` is either a `term` or a head-tagged noun. For instance:
* `/examples/counter/one` would be represented as `~[%examples %counter %one]`.
* `/~sampel/examples/counter/one` would be represented as `~[[%p ~sampel] %examples %counter %one]`.
* `/~sampel/examples/counter/1` would be represented as `~[[%p ~sampel] %examples %counter [%ud 1]]`.
(You might also see a `pith` written in this irregular form `#/[p/our.bowl]/examples/counter/one`.)
Data in Shrubbery is stored by `pith`.
A `note` is one of the four types of command any shrub will accept.
```
+$ note
$% [%make made] :: create a shrub
[%poke =pail] :: poke a shrub
[%tomb cas=(unit case)] :: tombstone a case of the shrub
[%cull ~] :: forward delete
==
```
Lets `%make` a shrub at path `/foo/bar` from the Dojo, giving it an initial state of `0`. Well explain the structure of the `%make` note in more detail in the Diary tutorial.
```
:neo &neo-card [~[[%p our] %foo %bar] [%make %counter `[%number !>(0)] ~]]
```
You should see `>> %make /foo/bar` in the Dojo if successful.
Now we can now send a `%poke` to the counter shrub at this path.
```
:neo &neo-card [~[[%p our] %foo %bar] [%poke [%counter-diff !>([%inc ~])]]]
```
## Counter frontend in Sky
Shrubbery aims to be interface-agnostic. One part of that vision is `/con` files, which make it possible to convert data from one type to another. Here are Counters `/con` files.
### /con/number-htmx.hoon
This converts data stored as the `number` protocol (which is just a `@ud`) to the `htmx` protocol. When you open a shrub in Sky, Sky will attempt to convert its data to the `htmx` type (because Sky includes the [HTMX](https://htmx.org/) library in its frontend) using the appropriate `/con` file. In practice, this means that our `/con` file will take in our shrub's state (and bowl) and output some [Sail](https://docs.urbit.org/language/hoon/guides/sail) that interpolates the `number` in a basic interface consisting of a heading, the number itself, and one button to send an `%inc` poke to the Counter shrub.
```
/@ number :: @ud
:: import /lib/feather-icons (see feather-intro.txt)
/- feather-icons
:: declare that this is a conversion from number to HTMX
:- [%number %$ %htmx]
::
:: this gate accepts a number and
:: a gate that accepts a bowl:neo;
:: we'll use bowl:neo to get the
:: here.bowl of the shrub that's using this /con file
|= =number
|= =bowl:neo
::
:: this gate returns a manx, which is what Hoon uses
:: to store dynamic XML nodes; in this case we'll use
:: Sail to specify a manx that expects the HTMX library
:: to be available on the frontend
^- manx
::
:: open a <div class="p3 fc g2 ac br2">
:: these utility classes are specified in feather.css,
:: which this /con file expects on the frontend
;div.p3.fc.g2.ac.br2
:: <h1>Counter</h1>
;h1: Counter
:: <p>{number}</p>
;p: {<number>}
:: open a <form> with HTMX attributes
;form
::
:: hx-post will issue a POST request to the provided
:: url and swap the response into the DOM
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=counter-diff"
::
:: hx-target specifies the target for hx-post's DOM
:: swap: the element with class "loading"
=hx-target "find .loading"
::
:: hx-swap specifies how the response to hx-post's
:: request will be swapped in relative to the target
=hx-swap "outerHTML"
::
:: here, the head attribute specifies the poke that
:: hx-post will send to the target shrub; look at
:: /con/node-counter-diff.hoon for more on =head
=head "inc"
::
:: below, the classes "loaded", "loader", and
:: "loading" provide loading spinner behavior on
:: sending and receiving this form's POST request
::
:: <button class="bd1 br1 pr b1 hover loader">
;button.bd1.br1.p2.b1.hover.loader
:: <span class="loaded">Increment</span>
;span.loaded: Increment
:: <span class="loading">
;span.loading
:: import +loading sail from /lib/feather-icons
;+ loading.feather-icons
== :: </span>
== :: </button>
== :: </form>
== :: </div>
```
### /con/node-counter-diff.hoon
This is a more straightforward conversion from a dynamic XML node (in this case, HTMX), to a `%counter-diff`. Using a modified version of the [manx-utils](https://github.com/tinnus-napbus/manx-utils) Hoon library for brevity, we extract the XML nodes `head` attribute and use that to form the `%counter-diff`, which is `[%inc ~]`.
```
/@ node :: manx
/@ counter-diff :: [%inc ~]
:: import /lib/manx-utils, which helps us work with XML
/- manx-utils
:: declare this is a conversion from node to counter-diff
:- [%node %$ %counter-diff]
|= =node
^- counter-diff
:: initiate the manx-utils door with node
=/ mu ~(. manx-utils node)
::
:: got:mu gets an attribute from the manx by its name
:: in this case, the =head specified in /con/number-htmx
:: we expect the head from the manx to be %inc,
:: but we could add more terms to that type union...
=/ head (?(%inc) (got:mu %head))
::
:: return the [%inc ~] poke
[head ~]
```
## Testing the Counter in Sky
The Sky homepage shows you one tile for all of the shrubs who are the immediate children of your `/home` shurb, which was made for you upon booting `%neo` for the first time. You wont see a Counter tile there because there is no `/counter` shrub beneath `/home`, so lets make one.
```
:neo &neo-card [~[[%p our] %home %counter] [%make %counter `[%number !>(0)] ~]]
```
If you refresh your browser you should now see a tile labelled “counter”. Click there to see the Counter frontend from the `/con` file and increment the state of the `/counter` shrub.
## Building on the Counter
You should now be able to make some minor changes to the counter example above. Try the following:
- Initialize the shrub with a default state if the given `(unit vase)` in `+init` is empty.
- Add pokes for `%dec`, `%add`, and `%sub`.

View File

@ -0,0 +1,308 @@
# Chapter 2: Diary
Now that you understand the structure of a shrub, the natural next step is to look at a shrub with kids.
Unlike the Counter example, there is no equivalent way to implement `/imp/diary` in Gall. Were now going to work directly with Urbits programmable, global, referentially transparent namespace as a tool to read and write data.
## /imp/diary
Diary is an app that lets you write timestamped diary entries that the frontend will show in a chronological feed. Heres a succinct version of the apps backend logic, which clocks in at 34 lines of code.
```
:: /imp/diary.hoon
/@ txt :: @t
/@ diary :: name=@t
/@ diary-diff :: ?([%put-entry id=@da =txt] [%del-entry id=@da])
^- kook:neo
|%
++ state only/%diary
++ poke (sy %diary-diff ~)
++ kids `y/(~(gas by *lads:neo) ~[[[|/%da |] [only/%txt ~]]])
++ deps *deps:neo
++ form
^- form:neo
|_ [=bowl:neo =aeon:neo =pail:neo]
++ init
|= old=(unit pail:neo)
^- (quip card:neo pail:neo)
[~ ?~(old diary/!>(*diary) u.old)]
++ poke
|= [=stud:neo vax=vase]
^- (quip card:neo pail:neo)
?> =(%diary-diff stud)
=/ state !<(diary q.pail)
=/ act !<(diary-diff vax)
?> =(our ship.src):bowl
?- -.act
%put-entry
:_ diary/!>(state)
~[[(welp here.bowl ~[da/id.act]) [%make %txt `txt/!>(txt.act) ~]]]
%del-entry
:_ diary/!>(state)
~[[(welp here.bowl ~[da/id.act]) [%tomb ~]]]
==
--
--
```
Most of this should be legible after the first tutorial. The only new ideas are the `+kids` arm, the use of `bowl`, and `%tomb`.
## +kids
Every shrub is a node in one tree, with one “root shrub” at the top of that tree. Every shrub below the root shrub is either one of its immediate children or one of its descendants.
In its `+kids` arm, every shrub can define constraints for the shrubs below it in the namespace, whether thats constraining the types of their state or the pokes theyll accept from other shrubs.
Lets expand on diarys `+kids` arm.
```
:: /imp/diary.hoon
::
:: constrain shrubs below diary in the namespace
:: by defining the types of their state and pokes
++ kids
::
:: kids:neo is a (unit port:neo)
^- kids:neo
%- some
::
:: port:neo is (pair dare:neo lads:neo)
:: dare:neo is ?(%y %z)
:: if %y, only constrain our immediate children
:: if %z, recursively constrain all descendants
:- %y
:: lads:neo is (map pish:neo lash:neo)
%- ~(gas by *lads:neo)
:~ :- ::
:: pish:neo
:: to simplify: [%.n @da] means the kid's
:: path contains any @da, and %.n is there
:: to signify that the pith can not have more
:: fields afterwards
[[%.n %da] %.n]
::
:: lash:neo is (pair curb:neo (set stud:neo))
:: curb:neo defines the kids' state
:: (set stud:neo) defines the kids' pokes
[[%only %txt] ~]
==
```
In this case, Diary only constrains its immediate children. Each of its children lives at `/path/to/diary/<@da>`, where `<@da>` is used as an ID for the entry, and those children are just `%txt`s (cords) which store the text of the diary entry.
Theres no need for Diary to recursively constrain every single path that nests under `/path/to/diary`, since the app only needs to reserve the first “generation” of shrubs below it in order to work. In this case, the developer has forbidden any shrubs being created under the diary entries by ending the `pish` in a `%.n`. If that were `%.y`, any app could make a shrub at `/path/to/diary/<@da>/comments`. or `/path/to/diary/<@da>/backlinks`.
To define the shrubs kids, we create an empty map which is the bunt of `lads:neo`, then use `+gas:by` to populate the map with our own data, which will be a `(list (pair pish:neo lash:neo))`.
The `pish:neo` statically types the paths which well allow to be created beneath this shrub, and the `lash:neo` defines the kids state and pokes. In this case, the kids take no pokes and their state can only be `%txt`.
(Its worth flagging that `$curb:neo` contains several combinatorial rules about state types. For example `[%pro %txt]` would mean “the state of the child shrub can be any type which is readily convertible into a `%txt` with a conversion we have available in the `/con` folder”. This gives us a clue as to how we could handle state transitions and interoperability over the lifetime of our shrub, but its outside the remit of this tutorial.)
## bowl:neo
Notice that the `src` in `bowl:neo` differs from `bowl:gall`. Heres the new type in full.
```
:: /sur/neo.hoon
+$ bowl
$: src=[=ship =pith] :: a request's source ship and shrub
our=@p :: our ship
here=pith :: path to this shrub
now=@da :: current datetime
eny=@uvJ :: entropy
deps=(map term (pair pith lore)) :: dependencies
kids=lore :: our kids' state
==
```
## Generating cards, tombstoning shrubs
We covered `card:neo` in the Counter tutorial, but this is the first time were seeing one generated within a shrub. Diary takes two pokes: `%put-entry`, to create a new diary entry, and `%del-entry` to tombstone one.
Heres the `+poke` arm of the Diary shrub, expanded with comments.
```
:: /imp/diary.hoon
++ poke
|= [=stud:neo vax=vase]
^- (quip card:neo pail:neo)
?> =(%diary p.pail)
?> =(%diary-diff stud)
=/ state !<(diary q.pail)
=/ act !<(diary-diff vax)
::
:: assert the poke comes from our ship
:: src.bowl:neo is (pair ship pith)
?> =(our ship.src):bowl
?- -.act
%put-entry
:: return unchanged state
:_ [%diary !>(state)]
::
:: create list of one card:neo
:: card:neo is (pair pith:neo note:neo)
:~ :- %+ welp
::
:: here.bowl is the path of this shrub
:: /path/to/diary
here.bowl
::
:: append post id
:: /path/to/diary/~2024.6.3..14.07.15..7098
~[[%da id.act]]
::
:: this note will %make a new shrub
:: at the pith we defined above
^- note:neo
:: [%make stud:neo (unit pail:neo) conf:neo]
:* %make
::
:: new shrub has the implementation %txt
:: see /imp/txt.hoon, a stub that allows
:: you to create a %txt in the namespace
%txt
::
:: new shrub's initial state
:: is the text from the poke
`[%txt !>(txt.act)]
::
:: conf:neo is (map term pith:neo)
:: declare this new shrub's dependencies
:: which are also shrubs; diary has none
~
==
==
::
%del-entry
:: return unchanged state
:_ [%diary !>(state)]
::
:: send a %tomb note to /path/to/diary/<id>
:: this will tombstone the diary entry,
:: effectively deleting it from the namespace
:~ :- %+ welp
here.bowl
~[[%da id.act]]
^- note:neo
[%tomb ~]
==
==
```
The above is mostly self-explanatory, but its worth emphasizing a few points.
Diarys state never changes. Its state is just its name, a `@t`. It stores all its entries in the namespace. This makes every one of them amenable to being scried out by other apps, and it leaves room for other apps to make shrubs beneath `/path/to/diary/<@da>` at paths like `/<@da>/comments`, `/<@da>/reacts`, or `/<@da>/backlinks`.
The location of this shrub, `here.bowl`, is just a list. So its easy to `+welp` paths like `/<@da>` or `/<@da>/comments` onto the end. In this context, just keep in mind that they need to be `iota`s like `[%da now.bowl]`.
The `%make` card has two mysteries: it initializes diary entries with an empty `%txt` implementation and an empty map of dependencies. Well punt on dependencies until the next tutorial. If you look at `/imp/txt.hoon`, its just a `~`. This allows us to shove `%txt`s into the namespace; if the `/imp/<foo>` file is just a `~`, `/app/neo` will notice this and substitute in a shrub that takes the state of the type defined in `/pro/<foo>`. Like everything else in these tutorials this is subject to change!
## Diary frontend
Like Counter, the Diary shrub just has two `/con` files to convert to and from an HTMX frontend within the Sky browser.
```
:: /con/diary-htmx.hoon
/@ diary :: name=@t
/- feather-icons
:- [%diary %$ %htmx]
|= dia=diary
|= =bowl:neo
^- manx
|^
;div.p2
=label "Diary"
;div.ma.fc.g2
=style "max-width: 650px;"
;+ form-put-entry
;*
%+ turn
~
link-entry
==
==
++ form-put-entry
;form.fc.g2
=style "margin-bottom: 30px;"
=hx-post "{(en-tape:pith:neo :(weld /neo/hawk here.bowl))}?stud=diary-diff"
=hx-on-submit "this.reset()"
=hx-target "this"
=hx-swap "afterend"
=head "put-entry"
;date-now(name "id");
;textarea.p2.bd1.br1
=name "text"
=placeholder "today, i ..."
=oninput "this.setAttribute('value', this.value)"
=rows "5"
=required ""
=autocomplete "off"
;
==
;button.p2.b1.br1.bd1.wfc.hover.loader
;span.loaded.s2: create
;span.loading
;+ loading.feather-icons
==
==
==
++ link-entry
|= [pax=pith =pail:neo]
=/ tape (trip !<(@t q.pail))
=/ subject-end (fall (find [10]~ tape) 56)
=/ subject (scag subject-end tape)
=/ id (trip (snag 0 (pout pax)))
;div.fr.g2
;a.p2.br1.grow.b1.hover.loader
=href "{(en-tape:pith:neo (weld /neo/hawk here.bowl))}/{id}"
;div.loaded.fc.g1.js.as.g2
;span.f3: {(pretty-date `@da`->:pax)}
;span.bold: {subject}
==
;span.loading
;+ loading.feather-icons
==
==
;button.p2.br1.fr.g2.b1.hover.fc.ac.jc.loader
=onclick "alert('not yet implemented. no tombstoning?')"
;span.loaded
;+ close.feather-icons
==
;span.loading
;+ loading.feather-icons
==
==
==
++ pretty-date
|= date=@da
^- tape
=/ d (yore date)
"{(y-co:co y:d)}-{(y-co:co m:d)}-{(y-co:co d:t:d)}"
--
```
Theres only a bit more going on here than in Counters `/con/number-htmx.hoon` file. The main thing is that we have `+link-entry` and `+pretty-date` helper arms which are being used like functional frontend components.
The Diary frontend is a text box at the top with a list of entries generated from a list of the Diary shrubs child `pith`s. Nowhere is a list of children in the state being passed from the backend to the frontend, like you might see with a Gall agent passing converting a `(list item)` to a JSON array through a mark in the event that a frontend has scried or subscribed on a path, all of which would require painstaking specification by the developer.
```
:: /con/node-diary-diff.hoon
/@ node :: manx
/@ diary-diff :: ?([%put-entry id=@da txt=@t] [%del-entry id=@da])
/- manx-utils
:- [%node %$ %diary-diff]
|= nod=node
^- diary-diff
=/ mu ~(. manx-utils nod)
=/ head (@tas (got:mu %head))
=/ id (slav %da (vol:mu "id"))
=/ text (vol:mu "text")
[%put-entry id text]
```
Just like the `/con/node-counter-diff.hoon` in the Counter tutorial, all this does is extract attributes from an XML node, having been converted into a `manx`, and manually constructs the poke expected by the shrub.
## Building on Diary
- Amend the `+kids` arm so that other apps could create shrubs like `/path/to/diary/<@da>/comments`.
- Diary takes two pokes: `%put-entry` and `%del-entry`, but only one of these is supported on the frontend. Implement a `%del-entry` poke from the frontend.

View File

@ -0,0 +1,691 @@
# Intro to Feather
Feather is a _Design System_ which gives
Sail developers easy access to a small set of
predefined styles.
Feather is implemented as a library of CSS classes,
and is bundled with Sky and Hawk.
Benefits of opting into
Feather's constraints:
- Feather uses CSS variables that...
- the user can override
- respect OS light/dark theme
- UIs styled with Feather fit in
with the style of Sky and Hawk
- "birds of a feather flock together"
-----------------------------------------------
## The `prose` Class
the `.prose` class adds blog-like spacing,
sizing, and readability styling to semantic
children such as `p`
`li` `h1` `h2` `a` etc.
This document uses it.
```
;article.prose
# cool
- neat
- fine
==
```
-----------------------------------------------
## Flexbox
;*
%+ turn
:~
"fr jb"
"fr ja"
"fr jc"
"fr js"
"fr je"
"fc ac"
"fc as"
"fc ae"
"fc af"
==
|= =tape
;div.fc.g1.br1(style "margin-top: 20px;")
;code: {tape}
;div
=class "bd1 br1 p3 g1 {tape}"
;* %+ turn (gulf 1 3)
|= n=@
;b.b1.f3.p1.br1: X
==
==
;div.fc.g3(style "margin-top: 50px;")
;*
%+ turn
:~
"fr g0"
"fr g1"
"fr g2"
"fr g3"
"fr g4"
"fr g5"
"fr g6"
"fr g7"
"fr g8"
==
|= =tape
;div
=class "s-2 mono {tape}"
;div.bd1.p2: {tape}
;* %+ turn (gulf 1 3)
|= n=@
;div.bd1.p2;
==
==
;div.fr.g2(style "margin-top: 50px;")
;*
%+ turn
:~
"fc g0"
"fc g1"
"fc g2"
"fc g3"
"fc g4"
"fc g5"
"fc g6"
"fc g7"
"fc g8"
==
|= =tape
;div
=class "s-2 mono {tape}"
;div.bd1.p1(style "width: min-content;"): {tape}
;* %+ turn (gulf 1 3)
|= n=@
;div.bd1.p2;
==
==
;div.frw.g2(style "margin-top: 50px;")
;*
%+ turn (gulf 1 10)
|= n=@
;div.p2.bd1.mono: frw g2
==
;div.f2.mono
;div.fr.g4.p2.bd1.br1(style "margin-top: 50px;")
;div.p2.br1.b1;
;div.p2.br1.b1.tc.grow: grow
;div.p2.br1.b1;
==
;div.fr.g4.p2.bd1.br1(style "margin-top: 20px;")
;div.p2.br1.b1;
;div.p2.br1.b1;
;div.p2.br1.b1.tc.grow: grow
==
;div.fr.g4.p2.bd1.br1(style "margin-top: 20px;")
;div.p2.br1.b1.tc.grow: grow
;div.p2.br1.b1;
;div.p2.br1.b1.tc.grow: grow
==
==
-----------------------------------------------
## Typography
;div.frw.g1.br1.ac.jc
;*
%+ turn
:~
"s-2"
"s-1"
"s0"
"s2"
"s3"
"s4"
"s5"
"s6"
==
|= =tape
;span
=class "p2 {tape}"
; {tape}
==
==
;div.frw.g1.br1.ac.jc
;*
%+ turn
:~
"mono"
"bold"
"italic"
"underline"
"strike"
==
|= =tape
;span
=class "p2 {tape}"
; {tape}
==
==
-----------------------------------------------
## Text Alignment
;*
%+ turn
:~
"tl"
"tc"
"tr"
==
|= =tape
;div
=class "mono {tape}"
; {tape}
==
-----------------------------------------------
## Foreground & Background Colors
;div.frw.g1.br1.ac.jc.mono
;*
%+ turn
:~
"f-3"
"f-2"
"f-1"
"f0"
"f1"
"f2"
"f3"
"f4"
==
|= =tape
;span
=class "p2 bold {tape}"
; {tape}
==
==
;div.frw.g1.br1.ac.jc.mono
;*
%+ turn
:~
"b-3"
"b-2"
"b-1"
"b0"
"b1"
"b2"
"b3"
"b4"
==
|= =tape
;span
=class "p2 {tape}"
; {tape}
==
==
-----------------------------------------------
## Padding
;div.fc.ac.g2
;*
%+ turn
:~
"p-8"
"p-7"
"p-6"
"p-5"
"p-4"
"p-3"
"p-2"
"p-1"
"p0"
"p1"
"p2"
"p3"
"p4"
"p5"
"p6"
"p7"
"p8"
"p-page"
==
|= =tape
;div
=class "wfc mono f2 b1 {tape}"
; {tape}
==
==
-----------------------------------------------
## Margin
;div
;*
%+ turn
:~
"m0"
"ma"
"mt1"
"mt2"
"mt3"
==
|= =tape
;div
=class "mono f2 b2 br1 wfc p2 {tape}"
; {tape}
==
==
-----------------------------------------------
## Opacity
;div.frw.g2.ac.jc
;*
%+ turn
:~
"o0"
"o1"
"o2"
"o3"
"o4"
"o5"
"o6"
"o7"
"o8"
"o9"
"o10"
==
|= =tape
;div.fc.g1.ac.jc
;span.mono.s-1.f2: {tape}
;div
=class "wfc mono f0 b1 p4 bd1 {tape}"
;
==
==
==
-----------------------------------------------
## Borders
;div.frw.ac.g2(style "margin-top: 20px;")
;*
%+ turn
:~
"bd0"
"bd1"
"bd2"
"bd3"
==
|= =tape
;div
=class "wfc mono f2 p2 {tape}"
; {tape}
==
==
;div.frw.ac.g2(style "margin-top: 20px;")
;*
%+ turn
:~
"br0"
"br1"
"br2"
"br3"
==
|= =tape
;div
=class "wfc mono f2 p2 bd1 {tape}"
; {tape}
==
==
-----------------------------------------------
## Dimensions
- `wf` width: full
- `wfc` width: fit-content
- `mw-page` max-width: page (650px)
- `hf` height: full
- `hfc` height: fit-content
-----------------------------------------------
## Special
;*
%+ turn
:~
"toggled"
"hover"
==
|= =tape
;button(style "margin: 5px;")
=class "wfc mono f0 b0 p2 bd1 {tape}"
; {tape}
==
the `hidden` class hides the element.
-----------------------------------------------
## Request indicators
`loader` indicator parent
`loading` loading state
`loaded` loaded state
;details.mt1
;summary: Example
;button.mt1.b1.p1.hover.br1.bd1.f1.loader
=onclick "$(this).toggleClass('htmx-request')"
;span.loaded: toggle load state
;span.loading.f1: ...loading
==
```
;button.loader
=onclick "$(this).toggleClass('htmx-request')"
;span.loaded: toggle load state
;span.loading: ...loading
==
```
==
-----------------------------------------------
## Misc
`scroll-y`\
scroll-y: auto
`scroll-x`\
scroll-x: auto
`relative`\
position: relative
`sticky`\
position: sticky
`absolute`\
position: absolute
`fixed`\
postion: fixed
`block`\
display: block
`inline`\
display: inline-block
`pre`\
white-space: pre
`pre-line`\
white-space: pre-line
`break`\
word-break: break-word
`action`\
touch-action: manipulation
-----------------------------------------------
## Feather Sutra
> Order requires constraints.
### Primary Constraint
Interfaces must work on a mobile web browser.
### Consequent Constraints
- no element should need to be wider than 350px
- avoid horizontal scrolling
- left-click is the only mouse event
### Locality of Behavior
- co-locate actionable elements with the elements on which they act
- put styling inline
- put javascript inline
### Mechanical Simplicity
- don't fight the browser
- avoid animations
- store state as text attributes in the DOM, not javascript state
### UX low-hanging fruit
- network requests should always have indicators
- prefer autosave to manually saving
- be semantic with your tags
-----------------------------------------------
## Feather Tantra
> Life evolves through a vital chaos.
```
;div.any.class(style "any: css;");
;div
=class "any class"
=style
"""
any: "css";
that-you: "want;
"""
;
==
;style
;+ ;/ %- trip
'''
.any-css {
that-you: "want";
}
'''
==
;script
;+ ;/ %- trip
'''
// any javascript you want
'''
==
```
;style
;+ ;/ %- trip
'''
details {
display: flex !important;
flex-direction: column;
padding: 12px;
background: var(--b1);
box-sizing: border-box;
}
hr {
margin: 100px 0;
}
'''
==

View File

@ -622,11 +622,11 @@ button {
.numbered > *:before { .numbered > *:before {
content: counter(line); content: counter(line);
display: inline-block; display: inline-block;
border-right: 1px solid var(--f3); /* border-right: 1px solid var(--f3); */
padding: 0 .5em; /* padding: 0 .5em; */
margin-right: .5em; /* margin-right: .5em; */
color: var(--f3); color: var(--f3);
min-width: 34px; /* min-width: 34px; */
text-align: right; text-align: right;
} }
.numbered > * { .numbered > * {

Some files were not shown because too many files have changed in this diff Show More