Merge branch 'next/arvo' into jon/doccords

This commit is contained in:
Philip Monk 2023-01-12 13:14:06 -07:00
commit 0119eef28d
125 changed files with 3997 additions and 2324 deletions

View File

@ -1,24 +0,0 @@
name: frontend-test
on:
pull_request:
paths:
- 'pkg/interface/**'
- 'pkg/btc-wallet/**'
- 'pkg/npm/**'
jobs:
frontend-test:
runs-on: ubuntu-latest
name: "Test changed frontend packages"
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- run: git fetch --prune
- name: 'Setup root deps'
run: npm ci
- name: 'Setup dependencies'
run: npm run bootstrap
- name: 'Run tests'
run: npm run test -- --since origin/$GITHUB_BASE_REF --include-dependents

View File

@ -162,86 +162,9 @@ jobs:
- if: ${{ matrix.os == 'ubuntu-latest' }}
run: nix-build -A docker-image
mingw:
runs-on: windows-latest
defaults:
run:
shell: >
C:\msys64\msys2_shell.cmd -mingw64 -defterm -no-start -here -c
". <(cygpath '{0}')"
working-directory: ./pkg/urbit
steps:
- uses: actions/checkout@v2
with:
lfs: true
# echo suppresses pacman prompt
- run: echo|./configure
env:
CACHIX_CACHE: ares
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
- run: mingw32-make build/urbit
- run: mingw32-make test
- run: >
build/urbit -l -d -B ../../bin/solid.pill -F bus &&
curl -f --data '{"source":{"dojo":"+hood/exit"},"sink":{"app":"hood"}}'
http://localhost:12321
- name: confirm binary is mostly static
run: |
if [ -z "$(ldd build/urbit | grep -vi "windows/system32")"]; then
echo "it's mostly static"
exit 0
else
echo "dynamic links found:"
ldd build/urbit
exit 1
fi
- uses: actions/setup-python@v2
if: inputs.upload
with:
python-version: 3.7
- uses: google-github-actions/setup-gcloud@v0.6.0
if: inputs.upload
env:
# see https://github.com/google-github-actions/setup-gcloud/issues/100
CLOUDSDK_PYTHON: ${{env.pythonLocation}}\python.exe
with:
service_account_key: ${{ secrets.GCS_SERVICE_ACCOUNT_KEY }}
project_id: ${{ secrets.GCS_PROJECT }}
export_default_credentials: true
- name: upload binary to bootstrap.urbit.org
if: inputs.upload
env:
CLOUDSDK_PYTHON: ${{env.pythonLocation}}\python.exe
shell: bash
run: |
if [ "real" == "$VERSION_TYPE" ]; then
version="$(cat ./version)"
else
version="${GITHUB_SHA:0:9}"
fi
system="x86_64-windows"
target="gs://${UPLOAD_BASE}/${VERE_PACE}/${version}/vere-v${version}-${system}.exe"
gsutil cp -n ./build/urbit.exe "$target"
exitcode=$?
test $exitcode -eq 0 &&
echo "upload to $target complete." ||
echo "upload to $target failed.";
exit $exitcode
after:
runs-on: ubuntu-latest
needs: [urbit, mingw]
needs: [urbit]
if: inputs.upload
steps:
- uses: google-github-actions/setup-gcloud@v0.2.0

View File

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

View File

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

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e46c7fb35826bcc3352eca8dbfeea3a8bdf1686cf46b3f873fad0c09bc25c5a7
size 5715362
oid sha256:f4d585474b6df173dc1c172f343192ac88bd3ced1a9c7cf6877402722ac139de
size 5748201

View File

@ -10,9 +10,9 @@
:::: :: ::::
:: :: ::
=> |% :: external structures
+$ id @tasession :: session id
+$ id sole-id :: session id
+$ house :: all state
$: %8
$: %9
egg=@u :: command count
hoc=(map id session) :: conversations
acl=(set ship) :: remote access whitelist
@ -850,12 +850,23 @@
=/ poz=vase (dy-sore p.cig)
=/ kev=vase
=/ kuv=(unit vase) (slew 7 som)
?: =(~ q.cig)
(fall kuv !>(~))
=/ soz=(list [var=term vax=vase])
%~ tap by
%- ~(run by q.cig)
|=(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)
%+ slap
(with-faces kuv+(need kuv) rep+(with-faces soz) ~)
@ -1048,13 +1059,14 @@
|= =card:agent:gall
^+ +>
=? card ?=(%pass -.card)
card(p [id p.card])
^- card:agent:gall
card(p [(scot %p who.id) ses.id p.card])
%_(+> moz [card moz])
::
++ he-diff :: emit update
|= 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
^+ .
@ -1562,21 +1574,47 @@
::
++ on-load
|= ole=vase
^- (quip card:agent:gall _..on-init)
|^ =+ old=!<(house-any ole)
=? old ?=(%5 -.old)
^- house-any
^- house-6
(house-5-to-6 old)
=? old ?=(?(%6 %7) -.old)
(house-6-7-to-8 +.old)
?> ?=(%8 -.old)
`..on-init(state old)
=^ caz 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-6 [%6 house-6-7]
+$ house-6-7
$: egg=@u :: command count
hoc=(map id session-6) :: conversations
hoc=(map id-8 session-6) :: conversations
acl=(set ship) :: remote access whitelist
== ::
+$ session-6 :: per conversation
@ -1603,9 +1641,10 @@
old(poy ~, -.dir [our.hid %base ud+0])
::
+$ house-5
[%5 egg=@u hoc=(map id session)]
[%5 egg=@u hoc=(map id-8 session-6)]
++ house-5-to-6
|= old=house-5
^- house-6
[%6 egg.old hoc.old *(set ship)]
--
::
@ -1621,7 +1660,8 @@
he-abet:(~(he-type he hid id.act ~ (~(got by hoc) id.act)) act)
::
%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)
::
%allow-remote-login
@ -1659,8 +1699,7 @@
?> ?| (team:title our.hid src.hid)
(~(has in acl) src.hid)
==
?> ?=([%sole @ ~] path)
=/ id i.t.path
=/ =id (need (path-to-id:sole path))
=? hoc (~(has by hoc) id)
~& [%dojo-peer-replaced id]
(~(del by hoc) id)
@ -1672,7 +1711,7 @@
++ on-leave
|= =path
?> ?=([%sole *] path)
=. hoc (~(del by hoc) t.path)
=. hoc (~(del by hoc) (need (path-to-id:sole path)))
[~ ..on-init]
::
++ on-peek
@ -1681,13 +1720,15 @@
::
++ on-agent
|= [=wire =sign:agent:gall]
?> ?=([@ @ *] wire)
=/ =session (~(got by hoc) i.wire)
=/ he-full ~(. he hid i.wire ~ session)
^- (quip card:agent:gall _..on-init)
?> ?=([@ @ @ *] wire)
=/ =id [(slav %p i.wire) i.t.wire]
=/ =session (~(got by hoc) id)
=/ he-full ~(. he hid id ~ session)
=^ moves state
=< he-abet
^+ 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)
%wool (he-wool:he-full t.wire sign)
==
@ -1695,14 +1736,16 @@
::
++ on-arvo
|= [=wire =sign-arvo]
?> ?=([@ *] wire)
=/ =session (~(got by hoc) i.wire)
=/ he-full ~(. he hid i.wire ~ session)
^- (quip card:agent:gall _..on-init)
?> ?=([@ @ *] wire)
=/ =id [(slav %p i.wire) i.t.wire]
=/ =session (~(got by hoc) id)
=/ he-full ~(. he hid id ~ session)
=^ moves state
=< he-abet
?+ +<.sign-arvo ~|([%dojo-bad-take +<.sign-arvo] !!)
%writ (he-writ:he-full t.wire +>.sign-arvo)
%http-response (he-http-response:he-full t.wire +>.sign-arvo)
%writ (he-writ:he-full t.t.wire +>.sign-arvo)
%http-response (he-http-response:he-full t.t.wire +>.sign-arvo)
==
[moves ..on-init]
:: 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
/+ default-agent, dbug, verb
:: keep relevant mark conversions in cache for performance
::
/$ blit-to-json %blit %json
/$ json-to-blit %json %blit
/$ json-to-task %json %herm-task
::
=, jael
|%
+$ state-0 [%0 ~]
@ -13,15 +18,18 @@
%+ verb |
%- agent:dbug
^- agent:gall
=> |%
++ pass-session
|= [ses=@tas tas=session-task:dill]
[%pass /dill/[ses] %arvo %d %shot ses tas]
--
|_ =bowl:gall
+* this .
def ~(. (default-agent this %|) bowl)
::
++ on-init
^- (quip card:agent:gall _this)
:: set up dill session subscription
::
[[%pass [%view %$ ~] %arvo %d %view ~]~ this]
[~ this]
::
++ on-save !>([%0 ~])
++ on-load
@ -32,47 +40,68 @@
++ on-watch
|= =path
^- (quip card:agent:gall _this)
?> =(our src):bowl
?> ?=([%session @ %view ~] path)
:_ 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
/dx/(scot %p our.bowl)//(scot %da now.bowl)/sessions
:~ [%give %fact ~ %blit !>(.^(blit:dill (weld base //line)))]
[%give %fact ~ %blit !>(`blit:dill`hop+.^(@ud (weld base //cursor)))]
==
::NOTE multiple views do not result in multiple subscriptions
:: because they go over the same wire/duct
::
[(pass-session ses %view ~)]~
::
++ on-arvo
|= [=wire =sign-arvo]
^- (quip card:agent:gall _this)
~| wire
?+ wire (on-arvo:def wire sign-arvo)
[%tube *] [~ this] :: we no longer care about these
::
:: pass on dill blits for the session
::
[%view %$ ~]
[%dill @ ~]
=* ses i.t.wire
?. ?=([%dill %blit *] sign-arvo)
~| [%unexpected-sign [- +<]:sign-arvo]
!!
:_ this
%+ turn p.sign-arvo
|= =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
|= [=mark =vase]
^- (quip card:agent:gall _this)
?> =(our src):bowl
?. ?=(%belt mark)
~| [%unexpected-mark mark]
!!
:_ 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-peek on-peek:def
::
++ on-agent on-agent:def
++ on-fail on-fail:def
--

View File

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

View File

@ -83,7 +83,8 @@
::
?+ -.source.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
:_ this(job.state (some [eyre-id com]))

View File

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

View File

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

View File

@ -8,9 +8,11 @@
::
:- %say
|= $: [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-session
?~ +.arg
[p.byk dap.arg]
[who.arg dap.arg]

View File

@ -8,9 +8,11 @@
::
:- %say
|= $: [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-session
?~ +.arg
[p.byk dap.arg]
[who.arg dap.arg]

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

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

View File

@ -1,34 +1,66 @@
/- *sole
/+ sole
|%
+$ state state-4
+$ state state-5
+$ any-state
$~ *state
$% state-4
$% state-5
state-4
state-3
state-2
==
+$ state-5 [%5 pith-5]
+$ state-4 [%4 pith-4]
+$ state-3 [%3 pith-3]
+$ state-2 [%2 pith-2]
::
+$ pith-5
$: bin=(map @ source) :: terminals
==
::
+$ pith-4
$: 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 ::
$: eel=(set gill:gall) :: connect to
ray=(map dude:gall desk) ::
fur=(map dude:gall (unit *)) :: servers
bin=(map bone source) :: terminals
bin=(map bone source-4) :: terminals
== ::
:: ::
++ pith-2 ::
$: eel=(set gill:gall) :: connect to
ray=(set well:gall) ::
fur=(map dude:gall (unit *)) :: servers
bin=(map bone source) :: terminals
bin=(map bone source-4) :: terminals
== ::
:: ::
++ kill :: kill ring
@ -42,6 +74,7 @@
off=@ud :: window offset
kil=kill :: kill buffer
inx=@ud :: ring index
eel=(set gill:gall) :: connect to
fug=(map gill:gall (unit target)) :: connections
mir=(pair @ud stub) :: mirrored terminal
== ::
@ -65,52 +98,74 @@
pom=sole-prompt :: static prompt
inp=sole-command :: input state
== ::
::
--
:: :: ::
:::: :: ::
:: :: ::
|%
++ en-gill :: gill to wire
|= gyl=gill:gall
|= [ses=@tas gyl=gill:gall]
^- wire
[%drum %phat (scot %p p.gyl) q.gyl ~]
[%drum %phat (scot %p p.gyl) q.gyl ?:(=(%$ ses) ~ [ses ~])]
::
++ de-gill :: gill from wire
|= way=wire ^- gill:gall
~| way
?>(?=([@ @ *] way) [(slav %p i.way) i.t.way])
|= way=wire
^- [@tas gill:gall]
~| wire=way
?> ?=([@ @ ?(~ [@ ~])] way)
:- ?~(t.t.way %$ i.t.t.way)
[(slav %p i.way) i.t.way]
--
:: TODO: remove .ost
::
|= [hid=bowl:gall state]
=* sat +<+
=/ ost 0
=+ (~(gut by bin) ost *source)
=/ ses=@tas %$
=+ (~(gut by bin) ses *source)
=* dev -
=| moz=(list card:agent:gall)
=| biz=(list dill-blit:dill)
=| biz=(list blit:dill) ::TODO should be per-session
|%
++ this .
++ klr klr:format
+$ state ^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
|= [way=wire fec=sole-effect]
=< se-abet =< se-view
=+ gyl=(de-gill way)
=< se-abet
=^ gyl this (open way)
?: (se-aint gyl) +>.$
(se-diff gyl fec)
::
++ peer ::
|= pax=path
=? this ?=([%dill @ ~] pax)
(prep i.t.pax)
~| [%drum-unauthorized our+our.hid src+src.hid] :: ourself
?> (team:title our.hid src.hid) :: or our own moon
=< se-abet =< se-view
=< se-abet
(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
|= bet=dill-belt:dill
=< se-abet =< se-view
=< se-abet
(se-belt bet)
::
++ poke-dill-blit :: terminal output
@ -118,29 +173,29 @@
se-abet:(se-blit-sys bit)
::
++ poke-link :: connect app
|= gyl=gill:gall
=< se-abet =< se-view
(se-link gyl)
|= [ses=@tas gyl=gill:gall]
=< se-abet
(se-link:(prep ses) gyl)
::
++ poke-unlink :: disconnect app
|= gyl=gill:gall
=< se-abet =< se-view
(se-drop:(se-pull gyl) & gyl)
|= [ses=@ta gyl=gill:gall]
=< se-abet
(se-drop:(se-pull:(prep ses) gyl) & gyl)
::
++ poke-exit :: shutdown
|= ~
se-abet:(se-blit-sys `dill-blit:dill`[%qit ~])
::
++ 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]) ::
::
++ poke
|= [=mark =vase]
?> =(our src):hid
?+ mark ~|([%poke-drum-bad-mark mark] !!)
%drum-dill-belt =;(f (f !<(_+<.f vase)) poke-dill-belt)
%drum-dill-blit =;(f (f !<(_+<.f vase)) poke-dill-blit)
%dill-poke =;(f (f !<(_+<.f vase)) poke-dill)
%drum-exit =;(f (f !<(_+<.f vase)) poke-exit)
%drum-link =;(f (f !<(_+<.f vase)) poke-link)
%drum-put =;(f (f !<(_+<.f vase)) poke-put)
@ -149,19 +204,40 @@
::
++ on-load
|= [hood-version=@ud old=any-state]
=< se-abet =< se-view
=< se-abet
=? old ?=(%2 -.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
=. dev (~(gut by bin) ost *source)
=. dev (~(gut by bin) ses *source)
this
::
++ reap-phat :: ack connect
|= [way=wire saw=(unit tang)]
=< se-abet =< se-view
=+ gyl=(de-gill way)
=< se-abet
=^ gyl this (open way)
?~ saw
(se-join gyl)
:: Don't print stack trace because we probably just crashed to
@ -171,9 +247,9 @@
::
++ take-coup-phat :: ack poke
|= [way=wire saw=(unit tang)]
=< se-abet =< se-view
=< se-abet
?~ saw +>
=+ gyl=(de-gill way)
=^ gyl this (open way)
?: (se-aint gyl) +>.$
%- se-dump:(se-drop:(se-pull gyl) & gyl)
:_ u.saw
@ -196,8 +272,8 @@
::
++ quit-phat ::
|= way=wire
=< se-abet =< se-view
=+ gyl=(de-gill way)
=< se-abet
=^ gyl this (open way)
~& [%drum-quit src.hid gyl]
(se-drop %| gyl)
:: :: ::
@ -205,13 +281,18 @@
:: :: ::
++ se-abet :: resolve
^- (quip card:agent:gall state)
=. . se-subze:se-adze
:_ sat(bin (~(put by bin) ost dev))
=. . se-view:se-subze:se-adze
:_ sat(bin (~(put by bin) ses dev))
^- (list card:agent:gall)
?~ biz (flop moz)
:_ (flop moz)
=/ =dill-blit:dill ?~(t.biz i.biz [%mor (flop biz)])
[%give %fact ~[/drum] %dill-blit !>(dill-blit)]
=/ =blit:dill ?~(t.biz i.biz [%mor (flop biz)])
::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
^+ .
@ -230,14 +311,14 @@
(se-peer gil)
::
++ se-subze :: downdate connections
=< .(dev (~(got by bin) ost))
=. bin (~(put by bin) ost dev)
=< .(dev (~(got by bin) ses))
=. bin (~(put by bin) ses dev)
^+ .
%- ~(rep by bin)
=< .(con +>)
|: $:,[[ost=bone dev=source] con=_.] ^+ con
=+ xeno=se-subze-local:%_(con ost ost, dev dev)
xeno(ost ost.con, dev dev.con, bin (~(put by bin) ost dev.xeno))
|: $:,[[ses=@tas dev=source] con=_.] ^+ con
=+ xeno=se-subze-local:%_(con ses ses, dev dev)
xeno(ses ses.con, dev dev.con, bin (~(put by bin.xeno) ses dev.xeno))
::
++ se-subze-local
^+ .
@ -252,7 +333,7 @@
++ se-aint :: ignore result
|= gyl=gill:gall
^- ?
?. (~(has by bin) ost) &
?. (~(has by bin) ses) &
=+ gyr=(~(get by fug) gyl)
|(?=(~ gyr) ?=(~ u.gyr))
::
@ -290,7 +371,7 @@
[%cru *] (se-dump:(se-text (trip p.bet)) q.bet)
[%hey *] +>(mir [0 ~]) :: refresh
[%rez *] +>(edg (dec p.bet)) :: resize window
[%yow *] ~&([%no-yow -.bet] +>)
[%yow *] (se-link p.bet)
==
=+ gul=se-agon
?: |(?=(~ gul) (se-aint u.gul))
@ -341,6 +422,21 @@
leaf+(weld (scag (sub edg 3) 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
|= tac=(list tank)
^+ +>
@ -351,7 +447,7 @@
?. ((sane %t) (crip i.wol)) :: XX upstream validation
~& bad-text+<`*`i.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
|= gyl=gill:gall
@ -379,20 +475,21 @@
+>(eel (~(put in eel) gyl))
::
++ se-blit :: give output
|= bil=dill-blit:dill
|= bil=blit:dill
+>(biz [bil biz])
::
++ se-blit-sys :: output to system
|= 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
|= lin=(pair @ud stub)
^+ +>
?: =(mir lin) +>
=. +> ?:(=(p.mir p.lin) +> (se-blit %hop p.lin))
=. +> ?:(=(q.mir q.lin) +> (se-blit %pom q.lin))
+>(mir lin)
%- se-blit(mir lin)
?: =(q.mir q.lin) [%hop p.lin]
mor+[[%hop 0] [%wyp ~] [%klr q.lin] [%hop p.lin] ~]
::
++ se-just :: adjusted buffer
|= [pom=stub lin=(pair @ud (list @c))]
@ -430,22 +527,22 @@
?. ((sane %t) (crip txt)) :: XX upstream validation
~& bad-text+<`*`txt>
+>
(se-blit %out (tuba txt))
(se-blin %put (tuba txt))
::
++ se-poke :: send a poke
|= [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
|= gyl=gill:gall
~> %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 ~))
[%pass (en-gill gyl) %agent gyl %watch path]
[%pass (en-gill ses gyl) %agent gyl %watch path]
::
++ se-pull :: cancel subscription
|= 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
|= gyl=gill:gall
@ -470,7 +567,7 @@
^+ +>
(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
|= key=?(%d %l %r %u)
@ -499,13 +596,19 @@
?< ?=([?(%cru %hey %rez %yow) *] bet) :: target-specific
=. blt [q.blt `bet] :: remember belt
?- bet
@ (ta-txt bet ~)
[%aro *] (ta-aro p.bet)
[%bac *] ta-bac
[%ctl *] (ta-ctl p.bet)
[%del *] ta-del
[%met *] (ta-met p.bet)
[%hit *] (ta-hit +.bet)
[%ret *] ta-ret
[%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
@ -529,7 +632,7 @@
(ta-hom %del (dec pos.inp))
::
++ ta-ctl :: hear control
|= key=@ud
|= key=bolt:dill
^+ +>
=. ris ?.(?=(?(%g %r) key) ~ ris)
?+ key ta-bel
@ -539,7 +642,7 @@
%d ?^ buf.say.inp
ta-del
?: =([our.hid %dojo] gyl)
+>(..ta (se-blit qit+~)) :: quit pier
+>(..ta (se-blit-sys %qit ~)) :: quit pier
+>(..ta (se-klin gyl)) :: unlink app
%e +>(pos.inp (lent buf.say.inp))
%f (ta-aro %r)
@ -550,7 +653,7 @@
?: =(pos.inp len)
ta-bel
(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)
%p (ta-aro %u)
%r ?~ ris
@ -583,6 +686,14 @@
ta-bel
(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
|= pos=@ud
ta-bel(pos.inp (min pos (lent buf.say.inp)))
@ -594,14 +705,13 @@
++ ta-fec :: apply effect
|= fec=sole-effect
^+ +>
?- fec
?+ fec +>(..ta (se-blit fec))
[%bel *] ta-bel
[%blk *] +>
[%bye *] +>(..ta (se-klin gyl))
[%clr *] +>(..ta (se-blit fec))
[%det *] (ta-got +.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 *] |- ^+ +>.^$
?~ p.fec +>.^$
$(p.fec t.p.fec, +>.^$ ^$(fec i.p.fec))
@ -609,10 +719,8 @@
[%pro *] (ta-pro +.fec)
[%tab *] +>(..ta (se-tab p.fec))
[%tan *] +>(..ta (se-dump p.fec))
[%sag *] +>(..ta (se-blit fec))
[%sav *] +>(..ta (se-blit 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
@ -664,8 +772,8 @@
kil
?. ?& ?=(^ old.kil)
?=(^ p.blt)
?| ?=([%ctl ?(%k %u %w)] u.p.blt)
?=([%met ?(%d %bac)] u.p.blt)
?| ?=([%mod %ctl ?(%k %u %w)] u.p.blt)
?=([%mod %met ?(%d [%bac ~])] u.p.blt)
== ==
%= kil :: prepend
num +(num.kil)
@ -682,17 +790,18 @@
==
::
++ ta-met :: meta key
|= key=@ud
|= key=bolt:dill
^+ +>
=. ris ~
?+ key ta-bel
%dot ?. &(?=(^ old.hit) ?=(^ i.old.hit)) :: last "arg" from hist
%'.' ?. &(?=(^ old.hit) ?=(^ i.old.hit)) :: last "arg" from hist
ta-bel
=+ old=`(list @c)`i.old.hit
=+ sop=(ta-jump(buf.say.inp old) %l %ace (lent 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
=+ sop=(ta-pos %l %edg pos.inp)
(ta-kil %l [(sub pos.inp sop) sop])
@ -748,8 +857,8 @@
::
%y ?. ?& ?=(^ old.kil) :: rotate & yank
?=(^ p.blt)
?| ?=([%ctl %y] u.p.blt)
?=([%met %y] u.p.blt)
?| ?=([%mod %ctl %y] u.p.blt)
?=([%mod %met %y] u.p.blt)
== ==
ta-bel
=+ las=(lent ta-yan)
@ -927,82 +1036,4 @@
?: |(?=(~ a) (alnm i.a)) i
$(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

@ -504,7 +504,7 @@
[%x %kiln %pikes ~]
=+ .^(=rock:tire %cx /(scot %p our)//(scot %da now)/tire)
:^ ~ ~ %kiln-pikes
!> ^- pikes
!> ^- pikes
%- ~(rut by rock)
|= [=desk =zest wic=(set weft)]
^- pike

View File

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

View File

@ -19,8 +19,10 @@
^- ^json
?+ -.dib ~|(unsupported-blit+-.dib !!)
%mor [%a (turn p.dib |=(a=dill-blit:dill json(dib a)))]
%hop (frond %hop (numb p.dib))
?(%pro %out) (frond -.dib (tape (tufa p.dib)))
%hop %+ frond %hop
?@ 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)
==
--

View File

@ -1,8 +1,7 @@
:: %drum-put: download into host system
::
:::: /hoon/do-claim/womb/mar
::
/? 310
|_ [path @]
|_ [path $@(@ [@ta @])]
::
++ grad %noun
++ grow
@ -11,6 +10,6 @@
--
++ 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 416]

View File

@ -1181,10 +1181,10 @@
=| [l=(unit) r=(unit)]
|. ^- ?
?~ a &
?& ?~(l & &((gor n.a u.l) !=(n.a u.l)))
?~(r & &((gor u.r n.a) !=(u.r n.a)))
?~(l.a & ?&((mor n.a n.l.a) !=(n.a n.l.a) $(a l.a, l `n.a)))
?~(r.a & ?&((mor n.a n.r.a) !=(n.a n.r.a) $(a r.a, r `n.a)))
?& ?~(l & (gor n.a u.l))
?~(r & (gor u.r n.a))
?~(l.a & ?&((mor n.a n.l.a) $(a l.a, l `n.a)))
?~(r.a & ?&((mor n.a n.r.a) $(a r.a, r `n.a)))
==
::
++ bif :: splits a by b

View File

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

View File

@ -432,7 +432,10 @@
task ::
== ::
$: %d :: to %dill
$>(%flog task:dill) ::
$> $? %flog ::
%text ::
== ::
task:dill ::
== ::
$: %g :: to %gall
$> $? %deal
@ -460,14 +463,12 @@
== == ::
$: %clay ::
$> $? %mere ::
%note ::
%writ ::
== ::
gift ::
== ::
$: %gall
$> $? %onto
%unto
$> $? %unto
==
gift:gall
==
@ -2209,7 +2210,8 @@
|= [prefix=@tD paths=(set path)]
%+ turn ~(tap in paths)
|= =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
@ -5774,8 +5776,6 @@
?^ dud
~|(%clay-take-dud (mean tang.u.dud))
?: ?=([%lu %load *] tea)
?: ?=(%onto +<.hin)
[~ ..^$]
?> ?=(%unto +<.hin)
?> ?=(%poke-ack -.p.hin)
?~ p.p.hin
@ -5950,7 +5950,6 @@
q.p.p.+.hin
[~ ..^$]
::
%note [[hen %give +.hin]~ ..^$]
%wake
:: TODO: handle behn errors
::
@ -5973,7 +5972,6 @@
::
%boon !!
%lost !!
%onto !!
%unto !!
%writ
%- (slog leaf+"clay: strange writ (expected on upgrade to Fusion)" ~)

View File

@ -8,27 +8,25 @@
-- ::
=> |% :: console protocol
+$ axle ::
$: %4 ::TODO replace ducts with session ids ::
$: %5 ::
hey=(unit duct) :: default duct
dug=(map duct axon) :: conversations
eye=(jug duct duct) :: outside listeners
dug=(map @tas axon) :: conversations
eye=(jug @tas duct) :: outside listeners
lit=? :: boot in lite mode
$= veb :: vane verbosities
$~ (~(put by *(map @tas log-level)) %hole %soft) :: quiet packet crashes
(map @tas log-level) ::
== ::
+$ axon :: dill per duct
+$ axon :: dill session
$: ram=term :: console program
tem=(unit (list dill-belt)) :: pending, reverse
wid=_80 :: terminal width
pos=@ud :: cursor position
see=$%([%lin (list @c)] [%klr stub]) :: current line
== ::
+$ log-level ?(%hush %soft %loud) :: none, line, full
-- => ::
|% :: protocol outward
+$ mess ::
$% [%dill-belt p=(hypo dill-belt)] ::
$% [%dill-poke p=(hypo poke)] ::
== ::
+$ move [p=duct q=(wind note gift)] :: local move
+$ note :: out request $->
@ -69,7 +67,6 @@
== == ::
$: %clay ::
$> $? %mere ::
%note ::
%writ ::
== ::
gift:clay ::
@ -78,10 +75,7 @@
$>(%blit gift:dill) ::
== ::
$: %gall ::
$> $? %onto ::
%unto ::
== ::
gift:gall ::
$>(%unto gift:gall) ::
== == ::
:::::::: :: dill tiles
--
@ -91,39 +85,27 @@
|%
++ as :: per cause
=| moz=(list move)
|_ [hen=duct axon]
|_ [hen=duct ses=@tas axon]
++ abet :: resolve
^- [(list move) axle]
[(flop moz) all(dug (~(put by dug.all) hen +<+))]
[(flop moz) all(dug (~(put by dug.all) ses +<+>))]
::
++ call :: receive input
|= kyz=task
^+ +>
?+ -.kyz ~& [%strange-kiss -.kyz] +>
%flow +>
%harm +>
%hail (send %hey ~)
%text (from %out (tuba p.kyz))
%crud :: (send `dill-belt`[%cru p.kyz q.kyz])
(crud p.kyz q.kyz)
%blew (send %rez p.p.kyz q.p.kyz)
%heft (pass /whey %$ whey/~)
%meld (dump kyz)
%pack (dump kyz)
%crop (dump trim+p.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])
%hail (send %hey ~)
%belt (send `dill-belt`p.kyz)
%talk (talk p.kyz)
%text (fore (tuba p.kyz) ~)
%crud :: (send `dill-belt`[%cru p.kyz q.kyz])
(crud p.kyz q.kyz)
%blew (send(wid p.p.kyz) %rez p.p.kyz q.p.kyz)
%heft (pass /whey %$ whey/~)
%meld (dump kyz)
%pack (dump kyz)
%crop (dump trim+p.kyz)
%verb (pass /verb %$ kyz)
==
::
++ crud
@ -133,30 +115,30 @@
=/ lev=log-level (~(gut by veb.all) err %loud)
:: apply log level for this error tag
::
=/ =wall
?- lev
%hush ~
%soft ~["crud: %{(trip err)} event failed"]
%loud :- "crud: %{(trip err)} event failed"
%- zing
%+ turn (flop tac)
|=(a=tank (~(win re a) [0 wid]))
==
|- ^+ +>.^$
?~ wall +>.^$
$(wall t.wall, +>.^$ (from %out (tuba i.wall)))
?- lev
%hush +>.$
%soft (fore (tuba "crud: %{(trip err)} event failed") ~)
%loud (talk leaf+"crud: %{(trip err)} event failed" (flop tac))
==
::
++ talk
|= tac=(list tank)
%- fore
%- zing
%+ turn tac
|= a=tank
(turn (~(win re a) [0 wid]) tuba)
::
++ dump :: pass down to hey
|= git=gift
?> ?=(^ hey.all)
+>(moz [[u.hey.all %give git] moz])
::
++ done :: return gift
++ done :: gift to viewers
|= git=gift
=- +>.$(moz (weld - moz))
%+ turn
:- hen
~(tap in (~(get ju eye.all) hen))
~(tap in (~(get ju eye.all) ses))
|=(=duct [duct %give git])
::
++ deal :: pass to %gall
@ -167,44 +149,37 @@
|= [=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
|= 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)
(dump %logo ~)
(done %blit [bit ~])
::TODO so why is this a (list blit) again?
(done %blit bit ~)
::
++ sponsor
^- ship
@ -221,7 +196,7 @@
=. tem ~
=. ..mere (pass /zest %c %zest %base %live)
=. ..mere (show-desk %kids)
=. ..mere drum-watch
=. ..mere (open ~)
|- ^+ ..mere
?~ myt ..mere
$(myt t.myt, ..mere (send i.myt))
@ -231,15 +206,27 @@
=. tem `(turn gyl |=(a=gill [%yow a]))
(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
|= bet=dill-belt
^+ +>
?^ tem
+>(tem `[bet u.tem])
(deal / [%poke [%dill-belt -:!>(bet) bet]])
(deal /send/[ses] [%poke [%dill-poke !>([ses bet])]])
::
++ drum-watch
(deal / [%watch /drum])
++ peer
(deal /peer/[ses] %watch /dill/[ses])
::
++ pull
(deal /peer/[ses] %leave ~)
::
++ show-desk :: permit reads on desk
|= des=desk
@ -249,21 +236,11 @@
|= [tea=wire sih=sign]
^+ +>
?- 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 *]
:: ~& [%take-gall-unto +>.sih]
?- -.+>.sih
%raw-fact !!
%kick drum-watch
%kick peer
%poke-ack ?~(p.p.+>.sih +>.$ (crud %coup u.p.p.+>.sih))
%watch-ack
?~ p.p.+>.sih
@ -275,9 +252,6 @@
+>.$
(from ;;(dill-blit q.q.cage.p.+>.sih))
==
::
[%clay %note *]
(from %out (tuba p.sih ' ' ~(ram re q.sih)))
::
[?(%behn %clay) %writ *]
init
@ -292,12 +266,20 @@
==
--
::
++ ax :: make ++as
|= hen=duct
++ ax :: make ++as from name
|= [hen=duct ses=@tas]
^- (unit _as)
=/ nux (~(get by dug.all) hen)
=/ nux (~(get by dug.all) ses)
?~ 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
++ call :: handle request
@ -308,7 +290,10 @@
^+ [*(list move) ..^$]
~| 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
::
=? task ?=(^ dud)
@ -338,10 +323,11 @@
::
=* duc (need hey.all)
=/ app %hood
=/ see (tuba "<awaiting {(trip app)}, this may take a minute>")
=/ zon=axon [app input=[~ ~] width=80 cursor=(lent see) lin+see]
=/ say (tuba "<awaiting {(trip app)}, this may take a minute>")
=/ 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 ..^$]
:: %flog tasks are unwrapped and sent back to us on our default duct
::
@ -362,35 +348,60 @@
?: ?=(%knob -.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)
:: 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]
?> =(~ session.task)
=/ session (need hey.all)
=/ =axon (~(got by dug.all) session)
:: register the viewer and send them the prompt line
::
:- [hen %give %blit [see.axon]~]~
..^$(eye.all (~(put ju eye.all) session hen))
=^ moz all
abet:(send:nus %hey ~)
:- moz
..^$(eye.all (~(put ju eye.all) ses hen))
:: %flee closes a subscription to the target session, from the current duct
::
?: ?=(%flee -.task)
:- ~
~| [%no-session session.task]
?> =(~ session.task)
=/ session (need hey.all)
..^$(eye.all (~(del ju eye.all) session hen))
..^$(eye.all (~(del ju eye.all) ses hen))
::
=/ nus (ax hen)
=? nus &(?=(~ nus) ?=(^ hey.all))
::TODO allow specifying target session in task
(ax u.hey.all)
=/ nus
(ax hen ses)
?~ nus
:: :hen is an unrecognized duct
:: session :ses does not exist
:: 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 ~)
[((slog (flop tan)) ~) ..^$]
::
@ -398,8 +409,63 @@
[moz ..^$]
::
++ load :: import old state
|= old=axle
..^$(all old)
=< |= old=any-axle
?- -.old
%5 ..^$(all old)
%4 $(old (axle-4-to-5 old))
==
|%
+$ any-axle $%(axle axle-4)
::
+$ 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
=- [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
^- roon
@ -428,19 +494,12 @@
=(%$ syd)
==
~
:: /dx/sessions//line blit current line (prompt) of default session
:: /dx/sessions//cursor @ud current cursor position of default session
::TODO support asking for specific sessions once session ids are real
:: /dy/sessions (set @tas) all existing sessions
:: /du/sessions/[ses] ? does session ses exist?
::
?. ?=(%x ren) ~
?+ tyl ~
[%sessions %$ *]
?~ hey.all [~ ~]
?~ session=(~(get by dug.all) u.hey.all) [~ ~]
?+ t.t.tyl ~
[%line ~] ``blit+!>(`blit`see.u.session)
[%cursor ~] ``atom+!>(pos.u.session)
==
?+ [ren tyl] ~
[%y %sessions ~] ``noun+!>(~(key by dug.all))
[%u %sessions @ ~] ``noun+!>((~(has by dug.all) (snag 1 tyl)))
==
::
++ stay all
@ -451,12 +510,11 @@
?^ dud
~|(%dill-take-dud (mean tang.u.dud))
::
=/ nus (ax hen)
=/ nus (aw hen tea)
?~ nus
:: :hen is an unrecognized duct
:: could be before %boot (or %boot failed)
:: :tea points to an unrecognized session
::
~& [%dill-take-no-flow hen -.hin +<.hin]
~& [%dill-take-no-session tea -.hin +<.hin]
[~ ..^$]
=^ moz all abet:(take:u.nus tea hin)
[moz ..^$]

View File

@ -198,11 +198,21 @@
:: +mo-abet: finalize, reversing 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-talk: build task to print config report or failure trace
::
++ mo-core .
++ mo-abed |=(hun=duct mo-core(hen hun))
++ mo-abet [(flop moves) gall-payload]
++ 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-slip |=(p=note-arvo mo-core(moves [[hen slip+p] moves]))
++ mo-past
@ -303,12 +313,12 @@
=/ ap-core +.wag
?^ maybe-tang
=. 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 (mo-clear-queue dap)
=/ =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
@ -904,8 +914,8 @@
::
=/ running (~(put by yokes.state) agent-name yoke)
=/ moves
=/ giver |=(report=(each suss tang) [hen %give %onto report])
=/ from-suss (turn agent-config giver)
=/ talker |=(report=(each suss tang) [hen %pass (mo-talk report)])
=/ from-suss (turn agent-config talker)
:(weld agent-moves from-suss moves)
::
%_ mo-core

View File

@ -105,11 +105,8 @@
$>(%wake gift:behn) ::
== ::
$: %gall ::
$> $? %onto ::
%unto ::
== ::
gift:gall ::
==
$>(%unto gift:gall) ::
== ::
== ::
-- ::
:: ::::
@ -507,7 +504,7 @@
%ruin
::NOTE we blast this out to _all_ known ducts, because the common
:: 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)
=/ sis ~(tap in ships.tac)
|-
@ -550,10 +547,6 @@
=/ ships (~(get ju ship-sources-reverse.etn) source-id)
%- curd =< abet
(sources:~(feel su hen now pki etn) ships source)
::
[%gall %onto *]
~& [%jael-onto tea hin]
+>.$
::
[%gall %unto *]
?- +>-.hin

View File

@ -4,7 +4,7 @@
=> ..lull
~% %zuse ..part ~
|%
++ zuse %417
++ zuse %416
:: :: ::
:::: :: :: (2) engines
:: :: ::
@ -3843,6 +3843,102 @@
~
(some (~(run by lum) need))
-- ::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
::
@ -4928,7 +5024,7 @@
=< q.q %- need %- need
(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
@ -4968,7 +5064,7 @@
%pawn (end 4 who)
==
--
:: surface core: stateless queries for default numeric sponsorship
:: surface core: for userspace use, with .^
::
|%
:: :: ++cite:title
@ -5003,13 +5099,25 @@
%j
/(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 :: our / our moon
|= [our=ship who=ship]
++ team :: her
|= [her=ship who=ship]
^- ?
?| =(our who)
&(?=(%earl (clan who)) =(our (^sein who)))
==
=(her who)
:: :: ++moon:title
++ moon :: her moon
|= [her=ship who=ship]
^- ?
&(=(%earl (clan who)) =(her (^sein who)))
-- ::title
:: ::
:::: ++milly :: (2k) milliseconds

View File

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

View File

@ -106,10 +106,6 @@
:: Doesn't follow horizontal & vertical ordering
::
=/ unbalanced-e=(set @) [1 [3 ~ ~] [2 ~ ~]]
:: Duplicate elements
::
=/ has-dupes=(set @) [1 [1 ~ ~] ~]
::
;: weld
%+ expect-eq
!> [%b-a %.y]
@ -129,9 +125,6 @@
%+ expect-eq
!> [%u-e %.n]
!> [%u-e ~(apt in unbalanced-e)]
%+ expect-eq
!> [%h-d %.n]
!> [%h-d ~(apt in has-dupes)]
==
::
:: Test splits a in b

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

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

View File

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

View File

@ -136,4 +136,28 @@
=+ dat=(transmute [%mor leg] [%ins pos `@c`0])
?> ?=(%ins -.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
::
/+ dill
::
|_ =belt:dill
++ grad %noun
:: +grab: convert from
@ -7,18 +9,7 @@
++ grab
|%
++ noun belt:dill
++ json
^- $-(^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))
==
++ json belt:dejs:dill
--
:: +grow: convert to
::

View File

@ -1,5 +1,7 @@
:: blit: runtime blit structure
::
/+ dill
::
|_ =blit:dill
++ grad %noun
:: +grab: convert from
@ -13,49 +15,6 @@
++ grow
|%
++ noun blit
++ json
^- ^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)))
--
==
==
++ json (blit:enjs:dill blit)
--
--

View File

@ -20,7 +20,9 @@
|= jon=^json ^- sole-action
%- need %. jon
=> [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
|* [a=term b=fist]
|=(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
$: id=@ta :: duct id
$: id=sole-id :: session id
$= dat
$% :: [%abo ~] :: reset interaction
[%det sole-change] :: command line edit

View File

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

View File

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

View File

@ -119,15 +119,25 @@ deriveNoun ''BehnEf
data Blit
= Bel ()
| Clr ()
| Hop Word64
| Hop HopTarget
| Klr Stub
| Lin [Char]
| Mor ()
| Put [Char]
| Nel ()
| Sag Path Noun
| Sav Path Atom
| Url Cord
| Wyp ()
--TMP backwards compatibility
| Lin [Char]
| Mor ()
deriving (Eq, Ord)
--NOTE bottom-left-0-based coordinates
data HopTarget
= Col Word64
| Roc Word64 Word64 -- row, col
deriving (Eq, Ord, Show)
data Deco
= DecoBl
| DecoBr
@ -205,18 +215,33 @@ instance FromNoun Tint where
"w" -> pure TintW
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
-- megabytes and makes king hang.
instance Show Blit where
show (Bel ()) = "Bel ()"
show (Clr ()) = "Clr ()"
show (Hop x) = "Hop " ++ (show x)
show (Hop t) = "Hop " ++ (show t)
show (Klr s) = "Klr " ++ (show s)
show (Lin c) = "Lin " ++ (show c)
show (Mor ()) = "Mor ()"
show (Put c) = "Put " ++ (show c)
show (Nel ()) = "Nel ()"
show (Sag path _) = "Sag " ++ (show path)
show (Sav path _) = "Sav " ++ (show path)
show (Url c) = "Url " ++ (show c)
show (Wyp ()) = "Wyp ()"
--
show (Lin c) = "Lin " ++ (show c)
show (Mor ()) = "Mor ()"
{-|
%blip -- TODO

View File

@ -20,6 +20,7 @@ import Urbit.Arvo.Common (ReOrg(..), reorgThroughNoun)
import qualified Crypto.Sign.Ed25519 as Ed
import qualified Data.ByteString as BS
import qualified Data.Char as C
import qualified Data.ByteString.Char8 as C
import qualified Network.HTTP.Types.Method as H
@ -318,19 +319,52 @@ data LegacyBootEvent
| Dawn Dawn
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)
data Belt
= Aro ArrowKey
| Bac ()
| Ctl Cord
| Del ()
| Met Cord
| Ret ()
= Bol Bolt
| Mod Modifier Bolt
| Txt Tour
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
= TermEvBelt (UD, ()) Belt
| TermEvBlew (UD, ()) Word Word
@ -341,7 +375,7 @@ data TermEv
deriveNoun ''LegacyBootEvent
deriveNoun ''ArrowKey
deriveNoun ''Belt
deriveNoun ''Modifier
deriveNoun ''TermEv
@ -392,27 +426,23 @@ instance FromNoun Ev where
-- Short Event Names -----------------------------------------------------------
{-
In the case of the user hitting enter, the cause is technically a
terminal event, but we don't display any name because the cause is
really the user.
In the case of user input, the cause is technically a terminal event,
but we don't display any name because the cause is really the user.
-}
getSpinnerNameForEvent :: Ev -> Maybe Text
getSpinnerNameForEvent = \case
EvBlip b -> case b of
BlipEvAmes _ -> Just "ames"
BlipEvArvo _ -> Just "arvo"
BlipEvBehn _ -> Just "behn"
BlipEvBoat _ -> Just "boat"
BlipEvHttpClient _ -> Just "iris"
BlipEvHttpServer _ -> Just "eyre"
BlipEvJael _ -> Just "jael"
BlipEvNewt _ -> Just "newt"
BlipEvSync _ -> Just "clay"
BlipEvTerm t | isRet t -> Nothing
BlipEvTerm t -> Just "term"
where
isRet (TermEvBelt _ (Ret ())) = True
isRet _ = False
BlipEvAmes _ -> Just "ames"
BlipEvArvo _ -> Just "arvo"
BlipEvBehn _ -> Just "behn"
BlipEvBoat _ -> Just "boat"
BlipEvHttpClient _ -> Just "iris"
BlipEvHttpServer _ -> Just "eyre"
BlipEvJael _ -> Just "jael"
BlipEvNewt _ -> Just "newt"
BlipEvSync _ -> Just "clay"
BlipEvTerm (TermEvBelt _ _) -> Nothing
BlipEvTerm t -> Just "term"
summarizeEvent :: Ev -> Text
summarizeEvent ev =

View File

@ -333,7 +333,7 @@ pier (serf, log) vSlog startedSig injected = do
io $ readTVarIO siteSlog >>= ($ s)
logOther "serf" (display $ T.strip $ tankToText tank)
let err = atomically . Term.trace muxed . (<> "\r\n")
let err = atomically . Term.trace muxed
(bootEvents, startDrivers) <- do
env <- ask
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.
data LineState = LineState
{ lsLine :: Text
, lsCurPos :: Int
{ lsLine :: [(Stye, [Char])]
, lsCurPos :: CurPos
, lsSpinTimer :: Maybe (Async ())
, lsSpinCause :: Maybe Text
, lsSpinFirstRender :: Bool
@ -54,11 +54,19 @@ data LineState = LineState
, lsPrevEndTime :: Wen
}
data CurPos = CurPos
{ row :: Int
, col :: Int
}
-- | A record used in reading data from stdInput.
data ReadData = ReadData
{ rdBuf :: Ptr Word8
, rdEscape :: Bool
, rdBracket :: Bool
, rdMouse :: Bool
, rdMouseBut :: Word8
, rdMouseCol :: Word8
, rdUTF8 :: ByteString
, rdUTF8width :: Int
}
@ -165,7 +173,8 @@ leftBracket, rightBracket :: Text
leftBracket = "«"
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_warm_us = 50000
_spin_rate_us = 250000
@ -201,6 +210,9 @@ localClient doneSignal = fst <$> mkRAcquire start stop
-- to the muxing client.
putTMVar tsSizeChange ts)
-- start mouse reporting
putStr "\x1b[?9h"
pWriterThread <- asyncBound
(writeTerminal tsWriteQueue spinnerMVar tsizeTVar)
@ -217,7 +229,7 @@ localClient doneSignal = fst <$> mkRAcquire start stop
tsReadQueue <- newTQueueIO
pReaderThread <- asyncBound
(readTerminal tsReadQueue tsWriteQueue (bell tsWriteQueue))
(readTerminal tsReadQueue tsWriteQueue tsizeTVar (bell tsWriteQueue))
let client = Client { take = Just <$> asum
[ readTQueue tsReadQueue <&> ClientTakeBelt,
@ -238,6 +250,9 @@ localClient doneSignal = fst <$> mkRAcquire start stop
-- at shutdown, just leak the file descriptor.
cancel pWriterThread
-- stop mouse reporting
putStr "\x1b[?9l"
-- inject one final newline, as we're usually on the prompt.
putStr "\r\n"
@ -266,31 +281,50 @@ localClient doneSignal = fst <$> mkRAcquire start stop
-- Writes data to the terminal. Both the terminal reading, normal logging,
-- 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 q spinner termSizeVar = do
currentTime <- io $ now
loop (LineState "" 0 Nothing Nothing True 0 currentTime)
loop
termSizeVar
(LineState [] (CurPos 0 0) Nothing Nothing True 0 currentTime)
where
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 ls p = do
putStr "\r"
T.clearLine
putStr p
termRefreshLine ls
TermSize _ height <- readTVarIO termSizeVar
T.hijack (fromIntegral height) $ putStr p
pure ls
writeSlog :: LineState -> (Atom, Tank) -> RIO e LineState
writeSlog ls slog = do
putStr "\r"
T.clearLine
TermSize width _ <- atomically $ readTVar termSizeVar
-- TODO: Ignoring priority for now. Priority changes the color of,
-- and adds a prefix of '>' to, the output.
let lines = fmap unTape $ wash (WashCfg 0 width) $ tankTree $ snd slog
forM lines $ \line -> putStr (line <> "\r\n")
termRefreshLine ls
TermSize width height <- readTVarIO termSizeVar
T.hijack (fromIntegral height) do
let lines = fmap (pref . unTape) $
wash (WashCfg 0 width) $ tankTree $ snd slog
T.putCsi 'm' styl
forM (intersperse "\n" lines) $ \line -> putStr line
T.putCsi 'm' [0]
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
@ -305,7 +339,7 @@ localClient doneSignal = fst <$> mkRAcquire start stop
current <- io $ now
delay <- pure $ case mTxt of
Nothing -> 0
Nothing -> _spin_fast_us
Just _ ->
if (gap current lsPrevEndTime ^. microSecs) < _spin_idle_us
then _spin_warm_us
@ -326,34 +360,41 @@ localClient doneSignal = fst <$> mkRAcquire start stop
maybe (pure ()) cancel lsSpinTimer
-- We do a final flush of the spinner mvar to ensure we don't
-- have a lingering signal which will redisplay the spinner after
-- we call termRefreshLine below.
-- we call termRestoreLine below.
atomically $ tryTakeTMVar spinner
-- If we ever actually ran the spinner display callback, we need
-- to force a redisplay of the command prompt.
ls <- if not lsSpinFirstRender || True
then termRefreshLine ls
else pure ls
if not lsSpinFirstRender
then termRestoreLine ls termSizeVar
else pure ()
endTime <- io $ now
pure $ ls { lsSpinTimer = Nothing, lsPrevEndTime = endTime }
execEv :: LineState -> Term.Ev -> RIO e LineState
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.Slog s -> writeSlog ls s
Term.Blank -> writeBlank ls
Term.Spinr (Just txt) -> doSpin ls (unCord <$> txt)
Term.Spinr Nothing -> unspin ls
-- TODO What does this do?
spin :: LineState -> RIO e LineState
spin ls@LineState{..} = do
spin :: TVar TermSize -> LineState -> RIO e LineState
spin ts ls@LineState{..} = do
let spinner = (spinners !! lsSpinFrame) ++ case lsSpinCause of
Nothing -> ""
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)))
let newFrame = (lsSpinFrame + 1) `mod` length spinners
@ -362,28 +403,35 @@ localClient doneSignal = fst <$> mkRAcquire start stop
, lsSpinFrame = newFrame
}
loop :: LineState -> RIO e ()
loop ls = do
loop :: TVar TermSize -> LineState -> RIO e ()
loop ts ls = do
join $ atomically $ asum
[ readTQueue q >>= pure . (foldM execEv ls >=> loop)
, takeTMVar spinner >> pure (spin ls >>= loop)
[ readTQueue q >>= pure . (foldM execEv ls >=> loop ts)
, takeTMVar spinner >> pure (spin ts ls >>= loop ts)
]
-- Writes an individual blit to the screen
writeBlit :: LineState -> Blit -> RIO e LineState
writeBlit ls = \case
writeBlit :: TVar TermSize -> LineState -> Blit -> RIO e LineState
writeBlit ts ls = \case
Bel () -> T.soundBell $> ls
Clr () -> do T.clearScreen
termRefreshLine ls
Hop w -> termShowCursor ls (fromIntegral w)
Klr s -> do ls2 <- termShowClear ls
termShowStub ls2 s
Lin c -> do ls2 <- termShowClear ls
termShowLine ls2 (pack c)
Mor () -> termShowMore ls
T.cursorRestore
pure ls
Hop t -> case t of
Col c -> termShowCursor ls ts 0 (fromIntegral c)
Roc r c -> termShowCursor ls ts (fromIntegral r) (fromIntegral c)
Klr s -> termShowStub ls s
Put c -> termShowLine ls (pack c)
Nel () -> termShowNewline ls
Sag path noun -> pure ls
Sav path atom -> 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 = \case
@ -428,55 +476,88 @@ localClient doneSignal = fst <$> mkRAcquire start stop
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 ls (Stub s) = do
let visualLength = sum $ fmap (length . snd) s
let outText = pack $ mconcat $ fmap (uncurry termRenderStubSegment) s
putStr outText
pure ls { lsLine = outText, lsCurPos = visualLength }
termShowStub ls@LineState{lsCurPos, lsLine} (Stub s) = do
putStr $ pack $ mconcat $ fmap (uncurry termRenderStubSegment) s
T.cursorRestore
case row lsCurPos of
0 -> pure ls { lsLine = overwriteStub lsLine (col lsCurPos) s }
_ -> pure ls
-- Moves the cursor to the requested position
termShowCursor :: LineState -> Int -> RIO e LineState
termShowCursor ls@LineState{..} {-line pos)-} newPos = do
if newPos < lsCurPos then do
T.cursorLeft (lsCurPos - newPos)
pure ls { lsCurPos = newPos }
else if newPos > lsCurPos then do
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
termShowCursor :: LineState -> TVar TermSize -> Int -> Int -> RIO e LineState
termShowCursor ls ts row col = do
TermSize _ h <- readTVarIO ts
T.cursorMove (max 0 (fromIntegral h - row - 1)) col
T.cursorSave
pure ls { lsCurPos = CurPos row col }
-- Displays and sets the current line
termShowLine :: LineState -> Text -> RIO e LineState
termShowLine ls newStr = do
termShowLine ls@LineState{lsCurPos, lsLine} newStr = do
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 ls = do
termShowClear ls@LineState{lsCurPos} = do
putStr "\r"
T.clearLine
pure ls { lsLine = "", lsCurPos = 0 }
T.cursorRestore
case row lsCurPos of
0 -> pure ls { lsLine = [] }
_ -> pure ls
-- New Current Line
termShowMore :: LineState -> RIO e LineState
termShowMore ls = do
termShowNewline :: LineState -> RIO e LineState
termShowNewline ls@LineState{lsCurPos} = do
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
termRefreshLine :: LineState -> RIO e LineState
termRefreshLine ls@LineState{lsCurPos,lsLine} = do
ls <- termShowClear ls
ls <- termShowLine ls lsLine
termShowCursor ls lsCurPos
-- Redraw the bottom LineState, maintaining the current curpos
termRestoreLine :: LineState -> TVar TermSize -> RIO e ()
termRestoreLine ls@LineState{lsLine} ts = do
TermSize _ h <- readTVarIO ts
T.cursorMove (fromIntegral h - 1) 0
T.clearLine
putStr $ pack $ mconcat $ fmap (uncurry termRenderStubSegment) lsLine
T.cursorRestore
-- ring my bell
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,
-- since that's kinda closer to what libuv does?
readTerminal :: forall e. HasLogFunc e
=> TQueue Belt -> TQueue [Term.Ev] -> (RIO e ()) -> RIO e ()
readTerminal rq wq bell =
rioAllocaBytes 1 $ \ buf -> loop (ReadData buf False False mempty 0)
=> TQueue Belt
-> TQueue [Term.Ev]
-> 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
loop :: ReadData -> RIO e ()
loop rd@ReadData{..} = do
@ -513,26 +599,41 @@ localClient doneSignal = fst <$> mkRAcquire start stop
if rdEscape then
if rdBracket then do
case c of
'A' -> sendBelt $ Aro U
'B' -> sendBelt $ Aro D
'C' -> sendBelt $ Aro R
'D' -> sendBelt $ Aro L
'A' -> sendBelt $ Bol $ Aro U
'B' -> sendBelt $ Bol $ Aro D
'C' -> sendBelt $ Bol $ Aro R
'D' -> sendBelt $ Bol $ Aro L
'M' -> pure ()
_ -> 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
sendBelt $ Met $ Cord $ pack [c]
loop rd { rdEscape = False }
else if c == '.' then do
sendBelt $ Met $ Cord "dot"
sendBelt $ Mod Met $ Key c
loop rd { rdEscape = False }
else if w == 8 || w == 127 then do
sendBelt $ Met $ Cord "bac"
sendBelt $ Mod Met $ Bac ()
loop rd { rdEscape = False }
else if c == '[' || c == '0' then do
loop rd { rdBracket = True }
else do
bell
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
-- continue reading into the utf8 accumulation buffer
rd@ReadData{..} <- pure rd { rdUTF8 = snoc rdUTF8 w }
@ -543,30 +644,31 @@ localClient doneSignal = fst <$> mkRAcquire start stop
error "empty utf8 accumulation buffer"
Just (c, bytes) | bytes /= rdUTF8width ->
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 }
else if w >= 32 && w < 127 then do
sendBelt $ Txt $ Tour $ [c]
sendBelt $ Bol $ Key c
loop rd
else if w == 0 then do
bell
loop rd
else if w == 8 || w == 127 then do
sendBelt $ Bac ()
sendBelt $ Bol $ Bac ()
loop rd
else if w == 13 then do
sendBelt $ Ret ()
sendBelt $ Bol $ Ret ()
loop rd
else if w == 3 then do
-- ETX (^C)
logInfo $ "Ctrl-c interrupt"
atomically $ do
writeTQueue wq [Term.Trace "interrupt\r\n"]
writeTQueue rq $ Ctl $ Cord "c"
writeTQueue wq [Term.Trace "interrupt"]
writeTQueue rq $ Mod Ctl $ Key 'c'
loop rd
else if w <= 26 then do
case pack [BS.w2c (w + 97 - 1)] of
c -> do sendBelt $ Ctl $ Cord c
case BS.w2c (w + 97 - 1) of
'd' -> atomically doneSignal
c -> do sendBelt $ Mod Ctl $ Key c
loop rd
else if w == 27 then do
loop rd { rdEscape = True }
@ -643,7 +745,7 @@ term env (tsize, Client{..}) plan stat serfSIGINT = runTerm
atomically take >>= \case
Nothing -> pure ()
Just (ClientTakeBelt b) -> do
when (b == Ctl (Cord "c")) $ do
when (b == Mod Ctl (Key 'c')) $ do
io serfSIGINT
let beltEv = EvBlip $ BlipEvTerm $ TermEvBelt (UD 1, ()) $ b
let beltFailed _ = pure ()

View File

@ -22,7 +22,7 @@ import Urbit.TermSize
Input Event for terminal driver:
%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
%blank -- print a blank line
%spinr -- Start or stop the spinner

View File

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

View File

@ -4,9 +4,12 @@
module Urbit.Vere.Term.Render
( clearScreen
, clearLine
, cursorRight
, cursorLeft
, soundBell
, cursorMove
, cursorSave
, cursorRestore
, putCsi
, hijack
) where
import Urbit.Prelude
@ -25,8 +28,27 @@ clearLine = liftIO $ ANSI.clearLine
soundBell :: MonadIO m => m ()
soundBell = liftIO $ putStr "\a"
cursorLeft :: MonadIO m => Int -> m ()
cursorLeft = liftIO . ANSI.cursorBackward
--NOTE top-left-0-based coordinates
cursorMove :: MonadIO m => Int -> Int -> m ()
cursorMove r c = liftIO $ ANSI.setCursorPosition r c
cursorRight :: MonadIO m => Int -> m ()
cursorRight = liftIO . ANSI.cursorForward
cursorSave :: MonadIO m => m ()
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

@ -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">
<style>
body, #root {
height: 100vh;
height: 99vh; /* prevent scrollbar on outer frame */
margin: 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>
</head>
<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 { useTheme } from './settings';
import useTermState from './state';
import useTermState from '../state';
export function useDark() {
const [osDark, setOsDark] = useState(false);
@ -11,12 +10,11 @@ export function useDark() {
setOsDark(e.matches);
};
setOsDark(themeWatcher.matches);
themeWatcher.addListener(update);
themeWatcher.addEventListener('change', update);
return () => {
themeWatcher.removeListener(update);
}
themeWatcher.removeEventListener('change', update);
};
}, []);
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;

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@
"@urbit/api": "^1.1.1",
"@urbit/http-api": "^1.2.1",
"file-saver": "^2.0.5",
"lodash": "^4.17.21",
"react": "^16.14.0",
"react-dom": "^16.14.0",
"react-router-dom": "^5.2.0",
@ -36,7 +37,7 @@
"@types/styled-system": "^5.1.10",
"@typescript-eslint/eslint-plugin": "^4.15.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",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.6.3",
@ -45,7 +46,9 @@
"clean-webpack-plugin": "^3.0.0",
"cross-env": "^7.0.3",
"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",
"html-webpack-plugin": "^4.5.1",
"husky": "^6.0.0",
@ -58,7 +61,8 @@
"webpack-dev-server": "^3.11.2"
},
"scripts": {
"lint": "eslint ./src/**/*.{ts,tsx}",
"lint": "eslint ./**/*.{ts,tsx}",
"lint-fix": "eslint --fix ./**/*.{ts,tsx}",
"lint-file": "eslint",
"tsc": "tsc",
"tsc:watch": "tsc --watch",

View File

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

View File

@ -16,15 +16,15 @@
+$ card card:shoe
::
+$ versioned-state
$% state-3
$% state-4
state-3
state-2
state-1
state-0
==
::
+$ state-3
$: %3
::TODO support multiple sessions
+$ state-4
$: %4
sessions=(map sole-id session) :: sole sessions
bound=(map resource glyph) :: bound resource glyphs
binds=(jug glyph resource) :: resource glyph lookup
@ -33,7 +33,17 @@
timez=(pair ? @ud) :: timezone adjustment
==
::
+$ sole-id @ta
+$ state-3
$: %3
sessions=(map @ta session)
bound=(map resource glyph)
binds=(jug glyph resource)
settings=(set term)
width=@ud
timez=(pair ? @ud)
==
::
+$ sole-id sole-id:shoe
+$ session
$: viewing=(set resource) :: connected graphs
history=(list uid:post) :: scrollback pointers
@ -115,7 +125,7 @@
== ::
::
--
=| state-3
=| state-4
=* state -
::
%- agent:dbug
@ -258,14 +268,14 @@
settings width timez
==
::
=^ cards u.old
=^ cards-1 u.old
?. ?=(%2 -.u.old) [~ u.old]
:- :~ [%pass /chat-store %agent [our-self %chat-store] %leave ~]
[%pass /invites %agent [our.bowl %invite-store] %leave ~]
==
^- state-3
:- %3
:* %+ ~(put in *(map sole-id session))
:* %+ ~(put in *(map @ta session))
(cat 3 'drum_' (scot %p our.bowl))
:* ~ ~ 0
::
@ -290,14 +300,29 @@
timez.u.old
==
::
?> ?=(%3 -.u.old)
=^ cards-2 u.old
?. ?=(%3 -.u.old) [~ u.old]
:- %+ turn ~(tap in ~(key by sessions.u.old))
|= id=@ta
^- card:agent:gall
[%give %kick ~[/sole/[id]] ~]
=- u.old(- %4, sessions -)
%- ~(gas by *(map sole-id session))
%+ murn ~(tap by sessions.u.old)
|= [id=@ta s=session]
(bind (upgrade-id:sole:shoe id) (late s))
::
?> ?=(%4 -.u.old)
:_ u.old
%+ welp
cards
?: %- ~(has by wex.bowl)
[/graph-store our-self %graph-store]
~
~[connect]
;: welp
cards-1
cards-2
::
?: %- ~(has by wex.bowl)
[/graph-store our-self %graph-store]
~
~[connect]
==
:: +connect: connect to the graph-store
::
++ connect

View File

@ -41,6 +41,7 @@
state-one
state-two
state-three
state-four
==
::
+$ state-zero
@ -61,9 +62,15 @@
=groups
wait=(set ship)
==
::
+$ state-four
$: %4
=groups
wait=(set ship)
==
--
::
=| state-three
=| state-four
=* state -
::
%- agent:dbug
@ -84,7 +91,15 @@
=| cards=(list card)
|^
?- -.old
%3 [(flop cards) this(state old)]
%4 [(flop cards) this(state old)]
::
%3
%_ $
old [%4 +.old]
cards
:_ cards
[%pass /pyre/rebuild %agent [our dap]:bowl %poke noun+!>(%rebuild)]
==
::
%2
%_ $
@ -140,6 +155,7 @@
?+ q.vase !!
%migrate poke-migrate:gc
%export poke-export:gc
%rebuild poke-rebuild:gc
==
::
?(%group-update-0 %group-action)
@ -235,6 +251,42 @@
::
|_ bol=bowl:gall
+* io ~(. agentio bol)
++ poke-rebuild
^- (quip card _state)
|^
=. wait
put-missing
=^ cards state
rewatch
[cards state]
::
++ rewatch
=/ wait ~(tap in wait)
=| cards=(list card)
|-
?~ wait
[cards state]
=/ wir /gladio/(scot %p i.wait)
=. cards
:_(cards (watch-init-migrate i.wait))
:: if we have a subscription already, leave first to restart
=? cards
(~(has by wex.bol) [wir i.wait %groups])
:_(cards [%pass wir %agent [i.wait %groups] %leave ~])
$(wait t.wait)
::
++ put-missing
=/ wex ~(tap by wex.bol)
|-
?~ wex
wait
=/ [[=wire =ship =term] [acked=? =(pole knot)]]
i.wex
?. ?=([%gladio ship=@ ~] pole)
$(wex t.wex)
$(wex t.wex, wait (~(put in wait) (slav %p ship.pole)))
--
::
++ poke-export
^- (quip card _state)
:_ state
@ -351,8 +403,8 @@
|= arc=*
^- (quip card _state)
|^
=/ sty=state-three
[%3 (remake-groups ;;((tree [resource tree-group]) +.arc)) ~]
=/ sty=state-four
[%4 (remake-groups ;;((tree [resource tree-group]) +.arc)) ~]
:_ sty
%+ roll ~(tap by groups.sty)
|= [[rid=resource grp=group] out=(list card)]

View File

@ -9,12 +9,14 @@
+$ card card:agent:gall
+$ versioned-state
$% state-zero
state-one
==
::
+$ state-zero [%0 =credentials =configuration]
+$ state-zero [%0 =credentials:zero:past =configuration:zero:past]
+$ state-one [%1 =credentials =configuration]
--
::
=| state-zero
=| state-one
=* state -
::
%- agent:dbug
@ -28,8 +30,28 @@
++ on-init on-init:def
++ on-save !>(state)
++ on-load
|= old-vase=vase
[~ this(state !<(state-zero old-vase))]
|= =vase
=/ old !<(versioned-state vase)
|^
?- -.old
%1 `this(state old)
%0 `this(state (state-0-to-1 old))
==
++ state-0-to-1
|= zer=state-zero
^- state-one
:* %1
credentials.zer
(configuration-0-to-1 configuration.zer)
==
++ configuration-0-to-1
|= conf=configuration:zero:past
^- ^configuration
:* buckets.conf
current-bucket.conf
''
==
--
::
++ on-poke
~/ %s3-poke
@ -56,6 +78,9 @@
::
%set-secret-access-key
state(secret-access-key.credentials secret-access-key.act)
::
%set-region
state(region.configuration region.act)
::
%set-current-bucket
%_ state

View File

@ -0,0 +1,10 @@
:: s3-store|set-current-bucket: set current bucket for S3
::
/- *s3
:- %say
|= $: [now=@da eny=@uvJ =beak]
[[region=@t ~] ~]
==
:- %s3-action
^- action
[%set-region region]

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

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

View File

@ -10,6 +10,7 @@
:~ [%set-endpoint so:dejs]
[%set-access-key-id so:dejs]
[%set-secret-access-key so:dejs]
[%set-region so:dejs]
[%add-bucket so:dejs]
[%remove-bucket so:dejs]
[%set-current-bucket so:dejs]
@ -25,6 +26,7 @@
:~ ?- -.upd
%set-current-bucket [%'setCurrentBucket' s+bucket.upd]
%add-bucket [%'addBucket' s+bucket.upd]
%set-region [%'setRegion' s+region.upd]
%remove-bucket [%'removeBucket' s+bucket.upd]
%set-endpoint [%'setEndpoint' s+endpoint.upd]
%set-access-key-id [%'setAccessKeyId' s+access-key-id.upd]
@ -44,6 +46,7 @@
%- pairs:enjs
:~ [%buckets a+(turn ~(tap in buckets.configuration.upd) |=(a=@t s+a))]
[%'currentBucket' s+current-bucket.configuration.upd]
[%'region' s+region.configuration.upd]
==
==
==

View File

@ -0,0 +1,27 @@
|%
+$ credentials
$: endpoint=@t
access-key-id=@t
secret-access-key=@t
==
::
+$ configuration
$: buckets=(set @t)
current-bucket=@t
==
::
+$ action
$% [%set-endpoint endpoint=@t]
[%set-access-key-id access-key-id=@t]
[%set-secret-access-key secret-access-key=@t]
[%add-bucket bucket=@t]
[%remove-bucket bucket=@t]
[%set-current-bucket bucket=@t]
==
::
+$ update
$% [%credentials =credentials]
[%configuration =configuration]
action
==
--

View File

@ -1,4 +1,9 @@
/- zer=s3-0
|%
++ past
|%
++ zero zer
--
+$ credentials
$: endpoint=@t
access-key-id=@t
@ -8,6 +13,7 @@
+$ configuration
$: buckets=(set @t)
current-bucket=@t
region=@t
==
::
+$ action
@ -17,6 +23,7 @@
[%add-bucket bucket=@t]
[%remove-bucket bucket=@t]
[%set-current-bucket bucket=@t]
[%set-region region=@t]
==
::
+$ update

View File

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

View File

@ -1,4 +1,5 @@
import { Poke } from '../lib'
import { Scry } from '../../http-api/src'
import { Poke } from '../../http-api/src/types';
import { Belt, Task, SessionTask } from './types';
export const pokeTask = (session: string, task: Task): Poke<SessionTask> => ({
@ -13,9 +14,7 @@ export const pokeBelt = (
): Poke<SessionTask> => pokeTask(session, { belt });
//NOTE scry will return string[]
// export const scrySessions = (): Scry => ({
// app: 'herm',
// path: `/sessions`
// });
//TODO remove stub once new backend lands
export const scrySessions = (): string[] => [''];
export const scrySessions = (): Scry => ({
app: 'herm',
path: `/sessions`
});

View File

@ -25,17 +25,15 @@ export type Stub = {
export type Blit =
| { bel: null } // make a noise
| { clr: null } // clear the screen
| { hop: number | { r: number, c: number } } // set cursor col/pos
| { hop: number | { x: number, y: number } } // set cursor col/pos
| { klr: Stub[] } // put styled
| { put: string[] } // put text at cursor
| { mor: Blit[] } // multiple blits
| { nel: null } // newline
| { put: string[] } // put text at cursor
| { sag: { path: string, file: string } } // save to jamfile
| { sav: { path: string, file: string } } // save to file
| { url: string } // activate url
| { wyp: null } // wipe cursor line
//
| { lin: string[] } // legacy put
| { mor: true } // legacy nel
// inputs
//
@ -45,21 +43,19 @@ export type Bolt =
| { aro: 'd' | 'l' | 'r' | 'u' }
| { bac: null }
| { del: null }
| { hit: { r: number, c: number } }
| { hit: { x: number, y: number } }
| { ret: null }
export type Belt =
| Bolt
| { mod: { mod: 'ctl' | 'met' | 'hyp', key: Bolt } }
| { txt: Array<string> }
//
| { ctl: string }; // legacy mod
export type Task =
| { belt: Belt }
| { blew: { w: number, h: number } }
| { flow: { term: string, apps: Array<{ who: string, app: string }> } }
| { hail: null }
| { hook: null }
| { open: { term: string, apps: Array<{ who: string, app: string }> } }
| { shut: null }
export type SessionTask = { session: string } & Task

View File

@ -167,6 +167,9 @@ u3_ptty_init(uv_loop_t* lup_u, const c3_c** err_c)
// Construct raw termios configuration.
//
// makes input available per-character, does not echo input,
// disables special input pre-processing, output post-processing.
//
{
pty_u->raw_u = pty_u->bak_u;

2
pkg/urbit/configure vendored
View File

@ -211,7 +211,7 @@ for citem in $compat; do
done
cat >config.mk <<EOF
CFLAGS := $CFLAGS -funsigned-char -ffast-math -fcommon -std=gnu99
CFLAGS := $CFLAGS -funsigned-char -ffast-math -fcommon -std=gnu99 -Wno-format-zero-length
LDFLAGS := $LDFLAGS
CC := ${CC-cc}
compat := $compat

View File

@ -572,7 +572,7 @@ _setup_cert_store()
{
BIO* cbio = BIO_new_mem_buf(include_ca_bundle_crt, include_ca_bundle_crt_len);
if ( !cbio || !(_cert_store = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL)) ) {
u3l_log("boot: failed to decode embedded CA certificates\r\n");
u3l_log("boot: failed to decode embedded CA certificates");
exit(1);
}
@ -1267,7 +1267,7 @@ _cw_eval(c3_i argc, c3_c* argv[])
}
u3s_cue_xeno_done(sil_u);
if ( c3n == u3v_boot_lite(pil) ) {
u3l_log("lite: boot failed\r\n");
u3l_log("lite: boot failed");
exit(1);
}
}
@ -1858,7 +1858,7 @@ _cw_vere(c3_i argc, c3_c* argv[])
// initialize curl
//
if ( 0 != curl_global_init(CURL_GLOBAL_DEFAULT) ) {
u3l_log("boot: curl initialization failed\r\n");
u3l_log("boot: curl initialization failed");
exit(1);
}
@ -1888,11 +1888,11 @@ _cw_vere(c3_i argc, c3_c* argv[])
if ( u3_king_vere(pac_c, ver_c, arc_c, dir_c, 0) ) {
u3l_log("vere: download failed\r\n");
u3l_log("vere: download failed");
exit(1);
}
u3l_log("vere: download succeeded\r\n");
u3l_log("vere: download succeeded");
}
/* _cw_vile(): generatoe/print keyfile
@ -2138,7 +2138,7 @@ main(c3_i argc,
sigemptyset(&set);
sigaddset(&set, SIGPROF);
if ( 0 != pthread_sigmask(SIG_BLOCK, &set, NULL) ) {
u3l_log("boot: thread mask SIGPROF: %s\r\n", strerror(errno));
u3l_log("boot: thread mask SIGPROF: %s", strerror(errno));
exit(1);
}
}
@ -2230,7 +2230,7 @@ main(c3_i argc,
{
SECURITY_ATTRIBUTES sa = {sizeof(sa), NULL, TRUE};
if ( NULL == (u3_Host.cev_u = CreateEvent(&sa, FALSE, FALSE, NULL)) ) {
u3l_log("boot: failed to create Ctrl-C event: %d\r\n", GetLastError());
u3l_log("boot: failed to create Ctrl-C event: %d", GetLastError());
exit(1);
}
}
@ -2251,7 +2251,7 @@ main(c3_i argc,
// initialize curl
//
if ( 0 != curl_global_init(CURL_GLOBAL_DEFAULT) ) {
u3l_log("boot: curl initialization failed\r\n");
u3l_log("boot: curl initialization failed");
exit(1);
}

View File

@ -615,6 +615,7 @@
# define c3__khan c3_s4('k','h','a','n')
# define c3__keep c3_s4('k','e','e','p')
# define c3__kern c3_s4('k','e','r','n')
# define c3__key c3_s3('k','e','y')
# define c3__kgo c3_s3('k','g','o')
# define c3__kick c3_s4('k','i','c','k')
# define c3__king c3_s4('k','i','n','g')
@ -786,6 +787,7 @@
# define c3__ne c3_s2('n','e')
# define c3__need c3_s4('n','e','e','d')
# define c3__neft c3_s4('n','e','f','t')
# define c3__nel c3_s3('n','e','l')
# define c3__nest c3_s4('n','e','s','t')
# define c3__netd c3_s4('n','e','t','d')
# define c3__new c3_s3('n','e','w')
@ -1298,6 +1300,7 @@
# define c3__wtsg c3_s4('w','t','s','g')
# define c3__wtts c3_s4('w','t','t','s')
# define c3__wtzp c3_s4('w','t','z','p')
# define c3__wyp c3_s3('w','y','p')
# define c3__wyrd c3_s4('w','y','r','d')
# define c3__xray c3_s4('x','r','a','y')
# define c3__yell c3_s4('y','e','l','l')

View File

@ -145,22 +145,25 @@
} siz;
struct {
c3_y* lin_y; // current line (utf8)
c3_w byt_w; // utf8 line-length
c3_w wor_w; // utf32 line-length
c3_w sap_w; // escape chars in line
c3_w cus_w; // cursor position
u3_noun lin; // bottom line (stub)
c3_w rus_w; // cursor position (row)
c3_w cus_w; // cursor position (column)
} mir;
struct { // escape code control
c3_o ape; // escape received
c3_o bra; // bracket or O received
c3_o mou; // M (for mouse event) received
c3_y ton_y; // mouse button
c3_y col_y; // column coordinate
c3_y seq_y; // vt sequence
} esc;
struct {
c3_y syb_y[5]; // utf8 code buffer
c3_w len_w; // present length
c3_w wid_w; // total width
struct { // input buffering
c3_y syb_y[5]; // utf8 code buffer
c3_w len_w; // present length
c3_w wid_w; // total width
u3_noun imp; // %txt input buffer
} fut;
struct {
@ -180,30 +183,22 @@
struct _u3_usig* nex_u;
} u3_usig;
/* u2_utfo: unix terminfo strings.
/* u2_utfo: terminal escape sequences
*/
typedef struct {
// disabled, currently unused
uv_buf_t mon_u; // mouse reporting on
uv_buf_t mof_u; // mouse reporting off
//
// struct {
// uv_buf_t kcuu1_u; // key_up
// uv_buf_t kcud1_u; // key_down
// uv_buf_t kcub1_u; // key_back
// uv_buf_t kcuf1_u; // key_forward
// } inn;
struct {
uv_buf_t clear_u; // clear_screen
uv_buf_t el_u; // clr_bol clear to beginning
// uv_buf_t el1_u; // clr_eol clear to end
uv_buf_t ed_u; // clear to end of screen
uv_buf_t bel_u; // bel sound bell
uv_buf_t cub1_u; // parm_left
uv_buf_t cuf1_u; // parm_right
uv_buf_t cuu1_u; // parm_up
uv_buf_t cud1_u; // parm_down
// uv_buf_t cub_u; // parm_left_cursor #num
// uv_buf_t cuf_u; // parm_right_cursor #num
} out;
uv_buf_t reg_u; // restore scroll region
//
uv_buf_t suc_u; // save cursor position
uv_buf_t ruc_u; // restore cursor position
uv_buf_t cub_u; // move cursor left one column
//
uv_buf_t clr_u; // clear screen
uv_buf_t cel_u; // clear to end of line
//
uv_buf_t bel_u; // bel sound bell
} u3_utfo;
#if 0
@ -253,7 +248,7 @@
c3_l* row_l); // return tty window size
c3_i fid_i; // file descriptor
c3_w tid_l; // terminal identity number
u3_utfo ufo_u; // terminfo strings
u3_utfo ufo_u; // escape sequences
u3_utat tat_u; // control state
struct _u3_auto* car_u; // driver hack
} u3_utty;
@ -1113,7 +1108,7 @@
/* u3_term_io_loja(): release console from cooked print.
*/
void
u3_term_io_loja(int x);
u3_term_io_loja(int x, FILE* f);
/* u3_term_log_init(): initialize terminal for logging
*/

View File

@ -169,7 +169,7 @@ u3qc_rep(u3_atom a,
return _bit_rep(b, c);
}
u3l_log("rep: stub\r\n");
u3l_log("rep: stub");
return u3_none;
}

View File

@ -159,7 +159,7 @@ u3qc_rip(u3_atom a,
return _bit_rip(b, c);
}
u3l_log("rip: stub\r\n");
u3l_log("rip: stub");
return u3_none;
}

View File

@ -13,21 +13,15 @@ _in_apt(u3_noun a, u3_weak l, u3_weak r)
u3_noun n_a, l_a, r_a;
u3x_trel(a, &n_a, &l_a, &r_a);
if ( (u3_none != l) &&
( (c3y == u3r_sing(n_a, l)) || (c3n == u3qc_gor(n_a, l)) )) {
if ( (u3_none != l) && (c3n == u3qc_gor(n_a, l)) ) {
return c3n;
}
if ( (u3_none != r) &&
( (c3y == u3r_sing(r, n_a)) || (c3n == u3qc_gor(r, n_a)) )) {
if ( (u3_none != r) && (c3n == u3qc_gor(r, n_a)) ) {
return c3n;
}
if ( u3_nul != l_a ) {
if ( c3y == u3r_sing(n_a, u3h(l_a)) ) {
return c3n;
}
if ( c3n == u3qc_mor(n_a, u3h(l_a)) ) {
return c3n;
}
@ -38,10 +32,6 @@ _in_apt(u3_noun a, u3_weak l, u3_weak r)
}
if ( u3_nul != r_a ) {
if ( c3y == u3r_sing(n_a, u3h(r_a)) ) {
return c3n;
}
if ( c3n == u3qc_mor(n_a, u3h(r_a)) ) {
return c3n;
}

View File

@ -98,7 +98,7 @@
}
else {
ret = u3_none;
u3l_log("argon2-error: %s\r\n", err_c);
u3l_log("argon2-error: %s", err_c);
}
u3a_free(out_y);

View File

@ -14,14 +14,14 @@ u3qe_jam(u3_atom a)
siz_w = u3a_count_noun(u3h(som));
tot_w += siz_w;
if ( 0 == siz_w ) {
u3l_log("item: B/0\r\n");
u3l_log("item: B/0");
}
else {
u3a_print_memory(stderr, "item", siz_w);
}
}
if ( u3_blip != som ) {
u3l_log("forgot to terminate list!\r\n");
u3l_log("forgot to terminate list!");
}
c3_w mem_w = u3h_count(u3R->cax.har_p);
@ -31,7 +31,7 @@ u3qe_jam(u3_atom a)
u3a_print_memory(stderr, "total", tot_w);
u3a_print_memory(stderr, "memoization cache", mem_w);
u3h_root* har_u = u3to(u3h_root, u3R->cax.har_p);
u3l_log("memoization entries: %d\r\n", har_u->use_w);
u3l_log("memoization entries: %d", har_u->use_w);
u3a_print_memory(stderr, "unused free", u3a_open(u3R));
return tot_w;
}

View File

@ -31,7 +31,7 @@
// Sanity check: crash if decoding more bits than available
if ( c3y == u3qa_gth(x, m)) {
// u3l_log("[%%rub-hard %d %d %d]\r\n", a, x, m);
// u3l_log("[%%rub-hard %d %d %d]", a, x, m);
return u3m_bail(c3__exit);
}

View File

@ -16,7 +16,7 @@ u3je_secp_init()
sec_u = malloc(urcrypt_secp_prealloc_size());
if ( 0 != urcrypt_secp_init(sec_u, ent_y) ) {
u3l_log("u3e_secp_init failed\r\n");
u3l_log("u3e_secp_init failed");
abort();
}
}

View File

@ -22,7 +22,7 @@
(u3_nul == u3h(hr_con)) &&
(u3_nul == u3t(hr_con)) )
{
u3l_log("old core\r\n");
u3l_log("old core");
abort();
}
}

View File

@ -20,7 +20,7 @@
u3r_trel(dab, &n_dab, &l_dab, &r_dab);
if ( c3n == u3du(n_dab) ) {
// return u3m_bail(c3__fail);
u3l_log("bad look\r\n");
u3l_log("bad look");
return u3m_bail(c3__exit) ;
}
else {

View File

@ -431,7 +431,7 @@ _ca_willoc(c3_w len_w, c3_w ald_w, c3_w alp_w)
sel_w += 1;
}
// u3l_log("walloc %d: *pfr_p %x\n", len_w, u3R->all.fre_p[sel_w]);
// u3l_log("walloc %d: *pfr_p %x", len_w, u3R->all.fre_p[sel_w]);
while ( 1 ) {
u3p(u3a_fbox) *pfr_p = &u3R->all.fre_p[sel_w];
@ -566,7 +566,7 @@ u3a_walloc(c3_w len_w)
u3a_botox(ptr_v) == (u3a_box*)(void *)0x200dfe3e4 ) {
static int xuc_i;
u3l_log("xuc_i %d\r\n", xuc_i);
u3l_log("xuc_i %d", xuc_i);
if ( 1 == xuc_i ) {
u3a_box* box_u = u3a_botox(ptr_v);
@ -682,7 +682,7 @@ u3a_malloc(size_t len_i)
if ( u3a_botox(out_w) == (u3a_box*)(void *)0x3bdd1c80) {
static int xuc_i = 0;
u3l_log("xuc_i %d\r\n", xuc_i);
u3l_log("xuc_i %d", xuc_i);
// if ( 1 == xuc_i ) { abort(); }
xuc_i++;
}
@ -885,7 +885,7 @@ u3a_free(void* tox_v)
c3_w pad_w = tox_w[-1];
c3_w* org_w = tox_w - (pad_w + 1);
// u3l_log("free %p %p\r\n", org_w, tox_w);
// u3l_log("free %p %p", org_w, tox_w);
u3a_wfree(org_w);
}
@ -1013,7 +1013,7 @@ _ca_take_atom(u3a_atom* old_u)
u3_noun new = u3a_to_pug(u3a_outa(new_u));
#ifdef VERBOSE_TAKE
u3l_log("%s: atom %p to %p\r\n", ( c3y == u3a_is_north(u3R) )
u3l_log("%s: atom %p to %p", ( c3y == u3a_is_north(u3R) )
? "north"
: "south",
old_u,
@ -1051,7 +1051,7 @@ _ca_take_cell(u3a_cell* old_u, u3_noun hed, u3_noun tel)
u3_cell new = u3a_to_pom(u3a_outa(new_u));
#ifdef VERBOSE_TAKE
u3l_log("%s: cell %p to %p\r\n", ( c3y == u3a_is_north(u3R) )
u3l_log("%s: cell %p to %p", ( c3y == u3a_is_north(u3R) )
? "north"
: "south",
old_u,
@ -1110,7 +1110,7 @@ _ca_take_next_north(u3a_pile* pil_u, u3_noun veb)
c3_assert( c3y == u3a_north_is_normal(u3R, nov) );
#ifdef VERBOSE_TAKE
u3l_log("north: %p is already %p\r\n", veb_u, u3a_to_ptr(nov));
u3l_log("north: %p is already %p", veb_u, u3a_to_ptr(nov));
#endif
_me_gain_use(nov); // bypass branches in u3k()
@ -1165,7 +1165,7 @@ _ca_take_next_south(u3a_pile* pil_u, u3_noun veb)
c3_assert( c3y == u3a_south_is_normal(u3R, nov) );
#ifdef VERBOSE_TAKE
u3l_log("south: %p is already %p\r\n", veb_u, u3a_to_ptr(nov));
u3l_log("south: %p is already %p", veb_u, u3a_to_ptr(nov));
#endif
_me_gain_use(nov); // bypass branches in u3k()

View File

@ -142,7 +142,7 @@ u3e_check(c3_c* cap_c)
}
sum_w += mug_w;
}
u3l_log("%s: sum %x (%x, %x)\r\n", cap_c, sum_w, nor_w, sou_w);
u3l_log("%s: sum %x (%x, %x)", cap_c, sum_w, nor_w, sou_w);
}
}
@ -488,7 +488,7 @@ _ce_patch_verify(u3_ce_patch* pat_u)
}
#if 0
else {
u3l_log("verify: patch %d/%d, %x\r\n", pag_w, i_w, mug_w);
u3l_log("verify: patch %d/%d, %x", pag_w, i_w, mug_w);
}
#endif
}
@ -815,7 +815,7 @@ _ce_patch_apply(u3_ce_patch* pat_u)
}
}
#if 0
u3l_log("apply: %d, %x\n", pag_w, u3r_mug_words(mem_w, pag_wiz_i));
u3l_log("apply: %d, %x", pag_w, u3r_mug_words(mem_w, pag_wiz_i));
#endif
}
}
@ -1169,13 +1169,13 @@ u3e_live(c3_o nuu_o, c3_c* dir_c)
(u3_Loom + u3C.wor_i) - pag_wiz_i,
-(ssize_t)pag_wiz_i);
u3l_log("boot: protected loom\r\n");
u3l_log("boot: protected loom");
}
/* If the images were empty, we are logically booting.
*/
if ( (0 == u3P.nor_u.pgs_w) && (0 == u3P.sou_u.pgs_w) ) {
u3l_log("live: logical boot\r\n");
u3l_log("live: logical boot");
nuu_o = c3y;
}
else {

View File

@ -75,7 +75,7 @@ _cj_hash(c3_c* has_c)
{
c3_w i_w, len_w = strlen(has_c);
if ( 64 != len_w ) {
u3l_log("bash not 64 characters: %s\r\n", has_c);
u3l_log("bash not 64 characters: %s", has_c);
c3_assert(0);
}
c3_assert( 64 == len_w );
@ -236,18 +236,18 @@ _cj_axis(u3_noun fol)
(0 != p_fol) ||
(!_(u3a_is_cat(q_fol))) )
{
u3l_log("axis: bad a\r\n");
u3l_log("axis: bad a");
return 0;
}
return q_fol;
}
else {
if ( 9 != p_fol )
{ u3l_log("axis: bad b\r\n"); return 0; }
{ u3l_log("axis: bad b"); return 0; }
if ( !_(u3a_is_cat(q_fol)) )
{ u3l_log("axis: bad c\r\n"); return 0; }
{ u3l_log("axis: bad c"); return 0; }
if ( !_(u3du(r_fol)) || (0 != u3h(r_fol)) || (1 != u3t(r_fol)) )
{ u3l_log("axis: bad d\r\n"); return 0; }
{ u3l_log("axis: bad d"); return 0; }
return q_fol;
}
@ -278,7 +278,7 @@ _cj_warm_hump(c3_l jax_l, u3_noun huc)
((1 << 31) & (axe_l = (c3_w)axe_d)) ||
(axe_l < 2) )
{
u3l_log("jets: activate: bad fcs %s\r\n", jet_u->fcs_c);
u3l_log("jets: activate: bad fcs %s", jet_u->fcs_c);
}
}
else {
@ -286,7 +286,7 @@ _cj_warm_hump(c3_l jax_l, u3_noun huc)
u3_noun fol = u3kdb_get(u3k(huc), nam);
if ( u3_none == fol ) {
u3l_log("jets: activate: bad fcs %s\r\n", jet_u->fcs_c);
u3l_log("jets: activate: bad fcs %s", jet_u->fcs_c);
}
else {
axe_l = _cj_axis(fol);
@ -781,7 +781,7 @@ _cj_hot_mean(c3_l par_l, u3_noun nam)
while ( (cop_u = &dev_u[i_l])->cos_c ) {
if ( _(u3r_sing_c(cop_u->cos_c, nam)) ) {
#if 0
u3l_log("hot: bound jet %d/%s/%s/\r\n",
u3l_log("hot: bound jet %d/%s/%s/",
cop_u->jax_l,
cop_u->cos_c,
par_u ? par_u->cos_c : "~");
@ -893,7 +893,7 @@ _cj_kick_z(u3_noun cor, u3j_core* cop_u, u3j_harm* ham_u, u3_atom axe)
ham_u->liv = c3y;
if ( c3n == u3r_sing(ame, pro) ) {
u3l_log("test: %s %s: mismatch: good %x, bad %x\r\n",
u3l_log("test: %s %s: mismatch: good %x, bad %x",
cop_u->cos_c,
(!strcmp(".2", ham_u->fcs_c)) ? "$" : ham_u->fcs_c,
u3r_mug(ame),
@ -905,7 +905,7 @@ _cj_kick_z(u3_noun cor, u3j_core* cop_u, u3j_harm* ham_u, u3_atom axe)
else {
#if 0
u3l_log("test: %s %s\r\n",
u3l_log("test: %s %s",
cop_u->cos_c,
(!strcmp(".2", ham_u->fcs_c)) ? "$" : ham_u->fcs_c);
#endif
@ -928,13 +928,13 @@ _cj_hook_in(u3_noun cor,
u3_noun roc, tem, got, pat, nam, huc;
if ( c3n == u3du(cor) ) {
u3l_log("_cj_hook_in failure: c3n == u3du(cor)\r\n");
u3l_log("_cj_hook_in failure: c3n == u3du(cor)");
return u3m_bail(c3__fail);
}
loc = _cj_spot(cor, NULL);
if ( u3_none == loc ) {
u3l_log("_cj_hook_in failure: u3_none == loc\r\n");
u3l_log("_cj_hook_in failure: u3_none == loc");
return u3m_bail(c3__fail);
}
@ -999,7 +999,7 @@ _cj_hook_in(u3_noun cor,
else {
u3_noun sat = u3t(pat);
if ( c3y == u3h(sat) ) {
u3l_log("_cj_hook_in failure: c3y == u3h(sat)\r\n");
u3l_log("_cj_hook_in failure: c3y == u3h(sat)");
return u3m_bail(c3__fail);
}
else {
@ -1687,7 +1687,7 @@ u3j_gate_prep(u3j_site* sit_u, u3_noun cor)
pay = u3qc_cap(pax),
pam = u3qc_mas(pax);
if ( 3 != pay || 2 == pam || (3 != pam && 3 != u3qc_cap(pam)) ) {
u3l_log("u3j_gate_prep(): parent axis includes sample\r\n");
u3l_log("u3j_gate_prep(): parent axis includes sample");
u3m_p("axis", pax);
u3_weak act = _cj_find_warm(loc);
c3_assert( u3_none != act );
@ -1758,12 +1758,12 @@ _cj_minx(u3_noun cey, u3_noun cor)
par = u3r_at(axe, cor);
if ( u3_none == par || c3n == u3du(par) ) {
u3l_log("fund: %s is bogus\r\n", u3r_string(nam));
u3l_log("fund: %s is bogus", u3r_string(nam));
return u3_none;
}
pel = _cj_spot(par, NULL);
if ( u3_none == pel ) {
u3l_log("fund: in %s, parent %x not found at %d\r\n",
u3l_log("fund: in %s, parent %x not found at %d",
u3r_string(nam),
u3r_mug(u3h(par)),
axe);
@ -1822,7 +1822,7 @@ _cj_mine(u3_noun cey, u3_noun cor, u3_noun bas)
jax_l = _cj_hot_mean(par_l, nam);
#if 0
u3m_p("new jet", bal);
u3l_log(" bat %x, jax %d\r\n", u3r_mug(bat), jax_l);
u3l_log(" bat %x, jax %d", u3r_mug(bat), jax_l);
#endif
if ( !(u3C.wag_w & u3o_hashless) ) {
@ -1840,7 +1840,7 @@ _cj_mine(u3_noun cey, u3_noun cor, u3_noun bas)
for ( i_w = 32; i_w > 0; ) {
u3l_log("%02x", dig_y[--i_w]);
}
u3l_log("\r\n");
u3l_log("");
}
}
@ -1870,7 +1870,7 @@ _cj_mine(u3_noun cey, u3_noun cor, u3_noun bas)
if ( c3n == hav_o ) {
u3m_p("unregistered battery", bal);
u3l_log("hash: %x\r\n", bas);
u3l_log("hash: %x", bas);
}
u3z(bas);
}
@ -2093,7 +2093,7 @@ _cj_ream(u3_noun all)
act = u3nq(jax_l, hap, bal, _cj_jit(jax_l, bat));
#if 0
u3m_p("old jet", bal);
u3l_log(" bat %x, jax %d\r\n", u3r_mug(bat), jax_l);
u3l_log(" bat %x, jax %d", u3r_mug(bat), jax_l);
#endif
u3h_put(u3R->jed.war_p, loc, act);
}
@ -2132,7 +2132,7 @@ _cj_ream(u3_noun all)
act = u3nq(jax_l, hap, bal, _cj_jit(jax_l, bat));
#if 0
u3m_p("old jet", bal);
u3l_log(" bat %x, jax %d\r\n", u3r_mug(bat), jax_l);
u3l_log(" bat %x, jax %d", u3r_mug(bat), jax_l);
#endif
u3h_put(u3R->jed.war_p, loc, act);
}

View File

@ -22,6 +22,8 @@ u3l_log(const char* format, ...)
// this process did not set a logging function, fallback to stderr
//
vfprintf(stderr, format, myargs);
fprintf(stderr, "\r\n");
fflush(stderr);
}
va_end(myargs);
@ -31,7 +33,7 @@ u3_weak
u3l_punt(const char* name, u3_weak pro)
{
if ( u3_none == pro ) {
u3l_log("%s-punt\r\n", name);
u3l_log("%s-punt", name);
}
return pro;
}

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