on master help sign in
Create sail.umd
099c808rmariani
docs/tutorials/sail.umdnew file+688
@@ -0,0 +1,688 @@
1+:- :~ navhome/'/docs/'
2+ sort/'10'
3+ title/'Introduction to Sail'
4+ ==
5+
6+;>
7+
8+
9+
10+# Introduction to Sail
11+
12+Sail is Hoon markup that’s used to render a web page with XML. But what makes
13+it special is that you can run arbitrary Hoon code within such a web page
14+without using a separate markup language. In this tutorial, we will
15+be dealing with Sail as it renders to HTML, a subset of XML.
16+
17+### Getting Started
18+
19+Before starting, make sure that your urbit is
20+[mounted to Unix](https://urbit.org/docs/using/setup/)
21+
22+To host that output, your ship also has a web-server, called
23+[Eyre](https://urbit.org/docs/using/web/), that can be found at
24+`http://localhost:8080/` if it’s your first ship that’s running on the a
25+machine, `http://localhost:8081/` if it’s the second ship on that same machine,
26+and so on. In the startup messagers, a ship will tell you which HTTP port it's
27+using.
28+
29+The `/web` directory of the `%home` desk is served by default. You can change
30+which desk you're serving by using the command `|serve` in the Dojo. If you
31+have already created and mounted a desk named `%sandbox`, for example, you can
32+switch to serving it with this command:
33+
34+```
35+|serve %sandbox
36+```
37+
38+The first time you serve a desk, `/web` will be included as default. After that,
39+you will need to explicitly append `/web` to the desk you're switching to --
40+otherwise, you'll need to write `http://localhost:8080/web` every time you
41+navigate to your web-server. Newly served desks not automatically having `/web`
42+as their root directory is a bug.
43+
44+To switch back to your `%home` desk and set `/web` as your root directory, run:
45+
46+```
47+|serve %/web
48+```
49+
50+We'll be serving the `%home` desk for the examples in this tutorial.
51+
52+#### Rendering
53+
54+That server has access to source files located in `/<your-urbit>/home/web` and
55+any sub-folders thereof. For the purposes of this tutorial, we will only be
56+using files that are located in the `/<your-urbit>/home/web/pages` path.
57+
58+There is an important distinction between these two paths. According to
59+`/ren/urb.hoon`, any file inside of `/web` or any of its sub-directories
60+is put through a tree of renderers specified at `/ren/urb/tree.hoon`
61+-- _except_ for files inside of `/web/pages`. All of the files in `/web` and
62+its non-`/pages` children directories have various operations on files, such as
63+wrapping your Sail the `html`, `head`, and `body` nodes. This rendering tool,
64+called simply *Tree*, also adds certain formatting polish, such as a sidebar
65+that lists sibling files in the same directory.
66+
67+The `/web/pages` sub-directory is a unique case with its own rendering rules.
68+The Tree is not used when rendering files in this path. The existence of no tag
69+is inferred, and no special formatting is applied. Such simplicity is ideal for
70+introducing the basics of Sail. Any source file located in `/web/pages` must
71+produce a complete HTML node with "head" and "body" nodes as children.
72+
73+Understanding the details of the rendering pipeline is not necessary to complete
74+this tutorial. But, if you are curious, you might find it illuminating to
75+explore the contents of the `/ren` directory.
76+
77+So, if a Sail source file named `sailtest.hoon` is saved in your `/web/pages`
78+folder on your only running urbit process, you can view that source rendered
79+into a web-page at `localhost:8080/pages/sailtest/`.
80+
81+### The Basics
82+
83+It’s easy to see how Sail can directly translate to HTML:
84+
85+#### Sail code
86+
87+```
88+;html
89+ ;head
90+ ;title: My first webpage
91+ ==
92+ ;body
93+ ;h1: Welcome!
94+ ; Hello, world!
95+ ; We're on the web.
96+ ;div;
97+ ;script@"http://unsafely.tracking.you/cookiemonster.js";
98+ ==
99+==
100+```
101+
102+#### HTML code
103+
104+```
105+<html>
106+ <head>
107+ <title>My first webpage</title>
108+ </head>
109+ <body>
110+ <h1>Welcome!</h1>
111+ Hello, world!
112+ We’re on the web.
113+ <div></div>
114+ <script src="http://unsafely.tracking.you/cookiemonster.js"></script>
115+ </body>
116+</html>
117+```
118+
119+Save the above Sail code in `/home/web/pages/firstsail.hoon`, and the above
120+HTML code in `/home/web/pages/firsth.html`. Access the resulting pages by
121+navigating to `http://localhost:8080/pages/firstsail` and
122+`http://localhost:8080/pages/firsth.html`, respectively, in your browser. The
123+resulting pages should be identical!
124+
125+It shouldn't be hard to see the similarities here. So let's go into more
126+detail about what the differences are.
127+
128+### Tags and Closing
129+
130+In Sail, tag heads are written with the tag name prepended by `;`. Unlike in
131+HTML, there are different ways on closing tags, depending on the needs of the
132+tag. One of the nice things about Hoon is that you don’t have to be constantly
133+closing expressions; Sail inherits this convenience.
134+
135+#### Empty
136+
137+Empty tags are closed with a `;` following the tag. Example:
138+
139+```
140+;div;
141+```
142+
143+Equals:
144+
145+```
146+<div></div>
147+```
148+
149+#### Filled
150+
151+Filled tags are closed via line-break. To fill text inside, add `:` after the
152+tag name, then insert your plain text following a space. Example:
153+
154+```
155+;h1: The title
156+```
157+
158+Equals:
159+
160+```
161+<h1>The title</h1>
162+```
163+
164+#### Nested
165+
166+To nest tags, simply create a new line. Nested tags need to be closed
167+with `==`, because they expect a list of sub-tags. If we nest a line of plain
168+text with no tag, a `<p>` is prepended.
169+
170+Sail, like Hoon, is white-space sensitive. Unlike in Hoon, however, two spaces
171+(called a "gap") is not necessarily equivalent to a line-break in Sail.
172+
173+```
174+;body
175+ ;h1: Blog title
176+ This is some good content.
177+==
178+```
179+
180+Equals:
181+
182+```
183+<body>
184+ <h1>Blog title</h1>
185+ <p>This is some good content.</p>
186+</body>
187+```
188+
189+
190+Conversely, if we want to write a string with no tag at all, then we can prepend
191+those untagged lines with `;`.
192+
193+```
194+;body
195+ ;h1: Welcome!
196+ ; Hello, world!
197+ ; We’re on the web.
198+==
199+```
200+
201+Equals:
202+
203+```
204+<body>
205+ <h1>Welcome~</h1>
206+ Hello, world.
207+ We’re on the web.
208+</body>
209+```
210+
211+
212+#### Attributes
213+
214+Attributes are key-value pairs that go into an HTML node.
215+
216+Adding attributes is simple: just add the desired attribute between parentheses,
217+right after the tag name without a space. We separate different attributes of
218+the same node by using `,`.
219+
220+Attributes can be used in two forms: flat, which uses one line; and tall, which
221+uses multiple lines, when a single line would not be practical. Flat forms and
222+flat forms are two syntaxes of semantically equivalent expressions.
223+
224+
225+#### Generic
226+
227+The code below produces a “Submit” button on the page.
228+
229+Wide-form Sail:
230+
231+```
232+;input(type "submit", value "Submit");
233+```
234+
235+Tall-form Sail:
236+
237+```
238+;input
239+ =type "submit"
240+ =value "Submit";
241+==
242+```
243+
244+Equals:
245+
246+```
247+<input type="submit" value="Submit">`
248+```
249+
250+#### IDs
251+
252+```
253+;nav#header: Menu
254+```
255+
256+Equals:
257+
258+```
259+<nav id="header">Menu</nav>
260+```
261+
262+Add `#` after tag name to add an ID.
263+
264+#### Classes
265+
266+`;h1.text-blue: Title` equals `<h1 class="text-blue">Title</h1>`
267+
268+Add `.` after tag name to add a class. However, if you want a class name that
269+contains a space, you will need to use use the syntax of a generic attribute:
270+
271+`;div(class "logo inverse");` equals `<div class="logo inverse"></div>`
272+
273+
274+#### Image
275+
276+`;img@"example.png";`
277+
278+Equals
279+
280+`<img src="example.png"/>`
281+
282+Add `@` after the tag name to link your source.
283+
284+To add attributes to the image, like size specifications, add the
285+desired attribute after the `"` of the image name and before the final `;` of
286+the `img` tag.
287+
288+For example:
289+
290+`;img@"https://urbit.org/example.png"(width "100%");`
291+
292+#### Linking
293+
294+`;a/"urbit.org": A link to Urbit.org`
295+
296+Equals
297+
298+`<a href="urbit.org">A link to Urbit.org</a>`
299+
300+Add `/` after tag name to start an href.
301+
302+### Hoon in Sail
303+
304+Our first example is useful to understand how Sail syntax translates to HTML
305+syntax, but Sail finds its usefulness in the fact that it can be used seamlessly
306+with Hoon code.
307+
308+One place where Sail diverges from HTML is that it supports string
309+interpolation. In Sail, the contents of all tags are a string type called `tape`
310+unless otherwise designated. Tapes are delineated by the double quotes `""`.
311+That’s important, because tapes can be interpolated with Hoon expressions,
312+provided that those expressions produce something a tape as well. Interpolation
313+is done by wrapping the code to be inserted in `{}`. In your Dojo prompt, try
314+the command below (without the `>`):
315+
316+```
317+ > "I am a l{(mul 3 11)}t Urbit user."
318+ ! exit
319+```
320+
321+Oh no! That command produced a nest-fail error, which indicates that there was
322+a problem related to Hoon type-system. We used the proper `{}` syntax for
323+interpolation, and we used the proper function-call syntax inside of it. So
324+what happened?
325+
326+Trying the `mul` function on its own will help answer this question. Try the
327+following command in your Dojo:
328+
329+```
330+ > (mul 3 11)
331+ 33
332+```
333+
334+This should work, producing `33`, an atom. That’s our problem. The
335+interpolation expression expects a tape, but our first command tried to
336+interpolate with something that results in an atom. Try this now:
337+
338+```
339+ > <(mul 3 11)>
340+ "33"
341+```
342+
343+We get a similar result, but we know that it’s a tape because it’s wrapped in
344+`""`. Bingo! With this knowledge, let’s perform a successful interpolation:
345+
346+```
347+ > "I am a l{<(mul 3 11)>}t Urbit user."
348+ "I am a l33t Urbit user."
349+```
350+
351+Great!
352+
353+### The Subject
354+
355+The default subject of a Sail file is different from the subject that
356+expressions in the Dojo or a Hoon generator are evaluated against.
357+
358+To see this difference, first save the code below to a file at
359+`home/web/pages/sub.hoon` and view the rendering at
360+`http://localhost:8080/pages/sub`.
361+
362+```
363+;html
364+ ;head;
365+ ;body
366+ {<.>}
367+ ==
368+==
369+```
370+
371+Then enter the following command in the Dojo:
372+
373+```
374+ > .
375+```
376+
377+You'll notice that the Sail subject is like a stripped-down version of the Dojo
378+subject. Its final line should match the Dojo subject.
379+
380+Now swap the code below into your Sail file.
381+
382+```
383+/= gas /$ fuel:html
384+;html
385+ ;head;
386+ ;body
387+ {<.>}
388+ ==
389+==
390+```
391+
392+You'll find that the resulting Sail subject is much larger. If you look closely,
393+you'll see that there's some new similarities with the Dojo subject, such as
394+containing the name of your ship. There's also some new differences, since
395+`fuel:html` contains things that are specifically useful for performing
396+web-related operations.
397+
398+### A More Interesting Example
399+
400+Now let’s apply knowledge of string interpolation and the Sail subject in a Sail
401+source file. The following code produces more interesting things than the
402+example we saw before.
403+
404+```
405+/= gas /$ fuel:html
406+=/ show-list &
407+=+ wid=(met 3 p.bem.gas)
408+=/ what-kind
409+?: (lte wid 1) "galaxy"
410+?: =(2 wid) "star"
411+?: (lte wid 4) "planet"
412+?: (lte wid 8) "moon"
413+ "comet"
414+;html
415+ ;head
416+ ;meta(charset "utf-8");
417+ ;title: A more advanced page
418+ ==
419+ ;body
420+ ;h1: This is the Title
421+ ; This is a
422+ ;a/"http://urbit.org": link to Urbit.org.
423+ ;span: Check it out!
424+ ;+ ?: show-list
425+ ;ol
426+ ;li(style "color: green"): We're doing interesting stuff now.
427+ ;li: We're pretty-printing this sum with Hoon: {<(add 50 50)>}.
428+ ;li: The code above is shorthand for {(scow %ud (add 50 50))}.
429+ ;li: I am {(trip '~lodleb-ritrul')}.
430+ ;li: Actually, my name is {<p.bem.gas>}. I'm a {what-kind}.
431+ ==
432+ ;div: My name is {<p.bem.gas>}. I'm a {what-kind}.
433+ ==
434+==
435+```
436+
437+Save the above Sail code in to `home/web/pages/secondsail.hoon` and access the
438+resulting page by navigating to `http://localhost:8080/pages/secondsail` in
439+your browser.
440+
441+There are some interesting things here. Let’s go through this code piece by
442+piece.
443+
444+```
445+/= gas /$ fuel:html
446+```
447+
448+Later in this code we want produce the name of the ship is hosting it, something
449+that looks like ~lodleb-ritrul. In a generator, we could produce our ship name
450+by writing `our` -- try it in the Dojo. But remember that Sail is rendered
451+against its own subject, `our` is not part of the default subject. To augment
452+our subject with the information that we need, we use `/= gas /$ fuel:html`.
453+
454+The above expression uses two Ford runes, `/=` and `/$`, to add the relevant
455+information to the current subject. We can pull the ship’s name out of this
456+augmented subject later. It's important to note that these runes are not part of
457+Hoon. They are part of Ford, our build system.
458+
459+`/$` is used to get data from the environment, and `/=` adds that data to
460+subject in the face `gas`. The
461+[Ford user manual](https://urbit.org/docs/arvo/internals/ford/runes/) has
462+details on these and other Ford runes, but understanding these runes isn’t
463+necessary for the purposes of this tutorial.
464+
465+`fuel:html` gets extra data from your ship’s Eyre module, which handles all
466+things HTTP, and sticks it in the subject when Eyre renders a page. This
467+includes the name of the ship, which is what we look for in the next line, but
468+it includes much more.
469+
470+`p.bem.gas` is an expression that looks for `p` within `bem` within `gas`, the
471+face that we stored the above `fuel:html` expression in. That wing happens to
472+resolve to the name of the ship that is hosting the web-server. If we wanted to
473+access the current desk, we would use the wing expression `q.bem.gas`.
474+
475+You can take a look at what you can access by typing `fuel:html` in the Dojo,
476+and then explore it by modifying your wing expression in your Sail file
477+accordingly.
478+
479+```
480+=/ show-list &
481+```
482+
483+The above line of code stores a variable used later for a conditional. `&` means
484+`true`, meaning that any evaluation of `show-list` will be true until changed in
485+the source code.
486+
487+```
488+=+ wid=(met 3 p.bem.gas)
489+=/ what-kind
490+ ?: (lte wid 1) "galaxy"
491+ ?: =(2 wid) "star"
492+ ?: (lte wid 4) "planet"
493+ ?: (lte wid 8) "moon"
494+ "comet"
495+```
496+
497+This code chunk is a series of conditionals that checks the host ship’s name to
498+see what its value is.
499+
500+The first line, `=+ wid=(met 3 p.bem.gas)`, combines a new noun with the
501+subject and gives it the face `wid`. This noun is produced by the the
502+standard-library function [`met`](../reference/library/2c), which measures the number of
503+[blocks](../reference/library/1c/) of size `a` within `b`. Blocks are units that have a
504+bitwidth of `2^a`. So, in this case, it measures how many bytes (blocks of size
505+3 are bitwidths of 8; `2^3 = 8`) are fully contained in your ship's address.
506+
507+Galaxies contain zero to one 3-blocks; stars contain two 3-blocks; planets
508+contain three to four 3-blocks; moons contain five to eight 3-blocks; comets
509+contain nine to sixteen 3-blocks. Each test uses `lte`, the
510+less-than-or-equal-to function, to determine if `wid` is of a given size. The
511+result of this series of tests is added to the subject and given the face
512+`what-kind`.
513+
514+Ship names are simply another representation of atoms, and ship
515+categories are different ranges of possible atomic values. Because of this, we
516+perform less-than tests to see what kind of ship is running the web-server.
517+
518+```
519+;html
520+ ;head
521+ ;meta(charset "utf-8");
522+ ;title: A more advanced page
523+ ==
524+```
525+
526+Sail proper begins here. These four lines are four nodes. The `;html` node
527+indicates that the contained code should be rendered as HTML; this tag is closed
528+on the final line. The `;head` node contains metadata, and is closed three lines
529+later. The `;meta` node sets the character set to UTF-8, and the `;title` node
530+sets the title of the page that shows up in the browser tab.
531+
532+```
533+ ;body
534+ ;h1: This is the Title
535+ ; This is a
536+ ;a/"http://urbit.org": link to Urbit.org.
537+ ;span: Check it out!
538+```
539+
540+The first line here opens, of course, the body node. The second line creates
541+header text.
542+
543+The third, fourth, and fifth lines of code here construct a single line with an
544+inline link.
545+`; This is a` begins the rendered line with plain text.
546+
547+`;a/"http://urbit.org": link to Urbit.org.` continues that same rendered line,
548+and creates hyperlinked text out of `link to Urbit.org.`
549+
550+`;span: Check it out!` continues that same rendered line further. `;span:`
551+has the same use as `<span>` in HTML, and by following it with just a `:` and no
552+attributes, it continues the line without formatting. Following `;span:` with
553+**two** spaces causes there to be single space following the produced `<span>`
554+element, because one of those spaces is syntactically necessary.
555+
556+In the following lines, we beginning to use some Hoon expressions again.
557+
558+```
559+ ;+ ?: show-list
560+ ;ol
561+```
562+
563+In the top line in the chunk above, we use the `;+` Sail rune, which
564+resolves an expression to a single node. That expression, in this case, is
565+`?:`, which tests the truth value of `show-list`, which we assigned the value
566+`&` (meaning “true”) at the beginning of the program. It’s closed by the `==` on
567+the last line.
568+
569+Thus, this program resolves to the first child of `show-list`, the node `;ol`.
570+That node creates an ordered list, and the items contained within that node.
571+
572+```
573+ ;li(style "color: green"): We're doing more interesting stuff now.
574+```
575+
576+The line above is the only element of this list that does not use
577+Hoon proper. The line renders as green, as interpreted by the browser,
578+because of the Sail attribute.
579+
580+The next items in the list use `{}`. Recall that these braces, pronounced “lob”
581+and “rob” in Hoon-speak, allow for the interpolation of code within a string.
582+
583+```
584+ ;li: We're pretty-printing this sum with Hoon: {<(add 50 50)>}.
585+```
586+
587+The line above is interpolated with Hoon code that produces the sum of 50 plus
588+50, which is wrapped in `<>` to put the product in double quotes to make it a
589+tape, like the rest of the line.
590+
591+
592+```
593+ ;li: The code above is shorthand for {(scow %ud (add 50 50))}.
594+```
595+
596+The `{(scow %ud (add 50 50)}` on this line is just a different way
597+writing the `{<(add 50 50)>}` expression. `scow` is a Hoon function that turns a
598+noun into a `tape`, Hoon’s string type. `%ud` tells `scow` that its argument
599+should be displayed in the form of an unsigned decimal.
600+
601+
602+```
603+ ;li: I am {(trip '~lodleb-ritrul')}.
604+```
605+
606+`trip` is a function that takes a `cord` and produces a `tape`. A piece of
607+data of the cord type is one big atom formed from adjacent unicode bytes and
608+delineated by `''`. Remember that all text rendered in Sail is treated as a
609+tape. So, by converting `~lodleb-ritrul` to a tape, it can be included in the
610+tape that we are trying to insert it into without getting a type error.
611+
612+```
613+ ;li: Actually, my name is {<p.bem.gas>}. I'm a {what-kind}.
614+ ==
615+```
616+
617+The line above has interpolated code that uses a wing expression to access the
618+name of the host ship, and then accesses the face `what-kind` contains a string
619+describing what type of ship it is. We declared `gas` on the very first line so
620+that we could add that sort of information to the subject that our Sail is
621+rendered against. The wing expression `p.bem.gas` looks for `p` within `bem`
622+within `gas`, which happens to be where the name of the ship is located.
623+
624+Note that `{what-kind}` does not have a `<>` wrapper. Why do you think this is?
625+
626+```
627+ ;div; My name is {<p.bem.gas>}. I'm a {ship}.
628+ ==
629+==
630+```
631+
632+The `;div;` node above is only rendered, as an alternative to the above list,
633+if `show-list` is evaluated as true. This means it won’t be shown with your
634+default code. To show this line, change the `&` on line 2 to `|` (“false”).
635+
636+### Sail Runes
637+
638+In the previous example, we used a few special runes that aren’t used in typical
639+Hoon code. But there are others that are worth learning about at this point.
640+
641+`;+` is an expression that resolves to a single node. We saw this on line 20
642+in our Sail example above: `;+ ?: show-list` resolves to the node `;ol` and
643+all of that node’s children.
644+
645+`;*` is an expression that resolves to a list of nodes. If we want to render
646+multiple nodes side-by-side, and not just the children of a single node, this
647+is the expression that we use.
648+
649+`;=` turns a tuple of nodes into a list of nodes.
650+
651+
652+To see how these runes work, let’s take a chunk of our previous code starting at
653+line 20 and modify it a bit:
654+
655+```
656+ ;* ?: show-list
657+ ;=
658+ ;li: I am {(trip '~lodleb-ritrul')}.
659+ ;li: Actually, my name is {<p.bem.gas>}.
660+ ==
661+ ;=
662+ ;div: My name is {<p.bem.gas>}. I'm a {what-kind}.
663+ ;div: No list here!
664+ ==
665+ ==
666+```
667+
668+We changed the conditional branches so that each contains two Sail nodes,
669+side-by-side -- notice that the `;ol` is absent from the first branch.
670+
671+We begin with the `;*` rune, which resolves to a list of nodes, instead of the
672+`;+` rune, which only resolves to a single node.
673+
674+But that’s not enough on its own. `;*` needs to resolve to a list, and a few
675+Sail nodes aren’t lists until they are explicitly made into lists. Until we wrap
676+those nodes in `;=`, the nodes treated as mere tuples. All branches must be
677+valid lists for the `;* ?: show-list` expression to resolve.
678+
679+
680+### Conclusion
681+
682+You should now have foundational knowledge for making web pages with Sail. There
683+is, of course, more to learn. If you’re curious, there’s more advanced
684+resources out there.
685+The [Ford manual](https://urbit.org/docs/arvo/internals/ford/runes/)
686+can show you how to access various ship resources for user in your pages. To
687+learn more about how the renderer works, take a look at the
688+`/home/ren/urb.hoon` file inside your urbit.