Merge remote-tracking branch 'origin/next/arvo' into m/detest

This commit is contained in:
Philip Monk 2023-01-18 18:01:59 -07:00
commit 83b39e82a7
151 changed files with 6358 additions and 3032 deletions

View File

@ -1,32 +0,0 @@
#!/usr/bin/env bash
cd "$GITHUB_WORKSPACE" || exit
echo "$2" | base64 -d > service-account
echo "$3" | base64 -d > id_ssh
echo "$4" | base64 -d > id_ssh.pub
chmod 600 service-account
chmod 600 id_ssh
chmod 600 id_ssh.pub
janeway release glob-all --dev --no-pill \
--credentials service-account \
--ssh-key id_ssh \
--ci \
| bash
SHORTHASH=$(git rev-parse --short HEAD)
janeway release prepare-ota arvo-glob-"$SHORTHASH" "$1" \
--credentials service-account \
--ssh-key id_ssh \
--ci \
| bash
janeway release perform-ota "$1" \
--credentials service-account \
--ssh-key id_ssh \
--ci \
| bash

View File

@ -1,4 +1,4 @@
FROM tloncorp/janeway:v0.15.4 FROM tloncorp/janeway:v0.17.0
COPY entrypoint.sh /entrypoint.sh COPY entrypoint.sh /entrypoint.sh
EXPOSE 22/tcp EXPOSE 22/tcp
ENTRYPOINT ["/entrypoint.sh"] ENTRYPOINT ["/entrypoint.sh"]

View File

@ -1,18 +1,21 @@
name: 'glob' name: 'ota'
description: 'Create a glob and deploy it to a moon' description: 'perform an OTA update of arvo on a remote ship'
inputs: inputs:
ship: ship:
description: "Ship to deploy to" description: "target ship"
required: true required: true
credentials: credentials:
description: "base64-encoded GCP Service Account credentials" description: "base64-encoded GCP Service Account credentials"
required: true required: true
ssh-sec-key: ssh-sec-key:
description: "A base64-encoded SSH secret key for the container to use" description: "base64-encoded SSH secret key for the container to use"
required: true required: true
ssh-pub-key: ssh-pub-key:
description: "The corresponding base64-encoded SSH public key" description: "base64-encoded corresponding SSH public key"
required: true required: true
ref:
description: "git ref of arvo source to check out"
required: false
runs: runs:
using: 'docker' using: 'docker'
@ -22,4 +25,4 @@ runs:
- ${{ inputs.credentials }} - ${{ inputs.credentials }}
- ${{ inputs.ssh-sec-key }} - ${{ inputs.ssh-sec-key }}
- ${{ inputs.ssh-pub-key }} - ${{ inputs.ssh-pub-key }}
- ${{ inputs.ref }}

20
.github/actions/ota/entrypoint.sh vendored Executable file
View File

@ -0,0 +1,20 @@
#!/usr/bin/env bash
echo "$2" | base64 -d > /service-account
echo "$3" | base64 -d > /id_ssh
echo "$4" | base64 -d > /id_ssh.pub
chmod 600 /service-account
chmod 600 /id_ssh
chmod 600 /id_ssh.pub
janeway \
--ci \
--verbose \
--credentials /service-account \
--ssh-key /id_ssh \
release ota \
arvo \
"$1" \
${5:+"--ref"} ${5:+"$5"} \
| bash

View File

@ -1,27 +0,0 @@
name: Chromatic Deployment
on:
pull_request:
paths:
- 'pkg/interface/**'
push:
paths:
- 'pkg/interface/**'
branches:
- 'release/next-userspace'
jobs:
chromatic-deployment:
runs-on: ubuntu-latest
name: "Deploy Chromatic"
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- run: npm i && npm run bootstrap
- name: Publish to Chromatic
uses: chromaui/action@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
workingDir: pkg/interface

View File

@ -1,20 +0,0 @@
name: glob
on:
push:
branches:
- 'release/next-userspace'
jobs:
glob:
runs-on: ubuntu-latest
name: "Create and deploy a glob to ~hanruc-nalfus-nidsut-tomdun"
steps:
- uses: actions/checkout@v2
with:
lfs: true
- uses: ./.github/actions/glob
with:
ship: 'hanruc-nalfus-nidsut-tomdun'
credentials: ${{ secrets.JANEWAY_SERVICE_KEY }}
ssh-sec-key: ${{ secrets.JANEWAY_SSH_SEC_KEY }}
ssh-pub-key: ${{ secrets.JANEWAY_SSH_PUB_KEY }}

View File

@ -1,27 +0,0 @@
name: merge
on:
push:
branches:
- 'master'
jobs:
merge-to-next-js:
runs-on: ubuntu-latest
name: "Merge master to release/next-userspace"
steps:
- uses: actions/checkout@v2
- uses: devmasx/merge-branch@v1.3.1
with:
type: now
target_branch: release/next-userspace
github_token: ${{ secrets.JANEWAY_BOT_TOKEN }}
merge-to-group-timer:
runs-on: ubuntu-latest
name: "Merge master to ops/group-timer"
steps:
- uses: actions/checkout@v2
- uses: devmasx/merge-branch@v1.3.1
with:
type: now
target_branch: ops/group-timer
github_token: ${{ secrets.JANEWAY_BOT_TOKEN }}

View File

@ -1,17 +0,0 @@
name: ops-merge
on:
push:
branches:
- 'release/*'
jobs:
merge-release-to-ops:
runs-on: ubuntu-latest
name: "Merge to ops-tlon"
steps:
- uses: actions/checkout@v2
- uses: devmasx/merge-branch@v1.3.1
with:
type: now
target_branch: ops-tlon
github_token: ${{ secrets.JANEWAY_BOT_TOKEN }}

19
.github/workflows/ota.yml vendored Normal file
View File

@ -0,0 +1,19 @@
name: ota
on:
workflow_dispatch:
push:
branches:
- 'next/arvo'
jobs:
deploy:
runs-on: ubuntu-latest
name: "make an OTA update to arvo on ~binnec-dozzod-marzod"
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/ota
with:
ship: 'canary'
credentials: ${{ secrets.JANEWAY_SERVICE_KEY }}
ssh-sec-key: ${{ secrets.JANEWAY_SSH_SEC_KEY }}
ssh-pub-key: ${{ secrets.JANEWAY_SSH_PUB_KEY }}
ref: 'next/arvo'

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:c4247c64a7d9fc0c0f1d2f017c21dd3464ddfe56529c7d6eef0e64554bd453e8 oid sha256:bd487cdb8294fdef6878f623bceb893553b36b2a616d22d30017b430361586fb
size 7611162 size 3889185

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:5123a1ac30b83ec026587574df1ce13a73e72d06588ff68b5c41c09e1bebb5b7 oid sha256:26ff86808886beb831e4a135f478e42ce83ef4a09ad24808b3fe97248ce7a6b7
size 949962 size 1136643

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:40bc203b8a2d2ebad81723da6fc946ee32d2f8a204884f50f9710177ae257d08 oid sha256:dfceb32839ee1444325c070397724d42773b352ae006da148e5bb98d408c4be5
size 5712264 size 5924071

70
doc/spec/nock/10.txt Normal file
View File

@ -0,0 +1,70 @@
Author: Mencius Moldbug [moldbug@gmail.com]
Date: 9/15/2008
Version: 10K
1. Introduction
This file defines one function, "nock."
nock is in the public domain.
2. Data
A "noun" is either an "atom" or a "cell." An "atom" is an unsigned
integer of any size. A "cell" is an ordered pair of any two nouns,
the "head" and "tail."
3. Semantics
nock maps one noun to another. It doesn't always terminate.
4. Pseudocode
nock is defined in a pattern-matching pseudocode, below.
Brackets enclose cells. [a b c] is [a [b c]].
5. Definition
5.1 Transformations
*[a [b c] d] => [*[a b c] *[a d]]
*[a 0 b] => /[b a]
*[a 1 b] => [b]
*[a 2 b c d] => *[a 3 [0 1] 3 [1 c d] [1 0] 3 [1 2 3] [1 0] 5 5 b]
*[a 3 b] => **[a b]
*[a 4 b] => &*[a b]
*[a 5 b] => ^*[a b]
*[a 6 b] => =*[a b]
*[a] => *[a]
5.2 Operators
5.2.1 Goto [*]
*[a] -> nock[a]
5.2.2 Deep [&]
&[a b] -> 0
&[a] -> 1
5.2.4 Bump [^]
^[a b] -> ^[a b]
^[a] -> (a + 1)
5.2.5 Like [=]
=[a a] -> 0
=[a b] -> 1
=[a] -> =[a]
5.2.6 Snip [/]
/[1 a] -> a
/[2 a b] -> a
/[3 a b] -> b
/[(a + a) b] -> /[2 /[a b]]
/[(a + a + 1) b] -> /[3 /[a b]]
/[a] -> /[a]

74
doc/spec/nock/11.txt Normal file
View File

@ -0,0 +1,74 @@
Author: Mencius Moldbug (moldbug@gmail.com)
Date: 5/25/2008
Version: 11K
1. Introduction
This file defines one function, "nock."
nock is in the public domain.
2. Data
A "noun" is either an "atom" or a "cell." An "atom" is an unsigned
integer of any size. A "cell" is an ordered pair of any two nouns,
the "head" and "tail."
3. Semantics
nock maps one noun to another. It doesn't always terminate.
4. Pseudocode
nock is defined in a pattern-matching pseudocode, below.
Parentheses enclose cells. (a b c) is (a (b c)).
5. Definition
5.1 Transformations
*(a (b c) d) => (*(a b c) *(a d))
*(a 0 b) => /(b a)
*(a 1 b) => (b)
*(a 2 b c d) => *(a 3 (0 1) 3 (1 c d) (1 0) 3 (1 2 3) (1 0) 5 5 b)
*(a 3 b) => **(a b)
*(a 4 b) => &*(a b)
*(a 5 b) => ^*(a b)
*(a 6 b) => =*(a b)
*(a 7 b c) => *(a 3 (((1 0) b) c) 1 0 3)
*(a 8 b c) => *(a c)
*(a) => *(a)
5.2 Operators
5.2.1 Goto (*)
*(a) -> nock(a)
5.2.2 Deep (&)
&(a b) -> 0
&(a) -> 1
5.2.4 Bump (^)
^(a b) -> ^(a b)
^(a) -> a + 1
5.2.5 Same (=)
=(a a) -> 0
=(a b) -> 1
=(a) -> =(a)
5.2.6 Snip (/)
/(1 a) -> a
/(2 a b) -> a
/(3 a b) -> b
/((a + a) b) -> /(2 /(a b))
/((a + a + 1) b) -> /(3 /(a b))
/(a) -> /(a)

75
doc/spec/nock/12.txt Normal file
View File

@ -0,0 +1,75 @@
Author: Curtis Yarvin (curtis.yarvin@gmail.com)
Date: 3/28/2008
Version: 0.12
1. Introduction
This file defines one function, "nock."
nock is in the public domain.
2. Data
A "noun" is either an "atom" or a "cell." An "atom" is an unsigned
integer of any size. A "cell" is an ordered pair of any two nouns,
the "head" and "tail."
3. Semantics
nock maps one noun to another. It doesn't always terminate.
4. Pseudocode
nock is defined in a pattern-matching pseudocode, below.
Parentheses enclose cells. (a b c) is (a (b c)).
5. Definition
5.1 Transformations
*(a (b c) d) => (*(a b c) *(a d))
*(a 0 b) => /(b a)
*(a 1 b) => (b)
*(a 2 b c) => *(*(a b) c)
*(a 3 b) => **(a b)
*(a 4 b) => &*(a b)
*(a 5 b) => ^*(a b)
*(a 6 b) => =*(a b)
*(a 7 b c d) => *(a 3 (0 1) 3 (1 c d) (1 0) 3 (1 2 3) (1 0) 5 5 b)
*(a 8 b c) => *(a 2 (((1 0) b) c) 0 3)
*(a 9 b c) => *(a c)
*(a) => *(a)
5.2 Operators
5.2.1 Goto (*)
*(a) -> nock(a)
5.2.2 Deep (&)
&(a b) -> 0
&(a) -> 1
5.2.4 Bump (^)
^(a b) -> ^(a b)
^(a) -> a + 1
5.2.5 Same (=)
=(a a) -> 0
=(a b) -> 1
=(a) -> =(a)
5.2.6 Snip (/)
/(1 a) -> a
/(2 a b) -> a
/(3 a b) -> b
/((a + a) b) -> /(2 /(a b))
/((a + a + 1) b) -> /(3 /(a b))
/(a) -> /(a)

71
doc/spec/nock/13.txt Normal file
View File

@ -0,0 +1,71 @@
Author: Curtis Yarvin (curtis.yarvin@gmail.com)
Date: 3/8/2008
Version: 0.13
1. Manifest
This file defines one Turing-complete function, "nock."
nock is in the public domain. So far as I know, it is
neither patentable nor patented. Use it at your own risk.
2. Data
Both the domain and range of nock are "nouns."
A "noun" is either an "atom" or a "cell." An "atom" is an unsigned
integer of any size. A "cell" is an ordered pair of any two nouns,
the "head" and "tail."
3. Pseudocode
nock is defined in a pattern-matching pseudocode.
Match precedence is top-down. Operators are prefix. Parens
denote cells, and group right: (a b c) is (a (b c)).
4. Definition
4.1 Transformations
*(a 0 b c) => *(*(a b) c)
*(a 0 b) => /(b a)
*(a 1 b) => (b)
*(a 2 b) => **(a b)
*(a 3 b) => &*(a b)
*(a 4 b) => ^*(a b)
*(a 5 b) => =*(a b)
*(a 6 b c d) => *(a 2 (0 1) 2 (1 c d) (1 0) 2 (1 2 3) (1 0) 4 4 b)
*(a b c) => (*(a b) *(a c))
*(a) => *(a)
4.2 Operators
4.2.1 Goto (*)
*(a) -> nock(a)
4.2.2 Deep (&)
&(a b) -> 0
&(a) -> 1
4.2.3 Bump (^)
^(a b) -> ^(a b)
^(a) -> a + 1
4.2.4 Same (=)
=(a a) -> 0
=(a b) -> 1
=(a) -> =(a)
4.2.5 Snip (/)
/(1 a) -> a
/(2 a b) -> a
/(3 a b) -> b
/((a + a) b) -> /(2 /(a b))
/((a + a + 1) b) -> /(3 /(a b))
/(a) -> /(a)

42
doc/spec/nock/6.txt Normal file
View File

@ -0,0 +1,42 @@
1 Structures
A noun is an atom or a cell. An atom is any natural number.
A cell is an ordered pair of nouns.
2 Reductions
nock(a) *a
[a b c] [a [b c]]
?[a b] 0
?a 1
+a 1 + a
=[a a] 0
=[a b] 1
/[1 a] a
/[2 a b] a
/[3 a b] b
/[(a + a) b] /[2 /[a b]]
/[(a + a + 1) b] /[3 /[a b]]
*[a [b c] d] [*[a b c] *[a d]]
*[a 0 b] /[b a]
*[a 1 b] b
*[a 2 b c] *[*[a b] *[a c]]
*[a 3 b] ?*[a b]
*[a 4 b] +*[a b]
*[a 5 b] =*[a b]
*[a 6 b c d] *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
*[a 7 b c] *[a 2 b 1 c]
*[a 8 b c] *[a 7 [[0 1] b] c]
*[a 9 b c] *[a 7 c 0 b]
*[a 10 b c] *[a c]
*[a 10 [b c] d] *[a 8 c 7 [0 2] d]
+[a b] +[a b]
=a =a
/a /a
*a *a

42
doc/spec/nock/7.txt Normal file
View File

@ -0,0 +1,42 @@
1 Structures
A noun is an atom or a cell. An atom is any natural number.
A cell is any ordered pair of nouns.
2 Pseudocode
[a b c] [a [b c]]
nock(a) *a
?[a b] 0
?a 1
^a 1 + a
=[a a] 0
=[a b] 1
/[1 a] a
/[2 a b] a
/[3 a b] b
/[(a + a) b] /[2 /[a b]]
/[(a + a + 1) b] /[3 /[a b]]
*[a [b c] d] [*[a b c] *[a d]]
*[a 0 b] /[b a]
*[a 1 b] b
*[a 2 b c] *[*[a b] *[a c]]
*[a 3 b] ?*[a b]
*[a 4 b] ^*[a b]
*[a 5 b] =*[a b]
*[a 6 b c d] *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
*[a 7 b c] *[a 2 b 1 c]
*[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
*[a 9 b c] *[a 7 c 0 b]
*[a 10 b c] *[a c]
*[a 10 [b c] d] *[a 8 c 7 [0 3] d]
^[a b] ^[a b]
=a =a
/a /a
*a *a

45
doc/spec/nock/8.txt Normal file
View File

@ -0,0 +1,45 @@
1 Structures
A noun is an atom or a cell. An atom is any unsigned integer.
A cell is an ordered pair of nouns.
2 Pseudocode
[a b c] is [a [b c]]; *a is nock(a). Reductions match top-down.
3 Reductions
?[a b] 0
?a 1
^a (a + 1)
=[a a] 0
=[a b] 1
/[1 a] a
/[2 a b] a
/[3 a b] b
/[(a + a) b] /[2 /[a b]]
/[(a + a + 1) b] /[3 /[a b]]
*[a [b c] d] [*[a b c] *[a d]]
*[a 0 b] /[b a]
*[a 1 b] b
*[a 2 b c] *[*[a b] *[a c]]
*[a 3 b] ?*[a b]
*[a 4 b] ^*[a b]
*[a 5 b] =*[a b]
*[a 6 b c d] *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
*[a 7 b c] *[a 2 b 1 c]
*[a 8 b c] *[a 7 [7 b [0 1]] c]
*[a 9 b c] *[a 8 b 2 [[7 [0 3] d] [0 5]] 0 5]
*[a 10 b c] *[a 8 b 8 [7 [0 3] c] 0 2]
*[a 11 b c] *[a 8 b 7 [0 3] c]
*[a 12 b c] *[a [1 0] 1 c]
^[a b] ^[a b]
=a =a
/a /a
*a *a

43
doc/spec/nock/9.txt Normal file
View File

@ -0,0 +1,43 @@
1 Context
This spec defines one function, Nock.
2 Structures
A noun is an atom or a cell. An atom is any unsigned integer.
A cell is an ordered pair of any two nouns.
3 Pseudocode
Brackets enclose cells. [a b c] is [a [b c]].
*a is Nock(a). Reductions match top-down.
4 Reductions
?[a b] => 0
?a => 1
^[a b] => ^[a b]
^a => (a + 1)
=[a a] => 0
=[a b] => 1
=a => =a
/[1 a] => a
/[2 a b] => a
/[3 a b] => b
/[(a + a) b] => /[2 /[a b]]
/[(a + a + 1) b] => /[3 /[a b]]
/a => /a
*[a 0 b] => /[b a]
*[a 1 b] => b
*[a 2 b c d] => *[a 3 [0 1] 3 [1 c d] [1 0] 3 [1 2 3] [1 0] 5 5 b]
*[a 3 b] => **[a b]
*[a 4 b] => ?*[a b]
*[a 5 b] => ^*[a b]
*[a 6 b] => =*[a b]
*[a [b c] d] => [*[a b c] *[a d]]
*a => *a

View File

@ -716,7 +716,7 @@
'rtt'^(numb (div rtt ~s1)) 'rtt'^(numb (div rtt ~s1))
'rttvar'^(numb (div rttvar ~s1)) 'rttvar'^(numb (div rttvar ~s1))
'ssthresh'^(numb ssthresh) 'ssthresh'^(numb ssthresh)
'num-live'^(numb num-live) 'num-live'^(numb ~(wyt by live))
'cwnd'^(numb cwnd) 'cwnd'^(numb cwnd)
'counter'^(numb counter) 'counter'^(numb counter)
== ==

Binary file not shown.

View File

@ -3,16 +3,16 @@
:: :: :: :: :: ::
/? 309 :: arvo kelvin /? 309 :: arvo kelvin
/- *sole, lens :: console structures /- *sole, lens :: console structures
/+ sole, pprint, :: /+ sole, pprint, dprint, ::
auto=language-server-complete, :: auto=language-server-complete, ::
easy-print=language-server-easy-print :: easy-print=language-server-easy-print ::
:: :: :: :: :: ::
:::: :: :::: :::: :: ::::
:: :: :: :: :: ::
=> |% :: external structures => |% :: external structures
+$ id @tasession :: session id +$ id sole-id :: session id
+$ house :: all state +$ house :: all state
$: %8 $: %9
egg=@u :: command count egg=@u :: command count
hoc=(map id session) :: conversations hoc=(map id session) :: conversations
acl=(set ship) :: remote access whitelist acl=(set ship) :: remote access whitelist
@ -54,6 +54,7 @@
r=@t r=@t
== ==
[%poke p=goal] :: poke app [%poke p=goal] :: poke app
[%help p=(list term)] :: doccords
[%show p=?(%0 %1 %2 %3 %4 %5)] :: val/type/hoon/xray [%show p=?(%0 %1 %2 %3 %4 %5)] :: val/type/hoon/xray
[%verb p=term] :: store variable [%verb p=term] :: store variable
== :: == ::
@ -180,6 +181,18 @@
;~(pfix cen gap (parse-variable sym ;~(pfix gap parse-mark))) ;~(pfix cen gap (parse-variable sym ;~(pfix gap parse-mark)))
== ==
== ==
::
;~ pfix hax
;~ pose
;~ pfix ace
%+ cook
|= a=(list term)
[[%help (flop a)] 0 %ex [%cnts p=~[[%.y p=1]] q=~]]
(most fas sym)
==
(easy [[%help ~[%$]] 0 %ex [%cnts p=~[[%.y p=1]] q=~]])
==
==
:: ::
;~((glue ace) parse-sink parse-source) ;~((glue ace) parse-sink parse-source)
(stag [%show %0] parse-source) (stag [%show %0] parse-source)
@ -621,6 +634,9 @@
++ maar ?: =(%noun p.cay) ~ ++ maar ?: =(%noun p.cay) ~
[[%rose [~ " " ~] >p.cay< ~] ~] [[%rose [~ " " ~] >p.cay< ~] ~]
-- --
::
%help
(dy-inspect p.p.mad p.q.cay)
== ==
:: ::
++ dy-show |=(cay=cage (dy-print cay ~)) ++ dy-show |=(cay=cage (dy-print cay ~))
@ -660,6 +676,20 @@
:- i="" :- i=""
t=(turn `wain`?~(r.hit ~ (to-wain:format q.u.r.hit)) trip) t=(turn `wain`?~(r.hit ~ (to-wain:format q.u.r.hit)) trip)
== ==
::
++ dy-inspect
|= [topics=(list term) sut=type]
%+ dy-rash %mor
=+ to-display=(mule |.((find-item-in-type:dprint (flop topics) sut)))
?: ?=(%| -.to-display)
[%tan [%leaf "Could not find help A"] p.to-display]~
?~ p.to-display
[%tan [%leaf "Could not find help B"]~]~
=/ item (mule |.((print-item:dprint u.p.to-display)))
?: ?=(%| -.item)
[%tan [%leaf "Could not find help C"] p.item]~
p.item
::
++ dy-show-type-noun ++ dy-show-type-noun
|= a=type ^- tank |= a=type ^- tank
=- >[-]< =- >[-]<
@ -676,11 +706,16 @@
[%face ^] a(q $(a q.a)) [%face ^] a(q $(a q.a))
[%cell ^] a(p $(a p.a), q $(a q.a)) [%cell ^] a(p $(a p.a), q $(a q.a))
[%fork *] a(p (silt (turn ~(tap in p.a) |=(b=type ^$(a b))))) [%fork *] a(p (silt (turn ~(tap in p.a) |=(b=type ^$(a b)))))
[%hint *] ?. ?=(%know -.q.p.a) $(a q.a) [%hint *] ?+ q.p.a $(a q.a)
?@ p.q.p.a [(cat 3 '#' mark.p.q.p.a)]~ [%know *]
[(rap 3 '#' auth.p.q.p.a (spat type.p.q.p.a) ~)]~ ?@ p.q.p.a [(cat 3 '#' mark.p.q.p.a)]~
[(rap 3 '#' auth.p.q.p.a (spat type.p.q.p.a) ~)]~
::
[%help *]
[summary.crib.p.q.p.a]~
==
[%core ^] `wain`/core [%core ^] `wain`/core
[%hold *] a(p $(a p.a)) [%hold *] $(a (~(play ut p.a) q.a))
== ==
:: ::
:: XX needs filter :: XX needs filter
@ -820,12 +855,23 @@
=/ poz=vase (dy-sore p.cig) =/ poz=vase (dy-sore p.cig)
=/ kev=vase =/ kev=vase
=/ kuv=(unit vase) (slew 7 som) =/ kuv=(unit vase) (slew 7 som)
?: =(~ q.cig)
(fall kuv !>(~))
=/ soz=(list [var=term vax=vase]) =/ soz=(list [var=term vax=vase])
%~ tap by %~ tap by
%- ~(run by q.cig) %- ~(run by q.cig)
|=(val=(unit dojo-source) ?~(val !>([~ ~]) (dy-vase p.u.val))) |=(val=(unit dojo-source) ?~(val !>([~ ~]) (dy-vase p.u.val)))
:: if the generator takes a named argument "drum-session",
:: then if a value isn't already supplied, we set it to the session
:: that this dojo instance is being run in.
:: (dojo is, indeed, quite coupled with drum.)
::
=? soz
?& ?=(^ kuv)
(slab %both %drum-session p.u.kuv)
!(~(has by q.cig) %drum-session)
==
[[%drum-session !>(ses.id)] soz] ::TODO does the who matter?
?: =(~ soz)
(fall kuv !>(~))
~| keyword-arg-failure+~(key by q.cig) ~| keyword-arg-failure+~(key by q.cig)
%+ slap %+ slap
(with-faces kuv+(need kuv) rep+(with-faces soz) ~) (with-faces kuv+(need kuv) rep+(with-faces soz) ~)
@ -1018,13 +1064,14 @@
|= =card:agent:gall |= =card:agent:gall
^+ +> ^+ +>
=? card ?=(%pass -.card) =? card ?=(%pass -.card)
card(p [id p.card]) ^- card:agent:gall
card(p [(scot %p who.id) ses.id p.card])
%_(+> moz [card moz]) %_(+> moz [card moz])
:: ::
++ he-diff :: emit update ++ he-diff :: emit update
|= fec=sole-effect |= fec=sole-effect
^+ +> ^+ +>
(he-card %give %fact ~[/sole/[id]] %sole-effect !>(fec)) (he-card %give %fact ~[(id-to-path:sole id)] %sole-effect !>(fec))
:: ::
++ he-stop :: abort work ++ he-stop :: abort work
^+ . ^+ .
@ -1532,21 +1579,47 @@
:: ::
++ on-load ++ on-load
|= ole=vase |= ole=vase
^- (quip card:agent:gall _..on-init)
|^ =+ old=!<(house-any ole) |^ =+ old=!<(house-any ole)
=? old ?=(%5 -.old) =? old ?=(%5 -.old)
^- house-any
^- house-6
(house-5-to-6 old) (house-5-to-6 old)
=? old ?=(?(%6 %7) -.old) =? old ?=(?(%6 %7) -.old)
(house-6-7-to-8 +.old) (house-6-7-to-8 +.old)
?> ?=(%8 -.old) =^ caz old
`..on-init(state old) ?. ?=(%8 -.old) [~ old]
(house-8-to-9 old)
?> ?=(%9 -.old)
[caz ..on-init(state old)]
:: ::
+$ house-any $%(house house-7 house-6 house-5) +$ house-any $%(house house-8 house-7 house-6 house-5)
::
+$ id-8 @tasession
+$ house-8
$: %8
egg=@u
hoc=(map id-8 session)
acl=(set ship)
==
++ house-8-to-9
|= old=house-8
^- (quip card:agent:gall house)
:- %+ turn ~(tap in ~(key by hoc.old))
|= id=@ta
^- card:agent:gall
[%give %kick ~[/sole/[id]] ~]
=- [%9 egg.old - acl.old]
%- ~(gas by *(map sole-id session))
%+ murn ~(tap by hoc.old)
|= [id=@ta s=session]
(bind (upgrade-id:sole id) (late s))
:: ::
+$ house-7 [%7 house-6-7] +$ house-7 [%7 house-6-7]
+$ house-6 [%6 house-6-7] +$ house-6 [%6 house-6-7]
+$ house-6-7 +$ house-6-7
$: egg=@u :: command count $: egg=@u :: command count
hoc=(map id session-6) :: conversations hoc=(map id-8 session-6) :: conversations
acl=(set ship) :: remote access whitelist acl=(set ship) :: remote access whitelist
== :: == ::
+$ session-6 :: per conversation +$ session-6 :: per conversation
@ -1573,9 +1646,10 @@
old(poy ~, -.dir [our.hid %base ud+0]) old(poy ~, -.dir [our.hid %base ud+0])
:: ::
+$ house-5 +$ house-5
[%5 egg=@u hoc=(map id session)] [%5 egg=@u hoc=(map id-8 session-6)]
++ house-5-to-6 ++ house-5-to-6
|= old=house-5 |= old=house-5
^- house-6
[%6 egg.old hoc.old *(set ship)] [%6 egg.old hoc.old *(set ship)]
-- --
:: ::
@ -1591,7 +1665,8 @@
he-abet:(~(he-type he hid id.act ~ (~(got by hoc) id.act)) act) he-abet:(~(he-type he hid id.act ~ (~(got by hoc) id.act)) act)
:: ::
%lens-command %lens-command
=+ !<([=id =command:lens] vase) =+ !<([ses=@ta =command:lens] vase)
=/ =id [our.hid ses]
he-abet:(~(he-lens he hid id ~ (~(got by hoc) id)) command) he-abet:(~(he-lens he hid id ~ (~(got by hoc) id)) command)
:: ::
%allow-remote-login %allow-remote-login
@ -1629,8 +1704,7 @@
?> ?| (team:title our.hid src.hid) ?> ?| (team:title our.hid src.hid)
(~(has in acl) src.hid) (~(has in acl) src.hid)
== ==
?> ?=([%sole @ ~] path) =/ =id (need (path-to-id:sole path))
=/ id i.t.path
=? hoc (~(has by hoc) id) =? hoc (~(has by hoc) id)
~& [%dojo-peer-replaced id] ~& [%dojo-peer-replaced id]
(~(del by hoc) id) (~(del by hoc) id)
@ -1642,7 +1716,7 @@
++ on-leave ++ on-leave
|= =path |= =path
?> ?=([%sole *] path) ?> ?=([%sole *] path)
=. hoc (~(del by hoc) t.path) =. hoc (~(del by hoc) (need (path-to-id:sole path)))
[~ ..on-init] [~ ..on-init]
:: ::
++ on-peek ++ on-peek
@ -1651,13 +1725,15 @@
:: ::
++ on-agent ++ on-agent
|= [=wire =sign:agent:gall] |= [=wire =sign:agent:gall]
?> ?=([@ @ *] wire) ^- (quip card:agent:gall _..on-init)
=/ =session (~(got by hoc) i.wire) ?> ?=([@ @ @ *] wire)
=/ he-full ~(. he hid i.wire ~ session) =/ =id [(slav %p i.wire) i.t.wire]
=/ =session (~(got by hoc) id)
=/ he-full ~(. he hid id ~ session)
=^ moves state =^ moves state
=< he-abet =< he-abet
^+ he ^+ he
?+ i.t.wire ~|([%dojo-bad-on-agent wire -.sign] !!) ?+ i.t.t.wire ~|([%dojo-bad-on-agent wire -.sign] !!)
%poke (he-unto:he-full t.wire sign) %poke (he-unto:he-full t.wire sign)
%wool (he-wool:he-full t.wire sign) %wool (he-wool:he-full t.wire sign)
== ==
@ -1665,14 +1741,16 @@
:: ::
++ on-arvo ++ on-arvo
|= [=wire =sign-arvo] |= [=wire =sign-arvo]
?> ?=([@ *] wire) ^- (quip card:agent:gall _..on-init)
=/ =session (~(got by hoc) i.wire) ?> ?=([@ @ *] wire)
=/ he-full ~(. he hid i.wire ~ session) =/ =id [(slav %p i.wire) i.t.wire]
=/ =session (~(got by hoc) id)
=/ he-full ~(. he hid id ~ session)
=^ moves state =^ moves state
=< he-abet =< he-abet
?+ +<.sign-arvo ~|([%dojo-bad-take +<.sign-arvo] !!) ?+ +<.sign-arvo ~|([%dojo-bad-take +<.sign-arvo] !!)
%writ (he-writ:he-full t.wire +>.sign-arvo) %writ (he-writ:he-full t.t.wire +>.sign-arvo)
%http-response (he-http-response:he-full t.wire +>.sign-arvo) %http-response (he-http-response:he-full t.t.wire +>.sign-arvo)
== ==
[moves ..on-init] [moves ..on-init]
:: if dojo fails unexpectedly, kill whatever each session is working on :: if dojo fails unexpectedly, kill whatever each session is working on

View File

@ -1,8 +1,13 @@
:: herm: stand-in for term.c with http interface :: herm: stand-in for term.c with http interface
:: ::
/- herm
/+ default-agent, dbug, verb /+ default-agent, dbug, verb
:: 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-blit %json %blit
/$ json-to-task %json %herm-task
::
=, jael =, jael
|% |%
+$ state-0 [%0 ~] +$ state-0 [%0 ~]
@ -13,15 +18,18 @@
%+ verb | %+ verb |
%- agent:dbug %- agent:dbug
^- agent:gall ^- agent:gall
=> |%
++ pass-session
|= [ses=@tas tas=session-task:dill]
[%pass /dill/[ses] %arvo %d %shot ses tas]
--
|_ =bowl:gall |_ =bowl:gall
+* this . +* this .
def ~(. (default-agent this %|) bowl) def ~(. (default-agent this %|) bowl)
:: ::
++ on-init ++ on-init
^- (quip card:agent:gall _this) ^- (quip card:agent:gall _this)
:: set up dill session subscription [~ this]
::
[[%pass [%view %$ ~] %arvo %d %view ~]~ this]
:: ::
++ on-save !>([%0 ~]) ++ on-save !>([%0 ~])
++ on-load ++ on-load
@ -32,47 +40,68 @@
++ on-watch ++ on-watch
|= =path |= =path
^- (quip card:agent:gall _this) ^- (quip card:agent:gall _this)
?> =(our src):bowl
?> ?=([%session @ %view ~] path)
:_ this :_ this
:: scry prompt and cursor position out of dill for initial response ~| path
?> ?=([%session @ %view ~] path)
=* ses i.t.path
:: subscribe to the requested session
:: ::
=/ base=^path ::NOTE multiple views do not result in multiple subscriptions
/dx/(scot %p our.bowl)//(scot %da now.bowl)/sessions :: because they go over the same wire/duct
:~ [%give %fact ~ %blit !>(.^(blit:dill (weld base //line)))] ::
[%give %fact ~ %blit !>(`blit:dill`hop+.^(@ud (weld base //cursor)))] [(pass-session ses %view ~)]~
==
:: ::
++ on-arvo ++ on-arvo
|= [=wire =sign-arvo] |= [=wire =sign-arvo]
^- (quip card:agent:gall _this) ^- (quip card:agent:gall _this)
~| wire
?+ wire (on-arvo:def wire sign-arvo) ?+ wire (on-arvo:def wire sign-arvo)
[%tube *] [~ this] :: we no longer care about these [%tube *] [~ this] :: we no longer care about these
:: ::
:: pass on dill blits for the session :: pass on dill blits for the session
:: ::
[%view %$ ~] [%dill @ ~]
=* ses i.t.wire
?. ?=([%dill %blit *] sign-arvo) ?. ?=([%dill %blit *] sign-arvo)
~| [%unexpected-sign [- +<]:sign-arvo] ~| [%unexpected-sign [- +<]:sign-arvo]
!! !!
:_ this :_ this
%+ turn p.sign-arvo %+ turn p.sign-arvo
|= =blit:dill |= =blit:dill
[%give %fact [%session %$ %view ~]~ %blit !>(blit)] [%give %fact [%session ses %view ~]~ %blit !>(blit)]
::
:: clean up old-style subscriptions
::
[%view @ ~]
=* ses i.t.wire
:_ this
[%pass wire %arvo %d %shot ses %flee ~]~
== ==
:: ::
++ on-poke ++ on-poke
|= [=mark =vase] |= [=mark =vase]
^- (quip card:agent:gall _this) ^- (quip card:agent:gall _this)
?> =(our src):bowl
?. ?=(%belt mark)
~| [%unexpected-mark mark]
!!
:_ this :_ this
[%pass [%belt %$ ~] %arvo %d %belt !<(belt:dill vase)]~ :_ ~
?+ mark ~|([%unexpected-mark mark] !!)
%belt (pass-session %$ %belt !<(belt:dill vase))
%herm-task (pass-session !<(task:herm vase))
==
::
++ on-peek
|= =path
^- (unit (unit cage))
?+ path ~
[%x %sessions ~]
:+ ~ ~
:- %json
!> ^- json
=- a+(turn ~(tap in -) (lead %s))
.^((set @tas) %dy /(scot %p our.bowl)//(scot %da now.bowl)/sessions)
==
:: ::
++ on-leave on-leave:def ++ on-leave on-leave:def
++ on-peek on-peek:def ::
++ on-agent on-agent:def ++ on-agent on-agent:def
++ on-fail on-fail:def ++ on-fail on-fail:def
-- --

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
$~ [%24 *state:drum *state:helm *state:kiln] $~ [%25 *state:drum *state:helm *state:kiln]
$>(%24 any-state) $>(%25 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)]
@ -25,6 +25,7 @@
[%22 drum=state-4:drum helm=state-1:helm kiln=state-9:kiln] [%22 drum=state-4:drum helm=state-1:helm kiln=state-9:kiln]
[%23 drum=state-4:drum helm=state-2:helm kiln=state-9:kiln] [%23 drum=state-4:drum helm=state-2:helm kiln=state-9:kiln]
[%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]
== ==
+$ any-state-tuple +$ any-state-tuple
$: drum=any-state:drum $: drum=any-state:drum
@ -92,8 +93,7 @@
:: ::
?+ mark (on-poke:def mark vase) ?+ mark (on-poke:def mark vase)
%atom poke-helm(mark %helm-atom) %atom poke-helm(mark %helm-atom)
%dill-belt poke-drum(mark %drum-dill-belt) %dill-poke poke-drum
%dill-blit poke-drum(mark %drum-dill-blit)
%hood-sync poke-kiln(mark %kiln-sync) %hood-sync poke-kiln(mark %kiln-sync)
%write-sec-atom poke-helm(mark %helm-write-sec-atom) %write-sec-atom poke-helm(mark %helm-write-sec-atom)
== ==
@ -108,6 +108,7 @@
?+ path (on-watch:def +<) ?+ path (on-watch:def +<)
[%drum *] =^(c drum.state (peer:drum-core t.path) [c this]) [%drum *] =^(c drum.state (peer:drum-core t.path) [c this])
[%kiln *] =^(c kiln.state (peer:kiln-core t.path) [c this]) [%kiln *] =^(c kiln.state (peer:kiln-core t.path) [c this])
[%dill *] =^(c drum.state (peer:drum-core +<) [c this])
== ==
:: ::
++ on-agent ++ on-agent

View File

@ -83,7 +83,8 @@
:: ::
?+ -.source.com ?+ -.source.com
:_ this(job.state (some [eyre-id com])) :_ this(job.state (some [eyre-id com]))
[%pass /sole %agent [our.bowl %dojo] %watch /sole/[eyre-id]]~ =/ =path /sole/(scot %p our.bowl)/[eyre-id]
[%pass /sole %agent [our.bowl %dojo] %watch path]~
:: ::
%export %export
:_ this(job.state (some [eyre-id com])) :_ this(job.state (some [eyre-id com]))

View File

@ -43,13 +43,13 @@
++ on-fail on-fail:def ++ on-fail on-fail:def
:: ::
++ command-parser ++ command-parser
|= sole-id=@ta |= =sole-id:shoe
^+ |~(nail *(like [? command])) ^+ |~(nail *(like [? command]))
%+ stag & %+ stag &
(perk %demo %row %table ~) (perk %demo %row %table ~)
:: ::
++ tab-list ++ tab-list
|= sole-id=@ta |= =sole-id:shoe
^- (list [@t tank]) ^- (list [@t tank])
:~ ['demo' leaf+"run example command"] :~ ['demo' leaf+"run example command"]
['row' leaf+"print a row"] ['row' leaf+"print a row"]
@ -57,7 +57,7 @@
== ==
:: ::
++ on-command ++ on-command
|= [sole-id=@ta =command] |= [=sole-id:shoe =command]
^- (quip card _this) ^- (quip card _this)
=; [to=(list _sole-id) fec=shoe-effect:shoe] =; [to=(list _sole-id) fec=shoe-effect:shoe]
[[%shoe to fec]~ this] [[%shoe to fec]~ this]
@ -87,7 +87,7 @@
== ==
:: ::
++ can-connect ++ can-connect
|= sole-id=@ta |= =sole-id:shoe
^- ? ^- ?
?| =(~zod src.bowl) ?| =(~zod src.bowl)
(team:title [our src]:bowl) (team:title [our src]:bowl)

View File

@ -5,8 +5,8 @@
:- %aqua-events :- %aqua-events
%+ turn %+ turn
^- (list unix-event) ^- (list unix-event)
:~ [/d/term/1 %belt %ctl `@c`%e] :~ [/d/term/1 %belt %mod %ctl `@c`%e]
[/d/term/1 %belt %ctl `@c`%u] [/d/term/1 %belt %mod %ctl `@c`%u]
[/d/term/1 %belt %txt ((list @c) command)] [/d/term/1 %belt %txt ((list @c) command)]
[/d/term/1 %belt %ret ~] [/d/term/1 %belt %ret ~]
== ==

View File

@ -39,7 +39,7 @@
|= a=* ^- [cord path] |= a=* ^- [cord path]
[;;(@t a) (welp (slag len pax) /[nam])] [;;(@t a) (welp (slag len pax) /[nam])]
-- --
:: ::TODO: make this work with doccords
:- %say :- %say
|= [[now=time @ our=ship ^] typ=$@(~ [p=term ~]) ~] |= [[now=time @ our=ship ^] typ=$@(~ [p=term ~]) ~]
=/ pax=path /(scot %p our)/base/(scot %da now)/gen :: XX hardcoded =/ pax=path /(scot %p our)/base/(scot %da now)/gen :: XX hardcoded

View File

@ -0,0 +1,10 @@
:: Helm: Set Ames Blocklist
::
/? 310
::
::::
::
:- %say
|= [^ ships=(list ship) ~]
:- %helm-ames-snub
ships

View File

@ -8,7 +8,7 @@
:: ::
:- %say :- %say
|= $: [now=@da eny=@uvJ bec=beak] |= $: [now=@da eny=@uvJ bec=beak]
[[her=@p rem=desk ~] local=@tas] [[her=@p rem=desk ~] local=@tas once=_|]
== ==
=/ loc=desk ?:(=(%$ local) rem local) =/ loc=desk ?:(=(%$ local) rem local)
[%kiln-install loc her rem] [%kiln-install loc her rem once]

View File

@ -8,9 +8,11 @@
:: ::
:- %say :- %say
|= $: [now=@da eny=@uvJ byk=beak] |= $: [now=@da eny=@uvJ byk=beak]
[arg=$?([dap=term ~] [who=ship dap=term ~]) ~] arg=$?([dap=term ~] [who=ship dap=term ~])
drum-session=@ta
== ==
:- %drum-link :- %drum-link
:- drum-session
?~ +.arg ?~ +.arg
[p.byk dap.arg] [p.byk dap.arg]
[who.arg dap.arg] [who.arg dap.arg]

View File

@ -8,9 +8,11 @@
:: ::
:- %say :- %say
|= $: [now=@da eny=@uvJ byk=beak] |= $: [now=@da eny=@uvJ byk=beak]
[arg=$?([dap=term ~] [who=ship dap=term ~]) ~] arg=$?([dap=term ~] [who=ship dap=term ~])
drum-session=@ta
== ==
:- %drum-unlink :- %drum-unlink
:- drum-session
?~ +.arg ?~ +.arg
[p.byk dap.arg] [p.byk dap.arg]
[who.arg dap.arg] [who.arg dap.arg]

189
pkg/arvo/lib/deco.hoon Normal file
View File

@ -0,0 +1,189 @@
:: Hoon doccords sample
::
:: this is a sample file designed to explain syntax and conventions
:: for doccords
::
:: all lines must be under 80 characters. no blank lines.
:: any line longer than 60 characters is probably too long.
:: uppercase or non-ascii letters are strongly discouraged.
::
:: whenever possible, use formal decorations. {::} decorates
:: the next expression when put on its own line, and the previous
:: expression if written on the same line
::
:: there are two places to put decorations: in line with the
:: code, and on the right margin.
::
:: the file below is a well-commented library, built around
:: a typical two-core structure. the cores are labeled {%arch}
:: (structures) and {%work} (productions).
::
:: this code is written to display the variety of formatting
:: options the parser allows. a specific convention should pick
:: one of these styles and stick to it.
::
:: there are three ways to mark the beginning of a formal comment:
:: 1- {:: $foo:}
:: 2- {:: +bar:}
:: 3- {:: }
::
:: style 1 may optionally be followed by a series of paragraphs, where each
:: paragraph is preceded by a line containing only {::} and whitespace, and
:: each line of a given paragraph is preceded by four aces.
:: {::}
:: {:: more text}
:: {:: even more text}
:: {::}
:: {:: |=(code=hoon !!)}
::
:: style 2 is much like style 1, but paragraphs are indented by two spaces
:: instead of four.
:: {::}
:: {:: more text}
:: {:: even more text}
:: {::}
:: {:: |=(code=hoon !!)}
::
:: code is indented a total of six aces, for either style.
::
:: style 3 is used to annotate the hoon or spec that immediately follows
:: the comment. paragraphs are written with style 2.
::
:: the $foo and +bar above are examples of *lexical locations* for
:: style and batch-commenting purposes. this tells the parser to attempt
:: to attach the comment to the specified location. these locations
:: may be written as follows:
:: - `|foo` means a chapter
:: - `%foo` means a constant
:: - `.foo` means a face
:: - `+foo` means an arm
:: - `$foo` means a spec
:: - `^foo` means a core
:: - `_foo` means a door
:: - `=foo` means a gate
:: - `/foo` means a file path segment
::
:: thus /lib/foo^widget|initial=open means the =open gate in the |initial
:: chapter of the ^widget core in the /foo library
::
:: at present, doccords does not support lexical locations in full.
:: only single-element locations of the form `$foo` and `+foo` are supported,
:: and must be written above an arm in the core to which they are to be
:: attached, and after the chapter they are in (if the core has chapters).
:: you may still write doccords for other locations in anticipation of the
:: fully supported lexical location, but they will be thrown away before they
:: make it to the compiler.
::
:: a postfix formal comment will either attach to hoon or spec on the
:: current line, or the arm name if there is no hoon or spec on the
:: line. the convention for +$ arms is that the comment attached to the
:: arm is about the mold itself, while the comment attached to the spec
:: is about the output type of the mold.
::
:: to inspect doccords in this file from dojo, try the following:
::
:: > =deco -build-file %/lib/deco/hoon
:: > # deco
:: > # deco/arch
:: > # deco/arch/molds
:: > # deco/arch/molds/goof
::
:: > ?? *goof:deco
::
=> ::
:: structures for our imaginary hello, world generator.
::
:: nothing forces us to put structures in a separate core.
:: but compile-time evaluation doesnt work in the current
:: core; we often want to statically evaluate structures.
::
:: there are three kinds of structures: moldss (normalizing
:: functions), mold builders (functions that build molds), and
:: constants (static data).
::
:: most code will not need its own mold builders. but put them
:: in a separate chapter (separated by {+|}).
|%
:: molds are functions that normalize nouns.
::
:: arms producing molds are introduced with {+$}. the
:: compiler will copy the arm decoration onto its product
+| %molds
:: $jam: some delicious jam
:: $jelly: different from jam?
+$ spot [p=@ q=@] :: a coordinate
+$ tops :: mold for coordinate
[p=@ q=@] :: another coordinate
+$ goof :: a simple tuple mold
$: foo=@ :: something mysterious
bar=@ :: go here for drink
moo=(binary-tree juice) :: cows do this
==
+$ juice :: fruity beverage mold
$% [%plum p=@] :: fresh prune
[%pear p=@ q=@] :: good for cider
[%acai p=@] :: aztec superfood
==
+$ jam @tas
+$ jelly @tas
:: mold builders are functions that build molds from other molds
::
:: other languages might call these "type constructors"
:: or "higher-kinded types".
+| %mold-builders
++ binary-tree :: tree mold builder
|* a=$-(* *)
$@(~ [n=a l=(binary-tree a) r=(binary-tree a)])
::
:: if you have constants, put them in their own chapter.
+| %constant
++ answer :: answer to everything
42
--
:: engines for our imaginary hello, world app.
::
|%
:: +default-jam: bunts $jam
:: +default-juice: bunts $juice
++ say-hello :: say hi to someone
:: friendly welcome message
::
|=
:: .txt: friend to say hi to
::
txt=term
^- tape
"hello, {(rip 3 txt)}"
:: +say-goodbye: say a really proper goodbye
::
:: some paragraphs about the goodbye algorithm, possibly
:: including code indented by four extra spaces:
::
:: ?: =(%hello %world)
:: %hello
:: %world
::
++ say-goodbye
:: describe product of function
::
|=
:: .txt: departing friend
:: .num: number of friends
$: txt=term
num=@
==
^- tape
:: .foo: four
:: .bar: forty-two
=/ foo (add 2 2)
=/ bar (add (mul num foo) 2)
=/ moo (mul num bar) :: for all the cows
"goodbye and {(scow %ud moo)}, {(rip 3 txt)}"
::
++ say-minimum :: minimal decoration
|= txt=term
"nothing to say to {(rip 3 txt)}"
::
++ default-jam *jam
++ default-juice *juice
--

1
pkg/arvo/lib/dill.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/lib/dill.hoon

773
pkg/arvo/lib/dprint.hoon Normal file
View File

@ -0,0 +1,773 @@
/- *sole
/+ easy-print=language-server-easy-print
:: a library for printing doccords
=/ debug |
=>
:: dprint-types
|%
:: $overview: an overview of all named things in the type.
::
:: each element in the overview list is either a documentation for a sublist
:: or an association betwen a term and documentation for it
+$ overview (list overview-item)
::
:: $overview-item: an element of an overview
+$ overview-item
$% [%header doc=what children=overview]
[%item name=tape doc=what]
==
::
:: $item: the part of a type being inspected
+$ item
$%
:: overview of a type
::
[%view items=overview]
:: inspecting a full core
$: %core
name=tape :: arm that built it
docs=what ::
sut=type :: [%core *]
children=(unit item) :: compiled against
==
:: inspecting a single arm on a core
$: %arm
name=tape :: arm name
adoc=what :: arm doc
pdoc=what :: product doc
cdoc=what :: $ arm/prod doc
gen=hoon :: arm hoon AST
sut=type :: subject of arm
==
:: inspecting a face and what's behind it
$: %face
name=tape :: name of face
docs=what ::
children=(unit item) :: face referent
==
:: inspecting a single chapter on a core
$: %chapter
name=tape :: name of chapter
docs=what ::
sut=type :: [%core *]
tom=tome :: tome of chapter
==
==
::
--
:: dprint
::
:: core containing doccords search and printing utilities
|%
:: contains arms used for looking for docs inside of a type
::
:: the entrypoint for finding docs within a type is +find-item-in-type.
+| %searching
:: +find-item-in-type: returns the item to print while searching through topic
::
:: this gate is a thin wrapper around _hunt for usability, since the only entry
:: point most users should care about is find-item:hunt
::
++ find-item-in-type
|= [topics=(list term) sut=type]
?~ topics !!
=/ top=(lest term) topics
~(find-item hunt [top sut])
::
:: +hunt: door used for refining the type while searching for doccords
::
++ hunt
|_ [topics=(lest term) sut=type]
+* this .
::
+| %find
::
++ find-item
~? >> debug %find-item
^- (unit item)
?- sut
%noun ~
%void ~
[%atom *] ~
[%cell *] find-cell
[%core *] find-core
[%face *] find-face
[%fork *] find-fork
[%hint *] find-hint
[%hold *] find-item:this(sut (~(play ut p.sut) q.sut))
==
::
++ find-cell
~? >> debug %find-cell
^- (unit item)
?> ?=([%cell *] sut)
=/ lhs find-item:this(sut p.sut)
?~ lhs
find-item:this(sut q.sut)
lhs
::
++ find-core
~? >> debug %find-core
^- (unit item)
?> ?=([%core *] sut)
?: check-arm
?: check-search
?: check-arm-core
return-arm-core
return-arm
recurse-arm-core
?: check-chap
?: check-search
return-chap
recurse-chap
recurse-core
::
++ find-face
~? >> debug %find-face
^- (unit item)
?> ?=([%face *] sut)
?. ?=(term p.sut)
::TODO: handle $tune case
find-item:this(sut q.sut)
?. =(i.topics p.sut)
~
?~ t.topics
return-face
find-item:this(sut q.sut, topics t.topics)
::
++ find-fork
~? >> debug %find-fork
^- (unit item)
?> ?=([%fork *] sut)
=/ types=(list type) ~(tap in p.sut)
|-
?~ types ~
=+ res=find-item:this(sut i.types)
?~ res
$(types t.types)
res
::
++ find-hint
~? >> debug %find-hint
^- (unit item)
|^
?> ?=([%hint *] sut)
?. ?=([%help *] q.p.sut)
find-item:this(sut q.sut)
?+ q.sut ~
[%cell *] find-cell:this(sut q.sut)
[%core *] find-hint-core
[%face *] find-hint-face
[%fork *] find-fork:this(sut q.sut)
[%hint *] find-hint:this(sut q.sut)
[%hold *] find-hint:this(q.sut (~(play ut p.q.sut) q.q.sut))
==
::
++ find-hint-core
~? >> debug %find-hint-core
^- (unit item)
?> &(?=([%hint *] sut) ?=([%help *] q.p.sut) ?=([%core *] q.sut))
::
?. ?& ((sane %tas) summary.crib.p.q.p.sut)
=(summary.crib.p.q.p.sut i.topics)
==
find-core:this(sut q.sut)
?~ t.topics
return-hint-core
find-item:this(sut q.sut, topics t.topics)
::
++ find-hint-face
~? >> debug %find-hint-face
^- (unit item)
?> &(?=([%hint *] sut) ?=([%help *] q.p.sut) ?=([%face *] q.sut))
?: check-face:this(sut q.sut)
?~ t.topics
return-hint-face
find-item:this(sut q.q.sut, topics t.topics)
find-item:this(sut q.q.sut)
--
::
::+| %recurse
++ recurse-core
~? >> debug %recurse-core
^- (unit item)
?> ?=([%core *] sut)
find-item:this(sut p.sut)
++ recurse-chap
~? >> debug %recurse-chap
^- (unit item)
?> ?=([%core *] sut)
?~ t.topics !!
find-item:this(topics t.topics)
++ recurse-arm-core
~? >> debug %recurse-arm-core
^- (unit item)
?> ?=([%core *] sut)
?~ t.topics !!
find-item:this(sut arm-type, topics t.topics)
::
+| %check
::
++ check-arm
~? >> debug %recurse-core
^- ?
!=(~ (find ~[i.topics] (sloe sut)))
++ check-chap
~? >> debug %check-chap
^- ?
?> ?=([%core *] sut)
(~(has by q.r.q.sut) i.topics)
++ check-face
~? >> debug %check-face
^- ?
?> ?=([%face *] sut)
?. ?=(term p.sut)
::TODO: handle $tune case
%.n
=(p.sut i.topics)
++ check-search
~? >> debug %check-search
^- ?
=(~ t.topics)
++ check-arm-core
~? >> debug %check-arm-core
^- ?
=+ arm-list=(sloe (~(play ut sut) arm-hoon))
&(!=(arm-list ~) !=(arm-list ~[%$]) ?=([%core *] arm-type))
::
+| %return
::
++ return-cell
~? >>> debug %return-cell
^- (unit item)
?> ?=([%cell *] sut)
(join-items return-item:this(sut p.sut) return-item:this(sut q.sut))
::
++ return-core
~? >>> debug %return-core
^- (unit item)
?> ?=([%core *] sut)
=* compiled-against return-item:this(sut p.sut)
`[%core (trip i.topics) *what sut compiled-against]
::
++ return-face
~? >>> debug %return-face
^- (unit item)
?> ?=([%face *] sut)
:: TODO: handle tune case
?> ?=(term p.sut)
=* compiled-against return-item:this(sut q.sut)
`[%face (trip p.sut) *what compiled-against]
::
++ return-fork
~? >>> debug %return-fork
^- (unit item)
?> ?=([%fork *] sut)
=* types ~(tap in p.sut)
=* items (turn types |=(a=type return-item:this(sut a)))
(roll items join-items)
::
++ return-hint
~? >>> debug %return-hint
^- (unit item)
?> ?=([%hint *] sut)
=* res return-item:this(sut q.sut)
?. ?=([%help *] q.p.sut)
~
?: ?=([%core *] q.sut)
return-hint-core
?: ?=([%face *] q.sut)
return-hint-face
`[%view [%header `crib.p.q.p.sut (item-as-overview res)]~]
::
++ return-arm
~? >>> debug %return-arm
^- (unit item)
?> ?=([%core *] sut)
=+ [adoc pdoc cdoc]=(arm-docs i.topics sut)
::TODO: should this p.sut be sut? or the compiled type of the arm?
`[%arm (trip i.topics) adoc pdoc cdoc arm-hoon sut]
::
++ return-chap
~? >>> debug %return-chap
^- (unit item)
?> ?=([%core *] sut)
=/ tom=tome (~(got by q.r.q.sut) i.topics)
`[%chapter (trip i.topics) p.tom sut (~(got by q.r.q.sut) i.topics)]
::
++ return-arm-core
~? >>> debug %return-arm-core
^- (unit item)
?> ?=([%core *] sut)
=+ [adoc pdoc cdoc]=(arm-docs i.topics sut)
=/ dox=what ?~(adoc ?~(pdoc ~ pdoc) adoc)
=/ at arm-type
?> ?=([%core *] at)
=* compiled-against return-item:this(sut p.sut)
`[%core (trip i.topics) dox at compiled-against]
::
++ return-item
~? >>> debug %return-item
^- (unit item)
?- sut
%noun ~
%void ~
[%atom *] ~
[%cell *] return-cell
[%core *] return-core
[%face *] return-face
[%fork *] return-fork
[%hint *] return-hint
[%hold *] return-item:this(sut (~(play ut p.sut) q.sut))
==
::
++ return-hint-core
~? >>> debug %return-hint-core
^- (unit item)
?> &(?=([%hint *] sut) ?=([%core *] q.sut))
(apply-hint return-core:this(sut q.sut))
::
++ return-hint-face
~? >>> debug %return-hint-face
^- (unit item)
?> &(?=([%hint *] sut) ?=([%face *] q.sut))
(apply-hint return-face:this(sut q.sut))
::
++ apply-hint
~? >> debug %apply-hint
|= uit=(unit item)
^- (unit item)
?~ uit ~
?> &(?=([%hint *] sut) ?=([%help *] q.p.sut))
?+ u.uit ~
?([%core *] [%face *]) (some u.uit(docs `crib.p.q.p.sut))
==
::
+| %misc
++ arm-hoon
^- hoon
?> ?=([%core *] sut)
(^arm-hoon i.topics sut)
::
++ arm-type
^- type
?> ?=([%core *] sut)
(^arm-type i.topics sut)
--
::
:: +arm-hoon: looks for an arm in a core type and returns its hoon
++ arm-hoon
|= [nom=term sut=type]
^- hoon
?> ?=([%core *] sut)
=/ tomes=(list [p=term q=tome]) ~(tap by q.r.q.sut)
|-
?~ tomes !!
=+ gen=(~(get by q.q.i.tomes) nom)
?~ gen
$(tomes t.tomes)
u.gen
::
:: +arm-type: looks for an arm in a core type and returns its type
++ arm-type
|= [nom=term sut=type]
^- type
?> ?=([%core *] sut)
(~(play ut sut) (arm-hoon nom sut))
::
:: +hint-doc: returns docs if type is %help $hint w/ matching cuff
++ hint-doc
|= [=cuff sut=type]
^- what
?. &(?=([%hint *] sut) ?=([%help *] q.p.sut) =(cuff cuff.p.q.p.sut))
~
`crib.p.q.p.sut
::
:: +arm-doc: returns arm doc of an arm
::
:: we just check if the $cuff is from a ++ or +$ arm but this will
:: probably need to be revisited once more sophisticated cuffs are used
++ arm-doc
|= [nom=term sut=type]
^- what
?~ (hint-doc [%funk nom]~ sut)
(hint-doc [%plan nom]~ sut)
(hint-doc [%funk nom]~ sut)
::
:: +prod-doc: wrapper for +hint-doc with empty cuff
++ prod-doc
|= sut=type
^- what
(hint-doc ~ sut)
::
:: +buc-doc: checks if type is core and returns docs on $ arm if it exists
++ buc-doc
|= sut=type
^- what
?. ?=([%core *] sut)
~
?~ (find [%$]~ (sloe sut))
~
=/ sat=type (arm-type %$ sut)
?~ (arm-doc %$ sat)
(prod-doc sat)
(arm-doc %$ sat)
::
:: +arm-docs: grabs the docs for an arm.
::
:: there are three possible places with relevant docs for an arm:
:: docs for the arm itself, docs for the product of the arm, and
:: if the arm builds a core, docs for the default arm of that core.
::
:: .adoc: docs written above the the arm
:: .pdoc: docs for the product of the arm
:: .cdoc: docs for the default arm of the core produced by the arm
++ arm-docs
|= [nom=term sut=type]
^- [what what what]
?> ?=([%core *] sut)
=/ sat=type (~(play ut sut) (arm-hoon nom sut))
=/ adoc=what (arm-doc nom sat)
=/ pdoc=what
?~ adoc
(prod-doc sat)
?> ?=([%hint *] sat)
(prod-doc q.sat)
=/ cdoc=what
?~ adoc
?~ pdoc
(buc-doc sat)
?> ?=([%hint *] sat)
(buc-doc q.sat)
?~ pdoc
?> ?=([%hint *] sat)
(buc-doc q.sat)
?> &(?=([%hint *] sat) ?=([%hint *] q.sat))
(buc-doc q.q.sat)
[adoc pdoc cdoc]
::
:: +arm-and-chapter-overviews: returns an overview of a core's contents
::
:: returns an overview for arms which are part of unnamed chapters, and
:: an overview of the named chapters
::
++ arm-and-chapter-overviews
|= =item
^- [overview overview]
?> &(?=([%core *] item) ?=([%core *] sut.item))
=| [adocs=overview cdocs=overview]
=/ tomes ~(tap by q.r.q.sut.item)
|-
?~ tomes
[(sort-overview adocs) (sort-overview cdocs)]
?~ p.i.tomes
:: chapter has no name. add documentation for its arms to arm-docs
=. adocs (weld adocs (tome-as-overview q.i.tomes sut.item))
$(tomes t.tomes)
:: chapter has a name. add to list of chapters
=. cdocs
%+ weld cdocs
^- overview
[%item :(weld "^" name.item "|" (trip -.i.tomes)) p.q.i.tomes]~
$(tomes t.tomes)
::
:: +arms-in-chapter: returns an overview of the arms in a specific chapter
++ arms-in-chapter
|= [sut=type tom=tome]
^- overview
(sort-overview (tome-as-overview tom sut))
::
:: +sort-overview: sort items in an overview in alphabetical order
++ sort-overview
|= ovr=overview
^- overview
%+ sort ovr
|= [lhs=overview-item rhs=overview-item]
(aor (get-overview-name lhs) (get-overview-name rhs))
::
:: +get-overview-name: returns the name of an overview
++ get-overview-name
|= ovr=overview-item
?- ovr
[%header *] ""
[%item *] name.ovr
==
::
:: +tome-as-overview: translate a tome into an overview
++ tome-as-overview
|= [tom=tome sut=type]
^- overview
%+ turn ~(tap by q.tom)
|= ar=(pair term hoon)
:* %item
::TODO make this distinguish between ++ and +$ arms
(weld "+" (trip p.ar))
=/ adoc (arm-doc p.ar (~(play ut sut) q.ar))
=/ pdoc (prod-doc (~(play ut sut) q.ar))
?~ adoc
pdoc
adoc
==
::
:: +item-as-overview: changes an item into an overview
++ item-as-overview
|= uit=(unit item)
~? >> debug %item-as-overview
^- overview
?~ uit ~
=+ itm=(need uit)
?- itm
[%view *] items.itm
::
[%core *]
?~ name.itm
(item-as-overview children.itm)
:- [%item (weld "^" name.itm) docs.itm]
(item-as-overview children.itm)
::
[%arm *]
:_ ~
::TODO make this distinguish between ++ and +$ arms
:* %item (weld "+" name.itm)
?~ adoc.itm
?~ pdoc.itm
cdoc.itm
pdoc.itm
adoc.itm
==
::
[%chapter *]
[%item (weld "|" name.itm) docs.itm]~
::
[%face *]
?~ name.itm
~
[%item (weld "." name.itm) docs.itm]~
==
::
:: +join-items: combines two (unit items) together
++ join-items
|= [lhs=(unit item) rhs=(unit item)]
^- (unit item)
?~ lhs rhs
?~ rhs lhs
`[%view (weld (item-as-overview lhs) (item-as-overview rhs))]
::
:: contains arms using for printing doccords items
+| %printing
:: +print-item: prints a doccords item
++ print-item
|= =item
~? >> debug %print-item
^- (list sole-effect)
?- item
[%view *] (print-overview item *(pair styl styl))
[%core *] (print-core item)
[%arm *] (print-arm item)
[%chapter *] (print-chapter item)
[%face *] (print-face item)
==
::
:: +print-core: renders documentation for a full core
++ print-core
|= =item
^- (list sole-effect)
?> ?=([%core *] item)
=+ [arms chapters]=(arm-and-chapter-overviews item)
=/ styles=(pair styl styl) [[`%br ~ `%b] [`%br ~ `%m]]
;: weld
(print-header (weld "^" name.item) docs.item)
::
[%txt ""]~
::
(print-signature ~(duck easy-print sut.item))
::
[%txt ""]~
::
?~ arms
~
(print-overview [%view [%header `['arms:' ~] arms]~] styles)
::
?~ chapters
~
(print-overview [%view [%header `['chapters:' ~] chapters]~] styles)
::
?~ children.item
~
=/ child ?: ?=([%core *] u.children.item)
u.children.item(children ~)
?: ?=([%face *] u.children.item)
u.children.item(children ~)
u.children.item
=+ compiled=(item-as-overview `child)
?~ compiled
~
(print-overview [%view [%header `['compiled against: ' ~] [i.compiled]~]~] styles)
==
::
:: +print-chapter: renders documentation for a single chapter
++ print-chapter
|= =item
^- (list sole-effect)
?> ?=([%chapter *] item)
~? > debug %print-chapter
=/ styles=(pair styl styl) [[`%br ~ `%b] [`%br ~ `%m]]
;: weld
(print-header (weld "|" name.item) docs.item)
::
=+ arms=(arms-in-chapter sut.item tom.item)
?~ arms
~
(print-overview [%view [%header `['arms:' ~] arms]~] styles)
==
::
:: +print-signature: turns product of duck:easy-print into a (list sole-effect)
++ print-signature
|= =tank
^- (list sole-effect)
=/ tan (wash [3 80] tank)
?. (gte (lent tan) 3)
(turn tan |=(a=tape [%txt a]))
%+ weld
(turn (scag 3 tan) |=(a=tape [%txt a]))
(styled [[`%br ~ `%g] ' ...']~)
::
:: +print-arm: renders documentation for a single arm in a core
++ print-arm
|= =item
^- (list sole-effect)
?> ?=([%arm *] item)
~? >> debug %print-arm
;: weld
(print-header (weld "+" name.item) adoc.item)
[%txt ""]~
::
(print-signature ~(duck easy-print (~(play ut sut.item) gen.item)))
::
[%txt ""]~
::
?~ pdoc.item
*(list sole-effect)
%- zing :~ (styled [[`%br ~ `%b] 'product:']~)
(print-header "" pdoc.item)
[%txt ""]~
==
::
?~ cdoc.item
*(list sole-effect)
%- zing :~ (styled [[`%br ~ `%b] '$:']~)
(print-header "" cdoc.item)
==
==
::
:: +print-face: renders documentation for a face
++ print-face
|= =item
^- (list sole-effect)
?> ?=([%face *] item)
~? >> debug %print-face
;: weld
(print-header (weld "." name.item) docs.item)
[%txt ""]~
::
?~ children.item
~
(print-item u.children.item)
==
::
:: +print-header: prints name and docs only
++ print-header
|= [name=tape doc=what]
^- (list sole-effect)
~? >> debug %print-header
;: weld
(styled [[`%br ~ `%g] (crip name)]~)
?~ doc *(list sole-effect)
:: (styled [[`%br ~ `%r] '(undocumented)']~)
:~ :- %tan
%- flop
;: weld
[%leaf "{(trip p.u.doc)}"]~
(print-sections q.u.doc)
== ==
==
::
:: +print-overview: prints summaries of several items
::
:: the (pair styl styl) provides styles for each generation of child items
++ print-overview
|= [view=item styles=(pair styl styl)]
?> ?=([%view *] view)
~? >> debug %print-overview
=| out=(list sole-effect)
|- ^- (list sole-effect)
?~ items.view out
=/ oitem i.items.view
?- oitem
[%header *]
%= $
items.view t.items.view
out ;: weld
out
?~ doc.oitem ~
(styled [p.styles (crip "{(trip p.u.doc.oitem)}")]~)
^$(view [%view children.oitem])
== ==
::
[%item *]
%= $
items.view t.items.view
out ;: weld
out
(styled [q.styles (crip name.oitem)]~)
?~ doc.oitem
%- styled
:~ [[`%br ~ `%r] '(undocumented)']
[[~ ~ ~] '']
==
^- (list sole-effect)
[%tan [[%leaf ""] [%leaf "{(trip p.u.doc.oitem)}"] ~]]~
== ==
==
::
:: +print-sections: renders a list of sections as tang
::
:: prints the longform documentation
++ print-sections
|= sections=(list sect)
^- tang
=| out=tang
|-
?~ sections out
=. out
;: weld
out
`tang`[%leaf ""]~
(print-section i.sections)
==
$(sections t.sections)
::
:: +print-section: renders a sect as a tang
++ print-section
|= section=sect
^- tang
%+ turn section
|= =pica
^- tank
?: p.pica
[%leaf (trip q.pica)]
[%leaf " {(trip q.pica)}"]
::
:: +styled: makes $sole-effects out of $styls and $cords
++ styled
|= [in=(list (pair styl cord))]
^- (list sole-effect)
=| out=(list sole-effect)
|-
?~ in out
=/ eff=styx [p.i.in [q.i.in]~]~
%= $
in t.in
out (snoc out [%klr eff])
==
--

View File

@ -1,34 +1,66 @@
/- *sole /- *sole
/+ sole /+ sole
|% |%
+$ state state-4 +$ state state-5
+$ any-state +$ any-state
$~ *state $~ *state
$% state-4 $% state-5
state-4
state-3 state-3
state-2 state-2
== ==
+$ state-5 [%5 pith-5]
+$ state-4 [%4 pith-4] +$ state-4 [%4 pith-4]
+$ state-3 [%3 pith-3] +$ state-3 [%3 pith-3]
+$ state-2 [%2 pith-2] +$ state-2 [%2 pith-2]
:: ::
+$ pith-5
$: bin=(map @ source) :: terminals
==
::
+$ pith-4 +$ pith-4
$: eel=(set gill:gall) :: connect to $: eel=(set gill:gall) :: connect to
bin=(map bone source) :: terminals bin=(map bone source-4) :: terminals
== :: == ::
:: ::
+$ source-4
$: edg=_80
off=@ud
kil=kill
inx=@ud
fug=(map gill:gall (unit target-4))
mir=(pair @ud stub)
==
::
+$ target-4
$: $= blt
%+ pair
(unit dill-belt-4)
(unit dill-belt-4)
ris=(unit search)
hit=history
pom=sole-prompt
inp=sole-command
==
::
+$ dill-belt-4
$% [%ctl p=@c]
[%met p=@c]
dill-belt:dill
==
::
++ pith-3 :: ++ pith-3 ::
$: eel=(set gill:gall) :: connect to $: eel=(set gill:gall) :: connect to
ray=(map dude:gall desk) :: ray=(map dude:gall desk) ::
fur=(map dude:gall (unit *)) :: servers fur=(map dude:gall (unit *)) :: servers
bin=(map bone source) :: terminals bin=(map bone source-4) :: terminals
== :: == ::
:: :: :: ::
++ pith-2 :: ++ pith-2 ::
$: eel=(set gill:gall) :: connect to $: eel=(set gill:gall) :: connect to
ray=(set well:gall) :: ray=(set well:gall) ::
fur=(map dude:gall (unit *)) :: servers fur=(map dude:gall (unit *)) :: servers
bin=(map bone source) :: terminals bin=(map bone source-4) :: terminals
== :: == ::
:: :: :: ::
++ kill :: kill ring ++ kill :: kill ring
@ -42,6 +74,7 @@
off=@ud :: window offset off=@ud :: window offset
kil=kill :: kill buffer kil=kill :: kill buffer
inx=@ud :: ring index inx=@ud :: ring index
eel=(set gill:gall) :: connect to
fug=(map gill:gall (unit target)) :: connections fug=(map gill:gall (unit target)) :: connections
mir=(pair @ud stub) :: mirrored terminal mir=(pair @ud stub) :: mirrored terminal
== :: == ::
@ -65,52 +98,74 @@
pom=sole-prompt :: static prompt pom=sole-prompt :: static prompt
inp=sole-command :: input state inp=sole-command :: input state
== :: == ::
::
-- --
:: :: :: :: :: ::
:::: :: :: :::: :: ::
:: :: :: :: :: ::
|% |%
++ en-gill :: gill to wire ++ en-gill :: gill to wire
|= gyl=gill:gall |= [ses=@tas gyl=gill:gall]
^- wire ^- wire
[%drum %phat (scot %p p.gyl) q.gyl ~] [%drum %phat (scot %p p.gyl) q.gyl ?:(=(%$ ses) ~ [ses ~])]
:: ::
++ de-gill :: gill from wire ++ de-gill :: gill from wire
|= way=wire ^- gill:gall |= way=wire
~| way ^- [@tas gill:gall]
?>(?=([@ @ *] way) [(slav %p i.way) i.t.way]) ~| wire=way
?> ?=([@ @ ?(~ [@ ~])] way)
:- ?~(t.t.way %$ i.t.t.way)
[(slav %p i.way) i.t.way]
-- --
:: TODO: remove .ost
:: ::
|= [hid=bowl:gall state] |= [hid=bowl:gall state]
=* sat +<+ =* sat +<+
=/ ost 0 =/ ses=@tas %$
=+ (~(gut by bin) ost *source) =+ (~(gut by bin) ses *source)
=* dev - =* dev -
=| moz=(list card:agent:gall) =| moz=(list card:agent:gall)
=| biz=(list dill-blit:dill) =| biz=(list blit:dill) ::TODO should be per-session
|% |%
++ this . ++ this .
++ klr klr:format
+$ state ^state :: proxy +$ state ^state :: proxy
+$ any-state ^any-state :: proxy +$ any-state ^any-state :: proxy
++ on-init (poke-link our.hid %dojo) ++ on-init (poke-link %$ our.hid %dojo)
::
++ prep
|= s=@tas
=. ses s
=. dev (~(gut by bin) ses *source)
this
::
++ open
%+ cork de-gill
|= [s=@tas g=gill:gall]
[g (prep s)]
::
++ diff-sole-effect-phat :: app event ++ diff-sole-effect-phat :: app event
|= [way=wire fec=sole-effect] |= [way=wire fec=sole-effect]
=< se-abet =< se-view =< se-abet
=+ gyl=(de-gill way) =^ gyl this (open way)
?: (se-aint gyl) +>.$ ?: (se-aint gyl) +>.$
(se-diff gyl fec) (se-diff gyl fec)
:: ::
++ peer :: ++ peer ::
|= pax=path |= pax=path
=? this ?=([%dill @ ~] pax)
(prep i.t.pax)
~| [%drum-unauthorized our+our.hid src+src.hid] :: ourself ~| [%drum-unauthorized our+our.hid src+src.hid] :: ourself
?> (team:title our.hid src.hid) :: or our own moon ?> (team:title our.hid src.hid) :: or our own moon
=< se-abet =< se-view =< se-abet
(se-text "[{<src.hid>}, driving {<our.hid>}]") (se-text "[{<src.hid>}, driving {<our.hid>}]")
:: ::
++ poke-dill
|= [ses=@tas bet=dill-belt:dill]
(poke-dill-belt:(prep ses) bet)
::
++ poke-dill-belt :: terminal event ++ poke-dill-belt :: terminal event
|= bet=dill-belt:dill |= bet=dill-belt:dill
=< se-abet =< se-view =< se-abet
(se-belt bet) (se-belt bet)
:: ::
++ poke-dill-blit :: terminal output ++ poke-dill-blit :: terminal output
@ -118,29 +173,29 @@
se-abet:(se-blit-sys bit) se-abet:(se-blit-sys bit)
:: ::
++ poke-link :: connect app ++ poke-link :: connect app
|= gyl=gill:gall |= [ses=@tas gyl=gill:gall]
=< se-abet =< se-view =< se-abet
(se-link gyl) (se-link:(prep ses) gyl)
:: ::
++ poke-unlink :: disconnect app ++ poke-unlink :: disconnect app
|= gyl=gill:gall |= [ses=@ta gyl=gill:gall]
=< se-abet =< se-view =< se-abet
(se-drop:(se-pull gyl) & gyl) (se-drop:(se-pull:(prep ses) gyl) & gyl)
:: ::
++ poke-exit :: shutdown ++ poke-exit :: shutdown
|= ~ |= ~
se-abet:(se-blit-sys `dill-blit:dill`[%qit ~]) se-abet:(se-blit-sys `dill-blit:dill`[%qit ~])
:: ::
++ poke-put :: write file ++ poke-put :: write file
|= [pax=path txt=@] |= [pax=path arg=$@(@ [@tas @])]
=^ txt +> ?@(arg [arg +>] [+.arg (prep -.arg)])
se-abet:(se-blit-sys [%sav pax txt]) :: se-abet:(se-blit-sys [%sav pax txt]) ::
:: ::
++ poke ++ poke
|= [=mark =vase] |= [=mark =vase]
?> =(our src):hid ?> =(our src):hid
?+ mark ~|([%poke-drum-bad-mark mark] !!) ?+ mark ~|([%poke-drum-bad-mark mark] !!)
%drum-dill-belt =;(f (f !<(_+<.f vase)) poke-dill-belt) %dill-poke =;(f (f !<(_+<.f vase)) poke-dill)
%drum-dill-blit =;(f (f !<(_+<.f vase)) poke-dill-blit)
%drum-exit =;(f (f !<(_+<.f vase)) poke-exit) %drum-exit =;(f (f !<(_+<.f vase)) poke-exit)
%drum-link =;(f (f !<(_+<.f vase)) poke-link) %drum-link =;(f (f !<(_+<.f vase)) poke-link)
%drum-put =;(f (f !<(_+<.f vase)) poke-put) %drum-put =;(f (f !<(_+<.f vase)) poke-put)
@ -149,19 +204,40 @@
:: ::
++ on-load ++ on-load
|= [hood-version=@ud old=any-state] |= [hood-version=@ud old=any-state]
=< se-abet =< se-view =< se-abet
=? old ?=(%2 -.old) [%4 [eel bin]:old] =? old ?=(%2 -.old) [%4 [eel bin]:old]
=? old ?=(%3 -.old) [%4 [eel bin]:old] =? old ?=(%3 -.old) [%4 [eel bin]:old]
=? old ?=(%4 -.old)
|^ 5+(~(run by bin.old) source-4-to-5)
++ source-4-to-5
|= source-4
^- source
=; fug [edg off kil inx eel.old fug mir]
(~(run by fug) |=(t=(unit target-4) (bind t target-4-to-5)))
::
++ target-4-to-5
|= t=target-4
^- target
:_ +.t
:- (bind p.blt.t belt-4-to-5)
(bind q.blt.t belt-4-to-5)
::
++ belt-4-to-5
|= b=dill-belt-4
^- dill-belt:dill
?. ?=(?(%ctl %met) -.b) b
[%mod -.b p.b]
--
:: ::
?> ?=(%4 -.old) ?> ?=(%5 -.old)
=. sat old =. sat old
=. dev (~(gut by bin) ost *source) =. dev (~(gut by bin) ses *source)
this this
:: ::
++ reap-phat :: ack connect ++ reap-phat :: ack connect
|= [way=wire saw=(unit tang)] |= [way=wire saw=(unit tang)]
=< se-abet =< se-view =< se-abet
=+ gyl=(de-gill way) =^ gyl this (open way)
?~ saw ?~ saw
(se-join gyl) (se-join gyl)
:: Don't print stack trace because we probably just crashed to :: Don't print stack trace because we probably just crashed to
@ -171,9 +247,9 @@
:: ::
++ take-coup-phat :: ack poke ++ take-coup-phat :: ack poke
|= [way=wire saw=(unit tang)] |= [way=wire saw=(unit tang)]
=< se-abet =< se-view =< se-abet
?~ saw +> ?~ saw +>
=+ gyl=(de-gill way) =^ gyl this (open way)
?: (se-aint gyl) +>.$ ?: (se-aint gyl) +>.$
%- se-dump:(se-drop:(se-pull gyl) & gyl) %- se-dump:(se-drop:(se-pull gyl) & gyl)
:_ u.saw :_ u.saw
@ -196,8 +272,8 @@
:: ::
++ quit-phat :: ++ quit-phat ::
|= way=wire |= way=wire
=< se-abet =< se-view =< se-abet
=+ gyl=(de-gill way) =^ gyl this (open way)
~& [%drum-quit src.hid gyl] ~& [%drum-quit src.hid gyl]
(se-drop %| gyl) (se-drop %| gyl)
:: :: :: :: :: ::
@ -205,13 +281,18 @@
:: :: :: :: :: ::
++ se-abet :: resolve ++ se-abet :: resolve
^- (quip card:agent:gall state) ^- (quip card:agent:gall state)
=. . se-subze:se-adze =. . se-view:se-subze:se-adze
:_ sat(bin (~(put by bin) ost dev)) :_ sat(bin (~(put by bin) ses dev))
^- (list card:agent:gall) ^- (list card:agent:gall)
?~ biz (flop moz) ?~ biz (flop moz)
:_ (flop moz) :_ (flop moz)
=/ =dill-blit:dill ?~(t.biz i.biz [%mor (flop biz)]) =/ =blit:dill ?~(t.biz i.biz [%mor (flop biz)])
[%give %fact ~[/drum] %dill-blit !>(dill-blit)] ::TODO remove /drum after dill cleans up
::TODO but once we remove it, the empty trailing segment of
:: /dill/[ses] would prevent outsiders from subscribing
:: to the default session...
=/ to=(list path) [/dill/[ses] ?~(ses ~[/drum] ~)]
[%give %fact to %dill-blit !>(blit)]
:: ::
++ se-adze :: update connections ++ se-adze :: update connections
^+ . ^+ .
@ -230,14 +311,14 @@
(se-peer gil) (se-peer gil)
:: ::
++ se-subze :: downdate connections ++ se-subze :: downdate connections
=< .(dev (~(got by bin) ost)) =< .(dev (~(got by bin) ses))
=. bin (~(put by bin) ost dev) =. bin (~(put by bin) ses dev)
^+ . ^+ .
%- ~(rep by bin) %- ~(rep by bin)
=< .(con +>) =< .(con +>)
|: $:,[[ost=bone dev=source] con=_.] ^+ con |: $:,[[ses=@tas dev=source] con=_.] ^+ con
=+ xeno=se-subze-local:%_(con ost ost, dev dev) =+ xeno=se-subze-local:%_(con ses ses, dev dev)
xeno(ost ost.con, dev dev.con, bin (~(put by bin) ost dev.xeno)) xeno(ses ses.con, dev dev.con, bin (~(put by bin.xeno) ses dev.xeno))
:: ::
++ se-subze-local ++ se-subze-local
^+ . ^+ .
@ -252,7 +333,7 @@
++ se-aint :: ignore result ++ se-aint :: ignore result
|= gyl=gill:gall |= gyl=gill:gall
^- ? ^- ?
?. (~(has by bin) ost) & ?. (~(has by bin) ses) &
=+ gyr=(~(get by fug) gyl) =+ gyr=(~(get by fug) gyl)
|(?=(~ gyr) ?=(~ u.gyr)) |(?=(~ gyr) ?=(~ u.gyr))
:: ::
@ -290,7 +371,7 @@
[%cru *] (se-dump:(se-text (trip p.bet)) q.bet) [%cru *] (se-dump:(se-text (trip p.bet)) q.bet)
[%hey *] +>(mir [0 ~]) :: refresh [%hey *] +>(mir [0 ~]) :: refresh
[%rez *] +>(edg (dec p.bet)) :: resize window [%rez *] +>(edg (dec p.bet)) :: resize window
[%yow *] ~&([%no-yow -.bet] +>) [%yow *] (se-link p.bet)
== ==
=+ gul=se-agon =+ gul=se-agon
?: |(?=(~ gul) (se-aint u.gul)) ?: |(?=(~ gul) (se-aint u.gul))
@ -341,6 +422,21 @@
leaf+(weld (scag (sub edg 3) tape) "...") leaf+(weld (scag (sub edg 3) tape) "...")
leaf+tape leaf+tape
:: ::
++ se-blin :: print and newline
|= $= lin
$~ [%put ~]
$>(?(%put %klr) dill-blit:dill)
^+ +>
:: newline means we need to redraw the prompt,
:: so update the prompt mirror accordingly.
::
=. mir [0 ~]
::TODO doing hops and wyps conditionally based on the mirror state seems
:: better, but doesn't cover edge cases. results in dojo's ">=" being
:: rendered alongside the prompt in scrollback, for example.
:: figure out a way to make that work!
(se-blit %mor [%hop 0] [%wyp ~] lin [%nel ~] ~)
::
++ se-dump :: print tanks ++ se-dump :: print tanks
|= tac=(list tank) |= tac=(list tank)
^+ +> ^+ +>
@ -351,7 +447,7 @@
?. ((sane %t) (crip i.wol)) :: XX upstream validation ?. ((sane %t) (crip i.wol)) :: XX upstream validation
~& bad-text+<`*`i.wol> ~& bad-text+<`*`i.wol>
$(wol t.wol) $(wol t.wol)
$(wol t.wol, +>.^$ (se-blit %out (tuba i.wol))) $(wol t.wol, +>.^$ (se-blin %put (tuba i.wol)))
:: ::
++ se-join :: confirm connection ++ se-join :: confirm connection
|= gyl=gill:gall |= gyl=gill:gall
@ -379,20 +475,21 @@
+>(eel (~(put in eel) gyl)) +>(eel (~(put in eel) gyl))
:: ::
++ se-blit :: give output ++ se-blit :: give output
|= bil=dill-blit:dill |= bil=blit:dill
+>(biz [bil biz]) +>(biz [bil biz])
:: ::
++ se-blit-sys :: output to system ++ se-blit-sys :: output to system
|= bil=dill-blit:dill ^+ +> |= bil=dill-blit:dill ^+ +>
(se-emit %give %fact ~[/drum] %dill-blit !>(bil)) ::TODO remove /drum after dill cleans up
(se-emit %give %fact ~[/drum /dill/[ses]] %dill-blit !>(bil))
:: ::
++ se-show :: show buffer, raw ++ se-show :: show buffer, raw
|= lin=(pair @ud stub) |= lin=(pair @ud stub)
^+ +> ^+ +>
?: =(mir lin) +> ?: =(mir lin) +>
=. +> ?:(=(p.mir p.lin) +> (se-blit %hop p.lin)) %- se-blit(mir lin)
=. +> ?:(=(q.mir q.lin) +> (se-blit %pom q.lin)) ?: =(q.mir q.lin) [%hop p.lin]
+>(mir lin) mor+[[%hop 0] [%wyp ~] [%klr q.lin] [%hop p.lin] ~]
:: ::
++ se-just :: adjusted buffer ++ se-just :: adjusted buffer
|= [pom=stub lin=(pair @ud (list @c))] |= [pom=stub lin=(pair @ud (list @c))]
@ -430,22 +527,22 @@
?. ((sane %t) (crip txt)) :: XX upstream validation ?. ((sane %t) (crip txt)) :: XX upstream validation
~& bad-text+<`*`txt> ~& bad-text+<`*`txt>
+> +>
(se-blit %out (tuba txt)) (se-blin %put (tuba txt))
:: ::
++ se-poke :: send a poke ++ se-poke :: send a poke
|= [gyl=gill:gall par=cage] |= [gyl=gill:gall par=cage]
(se-emit %pass (en-gill gyl) %agent gyl %poke par) (se-emit %pass (en-gill ses gyl) %agent gyl %poke par)
:: ::
++ se-peer :: send a peer ++ se-peer :: send a peer
|= gyl=gill:gall |= gyl=gill:gall
~> %slog.0^leaf/"drum: link {<[p q]:gyl>}" ~> %slog.0^leaf/"drum: link {<[p q]:gyl>}"
=/ =path /sole/(cat 3 'drum_' (scot %p our.hid)) =/ =path (id-to-path:sole our.hid ses)
%- se-emit(fug (~(put by fug) gyl ~)) %- se-emit(fug (~(put by fug) gyl ~))
[%pass (en-gill gyl) %agent gyl %watch path] [%pass (en-gill ses gyl) %agent gyl %watch path]
:: ::
++ se-pull :: cancel subscription ++ se-pull :: cancel subscription
|= gyl=gill:gall |= gyl=gill:gall
(se-emit %pass (en-gill gyl) %agent gyl %leave ~) (se-emit %pass (en-gill ses gyl) %agent gyl %leave ~)
:: ::
++ se-tame :: switch connection ++ se-tame :: switch connection
|= gyl=gill:gall |= gyl=gill:gall
@ -470,7 +567,7 @@
^+ +> ^+ +>
(ta-poke %sole-action !>(act)) (ta-poke %sole-action !>(act))
:: ::
++ ta-id (cat 3 'drum_' (scot %p our.hid)) :: per-ship duct id ++ ta-id [our.hid ses] :: per-ship-session id
:: ::
++ ta-aro :: hear arrow ++ ta-aro :: hear arrow
|= key=?(%d %l %r %u) |= key=?(%d %l %r %u)
@ -499,13 +596,19 @@
?< ?=([?(%cru %hey %rez %yow) *] bet) :: target-specific ?< ?=([?(%cru %hey %rez %yow) *] bet) :: target-specific
=. blt [q.blt `bet] :: remember belt =. blt [q.blt `bet] :: remember belt
?- bet ?- bet
@ (ta-txt bet ~)
[%aro *] (ta-aro p.bet) [%aro *] (ta-aro p.bet)
[%bac *] ta-bac [%bac *] ta-bac
[%ctl *] (ta-ctl p.bet)
[%del *] ta-del [%del *] ta-del
[%met *] (ta-met p.bet) [%hit *] (ta-hit +.bet)
[%ret *] ta-ret [%ret *] ta-ret
[%txt *] (ta-txt p.bet) [%txt *] (ta-txt p.bet)
::
[%mod *]
?+ mod.bet $(bet key.bet)
%ctl (ta-ctl key.bet)
%met (ta-met key.bet)
==
== ==
:: ::
++ ta-det :: send edit ++ ta-det :: send edit
@ -529,7 +632,7 @@
(ta-hom %del (dec pos.inp)) (ta-hom %del (dec pos.inp))
:: ::
++ ta-ctl :: hear control ++ ta-ctl :: hear control
|= key=@ud |= key=bolt:dill
^+ +> ^+ +>
=. ris ?.(?=(?(%g %r) key) ~ ris) =. ris ?.(?=(?(%g %r) key) ~ ris)
?+ key ta-bel ?+ key ta-bel
@ -539,7 +642,7 @@
%d ?^ buf.say.inp %d ?^ buf.say.inp
ta-del ta-del
?: =([our.hid %dojo] gyl) ?: =([our.hid %dojo] gyl)
+>(..ta (se-blit qit+~)) :: quit pier +>(..ta (se-blit-sys %qit ~)) :: quit pier
+>(..ta (se-klin gyl)) :: unlink app +>(..ta (se-klin gyl)) :: unlink app
%e +>(pos.inp (lent buf.say.inp)) %e +>(pos.inp (lent buf.say.inp))
%f (ta-aro %r) %f (ta-aro %r)
@ -550,7 +653,7 @@
?: =(pos.inp len) ?: =(pos.inp len)
ta-bel ta-bel
(ta-kil %r [pos.inp (sub len pos.inp)]) (ta-kil %r [pos.inp (sub len pos.inp)])
%l +>(..ta (se-blit %clr ~)) %l +>(..ta (se-blit(q.mir ~) %clr ~))
%n (ta-aro %d) %n (ta-aro %d)
%p (ta-aro %u) %p (ta-aro %u)
%r ?~ ris %r ?~ ris
@ -583,6 +686,14 @@
ta-bel ta-bel
(ta-hom %del pos.inp) (ta-hom %del pos.inp)
:: ::
++ ta-hit :: hear click
|= [x=@ud y=@ud]
^+ +>
=/ pol=@ud
(lent-char:klr (make:klr cad.pom))
=? x (lth x pol) pol
+>.$(pos.inp (min (sub x pol) (lent buf.say.inp)))
::
++ ta-erl :: hear local error ++ ta-erl :: hear local error
|= pos=@ud |= pos=@ud
ta-bel(pos.inp (min pos (lent buf.say.inp))) ta-bel(pos.inp (min pos (lent buf.say.inp)))
@ -594,14 +705,13 @@
++ ta-fec :: apply effect ++ ta-fec :: apply effect
|= fec=sole-effect |= fec=sole-effect
^+ +> ^+ +>
?- fec ?+ fec +>(..ta (se-blit fec))
[%bel *] ta-bel [%bel *] ta-bel
[%blk *] +> [%blk *] +>
[%bye *] +>(..ta (se-klin gyl)) [%bye *] +>(..ta (se-klin gyl))
[%clr *] +>(..ta (se-blit fec))
[%det *] (ta-got +.fec) [%det *] (ta-got +.fec)
[%err *] (ta-err p.fec) [%err *] (ta-err p.fec)
[%klr *] +>(..ta (se-blit %klr (make:klr p.fec))) [%klr *] +>(..ta (se-blin %klr (make:klr p.fec)))
[%mor *] |- ^+ +>.^$ [%mor *] |- ^+ +>.^$
?~ p.fec +>.^$ ?~ p.fec +>.^$
$(p.fec t.p.fec, +>.^$ ^$(fec i.p.fec)) $(p.fec t.p.fec, +>.^$ ^$(fec i.p.fec))
@ -609,10 +719,8 @@
[%pro *] (ta-pro +.fec) [%pro *] (ta-pro +.fec)
[%tab *] +>(..ta (se-tab p.fec)) [%tab *] +>(..ta (se-tab p.fec))
[%tan *] +>(..ta (se-dump p.fec)) [%tan *] +>(..ta (se-dump p.fec))
[%sag *] +>(..ta (se-blit fec))
[%sav *] +>(..ta (se-blit fec))
[%txt *] +>(..ta (se-text p.fec)) [%txt *] +>(..ta (se-text p.fec))
[%url *] +>(..ta (se-blit fec)) [%url *] +>(..ta (se-text:(se-blit fec) (trip p.fec)))
== ==
:: ::
++ ta-dog :: change cursor ++ ta-dog :: change cursor
@ -664,8 +772,8 @@
kil kil
?. ?& ?=(^ old.kil) ?. ?& ?=(^ old.kil)
?=(^ p.blt) ?=(^ p.blt)
?| ?=([%ctl ?(%k %u %w)] u.p.blt) ?| ?=([%mod %ctl ?(%k %u %w)] u.p.blt)
?=([%met ?(%d %bac)] u.p.blt) ?=([%mod %met ?(%d [%bac ~])] u.p.blt)
== == == ==
%= kil :: prepend %= kil :: prepend
num +(num.kil) num +(num.kil)
@ -682,17 +790,18 @@
== ==
:: ::
++ ta-met :: meta key ++ ta-met :: meta key
|= key=@ud |= key=bolt:dill
^+ +> ^+ +>
=. ris ~ =. ris ~
?+ key ta-bel ?+ key ta-bel
%dot ?. &(?=(^ old.hit) ?=(^ i.old.hit)) :: last "arg" from hist %'.' ?. &(?=(^ old.hit) ?=(^ i.old.hit)) :: last "arg" from hist
ta-bel ta-bel
=+ old=`(list @c)`i.old.hit =+ old=`(list @c)`i.old.hit
=+ sop=(ta-jump(buf.say.inp old) %l %ace (lent old)) =+ sop=(ta-jump(buf.say.inp old) %l %ace (lent old))
(ta-hom (cat:edit pos.inp (slag sop old))) (ta-hom (cat:edit pos.inp (slag sop old)))
:: ::
%bac ?: =(0 pos.inp) :: kill left-word [%bac ~]
?: =(0 pos.inp) :: kill left-word
ta-bel ta-bel
=+ sop=(ta-pos %l %edg pos.inp) =+ sop=(ta-pos %l %edg pos.inp)
(ta-kil %l [(sub pos.inp sop) sop]) (ta-kil %l [(sub pos.inp sop) sop])
@ -748,8 +857,8 @@
:: ::
%y ?. ?& ?=(^ old.kil) :: rotate & yank %y ?. ?& ?=(^ old.kil) :: rotate & yank
?=(^ p.blt) ?=(^ p.blt)
?| ?=([%ctl %y] u.p.blt) ?| ?=([%mod %ctl %y] u.p.blt)
?=([%met %y] u.p.blt) ?=([%mod %met %y] u.p.blt)
== == == ==
ta-bel ta-bel
=+ las=(lent ta-yan) =+ las=(lent ta-yan)
@ -927,82 +1036,4 @@
?: |(?=(~ a) (alnm i.a)) i ?: |(?=(~ a) (alnm i.a)) i
$(i +(i), a t.a) $(i +(i), a t.a)
-- --
::
++ klr :: styx/stub engine
=, dill
|%
++ make :: stub from styx
|= a=styx ^- stub
=| b=stye
%+ reel
|- ^- stub
%- zing %+ turn a
|= a=$@(@t (pair styl styx))
?@ a [b (tuba (trip a))]~
^$(a q.a, b (styd p.a b))
::
|= [a=(pair stye (list @c)) b=stub]
?~ b [a ~]
?. =(p.a p.i.b) [a b]
[[p.a (weld q.a q.i.b)] t.b]
::
++ styd :: stye from styl
|= [a=styl b=stye] ^+ b :: with inheritance
:+ ?~ p.a p.b
?~ u.p.a ~
(~(put in p.b) u.p.a)
(fall p.q.a p.q.b)
(fall q.q.a q.q.b)
::
++ lent-char
|= a=stub ^- @
(roll (lnts-char a) add)
::
++ lnts-char :: stub pair tail lengths
|= a=stub ^- (list @)
%+ turn a
|= a=(pair stye (list @c))
(lent q.a)
::
++ brek :: index + incl-len of
|= [a=@ b=(list @)] :: stub pair w= idx a
=| [c=@ i=@]
|- ^- (unit (pair @ @))
?~ b ~
=. c (add c i.b)
?: (gte c a)
`[i c]
$(i +(i), b t.b)
::
++ slag :: slag stub, keep stye
|= [a=@ b=stub]
^- stub
=+ c=(lnts-char b)
=+ i=(brek a c)
?~ i b
=+ r=(^slag +(p.u.i) b)
?: =(a q.u.i)
r
=+ n=(snag p.u.i b)
:_ r :- p.n
(^slag (sub (snag p.u.i c) (sub q.u.i a)) q.n)
::
++ scag :: scag stub, keep stye
|= [a=@ b=stub]
^- stub
=+ c=(lnts-char b)
=+ i=(brek a c)
?~ i b
?: =(a q.u.i)
(^scag +(p.u.i) b)
%+ welp
(^scag p.u.i b)
=+ n=(snag p.u.i b)
:_ ~ :- p.n
(^scag (sub (snag p.u.i c) (sub q.u.i a)) q.n)
::
++ swag :: swag stub, keep stye
|= [[a=@ b=@] c=stub]
(scag b (slag a c))
--
-- --

View File

@ -202,6 +202,10 @@
|= ships=(list ship) |= ships=(list ship)
abet:(emit %pass /helm/prod %arvo %a %prod ships) abet:(emit %pass /helm/prod %arvo %a %prod ships)
:: ::
++ poke-ames-snub
|= ships=(list ship)
abet:(emit %pass /helm/snub %arvo %a %snub ships)
::
++ poke-atom ++ poke-atom
|= ato=@ |= ato=@
=+ len=(scow %ud (met 3 ato)) =+ len=(scow %ud (met 3 ato))
@ -273,6 +277,7 @@
== ==
?+ mark ~|([%poke-helm-bad-mark mark] !!) ?+ mark ~|([%poke-helm-bad-mark mark] !!)
%helm-ames-prod =;(f (f !<(_+<.f vase)) poke-ames-prod) %helm-ames-prod =;(f (f !<(_+<.f vase)) poke-ames-prod)
%helm-ames-snub =;(f (f !<(_+<.f vase)) poke-ames-snub)
%helm-ames-sift =;(f (f !<(_+<.f vase)) poke-ames-sift) %helm-ames-sift =;(f (f !<(_+<.f vase)) poke-ames-sift)
%helm-ames-verb =;(f (f !<(_+<.f vase)) poke-ames-verb) %helm-ames-verb =;(f (f !<(_+<.f vase)) poke-ames-verb)
%helm-ames-wake =;(f (f !<(_+<.f vase)) poke-ames-wake) %helm-ames-wake =;(f (f !<(_+<.f vase)) poke-ames-wake)

View File

@ -504,7 +504,7 @@
[%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) %- ~(rut by rock)
|= [=desk =zest wic=(set weft)] |= [=desk =zest wic=(set weft)]
^- pike ^- pike
@ -687,7 +687,7 @@
abet:(emit:(spam leaf+mez ~) %pass /kiln %arvo %c [%info u.tor]) abet:(emit:(spam leaf+mez ~) %pass /kiln %arvo %c [%info u.tor])
:: ::
++ poke-install ++ poke-install
|= [loc=desk her=ship rem=desk] |= [loc=desk her=ship rem=desk once=?]
=+ .^(=rock:tire %cx /(scot %p our)//(scot %da now)/tire) =+ .^(=rock:tire %cx /(scot %p our)//(scot %da now)/tire)
=/ =zest =/ =zest
?~ got=(~(get by rock) loc) ?~ got=(~(get by rock) loc)
@ -703,6 +703,8 @@
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
?: once
abet:abet:(merge:(work loc) her rem da+now %only-that)
=/ sun (sync loc her rem) =/ sun (sync loc her rem)
~> %slog.(fmt "beginning install into {here:sun}") ~> %slog.(fmt "beginning install into {here:sun}")
=< abet:abet:init =< abet:abet:init
@ -764,11 +766,19 @@
:: ::
++ poke-rm ++ poke-rm
|= a=path |= a=path
=| c=(list (unit toro))
%+ poke-info "removed: {<a>}"
=- %+ roll -
|= [a=(unit toro) b=(unit toro)]
(clap a b furl)
|- ^- (list (unit toro))
=+ b=.^(arch %cy a) =+ b=.^(arch %cy a)
?~ fil.b ?: ?=([^ ~] b) (snoc c `(fray a))
=+ ~[leaf+"No such file:" leaf+"{<a>}"] =? c ?=(^ fil.b) (snoc c `(fray a))
abet:(spam -) %- zing
(poke-info "removed" `(fray a)) %+ turn ~(tap by dir.b)
|= [kid=@ta ~]
^$(a (weld a /[kid]))
:: ::
++ poke-schedule ++ poke-schedule
|= [where=path tym=@da eve=@t] |= [where=path tym=@da eve=@t]

View File

@ -632,6 +632,7 @@
[%atom *] (cat 3 '@' p.p.spec) [%atom *] (cat 3 '@' p.p.spec)
== ==
%dbug $(spec q.spec) %dbug $(spec q.spec)
%gist $(spec q.spec)
%leaf =+((scot p.spec q.spec) ?:(=('~' -) - (cat 3 '%' -))) %leaf =+((scot p.spec q.spec) ?:(=('~' -) - (cat 3 '%' -)))
%like tree/[[`[':' ~] ~] (turn `(list wing)`+.spec wing-to-plum)] %like tree/[[`[':' ~] ~] (turn `(list wing)`+.spec wing-to-plum)]
%loop (cat 3 '$' p.spec) %loop (cat 3 '$' p.spec)

View File

@ -45,8 +45,8 @@
=+ cha=(tuba (trip q.kev)) =+ cha=(tuba (trip q.kev))
?> ?=([@ ~] cha) :: of a single character ?> ?=([@ ~] cha) :: of a single character
?+ mod !! :: modified by one buckykey ?+ mod !! :: modified by one buckykey
[%ctrl ~ ~] [%ctl i.cha] [%ctrl ~ ~] [%mod %ctl i.cha]
[%alt ~ ~] [%met i.cha] [%alt ~ ~] [%mod %met i.cha]
== ==
?@ q.kev ?@ q.kev
[%txt (tuba (trip q.kev))] [%txt (tuba (trip q.kev))]

View File

@ -19,8 +19,10 @@
^- ^json ^- ^json
?+ -.dib ~|(unsupported-blit+-.dib !!) ?+ -.dib ~|(unsupported-blit+-.dib !!)
%mor [%a (turn p.dib |=(a=dill-blit:dill json(dib a)))] %mor [%a (turn p.dib |=(a=dill-blit:dill json(dib a)))]
%hop (frond %hop (numb p.dib)) %hop %+ frond %hop
?(%pro %out) (frond -.dib (tape (tufa p.dib))) ?@ p.dib (numb p.dib)
(pairs 'x'^(numb x.p.dib) 'y'^(numb y.p.dib) ~)
%put (frond -.dib (tape (tufa p.dib)))
?(%bel %clr) (frond %act %s -.dib) ?(%bel %clr) (frond %act %s -.dib)
== ==
-- --

View File

@ -1,8 +1,7 @@
:: %drum-put: download into host system
:: ::
:::: /hoon/do-claim/womb/mar
::
/? 310 /? 310
|_ [path @] |_ [path $@(@ [@ta @])]
:: ::
++ grad %noun ++ grad %noun
++ grow ++ grow
@ -11,6 +10,6 @@
-- --
++ grab :: convert from ++ grab :: convert from
|% |%
+$ noun [path @] :: clam from %noun +$ noun [path $@(@ [@ta @])] :: clam from %noun
-- --
-- --

View File

@ -0,0 +1,46 @@
:: task: herm task for passthrough to dill
::
/- herm
/+ dill
::
|_ =task:herm
++ grad %noun
:: +grab: convert from
::
++ grab
|%
++ noun task:herm
::
++ json
|= jon=^json
^+ task
~| jon
?> ?=([%o *] jon)
=+ ses=(~(got by p.jon) 'session')
?> ?=([%s *] ses)
:- ?: =('' p.ses) %$
(slav %tas p.ses)
=. p.jon (~(del by p.jon) 'session')
%. jon
=, dejs:format
|^ task
++ task
%- of
:~ belt+belt:dejs:^dill
blew+(ot 'w'^ni 'h'^ni ~)
hail+ul
open+(ot 'term'^(se %tas) 'apps'^(ar gill) ~)
shut+ul
==
::
++ gill
(ot 'who'^(se %p) 'app'^(se %tas) ~)
--
--
:: +grow: convert to
::
++ grow
|%
++ noun task
--
--

9
pkg/arvo/sur/herm.hoon Normal file
View File

@ -0,0 +1,9 @@
:: herm: stand-in for term.c with http interface
::
|%
+$ task
$~ [%$ %hail ~]
$: session=@tas
task=$>(?(%open %shut %belt %blew %hail) session-task:dill)
==
--

View File

@ -1 +1 @@
[%zuse 417] [%zuse 415]

View File

@ -3,7 +3,7 @@
|% |%
+| %global +| %global
:: ::
++ arvo %240 ++ arvo %239
:: ::
:: $arch: node identity :: $arch: node identity
:: $axal: fundamental node, recursive (trie) :: $axal: fundamental node, recursive (trie)
@ -415,7 +415,7 @@
== ==
-- --
:: ::
:: |de: axal engine :: |of: axal engine
:: ::
++ of ++ of
=| fat=(axal) =| fat=(axal)

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
!: !:
=> ..part => ..part
|% |%
++ lull %328 ++ lull %326
:: :: :: :: :: ::
:::: :: :: (1) models :::: :: :: (1) models
:: :: :: :: :: ::
@ -360,6 +360,7 @@
:: %init: vane boot :: %init: vane boot
:: %prod: re-send a packet per flow, to all peers if .ships is ~ :: %prod: re-send a packet per flow, to all peers if .ships is ~
:: %sift: limit verbosity to .ships :: %sift: limit verbosity to .ships
:: %snub: set packet blacklist to .ships
:: %spew: set verbosity toggles :: %spew: set verbosity toggles
:: %trim: release memory :: %trim: release memory
:: %vega: kernel reload notification :: %vega: kernel reload notification
@ -375,6 +376,7 @@
$>(%init vane-task) $>(%init vane-task)
[%prod ships=(list ship)] [%prod ships=(list ship)]
[%sift ships=(list ship)] [%sift ships=(list ship)]
[%snub ships=(list ship)]
[%spew veb=(list verb)] [%spew veb=(list verb)]
[%stir arg=@t] [%stir arg=@t]
$>(%trim vane-task) $>(%trim vane-task)
@ -752,7 +754,6 @@
[%hill p=(list @tas)] :: mount points [%hill p=(list @tas)] :: mount points
[%done error=(unit error:ames)] :: ames message (n)ack [%done error=(unit error:ames)] :: ames message (n)ack
[%mere p=(each (set path) (pair term tang))] :: merge result [%mere p=(each (set path) (pair term tang))] :: merge result
[%note p=@tD q=tank] :: debug message
[%ogre p=@tas] :: delete mount point [%ogre p=@tas] :: delete mount point
[%rule red=dict wit=dict] :: node r+w permissions [%rule red=dict wit=dict] :: node r+w permissions
[%tire p=(each rock:tire wave:tire)] :: app state [%tire p=(each rock:tire wave:tire)] :: app state
@ -1160,9 +1161,7 @@
++ dill ^? ++ dill ^?
|% |%
+$ gift :: out result <-$ +$ gift :: out result <-$
$% [%bbye ~] :: reset prompt $% [%blit p=(list blit)] :: terminal output
[%blit p=(list blit)] :: terminal output
[%burl p=@t] :: activate url
[%logo ~] :: logout [%logo ~] :: logout
[%meld ~] :: unify memory [%meld ~] :: unify memory
[%pack ~] :: compact memory [%pack ~] :: compact memory
@ -1170,29 +1169,32 @@
== :: == ::
+$ task :: in request ->$ +$ task :: in request ->$
$~ [%vega ~] :: $~ [%vega ~] ::
$% [%belt p=belt] :: terminal input $% [%boot lit=? p=*] :: weird %dill boot
[%blew p=blew] :: terminal config
[%boot lit=? p=*] :: weird %dill boot
[%crop p=@ud] :: trim kernel state [%crop p=@ud] :: trim kernel state
[%crud p=@tas q=(list tank)] :: print error [%crud p=@tas q=(list tank)] :: print error
[%flee session=~] :: unwatch session
[%flog p=flog] :: wrapped error [%flog p=flog] :: wrapped error
[%flow p=@tas q=(list gill:gall)] :: terminal config
[%hail ~] :: terminal refresh
[%heft ~] :: memory report [%heft ~] :: memory report
[%hook ~] :: this term hung up
[%harm ~] :: all terms hung up
$>(%init vane-task) :: after gall ready $>(%init vane-task) :: after gall ready
[%meld ~] :: unify memory [%meld ~] :: unify memory
[%noop ~] :: no operation
[%pack ~] :: compact memory [%pack ~] :: compact memory
[%talk p=tank] :: [%shot ses=@tas task=session-task] :: task for session
[%text p=tape] :: [%talk p=(list tank)] :: print tanks
[%view session=~] :: watch session blits [%text p=tape] :: print tape
$>(%trim vane-task) :: trim state $>(%trim vane-task) :: trim state
$>(%vega vane-task) :: report upgrade $>(%vega vane-task) :: report upgrade
[%verb ~] :: verbose mode [%verb ~] :: verbose mode
[%knob tag=term level=?(%hush %soft %loud)] :: error verbosity [%knob tag=term level=?(%hush %soft %loud)] :: error verbosity
session-task :: for default session
== ::
:: ::
+$ session-task :: session request
$% [%belt p=belt] :: terminal input
[%blew p=blew] :: terminal config
[%flee ~] :: unwatch session
[%hail ~] :: terminal refresh
[%open p=dude:gall q=(list gill:gall)] :: setup session
[%shut ~] :: close session
[%view ~] :: watch session blits
== :: == ::
:: ::
:::: :: (1d2) :::: :: (1d2)
@ -1200,59 +1202,41 @@
+$ blew [p=@ud q=@ud] :: columns rows +$ blew [p=@ud q=@ud] :: columns rows
+$ belt :: client input +$ belt :: client input
$? bolt :: simple input $? bolt :: simple input
$% [%mod mod=?(%ctl %met %hyp) key=bolt] :: w/ modifier [%mod mod=?(%ctl %met %hyp) key=bolt] :: w/ modifier
[%txt p=(list @c)] :: utf32 text [%txt p=(list @c)] :: utf32 text
::TODO consider moving %hey, %rez, %yow here :: ::TODO consider moving %hey, %rez, %yow here ::
::TMP forward backwards-compatibility :: == ::
:: ::
[%ctl p=@c] ::
[%met p=@c] ::
== == ::
+$ bolt :: simple input +$ bolt :: simple input
$@ @c :: simple keystroke $@ @c :: simple keystroke
$% [%aro p=?(%d %l %r %u)] :: arrow key $% [%aro p=?(%d %l %r %u)] :: arrow key
[%bac ~] :: true backspace [%bac ~] :: true backspace
[%del ~] :: true delete [%del ~] :: true delete
[%hit r=@ud c=@ud] :: mouse click [%hit x=@ud y=@ud] :: mouse click
[%ret ~] :: return [%ret ~] :: return
== :: == ::
+$ blit :: old blit +$ blit :: client output
$% [%bel ~] :: make a noise $% [%bel ~] :: make a noise
[%clr ~] :: clear the screen [%clr ~] :: clear the screen
[%hop p=@ud] :: set cursor position [%hop p=$@(@ud [x=@ud y=@ud])] :: set cursor col/pos
[%klr p=stub] :: set styled line [%klr p=stub] :: put styled
[%lin p=(list @c)] :: set current line [%mor p=(list blit)] :: multiple blits
[%mor ~] :: newline [%nel ~] :: newline
[%put p=(list @c)] :: put text at cursor
[%sag p=path q=*] :: save to jamfile [%sag p=path q=*] :: save to jamfile
[%sav p=path q=@] :: save to file [%sav p=path q=@] :: save to file
[%url p=@t] :: activate url [%url p=@t] :: activate url
[%wyp ~] :: wipe cursor line
== :: == ::
+$ dill-belt :: new belt +$ dill-belt :: arvo input
$% [%aro p=?(%d %l %r %u)] :: arrow key $% belt :: client input
[%bac ~] :: true backspace
[%cru p=@tas q=(list tank)] :: echo error [%cru p=@tas q=(list tank)] :: echo error
[%ctl p=@] :: control-key
[%del ~] :: true delete
[%hey ~] :: refresh [%hey ~] :: refresh
[%met p=@] :: meta-key
[%ret ~] :: return
[%rez p=@ud q=@ud] :: resize, cols, rows [%rez p=@ud q=@ud] :: resize, cols, rows
[%txt p=(list @c)] :: utf32 text
[%yow p=gill:gall] :: connect to app [%yow p=gill:gall] :: connect to app
== :: == ::
+$ dill-blit :: new blit +$ dill-blit :: arvo output
$% [%bel ~] :: make a noise $% blit :: client output
[%clr ~] :: clear the screen
[%hop p=@ud] :: set cursor position
[%klr p=stub] :: styled text
[%mor p=(list dill-blit)] :: multiple blits
[%pom p=stub] :: styled prompt
[%pro p=(list @c)] :: show as cursor+line
[%qit ~] :: close console [%qit ~] :: close console
[%out p=(list @c)] :: send output line
[%sag p=path q=*] :: save to jamfile
[%sav p=path q=@] :: save to file
[%url p=@t] :: activate url
== :: == ::
+$ flog :: sent to %dill +$ flog :: sent to %dill
$% [%crop p=@ud] :: trim kernel state $% [%crop p=@ud] :: trim kernel state
@ -1263,6 +1247,11 @@
[%text p=tape] :: [%text p=tape] ::
[%verb ~] :: verbose mode [%verb ~] :: verbose mode
== :: == ::
:: ::
+$ poke :: dill to userspace
$: ses=@tas :: target session
dill-belt :: input
== ::
-- ::dill -- ::dill
:: :::: :: ::::
:::: ++eyre :: (1e) http-server :::: ++eyre :: (1e) http-server
@ -1763,7 +1752,6 @@
+$ gift :: outgoing result +$ gift :: outgoing result
$% [%boon payload=*] :: ames response $% [%boon payload=*] :: ames response
[%done error=(unit error:ames)] :: ames message (n)ack [%done error=(unit error:ames)] :: ames message (n)ack
[%onto p=(each suss tang)] :: about agent
[%unto p=unto] :: [%unto p=unto] ::
== :: == ::
+$ task :: incoming request +$ task :: incoming request
@ -2531,9 +2519,6 @@
:: %ames: hear packet :: %ames: hear packet
:: ::
$>(%hear task:ames) $>(%hear task:ames)
:: %dill: hangup
::
$>(%hook task:dill)
:: %clay: external edit :: %clay: external edit
:: ::
$>(%into task:clay) $>(%into task:clay)
@ -2554,6 +2539,9 @@
:: %eyre: starts handling an backdoor http request :: %eyre: starts handling an backdoor http request
:: ::
$>(%request-local task:eyre) $>(%request-local task:eyre)
:: %dill: close session
::
$>(%shut task:dill)
:: %behn: wakeup :: %behn: wakeup
:: ::
$>(%wake task:behn) $>(%wake task:behn)

View File

@ -607,19 +607,20 @@
:: life: our $life; how many times we've rekeyed :: life: our $life; how many times we've rekeyed
:: crypto-core: interface for encryption and signing :: crypto-core: interface for encryption and signing
:: bug: debug printing configuration :: bug: debug printing configuration
:: corks(STALE):wires for cork flows pending publisher update :: snub: blocklist for incoming packets
:: ::
:: Note: .corks is only still present for unreleased migration reasons :: Note: .corks is only still present for unreleased migration reasons
:: ::
::
+$ ames-state +$ ames-state
$: peers=(map ship ship-state) $: peers=(map ship ship-state)
=unix=duct =unix=duct
=life =life
crypto-core=acru:ames crypto-core=acru:ames
=bug =bug
corks=(set wire) ::TODO unused, remove in next version of state corks=(set wire)
snub=(set ship)
== ==
::
+$ ames-state-4 ames-state-5 +$ ames-state-4 ames-state-5
+$ ames-state-5 +$ ames-state-5
$: peers=(map ship ship-state-5) $: peers=(map ship ship-state-5)
@ -686,6 +687,17 @@
crypto-core=acru:ames crypto-core=acru:ames
=bug =bug
== ==
::
+$ ames-state-8
$: peers=(map ship ship-state)
=unix=duct
=life
crypto-core=acru:ames
=bug
corks=(set wire)
==
::
:: $bug: debug printing configuration :: $bug: debug printing configuration
:: ::
:: veb: verbosity toggles :: veb: verbosity toggles
@ -733,6 +745,7 @@
$% [%private-keys ~] $% [%private-keys ~]
[%public-keys ships=(set ship)] [%public-keys ships=(set ship)]
[%turf ~] [%turf ~]
[%ruin ships=(set ship)]
== == == ==
$: @tas $: @tas
$% [%plea =ship =plea] $% [%plea =ship =plea]
@ -841,7 +854,14 @@
:: ::
=< =* adult-gate . =< =* adult-gate .
=| queued-events=(qeu queued-event) =| queued-events=(qeu queued-event)
=| cached-state=(unit $%([%5 ames-state-5] [%6 ames-state-6] [%7 ames-state-7] [%8 ^ames-state])) =| $= cached-state
%- unit
$% [%5 ames-state-5]
[%6 ames-state-6]
[%7 ames-state-7]
[%8 ames-state-8]
[%9 ^ames-state]
==
:: ::
|= [now=@da eny=@ rof=roof] |= [now=@da eny=@ rof=roof]
=* larval-gate . =* larval-gate .
@ -963,7 +983,7 @@
:: lifecycle arms; mostly pass-throughs to the contained adult ames :: lifecycle arms; mostly pass-throughs to the contained adult ames
:: ::
++ scry scry:adult-core ++ scry scry:adult-core
++ stay [%8 %larva queued-events ames-state.adult-gate] ++ stay [%9 %larva queued-events ames-state.adult-gate]
++ load ++ load
|= $= old |= $= old
$% $: %4 $% $: %4
@ -995,6 +1015,13 @@
[%adult state=ames-state-7] [%adult state=ames-state-7]
== == == ==
$: %8 $: %8
$% $: %larva
events=(qeu queued-event)
state=ames-state-8
==
[%adult state=ames-state-8]
== ==
$: %9
$% $: %larva $% $: %larva
events=(qeu queued-event) events=(qeu queued-event)
state=_ames-state.adult-gate state=_ames-state.adult-gate
@ -1039,12 +1066,22 @@
=. queued-events events.old =. queued-events events.old
larval-gate larval-gate
:: ::
[%8 %adult *] (load:adult-core %8 state.old) [%8 %adult *]
=. cached-state `[%8 state.old]
~> %slog.0^leaf/"ames: larva reload"
larval-gate
:: ::
[%8 %larva *] [%8 %larva *]
~> %slog.0^leaf/"ames: larva: load"
=. queued-events events.old
larval-gate
::
[%9 %adult *] (load:adult-core %9 state.old)
::
[%9 %larva *]
~> %slog.1^leaf/"ames: larva: load" ~> %slog.1^leaf/"ames: larva: load"
=. queued-events events.old =. queued-events events.old
=. adult-gate (load:adult-core %8 state.old) =. adult-gate (load:adult-core %9 state.old)
larval-gate larval-gate
:: ::
== ==
@ -1063,7 +1100,9 @@
~> %slog.0^leaf/"ames: init daily recork timer" ~> %slog.0^leaf/"ames: init daily recork timer"
:- [[/ames]~ %pass /recork %b %wait `@da`(add now ~d1)]~ :- [[/ames]~ %pass /recork %b %wait `@da`(add now ~d1)]~
8+(state-7-to-8:load:adult-core +.u.cached-state) 8+(state-7-to-8:load:adult-core +.u.cached-state)
?> ?=(%8 -.u.cached-state) =? u.cached-state ?=(%8 -.u.cached-state)
9+(state-8-to-9:load:adult-core +.u.cached-state)
?> ?=(%9 -.u.cached-state)
=. ames-state.adult-gate +.u.cached-state =. ames-state.adult-gate +.u.cached-state
[moz larval-core(cached-state ~)] [moz larval-core(cached-state ~)]
-- --
@ -1102,6 +1141,7 @@
%jilt (on-jilt:event-core ship.task) %jilt (on-jilt:event-core ship.task)
%prod (on-prod:event-core ships.task) %prod (on-prod:event-core ships.task)
%sift (on-sift:event-core ships.task) %sift (on-sift:event-core ships.task)
%snub (on-snub:event-core ships.task)
%spew (on-spew:event-core veb.task) %spew (on-spew:event-core veb.task)
%stir (on-stir:event-core arg.task) %stir (on-stir:event-core arg.task)
%trim on-trim:event-core %trim on-trim:event-core
@ -1138,15 +1178,15 @@
[moves ames-gate] [moves ames-gate]
:: +stay: extract state before reload :: +stay: extract state before reload
:: ::
++ stay [%8 %adult ames-state] ++ stay [%9 %adult ames-state]
:: +load: load in old state after reload :: +load: load in old state after reload
:: ::
++ load ++ load
=< |= $= old-state =< |= $= old-state
$% [%8 ^ames-state] $% [%9 ^ames-state]
== ==
^+ ames-gate ^+ ames-gate
?> ?=(%8 -.old-state) ?> ?=(%9 -.old-state)
ames-gate(ames-state +.old-state) ames-gate(ames-state +.old-state)
:: ::
|% |%
@ -1210,7 +1250,7 @@
:: ::
++ state-7-to-8 ++ state-7-to-8
|= ames-state=ames-state-7 |= ames-state=ames-state-7
^- ^^ames-state ^- ames-state-8
:* peers.ames-state :* peers.ames-state
unix-duct.ames-state unix-duct.ames-state
life.ames-state life.ames-state
@ -1218,6 +1258,17 @@
bug.ames-state bug.ames-state
*(set wire) *(set wire)
== ==
++ state-8-to-9
|= ames-state=ames-state-8
^- ^^ames-state
:* peers.ames-state
unix-duct.ames-state
life.ames-state
crypto-core.ames-state
bug.ames-state
corks.ames-state
*(set ship)
==
-- --
:: +scry: dereference namespace :: +scry: dereference namespace
:: ::
@ -1247,7 +1298,7 @@
=(%$ syd) =(%$ syd)
== ==
?. for.veb.bug.ames-state ~ ?. for.veb.bug.ames-state ~
~> %slog.0^leaf/"ames: scry-fail {<[why=why lot=lot now=now syd=syd]>}" ~> %slog.0^leaf/"ames: scry-fail {<why=why lot=lot now=now syd=syd>}"
~ ~
:: /ax/protocol/version @ :: /ax/protocol/version @
:: /ax/peers (map ship ?(%alien %known)) :: /ax/peers (map ship ?(%alien %known))
@ -1430,6 +1481,13 @@
^+ event-core ^+ event-core
=. ships.bug.ames-state (sy ships) =. ships.bug.ames-state (sy ships)
event-core event-core
:: +on-snub: handle request to change ship blacklist
::
++ on-snub
|= ships=(list ship)
^+ event-core
=. snub.ames-state (sy ships)
event-core
:: +on-spew: handle request to set verbosity toggles on debug output :: +on-spew: handle request to set verbosity toggles on debug output
:: ::
++ on-spew ++ on-spew
@ -1561,11 +1619,13 @@
~/ %on-hear-packet ~/ %on-hear-packet
|= [=lane =packet dud=(unit goof)] |= [=lane =packet dud=(unit goof)]
^+ event-core ^+ event-core
%- %^ trace odd.veb sndr.packet %- (trace odd.veb sndr.packet |.("received packet"))
|.("received packet")
:: ::
?: =(our sndr.packet) ?: =(our sndr.packet)
event-core event-core
?: (~(has in snub.ames-state) sndr.packet)
%- (trace rcv.veb sndr.packet |.("snubbed"))
event-core
:: ::
%. +< %. +<
:: ::
@ -1774,28 +1834,30 @@
|. ^- tape |. ^- tape
=/ sndr [our our-life.channel] =/ sndr [our our-life.channel]
=/ rcvr [ship her-life.channel] =/ rcvr [ship her-life.channel]
"plea {<sndr^rcvr^bone=bone^vane.plea^path.plea>}" "plea {<sndr rcvr bone=bone vane.plea path.plea>}"
abet:(on-memo:(make-peer-core peer-state channel) bone plea %plea) abet:(on-memo:(make-peer-core peer-state channel) bone plea %plea)
:: +on-cork: handle request to kill a flow :: +on-cork: handle request to kill a flow
:: ::
++ on-cork ++ on-cork
|= =ship |= =ship
^+ event-core ^+ event-core
=/ =plea [%$ /flow [%cork ~]]
=/ ship-state (~(get by peers.ames-state) ship) =/ ship-state (~(get by peers.ames-state) ship)
:: ?. ?=([~ %known *] ship-state)
?> ?=([~ %known *] ship-state) %+ enqueue-alien-todo ship
|= todos=alien-agenda
todos(messages [[duct plea] messages.todos])
=/ =peer-state +.u.ship-state =/ =peer-state +.u.ship-state
=/ =channel [[our ship] now channel-state -.peer-state] =/ =channel [[our ship] now channel-state -.peer-state]
:: ::
=^ =bone ossuary.peer-state (bind-duct ossuary.peer-state duct) =^ =bone ossuary.peer-state (bind-duct ossuary.peer-state duct)
=/ =plea [%$ /flow [%cork ~]]
:: ::
=. closing.peer-state (~(put in closing.peer-state) bone) =. closing.peer-state (~(put in closing.peer-state) bone)
%- %^ trace msg.veb ship %- %^ trace msg.veb ship
|. ^- tape |. ^- tape
=/ sndr [our our-life.channel] =/ sndr [our our-life.channel]
=/ rcvr [ship her-life.channel] =/ rcvr [ship her-life.channel]
"cork plea {<sndr^rcvr^bone=bone^vane.plea^path.plea>}" "cork plea {<sndr rcvr bone=bone vane.plea path.plea>}"
abet:(on-memo:(make-peer-core peer-state channel) bone plea %plea) abet:(on-memo:(make-peer-core peer-state channel) bone plea %plea)
:: +on-take-wake: receive wakeup or error notification from behn :: +on-take-wake: receive wakeup or error notification from behn
:: ::
@ -1923,14 +1985,14 @@
:: we shouldn't be hearing about ships we don't care about :: we shouldn't be hearing about ships we don't care about
:: ::
?~ ship-state ?~ ship-state
~> %slog.0^leaf/"ames: breach unknown {<our^ship>}" ~> %slog.0^leaf/"ames: breach unknown {<our ship>}"
event-core event-core
:: if an alien breached, this doesn't affect us :: if an alien breached, this doesn't affect us
:: ::
?: ?=([~ %alien *] ship-state) ?: ?=([~ %alien *] ship-state)
~> %slog.0^leaf/"ames: breach alien {<our^ship>}" ~> %slog.0^leaf/"ames: breach alien {<our ship>}"
event-core event-core
~> %slog.0^leaf/"ames: breach peer {<our^ship>}" ~> %slog.0^leaf/"ames: breach peer {<our ship>}"
:: a peer breached; drop messaging state :: a peer breached; drop messaging state
:: ::
=/ =peer-state +.u.ship-state =/ =peer-state +.u.ship-state
@ -2063,6 +2125,8 @@
=. event-core =. event-core
%+ reel messages.todos %+ reel messages.todos
|= [[=^duct =plea] core=_event-core] |= [[=^duct =plea] core=_event-core]
?: ?=(%$ -.plea)
(on-cork:core(duct duct) ship)
(on-plea:core(duct duct) ship plea) (on-plea:core(duct duct) ship plea)
:: apply outgoing packet blobs :: apply outgoing packet blobs
:: ::
@ -2141,10 +2205,27 @@
:: ::
(emit unix-duct.ames-state %give %turf turfs) (emit unix-duct.ames-state %give %turf turfs)
:: +on-vega: handle kernel reload :: +on-vega: handle kernel reload
:: +on-trim: handle request to free memory
:: ::
++ on-vega event-core ++ on-vega event-core
++ on-trim event-core :: +on-trim: handle request to free memory
::
:: %ruin comets not seen for six months
::
++ on-trim
^+ event-core
=; rui=(set @p)
(emit duct %pass /ruin %j %ruin rui)
=- (silt (turn - head))
%+ skim
~(tap by peers.ames-state)
|= [=ship s=ship-state]
?. &(?=(%known -.s) =(%pawn (clan:title ship))) %.n
?& (gth (sub now ~d180) last-contact.qos.s)
::
%- ~(any by snd.s)
|= m=message-pump-state
!=(~ unsent-fragments.m)
==
:: +enqueue-alien-todo: helper to enqueue a pending request :: +enqueue-alien-todo: helper to enqueue a pending request
:: ::
:: Also requests key and life from Jael on first request. :: Also requests key and life from Jael on first request.
@ -2590,12 +2671,12 @@
=(~ unsent-fragments.pum) =(~ unsent-fragments.pum)
=(~ live.packet-pump-state.pum) =(~ live.packet-pump-state.pum)
== ==
~> %slog.0^leaf/"ames: bad pump state {<[her.channel i.boz]>}" ~> %slog.0^leaf/"ames: bad pump state {<her.channel i.boz>}"
$(boz t.boz) $(boz t.boz)
:: no outstanding messages, so send a new %cork :: no outstanding messages, so send a new %cork
:: ::
:: TODO use +trace :: TODO use +trace
~> %slog.0^leaf/"ames: recork {<[her.channel i.boz]>}" ~> %slog.0^leaf/"ames: recork {<her.channel i.boz>}"
=/ =plea [%$ /flow [%cork ~]] =/ =plea [%$ /flow [%cork ~]]
(on-memo i.boz plea %plea) (on-memo i.boz plea %plea)
:: +got-duct: look up $duct by .bone, asserting already bound :: +got-duct: look up $duct by .bone, asserting already bound
@ -2768,11 +2849,18 @@
:: ::
(emit [/ames]~ %pass wire %b %rest next-wake) (emit [/ames]~ %pass wire %b %rest next-wake)
=/ nax-bone=^bone (mix 0b10 bone) =/ nax-bone=^bone (mix 0b10 bone)
=? peer-core (~(has by snd.peer-state) nax-bone)
%. peer-core
%+ trace odd.veb
=/ dat [her.channel bone=nax-bone message-num=message-num -.task]
|.("remove naxplanation flow {<dat>}")
=. peer-state =. peer-state
=, peer-state =, peer-state
%_ peer-state %_ peer-state
:: preemptively delete nax flows (e.g. nacks for initial %watches)
::
snd (~(del by (~(del by snd) bone)) nax-bone)
rcv (~(del by rcv) bone) rcv (~(del by rcv) bone)
snd (~(del by snd) bone)
corked (~(put in corked) bone) corked (~(put in corked) bone)
closing (~(del in closing) bone) closing (~(del in closing) bone)
krocs (~(del in krocs) bone) krocs (~(del in krocs) bone)
@ -3196,9 +3284,14 @@
++ packet-queue ++ packet-queue
%- (ordered-map live-packet-key live-packet-val) %- (ordered-map live-packet-key live-packet-val)
lte-packets lte-packets
:: +live-packets: number of sent packets awaiting ack
::
++ live-packets
^- @ud
~(wyt by live.state)
:: +gauge: inflate a |pump-gauge to track congestion control :: +gauge: inflate a |pump-gauge to track congestion control
:: ::
++ gauge (make-pump-gauge now.channel metrics.state [her bug]:channel) ++ gauge (make-pump-gauge metrics.state live-packets [now her bug]:channel)
:: +work: handle $packet-pump-task request :: +work: handle $packet-pump-task request
:: ::
++ work ++ work
@ -3253,7 +3346,7 @@
=? packet-pump ?=(^ static-fragment) =? packet-pump ?=(^ static-fragment)
%- %+ trace snd.veb %- %+ trace snd.veb
=/ nums [message-num fragment-num]:u.static-fragment.res =/ nums [message-num fragment-num]:u.static-fragment.res
|.("dead {<nums^show:gauge>}") |.("dead {<nums show:gauge>}")
(give %send u.static-fragment.res) (give %send u.static-fragment.res)
packet-pump packet-pump
:: ::
@ -3312,7 +3405,6 @@
:: update .live and .metrics :: update .live and .metrics
:: ::
=. live.state (gas:packet-queue live.state send-list) =. live.state (gas:packet-queue live.state send-list)
=. metrics.state (on-sent:gauge (lent send-list))
:: TMI :: TMI
:: ::
=> .(sent `(list static-fragment)`sent) => .(sent `(list static-fragment)`sent)
@ -3374,7 +3466,7 @@
=(0 (mod counter.metrics.state 20)) =(0 (mod counter.metrics.state 20))
== ==
same same
(trace snd.veb |.("send: {<[fragment=fragment-num show:gauge]>}")) (trace snd.veb |.("send: {<fragment=fragment-num show:gauge>}"))
:: .resends is backward, so fold backward and emit :: .resends is backward, so fold backward and emit
:: ::
=. packet-pump =. packet-pump
@ -3398,7 +3490,7 @@
== ==
^- [new-val=(unit live-packet-val) stop=? _acc] ^- [new-val=(unit live-packet-val) stop=? _acc]
:: ::
=/ gauge (make-pump-gauge now.channel metrics.acc [her bug]:channel) =/ gauge (make-pump-gauge metrics.acc live-packets [now her bug]:channel)
:: is this the acked packet? :: is this the acked packet?
:: ::
?: =(key [message-num fragment-num]) ?: =(key [message-num fragment-num])
@ -3433,7 +3525,7 @@
=- =. metrics.state metrics.- =- =. metrics.state metrics.-
=. live.state live.- =. live.state live.-
:: ::
%- (trace snd.veb |.("done {<message-num=message-num^show:gauge>}")) %- (trace snd.veb |.("done {<message-num=message-num show:gauge>}"))
(fast-resend-after-ack message-num `fragment-num`0) (fast-resend-after-ack message-num `fragment-num`0)
:: ::
^+ [metrics=metrics.state live=live.state] ^+ [metrics=metrics.state live=live.state]
@ -3445,7 +3537,7 @@
== ==
^- [new-val=(unit live-packet-val) stop=? pump-metrics] ^- [new-val=(unit live-packet-val) stop=? pump-metrics]
:: ::
=/ gauge (make-pump-gauge now.channel metrics [her bug]:channel) =/ gauge (make-pump-gauge metrics live-packets [now her bug]:channel)
:: if we get an out-of-order ack for a message, skip until it :: if we get an out-of-order ack for a message, skip until it
:: ::
?: (lth message-num.key message-num) ?: (lth message-num.key message-num)
@ -3493,9 +3585,10 @@
:: +make-pump-gauge: construct |pump-gauge congestion control core :: +make-pump-gauge: construct |pump-gauge congestion control core
:: ::
++ make-pump-gauge ++ make-pump-gauge
|= [now=@da pump-metrics =ship =bug] |= [pump-metrics live-packets=@ud now=@da =ship =bug]
:: TODO rename live-packets num-live
=* veb veb.bug =* veb veb.bug
=* metrics +<+< =* metrics +<-
|% |%
++ trace ++ trace
|= [verb=? print=(trap tape)] |= [verb=? print=(trap tape)]
@ -3515,15 +3608,7 @@
:: ::
++ num-slots ++ num-slots
^- @ud ^- @ud
(sub-safe cwnd num-live) (sub-safe cwnd live-packets)
:: +on-sent: adjust metrics based on sending .num-sent fresh packets
::
++ on-sent
|= num-sent=@ud
^- pump-metrics
::
=. num-live (add num-live num-sent)
metrics
:: +on-ack: adjust metrics based on a packet getting acknowledged :: +on-ack: adjust metrics based on a packet getting acknowledged
:: ::
++ on-ack ++ on-ack
@ -3531,7 +3616,6 @@
^- pump-metrics ^- pump-metrics
:: ::
=. counter +(counter) =. counter +(counter)
=. num-live (dec num-live)
:: if below congestion threshold, add 1; else, add avg. 1 / cwnd :: if below congestion threshold, add 1; else, add avg. 1 / cwnd
:: ::
=. cwnd =. cwnd
@ -3571,7 +3655,7 @@
:: ::
=? cwnd !in-recovery (max 2 (div cwnd 2)) =? cwnd !in-recovery (max 2 (div cwnd 2))
%- %+ trace snd.veb %- %+ trace snd.veb
|.("skip {<[resend=resend in-recovery=in-recovery show]>}") |.("skip {<resend=resend in-recovery=in-recovery show>}")
metrics metrics
:: +on-timeout: (re)enter slow-start mode on packet loss :: +on-timeout: (re)enter slow-start mode on packet loss
:: ::
@ -3597,12 +3681,12 @@
(lth cwnd ssthresh) (lth cwnd ssthresh)
:: +in-recovery: %.y iff we're recovering from a skipped packet :: +in-recovery: %.y iff we're recovering from a skipped packet
:: ::
:: We finish recovering when .num-live finally dips back down to :: We finish recovering when .live-packets finally dips back down to
:: .cwnd. :: .cwnd.
:: ::
++ in-recovery ++ in-recovery
^- ? ^- ?
(gth num-live cwnd) (gth live-packets cwnd)
:: +sub-safe: subtract with underflow protection :: +sub-safe: subtract with underflow protection
:: ::
++ sub-safe ++ sub-safe
@ -3619,7 +3703,7 @@
rttvar=(div rttvar ms) rttvar=(div rttvar ms)
ssthresh=ssthresh ssthresh=ssthresh
cwnd=cwnd cwnd=cwnd
num-live=num-live num-live=live-packets
counter=counter counter=counter
== ==
-- --
@ -3665,7 +3749,7 @@
:: ::
?: (gte seq (add 10 last-acked.state)) ?: (gte seq (add 10 last-acked.state))
%- %+ trace odd.veb %- %+ trace odd.veb
|.("future %hear {<seq=seq^last-acked=last-acked.state>}") |.("future %hear {<seq=seq last-acked=last-acked.state>}")
message-sink message-sink
:: ::
=/ is-last-fragment=? =(+(fragment-num) num-fragments) =/ is-last-fragment=? =(+(fragment-num) num-fragments)
@ -3676,7 +3760,7 @@
:: single packet ack :: single packet ack
:: ::
%- %+ trace rcv.veb %- %+ trace rcv.veb
|.("send dupe ack {<seq=seq^fragment-num=fragment-num>}") |.("send dupe ack {<seq=seq fragment-num>}")
(give %send seq %& fragment-num) (give %send seq %& fragment-num)
:: whole message (n)ack :: whole message (n)ack
:: ::
@ -3696,8 +3780,8 @@
%- %+ trace rcv.veb %- %+ trace rcv.veb
|. ^- tape |. ^- tape
=/ data =/ data
:* her.channel seq=seq bone=bone :* her.channel seq=seq bone=bone.shut-packet
fragment-num=fragment-num num-fragments=num-fragments fragment-num num-fragments
la=last-acked.state lh=last-heard.state la=last-acked.state lh=last-heard.state
== ==
"hear last in-progress {<data>}" "hear last in-progress {<data>}"
@ -3706,8 +3790,8 @@
:: ::
%- %+ trace rcv.veb |. %- %+ trace rcv.veb |.
=/ data =/ data
:* seq=seq fragment-num=fragment-num :* seq=seq fragment-num
num-fragments=num-fragments closing=closing num-fragments closing=closing
== ==
"send ack-1 {<data>}" "send ack-1 {<data>}"
(give %send seq %& fragment-num) (give %send seq %& fragment-num)
@ -3737,7 +3821,7 @@
"hear last dupe {<data>}" "hear last dupe {<data>}"
message-sink message-sink
%- %+ trace rcv.veb %- %+ trace rcv.veb
|.("send dupe ack {<her.channel^seq=seq^fragment-num=fragment-num>}") |.("send dupe ack {<her.channel seq=seq fragment-num>}")
(give %send seq %& fragment-num) (give %send seq %& fragment-num)
:: new fragment; store in state and check if message is done :: new fragment; store in state and check if message is done
:: ::
@ -3754,7 +3838,7 @@
=? message-sink !is-last-fragment =? message-sink !is-last-fragment
%- %+ trace rcv.veb |. %- %+ trace rcv.veb |.
=/ data =/ data
[seq=seq fragment-num=fragment-num num-fragments=num-fragments] [seq=seq fragment-num num-fragments]
"send ack-2 {<data>}" "send ack-2 {<data>}"
(give %send seq %& fragment-num) (give %send seq %& fragment-num)
:: enqueue all completed messages starting at +(last-heard.state) :: enqueue all completed messages starting at +(last-heard.state)

View File

@ -432,7 +432,10 @@
task :: task ::
== :: == ::
$: %d :: to %dill $: %d :: to %dill
$>(%flog task:dill) :: $> $? %flog ::
%text ::
== ::
task:dill ::
== :: == ::
$: %g :: to %gall $: %g :: to %gall
$> $? %deal $> $? %deal
@ -460,14 +463,13 @@
== == :: == == ::
$: %clay :: $: %clay ::
$> $? %mere :: $> $? %mere ::
%note ::
%writ :: %writ ::
%wris ::
== :: == ::
gift :: gift ::
== :: == ::
$: %gall $: %gall
$> $? %onto $> $? %unto
%unto
== ==
gift:gall gift:gall
== ==
@ -2209,7 +2211,8 @@
|= [prefix=@tD paths=(set path)] |= [prefix=@tD paths=(set path)]
%+ turn ~(tap in paths) %+ turn ~(tap in paths)
|= =path |= =path
[u.hun %give %note prefix (path-to-tank path)] ^- move
[u.hun %pass /note %d %text prefix ' ' ~(ram re (path-to-tank path))]
:: ::
++ path-to-tank ++ path-to-tank
|= =path |= =path
@ -5774,8 +5777,6 @@
?^ dud ?^ dud
~|(%clay-take-dud (mean tang.u.dud)) ~|(%clay-take-dud (mean tang.u.dud))
?: ?=([%lu %load *] tea) ?: ?=([%lu %load *] tea)
?: ?=(%onto +<.hin)
[~ ..^$]
?> ?=(%unto +<.hin) ?> ?=(%unto +<.hin)
?> ?=(%poke-ack -.p.hin) ?> ?=(%poke-ack -.p.hin)
?~ p.p.hin ?~ p.p.hin
@ -5822,6 +5823,7 @@
[mos ..^$] [mos ..^$]
:: ::
?: ?=([%foreign-warp *] tea) ?: ?=([%foreign-warp *] tea)
?: ?=(%wris +<.hin) ~& %dropping-wris `..^$
?> ?=(%writ +<.hin) ?> ?=(%writ +<.hin)
:_ ..^$ :_ ..^$
[hen %give %boon `(unit rand)`(bind `riot`p.hin rant-to-rand)]~ [hen %give %boon `(unit rand)`(bind `riot`p.hin rant-to-rand)]~
@ -5950,7 +5952,6 @@
q.p.p.+.hin q.p.p.+.hin
[~ ..^$] [~ ..^$]
:: ::
%note [[hen %give +.hin]~ ..^$]
%wake %wake
:: TODO: handle behn errors :: TODO: handle behn errors
:: ::
@ -5973,8 +5974,8 @@
:: ::
%boon !! %boon !!
%lost !! %lost !!
%onto !!
%unto !! %unto !!
%wris ~& %strange-wris !!
%writ %writ
%- (slog leaf+"clay: strange writ (expected on upgrade to Fusion)" ~) %- (slog leaf+"clay: strange writ (expected on upgrade to Fusion)" ~)
[~ ..^$] [~ ..^$]

View File

@ -8,27 +8,26 @@
-- :: -- ::
=> |% :: console protocol => |% :: console protocol
+$ axle :: +$ axle ::
$: %4 ::TODO replace ducts with session ids :: $: %6 ::
hey=(unit duct) :: default duct hey=(unit duct) :: default duct
dug=(map duct axon) :: conversations dug=(map @tas axon) :: conversations
eye=(jug duct duct) :: outside listeners eye=(jug @tas duct) :: outside listeners
lit=? :: boot in lite mode lit=? :: boot in lite mode
$= veb :: vane verbosities $= veb :: vane verbosities
$~ (~(put by *(map @tas log-level)) %hole %soft) :: quiet packet crashes $~ (~(put by *(map @tas log-level)) %hole %soft) :: quiet packet crashes
(map @tas log-level) :: (map @tas log-level) ::
egg=_| :: see +take, removeme
== :: == ::
+$ axon :: dill per duct +$ axon :: dill session
$: ram=term :: console program $: ram=term :: console program
tem=(unit (list dill-belt)) :: pending, reverse tem=(unit (list dill-belt)) :: pending, reverse
wid=_80 :: terminal width wid=_80 :: terminal width
pos=@ud :: cursor position
see=$%([%lin (list @c)] [%klr stub]) :: current line
== :: == ::
+$ log-level ?(%hush %soft %loud) :: none, line, full +$ log-level ?(%hush %soft %loud) :: none, line, full
-- => :: -- => ::
|% :: protocol outward |% :: protocol outward
+$ mess :: +$ mess ::
$% [%dill-belt p=(hypo dill-belt)] :: $% [%dill-poke p=(hypo poke)] ::
== :: == ::
+$ move [p=duct q=(wind note gift)] :: local move +$ move [p=duct q=(wind note gift)] :: local move
+$ note :: out request $-> +$ note :: out request $->
@ -69,7 +68,6 @@
== == :: == == ::
$: %clay :: $: %clay ::
$> $? %mere :: $> $? %mere ::
%note ::
%writ :: %writ ::
== :: == ::
gift:clay :: gift:clay ::
@ -78,10 +76,7 @@
$>(%blit gift:dill) :: $>(%blit gift:dill) ::
== :: == ::
$: %gall :: $: %gall ::
$> $? %onto :: $>(%unto gift:gall) ::
%unto ::
== ::
gift:gall ::
== == :: == == ::
:::::::: :: dill tiles :::::::: :: dill tiles
-- --
@ -91,39 +86,27 @@
|% |%
++ as :: per cause ++ as :: per cause
=| moz=(list move) =| moz=(list move)
|_ [hen=duct axon] |_ [hen=duct ses=@tas axon]
++ abet :: resolve ++ abet :: resolve
^- [(list move) axle] ^- [(list move) axle]
[(flop moz) all(dug (~(put by dug.all) hen +<+))] [(flop moz) all(dug (~(put by dug.all) ses +<+>))]
:: ::
++ call :: receive input ++ call :: receive input
|= kyz=task |= kyz=task
^+ +> ^+ +>
?+ -.kyz ~& [%strange-kiss -.kyz] +> ?+ -.kyz ~& [%strange-kiss -.kyz] +>
%flow +> %hail (send %hey ~)
%harm +> %belt (send `dill-belt`p.kyz)
%hail (send %hey ~) %talk (talk p.kyz)
%text (from %out (tuba p.kyz)) %text (fore (tuba p.kyz) ~)
%crud :: (send `dill-belt`[%cru p.kyz q.kyz]) %crud :: (send `dill-belt`[%cru p.kyz q.kyz])
(crud p.kyz q.kyz) (crud p.kyz q.kyz)
%blew (send %rez p.p.kyz q.p.kyz) %blew (send(wid p.p.kyz) %rez p.p.kyz q.p.kyz)
%heft (pass /whey %$ whey/~) %heft (pass /whey %$ whey/~)
%meld (dump kyz) %meld (dump kyz)
%pack (dump kyz) %pack (dump kyz)
%crop (dump trim+p.kyz) %crop (dump trim+p.kyz)
%verb (pass /verb %$ kyz) %verb (pass /verb %$ kyz)
%noop +>
%belt
%- send
::TMP forwards compatibility with next-dill
::
?@ p.kyz [%txt p.kyz ~]
?: ?=(%hit -.p.kyz) [%txt ~]
?. ?=(%mod -.p.kyz) p.kyz
=/ =@c
?@ key.p.kyz key.p.kyz
?:(?=(?(%bac %del %ret) -.key.p.kyz) `@`-.key.p.kyz ~-)
?:(?=(%met mod.p.kyz) [%met c] [%ctl c])
== ==
:: ::
++ crud ++ crud
@ -133,30 +116,30 @@
=/ lev=log-level (~(gut by veb.all) err %loud) =/ lev=log-level (~(gut by veb.all) err %loud)
:: apply log level for this error tag :: apply log level for this error tag
:: ::
=/ =wall ?- lev
?- lev %hush +>.$
%hush ~ %soft (fore (tuba "crud: %{(trip err)} event failed") ~)
%soft ~["crud: %{(trip err)} event failed"] %loud (talk leaf+"crud: %{(trip err)} event failed" (flop tac))
%loud :- "crud: %{(trip err)} event failed" ==
%- zing ::
%+ turn (flop tac) ++ talk
|=(a=tank (~(win re a) [0 wid])) |= tac=(list tank)
== %- fore
|- ^+ +>.^$ %- zing
?~ wall +>.^$ %+ turn tac
$(wall t.wall, +>.^$ (from %out (tuba i.wall))) |= a=tank
(turn (~(win re a) [0 wid]) tuba)
:: ::
++ dump :: pass down to hey ++ dump :: pass down to hey
|= git=gift |= git=gift
?> ?=(^ hey.all) ?> ?=(^ hey.all)
+>(moz [[u.hey.all %give git] moz]) +>(moz [[u.hey.all %give git] moz])
:: ::
++ done :: return gift ++ done :: gift to viewers
|= git=gift |= git=gift
=- +>.$(moz (weld - moz)) =- +>.$(moz (weld - moz))
%+ turn %+ turn
:- hen ~(tap in (~(get ju eye.all) ses))
~(tap in (~(get ju eye.all) hen))
|=(=duct [duct %give git]) |=(=duct [duct %give git])
:: ::
++ deal :: pass to %gall ++ deal :: pass to %gall
@ -167,44 +150,37 @@
|= [=wire =note] |= [=wire =note]
+>(moz :_(moz [hen %pass wire note])) +>(moz :_(moz [hen %pass wire note]))
:: ::
++ fore :: send dill output
::NOTE there are still implicit assumptions
:: about the underlying console app's
:: semantics here. specifically, trailing
:: newlines are important to not getting
:: overwritten by the drum prompt, and a
:: bottom-of-screen cursor position gives
:: nicest results. a more agnostic solution
:: will need to replace this arm, someday.
:: perhaps +send this to .ram instead?
::
|= liz=(list (list @c))
~? !=(%$ ses) [%d %foreing-in-session ses]
^+ +>
=. +>
=| biz=(list blit)
|- ^+ +>.^$
?~ liz (done %blit [%hop 0] [%wyp ~] biz)
$(liz t.liz, biz (welp biz [%put i.liz] [%nel ~] ~))
:: since dill is acting on its own accord,
:: we %hey the term app so it may clean up.
::
(send %hey ~)
::
++ from :: receive blit ++ from :: receive blit
|= bit=dill-blit |= bit=dill-blit
^+ +> ^+ +>
?: ?=(%mor -.bit)
|- ^+ +>.^$
?~ p.bit +>.^$
$(p.bit t.p.bit, +>.^$ ^$(bit i.p.bit))
?: ?=(%out -.bit)
%+ done %blit
:~ [%lin p.bit]
[%mor ~]
see
[%hop pos]
==
?: ?=(%klr -.bit)
%+ done %blit
:~ [%klr p.bit]
[%mor ~]
see
[%hop pos]
==
?: ?=(%pro -.bit)
=. see [%lin p.bit]
(done %blit [see [%hop pos] ~])
?: ?=(%pom -.bit)
::NOTE treat "styled prompt" without style as plain prompt,
:: to allow rendering by older runtimes
::TODO remove me once v0.10.9+ has high/guaranteed adoption
::
?: (levy p.bit (cork head |*(s=stye =(*stye s))))
$(bit [%pro (zing (turn p.bit tail))])
=. see [%klr p.bit]
(done %blit [see [%hop pos] ~])
?: ?=(%hop -.bit)
(done(pos p.bit) %blit [bit ~])
?: ?=(%qit -.bit) ?: ?=(%qit -.bit)
(dump %logo ~) (dump %logo ~)
(done %blit [bit ~]) ::TODO so why is this a (list blit) again?
(done %blit bit ~)
:: ::
++ sponsor ++ sponsor
^- ship ^- ship
@ -221,7 +197,7 @@
=. tem ~ =. tem ~
=. ..mere (pass /zest %c %zest %base %live) =. ..mere (pass /zest %c %zest %base %live)
=. ..mere (show-desk %kids) =. ..mere (show-desk %kids)
=. ..mere drum-watch =. ..mere (open ~)
|- ^+ ..mere |- ^+ ..mere
?~ myt ..mere ?~ myt ..mere
$(myt t.myt, ..mere (send i.myt)) $(myt t.myt, ..mere (send i.myt))
@ -231,15 +207,27 @@
=. tem `(turn gyl |=(a=gill [%yow a])) =. tem `(turn gyl |=(a=gill [%yow a]))
(pass / [%c %warp our %base `[%sing %y [%ud 1] /]]) (pass / [%c %warp our %base `[%sing %y [%ud 1] /]])
:: ::
++ open
|= gyl=(list gill)
::TODO should allow handlers from non-base desks
::TODO maybe ensure :ram is running?
=. +> peer
%+ roll gyl
|= [g=gill _..open]
(send [%yow g])
::
++ send :: send action ++ send :: send action
|= bet=dill-belt |= bet=dill-belt
^+ +> ^+ +>
?^ tem ?^ tem
+>(tem `[bet u.tem]) +>(tem `[bet u.tem])
(deal / [%poke [%dill-belt -:!>(bet) bet]]) (deal /send/[ses] [%poke [%dill-poke !>([ses bet])]])
:: ::
++ drum-watch ++ peer
(deal / [%watch /drum]) (deal /peer/[ses] %watch /dill/[ses])
::
++ pull
(deal /peer/[ses] %leave ~)
:: ::
++ show-desk :: permit reads on desk ++ show-desk :: permit reads on desk
|= des=desk |= des=desk
@ -249,21 +237,11 @@
|= [tea=wire sih=sign] |= [tea=wire sih=sign]
^+ +> ^+ +>
?- sih ?- sih
[%gall %onto *]
:: NOTE effects during initial boot sequence are ignored,
:: so :hood compilation errors will not print; slog if desired
::
:: ~& [%take-gall-onto +>.sih]
?- -.+>.sih
%| (crud %onto p.p.+>.sih)
%& (done %blit [%lin (tuba "{<p.p.sih>}")]~)
==
::
[%gall %unto *] [%gall %unto *]
:: ~& [%take-gall-unto +>.sih] :: ~& [%take-gall-unto +>.sih]
?- -.+>.sih ?- -.+>.sih
%raw-fact !! %raw-fact !!
%kick drum-watch %kick peer
%poke-ack ?~(p.p.+>.sih +>.$ (crud %coup u.p.p.+>.sih)) %poke-ack ?~(p.p.+>.sih +>.$ (crud %coup u.p.p.+>.sih))
%watch-ack %watch-ack
?~ p.p.+>.sih ?~ p.p.+>.sih
@ -275,9 +253,6 @@
+>.$ +>.$
(from ;;(dill-blit q.q.cage.p.+>.sih)) (from ;;(dill-blit q.q.cage.p.+>.sih))
== ==
::
[%clay %note *]
(from %out (tuba p.sih ' ' ~(ram re q.sih)))
:: ::
[?(%behn %clay) %writ *] [?(%behn %clay) %writ *]
init init
@ -292,12 +267,20 @@
== ==
-- --
:: ::
++ ax :: make ++as ++ ax :: make ++as from name
|= hen=duct |= [hen=duct ses=@tas]
^- (unit _as) ^- (unit _as)
=/ nux (~(get by dug.all) hen) =/ nux (~(get by dug.all) ses)
?~ nux ~ ?~ nux ~
(some ~(. as hen u.nux)) (some ~(. as hen ses u.nux))
::
++ aw :: make ++as from wire
|= [hen=duct wir=wire]
^- (unit _as)
%+ ax hen
?+ wir %$
[?(%peer %send) @ *] i.t.wir
==
-- --
|% :: poke+peek pattern |% :: poke+peek pattern
++ call :: handle request ++ call :: handle request
@ -308,7 +291,10 @@
^+ [*(list move) ..^$] ^+ [*(list move) ..^$]
~| wrapped-task ~| wrapped-task
=/ task=task ((harden task) wrapped-task) =/ task=task ((harden task) wrapped-task)
:: unwrap session tasks, default to session %$
:: ::
=^ ses=@tas task
?:(?=(%shot -.task) +.task [%$ task])
:: error notifications "downcast" to %crud :: error notifications "downcast" to %crud
:: ::
=? task ?=(^ dud) =? task ?=(^ dud)
@ -338,10 +324,11 @@
:: ::
=* duc (need hey.all) =* duc (need hey.all)
=/ app %hood =/ app %hood
=/ see (tuba "<awaiting {(trip app)}, this may take a minute>") =/ say (tuba "<awaiting {(trip app)}, this may take a minute>")
=/ zon=axon [app input=[~ ~] width=80 cursor=(lent see) lin+see] =/ zon=axon [app input=[~ ~] width=80]
:: ::
=^ moz all abet:(~(into as duc zon) ~) =^ moz all abet:(~(into as duc %$ zon) ~)
=. eye.all (~(put ju eye.all) %$ duc)
[moz ..^$] [moz ..^$]
:: %flog tasks are unwrapped and sent back to us on our default duct :: %flog tasks are unwrapped and sent back to us on our default duct
:: ::
@ -362,35 +349,60 @@
?: ?=(%knob -.task) ?: ?=(%knob -.task)
=. veb.all (~(put by veb.all) tag.task level.task) =. veb.all (~(put by veb.all) tag.task level.task)
[~ ..^$] [~ ..^$]
:: %open opens a new dill session
::
?: ?=(%open -.task)
?: (~(has by dug.all) ses)
::TODO should we allow, and just send the %yow blits?
~| [%cannot-open-existing ses]
!!
=/ zon=axon [p.task ~ width=80]
=^ moz all abet:(~(open as hen ses zon) q.task)
=. eye.all (~(put ju eye.all) ses hen)
[moz ..^$]
:: %shut closes an existing dill session
::
?: ?=(%shut -.task)
?: =(%$ ses)
~| %cannot-shut-default-session
!!
=/ nus
~| [%no-session ses]
(need (ax hen ses))
::NOTE we do deletion from state outside of the core,
:: because +abet would re-insert.
::TODO send a %bye blit? xx
=^ moz all abet:pull:nus
=. dug.all (~(del by dug.all) ses)
=. eye.all (~(del by eye.all) ses)
[moz ..^$]
:: %view opens a subscription to the target session, on the current duct
:: ::
?: ?=(%view -.task) ?: ?=(%view -.task)
:: crash on viewing non-existent session =/ nus
:: crash on viewing non-existent session
::
~| [%no-session ses]
(need (ax hen ses))
:: register the viewer and send a %hey so they get the full screen
:: ::
~| [%no-session session.task] =^ moz all
?> =(~ session.task) abet:(send:nus %hey ~)
=/ session (need hey.all) :- moz
=/ =axon (~(got by dug.all) session) ..^$(eye.all (~(put ju eye.all) ses hen))
:: register the viewer and send them the prompt line :: %flee closes a subscription to the target session, from the current duct
::
:- [hen %give %blit [see.axon]~]~
..^$(eye.all (~(put ju eye.all) session hen))
:: ::
?: ?=(%flee -.task) ?: ?=(%flee -.task)
:- ~ :- ~
~| [%no-session session.task] ..^$(eye.all (~(del ju eye.all) ses hen))
?> =(~ session.task)
=/ session (need hey.all)
..^$(eye.all (~(del ju eye.all) session hen))
:: ::
=/ nus (ax hen) =/ nus
=? nus &(?=(~ nus) ?=(^ hey.all)) (ax hen ses)
::TODO allow specifying target session in task
(ax u.hey.all)
?~ nus ?~ nus
:: :hen is an unrecognized duct :: session :ses does not exist
:: could be before %boot (or %boot failed) :: could be before %boot (or %boot failed)
:: ::
~& [%dill-call-no-flow hen -.task] ~& [%dill-call-no-session ses hen -.task]
=/ tan ?:(?=(%crud -.task) q.task ~) =/ tan ?:(?=(%crud -.task) q.task ~)
[((slog (flop tan)) ~) ..^$] [((slog (flop tan)) ~) ..^$]
:: ::
@ -398,8 +410,79 @@
[moz ..^$] [moz ..^$]
:: ::
++ load :: import old state ++ load :: import old state
|= old=axle =< |= old=any-axle
..^$(all old) ?- -.old
%6 ..^$(all old)
%5 $(old (axle-5-to-6 old))
%4 $(old (axle-4-to-5 old))
==
|%
+$ any-axle $%(axle axle-5 axle-4)
::
+$ axle-5
$: %5
hey=(unit duct) :: default duct
dug=(map @tas axon) :: conversations
eye=(jug @tas duct) :: outside listeners
lit=? :: boot in lite mode
veb=(map @tas log-level)
==
::
++ axle-5-to-6
|= a=axle-5
^- axle
:: [%6 hey `(map @tas axon)`dug eye lit veb |]
a(- %6, veb [veb.a &])
::
+$ axle-4
$: %4
hey=(unit duct)
dug=(map duct axon-4)
eye=(jug duct duct)
lit=?
veb=(map @tas log-level)
==
::
+$ axon-4
$: ram=term
tem=(unit (list dill-belt-4))
wid=_80
pos=$@(@ud [@ud @ud])
see=$%([%lin (list @c)] [%klr stub])
==
::
+$ dill-belt-4
$% [%ctl p=@c]
[%met p=@c]
dill-belt
==
::
++ axle-4-to-5
|= axle-4
^- axle-5
:- %5
=- [hey nug nay lit veb]
%+ roll ~(tap by dug)
|= [[=duct =axon-4] nug=(map @tas axon) nay=(jug @tas duct)]
=/ ses=@tas
~| [%unexpected-duct duct]
?>(=([//term/1]~ duct) %$)
:- (~(put by nug) ses (axon-4-to-5 axon-4))
%+ ~(put by nay) ses
(~(put in (~(get ju eye) duct)) duct)
::
++ axon-4-to-5
|= axon-4
^- axon
=; tem [ram tem wid]
?~ tem ~
%- some
%+ turn u.tem
|= b=dill-belt-4
^- dill-belt
?. ?=(?(%ctl %met) -.b) b
[%mod -.b p.b]
--
:: ::
++ scry ++ scry
^- roon ^- roon
@ -428,19 +511,12 @@
=(%$ syd) =(%$ syd)
== ==
~ ~
:: /dx/sessions//line blit current line (prompt) of default session :: /dy/sessions (set @tas) all existing sessions
:: /dx/sessions//cursor @ud current cursor position of default session :: /du/sessions/[ses] ? does session ses exist?
::TODO support asking for specific sessions once session ids are real
:: ::
?. ?=(%x ren) ~ ?+ [ren tyl] ~
?+ tyl ~ [%y %sessions ~] ``noun+!>(~(key by dug.all))
[%sessions %$ *] [%u %sessions @ ~] ``noun+!>((~(has by dug.all) (snag 1 tyl)))
?~ hey.all [~ ~]
?~ session=(~(get by dug.all) u.hey.all) [~ ~]
?+ t.t.tyl ~
[%line ~] ``blit+!>(`blit`see.u.session)
[%cursor ~] ``atom+!>(pos.u.session)
==
== ==
:: ::
++ stay all ++ stay all
@ -451,12 +527,27 @@
?^ dud ?^ dud
~|(%dill-take-dud (mean tang.u.dud)) ~|(%dill-take-dud (mean tang.u.dud))
:: ::
=/ nus (ax hen) =; [moz=(list move) lax=_..^$]
=? moz egg.all.lax
:: dill pre-release (version %5) in some cases ended up in a state
:: where it had both an old-style and new-style subscription open
:: for the default session. here, we obliterate both and establish
:: only the new-style subscription.
::
=/ hey (need hey.all.lax)
:* [hey %pass / %g %deal [our our] %hood %leave ~]
[hey %pass [%peer %$ ~] %g %deal [our our] %hood %leave ~]
[hey %pass [%peer %$ ~] %g %deal [our our] %hood %watch [%dill %$ ~]]
moz
==
=. egg.all.lax |
[moz lax]
::
=/ nus (aw hen tea)
?~ nus ?~ nus
:: :hen is an unrecognized duct :: :tea points to an unrecognized session
:: could be before %boot (or %boot failed)
:: ::
~& [%dill-take-no-flow hen -.hin +<.hin] ~& [%dill-take-no-session tea -.hin +<.hin]
[~ ..^$] [~ ..^$]
=^ moz all abet:(take:u.nus tea hin) =^ moz all abet:(take:u.nus tea hin)
[moz ..^$] [moz ..^$]

View File

@ -198,11 +198,21 @@
:: +mo-abet: finalize, reversing moves :: +mo-abet: finalize, reversing moves
:: +mo-pass: prepend a standard %pass to the current list of moves :: +mo-pass: prepend a standard %pass to the current list of moves
:: +mo-give: prepend a standard %give to the current list of moves :: +mo-give: prepend a standard %give to the current list of moves
:: +mo-talk: build task to print config report or failure trace
:: ::
++ mo-core . ++ mo-core .
++ mo-abed |=(hun=duct mo-core(hen hun)) ++ mo-abed |=(hun=duct mo-core(hen hun))
++ mo-abet [(flop moves) gall-payload] ++ mo-abet [(flop moves) gall-payload]
++ mo-give |=(g=gift mo-core(moves [[hen give+g] moves])) ++ mo-give |=(g=gift mo-core(moves [[hen give+g] moves]))
++ mo-talk
|= rup=(each suss tang)
^- [wire note-arvo]
:+ /sys/say %d
^- task:dill
?- -.rup
%& [%text "gall: {(t q)}ed %{(t p)}":[t=trip p.rup]]
%| [%talk leaf+"gall: failed" (flop p.rup)]
==
++ mo-pass |=(p=[wire note-arvo] mo-core(moves [[hen pass+p] moves])) ++ mo-pass |=(p=[wire note-arvo] mo-core(moves [[hen pass+p] moves]))
++ mo-slip |=(p=note-arvo mo-core(moves [[hen slip+p] moves])) ++ mo-slip |=(p=note-arvo mo-core(moves [[hen slip+p] moves]))
++ mo-past ++ mo-past
@ -303,12 +313,12 @@
=/ ap-core +.wag =/ ap-core +.wag
?^ maybe-tang ?^ maybe-tang
=. mo-core old =. mo-core old
(mo-give %onto %.n u.maybe-tang) (mo-pass (mo-talk %.n u.maybe-tang))
:: ::
=. mo-core ap-abet:ap-core =. mo-core ap-abet:ap-core
=. mo-core (mo-clear-queue dap) =. mo-core (mo-clear-queue dap)
=/ =suss [dap %boot now] =/ =suss [dap %boot now]
(mo-give %onto [%.y suss]) (mo-pass (mo-talk %.y suss))
:: +mo-send-foreign-request: handle local request to .ship :: +mo-send-foreign-request: handle local request to .ship
:: ::
++ mo-send-foreign-request ++ mo-send-foreign-request
@ -523,6 +533,11 @@
?~ error=error.sign-arvo ?~ error=error.sign-arvo
~ ~
`[[%leaf (trip tag.u.error)] tang.u.error] `[[%leaf (trip tag.u.error)] tang.u.error]
:: send a %cork if we get a nack upon initial subscription
::
=? mo-core
&(?=(^ err) |(?=(%watch-as remote-request) ?=(%watch remote-request)))
(mo-pass [%sys wire] %a %cork ship)
:: ::
?- remote-request ?- remote-request
%watch-as (mo-give %unto %watch-ack err) %watch-as (mo-give %unto %watch-ack err)
@ -899,8 +914,8 @@
:: ::
=/ running (~(put by yokes.state) agent-name yoke) =/ running (~(put by yokes.state) agent-name yoke)
=/ moves =/ moves
=/ giver |=(report=(each suss tang) [hen %give %onto report]) =/ talker |=(report=(each suss tang) [hen %pass (mo-talk report)])
=/ from-suss (turn agent-config giver) =/ from-suss (turn agent-config talker)
:(weld agent-moves from-suss moves) :(weld agent-moves from-suss moves)
:: ::
%_ mo-core %_ mo-core

View File

@ -105,11 +105,8 @@
$>(%wake gift:behn) :: $>(%wake gift:behn) ::
== :: == ::
$: %gall :: $: %gall ::
$> $? %onto :: $>(%unto gift:gall) ::
%unto :: == ::
== ::
gift:gall ::
==
== :: == ::
-- :: -- ::
:: :::: :: ::::
@ -462,12 +459,12 @@
:: [%vega ~] :: [%vega ~]
:: ::
%vega %vega
+>.$:: +>.$
::
:: in response to memory pressure :: in response to memory pressure
:: [%trim p=@ud] :: [%trim p=@ud]
:: ::
%trim %trim
::TODO consider %ruin-ing long-offline comets
+>.$ +>.$
:: ::
:: watch private keys :: watch private keys
@ -507,7 +504,7 @@
%ruin %ruin
::NOTE we blast this out to _all_ known ducts, because the common ::NOTE we blast this out to _all_ known ducts, because the common
:: use case for this is comets, about who nobody cares. :: use case for this is comets, about who nobody cares.
=/ dus ~(key by yen.zim.pki) =/ dus (~(uni in nel.zim.pki) ~(key by yen.zim.pki))
=/ sus ~(. su hen now pki etn) =/ sus ~(. su hen now pki etn)
=/ sis ~(tap in ships.tac) =/ sis ~(tap in ships.tac)
|- |-
@ -550,10 +547,6 @@
=/ ships (~(get ju ship-sources-reverse.etn) source-id) =/ ships (~(get ju ship-sources-reverse.etn) source-id)
%- curd =< abet %- curd =< abet
(sources:~(feel su hen now pki etn) ships source) (sources:~(feel su hen now pki etn) ships source)
::
[%gall %onto *]
~& [%jael-onto tea hin]
+>.$
:: ::
[%gall %unto *] [%gall %unto *]
?- +>-.hin ?- +>-.hin
@ -736,12 +729,10 @@
++ subscribers-on-ship ++ subscribers-on-ship
|= =ship |= =ship
^- (set duct) ^- (set duct)
=/ specific-subs (~(get ju ney.zim) ship) :: union of general and ship-specific subs
=/ general-subs=(set duct) ::
?: ?=(?(%czar %king %duke) (clan:title ship)) %- ~(uni in nel.zim)
nel.zim (~(get ju ney.zim) ship)
~
(~(uni in specific-subs) general-subs)
:: ::
++ feed ++ feed
|_ :: hen: subscription source |_ :: hen: subscription source
@ -997,7 +988,7 @@
=| lex=state-2 =| lex=state-2
|= $: :: now: current time |= $: :: now: current time
:: eny: unique entropy :: eny: unique entropy
:: ski: namespace resolver :: rof: namespace resolver
:: ::
now=@da now=@da
eny=@uvJ eny=@uvJ

View File

@ -4,7 +4,7 @@
=> ..lull => ..lull
~% %zuse ..part ~ ~% %zuse ..part ~
|% |%
++ zuse %417 ++ zuse %415
:: :: :: :: :: ::
:::: :: :: (2) engines :::: :: :: (2) engines
:: :: :: :: :: ::
@ -3843,6 +3843,102 @@
~ ~
(some (~(run by lum) need)) (some (~(run by lum) need))
-- ::dejs-soft -- ::dejs-soft
::
++ klr :: styx/stub engine
=, dill
|%
++ make :: stub from styx
|= a=styx ^- stub
=| b=stye
%+ reel
|- ^- stub
%- zing %+ turn a
|= a=$@(@t (pair styl styx))
?@ a [b (tuba (trip a))]~
^$(a q.a, b (styd p.a b))
::
|= [a=(pair stye (list @c)) b=stub]
?~ b [a ~]
?. =(p.a p.i.b) [a b]
[[p.a (weld q.a q.i.b)] t.b]
::
++ styd :: stye from styl
|= [a=styl b=stye] ^+ b :: with inheritance
:+ ?~ p.a p.b
?~ u.p.a ~
(~(put in p.b) u.p.a)
(fall p.q.a p.q.b)
(fall q.q.a q.q.b)
::
++ lent-char
|= a=stub ^- @
(roll (lnts-char a) add)
::
++ lnts-char :: stub text lengths
|= a=stub ^- (list @)
%+ turn a
|= a=(pair stye (list @c))
(lent q.a)
::
++ brek :: index + incl-len of
|= [a=@ b=(list @)] :: stub pair w/ idx a
=| [c=@ i=@]
|- ^- (unit (pair @ @))
?~ b ~
=. c (add c i.b)
?: (gte c a)
`[i c]
$(i +(i), b t.b)
::
++ pact :: condense stub
|= a=stub
^- stub
?~ a ~
?~ t.a a
?. =(p.i.a p.i.t.a) [i.a $(a t.a)]
=. q.i.t.a (weld q.i.a q.i.t.a)
$(a t.a)
::
++ slag :: slag stub
|= [a=@ b=stub]
^- stub
?: =(0 a) b
?~ b ~
=+ c=(lent q.i.b)
?: =(c a) t.b
?: (gth c a)
[[p.i.b (^slag a q.i.b)] t.b]
$(a (sub a c), b t.b)
::
++ scag :: scag stub
|= [a=@ b=stub]
^- stub
?: =(0 a) ~
?~ b ~
=+ c=(lent q.i.b)
?: (gth c a)
[p.i.b (^scag a q.i.b)]~
:- i.b
$(a (sub a c), b t.b)
::
++ swag :: swag stub
|= [[a=@ b=@] c=stub]
(scag b (slag a c))
::
++ wail :: overlay stub
|= [a=stub b=@ c=stub d=@c]
^- stub
;: weld
(scag b a)
::
=+ e=(lent-char a)
?: (lte b e) ~
[*stye (reap (sub b e) d)]~
::
c
(slag (add b (lent-char c)) a)
==
-- :: klr
-- --
:: |cloy: clay helpers :: |cloy: clay helpers
:: ::
@ -4928,7 +5024,7 @@
=< q.q %- need %- need =< q.q %- need %- need
(rof ~ %j `beam`[[our %sein %da now] /(scot %p who)]) (rof ~ %j `beam`[[our %sein %da now] /(scot %p who)])
-- --
:: middle core: for userspace use, with .^ :: middle core: stateless queries for default numeric sponsorship
:: ::
=> |% => |%
:: :: ++clan:title :: :: ++clan:title
@ -4968,7 +5064,7 @@
%pawn (end 4 who) %pawn (end 4 who)
== ==
-- --
:: surface core: stateless queries for default numeric sponsorship :: surface core: for userspace use, with .^
:: ::
|% |%
:: :: ++cite:title :: :: ++cite:title
@ -5003,13 +5099,25 @@
%j %j
/(scot %p our)/sein/(scot %da now)/(scot %p who) /(scot %p our)/sein/(scot %da now)/(scot %p who)
== ==
:: +team was created with two meanings:
:: A. her / her moon
:: B. whoever should be able to control her ship
::
:: these two things aren't obviously equal anymore,
:: and it's more important for +team to satisfy B than A,
:: so now +team just means "her".
::
:: (ships can definitely be trusted to control themselves)
:: :: ++team:title :: :: ++team:title
++ team :: our / our moon ++ team :: her
|= [our=ship who=ship] |= [her=ship who=ship]
^- ? ^- ?
?| =(our who) =(her who)
&(?=(%earl (clan who)) =(our (^sein who))) :: :: ++moon:title
== ++ moon :: her moon
|= [her=ship who=ship]
^- ?
&(=(%earl (clan who)) =(her (^sein who)))
-- ::title -- ::title
:: :: :: ::
:::: ++milly :: (2k) milliseconds :::: ++milly :: (2k) milliseconds

View File

@ -17,15 +17,16 @@
%+ roll blits %+ roll blits
|= [b=blit:dill line=tape] |= [b=blit:dill line=tape]
?- -.b ?- -.b
%lin (tape p.b) %put (tape p.b)
%klr (tape (zing (turn p.b tail))) %klr (tape (zing (turn p.b tail)))
%mor ~& "{<who>}: {line}" "" %nel ~& "{<who>}: {line}" ""
%hop line %hop line
%bel line %bel line
%clr "" %clr ""
%sag ~& [%save-jamfile-to p.b] line %sag ~& [%save-jamfile-to p.b] line
%sav ~& [%save-file-to p.b] line %sav ~& [%save-file-to p.b] line
%url ~& [%activate-url p.b] line %url ~& [%activate-url p.b] line
%wyp ""
== ==
~? !=(~ last-line) last-line ~? !=(~ last-line) last-line
~ ~

View File

@ -93,11 +93,6 @@
(arvo %e %connect binding app) (arvo %e %connect binding app)
-- --
:: ::
++ fact-curry
|* [=mark =mold]
|= [paths=(list path) fac=mold]
(fact mark^!>(fac) paths)
::
++ fact-kick ++ fact-kick
|= [=path =cage] |= [=path =cage]
^- (list card) ^- (list card)

View File

@ -143,6 +143,7 @@
|= a=@ |= a=@
^- hexb ^- hexb
=/ l=@ (met 3 a) =/ l=@ (met 3 a)
?: =(l 0) 1^a
?: =(l 1) 1^a ?: =(l 1) 1^a
?: =(l 2) (cat:byt ~[1^0xfd (flip:byt 2^a)]) ?: =(l 2) (cat:byt ~[1^0xfd (flip:byt 2^a)])
?: (lte l 4) (cat:byt ~[1^0xfe (flip:byt 4^a)]) ?: (lte l 4) (cat:byt ~[1^0xfe (flip:byt 4^a)])
@ -162,7 +163,7 @@
%0xfe 2 %0xfe 2
%0xff 3 %0xff 3
== ==
:_ (drop:byt (add 1 len) h) :_ (drop:byt (add 1 (bex len)) h)
%- flip:byt %- flip:byt
(take:byt (bex len) (drop:byt 1 h)) (take:byt (bex len) (drop:byt 1 h))
:: +dea: atom instead of hexb for parsed CompactSize :: +dea: atom instead of hexb for parsed CompactSize

View File

@ -0,0 +1,94 @@
:: dill: utilities for dill's data structures
::
=, dill
|%
++ enjs
|%
++ blit
|= =blit:dill
^- json
=, enjs:format
%+ frond -.blit
?- -.blit
%bel b+&
%clr b+&
%hop ?@ p.blit (numb p.blit)
(pairs 'x'^(numb x.p.blit) 'y'^(numb y.p.blit) ~)
%put a+(turn p.blit |=(c=@c s+(tuft c)))
%nel b+&
%url s+p.blit
%wyp b+&
%mor a+(turn p.blit ^blit)
::
%sag
%- pairs
:~ 'path'^(path p.blit)
'file'^s+(en:base64:mimes:html (as-octs:mimes:html (jam q.blit)))
==
::
%sav
%- pairs
:~ 'path'^(path p.blit)
'file'^s+(en:base64:mimes:html (as-octs:mimes:html q.blit))
==
::
%klr
:- %a
%+ turn p.blit
|= [=stye text=(list @c)]
%- pairs
:~ 'text'^a+(turn text |=(c=@c s+(tuft c)))
::
:- 'stye'
%- pairs
|^ :~ 'back'^(color p.q.stye)
'fore'^(color q.q.stye)
'deco'^a+(turn ~(tap in p.stye) |=(d=deco ?~(d ~ s+d)))
==
++ color
|= =tint
?@ tint ?~(tint ~ s+tint)
=, tint
(pairs r+(numb r) g+(numb g) b+(numb b) ~)
--
==
==
--
::
++ dejs
|%
++ belt
|= jon=json
^- belt:dill
?: ?=([%s *] jon)
(taft p.jon)
=, dejs:format
%. jon
%- of
|^ :* mod+(ot 'mod'^mod 'key'^bot ~)
txt+(ar (cu taft so))
bol
==
::
++ bol
:~ aro+(su (perk %d %l %r %u ~))
bac+ul
del+ul
hit+(ot 'x'^ni 'y'^ni ~)
ret+ul
==
::
++ bot
|= j=json
^- bolt:dill
?+ j !!
[%s *] (taft p.j)
[%o *] ((of bol) j)
==
::
++ mod
|= j=json
((su (perk %ctl %met %hyp ~)) j)
--
--
--

View File

@ -3,7 +3,8 @@
:: ::
=/ debug | =/ debug |
|% |%
+* option [item] ++ option
|$ [item]
[term=cord detail=item] [term=cord detail=item]
:: ::
:: Like +rose except also produces line number :: Like +rose except also produces line number

View File

@ -28,8 +28,8 @@
%+ send-events-to who %+ send-events-to who
^- (list unix-event) ^- (list unix-event)
:~ :~
[/d/term/1 %belt %ctl `@c`%e] [/d/term/1 %belt %mod %ctl `@c`%e]
[/d/term/1 %belt %ctl `@c`%u] [/d/term/1 %belt %mod %ctl `@c`%u]
[/d/term/1 %belt %txt ((list @c) what)] [/d/term/1 %belt %txt ((list @c) what)]
[/d/term/1 %belt %ret ~] [/d/term/1 %belt %ret ~]
== ==
@ -40,7 +40,7 @@
|= [who=ship what=term] |= [who=ship what=term]
^- (list ph-event) ^- (list ph-event)
%+ send-events-to who %+ send-events-to who
:~ [/d/term/1 %belt %ctl (,@c what)] :~ [/d/term/1 %belt %mod %ctl (,@c what)]
== ==
:: ::
:: Inject a file into a ship :: Inject a file into a ship
@ -67,7 +67,7 @@
:: ::
%+ lien p.q.uf %+ lien p.q.uf
|= =blit:dill |= =blit:dill
?. ?=(%lin -.blit) ?. ?=(%put -.blit)
| |
!=(~ (find what p.blit)) !=(~ (find what p.blit))
== ==

View File

@ -13,15 +13,15 @@
/- *sole /- *sole
/+ sole, auto=language-server-complete /+ sole, auto=language-server-complete
|% |%
+$ state-0 +$ state-1
$: %0 $: %1
soles=(map @ta sole-share) soles=(map sole-id sole-share)
== ==
:: $card: standard gall cards plus shoe effects :: $card: standard gall cards plus shoe effects
:: ::
+$ card +$ card
$% card:agent:gall $% card:agent:gall
[%shoe sole-ids=(list @ta) effect=shoe-effect] :: ~ sends to all soles [%shoe sole-ids=(list sole-id) effect=shoe-effect] :: ~ sends to all
== ==
:: $shoe-effect: easier sole-effects :: $shoe-effect: easier sole-effects
:: ::
@ -47,30 +47,30 @@
:: if the head of the result is true, instantly run the command :: if the head of the result is true, instantly run the command
:: ::
++ command-parser ++ command-parser
|~ sole-id=@ta |~ =sole-id
|~(nail *(like [? command-type])) |~(nail *(like [? command-type]))
:: +tab-list: autocomplete options for the session (to match +command-parser) :: +tab-list: autocomplete options for the session (to match +command-parser)
:: ::
++ tab-list ++ tab-list
|~ sole-id=@ta |~ =sole-id
:: (list [@t tank]) :: (list [@t tank])
*(list (option:auto tank)) *(list (option:auto tank))
:: +on-command: called when a valid command is run :: +on-command: called when a valid command is run
:: ::
++ on-command ++ on-command
|~ [sole-id=@ta command=command-type] |~ [=sole-id command=command-type]
*(quip card _^|(..on-init)) *(quip card _^|(..on-init))
:: ::
++ can-connect ++ can-connect
|~ sole-id=@ta |~ =sole-id
*? *?
:: ::
++ on-connect ++ on-connect
|~ sole-id=@ta |~ =sole-id
*(quip card _^|(..on-init)) *(quip card _^|(..on-init))
:: ::
++ on-disconnect ++ on-disconnect
|~ sole-id=@ta |~ =sole-id
*(quip card _^|(..on-init)) *(quip card _^|(..on-init))
:: ::
::NOTE standard gall agent arms below, though they may produce %shoe cards ::NOTE standard gall agent arms below, though they may produce %shoe cards
@ -119,27 +119,27 @@
|* [shoe=* command-type=mold] |* [shoe=* command-type=mold]
|_ =bowl:gall |_ =bowl:gall
++ command-parser ++ command-parser
|= sole-id=@ta |= =sole-id
(easy *[? command-type]) (easy *[? command-type])
:: ::
++ tab-list ++ tab-list
|= sole-id=@ta |= =sole-id
~ ~
:: ::
++ on-command ++ on-command
|= [sole-id=@ta command=command-type] |= [=sole-id command=command-type]
[~ shoe] [~ shoe]
:: ::
++ can-connect ++ can-connect
|= sole-id=@ta |= =sole-id
(team:title [our src]:bowl) (team:title [our src]:bowl)
:: ::
++ on-connect ++ on-connect
|= sole-id=@ta |= =sole-id
[~ shoe] [~ shoe]
:: ::
++ on-disconnect ++ on-disconnect
|= sole-id=@ta |= =sole-id
[~ shoe] [~ shoe]
-- --
:: +agent: creates wrapper core that handles sole events and calls shoe arms :: +agent: creates wrapper core that handles sole events and calls shoe arms
@ -147,7 +147,7 @@
++ agent ++ agent
|* command-type=mold |* command-type=mold
|= =(shoe command-type) |= =(shoe command-type)
=| state-0 =| state-1
=* state - =* state -
^- agent:gall ^- agent:gall
=> =>
@ -164,8 +164,7 @@
%+ turn %+ turn
?^ sole-ids.card sole-ids.card ?^ sole-ids.card sole-ids.card
~(tap in ~(key by soles)) ~(tap in ~(key by soles))
|= sole-id=@ta id-to-path:sole
/sole/[sole-id]
:: ::
%table %table
=; fez=(list sole-effect) =; fez=(list sole-effect)
@ -202,9 +201,36 @@
?. ?=([%shoe-app ^] q.old-state) ?. ?=([%shoe-app ^] q.old-state)
=^ cards shoe (on-load:og old-state) =^ cards shoe (on-load:og old-state)
[(deal cards) this] [(deal cards) this]
=^ old-inner state +:!<([%shoe-app vase state-0] old-state) |^ =| old-outer=state-any
=^ cards shoe (on-load:og old-inner) =^ old-inner old-outer
[(deal cards) this] +:!<([%shoe-app vase state-any] old-state)
:: ~! q.old-state
:: ?+ +>.q.old-state !!
:: [%0 *] +:!<([%shoe-app vase state-0] old-state)
:: [%1 *] +:!<([%shoe-app vase state-1] old-state)
:: ==
=^ caz shoe (on-load:og old-inner)
=^ cuz old-outer
?. ?=(%0 -.old-outer) [~ old-outer]
(state-0-to-1 old-outer)
?> ?=(%1 -.old-outer)
[(weld cuz (deal caz)) this(state old-outer)]
::
+$ state-any $%(state-1 state-0)
+$ state-0 [%0 soles=(map @ta sole-share)]
++ state-0-to-1
|= old=state-0
^- (quip card:agent:gall state-1)
:- %+ turn ~(tap in ~(key by soles.old))
|= id=@ta
^- card:agent:gall
[%give %kick ~[/sole/[id]] ~]
:- %1
%- ~(gas by *(map sole-id sole-share))
%+ murn ~(tap by soles.old)
|= [id=@ta s=sole-share]
(bind (upgrade-id:sole id) (late s))
--
:: ::
++ on-poke ++ on-poke
|= [=mark =vase] |= [=mark =vase]
@ -326,19 +352,18 @@
++ on-watch ++ on-watch
|= =path |= =path
^- (quip card:agent:gall agent:gall) ^- (quip card:agent:gall agent:gall)
?. ?=([%sole @ ~] path) ?~ sole-id=(path-to-id:sole path)
=^ cards shoe =^ cards shoe
(on-watch:og path) (on-watch:og path)
[(deal cards) this] [(deal cards) this]
=* sole-id i.t.path ?> (can-connect:og u.sole-id)
?> (can-connect:og sole-id) =. soles (~(put by soles) u.sole-id *sole-share)
=. soles (~(put by soles) sole-id *sole-share)
=^ cards shoe =^ cards shoe
(on-connect:og sole-id) (on-connect:og u.sole-id)
:_ this :_ this
%- deal %- deal
:_ cards :_ cards
[%shoe [sole-id]~ %sole %pro & dap.bowl "> "] [%shoe [u.sole-id]~ %sole %pro & dap.bowl "> "]
:: ::
++ on-leave ++ on-leave
|= =path |= =path

View File

@ -136,4 +136,28 @@
=+ dat=(transmute [%mor leg] [%ins pos `@c`0]) =+ dat=(transmute [%mor leg] [%ins pos `@c`0])
?> ?=(%ins -.dat) ?> ?=(%ins -.dat)
p.dat p.dat
::
::
++ path-to-id
|= =path
^- (unit sole-id)
?. ?=([%sole @ ?(~ [@ ~])] path) ~
?~ who=(slaw %p i.t.path) ~
`[u.who ?~(t.t.path %$ i.t.t.path)]
::
++ id-to-path
|= sole-id
^- path
::TODO this whole "no empty path ending" business feels icky.
:: do we want default session to be ~.~ ?
:: concern here is that outsiders cannot subscribe to the default
:: session, because /sole/~zod/ isn't a valid path...
[%sole (scot %p who) ?~(ses ~ /[ses])]
::
++ upgrade-id
|= old=@ta
^- (unit sole-id)
%+ rush old
%+ cook (late %$)
;~(pfix (jest 'drum_~') fed:ag)
-- --

View File

@ -1,5 +1,7 @@
:: belt: runtime belt structure :: belt: runtime belt structure
:: ::
/+ dill
::
|_ =belt:dill |_ =belt:dill
++ grad %noun ++ grad %noun
:: +grab: convert from :: +grab: convert from
@ -7,18 +9,7 @@
++ grab ++ grab
|% |%
++ noun belt:dill ++ noun belt:dill
++ json ++ json belt:dejs:dill
^- $-(^json belt:dill)
=, dejs:format
%- of
:~ aro+(su (perk %d %l %r %u ~))
bac+ul
ctl+(cu taft so)
del+ul
met+(cu taft so)
ret+ul
txt+(ar (cu taft so))
==
-- --
:: +grow: convert to :: +grow: convert to
:: ::

View File

@ -1,5 +1,7 @@
:: blit: runtime blit structure :: blit: runtime blit structure
:: ::
/+ dill
::
|_ =blit:dill |_ =blit:dill
++ grad %noun ++ grad %noun
:: +grab: convert from :: +grab: convert from
@ -13,49 +15,6 @@
++ grow ++ grow
|% |%
++ noun blit ++ noun blit
++ json ++ json (blit:enjs:dill blit)
^- ^json
=, enjs:format
%+ frond -.blit
?- -.blit
%bel b+&
%clr b+&
%hop (numb p.blit)
%lin a+(turn p.blit |=(c=@c s+(tuft c)))
%mor b+&
%url s+p.blit
::
%sag
%- pairs
:~ 'path'^(path p.blit)
'file'^s+(en:base64:mimes:html (as-octs:mimes:html (jam q.blit)))
==
::
%sav
%- pairs
:~ 'path'^(path p.blit)
'file'^s+(en:base64:mimes:html (as-octs:mimes:html q.blit))
==
::
%klr
:- %a
%+ turn p.blit
|= [=stye text=(list @c)]
%- pairs
:~ 'text'^a+(turn text |=(c=@c s+(tuft c)))
::
:- 'stye'
%- pairs
|^ :~ 'back'^(color p.q.stye)
'fore'^(color q.q.stye)
'deco'^a+(turn ~(tap in p.stye) |=(d=deco ?~(d ~ s+d)))
==
++ color
|= =tint
?@ tint ?~(tint ~ s+tint)
s+(crip ((x-co:co 6) (rep 3 ~[b g r]:tint)))
--
==
==
-- --
-- --

View File

@ -20,7 +20,9 @@
|= jon=^json ^- sole-action |= jon=^json ^- sole-action
%- need %. jon %- need %. jon
=> [dejs-soft:format ..sole-action] => [dejs-soft:format ..sole-action]
|^ (ot id+so dat+(fo %ret (of det+change tab+ni ~)) ~) |^ (ot id+id dat+(fo %ret (of det+change tab+ni ~)) ~)
++ id
(ot who+(su ;~(pfix sig fed:ag)) ses+so ~)
++ fo ++ fo
|* [a=term b=fist] |* [a=term b=fist]
|=(c=json ?.(=([%s a] c) (b c) (some [a ~]))) |=(c=json ?.(=([%s a] c) (b c) (some [a ~])))

View File

@ -3,8 +3,9 @@
:: ::
^? ^?
|% |%
+$ sole-id [who=@p ses=@ta]
+$ sole-action :: sole to app +$ sole-action :: sole to app
$: id=@ta :: duct id $: id=sole-id :: session id
$= dat $= dat
$% :: [%abo ~] :: reset interaction $% :: [%abo ~] :: reset interaction
[%det sole-change] :: command line edit [%det sole-change] :: command line edit

View File

@ -1 +1,2 @@
[%zuse 417] [%zuse 417]
[%zuse 416]

View File

@ -1 +1 @@
[%zuse 417] [%zuse 416]

View File

@ -119,15 +119,25 @@ deriveNoun ''BehnEf
data Blit data Blit
= Bel () = Bel ()
| Clr () | Clr ()
| Hop Word64 | Hop HopTarget
| Klr Stub | Klr Stub
| Lin [Char] | Put [Char]
| Mor () | Nel ()
| Sag Path Noun | Sag Path Noun
| Sav Path Atom | Sav Path Atom
| Url Cord | Url Cord
| Wyp ()
--TMP backwards compatibility
| Lin [Char]
| Mor ()
deriving (Eq, Ord) deriving (Eq, Ord)
--NOTE bottom-left-0-based coordinates
data HopTarget
= Col Word64
| Roc Word64 Word64 -- row, col
deriving (Eq, Ord, Show)
data Deco data Deco
= DecoBl = DecoBl
| DecoBr | DecoBr
@ -205,18 +215,33 @@ instance FromNoun Tint where
"w" -> pure TintW "w" -> pure TintW
t -> fail ("invalid: " <> unpack t) t -> fail ("invalid: " <> unpack t)
instance FromNoun HopTarget where
parseNoun = \case
A c -> pure $ Col (fromIntegral c)
C (A r) (A c) -> pure $ Roc (fromIntegral r) (fromIntegral c)
n -> fail ("invalid hop target: " <> show n)
instance ToNoun HopTarget where
toNoun = \case
Col c -> A (fromIntegral c)
Roc r c -> C (A (fromIntegral r)) (A (fromIntegral c))
-- Manual instance to not save the noun/atom in Sag/Sav, because these can be -- Manual instance to not save the noun/atom in Sag/Sav, because these can be
-- megabytes and makes king hang. -- megabytes and makes king hang.
instance Show Blit where instance Show Blit where
show (Bel ()) = "Bel ()" show (Bel ()) = "Bel ()"
show (Clr ()) = "Clr ()" show (Clr ()) = "Clr ()"
show (Hop x) = "Hop " ++ (show x) show (Hop t) = "Hop " ++ (show t)
show (Klr s) = "Klr " ++ (show s) show (Klr s) = "Klr " ++ (show s)
show (Lin c) = "Lin " ++ (show c) show (Put c) = "Put " ++ (show c)
show (Mor ()) = "Mor ()" show (Nel ()) = "Nel ()"
show (Sag path _) = "Sag " ++ (show path) show (Sag path _) = "Sag " ++ (show path)
show (Sav path _) = "Sav " ++ (show path) show (Sav path _) = "Sav " ++ (show path)
show (Url c) = "Url " ++ (show c) show (Url c) = "Url " ++ (show c)
show (Wyp ()) = "Wyp ()"
--
show (Lin c) = "Lin " ++ (show c)
show (Mor ()) = "Mor ()"
{-| {-|
%blip -- TODO %blip -- TODO

View File

@ -20,6 +20,7 @@ import Urbit.Arvo.Common (ReOrg(..), reorgThroughNoun)
import qualified Crypto.Sign.Ed25519 as Ed import qualified Crypto.Sign.Ed25519 as Ed
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
import qualified Data.Char as C
import qualified Data.ByteString.Char8 as C import qualified Data.ByteString.Char8 as C
import qualified Network.HTTP.Types.Method as H import qualified Network.HTTP.Types.Method as H
@ -318,19 +319,52 @@ data LegacyBootEvent
| Dawn Dawn | Dawn Dawn
deriving (Eq, Show) deriving (Eq, Show)
data ArrowKey = D | L | R | U data Bolt
= Key Char
| Aro ArrowKey
| Bac ()
| Del ()
| Hit Word64 Word64
| Ret ()
deriving (Eq, Ord, Show) deriving (Eq, Ord, Show)
data Belt data Belt
= Aro ArrowKey = Bol Bolt
| Bac () | Mod Modifier Bolt
| Ctl Cord
| Del ()
| Met Cord
| Ret ()
| Txt Tour | Txt Tour
deriving (Eq, Ord, Show) deriving (Eq, Ord, Show)
data ArrowKey = D | L | R | U
deriving (Eq, Ord, Show)
data Modifier = Ctl | Met | Hyp
deriving (Eq, Ord, Show)
--NOTE required to get the above declarations into reify's type environment
-- see also ghc/ghc#9813
$(pure [])
instance FromNoun Bolt where
parseNoun = \case
A c -> pure $ Key $ C.chr $ fromIntegral c
C (A 7955819) _ -> fail "%key not valid bolt tag"
n -> $(deriveFromNounFunc ''Bolt) n
instance FromNoun Belt where
parseNoun = \case
C (A 7106402) _ -> fail "%bol not valid belt tag"
n -> Bol <$> parseNoun n <|> $(deriveFromNounFunc ''Belt) n
instance ToNoun Bolt where
toNoun = \case
Key c -> A $ fromIntegral $ C.ord c
n -> $(deriveToNounFunc ''Bolt) n
instance ToNoun Belt where
toNoun = \case
Bol b -> toNoun b
n -> $(deriveToNounFunc ''Belt) n
data TermEv data TermEv
= TermEvBelt (UD, ()) Belt = TermEvBelt (UD, ()) Belt
| TermEvBlew (UD, ()) Word Word | TermEvBlew (UD, ()) Word Word
@ -341,7 +375,7 @@ data TermEv
deriveNoun ''LegacyBootEvent deriveNoun ''LegacyBootEvent
deriveNoun ''ArrowKey deriveNoun ''ArrowKey
deriveNoun ''Belt deriveNoun ''Modifier
deriveNoun ''TermEv deriveNoun ''TermEv
@ -392,27 +426,23 @@ instance FromNoun Ev where
-- Short Event Names ----------------------------------------------------------- -- Short Event Names -----------------------------------------------------------
{- {-
In the case of the user hitting enter, the cause is technically a In the case of user input, the cause is technically a terminal event,
terminal event, but we don't display any name because the cause is but we don't display any name because the cause is really the user.
really the user.
-} -}
getSpinnerNameForEvent :: Ev -> Maybe Text getSpinnerNameForEvent :: Ev -> Maybe Text
getSpinnerNameForEvent = \case getSpinnerNameForEvent = \case
EvBlip b -> case b of EvBlip b -> case b of
BlipEvAmes _ -> Just "ames" BlipEvAmes _ -> Just "ames"
BlipEvArvo _ -> Just "arvo" BlipEvArvo _ -> Just "arvo"
BlipEvBehn _ -> Just "behn" BlipEvBehn _ -> Just "behn"
BlipEvBoat _ -> Just "boat" BlipEvBoat _ -> Just "boat"
BlipEvHttpClient _ -> Just "iris" BlipEvHttpClient _ -> Just "iris"
BlipEvHttpServer _ -> Just "eyre" BlipEvHttpServer _ -> Just "eyre"
BlipEvJael _ -> Just "jael" BlipEvJael _ -> Just "jael"
BlipEvNewt _ -> Just "newt" BlipEvNewt _ -> Just "newt"
BlipEvSync _ -> Just "clay" BlipEvSync _ -> Just "clay"
BlipEvTerm t | isRet t -> Nothing BlipEvTerm (TermEvBelt _ _) -> Nothing
BlipEvTerm t -> Just "term" BlipEvTerm t -> Just "term"
where
isRet (TermEvBelt _ (Ret ())) = True
isRet _ = False
summarizeEvent :: Ev -> Text summarizeEvent :: Ev -> Text
summarizeEvent ev = summarizeEvent ev =

View File

@ -333,7 +333,7 @@ pier (serf, log) vSlog startedSig injected = do
io $ readTVarIO siteSlog >>= ($ s) io $ readTVarIO siteSlog >>= ($ s)
logOther "serf" (display $ T.strip $ tankToText tank) logOther "serf" (display $ T.strip $ tankToText tank)
let err = atomically . Term.trace muxed . (<> "\r\n") let err = atomically . Term.trace muxed
(bootEvents, startDrivers) <- do (bootEvents, startDrivers) <- do
env <- ask env <- ask
siz <- atomically $ Term.curDemuxSize demux siz <- atomically $ Term.curDemuxSize demux

View File

@ -45,8 +45,8 @@ import qualified Urbit.Vere.Term.Render as T
-- | All stateful data in the printing to stdOutput. -- | All stateful data in the printing to stdOutput.
data LineState = LineState data LineState = LineState
{ lsLine :: Text { lsLine :: [(Stye, [Char])]
, lsCurPos :: Int , lsCurPos :: CurPos
, lsSpinTimer :: Maybe (Async ()) , lsSpinTimer :: Maybe (Async ())
, lsSpinCause :: Maybe Text , lsSpinCause :: Maybe Text
, lsSpinFirstRender :: Bool , lsSpinFirstRender :: Bool
@ -54,11 +54,19 @@ data LineState = LineState
, lsPrevEndTime :: Wen , lsPrevEndTime :: Wen
} }
data CurPos = CurPos
{ row :: Int
, col :: Int
}
-- | A record used in reading data from stdInput. -- | A record used in reading data from stdInput.
data ReadData = ReadData data ReadData = ReadData
{ rdBuf :: Ptr Word8 { rdBuf :: Ptr Word8
, rdEscape :: Bool , rdEscape :: Bool
, rdBracket :: Bool , rdBracket :: Bool
, rdMouse :: Bool
, rdMouseBut :: Word8
, rdMouseCol :: Word8
, rdUTF8 :: ByteString , rdUTF8 :: ByteString
, rdUTF8width :: Int , rdUTF8width :: Int
} }
@ -165,7 +173,8 @@ leftBracket, rightBracket :: Text
leftBracket = "«" leftBracket = "«"
rightBracket = "»" rightBracket = "»"
_spin_cool_us, _spin_warm_us, _spin_rate_us, _spin_idle_us :: Integral i => i _spin_fast_us, _spin_cool_us, _spin_warm_us, _spin_rate_us, _spin_idle_us :: Integral i => i
_spin_fast_us = 100000
_spin_cool_us = 500000 _spin_cool_us = 500000
_spin_warm_us = 50000 _spin_warm_us = 50000
_spin_rate_us = 250000 _spin_rate_us = 250000
@ -201,6 +210,9 @@ localClient doneSignal = fst <$> mkRAcquire start stop
-- to the muxing client. -- to the muxing client.
putTMVar tsSizeChange ts) putTMVar tsSizeChange ts)
-- start mouse reporting
putStr "\x1b[?9h"
pWriterThread <- asyncBound pWriterThread <- asyncBound
(writeTerminal tsWriteQueue spinnerMVar tsizeTVar) (writeTerminal tsWriteQueue spinnerMVar tsizeTVar)
@ -217,7 +229,7 @@ localClient doneSignal = fst <$> mkRAcquire start stop
tsReadQueue <- newTQueueIO tsReadQueue <- newTQueueIO
pReaderThread <- asyncBound pReaderThread <- asyncBound
(readTerminal tsReadQueue tsWriteQueue (bell tsWriteQueue)) (readTerminal tsReadQueue tsWriteQueue tsizeTVar (bell tsWriteQueue))
let client = Client { take = Just <$> asum let client = Client { take = Just <$> asum
[ readTQueue tsReadQueue <&> ClientTakeBelt, [ readTQueue tsReadQueue <&> ClientTakeBelt,
@ -238,6 +250,9 @@ localClient doneSignal = fst <$> mkRAcquire start stop
-- at shutdown, just leak the file descriptor. -- at shutdown, just leak the file descriptor.
cancel pWriterThread cancel pWriterThread
-- stop mouse reporting
putStr "\x1b[?9l"
-- inject one final newline, as we're usually on the prompt. -- inject one final newline, as we're usually on the prompt.
putStr "\r\n" putStr "\r\n"
@ -266,31 +281,50 @@ localClient doneSignal = fst <$> mkRAcquire start stop
-- Writes data to the terminal. Both the terminal reading, normal logging, -- Writes data to the terminal. Both the terminal reading, normal logging,
-- and effect handling can all emit bytes which go to the terminal. -- and effect handling can all emit bytes which go to the terminal.
--TODO blanks, traces and slogs should only be written into the default
-- terminal session.
writeTerminal :: TQueue [Term.Ev] -> TMVar () -> TVar TermSize -> RIO e () writeTerminal :: TQueue [Term.Ev] -> TMVar () -> TVar TermSize -> RIO e ()
writeTerminal q spinner termSizeVar = do writeTerminal q spinner termSizeVar = do
currentTime <- io $ now currentTime <- io $ now
loop (LineState "" 0 Nothing Nothing True 0 currentTime) loop
termSizeVar
(LineState [] (CurPos 0 0) Nothing Nothing True 0 currentTime)
where where
writeBlank :: LineState -> RIO e LineState writeBlank :: LineState -> RIO e LineState
writeBlank ls = putStr "\r\n" $> ls writeBlank ls = do
TermSize _ height <- readTVarIO termSizeVar
--NOTE hijack creates a blank line
T.hijack (fromIntegral height) $ pure ()
pure ls
writeTrace :: LineState -> Text -> RIO e LineState writeTrace :: LineState -> Text -> RIO e LineState
writeTrace ls p = do writeTrace ls p = do
putStr "\r" TermSize _ height <- readTVarIO termSizeVar
T.clearLine T.hijack (fromIntegral height) $ putStr p
putStr p pure ls
termRefreshLine ls
writeSlog :: LineState -> (Atom, Tank) -> RIO e LineState writeSlog :: LineState -> (Atom, Tank) -> RIO e LineState
writeSlog ls slog = do writeSlog ls slog = do
putStr "\r" TermSize width height <- readTVarIO termSizeVar
T.clearLine T.hijack (fromIntegral height) do
TermSize width _ <- atomically $ readTVar termSizeVar let lines = fmap (pref . unTape) $
-- TODO: Ignoring priority for now. Priority changes the color of, wash (WashCfg 0 width) $ tankTree $ snd slog
-- and adds a prefix of '>' to, the output. T.putCsi 'm' styl
let lines = fmap unTape $ wash (WashCfg 0 width) $ tankTree $ snd slog forM (intersperse "\n" lines) $ \line -> putStr line
forM lines $ \line -> putStr (line <> "\r\n") T.putCsi 'm' [0]
termRefreshLine ls pure ls
where
prio = fromIntegral $ fst slog
maxp = 3
styl
| prio == 3 = [31]
| prio == 2 = [33]
| prio == 1 = [32]
| otherwise = [90]
pref
| prio > 0 && prio <= maxp =
((replicate prio '>' ++ replicate (1 + maxp - prio) ' ') ++)
| otherwise = id
{- {-
Figure out how long to wait to show the spinner. When we Figure out how long to wait to show the spinner. When we
@ -305,7 +339,7 @@ localClient doneSignal = fst <$> mkRAcquire start stop
current <- io $ now current <- io $ now
delay <- pure $ case mTxt of delay <- pure $ case mTxt of
Nothing -> 0 Nothing -> _spin_fast_us
Just _ -> Just _ ->
if (gap current lsPrevEndTime ^. microSecs) < _spin_idle_us if (gap current lsPrevEndTime ^. microSecs) < _spin_idle_us
then _spin_warm_us then _spin_warm_us
@ -326,34 +360,41 @@ localClient doneSignal = fst <$> mkRAcquire start stop
maybe (pure ()) cancel lsSpinTimer maybe (pure ()) cancel lsSpinTimer
-- We do a final flush of the spinner mvar to ensure we don't -- We do a final flush of the spinner mvar to ensure we don't
-- have a lingering signal which will redisplay the spinner after -- have a lingering signal which will redisplay the spinner after
-- we call termRefreshLine below. -- we call termRestoreLine below.
atomically $ tryTakeTMVar spinner atomically $ tryTakeTMVar spinner
-- If we ever actually ran the spinner display callback, we need -- If we ever actually ran the spinner display callback, we need
-- to force a redisplay of the command prompt. -- to force a redisplay of the command prompt.
ls <- if not lsSpinFirstRender || True if not lsSpinFirstRender
then termRefreshLine ls then termRestoreLine ls termSizeVar
else pure ls else pure ()
endTime <- io $ now endTime <- io $ now
pure $ ls { lsSpinTimer = Nothing, lsPrevEndTime = endTime } pure $ ls { lsSpinTimer = Nothing, lsPrevEndTime = endTime }
execEv :: LineState -> Term.Ev -> RIO e LineState execEv :: LineState -> Term.Ev -> RIO e LineState
execEv ls = \case execEv ls = \case
Term.Blits bs -> foldM writeBlit ls bs Term.Blits bs -> foldM (writeBlit termSizeVar) ls bs
Term.Trace p -> writeTrace ls (unCord p) Term.Trace p -> writeTrace ls (unCord p)
Term.Slog s -> writeSlog ls s Term.Slog s -> writeSlog ls s
Term.Blank -> writeBlank ls Term.Blank -> writeBlank ls
Term.Spinr (Just txt) -> doSpin ls (unCord <$> txt) Term.Spinr (Just txt) -> doSpin ls (unCord <$> txt)
Term.Spinr Nothing -> unspin ls Term.Spinr Nothing -> unspin ls
-- TODO What does this do? spin :: TVar TermSize -> LineState -> RIO e LineState
spin :: LineState -> RIO e LineState spin ts ls@LineState{..} = do
spin ls@LineState{..} = do
let spinner = (spinners !! lsSpinFrame) ++ case lsSpinCause of let spinner = (spinners !! lsSpinFrame) ++ case lsSpinCause of
Nothing -> "" Nothing -> ""
Just str -> leftBracket ++ str ++ rightBracket Just str -> leftBracket ++ str ++ rightBracket
--NOTE even after first render, because cursor might have moved...
if row lsCurPos > 0
then do
TermSize _ h <- readTVarIO ts
T.cursorMove (fromIntegral h - 1) 0
else
T.cursorRestore
putStr (spinner <> pack (ANSI.cursorBackwardCode (length spinner))) putStr (spinner <> pack (ANSI.cursorBackwardCode (length spinner)))
let newFrame = (lsSpinFrame + 1) `mod` length spinners let newFrame = (lsSpinFrame + 1) `mod` length spinners
@ -362,28 +403,35 @@ localClient doneSignal = fst <$> mkRAcquire start stop
, lsSpinFrame = newFrame , lsSpinFrame = newFrame
} }
loop :: LineState -> RIO e () loop :: TVar TermSize -> LineState -> RIO e ()
loop ls = do loop ts ls = do
join $ atomically $ asum join $ atomically $ asum
[ readTQueue q >>= pure . (foldM execEv ls >=> loop) [ readTQueue q >>= pure . (foldM execEv ls >=> loop ts)
, takeTMVar spinner >> pure (spin ls >>= loop) , takeTMVar spinner >> pure (spin ts ls >>= loop ts)
] ]
-- Writes an individual blit to the screen -- Writes an individual blit to the screen
writeBlit :: LineState -> Blit -> RIO e LineState writeBlit :: TVar TermSize -> LineState -> Blit -> RIO e LineState
writeBlit ls = \case writeBlit ts ls = \case
Bel () -> T.soundBell $> ls Bel () -> T.soundBell $> ls
Clr () -> do T.clearScreen Clr () -> do T.clearScreen
termRefreshLine ls T.cursorRestore
Hop w -> termShowCursor ls (fromIntegral w) pure ls
Klr s -> do ls2 <- termShowClear ls Hop t -> case t of
termShowStub ls2 s Col c -> termShowCursor ls ts 0 (fromIntegral c)
Lin c -> do ls2 <- termShowClear ls Roc r c -> termShowCursor ls ts (fromIntegral r) (fromIntegral c)
termShowLine ls2 (pack c) Klr s -> termShowStub ls s
Mor () -> termShowMore ls Put c -> termShowLine ls (pack c)
Nel () -> termShowNewline ls
Sag path noun -> pure ls Sag path noun -> pure ls
Sav path atom -> pure ls Sav path atom -> pure ls
Url url -> pure ls Url url -> pure ls
Wyp () -> termShowClear ls
--
Lin c -> do termShowCursor ls ts 0 0
termShowClear ls
termShowLine ls (pack c)
Mor () -> termShowNewline ls
termRenderDeco :: Deco -> Char termRenderDeco :: Deco -> Char
termRenderDeco = \case termRenderDeco = \case
@ -428,55 +476,88 @@ localClient doneSignal = fst <$> mkRAcquire start stop
styled = mconcat [escape, styles, "m", tape, escape, "0m"] styled = mconcat [escape, styles, "m", tape, escape, "0m"]
-- Displays and sets styled text as the current line bareStub :: [Char] -> [(Stye, [Char])]
bareStub c = [(Stye (setToHoonSet mempty) TintNull TintNull, c)]
-- overwrite substring of base with put, starting at index
overwriteStub :: [(Stye, [Char])] -> Int -> [(Stye, [Char])] -> [(Stye, [Char])]
overwriteStub base index put =
scagStub index base
++ ( let l = lentStub base in
if index <= l then []
else bareStub $ take (index - l) [' ',' '..]
)
++ put
++ slagStub (index + lentStub put) base
where
lentStub :: [(Stye, [Char])] -> Int
lentStub s = sum $ map (length . snd) s
scagStub :: Int -> [(Stye, [Char])] -> [(Stye, [Char])]
scagStub 0 _ = []
scagStub _ [] = []
scagStub i ((y,c):s) =
(y, take i c) : scagStub (i - min i (length c)) s
slagStub :: Int -> [(Stye, [Char])] -> [(Stye, [Char])]
slagStub 0 s = s
slagStub _ [] = []
slagStub i ((y,c):s)
| i > l = slagStub (i - l) s
| otherwise = (y, drop i c) : s
where l = length c
-- Displays styled text at the cursor
termShowStub :: LineState -> Stub -> RIO e LineState termShowStub :: LineState -> Stub -> RIO e LineState
termShowStub ls (Stub s) = do termShowStub ls@LineState{lsCurPos, lsLine} (Stub s) = do
let visualLength = sum $ fmap (length . snd) s putStr $ pack $ mconcat $ fmap (uncurry termRenderStubSegment) s
let outText = pack $ mconcat $ fmap (uncurry termRenderStubSegment) s T.cursorRestore
putStr outText case row lsCurPos of
pure ls { lsLine = outText, lsCurPos = visualLength } 0 -> pure ls { lsLine = overwriteStub lsLine (col lsCurPos) s }
_ -> pure ls
-- Moves the cursor to the requested position -- Moves the cursor to the requested position
termShowCursor :: LineState -> Int -> RIO e LineState termShowCursor :: LineState -> TVar TermSize -> Int -> Int -> RIO e LineState
termShowCursor ls@LineState{..} {-line pos)-} newPos = do termShowCursor ls ts row col = do
if newPos < lsCurPos then do TermSize _ h <- readTVarIO ts
T.cursorLeft (lsCurPos - newPos) T.cursorMove (max 0 (fromIntegral h - row - 1)) col
pure ls { lsCurPos = newPos } T.cursorSave
else if newPos > lsCurPos then do pure ls { lsCurPos = CurPos row col }
T.cursorRight (newPos - lsCurPos)
pure ls { lsCurPos = newPos }
else
pure ls
-- Moves the cursor left without any mutation of the LineState. Used only
-- in cursor spinning.
_termSpinnerMoveLeft :: Int -> RIO e ()
_termSpinnerMoveLeft = T.cursorLeft
-- Displays and sets the current line -- Displays and sets the current line
termShowLine :: LineState -> Text -> RIO e LineState termShowLine :: LineState -> Text -> RIO e LineState
termShowLine ls newStr = do termShowLine ls@LineState{lsCurPos, lsLine} newStr = do
putStr newStr putStr newStr
pure ls { lsLine = newStr, lsCurPos = (length newStr) } T.cursorRestore
case row lsCurPos of
0 -> pure ls { lsLine = overwriteStub lsLine (col lsCurPos) (bareStub $ unpack newStr) }
_ -> pure ls
termShowClear :: LineState -> RIO e LineState termShowClear :: LineState -> RIO e LineState
termShowClear ls = do termShowClear ls@LineState{lsCurPos} = do
putStr "\r" putStr "\r"
T.clearLine T.clearLine
pure ls { lsLine = "", lsCurPos = 0 } T.cursorRestore
case row lsCurPos of
0 -> pure ls { lsLine = [] }
_ -> pure ls
-- New Current Line -- New Current Line
termShowMore :: LineState -> RIO e LineState termShowNewline :: LineState -> RIO e LineState
termShowMore ls = do termShowNewline ls@LineState{lsCurPos} = do
putStr "\r\n" putStr "\r\n"
pure ls { lsLine = "", lsCurPos = 0 } case row lsCurPos of
0 -> pure ls { lsLine = [], lsCurPos = lsCurPos { col = 0 } }
r -> pure ls { lsCurPos = CurPos (r-1) 0 }
-- Redraw the current LineState, maintaining the current curpos -- Redraw the bottom LineState, maintaining the current curpos
termRefreshLine :: LineState -> RIO e LineState termRestoreLine :: LineState -> TVar TermSize -> RIO e ()
termRefreshLine ls@LineState{lsCurPos,lsLine} = do termRestoreLine ls@LineState{lsLine} ts = do
ls <- termShowClear ls TermSize _ h <- readTVarIO ts
ls <- termShowLine ls lsLine T.cursorMove (fromIntegral h - 1) 0
termShowCursor ls lsCurPos T.clearLine
putStr $ pack $ mconcat $ fmap (uncurry termRenderStubSegment) lsLine
T.cursorRestore
-- ring my bell -- ring my bell
bell :: TQueue [Term.Ev] -> RIO e () bell :: TQueue [Term.Ev] -> RIO e ()
@ -491,9 +572,14 @@ localClient doneSignal = fst <$> mkRAcquire start stop
-- A better way to do this would be to get some sort of epoll on stdInput, -- A better way to do this would be to get some sort of epoll on stdInput,
-- since that's kinda closer to what libuv does? -- since that's kinda closer to what libuv does?
readTerminal :: forall e. HasLogFunc e readTerminal :: forall e. HasLogFunc e
=> TQueue Belt -> TQueue [Term.Ev] -> (RIO e ()) -> RIO e () => TQueue Belt
readTerminal rq wq bell = -> TQueue [Term.Ev]
rioAllocaBytes 1 $ \ buf -> loop (ReadData buf False False mempty 0) -> TVar TermSize
-> RIO e ()
-> RIO e ()
readTerminal rq wq ts bell =
rioAllocaBytes 1 $ \ buf
-> loop (ReadData buf False False False 0 0 mempty 0)
where where
loop :: ReadData -> RIO e () loop :: ReadData -> RIO e ()
loop rd@ReadData{..} = do loop rd@ReadData{..} = do
@ -513,26 +599,41 @@ localClient doneSignal = fst <$> mkRAcquire start stop
if rdEscape then if rdEscape then
if rdBracket then do if rdBracket then do
case c of case c of
'A' -> sendBelt $ Aro U 'A' -> sendBelt $ Bol $ Aro U
'B' -> sendBelt $ Aro D 'B' -> sendBelt $ Bol $ Aro D
'C' -> sendBelt $ Aro R 'C' -> sendBelt $ Bol $ Aro R
'D' -> sendBelt $ Aro L 'D' -> sendBelt $ Bol $ Aro L
'M' -> pure ()
_ -> bell _ -> bell
loop rd { rdEscape = False, rdBracket = False} rd <- case c of
'M' -> pure rd { rdMouse = True }
_ -> pure rd
loop rd { rdEscape = False, rdBracket = False }
else if isAsciiLower c then do else if isAsciiLower c then do
sendBelt $ Met $ Cord $ pack [c] sendBelt $ Mod Met $ Key c
loop rd { rdEscape = False }
else if c == '.' then do
sendBelt $ Met $ Cord "dot"
loop rd { rdEscape = False } loop rd { rdEscape = False }
else if w == 8 || w == 127 then do else if w == 8 || w == 127 then do
sendBelt $ Met $ Cord "bac" sendBelt $ Mod Met $ Bac ()
loop rd { rdEscape = False } loop rd { rdEscape = False }
else if c == '[' || c == '0' then do else if c == '[' || c == '0' then do
loop rd { rdBracket = True } loop rd { rdBracket = True }
else do else do
bell bell
loop rd { rdEscape = False } loop rd { rdEscape = False }
else if rdMouse then
if rdMouseBut == 0 then do
loop rd { rdMouseBut = w - 31 }
else if rdMouseCol == 0 then do
loop rd { rdMouseCol = w - 32 }
else do
if rdMouseBut == 1 then do
let rdMouseRow = w - 32
TermSize _ h <- readTVarIO ts
sendBelt $ Bol $ Hit
(fromIntegral h - fromIntegral rdMouseRow)
(fromIntegral rdMouseCol - 1)
else do pure ()
loop rd { rdMouse = False, rdMouseBut = 0, rdMouseCol = 0 }
else if rdUTF8width /= 0 then do else if rdUTF8width /= 0 then do
-- continue reading into the utf8 accumulation buffer -- continue reading into the utf8 accumulation buffer
rd@ReadData{..} <- pure rd { rdUTF8 = snoc rdUTF8 w } rd@ReadData{..} <- pure rd { rdUTF8 = snoc rdUTF8 w }
@ -543,30 +644,31 @@ localClient doneSignal = fst <$> mkRAcquire start stop
error "empty utf8 accumulation buffer" error "empty utf8 accumulation buffer"
Just (c, bytes) | bytes /= rdUTF8width -> Just (c, bytes) | bytes /= rdUTF8width ->
error "utf8 character size mismatch?!" error "utf8 character size mismatch?!"
Just (c, bytes) -> sendBelt $ Txt $ Tour $ [c] Just (c, bytes) -> sendBelt $ Bol $ Key c
loop rd { rdUTF8 = mempty, rdUTF8width = 0 } loop rd { rdUTF8 = mempty, rdUTF8width = 0 }
else if w >= 32 && w < 127 then do else if w >= 32 && w < 127 then do
sendBelt $ Txt $ Tour $ [c] sendBelt $ Bol $ Key c
loop rd loop rd
else if w == 0 then do else if w == 0 then do
bell bell
loop rd loop rd
else if w == 8 || w == 127 then do else if w == 8 || w == 127 then do
sendBelt $ Bac () sendBelt $ Bol $ Bac ()
loop rd loop rd
else if w == 13 then do else if w == 13 then do
sendBelt $ Ret () sendBelt $ Bol $ Ret ()
loop rd loop rd
else if w == 3 then do else if w == 3 then do
-- ETX (^C) -- ETX (^C)
logInfo $ "Ctrl-c interrupt" logInfo $ "Ctrl-c interrupt"
atomically $ do atomically $ do
writeTQueue wq [Term.Trace "interrupt\r\n"] writeTQueue wq [Term.Trace "interrupt"]
writeTQueue rq $ Ctl $ Cord "c" writeTQueue rq $ Mod Ctl $ Key 'c'
loop rd loop rd
else if w <= 26 then do else if w <= 26 then do
case pack [BS.w2c (w + 97 - 1)] of case BS.w2c (w + 97 - 1) of
c -> do sendBelt $ Ctl $ Cord c 'd' -> atomically doneSignal
c -> do sendBelt $ Mod Ctl $ Key c
loop rd loop rd
else if w == 27 then do else if w == 27 then do
loop rd { rdEscape = True } loop rd { rdEscape = True }
@ -643,7 +745,7 @@ term env (tsize, Client{..}) plan stat serfSIGINT = runTerm
atomically take >>= \case atomically take >>= \case
Nothing -> pure () Nothing -> pure ()
Just (ClientTakeBelt b) -> do Just (ClientTakeBelt b) -> do
when (b == Ctl (Cord "c")) $ do when (b == Mod Ctl (Key 'c')) $ do
io serfSIGINT io serfSIGINT
let beltEv = EvBlip $ BlipEvTerm $ TermEvBelt (UD 1, ()) $ b let beltEv = EvBlip $ BlipEvTerm $ TermEvBelt (UD 1, ()) $ b
let beltFailed _ = pure () let beltFailed _ = pure ()

View File

@ -22,7 +22,7 @@ import Urbit.TermSize
Input Event for terminal driver: Input Event for terminal driver:
%blits -- list of blits from arvo. %blits -- list of blits from arvo.
%trace -- stderr line from runtime. %trace -- stderr line from runtime (without trailing newline).
%slog -- nock worker logging with priority %slog -- nock worker logging with priority
%blank -- print a blank line %blank -- print a blank line
%spinr -- Start or stop the spinner %spinr -- Start or stop the spinner

View File

@ -39,11 +39,11 @@ data Ev
= EvLine Text = EvLine Text
| EvSlog (Atom, Tank) | EvSlog (Atom, Tank)
| EvSpin SpinnerState | EvSpin SpinnerState
| EvMove Word | EvMove (Word, Word)
| EvBell | EvBell
| EvDraw | EvDraw
| EvEdit Text | EvEdit Text
| EvMore | EvNewl
deriving (Show) deriving (Show)
data Ef data Ef
@ -62,7 +62,7 @@ data History
data St = St data St = St
{ sHistory :: !(Seq History) { sHistory :: !(Seq History)
, sLine :: !Text , sLine :: !Text
, sCurPos :: !Word , sCurPos :: !(Word, Word)
, sSpinner :: !SpinnerState , sSpinner :: !SpinnerState
} }
deriving (Show) deriving (Show)
@ -70,10 +70,10 @@ data St = St
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
init :: St init :: St
init = St mempty "" 0 Nothing init = St mempty "" (0, 0) Nothing
{-| {-|
When we process `EvMore`, we need to append a newline to the end of When we process `EvNewl`, we need to append a newline to the end of
the current line. During normal play, the ENTER key inserts the the current line. During normal play, the ENTER key inserts the
newline for us, so we need to recreate that newline when we rebuild newline for us, so we need to recreate that newline when we rebuild
the state for a new terminal connection. the state for a new terminal connection.
@ -83,15 +83,17 @@ step st@St{..} = \case
EvLine t -> st & recordText t EvLine t -> st & recordText t
EvSlog s -> st & recordSlog s EvSlog s -> st & recordSlog s
EvSpin s -> st { sSpinner = s } EvSpin s -> st { sSpinner = s }
EvMove w -> st { sCurPos = min w (word $ length sLine) } EvMove p -> st { sCurPos = p }
EvEdit t -> st { sLine = t, sCurPos = word (length t) }
EvMore -> st { sLine = "", sCurPos = 0 } & recordText (sLine <> "\n")
EvBell -> st EvBell -> st
EvDraw -> st EvDraw -> st
EvEdit t | (0, _) <- sCurPos -> st { sLine = t }
| otherwise -> st
EvNewl | (0, _) <- sCurPos ->
st { sLine = "", sCurPos = (0, 0) }
& recordText (sLine <> "\n")
| otherwise ->
st { sCurPos = (fst sCurPos - 1, 0) }
where where
word :: Integral i => i -> Word
word = fromIntegral
recordText :: Text -> St -> St recordText :: Text -> St -> St
recordText !t st@St{..} = st { recordText !t st@St{..} = st {
sHistory = trim (sHistory |> (HistoryText t)) sHistory = trim (sHistory |> (HistoryText t))
@ -111,8 +113,10 @@ drawState :: St -> [Ev]
drawState St{..} = hist <> out <> cur <> spin drawState St{..} = hist <> out <> cur <> spin
where where
hist = drawHistory <$> toList sHistory hist = drawHistory <$> toList sHistory
out = if null sLine then [] else [EvEdit sLine] out | null sLine = []
cur = if 0 == sCurPos then [] else [EvMove $ fromIntegral $ sCurPos] | otherwise = [EvEdit sLine]
cur | (0, _) <- sCurPos = []
| otherwise = [EvMove sCurPos]
spin = maybe [] (singleton . EvSpin . Just) sSpinner spin = maybe [] (singleton . EvSpin . Just) sSpinner
drawHistory (HistoryText t) = EvLine t drawHistory (HistoryText t) = EvLine t
@ -123,12 +127,13 @@ drawState St{..} = hist <> out <> cur <> spin
fromBlit :: Arvo.Blit -> Maybe Ev fromBlit :: Arvo.Blit -> Maybe Ev
fromBlit = \case fromBlit = \case
Arvo.Hop w -> Just $ EvMove $ fromIntegral w Arvo.Hop (Arvo.Col c) -> Just $ EvMove (0, fromIntegral c)
Arvo.Bel () -> Just EvBell Arvo.Hop (Arvo.Roc r c) -> Just $ EvMove (fromIntegral r, fromIntegral c)
Arvo.Clr () -> Just EvDraw Arvo.Bel () -> Just EvBell
Arvo.Lin s -> Just $ EvEdit (pack s) Arvo.Clr () -> Just EvDraw
Arvo.Mor () -> Just EvMore Arvo.Put s -> Just $ EvEdit (pack s)
_ -> Nothing Arvo.Nel () -> Just EvNewl
_ -> Nothing
toCause :: Maybe Cord -> SpinnerCause toCause :: Maybe Cord -> SpinnerCause
toCause Nothing = User toCause Nothing = User
@ -148,12 +153,12 @@ fromTermEv = \case
toTermEv :: Ev -> Term.Ev toTermEv :: Ev -> Term.Ev
toTermEv = \case toTermEv = \case
EvLine "" -> Term.Blank EvLine "" -> Term.Blank
EvLine t -> Term.Trace (Cord t) EvLine t -> Term.Trace (Cord t)
EvSlog s -> Term.Slog s EvSlog s -> Term.Slog s
EvSpin s -> Term.Spinr (fromCause <$> s) EvSpin s -> Term.Spinr (fromCause <$> s)
EvMove w -> Term.Blits [Arvo.Hop $ fromIntegral w] EvMove (r, c) -> Term.Blits [Arvo.Hop $ Arvo.Roc (fromIntegral r) (fromIntegral c)]
EvBell -> Term.Blits [Arvo.Bel ()] EvBell -> Term.Blits [Arvo.Bel ()]
EvDraw -> Term.Blits [Arvo.Clr ()] EvDraw -> Term.Blits [Arvo.Clr ()]
EvEdit t -> Term.Blits [Arvo.Lin $ unpack t] EvEdit t -> Term.Blits [Arvo.Put $ unpack t]
EvMore -> Term.Blits [Arvo.Mor ()] EvNewl -> Term.Blits [Arvo.Nel ()]

View File

@ -4,9 +4,12 @@
module Urbit.Vere.Term.Render module Urbit.Vere.Term.Render
( clearScreen ( clearScreen
, clearLine , clearLine
, cursorRight
, cursorLeft
, soundBell , soundBell
, cursorMove
, cursorSave
, cursorRestore
, putCsi
, hijack
) where ) where
import Urbit.Prelude import Urbit.Prelude
@ -25,8 +28,27 @@ clearLine = liftIO $ ANSI.clearLine
soundBell :: MonadIO m => m () soundBell :: MonadIO m => m ()
soundBell = liftIO $ putStr "\a" soundBell = liftIO $ putStr "\a"
cursorLeft :: MonadIO m => Int -> m () --NOTE top-left-0-based coordinates
cursorLeft = liftIO . ANSI.cursorBackward cursorMove :: MonadIO m => Int -> Int -> m ()
cursorMove r c = liftIO $ ANSI.setCursorPosition r c
cursorRight :: MonadIO m => Int -> m () cursorSave :: MonadIO m => m ()
cursorRight = liftIO . ANSI.cursorForward cursorSave = liftIO ANSI.saveCursor
cursorRestore :: MonadIO m => m ()
cursorRestore = liftIO ANSI.restoreCursor
putCsi :: MonadIO m => Char -> [Int] -> m ()
putCsi c a = liftIO do
putStr "\x1b["
putStr $ pack $ mconcat $ intersperse ";" (fmap show a)
putStr $ pack [c]
hijack :: MonadIO m => Int -> IO () -> m ()
hijack h d = liftIO do
putCsi 'r' [1, h-1] -- set scroll region to exclude bottom line
putCsi 'S' [1] -- scroll up one line
cursorMove (h-2) 0 -- move cursor to empty space
d
putCsi 'r' [] -- reset scroll region
cursorRestore -- restory cursor position

View File

@ -158,6 +158,7 @@ a {
@media all and (prefers-color-scheme: dark) { @media all and (prefers-color-scheme: dark) {
body { body {
background-color: #333; background-color: #333;
color: white;
} }
.bg-black-d { .bg-black-d {
background-color: black; background-color: black;

View File

@ -0,0 +1,23 @@
module.exports = exports = {
"rules": {
"spaced-comment": 0,
},
"extends": [
"eslint:recommended",
"plugin:import/errors",
"plugin:react/recommended",
],
"settings": {
"react": {
"version": "detect"
},
"import/resolver": {
typescript: {} // this loads <rootdir>/tsconfig.json to eslint
},
},
"env": {
"browser": true,
"es6": true
},
"plugins": ["import", "react-hooks"]
}

View File

@ -0,0 +1 @@
16.14.0

View File

@ -0,0 +1,94 @@
import React, {
useCallback, useEffect
} from 'react';
import useTermState from './state';
import { useDark } from './lib/useDark';
import api from './api';
import { _dark, _light } from '@tlon/indigo-react';
import 'xterm/css/xterm.css';
import {
scrySessions
} from '@urbit/api/term';
import { ThemeProvider } from 'styled-components';
import { Tabs } from './Tabs';
import Buffer from './Buffer';
import { DEFAULT_SESSION } from './constants';
import { showSlog } from './lib/blit';
import { InfoButton } from './InfoButton';
const initSessions = async () => {
const response = await api.scry(scrySessions());
useTermState.getState().set((state) => {
state.names = response.sort();
});
};
export default function TermApp() {
const { names, selected } = useTermState();
const dark = useDark();
const setupSlog = useCallback(() => {
console.log('slog: setting up...');
let available = false;
const slog = new EventSource('/~_~/slog', { withCredentials: true });
slog.onopen = () => {
console.log('slog: opened stream');
available = true;
};
slog.onmessage = (e) => {
const session = useTermState.getState().sessions[DEFAULT_SESSION];
if (!session) {
console.log('slog: default session mia!', 'msg:', e.data);
console.log(Object.keys(useTermState.getState().sessions), session);
return;
}
showSlog(session.term, e.data);
};
slog.onerror = (e) => {
console.error('slog: eventsource error:', e);
if (available) {
window.setTimeout(() => {
if (slog.readyState !== EventSource.CLOSED) {
return;
}
console.log('slog: reconnecting...');
setupSlog();
}, 10000);
}
};
useTermState.getState().set((state) => {
state.slogstream = slog;
});
}, []);
useEffect(() => {
initSessions();
setupSlog();
}, []);
return (
<>
<ThemeProvider theme={dark ? _dark : _light}>
<div className="header">
<Tabs />
<InfoButton />
</div>
<div className="buffer-container">
{names.map((name) => {
return <Buffer key={name} name={name} selected={name === selected} dark={dark} />;
})}
</div>
</ThemeProvider>
</>
);
}

View File

@ -0,0 +1,350 @@
import { Terminal, ITerminalOptions } from 'xterm';
import { FitAddon } from 'xterm-addon-fit';
import { debounce } from 'lodash';
import bel from './lib/bel';
import api from './api';
import {
Belt, pokeTask, pokeBelt
} from '@urbit/api/term';
import { Session } from './state';
import { useCallback, useEffect, useRef } from 'react';
import useTermState from './state';
import React from 'react';
import { Box, Col } from '@tlon/indigo-react';
import { makeTheme } from './lib/theme';
import { showBlit, csi, hasBell } from './lib/blit';
import { DEFAULT_SESSION, RESIZE_DEBOUNCE_MS, RESIZE_THRESHOLD_PX } from './constants';
import { retry } from './lib/retry';
const termConfig: ITerminalOptions = {
logLevel: 'warn',
//
convertEol: true,
//
rows: 24,
cols: 80,
scrollback: 10000,
//
fontFamily: '"Source Code Pro", "Roboto mono", "Courier New", monospace',
fontWeight: 400,
// NOTE theme colors configured dynamically
//
bellStyle: 'sound',
bellSound: bel,
//
// allows text selection by holding modifier (option, or shift)
macOptionClickForcesSelection: true,
// prevent insertion of simulated arrow keys on-altclick
altClickMovesCursor: false
};
const readInput = (term: Terminal, e: string): Belt[] => {
const belts: Belt[] = [];
let strap = '';
while (e.length > 0) {
let c = e.charCodeAt(0);
// text input
//
if (c >= 32 && c !== 127) {
strap += e[0];
e = e.slice(1); //TODO revisit wrt (list @c) & unicode characters
continue;
} else if ('' !== strap) {
belts.push({ txt: strap.split('') });
strap = '';
}
// special keys/characters
//
if (0 === c) {
term.write('\x07'); // bel
} else if (8 === c || 127 === c) {
belts.push({ bac: null });
} else if (13 === c) {
belts.push({ ret: null });
} else if (c <= 26) {
const k = String.fromCharCode(96 + c);
//NOTE prevent remote shut-downs
if ('d' !== k) {
belts.push({ mod: { mod: 'ctl', key: k } });
}
}
// escape sequences
//
if (27 === c) { // ESC
e = e.slice(1);
c = e.charCodeAt(0);
if (91 === c || 79 === c) { // [ or O
e = e.slice(1);
c = e.charCodeAt(0);
/* eslint-disable max-statements-per-line */
switch (c) {
case 65: belts.push({ aro: 'u' }); break;
case 66: belts.push({ aro: 'd' }); break;
case 67: belts.push({ aro: 'r' }); break;
case 68: belts.push({ aro: 'l' }); break;
//
case 77: {
const m = e.charCodeAt(1) - 31;
if (1 === m) {
const c = e.charCodeAt(2) - 32;
const r = e.charCodeAt(3) - 32;
belts.push({ hit: { y: r - 1, x: c - 1 } });
}
e = e.slice(3);
break;
}
//
default: term.write('\x07'); break; // bel
}
} else if (c >= 97 && c <= 122) { // a <= c <= z
belts.push({ mod: { mod: 'met', key: e[0] } });
} else if (c === 46) { // .
belts.push({ mod: { mod: 'met', key: '.' } });
} else if (c === 8 || c === 127) {
belts.push({ mod: { mod: 'met', key: { bac: null } } });
} else {
term.write('\x07'); break; // bel
}
}
e = e.slice(1);
}
if ('' !== strap) {
if (1 === strap.length) {
belts.push(strap);
} else {
belts.push({ txt: strap.split('') });
}
strap = '';
}
return belts;
};
const onResize = async (name: string, session: Session) => {
if (session) {
session.fit.fit();
useTermState.getState().set((state) => {
state.sessions[name].pending++;
});
api.poke(pokeTask(name, { blew: { w: session.term.cols, h: session.term.rows } })).then(() => {
useTermState.getState().set((state) => {
state.sessions[name].pending--;
});
});
}
};
const onInput = (name: string, session: Session, e: string) => {
if (!session) {
return;
}
const term = session.term;
const belts = readInput(term, e);
belts.forEach((b) => {
useTermState.getState().set((state) => {
state.sessions[name].pending++;
});
api.poke(pokeBelt(name, b)).then(() => {
useTermState.getState().set((state) => {
state.sessions[name].pending--;
});
});
});
};
interface BufferProps {
name: string,
selected: boolean,
dark: boolean,
}
export default function Buffer({ name, selected, dark }: BufferProps) {
const containerRef = useRef<HTMLDivElement | null>(null);
const session: Session = useTermState(s => s.sessions[name]);
const initSession = useCallback(async (name: string, dark: boolean) => {
console.log('setting up', name === DEFAULT_SESSION ? 'default' : name);
// set up xterm terminal
//
const term = new Terminal(termConfig);
term.options.theme = makeTheme(dark);
const fit = new FitAddon();
term.loadAddon(fit);
fit.fit();
term.focus();
// start mouse reporting
//
term.write(csi('?9h'));
const ses: Session = {
term,
fit,
hasBell: false,
pending: 0,
subscriptionId: null
};
// set up event handlers
//
term.attachCustomKeyEventHandler((e: KeyboardEvent) => {
//NOTE ctrl+shift keypresses never make it into term.onData somehow,
// so we handle them specially ourselves.
// we may be able to remove this once xterm.js fixes #3382 & co.
if (e.shiftKey
&& e.ctrlKey
&& e.type === 'keydown'
&& e.key.length === 1
) {
api.poke(pokeBelt(name, { mod: { mod: 'ctl', key: e.key } }));
return false;
}
return true;
});
term.onData(e => onInput(name, ses, e));
term.onBinary(e => onInput(name, ses, e));
// open subscription
//
const initSubscription = async () => {
const subscriptionId = await api.subscribe({
app: 'herm', path: '/session/' + name + '/view',
event: (e) => {
showBlit(ses.term, e);
//NOTE getting selected from state because selected prop is stale
if (hasBell(e) && (useTermState.getState().selected !== name)) {
useTermState.getState().set((state) => {
state.sessions[name].hasBell = true;
});
}
//TODO should handle %bye on this higher level though, for deletion
},
err: (e, id) => {
console.log(`subscription error, id ${id}:`, e);
},
quit: async () => { // quit
console.error('quit, reconnecting...');
try {
const newSubscriptionId = await retry(initSubscription, () => {
console.log('attempting to reconnect ...');
}, 5);
useTermState.getState().set((state) => {
state.sessions[name].subscriptionId = newSubscriptionId;
});
} catch (error) {
console.log('unable to reconnect', error);
}
}
});
return subscriptionId;
};
ses.subscriptionId = await initSubscription();
useTermState.getState().set((state) => {
state.sessions[name] = ses;
});
}, []);
const shouldResize = useCallback(() => {
if(!session) {
return false;
}
const containerHeight = document.querySelector('.buffer-container')?.clientHeight || Infinity;
const terminalHeight = session.term.element?.clientHeight || 0;
return (containerHeight - terminalHeight) >= RESIZE_THRESHOLD_PX;
}, [session]);
const onSelect = useCallback(async () => {
if (session && selected && shouldResize()) {
session.fit.fit();
await api.poke(pokeTask(name, { blew: { w: session.term.cols, h: session.term.rows } }));
session.term.focus();
}
}, [session?.term, selected]);
// Effects
// init session
useEffect(() => {
if(session) {
return;
}
initSession(name, dark);
}, [name]);
// attach to DOM when ref is available
useEffect(() => {
if(session && containerRef.current && !session.term.element) {
session.term.open(containerRef.current);
}
}, [session, containerRef]);
// initialize resize listeners
//
useEffect(() => {
if(!session) {
return;
}
// TODO: use ResizeObserver for improved performance?
const debouncedResize = debounce(() => onResize(name, session), RESIZE_DEBOUNCE_MS);
window.addEventListener('resize', debouncedResize);
return () => {
window.removeEventListener('resize', debouncedResize);
};
}, [session]);
// on dark mode change, change terminals' theme
//
useEffect(() => {
const theme = makeTheme(dark);
if (session) {
session.term.options.theme = theme;
}
if (containerRef.current) {
containerRef.current.style.backgroundColor = theme.background || '';
}
}, [session, dark]);
// On select, resize, focus, and poke herm with updated cols and rows
useEffect(() => {
onSelect();
}, [onSelect]);
return (
!session && !selected ?
<p>Loading...</p>
:
<Box
width='100%'
height='100%'
bg='white'
fontFamily='mono'
overflow='hidden'
className="terminal-container"
style={selected ? { zIndex: 999 } : {}}
>
<Col
width='100%'
height='100%'
minHeight='0'
px={['0', '2']}
pb={['0', '2']}
ref={containerRef}
>
</Col>
</Box>
);
}

View File

@ -0,0 +1,24 @@
import React, { useCallback } from 'react';
import { Icon } from '@tlon/indigo-react';
import { useDetectOS } from './lib/useDetectOS';
export const InfoButton = () => {
const { isMacOS } = useDetectOS();
const onInfoClick = useCallback(() => {
const key = isMacOS ? 'alt' : 'shift';
alert(`To select text in the terminal, hold down the ${key} key.`);
}, [isMacOS]);
return (
<>
<button className="info-btn" onClick={onInfoClick}>
<Icon
icon="Info"
size="18px"
/>
</button>
</>
);
};

View File

@ -0,0 +1,55 @@
import useIsMounted from './lib/useIsMounted';
import React from 'react';
import { useEffect, useState } from 'react';
const DELAY_MS = 1000;
const FRAME_MS = 250;
const CHARS = '|/-\\';
const Spinner = () => {
const [index, setIndex] = useState(0);
const [intervalTimer, setIntervalTimer] = useState<ReturnType<typeof setInterval> | undefined>();
const isMounted = useIsMounted();
useEffect(() => {
setIntervalTimer(
setInterval(() => {
if (isMounted()) {
setIndex(idx => idx === CHARS.length - 1 ? 0 : idx + 1);
}
}, FRAME_MS)
);
return () => {
if (intervalTimer) {
clearInterval(intervalTimer);
}
};
}, []);
return <span>&nbsp;{CHARS[index]}</span>;
};
export const DelayedSpinner = () => {
const [showSpinner, setShowSpinner] = useState(false);
const [delayTimer, setDelayTimer] = useState<ReturnType<typeof setTimeout> | undefined>();
const isMounted = useIsMounted();
useEffect(() => {
setDelayTimer(
setTimeout(() => {
if (isMounted()) {
setShowSpinner(true);
}
}, DELAY_MS)
);
return () => {
if (delayTimer) {
clearTimeout(delayTimer);
}
};
}, []);
return showSpinner ? <Spinner /> : null;
};

View File

@ -0,0 +1,55 @@
import { DEFAULT_SESSION } from './constants';
import React, { useCallback, useEffect } from 'react';
import useTermState, { Session } from './state';
import api from './api';
import { pokeTask } from '@urbit/api/term';
import { DelayedSpinner as Spinner } from './Spinner';
interface TabProps {
session: Session;
name: string;
}
export const Tab = ( { session, name }: TabProps ) => {
const isSelected = useTermState().selected === name;
const onClick = () => {
useTermState.getState().set((state) => {
state.selected = name;
state.sessions[name].hasBell = false;
});
};
const onDelete = useCallback(async (e) => {
e.stopPropagation();
// clean up subscription
if(session && session.subscriptionId) {
await api.unsubscribe(session.subscriptionId);
}
// DELETE
await api.poke(pokeTask(name, { shut: null }));
// remove from zustand
useTermState.getState().set((state) => {
if (state.selected === name) {
state.selected = DEFAULT_SESSION;
}
state.names = state.names.filter(n => n !== name);
delete state.sessions[name];
});
}, [session]);
return (
<div className={'tab ' + (isSelected ? 'selected' : '')} onClick={onClick}>
<a className='session-name'>
{session?.hasBell ? '🔔 ' : ''}
{name === DEFAULT_SESSION ? 'default' : name}
{session && session.pending > 0 ? <Spinner /> : null}
{' '}
</a>
{name === DEFAULT_SESSION ? null : <a className="delete-session" onClick={onDelete}>x</a>}
</div>
);
};

View File

@ -0,0 +1,26 @@
import React from 'react';
import useTermState from './state';
import { Tab } from './Tab';
import { useAddSession } from './lib/useAddSession';
import { Icon } from '@tlon/indigo-react';
export const Tabs = () => {
const { sessions, names } = useTermState();
const addSession = useAddSession();
return (
<div className="tabs">
{names.map((n, i) => {
return (
<Tab session={sessions[n]} name={n} key={i} />
);
})}
<button className="tab" onClick={addSession}>
<Icon
icon="Plus"
size="18px"
/>
</button>
</div>
);
};

View File

@ -1,475 +0,0 @@
/* eslint-disable max-lines */
import React, {
useEffect,
useRef,
useCallback
} from 'react';
import useTermState from './state';
import { useDark } from './join';
import api from './api';
import { Terminal, ITerminalOptions, ITheme } from 'xterm';
import { FitAddon } from 'xterm-addon-fit';
import { saveAs } from 'file-saver';
import { Box, Col, Reset, _dark, _light } from '@tlon/indigo-react';
import 'xterm/css/xterm.css';
import {
Belt, Blit, Stye, Stub, Tint, Deco,
pokeTask, pokeBelt
} from '@urbit/api/term';
import bel from './lib/bel';
import { ThemeProvider } from 'styled-components';
type TermAppProps = {
ship: string;
}
const makeTheme = (dark: boolean): ITheme => {
let fg, bg: string;
if (dark) {
fg = 'white';
bg = 'rgb(26,26,26)';
} else {
fg = 'black';
bg = 'white';
}
// TODO indigo colors.
// we can't pluck these from ThemeContext because they have transparency.
// technically xterm supports transparency, but it degrades performance.
return {
foreground: fg,
background: bg,
brightBlack: '#7f7f7f', // NOTE slogs
cursor: fg,
cursorAccent: bg,
selection: fg
};
};
const termConfig: ITerminalOptions = {
logLevel: 'warn',
//
convertEol: true,
//
rows: 24,
cols: 80,
scrollback: 10000,
//
fontFamily: '"Source Code Pro", "Roboto mono", "Courier New", monospace',
fontWeight: 400,
// NOTE theme colors configured dynamically
//
bellStyle: 'sound',
bellSound: bel,
//
// allows text selection by holding modifier (option, or shift)
macOptionClickForcesSelection: true,
// prevent insertion of simulated arrow keys on-altclick
altClickMovesCursor: false
};
const csi = (cmd: string, ...args: number[]) => {
return '\x1b[' + args.join(';') + cmd;
};
const tint = (t: Tint) => {
switch (t) {
case null: return '9';
case 'k': return '0';
case 'r': return '1';
case 'g': return '2';
case 'y': return '3';
case 'b': return '4';
case 'm': return '5';
case 'c': return '6';
case 'w': return '7';
default: return `8;2;${t.r%256};${t.g%256};${t.b%256}`;
}
};
const stye = (s: Stye) => {
let out = '';
// text decorations
//
if (s.deco.length > 0) {
out += s.deco.reduce((decs: number[], deco: Deco) => {
/* eslint-disable max-statements-per-line */
switch (deco) {
case null: decs.push(0); return decs;
case 'br': decs.push(1); return decs;
case 'un': decs.push(4); return decs;
case 'bl': decs.push(5); return decs;
default: console.log('weird deco', deco); return decs;
}
}, []).join(';');
}
// background color
//
if (s.back !== null) {
if (out !== '') {
out += ';';
}
out += '4';
out += tint(s.back);
}
// foreground color
//
if (s.fore !== null) {
if (out !== '') {
out += ';';
}
out += '3';
out += tint(s.fore);
}
if (out === '') {
return out;
}
return '\x1b[' + out + 'm';
};
const showBlit = (term: Terminal, blit: Blit) => {
let out = '';
if ('bel' in blit) {
out += '\x07';
} else if ('clr' in blit) {
term.clear();
out += csi('u');
} else if ('hop' in blit) {
if (typeof blit.hop === 'number') {
out += csi('H', term.rows, blit.hop + 1);
} else {
out += csi('H', term.rows - blit.hop.r, blit.hop.c + 1);
}
out += csi('s'); // save cursor position
} else if ('put' in blit) {
out += blit.put.join('');
out += csi('u');
} else if ('klr' in blit) {
//TODO remove for new backend
{
out += csi('H', term.rows, 1);
out += csi('K');
}
out += blit.klr.reduce((lin: string, p: Stub) => {
lin += stye(p.stye);
lin += p.text.join('');
lin += csi('m', 0);
return lin;
}, '');
out += csi('u');
} else if ('nel' in blit) {
out += '\n';
} else if ('sag' in blit || 'sav' in blit) {
const sav = ('sag' in blit) ? blit.sag : blit.sav;
const name = sav.path.split('/').slice(-2).join('.');
const buff = Buffer.from(sav.file, 'base64');
const blob = new Blob([buff], { type: 'application/octet-stream' });
saveAs(blob, name);
} else if ('url' in blit) {
window.open(blit.url);
} else if ('wyp' in blit) {
out += '\r' + csi('K');
out += csi('u');
//
//TODO remove for new backend
} else if ('lin' in blit) {
out += csi('H', term.rows, 1);
out += csi('K');
out += blit.lin.join('');
} else if ('mor' in blit) {
out += '\n';
} else {
console.log('weird blit', blit);
}
term.write(out);
};
// NOTE should generally only be passed the default terminal session
const showSlog = (term: Terminal, slog: string) => {
// set scroll region to exclude the bottom line,
// scroll up one line,
// move cursor to start of the newly created whitespace,
// set text to grey,
// print the slog,
// restore color, scroll region, and cursor.
//
term.write(csi('r', 1, term.rows - 1)
+ csi('S', 1)
+ csi('H', term.rows - 1, 1)
+ csi('m', 90)
+ slog
+ csi('m', 0)
+ csi('r')
+ csi('u'));
};
const readInput = (term: Terminal, e: string): Belt[] => {
const belts: Belt[] = [];
let strap = '';
while (e.length > 0) {
let c = e.charCodeAt(0);
// text input
//
if (c >= 32 && c !== 127) {
strap += e[0];
e = e.slice(1);
continue;
} else if ('' !== strap) {
belts.push({ txt: strap.split('') });
strap = '';
}
// special keys/characters
//
if (0 === c) {
term.write('\x07'); // bel
} else if (8 === c || 127 === c) {
belts.push({ bac: null });
} else if (13 === c) {
belts.push({ ret: null });
} else if (c <= 26) {
let k = String.fromCharCode(96 + c);
//NOTE prevent remote shut-downs
if ('d' !== k) {
belts.push({ ctl: k });
//TODO for new backend
// belts.push({ mod: { mod: 'ctl', key: k } });
}
}
// escape sequences
//
if (27 === c) { // ESC
e = e.slice(1);
c = e.charCodeAt(0);
if (91 === c || 79 === c) { // [ or O
e = e.slice(1);
c = e.charCodeAt(0);
/* eslint-disable max-statements-per-line */
switch (c) {
case 65: belts.push({ aro: 'u' }); break;
case 66: belts.push({ aro: 'd' }); break;
case 67: belts.push({ aro: 'r' }); break;
case 68: belts.push({ aro: 'l' }); break;
//
case 77: {
const m = e.charCodeAt(1) - 31;
if (1 === m) {
const c = e.charCodeAt(2) - 32;
const r = e.charCodeAt(3) - 32;
//TODO re-enable for new backend
// belts.push({ hit: { r: term.rows - r, c: c - 1 } });
}
e = e.slice(3);
break;
}
//
default: term.write('\x07'); break; // bel
}
} else if (c >= 97 && c <= 122) { // a <= c <= z
belts.push({ mod: { mod: 'met', key: e[0] } });
} else if (c === 46) { // .
belts.push({ mod: { mod: 'met', key: '.' } });
} else if (c === 8 || c === 127) {
belts.push({ mod: { mod: 'met', key: { bac: null } } });
} else {
term.write('\x07'); break; // bel
}
}
e = e.slice(1);
}
if ('' !== strap) {
belts.push({ txt: strap.split('') });
strap = '';
}
return belts;
};
export default function TermApp(props: TermAppProps) {
const container = useRef<HTMLDivElement>(null);
// TODO allow switching of selected
const { sessions, selected, slogstream, set } = useTermState();
const session = sessions[selected];
const dark = useDark();
const setupSlog = useCallback(() => {
console.log('slog: setting up...');
let available = false;
const slog = new EventSource('/~_~/slog', { withCredentials: true });
slog.onopen = (e) => {
console.log('slog: opened stream');
available = true;
};
slog.onmessage = (e) => {
const session = useTermState.getState().sessions[''];
if (!session) {
console.log('default session mia!', 'slog:', slog);
return;
}
showSlog(session.term, e.data);
};
slog.onerror = (e) => {
console.error('slog: eventsource error:', e);
if (available) {
window.setTimeout(() => {
if (slog.readyState !== EventSource.CLOSED) {
return;
}
console.log('slog: reconnecting...');
setupSlog();
}, 10000);
}
};
set((state) => {
state.slogstream = slog;
});
}, [sessions]);
const onInput = useCallback((ses: string, e: string) => {
const term = useTermState.getState().sessions[ses].term;
const belts = readInput(term, e);
belts.map((b) => { // NOTE passing api.poke(pokeBelt makes `this` undefined!
//TODO pokeBelt(ses, b);
api.poke({
app: 'herm',
mark: 'belt',
json: b
});
});
}, [sessions]);
const onResize = useCallback(() => {
// TODO debounce, if it ever becomes a problem
session?.fit.fit();
}, [session]);
// on-init, open slogstream
//
useEffect(() => {
if (!slogstream) {
setupSlog();
}
window.addEventListener('resize', onResize);
return () => {
// TODO clean up subs?
window.removeEventListener('resize', onResize);
};
}, [onResize, setupSlog]);
// on dark mode change, change terminals' theme
//
useEffect(() => {
const theme = makeTheme(dark);
for (const ses in sessions) {
sessions[ses].term.setOption('theme', theme);
}
if (container.current) {
container.current.style.backgroundColor = theme.background || '';
}
}, [dark, sessions]);
// on selected change, maybe setup the term, or put it into the container
//
useEffect(() => {
let ses = session;
// initialize terminal
//
if (!ses) {
// set up terminal
//
const term = new Terminal(termConfig);
term.setOption('theme', makeTheme(dark));
const fit = new FitAddon();
term.loadAddon(fit);
// start mouse reporting
//
term.write(csi('?9h'));
// set up event handlers
//
term.onData(e => onInput(selected, e));
term.onBinary(e => onInput(selected, e));
term.onResize((e) => {
//TODO re-enable once new backend lands
// api.poke(pokeTask(selected, { blew: { w: e.cols, h: e.rows } }));
});
ses = { term, fit };
// open subscription
//
api.subscribe({ app: 'herm', path: '/session/'+selected+'/view',
event: (e) => {
const ses = useTermState.getState().sessions[selected];
if (!ses) {
console.log('on blit: no such session', selected, sessions, useTermState.getState().sessions);
return;
}
showBlit(ses.term, e);
},
quit: () => { // quit
// TODO show user a message
}
});
}
if (container.current && !container.current.contains(ses.term.element || null)) {
ses.term.open(container.current);
ses.fit.fit();
ses.term.focus();
}
set((state) => {
state.sessions[selected] = ses;
});
return () => {
// TODO unload term from container
// but term.dispose is too powerful? maybe just empty the container?
};
}, [set, session, container]);
return (
<>
<ThemeProvider theme={dark ? _dark : _light}>
<Reset />
<Box
width='100%'
height='100%'
bg='white'
fontFamily='mono'
overflow='hidden'
>
<Col
width='100%'
height='100%'
minHeight='0'
px={['0','2']}
pb={['0','2']}
ref={container}
>
</Col>
</Box>
</ThemeProvider>
</>
);
}

View File

@ -0,0 +1,28 @@
export const DEFAULT_SESSION = '';
export const DEFAULT_HANDLER = 'hood';
export const RESIZE_DEBOUNCE_MS = 100;
export const RESIZE_THRESHOLD_PX = 15;
/**
* Session ID validity:
*
* - must start with an alphabetical
* - can be composed of alphanumerics with hyphens
* - can be length 1 or longer
*/
export const SESSION_ID_REGEX = /(^[a-z]{1}[a-z\d-]*$)/;
/**
* Open a session with a given agent using `[agent]![session_name]`
*
* For example:
* ```
* book!my-session
* ```
*
* This will create a new session in webterm for the `%book` agent.
*
* Note that the second capture group after the ! is composed of the session ID
* regex above.
*/
export const AGENT_SESSION_REGEX = /^([a-z]{1}[a-z\d-]*)!([a-z]{1}[a-z\d-]*$)/;

View File

@ -23,10 +23,113 @@
<link href="https://fonts.googleapis.com/css2?family=Source+Code+Pro&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Source+Code+Pro&display=swap" rel="stylesheet">
<style> <style>
body, #root { body, #root {
height: 100vh; height: 99vh; /* prevent scrollbar on outer frame */
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
.buffer-container {
height: calc(100% - 40px);
position: relative;
}
.terminal-container {
position: absolute;
top: 0;
}
div.header {
display: grid;
grid-template-areas: "tabs info";
grid-template-columns: auto min-content;
grid-template-rows: auto;
}
div.info {
grid-area: info;
}
div.tabs {
grid-area: tabs;
height: 40px;
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
padding: 5px 5px 0 5px;
border-bottom: 1px solid black;
background-color: white;
}
div.tabs > * {
margin-left: 5px;
margin-right: 5px;
border: solid 1px black;
padding: 10px;
cursor: pointer;
}
div.tab, button.tab {
margin-bottom: -1px; /** To overlay the selected tab on the tabs container bottom border */
border-top-left-radius: 5px;
border-top-right-radius: 5px;
font-family: monospace;
font-size: 14px;
line-height: 18px;
}
div.tabs > div.selected {
border-bottom: white solid 1px;
}
div.tabs > div.selected > a.session-name {
font-weight: bold;
}
div.tabs > a.delete-session {
padding: 5px;
}
button.info-btn {
border: none;
border-bottom: solid black 1px;
background: transparent;
padding: 10px;
line-height: 10px;
cursor: pointer;
}
@media (prefers-color-scheme: dark) {
html {
background-color: rgb(26,26,26);
}
div.tabs {
background-color: rgb(26, 26, 26);
color: rgba(255, 255, 255, 0.9);
border-bottom-color: rgba(255, 255, 255, 0.9);
}
div.tab {
background-color: rgb(26, 26, 26);
color: rgba(255, 255, 255, 0.9);
border-color: rgba(255, 255, 255, 0.9);
}
button.tab {
background-color: rgb(42, 42, 42);
color: rgba(255, 255, 255, 0.9);
border-color: rgba(255, 255, 255, 0.9);
}
div.tabs > div.selected {
border-bottom: rgb(26,26,26) solid 1px;
}
button.info-btn {
border-bottom: solid rgba(255, 255, 255, 0.9) 1px;
background: rgb(26, 26, 26);
}
}
</style> </style>
</head> </head>
<body> <body>

View File

@ -0,0 +1,129 @@
import { Terminal } from 'xterm';
import { saveAs } from 'file-saver';
import { Blit, Stub, Stye } from '@urbit/api/term';
import { stye } from '../lib/stye';
export const csi = (cmd: string, ...args: number[]) => {
return '\x1b[' + args.join(';') + cmd;
};
export const showBlit = (term: Terminal, blit: Blit) => {
let out = '';
if ('mor' in blit) {
return blit.mor.map(b => showBlit(term, b));
} else if ('bel' in blit) {
out += '\x07';
} else if ('clr' in blit) {
term.clear();
out += csi('u');
} else if ('hop' in blit) {
if (typeof blit.hop === 'number') {
out += csi('H', term.rows, blit.hop + 1);
} else {
out += csi('H', blit.hop.y + 1, blit.hop.x + 1);
}
out += csi('s'); // save cursor position
} else if ('put' in blit) {
out += blit.put.join('');
out += csi('u');
} else if ('klr' in blit) {
out += blit.klr.reduce((lin: string, p: Stub) => {
lin += stye(p.stye);
lin += p.text.join('');
lin += csi('m', 0);
return lin;
}, '');
out += csi('u');
} else if ('nel' in blit) {
out += '\n';
} else if ('sag' in blit || 'sav' in blit) {
const sav = ('sag' in blit) ? blit.sag : blit.sav;
const name = sav.path.split('/').slice(-2).join('.');
const buff = Buffer.from(sav.file, 'base64');
const blob = new Blob([buff], { type: 'application/octet-stream' });
saveAs(blob, name);
} else if ('url' in blit) {
window.open(blit.url);
} else if ('wyp' in blit) {
out += '\r' + csi('K');
out += csi('u');
//
} else {
console.log('weird blit', blit);
}
term.write(out);
};
export const showSlog = (term: Terminal, slog: string) => {
// set scroll region to exclude the bottom line,
// scroll up one line,
// move cursor to start of the newly created whitespace,
// set text to grey,
// print the slog,
// restore color, scroll region, and cursor.
//
term.write(csi('r', 1, term.rows - 1)
+ csi('S', 1)
+ csi('H', term.rows - 1, 1)
+ csi('m', 90)
+ slog
+ csi('m', 0)
+ csi('r')
+ csi('u'));
};
export const hasBell = (blit: Blit) => {
if ('bel' in blit) {
return true;
} else if ('mor' in blit) {
return blit.mor.some(hasBell);
} else {
return false;
}
};
// debug rendering
//NOTE doesn't behave nicely in the presence of eob %nel blits,
// because those aren't idempotent
const blotStye: Stye = { deco: [], back: { r: 255, g: 0, b: 255 }, fore: 'k' };
const blitToBlot = (blit: Blit): Blit => {
if ('mor' in blit) {
return { mor: blit.mor.map(blitToBlot) };
} else if ('put' in blit) {
return { klr: [{ text: blit.put, stye: blotStye }] };
} else if ('klr' in blit) {
return { klr: blit.klr.map((s: Stub) => {
return { text: s.text, stye: blotStye };
}) };
} else {
return blit;
}
};
const queue: {term: Terminal, blit: Blit}[] = [];
const renderFromQueue = () => {
const next = queue.shift();
if (!next) {
return;
}
showBlit(next.term, next.blit);
if (0 === queue.length) {
return;
}
setTimeout(renderFromQueue, 200);
};
export const showBlitDebug = (term: Terminal, blit: Blit) => {
const blot = blitToBlot(blit);
if (0 === queue.length) {
showBlit(term, blot);
queue.push({ term, blit });
setTimeout(renderFromQueue, 200);
} else {
queue.push({ term, blit: blot });
queue.push({ term, blit });
}
};

View File

@ -0,0 +1,39 @@
/**
* Wait for the given milliseconds
* @param {number} milliseconds The given time to wait
* @returns {Promise} A fulfiled promise after the given time has passed
*/
function waitFor(milliseconds) {
return new Promise(resolve => setTimeout(resolve, milliseconds));
}
/**
* Execute a promise and retry with exponential backoff
* based on the maximum retry attempts it can perform
* @param {Promise} promise promise to be executed
* @param {function} onRetry callback executed on every retry
* @param {number} maxRetries The maximum number of retries to be attempted
* @returns {Promise} The result of the given promise passed in
*/
export function retry(promise, onRetry, maxRetries) {
async function retryWithBackoff(retries) {
try {
if (retries > 0) {
const timeToWait = 2 ** retries * 100;
console.log(`waiting for ${timeToWait}ms...`);
await waitFor(timeToWait);
}
return await promise();
} catch (e) {
if (retries < maxRetries) {
onRetry();
return retryWithBackoff(retries + 1);
} else {
console.warn('Max retries reached. Bubbling the error up');
throw e;
}
}
}
return retryWithBackoff(0);
}

View File

@ -0,0 +1,60 @@
import { Deco, Stye, Tint } from '@urbit/api/term';
const tint = (t: Tint) => {
switch (t) {
case null: return '9';
case 'k': return '0';
case 'r': return '1';
case 'g': return '2';
case 'y': return '3';
case 'b': return '4';
case 'm': return '5';
case 'c': return '6';
case 'w': return '7';
default: return `8;2;${t.r%256};${t.g%256};${t.b%256}`;
}
};
export const stye = (s: Stye) => {
let out = '';
// text decorations
//
if (s.deco.length > 0) {
out += s.deco.reduce((decs: number[], deco: Deco) => {
/* eslint-disable max-statements-per-line */
switch (deco) {
case null: decs.push(0); return decs;
case 'br': decs.push(1); return decs;
case 'un': decs.push(4); return decs;
case 'bl': decs.push(5); return decs;
default: console.log('weird deco', deco); return decs;
}
}, []).join(';');
}
// background color
//
if (s.back !== null) {
if (out !== '') {
out += ';';
}
out += '4';
out += tint(s.back);
}
// foreground color
//
if (s.fore !== null) {
if (out !== '') {
out += ';';
}
out += '3';
out += tint(s.fore);
}
if (out === '') {
return out;
}
return '\x1b[' + out + 'm';
};

View File

@ -0,0 +1,23 @@
import { ITheme } from 'xterm';
export const makeTheme = (dark: boolean): ITheme => {
let fg, bg: string;
if (dark) {
fg = 'white';
bg = 'rgb(26,26,26)';
} else {
fg = 'black';
bg = 'white';
}
// TODO indigo colors.
// we can't pluck these from ThemeContext because they have transparency.
// technically xterm supports transparency, but it degrades performance.
return {
foreground: fg,
background: bg,
brightBlack: '#7f7f7f', // NOTE slogs
cursor: fg,
cursorAccent: bg,
selection: fg
};
};

View File

@ -0,0 +1,66 @@
import {
DEFAULT_HANDLER,
AGENT_SESSION_REGEX,
SESSION_ID_REGEX
} from '../constants';
import useTermState from '../state';
import api from '../api';
import { pokeTask } from '@urbit/api/term';
import { useCallback } from 'react';
export const useAddSession = () => {
const { names } = useTermState();
const addSession = useCallback(async () => {
let agent = DEFAULT_HANDLER;
let sessionName: string;
const userInput = prompt('Please enter an alpha-numeric session name.');
// user canceled or did not enter a value
if (null === userInput) {
return;
}
// check for custom agent session syntax
if (AGENT_SESSION_REGEX.test(userInput)) {
const match = AGENT_SESSION_REGEX.exec(userInput);
if (!match) {
alert('Invalid format. Valid syntax: agent!session-name');
return;
}
agent = match[1];
sessionName = match[2];
// else, use the default session creation regex
} else if (SESSION_ID_REGEX.test(userInput)) {
const match = SESSION_ID_REGEX.exec(userInput);
if (!match) {
alert('Invalid format. Valid syntax: session-name');
return;
}
sessionName = match[1];
} else {
alert('Invalid format. Valid syntax: session-name');
return;
}
// prevent duplicate sessions
if(names.includes(sessionName)) {
alert(`Session name must be unique ("${sessionName}" already in use)`);
return;
}
try {
//TODO eventually, customizable app pre-linking?
await api.poke(pokeTask(sessionName, { open: { term: agent, apps: [{ who: '~' + (window as any).ship, app: 'dojo' }] } }));
useTermState.getState().set((state) => {
state.names = [sessionName, ...state.names].sort();
state.selected = sessionName;
state.sessions[sessionName] = null;
});
} catch (error) {
console.log('unable to create session:', error);
}
}, [names]);
return addSession;
};

View File

@ -1,6 +1,5 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useTheme } from './settings'; import useTermState from '../state';
import useTermState from './state';
export function useDark() { export function useDark() {
const [osDark, setOsDark] = useState(false); const [osDark, setOsDark] = useState(false);
@ -11,12 +10,11 @@ export function useDark() {
setOsDark(e.matches); setOsDark(e.matches);
}; };
setOsDark(themeWatcher.matches); setOsDark(themeWatcher.matches);
themeWatcher.addListener(update); themeWatcher.addEventListener('change', update);
return () => { return () => {
themeWatcher.removeListener(update); themeWatcher.removeEventListener('change', update);
} };
}, []); }, []);
const theme = useTermState(s => s.theme); const theme = useTermState(s => s.theme);

View File

@ -0,0 +1,44 @@
/* eslint-disable no-useless-escape */
// Regex patterns inspired by:
// https://github.com/faisalman/ua-parser-js/blob/master/src/ua-parser.js
const LINUX = [
/\b(joli|palm)\b ?(?:os)?\/?([\w\.]*)/i,
/(mint)[\/\(\) ]?(\w*)/i,
/(mageia|vectorlinux)[; ]/i,
/([kxln]?ubuntu|debian|suse|opensuse|gentoo|arch(?= linux)|slackware|fedora|mandriva|centos|pclinuxos|red ?hat|zenwalk|linpus|raspbian|plan 9|minix|risc os|contiki|deepin|manjaro|elementary os|sabayon|linspire)(?: gnu\/linux)?(?: enterprise)?(?:[- ]linux)?(?:-gnu)?[-\/ ]?(?!chrom|package)([-\w\.]*)/i,
/(hurd|linux) ?([\w\.]*)/i,
/(gnu) ?([\w\.]*)/i,
/\b([-frentopcghs]{0,5}bsd|dragonfly)[\/ ]?(?!amd|[ix346]{1,2}86)([\w\.]*)/i,
/(haiku) (\w+)/i,
/(sunos) ?([\w\.\d]*)/i,
/((?:open)?solaris)[-\/ ]?([\w\.]*)/i,
/(aix) ((\d)(?=\.|\)| )[\w\.])*/i,
/\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux)/i,
/(unix) ?([\w\.]*)/i
];
const MAC_OS = [
/(mac os x) ?([\w\. ]*)/i,
/(macintosh|mac_powerpc\b)(?!.+haiku)/i
];
const WINDOWS = [
/microsoft (windows) (vista|xp)/i,
/(windows) nt 6\.2; (arm)/i,
/(windows (?:phone(?: os)?|mobile))[\/ ]?([\d\.\w ]*)/i,
/(windows)[\/ ]?([ntce\d\. ]+\w)(?!.+xbox)/i
];
export const useDetectOS = () => {
const userAgent = navigator.userAgent;
const isLinux = LINUX.some(regex => regex.test(userAgent));
const isMacOS = MAC_OS.some(regex => regex.test(userAgent));
const isWindows = WINDOWS.some(regex => regex.test(userAgent));
return {
isLinux,
isMacOS,
isWindows
};
};

View File

@ -0,0 +1,17 @@
import { useCallback, useEffect, useRef } from 'react';
function useIsMounted() {
const isMounted = useRef(false);
useEffect(() => {
isMounted.current = true;
return () => {
isMounted.current = false;
};
}, []);
return useCallback(() => isMounted.current, []);
}
export default useIsMounted;

Binary file not shown.

View File

@ -11,6 +11,7 @@
"@urbit/api": "^1.1.1", "@urbit/api": "^1.1.1",
"@urbit/http-api": "^1.2.1", "@urbit/http-api": "^1.2.1",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"lodash": "^4.17.21",
"react": "^16.14.0", "react": "^16.14.0",
"react-dom": "^16.14.0", "react-dom": "^16.14.0",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
@ -36,7 +37,7 @@
"@types/styled-system": "^5.1.10", "@types/styled-system": "^5.1.10",
"@typescript-eslint/eslint-plugin": "^4.15.0", "@typescript-eslint/eslint-plugin": "^4.15.0",
"@typescript-eslint/parser": "^4.24.0", "@typescript-eslint/parser": "^4.24.0",
"@urbit/eslint-config": "^1.0.0", "@urbit/eslint-config": "^1.0.3",
"@welldone-software/why-did-you-render": "^6.1.0", "@welldone-software/why-did-you-render": "^6.1.0",
"babel-eslint": "^10.1.0", "babel-eslint": "^10.1.0",
"babel-jest": "^26.6.3", "babel-jest": "^26.6.3",
@ -45,7 +46,9 @@
"clean-webpack-plugin": "^3.0.0", "clean-webpack-plugin": "^3.0.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"eslint": "^7.26.0", "eslint": "^7.26.0",
"eslint-plugin-react": "^7.22.0", "eslint-import-resolver-typescript": "^2.5.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-react-hooks": "^4.3.0",
"file-loader": "^6.2.0", "file-loader": "^6.2.0",
"html-webpack-plugin": "^4.5.1", "html-webpack-plugin": "^4.5.1",
"husky": "^6.0.0", "husky": "^6.0.0",
@ -58,7 +61,8 @@
"webpack-dev-server": "^3.11.2" "webpack-dev-server": "^3.11.2"
}, },
"scripts": { "scripts": {
"lint": "eslint ./src/**/*.{ts,tsx}", "lint": "eslint ./**/*.{ts,tsx}",
"lint-fix": "eslint --fix ./**/*.{ts,tsx}",
"lint-file": "eslint", "lint-file": "eslint",
"tsc": "tsc", "tsc": "tsc",
"tsc:watch": "tsc --watch", "tsc:watch": "tsc --watch",

View File

@ -3,21 +3,33 @@ import { FitAddon } from 'xterm-addon-fit';
import create from 'zustand'; import create from 'zustand';
import produce from 'immer'; import produce from 'immer';
type Session = { term: Terminal, fit: FitAddon }; export type Session = {
type Sessions = { [id: string]: Session; } term: Terminal,
fit: FitAddon,
hasBell: boolean,
pending: number,
subscriptionId: number | null,
} | null;
export type Sessions = { [id: string]: Session; }
export interface TermState { export interface TermState {
sessions: Sessions, sessions: Sessions,
names: string[],
selected: string, selected: string,
slogstream: null | EventSource, slogstream: null | EventSource,
theme: 'auto' | 'light' | 'dark' theme: 'auto' | 'light' | 'dark',
}; //TODO: figure out the type
set: any,
}
// eslint-disable-next-line no-unused-vars
const useTermState = create<TermState>((set, get) => ({ const useTermState = create<TermState>((set, get) => ({
sessions: {} as Sessions, sessions: {} as Sessions,
names: [''],
selected: '', // empty string is default session selected: '', // empty string is default session
slogstream: null, slogstream: null,
theme: 'auto', theme: 'auto',
// eslint-disable-next-line no-unused-vars
set: (f: (draft: TermState) => void) => { set: (f: (draft: TermState) => void) => {
set(produce(f)); set(produce(f));
} }

View File

@ -0,0 +1,26 @@
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"noFallthroughCasesInSwitch": true,
"noUnusedParameters": false,
"noImplicitReturns": false,
"moduleResolution": "node",
"esModuleInterop": true,
"noUnusedLocals": false,
"noImplicitAny": false,
"noEmit": true,
"target": "ESNext",
"module": "ESNext",
"strict": false,
"strictNullChecks": true,
"jsx": "react",
"baseUrl": "."
},
"include": [
"**/*"
],
"exclude": [
"node_modules",
"dist"
]
}

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