@@ -10,9 +10,10 @@ In this walkthrough we will go in-depth on how to build command line interface (
10applications in Urbit using the `shoe` library.
10applications in Urbit using the `shoe` library.
12There are three CLI apps that currently ship with urbit - `%dojo`, `%chat-cli`,
12There are three CLI apps that currently ship with urbit - `%dojo`, `%chat-cli`,
13−and `%shoe`. You should be familiar with the former two, the latter is an example
13+and `%shoe`. You should be familiar with the former two, the latter is an
14−app that shows off how the `shoe` library works that we will be looking at
14+example app that shows off how the `shoe` library works that we will be looking
15−closely. These are all Gall apps, and as such their source can be found in the `app/` folder of your `%home` desk.
15+at closely. These are all Gall apps, and their source can be found in the `app/`
16+folder of your `%base` desk.
17In [the `shoe` library](#the-shoe-library) we take a closer look at the `shoe` library and its
18In [the `shoe` library](#the-shoe-library) we take a closer look at the `shoe` library and its
18cores and how they are utilized in CLI apps. Then in [the `sole`
19cores and how they are utilized in CLI apps. Then in [the `sole`
@@ -26,7 +27,6 @@ lesson](/docs/hoon/hoon-school/generators#ask) on `sole` and `%ask`
26generators, which only covers the bare minimum necessary to write generators
27generators, which only covers the bare minimum necessary to write generators
27that take user input.
28that take user input.
30## The `shoe` library {#the-shoe-library}
30## The `shoe` library {#the-shoe-library}
32Here we describe how sessions are identified, the specialized `card`s that Gall agents
32Here we describe how sessions are identified, the specialized `card`s that Gall agents
@@ -44,9 +44,11 @@ ship and which session on that ship if there are multiple.
45Gall agents with the `shoe` library are able to utilize `%shoe` `card`s. These
45Gall agents with the `shoe` library are able to utilize `%shoe` `card`s. These
46additions to the standard set of `cards` have the following shape:
46additions to the standard set of `cards` have the following shape:
48[%shoe sole-ids=(list @ta) effect=shoe-effect]`
49[%shoe sole-ids=(list @ta) effect=shoe-effect]`
50`sole-ids` is the `list` of session ids that the following `effect` is
52`sole-ids` is the `list` of session ids that the following `effect` is
51emitted to. An empty `sole-ids` sends the effect to all connected sessions.
53emitted to. An empty `sole-ids` sends the effect to all connected sessions.
52`shoe-effect`s, for now, are always of the shape `[%sole effect=sole-effect]`, where
54`shoe-effect`s, for now, are always of the shape `[%sole effect=sole-effect]`, where
@@ -144,14 +146,13 @@ This is a function for wrapping a `shoe` core, which has too many
144arms to be a valid Gall agent core. This turns it into a standard Gall agent core by
146arms to be a valid Gall agent core. This turns it into a standard Gall agent core by
145integrating the additional arms into the standard ones.
147integrating the additional arms into the standard ones.
148## The `sole` library {#the-sole-library}
149## The `sole` library {#the-sole-library}
150−`shoe` apps may create specialized `card`s of the `[%shoe
151−(list @ta) shoe-effect]` shape, where `shoe-effect` currently just wrap `sole-effect`s, i.e. instructions for displaying text and producing other effects in the console.
151+`shoe` apps may create specialized `card`s of the `[%shoe (list @ta) shoe-effect]` shape, where `shoe-effect` currently just wrap `sole-effect`s, i.e. instructions for displaying text and producing other effects in the console.
153The list of possible `sole-effects` can be found in `/sur/sole.hoon`. A few
153The list of possible `sole-effects` can be found in `/sur/sole.hoon`. A few
154commonly used ones are as follows.
154commonly used ones are as follows.
155- `[%txt tape]` is used to display a line of text.
156- `[%txt tape]` is used to display a line of text.
156- `[%bel ~]` is used to emit a beep.
157- `[%bel ~]` is used to emit a beep.
157- `[%pro sole-prompt]` is used to set the prompt.
158- `[%pro sole-prompt]` is used to set the prompt.
@@ -159,6 +160,7 @@ commonly used ones are as follows.
160For example, a `sole-effect` that beeps and displays `This is some text.` would
161For example, a `sole-effect` that beeps and displays `This is some text.` would
161be structured as
162be structured as
163[%mor [%txt "This is some text."] [%bel ~] ~]
165[%mor [%txt "This is some text."] [%bel ~] ~]
@@ -180,20 +182,23 @@ intention is to connect their `%shoe` apps.
180On each fake ship start `%shoe` by entering `|start %shoe` into dojo. This will
182On each fake ship start `%shoe` by entering `|start %shoe` into dojo. This will
181automatically
183automatically
182change the prompt to `~zod:shoe>` and `~nus:shoe>`. Type `demo` and watch the following appear:
184change the prompt to `~zod:shoe>` and `~nus:shoe>`. Type `demo` and watch the following appear:
184~zod ran the command
187~zod ran the command
185~zod:shoe>
188~zod:shoe>
187`~zod ran the command` should be displayed in bold green text, signifying that
191`~zod ran the command` should be displayed in bold green text, signifying that
188the command originated locally.
192the command originated locally.
190−Now we will connect the sessions. Switch `~zod` back to dojo with `Ctrl-X` and enter `|link
194+Now we will connect the sessions. Switch `~zod` back to dojo with `Ctrl-X` and enter `|link ~nus %shoe`. If this succeeds you will see the following.
191−~nus %shoe`. If this succeeds you will see the following.
195+
194; ~nus is your neighbor
198; ~nus is your neighbor
195[linked to [p=~nus q=%shoe]]
199[linked to [p=~nus q=%shoe]]
197Now `~zod` will have two `%shoe` sessions running - one local one on `~zod` and
202Now `~zod` will have two `%shoe` sessions running - one local one on `~zod` and
198one remote one on `~nus`, which you can access by pressing `Ctrl-X` until you see
203one remote one on `~nus`, which you can access by pressing `Ctrl-X` until you see
199`~nus:shoe>` from `~zod`'s console. On the other hand, you should not see
204`~nus:shoe>` from `~zod`'s console. On the other hand, you should not see
@@ -207,10 +212,12 @@ bold green text.
208Now try to link to `~zod`'s `%shoe` session from `~nus` by switching to the dojo
213Now try to link to `~zod`'s `%shoe` session from `~nus` by switching to the dojo
209on `~nus` and entering `|link ~zod %shoe`. You should see
214on `~nus` and entering `|link ~zod %shoe`. You should see
212[unlinked from [p=~zod q=%shoe]]
218[unlinked from [p=~zod q=%shoe]]
214and if you press `Ctrl-X` you will not get a `~zod:shoe>` prompt. This is
221and if you press `Ctrl-X` you will not get a `~zod:shoe>` prompt. This is
215because the example app is set up to always allow `~zod` to connect (as well as
222because the example app is set up to always allow `~zod` to connect (as well as
216subject moons if the ship happens to be a planet) but not `~nus`, so this
223subject moons if the ship happens to be a planet) but not `~nus`, so this
@@ -229,11 +236,12 @@ message means that `~nus` failed to connect to `~zod`'s `%shoe` session.
230`/+` is the Ford rune which imports libraries from the `/lib` directory into
237`/+` is the Ford rune which imports libraries from the `/lib` directory into
231the subject.
238the subject.
232− * `shoe` is the `shoe` library.
240+- `shoe` is the `shoe` library.
233− * `verb` is a library used to print what a Gall agent is doing.
241+- `verb` is a library used to print what a Gall agent is doing.
234− * `dbug` is a library of debugging tools.
242+- `dbug` is a library of debugging tools.
235− * `default-agent` contains a Gall agent core with minimal implementations of
243+- `default-agent` contains a Gall agent core with minimal implementations of
236− required Gall arms.
244+ required Gall arms.
@@ -243,6 +251,7 @@ the subject.
243+$ card card:shoe
251+$ card card:shoe
246The types used by the app.
255The types used by the app.
248`state-0` stores the state of the app, which is null as there is no state to
257`state-0` stores the state of the app, which is null as there is no state to
@@ -254,8 +263,7 @@ commands that can be entered by the user. Since this app only supports one
254command, it is unnecessary for it to have any associated data, thus the command
263command, it is unnecessary for it to have any associated data, thus the command
255is represented by `~`.
264is represented by `~`.
257−In a non-trivial context, a `command` is commonly given by `[%name
258−data]`, where `%name` is the identifier for the type of command and `data` is
266+In a non-trivial context, a `command` is commonly given by `[%name data]`, where `%name` is the identifier for the type of command and `data` is
259a type or list of types that contain data needed to execute the command. See
267a type or list of types that contain data needed to execute the command. See
260`app/chat-cli.hoon` for examples of commands, such as `[%say letter:store]` and
268`app/chat-cli.hoon` for examples of commands, such as `[%say letter:store]` and
261`[%delete path]`. This is not required though, and you could use something like
269`[%delete path]`. This is not required though, and you could use something like
@@ -264,7 +272,7 @@ a type or list of types that contain data needed to execute the command. See
264`card` is either an ordinary Gall agent `card` or a `%shoe` `card`, which takes
272`card` is either an ordinary Gall agent `card` or a `%shoe` `card`, which takes
265the shape `[%shoe sole-ids=(list @ta) effect=shoe-effect]`. A `%shoe` `card` is
273the shape `[%shoe sole-ids=(list @ta) effect=shoe-effect]`. A `%shoe` `card` is
266sent to all `sole`s listed in `sole-ids`, imaking them run the `sole-effect`
274sent to all `sole`s listed in `sole-ids`, imaking them run the `sole-effect`
267−specified by `effect` (i.e. printing some text). Here we can
275+specified by `effect` (i.e. printing some text). Here we can
268reference `card:shoe` because of `/+ shoe` at the beginning of the app.
276reference `card:shoe` because of `/+ shoe` at the beginning of the app.
@@ -272,6 +280,7 @@ reference `card:shoe` because of `/+ shoe` at the beginning of the app.
272=* state -
280=* state -
275Add the bunt value of `state-0` to the head of the subject, then give it the
284Add the bunt value of `state-0` to the head of the subject, then give it the
276macro `state`. The `-` here is a lark expression referring to the head of the
285macro `state`. The `-` here is a lark expression referring to the head of the
277subject. This allows us to use `state` to refer to the state elsewhere in the
286subject. This allows us to use `state` to refer to the state elsewhere in the
@@ -293,13 +302,13 @@ producing a standard Gall agent core. Then we call wrap the Gall agent core with
293`agent:dbug`, endowing it with additional arms useful for debugging, and then
302`agent:dbug`, endowing it with additional arms useful for debugging, and then
294wrap again with `verb`.
303wrap again with `verb`.
298|_ =bowl:gall
306|_ =bowl:gall
300 def ~(. (default-agent this %|) bowl)
308 def ~(. (default-agent this %|) bowl)
301 des ~(. (default:shoe this command) bowl)
309 des ~(. (default:shoe this command) bowl)
303This is boilerplate Gall agent core code. We set `this` to be a macro for the
312This is boilerplate Gall agent core code. We set `this` to be a macro for the
304subject, which is the Gall agent core itself. We set `def` and `des` to be
313subject, which is the Gall agent core itself. We set `def` and `des` to be
305macros for initialized `default-agent` and `default:shoe` doors respectively.
314macros for initialized `default-agent` and `default:shoe` doors respectively.
@@ -323,23 +332,25 @@ the standard Gall arms:
323++ on-arvo on-arvo:def
332++ on-arvo on-arvo:def
324++ on-fail on-fail:def
333++ on-fail on-fail:def
326These are minimalist Gall app arm implementations using the default behavior found in `def`.
336These are minimalist Gall app arm implementations using the default behavior found in `def`.
328Here begins the implementation of the additional arms required by the
338Here begins the implementation of the additional arms required by the
329`(shoe:shoe command)` interface.
339`(shoe:shoe command)` interface.
331++ command-parser
342++ command-parser
332 |= sole-id=@ta
343 |= sole-id=@ta
333 ^+ |~(nail *(like [? command]))
344 ^+ |~(nail *(like [? command]))
334 (cold [& ~] (jest 'demo'))
345 (cold [& ~] (jest 'demo'))
336`+command-parser` is of central importance - it is what is used to parse user
348`+command-parser` is of central importance - it is what is used to parse user
337input and transform it into `command`s for the app to execute. Writing a proper
349input and transform it into `command`s for the app to execute. Writing a proper
338command parser requires understanding of the Hoon parsing functions found in the
350command parser requires understanding of the Hoon parsing functions found in the
339standard library. How to do so may be found in the [parsing tutorial](/docs/hoon/guides/parsing). For now, it is sufficient to know that this arm matches the text "demo" and
351standard library. How to do so may be found in the [parsing tutorial](/docs/hoon/guides/parsing). For now, it is sufficient to know that this arm matches the text "demo" and
340produces a `[? command]`-shaped noun in response. Note how the `&` signifies that the command will be run as soon as it has been entered, without waiting for the user to press return.
352produces a `[? command]`-shaped noun in response. Note how the `&` signifies that the command will be run as soon as it has been entered, without waiting for the user to press return.
344++ tab-list
355++ tab-list
345 |= sole-id=@ta
356 |= sole-id=@ta
@@ -347,47 +358,57 @@ produces a `[? command]`-shaped noun in response. Note how the `&` signifies tha
347 :~ ['demo' leaf+"run example command"]
358 :~ ['demo' leaf+"run example command"]
350`+tab-list` is pretty much plug-n-play. For each command you want to be tab
362`+tab-list` is pretty much plug-n-play. For each command you want to be tab
351−completed, add an entry to the `list` begun by `:~` of the form `[%command
352−leaf+"description"]`. Now whenever the user types a partial command and presses
363+completed, add an entry to the `list` begun by `:~` of the form `[%command leaf+"description"]`. Now whenever the user types a partial command and presses
353tab, the console will display the list of commmands that match the partial
364tab, the console will display the list of commmands that match the partial
354command as well as the descriptions given here.
365command as well as the descriptions given here.
356Thus here we have that starting to type `demo` and pressing tab will result in
367Thus here we have that starting to type `demo` and pressing tab will result in
357the following output in the console:
368the following output in the console:
359demo run example command
371demo run example command
360~zod:shoe> demo
372~zod:shoe> demo
362with the remainder of `demo` now added to the input line.
375with the remainder of `demo` now added to the input line.
364Next we have `+on-command`, which is called whenever `+command-parser`
377Next we have `+on-command`, which is called whenever `+command-parser`
365recognizes that `demo` has been entered by a user.
378recognizes that `demo` has been entered by a user.
367++ on-command
381++ on-command
368 |= [sole-id=@ta =command]
382 |= [sole-id=@ta =command]
369 ^- (quip card _this)
383 ^- (quip card _this)
371This is a gate that takes in the `sole-id` corresponding to the session and the
386This is a gate that takes in the `sole-id` corresponding to the session and the
372`command` noun parsed by `+command-parser` and returns a `list` of `card`s and
387`command` noun parsed by `+command-parser` and returns a `list` of `card`s and
373`_this`, which is our shoe agent core including its state.
388`_this`, which is our shoe agent core including its state.
375 =- [[%shoe ~ %sole -]~ this]
391 =- [[%shoe ~ %sole -]~ this]
377This creates a cell of a `%shoe` card that triggers a `sole-effect` given by the head of
394This creates a cell of a `%shoe` card that triggers a `sole-effect` given by the head of
378the subject `-`, then the Gall agent core `this` - i.e. the return result of
395the subject `-`, then the Gall agent core `this` - i.e. the return result of
379this gate. The use of the `=-` rune means that what follows this
396this gate. The use of the `=-` rune means that what follows this
380expression is actually run first, which puts the desired `sole-effect` into the
397expression is actually run first, which puts the desired `sole-effect` into the
381head of the subject.
398head of the subject.
383 =/ =tape "{(scow %p src.bowl)} ran the command"
401 =/ =tape "{(scow %p src.bowl)} ran the command"
385We define the `tape` that we want to be printed.
404We define the `tape` that we want to be printed.
387 ?. =(src our):bowl
407 ?. =(src our):bowl
388 [%txt tape]
408 [%txt tape]
389 [%klr [[`%br ~ `%g] [(crip tape)]~]~]
409 [%klr [[`%br ~ `%g] [(crip tape)]~]~]
391We cannot just produce the `tape` we want printed, - it needs to fit the
412We cannot just produce the `tape` we want printed, - it needs to fit the
392`sole-effect` type. This tells us that if the
413`sole-effect` type. This tells us that if the
393origin of the command is not our ship to just print it normally with the `%txt`
414origin of the command is not our ship to just print it normally with the `%txt`
@@ -396,6 +417,7 @@ makes the text green and bold).
397The following allows either `~zod`, or the host ship and its moons, to connect to
418The following allows either `~zod`, or the host ship and its moons, to connect to
398this app's command line interface using `|link`.
419this app's command line interface using `|link`.
400++ can-connect
422++ can-connect
401 |= sole-id=@ta
423 |= sole-id=@ta
@@ -407,6 +429,7 @@ this app's command line interface using `|link`.
408We use the minimal implementations for the final two `shoe` arms, since we don't
430We use the minimal implementations for the final two `shoe` arms, since we don't
409want to do anything special when users connect or disconnect.
431want to do anything special when users connect or disconnect.
411++ on-connect on-connect:des
434++ on-connect on-connect:des
412++ on-disconnect on-disconnect:des
435++ on-disconnect on-disconnect:des