aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkshay <[email protected]>2023-02-12 06:43:49 +0000
committerAkshay <[email protected]>2023-02-12 06:43:49 +0000
commit366df8852f503523cc4f9046d82ba9a99dd51d7f (patch)
tree635884dd5700cdc2a22a8885031aa67816bbe1b0
parent57a1fc656e05e1fcf07e4cff3dc988c6b5c2bc59 (diff)
new art: lapse
-rw-r--r--art/lapse.pngbin0 -> 3756 bytes
-rw-r--r--docs/art/index.html37
-rw-r--r--docs/art/lapse.pngbin0 -> 3756 bytes
-rw-r--r--docs/index.html12
-rw-r--r--docs/index.xml2384
-rw-r--r--docs/posts/SDL2_devlog/index.html240
-rw-r--r--docs/posts/WPA_woes/index.html13
-rw-r--r--docs/posts/a_reference_counted_afterlife/index.html40
-rw-r--r--docs/posts/auto-currying_rust_functions/index.html496
-rw-r--r--docs/posts/bash_harder_with_vim/index.html22
-rw-r--r--docs/posts/bye_bye_BDFs/index.html28
-rw-r--r--docs/posts/call_to_ARMs/index.html49
-rw-r--r--docs/posts/color_conundrum/index.html36
-rw-r--r--docs/posts/curing_a_case_of_git-UX/index.html180
-rw-r--r--docs/posts/font_size_fallacies/index.html79
-rw-r--r--docs/posts/get_better_at_yanking_and_putting_in_vim/index.html5
-rw-r--r--docs/posts/gripes_with_go/index.html85
-rw-r--r--docs/posts/hold_position!/index.html20
-rw-r--r--docs/posts/index.html14
-rw-r--r--docs/posts/lightweight_linting/index.html212
-rw-r--r--docs/posts/lotus58/index.html83
-rw-r--r--docs/posts/my_setup/index.html25
-rw-r--r--docs/posts/nixOS/index.html74
-rw-r--r--docs/posts/novice_nix:_flake_templates/index.html171
-rw-r--r--docs/posts/onivim_sucks/index.html39
-rw-r--r--docs/posts/pixel_art_in_GIMP/index.html101
-rw-r--r--docs/posts/programming_on_34_keys/index.html157
-rw-r--r--docs/posts/rapid_refactoring_with_vim/index.html119
-rw-r--r--docs/posts/self-hosting_git/index.html67
-rw-r--r--docs/posts/static_sites_with_bash/index.html36
-rw-r--r--docs/posts/termux_tandem/index.html29
-rw-r--r--docs/posts/turing_complete_type_systems/index.html24
32 files changed, 3632 insertions, 1245 deletions
diff --git a/art/lapse.png b/art/lapse.png
new file mode 100644
index 0000000..52b7721
--- /dev/null
+++ b/art/lapse.png
Binary files differ
diff --git a/docs/art/index.html b/docs/art/index.html
index 88c6cce..e3dee61 100644
--- a/docs/art/index.html
+++ b/docs/art/index.html
@@ -21,7 +21,18 @@
21 <h1>Art</h1> 21 <h1>Art</h1>
22 <div class="separator"></div> 22 <div class="separator"></div>
23 <div id="photos"> 23 <div id="photos">
24 <a href="/art/ferris.png"> 24 <a href="/art/lapse.png">
25 <div class="photo-container">
26 <img src="/art/lapse.png">
27 <div class="photo-overlay">
28 <div class="photo-text">
29 <div class="photo-title">Lapse</div>
30 <div class="photo-date">12/02 — 2023</div>
31 </div>
32 </div>
33 </div>
34</a>
35<a href="/art/ferris.png">
25 <div class="photo-container"> 36 <div class="photo-container">
26 <img src="/art/ferris.png"> 37 <img src="/art/ferris.png">
27 <div class="photo-overlay"> 38 <div class="photo-overlay">
@@ -43,23 +54,23 @@
43 </div> 54 </div>
44 </div> 55 </div>
45</a> 56</a>
46<a href="/art/the_sect.png"> 57<a href="/art/ivory_tower.png">
47 <div class="photo-container"> 58 <div class="photo-container">
48 <img src="/art/the_sect.png"> 59 <img src="/art/ivory_tower.png">
49 <div class="photo-overlay"> 60 <div class="photo-overlay">
50 <div class="photo-text"> 61 <div class="photo-text">
51 <div class="photo-title">The Sect</div> 62 <div class="photo-title">Ivory Tower</div>
52 <div class="photo-date">03/06 — 2022</div> 63 <div class="photo-date">03/06 — 2022</div>
53 </div> 64 </div>
54 </div> 65 </div>
55 </div> 66 </div>
56</a> 67</a>
57<a href="/art/ivory_tower.png"> 68<a href="/art/the_sect.png">
58 <div class="photo-container"> 69 <div class="photo-container">
59 <img src="/art/ivory_tower.png"> 70 <img src="/art/the_sect.png">
60 <div class="photo-overlay"> 71 <div class="photo-overlay">
61 <div class="photo-text"> 72 <div class="photo-text">
62 <div class="photo-title">Ivory Tower</div> 73 <div class="photo-title">The Sect</div>
63 <div class="photo-date">03/06 — 2022</div> 74 <div class="photo-date">03/06 — 2022</div>
64 </div> 75 </div>
65 </div> 76 </div>
@@ -241,23 +252,23 @@
241 </div> 252 </div>
242 </div> 253 </div>
243</a> 254</a>
244<a href="/art/beret_beaver.png"> 255<a href="/art/aviator_owl.png">
245 <div class="photo-container"> 256 <div class="photo-container">
246 <img src="/art/beret_beaver.png"> 257 <img src="/art/aviator_owl.png">
247 <div class="photo-overlay"> 258 <div class="photo-overlay">
248 <div class="photo-text"> 259 <div class="photo-text">
249 <div class="photo-title">Beret Beaver</div> 260 <div class="photo-title">Aviator Owl</div>
250 <div class="photo-date">01/05 — 2021</div> 261 <div class="photo-date">01/05 — 2021</div>
251 </div> 262 </div>
252 </div> 263 </div>
253 </div> 264 </div>
254</a> 265</a>
255<a href="/art/aviator_owl.png"> 266<a href="/art/beret_beaver.png">
256 <div class="photo-container"> 267 <div class="photo-container">
257 <img src="/art/aviator_owl.png"> 268 <img src="/art/beret_beaver.png">
258 <div class="photo-overlay"> 269 <div class="photo-overlay">
259 <div class="photo-text"> 270 <div class="photo-text">
260 <div class="photo-title">Aviator Owl</div> 271 <div class="photo-title">Beret Beaver</div>
261 <div class="photo-date">01/05 — 2021</div> 272 <div class="photo-date">01/05 — 2021</div>
262 </div> 273 </div>
263 </div> 274 </div>
diff --git a/docs/art/lapse.png b/docs/art/lapse.png
new file mode 100644
index 0000000..52b7721
--- /dev/null
+++ b/docs/art/lapse.png
Binary files differ
diff --git a/docs/index.html b/docs/index.html
index b3d6de9..9c74671 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -50,7 +50,7 @@
50 </td> 50 </td>
51 <td class=table-stats> 51 <td class=table-stats>
52 <span class="stats-number"> 52 <span class="stats-number">
53 9.5 53 9.6
54 </span> 54 </span>
55 <span class=stats-unit>min</span> 55 <span class=stats-unit>min</span>
56 </td> 56 </td>
@@ -78,15 +78,15 @@
78 <tr> 78 <tr>
79 <td class=table-post> 79 <td class=table-post>
80 <div class="date"> 80 <div class="date">
81 29/08 — 2022 81 12/02 — 2023
82 </div> 82 </div>
83 <a href="/art/ferris.png" class="post-link"> 83 <a href="/art/lapse.png" class="post-link">
84 <span class="post-link">Ferris</span> 84 <span class="post-link">Lapse</span>
85 </a> 85 </a>
86 </td> 86 </td>
87 <td class="table-stats"> 87 <td class="table-stats">
88 <a href="/art/ferris.png"> 88 <a href="/art/lapse.png">
89 <img src="/art/ferris.png" height="50px"> 89 <img src="/art/lapse.png" height="50px">
90 </a> 90 </a>
91 </td> 91 </td>
92 </tr> 92 </tr>
diff --git a/docs/index.xml b/docs/index.xml
index 5586abd..c0277f1 100644
--- a/docs/index.xml
+++ b/docs/index.xml
@@ -13,51 +13,86 @@
13 <copyright>Creative Commons BY-NC-SA 4.0</copyright> 13 <copyright>Creative Commons BY-NC-SA 4.0</copyright>
14 <item> 14 <item>
15<title>Curing A Case Of Git-UX</title> 15<title>Curing A Case Of Git-UX</title>
16<description>&lt;p&gt;Git worktrees are great, but they fall behind the venerable &lt;code&gt;git checkout&lt;/code&gt; sometimes. I attempted to fix that with &lt;a href="https://github.com/junegunn/fzf"&gt;fzf&lt;/a&gt; and a bit of bash.&lt;/p&gt; 16<description>&lt;p&gt;Git worktrees are great, but they fall behind the venerable
17&lt;p&gt;&lt;a href="https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps"&gt;&lt;img src="https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps.svg" /&gt;&lt;/a&gt;&lt;/p&gt; 17&lt;code&gt;git checkout&lt;/code&gt; sometimes. I attempted to fix that with &lt;a
18&lt;p&gt;Fear not if you haven’t heard of “worktrees”, I have included a primer here.&lt;br /&gt; 18href="https://github.com/junegunn/fzf"&gt;fzf&lt;/a&gt; and a bit of bash.&lt;/p&gt;
19&lt;p&gt;&lt;a href="https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps"&gt;&lt;img
20src="https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps.svg" /&gt;&lt;/a&gt;&lt;/p&gt;
21&lt;p&gt;Fear not if you haven’t heard of “worktrees”, I have included a
22primer here.&lt;br /&gt;
19&lt;a href="#what-makes-them-clunky"&gt;Skip the primer -&amp;gt;&lt;/a&gt;.&lt;/p&gt; 23&lt;a href="#what-makes-them-clunky"&gt;Skip the primer -&amp;gt;&lt;/a&gt;.&lt;/p&gt;
20&lt;h3 id="why-worktrees"&gt;Why Worktrees?&lt;/h3&gt; 24&lt;h3 id="why-worktrees"&gt;Why Worktrees?&lt;/h3&gt;
21&lt;p&gt;Picture this. You are whacking away on a feature branch. Halfway there, in fact. Your friend asks you fix something urgently. You proceed to do one of three things:&lt;/p&gt; 25&lt;p&gt;Picture this. You are whacking away on a feature branch. Halfway
26there, in fact. Your friend asks you fix something urgently. You proceed
27to do one of three things:&lt;/p&gt;
22&lt;ul&gt; 28&lt;ul&gt;
23&lt;li&gt;create a temporary branch, make a WIP commit, begin working on the fix&lt;/li&gt; 29&lt;li&gt;create a temporary branch, make a WIP commit, begin working on the
30fix&lt;/li&gt;
24&lt;li&gt;stash away your changes, begin working on the fix&lt;/li&gt; 31&lt;li&gt;stash away your changes, begin working on the fix&lt;/li&gt;
25&lt;li&gt;unfriend said friend for disturbing your flow&lt;/li&gt; 32&lt;li&gt;unfriend said friend for disturbing your flow&lt;/li&gt;
26&lt;/ul&gt; 33&lt;/ul&gt;
27&lt;p&gt;All of these options are … subpar. With the temporary branch, you are forced to create a partial, non-working commit, and then reset said commit once done with the fix. With the stash approach, you are required to now keep a mental model of the stash, be aware of untracked files that don’t get stashed by default, etc. Why won’t git just let you work on two things at the same time without &lt;em&gt;thinking&lt;/em&gt; so much?&lt;/p&gt; 34&lt;p&gt;All of these options are … subpar. With the temporary branch, you are
28&lt;p&gt;That is exactly what worktrees let you do. Worktrees let you have more than one checkout at a time, each checkout in a separate directory. Like creating a new clone, but safer (it disallows checking out the same branch twice) and a lot more space efficient (the new working tree is “linked” to the “main” worktree, and a good amount of stuff is shared). When your friend asks you to make the fix, you proceed like so:&lt;/p&gt; 35forced to create a partial, non-working commit, and then reset said
36commit once done with the fix. With the stash approach, you are required
37to now keep a mental model of the stash, be aware of untracked files
38that don’t get stashed by default, etc. Why won’t git just let you work
39on two things at the same time without &lt;em&gt;thinking&lt;/em&gt; so much?&lt;/p&gt;
40&lt;p&gt;That is exactly what worktrees let you do. Worktrees let you have
41more than one checkout at a time, each checkout in a separate directory.
42Like creating a new clone, but safer (it disallows checking out the same
43branch twice) and a lot more space efficient (the new working tree is
44“linked” to the “main” worktree, and a good amount of stuff is shared).
45When your friend asks you to make the fix, you proceed like so:&lt;/p&gt;
29&lt;ol type="1"&gt; 46&lt;ol type="1"&gt;
30&lt;li&gt;Create a new working tree with:&lt;/li&gt; 47&lt;li&gt;Create a new working tree with:&lt;/li&gt;
31&lt;/ol&gt; 48&lt;/ol&gt;
32&lt;div class="sourceCode" id="cb1"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# git worktree add -b &amp;lt;branch-name&amp;gt; &amp;lt;path&amp;gt; &amp;lt;from&amp;gt;&lt;/span&gt;&lt;/span&gt; 49&lt;div class="sourceCode" id="cb1"&gt;&lt;pre
50class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# git worktree add -b &amp;lt;branch-name&amp;gt; &amp;lt;path&amp;gt; &amp;lt;from&amp;gt;&lt;/span&gt;&lt;/span&gt;
33&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;git&lt;/span&gt; worktree add &lt;span class="at"&gt;-b&lt;/span&gt; fix-stuff /path/to/tree master&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 51&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;git&lt;/span&gt; worktree add &lt;span class="at"&gt;-b&lt;/span&gt; fix-stuff /path/to/tree master&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
34&lt;ol start="2" type="1"&gt; 52&lt;ol start="2" type="1"&gt;
35&lt;li&gt;&lt;code&gt;cd&lt;/code&gt; into &lt;code&gt;/path/to/tree&lt;/code&gt;&lt;/li&gt; 53&lt;li&gt;&lt;code&gt;cd&lt;/code&gt; into &lt;code&gt;/path/to/tree&lt;/code&gt;&lt;/li&gt;
36&lt;li&gt;Fix, test, commit, push, party&lt;/li&gt; 54&lt;li&gt;Fix, test, commit, push, party&lt;/li&gt;
37&lt;li&gt;Go back to your work, &lt;code&gt;cd -&lt;/code&gt;&lt;/li&gt; 55&lt;li&gt;Go back to your work, &lt;code&gt;cd -&lt;/code&gt;&lt;/li&gt;
38&lt;/ol&gt; 56&lt;/ol&gt;
39&lt;p&gt;Easy as cake. You didn’t have to settle for a partially working commit, you didn’t to deal with this “stash” thing, &lt;em&gt;and&lt;/em&gt; you didn’t have to unfriend your friend. Treating each branch as a directory just &lt;em&gt;feels&lt;/em&gt; more intuitive, more UNIX-y.&lt;/p&gt; 57&lt;p&gt;Easy as cake. You didn’t have to settle for a partially working
40&lt;p&gt;A few weeks later, you find yourself singing in praise of worktrees, working on several things simultaneously. And at the same time, cursing them for being a little … clunky.&lt;/p&gt; 58commit, you didn’t to deal with this “stash” thing, &lt;em&gt;and&lt;/em&gt; you
59didn’t have to unfriend your friend. Treating each branch as a directory
60just &lt;em&gt;feels&lt;/em&gt; more intuitive, more UNIX-y.&lt;/p&gt;
61&lt;p&gt;A few weeks later, you find yourself singing in praise of worktrees,
62working on several things simultaneously. And at the same time, cursing
63them for being a little … clunky.&lt;/p&gt;
41&lt;h3 id="what-makes-them-clunky"&gt;What makes them clunky?&lt;/h3&gt; 64&lt;h3 id="what-makes-them-clunky"&gt;What makes them clunky?&lt;/h3&gt;
42&lt;p&gt;Worktrees are great at what they claim to do. They stay out of the way when you need a checkout posthaste. However, as you start using them regularly, you realize they are not as flexible as &lt;code&gt;git checkout&lt;/code&gt; or &lt;code&gt;git switch&lt;/code&gt;.&lt;/p&gt; 65&lt;p&gt;Worktrees are great at what they claim to do. They stay out of the
66way when you need a checkout posthaste. However, as you start using them
67regularly, you realize they are not as flexible as
68&lt;code&gt;git checkout&lt;/code&gt; or &lt;code&gt;git switch&lt;/code&gt;.&lt;/p&gt;
43&lt;h4 id="branch-hopping"&gt;Branch-hopping&lt;/h4&gt; 69&lt;h4 id="branch-hopping"&gt;Branch-hopping&lt;/h4&gt;
44&lt;p&gt;You can &lt;code&gt;git checkout &amp;lt;branch&amp;gt;&lt;/code&gt; from anywhere within a git repository. You can’t “jump” to a worktree in the same fashion. The closest you can get, is to run &lt;code&gt;git worktree list&lt;/code&gt;, copy the path corresponding to your branch, and &lt;code&gt;cd&lt;/code&gt; into it.&lt;/p&gt; 70&lt;p&gt;You can &lt;code&gt;git checkout &amp;lt;branch&amp;gt;&lt;/code&gt; from anywhere within
71a git repository. You can’t “jump” to a worktree in the same fashion.
72The closest you can get, is to run &lt;code&gt;git worktree list&lt;/code&gt;, copy
73the path corresponding to your branch, and &lt;code&gt;cd&lt;/code&gt; into it.&lt;/p&gt;
45&lt;p&gt;Branch-hopping with the good ol’ git-checkout:&lt;/p&gt; 74&lt;p&gt;Branch-hopping with the good ol’ git-checkout:&lt;/p&gt;
46&lt;div class="sourceCode" id="cb2"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# anywhere, anytime&lt;/span&gt;&lt;/span&gt; 75&lt;div class="sourceCode" id="cb2"&gt;&lt;pre
76class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# anywhere, anytime&lt;/span&gt;&lt;/span&gt;
47&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git checkout feature/is-ascii-octdigit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 77&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git checkout feature/is-ascii-octdigit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
48&lt;p&gt;Meanwhile, in worktree world:&lt;/p&gt; 78&lt;p&gt;Meanwhile, in worktree world:&lt;/p&gt;
49&lt;div class="sourceCode" id="cb3"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# keeping these paths in your head is hard&lt;/span&gt;&lt;/span&gt; 79&lt;div class="sourceCode" id="cb3"&gt;&lt;pre
80class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# keeping these paths in your head is hard&lt;/span&gt;&lt;/span&gt;
50&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git worktree list&lt;/span&gt; 81&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git worktree list&lt;/span&gt;
51&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/worktrees/rustc/master&lt;/span&gt; eac6c33bc63 [master]&lt;/span&gt; 82&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/worktrees/rustc/master&lt;/span&gt; eac6c33bc63 &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;master&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;
52&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/worktrees/rustc/improve-std-char-docs&lt;/span&gt; 94cba88553e [improve-std-char-docs]&lt;/span&gt; 83&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/worktrees/rustc/improve-std-char-docs&lt;/span&gt; 94cba88553e &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;improve&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;std&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;char&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;docs&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;
53&lt;span id="cb3-5"&gt;&lt;a href="#cb3-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/worktrees/rustc/is-ascii-octdigit&lt;/span&gt; bc57be3af7a [feature/is-ascii-octdigit]&lt;/span&gt; 84&lt;span id="cb3-5"&gt;&lt;a href="#cb3-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/worktrees/rustc/is-ascii-octdigit&lt;/span&gt; bc57be3af7a &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;feature/is&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;ascii&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;octdigit&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;
54&lt;span id="cb3-6"&gt;&lt;a href="#cb3-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/my/other/path/oh/god&lt;/span&gt; op57or3ns7n [fix/some-error]&lt;/span&gt; 85&lt;span id="cb3-6"&gt;&lt;a href="#cb3-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/my/other/path/oh/god&lt;/span&gt; op57or3ns7n &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;fix/some&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;error&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;
55&lt;span id="cb3-7"&gt;&lt;a href="#cb3-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 86&lt;span id="cb3-7"&gt;&lt;a href="#cb3-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
56&lt;span id="cb3-8"&gt;&lt;a href="#cb3-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; cd ~/worktrees/rustc/is-ascii-octdigit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 87&lt;span id="cb3-8"&gt;&lt;a href="#cb3-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; cd ~/worktrees/rustc/is-ascii-octdigit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
57&lt;h4 id="branch-previewing"&gt;Branch-previewing&lt;/h4&gt; 88&lt;h4 id="branch-previewing"&gt;Branch-previewing&lt;/h4&gt;
58&lt;p&gt;You can “preview” branches with &lt;code&gt;git branch -v&lt;/code&gt;. However, to get an idea of what “recent activity” on a worktree looks like, you might need some juggling. You can’t glean much info about a worktree in a jiffy.&lt;/p&gt; 89&lt;p&gt;You can “preview” branches with &lt;code&gt;git branch -v&lt;/code&gt;. However,
90to get an idea of what “recent activity” on a worktree looks like, you
91might need some juggling. You can’t glean much info about a worktree in
92a jiffy.&lt;/p&gt;
59&lt;p&gt;Branch-previewing with the good ol’ git-branch:&lt;/p&gt; 93&lt;p&gt;Branch-previewing with the good ol’ git-branch:&lt;/p&gt;
60&lt;div class="sourceCode" id="cb4"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb4-1"&gt;&lt;a href="#cb4-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git branch &lt;span class="at"&gt;-v&lt;/span&gt;&lt;/span&gt; 94&lt;div class="sourceCode" id="cb4"&gt;&lt;pre
95class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb4-1"&gt;&lt;a href="#cb4-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git branch &lt;span class="at"&gt;-v&lt;/span&gt;&lt;/span&gt;
61&lt;span id="cb4-2"&gt;&lt;a href="#cb4-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;+&lt;/span&gt; feature/is-ascii-octdigit bc57be3af7a introduce {char, u8}::is_ ...&lt;/span&gt; 96&lt;span id="cb4-2"&gt;&lt;a href="#cb4-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;+&lt;/span&gt; feature/is-ascii-octdigit bc57be3af7a introduce {char, u8}::is_ ...&lt;/span&gt;
62&lt;span id="cb4-3"&gt;&lt;a href="#cb4-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;+&lt;/span&gt; improve-std-char-docs 94cba88553e add whitespace in assert ...&lt;/span&gt; 97&lt;span id="cb4-3"&gt;&lt;a href="#cb4-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;+&lt;/span&gt; improve-std-char-docs 94cba88553e add whitespace in assert ...&lt;/span&gt;
63&lt;span id="cb4-4"&gt;&lt;a href="#cb4-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;*&lt;/span&gt; master eac6c33bc63 Auto merge of &lt;span class="co"&gt;#100869 - n ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 98&lt;span id="cb4-4"&gt;&lt;a href="#cb4-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;*&lt;/span&gt; master eac6c33bc63 Auto merge of &lt;span class="co"&gt;#100869 - n ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
@@ -76,41 +111,60 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
76 111
77# extra work to make the branch &amp;lt;-&amp;gt; worktree correspondence&lt;/code&gt;&lt;/pre&gt; 112# extra work to make the branch &amp;lt;-&amp;gt; worktree correspondence&lt;/code&gt;&lt;/pre&gt;
78&lt;h4 id="shell-completions"&gt;Shell completions&lt;/h4&gt; 113&lt;h4 id="shell-completions"&gt;Shell completions&lt;/h4&gt;
79&lt;p&gt;Lastly, you can bank on shell completions to fill in your branch whilst using &lt;code&gt;git checkout&lt;/code&gt;. Worktrees have no such conveniences.&lt;/p&gt; 114&lt;p&gt;Lastly, you can bank on shell completions to fill in your branch
115whilst using &lt;code&gt;git checkout&lt;/code&gt;. Worktrees have no such
116conveniences.&lt;/p&gt;
80&lt;p&gt;We can mend these minor faults with fzf.&lt;/p&gt; 117&lt;p&gt;We can mend these minor faults with fzf.&lt;/p&gt;
81&lt;h3 id="unclunkifying-worktrees"&gt;Unclunkifying worktrees&lt;/h3&gt; 118&lt;h3 id="unclunkifying-worktrees"&gt;Unclunkifying worktrees&lt;/h3&gt;
82&lt;p&gt;I’d suggest looking up &lt;a href="https://github.com/junegunn/fzf"&gt;fzf&lt;/a&gt; (or &lt;a href="https://github.com/lotabout/skim"&gt;skim&lt;/a&gt; or &lt;a href="https://github.com/jhawthorn/fzy"&gt;fzy&lt;/a&gt;). These things make it cake-easy to add interactivity to your shell. Onto fixing the first minor fault, the inability to “jump” to a worktree from anywhere within a git repository.&lt;/p&gt; 119&lt;p&gt;I’d suggest looking up &lt;a
83&lt;p&gt;I have a little function called &lt;code&gt;gwj&lt;/code&gt; which stands for “git worktree jump”. The idea is to list all the worktrees, select one with fzf, and &lt;code&gt;cd&lt;/code&gt; to it upon selection:&lt;/p&gt; 120href="https://github.com/junegunn/fzf"&gt;fzf&lt;/a&gt; (or &lt;a
84&lt;div class="sourceCode" id="cb6"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb6-1"&gt;&lt;a href="#cb6-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;gwj ()&lt;/span&gt; &lt;span class="kw"&gt;{&lt;/span&gt;&lt;/span&gt; 121href="https://github.com/lotabout/skim"&gt;skim&lt;/a&gt; or &lt;a
122href="https://github.com/jhawthorn/fzy"&gt;fzy&lt;/a&gt;). These things make it
123cake-easy to add interactivity to your shell. Onto fixing the first
124minor fault, the inability to “jump” to a worktree from anywhere within
125a git repository.&lt;/p&gt;
126&lt;p&gt;I have a little function called &lt;code&gt;gwj&lt;/code&gt; which stands for
127“git worktree jump”. The idea is to list all the worktrees, select one
128with fzf, and &lt;code&gt;cd&lt;/code&gt; to it upon selection:&lt;/p&gt;
129&lt;div class="sourceCode" id="cb6"&gt;&lt;pre
130class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb6-1"&gt;&lt;a href="#cb6-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;gwj ()&lt;/span&gt; &lt;span class="kw"&gt;{&lt;/span&gt;&lt;/span&gt;
85&lt;span id="cb6-2"&gt;&lt;a href="#cb6-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;local&lt;/span&gt; &lt;span class="va"&gt;out&lt;/span&gt;&lt;/span&gt; 131&lt;span id="cb6-2"&gt;&lt;a href="#cb6-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;local&lt;/span&gt; &lt;span class="va"&gt;out&lt;/span&gt;&lt;/span&gt;
86&lt;span id="cb6-3"&gt;&lt;a href="#cb6-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;out&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="va"&gt;$(&lt;/span&gt;&lt;span class="fu"&gt;git&lt;/span&gt; worktree list &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="ex"&gt;fzf&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;awk&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{print $1}&amp;#39;&lt;/span&gt;&lt;span class="va"&gt;)&lt;/span&gt;&lt;/span&gt; 132&lt;span id="cb6-3"&gt;&lt;a href="#cb6-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;out&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="va"&gt;$(&lt;/span&gt;&lt;span class="fu"&gt;git&lt;/span&gt; worktree list &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="ex"&gt;fzf&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;awk&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{print $1}&amp;#39;&lt;/span&gt;&lt;span class="va"&gt;)&lt;/span&gt;&lt;/span&gt;
87&lt;span id="cb6-4"&gt;&lt;a href="#cb6-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;cd&lt;/span&gt; &lt;span class="va"&gt;$out&lt;/span&gt;&lt;/span&gt; 133&lt;span id="cb6-4"&gt;&lt;a href="#cb6-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;cd&lt;/span&gt; &lt;span class="va"&gt;$out&lt;/span&gt;&lt;/span&gt;
88&lt;span id="cb6-5"&gt;&lt;a href="#cb6-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 134&lt;span id="cb6-5"&gt;&lt;a href="#cb6-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
89&lt;p&gt;That is all of it really. Head into a git repository:&lt;/p&gt; 135&lt;p&gt;That is all of it really. Head into a git repository:&lt;/p&gt;
90&lt;div class="sourceCode" id="cb7"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb7-1"&gt;&lt;a href="#cb7-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# here, &amp;quot;master&amp;quot; is a directory, which contains my main&lt;/span&gt;&lt;/span&gt; 136&lt;div class="sourceCode" id="cb7"&gt;&lt;pre
137class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb7-1"&gt;&lt;a href="#cb7-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# here, &amp;quot;master&amp;quot; is a directory, which contains my main&lt;/span&gt;&lt;/span&gt;
91&lt;span id="cb7-2"&gt;&lt;a href="#cb7-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# worktree: a checkout of the master branch on rust-lang/rust &lt;/span&gt;&lt;/span&gt; 138&lt;span id="cb7-2"&gt;&lt;a href="#cb7-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# worktree: a checkout of the master branch on rust-lang/rust &lt;/span&gt;&lt;/span&gt;
92&lt;span id="cb7-3"&gt;&lt;a href="#cb7-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; cd ~/worktrees/rustc/master/library/core/src&lt;/span&gt; 139&lt;span id="cb7-3"&gt;&lt;a href="#cb7-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; cd ~/worktrees/rustc/master/library/core/src&lt;/span&gt;
93&lt;span id="cb7-4"&gt;&lt;a href="#cb7-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; &lt;span class="co"&gt;# hack away&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 140&lt;span id="cb7-4"&gt;&lt;a href="#cb7-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; &lt;span class="co"&gt;# hack away&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
94&lt;p&gt;Preferably one with a few worktrees:&lt;/p&gt; 141&lt;p&gt;Preferably one with a few worktrees:&lt;/p&gt;
95&lt;div class="sourceCode" id="cb8"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb8-1"&gt;&lt;a href="#cb8-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git worktree list&lt;/span&gt; 142&lt;div class="sourceCode" id="cb8"&gt;&lt;pre
96&lt;span id="cb8-2"&gt;&lt;a href="#cb8-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/worktrees/rustc/master&lt;/span&gt; eac6c33bc63 [master]&lt;/span&gt; 143class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb8-1"&gt;&lt;a href="#cb8-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git worktree list&lt;/span&gt;
97&lt;span id="cb8-3"&gt;&lt;a href="#cb8-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/worktrees/rustc/improve-std-char-docs&lt;/span&gt; 94cba88553e [improve-std-char-docs]&lt;/span&gt; 144&lt;span id="cb8-2"&gt;&lt;a href="#cb8-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/worktrees/rustc/master&lt;/span&gt; eac6c33bc63 &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;master&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;
98&lt;span id="cb8-4"&gt;&lt;a href="#cb8-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/worktrees/rustc/is-ascii-octdigit&lt;/span&gt; bc57be3af7a [feature/is-ascii-octdigit]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 145&lt;span id="cb8-3"&gt;&lt;a href="#cb8-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/worktrees/rustc/improve-std-char-docs&lt;/span&gt; 94cba88553e &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;improve&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;std&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;char&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;docs&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;
99&lt;p&gt;And hit &lt;code&gt;gwj&lt;/code&gt; (pretend that the pipe, |, is your cursor):&lt;/p&gt; 146&lt;span id="cb8-4"&gt;&lt;a href="#cb8-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/worktrees/rustc/is-ascii-octdigit&lt;/span&gt; bc57be3af7a &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;feature/is&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;ascii&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;octdigit&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
100&lt;div class="sourceCode" id="cb9"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb9-1"&gt;&lt;a href="#cb9-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; gwj&lt;/span&gt; 147&lt;p&gt;And hit &lt;code&gt;gwj&lt;/code&gt; (pretend that the pipe, |, is your
148cursor):&lt;/p&gt;
149&lt;div class="sourceCode" id="cb9"&gt;&lt;pre
150class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb9-1"&gt;&lt;a href="#cb9-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; gwj&lt;/span&gt;
101&lt;span id="cb9-2"&gt;&lt;a href="#cb9-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt;&lt;/span&gt; 151&lt;span id="cb9-2"&gt;&lt;a href="#cb9-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt;&lt;/span&gt;
102&lt;span id="cb9-3"&gt;&lt;a href="#cb9-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;4/4&lt;/span&gt;&lt;/span&gt; 152&lt;span id="cb9-3"&gt;&lt;a href="#cb9-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;4/4&lt;/span&gt;&lt;/span&gt;
103&lt;span id="cb9-4"&gt;&lt;a href="#cb9-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; ~/worktrees/rustc/master &lt;span class="ex"&gt;eac6c33bc63&lt;/span&gt; [master]&lt;/span&gt; 153&lt;span id="cb9-4"&gt;&lt;a href="#cb9-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; ~/worktrees/rustc/master &lt;span class="ex"&gt;eac6c33bc63&lt;/span&gt; &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;master&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;
104&lt;span id="cb9-5"&gt;&lt;a href="#cb9-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;~/worktrees/rustc/improve-std-char-docs&lt;/span&gt; 94cba88553e [improve-std-char-docs]&lt;/span&gt; 154&lt;span id="cb9-5"&gt;&lt;a href="#cb9-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;~/worktrees/rustc/improve-std-char-docs&lt;/span&gt; 94cba88553e &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;improve&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;std&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;char&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;docs&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;
105&lt;span id="cb9-6"&gt;&lt;a href="#cb9-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;~/worktrees/rustc/is-ascii-octdigit&lt;/span&gt; bc57be3af7a [feature/is-ascii-octdigit]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 155&lt;span id="cb9-6"&gt;&lt;a href="#cb9-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;~/worktrees/rustc/is-ascii-octdigit&lt;/span&gt; bc57be3af7a &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;feature/is&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;ascii&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;octdigit&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
106&lt;p&gt;Approximately type in your branch of choice:&lt;/p&gt; 156&lt;p&gt;Approximately type in your branch of choice:&lt;/p&gt;
107&lt;div class="sourceCode" id="cb10"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb10-1"&gt;&lt;a href="#cb10-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; gwj&lt;/span&gt; 157&lt;div class="sourceCode" id="cb10"&gt;&lt;pre
158class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb10-1"&gt;&lt;a href="#cb10-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; gwj&lt;/span&gt;
108&lt;span id="cb10-2"&gt;&lt;a href="#cb10-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; docs&lt;span class="kw"&gt;|&lt;/span&gt;&lt;/span&gt; 159&lt;span id="cb10-2"&gt;&lt;a href="#cb10-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; docs&lt;span class="kw"&gt;|&lt;/span&gt;&lt;/span&gt;
109&lt;span id="cb10-3"&gt;&lt;a href="#cb10-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;4/4&lt;/span&gt;&lt;/span&gt; 160&lt;span id="cb10-3"&gt;&lt;a href="#cb10-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;4/4&lt;/span&gt;&lt;/span&gt;
110&lt;span id="cb10-4"&gt;&lt;a href="#cb10-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; ~/worktrees/rustc/improve-std-char-docs &lt;span class="ex"&gt;94cba88553e&lt;/span&gt; [improve-std-char-docs]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 161&lt;span id="cb10-4"&gt;&lt;a href="#cb10-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; ~/worktrees/rustc/improve-std-char-docs &lt;span class="ex"&gt;94cba88553e&lt;/span&gt; &lt;span class="pp"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;improve&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;std&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;char&lt;/span&gt;&lt;span class="pp"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;docs&lt;/span&gt;&lt;span class="pp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
111&lt;p&gt;And hit enter. You should find yourself in the selected worktree.&lt;/p&gt; 162&lt;p&gt;And hit enter. You should find yourself in the selected worktree.&lt;/p&gt;
112&lt;p&gt;Onward, to the next fault, lack of preview-bility. We can utilize fzf’s aptly named &lt;code&gt;--preview&lt;/code&gt; flag, to, well, preview our worktree before performing a selection:&lt;/p&gt; 163&lt;p&gt;Onward, to the next fault, lack of preview-bility. We can utilize
113&lt;div class="sourceCode" id="cb11"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb11-1"&gt;&lt;a href="#cb11-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;gwj ()&lt;/span&gt; &lt;span class="kw"&gt;{&lt;/span&gt;&lt;/span&gt; 164fzf’s aptly named &lt;code&gt;--preview&lt;/code&gt; flag, to, well, preview our
165worktree before performing a selection:&lt;/p&gt;
166&lt;div class="sourceCode" id="cb11"&gt;&lt;pre
167class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb11-1"&gt;&lt;a href="#cb11-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;gwj ()&lt;/span&gt; &lt;span class="kw"&gt;{&lt;/span&gt;&lt;/span&gt;
114&lt;span id="cb11-2"&gt;&lt;a href="#cb11-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;local&lt;/span&gt; &lt;span class="va"&gt;out&lt;/span&gt;&lt;/span&gt; 168&lt;span id="cb11-2"&gt;&lt;a href="#cb11-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;local&lt;/span&gt; &lt;span class="va"&gt;out&lt;/span&gt;&lt;/span&gt;
115&lt;span id="cb11-3"&gt;&lt;a href="#cb11-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;out&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="va"&gt;$(&lt;/span&gt;&lt;/span&gt; 169&lt;span id="cb11-3"&gt;&lt;a href="#cb11-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;out&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="va"&gt;$(&lt;/span&gt;&lt;/span&gt;
116&lt;span id="cb11-4"&gt;&lt;a href="#cb11-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="fu"&gt;git&lt;/span&gt; worktree list &lt;span class="kw"&gt;|&lt;/span&gt;&lt;/span&gt; 170&lt;span id="cb11-4"&gt;&lt;a href="#cb11-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="fu"&gt;git&lt;/span&gt; worktree list &lt;span class="kw"&gt;|&lt;/span&gt;&lt;/span&gt;
@@ -119,8 +173,10 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
119&lt;span id="cb11-7"&gt;&lt;a href="#cb11-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;)&lt;/span&gt;&lt;/span&gt; 173&lt;span id="cb11-7"&gt;&lt;a href="#cb11-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;)&lt;/span&gt;&lt;/span&gt;
120&lt;span id="cb11-8"&gt;&lt;a href="#cb11-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;cd&lt;/span&gt; &lt;span class="va"&gt;$out&lt;/span&gt;&lt;/span&gt; 174&lt;span id="cb11-8"&gt;&lt;a href="#cb11-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;cd&lt;/span&gt; &lt;span class="va"&gt;$out&lt;/span&gt;&lt;/span&gt;
121&lt;span id="cb11-9"&gt;&lt;a href="#cb11-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 175&lt;span id="cb11-9"&gt;&lt;a href="#cb11-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
122&lt;p&gt;Once again, hit &lt;code&gt;gwj&lt;/code&gt; inside a git repository with linked worktrees:&lt;/p&gt; 176&lt;p&gt;Once again, hit &lt;code&gt;gwj&lt;/code&gt; inside a git repository with linked
123&lt;div class="sourceCode" id="cb12"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb12-1"&gt;&lt;a href="#cb12-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; gwj&lt;/span&gt; 177worktrees:&lt;/p&gt;
178&lt;div class="sourceCode" id="cb12"&gt;&lt;pre
179class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb12-1"&gt;&lt;a href="#cb12-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; gwj&lt;/span&gt;
124&lt;span id="cb12-2"&gt;&lt;a href="#cb12-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;╭─────────────────────────────────────────────────────────╮&lt;/span&gt;&lt;/span&gt; 180&lt;span id="cb12-2"&gt;&lt;a href="#cb12-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;╭─────────────────────────────────────────────────────────╮&lt;/span&gt;&lt;/span&gt;
125&lt;span id="cb12-3"&gt;&lt;a href="#cb12-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;│&lt;/span&gt; eac6c33bc63 Auto merge of 100869 nnethercote:replace... │&lt;/span&gt; 181&lt;span id="cb12-3"&gt;&lt;a href="#cb12-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;│&lt;/span&gt; eac6c33bc63 Auto merge of 100869 nnethercote:replace... │&lt;/span&gt;
126&lt;span id="cb12-4"&gt;&lt;a href="#cb12-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;│&lt;/span&gt; b32223fec10 Auto merge of 100707 dzvon:fix-typo, r=d... │&lt;/span&gt; 182&lt;span id="cb12-4"&gt;&lt;a href="#cb12-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;│&lt;/span&gt; b32223fec10 Auto merge of 100707 dzvon:fix-typo, r=d... │&lt;/span&gt;
@@ -138,9 +194,16 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
138&lt;span id="cb12-16"&gt;&lt;a href="#cb12-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; /home/np/worktrees/compiler/master &lt;span class="ex"&gt;eac6c...&lt;/span&gt;&lt;/span&gt; 194&lt;span id="cb12-16"&gt;&lt;a href="#cb12-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; /home/np/worktrees/compiler/master &lt;span class="ex"&gt;eac6c...&lt;/span&gt;&lt;/span&gt;
139&lt;span id="cb12-17"&gt;&lt;a href="#cb12-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;/home/np/worktrees/compiler/improve-std-char-docs&lt;/span&gt; 94cba...&lt;/span&gt; 195&lt;span id="cb12-17"&gt;&lt;a href="#cb12-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;/home/np/worktrees/compiler/improve-std-char-docs&lt;/span&gt; 94cba...&lt;/span&gt;
140&lt;span id="cb12-18"&gt;&lt;a href="#cb12-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;/home/np/worktrees/compiler/is-ascii-octdigit&lt;/span&gt; bc57b...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 196&lt;span id="cb12-18"&gt;&lt;a href="#cb12-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;/home/np/worktrees/compiler/is-ascii-octdigit&lt;/span&gt; bc57b...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
141&lt;p&gt;A fancy preview of the last 10 commits on the branch that the selected worktree corresponds to. In other words, sight for sore eyes. Our little script is already shaping up to be useful, you hit &lt;code&gt;gwj&lt;/code&gt;, browse through your worktrees, preview each one and automatically &lt;code&gt;cd&lt;/code&gt; to your selection. But we are not done yet.&lt;/p&gt; 197&lt;p&gt;A fancy preview of the last 10 commits on the branch that the
142&lt;p&gt;The last fault was lack shell completions. A quick review of what a shell completion really does:&lt;/p&gt; 198selected worktree corresponds to. In other words, sight for sore eyes.
143&lt;div class="sourceCode" id="cb13"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb13-1"&gt;&lt;a href="#cb13-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git checkout f&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;tab&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt; 199Our little script is already shaping up to be useful, you hit
200&lt;code&gt;gwj&lt;/code&gt;, browse through your worktrees, preview each one and
201automatically &lt;code&gt;cd&lt;/code&gt; to your selection. But we are not done
202yet.&lt;/p&gt;
203&lt;p&gt;The last fault was lack shell completions. A quick review of what a
204shell completion really does:&lt;/p&gt;
205&lt;div class="sourceCode" id="cb13"&gt;&lt;pre
206class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb13-1"&gt;&lt;a href="#cb13-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git checkout f&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;tab&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
144&lt;span id="cb13-2"&gt;&lt;a href="#cb13-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;feature/is-ascii-octdigit&lt;/span&gt;&lt;/span&gt; 207&lt;span id="cb13-2"&gt;&lt;a href="#cb13-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;feature/is-ascii-octdigit&lt;/span&gt;&lt;/span&gt;
145&lt;span id="cb13-3"&gt;&lt;a href="#cb13-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;fix/some-error&lt;/span&gt;&lt;/span&gt; 208&lt;span id="cb13-3"&gt;&lt;a href="#cb13-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;fix/some-error&lt;/span&gt;&lt;/span&gt;
146&lt;span id="cb13-4"&gt;&lt;a href="#cb13-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;format-doc-tests&lt;/span&gt;&lt;/span&gt; 209&lt;span id="cb13-4"&gt;&lt;a href="#cb13-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;format-doc-tests&lt;/span&gt;&lt;/span&gt;
@@ -148,16 +211,22 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
148&lt;span id="cb13-6"&gt;&lt;a href="#cb13-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git checkout feat&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;tab&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt; 211&lt;span id="cb13-6"&gt;&lt;a href="#cb13-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git checkout feat&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;tab&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
149&lt;span id="cb13-7"&gt;&lt;a href="#cb13-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 212&lt;span id="cb13-7"&gt;&lt;a href="#cb13-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
150&lt;span id="cb13-8"&gt;&lt;a href="#cb13-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git checkout feature/is-ascii-octdigit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 213&lt;span id="cb13-8"&gt;&lt;a href="#cb13-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git checkout feature/is-ascii-octdigit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
151&lt;p&gt;Each time you hit “tab”, the shell produces a few “completion candidates”, and once you have just a single candidate left, the shell inserts that for you directly into your edit line. Of course, this process varies from shell to shell.&lt;/p&gt; 214&lt;p&gt;Each time you hit “tab”, the shell produces a few “completion
152&lt;p&gt;fzf narrows down your options as you type into the prompt, but you still have to:&lt;/p&gt; 215candidates”, and once you have just a single candidate left, the shell
216inserts that for you directly into your edit line. Of course, this
217process varies from shell to shell.&lt;/p&gt;
218&lt;p&gt;fzf narrows down your options as you type into the prompt, but you
219still have to:&lt;/p&gt;
153&lt;ol type="1"&gt; 220&lt;ol type="1"&gt;
154&lt;li&gt;Type &lt;code&gt;gwj&lt;/code&gt;&lt;/li&gt; 221&lt;li&gt;Type &lt;code&gt;gwj&lt;/code&gt;&lt;/li&gt;
155&lt;li&gt;Hit enter&lt;/li&gt; 222&lt;li&gt;Hit enter&lt;/li&gt;
156&lt;li&gt;Type out a query and narrow down your search&lt;/li&gt; 223&lt;li&gt;Type out a query and narrow down your search&lt;/li&gt;
157&lt;li&gt;Hit enter&lt;/li&gt; 224&lt;li&gt;Hit enter&lt;/li&gt;
158&lt;/ol&gt; 225&lt;/ol&gt;
159&lt;p&gt;We can speed that up a bit, have fzf narrow down the candidates on startup, just like our shell does:&lt;/p&gt; 226&lt;p&gt;We can speed that up a bit, have fzf narrow down the candidates on
160&lt;div class="sourceCode" id="cb14"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb14-1"&gt;&lt;a href="#cb14-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;gwj ()&lt;/span&gt; &lt;span class="kw"&gt;{&lt;/span&gt;&lt;/span&gt; 227startup, just like our shell does:&lt;/p&gt;
228&lt;div class="sourceCode" id="cb14"&gt;&lt;pre
229class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb14-1"&gt;&lt;a href="#cb14-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;gwj ()&lt;/span&gt; &lt;span class="kw"&gt;{&lt;/span&gt;&lt;/span&gt;
161&lt;span id="cb14-2"&gt;&lt;a href="#cb14-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;local&lt;/span&gt; &lt;span class="va"&gt;out&lt;/span&gt; &lt;span class="va"&gt;query&lt;/span&gt;&lt;/span&gt; 230&lt;span id="cb14-2"&gt;&lt;a href="#cb14-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;local&lt;/span&gt; &lt;span class="va"&gt;out&lt;/span&gt; &lt;span class="va"&gt;query&lt;/span&gt;&lt;/span&gt;
162&lt;span id="cb14-3"&gt;&lt;a href="#cb14-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;query&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;${1&lt;/span&gt;&lt;span class="op"&gt;:-&lt;/span&gt; &lt;span class="va"&gt;}&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; 231&lt;span id="cb14-3"&gt;&lt;a href="#cb14-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;query&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;${1&lt;/span&gt;&lt;span class="op"&gt;:-&lt;/span&gt; &lt;span class="va"&gt;}&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
163&lt;span id="cb14-4"&gt;&lt;a href="#cb14-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;out&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="va"&gt;$(&lt;/span&gt;&lt;/span&gt; 232&lt;span id="cb14-4"&gt;&lt;a href="#cb14-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;out&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="va"&gt;$(&lt;/span&gt;&lt;/span&gt;
@@ -167,8 +236,12 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
167&lt;span id="cb14-8"&gt;&lt;a href="#cb14-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;)&lt;/span&gt;&lt;/span&gt; 236&lt;span id="cb14-8"&gt;&lt;a href="#cb14-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;)&lt;/span&gt;&lt;/span&gt;
168&lt;span id="cb14-9"&gt;&lt;a href="#cb14-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;cd&lt;/span&gt; &lt;span class="va"&gt;$out&lt;/span&gt;&lt;/span&gt; 237&lt;span id="cb14-9"&gt;&lt;a href="#cb14-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;cd&lt;/span&gt; &lt;span class="va"&gt;$out&lt;/span&gt;&lt;/span&gt;
169&lt;span id="cb14-10"&gt;&lt;a href="#cb14-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 238&lt;span id="cb14-10"&gt;&lt;a href="#cb14-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
170&lt;p&gt;The change is extremely tiny, blink-and-you’ll-miss-it kinda tiny. We added a little &lt;code&gt;--query&lt;/code&gt; flag, that allows you to prefill the prompt, and the &lt;code&gt;-1&lt;/code&gt; flag, that avoids the interactive finder if only one match exists on startup:&lt;/p&gt; 239&lt;p&gt;The change is extremely tiny, blink-and-you’ll-miss-it kinda tiny. We
171&lt;div class="sourceCode" id="cb15"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb15-1"&gt;&lt;a href="#cb15-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# skip through the fzf prompt:&lt;/span&gt;&lt;/span&gt; 240added a little &lt;code&gt;--query&lt;/code&gt; flag, that allows you to prefill the
241prompt, and the &lt;code&gt;-1&lt;/code&gt; flag, that avoids the interactive finder
242if only one match exists on startup:&lt;/p&gt;
243&lt;div class="sourceCode" id="cb15"&gt;&lt;pre
244class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb15-1"&gt;&lt;a href="#cb15-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# skip through the fzf prompt:&lt;/span&gt;&lt;/span&gt;
172&lt;span id="cb15-2"&gt;&lt;a href="#cb15-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; gwj master&lt;/span&gt; 245&lt;span id="cb15-2"&gt;&lt;a href="#cb15-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; gwj master&lt;/span&gt;
173&lt;span id="cb15-3"&gt;&lt;a href="#cb15-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# cd -- ~/worktrees/rustc/master&lt;/span&gt;&lt;/span&gt; 246&lt;span id="cb15-3"&gt;&lt;a href="#cb15-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# cd -- ~/worktrees/rustc/master&lt;/span&gt;&lt;/span&gt;
174&lt;span id="cb15-4"&gt;&lt;a href="#cb15-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 247&lt;span id="cb15-4"&gt;&lt;a href="#cb15-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
@@ -183,8 +256,11 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
183&lt;span id="cb15-13"&gt;&lt;a href="#cb15-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;2/2&lt;/span&gt;&lt;/span&gt; 256&lt;span id="cb15-13"&gt;&lt;a href="#cb15-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;2/2&lt;/span&gt;&lt;/span&gt;
184&lt;span id="cb15-14"&gt;&lt;a href="#cb15-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; /home/np/worktrees/compiler/improve-const-perf &lt;span class="ex"&gt;eac6c...&lt;/span&gt;&lt;/span&gt; 257&lt;span id="cb15-14"&gt;&lt;a href="#cb15-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; /home/np/worktrees/compiler/improve-const-perf &lt;span class="ex"&gt;eac6c...&lt;/span&gt;&lt;/span&gt;
185&lt;span id="cb15-15"&gt;&lt;a href="#cb15-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;/home/np/worktrees/compiler/improve-std-char-docs&lt;/span&gt; 94cba...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 258&lt;span id="cb15-15"&gt;&lt;a href="#cb15-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;/home/np/worktrees/compiler/improve-std-char-docs&lt;/span&gt; 94cba...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
186&lt;p&gt;Throw some error handling in there, hook up a similar script to improve the UX of &lt;code&gt;git worktree remove&lt;/code&gt;, go wild. A few more helpers I’ve got:&lt;/p&gt; 259&lt;p&gt;Throw some error handling in there, hook up a similar script to
187&lt;div class="sourceCode" id="cb16"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb16-1"&gt;&lt;a href="#cb16-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# gwa /path/to/branch-name&lt;/span&gt;&lt;/span&gt; 260improve the UX of &lt;code&gt;git worktree remove&lt;/code&gt;, go wild. A few more
261helpers I’ve got:&lt;/p&gt;
262&lt;div class="sourceCode" id="cb16"&gt;&lt;pre
263class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb16-1"&gt;&lt;a href="#cb16-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# gwa /path/to/branch-name&lt;/span&gt;&lt;/span&gt;
188&lt;span id="cb16-2"&gt;&lt;a href="#cb16-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# creates a new branch and &amp;quot;switches&amp;quot; to it&lt;/span&gt;&lt;/span&gt; 264&lt;span id="cb16-2"&gt;&lt;a href="#cb16-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# creates a new branch and &amp;quot;switches&amp;quot; to it&lt;/span&gt;&lt;/span&gt;
189&lt;span id="cb16-3"&gt;&lt;a href="#cb16-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;function&lt;/span&gt;&lt;span class="fu"&gt; gwa ()&lt;/span&gt; &lt;span class="kw"&gt;{&lt;/span&gt;&lt;/span&gt; 265&lt;span id="cb16-3"&gt;&lt;a href="#cb16-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;function&lt;/span&gt;&lt;span class="fu"&gt; gwa ()&lt;/span&gt; &lt;span class="kw"&gt;{&lt;/span&gt;&lt;/span&gt;
190&lt;span id="cb16-4"&gt;&lt;a href="#cb16-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="fu"&gt;git&lt;/span&gt; worktree add &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$1&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; &lt;span class="kw"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="bu"&gt;cd&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$1&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; 266&lt;span id="cb16-4"&gt;&lt;a href="#cb16-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="fu"&gt;git&lt;/span&gt; worktree add &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$1&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; &lt;span class="kw"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="bu"&gt;cd&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$1&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
@@ -197,88 +273,175 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
197</item> 273</item>
198<item> 274<item>
199<title>Programming On 34 Keys</title> 275<title>Programming On 34 Keys</title>
200<description>&lt;p&gt;Minimizing your keyboard layout is a slippery slope. A few months ago, I built the &lt;a href="https://github.com/icyphox/ferricy"&gt;Ferricy&lt;/a&gt;, a 34-key-split-ortho-ergo keyboard. The Ferricy is a fork of the &lt;a href="https://github.com/davidphilipbarr/Sweep/tree/main/Sweep%20Bling%20MX"&gt;Ferris Sweep MX Bling&lt;/a&gt;.&lt;/p&gt; 276<description>&lt;p&gt;Minimizing your keyboard layout is a slippery slope. A few months
277ago, I built the &lt;a
278href="https://github.com/icyphox/ferricy"&gt;Ferricy&lt;/a&gt;, a
27934-key-split-ortho-ergo keyboard. The Ferricy is a fork of the &lt;a
280href="https://github.com/davidphilipbarr/Sweep/tree/main/Sweep%20Bling%20MX"&gt;Ferris
281Sweep MX Bling&lt;/a&gt;.&lt;/p&gt;
201&lt;figure&gt; 282&lt;figure&gt;
202&lt;img src="https://u.peppe.rs/otz.jpg" alt="The Ferricy, designed by icyphox" /&gt;&lt;figcaption aria-hidden="true"&gt;The Ferricy, designed by &lt;a href="https://icyphox.sh"&gt;icyphox&lt;/a&gt;&lt;/figcaption&gt; 283&lt;img src="https://u.peppe.rs/otz.jpg"
284alt="The Ferricy, designed by icyphox" /&gt;
285&lt;figcaption aria-hidden="true"&gt;The Ferricy, designed by &lt;a
286href="https://icyphox.sh"&gt;icyphox&lt;/a&gt;&lt;/figcaption&gt;
203&lt;/figure&gt; 287&lt;/figure&gt;
204&lt;p&gt;My daily use consists of a bit of prose and a lot of program, my layout has evolved accordingly.&lt;/p&gt; 288&lt;p&gt;My daily use consists of a bit of prose and a lot of program, my
289layout has evolved accordingly.&lt;/p&gt;
205&lt;h1 id="base-layer"&gt;Base Layer&lt;/h1&gt; 290&lt;h1 id="base-layer"&gt;Base Layer&lt;/h1&gt;
206&lt;figure&gt; 291&lt;figure&gt;
207&lt;img src="https://u.peppe.rs/base.png" alt="Colemak with no mods" /&gt;&lt;figcaption aria-hidden="true"&gt;Colemak with no mods&lt;/figcaption&gt; 292&lt;img src="https://u.peppe.rs/base.png" alt="Colemak with no mods" /&gt;
293&lt;figcaption aria-hidden="true"&gt;Colemak with no mods&lt;/figcaption&gt;
208&lt;/figure&gt; 294&lt;/figure&gt;
209&lt;p&gt;The base layer contains alphabets, four symbols and four whitespace keys:&lt;/p&gt; 295&lt;p&gt;The base layer contains alphabets, four symbols and four whitespace
296keys:&lt;/p&gt;
210&lt;ul&gt; 297&lt;ul&gt;
211&lt;li&gt;Alphas: Stock Colemak, with no modifications whatsoever&lt;/li&gt; 298&lt;li&gt;Alphas: Stock Colemak, with no modifications whatsoever&lt;/li&gt;
212&lt;li&gt;Symbols: &lt;code&gt;. , / ;&lt;/code&gt;&lt;/li&gt; 299&lt;li&gt;Symbols: &lt;code&gt;. , / ;&lt;/code&gt;&lt;/li&gt;
213&lt;li&gt;Whitespace: tab, space, enter, backspace (from left to right)&lt;/li&gt; 300&lt;li&gt;Whitespace: tab, space, enter, backspace (from left to right)&lt;/li&gt;
214&lt;/ul&gt; 301&lt;/ul&gt;
215&lt;h1 id="layers"&gt;Layers&lt;/h1&gt; 302&lt;h1 id="layers"&gt;Layers&lt;/h1&gt;
216&lt;p&gt;Keyboard input is complex and it is impossible to skirt around it. You can either use a keyboard with enough keys to supply all possible inputs (a mechanical burden), or you can use firmware to supply all possible inputs (a cognitive burden). Layers are a cognitive burden.&lt;/p&gt; 303&lt;p&gt;Keyboard input is complex and it is impossible to skirt around it.
217&lt;p&gt;I use 3 layers, heavily inspired by &lt;a href="https://github.com/manna-harbour/miryoku"&gt;Miryoku&lt;/a&gt;, but tuned for programming. Excluding the base Colemak layer:&lt;/p&gt; 304You can either use a keyboard with enough keys to supply all possible
305inputs (a mechanical burden), or you can use firmware to supply all
306possible inputs (a cognitive burden). Layers are a cognitive burden.&lt;/p&gt;
307&lt;p&gt;I use 3 layers, heavily inspired by &lt;a
308href="https://github.com/manna-harbour/miryoku"&gt;Miryoku&lt;/a&gt;, but tuned
309for programming. Excluding the base Colemak layer:&lt;/p&gt;
218&lt;ul&gt; 310&lt;ul&gt;
219&lt;li&gt;&lt;code&gt;NAV&lt;/code&gt;: activated on holding &lt;code&gt;space&lt;/code&gt; (left thumb)&lt;/li&gt; 311&lt;li&gt;&lt;code&gt;NAV&lt;/code&gt;: activated on holding &lt;code&gt;space&lt;/code&gt; (left
220&lt;li&gt;&lt;code&gt;NUM&lt;/code&gt;: activated on holding &lt;code&gt;tab&lt;/code&gt; (left thumb)&lt;/li&gt; 312thumb)&lt;/li&gt;
221&lt;li&gt;&lt;code&gt;SYM&lt;/code&gt;: activated on holding &lt;code&gt;enter&lt;/code&gt; (right thumb)&lt;/li&gt; 313&lt;li&gt;&lt;code&gt;NUM&lt;/code&gt;: activated on holding &lt;code&gt;tab&lt;/code&gt; (left
314thumb)&lt;/li&gt;
315&lt;li&gt;&lt;code&gt;SYM&lt;/code&gt;: activated on holding &lt;code&gt;enter&lt;/code&gt; (right
316thumb)&lt;/li&gt;
222&lt;/ul&gt; 317&lt;/ul&gt;
223&lt;h2 id="the-nav-layer"&gt;The &lt;code&gt;NAV&lt;/code&gt; Layer&lt;/h2&gt; 318&lt;h2 id="the-nav-layer"&gt;The &lt;code&gt;NAV&lt;/code&gt; Layer&lt;/h2&gt;
224&lt;p&gt;As the name suggests, this layer is focused on navigation. Arrow keys and the likes.&lt;/p&gt; 319&lt;p&gt;As the name suggests, this layer is focused on navigation. Arrow keys
320and the likes.&lt;/p&gt;
225&lt;figure&gt; 321&lt;figure&gt;
226&lt;img src="https://u.peppe.rs/nav.png" alt="NAV, on holding space" /&gt;&lt;figcaption aria-hidden="true"&gt;&lt;code&gt;NAV&lt;/code&gt;, on holding &lt;code&gt;space&lt;/code&gt;&lt;/figcaption&gt; 322&lt;img src="https://u.peppe.rs/nav.png" alt="NAV, on holding space" /&gt;
323&lt;figcaption aria-hidden="true"&gt;&lt;code&gt;NAV&lt;/code&gt;, on holding
324&lt;code&gt;space&lt;/code&gt;&lt;/figcaption&gt;
227&lt;/figure&gt; 325&lt;/figure&gt;
228&lt;p&gt;Using Vim and Colemak means you lose out on HJKL navigation. However, on activating the &lt;code&gt;NAV&lt;/code&gt; layer, the right home-row is converted into arrow keys. In essence, by holding space, I can navigate Vim with the home-row, or Firefox, or my PDF reader. I no longer need to look for software that allows Vim navigation keys, because it is baked into the firmware!&lt;/p&gt; 326&lt;p&gt;Using Vim and Colemak means you lose out on HJKL navigation. However,
229&lt;p&gt;My Vim motions are not limited to HJKL. In fact, my Vim motions are rarely HJKL. I tend to use &lt;code&gt;}&lt;/code&gt; (next paragraph) and &lt;code&gt;)&lt;/code&gt; (next sentence) more often. As a result, these have found their way into my &lt;code&gt;NAV&lt;/code&gt; layer, over the likes of &lt;code&gt;PgDown&lt;/code&gt; and &lt;code&gt;End&lt;/code&gt;. Having brackets at my index and middle fingers is nice for programming too.&lt;/p&gt; 327on activating the &lt;code&gt;NAV&lt;/code&gt; layer, the right home-row is
328converted into arrow keys. In essence, by holding space, I can navigate
329Vim with the home-row, or Firefox, or my PDF reader. I no longer need to
330look for software that allows Vim navigation keys, because it is baked
331into the firmware!&lt;/p&gt;
332&lt;p&gt;My Vim motions are not limited to HJKL. In fact, my Vim motions are
333rarely HJKL. I tend to use &lt;code&gt;}&lt;/code&gt; (next paragraph) and
334&lt;code&gt;)&lt;/code&gt; (next sentence) more often. As a result, these have found
335their way into my &lt;code&gt;NAV&lt;/code&gt; layer, over the likes of
336&lt;code&gt;PgDown&lt;/code&gt; and &lt;code&gt;End&lt;/code&gt;. Having brackets at my index
337and middle fingers is nice for programming too.&lt;/p&gt;
230&lt;h2 id="the-sym-layer"&gt;The &lt;code&gt;SYM&lt;/code&gt; Layer&lt;/h2&gt; 338&lt;h2 id="the-sym-layer"&gt;The &lt;code&gt;SYM&lt;/code&gt; Layer&lt;/h2&gt;
231&lt;figure&gt; 339&lt;figure&gt;
232&lt;img src="https://u.peppe.rs/sym.png" alt="SYM, on holding enter" /&gt;&lt;figcaption aria-hidden="true"&gt;&lt;code&gt;SYM&lt;/code&gt;, on holding &lt;code&gt;enter&lt;/code&gt;&lt;/figcaption&gt; 340&lt;img src="https://u.peppe.rs/sym.png" alt="SYM, on holding enter" /&gt;
341&lt;figcaption aria-hidden="true"&gt;&lt;code&gt;SYM&lt;/code&gt;, on holding
342&lt;code&gt;enter&lt;/code&gt;&lt;/figcaption&gt;
233&lt;/figure&gt; 343&lt;/figure&gt;
234&lt;p&gt;This layer contains all the symbols that you would find by hitting &lt;code&gt;Shift&lt;/code&gt; and a key on the number row. Probably noteworthy to Vim users: the symbols are arranged in the form of a mirrored numpad for exactly one reason: to move &lt;code&gt;$&lt;/code&gt; to the left of &lt;code&gt;^&lt;/code&gt;. It has always annoyed me that &lt;code&gt;$&lt;/code&gt; moves the cursor to the end of the line and &lt;code&gt;^&lt;/code&gt; moves it to the beginning, but their position on a typical number row are reversed, 4 comes before 6.&lt;/p&gt; 344&lt;p&gt;This layer contains all the symbols that you would find by hitting
345&lt;code&gt;Shift&lt;/code&gt; and a key on the number row. Probably noteworthy to
346Vim users: the symbols are arranged in the form of a mirrored numpad for
347exactly one reason: to move &lt;code&gt;$&lt;/code&gt; to the left of
348&lt;code&gt;^&lt;/code&gt;. It has always annoyed me that &lt;code&gt;$&lt;/code&gt; moves the
349cursor to the end of the line and &lt;code&gt;^&lt;/code&gt; moves it to the
350beginning, but their position on a typical number row are reversed, 4
351comes before 6.&lt;/p&gt;
235&lt;h2 id="the-num-layer"&gt;The &lt;code&gt;NUM&lt;/code&gt; layer&lt;/h2&gt; 352&lt;h2 id="the-num-layer"&gt;The &lt;code&gt;NUM&lt;/code&gt; layer&lt;/h2&gt;
236&lt;figure&gt; 353&lt;figure&gt;
237&lt;img src="https://u.peppe.rs/num.png" alt="NUM, on holding tab" /&gt;&lt;figcaption aria-hidden="true"&gt;&lt;code&gt;NUM&lt;/code&gt;, on holding &lt;code&gt;tab&lt;/code&gt;&lt;/figcaption&gt; 354&lt;img src="https://u.peppe.rs/num.png" alt="NUM, on holding tab" /&gt;
355&lt;figcaption aria-hidden="true"&gt;&lt;code&gt;NUM&lt;/code&gt;, on holding
356&lt;code&gt;tab&lt;/code&gt;&lt;/figcaption&gt;
238&lt;/figure&gt; 357&lt;/figure&gt;
239&lt;p&gt;Another deviation from Miryoku, the numpad just feels &lt;em&gt;right&lt;/em&gt; on my &lt;em&gt;right&lt;/em&gt; hand.&lt;/p&gt; 358&lt;p&gt;Another deviation from Miryoku, the numpad just feels &lt;em&gt;right&lt;/em&gt;
359on my &lt;em&gt;right&lt;/em&gt; hand.&lt;/p&gt;
240&lt;h1 id="zmk-combos"&gt;ZMK Combos&lt;/h1&gt; 360&lt;h1 id="zmk-combos"&gt;ZMK Combos&lt;/h1&gt;
241&lt;p&gt;If you have been paying close attention, you might have noticed that &lt;code&gt;escape&lt;/code&gt; didn’t make it to any layer. &lt;code&gt;escape&lt;/code&gt; is too crucial to put on a non-base layer, but at the same time, not as important to deserve a place on the base layer. That is where ZMK’s combos come in. Combos let you tap any number of keys, and combine them to form a single key. I have combos set up for underscore, minus, escape and caps-word (more on caps-word later):&lt;/p&gt; 361&lt;p&gt;If you have been paying close attention, you might have noticed that
362&lt;code&gt;escape&lt;/code&gt; didn’t make it to any layer. &lt;code&gt;escape&lt;/code&gt; is
363too crucial to put on a non-base layer, but at the same time, not as
364important to deserve a place on the base layer. That is where ZMK’s
365combos come in. Combos let you tap any number of keys, and combine them
366to form a single key. I have combos set up for underscore, minus, escape
367and caps-word (more on caps-word later):&lt;/p&gt;
242&lt;figure&gt; 368&lt;figure&gt;
243&lt;img src="https://u.peppe.rs/combos.png" alt="Combos are almost piano-like" /&gt;&lt;figcaption aria-hidden="true"&gt;Combos are almost piano-like&lt;/figcaption&gt; 369&lt;img src="https://u.peppe.rs/combos.png"
370alt="Combos are almost piano-like" /&gt;
371&lt;figcaption aria-hidden="true"&gt;Combos are almost piano-like&lt;/figcaption&gt;
244&lt;/figure&gt; 372&lt;/figure&gt;
245&lt;h1 id="home-row-mods"&gt;Home-row Mods&lt;/h1&gt; 373&lt;h1 id="home-row-mods"&gt;Home-row Mods&lt;/h1&gt;
246&lt;p&gt;Inherited from Miryoku, I have home-row mods for activating &lt;code&gt;Super&lt;/code&gt;, &lt;code&gt;Alt&lt;/code&gt;, &lt;code&gt;Shift&lt;/code&gt;, &lt;code&gt;Ctrl&lt;/code&gt; and &lt;code&gt;Hyper&lt;/code&gt; (&lt;code&gt;Ctrl + Shift + Alt + Super&lt;/code&gt;). The idea is to send &lt;code&gt;T&lt;/code&gt; on tap and &lt;code&gt;Ctrl&lt;/code&gt; on hold. Home-row mods are fairly popular, so I’ll not go into the details.&lt;/p&gt; 374&lt;p&gt;Inherited from Miryoku, I have home-row mods for activating
375&lt;code&gt;Super&lt;/code&gt;, &lt;code&gt;Alt&lt;/code&gt;, &lt;code&gt;Shift&lt;/code&gt;,
376&lt;code&gt;Ctrl&lt;/code&gt; and &lt;code&gt;Hyper&lt;/code&gt;
377(&lt;code&gt;Ctrl + Shift + Alt + Super&lt;/code&gt;). The idea is to send
378&lt;code&gt;T&lt;/code&gt; on tap and &lt;code&gt;Ctrl&lt;/code&gt; on hold. Home-row mods are
379fairly popular, so I’ll not go into the details.&lt;/p&gt;
247&lt;figure&gt; 380&lt;figure&gt;
248&lt;img src="https://u.peppe.rs/homerow.png" alt="Super, Alt, Shift, Ctrl, Hyper; on the left half, and mirrored on the right half" /&gt;&lt;figcaption aria-hidden="true"&gt;Super, Alt, Shift, Ctrl, Hyper; on the left half, and mirrored on the right half&lt;/figcaption&gt; 381&lt;img src="https://u.peppe.rs/homerow.png"
382alt="Super, Alt, Shift, Ctrl, Hyper; on the left half, and mirrored on the right half" /&gt;
383&lt;figcaption aria-hidden="true"&gt;Super, Alt, Shift, Ctrl, Hyper; on the
384left half, and mirrored on the right half&lt;/figcaption&gt;
249&lt;/figure&gt; 385&lt;/figure&gt;
250&lt;p&gt;&lt;code&gt;Hyper&lt;/code&gt; bridges the gap between firmware and software. You can never configure key combination that, opens Firefox, for example, through firmware alone. However, with the &lt;code&gt;Hyper&lt;/code&gt; key, and some &lt;code&gt;sxhkd&lt;/code&gt; magic, you can emulate that. Pressing &lt;code&gt;Hyper + F&lt;/code&gt; on a keyboard is just two keys, but the key codes sent are &lt;code&gt;Ctrl + Shift + Alt + Super + F&lt;/code&gt;. That key combination is not intercepted by any application as a shortcut, except for the following &lt;code&gt;sxhkd&lt;/code&gt; stanza:&lt;/p&gt; 386&lt;p&gt;&lt;code&gt;Hyper&lt;/code&gt; bridges the gap between firmware and software. You
251&lt;div class="sourceCode" id="cb1"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;super&lt;/span&gt; + alt + shift + ctrl + f&lt;/span&gt; 387can never configure key combination that, opens Firefox, for example,
388through firmware alone. However, with the &lt;code&gt;Hyper&lt;/code&gt; key, and
389some &lt;code&gt;sxhkd&lt;/code&gt; magic, you can emulate that. Pressing
390&lt;code&gt;Hyper + F&lt;/code&gt; on a keyboard is just two keys, but the key codes
391sent are &lt;code&gt;Ctrl + Shift + Alt + Super + F&lt;/code&gt;. That key
392combination is not intercepted by any application as a shortcut, except
393for the following &lt;code&gt;sxhkd&lt;/code&gt; stanza:&lt;/p&gt;
394&lt;div class="sourceCode" id="cb1"&gt;&lt;pre
395class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;super&lt;/span&gt; + alt + shift + ctrl + f&lt;/span&gt;
252&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;xdotool&lt;/span&gt; search &lt;span class="st"&gt;&amp;quot;Mozilla Firefox&amp;quot;&lt;/span&gt; windowactivate&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 396&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;xdotool&lt;/span&gt; search &lt;span class="st"&gt;&amp;quot;Mozilla Firefox&amp;quot;&lt;/span&gt; windowactivate&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
253&lt;p&gt;Alternatively, you can intercept unused &lt;code&gt;F&lt;/code&gt; keys: &lt;code&gt;F13&lt;/code&gt; through &lt;code&gt;F24&lt;/code&gt;.&lt;/p&gt; 397&lt;p&gt;Alternatively, you can intercept unused &lt;code&gt;F&lt;/code&gt; keys:
254&lt;p&gt;Home-row mods are mirrored on each half because it would be impossible to hit &lt;code&gt;Ctrl + T&lt;/code&gt; if not; they lie on the same key.&lt;/p&gt; 398&lt;code&gt;F13&lt;/code&gt; through &lt;code&gt;F24&lt;/code&gt;.&lt;/p&gt;
399&lt;p&gt;Home-row mods are mirrored on each half because it would be
400impossible to hit &lt;code&gt;Ctrl + T&lt;/code&gt; if not; they lie on the same
401key.&lt;/p&gt;
255&lt;h1 id="caps-word"&gt;Caps-word&lt;/h1&gt; 402&lt;h1 id="caps-word"&gt;Caps-word&lt;/h1&gt;
256&lt;p&gt;Caps-word is a clever caps-lock, built into ZMK. Typing out constants such as &lt;code&gt;PORT&lt;/code&gt; with home-row mods would look like this:&lt;/p&gt; 403&lt;p&gt;Caps-word is a clever caps-lock, built into ZMK. Typing out constants
404such as &lt;code&gt;PORT&lt;/code&gt; with home-row mods would look like this:&lt;/p&gt;
257&lt;ul&gt; 405&lt;ul&gt;
258&lt;li&gt;hold &lt;code&gt;e&lt;/code&gt; (shift) on left hand, and tap &lt;code&gt;p&lt;/code&gt; on right hand&lt;/li&gt; 406&lt;li&gt;hold &lt;code&gt;e&lt;/code&gt; (shift) on left hand, and tap &lt;code&gt;p&lt;/code&gt; on
259&lt;li&gt;hold &lt;code&gt;e&lt;/code&gt; (shift) on left hand, and tap &lt;code&gt;o&lt;/code&gt; on right hand&lt;/li&gt; 407right hand&lt;/li&gt;
260&lt;li&gt;hold &lt;code&gt;s&lt;/code&gt; (shift) on right hand, and tap &lt;code&gt;r&lt;/code&gt; on left hand&lt;/li&gt; 408&lt;li&gt;hold &lt;code&gt;e&lt;/code&gt; (shift) on left hand, and tap &lt;code&gt;o&lt;/code&gt; on
261&lt;li&gt;hold &lt;code&gt;s&lt;/code&gt; (shift) on right hand, and tap &lt;code&gt;t&lt;/code&gt; on left hand&lt;/li&gt; 409right hand&lt;/li&gt;
410&lt;li&gt;hold &lt;code&gt;s&lt;/code&gt; (shift) on right hand, and tap &lt;code&gt;r&lt;/code&gt; on
411left hand&lt;/li&gt;
412&lt;li&gt;hold &lt;code&gt;s&lt;/code&gt; (shift) on right hand, and tap &lt;code&gt;t&lt;/code&gt; on
413left hand&lt;/li&gt;
262&lt;/ul&gt; 414&lt;/ul&gt;
263&lt;p&gt;This hold-alternate-hold dance gets tiring quickly. With caps-word, however:&lt;/p&gt; 415&lt;p&gt;This hold-alternate-hold dance gets tiring quickly. With caps-word,
416however:&lt;/p&gt;
264&lt;ul&gt; 417&lt;ul&gt;
265&lt;li&gt;toggle &lt;code&gt;caps_word&lt;/code&gt;&lt;/li&gt; 418&lt;li&gt;toggle &lt;code&gt;caps_word&lt;/code&gt;&lt;/li&gt;
266&lt;li&gt;type out &lt;code&gt;p&lt;/code&gt;, &lt;code&gt;o&lt;/code&gt;, &lt;code&gt;r&lt;/code&gt;, &lt;code&gt;t&lt;/code&gt;&lt;/li&gt; 419&lt;li&gt;type out &lt;code&gt;p&lt;/code&gt;, &lt;code&gt;o&lt;/code&gt;, &lt;code&gt;r&lt;/code&gt;,
420&lt;code&gt;t&lt;/code&gt;&lt;/li&gt;
267&lt;li&gt;hit a &lt;em&gt;break&lt;/em&gt; character (space, enter will do)&lt;/li&gt; 421&lt;li&gt;hit a &lt;em&gt;break&lt;/em&gt; character (space, enter will do)&lt;/li&gt;
268&lt;li&gt;continue&lt;/li&gt; 422&lt;li&gt;continue&lt;/li&gt;
269&lt;/ul&gt; 423&lt;/ul&gt;
270&lt;p&gt;Caps-word automatically disables capitalization upon encountering a breaking character, (which are space, enter or any modifier, by default) right in the firmware!&lt;/p&gt; 424&lt;p&gt;Caps-word automatically disables capitalization upon encountering a
425breaking character, (which are space, enter or any modifier, by default)
426right in the firmware!&lt;/p&gt;
271&lt;h1 id="findings"&gt;Findings&lt;/h1&gt; 427&lt;h1 id="findings"&gt;Findings&lt;/h1&gt;
272&lt;p&gt;34-keys has been reasonably comfortable to use, for both prose and program. My palms do not move across the desk at all, as I reach for keys. I mostly write Rust and Bash, and my layout has evolved to accomodate special characters from their grammars (angled brackets and hyphens, specifically). If you are on a similar journey, I would suggest focusing on accuracy and comfort over speed. Speed comes with time.&lt;/p&gt;</description> 428&lt;p&gt;34-keys has been reasonably comfortable to use, for both prose and
429program. My palms do not move across the desk at all, as I reach for
430keys. I mostly write Rust and Bash, and my layout has evolved to
431accomodate special characters from their grammars (angled brackets and
432hyphens, specifically). If you are on a similar journey, I would suggest
433focusing on accuracy and comfort over speed. Speed comes with time.&lt;/p&gt;</description>
273<link>https://peppe.rs/posts/programming_on_34_keys/</link> 434<link>https://peppe.rs/posts/programming_on_34_keys/</link>
274<pubDate>Sun, 28 Aug 2022 13:51:00 +0000</pubDate> 435<pubDate>Sun, 28 Aug 2022 13:51:00 +0000</pubDate>
275<guid>https://peppe.rs/posts/programming_on_34_keys/</guid> 436<guid>https://peppe.rs/posts/programming_on_34_keys/</guid>
276</item> 437</item>
277<item> 438<item>
278<title>A Reference Counted Afterlife</title> 439<title>A Reference Counted Afterlife</title>
279<description>&lt;p&gt;I took interest in the Egyptian rendition of the afterlife recently.&lt;/p&gt; 440<description>&lt;p&gt;I took interest in the Egyptian rendition of the afterlife
441recently.&lt;/p&gt;
280&lt;h3 id="parts-of-the-soul"&gt;Parts of the Soul&lt;/h3&gt; 442&lt;h3 id="parts-of-the-soul"&gt;Parts of the Soul&lt;/h3&gt;
281&lt;p&gt;Ancient Egyptians believed that the soul comprised of several components:&lt;/p&gt; 443&lt;p&gt;Ancient Egyptians believed that the soul comprised of several
444components:&lt;/p&gt;
282&lt;ul&gt; 445&lt;ul&gt;
283&lt;li&gt;&lt;em&gt;ren&lt;/em&gt;&lt;/li&gt; 446&lt;li&gt;&lt;em&gt;ren&lt;/em&gt;&lt;/li&gt;
284&lt;li&gt;&lt;em&gt;ka&lt;/em&gt;&lt;/li&gt; 447&lt;li&gt;&lt;em&gt;ka&lt;/em&gt;&lt;/li&gt;
@@ -286,47 +449,80 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
286&lt;li&gt;&lt;em&gt;ba&lt;/em&gt;&lt;/li&gt; 449&lt;li&gt;&lt;em&gt;ba&lt;/em&gt;&lt;/li&gt;
287&lt;li&gt;&lt;em&gt;sheut&lt;/em&gt;&lt;/li&gt; 450&lt;li&gt;&lt;em&gt;sheut&lt;/em&gt;&lt;/li&gt;
288&lt;/ul&gt; 451&lt;/ul&gt;
289&lt;p&gt;Egyptians emphasized on preserving the different parts of the soul. Mummification for example, served to preserve the physical part of the soul. The other components have their respective preservation strategies.&lt;/p&gt; 452&lt;p&gt;Egyptians emphasized on preserving the different parts of the soul.
290&lt;p&gt;Of all of these bits, I find &lt;em&gt;ren&lt;/em&gt;, which simply means &lt;em&gt;name&lt;/em&gt;, to be the most interesting. &lt;em&gt;Ba&lt;/em&gt;, the human-headed chicken that represents &lt;em&gt;personality&lt;/em&gt;, is a close favourite.&lt;/p&gt; 453Mummification for example, served to preserve the physical part of the
291&lt;p&gt;&lt;em&gt;Ren&lt;/em&gt; is the name given to a person at birth. Egyptians believed that this portion of the soul would continue to live on for as long as it was spoken. If you were someone worthy of continued existence, your name would be inscribed all over the place. If you were the type to snatch away bread from children, your name would be condemned from memory, forgotten.&lt;/p&gt; 454soul. The other components have their respective preservation
455strategies.&lt;/p&gt;
456&lt;p&gt;Of all of these bits, I find &lt;em&gt;ren&lt;/em&gt;, which simply means
457&lt;em&gt;name&lt;/em&gt;, to be the most interesting. &lt;em&gt;Ba&lt;/em&gt;, the human-headed
458chicken that represents &lt;em&gt;personality&lt;/em&gt;, is a close favourite.&lt;/p&gt;
459&lt;p&gt;&lt;em&gt;Ren&lt;/em&gt; is the name given to a person at birth. Egyptians
460believed that this portion of the soul would continue to live on for as
461long as it was spoken. If you were someone worthy of continued
462existence, your name would be inscribed all over the place. If you were
463the type to snatch away bread from children, your name would be
464condemned from memory, forgotten.&lt;/p&gt;
292&lt;h3 id="garbage-collection"&gt;Garbage-collection&lt;/h3&gt; 465&lt;h3 id="garbage-collection"&gt;Garbage-collection&lt;/h3&gt;
293&lt;p&gt;The concept of &lt;em&gt;ren&lt;/em&gt; seems to be perfectly analogous to reference counted garbage-collection.&lt;/p&gt; 466&lt;p&gt;The concept of &lt;em&gt;ren&lt;/em&gt; seems to be perfectly analogous to
467reference counted garbage-collection.&lt;/p&gt;
294&lt;ul&gt; 468&lt;ul&gt;
295&lt;li&gt;A name (&lt;em&gt;ren&lt;/em&gt;) is assigned to an object (person) on initialization (at birth)&lt;/li&gt; 469&lt;li&gt;A name (&lt;em&gt;ren&lt;/em&gt;) is assigned to an object (person) on
470initialization (at birth)&lt;/li&gt;
296&lt;li&gt;Names are used to refer to objects&lt;/li&gt; 471&lt;li&gt;Names are used to refer to objects&lt;/li&gt;
297&lt;li&gt;Objects go out of existence when there are no more references to them&lt;/li&gt; 472&lt;li&gt;Objects go out of existence when there are no more references to
473them&lt;/li&gt;
298&lt;/ul&gt; 474&lt;/ul&gt;
299&lt;p&gt;The concept of &lt;em&gt;ren&lt;/em&gt; seems to model human-memory. The similarity with garbage-collection is now easily explained, because garbage-collection models a program’s memory.&lt;/p&gt; 475&lt;p&gt;The concept of &lt;em&gt;ren&lt;/em&gt; seems to model human-memory. The
300&lt;p&gt;Perhaps some cheeky Egyptian has attained immortality by creating a &lt;em&gt;ren&lt;/em&gt;-cycle.&lt;/p&gt;</description> 476similarity with garbage-collection is now easily explained, because
477garbage-collection models a program’s memory.&lt;/p&gt;
478&lt;p&gt;Perhaps some cheeky Egyptian has attained immortality by creating a
479&lt;em&gt;ren&lt;/em&gt;-cycle.&lt;/p&gt;</description>
301<link>https://peppe.rs/posts/a_reference_counted_afterlife/</link> 480<link>https://peppe.rs/posts/a_reference_counted_afterlife/</link>
302<pubDate>Tue, 02 Aug 2022 16:47:00 +0000</pubDate> 481<pubDate>Tue, 02 Aug 2022 16:47:00 +0000</pubDate>
303<guid>https://peppe.rs/posts/a_reference_counted_afterlife/</guid> 482<guid>https://peppe.rs/posts/a_reference_counted_afterlife/</guid>
304</item> 483</item>
305<item> 484<item>
306<title>Lotus58</title> 485<title>Lotus58</title>
307<description>&lt;p&gt;Earlier this month, I decided that I would laugh at Indian customs in the face by building a split-ergo mechanical keyboard from scratch rather than purchasing a Moonlander.&lt;/p&gt; 486<description>&lt;p&gt;Earlier this month, I decided that I would laugh at Indian customs in
487the face by building a split-ergo mechanical keyboard from scratch
488rather than purchasing a Moonlander.&lt;/p&gt;
308&lt;figure&gt; 489&lt;figure&gt;
309&lt;img src="https://u.peppe.rs/i8k.jpg" alt="The finished product" /&gt;&lt;figcaption aria-hidden="true"&gt;The finished product&lt;/figcaption&gt; 490&lt;img src="https://u.peppe.rs/i8k.jpg" alt="The finished product" /&gt;
491&lt;figcaption aria-hidden="true"&gt;The finished product&lt;/figcaption&gt;
310&lt;/figure&gt; 492&lt;/figure&gt;
311&lt;h2 id="sourcing-the-parts"&gt;Sourcing the parts&lt;/h2&gt; 493&lt;h2 id="sourcing-the-parts"&gt;Sourcing the parts&lt;/h2&gt;
312&lt;p&gt;If you, like me, live in India, you might find this section useful. My approach to finding parts:&lt;/p&gt; 494&lt;p&gt;If you, like me, live in India, you might find this section useful.
495My approach to finding parts:&lt;/p&gt;
313&lt;ul&gt; 496&lt;ul&gt;
314&lt;li&gt;Check reputed, local online stores&lt;/li&gt; 497&lt;li&gt;Check reputed, local online stores&lt;/li&gt;
315&lt;li&gt;Check physical hardware stores&lt;/li&gt; 498&lt;li&gt;Check physical hardware stores&lt;/li&gt;
316&lt;li&gt;Import the part&lt;/li&gt; 499&lt;li&gt;Import the part&lt;/li&gt;
317&lt;/ul&gt; 500&lt;/ul&gt;
318&lt;h3 id="pcbs"&gt;PCBs&lt;/h3&gt; 501&lt;h3 id="pcbs"&gt;PCBs&lt;/h3&gt;
319&lt;p&gt;This was by far the hardest component to procure. Fabrication services have certain &lt;em&gt;capabilities&lt;/em&gt;. Capabilities are the limitations of a fabrication service. For example, a service may be capable of drilling holes no smaller than 0.3mm in diameter. Most sites have a verification process to check if their capabilities meet your design’s requirements. I tried a few local PCB fabrication services:&lt;/p&gt; 502&lt;p&gt;This was by far the hardest component to procure. Fabrication
503services have certain &lt;em&gt;capabilities&lt;/em&gt;. Capabilities are the
504limitations of a fabrication service. For example, a service may be
505capable of drilling holes no smaller than 0.3mm in diameter. Most sites
506have a verification process to check if their capabilities meet your
507design’s requirements. I tried a few local PCB fabrication services:&lt;/p&gt;
320&lt;ul&gt; 508&lt;ul&gt;
321&lt;li&gt;Lion PCB: Capabilities did not meet my requirements&lt;/li&gt; 509&lt;li&gt;Lion PCB: Capabilities did not meet my requirements&lt;/li&gt;
322&lt;li&gt;PCBPower: Capabilities did not meet my requirements&lt;/li&gt; 510&lt;li&gt;PCBPower: Capabilities did not meet my requirements&lt;/li&gt;
323&lt;li&gt;Circuitwala: Capabilities did not meet my requirements&lt;/li&gt; 511&lt;li&gt;Circuitwala: Capabilities did not meet my requirements&lt;/li&gt;
324&lt;/ul&gt; 512&lt;/ul&gt;
325&lt;p&gt;I settled for JLCPCB, a Chinese service. PCBs themselves were 16 USD, shipping was another 35 USD, and customs was another 3.5K INR (ouch).&lt;/p&gt; 513&lt;p&gt;I settled for JLCPCB, a Chinese service. PCBs themselves were 16 USD,
514shipping was another 35 USD, and customs was another 3.5K INR
515(ouch).&lt;/p&gt;
326&lt;h3 id="case-material"&gt;Case material&lt;/h3&gt; 516&lt;h3 id="case-material"&gt;Case material&lt;/h3&gt;
327&lt;p&gt;I don’t really have a case for the Lotus58, it is more of a “plastic sandwich”. I purchased acrylic plates from Robu. Cheap, fast, solid, and customizable. I cannot recommend Robu enough. A full set of plates (2 top plates and 2 bottom plates) cost me about 500 INR. I also bought a pair of laptop height raisers on Amazon to create a budget tenting setup.&lt;/p&gt; 517&lt;p&gt;I don’t really have a case for the Lotus58, it is more of a “plastic
518sandwich”. I purchased acrylic plates from Robu. Cheap, fast, solid, and
519customizable. I cannot recommend Robu enough. A full set of plates (2
520top plates and 2 bottom plates) cost me about 500 INR. I also bought a
521pair of laptop height raisers on Amazon to create a budget tenting
522setup.&lt;/p&gt;
328&lt;h3 id="electronics"&gt;Electronics&lt;/h3&gt; 523&lt;h3 id="electronics"&gt;Electronics&lt;/h3&gt;
329&lt;p&gt;You’ll need a few rather specific electronic components such as hotswap sockets and TRRS mounts, the rest are commonly available:&lt;/p&gt; 524&lt;p&gt;You’ll need a few rather specific electronic components such as
525hotswap sockets and TRRS mounts, the rest are commonly available:&lt;/p&gt;
330&lt;ul&gt; 526&lt;ul&gt;
331&lt;li&gt;Hotswap sockets: StacksKB&lt;/li&gt; 527&lt;li&gt;Hotswap sockets: StacksKB&lt;/li&gt;
332&lt;li&gt;TRRS mounts (PJ 320A): StacksKB&lt;/li&gt; 528&lt;li&gt;TRRS mounts (PJ 320A): StacksKB&lt;/li&gt;
@@ -335,7 +531,8 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
335&lt;li&gt;M2 spacers: ThinkRobotics&lt;/li&gt; 531&lt;li&gt;M2 spacers: ThinkRobotics&lt;/li&gt;
336&lt;li&gt;Arduino Pro Micro: Robu&lt;/li&gt; 532&lt;li&gt;Arduino Pro Micro: Robu&lt;/li&gt;
337&lt;/ul&gt; 533&lt;/ul&gt;
338&lt;p&gt;I skimped out on optional components such as OLEDs and rotary encoders.&lt;/p&gt; 534&lt;p&gt;I skimped out on optional components such as OLEDs and rotary
535encoders.&lt;/p&gt;
339&lt;h3 id="switches-and-keycaps"&gt;Switches and Keycaps&lt;/h3&gt; 536&lt;h3 id="switches-and-keycaps"&gt;Switches and Keycaps&lt;/h3&gt;
340&lt;p&gt;Arguably the most fun part of the build:&lt;/p&gt; 537&lt;p&gt;Arguably the most fun part of the build:&lt;/p&gt;
341&lt;ul&gt; 538&lt;ul&gt;
@@ -343,30 +540,57 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
343&lt;li&gt;DSA blanks: Meckeys&lt;/li&gt; 540&lt;li&gt;DSA blanks: Meckeys&lt;/li&gt;
344&lt;/ul&gt; 541&lt;/ul&gt;
345&lt;h2 id="building-the-keyboard"&gt;Building the keyboard&lt;/h2&gt; 542&lt;h2 id="building-the-keyboard"&gt;Building the keyboard&lt;/h2&gt;
346&lt;p&gt;The the build is extremely straightforward. Through hole components are easy to solder. Be wary of component placement and orientation. Check thrice, solder once. Few debugging tips:&lt;/p&gt; 543&lt;p&gt;The the build is extremely straightforward. Through hole components
544are easy to solder. Be wary of component placement and orientation.
545Check thrice, solder once. Few debugging tips:&lt;/p&gt;
347&lt;ul&gt; 546&lt;ul&gt;
348&lt;li&gt;if a single key does not actuate, check the hotswap for poor soldering (reflow the joint), and the switch pins for deformation during installation&lt;/li&gt; 547&lt;li&gt;if a single key does not actuate, check the hotswap for poor
349&lt;li&gt;if an entire column or row activates on a single key-press, a connection has been shorted&lt;/li&gt; 548soldering (reflow the joint), and the switch pins for deformation during
350&lt;li&gt;if only some of the keys on a given row actuate, a diode has been soldered on the wrong way&lt;/li&gt; 549installation&lt;/li&gt;
550&lt;li&gt;if an entire column or row activates on a single key-press, a
551connection has been shorted&lt;/li&gt;
552&lt;li&gt;if only some of the keys on a given row actuate, a diode has been
553soldered on the wrong way&lt;/li&gt;
351&lt;/ul&gt; 554&lt;/ul&gt;
352&lt;h2 id="the-typing-experience"&gt;The typing experience&lt;/h2&gt; 555&lt;h2 id="the-typing-experience"&gt;The typing experience&lt;/h2&gt;
353&lt;p&gt;I decidede to give QWERTY the boot and learn Colemak along with the new keyboard. The first few weeks were terrible because I could neither type QWERTY nor Colemak, but I got the hang of it pretty quickly. Typing websites do help, but it is best to simply use it in your daily workflow. No site can help you get accustomed to the various things you use your keyboard for such as switching windows or navigating vim/tmux.&lt;/p&gt; 556&lt;p&gt;I decidede to give QWERTY the boot and learn Colemak along with the
557new keyboard. The first few weeks were terrible because I could neither
558type QWERTY nor Colemak, but I got the hang of it pretty quickly. Typing
559websites do help, but it is best to simply use it in your daily
560workflow. No site can help you get accustomed to the various things you
561use your keyboard for such as switching windows or navigating
562vim/tmux.&lt;/p&gt;
354&lt;h3 id="colemak"&gt;Colemak&lt;/h3&gt; 563&lt;h3 id="colemak"&gt;Colemak&lt;/h3&gt;
355&lt;p&gt;Alt layouts such as Colemak are definitely worth it. I find that Colemak reduces finger movement a lot, a good portion of the keys on the left hand are the same as QWERTY, it is fairly easy to pick up as well.&lt;/p&gt; 564&lt;p&gt;Alt layouts such as Colemak are definitely worth it. I find that
565Colemak reduces finger movement a lot, a good portion of the keys on the
566left hand are the same as QWERTY, it is fairly easy to pick up as
567well.&lt;/p&gt;
356&lt;h3 id="vim"&gt;Vim&lt;/h3&gt; 568&lt;h3 id="vim"&gt;Vim&lt;/h3&gt;
357&lt;p&gt;Using an alt layout means most programs with keyboard shortcuts are not going to work as expected, &lt;code&gt;HJKL&lt;/code&gt; on vim for movements being one of them. I took the short route out by creating a new layer with arrow keys on the home row:&lt;/p&gt; 569&lt;p&gt;Using an alt layout means most programs with keyboard shortcuts are
570not going to work as expected, &lt;code&gt;HJKL&lt;/code&gt; on vim for movements
571being one of them. I took the short route out by creating a new layer
572with arrow keys on the home row:&lt;/p&gt;
358&lt;pre&gt;&lt;code&gt;default homerow: 573&lt;pre&gt;&lt;code&gt;default homerow:
359H N E I 574H N E I
360 575
361&amp;quot;nav&amp;quot; layer: 576&amp;quot;nav&amp;quot; layer:
362&amp;lt; v ^ &amp;gt;&lt;/code&gt;&lt;/pre&gt; 577&amp;lt; v ^ &amp;gt;&lt;/code&gt;&lt;/pre&gt;
363&lt;p&gt;The remaining commands in vim are largely mnemonics. Navigating with home-row arrow keys also means that I can use “HJKL” globally, to scroll a website, for example.&lt;/p&gt; 578&lt;p&gt;The remaining commands in vim are largely mnemonics. Navigating with
579home-row arrow keys also means that I can use “HJKL” globally, to scroll
580a website, for example.&lt;/p&gt;
364&lt;h3 id="cutting-down-to-34-keys"&gt;Cutting down to 34 keys&lt;/h3&gt; 581&lt;h3 id="cutting-down-to-34-keys"&gt;Cutting down to 34 keys&lt;/h3&gt;
365&lt;p&gt;A couple months into my ergo journey, I realized that I could get away by moving my fingers even lesser. I moved modifiers such as &lt;code&gt;Super&lt;/code&gt;, &lt;code&gt;Ctrl&lt;/code&gt;, &lt;code&gt;Alt&lt;/code&gt; and &lt;code&gt;Shift&lt;/code&gt; to the home-row as QMK Mod Taps. The rest of the keys are cleverly placed in layers, not too much unlike the Miryoku layout. Even for someone that writes Rust (a symbol-heavy grammar), I find 34-keys to be sufficient.&lt;/p&gt; 582&lt;p&gt;A couple months into my ergo journey, I realized that I could get
583away by moving my fingers even lesser. I moved modifiers such as
584&lt;code&gt;Super&lt;/code&gt;, &lt;code&gt;Ctrl&lt;/code&gt;, &lt;code&gt;Alt&lt;/code&gt; and
585&lt;code&gt;Shift&lt;/code&gt; to the home-row as QMK Mod Taps. The rest of the keys
586are cleverly placed in layers, not too much unlike the Miryoku layout.
587Even for someone that writes Rust (a symbol-heavy grammar), I find
58834-keys to be sufficient.&lt;/p&gt;
366&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt; 589&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
367&lt;p&gt;I have been bitten by the ergomech bug.&lt;/p&gt; 590&lt;p&gt;I have been bitten by the ergomech bug.&lt;/p&gt;
368&lt;figure&gt; 591&lt;figure&gt;
369&lt;img src="https://u.peppe.rs/XM3.jpg" alt="The Lotus58 in action" /&gt;&lt;figcaption aria-hidden="true"&gt;The Lotus58 in action&lt;/figcaption&gt; 592&lt;img src="https://u.peppe.rs/XM3.jpg" alt="The Lotus58 in action" /&gt;
593&lt;figcaption aria-hidden="true"&gt;The Lotus58 in action&lt;/figcaption&gt;
370&lt;/figure&gt;</description> 594&lt;/figure&gt;</description>
371<link>https://peppe.rs/posts/lotus58/</link> 595<link>https://peppe.rs/posts/lotus58/</link>
372<pubDate>Mon, 13 Jun 2022 13:55:00 +0000</pubDate> 596<pubDate>Mon, 13 Jun 2022 13:55:00 +0000</pubDate>
@@ -374,14 +598,23 @@ H N E I
374</item> 598</item>
375<item> 599<item>
376<title>Lightweight Linting</title> 600<title>Lightweight Linting</title>
377<description>&lt;p&gt;&lt;a href="https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries"&gt;Tree-sitter&lt;/a&gt; queries allow you to search for patterns in syntax trees, much like a regex would, in text. Combine that with some Rust glue to write simple, custom linters.&lt;/p&gt; 601<description>&lt;p&gt;&lt;a
602href="https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries"&gt;Tree-sitter&lt;/a&gt;
603queries allow you to search for patterns in syntax trees, much like a
604regex would, in text. Combine that with some Rust glue to write simple,
605custom linters.&lt;/p&gt;
378&lt;h3 id="tree-sitter-syntax-trees"&gt;Tree-sitter syntax trees&lt;/h3&gt; 606&lt;h3 id="tree-sitter-syntax-trees"&gt;Tree-sitter syntax trees&lt;/h3&gt;
379&lt;p&gt;Here is a quick crash course on syntax trees generated by tree-sitter. Syntax trees produced by tree-sitter are represented by S-expressions. The generated S-expression for the following Rust code,&lt;/p&gt; 607&lt;p&gt;Here is a quick crash course on syntax trees generated by
380&lt;div class="sourceCode" id="cb1"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; main() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 608tree-sitter. Syntax trees produced by tree-sitter are represented by
609S-expressions. The generated S-expression for the following Rust
610code,&lt;/p&gt;
611&lt;div class="sourceCode" id="cb1"&gt;&lt;pre
612class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; main() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
381&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; x &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 613&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; x &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
382&lt;span id="cb1-3"&gt;&lt;a href="#cb1-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 614&lt;span id="cb1-3"&gt;&lt;a href="#cb1-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
383&lt;p&gt;would be:&lt;/p&gt; 615&lt;p&gt;would be:&lt;/p&gt;
384&lt;div class="sourceCode" id="cb2"&gt;&lt;pre class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(source_file&lt;/span&gt; 616&lt;div class="sourceCode" id="cb2"&gt;&lt;pre
617class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(source_file&lt;/span&gt;
385&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (function_item&lt;/span&gt; 618&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (function_item&lt;/span&gt;
386&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; name: (identifier)&lt;/span&gt; 619&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; name: (identifier)&lt;/span&gt;
387&lt;span id="cb2-4"&gt;&lt;a href="#cb2-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; parameters: (parameters)&lt;/span&gt; 620&lt;span id="cb2-4"&gt;&lt;a href="#cb2-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; parameters: (parameters)&lt;/span&gt;
@@ -390,13 +623,19 @@ H N E I
390&lt;span id="cb2-7"&gt;&lt;a href="#cb2-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (let_declaration &lt;/span&gt; 623&lt;span id="cb2-7"&gt;&lt;a href="#cb2-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (let_declaration &lt;/span&gt;
391&lt;span id="cb2-8"&gt;&lt;a href="#cb2-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; pattern: (identifier)&lt;/span&gt; 624&lt;span id="cb2-8"&gt;&lt;a href="#cb2-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; pattern: (identifier)&lt;/span&gt;
392&lt;span id="cb2-9"&gt;&lt;a href="#cb2-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; value: (integer_literal)))))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 625&lt;span id="cb2-9"&gt;&lt;a href="#cb2-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; value: (integer_literal)))))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
393&lt;p&gt;Syntax trees generated by tree-sitter have a couple of other cool properties: they are &lt;em&gt;lossless&lt;/em&gt; syntax trees. Given a lossless syntax tree, you can regenerate the original source code in its entirety. Consider the following addition to our example:&lt;/p&gt; 626&lt;p&gt;Syntax trees generated by tree-sitter have a couple of other cool
394&lt;div class="sourceCode" id="cb3"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;fn&lt;/span&gt; main() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 627properties: they are &lt;em&gt;lossless&lt;/em&gt; syntax trees. Given a lossless
628syntax tree, you can regenerate the original source code in its
629entirety. Consider the following addition to our example:&lt;/p&gt;
630&lt;div class="sourceCode" id="cb3"&gt;&lt;pre
631class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;fn&lt;/span&gt; main() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
395&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="co"&gt;// a comment goes here&lt;/span&gt;&lt;/span&gt; 632&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="co"&gt;// a comment goes here&lt;/span&gt;&lt;/span&gt;
396&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; x &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 633&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; x &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
397&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 634&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
398&lt;p&gt;The tree-sitter syntax tree preserves the comment, while the typical abstract syntax tree wouldn’t:&lt;/p&gt; 635&lt;p&gt;The tree-sitter syntax tree preserves the comment, while the typical
399&lt;div class="sourceCode" id="cb4"&gt;&lt;pre class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb4-1"&gt;&lt;a href="#cb4-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (source_file&lt;/span&gt; 636abstract syntax tree wouldn’t:&lt;/p&gt;
637&lt;div class="sourceCode" id="cb4"&gt;&lt;pre
638class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb4-1"&gt;&lt;a href="#cb4-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (source_file&lt;/span&gt;
400&lt;span id="cb4-2"&gt;&lt;a href="#cb4-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (function_item&lt;/span&gt; 639&lt;span id="cb4-2"&gt;&lt;a href="#cb4-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (function_item&lt;/span&gt;
401&lt;span id="cb4-3"&gt;&lt;a href="#cb4-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; name: (identifier)&lt;/span&gt; 640&lt;span id="cb4-3"&gt;&lt;a href="#cb4-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; name: (identifier)&lt;/span&gt;
402&lt;span id="cb4-4"&gt;&lt;a href="#cb4-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; parameters: (parameters)&lt;/span&gt; 641&lt;span id="cb4-4"&gt;&lt;a href="#cb4-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; parameters: (parameters)&lt;/span&gt;
@@ -407,25 +646,34 @@ H N E I
407&lt;span id="cb4-9"&gt;&lt;a href="#cb4-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; pattern: (identifier)&lt;/span&gt; 646&lt;span id="cb4-9"&gt;&lt;a href="#cb4-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; pattern: (identifier)&lt;/span&gt;
408&lt;span id="cb4-10"&gt;&lt;a href="#cb4-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; value: (integer_literal)))))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 647&lt;span id="cb4-10"&gt;&lt;a href="#cb4-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; value: (integer_literal)))))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
409&lt;h3 id="tree-sitter-queries"&gt;Tree-sitter queries&lt;/h3&gt; 648&lt;h3 id="tree-sitter-queries"&gt;Tree-sitter queries&lt;/h3&gt;
410&lt;p&gt;Tree-sitter provides a DSL to match over CSTs. These queries resemble our S-expression syntax trees, here is a query to match all line comments in a Rust CST:&lt;/p&gt; 649&lt;p&gt;Tree-sitter provides a DSL to match over CSTs. These queries resemble
411&lt;div class="sourceCode" id="cb5"&gt;&lt;pre class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb5-1"&gt;&lt;a href="#cb5-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(line_comment)&lt;/span&gt; 650our S-expression syntax trees, here is a query to match all line
651comments in a Rust CST:&lt;/p&gt;
652&lt;div class="sourceCode" id="cb5"&gt;&lt;pre
653class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb5-1"&gt;&lt;a href="#cb5-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(line_comment)&lt;/span&gt;
412&lt;span id="cb5-2"&gt;&lt;a href="#cb5-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 654&lt;span id="cb5-2"&gt;&lt;a href="#cb5-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
413&lt;span id="cb5-3"&gt;&lt;a href="#cb5-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; matches the following rust code&lt;/span&gt;&lt;/span&gt; 655&lt;span id="cb5-3"&gt;&lt;a href="#cb5-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; matches the following rust code&lt;/span&gt;&lt;/span&gt;
414&lt;span id="cb5-4"&gt;&lt;a href="#cb5-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; // a comment goes here&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 656&lt;span id="cb5-4"&gt;&lt;a href="#cb5-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; // a comment goes here&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
415&lt;p&gt;Neat, eh? But don’t take my word for it, give it a go on the &lt;a href="https://tree-sitter.github.io/tree-sitter/playground"&gt;tree-sitter playground&lt;/a&gt;. Type in a query like so:&lt;/p&gt; 657&lt;p&gt;Neat, eh? But don’t take my word for it, give it a go on the &lt;a
416&lt;div class="sourceCode" id="cb6"&gt;&lt;pre class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb6-1"&gt;&lt;a href="#cb6-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; the web playground requires you to specify a &amp;quot;capture&amp;quot;&lt;/span&gt;&lt;/span&gt; 658href="https://tree-sitter.github.io/tree-sitter/playground"&gt;tree-sitter
659playground&lt;/a&gt;. Type in a query like so:&lt;/p&gt;
660&lt;div class="sourceCode" id="cb6"&gt;&lt;pre
661class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb6-1"&gt;&lt;a href="#cb6-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; the web playground requires you to specify a &amp;quot;capture&amp;quot;&lt;/span&gt;&lt;/span&gt;
417&lt;span id="cb6-2"&gt;&lt;a href="#cb6-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; you will notice the capture and the nodes it captured&lt;/span&gt;&lt;/span&gt; 662&lt;span id="cb6-2"&gt;&lt;a href="#cb6-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; you will notice the capture and the nodes it captured&lt;/span&gt;&lt;/span&gt;
418&lt;span id="cb6-3"&gt;&lt;a href="#cb6-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; turn blue&lt;/span&gt;&lt;/span&gt; 663&lt;span id="cb6-3"&gt;&lt;a href="#cb6-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; turn blue&lt;/span&gt;&lt;/span&gt;
419&lt;span id="cb6-4"&gt;&lt;a href="#cb6-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(line_comment) @capture&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 664&lt;span id="cb6-4"&gt;&lt;a href="#cb6-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(line_comment) @capture&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
420&lt;p&gt;Here’s another to match &lt;code&gt;let&lt;/code&gt; expressions that bind an integer to an identifier:&lt;/p&gt; 665&lt;p&gt;Here’s another to match &lt;code&gt;let&lt;/code&gt; expressions that bind an
421&lt;div class="sourceCode" id="cb7"&gt;&lt;pre class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb7-1"&gt;&lt;a href="#cb7-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(let_declaration&lt;/span&gt; 666integer to an identifier:&lt;/p&gt;
667&lt;div class="sourceCode" id="cb7"&gt;&lt;pre
668class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb7-1"&gt;&lt;a href="#cb7-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(let_declaration&lt;/span&gt;
422&lt;span id="cb7-2"&gt;&lt;a href="#cb7-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; pattern: (identifier)&lt;/span&gt; 669&lt;span id="cb7-2"&gt;&lt;a href="#cb7-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; pattern: (identifier)&lt;/span&gt;
423&lt;span id="cb7-3"&gt;&lt;a href="#cb7-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; value: (integer_literal))&lt;/span&gt; 670&lt;span id="cb7-3"&gt;&lt;a href="#cb7-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; value: (integer_literal))&lt;/span&gt;
424&lt;span id="cb7-4"&gt;&lt;a href="#cb7-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;/span&gt; 671&lt;span id="cb7-4"&gt;&lt;a href="#cb7-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;/span&gt;
425&lt;span id="cb7-5"&gt;&lt;a href="#cb7-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; matches:&lt;/span&gt;&lt;/span&gt; 672&lt;span id="cb7-5"&gt;&lt;a href="#cb7-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; matches:&lt;/span&gt;&lt;/span&gt;
426&lt;span id="cb7-6"&gt;&lt;a href="#cb7-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; let foo = 2;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 673&lt;span id="cb7-6"&gt;&lt;a href="#cb7-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; let foo = 2;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
427&lt;p&gt;We can &lt;em&gt;capture&lt;/em&gt; nodes into variables:&lt;/p&gt; 674&lt;p&gt;We can &lt;em&gt;capture&lt;/em&gt; nodes into variables:&lt;/p&gt;
428&lt;div class="sourceCode" id="cb8"&gt;&lt;pre class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb8-1"&gt;&lt;a href="#cb8-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(let_declaration &lt;/span&gt; 675&lt;div class="sourceCode" id="cb8"&gt;&lt;pre
676class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb8-1"&gt;&lt;a href="#cb8-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(let_declaration &lt;/span&gt;
429&lt;span id="cb8-2"&gt;&lt;a href="#cb8-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; pattern: (identifier) @my-capture&lt;/span&gt; 677&lt;span id="cb8-2"&gt;&lt;a href="#cb8-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; pattern: (identifier) @my-capture&lt;/span&gt;
430&lt;span id="cb8-3"&gt;&lt;a href="#cb8-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; value: (integer_literal))&lt;/span&gt; 678&lt;span id="cb8-3"&gt;&lt;a href="#cb8-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; value: (integer_literal))&lt;/span&gt;
431&lt;span id="cb8-4"&gt;&lt;a href="#cb8-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;/span&gt; 679&lt;span id="cb8-4"&gt;&lt;a href="#cb8-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;/span&gt;
@@ -435,7 +683,8 @@ H N E I
435&lt;span id="cb8-8"&gt;&lt;a href="#cb8-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; captures:&lt;/span&gt;&lt;/span&gt; 683&lt;span id="cb8-8"&gt;&lt;a href="#cb8-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; captures:&lt;/span&gt;&lt;/span&gt;
436&lt;span id="cb8-9"&gt;&lt;a href="#cb8-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; foo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 684&lt;span id="cb8-9"&gt;&lt;a href="#cb8-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; foo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
437&lt;p&gt;And apply certain &lt;em&gt;predicates&lt;/em&gt; to captures:&lt;/p&gt; 685&lt;p&gt;And apply certain &lt;em&gt;predicates&lt;/em&gt; to captures:&lt;/p&gt;
438&lt;div class="sourceCode" id="cb9"&gt;&lt;pre class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb9-1"&gt;&lt;a href="#cb9-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;((let_declaration&lt;/span&gt; 686&lt;div class="sourceCode" id="cb9"&gt;&lt;pre
687class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb9-1"&gt;&lt;a href="#cb9-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;((let_declaration&lt;/span&gt;
439&lt;span id="cb9-2"&gt;&lt;a href="#cb9-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; pattern: (identifier) @my-capture&lt;/span&gt; 688&lt;span id="cb9-2"&gt;&lt;a href="#cb9-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; pattern: (identifier) @my-capture&lt;/span&gt;
440&lt;span id="cb9-3"&gt;&lt;a href="#cb9-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; value: (integer_literal))&lt;/span&gt; 689&lt;span id="cb9-3"&gt;&lt;a href="#cb9-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; value: (integer_literal))&lt;/span&gt;
441&lt;span id="cb9-4"&gt;&lt;a href="#cb9-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (&lt;span class="sc"&gt;#e&lt;/span&gt;q? @my-capture &lt;span class="st"&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;))&lt;/span&gt; 690&lt;span id="cb9-4"&gt;&lt;a href="#cb9-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (&lt;span class="sc"&gt;#e&lt;/span&gt;q? @my-capture &lt;span class="st"&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;))&lt;/span&gt;
@@ -445,8 +694,10 @@ H N E I
445&lt;span id="cb9-8"&gt;&lt;a href="#cb9-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 694&lt;span id="cb9-8"&gt;&lt;a href="#cb9-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
446&lt;span id="cb9-9"&gt;&lt;a href="#cb9-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; and not:&lt;/span&gt;&lt;/span&gt; 695&lt;span id="cb9-9"&gt;&lt;a href="#cb9-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; and not:&lt;/span&gt;&lt;/span&gt;
447&lt;span id="cb9-10"&gt;&lt;a href="#cb9-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; let bar = 2;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 696&lt;span id="cb9-10"&gt;&lt;a href="#cb9-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; let bar = 2;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
448&lt;p&gt;The &lt;code&gt;#match?&lt;/code&gt; predicate checks if a capture matches a regex:&lt;/p&gt; 697&lt;p&gt;The &lt;code&gt;#match?&lt;/code&gt; predicate checks if a capture matches a
449&lt;div class="sourceCode" id="cb10"&gt;&lt;pre class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb10-1"&gt;&lt;a href="#cb10-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;((let_declaration&lt;/span&gt; 698regex:&lt;/p&gt;
699&lt;div class="sourceCode" id="cb10"&gt;&lt;pre
700class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb10-1"&gt;&lt;a href="#cb10-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;((let_declaration&lt;/span&gt;
450&lt;span id="cb10-2"&gt;&lt;a href="#cb10-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; pattern: (identifier) @my-capture&lt;/span&gt; 701&lt;span id="cb10-2"&gt;&lt;a href="#cb10-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; pattern: (identifier) @my-capture&lt;/span&gt;
451&lt;span id="cb10-3"&gt;&lt;a href="#cb10-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; value: (integer_literal))&lt;/span&gt; 702&lt;span id="cb10-3"&gt;&lt;a href="#cb10-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; value: (integer_literal))&lt;/span&gt;
452&lt;span id="cb10-4"&gt;&lt;a href="#cb10-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (#match? @my-capture &lt;span class="st"&gt;&amp;quot;foo|bar&amp;quot;&lt;/span&gt;))&lt;/span&gt; 703&lt;span id="cb10-4"&gt;&lt;a href="#cb10-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (#match? @my-capture &lt;span class="st"&gt;&amp;quot;foo|bar&amp;quot;&lt;/span&gt;))&lt;/span&gt;
@@ -454,8 +705,10 @@ H N E I
454&lt;span id="cb10-6"&gt;&lt;a href="#cb10-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; matches both `foo` and `bar`:&lt;/span&gt;&lt;/span&gt; 705&lt;span id="cb10-6"&gt;&lt;a href="#cb10-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; matches both `foo` and `bar`:&lt;/span&gt;&lt;/span&gt;
455&lt;span id="cb10-7"&gt;&lt;a href="#cb10-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; let foo = 2;&lt;/span&gt;&lt;/span&gt; 706&lt;span id="cb10-7"&gt;&lt;a href="#cb10-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; let foo = 2;&lt;/span&gt;&lt;/span&gt;
456&lt;span id="cb10-8"&gt;&lt;a href="#cb10-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; let bar = 2;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 707&lt;span id="cb10-8"&gt;&lt;a href="#cb10-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; let bar = 2;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
457&lt;p&gt;Exhibit indifference, as a stoic programmer would, with the &lt;em&gt;wildcard&lt;/em&gt; pattern:&lt;/p&gt; 708&lt;p&gt;Exhibit indifference, as a stoic programmer would, with the
458&lt;div class="sourceCode" id="cb11"&gt;&lt;pre class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb11-1"&gt;&lt;a href="#cb11-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(let_declaration&lt;/span&gt; 709&lt;em&gt;wildcard&lt;/em&gt; pattern:&lt;/p&gt;
710&lt;div class="sourceCode" id="cb11"&gt;&lt;pre
711class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb11-1"&gt;&lt;a href="#cb11-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(let_declaration&lt;/span&gt;
459&lt;span id="cb11-2"&gt;&lt;a href="#cb11-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; pattern: (identifier)&lt;/span&gt; 712&lt;span id="cb11-2"&gt;&lt;a href="#cb11-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; pattern: (identifier)&lt;/span&gt;
460&lt;span id="cb11-3"&gt;&lt;a href="#cb11-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; value: (&lt;span class="op"&gt;_&lt;/span&gt;))&lt;/span&gt; 713&lt;span id="cb11-3"&gt;&lt;a href="#cb11-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; value: (&lt;span class="op"&gt;_&lt;/span&gt;))&lt;/span&gt;
461&lt;span id="cb11-4"&gt;&lt;a href="#cb11-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;/span&gt; 714&lt;span id="cb11-4"&gt;&lt;a href="#cb11-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;/span&gt;
@@ -463,73 +716,106 @@ H N E I
463&lt;span id="cb11-6"&gt;&lt;a href="#cb11-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; let foo = &amp;quot;foo&amp;quot;;&lt;/span&gt;&lt;/span&gt; 716&lt;span id="cb11-6"&gt;&lt;a href="#cb11-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; let foo = &amp;quot;foo&amp;quot;;&lt;/span&gt;&lt;/span&gt;
464&lt;span id="cb11-7"&gt;&lt;a href="#cb11-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; let foo = 42;&lt;/span&gt;&lt;/span&gt; 717&lt;span id="cb11-7"&gt;&lt;a href="#cb11-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; let foo = 42;&lt;/span&gt;&lt;/span&gt;
465&lt;span id="cb11-8"&gt;&lt;a href="#cb11-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; let foo = bar;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 718&lt;span id="cb11-8"&gt;&lt;a href="#cb11-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;; let foo = bar;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
466&lt;p&gt;&lt;a href="https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries"&gt;The documentation&lt;/a&gt; does the tree-sitter query DSL more justice, but we now know enough to write our first lint.&lt;/p&gt; 719&lt;p&gt;&lt;a
720href="https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries"&gt;The
721documentation&lt;/a&gt; does the tree-sitter query DSL more justice, but we
722now know enough to write our first lint.&lt;/p&gt;
467&lt;h3 id="write-you-a-tree-sitter-lint"&gt;Write you a tree-sitter lint&lt;/h3&gt; 723&lt;h3 id="write-you-a-tree-sitter-lint"&gt;Write you a tree-sitter lint&lt;/h3&gt;
468&lt;p&gt;Strings in &lt;code&gt;std::env&lt;/code&gt; functions are error prone:&lt;/p&gt; 724&lt;p&gt;Strings in &lt;code&gt;std::env&lt;/code&gt; functions are error prone:&lt;/p&gt;
469&lt;div class="sourceCode" id="cb12"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb12-1"&gt;&lt;a href="#cb12-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="pp"&gt;std::env::&lt;/span&gt;remove_var(&lt;span class="st"&gt;&amp;quot;RUST_BACKTACE&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 725&lt;div class="sourceCode" id="cb12"&gt;&lt;pre
726class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb12-1"&gt;&lt;a href="#cb12-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="pp"&gt;std::env::&lt;/span&gt;remove_var(&lt;span class="st"&gt;&amp;quot;RUST_BACKTACE&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
470&lt;span id="cb12-2"&gt;&lt;a href="#cb12-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="co"&gt;// ^^^^ &amp;quot;TACE&amp;quot; instead of &amp;quot;TRACE&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 727&lt;span id="cb12-2"&gt;&lt;a href="#cb12-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="co"&gt;// ^^^^ &amp;quot;TACE&amp;quot; instead of &amp;quot;TRACE&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
471&lt;p&gt;I prefer this instead:&lt;/p&gt; 728&lt;p&gt;I prefer this instead:&lt;/p&gt;
472&lt;div class="sourceCode" id="cb13"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb13-1"&gt;&lt;a href="#cb13-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// somewhere in a module that is well spellchecked&lt;/span&gt;&lt;/span&gt; 729&lt;div class="sourceCode" id="cb13"&gt;&lt;pre
730class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb13-1"&gt;&lt;a href="#cb13-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// somewhere in a module that is well spellchecked&lt;/span&gt;&lt;/span&gt;
473&lt;span id="cb13-2"&gt;&lt;a href="#cb13-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;static&lt;/span&gt; BACKTRACE&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="op"&gt;&amp;amp;&lt;/span&gt;&lt;span class="dt"&gt;str&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;RUST_BACKTRACE&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 731&lt;span id="cb13-2"&gt;&lt;a href="#cb13-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;static&lt;/span&gt; BACKTRACE&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="op"&gt;&amp;amp;&lt;/span&gt;&lt;span class="dt"&gt;str&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;RUST_BACKTRACE&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
474&lt;span id="cb13-3"&gt;&lt;a href="#cb13-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 732&lt;span id="cb13-3"&gt;&lt;a href="#cb13-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
475&lt;span id="cb13-4"&gt;&lt;a href="#cb13-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// rest of the codebase&lt;/span&gt;&lt;/span&gt; 733&lt;span id="cb13-4"&gt;&lt;a href="#cb13-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// rest of the codebase&lt;/span&gt;&lt;/span&gt;
476&lt;span id="cb13-5"&gt;&lt;a href="#cb13-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="pp"&gt;std::env::&lt;/span&gt;remove_var(BACKTRACE)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 734&lt;span id="cb13-5"&gt;&lt;a href="#cb13-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="pp"&gt;std::env::&lt;/span&gt;remove_var(BACKTRACE)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
477&lt;p&gt;Let’s write a lint to find &lt;code&gt;std::env&lt;/code&gt; functions that use strings. Put aside the effectiveness of this lint for the moment, and take a stab at writing a tree-sitter query. For reference, a function call like so:&lt;/p&gt; 735&lt;p&gt;Let’s write a lint to find &lt;code&gt;std::env&lt;/code&gt; functions that use
478&lt;div class="sourceCode" id="cb14"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb14-1"&gt;&lt;a href="#cb14-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;remove_var(&lt;span class="st"&gt;&amp;quot;RUST_BACKTRACE&amp;quot;&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 736strings. Put aside the effectiveness of this lint for the moment, and
737take a stab at writing a tree-sitter query. For reference, a function
738call like so:&lt;/p&gt;
739&lt;div class="sourceCode" id="cb14"&gt;&lt;pre
740class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb14-1"&gt;&lt;a href="#cb14-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;remove_var(&lt;span class="st"&gt;&amp;quot;RUST_BACKTRACE&amp;quot;&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
479&lt;p&gt;Produces the following S-expression:&lt;/p&gt; 741&lt;p&gt;Produces the following S-expression:&lt;/p&gt;
480&lt;div class="sourceCode" id="cb15"&gt;&lt;pre class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb15-1"&gt;&lt;a href="#cb15-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(call_expression&lt;/span&gt; 742&lt;div class="sourceCode" id="cb15"&gt;&lt;pre
743class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb15-1"&gt;&lt;a href="#cb15-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(call_expression&lt;/span&gt;
481&lt;span id="cb15-2"&gt;&lt;a href="#cb15-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; function: (identifier)&lt;/span&gt; 744&lt;span id="cb15-2"&gt;&lt;a href="#cb15-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; function: (identifier)&lt;/span&gt;
482&lt;span id="cb15-3"&gt;&lt;a href="#cb15-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; arguments: (arguments (string_literal)))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 745&lt;span id="cb15-3"&gt;&lt;a href="#cb15-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; arguments: (arguments (string_literal)))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
483&lt;p&gt;We are definitely looking for a &lt;code&gt;call_expression&lt;/code&gt;:&lt;/p&gt; 746&lt;p&gt;We are definitely looking for a &lt;code&gt;call_expression&lt;/code&gt;:&lt;/p&gt;
484&lt;div class="sourceCode" id="cb16"&gt;&lt;pre class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb16-1"&gt;&lt;a href="#cb16-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(call_expression) @raise&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 747&lt;div class="sourceCode" id="cb16"&gt;&lt;pre
485&lt;p&gt;Whose function name matches &lt;code&gt;std::env::var&lt;/code&gt; or &lt;code&gt;std::env::remove_var&lt;/code&gt; at the very least (I know, I know, this isn’t the most optimal regex):&lt;/p&gt; 748class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb16-1"&gt;&lt;a href="#cb16-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(call_expression) @raise&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
486&lt;div class="sourceCode" id="cb17"&gt;&lt;pre class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb17-1"&gt;&lt;a href="#cb17-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;((call_expression&lt;/span&gt; 749&lt;p&gt;Whose function name matches &lt;code&gt;std::env::var&lt;/code&gt; or
750&lt;code&gt;std::env::remove_var&lt;/code&gt; at the very least (I know, I know,
751this isn’t the most optimal regex):&lt;/p&gt;
752&lt;div class="sourceCode" id="cb17"&gt;&lt;pre
753class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb17-1"&gt;&lt;a href="#cb17-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;((call_expression&lt;/span&gt;
487&lt;span id="cb17-2"&gt;&lt;a href="#cb17-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; function: (&lt;span class="op"&gt;_&lt;/span&gt;) @fn-name) @raise&lt;/span&gt; 754&lt;span id="cb17-2"&gt;&lt;a href="#cb17-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; function: (&lt;span class="op"&gt;_&lt;/span&gt;) @fn-name) @raise&lt;/span&gt;
488&lt;span id="cb17-3"&gt;&lt;a href="#cb17-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (#match? @fn-name &lt;span class="st"&gt;&amp;quot;std::env::(var|remove_var)&amp;quot;&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 755&lt;span id="cb17-3"&gt;&lt;a href="#cb17-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (#match? @fn-name &lt;span class="st"&gt;&amp;quot;std::env::(var|remove_var)&amp;quot;&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
489&lt;p&gt;Let’s turn that &lt;code&gt;std::&lt;/code&gt; prefix optional:&lt;/p&gt; 756&lt;p&gt;Let’s turn that &lt;code&gt;std::&lt;/code&gt; prefix optional:&lt;/p&gt;
490&lt;div class="sourceCode" id="cb18"&gt;&lt;pre class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb18-1"&gt;&lt;a href="#cb18-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;((call_expression&lt;/span&gt; 757&lt;div class="sourceCode" id="cb18"&gt;&lt;pre
758class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb18-1"&gt;&lt;a href="#cb18-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;((call_expression&lt;/span&gt;
491&lt;span id="cb18-2"&gt;&lt;a href="#cb18-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; function: (&lt;span class="op"&gt;_&lt;/span&gt;) @fn-name) @raise&lt;/span&gt; 759&lt;span id="cb18-2"&gt;&lt;a href="#cb18-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; function: (&lt;span class="op"&gt;_&lt;/span&gt;) @fn-name) @raise&lt;/span&gt;
492&lt;span id="cb18-3"&gt;&lt;a href="#cb18-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (#match? @fn-name &lt;span class="st"&gt;&amp;quot;(std::|)env::(var|remove_var)&amp;quot;&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 760&lt;span id="cb18-3"&gt;&lt;a href="#cb18-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (#match? @fn-name &lt;span class="st"&gt;&amp;quot;(std::|)env::(var|remove_var)&amp;quot;&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
493&lt;p&gt;And ensure that &lt;code&gt;arguments&lt;/code&gt; is a string:&lt;/p&gt; 761&lt;p&gt;And ensure that &lt;code&gt;arguments&lt;/code&gt; is a string:&lt;/p&gt;
494&lt;div class="sourceCode" id="cb19"&gt;&lt;pre class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb19-1"&gt;&lt;a href="#cb19-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;((call_expression&lt;/span&gt; 762&lt;div class="sourceCode" id="cb19"&gt;&lt;pre
763class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb19-1"&gt;&lt;a href="#cb19-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;((call_expression&lt;/span&gt;
495&lt;span id="cb19-2"&gt;&lt;a href="#cb19-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; function: (&lt;span class="op"&gt;_&lt;/span&gt;) @fn-name&lt;/span&gt; 764&lt;span id="cb19-2"&gt;&lt;a href="#cb19-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; function: (&lt;span class="op"&gt;_&lt;/span&gt;) @fn-name&lt;/span&gt;
496&lt;span id="cb19-3"&gt;&lt;a href="#cb19-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; arguments: (arguments (string_literal)))&lt;/span&gt; 765&lt;span id="cb19-3"&gt;&lt;a href="#cb19-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; arguments: (arguments (string_literal)))&lt;/span&gt;
497&lt;span id="cb19-4"&gt;&lt;a href="#cb19-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (#match? @fn-name &lt;span class="st"&gt;&amp;quot;(std::|)env::(var|remove_var)&amp;quot;&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 766&lt;span id="cb19-4"&gt;&lt;a href="#cb19-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (#match? @fn-name &lt;span class="st"&gt;&amp;quot;(std::|)env::(var|remove_var)&amp;quot;&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
498&lt;h3 id="running-our-linter"&gt;Running our linter&lt;/h3&gt; 767&lt;h3 id="running-our-linter"&gt;Running our linter&lt;/h3&gt;
499&lt;p&gt;We could always plug our query into the web playground, but let’s go a step further:&lt;/p&gt; 768&lt;p&gt;We could always plug our query into the web playground, but let’s go
500&lt;div class="sourceCode" id="cb20"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb20-1"&gt;&lt;a href="#cb20-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;cargo&lt;/span&gt; new &lt;span class="at"&gt;--bin&lt;/span&gt; toy-lint&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 769a step further:&lt;/p&gt;
501&lt;p&gt;Add &lt;code&gt;tree-sitter&lt;/code&gt; and &lt;code&gt;tree-sitter-rust&lt;/code&gt; to your dependencies:&lt;/p&gt; 770&lt;div class="sourceCode" id="cb20"&gt;&lt;pre
502&lt;div class="sourceCode" id="cb21"&gt;&lt;pre class="sourceCode toml"&gt;&lt;code class="sourceCode toml"&gt;&lt;span id="cb21-1"&gt;&lt;a href="#cb21-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# within Cargo.toml&lt;/span&gt;&lt;/span&gt; 771class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb20-1"&gt;&lt;a href="#cb20-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;cargo&lt;/span&gt; new &lt;span class="at"&gt;--bin&lt;/span&gt; toy-lint&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
772&lt;p&gt;Add &lt;code&gt;tree-sitter&lt;/code&gt; and &lt;code&gt;tree-sitter-rust&lt;/code&gt; to
773your dependencies:&lt;/p&gt;
774&lt;div class="sourceCode" id="cb21"&gt;&lt;pre
775class="sourceCode toml"&gt;&lt;code class="sourceCode toml"&gt;&lt;span id="cb21-1"&gt;&lt;a href="#cb21-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# within Cargo.toml&lt;/span&gt;&lt;/span&gt;
503&lt;span id="cb21-2"&gt;&lt;a href="#cb21-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;[&lt;/span&gt;&lt;span class="dt"&gt;dependencies&lt;/span&gt;&lt;span class="kw"&gt;]&lt;/span&gt;&lt;/span&gt; 776&lt;span id="cb21-2"&gt;&lt;a href="#cb21-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;[&lt;/span&gt;&lt;span class="dt"&gt;dependencies&lt;/span&gt;&lt;span class="kw"&gt;]&lt;/span&gt;&lt;/span&gt;
504&lt;span id="cb21-3"&gt;&lt;a href="#cb21-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;tree-sitter&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;0.20&amp;quot;&lt;/span&gt;&lt;/span&gt; 777&lt;span id="cb21-3"&gt;&lt;a href="#cb21-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;tree-sitter&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;0.20&amp;quot;&lt;/span&gt;&lt;/span&gt;
505&lt;span id="cb21-4"&gt;&lt;a href="#cb21-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 778&lt;span id="cb21-4"&gt;&lt;a href="#cb21-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
506&lt;span id="cb21-5"&gt;&lt;a href="#cb21-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;[&lt;/span&gt;&lt;span class="dt"&gt;dependencies&lt;/span&gt;&lt;span class="kw"&gt;.&lt;/span&gt;&lt;span class="dt"&gt;tree-sitter-rust&lt;/span&gt;&lt;span class="kw"&gt;]&lt;/span&gt;&lt;/span&gt; 779&lt;span id="cb21-5"&gt;&lt;a href="#cb21-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;[&lt;/span&gt;&lt;span class="dt"&gt;dependencies&lt;/span&gt;&lt;span class="kw"&gt;.&lt;/span&gt;&lt;span class="dt"&gt;tree-sitter-rust&lt;/span&gt;&lt;span class="kw"&gt;]&lt;/span&gt;&lt;/span&gt;
507&lt;span id="cb21-6"&gt;&lt;a href="#cb21-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;git&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://github.com/tree-sitter/tree-sitter-rust&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 780&lt;span id="cb21-6"&gt;&lt;a href="#cb21-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;git&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://github.com/tree-sitter/tree-sitter-rust&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
508&lt;p&gt;Let’s load in some Rust code to work with. As &lt;a href="https://en.wikipedia.org/wiki/Self-reference"&gt;an ode to Gödel&lt;/a&gt; (G&lt;code&gt;ode&lt;/code&gt;l?), why not load in our linter itself:&lt;/p&gt; 781&lt;p&gt;Let’s load in some Rust code to work with. As &lt;a
509&lt;div class="sourceCode" id="cb22"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb22-1"&gt;&lt;a href="#cb22-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; main() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 782href="https://en.wikipedia.org/wiki/Self-reference"&gt;an ode to Gödel&lt;/a&gt;
783(G&lt;code&gt;ode&lt;/code&gt;l?), why not load in our linter itself:&lt;/p&gt;
784&lt;div class="sourceCode" id="cb22"&gt;&lt;pre
785class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb22-1"&gt;&lt;a href="#cb22-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; main() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
510&lt;span id="cb22-2"&gt;&lt;a href="#cb22-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; src &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;include_str!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;main.rs&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 786&lt;span id="cb22-2"&gt;&lt;a href="#cb22-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; src &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;include_str!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;main.rs&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
511&lt;span id="cb22-3"&gt;&lt;a href="#cb22-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 787&lt;span id="cb22-3"&gt;&lt;a href="#cb22-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
512&lt;p&gt;Most tree-sitter APIs require a reference to a &lt;code&gt;Language&lt;/code&gt; struct, we will be working with Rust if you haven’t already guessed:&lt;/p&gt; 788&lt;p&gt;Most tree-sitter APIs require a reference to a &lt;code&gt;Language&lt;/code&gt;
513&lt;div class="sourceCode" id="cb23"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb23-1"&gt;&lt;a href="#cb23-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;tree_sitter::&lt;/span&gt;Language&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 789struct, we will be working with Rust if you haven’t already guessed:&lt;/p&gt;
790&lt;div class="sourceCode" id="cb23"&gt;&lt;pre
791class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb23-1"&gt;&lt;a href="#cb23-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;tree_sitter::&lt;/span&gt;Language&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
514&lt;span id="cb23-2"&gt;&lt;a href="#cb23-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 792&lt;span id="cb23-2"&gt;&lt;a href="#cb23-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
515&lt;span id="cb23-3"&gt;&lt;a href="#cb23-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; rust_lang&lt;span class="op"&gt;:&lt;/span&gt; Language &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;tree_sitter_rust::&lt;/span&gt;language()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 793&lt;span id="cb23-3"&gt;&lt;a href="#cb23-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; rust_lang&lt;span class="op"&gt;:&lt;/span&gt; Language &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;tree_sitter_rust::&lt;/span&gt;language()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
516&lt;p&gt;Enough scaffolding, let’s parse some Rust:&lt;/p&gt; 794&lt;p&gt;Enough scaffolding, let’s parse some Rust:&lt;/p&gt;
517&lt;div class="sourceCode" id="cb24"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb24-1"&gt;&lt;a href="#cb24-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;tree_sitter::&lt;/span&gt;Parser&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 795&lt;div class="sourceCode" id="cb24"&gt;&lt;pre
796class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb24-1"&gt;&lt;a href="#cb24-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;tree_sitter::&lt;/span&gt;Parser&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
518&lt;span id="cb24-2"&gt;&lt;a href="#cb24-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 797&lt;span id="cb24-2"&gt;&lt;a href="#cb24-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
519&lt;span id="cb24-3"&gt;&lt;a href="#cb24-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; &lt;span class="kw"&gt;mut&lt;/span&gt; parser &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;Parser::&lt;/span&gt;new()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 798&lt;span id="cb24-3"&gt;&lt;a href="#cb24-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; &lt;span class="kw"&gt;mut&lt;/span&gt; parser &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;Parser::&lt;/span&gt;new()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
520&lt;span id="cb24-4"&gt;&lt;a href="#cb24-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;parser&lt;span class="op"&gt;.&lt;/span&gt;set_language(rust_lang)&lt;span class="op"&gt;.&lt;/span&gt;unwrap()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 799&lt;span id="cb24-4"&gt;&lt;a href="#cb24-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;parser&lt;span class="op"&gt;.&lt;/span&gt;set_language(rust_lang)&lt;span class="op"&gt;.&lt;/span&gt;unwrap()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
521&lt;span id="cb24-5"&gt;&lt;a href="#cb24-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 800&lt;span id="cb24-5"&gt;&lt;a href="#cb24-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
522&lt;span id="cb24-6"&gt;&lt;a href="#cb24-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; parse_tree &lt;span class="op"&gt;=&lt;/span&gt; parser&lt;span class="op"&gt;.&lt;/span&gt;parse(&lt;span class="op"&gt;&amp;amp;&lt;/span&gt;src&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="cn"&gt;None&lt;/span&gt;)&lt;span class="op"&gt;.&lt;/span&gt;unwrap()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 801&lt;span id="cb24-6"&gt;&lt;a href="#cb24-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; parse_tree &lt;span class="op"&gt;=&lt;/span&gt; parser&lt;span class="op"&gt;.&lt;/span&gt;parse(&lt;span class="op"&gt;&amp;amp;&lt;/span&gt;src&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="cn"&gt;None&lt;/span&gt;)&lt;span class="op"&gt;.&lt;/span&gt;unwrap()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
523&lt;p&gt;The second argument to &lt;code&gt;Parser::parse&lt;/code&gt; may be of interest. Tree-sitter has this cool feature that allows for quick reparsing of existing parse trees if they contain edits. If you do happen to want to reparse a source file, you can pass in the old tree:&lt;/p&gt; 802&lt;p&gt;The second argument to &lt;code&gt;Parser::parse&lt;/code&gt; may be of interest.
524&lt;div class="sourceCode" id="cb25"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb25-1"&gt;&lt;a href="#cb25-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// if you wish to reparse instead of parse&lt;/span&gt;&lt;/span&gt; 803Tree-sitter has this cool feature that allows for quick reparsing of
804existing parse trees if they contain edits. If you do happen to want to
805reparse a source file, you can pass in the old tree:&lt;/p&gt;
806&lt;div class="sourceCode" id="cb25"&gt;&lt;pre
807class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb25-1"&gt;&lt;a href="#cb25-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// if you wish to reparse instead of parse&lt;/span&gt;&lt;/span&gt;
525&lt;span id="cb25-2"&gt;&lt;a href="#cb25-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;old_tree&lt;span class="op"&gt;.&lt;/span&gt;edit(&lt;span class="co"&gt;/* redacted */&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 808&lt;span id="cb25-2"&gt;&lt;a href="#cb25-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;old_tree&lt;span class="op"&gt;.&lt;/span&gt;edit(&lt;span class="co"&gt;/* redacted */&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
526&lt;span id="cb25-3"&gt;&lt;a href="#cb25-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 809&lt;span id="cb25-3"&gt;&lt;a href="#cb25-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
527&lt;span id="cb25-4"&gt;&lt;a href="#cb25-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// generate shiny new reparsed tree&lt;/span&gt;&lt;/span&gt; 810&lt;span id="cb25-4"&gt;&lt;a href="#cb25-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// generate shiny new reparsed tree&lt;/span&gt;&lt;/span&gt;
528&lt;span id="cb25-5"&gt;&lt;a href="#cb25-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; new_tree &lt;span class="op"&gt;=&lt;/span&gt; parser&lt;span class="op"&gt;.&lt;/span&gt;parse(&lt;span class="op"&gt;&amp;amp;&lt;/span&gt;src&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="cn"&gt;Some&lt;/span&gt;(old_tree))&lt;span class="op"&gt;.&lt;/span&gt;unwrap()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 811&lt;span id="cb25-5"&gt;&lt;a href="#cb25-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; new_tree &lt;span class="op"&gt;=&lt;/span&gt; parser&lt;span class="op"&gt;.&lt;/span&gt;parse(&lt;span class="op"&gt;&amp;amp;&lt;/span&gt;src&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="cn"&gt;Some&lt;/span&gt;(old_tree))&lt;span class="op"&gt;.&lt;/span&gt;unwrap()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
529&lt;p&gt;Anyhow (&lt;a href="http://github.com/dtolnay/anyhow"&gt;hah!&lt;/a&gt;), now that we have a parse tree, we can inspect it:&lt;/p&gt; 812&lt;p&gt;Anyhow (&lt;a href="http://github.com/dtolnay/anyhow"&gt;hah!&lt;/a&gt;), now
530&lt;div class="sourceCode" id="cb26"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb26-1"&gt;&lt;a href="#cb26-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="pp"&gt;println!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; parse_tree&lt;span class="op"&gt;.&lt;/span&gt;root_node()&lt;span class="op"&gt;.&lt;/span&gt;to_sexp())&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 813that we have a parse tree, we can inspect it:&lt;/p&gt;
814&lt;div class="sourceCode" id="cb26"&gt;&lt;pre
815class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb26-1"&gt;&lt;a href="#cb26-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="pp"&gt;println!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; parse_tree&lt;span class="op"&gt;.&lt;/span&gt;root_node()&lt;span class="op"&gt;.&lt;/span&gt;to_sexp())&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
531&lt;p&gt;Or better yet, run a query on it:&lt;/p&gt; 816&lt;p&gt;Or better yet, run a query on it:&lt;/p&gt;
532&lt;div class="sourceCode" id="cb27"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb27-1"&gt;&lt;a href="#cb27-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;tree_sitter::&lt;/span&gt;Query&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 817&lt;div class="sourceCode" id="cb27"&gt;&lt;pre
818class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb27-1"&gt;&lt;a href="#cb27-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;tree_sitter::&lt;/span&gt;Query&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
533&lt;span id="cb27-2"&gt;&lt;a href="#cb27-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 819&lt;span id="cb27-2"&gt;&lt;a href="#cb27-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
534&lt;span id="cb27-3"&gt;&lt;a href="#cb27-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; query &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;Query::&lt;/span&gt;new(&lt;/span&gt; 820&lt;span id="cb27-3"&gt;&lt;a href="#cb27-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; query &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;Query::&lt;/span&gt;new(&lt;/span&gt;
535&lt;span id="cb27-4"&gt;&lt;a href="#cb27-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; rust_lang&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt; 821&lt;span id="cb27-4"&gt;&lt;a href="#cb27-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; rust_lang&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
@@ -541,8 +827,11 @@ H N E I
541&lt;span id="cb27-10"&gt;&lt;a href="#cb27-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt; &amp;quot;#&lt;/span&gt;&lt;/span&gt; 827&lt;span id="cb27-10"&gt;&lt;a href="#cb27-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="st"&gt; &amp;quot;#&lt;/span&gt;&lt;/span&gt;
542&lt;span id="cb27-11"&gt;&lt;a href="#cb27-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;)&lt;/span&gt; 828&lt;span id="cb27-11"&gt;&lt;a href="#cb27-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;)&lt;/span&gt;
543&lt;span id="cb27-12"&gt;&lt;a href="#cb27-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;.&lt;/span&gt;unwrap()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 829&lt;span id="cb27-12"&gt;&lt;a href="#cb27-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;.&lt;/span&gt;unwrap()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
544&lt;p&gt;A &lt;code&gt;QueryCursor&lt;/code&gt; is tree-sitter’s way of maintaining state as we iterate through the matches or captures produced by running a query on the parse tree. Observe:&lt;/p&gt; 830&lt;p&gt;A &lt;code&gt;QueryCursor&lt;/code&gt; is tree-sitter’s way of maintaining state
545&lt;div class="sourceCode" id="cb28"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb28-1"&gt;&lt;a href="#cb28-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;tree_sitter::&lt;/span&gt;QueryCursor&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 831as we iterate through the matches or captures produced by running a
832query on the parse tree. Observe:&lt;/p&gt;
833&lt;div class="sourceCode" id="cb28"&gt;&lt;pre
834class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb28-1"&gt;&lt;a href="#cb28-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;tree_sitter::&lt;/span&gt;QueryCursor&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
546&lt;span id="cb28-2"&gt;&lt;a href="#cb28-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 835&lt;span id="cb28-2"&gt;&lt;a href="#cb28-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
547&lt;span id="cb28-3"&gt;&lt;a href="#cb28-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; &lt;span class="kw"&gt;mut&lt;/span&gt; query_cursor &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;QueryCursor::&lt;/span&gt;new()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 836&lt;span id="cb28-3"&gt;&lt;a href="#cb28-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; &lt;span class="kw"&gt;mut&lt;/span&gt; query_cursor &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;QueryCursor::&lt;/span&gt;new()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
548&lt;span id="cb28-4"&gt;&lt;a href="#cb28-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; all_matches &lt;span class="op"&gt;=&lt;/span&gt; query_cursor&lt;span class="op"&gt;.&lt;/span&gt;matches(&lt;/span&gt; 837&lt;span id="cb28-4"&gt;&lt;a href="#cb28-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; all_matches &lt;span class="op"&gt;=&lt;/span&gt; query_cursor&lt;span class="op"&gt;.&lt;/span&gt;matches(&lt;/span&gt;
@@ -550,15 +839,22 @@ H N E I
550&lt;span id="cb28-6"&gt;&lt;a href="#cb28-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; parse_tree&lt;span class="op"&gt;.&lt;/span&gt;root_node()&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt; 839&lt;span id="cb28-6"&gt;&lt;a href="#cb28-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; parse_tree&lt;span class="op"&gt;.&lt;/span&gt;root_node()&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
551&lt;span id="cb28-7"&gt;&lt;a href="#cb28-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; src&lt;span class="op"&gt;.&lt;/span&gt;as_bytes()&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt; 840&lt;span id="cb28-7"&gt;&lt;a href="#cb28-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; src&lt;span class="op"&gt;.&lt;/span&gt;as_bytes()&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
552&lt;span id="cb28-8"&gt;&lt;a href="#cb28-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 841&lt;span id="cb28-8"&gt;&lt;a href="#cb28-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
553&lt;p&gt;We begin by passing our query to the cursor, followed by the “root node”, which is another way of saying, “start from the top”, and lastly, the source itself. If you have already taken a look at the C API, you will notice that the last argument, the source (known as the &lt;code&gt;TextProvider&lt;/code&gt;), is not required. The Rust bindings seem to require this argument to provide predicate functionality such as &lt;code&gt;#match?&lt;/code&gt; and &lt;code&gt;#eq?&lt;/code&gt;.&lt;/p&gt; 842&lt;p&gt;We begin by passing our query to the cursor, followed by the “root
843node”, which is another way of saying, “start from the top”, and lastly,
844the source itself. If you have already taken a look at the C API, you
845will notice that the last argument, the source (known as the
846&lt;code&gt;TextProvider&lt;/code&gt;), is not required. The Rust bindings seem to
847require this argument to provide predicate functionality such as
848&lt;code&gt;#match?&lt;/code&gt; and &lt;code&gt;#eq?&lt;/code&gt;.&lt;/p&gt;
554&lt;p&gt;Do something with the matches:&lt;/p&gt; 849&lt;p&gt;Do something with the matches:&lt;/p&gt;
555&lt;div class="sourceCode" id="cb29"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb29-1"&gt;&lt;a href="#cb29-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// get the index of the capture named &amp;quot;raise&amp;quot;&lt;/span&gt;&lt;/span&gt; 850&lt;div class="sourceCode" id="cb29"&gt;&lt;pre
851class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb29-1"&gt;&lt;a href="#cb29-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// get the index of the capture named &amp;quot;raise&amp;quot;&lt;/span&gt;&lt;/span&gt;
556&lt;span id="cb29-2"&gt;&lt;a href="#cb29-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; raise_idx &lt;span class="op"&gt;=&lt;/span&gt; query&lt;span class="op"&gt;.&lt;/span&gt;capture_index_for_name(&lt;span class="st"&gt;&amp;quot;raise&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;.&lt;/span&gt;unwrap()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 852&lt;span id="cb29-2"&gt;&lt;a href="#cb29-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; raise_idx &lt;span class="op"&gt;=&lt;/span&gt; query&lt;span class="op"&gt;.&lt;/span&gt;capture_index_for_name(&lt;span class="st"&gt;&amp;quot;raise&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;.&lt;/span&gt;unwrap()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
557&lt;span id="cb29-3"&gt;&lt;a href="#cb29-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 853&lt;span id="cb29-3"&gt;&lt;a href="#cb29-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
558&lt;span id="cb29-4"&gt;&lt;a href="#cb29-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;for&lt;/span&gt; each_match &lt;span class="kw"&gt;in&lt;/span&gt; all_matches &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 854&lt;span id="cb29-4"&gt;&lt;a href="#cb29-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;for&lt;/span&gt; each_match &lt;span class="kw"&gt;in&lt;/span&gt; all_matches &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
559&lt;span id="cb29-5"&gt;&lt;a href="#cb29-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="co"&gt;// iterate over all captures called &amp;quot;raise&amp;quot;&lt;/span&gt;&lt;/span&gt; 855&lt;span id="cb29-5"&gt;&lt;a href="#cb29-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="co"&gt;// iterate over all captures called &amp;quot;raise&amp;quot;&lt;/span&gt;&lt;/span&gt;
560&lt;span id="cb29-6"&gt;&lt;a href="#cb29-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="co"&gt;// ignore captures such as &amp;quot;fn-name&amp;quot;&lt;/span&gt;&lt;/span&gt; 856&lt;span id="cb29-6"&gt;&lt;a href="#cb29-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="co"&gt;// ignore captures such as &amp;quot;fn-name&amp;quot;&lt;/span&gt;&lt;/span&gt;
561&lt;span id="cb29-7"&gt;&lt;a href="#cb29-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;for&lt;/span&gt; capture &lt;span class="kw"&gt;in&lt;/span&gt; each_match&lt;/span&gt; 857&lt;span id="cb29-7"&gt;&lt;a href="#cb29-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;for&lt;/span&gt; capture &lt;span class="kw"&gt;in&lt;/span&gt; each_match&lt;/span&gt;
562&lt;span id="cb29-8"&gt;&lt;a href="#cb29-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;.&lt;/span&gt;captures&lt;/span&gt; 858&lt;span id="cb29-8"&gt;&lt;a href="#cb29-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;.&lt;/span&gt;captures&lt;/span&gt;
563&lt;span id="cb29-9"&gt;&lt;a href="#cb29-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;.&lt;/span&gt;iter()&lt;/span&gt; 859&lt;span id="cb29-9"&gt;&lt;a href="#cb29-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;.&lt;/span&gt;iter()&lt;/span&gt;
564&lt;span id="cb29-10"&gt;&lt;a href="#cb29-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;.&lt;/span&gt;filter(&lt;span class="op"&gt;|&lt;/span&gt;c&lt;span class="op"&gt;|&lt;/span&gt; c&lt;span class="op"&gt;.&lt;/span&gt;idx &lt;span class="op"&gt;==&lt;/span&gt; raise_idx)&lt;/span&gt; 860&lt;span id="cb29-10"&gt;&lt;a href="#cb29-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;.&lt;/span&gt;filter(&lt;span class="op"&gt;|&lt;/span&gt;c&lt;span class="op"&gt;|&lt;/span&gt; c&lt;span class="op"&gt;.&lt;/span&gt;idx &lt;span class="op"&gt;==&lt;/span&gt; raise_idx)&lt;/span&gt;
@@ -573,8 +869,10 @@ H N E I
573&lt;span id="cb29-19"&gt;&lt;a href="#cb29-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; )&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 869&lt;span id="cb29-19"&gt;&lt;a href="#cb29-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; )&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
574&lt;span id="cb29-20"&gt;&lt;a href="#cb29-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 870&lt;span id="cb29-20"&gt;&lt;a href="#cb29-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
575&lt;span id="cb29-21"&gt;&lt;a href="#cb29-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 871&lt;span id="cb29-21"&gt;&lt;a href="#cb29-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
576&lt;p&gt;Lastly, add the following line to your source code, to get the linter to catch something:&lt;/p&gt; 872&lt;p&gt;Lastly, add the following line to your source code, to get the linter
577&lt;div class="sourceCode" id="cb30"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb30-1"&gt;&lt;a href="#cb30-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="pp"&gt;env::&lt;/span&gt;remove_var(&lt;span class="st"&gt;&amp;quot;RUST_BACKTRACE&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 873to catch something:&lt;/p&gt;
874&lt;div class="sourceCode" id="cb30"&gt;&lt;pre
875class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb30-1"&gt;&lt;a href="#cb30-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="pp"&gt;env::&lt;/span&gt;remove_var(&lt;span class="st"&gt;&amp;quot;RUST_BACKTRACE&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
578&lt;p&gt;And &lt;code&gt;cargo run&lt;/code&gt;:&lt;/p&gt; 876&lt;p&gt;And &lt;code&gt;cargo run&lt;/code&gt;:&lt;/p&gt;
579&lt;pre class="shell"&gt;&lt;code&gt;λ cargo run 877&lt;pre class="shell"&gt;&lt;code&gt;λ cargo run
580 Compiling toy-lint v0.1.0 (/redacted/path/to/toy-lint) 878 Compiling toy-lint v0.1.0 (/redacted/path/to/toy-lint)
@@ -583,17 +881,33 @@ H N E I
583[Line: 40, Col: 4] Offending source code: `env::remove_var(&amp;quot;RUST_BACKTRACE&amp;quot;)`&lt;/code&gt;&lt;/pre&gt; 881[Line: 40, Col: 4] Offending source code: `env::remove_var(&amp;quot;RUST_BACKTRACE&amp;quot;)`&lt;/code&gt;&lt;/pre&gt;
584&lt;p&gt;Thank you tree-sitter!&lt;/p&gt; 882&lt;p&gt;Thank you tree-sitter!&lt;/p&gt;
585&lt;h3 id="bonus"&gt;Bonus&lt;/h3&gt; 883&lt;h3 id="bonus"&gt;Bonus&lt;/h3&gt;
586&lt;p&gt;Keen readers will notice that I avoided &lt;code&gt;std::env::set_var&lt;/code&gt;. Because &lt;code&gt;set_var&lt;/code&gt; is called with two arguments, a “key” and a “value”, unlike &lt;code&gt;env::var&lt;/code&gt; and &lt;code&gt;env::remove_var&lt;/code&gt;. As a result, it requires more juggling:&lt;/p&gt; 884&lt;p&gt;Keen readers will notice that I avoided
587&lt;div class="sourceCode" id="cb32"&gt;&lt;pre class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb32-1"&gt;&lt;a href="#cb32-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;((call_expression&lt;/span&gt; 885&lt;code&gt;std::env::set_var&lt;/code&gt;. Because &lt;code&gt;set_var&lt;/code&gt; is called
886with two arguments, a “key” and a “value”, unlike &lt;code&gt;env::var&lt;/code&gt;
887and &lt;code&gt;env::remove_var&lt;/code&gt;. As a result, it requires more
888juggling:&lt;/p&gt;
889&lt;div class="sourceCode" id="cb32"&gt;&lt;pre
890class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb32-1"&gt;&lt;a href="#cb32-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;((call_expression&lt;/span&gt;
588&lt;span id="cb32-2"&gt;&lt;a href="#cb32-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; function: (&lt;span class="op"&gt;_&lt;/span&gt;) @fn-name&lt;/span&gt; 891&lt;span id="cb32-2"&gt;&lt;a href="#cb32-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; function: (&lt;span class="op"&gt;_&lt;/span&gt;) @fn-name&lt;/span&gt;
589&lt;span id="cb32-3"&gt;&lt;a href="#cb32-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; arguments: (arguments &lt;span class="op"&gt;.&lt;/span&gt; (string_literal)&lt;span class="op"&gt;?&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; (string_literal) &lt;span class="op"&gt;.&lt;/span&gt;)) @raise&lt;/span&gt; 892&lt;span id="cb32-3"&gt;&lt;a href="#cb32-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; arguments: (arguments &lt;span class="op"&gt;.&lt;/span&gt; (string_literal)&lt;span class="op"&gt;?&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; (string_literal) &lt;span class="op"&gt;.&lt;/span&gt;)) @raise&lt;/span&gt;
590&lt;span id="cb32-4"&gt;&lt;a href="#cb32-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (#match? @fn-name &lt;span class="st"&gt;&amp;quot;(std::|)env::(var|remove_var|set_var)&amp;quot;&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 893&lt;span id="cb32-4"&gt;&lt;a href="#cb32-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (#match? @fn-name &lt;span class="st"&gt;&amp;quot;(std::|)env::(var|remove_var|set_var)&amp;quot;&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
591&lt;p&gt;The interesting part of this query is the humble &lt;code&gt;.&lt;/code&gt;, the &lt;em&gt;anchor&lt;/em&gt; operator. Anchors help constrain child nodes in certain ways. In this case, it ensures that we match exactly two &lt;code&gt;string_literal&lt;/code&gt;s who are siblings or exactly one &lt;code&gt;string_literal&lt;/code&gt; with no siblings. Unfortunately, this query also matches the following invalid Rust code:&lt;/p&gt; 894&lt;p&gt;The interesting part of this query is the humble &lt;code&gt;.&lt;/code&gt;, the
592&lt;div class="sourceCode" id="cb33"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb33-1"&gt;&lt;a href="#cb33-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// remove_var accepts only 1 arg!&lt;/span&gt;&lt;/span&gt; 895&lt;em&gt;anchor&lt;/em&gt; operator. Anchors help constrain child nodes in certain
896ways. In this case, it ensures that we match exactly two
897&lt;code&gt;string_literal&lt;/code&gt;s who are siblings or exactly one
898&lt;code&gt;string_literal&lt;/code&gt; with no siblings. Unfortunately, this query
899also matches the following invalid Rust code:&lt;/p&gt;
900&lt;div class="sourceCode" id="cb33"&gt;&lt;pre
901class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb33-1"&gt;&lt;a href="#cb33-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// remove_var accepts only 1 arg!&lt;/span&gt;&lt;/span&gt;
593&lt;span id="cb33-2"&gt;&lt;a href="#cb33-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="pp"&gt;std::env::&lt;/span&gt;remove_var(&lt;span class="st"&gt;&amp;quot;RUST_BACKTRACE&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 902&lt;span id="cb33-2"&gt;&lt;a href="#cb33-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="pp"&gt;std::env::&lt;/span&gt;remove_var(&lt;span class="st"&gt;&amp;quot;RUST_BACKTRACE&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
594&lt;h3 id="notes"&gt;Notes&lt;/h3&gt; 903&lt;h3 id="notes"&gt;Notes&lt;/h3&gt;
595&lt;p&gt;All-in-all, the query DSL does a great job in lowering the bar to writing language tools. The knowledge gained from mastering the query DSL can be applied to other languages that have tree-sitter grammars too. This query detects &lt;code&gt;to_json&lt;/code&gt; methods that do not accept additional arguments, in Ruby:&lt;/p&gt; 904&lt;p&gt;All-in-all, the query DSL does a great job in lowering the bar to
596&lt;div class="sourceCode" id="cb34"&gt;&lt;pre class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb34-1"&gt;&lt;a href="#cb34-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;((method&lt;/span&gt; 905writing language tools. The knowledge gained from mastering the query
906DSL can be applied to other languages that have tree-sitter grammars
907too. This query detects &lt;code&gt;to_json&lt;/code&gt; methods that do not accept
908additional arguments, in Ruby:&lt;/p&gt;
909&lt;div class="sourceCode" id="cb34"&gt;&lt;pre
910class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb34-1"&gt;&lt;a href="#cb34-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;((method&lt;/span&gt;
597&lt;span id="cb34-2"&gt;&lt;a href="#cb34-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; name: (identifier) @fn&lt;/span&gt; 911&lt;span id="cb34-2"&gt;&lt;a href="#cb34-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; name: (identifier) @fn&lt;/span&gt;
598&lt;span id="cb34-3"&gt;&lt;a href="#cb34-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; !parameters)&lt;/span&gt; 912&lt;span id="cb34-3"&gt;&lt;a href="#cb34-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; !parameters)&lt;/span&gt;
599&lt;span id="cb34-4"&gt;&lt;a href="#cb34-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (&lt;span class="sc"&gt;#i&lt;/span&gt;s? @fn &lt;span class="st"&gt;&amp;quot;to_json&amp;quot;&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description> 913&lt;span id="cb34-4"&gt;&lt;a href="#cb34-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (&lt;span class="sc"&gt;#i&lt;/span&gt;s? @fn &lt;span class="st"&gt;&amp;quot;to_json&amp;quot;&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
@@ -603,13 +917,25 @@ H N E I
603</item> 917</item>
604<item> 918<item>
605<title>Novice Nix: Flake Templates</title> 919<title>Novice Nix: Flake Templates</title>
606<description>&lt;p&gt;Flakes are very handy to setup entirely pure, project-specific dependencies (not just dependencies, but build steps, shell environments and more) in a declarative way. Writing Flake expressions can get repetitive though, oftentimes, you’d much rather start off with a skeleton. Luckily, &lt;code&gt;nix&lt;/code&gt; already supports templates!&lt;/p&gt; 920<description>&lt;p&gt;Flakes are very handy to setup entirely pure, project-specific
607&lt;p&gt;You might already be familiar with &lt;code&gt;nix flake init&lt;/code&gt;, that drops a “default” flake expression into your current working directory. If you head over to the manpage:&lt;/p&gt; 921dependencies (not just dependencies, but build steps, shell environments
608&lt;div class="sourceCode" id="cb1"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;nix&lt;/span&gt; flake init &lt;span class="at"&gt;--help&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 922and more) in a declarative way. Writing Flake expressions can get
609&lt;p&gt;You will read that &lt;code&gt;nix flake init&lt;/code&gt; creates a flake using the “default template”. Additionally, you can create a flake from a specific template by passing the &lt;code&gt;-t&lt;/code&gt; flag. Where does this default originate from?&lt;/p&gt; 923repetitive though, oftentimes, you’d much rather start off with a
924skeleton. Luckily, &lt;code&gt;nix&lt;/code&gt; already supports templates!&lt;/p&gt;
925&lt;p&gt;You might already be familiar with &lt;code&gt;nix flake init&lt;/code&gt;, that
926drops a “default” flake expression into your current working directory.
927If you head over to the manpage:&lt;/p&gt;
928&lt;div class="sourceCode" id="cb1"&gt;&lt;pre
929class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;nix&lt;/span&gt; flake init &lt;span class="at"&gt;--help&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
930&lt;p&gt;You will read that &lt;code&gt;nix flake init&lt;/code&gt; creates a flake using
931the “default template”. Additionally, you can create a flake from a
932specific template by passing the &lt;code&gt;-t&lt;/code&gt; flag. Where does this
933default originate from?&lt;/p&gt;
610&lt;h2 id="flake-registries"&gt;Flake Registries&lt;/h2&gt; 934&lt;h2 id="flake-registries"&gt;Flake Registries&lt;/h2&gt;
611&lt;p&gt;Quick detour into registries! Registries are a way to alias popular flakes using identifiers:&lt;/p&gt; 935&lt;p&gt;Quick detour into registries! Registries are a way to alias popular
612&lt;div class="sourceCode" id="cb2"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# list a few predefined registries&lt;/span&gt;&lt;/span&gt; 936flakes using identifiers:&lt;/p&gt;
937&lt;div class="sourceCode" id="cb2"&gt;&lt;pre
938class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# list a few predefined registries&lt;/span&gt;&lt;/span&gt;
613&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix registry list&lt;/span&gt; 939&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix registry list&lt;/span&gt;
614&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;.&lt;/span&gt; . . &lt;/span&gt; 940&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;.&lt;/span&gt; . . &lt;/span&gt;
615&lt;span id="cb2-4"&gt;&lt;a href="#cb2-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;global&lt;/span&gt; flake:nixpkgs github:NixOS/nixpkgs&lt;/span&gt; 941&lt;span id="cb2-4"&gt;&lt;a href="#cb2-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;global&lt;/span&gt; flake:nixpkgs github:NixOS/nixpkgs&lt;/span&gt;
@@ -627,8 +953,11 @@ H N E I
627&lt;span id="cb2-16"&gt;&lt;a href="#cb2-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 953&lt;span id="cb2-16"&gt;&lt;a href="#cb2-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
628&lt;span id="cb2-17"&gt;&lt;a href="#cb2-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# which is short for&lt;/span&gt;&lt;/span&gt; 954&lt;span id="cb2-17"&gt;&lt;a href="#cb2-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# which is short for&lt;/span&gt;&lt;/span&gt;
629&lt;span id="cb2-18"&gt;&lt;a href="#cb2-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake show git+https://github.com/tweag/nickel&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 955&lt;span id="cb2-18"&gt;&lt;a href="#cb2-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake show git+https://github.com/tweag/nickel&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
630&lt;p&gt;You might notice a registry called &lt;code&gt;templates&lt;/code&gt; aliased to &lt;code&gt;github:NixOS/templates&lt;/code&gt;. Take a peek with &lt;code&gt;nix flake show&lt;/code&gt;:&lt;/p&gt; 956&lt;p&gt;You might notice a registry called &lt;code&gt;templates&lt;/code&gt; aliased to
631&lt;div class="sourceCode" id="cb3"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake show templates&lt;/span&gt; 957&lt;code&gt;github:NixOS/templates&lt;/code&gt;. Take a peek with
958&lt;code&gt;nix flake show&lt;/code&gt;:&lt;/p&gt;
959&lt;div class="sourceCode" id="cb3"&gt;&lt;pre
960class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake show templates&lt;/span&gt;
632&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;github:NixOS/templates/79f48a7b822f35c068c5e235da2e9fbd154cecee&lt;/span&gt;&lt;/span&gt; 961&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;github:NixOS/templates/79f48a7b822f35c068c5e235da2e9fbd154cecee&lt;/span&gt;&lt;/span&gt;
633&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;├───defaultTemplate:&lt;/span&gt; template: A very basic flake&lt;/span&gt; 962&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;├───defaultTemplate:&lt;/span&gt; template: A very basic flake&lt;/span&gt;
634&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;└───templates&lt;/span&gt;&lt;/span&gt; 963&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;└───templates&lt;/span&gt;&lt;/span&gt;
@@ -637,8 +966,12 @@ H N E I
637&lt;span id="cb3-7"&gt;&lt;a href="#cb3-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;├───rust-web-server:&lt;/span&gt; template: A Rust web server including a NixOS module&lt;/span&gt; 966&lt;span id="cb3-7"&gt;&lt;a href="#cb3-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;├───rust-web-server:&lt;/span&gt; template: A Rust web server including a NixOS module&lt;/span&gt;
638&lt;span id="cb3-8"&gt;&lt;a href="#cb3-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;├───simpleContainer:&lt;/span&gt; template: A NixOS container running apache-httpd&lt;/span&gt; 967&lt;span id="cb3-8"&gt;&lt;a href="#cb3-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;├───simpleContainer:&lt;/span&gt; template: A NixOS container running apache-httpd&lt;/span&gt;
639&lt;span id="cb3-9"&gt;&lt;a href="#cb3-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;└───trivial:&lt;/span&gt; template: A very basic flake&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 968&lt;span id="cb3-9"&gt;&lt;a href="#cb3-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;└───trivial:&lt;/span&gt; template: A very basic flake&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
640&lt;p&gt;Aha! There is a flake output called &lt;code&gt;defaultTemplate&lt;/code&gt;. This is the template being sourced when you run &lt;code&gt;nix flake init&lt;/code&gt;. Astute readers may conclude the following:&lt;/p&gt; 969&lt;p&gt;Aha! There is a flake output called &lt;code&gt;defaultTemplate&lt;/code&gt;.
641&lt;div class="sourceCode" id="cb4"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb4-1"&gt;&lt;a href="#cb4-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake init&lt;/span&gt; 970This is the template being sourced when you run
971&lt;code&gt;nix flake init&lt;/code&gt;. Astute readers may conclude the
972following:&lt;/p&gt;
973&lt;div class="sourceCode" id="cb4"&gt;&lt;pre
974class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb4-1"&gt;&lt;a href="#cb4-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake init&lt;/span&gt;
642&lt;span id="cb4-2"&gt;&lt;a href="#cb4-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 975&lt;span id="cb4-2"&gt;&lt;a href="#cb4-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
643&lt;span id="cb4-3"&gt;&lt;a href="#cb4-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# is equivalent to&lt;/span&gt;&lt;/span&gt; 976&lt;span id="cb4-3"&gt;&lt;a href="#cb4-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# is equivalent to&lt;/span&gt;&lt;/span&gt;
644&lt;span id="cb4-4"&gt;&lt;a href="#cb4-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake init &lt;span class="at"&gt;-t&lt;/span&gt; templates#defaultTemplate&lt;/span&gt; 977&lt;span id="cb4-4"&gt;&lt;a href="#cb4-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake init &lt;span class="at"&gt;-t&lt;/span&gt; templates#defaultTemplate&lt;/span&gt;
@@ -649,7 +982,8 @@ H N E I
649&lt;span id="cb4-9"&gt;&lt;a href="#cb4-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# which is short for&lt;/span&gt;&lt;/span&gt; 982&lt;span id="cb4-9"&gt;&lt;a href="#cb4-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# which is short for&lt;/span&gt;&lt;/span&gt;
650&lt;span id="cb4-10"&gt;&lt;a href="#cb4-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake init &lt;span class="at"&gt;-t&lt;/span&gt; git+https://github.com/NixOS/templates#defaultTemplate&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 983&lt;span id="cb4-10"&gt;&lt;a href="#cb4-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake init &lt;span class="at"&gt;-t&lt;/span&gt; git+https://github.com/NixOS/templates#defaultTemplate&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
651&lt;p&gt;Similarly, the other templates can be accessed via:&lt;/p&gt; 984&lt;p&gt;Similarly, the other templates can be accessed via:&lt;/p&gt;
652&lt;div class="sourceCode" id="cb5"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb5-1"&gt;&lt;a href="#cb5-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake init &lt;span class="at"&gt;-t&lt;/span&gt; templates#c-hello&lt;/span&gt; 985&lt;div class="sourceCode" id="cb5"&gt;&lt;pre
986class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb5-1"&gt;&lt;a href="#cb5-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake init &lt;span class="at"&gt;-t&lt;/span&gt; templates#c-hello&lt;/span&gt;
653&lt;span id="cb5-2"&gt;&lt;a href="#cb5-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake init &lt;span class="at"&gt;-t&lt;/span&gt; templates#simpleContainer&lt;/span&gt; 987&lt;span id="cb5-2"&gt;&lt;a href="#cb5-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake init &lt;span class="at"&gt;-t&lt;/span&gt; templates#simpleContainer&lt;/span&gt;
654&lt;span id="cb5-3"&gt;&lt;a href="#cb5-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# I think you get the drift ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 988&lt;span id="cb5-3"&gt;&lt;a href="#cb5-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# I think you get the drift ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
655&lt;h2 id="rolling-your-own-templates"&gt;Rolling your own templates&lt;/h2&gt; 989&lt;h2 id="rolling-your-own-templates"&gt;Rolling your own templates&lt;/h2&gt;
@@ -657,38 +991,52 @@ H N E I
657&lt;ul&gt; 991&lt;ul&gt;
658&lt;li&gt;create a flake with a &lt;code&gt;templates&lt;/code&gt; output&lt;/li&gt; 992&lt;li&gt;create a flake with a &lt;code&gt;templates&lt;/code&gt; output&lt;/li&gt;
659&lt;li&gt;populate our template directories with content&lt;/li&gt; 993&lt;li&gt;populate our template directories with content&lt;/li&gt;
660&lt;li&gt;(&lt;strong&gt;optionally&lt;/strong&gt;) alias our custom templates flake to an identifier using registries, for easier access&lt;/li&gt; 994&lt;li&gt;(&lt;strong&gt;optionally&lt;/strong&gt;) alias our custom templates flake to an
995identifier using registries, for easier access&lt;/li&gt;
661&lt;/ul&gt; 996&lt;/ul&gt;
662&lt;p&gt;Start off by creating a directory to store your templates in (we will be converting this to a registry later):&lt;/p&gt; 997&lt;p&gt;Start off by creating a directory to store your templates in (we will
663&lt;div class="sourceCode" id="cb6"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb6-1"&gt;&lt;a href="#cb6-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; mkdir ~/mytemplates&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 998be converting this to a registry later):&lt;/p&gt;
664&lt;p&gt;A flake that exposes a “template” as its output looks something like this:&lt;/p&gt; 999&lt;div class="sourceCode" id="cb6"&gt;&lt;pre
665&lt;div class="sourceCode" id="cb7"&gt;&lt;pre class="sourceCode nix"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb7-1"&gt;&lt;a href="#cb7-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# inside ~/mytemplates/flake.nix&lt;/span&gt;&lt;/span&gt; 1000class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb6-1"&gt;&lt;a href="#cb6-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; mkdir ~/mytemplates&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1001&lt;p&gt;A flake that exposes a “template” as its output looks something like
1002this:&lt;/p&gt;
1003&lt;div class="sourceCode" id="cb7"&gt;&lt;pre
1004class="sourceCode nix"&gt;&lt;code class="sourceCode nix"&gt;&lt;span id="cb7-1"&gt;&lt;a href="#cb7-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# inside ~/mytemplates/flake.nix&lt;/span&gt;&lt;/span&gt;
666&lt;span id="cb7-2"&gt;&lt;a href="#cb7-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 1005&lt;span id="cb7-2"&gt;&lt;a href="#cb7-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
667&lt;span id="cb7-3"&gt;&lt;a href="#cb7-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;{&lt;/span&gt;&lt;/span&gt; 1006&lt;span id="cb7-3"&gt;&lt;a href="#cb7-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
668&lt;span id="cb7-4"&gt;&lt;a href="#cb7-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;description&lt;/span&gt; = &lt;span class="st"&gt;&amp;quot;Pepper&amp;#39;s flake templates&amp;quot;&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt;&lt;/span&gt; 1007&lt;span id="cb7-4"&gt;&lt;a href="#cb7-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;description&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Pepper&amp;#39;s flake templates&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
669&lt;span id="cb7-5"&gt;&lt;a href="#cb7-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 1008&lt;span id="cb7-5"&gt;&lt;a href="#cb7-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
670&lt;span id="cb7-6"&gt;&lt;a href="#cb7-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;outputs&lt;/span&gt; = { self, ... }: {&lt;/span&gt; 1009&lt;span id="cb7-6"&gt;&lt;a href="#cb7-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;outputs&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="va"&gt;self&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;: &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
671&lt;span id="cb7-7"&gt;&lt;a href="#cb7-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;templates&lt;/span&gt; = {&lt;/span&gt; 1010&lt;span id="cb7-7"&gt;&lt;a href="#cb7-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;templates&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
672&lt;span id="cb7-8"&gt;&lt;a href="#cb7-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;latex-report&lt;/span&gt; = {&lt;/span&gt; 1011&lt;span id="cb7-8"&gt;&lt;a href="#cb7-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;latex-report&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
673&lt;span id="cb7-9"&gt;&lt;a href="#cb7-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;path&lt;/span&gt; = ./latex-report-template&lt;span class="kw"&gt;;&lt;/span&gt;&lt;/span&gt; 1012&lt;span id="cb7-9"&gt;&lt;a href="#cb7-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;path&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;./latex-report-template&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
674&lt;span id="cb7-10"&gt;&lt;a href="#cb7-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;description&lt;/span&gt; = &lt;span class="st"&gt;&amp;quot;A latex whitepaper project&amp;quot;&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt;&lt;/span&gt; 1013&lt;span id="cb7-10"&gt;&lt;a href="#cb7-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;description&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;A latex whitepaper project&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
675&lt;span id="cb7-11"&gt;&lt;a href="#cb7-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;};&lt;/span&gt;&lt;/span&gt; 1014&lt;span id="cb7-11"&gt;&lt;a href="#cb7-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt;
676&lt;span id="cb7-12"&gt;&lt;a href="#cb7-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;rust-hello&lt;/span&gt; = {&lt;/span&gt; 1015&lt;span id="cb7-12"&gt;&lt;a href="#cb7-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;rust-hello&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
677&lt;span id="cb7-13"&gt;&lt;a href="#cb7-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;path&lt;/span&gt; = ./rust-hello-template&lt;span class="kw"&gt;;&lt;/span&gt;&lt;/span&gt; 1016&lt;span id="cb7-13"&gt;&lt;a href="#cb7-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;path&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;./rust-hello-template&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
678&lt;span id="cb7-14"&gt;&lt;a href="#cb7-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;description&lt;/span&gt; = &lt;span class="st"&gt;&amp;quot;Simple Hello World in Rust&amp;quot;&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt;&lt;/span&gt; 1017&lt;span id="cb7-14"&gt;&lt;a href="#cb7-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;description&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Simple Hello World in Rust&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
679&lt;span id="cb7-15"&gt;&lt;a href="#cb7-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="er"&gt;}&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt;&lt;/span&gt; 1018&lt;span id="cb7-15"&gt;&lt;a href="#cb7-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt;
680&lt;span id="cb7-16"&gt;&lt;a href="#cb7-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="er"&gt;}&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt;&lt;/span&gt; 1019&lt;span id="cb7-16"&gt;&lt;a href="#cb7-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt;
681&lt;span id="cb7-17"&gt;&lt;a href="#cb7-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="er"&gt;}&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt;&lt;/span&gt; 1020&lt;span id="cb7-17"&gt;&lt;a href="#cb7-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt;
682&lt;span id="cb7-18"&gt;&lt;a href="#cb7-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="er"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1021&lt;span id="cb7-18"&gt;&lt;a href="#cb7-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
683&lt;p&gt;The &lt;code&gt;path&lt;/code&gt; attribute to each template is what gets copied over when you initialize a flake. Running &lt;code&gt;nix flake init -t .#latex-report&lt;/code&gt; will initialize the current directory with the contents of &lt;code&gt;./latex-report-template&lt;/code&gt; (we are yet to populate these directories).&lt;/p&gt; 1022&lt;p&gt;The &lt;code&gt;path&lt;/code&gt; attribute to each template is what gets copied
684&lt;p&gt;The output of &lt;code&gt;nix flake show&lt;/code&gt; should be something like:&lt;/p&gt; 1023over when you initialize a flake. Running
685&lt;div class="sourceCode" id="cb8"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb8-1"&gt;&lt;a href="#cb8-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake show&lt;/span&gt; 1024&lt;code&gt;nix flake init -t .#latex-report&lt;/code&gt; will initialize the
1025current directory with the contents of
1026&lt;code&gt;./latex-report-template&lt;/code&gt; (we are yet to populate these
1027directories).&lt;/p&gt;
1028&lt;p&gt;The output of &lt;code&gt;nix flake show&lt;/code&gt; should be something
1029like:&lt;/p&gt;
1030&lt;div class="sourceCode" id="cb8"&gt;&lt;pre
1031class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb8-1"&gt;&lt;a href="#cb8-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake show&lt;/span&gt;
686&lt;span id="cb8-2"&gt;&lt;a href="#cb8-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;path:/home/np/code/nix-stuff/template-tests?narHash=sha256-{...}&lt;/span&gt;&lt;/span&gt; 1032&lt;span id="cb8-2"&gt;&lt;a href="#cb8-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;path:/home/np/code/nix-stuff/template-tests?narHash=sha256-{...}&lt;/span&gt;&lt;/span&gt;
687&lt;span id="cb8-3"&gt;&lt;a href="#cb8-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;└───templates&lt;/span&gt;&lt;/span&gt; 1033&lt;span id="cb8-3"&gt;&lt;a href="#cb8-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;└───templates&lt;/span&gt;&lt;/span&gt;
688&lt;span id="cb8-4"&gt;&lt;a href="#cb8-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;├───latex-report:&lt;/span&gt; template: A latex whitepaper project&lt;/span&gt; 1034&lt;span id="cb8-4"&gt;&lt;a href="#cb8-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;├───latex-report:&lt;/span&gt; template: A latex whitepaper project&lt;/span&gt;
689&lt;span id="cb8-5"&gt;&lt;a href="#cb8-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;└───rust-hello:&lt;/span&gt; template: Simple Hello World in Rust&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1035&lt;span id="cb8-5"&gt;&lt;a href="#cb8-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;└───rust-hello:&lt;/span&gt; template: Simple Hello World in Rust&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
690&lt;p&gt;Populate your template directories with content, here are my template directories for example:&lt;/p&gt; 1036&lt;p&gt;Populate your template directories with content, here are my template
691&lt;div class="sourceCode" id="cb9"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb9-1"&gt;&lt;a href="#cb9-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; tree mytemplates&lt;/span&gt; 1037directories for example:&lt;/p&gt;
1038&lt;div class="sourceCode" id="cb9"&gt;&lt;pre
1039class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb9-1"&gt;&lt;a href="#cb9-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; tree mytemplates&lt;/span&gt;
692&lt;span id="cb9-2"&gt;&lt;a href="#cb9-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;mytemplates/&lt;/span&gt;&lt;/span&gt; 1040&lt;span id="cb9-2"&gt;&lt;a href="#cb9-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;mytemplates/&lt;/span&gt;&lt;/span&gt;
693&lt;span id="cb9-3"&gt;&lt;a href="#cb9-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;├──&lt;/span&gt; flake.nix&lt;/span&gt; 1041&lt;span id="cb9-3"&gt;&lt;a href="#cb9-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;├──&lt;/span&gt; flake.nix&lt;/span&gt;
694&lt;span id="cb9-4"&gt;&lt;a href="#cb9-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;├──&lt;/span&gt; latex-report-template&lt;/span&gt; 1042&lt;span id="cb9-4"&gt;&lt;a href="#cb9-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;├──&lt;/span&gt; latex-report-template&lt;/span&gt;
@@ -703,15 +1051,18 @@ H N E I
703&lt;span id="cb9-13"&gt;&lt;a href="#cb9-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;└──&lt;/span&gt; src&lt;/span&gt; 1051&lt;span id="cb9-13"&gt;&lt;a href="#cb9-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;└──&lt;/span&gt; src&lt;/span&gt;
704&lt;span id="cb9-14"&gt;&lt;a href="#cb9-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;└──&lt;/span&gt; main.rs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1052&lt;span id="cb9-14"&gt;&lt;a href="#cb9-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;└──&lt;/span&gt; main.rs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
705&lt;p&gt;And that’s it! Start using your templates with:&lt;/p&gt; 1053&lt;p&gt;And that’s it! Start using your templates with:&lt;/p&gt;
706&lt;div class="sourceCode" id="cb10"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb10-1"&gt;&lt;a href="#cb10-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake init &lt;span class="at"&gt;-t&lt;/span&gt; ~/mytemplates#rust-hello&lt;/span&gt; 1054&lt;div class="sourceCode" id="cb10"&gt;&lt;pre
1055class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb10-1"&gt;&lt;a href="#cb10-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake init &lt;span class="at"&gt;-t&lt;/span&gt; ~/mytemplates#rust-hello&lt;/span&gt;
707&lt;span id="cb10-2"&gt;&lt;a href="#cb10-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; tree .&lt;/span&gt; 1056&lt;span id="cb10-2"&gt;&lt;a href="#cb10-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; tree .&lt;/span&gt;
708&lt;span id="cb10-3"&gt;&lt;a href="#cb10-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;.&lt;/span&gt;&lt;/span&gt; 1057&lt;span id="cb10-3"&gt;&lt;a href="#cb10-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;.&lt;/span&gt;&lt;/span&gt;
709&lt;span id="cb10-4"&gt;&lt;a href="#cb10-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;├──&lt;/span&gt; Cargo.toml&lt;/span&gt; 1058&lt;span id="cb10-4"&gt;&lt;a href="#cb10-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;├──&lt;/span&gt; Cargo.toml&lt;/span&gt;
710&lt;span id="cb10-5"&gt;&lt;a href="#cb10-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;├──&lt;/span&gt; flake.nix&lt;/span&gt; 1059&lt;span id="cb10-5"&gt;&lt;a href="#cb10-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;├──&lt;/span&gt; flake.nix&lt;/span&gt;
711&lt;span id="cb10-6"&gt;&lt;a href="#cb10-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;└──&lt;/span&gt; src&lt;/span&gt; 1060&lt;span id="cb10-6"&gt;&lt;a href="#cb10-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;└──&lt;/span&gt; src&lt;/span&gt;
712&lt;span id="cb10-7"&gt;&lt;a href="#cb10-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;└──&lt;/span&gt; main.rs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1061&lt;span id="cb10-7"&gt;&lt;a href="#cb10-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;└──&lt;/span&gt; main.rs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
713&lt;p&gt;To avoid writing &lt;code&gt;~/mytemplates&lt;/code&gt; each time, simply alias it to a registry:&lt;/p&gt; 1062&lt;p&gt;To avoid writing &lt;code&gt;~/mytemplates&lt;/code&gt; each time, simply alias
714&lt;div class="sourceCode" id="cb11"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb11-1"&gt;&lt;a href="#cb11-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# alias it to `biscuits`&lt;/span&gt;&lt;/span&gt; 1063it to a registry:&lt;/p&gt;
1064&lt;div class="sourceCode" id="cb11"&gt;&lt;pre
1065class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb11-1"&gt;&lt;a href="#cb11-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# alias it to `biscuits`&lt;/span&gt;&lt;/span&gt;
715&lt;span id="cb11-2"&gt;&lt;a href="#cb11-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix registry add biscuits ~/mytemplates&lt;/span&gt; 1066&lt;span id="cb11-2"&gt;&lt;a href="#cb11-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix registry add biscuits ~/mytemplates&lt;/span&gt;
716&lt;span id="cb11-3"&gt;&lt;a href="#cb11-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 1067&lt;span id="cb11-3"&gt;&lt;a href="#cb11-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
717&lt;span id="cb11-4"&gt;&lt;a href="#cb11-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# you will see it listed under `user` registries&lt;/span&gt;&lt;/span&gt; 1068&lt;span id="cb11-4"&gt;&lt;a href="#cb11-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# you will see it listed under `user` registries&lt;/span&gt;&lt;/span&gt;
@@ -721,59 +1072,102 @@ H N E I
721&lt;span id="cb11-8"&gt;&lt;a href="#cb11-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;.&lt;/span&gt; . .&lt;/span&gt; 1072&lt;span id="cb11-8"&gt;&lt;a href="#cb11-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;.&lt;/span&gt; . .&lt;/span&gt;
722&lt;span id="cb11-9"&gt;&lt;a href="#cb11-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 1073&lt;span id="cb11-9"&gt;&lt;a href="#cb11-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
723&lt;span id="cb11-10"&gt;&lt;a href="#cb11-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake init &lt;span class="at"&gt;-t&lt;/span&gt; biscuits#latex-report&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1074&lt;span id="cb11-10"&gt;&lt;a href="#cb11-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix flake init &lt;span class="at"&gt;-t&lt;/span&gt; biscuits#latex-report&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
724&lt;h2 id="extending-the-official-templates"&gt;Extending the official templates&lt;/h2&gt; 1075&lt;h2 id="extending-the-official-templates"&gt;Extending the official
725&lt;p&gt;I personally, would like the &lt;code&gt;biscuits&lt;/code&gt; registry to include not just my homemade templates, but also the templates from &lt;code&gt;NixOS/templates&lt;/code&gt; (and maybe a couple of other repositories in the wild):&lt;/p&gt; 1076templates&lt;/h2&gt;
726&lt;div class="sourceCode" id="cb12"&gt;&lt;pre class="sourceCode nix"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb12-1"&gt;&lt;a href="#cb12-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;{&lt;/span&gt;&lt;/span&gt; 1077&lt;p&gt;I personally, would like the &lt;code&gt;biscuits&lt;/code&gt; registry to
727&lt;span id="cb12-2"&gt;&lt;a href="#cb12-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;description&lt;/span&gt; = &lt;span class="st"&gt;&amp;quot;Pepper&amp;#39;s flake templates&amp;quot;&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt;&lt;/span&gt; 1078include not just my homemade templates, but also the templates from
1079&lt;code&gt;NixOS/templates&lt;/code&gt; (and maybe a couple of other repositories
1080in the wild):&lt;/p&gt;
1081&lt;div class="sourceCode" id="cb12"&gt;&lt;pre
1082class="sourceCode nix"&gt;&lt;code class="sourceCode nix"&gt;&lt;span id="cb12-1"&gt;&lt;a href="#cb12-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1083&lt;span id="cb12-2"&gt;&lt;a href="#cb12-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;description&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Pepper&amp;#39;s flake templates&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
728&lt;span id="cb12-3"&gt;&lt;a href="#cb12-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;/span&gt; 1084&lt;span id="cb12-3"&gt;&lt;a href="#cb12-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;/span&gt;
729&lt;span id="cb12-4"&gt;&lt;a href="#cb12-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;+&lt;/span&gt; inputs = {&lt;/span&gt; 1085&lt;span id="cb12-4"&gt;&lt;a href="#cb12-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;+ &lt;span class="va"&gt;inputs&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
730&lt;span id="cb12-5"&gt;&lt;a href="#cb12-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;+&lt;/span&gt; official-templates.url = github:NixOS/templates&lt;span class="kw"&gt;;&lt;/span&gt;&lt;/span&gt; 1086&lt;span id="cb12-5"&gt;&lt;a href="#cb12-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;+ &lt;span class="va"&gt;official-templates&lt;/span&gt;.&lt;span class="va"&gt;url&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="va"&gt;github&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt;&lt;span class="ss"&gt;NixOS/templates&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
731&lt;span id="cb12-6"&gt;&lt;a href="#cb12-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;+&lt;/span&gt; other-templates.url = github:some-other/templates&lt;span class="kw"&gt;;&lt;/span&gt;&lt;/span&gt; 1087&lt;span id="cb12-6"&gt;&lt;a href="#cb12-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;+ &lt;span class="va"&gt;other-templates&lt;/span&gt;.&lt;span class="va"&gt;url&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="va"&gt;github&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt;&lt;span class="ss"&gt;some-other/templates&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
732&lt;span id="cb12-7"&gt;&lt;a href="#cb12-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;+&lt;/span&gt; }&lt;span class="kw"&gt;;&lt;/span&gt;&lt;/span&gt; 1088&lt;span id="cb12-7"&gt;&lt;a href="#cb12-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;+ &lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt;
733&lt;span id="cb12-8"&gt;&lt;a href="#cb12-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;/span&gt; 1089&lt;span id="cb12-8"&gt;&lt;a href="#cb12-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;/span&gt;
734&lt;span id="cb12-9"&gt;&lt;a href="#cb12-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;outputs&lt;/span&gt; = { self, official-templates, other-templates ... }: {&lt;/span&gt; 1090&lt;span id="cb12-9"&gt;&lt;a href="#cb12-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;outputs&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="va"&gt;self&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="va"&gt;official-templates&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="va"&gt;other-templates&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;: &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
735&lt;span id="cb12-10"&gt;&lt;a href="#cb12-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;/span&gt; 1091&lt;span id="cb12-10"&gt;&lt;a href="#cb12-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;/span&gt;
736&lt;span id="cb12-11"&gt;&lt;a href="#cb12-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;templates&lt;/span&gt; = {&lt;/span&gt; 1092&lt;span id="cb12-11"&gt;&lt;a href="#cb12-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;templates&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
737&lt;span id="cb12-12"&gt;&lt;a href="#cb12-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;latex-report&lt;/span&gt; = {&lt;/span&gt; 1093&lt;span id="cb12-12"&gt;&lt;a href="#cb12-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;latex-report&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
738&lt;span id="cb12-13"&gt;&lt;a href="#cb12-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;path&lt;/span&gt; = ./latex-report-template&lt;span class="kw"&gt;;&lt;/span&gt;&lt;/span&gt; 1094&lt;span id="cb12-13"&gt;&lt;a href="#cb12-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;path&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;./latex-report-template&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
739&lt;span id="cb12-14"&gt;&lt;a href="#cb12-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;description&lt;/span&gt; = &lt;span class="st"&gt;&amp;quot;A latex whitepaper project&amp;quot;&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt;&lt;/span&gt; 1095&lt;span id="cb12-14"&gt;&lt;a href="#cb12-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;description&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;A latex whitepaper project&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
740&lt;span id="cb12-15"&gt;&lt;a href="#cb12-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;};&lt;/span&gt;&lt;/span&gt; 1096&lt;span id="cb12-15"&gt;&lt;a href="#cb12-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt;
741&lt;span id="cb12-16"&gt;&lt;a href="#cb12-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;rust-hello&lt;/span&gt; = {&lt;/span&gt; 1097&lt;span id="cb12-16"&gt;&lt;a href="#cb12-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;rust-hello&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
742&lt;span id="cb12-17"&gt;&lt;a href="#cb12-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;path&lt;/span&gt; = ./rust-hello-template&lt;span class="kw"&gt;;&lt;/span&gt;&lt;/span&gt; 1098&lt;span id="cb12-17"&gt;&lt;a href="#cb12-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;path&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;./rust-hello-template&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
743&lt;span id="cb12-18"&gt;&lt;a href="#cb12-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;description&lt;/span&gt; = &lt;span class="st"&gt;&amp;quot;Simple Hello World in Rust, with overloaded Rust toolchain&amp;quot;&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt;&lt;/span&gt; 1099&lt;span id="cb12-18"&gt;&lt;a href="#cb12-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;description&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Simple Hello World in Rust, with overloaded Rust toolchain&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
744&lt;span id="cb12-19"&gt;&lt;a href="#cb12-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="er"&gt;}&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt;&lt;/span&gt; 1100&lt;span id="cb12-19"&gt;&lt;a href="#cb12-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt;
745&lt;span id="cb12-20"&gt;&lt;a href="#cb12-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="er"&gt;}&lt;/span&gt;&lt;/span&gt; 1101&lt;span id="cb12-20"&gt;&lt;a href="#cb12-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
746&lt;span id="cb12-21"&gt;&lt;a href="#cb12-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;+&lt;/span&gt; // official-templates.templates&lt;/span&gt; 1102&lt;span id="cb12-21"&gt;&lt;a href="#cb12-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="op"&gt;//&lt;/span&gt; official&lt;span class="op"&gt;-&lt;/span&gt;templates.templates&lt;/span&gt;
747&lt;span id="cb12-22"&gt;&lt;a href="#cb12-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;+&lt;/span&gt; // other-templates.templates&lt;span class="kw"&gt;;&lt;/span&gt;&lt;/span&gt; 1103&lt;span id="cb12-22"&gt;&lt;a href="#cb12-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="op"&gt;//&lt;/span&gt; other&lt;span class="op"&gt;-&lt;/span&gt;templates.templates&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
748&lt;span id="cb12-23"&gt;&lt;a href="#cb12-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;/span&gt; 1104&lt;span id="cb12-23"&gt;&lt;a href="#cb12-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;/span&gt;
749&lt;span id="cb12-24"&gt;&lt;a href="#cb12-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="er"&gt;}&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt;&lt;/span&gt; 1105&lt;span id="cb12-24"&gt;&lt;a href="#cb12-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt;
750&lt;span id="cb12-25"&gt;&lt;a href="#cb12-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="er"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1106&lt;span id="cb12-25"&gt;&lt;a href="#cb12-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
751&lt;p&gt;Running &lt;code&gt;nix flake show biscuits&lt;/code&gt; will now list templates from the &lt;code&gt;biscuits&lt;/code&gt; registry as well as the ones from &lt;code&gt;NixOS/templates&lt;/code&gt;. Ensure that the names don’t collide though.&lt;/p&gt;</description> 1107&lt;p&gt;Running &lt;code&gt;nix flake show biscuits&lt;/code&gt; will now list templates
1108from the &lt;code&gt;biscuits&lt;/code&gt; registry as well as the ones from
1109&lt;code&gt;NixOS/templates&lt;/code&gt;. Ensure that the names don’t collide
1110though.&lt;/p&gt;</description>
752<link>https://peppe.rs/posts/novice_nix:_flake_templates/</link> 1111<link>https://peppe.rs/posts/novice_nix:_flake_templates/</link>
753<pubDate>Tue, 05 Oct 2021 16:49:00 +0000</pubDate> 1112<pubDate>Tue, 05 Oct 2021 16:49:00 +0000</pubDate>
754<guid>https://peppe.rs/posts/novice_nix:_flake_templates/</guid> 1113<guid>https://peppe.rs/posts/novice_nix:_flake_templates/</guid>
755</item> 1114</item>
756<item> 1115<item>
757<title>SDL2 Devlog</title> 1116<title>SDL2 Devlog</title>
758<description>&lt;p&gt;I have been working on an editor for the &lt;a href="https://git.peppe.rs/graphics/obi/about"&gt;One Bit Image&lt;/a&gt; file format in Rust and SDL2. This entry in my blog follows my progress on the editor. The days are listed in reverse chronological order, begin from the bottom, if this is your first time on this page.&lt;/p&gt; 1117<description>&lt;p&gt;I have been working on an editor for the &lt;a
1118href="https://git.peppe.rs/graphics/obi/about"&gt;One Bit Image&lt;/a&gt; file
1119format in Rust and SDL2. This entry in my blog follows my progress on
1120the editor. The days are listed in reverse chronological order, begin
1121from the bottom, if this is your first time on this page.&lt;/p&gt;
759&lt;h3 id="day-20"&gt;Day 20&lt;/h3&gt; 1122&lt;h3 id="day-20"&gt;Day 20&lt;/h3&gt;
760&lt;p&gt;More &lt;code&gt;lisp&lt;/code&gt; stuff! I added a new brush, for rectangular selections. While selection doesn’t do much on its own, the selected area can be passed onto a &lt;code&gt;lisp&lt;/code&gt; procedure, for example, a procedure to draw horizontal black and white lines:&lt;/p&gt; 1123&lt;p&gt;More &lt;code&gt;lisp&lt;/code&gt; stuff! I added a new brush, for rectangular
1124selections. While selection doesn’t do much on its own, the selected
1125area can be passed onto a &lt;code&gt;lisp&lt;/code&gt; procedure, for example, a
1126procedure to draw horizontal black and white lines:&lt;/p&gt;
761&lt;figure&gt; 1127&lt;figure&gt;
762&lt;video src="https://u.peppe.rs/frU.mp4" controls=""&gt;&lt;a href="https://u.peppe.rs/frU.mp4"&gt;Day 20&lt;/a&gt;&lt;/video&gt;&lt;figcaption aria-hidden="true"&gt;Day 20&lt;/figcaption&gt; 1128&lt;video src="https://u.peppe.rs/frU.mp4" controls=""&gt;&lt;a
1129href="https://u.peppe.rs/frU.mp4"&gt;Day 20&lt;/a&gt;&lt;/video&gt;
1130&lt;figcaption aria-hidden="true"&gt;Day 20&lt;/figcaption&gt;
763&lt;/figure&gt; 1131&lt;/figure&gt;
764&lt;h3 id="day-19"&gt;Day 19&lt;/h3&gt; 1132&lt;h3 id="day-19"&gt;Day 19&lt;/h3&gt;
765&lt;p&gt;Attempted &lt;a href="https://peppe.rs/art/conduit.png"&gt;some isometric art&lt;/a&gt; within the editor. The angles displayed alongside the line brush are handly, however, having only a rectangular grid did not help. I implemented an isometric grid today. Isometric grids in pixel art differ in that the tangent of the isometric angle is exactly 0.5! For every pixel down, you go exactly two pixels sideways. The math works out really well in the drawing procedures too, dealing with floating points is a pain.&lt;/p&gt; 1133&lt;p&gt;Attempted &lt;a href="https://peppe.rs/art/conduit.png"&gt;some isometric
1134art&lt;/a&gt; within the editor. The angles displayed alongside the line brush
1135are handly, however, having only a rectangular grid did not help. I
1136implemented an isometric grid today. Isometric grids in pixel art differ
1137in that the tangent of the isometric angle is exactly 0.5! For every
1138pixel down, you go exactly two pixels sideways. The math works out
1139really well in the drawing procedures too, dealing with floating points
1140is a pain.&lt;/p&gt;
766&lt;figure&gt; 1141&lt;figure&gt;
767&lt;img src="https://u.peppe.rs/1Kb.png" alt="Day 19" /&gt;&lt;figcaption aria-hidden="true"&gt;Day 19&lt;/figcaption&gt; 1142&lt;img src="https://u.peppe.rs/1Kb.png" alt="Day 19" /&gt;
1143&lt;figcaption aria-hidden="true"&gt;Day 19&lt;/figcaption&gt;
768&lt;/figure&gt; 1144&lt;/figure&gt;
769&lt;h3 id="day-18"&gt;Day 18&lt;/h3&gt; 1145&lt;h3 id="day-18"&gt;Day 18&lt;/h3&gt;
770&lt;p&gt;I added basic support for guides, they can be added and activated from the &lt;code&gt;lisp&lt;/code&gt; REPL. Another long standing improvement I wanted to make was reworking the pixmap drawing procedure. The old procedure draws a square for each pixel in the pixmap, coloured according to its value in the pixmap. Naturally, this means, for an &lt;strong&gt;NxN&lt;/strong&gt; pixmap, there are &lt;strong&gt;N²&lt;/strong&gt; calls to SDL! I reworked this procedure to compress each line of the pixmap using RLE (run length encoding), and call out to SDL for each run in the line. This drastically improved drawing speeds on larger grids. The following is a comparison between the two procedures, the leftmost picture is the rendered image, the middle picture is the optimized drawing procedure (draws each run instead of pixel), and the right most picture is the primitive drawing procedure (draws each pixel):&lt;/p&gt; 1146&lt;p&gt;I added basic support for guides, they can be added and activated
1147from the &lt;code&gt;lisp&lt;/code&gt; REPL. Another long standing improvement I
1148wanted to make was reworking the pixmap drawing procedure. The old
1149procedure draws a square for each pixel in the pixmap, coloured
1150according to its value in the pixmap. Naturally, this means, for an
1151&lt;strong&gt;NxN&lt;/strong&gt; pixmap, there are &lt;strong&gt;N²&lt;/strong&gt; calls to SDL!
1152I reworked this procedure to compress each line of the pixmap using RLE
1153(run length encoding), and call out to SDL for each run in the line.
1154This drastically improved drawing speeds on larger grids. The following
1155is a comparison between the two procedures, the leftmost picture is the
1156rendered image, the middle picture is the optimized drawing procedure
1157(draws each run instead of pixel), and the right most picture is the
1158primitive drawing procedure (draws each pixel):&lt;/p&gt;
771&lt;figure&gt; 1159&lt;figure&gt;
772&lt;img src="https://u.peppe.rs/U4B.png" alt="Day 18" /&gt;&lt;figcaption aria-hidden="true"&gt;Day 18&lt;/figcaption&gt; 1160&lt;img src="https://u.peppe.rs/U4B.png" alt="Day 18" /&gt;
1161&lt;figcaption aria-hidden="true"&gt;Day 18&lt;/figcaption&gt;
773&lt;/figure&gt; 1162&lt;/figure&gt;
774&lt;h3 id="day-17"&gt;Day 17&lt;/h3&gt; 1163&lt;h3 id="day-17"&gt;Day 17&lt;/h3&gt;
775&lt;p&gt;I decided to give the text-only statusline a touch up, by adding a active color and dither level preview. Aligning the “widget” to the right of statusline involved a lot more than I thought, so I created a ghetto CSS-like rectangle placement system to position containers inside containers:&lt;/p&gt; 1164&lt;p&gt;I decided to give the text-only statusline a touch up, by adding a
776&lt;div class="sourceCode" id="cb1"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// roughly something like this&lt;/span&gt;&lt;/span&gt; 1165active color and dither level preview. Aligning the “widget” to the
1166right of statusline involved a lot more than I thought, so I created a
1167ghetto CSS-like rectangle placement system to position containers inside
1168containers:&lt;/p&gt;
1169&lt;div class="sourceCode" id="cb1"&gt;&lt;pre
1170class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// roughly something like this&lt;/span&gt;&lt;/span&gt;
777&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; statusline &lt;span class="op"&gt;=&lt;/span&gt; &lt;/span&gt; 1171&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; statusline &lt;span class="op"&gt;=&lt;/span&gt; &lt;/span&gt;
778&lt;span id="cb1-3"&gt;&lt;a href="#cb1-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="pp"&gt;Container::&lt;/span&gt;new(&lt;span class="pp"&gt;Offset::&lt;/span&gt;Left(&lt;span class="dv"&gt;0&lt;/span&gt;)&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="pp"&gt;Offset::&lt;/span&gt;Bottom(&lt;span class="dv"&gt;40&lt;/span&gt;))&lt;/span&gt; 1172&lt;span id="cb1-3"&gt;&lt;a href="#cb1-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="pp"&gt;Container::&lt;/span&gt;new(&lt;span class="pp"&gt;Offset::&lt;/span&gt;Left(&lt;span class="dv"&gt;0&lt;/span&gt;)&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="pp"&gt;Offset::&lt;/span&gt;Bottom(&lt;span class="dv"&gt;40&lt;/span&gt;))&lt;/span&gt;
779&lt;span id="cb1-4"&gt;&lt;a href="#cb1-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;.&lt;/span&gt;width(&lt;span class="pp"&gt;Size::&lt;/span&gt;Max)&lt;/span&gt; 1173&lt;span id="cb1-4"&gt;&lt;a href="#cb1-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;.&lt;/span&gt;width(&lt;span class="pp"&gt;Size::&lt;/span&gt;Max)&lt;/span&gt;
@@ -790,14 +1184,20 @@ H N E I
790&lt;span id="cb1-15"&gt;&lt;a href="#cb1-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1184&lt;span id="cb1-15"&gt;&lt;a href="#cb1-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
791&lt;p&gt;The result (brush preview on the bottom right):&lt;/p&gt; 1185&lt;p&gt;The result (brush preview on the bottom right):&lt;/p&gt;
792&lt;figure&gt; 1186&lt;figure&gt;
793&lt;video src="https://u.peppe.rs/OtU.mp4" controls=""&gt;&lt;a href="https://u.peppe.rs/OtU.mp4"&gt;Day 17&lt;/a&gt;&lt;/video&gt;&lt;figcaption aria-hidden="true"&gt;Day 17&lt;/figcaption&gt; 1187&lt;video src="https://u.peppe.rs/OtU.mp4" controls=""&gt;&lt;a
1188href="https://u.peppe.rs/OtU.mp4"&gt;Day 17&lt;/a&gt;&lt;/video&gt;
1189&lt;figcaption aria-hidden="true"&gt;Day 17&lt;/figcaption&gt;
794&lt;/figure&gt; 1190&lt;/figure&gt;
795&lt;h3 id="day-16"&gt;Day 16&lt;/h3&gt; 1191&lt;h3 id="day-16"&gt;Day 16&lt;/h3&gt;
796&lt;p&gt;The embedded lisp is coming along nicely, users can load a custom &lt;code&gt;rc.lisp&lt;/code&gt;, which is evaluated on startup. To disable to grid on start, for example:&lt;/p&gt; 1192&lt;p&gt;The embedded lisp is coming along nicely, users can load a custom
797&lt;div class="sourceCode" id="cb2"&gt;&lt;pre class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;;;; rc.lisp&lt;/span&gt;&lt;/span&gt; 1193&lt;code&gt;rc.lisp&lt;/code&gt;, which is evaluated on startup. To disable to grid
1194on start, for example:&lt;/p&gt;
1195&lt;div class="sourceCode" id="cb2"&gt;&lt;pre
1196class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;;;; rc.lisp&lt;/span&gt;&lt;/span&gt;
798&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(toggle-grid)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1197&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(toggle-grid)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
799&lt;p&gt;Some aliases to switch between brushes:&lt;/p&gt; 1198&lt;p&gt;Some aliases to switch between brushes:&lt;/p&gt;
800&lt;div class="sourceCode" id="cb3"&gt;&lt;pre class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;;;; rc.lisp&lt;/span&gt;&lt;/span&gt; 1199&lt;div class="sourceCode" id="cb3"&gt;&lt;pre
1200class="sourceCode scheme"&gt;&lt;code class="sourceCode scheme"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;;;; rc.lisp&lt;/span&gt;&lt;/span&gt;
801&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(&lt;span class="ex"&gt;define&lt;/span&gt;&lt;span class="fu"&gt; &lt;/span&gt;(brush kind)&lt;/span&gt; 1201&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(&lt;span class="ex"&gt;define&lt;/span&gt;&lt;span class="fu"&gt; &lt;/span&gt;(brush kind)&lt;/span&gt;
802&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (&lt;span class="kw"&gt;cond&lt;/span&gt;&lt;/span&gt; 1202&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (&lt;span class="kw"&gt;cond&lt;/span&gt;&lt;/span&gt;
803&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; ((&lt;span class="kw"&gt;eq?&lt;/span&gt; kind &amp;#39;f) (brush-fill))&lt;/span&gt; 1203&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; ((&lt;span class="kw"&gt;eq?&lt;/span&gt; kind &amp;#39;f) (brush-fill))&lt;/span&gt;
@@ -805,90 +1205,195 @@ H N E I
805&lt;span id="cb3-6"&gt;&lt;a href="#cb3-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; ((&lt;span class="kw"&gt;eq?&lt;/span&gt; kind &amp;#39;l) (brush-line))&lt;/span&gt; 1205&lt;span id="cb3-6"&gt;&lt;a href="#cb3-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; ((&lt;span class="kw"&gt;eq?&lt;/span&gt; kind &amp;#39;l) (brush-line))&lt;/span&gt;
806&lt;span id="cb3-7"&gt;&lt;a href="#cb3-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; ((&lt;span class="kw"&gt;eq?&lt;/span&gt; kind &amp;#39;l+) (brush-line-extend))&lt;/span&gt; 1206&lt;span id="cb3-7"&gt;&lt;a href="#cb3-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; ((&lt;span class="kw"&gt;eq?&lt;/span&gt; kind &amp;#39;l+) (brush-line-extend))&lt;/span&gt;
807&lt;span id="cb3-8"&gt;&lt;a href="#cb3-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (&lt;span class="kw"&gt;else&lt;/span&gt; (brush-circle))))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1207&lt;span id="cb3-8"&gt;&lt;a href="#cb3-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (&lt;span class="kw"&gt;else&lt;/span&gt; (brush-circle))))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
808&lt;p&gt;The following script draws a straight line along a given axis, at a given distance from the canvas boundary:&lt;/p&gt; 1208&lt;p&gt;The following script draws a straight line along a given axis, at a
1209given distance from the canvas boundary:&lt;/p&gt;
809&lt;figure&gt; 1210&lt;figure&gt;
810&lt;video src="https://u.peppe.rs/b3i.mp4" controls=""&gt;&lt;a href="https://u.peppe.rs/b3i.mp4"&gt;Day 16&lt;/a&gt;&lt;/video&gt;&lt;figcaption aria-hidden="true"&gt;Day 16&lt;/figcaption&gt; 1211&lt;video src="https://u.peppe.rs/b3i.mp4" controls=""&gt;&lt;a
1212href="https://u.peppe.rs/b3i.mp4"&gt;Day 16&lt;/a&gt;&lt;/video&gt;
1213&lt;figcaption aria-hidden="true"&gt;Day 16&lt;/figcaption&gt;
811&lt;/figure&gt; 1214&lt;/figure&gt;
812&lt;h3 id="day-15"&gt;Day 15&lt;/h3&gt; 1215&lt;h3 id="day-15"&gt;Day 15&lt;/h3&gt;
813&lt;p&gt;I began writing a standard library for the lisp, in lisp. It includes basic list operations: &lt;code&gt;car&lt;/code&gt;, &lt;code&gt;cdr&lt;/code&gt;, &lt;code&gt;null?&lt;/code&gt;, &lt;code&gt;list&lt;/code&gt;, higher order functions: &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;fold&lt;/code&gt;:&lt;/p&gt; 1216&lt;p&gt;I began writing a standard library for the lisp, in lisp. It includes
814&lt;div class="sourceCode" id="cb4"&gt;&lt;pre class="sourceCode lisp"&gt;&lt;code class="sourceCode commonlisp"&gt;&lt;span id="cb4-1"&gt;&lt;a href="#cb4-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(define (member? item ls)&lt;/span&gt; 1217basic list operations: &lt;code&gt;car&lt;/code&gt;, &lt;code&gt;cdr&lt;/code&gt;,
1218&lt;code&gt;null?&lt;/code&gt;, &lt;code&gt;list&lt;/code&gt;, higher order functions:
1219&lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;fold&lt;/code&gt;:&lt;/p&gt;
1220&lt;div class="sourceCode" id="cb4"&gt;&lt;pre
1221class="sourceCode lisp"&gt;&lt;code class="sourceCode commonlisp"&gt;&lt;span id="cb4-1"&gt;&lt;a href="#cb4-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(define (member? item ls)&lt;/span&gt;
815&lt;span id="cb4-2"&gt;&lt;a href="#cb4-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (fold &lt;span class="dv"&gt;#f&lt;/span&gt;&lt;/span&gt; 1222&lt;span id="cb4-2"&gt;&lt;a href="#cb4-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (fold &lt;span class="dv"&gt;#f&lt;/span&gt;&lt;/span&gt;
816&lt;span id="cb4-3"&gt;&lt;a href="#cb4-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (&lt;span class="kw"&gt;lambda&lt;/span&gt; (acc x) (&lt;span class="kw"&gt;or&lt;/span&gt; acc (eq? item x)))&lt;/span&gt; 1223&lt;span id="cb4-3"&gt;&lt;a href="#cb4-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; (&lt;span class="kw"&gt;lambda&lt;/span&gt; (acc x) (&lt;span class="kw"&gt;or&lt;/span&gt; acc (eq? item x)))&lt;/span&gt;
817&lt;span id="cb4-4"&gt;&lt;a href="#cb4-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; ls))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1224&lt;span id="cb4-4"&gt;&lt;a href="#cb4-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; ls))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
818&lt;h3 id="day-14"&gt;Day 14&lt;/h3&gt; 1225&lt;h3 id="day-14"&gt;Day 14&lt;/h3&gt;
819&lt;p&gt;I attempted a &lt;a href="https://peppe.rs/art/ramen_noodles.png"&gt;small art piece&lt;/a&gt; using the editor, while it was largely usable, I felt a certain lack of feedback. The brushes just didn’t relay as much info as I’d have liked, for example, the approximate points of the line or the angle made by the line against the x-axis. Unfortunately, the existing infrastructure around brushes and line drawing didn’t easily allow for this either. I went ahead and reimplemented brushes, and added a new flood fill brush too:&lt;/p&gt; 1226&lt;p&gt;I attempted a &lt;a href="https://peppe.rs/art/ramen_noodles.png"&gt;small
1227art piece&lt;/a&gt; using the editor, while it was largely usable, I felt a
1228certain lack of feedback. The brushes just didn’t relay as much info as
1229I’d have liked, for example, the approximate points of the line or the
1230angle made by the line against the x-axis. Unfortunately, the existing
1231infrastructure around brushes and line drawing didn’t easily allow for
1232this either. I went ahead and reimplemented brushes, and added a new
1233flood fill brush too:&lt;/p&gt;
820&lt;figure&gt; 1234&lt;figure&gt;
821&lt;video src="https://u.peppe.rs/8q.mp4" controls=""&gt;&lt;a href="https://u.peppe.rs/8q.mp4"&gt;Day 14&lt;/a&gt;&lt;/video&gt;&lt;figcaption aria-hidden="true"&gt;Day 14&lt;/figcaption&gt; 1235&lt;video src="https://u.peppe.rs/8q.mp4" controls=""&gt;&lt;a
1236href="https://u.peppe.rs/8q.mp4"&gt;Day 14&lt;/a&gt;&lt;/video&gt;
1237&lt;figcaption aria-hidden="true"&gt;Day 14&lt;/figcaption&gt;
822&lt;/figure&gt; 1238&lt;/figure&gt;
823&lt;h3 id="day-13"&gt;Day 13&lt;/h3&gt; 1239&lt;h3 id="day-13"&gt;Day 13&lt;/h3&gt;
824&lt;p&gt;I added a few more forms to the &lt;code&gt;lisp&lt;/code&gt; evaluator. It handles recursion, definitions, variable mutation and more. The prelude contains 20 subroutines so far, including comparision and logic operators. The REPL interface on the SDL side requires some UX tweaks; environment based completion, readline motions sound doable.&lt;/p&gt; 1240&lt;p&gt;I added a few more forms to the &lt;code&gt;lisp&lt;/code&gt; evaluator. It
1241handles recursion, definitions, variable mutation and more. The prelude
1242contains 20 subroutines so far, including comparision and logic
1243operators. The REPL interface on the SDL side requires some UX tweaks;
1244environment based completion, readline motions sound doable.&lt;/p&gt;
825&lt;figure&gt; 1245&lt;figure&gt;
826&lt;video src="https://u.peppe.rs/u3.mp4" controls=""&gt;&lt;a href="https://u.peppe.rs/u3.mp4"&gt;Day 13&lt;/a&gt;&lt;/video&gt;&lt;figcaption aria-hidden="true"&gt;Day 13&lt;/figcaption&gt; 1246&lt;video src="https://u.peppe.rs/u3.mp4" controls=""&gt;&lt;a
1247href="https://u.peppe.rs/u3.mp4"&gt;Day 13&lt;/a&gt;&lt;/video&gt;
1248&lt;figcaption aria-hidden="true"&gt;Day 13&lt;/figcaption&gt;
827&lt;/figure&gt; 1249&lt;/figure&gt;
828&lt;h3 id="day-12"&gt;Day 12&lt;/h3&gt; 1250&lt;h3 id="day-12"&gt;Day 12&lt;/h3&gt;
829&lt;p&gt;I lifted most of &lt;a href="https://github.com/murarth/ketos"&gt;murarth/ketos&lt;/a&gt; into the editor. &lt;code&gt;ketos&lt;/code&gt;’s implementation of &lt;code&gt;lisp&lt;/code&gt; is too vast for my use case. For example, the editor does not need data types to handle raw strings or byte strings. I have got a basic evaluator running inside the SDL2 context (notice the &lt;code&gt;lisp&lt;/code&gt; REPL at the bottom of the window). Over the following days, I intend to create a set of prelude functions to manipulate the pixmap. Users can implement their own brushes, dithering patterns, keybinds and more (hopefully).&lt;/p&gt; 1251&lt;p&gt;I lifted most of &lt;a
1252href="https://github.com/murarth/ketos"&gt;murarth/ketos&lt;/a&gt; into the
1253editor. &lt;code&gt;ketos&lt;/code&gt;’s implementation of &lt;code&gt;lisp&lt;/code&gt; is too
1254vast for my use case. For example, the editor does not need data types
1255to handle raw strings or byte strings. I have got a basic evaluator
1256running inside the SDL2 context (notice the &lt;code&gt;lisp&lt;/code&gt; REPL at
1257the bottom of the window). Over the following days, I intend to create a
1258set of prelude functions to manipulate the pixmap. Users can implement
1259their own brushes, dithering patterns, keybinds and more
1260(hopefully).&lt;/p&gt;
830&lt;figure&gt; 1261&lt;figure&gt;
831&lt;video src="https://u.peppe.rs/y0.mp4" controls=""&gt;&lt;a href="https://u.peppe.rs/y0.mp4"&gt;Day 12&lt;/a&gt;&lt;/video&gt;&lt;figcaption aria-hidden="true"&gt;Day 12&lt;/figcaption&gt; 1262&lt;video src="https://u.peppe.rs/y0.mp4" controls=""&gt;&lt;a
1263href="https://u.peppe.rs/y0.mp4"&gt;Day 12&lt;/a&gt;&lt;/video&gt;
1264&lt;figcaption aria-hidden="true"&gt;Day 12&lt;/figcaption&gt;
832&lt;/figure&gt; 1265&lt;/figure&gt;
833&lt;h3 id="day-11"&gt;Day 11&lt;/h3&gt; 1266&lt;h3 id="day-11"&gt;Day 11&lt;/h3&gt;
834&lt;p&gt;I intend to supplement the editor with scripting language and an inbuilt REPL for the same. I began by implementing a text box widget from scratch, with history and readline like editing:&lt;/p&gt; 1267&lt;p&gt;I intend to supplement the editor with scripting language and an
1268inbuilt REPL for the same. I began by implementing a text box widget
1269from scratch, with history and readline like editing:&lt;/p&gt;
835&lt;figure&gt; 1270&lt;figure&gt;
836&lt;video src="https://u.peppe.rs/Mh.mp4" controls=""&gt;&lt;a href="https://u.peppe.rs/Mh.mp4"&gt;Day 11&lt;/a&gt;&lt;/video&gt;&lt;figcaption aria-hidden="true"&gt;Day 11&lt;/figcaption&gt; 1271&lt;video src="https://u.peppe.rs/Mh.mp4" controls=""&gt;&lt;a
1272href="https://u.peppe.rs/Mh.mp4"&gt;Day 11&lt;/a&gt;&lt;/video&gt;
1273&lt;figcaption aria-hidden="true"&gt;Day 11&lt;/figcaption&gt;
837&lt;/figure&gt; 1274&lt;/figure&gt;
838&lt;h3 id="day-10"&gt;Day 10&lt;/h3&gt; 1275&lt;h3 id="day-10"&gt;Day 10&lt;/h3&gt;
839&lt;p&gt;I started reading up on dithering methods and half-toning, I wanted to create a dithering brush that would automatically produce popular dithering patterns. The method that caught my eye (and also the one used most often in pixel art), was Bayer’s ordered dithering. When applied to a black and white image, each pixel, based on its intensity, is mapped to a 4x4 grid of pixels. A completely empty (completely black) 4x4 grid represents zero intensity, and a filled 4x4 grid represents full intensity. Bayer’s ordered dithering can produce 15 steps of intensity between zero and full (by switching on exactly 1 pixel more at each level), thus, being able to draw 17 “shades” from white to black. Creating a dithering brush from here was fairly trivial. Our pixmap is supposed to represent the final dithered image, it must be divided into 4x4 grids. Each grid is colored based on the intensity of the brush passing over it:&lt;/p&gt; 1276&lt;p&gt;I started reading up on dithering methods and half-toning, I wanted
1277to create a dithering brush that would automatically produce popular
1278dithering patterns. The method that caught my eye (and also the one used
1279most often in pixel art), was Bayer’s ordered dithering. When applied to
1280a black and white image, each pixel, based on its intensity, is mapped
1281to a 4x4 grid of pixels. A completely empty (completely black) 4x4 grid
1282represents zero intensity, and a filled 4x4 grid represents full
1283intensity. Bayer’s ordered dithering can produce 15 steps of intensity
1284between zero and full (by switching on exactly 1 pixel more at each
1285level), thus, being able to draw 17 “shades” from white to black.
1286Creating a dithering brush from here was fairly trivial. Our pixmap is
1287supposed to represent the final dithered image, it must be divided into
12884x4 grids. Each grid is colored based on the intensity of the brush
1289passing over it:&lt;/p&gt;
840&lt;figure&gt; 1290&lt;figure&gt;
841&lt;img src="https://u.peppe.rs/Mn.png" alt="Day 10" /&gt;&lt;figcaption aria-hidden="true"&gt;Day 10&lt;/figcaption&gt; 1291&lt;img src="https://u.peppe.rs/Mn.png" alt="Day 10" /&gt;
1292&lt;figcaption aria-hidden="true"&gt;Day 10&lt;/figcaption&gt;
842&lt;/figure&gt; 1293&lt;/figure&gt;
843&lt;h3 id="day-9"&gt;Day 9&lt;/h3&gt; 1294&lt;h3 id="day-9"&gt;Day 9&lt;/h3&gt;
844&lt;p&gt;I started working towards an interface. I like the idea of a largely read-only HUD, i. e., an interface that simply describes the state of the application. Changes to this state are initiated via keybinds or text commands. I am proud of the symmetry indicator; &lt;code&gt;-&lt;/code&gt; for horizontal symmetry, &lt;code&gt;|&lt;/code&gt; for vertical symmetry, &lt;code&gt;+&lt;/code&gt; for radial symmetry.&lt;/p&gt; 1295&lt;p&gt;I started working towards an interface. I like the idea of a largely
1296read-only HUD, i. e., an interface that simply describes the state of
1297the application. Changes to this state are initiated via keybinds or
1298text commands. I am proud of the symmetry indicator; &lt;code&gt;-&lt;/code&gt; for
1299horizontal symmetry, &lt;code&gt;|&lt;/code&gt; for vertical symmetry,
1300&lt;code&gt;+&lt;/code&gt; for radial symmetry.&lt;/p&gt;
845&lt;figure&gt; 1301&lt;figure&gt;
846&lt;img src="https://u.peppe.rs/hx.png" alt="Day 9" /&gt;&lt;figcaption aria-hidden="true"&gt;Day 9&lt;/figcaption&gt; 1302&lt;img src="https://u.peppe.rs/hx.png" alt="Day 9" /&gt;
1303&lt;figcaption aria-hidden="true"&gt;Day 9&lt;/figcaption&gt;
847&lt;/figure&gt; 1304&lt;/figure&gt;
848&lt;h3 id="day-8"&gt;Day 8&lt;/h3&gt; 1305&lt;h3 id="day-8"&gt;Day 8&lt;/h3&gt;
849&lt;p&gt;One of my favourite features of GIMP was symmetric editing. I added some coordinate geometry primitives to my pixmap abstraction, allowing for mirroring and reflecting figures about lines or points. The result was an ergonomic function that applies symmetry to any painting operation, (undo/redo works as expected):&lt;/p&gt; 1306&lt;p&gt;One of my favourite features of GIMP was symmetric editing. I added
850&lt;div class="sourceCode" id="cb5"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb5-1"&gt;&lt;a href="#cb5-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; line &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;self&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;pixmap&lt;span class="op"&gt;.&lt;/span&gt;get_line(start&lt;span class="op"&gt;,&lt;/span&gt; end)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 1307some coordinate geometry primitives to my pixmap abstraction, allowing
1308for mirroring and reflecting figures about lines or points. The result
1309was an ergonomic function that applies symmetry to any painting
1310operation, (undo/redo works as expected):&lt;/p&gt;
1311&lt;div class="sourceCode" id="cb5"&gt;&lt;pre
1312class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb5-1"&gt;&lt;a href="#cb5-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; line &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;self&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;pixmap&lt;span class="op"&gt;.&lt;/span&gt;get_line(start&lt;span class="op"&gt;,&lt;/span&gt; end)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
851&lt;span id="cb5-2"&gt;&lt;a href="#cb5-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; sym_line &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;self&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;symmetry&lt;span class="op"&gt;.&lt;/span&gt;apply(&lt;span class="op"&gt;&amp;amp;&lt;/span&gt;line)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 1313&lt;span id="cb5-2"&gt;&lt;a href="#cb5-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; sym_line &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;self&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;symmetry&lt;span class="op"&gt;.&lt;/span&gt;apply(&lt;span class="op"&gt;&amp;amp;&lt;/span&gt;line)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
852&lt;span id="cb5-3"&gt;&lt;a href="#cb5-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;for&lt;/span&gt; point on line&lt;span class="op"&gt;.&lt;/span&gt;extend(sym_line) &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 1314&lt;span id="cb5-3"&gt;&lt;a href="#cb5-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;for&lt;/span&gt; point on line&lt;span class="op"&gt;.&lt;/span&gt;extend(sym_line) &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
853&lt;span id="cb5-4"&gt;&lt;a href="#cb5-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="co"&gt;// draw to window&lt;/span&gt;&lt;/span&gt; 1315&lt;span id="cb5-4"&gt;&lt;a href="#cb5-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="co"&gt;// draw to window&lt;/span&gt;&lt;/span&gt;
854&lt;span id="cb5-5"&gt;&lt;a href="#cb5-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1316&lt;span id="cb5-5"&gt;&lt;a href="#cb5-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
855&lt;figure&gt; 1317&lt;figure&gt;
856&lt;video src="https://u.peppe.rs/B1.mp4" controls=""&gt;&lt;a href="https://u.peppe.rs/B1.mp4"&gt;Day 8&lt;/a&gt;&lt;/video&gt;&lt;figcaption aria-hidden="true"&gt;Day 8&lt;/figcaption&gt; 1318&lt;video src="https://u.peppe.rs/B1.mp4" controls=""&gt;&lt;a
1319href="https://u.peppe.rs/B1.mp4"&gt;Day 8&lt;/a&gt;&lt;/video&gt;
1320&lt;figcaption aria-hidden="true"&gt;Day 8&lt;/figcaption&gt;
857&lt;/figure&gt; 1321&lt;/figure&gt;
858&lt;h3 id="day-7"&gt;Day 7&lt;/h3&gt; 1322&lt;h3 id="day-7"&gt;Day 7&lt;/h3&gt;
859&lt;p&gt;Bresenham saves the day again! This time, I implemented his line drawing algorithm, to, well, draw lines. Each point on the line is then “buffed” based on the active brush size. Today’s changes fit in very well with the undo system and the brush size feature. Creating the right abstractions, one at a time :)&lt;/p&gt; 1323&lt;p&gt;Bresenham saves the day again! This time, I implemented his line
1324drawing algorithm, to, well, draw lines. Each point on the line is then
1325“buffed” based on the active brush size. Today’s changes fit in very
1326well with the undo system and the brush size feature. Creating the right
1327abstractions, one at a time :)&lt;/p&gt;
860&lt;figure&gt; 1328&lt;figure&gt;
861&lt;video src="https://u.peppe.rs/xt.mp4" controls=""&gt;&lt;a href="https://u.peppe.rs/xt.mp4"&gt;Day 7&lt;/a&gt;&lt;/video&gt;&lt;figcaption aria-hidden="true"&gt;Day 7&lt;/figcaption&gt; 1329&lt;video src="https://u.peppe.rs/xt.mp4" controls=""&gt;&lt;a
1330href="https://u.peppe.rs/xt.mp4"&gt;Day 7&lt;/a&gt;&lt;/video&gt;
1331&lt;figcaption aria-hidden="true"&gt;Day 7&lt;/figcaption&gt;
862&lt;/figure&gt; 1332&lt;/figure&gt;
863&lt;h3 id="day-6"&gt;Day 6&lt;/h3&gt; 1333&lt;h3 id="day-6"&gt;Day 6&lt;/h3&gt;
864&lt;p&gt;I extended Bresenham’s algorithm to draw not just circle outlines, but also generate their fills. Unlike Bresenham’s algorithm, this variant generates points for two quadrants at once, these points are mirrored over the dividing axis to generate the other two quadrants.&lt;/p&gt; 1334&lt;p&gt;I extended Bresenham’s algorithm to draw not just circle outlines,
1335but also generate their fills. Unlike Bresenham’s algorithm, this
1336variant generates points for two quadrants at once, these points are
1337mirrored over the dividing axis to generate the other two quadrants.&lt;/p&gt;
865&lt;figure&gt; 1338&lt;figure&gt;
866&lt;img src="https://u.peppe.rs/f3.png" alt="Day 6" /&gt;&lt;figcaption aria-hidden="true"&gt;Day 6&lt;/figcaption&gt; 1339&lt;img src="https://u.peppe.rs/f3.png" alt="Day 6" /&gt;
1340&lt;figcaption aria-hidden="true"&gt;Day 6&lt;/figcaption&gt;
867&lt;/figure&gt; 1341&lt;/figure&gt;
868&lt;h3 id="day-5"&gt;Day 5&lt;/h3&gt; 1342&lt;h3 id="day-5"&gt;Day 5&lt;/h3&gt;
869&lt;p&gt;I discovered and implemented Bresenham’s algorithm for efficient circle drawing. The algorithm allowed for sized circular brushes, something I really liked from GIMP. Very convenient that the Wikipedia page for Bresenham’s algorithm also includes a section about optimizing for integer based arithmetic. I managed to abstract out another giant component of the application, the pixmap. Any image is just a grid of pixels (a pixmap), where the pixel’s value is decided by the application (1-bit in my case). I could potentially extend the application to a 24-bit image editor!&lt;/p&gt; 1343&lt;p&gt;I discovered and implemented Bresenham’s algorithm for efficient
1344circle drawing. The algorithm allowed for sized circular brushes,
1345something I really liked from GIMP. Very convenient that the Wikipedia
1346page for Bresenham’s algorithm also includes a section about optimizing
1347for integer based arithmetic. I managed to abstract out another giant
1348component of the application, the pixmap. Any image is just a grid of
1349pixels (a pixmap), where the pixel’s value is decided by the application
1350(1-bit in my case). I could potentially extend the application to a
135124-bit image editor!&lt;/p&gt;
870&lt;figure&gt; 1352&lt;figure&gt;
871&lt;video src="https://u.peppe.rs/Kh.mp4" controls=""&gt;&lt;a href="https://u.peppe.rs/Kh.mp4"&gt;Day 5&lt;/a&gt;&lt;/video&gt;&lt;figcaption aria-hidden="true"&gt;Day 5&lt;/figcaption&gt; 1353&lt;video src="https://u.peppe.rs/Kh.mp4" controls=""&gt;&lt;a
1354href="https://u.peppe.rs/Kh.mp4"&gt;Day 5&lt;/a&gt;&lt;/video&gt;
1355&lt;figcaption aria-hidden="true"&gt;Day 5&lt;/figcaption&gt;
872&lt;/figure&gt; 1356&lt;/figure&gt;
873&lt;h3 id="day-4"&gt;Day 4&lt;/h3&gt; 1357&lt;h3 id="day-4"&gt;Day 4&lt;/h3&gt;
874&lt;p&gt;I created a generic “undo stack” data structure that allows for infinite “undos” and “redos”. Every modification operation to the grid is persisted to the application state. A couple of keybinds allow the user to revert and re-apply these operations! I expect abstracting this component will come in handy down the line.&lt;/p&gt; 1358&lt;p&gt;I created a generic “undo stack” data structure that allows for
1359infinite “undos” and “redos”. Every modification operation to the grid
1360is persisted to the application state. A couple of keybinds allow the
1361user to revert and re-apply these operations! I expect abstracting this
1362component will come in handy down the line.&lt;/p&gt;
875&lt;figure&gt; 1363&lt;figure&gt;
876&lt;video src="https://u.peppe.rs/w5.mp4" controls=""&gt;&lt;a href="https://u.peppe.rs/w5.mp4"&gt;Day 4&lt;/a&gt;&lt;/video&gt;&lt;figcaption aria-hidden="true"&gt;Day 4&lt;/figcaption&gt; 1364&lt;video src="https://u.peppe.rs/w5.mp4" controls=""&gt;&lt;a
1365href="https://u.peppe.rs/w5.mp4"&gt;Day 4&lt;/a&gt;&lt;/video&gt;
1366&lt;figcaption aria-hidden="true"&gt;Day 4&lt;/figcaption&gt;
877&lt;/figure&gt; 1367&lt;/figure&gt;
878&lt;h3 id="day-3"&gt;Day 3&lt;/h3&gt; 1368&lt;h3 id="day-3"&gt;Day 3&lt;/h3&gt;
879&lt;p&gt;I implemented the bare minimum required to call the program an “editor”. The application displays a grid, tracks mouse events, paints white to the canvas on left click, and black to the canvas on right click. I created a make-shift MVC architecture à la Elm in Rust.&lt;/p&gt; 1369&lt;p&gt;I implemented the bare minimum required to call the program an
1370“editor”. The application displays a grid, tracks mouse events, paints
1371white to the canvas on left click, and black to the canvas on right
1372click. I created a make-shift MVC architecture à la Elm in Rust.&lt;/p&gt;
880&lt;figure&gt; 1373&lt;figure&gt;
881&lt;video src="https://u.peppe.rs/GF.mp4" controls=""&gt;&lt;a href="https://u.peppe.rs/GF.mp4"&gt;Day 3&lt;/a&gt;&lt;/video&gt;&lt;figcaption aria-hidden="true"&gt;Day 3&lt;/figcaption&gt; 1374&lt;video src="https://u.peppe.rs/GF.mp4" controls=""&gt;&lt;a
1375href="https://u.peppe.rs/GF.mp4"&gt;Day 3&lt;/a&gt;&lt;/video&gt;
1376&lt;figcaption aria-hidden="true"&gt;Day 3&lt;/figcaption&gt;
882&lt;/figure&gt; 1377&lt;/figure&gt;
883&lt;h3 id="day-2"&gt;Day 2&lt;/h3&gt; 1378&lt;h3 id="day-2"&gt;Day 2&lt;/h3&gt;
884&lt;p&gt;I started figuring out event handling today. Implemented a couple of keybinds to zoom in/out of the drawing area. Conversions of SDL2 coordinates (measured in signed 32 bit integers) to my internal “drawing area” coordinates (measured in unsigned 32 bit integers) is very annoying. Hopefully the unchecked conversions won’t haunt me later.&lt;/p&gt; 1379&lt;p&gt;I started figuring out event handling today. Implemented a couple of
1380keybinds to zoom in/out of the drawing area. Conversions of SDL2
1381coordinates (measured in signed 32 bit integers) to my internal “drawing
1382area” coordinates (measured in unsigned 32 bit integers) is very
1383annoying. Hopefully the unchecked conversions won’t haunt me later.&lt;/p&gt;
885&lt;figure&gt; 1384&lt;figure&gt;
886&lt;video src="https://u.peppe.rs/L4.mp4" controls=""&gt;&lt;a href="https://u.peppe.rs/L4.mp4"&gt;Day 2&lt;/a&gt;&lt;/video&gt;&lt;figcaption aria-hidden="true"&gt;Day 2&lt;/figcaption&gt; 1385&lt;video src="https://u.peppe.rs/L4.mp4" controls=""&gt;&lt;a
1386href="https://u.peppe.rs/L4.mp4"&gt;Day 2&lt;/a&gt;&lt;/video&gt;
1387&lt;figcaption aria-hidden="true"&gt;Day 2&lt;/figcaption&gt;
887&lt;/figure&gt; 1388&lt;/figure&gt;
888&lt;h3 id="day-1"&gt;Day 1&lt;/h3&gt; 1389&lt;h3 id="day-1"&gt;Day 1&lt;/h3&gt;
889&lt;p&gt;Getting started with Rust and SDL2 is very straightforward. The &lt;code&gt;rust-sdl2&lt;/code&gt; library contains some detailed examples that allowed me to get all the way to drawing a grid from a &lt;code&gt;Vec&amp;lt;bool&amp;gt;&lt;/code&gt;:&lt;/p&gt; 1390&lt;p&gt;Getting started with Rust and SDL2 is very straightforward. The
1391&lt;code&gt;rust-sdl2&lt;/code&gt; library contains some detailed examples that
1392allowed me to get all the way to drawing a grid from a
1393&lt;code&gt;Vec&amp;lt;bool&amp;gt;&lt;/code&gt;:&lt;/p&gt;
890&lt;figure&gt; 1394&lt;figure&gt;
891&lt;img src="https://u.peppe.rs/Ma.png" alt="Day 1" /&gt;&lt;figcaption aria-hidden="true"&gt;Day 1&lt;/figcaption&gt; 1395&lt;img src="https://u.peppe.rs/Ma.png" alt="Day 1" /&gt;
1396&lt;figcaption aria-hidden="true"&gt;Day 1&lt;/figcaption&gt;
892&lt;/figure&gt;</description> 1397&lt;/figure&gt;</description>
893<link>https://peppe.rs/posts/SDL2_devlog/</link> 1398<link>https://peppe.rs/posts/SDL2_devlog/</link>
894<pubDate>Sun, 11 Apr 2021 10:46:00 +0000</pubDate> 1399<pubDate>Sun, 11 Apr 2021 10:46:00 +0000</pubDate>
@@ -896,11 +1401,21 @@ H N E I
896</item> 1401</item>
897<item> 1402<item>
898<title>Self-hosting Git</title> 1403<title>Self-hosting Git</title>
899<description>&lt;p&gt;Earlier this week, I began migrating my repositories from Github to &lt;a href="https://git.zx2c4.com/cgit/about/"&gt;cgit&lt;/a&gt;. If you care at all about big corporates turning open-source into a T-shirt farming service, this is the way to go.&lt;/p&gt; 1404<description>&lt;p&gt;Earlier this week, I began migrating my repositories from Github to
1405&lt;a href="https://git.zx2c4.com/cgit/about/"&gt;cgit&lt;/a&gt;. If you care at all
1406about big corporates turning open-source into a T-shirt farming service,
1407this is the way to go.&lt;/p&gt;
900&lt;h3 id="offerings"&gt;Offerings&lt;/h3&gt; 1408&lt;h3 id="offerings"&gt;Offerings&lt;/h3&gt;
901&lt;p&gt;cgit is &lt;em&gt;very&lt;/em&gt; bare bones. It is &lt;a href="https://tools.ietf.org/html/rfc3875"&gt;cgi-based&lt;/a&gt; web interface to git, and nothing more. You may browse repositories, view diffs, commit logs and even clone via http. If you are looking to replace Github with cgit, keep in mind that cgit does not handle issues or pull/merge requests. If people wish to contribute to your work, they would have to send you a patch via email.&lt;/p&gt; 1409&lt;p&gt;cgit is &lt;em&gt;very&lt;/em&gt; bare bones. It is &lt;a
1410href="https://tools.ietf.org/html/rfc3875"&gt;cgi-based&lt;/a&gt; web interface
1411to git, and nothing more. You may browse repositories, view diffs,
1412commit logs and even clone via http. If you are looking to replace
1413Github with cgit, keep in mind that cgit does not handle issues or
1414pull/merge requests. If people wish to contribute to your work, they
1415would have to send you a patch via email.&lt;/p&gt;
902&lt;h3 id="setup"&gt;Setup&lt;/h3&gt; 1416&lt;h3 id="setup"&gt;Setup&lt;/h3&gt;
903&lt;p&gt;Installing cgit is fairly straightforward, if you would like to compile it from source:&lt;/p&gt; 1417&lt;p&gt;Installing cgit is fairly straightforward, if you would like to
1418compile it from source:&lt;/p&gt;
904&lt;div class="sourceCode" id="cb1"&gt;&lt;pre class="sourceCode sh"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# fetch&lt;/span&gt;&lt;/span&gt; 1419&lt;div class="sourceCode" id="cb1"&gt;&lt;pre class="sourceCode sh"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# fetch&lt;/span&gt;&lt;/span&gt;
905&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;git&lt;/span&gt; clone https://git.zx2c4.com &lt;span class="kw"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="bu"&gt;cd&lt;/span&gt; cgit&lt;/span&gt; 1420&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;git&lt;/span&gt; clone https://git.zx2c4.com &lt;span class="kw"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="bu"&gt;cd&lt;/span&gt; cgit&lt;/span&gt;
906&lt;span id="cb1-3"&gt;&lt;a href="#cb1-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;git&lt;/span&gt; submodule init&lt;/span&gt; 1421&lt;span id="cb1-3"&gt;&lt;a href="#cb1-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;git&lt;/span&gt; submodule init&lt;/span&gt;
@@ -909,9 +1424,16 @@ H N E I
909&lt;span id="cb1-6"&gt;&lt;a href="#cb1-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# install&lt;/span&gt;&lt;/span&gt; 1424&lt;span id="cb1-6"&gt;&lt;a href="#cb1-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# install&lt;/span&gt;&lt;/span&gt;
910&lt;span id="cb1-7"&gt;&lt;a href="#cb1-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;make&lt;/span&gt; NO_LUA=1&lt;/span&gt; 1425&lt;span id="cb1-7"&gt;&lt;a href="#cb1-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;make&lt;/span&gt; NO_LUA=1&lt;/span&gt;
911&lt;span id="cb1-8"&gt;&lt;a href="#cb1-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;sudo&lt;/span&gt; make install&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1426&lt;span id="cb1-8"&gt;&lt;a href="#cb1-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;sudo&lt;/span&gt; make install&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
912&lt;p&gt;This would drop the cgit cgi script (and the default css) into &lt;code&gt;/var/www/htdocs/cgit&lt;/code&gt;. You may configure cgit by editing &lt;code&gt;/etc/cgitrc&lt;/code&gt;. I specify the &lt;code&gt;NO_LUA&lt;/code&gt; flag to compile without lua support, exclude that flag if you would like to extend cgit via lua scripts.&lt;/p&gt; 1427&lt;p&gt;This would drop the cgit cgi script (and the default css) into
1428&lt;code&gt;/var/www/htdocs/cgit&lt;/code&gt;. You may configure cgit by editing
1429&lt;code&gt;/etc/cgitrc&lt;/code&gt;. I specify the &lt;code&gt;NO_LUA&lt;/code&gt; flag to
1430compile without lua support, exclude that flag if you would like to
1431extend cgit via lua scripts.&lt;/p&gt;
913&lt;h3 id="going-live"&gt;Going live&lt;/h3&gt; 1432&lt;h3 id="going-live"&gt;Going live&lt;/h3&gt;
914&lt;p&gt;You might want to use, &lt;a href="https://github.com/gnosek/fcgiwrap"&gt;fcgiwrap&lt;/a&gt;, a &lt;a href="http://www.nongnu.org/fastcgi"&gt;fastcgi&lt;/a&gt; wrapper for &lt;code&gt;cgi&lt;/code&gt; scripts,&lt;/p&gt; 1433&lt;p&gt;You might want to use, &lt;a
1434href="https://github.com/gnosek/fcgiwrap"&gt;fcgiwrap&lt;/a&gt;, a &lt;a
1435href="http://www.nongnu.org/fastcgi"&gt;fastcgi&lt;/a&gt; wrapper for
1436&lt;code&gt;cgi&lt;/code&gt; scripts,&lt;/p&gt;
915&lt;div class="sourceCode" id="cb2"&gt;&lt;pre class="sourceCode sh"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;sudo&lt;/span&gt; apt install fcgiwrap&lt;/span&gt; 1437&lt;div class="sourceCode" id="cb2"&gt;&lt;pre class="sourceCode sh"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;sudo&lt;/span&gt; apt install fcgiwrap&lt;/span&gt;
916&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;sudo&lt;/span&gt; systemctl start fcgiwrap.socket&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1438&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;sudo&lt;/span&gt; systemctl start fcgiwrap.socket&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
917&lt;p&gt;Expose the cgit cgi script to the web via &lt;code&gt;nginx&lt;/code&gt;:&lt;/p&gt; 1439&lt;p&gt;Expose the cgit cgi script to the web via &lt;code&gt;nginx&lt;/code&gt;:&lt;/p&gt;
@@ -935,15 +1457,21 @@ server {
935&lt;p&gt;Point cgit to your git repositories:&lt;/p&gt; 1457&lt;p&gt;Point cgit to your git repositories:&lt;/p&gt;
936&lt;pre&gt;&lt;code&gt;# /etc/cgitrc 1458&lt;pre&gt;&lt;code&gt;# /etc/cgitrc
937scan-path=/path/to/git/repos&lt;/code&gt;&lt;/pre&gt; 1459scan-path=/path/to/git/repos&lt;/code&gt;&lt;/pre&gt;
938&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note&lt;/em&gt;&lt;/strong&gt;: &lt;em&gt;&lt;code&gt;scan-path&lt;/code&gt; works best if you stick it at the end of your &lt;code&gt;cgitrc&lt;/code&gt;&lt;/em&gt;.&lt;/p&gt; 1460&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note&lt;/em&gt;&lt;/strong&gt;: &lt;em&gt;&lt;code&gt;scan-path&lt;/code&gt; works best
939&lt;p&gt;You may now create remote repositories at &lt;code&gt;/path/to/git/repos&lt;/code&gt;, via:&lt;/p&gt; 1461if you stick it at the end of your &lt;code&gt;cgitrc&lt;/code&gt;&lt;/em&gt;.&lt;/p&gt;
1462&lt;p&gt;You may now create remote repositories at
1463&lt;code&gt;/path/to/git/repos&lt;/code&gt;, via:&lt;/p&gt;
940&lt;pre&gt;&lt;code&gt;git init --bare&lt;/code&gt;&lt;/pre&gt; 1464&lt;pre&gt;&lt;code&gt;git init --bare&lt;/code&gt;&lt;/pre&gt;
941&lt;p&gt;Add the remote to your local repository:&lt;/p&gt; 1465&lt;p&gt;Add the remote to your local repository:&lt;/p&gt;
942&lt;pre&gt;&lt;code&gt;git remote set-url origin user@remote:/above/path 1466&lt;pre&gt;&lt;code&gt;git remote set-url origin user@remote:/above/path
943git push origin master&lt;/code&gt;&lt;/pre&gt; 1467git push origin master&lt;/code&gt;&lt;/pre&gt;
944&lt;h3 id="configuration"&gt;Configuration&lt;/h3&gt; 1468&lt;h3 id="configuration"&gt;Configuration&lt;/h3&gt;
945&lt;p&gt;cgit is fairly easy to configure, all configuration options can be found &lt;a href="https://git.zx2c4.com/cgit/tree/cgitrc.5.txt"&gt;in the manual&lt;/a&gt;, here are a couple of cool ones though:&lt;/p&gt; 1469&lt;p&gt;cgit is fairly easy to configure, all configuration options can be
946&lt;p&gt;&lt;strong&gt;enable-commit-graph&lt;/strong&gt;: Generates a text based graphical representation of the commit history, similar to &lt;code&gt;git log --graph --oneline&lt;/code&gt;.&lt;/p&gt; 1470found &lt;a href="https://git.zx2c4.com/cgit/tree/cgitrc.5.txt"&gt;in the
1471manual&lt;/a&gt;, here are a couple of cool ones though:&lt;/p&gt;
1472&lt;p&gt;&lt;strong&gt;enable-commit-graph&lt;/strong&gt;: Generates a text based
1473graphical representation of the commit history, similar to
1474&lt;code&gt;git log --graph --oneline&lt;/code&gt;.&lt;/p&gt;
947&lt;pre&gt;&lt;code&gt;| * | Add support for configuration file 1475&lt;pre&gt;&lt;code&gt;| * | Add support for configuration file
948* | | simplify command parsing logic 1476* | | simplify command parsing logic
949* | | Refactor parsers 1477* | | Refactor parsers
@@ -964,7 +1492,11 @@ git push origin master&lt;/code&gt;&lt;/pre&gt;
964| | * | Merge branch &amp;#39;fix/duplicate-habits&amp;#39; 1492| | * | Merge branch &amp;#39;fix/duplicate-habits&amp;#39;
965| | |\ \ 1493| | |\ \
966| | | * | move duplicate check to command parsing blo...&lt;/code&gt;&lt;/pre&gt; 1494| | | * | move duplicate check to command parsing blo...&lt;/code&gt;&lt;/pre&gt;
967&lt;p&gt;&lt;strong&gt;section-from-path&lt;/strong&gt;: This option paired with &lt;code&gt;scan-path&lt;/code&gt; will automatically generate sections in your cgit index page, from the path to each repo. For example, the directory structure used to generate sections on &lt;a href="https://git.peppe.rs"&gt;my cgit instance&lt;/a&gt; looks like this:&lt;/p&gt; 1495&lt;p&gt;&lt;strong&gt;section-from-path&lt;/strong&gt;: This option paired with
1496&lt;code&gt;scan-path&lt;/code&gt; will automatically generate sections in your cgit
1497index page, from the path to each repo. For example, the directory
1498structure used to generate sections on &lt;a href="https://git.peppe.rs"&gt;my
1499cgit instance&lt;/a&gt; looks like this:&lt;/p&gt;
968&lt;pre&gt;&lt;code&gt;├── cli 1500&lt;pre&gt;&lt;code&gt;├── cli
969│ ├── dijo 1501│ ├── dijo
970│ ├── eva 1502│ ├── eva
@@ -988,11 +1520,18 @@ git push origin master&lt;/code&gt;&lt;/pre&gt;
988└── web 1520└── web
989 └── isostatic&lt;/code&gt;&lt;/pre&gt; 1521 └── isostatic&lt;/code&gt;&lt;/pre&gt;
990&lt;h3 id="ease-of-use"&gt;Ease of use&lt;/h3&gt; 1522&lt;h3 id="ease-of-use"&gt;Ease of use&lt;/h3&gt;
991&lt;p&gt;As I mentioned before, &lt;code&gt;cgit&lt;/code&gt; is simply a view into your git repositories, you will have to manually create new repositories by entering your remote and using &lt;code&gt;git init --bare&lt;/code&gt;. Here are a couple of scripts I wrote to perform actions on remotes, think of it as a smaller version of Github’s &lt;code&gt;gh&lt;/code&gt; program.&lt;/p&gt; 1523&lt;p&gt;As I mentioned before, &lt;code&gt;cgit&lt;/code&gt; is simply a view into your
992&lt;p&gt;You may save these scripts as &lt;code&gt;git-script-name&lt;/code&gt; and drop them in your &lt;code&gt;$PATH&lt;/code&gt;, and git will automatically add an alias called &lt;code&gt;script-name&lt;/code&gt;, callable via:&lt;/p&gt; 1524git repositories, you will have to manually create new repositories by
1525entering your remote and using &lt;code&gt;git init --bare&lt;/code&gt;. Here are a
1526couple of scripts I wrote to perform actions on remotes, think of it as
1527a smaller version of Github’s &lt;code&gt;gh&lt;/code&gt; program.&lt;/p&gt;
1528&lt;p&gt;You may save these scripts as &lt;code&gt;git-script-name&lt;/code&gt; and drop
1529them in your &lt;code&gt;$PATH&lt;/code&gt;, and git will automatically add an alias
1530called &lt;code&gt;script-name&lt;/code&gt;, callable via:&lt;/p&gt;
993&lt;pre&gt;&lt;code&gt;git script-name&lt;/code&gt;&lt;/pre&gt; 1531&lt;pre&gt;&lt;code&gt;git script-name&lt;/code&gt;&lt;/pre&gt;
994&lt;h4 id="git-new-repo"&gt;git-new-repo&lt;/h4&gt; 1532&lt;h4 id="git-new-repo"&gt;git-new-repo&lt;/h4&gt;
995&lt;p&gt;Creates a new repository on your remote, the first arg may be a path (section/repo-name) or just the repo name:&lt;/p&gt; 1533&lt;p&gt;Creates a new repository on your remote, the first arg may be a path
1534(section/repo-name) or just the repo name:&lt;/p&gt;
996&lt;pre&gt;&lt;code&gt;#! /usr/bin/env bash 1535&lt;pre&gt;&lt;code&gt;#! /usr/bin/env bash
997# 1536#
998# usage: 1537# usage:
@@ -1009,7 +1548,10 @@ fi
1009 1548
1010ssh user@remote git init --bare &amp;quot;$1&amp;quot;;&lt;/code&gt;&lt;/pre&gt; 1549ssh user@remote git init --bare &amp;quot;$1&amp;quot;;&lt;/code&gt;&lt;/pre&gt;
1011&lt;h4 id="git-set-desc"&gt;git-set-desc&lt;/h4&gt; 1550&lt;h4 id="git-set-desc"&gt;git-set-desc&lt;/h4&gt;
1012&lt;p&gt;To set a one line repository description. It simply copies the local &lt;code&gt;.git/description&lt;/code&gt;, into &lt;code&gt;remote/description&lt;/code&gt;. &lt;code&gt;cgit&lt;/code&gt; displays the contents of this file on the index page:&lt;/p&gt; 1551&lt;p&gt;To set a one line repository description. It simply copies the local
1552&lt;code&gt;.git/description&lt;/code&gt;, into &lt;code&gt;remote/description&lt;/code&gt;.
1553&lt;code&gt;cgit&lt;/code&gt; displays the contents of this file on the index
1554page:&lt;/p&gt;
1013&lt;pre&gt;&lt;code&gt;#! /usr/bin/env bash 1555&lt;pre&gt;&lt;code&gt;#! /usr/bin/env bash
1014# 1556#
1015# usage: 1557# usage:
@@ -1024,11 +1566,24 @@ scp .git/description &amp;quot;$remote/description&amp;quot;&lt;/code&gt;&lt;/pr
1024</item> 1566</item>
1025<item> 1567<item>
1026<title>NixOS</title> 1568<title>NixOS</title>
1027<description>&lt;p&gt;I have been eyeing operating systems with functional package managers for a while now, aka, NixOS or Guix. Reproducible builds, declarative and rollback-able system configuration, system consistency, all sound pretty cool. I have been using NixOS for about a month now.&lt;/p&gt; 1569<description>&lt;p&gt;I have been eyeing operating systems with functional package managers
1570for a while now, aka, NixOS or Guix. Reproducible builds, declarative
1571and rollback-able system configuration, system consistency, all sound
1572pretty cool. I have been using NixOS for about a month now.&lt;/p&gt;
1028&lt;h3 id="installation"&gt;Installation&lt;/h3&gt; 1573&lt;h3 id="installation"&gt;Installation&lt;/h3&gt;
1029&lt;p&gt;I went with their minimal installation ISO. The installation was pretty smooth from start to end, no hitches there. The entire &lt;a href="https://nixos.org/manual/nixos/stable/"&gt;manual&lt;/a&gt; is available offline, and is accessible during the installation. Very handy.&lt;/p&gt; 1574&lt;p&gt;I went with their minimal installation ISO. The installation was
1575pretty smooth from start to end, no hitches there. The entire &lt;a
1576href="https://nixos.org/manual/nixos/stable/"&gt;manual&lt;/a&gt; is available
1577offline, and is accessible during the installation. Very handy.&lt;/p&gt;
1030&lt;h3 id="setup"&gt;Setup&lt;/h3&gt; 1578&lt;h3 id="setup"&gt;Setup&lt;/h3&gt;
1031&lt;p&gt;The entire system is configured via &lt;code&gt;/etc/nixos/configuration.nix&lt;/code&gt;. Wifi, &lt;code&gt;libinput&lt;/code&gt; gestures, audio, locale settings, there are options for literally everything. You can declaratively write down the packages you want installed too. With fresh installs of most distros, I usually fumble with getting things like screen backlight and media keys to work. If I do manage to fix it, I can’t carry it forward to future installations trivially. Getting all my hardware to work on NixOS is as easy as:&lt;/p&gt; 1579&lt;p&gt;The entire system is configured via
1580&lt;code&gt;/etc/nixos/configuration.nix&lt;/code&gt;. Wifi, &lt;code&gt;libinput&lt;/code&gt;
1581gestures, audio, locale settings, there are options for literally
1582everything. You can declaratively write down the packages you want
1583installed too. With fresh installs of most distros, I usually fumble
1584with getting things like screen backlight and media keys to work. If I
1585do manage to fix it, I can’t carry it forward to future installations
1586trivially. Getting all my hardware to work on NixOS is as easy as:&lt;/p&gt;
1032&lt;pre&gt;&lt;code&gt;{ 1587&lt;pre&gt;&lt;code&gt;{
1033 server.xserver.libinput.enable = true; # touchpad 1588 server.xserver.libinput.enable = true; # touchpad
1034 programs.light.enable = true; # backlight 1589 programs.light.enable = true; # backlight
@@ -1036,37 +1591,77 @@ scp .git/description &amp;quot;$remote/description&amp;quot;&lt;/code&gt;&lt;/pr
1036 networking.wireless.enable = true; # wifi 1591 networking.wireless.enable = true; # wifi
1037}&lt;/code&gt;&lt;/pre&gt; 1592}&lt;/code&gt;&lt;/pre&gt;
1038&lt;h3 id="developing-with-nix"&gt;Developing with Nix&lt;/h3&gt; 1593&lt;h3 id="developing-with-nix"&gt;Developing with Nix&lt;/h3&gt;
1039&lt;p&gt;Nix makes it easy to enter environments that aren’t affected by your system configuration using &lt;code&gt;nix-shell&lt;/code&gt;.&lt;/p&gt; 1594&lt;p&gt;Nix makes it easy to enter environments that aren’t affected by your
1040&lt;p&gt;Builds may be generated by specifying a &lt;code&gt;default.nix&lt;/code&gt; file, and running &lt;code&gt;nix-build&lt;/code&gt;. Conventional package managers require you to specify a dependency list, but there is no guarantee that this list is complete. The package will build on your machine even if you forget a dependency. However, with Nix, packages are installed to &lt;code&gt;/nix/store&lt;/code&gt;, and not global paths such as &lt;code&gt;/usr/bin/...&lt;/code&gt;, if your project builds, it means you have included every last one.&lt;/p&gt; 1595system configuration using &lt;code&gt;nix-shell&lt;/code&gt;.&lt;/p&gt;
1041&lt;p&gt;Issues on most my projects have been “unable to build because &lt;code&gt;libxcb&lt;/code&gt; is missing”, or “this version of &lt;code&gt;openssl&lt;/code&gt; is too old”. Tools like &lt;code&gt;cargo&lt;/code&gt; and &lt;code&gt;pip&lt;/code&gt; are poor package managers. While they &lt;em&gt;can&lt;/em&gt; guarantee that Rust or Python dependencies are met, they make assumptions about the target system.&lt;/p&gt; 1596&lt;p&gt;Builds may be generated by specifying a &lt;code&gt;default.nix&lt;/code&gt;
1042&lt;p&gt;For example, &lt;a href="https://github.com/nerdypepper/site"&gt;this website&lt;/a&gt; is now built using Nix, anyone using Nix may simply, clone the repository and run &lt;code&gt;./generate.sh&lt;/code&gt;, and it would &lt;em&gt;just work&lt;/em&gt;, while keeping your global namespace clean™:&lt;/p&gt; 1597file, and running &lt;code&gt;nix-build&lt;/code&gt;. Conventional package managers
1043&lt;div class="sourceCode" id="cb2"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;#! /usr/bin/env nix-shell&lt;/span&gt;&lt;/span&gt; 1598require you to specify a dependency list, but there is no guarantee that
1599this list is complete. The package will build on your machine even if
1600you forget a dependency. However, with Nix, packages are installed to
1601&lt;code&gt;/nix/store&lt;/code&gt;, and not global paths such as
1602&lt;code&gt;/usr/bin/...&lt;/code&gt;, if your project builds, it means you have
1603included every last one.&lt;/p&gt;
1604&lt;p&gt;Issues on most my projects have been “unable to build because
1605&lt;code&gt;libxcb&lt;/code&gt; is missing”, or “this version of
1606&lt;code&gt;openssl&lt;/code&gt; is too old”. Tools like &lt;code&gt;cargo&lt;/code&gt; and
1607&lt;code&gt;pip&lt;/code&gt; are poor package managers. While they &lt;em&gt;can&lt;/em&gt;
1608guarantee that Rust or Python dependencies are met, they make
1609assumptions about the target system.&lt;/p&gt;
1610&lt;p&gt;For example, &lt;a href="https://github.com/nerdypepper/site"&gt;this
1611website&lt;/a&gt; is now built using Nix, anyone using Nix may simply, clone
1612the repository and run &lt;code&gt;./generate.sh&lt;/code&gt;, and it would &lt;em&gt;just
1613work&lt;/em&gt;, while keeping your global namespace clean™:&lt;/p&gt;
1614&lt;div class="sourceCode" id="cb2"&gt;&lt;pre
1615class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;#! /usr/bin/env nix-shell&lt;/span&gt;&lt;/span&gt;
1044&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;#! nix-shell -i bash -p eva pandoc esh&lt;/span&gt;&lt;/span&gt; 1616&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;#! nix-shell -i bash -p eva pandoc esh&lt;/span&gt;&lt;/span&gt;
1045&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 1617&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1046&lt;span id="cb2-4"&gt;&lt;a href="#cb2-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# some bash magic ;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1618&lt;span id="cb2-4"&gt;&lt;a href="#cb2-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# some bash magic ;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1047&lt;p&gt;Dependencies are included with the &lt;code&gt;-p&lt;/code&gt; flag, the shell script is executed with an interpreter, specified with the &lt;code&gt;-i&lt;/code&gt; flag.&lt;/p&gt; 1619&lt;p&gt;Dependencies are included with the &lt;code&gt;-p&lt;/code&gt; flag, the shell
1620script is executed with an interpreter, specified with the
1621&lt;code&gt;-i&lt;/code&gt; flag.&lt;/p&gt;
1048&lt;h3 id="impressions"&gt;Impressions&lt;/h3&gt; 1622&lt;h3 id="impressions"&gt;Impressions&lt;/h3&gt;
1049&lt;p&gt;NixOS is by no means, simple. As a newcomer, using Nix was not easy, heck, I had to learn a purely functional, lazy language to just build programs. There is a lot to be desired on the tooling front as well. A well fleshed out LSP plugin would be nice (&lt;a href="https://github.com/nix-community/rnix-lsp"&gt;rnix-lsp looks promising&lt;/a&gt;).&lt;/p&gt; 1623&lt;p&gt;NixOS is by no means, simple. As a newcomer, using Nix was not easy,
1050&lt;p&gt;Being able to rollback changes at a system level is cool. Package broke something? Just &lt;code&gt;nixos-rebuild switch --rollback&lt;/code&gt;! Deleted &lt;code&gt;nix&lt;/code&gt; by mistake? Find the binary in &lt;code&gt;/nix/store&lt;/code&gt; and rollback! You aren’t punished for not thinking twice.&lt;/p&gt; 1624heck, I had to learn a purely functional, lazy language to just build
1051&lt;p&gt;I don’t see myself switching to anything else in the near future, NixOS does a lot of things right. If I ever need to reinstall NixOS, I can generate an &lt;a href="https://github.com/nix-community/nixos-generators"&gt;image of my current system&lt;/a&gt;.&lt;/p&gt; 1625programs. There is a lot to be desired on the tooling front as well. A
1052&lt;p&gt;&lt;a href="https://u.peppe.rs/6m.png"&gt;&lt;img src="https://u.peppe.rs/6m.png" /&gt;&lt;/a&gt;&lt;/p&gt;</description> 1626well fleshed out LSP plugin would be nice (&lt;a
1627href="https://github.com/nix-community/rnix-lsp"&gt;rnix-lsp looks
1628promising&lt;/a&gt;).&lt;/p&gt;
1629&lt;p&gt;Being able to rollback changes at a system level is cool. Package
1630broke something? Just &lt;code&gt;nixos-rebuild switch --rollback&lt;/code&gt;!
1631Deleted &lt;code&gt;nix&lt;/code&gt; by mistake? Find the binary in
1632&lt;code&gt;/nix/store&lt;/code&gt; and rollback! You aren’t punished for not
1633thinking twice.&lt;/p&gt;
1634&lt;p&gt;I don’t see myself switching to anything else in the near future,
1635NixOS does a lot of things right. If I ever need to reinstall NixOS, I
1636can generate an &lt;a
1637href="https://github.com/nix-community/nixos-generators"&gt;image of my
1638current system&lt;/a&gt;.&lt;/p&gt;
1639&lt;p&gt;&lt;a href="https://u.peppe.rs/6m.png"&gt;&lt;img
1640src="https://u.peppe.rs/6m.png" /&gt;&lt;/a&gt;&lt;/p&gt;</description>
1053<link>https://peppe.rs/posts/nixOS/</link> 1641<link>https://peppe.rs/posts/nixOS/</link>
1054<pubDate>Tue, 01 Sep 2020 07:08:00 +0000</pubDate> 1642<pubDate>Tue, 01 Sep 2020 07:08:00 +0000</pubDate>
1055<guid>https://peppe.rs/posts/nixOS/</guid> 1643<guid>https://peppe.rs/posts/nixOS/</guid>
1056</item> 1644</item>
1057<item> 1645<item>
1058<title>Gripes With Go</title> 1646<title>Gripes With Go</title>
1059<description>&lt;p&gt;You’ve read a lot of posts about the shortcomings of the Go programming language, so what’s one more.&lt;/p&gt; 1647<description>&lt;p&gt;You’ve read a lot of posts about the shortcomings of the Go
1648programming language, so what’s one more.&lt;/p&gt;
1060&lt;ol type="1"&gt; 1649&lt;ol type="1"&gt;
1061&lt;li&gt;&lt;a href="#lack-of-sum-types"&gt;Lack of sum types&lt;/a&gt;&lt;/li&gt; 1650&lt;li&gt;&lt;a href="#lack-of-sum-types"&gt;Lack of sum types&lt;/a&gt;&lt;/li&gt;
1062&lt;li&gt;&lt;a href="#type-assertions"&gt;Type assertions&lt;/a&gt;&lt;/li&gt; 1651&lt;li&gt;&lt;a href="#type-assertions"&gt;Type assertions&lt;/a&gt;&lt;/li&gt;
1063&lt;li&gt;&lt;a href="#date-and-time"&gt;Date and Time&lt;/a&gt;&lt;/li&gt; 1652&lt;li&gt;&lt;a href="#date-and-time"&gt;Date and Time&lt;/a&gt;&lt;/li&gt;
1064&lt;li&gt;&lt;a href="#statements-over-expressions"&gt;Statements over Expressions&lt;/a&gt;&lt;/li&gt; 1653&lt;li&gt;&lt;a href="#statements-over-expressions"&gt;Statements over
1065&lt;li&gt;&lt;a href="#erroring-out-on-unused-variables"&gt;Erroring out on unused variables&lt;/a&gt;&lt;/li&gt; 1654Expressions&lt;/a&gt;&lt;/li&gt;
1655&lt;li&gt;&lt;a href="#erroring-out-on-unused-variables"&gt;Erroring out on unused
1656variables&lt;/a&gt;&lt;/li&gt;
1066&lt;li&gt;&lt;a href="#error-handling"&gt;Error handling&lt;/a&gt;&lt;/li&gt; 1657&lt;li&gt;&lt;a href="#error-handling"&gt;Error handling&lt;/a&gt;&lt;/li&gt;
1067&lt;/ol&gt; 1658&lt;/ol&gt;
1068&lt;h3 id="lack-of-sum-types"&gt;Lack of Sum types&lt;/h3&gt; 1659&lt;h3 id="lack-of-sum-types"&gt;Lack of Sum types&lt;/h3&gt;
1069&lt;p&gt;A “Sum” type is a data type that can hold one of many states at a given time, similar to how a boolean can hold a true or a false, not too different from an &lt;code&gt;enum&lt;/code&gt; type in C. Go lacks &lt;code&gt;enum&lt;/code&gt; types unfortunately, and you are forced to resort to crafting your own substitute.&lt;/p&gt; 1660&lt;p&gt;A “Sum” type is a data type that can hold one of many states at a
1661given time, similar to how a boolean can hold a true or a false, not too
1662different from an &lt;code&gt;enum&lt;/code&gt; type in C. Go lacks
1663&lt;code&gt;enum&lt;/code&gt; types unfortunately, and you are forced to resort to
1664crafting your own substitute.&lt;/p&gt;
1070&lt;p&gt;A type to represent gender for example:&lt;/p&gt; 1665&lt;p&gt;A type to represent gender for example:&lt;/p&gt;
1071&lt;div class="sourceCode" id="cb1"&gt;&lt;pre class="sourceCode go"&gt;&lt;code class="sourceCode go"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; Gender &lt;span class="dt"&gt;int&lt;/span&gt;&lt;/span&gt; 1666&lt;div class="sourceCode" id="cb1"&gt;&lt;pre class="sourceCode go"&gt;&lt;code class="sourceCode go"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; Gender &lt;span class="dt"&gt;int&lt;/span&gt;&lt;/span&gt;
1072&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 1667&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
@@ -1081,17 +1676,18 @@ scp .git/description &amp;quot;$remote/description&amp;quot;&lt;/code&gt;&lt;/pr
1081&lt;span id="cb1-11"&gt;&lt;a href="#cb1-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// Oops! We have to implement String() for Gender ...&lt;/span&gt;&lt;/span&gt; 1676&lt;span id="cb1-11"&gt;&lt;a href="#cb1-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// Oops! We have to implement String() for Gender ...&lt;/span&gt;&lt;/span&gt;
1082&lt;span id="cb1-12"&gt;&lt;a href="#cb1-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 1677&lt;span id="cb1-12"&gt;&lt;a href="#cb1-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1083&lt;span id="cb1-13"&gt;&lt;a href="#cb1-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;func&lt;/span&gt; &lt;span class="op"&gt;(&lt;/span&gt;g Gender&lt;span class="op"&gt;)&lt;/span&gt; String&lt;span class="op"&gt;()&lt;/span&gt; &lt;span class="dt"&gt;string&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 1678&lt;span id="cb1-13"&gt;&lt;a href="#cb1-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;func&lt;/span&gt; &lt;span class="op"&gt;(&lt;/span&gt;g Gender&lt;span class="op"&gt;)&lt;/span&gt; String&lt;span class="op"&gt;()&lt;/span&gt; &lt;span class="dt"&gt;string&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1084&lt;span id="cb1-14"&gt;&lt;a href="#cb1-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;switch&lt;/span&gt; &lt;span class="op"&gt;(&lt;/span&gt;g&lt;span class="op"&gt;)&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 1679&lt;span id="cb1-14"&gt;&lt;a href="#cb1-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;switch&lt;/span&gt; &lt;span class="op"&gt;(&lt;/span&gt;g&lt;span class="op"&gt;)&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1085&lt;span id="cb1-15"&gt;&lt;a href="#cb1-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;case&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Male&amp;quot;&lt;/span&gt;&lt;/span&gt; 1680&lt;span id="cb1-15"&gt;&lt;a href="#cb1-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;case&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Male&amp;quot;&lt;/span&gt;&lt;/span&gt;
1086&lt;span id="cb1-16"&gt;&lt;a href="#cb1-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;case&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Female&amp;quot;&lt;/span&gt;&lt;/span&gt; 1681&lt;span id="cb1-16"&gt;&lt;a href="#cb1-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;case&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Female&amp;quot;&lt;/span&gt;&lt;/span&gt;
1087&lt;span id="cb1-17"&gt;&lt;a href="#cb1-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;default&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Other&amp;quot;&lt;/span&gt;&lt;/span&gt; 1682&lt;span id="cb1-17"&gt;&lt;a href="#cb1-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;default&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Other&amp;quot;&lt;/span&gt;&lt;/span&gt;
1088&lt;span id="cb1-18"&gt;&lt;a href="#cb1-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 1683&lt;span id="cb1-18"&gt;&lt;a href="#cb1-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
1089&lt;span id="cb1-19"&gt;&lt;a href="#cb1-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 1684&lt;span id="cb1-19"&gt;&lt;a href="#cb1-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
1090&lt;span id="cb1-20"&gt;&lt;a href="#cb1-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 1685&lt;span id="cb1-20"&gt;&lt;a href="#cb1-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1091&lt;span id="cb1-21"&gt;&lt;a href="#cb1-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// You can accidentally do stupid stuff like:&lt;/span&gt;&lt;/span&gt; 1686&lt;span id="cb1-21"&gt;&lt;a href="#cb1-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// You can accidentally do stupid stuff like:&lt;/span&gt;&lt;/span&gt;
1092&lt;span id="cb1-22"&gt;&lt;a href="#cb1-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;gender &lt;span class="op"&gt;:=&lt;/span&gt; Male &lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1687&lt;span id="cb1-22"&gt;&lt;a href="#cb1-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;gender &lt;span class="op"&gt;:=&lt;/span&gt; Male &lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1093&lt;p&gt;The Haskell equivalent of the same:&lt;/p&gt; 1688&lt;p&gt;The Haskell equivalent of the same:&lt;/p&gt;
1094&lt;div class="sourceCode" id="cb2"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Gender&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Male&lt;/span&gt;&lt;/span&gt; 1689&lt;div class="sourceCode" id="cb2"&gt;&lt;pre
1690class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Gender&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Male&lt;/span&gt;&lt;/span&gt;
1095&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Female&lt;/span&gt;&lt;/span&gt; 1691&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Female&lt;/span&gt;&lt;/span&gt;
1096&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Other&lt;/span&gt;&lt;/span&gt; 1692&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Other&lt;/span&gt;&lt;/span&gt;
1097&lt;span id="cb2-4"&gt;&lt;a href="#cb2-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;)&lt;/span&gt; 1693&lt;span id="cb2-4"&gt;&lt;a href="#cb2-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;)&lt;/span&gt;
@@ -1102,7 +1698,7 @@ scp .git/description &amp;quot;$remote/description&amp;quot;&lt;/code&gt;&lt;/pr
1102&lt;p&gt;Type assertions in Go allow you to do:&lt;/p&gt; 1698&lt;p&gt;Type assertions in Go allow you to do:&lt;/p&gt;
1103&lt;div class="sourceCode" id="cb3"&gt;&lt;pre class="sourceCode go"&gt;&lt;code class="sourceCode go"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;var&lt;/span&gt; x &lt;span class="kw"&gt;interface&lt;/span&gt;&lt;span class="op"&gt;{}&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;7&lt;/span&gt;&lt;/span&gt; 1699&lt;div class="sourceCode" id="cb3"&gt;&lt;pre class="sourceCode go"&gt;&lt;code class="sourceCode go"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;var&lt;/span&gt; x &lt;span class="kw"&gt;interface&lt;/span&gt;&lt;span class="op"&gt;{}&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;7&lt;/span&gt;&lt;/span&gt;
1104&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;y&lt;span class="op"&gt;,&lt;/span&gt; goodToGo &lt;span class="op"&gt;:=&lt;/span&gt; x&lt;span class="op"&gt;.(&lt;/span&gt;&lt;span class="dt"&gt;int&lt;/span&gt;&lt;span class="op"&gt;)&lt;/span&gt;&lt;/span&gt; 1700&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;y&lt;span class="op"&gt;,&lt;/span&gt; goodToGo &lt;span class="op"&gt;:=&lt;/span&gt; x&lt;span class="op"&gt;.(&lt;/span&gt;&lt;span class="dt"&gt;int&lt;/span&gt;&lt;span class="op"&gt;)&lt;/span&gt;&lt;/span&gt;
1105&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;if&lt;/span&gt; goodToGo &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 1701&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;if&lt;/span&gt; goodToGo &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1106&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; fmt&lt;span class="op"&gt;.&lt;/span&gt;Println&lt;span class="op"&gt;(&lt;/span&gt;y&lt;span class="op"&gt;)&lt;/span&gt;&lt;/span&gt; 1702&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; fmt&lt;span class="op"&gt;.&lt;/span&gt;Println&lt;span class="op"&gt;(&lt;/span&gt;y&lt;span class="op"&gt;)&lt;/span&gt;&lt;/span&gt;
1107&lt;span id="cb3-5"&gt;&lt;a href="#cb3-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1703&lt;span id="cb3-5"&gt;&lt;a href="#cb3-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1108&lt;p&gt;The error check however is optional:&lt;/p&gt; 1704&lt;p&gt;The error check however is optional:&lt;/p&gt;
@@ -1112,18 +1708,32 @@ scp .git/description &amp;quot;$remote/description&amp;quot;&lt;/code&gt;&lt;/pr
1112&lt;span id="cb4-4"&gt;&lt;a href="#cb4-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// results in a runtime error:&lt;/span&gt;&lt;/span&gt; 1708&lt;span id="cb4-4"&gt;&lt;a href="#cb4-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// results in a runtime error:&lt;/span&gt;&lt;/span&gt;
1113&lt;span id="cb4-5"&gt;&lt;a href="#cb4-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// panic: interface conversion: interface {} is int, not float64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1709&lt;span id="cb4-5"&gt;&lt;a href="#cb4-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// panic: interface conversion: interface {} is int, not float64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1114&lt;h3 id="date-and-time"&gt;Date and Time&lt;/h3&gt; 1710&lt;h3 id="date-and-time"&gt;Date and Time&lt;/h3&gt;
1115&lt;p&gt;Anyone that has written Go previously, will probably already know what I am getting at here. For the uninitiated, parsing and formatting dates in Go requires a “layout”. This “layout” is based on magical reference date:&lt;/p&gt; 1711&lt;p&gt;Anyone that has written Go previously, will probably already know
1712what I am getting at here. For the uninitiated, parsing and formatting
1713dates in Go requires a “layout”. This “layout” is based on magical
1714reference date:&lt;/p&gt;
1116&lt;pre&gt;&lt;code&gt;Mon Jan 2 15:04:05 MST 2006&lt;/code&gt;&lt;/pre&gt; 1715&lt;pre&gt;&lt;code&gt;Mon Jan 2 15:04:05 MST 2006&lt;/code&gt;&lt;/pre&gt;
1117&lt;p&gt;Which is the date produced when you write the first seven natural numbers like so:&lt;/p&gt; 1716&lt;p&gt;Which is the date produced when you write the first seven natural
1717numbers like so:&lt;/p&gt;
1118&lt;pre&gt;&lt;code&gt;01/02 03:04:05 &amp;#39;06 -0700&lt;/code&gt;&lt;/pre&gt; 1718&lt;pre&gt;&lt;code&gt;01/02 03:04:05 &amp;#39;06 -0700&lt;/code&gt;&lt;/pre&gt;
1119&lt;p&gt;Parsing a string in &lt;code&gt;YYYY-MM-DD&lt;/code&gt; format would look something like:&lt;/p&gt; 1719&lt;p&gt;Parsing a string in &lt;code&gt;YYYY-MM-DD&lt;/code&gt; format would look
1720something like:&lt;/p&gt;
1120&lt;div class="sourceCode" id="cb7"&gt;&lt;pre class="sourceCode go"&gt;&lt;code class="sourceCode go"&gt;&lt;span id="cb7-1"&gt;&lt;a href="#cb7-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;const&lt;/span&gt; layout &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2006-01-02&amp;quot;&lt;/span&gt;&lt;/span&gt; 1721&lt;div class="sourceCode" id="cb7"&gt;&lt;pre class="sourceCode go"&gt;&lt;code class="sourceCode go"&gt;&lt;span id="cb7-1"&gt;&lt;a href="#cb7-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;const&lt;/span&gt; layout &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2006-01-02&amp;quot;&lt;/span&gt;&lt;/span&gt;
1121&lt;span id="cb7-2"&gt;&lt;a href="#cb7-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;time&lt;span class="op"&gt;.&lt;/span&gt;Parse&lt;span class="op"&gt;(&lt;/span&gt;layout&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2020-08-01&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1722&lt;span id="cb7-2"&gt;&lt;a href="#cb7-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;time&lt;span class="op"&gt;.&lt;/span&gt;Parse&lt;span class="op"&gt;(&lt;/span&gt;layout&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;2020-08-01&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1122&lt;p&gt;This so-called “intuitive” method of formatting dates doesn’t allow you to print &lt;code&gt;0000 hrs&lt;/code&gt; as &lt;code&gt;2400 hrs&lt;/code&gt;, it doesn’t allow you to omit the leading zero in 24 hour formats. It is rife with inconveniences, if only there were a &lt;a href="https://man7.org/linux/man-pages/man3/strftime.3.html"&gt;tried and tested&lt;/a&gt; date formatting convention …&lt;/p&gt; 1723&lt;p&gt;This so-called “intuitive” method of formatting dates doesn’t allow
1724you to print &lt;code&gt;0000 hrs&lt;/code&gt; as &lt;code&gt;2400 hrs&lt;/code&gt;, it doesn’t
1725allow you to omit the leading zero in 24 hour formats. It is rife with
1726inconveniences, if only there were a &lt;a
1727href="https://man7.org/linux/man-pages/man3/strftime.3.html"&gt;tried and
1728tested&lt;/a&gt; date formatting convention …&lt;/p&gt;
1123&lt;h3 id="statements-over-expressions"&gt;Statements over Expressions&lt;/h3&gt; 1729&lt;h3 id="statements-over-expressions"&gt;Statements over Expressions&lt;/h3&gt;
1124&lt;p&gt;Statements have side effects, expressions return values. More often than not, expressions are easier to understand at a glance: evaluate the LHS and assign the same to the RHS.&lt;/p&gt; 1730&lt;p&gt;Statements have side effects, expressions return values. More often
1125&lt;p&gt;Rust allows you to create local namespaces, and treats blocks (&lt;code&gt;{}&lt;/code&gt;) as expressions:&lt;/p&gt; 1731than not, expressions are easier to understand at a glance: evaluate the
1126&lt;div class="sourceCode" id="cb8"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb8-1"&gt;&lt;a href="#cb8-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; twenty_seven &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 1732LHS and assign the same to the RHS.&lt;/p&gt;
1733&lt;p&gt;Rust allows you to create local namespaces, and treats blocks
1734(&lt;code&gt;{}&lt;/code&gt;) as expressions:&lt;/p&gt;
1735&lt;div class="sourceCode" id="cb8"&gt;&lt;pre
1736class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb8-1"&gt;&lt;a href="#cb8-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; twenty_seven &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1127&lt;span id="cb8-2"&gt;&lt;a href="#cb8-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; three &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt; &lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 1737&lt;span id="cb8-2"&gt;&lt;a href="#cb8-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; three &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt; &lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1128&lt;span id="cb8-3"&gt;&lt;a href="#cb8-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; nine &lt;span class="op"&gt;=&lt;/span&gt; three &lt;span class="op"&gt;*&lt;/span&gt; three&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 1738&lt;span id="cb8-3"&gt;&lt;a href="#cb8-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; nine &lt;span class="op"&gt;=&lt;/span&gt; three &lt;span class="op"&gt;*&lt;/span&gt; three&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1129&lt;span id="cb8-4"&gt;&lt;a href="#cb8-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; nine &lt;span class="op"&gt;*&lt;/span&gt; three&lt;/span&gt; 1739&lt;span id="cb8-4"&gt;&lt;a href="#cb8-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; nine &lt;span class="op"&gt;*&lt;/span&gt; three&lt;/span&gt;
@@ -1134,17 +1744,25 @@ scp .git/description &amp;quot;$remote/description&amp;quot;&lt;/code&gt;&lt;/pr
1134&lt;span id="cb9-3"&gt;&lt;a href="#cb9-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;three &lt;span class="op"&gt;:=&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt; &lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;/span&gt; 1744&lt;span id="cb9-3"&gt;&lt;a href="#cb9-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;three &lt;span class="op"&gt;:=&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt; &lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;/span&gt;
1135&lt;span id="cb9-4"&gt;&lt;a href="#cb9-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;nine &lt;span class="op"&gt;:=&lt;/span&gt; three &lt;span class="op"&gt;*&lt;/span&gt; three&lt;/span&gt; 1745&lt;span id="cb9-4"&gt;&lt;a href="#cb9-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;nine &lt;span class="op"&gt;:=&lt;/span&gt; three &lt;span class="op"&gt;*&lt;/span&gt; three&lt;/span&gt;
1136&lt;span id="cb9-5"&gt;&lt;a href="#cb9-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;twenty_seven &lt;span class="op"&gt;=&lt;/span&gt; nine &lt;span class="op"&gt;*&lt;/span&gt; three&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1746&lt;span id="cb9-5"&gt;&lt;a href="#cb9-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;twenty_seven &lt;span class="op"&gt;=&lt;/span&gt; nine &lt;span class="op"&gt;*&lt;/span&gt; three&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1137&lt;h3 id="erroring-out-on-unused-variables"&gt;Erroring out on unused variables&lt;/h3&gt; 1747&lt;h3 id="erroring-out-on-unused-variables"&gt;Erroring out on unused
1138&lt;p&gt;Want to quickly prototype something? Go says no! In all seriousness, a warning would suffice, I don’t want to have to go back and comment each unused import out, only to come back and uncomment them a few seconds later.&lt;/p&gt; 1748variables&lt;/h3&gt;
1749&lt;p&gt;Want to quickly prototype something? Go says no! In all seriousness,
1750a warning would suffice, I don’t want to have to go back and comment
1751each unused import out, only to come back and uncomment them a few
1752seconds later.&lt;/p&gt;
1139&lt;h3 id="error-handling"&gt;Error handling&lt;/h3&gt; 1753&lt;h3 id="error-handling"&gt;Error handling&lt;/h3&gt;
1140&lt;div class="sourceCode" id="cb10"&gt;&lt;pre class="sourceCode go"&gt;&lt;code class="sourceCode go"&gt;&lt;span id="cb10-1"&gt;&lt;a href="#cb10-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;if&lt;/span&gt; err &lt;span class="op"&gt;!=&lt;/span&gt; &lt;span class="ot"&gt;nil&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1754&lt;div class="sourceCode" id="cb10"&gt;&lt;pre
1755class="sourceCode go"&gt;&lt;code class="sourceCode go"&gt;&lt;span id="cb10-1"&gt;&lt;a href="#cb10-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;if&lt;/span&gt; err &lt;span class="op"&gt;!=&lt;/span&gt; &lt;span class="ot"&gt;nil&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1141&lt;p&gt;Need I say more? I will, for good measure:&lt;/p&gt; 1756&lt;p&gt;Need I say more? I will, for good measure:&lt;/p&gt;
1142&lt;ol type="1"&gt; 1757&lt;ol type="1"&gt;
1143&lt;li&gt;Error handling is optional&lt;/li&gt; 1758&lt;li&gt;Error handling is optional&lt;/li&gt;
1144&lt;li&gt;Errors are propagated via a clunky &lt;code&gt;if&lt;/code&gt; + &lt;code&gt;return&lt;/code&gt; statement&lt;/li&gt; 1759&lt;li&gt;Errors are propagated via a clunky &lt;code&gt;if&lt;/code&gt; +
1760&lt;code&gt;return&lt;/code&gt; statement&lt;/li&gt;
1145&lt;/ol&gt; 1761&lt;/ol&gt;
1146&lt;p&gt;I prefer Haskell’s “Monadic” error handling, which is employed by Rust as well:&lt;/p&gt; 1762&lt;p&gt;I prefer Haskell’s “Monadic” error handling, which is employed by
1147&lt;div class="sourceCode" id="cb11"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb11-1"&gt;&lt;a href="#cb11-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// 1. error handling is compulsory&lt;/span&gt;&lt;/span&gt; 1763Rust as well:&lt;/p&gt;
1764&lt;div class="sourceCode" id="cb11"&gt;&lt;pre
1765class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb11-1"&gt;&lt;a href="#cb11-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// 1. error handling is compulsory&lt;/span&gt;&lt;/span&gt;
1148&lt;span id="cb11-2"&gt;&lt;a href="#cb11-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// 2. errors are propagated with the `?` operator&lt;/span&gt;&lt;/span&gt; 1766&lt;span id="cb11-2"&gt;&lt;a href="#cb11-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// 2. errors are propagated with the `?` operator&lt;/span&gt;&lt;/span&gt;
1149&lt;span id="cb11-3"&gt;&lt;a href="#cb11-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; foo() &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Result&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dt"&gt;String&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="pp"&gt;io::&lt;/span&gt;&lt;span class="bu"&gt;Error&lt;/span&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 1767&lt;span id="cb11-3"&gt;&lt;a href="#cb11-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; foo() &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Result&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dt"&gt;String&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="pp"&gt;io::&lt;/span&gt;&lt;span class="bu"&gt;Error&lt;/span&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1150&lt;span id="cb11-4"&gt;&lt;a href="#cb11-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; &lt;span class="kw"&gt;mut&lt;/span&gt; f &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;File::&lt;/span&gt;open(&lt;span class="st"&gt;&amp;quot;foo.txt&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;?;&lt;/span&gt; &lt;span class="co"&gt;// return if error&lt;/span&gt;&lt;/span&gt; 1768&lt;span id="cb11-4"&gt;&lt;a href="#cb11-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; &lt;span class="kw"&gt;mut&lt;/span&gt; f &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;File::&lt;/span&gt;open(&lt;span class="st"&gt;&amp;quot;foo.txt&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;?;&lt;/span&gt; &lt;span class="co"&gt;// return if error&lt;/span&gt;&lt;/span&gt;
@@ -1158,13 +1776,16 @@ scp .git/description &amp;quot;$remote/description&amp;quot;&lt;/code&gt;&lt;/pr
1158&lt;span id="cb11-12"&gt;&lt;a href="#cb11-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; main() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 1776&lt;span id="cb11-12"&gt;&lt;a href="#cb11-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; main() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1159&lt;span id="cb11-13"&gt;&lt;a href="#cb11-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="co"&gt;// `contents` is an enum known as Result:&lt;/span&gt;&lt;/span&gt; 1777&lt;span id="cb11-13"&gt;&lt;a href="#cb11-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="co"&gt;// `contents` is an enum known as Result:&lt;/span&gt;&lt;/span&gt;
1160&lt;span id="cb11-14"&gt;&lt;a href="#cb11-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; contents &lt;span class="op"&gt;=&lt;/span&gt; foo()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 1778&lt;span id="cb11-14"&gt;&lt;a href="#cb11-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; contents &lt;span class="op"&gt;=&lt;/span&gt; foo()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1161&lt;span id="cb11-15"&gt;&lt;a href="#cb11-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;match&lt;/span&gt; contents &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 1779&lt;span id="cb11-15"&gt;&lt;a href="#cb11-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;match&lt;/span&gt; contents &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1162&lt;span id="cb11-16"&gt;&lt;a href="#cb11-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cn"&gt;Ok&lt;/span&gt;(c) &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;println!&lt;/span&gt;(c)&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt; 1780&lt;span id="cb11-16"&gt;&lt;a href="#cb11-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cn"&gt;Ok&lt;/span&gt;(c) &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;println!&lt;/span&gt;(c)&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
1163&lt;span id="cb11-17"&gt;&lt;a href="#cb11-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cn"&gt;Err&lt;/span&gt;(e) &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;eprintln!&lt;/span&gt;(e)&lt;/span&gt; 1781&lt;span id="cb11-17"&gt;&lt;a href="#cb11-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cn"&gt;Err&lt;/span&gt;(e) &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;eprintln!&lt;/span&gt;(e)&lt;/span&gt;
1164&lt;span id="cb11-18"&gt;&lt;a href="#cb11-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 1782&lt;span id="cb11-18"&gt;&lt;a href="#cb11-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
1165&lt;span id="cb11-19"&gt;&lt;a href="#cb11-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1783&lt;span id="cb11-19"&gt;&lt;a href="#cb11-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1166&lt;h3 id="conclusion"&gt;Conclusion&lt;/h3&gt; 1784&lt;h3 id="conclusion"&gt;Conclusion&lt;/h3&gt;
1167&lt;p&gt;I did not want to conclude without talking about stylistic choices, lack of metaprogramming, bizzare export rules, but, I am too busy converting my &lt;code&gt;interface{}&lt;/code&gt; types into actual generic code for Go v2.&lt;/p&gt;</description> 1785&lt;p&gt;I did not want to conclude without talking about stylistic choices,
1786lack of metaprogramming, bizzare export rules, but, I am too busy
1787converting my &lt;code&gt;interface{}&lt;/code&gt; types into actual generic code
1788for Go v2.&lt;/p&gt;</description>
1168<link>https://peppe.rs/posts/gripes_with_go/</link> 1789<link>https://peppe.rs/posts/gripes_with_go/</link>
1169<pubDate>Sat, 01 Aug 2020 11:55:00 +0000</pubDate> 1790<pubDate>Sat, 01 Aug 2020 11:55:00 +0000</pubDate>
1170<guid>https://peppe.rs/posts/gripes_with_go/</guid> 1791<guid>https://peppe.rs/posts/gripes_with_go/</guid>
@@ -1173,12 +1794,26 @@ scp .git/description &amp;quot;$remote/description&amp;quot;&lt;/code&gt;&lt;/pr
1173<title>Turing Complete Type Systems</title> 1794<title>Turing Complete Type Systems</title>
1174<description>&lt;p&gt;Rust’s type system is Turing complete:&lt;/p&gt; 1795<description>&lt;p&gt;Rust’s type system is Turing complete:&lt;/p&gt;
1175&lt;ul&gt; 1796&lt;ul&gt;
1176&lt;li&gt;&lt;a href="https://github.com/doctorn/trait-eval/"&gt;FizzBuzz with Rust Traits&lt;/a&gt;&lt;/li&gt; 1797&lt;li&gt;&lt;a href="https://github.com/doctorn/trait-eval/"&gt;FizzBuzz with Rust
1177&lt;li&gt;&lt;a href="https://github.com/Ashymad/fortraith"&gt;A Forth implementation with Rust Traits&lt;/a&gt;&lt;/li&gt; 1798Traits&lt;/a&gt;&lt;/li&gt;
1799&lt;li&gt;&lt;a href="https://github.com/Ashymad/fortraith"&gt;A Forth
1800implementation with Rust Traits&lt;/a&gt;&lt;/li&gt;
1178&lt;/ul&gt; 1801&lt;/ul&gt;
1179&lt;p&gt;It is impossible to determine if a program written in a generally Turing complete system will ever stop. That is, it is impossible to write a program &lt;code&gt;f&lt;/code&gt; that determines if a program &lt;code&gt;g&lt;/code&gt;, where &lt;code&gt;g&lt;/code&gt; is written in a Turing complete programming language, will ever halt. The &lt;a href="https://en.wikipedia.org/wiki/Halting_problem"&gt;Halting Problem&lt;/a&gt; is in fact, an &lt;a href="https://en.wikipedia.org/wiki/Undecidable_problem"&gt;undecidable problem&lt;/a&gt;.&lt;/p&gt; 1802&lt;p&gt;It is impossible to determine if a program written in a generally
1803Turing complete system will ever stop. That is, it is impossible to
1804write a program &lt;code&gt;f&lt;/code&gt; that determines if a program
1805&lt;code&gt;g&lt;/code&gt;, where &lt;code&gt;g&lt;/code&gt; is written in a Turing complete
1806programming language, will ever halt. The &lt;a
1807href="https://en.wikipedia.org/wiki/Halting_problem"&gt;Halting Problem&lt;/a&gt;
1808is in fact, an &lt;a
1809href="https://en.wikipedia.org/wiki/Undecidable_problem"&gt;undecidable
1810problem&lt;/a&gt;.&lt;/p&gt;
1180&lt;p&gt;&lt;em&gt;How is any of this relevant?&lt;/em&gt;&lt;/p&gt; 1811&lt;p&gt;&lt;em&gt;How is any of this relevant?&lt;/em&gt;&lt;/p&gt;
1181&lt;p&gt;Rust performs compile-time type inference. The type checker, in turn, compiles and infers types, I would describe it as a compiler inside a compiler. It is possible that &lt;code&gt;rustc&lt;/code&gt; may never finish compiling your Rust program! I lied, &lt;code&gt;rustc&lt;/code&gt; stops after a while, after hitting the recursion limit.&lt;/p&gt; 1812&lt;p&gt;Rust performs compile-time type inference. The type checker, in turn,
1813compiles and infers types, I would describe it as a compiler inside a
1814compiler. It is possible that &lt;code&gt;rustc&lt;/code&gt; may never finish
1815compiling your Rust program! I lied, &lt;code&gt;rustc&lt;/code&gt; stops after a
1816while, after hitting the recursion limit.&lt;/p&gt;
1182&lt;p&gt;I understand that this post lacks content.&lt;/p&gt;</description> 1817&lt;p&gt;I understand that this post lacks content.&lt;/p&gt;</description>
1183<link>https://peppe.rs/posts/turing_complete_type_systems/</link> 1818<link>https://peppe.rs/posts/turing_complete_type_systems/</link>
1184<pubDate>Wed, 17 Jun 2020 18:30:00 +0000</pubDate> 1819<pubDate>Wed, 17 Jun 2020 18:30:00 +0000</pubDate>
@@ -1186,13 +1821,22 @@ scp .git/description &amp;quot;$remote/description&amp;quot;&lt;/code&gt;&lt;/pr
1186</item> 1821</item>
1187<item> 1822<item>
1188<title>Auto-currying Rust Functions</title> 1823<title>Auto-currying Rust Functions</title>
1189<description>&lt;p&gt;This post contains a gentle introduction to procedural macros in Rust and a guide to writing a procedural macro to curry Rust functions. The source code for the entire library can be found &lt;a href="https://github.com/nerdypepper/cutlass"&gt;here&lt;/a&gt;. It is also available on &lt;a href="https://crates.io/crates/cutlass"&gt;crates.io&lt;/a&gt;.&lt;/p&gt; 1824<description>&lt;p&gt;This post contains a gentle introduction to procedural macros in Rust
1190&lt;p&gt;The following links might prove to be useful before getting started:&lt;/p&gt; 1825and a guide to writing a procedural macro to curry Rust functions. The
1826source code for the entire library can be found &lt;a
1827href="https://github.com/nerdypepper/cutlass"&gt;here&lt;/a&gt;. It is also
1828available on &lt;a
1829href="https://crates.io/crates/cutlass"&gt;crates.io&lt;/a&gt;.&lt;/p&gt;
1830&lt;p&gt;The following links might prove to be useful before getting
1831started:&lt;/p&gt;
1191&lt;ul&gt; 1832&lt;ul&gt;
1192&lt;li&gt;&lt;a href="https://doc.rust-lang.org/reference/procedural-macros.html"&gt;Procedural Macros&lt;/a&gt;&lt;/li&gt; 1833&lt;li&gt;&lt;a
1834href="https://doc.rust-lang.org/reference/procedural-macros.html"&gt;Procedural
1835Macros&lt;/a&gt;&lt;/li&gt;
1193&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Currying"&gt;Currying&lt;/a&gt;&lt;/li&gt; 1836&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Currying"&gt;Currying&lt;/a&gt;&lt;/li&gt;
1194&lt;/ul&gt; 1837&lt;/ul&gt;
1195&lt;p&gt;Or you can pretend you read them, because I have included a primer here :)&lt;/p&gt; 1838&lt;p&gt;Or you can pretend you read them, because I have included a primer
1839here :)&lt;/p&gt;
1196&lt;h3 id="contents"&gt;Contents&lt;/h3&gt; 1840&lt;h3 id="contents"&gt;Contents&lt;/h3&gt;
1197&lt;ol type="1"&gt; 1841&lt;ol type="1"&gt;
1198&lt;li&gt;&lt;a href="#currying"&gt;Currying&lt;/a&gt;&lt;br /&gt; 1842&lt;li&gt;&lt;a href="#currying"&gt;Currying&lt;/a&gt;&lt;br /&gt;
@@ -1217,7 +1861,12 @@ scp .git/description &amp;quot;$remote/description&amp;quot;&lt;/code&gt;&lt;/pr
1217&lt;li&gt;&lt;a href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/li&gt; 1861&lt;li&gt;&lt;a href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
1218&lt;/ol&gt; 1862&lt;/ol&gt;
1219&lt;h3 id="currying"&gt;Currying&lt;/h3&gt; 1863&lt;h3 id="currying"&gt;Currying&lt;/h3&gt;
1220&lt;p&gt;Currying is the process of transformation of a function call like &lt;code&gt;f(a, b, c)&lt;/code&gt; to &lt;code&gt;f(a)(b)(c)&lt;/code&gt;. A curried function returns a concrete value only when it receives all its arguments! If it does recieve an insufficient amount of arguments, say 1 of 3, it returns a &lt;em&gt;curried function&lt;/em&gt;, that returns after receiving 2 arguments.&lt;/p&gt; 1864&lt;p&gt;Currying is the process of transformation of a function call like
1865&lt;code&gt;f(a, b, c)&lt;/code&gt; to &lt;code&gt;f(a)(b)(c)&lt;/code&gt;. A curried function
1866returns a concrete value only when it receives all its arguments! If it
1867does recieve an insufficient amount of arguments, say 1 of 3, it returns
1868a &lt;em&gt;curried function&lt;/em&gt;, that returns after receiving 2
1869arguments.&lt;/p&gt;
1221&lt;pre&gt;&lt;code&gt;curry(f(a, b, c)) = h(a)(b)(c) 1870&lt;pre&gt;&lt;code&gt;curry(f(a, b, c)) = h(a)(b)(c)
1222 1871
1223h(x) = g &amp;lt;- curried function that takes upto 2 args (g) 1872h(x) = g &amp;lt;- curried function that takes upto 2 args (g)
@@ -1226,49 +1875,86 @@ k(z) = v &amp;lt;- a value (v)
1226 1875
1227Keen readers will conclude the following, 1876Keen readers will conclude the following,
1228h(x)(y)(z) = g(y)(z) = k(z) = v&lt;/code&gt;&lt;/pre&gt; 1877h(x)(y)(z) = g(y)(z) = k(z) = v&lt;/code&gt;&lt;/pre&gt;
1229&lt;p&gt;Mathematically, if &lt;code&gt;f&lt;/code&gt; is a function that takes two arguments &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;, such that &lt;code&gt;x ϵ X&lt;/code&gt;, and &lt;code&gt;y ϵ Y&lt;/code&gt; , we write it as:&lt;/p&gt; 1878&lt;p&gt;Mathematically, if &lt;code&gt;f&lt;/code&gt; is a function that takes two
1879arguments &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;, such that
1880&lt;code&gt;x ϵ X&lt;/code&gt;, and &lt;code&gt;y ϵ Y&lt;/code&gt; , we write it as:&lt;/p&gt;
1230&lt;pre&gt;&lt;code&gt;f: (X × Y) -&amp;gt; Z&lt;/code&gt;&lt;/pre&gt; 1881&lt;pre&gt;&lt;code&gt;f: (X × Y) -&amp;gt; Z&lt;/code&gt;&lt;/pre&gt;
1231&lt;p&gt;where &lt;code&gt;×&lt;/code&gt; denotes the Cartesian product of set &lt;code&gt;X&lt;/code&gt; and &lt;code&gt;Y&lt;/code&gt;, and curried &lt;code&gt;f&lt;/code&gt; (denoted by &lt;code&gt;h&lt;/code&gt; here) is written as:&lt;/p&gt; 1882&lt;p&gt;where &lt;code&gt;×&lt;/code&gt; denotes the Cartesian product of set
1883&lt;code&gt;X&lt;/code&gt; and &lt;code&gt;Y&lt;/code&gt;, and curried &lt;code&gt;f&lt;/code&gt; (denoted
1884by &lt;code&gt;h&lt;/code&gt; here) is written as:&lt;/p&gt;
1232&lt;pre&gt;&lt;code&gt;h: X -&amp;gt; (Y -&amp;gt; Z)&lt;/code&gt;&lt;/pre&gt; 1885&lt;pre&gt;&lt;code&gt;h: X -&amp;gt; (Y -&amp;gt; Z)&lt;/code&gt;&lt;/pre&gt;
1233&lt;h3 id="procedural-macros"&gt;Procedural Macros&lt;/h3&gt; 1886&lt;h3 id="procedural-macros"&gt;Procedural Macros&lt;/h3&gt;
1234&lt;p&gt;These are functions that take code as input and spit out modified code as output. Powerful stuff. Rust has three kinds of proc-macros:&lt;/p&gt; 1887&lt;p&gt;These are functions that take code as input and spit out modified
1888code as output. Powerful stuff. Rust has three kinds of proc-macros:&lt;/p&gt;
1235&lt;ul&gt; 1889&lt;ul&gt;
1236&lt;li&gt;Function like macros&lt;br /&gt; 1890&lt;li&gt;Function like macros&lt;br /&gt;
1237&lt;/li&gt; 1891&lt;/li&gt;
1238&lt;li&gt;Derive macros: &lt;code&gt;#[derive(...)]&lt;/code&gt;, used to automatically implement traits for structs/enums&lt;br /&gt; 1892&lt;li&gt;Derive macros: &lt;code&gt;#[derive(...)]&lt;/code&gt;, used to automatically
1893implement traits for structs/enums&lt;br /&gt;
1239&lt;/li&gt; 1894&lt;/li&gt;
1240&lt;li&gt;and Attribute macros: &lt;code&gt;#[test]&lt;/code&gt;, usually slapped onto functions&lt;/li&gt; 1895&lt;li&gt;and Attribute macros: &lt;code&gt;#[test]&lt;/code&gt;, usually slapped onto
1896functions&lt;/li&gt;
1241&lt;/ul&gt; 1897&lt;/ul&gt;
1242&lt;p&gt;We will be using Attribute macros to convert a Rust function into a curried Rust function, which we should be able to call via: &lt;code&gt;function(arg1)(arg2)&lt;/code&gt;.&lt;/p&gt; 1898&lt;p&gt;We will be using Attribute macros to convert a Rust function into a
1899curried Rust function, which we should be able to call via:
1900&lt;code&gt;function(arg1)(arg2)&lt;/code&gt;.&lt;/p&gt;
1243&lt;h3 id="definitions"&gt;Definitions&lt;/h3&gt; 1901&lt;h3 id="definitions"&gt;Definitions&lt;/h3&gt;
1244&lt;p&gt;Being respectable programmers, we define the input to and the output from our proc-macro. Here’s a good non-trivial function to start out with:&lt;/p&gt; 1902&lt;p&gt;Being respectable programmers, we define the input to and the output
1245&lt;div class="sourceCode" id="cb4"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb4-1"&gt;&lt;a href="#cb4-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; add(x&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; y&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; z&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 1903from our proc-macro. Here’s a good non-trivial function to start out
1246&lt;span id="cb4-2"&gt;&lt;a href="#cb4-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;return&lt;/span&gt; x &lt;span class="op"&gt;+&lt;/span&gt; y &lt;span class="op"&gt;+&lt;/span&gt; z&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 1904with:&lt;/p&gt;
1905&lt;div class="sourceCode" id="cb4"&gt;&lt;pre
1906class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb4-1"&gt;&lt;a href="#cb4-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; add(x&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; y&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; z&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1907&lt;span id="cb4-2"&gt;&lt;a href="#cb4-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;return&lt;/span&gt; x &lt;span class="op"&gt;+&lt;/span&gt; y &lt;span class="op"&gt;+&lt;/span&gt; z&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1247&lt;span id="cb4-3"&gt;&lt;a href="#cb4-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1908&lt;span id="cb4-3"&gt;&lt;a href="#cb4-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1248&lt;p&gt;Hmm, what would our output look like? What should our proc-macro generate ideally? Well, if we understood currying correctly, we should accept an argument and return a function that accepts an argument and returns … you get the point. Something like this should do:&lt;/p&gt; 1909&lt;p&gt;Hmm, what would our output look like? What should our proc-macro
1249&lt;div class="sourceCode" id="cb5"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb5-1"&gt;&lt;a href="#cb5-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; add_curried1(x&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;?&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 1910generate ideally? Well, if we understood currying correctly, we should
1250&lt;span id="cb5-2"&gt;&lt;a href="#cb5-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="kw"&gt;fn&lt;/span&gt; add_curried2 (y&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;?&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 1911accept an argument and return a function that accepts an argument and
1251&lt;span id="cb5-3"&gt;&lt;a href="#cb5-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="kw"&gt;fn&lt;/span&gt; add_curried3 (z&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 1912returns … you get the point. Something like this should do:&lt;/p&gt;
1252&lt;span id="cb5-4"&gt;&lt;a href="#cb5-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;return&lt;/span&gt; x &lt;span class="op"&gt;+&lt;/span&gt; y &lt;span class="op"&gt;+&lt;/span&gt; z&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 1913&lt;div class="sourceCode" id="cb5"&gt;&lt;pre
1914class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb5-1"&gt;&lt;a href="#cb5-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; add_curried1(x&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;?&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1915&lt;span id="cb5-2"&gt;&lt;a href="#cb5-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="kw"&gt;fn&lt;/span&gt; add_curried2 (y&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;?&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1916&lt;span id="cb5-3"&gt;&lt;a href="#cb5-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="kw"&gt;fn&lt;/span&gt; add_curried3 (z&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1917&lt;span id="cb5-4"&gt;&lt;a href="#cb5-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;return&lt;/span&gt; x &lt;span class="op"&gt;+&lt;/span&gt; y &lt;span class="op"&gt;+&lt;/span&gt; z&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1253&lt;span id="cb5-5"&gt;&lt;a href="#cb5-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 1918&lt;span id="cb5-5"&gt;&lt;a href="#cb5-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
1254&lt;span id="cb5-6"&gt;&lt;a href="#cb5-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 1919&lt;span id="cb5-6"&gt;&lt;a href="#cb5-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
1255&lt;span id="cb5-7"&gt;&lt;a href="#cb5-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1920&lt;span id="cb5-7"&gt;&lt;a href="#cb5-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1256&lt;p&gt;A couple of things to note:&lt;/p&gt; 1921&lt;p&gt;A couple of things to note:&lt;/p&gt;
1257&lt;p&gt;&lt;strong&gt;Return types&lt;/strong&gt;&lt;br /&gt; 1922&lt;p&gt;&lt;strong&gt;Return types&lt;/strong&gt;&lt;br /&gt;
1258We have placed &lt;code&gt;?&lt;/code&gt;s in place of return types. Let’s try to fix that. &lt;code&gt;add_curried3&lt;/code&gt; returns the ‘value’, so &lt;code&gt;u32&lt;/code&gt; is accurate. &lt;code&gt;add_curried2&lt;/code&gt; returns &lt;code&gt;add_curried3&lt;/code&gt;. What is the type of &lt;code&gt;add_curried3&lt;/code&gt;? It is a function that takes in a &lt;code&gt;u32&lt;/code&gt; and returns a &lt;code&gt;u32&lt;/code&gt;. So a &lt;code&gt;fn(u32) -&amp;gt; u32&lt;/code&gt; will do right? No, I’ll explain why in the next point, but for now, we will make use of the &lt;code&gt;Fn&lt;/code&gt; trait, our return type is &lt;code&gt;impl Fn(u32) -&amp;gt; u32&lt;/code&gt;. This basically tells the compiler that we will be returning something function-like, a.k.a, behaves like a &lt;code&gt;Fn&lt;/code&gt;. Cool!&lt;/p&gt; 1923We have placed &lt;code&gt;?&lt;/code&gt;s in place of return types. Let’s try to
1259&lt;p&gt;If you have been following along, you should be able to tell that the return type of &lt;code&gt;add_curried1&lt;/code&gt; is:&lt;/p&gt; 1924fix that. &lt;code&gt;add_curried3&lt;/code&gt; returns the ‘value’, so
1925&lt;code&gt;u32&lt;/code&gt; is accurate. &lt;code&gt;add_curried2&lt;/code&gt; returns
1926&lt;code&gt;add_curried3&lt;/code&gt;. What is the type of
1927&lt;code&gt;add_curried3&lt;/code&gt;? It is a function that takes in a
1928&lt;code&gt;u32&lt;/code&gt; and returns a &lt;code&gt;u32&lt;/code&gt;. So a
1929&lt;code&gt;fn(u32) -&amp;gt; u32&lt;/code&gt; will do right? No, I’ll explain why in
1930the next point, but for now, we will make use of the &lt;code&gt;Fn&lt;/code&gt;
1931trait, our return type is &lt;code&gt;impl Fn(u32) -&amp;gt; u32&lt;/code&gt;. This
1932basically tells the compiler that we will be returning something
1933function-like, a.k.a, behaves like a &lt;code&gt;Fn&lt;/code&gt;. Cool!&lt;/p&gt;
1934&lt;p&gt;If you have been following along, you should be able to tell that the
1935return type of &lt;code&gt;add_curried1&lt;/code&gt; is:&lt;/p&gt;
1260&lt;pre&gt;&lt;code&gt;impl Fn(u32) -&amp;gt; (impl Fn(u32) -&amp;gt; u32)&lt;/code&gt;&lt;/pre&gt; 1936&lt;pre&gt;&lt;code&gt;impl Fn(u32) -&amp;gt; (impl Fn(u32) -&amp;gt; u32)&lt;/code&gt;&lt;/pre&gt;
1261&lt;p&gt;We can drop the parentheses because &lt;code&gt;-&amp;gt;&lt;/code&gt; is right associative:&lt;/p&gt; 1937&lt;p&gt;We can drop the parentheses because &lt;code&gt;-&amp;gt;&lt;/code&gt; is right
1938associative:&lt;/p&gt;
1262&lt;pre&gt;&lt;code&gt;impl Fn(u32) -&amp;gt; impl Fn(u32) -&amp;gt; u32 1939&lt;pre&gt;&lt;code&gt;impl Fn(u32) -&amp;gt; impl Fn(u32) -&amp;gt; u32
1263&lt;/code&gt;&lt;/pre&gt; 1940&lt;/code&gt;&lt;/pre&gt;
1264&lt;p&gt;&lt;strong&gt;Accessing environment&lt;/strong&gt;&lt;br /&gt; 1941&lt;p&gt;&lt;strong&gt;Accessing environment&lt;/strong&gt;&lt;br /&gt;
1265A function cannot access it’s environment. Our solution will not work. &lt;code&gt;add_curried3&lt;/code&gt; attempts to access &lt;code&gt;x&lt;/code&gt;, which is not allowed! A closure&lt;a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; however, can. If we are returning a closure, our return type must be &lt;code&gt;impl Fn&lt;/code&gt;, and not &lt;code&gt;fn&lt;/code&gt;. The difference between the &lt;code&gt;Fn&lt;/code&gt; trait and function pointers is beyond the scope of this post.&lt;/p&gt; 1942A function cannot access it’s environment. Our solution will not work.
1943&lt;code&gt;add_curried3&lt;/code&gt; attempts to access &lt;code&gt;x&lt;/code&gt;, which is
1944not allowed! A closure&lt;a href="#fn1" class="footnote-ref" id="fnref1"
1945role="doc-noteref"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; however, can. If we are returning a
1946closure, our return type must be &lt;code&gt;impl Fn&lt;/code&gt;, and not
1947&lt;code&gt;fn&lt;/code&gt;. The difference between the &lt;code&gt;Fn&lt;/code&gt; trait and
1948function pointers is beyond the scope of this post.&lt;/p&gt;
1266&lt;h3 id="refinement"&gt;Refinement&lt;/h3&gt; 1949&lt;h3 id="refinement"&gt;Refinement&lt;/h3&gt;
1267&lt;p&gt;Armed with knowledge, we refine our expected output, this time, employing closures:&lt;/p&gt; 1950&lt;p&gt;Armed with knowledge, we refine our expected output, this time,
1268&lt;div class="sourceCode" id="cb8"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb8-1"&gt;&lt;a href="#cb8-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; add(x&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 1951employing closures:&lt;/p&gt;
1269&lt;span id="cb8-2"&gt;&lt;a href="#cb8-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;y&lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;z&lt;span class="op"&gt;|&lt;/span&gt; x &lt;span class="op"&gt;+&lt;/span&gt; y &lt;span class="op"&gt;+&lt;/span&gt; z&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 1952&lt;div class="sourceCode" id="cb8"&gt;&lt;pre
1953class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb8-1"&gt;&lt;a href="#cb8-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; add(x&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1954&lt;span id="cb8-2"&gt;&lt;a href="#cb8-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;y&lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;z&lt;span class="op"&gt;|&lt;/span&gt; x &lt;span class="op"&gt;+&lt;/span&gt; y &lt;span class="op"&gt;+&lt;/span&gt; z&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1270&lt;span id="cb8-3"&gt;&lt;a href="#cb8-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1955&lt;span id="cb8-3"&gt;&lt;a href="#cb8-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1271&lt;p&gt;Alas, that does not compile either! It errors out with the following message:&lt;/p&gt; 1956&lt;p&gt;Alas, that does not compile either! It errors out with the following
1957message:&lt;/p&gt;
1272&lt;pre&gt;&lt;code&gt;error[E0562]: `impl Trait` not allowed outside of function 1958&lt;pre&gt;&lt;code&gt;error[E0562]: `impl Trait` not allowed outside of function
1273and inherent method return types 1959and inherent method return types
1274 --&amp;gt; src/main.rs:17:37 1960 --&amp;gt; src/main.rs:17:37
@@ -1276,21 +1962,33 @@ and inherent method return types
1276 | fn add(x: u32) -&amp;gt; impl Fn(u32) -&amp;gt; impl Fn(u32) -&amp;gt; u32 1962 | fn add(x: u32) -&amp;gt; impl Fn(u32) -&amp;gt; impl Fn(u32) -&amp;gt; u32
1277 | ^^^^^^^^^^^^^^^^^^^ 1963 | ^^^^^^^^^^^^^^^^^^^
1278&lt;/code&gt;&lt;/pre&gt; 1964&lt;/code&gt;&lt;/pre&gt;
1279&lt;p&gt;You are allowed to return an &lt;code&gt;impl Fn&lt;/code&gt; only inside a function. We are currently returning it from another return! Or at least, that was the most I could make out of the error message.&lt;/p&gt; 1965&lt;p&gt;You are allowed to return an &lt;code&gt;impl Fn&lt;/code&gt; only inside a
1280&lt;p&gt;We are going to have to cheat a bit to fix this issue; with type aliases and a convenient nightly feature &lt;a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt; 1966function. We are currently returning it from another return! Or at
1281&lt;div class="sourceCode" id="cb10"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb10-1"&gt;&lt;a href="#cb10-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="at"&gt;#![&lt;/span&gt;feature&lt;span class="at"&gt;(&lt;/span&gt;type_alias_impl_trait&lt;span class="at"&gt;)]&lt;/span&gt; &lt;span class="co"&gt;// allows us to use `impl Fn` in type aliases!&lt;/span&gt;&lt;/span&gt; 1967least, that was the most I could make out of the error message.&lt;/p&gt;
1968&lt;p&gt;We are going to have to cheat a bit to fix this issue; with type
1969aliases and a convenient nightly feature &lt;a href="#fn2"
1970class="footnote-ref" id="fnref2"
1971role="doc-noteref"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;
1972&lt;div class="sourceCode" id="cb10"&gt;&lt;pre
1973class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb10-1"&gt;&lt;a href="#cb10-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="at"&gt;#![&lt;/span&gt;feature&lt;span class="at"&gt;(&lt;/span&gt;type_alias_impl_trait&lt;span class="at"&gt;)]&lt;/span&gt; &lt;span class="co"&gt;// allows us to use `impl Fn` in type aliases!&lt;/span&gt;&lt;/span&gt;
1282&lt;span id="cb10-2"&gt;&lt;a href="#cb10-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 1974&lt;span id="cb10-2"&gt;&lt;a href="#cb10-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1283&lt;span id="cb10-3"&gt;&lt;a href="#cb10-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt; &lt;span class="co"&gt;// the return value when zero args are to be applied&lt;/span&gt;&lt;/span&gt; 1975&lt;span id="cb10-3"&gt;&lt;a href="#cb10-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt; &lt;span class="co"&gt;// the return value when zero args are to be applied&lt;/span&gt;&lt;/span&gt;
1284&lt;span id="cb10-4"&gt;&lt;a href="#cb10-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T1 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; T0&lt;span class="op"&gt;;&lt;/span&gt; &lt;span class="co"&gt;// the return value when one arg is to be applied&lt;/span&gt;&lt;/span&gt; 1976&lt;span id="cb10-4"&gt;&lt;a href="#cb10-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T1 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; T0&lt;span class="op"&gt;;&lt;/span&gt; &lt;span class="co"&gt;// the return value when one arg is to be applied&lt;/span&gt;&lt;/span&gt;
1285&lt;span id="cb10-5"&gt;&lt;a href="#cb10-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T2 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; T1&lt;span class="op"&gt;;&lt;/span&gt; &lt;span class="co"&gt;// the return value when two args are to be applied&lt;/span&gt;&lt;/span&gt; 1977&lt;span id="cb10-5"&gt;&lt;a href="#cb10-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T2 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; T1&lt;span class="op"&gt;;&lt;/span&gt; &lt;span class="co"&gt;// the return value when two args are to be applied&lt;/span&gt;&lt;/span&gt;
1286&lt;span id="cb10-6"&gt;&lt;a href="#cb10-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 1978&lt;span id="cb10-6"&gt;&lt;a href="#cb10-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1287&lt;span id="cb10-7"&gt;&lt;a href="#cb10-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; add(x&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; T2 &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 1979&lt;span id="cb10-7"&gt;&lt;a href="#cb10-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; add(x&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; T2 &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1288&lt;span id="cb10-8"&gt;&lt;a href="#cb10-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;y&lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;z&lt;span class="op"&gt;|&lt;/span&gt; x &lt;span class="op"&gt;+&lt;/span&gt; y &lt;span class="op"&gt;+&lt;/span&gt; z&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 1980&lt;span id="cb10-8"&gt;&lt;a href="#cb10-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;y&lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;z&lt;span class="op"&gt;|&lt;/span&gt; x &lt;span class="op"&gt;+&lt;/span&gt; y &lt;span class="op"&gt;+&lt;/span&gt; z&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1289&lt;span id="cb10-9"&gt;&lt;a href="#cb10-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 1981&lt;span id="cb10-9"&gt;&lt;a href="#cb10-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1290&lt;p&gt;Drop that into a cargo project, call &lt;code&gt;add(4)(5)(6)&lt;/code&gt;, cross your fingers, and run &lt;code&gt;cargo +nightly run&lt;/code&gt;. You should see a 15 unless you forgot to print it!&lt;/p&gt; 1982&lt;p&gt;Drop that into a cargo project, call &lt;code&gt;add(4)(5)(6)&lt;/code&gt;, cross
1983your fingers, and run &lt;code&gt;cargo +nightly run&lt;/code&gt;. You should see a
198415 unless you forgot to print it!&lt;/p&gt;
1291&lt;h3 id="the-in-betweens"&gt;The In-Betweens&lt;/h3&gt; 1985&lt;h3 id="the-in-betweens"&gt;The In-Betweens&lt;/h3&gt;
1292&lt;p&gt;Let us write the magical bits that take us from function to curried function.&lt;/p&gt; 1986&lt;p&gt;Let us write the magical bits that take us from function to curried
1293&lt;p&gt;Initialize your workspace with &lt;code&gt;cargo new --lib currying&lt;/code&gt;. Proc-macro crates are libraries with exactly one export, the macro itself. Add a &lt;code&gt;tests&lt;/code&gt; directory to your crate root. Your directory should look something like this:&lt;/p&gt; 1987function.&lt;/p&gt;
1988&lt;p&gt;Initialize your workspace with &lt;code&gt;cargo new --lib currying&lt;/code&gt;.
1989Proc-macro crates are libraries with exactly one export, the macro
1990itself. Add a &lt;code&gt;tests&lt;/code&gt; directory to your crate root. Your
1991directory should look something like this:&lt;/p&gt;
1294&lt;pre&gt;&lt;code&gt;. 1992&lt;pre&gt;&lt;code&gt;.
1295├── Cargo.toml 1993├── Cargo.toml
1296├── src 1994├── src
@@ -1300,9 +1998,11 @@ and inherent method return types
1300&lt;h4 id="dependencies"&gt;Dependencies&lt;/h4&gt; 1998&lt;h4 id="dependencies"&gt;Dependencies&lt;/h4&gt;
1301&lt;p&gt;We will be using a total of 3 external crates:&lt;/p&gt; 1999&lt;p&gt;We will be using a total of 3 external crates:&lt;/p&gt;
1302&lt;ul&gt; 2000&lt;ul&gt;
1303&lt;li&gt;&lt;a href="https://docs.rs/proc-macro2/1.0.12/proc_macro2/"&gt;proc_macro2&lt;/a&gt;&lt;/li&gt; 2001&lt;li&gt;&lt;a
2002href="https://docs.rs/proc-macro2/1.0.12/proc_macro2/"&gt;proc_macro2&lt;/a&gt;&lt;/li&gt;
1304&lt;li&gt;&lt;a href="https://docs.rs/syn/1.0.18/syn/index.html"&gt;syn&lt;/a&gt;&lt;/li&gt; 2003&lt;li&gt;&lt;a href="https://docs.rs/syn/1.0.18/syn/index.html"&gt;syn&lt;/a&gt;&lt;/li&gt;
1305&lt;li&gt;&lt;a href="https://docs.rs/quote/1.0.4/quote/index.html"&gt;quote&lt;/a&gt;&lt;/li&gt; 2004&lt;li&gt;&lt;a
2005href="https://docs.rs/quote/1.0.4/quote/index.html"&gt;quote&lt;/a&gt;&lt;/li&gt;
1306&lt;/ul&gt; 2006&lt;/ul&gt;
1307&lt;p&gt;Here’s a sample &lt;code&gt;Cargo.toml&lt;/code&gt;:&lt;/p&gt; 2007&lt;p&gt;Here’s a sample &lt;code&gt;Cargo.toml&lt;/code&gt;:&lt;/p&gt;
1308&lt;pre&gt;&lt;code&gt;# Cargo.toml 2008&lt;pre&gt;&lt;code&gt;# Cargo.toml
@@ -1317,10 +2017,12 @@ features = [&amp;quot;full&amp;quot;]
1317 2017
1318[lib] 2018[lib]
1319proc-macro = true # this is important!&lt;/code&gt;&lt;/pre&gt; 2019proc-macro = true # this is important!&lt;/code&gt;&lt;/pre&gt;
1320&lt;p&gt;We will be using an external &lt;code&gt;proc-macro2&lt;/code&gt; crate as well as an internal &lt;code&gt;proc-macro&lt;/code&gt; crate. Not confusing at all!&lt;/p&gt; 2020&lt;p&gt;We will be using an external &lt;code&gt;proc-macro2&lt;/code&gt; crate as well
2021as an internal &lt;code&gt;proc-macro&lt;/code&gt; crate. Not confusing at all!&lt;/p&gt;
1321&lt;h4 id="the-attribute-macro"&gt;The attribute macro&lt;/h4&gt; 2022&lt;h4 id="the-attribute-macro"&gt;The attribute macro&lt;/h4&gt;
1322&lt;p&gt;Drop this into &lt;code&gt;src/lib.rs&lt;/code&gt;, to get the ball rolling.&lt;/p&gt; 2023&lt;p&gt;Drop this into &lt;code&gt;src/lib.rs&lt;/code&gt;, to get the ball rolling.&lt;/p&gt;
1323&lt;div class="sourceCode" id="cb13"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb13-1"&gt;&lt;a href="#cb13-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt; 2024&lt;div class="sourceCode" id="cb13"&gt;&lt;pre
2025class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb13-1"&gt;&lt;a href="#cb13-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt;
1324&lt;span id="cb13-2"&gt;&lt;a href="#cb13-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2026&lt;span id="cb13-2"&gt;&lt;a href="#cb13-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1325&lt;span id="cb13-3"&gt;&lt;a href="#cb13-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;proc_macro::&lt;/span&gt;TokenStream&lt;span class="op"&gt;;&lt;/span&gt; &lt;span class="co"&gt;// 1&lt;/span&gt;&lt;/span&gt; 2027&lt;span id="cb13-3"&gt;&lt;a href="#cb13-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;proc_macro::&lt;/span&gt;TokenStream&lt;span class="op"&gt;;&lt;/span&gt; &lt;span class="co"&gt;// 1&lt;/span&gt;&lt;/span&gt;
1326&lt;span id="cb13-4"&gt;&lt;a href="#cb13-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;quote::&lt;/span&gt;quote&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2028&lt;span id="cb13-4"&gt;&lt;a href="#cb13-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;quote::&lt;/span&gt;quote&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
@@ -1334,17 +2036,49 @@ proc-macro = true # this is important!&lt;/code&gt;&lt;/pre&gt;
1334&lt;span id="cb13-12"&gt;&lt;a href="#cb13-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2036&lt;span id="cb13-12"&gt;&lt;a href="#cb13-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1335&lt;span id="cb13-13"&gt;&lt;a href="#cb13-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; generate_curry(parsed&lt;span class="op"&gt;:&lt;/span&gt; ItemFn) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;proc_macro2::&lt;/span&gt;TokenStream &lt;span class="op"&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2037&lt;span id="cb13-13"&gt;&lt;a href="#cb13-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; generate_curry(parsed&lt;span class="op"&gt;:&lt;/span&gt; ItemFn) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;proc_macro2::&lt;/span&gt;TokenStream &lt;span class="op"&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1336&lt;p&gt;&lt;strong&gt;1. Imports&lt;/strong&gt;&lt;/p&gt; 2038&lt;p&gt;&lt;strong&gt;1. Imports&lt;/strong&gt;&lt;/p&gt;
1337&lt;p&gt;A &lt;code&gt;Tokenstream&lt;/code&gt; holds (hopefully valid) Rust code, this is the type of our input and output. Note that we are importing this type from &lt;code&gt;proc_macro&lt;/code&gt; and not &lt;code&gt;proc_macro2&lt;/code&gt;.&lt;/p&gt; 2039&lt;p&gt;A &lt;code&gt;Tokenstream&lt;/code&gt; holds (hopefully valid) Rust code, this is
1338&lt;p&gt;&lt;code&gt;quote!&lt;/code&gt; from the &lt;code&gt;quote&lt;/code&gt; crate is a macro that allows us to quickly produce &lt;code&gt;TokenStream&lt;/code&gt;s. Much like the LISP &lt;code&gt;quote&lt;/code&gt; procedure, you can use the &lt;code&gt;quote!&lt;/code&gt; macro for symbolic transformations.&lt;/p&gt; 2040the type of our input and output. Note that we are importing this type
1339&lt;p&gt;&lt;code&gt;ItemFn&lt;/code&gt; from the &lt;code&gt;syn&lt;/code&gt; crate holds the parsed &lt;code&gt;TokenStream&lt;/code&gt; of a Rust function. &lt;code&gt;parse_macro_input!&lt;/code&gt; is a helper macro provided by &lt;code&gt;syn&lt;/code&gt;.&lt;/p&gt; 2041from &lt;code&gt;proc_macro&lt;/code&gt; and not &lt;code&gt;proc_macro2&lt;/code&gt;.&lt;/p&gt;
2042&lt;p&gt;&lt;code&gt;quote!&lt;/code&gt; from the &lt;code&gt;quote&lt;/code&gt; crate is a macro that
2043allows us to quickly produce &lt;code&gt;TokenStream&lt;/code&gt;s. Much like the
2044LISP &lt;code&gt;quote&lt;/code&gt; procedure, you can use the &lt;code&gt;quote!&lt;/code&gt;
2045macro for symbolic transformations.&lt;/p&gt;
2046&lt;p&gt;&lt;code&gt;ItemFn&lt;/code&gt; from the &lt;code&gt;syn&lt;/code&gt; crate holds the parsed
2047&lt;code&gt;TokenStream&lt;/code&gt; of a Rust function.
2048&lt;code&gt;parse_macro_input!&lt;/code&gt; is a helper macro provided by
2049&lt;code&gt;syn&lt;/code&gt;.&lt;/p&gt;
1340&lt;p&gt;&lt;strong&gt;2. The lone export&lt;/strong&gt;&lt;/p&gt; 2050&lt;p&gt;&lt;strong&gt;2. The lone export&lt;/strong&gt;&lt;/p&gt;
1341&lt;p&gt;Annotate the only &lt;code&gt;pub&lt;/code&gt; of our crate with &lt;code&gt;#[proc_macro_attribute]&lt;/code&gt;. This tells rustc that &lt;code&gt;curry&lt;/code&gt; is a procedural macro, and allows us to use it as &lt;code&gt;#[crate_name::curry]&lt;/code&gt; in other crates. Note the signature of the &lt;code&gt;curry&lt;/code&gt; function. &lt;code&gt;_attr&lt;/code&gt; is the &lt;code&gt;TokenStream&lt;/code&gt; representing the attribute itself, &lt;code&gt;item&lt;/code&gt; refers to the thing we slapped our macro into, in this case a function (like &lt;code&gt;add&lt;/code&gt;). The return value is a modified &lt;code&gt;TokenStream&lt;/code&gt;, this will contain our curried version of &lt;code&gt;add&lt;/code&gt;.&lt;/p&gt; 2051&lt;p&gt;Annotate the only &lt;code&gt;pub&lt;/code&gt; of our crate with
2052&lt;code&gt;#[proc_macro_attribute]&lt;/code&gt;. This tells rustc that
2053&lt;code&gt;curry&lt;/code&gt; is a procedural macro, and allows us to use it as
2054&lt;code&gt;#[crate_name::curry]&lt;/code&gt; in other crates. Note the signature of
2055the &lt;code&gt;curry&lt;/code&gt; function. &lt;code&gt;_attr&lt;/code&gt; is the
2056&lt;code&gt;TokenStream&lt;/code&gt; representing the attribute itself,
2057&lt;code&gt;item&lt;/code&gt; refers to the thing we slapped our macro into, in this
2058case a function (like &lt;code&gt;add&lt;/code&gt;). The return value is a modified
2059&lt;code&gt;TokenStream&lt;/code&gt;, this will contain our curried version of
2060&lt;code&gt;add&lt;/code&gt;.&lt;/p&gt;
1342&lt;p&gt;&lt;strong&gt;3. The helper macro&lt;/strong&gt;&lt;/p&gt; 2061&lt;p&gt;&lt;strong&gt;3. The helper macro&lt;/strong&gt;&lt;/p&gt;
1343&lt;p&gt;A &lt;code&gt;TokenStream&lt;/code&gt; is a little hard to work with, which is why we have the &lt;code&gt;syn&lt;/code&gt; crate, which provides types to represent Rust tokens. An &lt;code&gt;RArrow&lt;/code&gt; struct to represent the return arrow on a function and so on. One of those types is &lt;code&gt;ItemFn&lt;/code&gt;, that represents an entire Rust function. The &lt;code&gt;parse_macro_input!&lt;/code&gt; automatically puts the input to our macro into an &lt;code&gt;ItemFn&lt;/code&gt;. What a gentleman!&lt;/p&gt; 2062&lt;p&gt;A &lt;code&gt;TokenStream&lt;/code&gt; is a little hard to work with, which is
2063why we have the &lt;code&gt;syn&lt;/code&gt; crate, which provides types to
2064represent Rust tokens. An &lt;code&gt;RArrow&lt;/code&gt; struct to represent the
2065return arrow on a function and so on. One of those types is
2066&lt;code&gt;ItemFn&lt;/code&gt;, that represents an entire Rust function. The
2067&lt;code&gt;parse_macro_input!&lt;/code&gt; automatically puts the input to our
2068macro into an &lt;code&gt;ItemFn&lt;/code&gt;. What a gentleman!&lt;/p&gt;
1344&lt;p&gt;&lt;strong&gt;4. Returning &lt;code&gt;TokenStream&lt;/code&gt;s &lt;/strong&gt;&lt;/p&gt; 2069&lt;p&gt;&lt;strong&gt;4. Returning &lt;code&gt;TokenStream&lt;/code&gt;s &lt;/strong&gt;&lt;/p&gt;
1345&lt;p&gt;We haven’t filled in &lt;code&gt;generate_curry&lt;/code&gt; yet, but we can see that it returns a &lt;code&gt;proc_macro2::TokenStream&lt;/code&gt; and not a &lt;code&gt;proc_macro::TokenStream&lt;/code&gt;, so drop a &lt;code&gt;.into()&lt;/code&gt; to convert it.&lt;/p&gt; 2070&lt;p&gt;We haven’t filled in &lt;code&gt;generate_curry&lt;/code&gt; yet, but we can see
1346&lt;p&gt;Lets move on, and fill in &lt;code&gt;generate_curry&lt;/code&gt;, I would suggest keeping the documentation for &lt;a href="https://docs.rs/syn/1.0.19/syn/struct.ItemFn.html"&gt;&lt;code&gt;syn::ItemFn&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://docs.rs/syn/1.0.19/syn/struct.Signature.html"&gt;&lt;code&gt;syn::Signature&lt;/code&gt;&lt;/a&gt; open.&lt;/p&gt; 2071that it returns a &lt;code&gt;proc_macro2::TokenStream&lt;/code&gt; and not a
1347&lt;div class="sourceCode" id="cb14"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb14-1"&gt;&lt;a href="#cb14-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt; 2072&lt;code&gt;proc_macro::TokenStream&lt;/code&gt;, so drop a &lt;code&gt;.into()&lt;/code&gt; to
2073convert it.&lt;/p&gt;
2074&lt;p&gt;Lets move on, and fill in &lt;code&gt;generate_curry&lt;/code&gt;, I would
2075suggest keeping the documentation for &lt;a
2076href="https://docs.rs/syn/1.0.19/syn/struct.ItemFn.html"&gt;&lt;code&gt;syn::ItemFn&lt;/code&gt;&lt;/a&gt;
2077and &lt;a
2078href="https://docs.rs/syn/1.0.19/syn/struct.Signature.html"&gt;&lt;code&gt;syn::Signature&lt;/code&gt;&lt;/a&gt;
2079open.&lt;/p&gt;
2080&lt;div class="sourceCode" id="cb14"&gt;&lt;pre
2081class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb14-1"&gt;&lt;a href="#cb14-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt;
1348&lt;span id="cb14-2"&gt;&lt;a href="#cb14-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2082&lt;span id="cb14-2"&gt;&lt;a href="#cb14-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1349&lt;span id="cb14-3"&gt;&lt;a href="#cb14-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; generate_curry(parsed&lt;span class="op"&gt;:&lt;/span&gt; ItemFn) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;proc_macro2::&lt;/span&gt;TokenStream &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2083&lt;span id="cb14-3"&gt;&lt;a href="#cb14-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; generate_curry(parsed&lt;span class="op"&gt;:&lt;/span&gt; ItemFn) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;proc_macro2::&lt;/span&gt;TokenStream &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1350&lt;span id="cb14-4"&gt;&lt;a href="#cb14-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; fn_body &lt;span class="op"&gt;=&lt;/span&gt; parsed&lt;span class="op"&gt;.&lt;/span&gt;block&lt;span class="op"&gt;;&lt;/span&gt; &lt;span class="co"&gt;// function body&lt;/span&gt;&lt;/span&gt; 2084&lt;span id="cb14-4"&gt;&lt;a href="#cb14-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; fn_body &lt;span class="op"&gt;=&lt;/span&gt; parsed&lt;span class="op"&gt;.&lt;/span&gt;block&lt;span class="op"&gt;;&lt;/span&gt; &lt;span class="co"&gt;// function body&lt;/span&gt;&lt;/span&gt;
@@ -1354,7 +2088,9 @@ proc-macro = true # this is important!&lt;/code&gt;&lt;/pre&gt;
1354&lt;span id="cb14-8"&gt;&lt;a href="#cb14-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; fn_args &lt;span class="op"&gt;=&lt;/span&gt; sig&lt;span class="op"&gt;.&lt;/span&gt;inputs&lt;span class="op"&gt;;&lt;/span&gt; &lt;span class="co"&gt;// comma separated args&lt;/span&gt;&lt;/span&gt; 2088&lt;span id="cb14-8"&gt;&lt;a href="#cb14-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; fn_args &lt;span class="op"&gt;=&lt;/span&gt; sig&lt;span class="op"&gt;.&lt;/span&gt;inputs&lt;span class="op"&gt;;&lt;/span&gt; &lt;span class="co"&gt;// comma separated args&lt;/span&gt;&lt;/span&gt;
1355&lt;span id="cb14-9"&gt;&lt;a href="#cb14-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; fn_return_type &lt;span class="op"&gt;=&lt;/span&gt; sig&lt;span class="op"&gt;.&lt;/span&gt;output&lt;span class="op"&gt;;&lt;/span&gt; &lt;span class="co"&gt;// return type&lt;/span&gt;&lt;/span&gt; 2089&lt;span id="cb14-9"&gt;&lt;a href="#cb14-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; fn_return_type &lt;span class="op"&gt;=&lt;/span&gt; sig&lt;span class="op"&gt;.&lt;/span&gt;output&lt;span class="op"&gt;;&lt;/span&gt; &lt;span class="co"&gt;// return type&lt;/span&gt;&lt;/span&gt;
1356&lt;span id="cb14-10"&gt;&lt;a href="#cb14-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2090&lt;span id="cb14-10"&gt;&lt;a href="#cb14-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1357&lt;p&gt;We are simply extracting the bits of the function, we will be reusing the original function’s visibility and name. Take a look at what &lt;code&gt;syn::Signature&lt;/code&gt; can tell us about a function:&lt;/p&gt; 2091&lt;p&gt;We are simply extracting the bits of the function, we will be reusing
2092the original function’s visibility and name. Take a look at what
2093&lt;code&gt;syn::Signature&lt;/code&gt; can tell us about a function:&lt;/p&gt;
1358&lt;pre&gt;&lt;code&gt; .-- syn::Ident (ident) 2094&lt;pre&gt;&lt;code&gt; .-- syn::Ident (ident)
1359 / 2095 /
1360 fn add(x: u32, y: u32) -&amp;gt; u32 2096 fn add(x: u32, y: u32) -&amp;gt; u32
@@ -1364,42 +2100,77 @@ syn::token::Fn --&amp;#39; / \ (output)
1364 Punctuated&amp;lt;FnArg, Comma&amp;gt; (inputs)&lt;/code&gt;&lt;/pre&gt; 2100 Punctuated&amp;lt;FnArg, Comma&amp;gt; (inputs)&lt;/code&gt;&lt;/pre&gt;
1365&lt;p&gt;Enough analysis, lets produce our first bit of Rust code.&lt;/p&gt; 2101&lt;p&gt;Enough analysis, lets produce our first bit of Rust code.&lt;/p&gt;
1366&lt;h4 id="function-body"&gt;Function Body&lt;/h4&gt; 2102&lt;h4 id="function-body"&gt;Function Body&lt;/h4&gt;
1367&lt;p&gt;Recall that the body of a curried &lt;code&gt;add&lt;/code&gt; should look like this:&lt;/p&gt; 2103&lt;p&gt;Recall that the body of a curried &lt;code&gt;add&lt;/code&gt; should look like
1368&lt;div class="sourceCode" id="cb16"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb16-1"&gt;&lt;a href="#cb16-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;y&lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;z&lt;span class="op"&gt;|&lt;/span&gt; x &lt;span class="op"&gt;+&lt;/span&gt; y &lt;span class="op"&gt;+&lt;/span&gt; z&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2104this:&lt;/p&gt;
2105&lt;div class="sourceCode" id="cb16"&gt;&lt;pre
2106class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb16-1"&gt;&lt;a href="#cb16-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;y&lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;z&lt;span class="op"&gt;|&lt;/span&gt; x &lt;span class="op"&gt;+&lt;/span&gt; y &lt;span class="op"&gt;+&lt;/span&gt; z&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1369&lt;p&gt;And in general:&lt;/p&gt; 2107&lt;p&gt;And in general:&lt;/p&gt;
1370&lt;div class="sourceCode" id="cb17"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb17-1"&gt;&lt;a href="#cb17-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;arg2&lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;arg3&lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;argN&lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;function body here&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2108&lt;div class="sourceCode" id="cb17"&gt;&lt;pre
1371&lt;p&gt;We already have the function’s body, provided by &lt;code&gt;fn_body&lt;/code&gt;, in our &lt;code&gt;generate_curry&lt;/code&gt; function. All that’s left to add is the &lt;code&gt;move |arg2| move |arg3| ...&lt;/code&gt; stuff, for which we need to extract the argument identifiers (doc: &lt;a href="https://docs.rs/syn/1.0.18/syn/punctuated/struct.Punctuated.html"&gt;Punctuated&lt;/a&gt;, &lt;a href="https://docs.rs/syn/1.0.18/syn/enum.FnArg.html"&gt;FnArg&lt;/a&gt;, &lt;a href="https://docs.rs/syn/1.0.18/syn/struct.PatType.html"&gt;PatType&lt;/a&gt;):&lt;/p&gt; 2109class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb17-1"&gt;&lt;a href="#cb17-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;arg2&lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;arg3&lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;argN&lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;function body here&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1372&lt;div class="sourceCode" id="cb18"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb18-1"&gt;&lt;a href="#cb18-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt; 2110&lt;p&gt;We already have the function’s body, provided by
2111&lt;code&gt;fn_body&lt;/code&gt;, in our &lt;code&gt;generate_curry&lt;/code&gt; function. All
2112that’s left to add is the &lt;code&gt;move |arg2| move |arg3| ...&lt;/code&gt;
2113stuff, for which we need to extract the argument identifiers (doc: &lt;a
2114href="https://docs.rs/syn/1.0.18/syn/punctuated/struct.Punctuated.html"&gt;Punctuated&lt;/a&gt;,
2115&lt;a href="https://docs.rs/syn/1.0.18/syn/enum.FnArg.html"&gt;FnArg&lt;/a&gt;, &lt;a
2116href="https://docs.rs/syn/1.0.18/syn/struct.PatType.html"&gt;PatType&lt;/a&gt;):&lt;/p&gt;
2117&lt;div class="sourceCode" id="cb18"&gt;&lt;pre
2118class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb18-1"&gt;&lt;a href="#cb18-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt;
1373&lt;span id="cb18-2"&gt;&lt;a href="#cb18-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;syn::punctuated::&lt;/span&gt;Punctuated&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2119&lt;span id="cb18-2"&gt;&lt;a href="#cb18-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;syn::punctuated::&lt;/span&gt;Punctuated&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1374&lt;span id="cb18-3"&gt;&lt;a href="#cb18-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;syn::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;parse_macro_input&lt;span class="op"&gt;,&lt;/span&gt; FnArg&lt;span class="op"&gt;,&lt;/span&gt; Pat&lt;span class="op"&gt;,&lt;/span&gt; ItemFn&lt;span class="op"&gt;,&lt;/span&gt; Block&lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt; 2120&lt;span id="cb18-3"&gt;&lt;a href="#cb18-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;syn::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;parse_macro_input&lt;span class="op"&gt;,&lt;/span&gt; FnArg&lt;span class="op"&gt;,&lt;/span&gt; Pat&lt;span class="op"&gt;,&lt;/span&gt; ItemFn&lt;span class="op"&gt;,&lt;/span&gt; Block&lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt;
1375&lt;span id="cb18-4"&gt;&lt;a href="#cb18-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2121&lt;span id="cb18-4"&gt;&lt;a href="#cb18-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1376&lt;span id="cb18-5"&gt;&lt;a href="#cb18-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; extract_arg_idents(fn_args&lt;span class="op"&gt;:&lt;/span&gt; Punctuated&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;FnArg&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="pp"&gt;syn::token::&lt;/span&gt;Comma&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Vec&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dt"&gt;Box&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;Pat&lt;span class="op"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt; &lt;/span&gt; 2122&lt;span id="cb18-5"&gt;&lt;a href="#cb18-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; extract_arg_idents(fn_args&lt;span class="op"&gt;:&lt;/span&gt; Punctuated&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;FnArg&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="pp"&gt;syn::token::&lt;/span&gt;Comma&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Vec&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dt"&gt;Box&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;Pat&lt;span class="op"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt; &lt;/span&gt;
1377&lt;span id="cb18-6"&gt;&lt;a href="#cb18-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;return&lt;/span&gt; fn_args&lt;span class="op"&gt;.&lt;/span&gt;into_iter()&lt;span class="op"&gt;.&lt;/span&gt;map(extract_arg_pat)&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="pp"&gt;collect::&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dt"&gt;Vec&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;_&lt;span class="op"&gt;&amp;gt;&amp;gt;&lt;/span&gt;()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2123&lt;span id="cb18-6"&gt;&lt;a href="#cb18-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;return&lt;/span&gt; fn_args&lt;span class="op"&gt;.&lt;/span&gt;into_iter()&lt;span class="op"&gt;.&lt;/span&gt;map(extract_arg_pat)&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="pp"&gt;collect::&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dt"&gt;Vec&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;_&lt;span class="op"&gt;&amp;gt;&amp;gt;&lt;/span&gt;()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1378&lt;span id="cb18-7"&gt;&lt;a href="#cb18-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2124&lt;span id="cb18-7"&gt;&lt;a href="#cb18-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1379&lt;p&gt;Alright, so we are iterating over function args (&lt;code&gt;Punctuated&lt;/code&gt; is a collection that you can iterate over) and mapping an &lt;code&gt;extract_arg_pat&lt;/code&gt; to every item. What’s &lt;code&gt;extract_arg_pat&lt;/code&gt;?&lt;/p&gt; 2125&lt;p&gt;Alright, so we are iterating over function args
1380&lt;div class="sourceCode" id="cb19"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb19-1"&gt;&lt;a href="#cb19-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt; 2126(&lt;code&gt;Punctuated&lt;/code&gt; is a collection that you can iterate over) and
2127mapping an &lt;code&gt;extract_arg_pat&lt;/code&gt; to every item. What’s
2128&lt;code&gt;extract_arg_pat&lt;/code&gt;?&lt;/p&gt;
2129&lt;div class="sourceCode" id="cb19"&gt;&lt;pre
2130class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb19-1"&gt;&lt;a href="#cb19-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt;
1381&lt;span id="cb19-2"&gt;&lt;a href="#cb19-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2131&lt;span id="cb19-2"&gt;&lt;a href="#cb19-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1382&lt;span id="cb19-3"&gt;&lt;a href="#cb19-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; extract_arg_pat(a&lt;span class="op"&gt;:&lt;/span&gt; FnArg) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Box&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;Pat&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2132&lt;span id="cb19-3"&gt;&lt;a href="#cb19-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; extract_arg_pat(a&lt;span class="op"&gt;:&lt;/span&gt; FnArg) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Box&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;Pat&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1383&lt;span id="cb19-4"&gt;&lt;a href="#cb19-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;match&lt;/span&gt; a &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2133&lt;span id="cb19-4"&gt;&lt;a href="#cb19-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;match&lt;/span&gt; a &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1384&lt;span id="cb19-5"&gt;&lt;a href="#cb19-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="pp"&gt;FnArg::&lt;/span&gt;Typed(p) &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; p&lt;span class="op"&gt;.&lt;/span&gt;pat&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt; 2134&lt;span id="cb19-5"&gt;&lt;a href="#cb19-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="pp"&gt;FnArg::&lt;/span&gt;Typed(p) &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; p&lt;span class="op"&gt;.&lt;/span&gt;pat&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
1385&lt;span id="cb19-6"&gt;&lt;a href="#cb19-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; _ &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;panic!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;Not supported on types with `self`!&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt; 2135&lt;span id="cb19-6"&gt;&lt;a href="#cb19-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; _ &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;panic!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;Not supported on types with `self`!&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
1386&lt;span id="cb19-7"&gt;&lt;a href="#cb19-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 2136&lt;span id="cb19-7"&gt;&lt;a href="#cb19-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
1387&lt;span id="cb19-8"&gt;&lt;a href="#cb19-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2137&lt;span id="cb19-8"&gt;&lt;a href="#cb19-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1388&lt;p&gt;&lt;code&gt;FnArg&lt;/code&gt; is an enum type as you might have guessed. The &lt;code&gt;Typed&lt;/code&gt; variant encompasses args that are written as &lt;code&gt;name: type&lt;/code&gt; and the other variant, &lt;code&gt;Reciever&lt;/code&gt; refers to &lt;code&gt;self&lt;/code&gt; types. Ignore those for now, keep it simple.&lt;/p&gt; 2138&lt;p&gt;&lt;code&gt;FnArg&lt;/code&gt; is an enum type as you might have guessed. The
1389&lt;p&gt;Every &lt;code&gt;FnArg::Typed&lt;/code&gt; value contains a &lt;code&gt;pat&lt;/code&gt;, which is in essence, the name of the argument. The type of the arg is accessible via &lt;code&gt;p.ty&lt;/code&gt; (we will be using this later).&lt;/p&gt; 2139&lt;code&gt;Typed&lt;/code&gt; variant encompasses args that are written as
1390&lt;p&gt;With that done, we should be able to write the codegen for the function body:&lt;/p&gt; 2140&lt;code&gt;name: type&lt;/code&gt; and the other variant, &lt;code&gt;Reciever&lt;/code&gt;
1391&lt;div class="sourceCode" id="cb20"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb20-1"&gt;&lt;a href="#cb20-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt; 2141refers to &lt;code&gt;self&lt;/code&gt; types. Ignore those for now, keep it
2142simple.&lt;/p&gt;
2143&lt;p&gt;Every &lt;code&gt;FnArg::Typed&lt;/code&gt; value contains a &lt;code&gt;pat&lt;/code&gt;,
2144which is in essence, the name of the argument. The type of the arg is
2145accessible via &lt;code&gt;p.ty&lt;/code&gt; (we will be using this later).&lt;/p&gt;
2146&lt;p&gt;With that done, we should be able to write the codegen for the
2147function body:&lt;/p&gt;
2148&lt;div class="sourceCode" id="cb20"&gt;&lt;pre
2149class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb20-1"&gt;&lt;a href="#cb20-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt;
1392&lt;span id="cb20-2"&gt;&lt;a href="#cb20-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2150&lt;span id="cb20-2"&gt;&lt;a href="#cb20-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1393&lt;span id="cb20-3"&gt;&lt;a href="#cb20-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; generate_body(fn_args&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="op"&gt;&amp;amp;&lt;/span&gt;[&lt;span class="dt"&gt;Box&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;Pat&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;]&lt;span class="op"&gt;,&lt;/span&gt; body&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;Box&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;Block&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;proc_macro2::&lt;/span&gt;TokenStream &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2151&lt;span id="cb20-3"&gt;&lt;a href="#cb20-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; generate_body(fn_args&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="op"&gt;&amp;amp;&lt;/span&gt;[&lt;span class="dt"&gt;Box&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;Pat&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;]&lt;span class="op"&gt;,&lt;/span&gt; body&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;Box&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;Block&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;proc_macro2::&lt;/span&gt;TokenStream &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1394&lt;span id="cb20-4"&gt;&lt;a href="#cb20-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="pp"&gt;quote!&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2152&lt;span id="cb20-4"&gt;&lt;a href="#cb20-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="pp"&gt;quote!&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1395&lt;span id="cb20-5"&gt;&lt;a href="#cb20-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;return&lt;/span&gt; #( &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;#fn_args&lt;span class="op"&gt;|&lt;/span&gt; )&lt;span class="op"&gt;*&lt;/span&gt; #body&lt;/span&gt; 2153&lt;span id="cb20-5"&gt;&lt;a href="#cb20-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;return&lt;/span&gt; #( &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;#fn_args&lt;span class="op"&gt;|&lt;/span&gt; )&lt;span class="op"&gt;*&lt;/span&gt; #body&lt;/span&gt;
1396&lt;span id="cb20-6"&gt;&lt;a href="#cb20-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 2154&lt;span id="cb20-6"&gt;&lt;a href="#cb20-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
1397&lt;span id="cb20-7"&gt;&lt;a href="#cb20-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2155&lt;span id="cb20-7"&gt;&lt;a href="#cb20-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1398&lt;p&gt;That is some scary looking syntax! Allow me to explain. The &lt;code&gt;quote!{ ... }&lt;/code&gt; returns a &lt;code&gt;proc_macro2::TokenStream&lt;/code&gt;, if we wrote &lt;code&gt;quote!{ let x = 1 + 2; }&lt;/code&gt;, it wouldn’t create a new variable &lt;code&gt;x&lt;/code&gt; with value 3, it would literally produce a stream of tokens with that expression.&lt;/p&gt; 2156&lt;p&gt;That is some scary looking syntax! Allow me to explain. The
1399&lt;p&gt;The &lt;code&gt;#&lt;/code&gt; enables variable interpolation. &lt;code&gt;#body&lt;/code&gt; will look for &lt;code&gt;body&lt;/code&gt; in the current scope, take its value, and insert it in the returned &lt;code&gt;TokenStream&lt;/code&gt;. Kinda like quasi quoting in LISPs, you have written one.&lt;/p&gt; 2157&lt;code&gt;quote!{ ... }&lt;/code&gt; returns a
1400&lt;p&gt;What about &lt;code&gt;#( move |#fn_args| )*&lt;/code&gt;? That is repetition. &lt;code&gt;quote&lt;/code&gt; iterates through &lt;code&gt;fn_args&lt;/code&gt;, and drops a &lt;code&gt;move&lt;/code&gt; behind each one, it then places pipes (&lt;code&gt;|&lt;/code&gt;), around it.&lt;/p&gt; 2158&lt;code&gt;proc_macro2::TokenStream&lt;/code&gt;, if we wrote
1401&lt;p&gt;Let us test our first bit of codegen! Modify &lt;code&gt;generate_curry&lt;/code&gt; like so:&lt;/p&gt; 2159&lt;code&gt;quote!{ let x = 1 + 2; }&lt;/code&gt;, it wouldn’t create a new variable
1402&lt;div class="sourceCode" id="cb21"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb21-1"&gt;&lt;a href="#cb21-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt; 2160&lt;code&gt;x&lt;/code&gt; with value 3, it would literally produce a stream of
2161tokens with that expression.&lt;/p&gt;
2162&lt;p&gt;The &lt;code&gt;#&lt;/code&gt; enables variable interpolation. &lt;code&gt;#body&lt;/code&gt;
2163will look for &lt;code&gt;body&lt;/code&gt; in the current scope, take its value,
2164and insert it in the returned &lt;code&gt;TokenStream&lt;/code&gt;. Kinda like quasi
2165quoting in LISPs, you have written one.&lt;/p&gt;
2166&lt;p&gt;What about &lt;code&gt;#( move |#fn_args| )*&lt;/code&gt;? That is repetition.
2167&lt;code&gt;quote&lt;/code&gt; iterates through &lt;code&gt;fn_args&lt;/code&gt;, and drops a
2168&lt;code&gt;move&lt;/code&gt; behind each one, it then places pipes
2169(&lt;code&gt;|&lt;/code&gt;), around it.&lt;/p&gt;
2170&lt;p&gt;Let us test our first bit of codegen! Modify
2171&lt;code&gt;generate_curry&lt;/code&gt; like so:&lt;/p&gt;
2172&lt;div class="sourceCode" id="cb21"&gt;&lt;pre
2173class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb21-1"&gt;&lt;a href="#cb21-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt;
1403&lt;span id="cb21-2"&gt;&lt;a href="#cb21-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2174&lt;span id="cb21-2"&gt;&lt;a href="#cb21-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1404&lt;span id="cb21-3"&gt;&lt;a href="#cb21-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;fn&lt;/span&gt; generate_curry(parsed&lt;span class="op"&gt;:&lt;/span&gt; ItemFn) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; TokenStream &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2175&lt;span id="cb21-3"&gt;&lt;a href="#cb21-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;fn&lt;/span&gt; generate_curry(parsed&lt;span class="op"&gt;:&lt;/span&gt; ItemFn) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; TokenStream &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1405&lt;span id="cb21-4"&gt;&lt;a href="#cb21-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; fn_body &lt;span class="op"&gt;=&lt;/span&gt; parsed&lt;span class="op"&gt;.&lt;/span&gt;block&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2176&lt;span id="cb21-4"&gt;&lt;a href="#cb21-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; fn_body &lt;span class="op"&gt;=&lt;/span&gt; parsed&lt;span class="op"&gt;.&lt;/span&gt;block&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
@@ -1416,10 +2187,11 @@ syn::token::Fn --&amp;#39; / \ (output)
1416&lt;span id="cb21-15"&gt;&lt;a href="#cb21-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="kw"&gt;let&lt;/span&gt; curried_body &lt;span class="op"&gt;=&lt;/span&gt; generate_body(&lt;span class="op"&gt;&amp;amp;&lt;/span&gt;arg_idents[&lt;span class="dv"&gt;1&lt;/span&gt;&lt;span class="op"&gt;..&lt;/span&gt;]&lt;span class="op"&gt;,&lt;/span&gt; fn_body&lt;span class="op"&gt;.&lt;/span&gt;clone())&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2187&lt;span id="cb21-15"&gt;&lt;a href="#cb21-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="kw"&gt;let&lt;/span&gt; curried_body &lt;span class="op"&gt;=&lt;/span&gt; generate_body(&lt;span class="op"&gt;&amp;amp;&lt;/span&gt;arg_idents[&lt;span class="dv"&gt;1&lt;/span&gt;&lt;span class="op"&gt;..&lt;/span&gt;]&lt;span class="op"&gt;,&lt;/span&gt; fn_body&lt;span class="op"&gt;.&lt;/span&gt;clone())&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1417&lt;span id="cb21-16"&gt;&lt;a href="#cb21-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="pp"&gt;println!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; curried_body)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2188&lt;span id="cb21-16"&gt;&lt;a href="#cb21-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="pp"&gt;println!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; curried_body)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1418&lt;span id="cb21-17"&gt;&lt;a href="#cb21-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2189&lt;span id="cb21-17"&gt;&lt;a href="#cb21-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1419&lt;span id="cb21-18"&gt;&lt;a href="#cb21-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="pp"&gt;TokenStream::&lt;/span&gt;new()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2190&lt;span id="cb21-18"&gt;&lt;a href="#cb21-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="pp"&gt;TokenStream::&lt;/span&gt;new()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1420&lt;span id="cb21-19"&gt;&lt;a href="#cb21-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2191&lt;span id="cb21-19"&gt;&lt;a href="#cb21-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1421&lt;p&gt;Add a little test to &lt;code&gt;tests/&lt;/code&gt;:&lt;/p&gt; 2192&lt;p&gt;Add a little test to &lt;code&gt;tests/&lt;/code&gt;:&lt;/p&gt;
1422&lt;div class="sourceCode" id="cb22"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb22-1"&gt;&lt;a href="#cb22-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// tests/smoke.rs&lt;/span&gt;&lt;/span&gt; 2193&lt;div class="sourceCode" id="cb22"&gt;&lt;pre
2194class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb22-1"&gt;&lt;a href="#cb22-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// tests/smoke.rs&lt;/span&gt;&lt;/span&gt;
1423&lt;span id="cb22-2"&gt;&lt;a href="#cb22-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2195&lt;span id="cb22-2"&gt;&lt;a href="#cb22-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1424&lt;span id="cb22-3"&gt;&lt;a href="#cb22-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="at"&gt;#[&lt;/span&gt;&lt;span class="pp"&gt;currying::&lt;/span&gt;curry&lt;span class="at"&gt;]&lt;/span&gt;&lt;/span&gt; 2196&lt;span id="cb22-3"&gt;&lt;a href="#cb22-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="at"&gt;#[&lt;/span&gt;&lt;span class="pp"&gt;currying::&lt;/span&gt;curry&lt;span class="at"&gt;]&lt;/span&gt;&lt;/span&gt;
1425&lt;span id="cb22-4"&gt;&lt;a href="#cb22-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; add(x&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; y&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; z&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2197&lt;span id="cb22-4"&gt;&lt;a href="#cb22-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; add(x&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; y&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; z&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
@@ -1430,17 +2202,23 @@ syn::token::Fn --&amp;#39; / \ (output)
1430&lt;span id="cb22-9"&gt;&lt;a href="#cb22-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; works() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2202&lt;span id="cb22-9"&gt;&lt;a href="#cb22-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; works() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1431&lt;span id="cb22-10"&gt;&lt;a href="#cb22-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="pp"&gt;assert!&lt;/span&gt;(&lt;span class="cn"&gt;true&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2203&lt;span id="cb22-10"&gt;&lt;a href="#cb22-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="pp"&gt;assert!&lt;/span&gt;(&lt;span class="cn"&gt;true&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1432&lt;span id="cb22-11"&gt;&lt;a href="#cb22-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2204&lt;span id="cb22-11"&gt;&lt;a href="#cb22-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1433&lt;p&gt;You should find something like this in the output of &lt;code&gt;cargo test&lt;/code&gt;:&lt;/p&gt; 2205&lt;p&gt;You should find something like this in the output of
2206&lt;code&gt;cargo test&lt;/code&gt;:&lt;/p&gt;
1434&lt;pre&gt;&lt;code&gt;return move | y | move | z | { x + y + z }&lt;/code&gt;&lt;/pre&gt; 2207&lt;pre&gt;&lt;code&gt;return move | y | move | z | { x + y + z }&lt;/code&gt;&lt;/pre&gt;
1435&lt;p&gt;Glorious &lt;code&gt;println!&lt;/code&gt; debugging!&lt;/p&gt; 2208&lt;p&gt;Glorious &lt;code&gt;println!&lt;/code&gt; debugging!&lt;/p&gt;
1436&lt;h4 id="function-signature"&gt;Function signature&lt;/h4&gt; 2209&lt;h4 id="function-signature"&gt;Function signature&lt;/h4&gt;
1437&lt;p&gt;This section gets into the more complicated bits of the macro, generating type aliases and the function signature. By the end of this section, we should have a full working auto-currying macro!&lt;/p&gt; 2210&lt;p&gt;This section gets into the more complicated bits of the macro,
1438&lt;p&gt;Recall what our generated type aliases should look like, for our &lt;code&gt;add&lt;/code&gt; function:&lt;/p&gt; 2211generating type aliases and the function signature. By the end of this
1439&lt;div class="sourceCode" id="cb24"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb24-1"&gt;&lt;a href="#cb24-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2212section, we should have a full working auto-currying macro!&lt;/p&gt;
2213&lt;p&gt;Recall what our generated type aliases should look like, for our
2214&lt;code&gt;add&lt;/code&gt; function:&lt;/p&gt;
2215&lt;div class="sourceCode" id="cb24"&gt;&lt;pre
2216class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb24-1"&gt;&lt;a href="#cb24-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1440&lt;span id="cb24-2"&gt;&lt;a href="#cb24-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T1 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; T0&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2217&lt;span id="cb24-2"&gt;&lt;a href="#cb24-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T1 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; T0&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1441&lt;span id="cb24-3"&gt;&lt;a href="#cb24-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T2 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; T1&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2218&lt;span id="cb24-3"&gt;&lt;a href="#cb24-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T2 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; T1&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1442&lt;p&gt;In general:&lt;/p&gt; 2219&lt;p&gt;In general:&lt;/p&gt;
1443&lt;div class="sourceCode" id="cb25"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb25-1"&gt;&lt;a href="#cb25-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="kw"&gt;type&lt;/span&gt;&amp;gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2220&lt;div class="sourceCode" id="cb25"&gt;&lt;pre
2221class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb25-1"&gt;&lt;a href="#cb25-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="kw"&gt;type&lt;/span&gt;&amp;gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1444&lt;span id="cb25-2"&gt;&lt;a href="#cb25-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T1 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kw"&gt;type&lt;/span&gt; of arg N&amp;gt;) -&amp;gt; T0&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2222&lt;span id="cb25-2"&gt;&lt;a href="#cb25-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T1 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kw"&gt;type&lt;/span&gt; of arg N&amp;gt;) -&amp;gt; T0&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1445&lt;span id="cb25-3"&gt;&lt;a href="#cb25-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T2 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kw"&gt;type&lt;/span&gt; of arg N - 1&amp;gt;) -&amp;gt; T1&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2223&lt;span id="cb25-3"&gt;&lt;a href="#cb25-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T2 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kw"&gt;type&lt;/span&gt; of arg N - 1&amp;gt;) -&amp;gt; T1&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1446&lt;span id="cb25-4"&gt;&lt;a href="#cb25-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;.&lt;/span&gt;&lt;/span&gt; 2224&lt;span id="cb25-4"&gt;&lt;a href="#cb25-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;.&lt;/span&gt;&lt;/span&gt;
@@ -1452,42 +2230,59 @@ syn::token::Fn --&amp;#39; / \ (output)
1452&lt;li&gt;all our inputs (arguments)&lt;/li&gt; 2230&lt;li&gt;all our inputs (arguments)&lt;/li&gt;
1453&lt;li&gt;the output (the return type)&lt;/li&gt; 2231&lt;li&gt;the output (the return type)&lt;/li&gt;
1454&lt;/ul&gt; 2232&lt;/ul&gt;
1455&lt;p&gt;To fetch the types of all our inputs, we can simply reuse the bits we wrote to fetch the names of all our inputs! (doc: &lt;a href="https://docs.rs/syn/1.0.18/syn/enum.Type.html"&gt;Type&lt;/a&gt;)&lt;/p&gt; 2233&lt;p&gt;To fetch the types of all our inputs, we can simply reuse the bits we
1456&lt;div class="sourceCode" id="cb26"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb26-1"&gt;&lt;a href="#cb26-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt; 2234wrote to fetch the names of all our inputs! (doc: &lt;a
2235href="https://docs.rs/syn/1.0.18/syn/enum.Type.html"&gt;Type&lt;/a&gt;)&lt;/p&gt;
2236&lt;div class="sourceCode" id="cb26"&gt;&lt;pre
2237class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb26-1"&gt;&lt;a href="#cb26-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt;
1457&lt;span id="cb26-2"&gt;&lt;a href="#cb26-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2238&lt;span id="cb26-2"&gt;&lt;a href="#cb26-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1458&lt;span id="cb26-3"&gt;&lt;a href="#cb26-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;syn::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;parse_macro_input&lt;span class="op"&gt;,&lt;/span&gt; Block&lt;span class="op"&gt;,&lt;/span&gt; FnArg&lt;span class="op"&gt;,&lt;/span&gt; ItemFn&lt;span class="op"&gt;,&lt;/span&gt; Pat&lt;span class="op"&gt;,&lt;/span&gt; ReturnType&lt;span class="op"&gt;,&lt;/span&gt; Type&lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt; 2239&lt;span id="cb26-3"&gt;&lt;a href="#cb26-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;syn::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;parse_macro_input&lt;span class="op"&gt;,&lt;/span&gt; Block&lt;span class="op"&gt;,&lt;/span&gt; FnArg&lt;span class="op"&gt;,&lt;/span&gt; ItemFn&lt;span class="op"&gt;,&lt;/span&gt; Pat&lt;span class="op"&gt;,&lt;/span&gt; ReturnType&lt;span class="op"&gt;,&lt;/span&gt; Type&lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt;
1459&lt;span id="cb26-4"&gt;&lt;a href="#cb26-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2240&lt;span id="cb26-4"&gt;&lt;a href="#cb26-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1460&lt;span id="cb26-5"&gt;&lt;a href="#cb26-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; extract_type(a&lt;span class="op"&gt;:&lt;/span&gt; FnArg) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Box&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;Type&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2241&lt;span id="cb26-5"&gt;&lt;a href="#cb26-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; extract_type(a&lt;span class="op"&gt;:&lt;/span&gt; FnArg) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Box&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;Type&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1461&lt;span id="cb26-6"&gt;&lt;a href="#cb26-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;match&lt;/span&gt; a &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2242&lt;span id="cb26-6"&gt;&lt;a href="#cb26-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;match&lt;/span&gt; a &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1462&lt;span id="cb26-7"&gt;&lt;a href="#cb26-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="pp"&gt;FnArg::&lt;/span&gt;Typed(p) &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; p&lt;span class="op"&gt;.&lt;/span&gt;ty&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="co"&gt;// notice `ty` instead of `pat`&lt;/span&gt;&lt;/span&gt; 2243&lt;span id="cb26-7"&gt;&lt;a href="#cb26-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="pp"&gt;FnArg::&lt;/span&gt;Typed(p) &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; p&lt;span class="op"&gt;.&lt;/span&gt;ty&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="co"&gt;// notice `ty` instead of `pat`&lt;/span&gt;&lt;/span&gt;
1463&lt;span id="cb26-8"&gt;&lt;a href="#cb26-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; _ &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;panic!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;Not supported on types with `self`!&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt; 2244&lt;span id="cb26-8"&gt;&lt;a href="#cb26-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; _ &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;panic!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;Not supported on types with `self`!&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
1464&lt;span id="cb26-9"&gt;&lt;a href="#cb26-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 2245&lt;span id="cb26-9"&gt;&lt;a href="#cb26-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
1465&lt;span id="cb26-10"&gt;&lt;a href="#cb26-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 2246&lt;span id="cb26-10"&gt;&lt;a href="#cb26-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
1466&lt;span id="cb26-11"&gt;&lt;a href="#cb26-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2247&lt;span id="cb26-11"&gt;&lt;a href="#cb26-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1467&lt;span id="cb26-12"&gt;&lt;a href="#cb26-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; extract_arg_types(fn_args&lt;span class="op"&gt;:&lt;/span&gt; Punctuated&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;FnArg&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="pp"&gt;syn::token::&lt;/span&gt;Comma&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Vec&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dt"&gt;Box&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;Type&lt;span class="op"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2248&lt;span id="cb26-12"&gt;&lt;a href="#cb26-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; extract_arg_types(fn_args&lt;span class="op"&gt;:&lt;/span&gt; Punctuated&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;FnArg&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="pp"&gt;syn::token::&lt;/span&gt;Comma&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Vec&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dt"&gt;Box&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;Type&lt;span class="op"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1468&lt;span id="cb26-13"&gt;&lt;a href="#cb26-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;return&lt;/span&gt; fn_args&lt;span class="op"&gt;.&lt;/span&gt;into_iter()&lt;span class="op"&gt;.&lt;/span&gt;map(extract_type)&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="pp"&gt;collect::&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dt"&gt;Vec&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;_&lt;span class="op"&gt;&amp;gt;&amp;gt;&lt;/span&gt;()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2249&lt;span id="cb26-13"&gt;&lt;a href="#cb26-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;return&lt;/span&gt; fn_args&lt;span class="op"&gt;.&lt;/span&gt;into_iter()&lt;span class="op"&gt;.&lt;/span&gt;map(extract_type)&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="pp"&gt;collect::&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dt"&gt;Vec&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;_&lt;span class="op"&gt;&amp;gt;&amp;gt;&lt;/span&gt;()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1469&lt;span id="cb26-14"&gt;&lt;a href="#cb26-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2250&lt;span id="cb26-14"&gt;&lt;a href="#cb26-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1470&lt;span id="cb26-15"&gt;&lt;a href="#cb26-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2251&lt;span id="cb26-15"&gt;&lt;a href="#cb26-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1471&lt;p&gt;A good reader would have looked at the docs for output member of the &lt;code&gt;syn::Signature&lt;/code&gt; struct. It has the type &lt;code&gt;syn::ReturnType&lt;/code&gt;. So there is no extraction to do here right? There are actually a couple of things we have to ensure here:&lt;/p&gt; 2252&lt;p&gt;A good reader would have looked at the docs for output member of the
2253&lt;code&gt;syn::Signature&lt;/code&gt; struct. It has the type
2254&lt;code&gt;syn::ReturnType&lt;/code&gt;. So there is no extraction to do here
2255right? There are actually a couple of things we have to ensure here:&lt;/p&gt;
1472&lt;ol type="1"&gt; 2256&lt;ol type="1"&gt;
1473&lt;li&gt;&lt;p&gt;We need to ensure that the function returns! A function that does not return is pointless in this case, and I will tell you why, in the &lt;a href="#notes"&gt;Notes&lt;/a&gt; section.&lt;/p&gt;&lt;/li&gt; 2257&lt;li&gt;&lt;p&gt;We need to ensure that the function returns! A function that does
1474&lt;li&gt;&lt;p&gt;A &lt;code&gt;ReturnType&lt;/code&gt; encloses the arrow of the return as well, we need to get rid of that. Recall:&lt;/p&gt; 2258not return is pointless in this case, and I will tell you why, in the &lt;a
1475&lt;div class="sourceCode" id="cb27"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb27-1"&gt;&lt;a href="#cb27-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;/span&gt; 2259href="#notes"&gt;Notes&lt;/a&gt; section.&lt;/p&gt;&lt;/li&gt;
2260&lt;li&gt;&lt;p&gt;A &lt;code&gt;ReturnType&lt;/code&gt; encloses the arrow of the return as
2261well, we need to get rid of that. Recall:&lt;/p&gt;
2262&lt;div class="sourceCode" id="cb27"&gt;&lt;pre
2263class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb27-1"&gt;&lt;a href="#cb27-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;/span&gt;
1476&lt;span id="cb27-2"&gt;&lt;a href="#cb27-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// and not&lt;/span&gt;&lt;/span&gt; 2264&lt;span id="cb27-2"&gt;&lt;a href="#cb27-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// and not&lt;/span&gt;&lt;/span&gt;
1477&lt;span id="cb27-3"&gt;&lt;a href="#cb27-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt; 2265&lt;span id="cb27-3"&gt;&lt;a href="#cb27-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
1478&lt;/ol&gt; 2266&lt;/ol&gt;
1479&lt;p&gt;Here is the snippet that handles extraction of the return type (doc: &lt;a href="https://docs.rs/syn/1.0.19/syn/enum.ReturnType.html"&gt;syn::ReturnType&lt;/a&gt;):&lt;/p&gt; 2267&lt;p&gt;Here is the snippet that handles extraction of the return type (doc:
1480&lt;div class="sourceCode" id="cb28"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb28-1"&gt;&lt;a href="#cb28-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt; 2268&lt;a
2269href="https://docs.rs/syn/1.0.19/syn/enum.ReturnType.html"&gt;syn::ReturnType&lt;/a&gt;):&lt;/p&gt;
2270&lt;div class="sourceCode" id="cb28"&gt;&lt;pre
2271class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb28-1"&gt;&lt;a href="#cb28-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt;
1481&lt;span id="cb28-2"&gt;&lt;a href="#cb28-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2272&lt;span id="cb28-2"&gt;&lt;a href="#cb28-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1482&lt;span id="cb28-3"&gt;&lt;a href="#cb28-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; extract_return_type(a&lt;span class="op"&gt;:&lt;/span&gt; ReturnType) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Box&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;Type&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2273&lt;span id="cb28-3"&gt;&lt;a href="#cb28-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; extract_return_type(a&lt;span class="op"&gt;:&lt;/span&gt; ReturnType) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Box&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;Type&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1483&lt;span id="cb28-4"&gt;&lt;a href="#cb28-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;match&lt;/span&gt; a &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2274&lt;span id="cb28-4"&gt;&lt;a href="#cb28-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;match&lt;/span&gt; a &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1484&lt;span id="cb28-5"&gt;&lt;a href="#cb28-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="pp"&gt;ReturnType::&lt;/span&gt;Type(_&lt;span class="op"&gt;,&lt;/span&gt; p) &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; p&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt; 2275&lt;span id="cb28-5"&gt;&lt;a href="#cb28-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="pp"&gt;ReturnType::&lt;/span&gt;Type(_&lt;span class="op"&gt;,&lt;/span&gt; p) &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; p&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
1485&lt;span id="cb28-6"&gt;&lt;a href="#cb28-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; _ &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;panic!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;Not supported on functions without return types!&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt; 2276&lt;span id="cb28-6"&gt;&lt;a href="#cb28-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; _ &lt;span class="op"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;panic!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;Not supported on functions without return types!&amp;quot;&lt;/span&gt;)&lt;span class="op"&gt;,&lt;/span&gt;&lt;/span&gt;
1486&lt;span id="cb28-7"&gt;&lt;a href="#cb28-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 2277&lt;span id="cb28-7"&gt;&lt;a href="#cb28-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
1487&lt;span id="cb28-8"&gt;&lt;a href="#cb28-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2278&lt;span id="cb28-8"&gt;&lt;a href="#cb28-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1488&lt;p&gt;You might notice that we are making extensive use of the &lt;code&gt;panic!&lt;/code&gt; macro. Well, that is because it is a good idea to quit on receiving an unsatisfactory &lt;code&gt;TokenStream&lt;/code&gt;.&lt;/p&gt; 2279&lt;p&gt;You might notice that we are making extensive use of the
1489&lt;p&gt;With all our types ready, we can get on with generating type aliases:&lt;/p&gt; 2280&lt;code&gt;panic!&lt;/code&gt; macro. Well, that is because it is a good idea to
1490&lt;div class="sourceCode" id="cb29"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb29-1"&gt;&lt;a href="#cb29-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt; 2281quit on receiving an unsatisfactory &lt;code&gt;TokenStream&lt;/code&gt;.&lt;/p&gt;
2282&lt;p&gt;With all our types ready, we can get on with generating type
2283aliases:&lt;/p&gt;
2284&lt;div class="sourceCode" id="cb29"&gt;&lt;pre
2285class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb29-1"&gt;&lt;a href="#cb29-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt;
1491&lt;span id="cb29-2"&gt;&lt;a href="#cb29-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2286&lt;span id="cb29-2"&gt;&lt;a href="#cb29-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1492&lt;span id="cb29-3"&gt;&lt;a href="#cb29-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;quote::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;quote&lt;span class="op"&gt;,&lt;/span&gt; format_ident&lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt; 2287&lt;span id="cb29-3"&gt;&lt;a href="#cb29-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;quote::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;quote&lt;span class="op"&gt;,&lt;/span&gt; format_ident&lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt;
1493&lt;span id="cb29-4"&gt;&lt;a href="#cb29-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2288&lt;span id="cb29-4"&gt;&lt;a href="#cb29-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
@@ -1501,7 +2296,7 @@ syn::token::Fn --&amp;#39; / \ (output)
1501&lt;span id="cb29-12"&gt;&lt;a href="#cb29-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; &lt;span class="kw"&gt;mut&lt;/span&gt; type_aliases &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;vec!&lt;/span&gt;[&lt;span class="pp"&gt;quote!&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="kw"&gt;type&lt;/span&gt; #type_t0 &lt;span class="op"&gt;=&lt;/span&gt; #fn_return_type &lt;span class="op"&gt;}&lt;/span&gt;]&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2296&lt;span id="cb29-12"&gt;&lt;a href="#cb29-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; &lt;span class="kw"&gt;mut&lt;/span&gt; type_aliases &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;vec!&lt;/span&gt;[&lt;span class="pp"&gt;quote!&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="kw"&gt;type&lt;/span&gt; #type_t0 &lt;span class="op"&gt;=&lt;/span&gt; #fn_return_type &lt;span class="op"&gt;}&lt;/span&gt;]&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1502&lt;span id="cb29-13"&gt;&lt;a href="#cb29-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2297&lt;span id="cb29-13"&gt;&lt;a href="#cb29-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1503&lt;span id="cb29-14"&gt;&lt;a href="#cb29-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="co"&gt;// 3&lt;/span&gt;&lt;/span&gt; 2298&lt;span id="cb29-14"&gt;&lt;a href="#cb29-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="co"&gt;// 3&lt;/span&gt;&lt;/span&gt;
1504&lt;span id="cb29-15"&gt;&lt;a href="#cb29-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;for&lt;/span&gt; (i&lt;span class="op"&gt;,&lt;/span&gt; t) &lt;span class="kw"&gt;in&lt;/span&gt; (&lt;span class="dv"&gt;1&lt;/span&gt;&lt;span class="op"&gt;..&lt;/span&gt;)&lt;span class="op"&gt;.&lt;/span&gt;zip(fn_arg_types&lt;span class="op"&gt;.&lt;/span&gt;into_iter()&lt;span class="op"&gt;.&lt;/span&gt;rev()) &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2299&lt;span id="cb29-15"&gt;&lt;a href="#cb29-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;for&lt;/span&gt; (i&lt;span class="op"&gt;,&lt;/span&gt; t) &lt;span class="kw"&gt;in&lt;/span&gt; (&lt;span class="dv"&gt;1&lt;/span&gt;&lt;span class="op"&gt;..&lt;/span&gt;)&lt;span class="op"&gt;.&lt;/span&gt;zip(fn_arg_types&lt;span class="op"&gt;.&lt;/span&gt;into_iter()&lt;span class="op"&gt;.&lt;/span&gt;rev()) &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1505&lt;span id="cb29-16"&gt;&lt;a href="#cb29-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; p &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;format_ident!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;_{}_{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; fn_name&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="pp"&gt;format!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;T{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; i &lt;span class="op"&gt;-&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;))&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2300&lt;span id="cb29-16"&gt;&lt;a href="#cb29-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; p &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;format_ident!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;_{}_{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; fn_name&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="pp"&gt;format!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;T{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; i &lt;span class="op"&gt;-&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;))&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1506&lt;span id="cb29-17"&gt;&lt;a href="#cb29-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; n &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;format_ident!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;_{}_{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; fn_name&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="pp"&gt;format!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;T{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; i))&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2301&lt;span id="cb29-17"&gt;&lt;a href="#cb29-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; n &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;format_ident!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;_{}_{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; fn_name&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="pp"&gt;format!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;T{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; i))&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1507&lt;span id="cb29-18"&gt;&lt;a href="#cb29-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2302&lt;span id="cb29-18"&gt;&lt;a href="#cb29-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
@@ -1510,45 +2305,70 @@ syn::token::Fn --&amp;#39; / \ (output)
1510&lt;span id="cb29-21"&gt;&lt;a href="#cb29-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2305&lt;span id="cb29-21"&gt;&lt;a href="#cb29-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1511&lt;span id="cb29-22"&gt;&lt;a href="#cb29-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 2306&lt;span id="cb29-22"&gt;&lt;a href="#cb29-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
1512&lt;span id="cb29-23"&gt;&lt;a href="#cb29-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2307&lt;span id="cb29-23"&gt;&lt;a href="#cb29-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1513&lt;span id="cb29-24"&gt;&lt;a href="#cb29-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;return&lt;/span&gt; type_aliases&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2308&lt;span id="cb29-24"&gt;&lt;a href="#cb29-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;return&lt;/span&gt; type_aliases&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1514&lt;span id="cb29-25"&gt;&lt;a href="#cb29-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2309&lt;span id="cb29-25"&gt;&lt;a href="#cb29-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1515&lt;p&gt;&lt;strong&gt;1. The return value&lt;/strong&gt;&lt;br /&gt; 2310&lt;p&gt;&lt;strong&gt;1. The return value&lt;/strong&gt;&lt;br /&gt;
1516We are returning a &lt;code&gt;Vec&amp;lt;proc_macro2::TokenStream&amp;gt;&lt;/code&gt;, i. e., a list of &lt;code&gt;TokenStream&lt;/code&gt;s, where each item is a type alias.&lt;/p&gt; 2311We are returning a &lt;code&gt;Vec&amp;lt;proc_macro2::TokenStream&amp;gt;&lt;/code&gt;, i.
2312e., a list of &lt;code&gt;TokenStream&lt;/code&gt;s, where each item is a type
2313alias.&lt;/p&gt;
1517&lt;p&gt;&lt;strong&gt;2. Format identifier?&lt;/strong&gt;&lt;br /&gt; 2314&lt;p&gt;&lt;strong&gt;2. Format identifier?&lt;/strong&gt;&lt;br /&gt;
1518I’ve got some explanation to do on this line. Clearly, we are trying to write the first type alias, and initialize our &lt;code&gt;TokenStream&lt;/code&gt; vector with &lt;code&gt;T0&lt;/code&gt;, because it is different from the others:&lt;/p&gt; 2315I’ve got some explanation to do on this line. Clearly, we are trying to
1519&lt;div class="sourceCode" id="cb30"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb30-1"&gt;&lt;a href="#cb30-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T0 &lt;span class="op"&gt;=&lt;/span&gt; something&lt;/span&gt; 2316write the first type alias, and initialize our &lt;code&gt;TokenStream&lt;/code&gt;
2317vector with &lt;code&gt;T0&lt;/code&gt;, because it is different from the
2318others:&lt;/p&gt;
2319&lt;div class="sourceCode" id="cb30"&gt;&lt;pre
2320class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb30-1"&gt;&lt;a href="#cb30-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T0 &lt;span class="op"&gt;=&lt;/span&gt; something&lt;/span&gt;
1520&lt;span id="cb30-2"&gt;&lt;a href="#cb30-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// the others are of the form&lt;/span&gt;&lt;/span&gt; 2321&lt;span id="cb30-2"&gt;&lt;a href="#cb30-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// the others are of the form&lt;/span&gt;&lt;/span&gt;
1521&lt;span id="cb30-3"&gt;&lt;a href="#cb30-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; Tr &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(something) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; something&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2322&lt;span id="cb30-3"&gt;&lt;a href="#cb30-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; Tr &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(something) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; something&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1522&lt;p&gt;&lt;code&gt;format_ident!&lt;/code&gt; is similar to &lt;code&gt;format!&lt;/code&gt;. Instead of returning a formatted string, it returns a &lt;code&gt;syn::Ident&lt;/code&gt;. Therefore, &lt;code&gt;type_t0&lt;/code&gt; is actually an identifier for, in the case of our &lt;code&gt;add&lt;/code&gt; function, &lt;code&gt;_add_T0&lt;/code&gt;. Why is this formatting important? Namespacing.&lt;/p&gt; 2323&lt;p&gt;&lt;code&gt;format_ident!&lt;/code&gt; is similar to &lt;code&gt;format!&lt;/code&gt;.
1523&lt;p&gt;Picture this, we have two functions, &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;subtract&lt;/code&gt;, that we wish to curry with our macro:&lt;/p&gt; 2324Instead of returning a formatted string, it returns a
1524&lt;div class="sourceCode" id="cb31"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb31-1"&gt;&lt;a href="#cb31-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="at"&gt;#[&lt;/span&gt;curry&lt;span class="at"&gt;]&lt;/span&gt;&lt;/span&gt; 2325&lt;code&gt;syn::Ident&lt;/code&gt;. Therefore, &lt;code&gt;type_t0&lt;/code&gt; is actually an
2326identifier for, in the case of our &lt;code&gt;add&lt;/code&gt; function,
2327&lt;code&gt;_add_T0&lt;/code&gt;. Why is this formatting important? Namespacing.&lt;/p&gt;
2328&lt;p&gt;Picture this, we have two functions, &lt;code&gt;add&lt;/code&gt; and
2329&lt;code&gt;subtract&lt;/code&gt;, that we wish to curry with our macro:&lt;/p&gt;
2330&lt;div class="sourceCode" id="cb31"&gt;&lt;pre
2331class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb31-1"&gt;&lt;a href="#cb31-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="at"&gt;#[&lt;/span&gt;curry&lt;span class="at"&gt;]&lt;/span&gt;&lt;/span&gt;
1525&lt;span id="cb31-2"&gt;&lt;a href="#cb31-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; add(&lt;span class="op"&gt;...&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 2332&lt;span id="cb31-2"&gt;&lt;a href="#cb31-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; add(&lt;span class="op"&gt;...&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
1526&lt;span id="cb31-3"&gt;&lt;a href="#cb31-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2333&lt;span id="cb31-3"&gt;&lt;a href="#cb31-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1527&lt;span id="cb31-4"&gt;&lt;a href="#cb31-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="at"&gt;#[&lt;/span&gt;curry&lt;span class="at"&gt;]&lt;/span&gt;&lt;/span&gt; 2334&lt;span id="cb31-4"&gt;&lt;a href="#cb31-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="at"&gt;#[&lt;/span&gt;curry&lt;span class="at"&gt;]&lt;/span&gt;&lt;/span&gt;
1528&lt;span id="cb31-5"&gt;&lt;a href="#cb31-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; sub(&lt;span class="op"&gt;...&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2335&lt;span id="cb31-5"&gt;&lt;a href="#cb31-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; sub(&lt;span class="op"&gt;...&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1529&lt;p&gt;Here is the same but with macros expanded:&lt;/p&gt; 2336&lt;p&gt;Here is the same but with macros expanded:&lt;/p&gt;
1530&lt;div class="sourceCode" id="cb32"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb32-1"&gt;&lt;a href="#cb32-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2337&lt;div class="sourceCode" id="cb32"&gt;&lt;pre
2338class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb32-1"&gt;&lt;a href="#cb32-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1531&lt;span id="cb32-2"&gt;&lt;a href="#cb32-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T1 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; T0&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2339&lt;span id="cb32-2"&gt;&lt;a href="#cb32-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T1 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; T0&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1532&lt;span id="cb32-3"&gt;&lt;a href="#cb32-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; add( &lt;span class="op"&gt;...&lt;/span&gt; ) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; T1 &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 2340&lt;span id="cb32-3"&gt;&lt;a href="#cb32-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; add( &lt;span class="op"&gt;...&lt;/span&gt; ) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; T1 &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
1533&lt;span id="cb32-4"&gt;&lt;a href="#cb32-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2341&lt;span id="cb32-4"&gt;&lt;a href="#cb32-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1534&lt;span id="cb32-5"&gt;&lt;a href="#cb32-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2342&lt;span id="cb32-5"&gt;&lt;a href="#cb32-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1535&lt;span id="cb32-6"&gt;&lt;a href="#cb32-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T1 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; T0&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2343&lt;span id="cb32-6"&gt;&lt;a href="#cb32-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; T1 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; T0&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1536&lt;span id="cb32-7"&gt;&lt;a href="#cb32-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; sub( &lt;span class="op"&gt;...&lt;/span&gt; ) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; T1 &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2344&lt;span id="cb32-7"&gt;&lt;a href="#cb32-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; sub( &lt;span class="op"&gt;...&lt;/span&gt; ) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; T1 &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1537&lt;p&gt;We end up with two definitions of &lt;code&gt;T0&lt;/code&gt;! Now, if we do the little &lt;code&gt;format_ident!&lt;/code&gt; dance we did up there:&lt;/p&gt; 2345&lt;p&gt;We end up with two definitions of &lt;code&gt;T0&lt;/code&gt;! Now, if we do the
1538&lt;div class="sourceCode" id="cb33"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb33-1"&gt;&lt;a href="#cb33-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; _add_T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2346little &lt;code&gt;format_ident!&lt;/code&gt; dance we did up there:&lt;/p&gt;
2347&lt;div class="sourceCode" id="cb33"&gt;&lt;pre
2348class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb33-1"&gt;&lt;a href="#cb33-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; _add_T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1539&lt;span id="cb33-2"&gt;&lt;a href="#cb33-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; _add_T1 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; _add_T0&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2349&lt;span id="cb33-2"&gt;&lt;a href="#cb33-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; _add_T1 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; _add_T0&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1540&lt;span id="cb33-3"&gt;&lt;a href="#cb33-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; add( &lt;span class="op"&gt;...&lt;/span&gt; ) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; _add_T1 &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 2350&lt;span id="cb33-3"&gt;&lt;a href="#cb33-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; add( &lt;span class="op"&gt;...&lt;/span&gt; ) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; _add_T1 &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
1541&lt;span id="cb33-4"&gt;&lt;a href="#cb33-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2351&lt;span id="cb33-4"&gt;&lt;a href="#cb33-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1542&lt;span id="cb33-5"&gt;&lt;a href="#cb33-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; _sub_T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2352&lt;span id="cb33-5"&gt;&lt;a href="#cb33-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; _sub_T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1543&lt;span id="cb33-6"&gt;&lt;a href="#cb33-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; _sub_T1 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; _sub_T0&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2353&lt;span id="cb33-6"&gt;&lt;a href="#cb33-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; _sub_T1 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; _sub_T0&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1544&lt;span id="cb33-7"&gt;&lt;a href="#cb33-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; sub( &lt;span class="op"&gt;...&lt;/span&gt; ) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; _sub_T1 &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2354&lt;span id="cb33-7"&gt;&lt;a href="#cb33-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; sub( &lt;span class="op"&gt;...&lt;/span&gt; ) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; _sub_T1 &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1545&lt;p&gt;Voilà! The type aliases don’t tread on each other. Remember to import &lt;code&gt;format_ident&lt;/code&gt; from the &lt;code&gt;quote&lt;/code&gt; crate.&lt;/p&gt; 2355&lt;p&gt;Voilà! The type aliases don’t tread on each other. Remember to import
2356&lt;code&gt;format_ident&lt;/code&gt; from the &lt;code&gt;quote&lt;/code&gt; crate.&lt;/p&gt;
1546&lt;p&gt;&lt;strong&gt;3. The TokenStream Vector&lt;/strong&gt;&lt;/p&gt; 2357&lt;p&gt;&lt;strong&gt;3. The TokenStream Vector&lt;/strong&gt;&lt;/p&gt;
1547&lt;p&gt;We iterate over our types in reverse order (&lt;code&gt;T0&lt;/code&gt; is the last return, &lt;code&gt;T1&lt;/code&gt; is the second last, so on), assign a number to each iteration with &lt;code&gt;zip&lt;/code&gt;, generate type names with &lt;code&gt;format_ident&lt;/code&gt;, push a &lt;code&gt;TokenStream&lt;/code&gt; with the help of &lt;code&gt;quote&lt;/code&gt; and variable interpolation.&lt;/p&gt; 2358&lt;p&gt;We iterate over our types in reverse order (&lt;code&gt;T0&lt;/code&gt; is the
1548&lt;p&gt;If you are wondering why we used &lt;code&gt;(1..).zip()&lt;/code&gt; instead of &lt;code&gt;.enumerate()&lt;/code&gt;, it’s because we wanted to start counting from 1 instead of 0 (we are already done with &lt;code&gt;T0&lt;/code&gt;!).&lt;/p&gt; 2359last return, &lt;code&gt;T1&lt;/code&gt; is the second last, so on), assign a number
2360to each iteration with &lt;code&gt;zip&lt;/code&gt;, generate type names with
2361&lt;code&gt;format_ident&lt;/code&gt;, push a &lt;code&gt;TokenStream&lt;/code&gt; with the help
2362of &lt;code&gt;quote&lt;/code&gt; and variable interpolation.&lt;/p&gt;
2363&lt;p&gt;If you are wondering why we used &lt;code&gt;(1..).zip()&lt;/code&gt; instead of
2364&lt;code&gt;.enumerate()&lt;/code&gt;, it’s because we wanted to start counting from
23651 instead of 0 (we are already done with &lt;code&gt;T0&lt;/code&gt;!).&lt;/p&gt;
1549&lt;h4 id="getting-it-together"&gt;Getting it together&lt;/h4&gt; 2366&lt;h4 id="getting-it-together"&gt;Getting it together&lt;/h4&gt;
1550&lt;p&gt;I promised we’d have a fully working macro by the end of last section. I lied, we have to tie everything together in our &lt;code&gt;generate_curry&lt;/code&gt; function:&lt;/p&gt; 2367&lt;p&gt;I promised we’d have a fully working macro by the end of last
1551&lt;div class="sourceCode" id="cb34"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb34-1"&gt;&lt;a href="#cb34-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt; 2368section. I lied, we have to tie everything together in our
2369&lt;code&gt;generate_curry&lt;/code&gt; function:&lt;/p&gt;
2370&lt;div class="sourceCode" id="cb34"&gt;&lt;pre
2371class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb34-1"&gt;&lt;a href="#cb34-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// src/lib.rs&lt;/span&gt;&lt;/span&gt;
1552&lt;span id="cb34-2"&gt;&lt;a href="#cb34-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2372&lt;span id="cb34-2"&gt;&lt;a href="#cb34-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1553&lt;span id="cb34-3"&gt;&lt;a href="#cb34-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;fn&lt;/span&gt; generate_curry(parsed&lt;span class="op"&gt;:&lt;/span&gt; ItemFn) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;proc_macro2::&lt;/span&gt;TokenStream &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2373&lt;span id="cb34-3"&gt;&lt;a href="#cb34-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;fn&lt;/span&gt; generate_curry(parsed&lt;span class="op"&gt;:&lt;/span&gt; ItemFn) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pp"&gt;proc_macro2::&lt;/span&gt;TokenStream &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1554&lt;span id="cb34-4"&gt;&lt;a href="#cb34-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; fn_body &lt;span class="op"&gt;=&lt;/span&gt; parsed&lt;span class="op"&gt;.&lt;/span&gt;block&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2374&lt;span id="cb34-4"&gt;&lt;a href="#cb34-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; fn_body &lt;span class="op"&gt;=&lt;/span&gt; parsed&lt;span class="op"&gt;.&lt;/span&gt;block&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
@@ -1572,20 +2392,39 @@ I’ve got some explanation to do on this line. Clearly, we are trying to write
1572&lt;span id="cb34-22"&gt;&lt;a href="#cb34-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2392&lt;span id="cb34-22"&gt;&lt;a href="#cb34-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1573&lt;span id="cb34-23"&gt;&lt;a href="#cb34-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="kw"&gt;let&lt;/span&gt; return_type &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;format_ident!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;_{}_{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="op"&gt;&amp;amp;&lt;/span&gt;fn_name&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="pp"&gt;format!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;T{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; type_aliases&lt;span class="op"&gt;.&lt;/span&gt;len() &lt;span class="op"&gt;-&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;))&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2393&lt;span id="cb34-23"&gt;&lt;a href="#cb34-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="kw"&gt;let&lt;/span&gt; return_type &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="pp"&gt;format_ident!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;_{}_{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="op"&gt;&amp;amp;&lt;/span&gt;fn_name&lt;span class="op"&gt;,&lt;/span&gt; &lt;span class="pp"&gt;format!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;T{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; type_aliases&lt;span class="op"&gt;.&lt;/span&gt;len() &lt;span class="op"&gt;-&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;))&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1574&lt;span id="cb34-24"&gt;&lt;a href="#cb34-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2394&lt;span id="cb34-24"&gt;&lt;a href="#cb34-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1575&lt;span id="cb34-25"&gt;&lt;a href="#cb34-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="pp"&gt;quote!&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2395&lt;span id="cb34-25"&gt;&lt;a href="#cb34-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="pp"&gt;quote!&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1576&lt;span id="cb34-26"&gt;&lt;a href="#cb34-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; #(#type_aliases)&lt;span class="op"&gt;;*&lt;/span&gt; &lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2396&lt;span id="cb34-26"&gt;&lt;a href="#cb34-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; #(#type_aliases)&lt;span class="op"&gt;;*&lt;/span&gt; &lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1577&lt;span id="cb34-27"&gt;&lt;a href="#cb34-27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; #vis &lt;span class="kw"&gt;fn&lt;/span&gt; #fn_name (#first_ident&lt;span class="op"&gt;:&lt;/span&gt; #first_type) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; #return_type &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2397&lt;span id="cb34-27"&gt;&lt;a href="#cb34-27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; #vis &lt;span class="kw"&gt;fn&lt;/span&gt; #fn_name (#first_ident&lt;span class="op"&gt;:&lt;/span&gt; #first_type) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; #return_type &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1578&lt;span id="cb34-28"&gt;&lt;a href="#cb34-28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; #curried_body &lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2398&lt;span id="cb34-28"&gt;&lt;a href="#cb34-28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; #curried_body &lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1579&lt;span id="cb34-29"&gt;&lt;a href="#cb34-29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 2399&lt;span id="cb34-29"&gt;&lt;a href="#cb34-29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
1580&lt;span id="cb34-30"&gt;&lt;a href="#cb34-30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt; 2400&lt;span id="cb34-30"&gt;&lt;a href="#cb34-30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt;
1581&lt;span id="cb34-31"&gt;&lt;a href="#cb34-31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2401&lt;span id="cb34-31"&gt;&lt;a href="#cb34-31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1582&lt;p&gt;Most of the additions are self explanatory, I’ll go through the return statement with you. We are returning a &lt;code&gt;quote!{ ... }&lt;/code&gt;, so a &lt;code&gt;proc_macro2::TokenStream&lt;/code&gt;. We are iterating through the &lt;code&gt;type_aliases&lt;/code&gt; variable, which you might recall, is a &lt;code&gt;Vec&amp;lt;TokenStream&amp;gt;&lt;/code&gt;. You might notice the sneaky semicolon before the &lt;code&gt;*&lt;/code&gt;. This basically tells &lt;code&gt;quote&lt;/code&gt;, to insert an item, then a semicolon, and then the next one, another semicolon, and so on. The semicolon is a separator. We need to manually insert another semicolon at the end of it all, &lt;code&gt;quote&lt;/code&gt; doesn’t insert a separator at the end of the iteration.&lt;/p&gt; 2402&lt;p&gt;Most of the additions are self explanatory, I’ll go through the
1583&lt;p&gt;We retain the visibility and name of our original function. Our curried function takes as args, just the first argument of our original function. The return type of our curried function is actually, the last type alias we create. If you think back to our manually curried &lt;code&gt;add&lt;/code&gt; function, we returned &lt;code&gt;T2&lt;/code&gt;, which was in fact, the last type alias we created.&lt;/p&gt; 2403return statement with you. We are returning a
1584&lt;p&gt;I am sure, at this point, you are itching to test this out, but before that, let me introduce you to some good methods of debugging proc-macro code.&lt;/p&gt; 2404&lt;code&gt;quote!{ ... }&lt;/code&gt;, so a &lt;code&gt;proc_macro2::TokenStream&lt;/code&gt;.
2405We are iterating through the &lt;code&gt;type_aliases&lt;/code&gt; variable, which
2406you might recall, is a &lt;code&gt;Vec&amp;lt;TokenStream&amp;gt;&lt;/code&gt;. You might
2407notice the sneaky semicolon before the &lt;code&gt;*&lt;/code&gt;. This basically
2408tells &lt;code&gt;quote&lt;/code&gt;, to insert an item, then a semicolon, and then
2409the next one, another semicolon, and so on. The semicolon is a
2410separator. We need to manually insert another semicolon at the end of it
2411all, &lt;code&gt;quote&lt;/code&gt; doesn’t insert a separator at the end of the
2412iteration.&lt;/p&gt;
2413&lt;p&gt;We retain the visibility and name of our original function. Our
2414curried function takes as args, just the first argument of our original
2415function. The return type of our curried function is actually, the last
2416type alias we create. If you think back to our manually curried
2417&lt;code&gt;add&lt;/code&gt; function, we returned &lt;code&gt;T2&lt;/code&gt;, which was in
2418fact, the last type alias we created.&lt;/p&gt;
2419&lt;p&gt;I am sure, at this point, you are itching to test this out, but
2420before that, let me introduce you to some good methods of debugging
2421proc-macro code.&lt;/p&gt;
1585&lt;h3 id="debugging-and-testing"&gt;Debugging and Testing&lt;/h3&gt; 2422&lt;h3 id="debugging-and-testing"&gt;Debugging and Testing&lt;/h3&gt;
1586&lt;p&gt;Install &lt;code&gt;cargo-expand&lt;/code&gt; via:&lt;/p&gt; 2423&lt;p&gt;Install &lt;code&gt;cargo-expand&lt;/code&gt; via:&lt;/p&gt;
1587&lt;pre&gt;&lt;code&gt;cargo install cargo-expand&lt;/code&gt;&lt;/pre&gt; 2424&lt;pre&gt;&lt;code&gt;cargo install cargo-expand&lt;/code&gt;&lt;/pre&gt;
1588&lt;p&gt;&lt;code&gt;cargo-expand&lt;/code&gt; is a neat little tool that expands your macro in places where it is used, and lets you view the generated code! For example:&lt;/p&gt; 2425&lt;p&gt;&lt;code&gt;cargo-expand&lt;/code&gt; is a neat little tool that expands your
2426macro in places where it is used, and lets you view the generated code!
2427For example:&lt;/p&gt;
1589&lt;pre class="shell"&gt;&lt;code&gt;# create a bin package hello 2428&lt;pre class="shell"&gt;&lt;code&gt;# create a bin package hello
1590$ cargo new hello 2429$ cargo new hello
1591 2430
@@ -1607,10 +2446,18 @@ fn main() {
1607 )); 2446 ));
1608 }; 2447 };
1609}&lt;/code&gt;&lt;/pre&gt; 2448}&lt;/code&gt;&lt;/pre&gt;
1610&lt;p&gt;Writing proc-macros without &lt;code&gt;cargo-expand&lt;/code&gt; is tantamount to driving a vehicle without rear view mirrors! Keep an eye on what is going on behind your back.&lt;/p&gt; 2449&lt;p&gt;Writing proc-macros without &lt;code&gt;cargo-expand&lt;/code&gt; is tantamount
1611&lt;p&gt;Now, your macro won’t always compile, you might just recieve the bee movie script as an error. &lt;code&gt;cargo-expand&lt;/code&gt; will not work in such cases. I would suggest printing out your variables to inspect them. &lt;code&gt;TokenStream&lt;/code&gt; implements &lt;code&gt;Display&lt;/code&gt; as well as &lt;code&gt;Debug&lt;/code&gt;. We don’t always have to be respectable programmers. Just print it.&lt;/p&gt; 2450to driving a vehicle without rear view mirrors! Keep an eye on what is
2451going on behind your back.&lt;/p&gt;
2452&lt;p&gt;Now, your macro won’t always compile, you might just recieve the bee
2453movie script as an error. &lt;code&gt;cargo-expand&lt;/code&gt; will not work in
2454such cases. I would suggest printing out your variables to inspect them.
2455&lt;code&gt;TokenStream&lt;/code&gt; implements &lt;code&gt;Display&lt;/code&gt; as well as
2456&lt;code&gt;Debug&lt;/code&gt;. We don’t always have to be respectable programmers.
2457Just print it.&lt;/p&gt;
1612&lt;p&gt;Enough of that, lets get testing:&lt;/p&gt; 2458&lt;p&gt;Enough of that, lets get testing:&lt;/p&gt;
1613&lt;div class="sourceCode" id="cb37"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb37-1"&gt;&lt;a href="#cb37-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// tests/smoke.rs&lt;/span&gt;&lt;/span&gt; 2459&lt;div class="sourceCode" id="cb37"&gt;&lt;pre
2460class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb37-1"&gt;&lt;a href="#cb37-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// tests/smoke.rs&lt;/span&gt;&lt;/span&gt;
1614&lt;span id="cb37-2"&gt;&lt;a href="#cb37-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2461&lt;span id="cb37-2"&gt;&lt;a href="#cb37-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1615&lt;span id="cb37-3"&gt;&lt;a href="#cb37-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="at"&gt;#![&lt;/span&gt;feature&lt;span class="at"&gt;(&lt;/span&gt;type_alias_impl_trait&lt;span class="at"&gt;)]&lt;/span&gt;&lt;/span&gt; 2462&lt;span id="cb37-3"&gt;&lt;a href="#cb37-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="at"&gt;#![&lt;/span&gt;feature&lt;span class="at"&gt;(&lt;/span&gt;type_alias_impl_trait&lt;span class="at"&gt;)]&lt;/span&gt;&lt;/span&gt;
1616&lt;span id="cb37-4"&gt;&lt;a href="#cb37-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2463&lt;span id="cb37-4"&gt;&lt;a href="#cb37-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
@@ -1623,55 +2470,81 @@ fn main() {
1623&lt;span id="cb37-11"&gt;&lt;a href="#cb37-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; works() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2470&lt;span id="cb37-11"&gt;&lt;a href="#cb37-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; works() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1624&lt;span id="cb37-12"&gt;&lt;a href="#cb37-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="pp"&gt;assert_eq!&lt;/span&gt;(&lt;span class="dv"&gt;15&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; add(&lt;span class="dv"&gt;4&lt;/span&gt;)(&lt;span class="dv"&gt;5&lt;/span&gt;)(&lt;span class="dv"&gt;6&lt;/span&gt;))&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2471&lt;span id="cb37-12"&gt;&lt;a href="#cb37-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="pp"&gt;assert_eq!&lt;/span&gt;(&lt;span class="dv"&gt;15&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; add(&lt;span class="dv"&gt;4&lt;/span&gt;)(&lt;span class="dv"&gt;5&lt;/span&gt;)(&lt;span class="dv"&gt;6&lt;/span&gt;))&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1625&lt;span id="cb37-13"&gt;&lt;a href="#cb37-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2472&lt;span id="cb37-13"&gt;&lt;a href="#cb37-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1626&lt;p&gt;Run &lt;code&gt;cargo +nightly test&lt;/code&gt;. You should see a pleasing message:&lt;/p&gt; 2473&lt;p&gt;Run &lt;code&gt;cargo +nightly test&lt;/code&gt;. You should see a pleasing
2474message:&lt;/p&gt;
1627&lt;pre&gt;&lt;code&gt;running 1 test 2475&lt;pre&gt;&lt;code&gt;running 1 test
1628test tests::works ... ok&lt;/code&gt;&lt;/pre&gt; 2476test tests::works ... ok&lt;/code&gt;&lt;/pre&gt;
1629&lt;p&gt;Take a look at the expansion for our curry macro, via &lt;code&gt;cargo +nightly expand --tests smoke&lt;/code&gt;:&lt;/p&gt; 2477&lt;p&gt;Take a look at the expansion for our curry macro, via
1630&lt;div class="sourceCode" id="cb39"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb39-1"&gt;&lt;a href="#cb39-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; _add_T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2478&lt;code&gt;cargo +nightly expand --tests smoke&lt;/code&gt;:&lt;/p&gt;
2479&lt;div class="sourceCode" id="cb39"&gt;&lt;pre
2480class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb39-1"&gt;&lt;a href="#cb39-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; _add_T0 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1631&lt;span id="cb39-2"&gt;&lt;a href="#cb39-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; _add_T1 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; _add_T0&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2481&lt;span id="cb39-2"&gt;&lt;a href="#cb39-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; _add_T1 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; _add_T0&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1632&lt;span id="cb39-3"&gt;&lt;a href="#cb39-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; _add_T2 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; _add_T1&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2482&lt;span id="cb39-3"&gt;&lt;a href="#cb39-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; _add_T2 &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;impl&lt;/span&gt; &lt;span class="bu"&gt;Fn&lt;/span&gt;(&lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; _add_T1&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1633&lt;span id="cb39-4"&gt;&lt;a href="#cb39-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; add(x&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; _add_T2 &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2483&lt;span id="cb39-4"&gt;&lt;a href="#cb39-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; add(x&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; _add_T2 &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1634&lt;span id="cb39-5"&gt;&lt;a href="#cb39-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;return&lt;/span&gt; (&lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;y&lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2484&lt;span id="cb39-5"&gt;&lt;a href="#cb39-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;return&lt;/span&gt; (&lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;y&lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1635&lt;span id="cb39-6"&gt;&lt;a href="#cb39-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;z&lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2485&lt;span id="cb39-6"&gt;&lt;a href="#cb39-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;move&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt;z&lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1636&lt;span id="cb39-7"&gt;&lt;a href="#cb39-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;return&lt;/span&gt; x &lt;span class="op"&gt;+&lt;/span&gt; y &lt;span class="op"&gt;+&lt;/span&gt; z&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2486&lt;span id="cb39-7"&gt;&lt;a href="#cb39-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;return&lt;/span&gt; x &lt;span class="op"&gt;+&lt;/span&gt; y &lt;span class="op"&gt;+&lt;/span&gt; z&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1637&lt;span id="cb39-8"&gt;&lt;a href="#cb39-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 2487&lt;span id="cb39-8"&gt;&lt;a href="#cb39-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
1638&lt;span id="cb39-9"&gt;&lt;a href="#cb39-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2488&lt;span id="cb39-9"&gt;&lt;a href="#cb39-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1639&lt;span id="cb39-10"&gt;&lt;a href="#cb39-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 2489&lt;span id="cb39-10"&gt;&lt;a href="#cb39-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
1640&lt;span id="cb39-11"&gt;&lt;a href="#cb39-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2490&lt;span id="cb39-11"&gt;&lt;a href="#cb39-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1641&lt;span id="cb39-12"&gt;&lt;a href="#cb39-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// a bunch of other stuff generated by #[test] and assert_eq!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2491&lt;span id="cb39-12"&gt;&lt;a href="#cb39-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;// a bunch of other stuff generated by #[test] and assert_eq!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1642&lt;p&gt;A sight for sore eyes.&lt;/p&gt; 2492&lt;p&gt;A sight for sore eyes.&lt;/p&gt;
1643&lt;p&gt;Here is a more complex example that generates ten multiples of the first ten natural numbers:&lt;/p&gt; 2493&lt;p&gt;Here is a more complex example that generates ten multiples of the
1644&lt;div class="sourceCode" id="cb40"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb40-1"&gt;&lt;a href="#cb40-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="at"&gt;#[&lt;/span&gt;curry&lt;span class="at"&gt;]&lt;/span&gt;&lt;/span&gt; 2494first ten natural numbers:&lt;/p&gt;
2495&lt;div class="sourceCode" id="cb40"&gt;&lt;pre
2496class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb40-1"&gt;&lt;a href="#cb40-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="at"&gt;#[&lt;/span&gt;curry&lt;span class="at"&gt;]&lt;/span&gt;&lt;/span&gt;
1645&lt;span id="cb40-2"&gt;&lt;a href="#cb40-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; product(x&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; y&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2497&lt;span id="cb40-2"&gt;&lt;a href="#cb40-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; product(x&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; y&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt;) &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;u32&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1646&lt;span id="cb40-3"&gt;&lt;a href="#cb40-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; x &lt;span class="op"&gt;*&lt;/span&gt; y&lt;/span&gt; 2498&lt;span id="cb40-3"&gt;&lt;a href="#cb40-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; x &lt;span class="op"&gt;*&lt;/span&gt; y&lt;/span&gt;
1647&lt;span id="cb40-4"&gt;&lt;a href="#cb40-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 2499&lt;span id="cb40-4"&gt;&lt;a href="#cb40-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
1648&lt;span id="cb40-5"&gt;&lt;a href="#cb40-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2500&lt;span id="cb40-5"&gt;&lt;a href="#cb40-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1649&lt;span id="cb40-6"&gt;&lt;a href="#cb40-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; multiples() &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Vec&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dt"&gt;Vec&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;&amp;gt;&amp;gt;{&lt;/span&gt;&lt;/span&gt; 2501&lt;span id="cb40-6"&gt;&lt;a href="#cb40-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;fn&lt;/span&gt; multiples() &lt;span class="op"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Vec&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dt"&gt;Vec&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dt"&gt;u32&lt;/span&gt;&lt;span class="op"&gt;&amp;gt;&amp;gt;{&lt;/span&gt;&lt;/span&gt;
1650&lt;span id="cb40-7"&gt;&lt;a href="#cb40-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; v &lt;span class="op"&gt;=&lt;/span&gt; (&lt;span class="dv"&gt;1&lt;/span&gt;&lt;span class="op"&gt;..=&lt;/span&gt;&lt;span class="dv"&gt;10&lt;/span&gt;)&lt;span class="op"&gt;.&lt;/span&gt;map(product)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2502&lt;span id="cb40-7"&gt;&lt;a href="#cb40-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; v &lt;span class="op"&gt;=&lt;/span&gt; (&lt;span class="dv"&gt;1&lt;/span&gt;&lt;span class="op"&gt;..=&lt;/span&gt;&lt;span class="dv"&gt;10&lt;/span&gt;)&lt;span class="op"&gt;.&lt;/span&gt;map(product)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1651&lt;span id="cb40-8"&gt;&lt;a href="#cb40-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;return&lt;/span&gt; (&lt;span class="dv"&gt;1&lt;/span&gt;&lt;span class="op"&gt;..=&lt;/span&gt;&lt;span class="dv"&gt;10&lt;/span&gt;)&lt;/span&gt; 2503&lt;span id="cb40-8"&gt;&lt;a href="#cb40-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="cf"&gt;return&lt;/span&gt; (&lt;span class="dv"&gt;1&lt;/span&gt;&lt;span class="op"&gt;..=&lt;/span&gt;&lt;span class="dv"&gt;10&lt;/span&gt;)&lt;/span&gt;
1652&lt;span id="cb40-9"&gt;&lt;a href="#cb40-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;.&lt;/span&gt;map(&lt;span class="op"&gt;|&lt;/span&gt;x&lt;span class="op"&gt;|&lt;/span&gt; v&lt;span class="op"&gt;.&lt;/span&gt;clone()&lt;span class="op"&gt;.&lt;/span&gt;map(&lt;span class="op"&gt;|&lt;/span&gt;f&lt;span class="op"&gt;|&lt;/span&gt; f(x))&lt;span class="op"&gt;.&lt;/span&gt;collect())&lt;/span&gt; 2504&lt;span id="cb40-9"&gt;&lt;a href="#cb40-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;.&lt;/span&gt;map(&lt;span class="op"&gt;|&lt;/span&gt;x&lt;span class="op"&gt;|&lt;/span&gt; v&lt;span class="op"&gt;.&lt;/span&gt;clone()&lt;span class="op"&gt;.&lt;/span&gt;map(&lt;span class="op"&gt;|&lt;/span&gt;f&lt;span class="op"&gt;|&lt;/span&gt; f(x))&lt;span class="op"&gt;.&lt;/span&gt;collect())&lt;/span&gt;
1653&lt;span id="cb40-10"&gt;&lt;a href="#cb40-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;.&lt;/span&gt;collect()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2505&lt;span id="cb40-10"&gt;&lt;a href="#cb40-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;.&lt;/span&gt;collect()&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1654&lt;span id="cb40-11"&gt;&lt;a href="#cb40-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2506&lt;span id="cb40-11"&gt;&lt;a href="#cb40-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1655&lt;h3 id="notes"&gt;Notes&lt;/h3&gt; 2507&lt;h3 id="notes"&gt;Notes&lt;/h3&gt;
1656&lt;p&gt;I didn’t quite explain why we use &lt;code&gt;move |arg|&lt;/code&gt; in our closure. This is because we want to take ownership of the variable supplied to us. Take a look at this example:&lt;/p&gt; 2508&lt;p&gt;I didn’t quite explain why we use &lt;code&gt;move |arg|&lt;/code&gt; in our
1657&lt;div class="sourceCode" id="cb41"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb41-1"&gt;&lt;a href="#cb41-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; v &lt;span class="op"&gt;=&lt;/span&gt; add(&lt;span class="dv"&gt;5&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2509closure. This is because we want to take ownership of the variable
2510supplied to us. Take a look at this example:&lt;/p&gt;
2511&lt;div class="sourceCode" id="cb41"&gt;&lt;pre
2512class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb41-1"&gt;&lt;a href="#cb41-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; v &lt;span class="op"&gt;=&lt;/span&gt; add(&lt;span class="dv"&gt;5&lt;/span&gt;)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1658&lt;span id="cb41-2"&gt;&lt;a href="#cb41-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; g&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2513&lt;span id="cb41-2"&gt;&lt;a href="#cb41-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;let&lt;/span&gt; g&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1659&lt;span id="cb41-3"&gt;&lt;a href="#cb41-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2514&lt;span id="cb41-3"&gt;&lt;a href="#cb41-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
1660&lt;span id="cb41-4"&gt;&lt;a href="#cb41-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; x &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;5&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2515&lt;span id="cb41-4"&gt;&lt;a href="#cb41-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;let&lt;/span&gt; x &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;5&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1661&lt;span id="cb41-5"&gt;&lt;a href="#cb41-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; g &lt;span class="op"&gt;=&lt;/span&gt; v(x)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2516&lt;span id="cb41-5"&gt;&lt;a href="#cb41-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; g &lt;span class="op"&gt;=&lt;/span&gt; v(x)&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1662&lt;span id="cb41-6"&gt;&lt;a href="#cb41-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt; 2517&lt;span id="cb41-6"&gt;&lt;a href="#cb41-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
1663&lt;span id="cb41-7"&gt;&lt;a href="#cb41-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="pp"&gt;println!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; g(&lt;span class="dv"&gt;2&lt;/span&gt;))&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2518&lt;span id="cb41-7"&gt;&lt;a href="#cb41-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="pp"&gt;println!&lt;/span&gt;(&lt;span class="st"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;,&lt;/span&gt; g(&lt;span class="dv"&gt;2&lt;/span&gt;))&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1664&lt;p&gt;Variable &lt;code&gt;x&lt;/code&gt; goes out of scope before &lt;code&gt;g&lt;/code&gt; can return a concrete value. If we take ownership of &lt;code&gt;x&lt;/code&gt; by &lt;code&gt;move&lt;/code&gt;ing it into our closure, we can expect this to work reliably. In fact, rustc understands this, and forces you to use &lt;code&gt;move&lt;/code&gt;.&lt;/p&gt; 2519&lt;p&gt;Variable &lt;code&gt;x&lt;/code&gt; goes out of scope before &lt;code&gt;g&lt;/code&gt; can
1665&lt;p&gt;This usage of &lt;code&gt;move&lt;/code&gt; is exactly why &lt;strong&gt;a curried function without a return is useless&lt;/strong&gt;. Every variable we pass to our curried function gets moved into its local scope. Playing with these variables cannot cause a change outside this scope. Returning is our only method of interaction with anything beyond this function.&lt;/p&gt; 2520return a concrete value. If we take ownership of &lt;code&gt;x&lt;/code&gt; by
2521&lt;code&gt;move&lt;/code&gt;ing it into our closure, we can expect this to work
2522reliably. In fact, rustc understands this, and forces you to use
2523&lt;code&gt;move&lt;/code&gt;.&lt;/p&gt;
2524&lt;p&gt;This usage of &lt;code&gt;move&lt;/code&gt; is exactly why &lt;strong&gt;a curried
2525function without a return is useless&lt;/strong&gt;. Every variable we pass to
2526our curried function gets moved into its local scope. Playing with these
2527variables cannot cause a change outside this scope. Returning is our
2528only method of interaction with anything beyond this function.&lt;/p&gt;
1666&lt;h3 id="conclusion"&gt;Conclusion&lt;/h3&gt; 2529&lt;h3 id="conclusion"&gt;Conclusion&lt;/h3&gt;
1667&lt;p&gt;Currying may not seem to be all that useful. Curried functions are unwieldy in Rust because the standard library is not built around currying. If you enjoy the possibilities posed by currying, consider taking a look at Haskell or Scheme.&lt;/p&gt; 2530&lt;p&gt;Currying may not seem to be all that useful. Curried functions are
1668&lt;p&gt;My original intention with &lt;a href="https://peppe.rs"&gt;peppe.rs&lt;/a&gt; was to post condensed articles, a micro blog, but this one turned out extra long.&lt;/p&gt; 2531unwieldy in Rust because the standard library is not built around
2532currying. If you enjoy the possibilities posed by currying, consider
2533taking a look at Haskell or Scheme.&lt;/p&gt;
2534&lt;p&gt;My original intention with &lt;a href="https://peppe.rs"&gt;peppe.rs&lt;/a&gt;
2535was to post condensed articles, a micro blog, but this one turned out
2536extra long.&lt;/p&gt;
1669&lt;p&gt;Perhaps I should call it a ‘macro’ blog :)&lt;/p&gt; 2537&lt;p&gt;Perhaps I should call it a ‘macro’ blog :)&lt;/p&gt;
1670&lt;section class="footnotes" role="doc-endnotes"&gt; 2538&lt;section id="footnotes" class="footnotes footnotes-end-of-document"
2539role="doc-endnotes"&gt;
1671&lt;hr /&gt; 2540&lt;hr /&gt;
1672&lt;ol&gt; 2541&lt;ol&gt;
1673&lt;li id="fn1" role="doc-endnote"&gt;&lt;p&gt;&lt;a href="https://doc.rust-lang.org/book/ch13-01-closures.html"&gt;https://doc.rust-lang.org/book/ch13-01-closures.html&lt;/a&gt;&lt;a href="#fnref1" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; 2542&lt;li id="fn1"&gt;&lt;p&gt;&lt;a
1674&lt;li id="fn2" role="doc-endnote"&gt;&lt;p&gt;&lt;a href="https://caniuse.rs"&gt;caniuse.rs&lt;/a&gt; contains an indexed list of features and their status.&lt;a href="#fnref2" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; 2543href="https://doc.rust-lang.org/book/ch13-01-closures.html"&gt;https://doc.rust-lang.org/book/ch13-01-closures.html&lt;/a&gt;&lt;a
2544href="#fnref1" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
2545&lt;li id="fn2"&gt;&lt;p&gt;&lt;a href="https://caniuse.rs"&gt;caniuse.rs&lt;/a&gt; contains an
2546indexed list of features and their status.&lt;a href="#fnref2"
2547class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
1675&lt;/ol&gt; 2548&lt;/ol&gt;
1676&lt;/section&gt;</description> 2549&lt;/section&gt;</description>
1677<link>https://peppe.rs/posts/auto-currying_rust_functions/</link> 2550<link>https://peppe.rs/posts/auto-currying_rust_functions/</link>
@@ -1680,54 +2553,105 @@ test tests::works ... ok&lt;/code&gt;&lt;/pre&gt;
1680</item> 2553</item>
1681<item> 2554<item>
1682<title>Pixel Art In GIMP</title> 2555<title>Pixel Art In GIMP</title>
1683<description>&lt;p&gt;I’ve always been an admirer of pixel art, because of it’s simplicity and it’s resemblance to bitmap font design. Recently, I decided to take the dive and make some art of my own.&lt;/p&gt; 2556<description>&lt;p&gt;I’ve always been an admirer of pixel art, because of it’s simplicity
1684&lt;p&gt;I used GIMP because I am fairly familiar with it. Aseprite seems to be the editor of choice for animated pixel art though.&lt;/p&gt; 2557and it’s resemblance to bitmap font design. Recently, I decided to take
2558the dive and make some art of my own.&lt;/p&gt;
2559&lt;p&gt;I used GIMP because I am fairly familiar with it. Aseprite seems to
2560be the editor of choice for animated pixel art though.&lt;/p&gt;
1685&lt;h3 id="setting-up-the-canvas"&gt;Setting up the canvas&lt;/h3&gt; 2561&lt;h3 id="setting-up-the-canvas"&gt;Setting up the canvas&lt;/h3&gt;
1686&lt;p&gt;Picking a canvas size is daunting. Too small, and you won’t be able to fit in enough detail to make a legible piece. Too big and you’ve got too many pixels to work with!&lt;/p&gt; 2562&lt;p&gt;Picking a canvas size is daunting. Too small, and you won’t be able
1687&lt;p&gt;I would suggest starting out with anywhere between 100x100 and 200x200. &lt;a href="https://u.peppe.rs/u9.png"&gt;Here’s&lt;/a&gt; a sample configuration.&lt;/p&gt; 2563to fit in enough detail to make a legible piece. Too big and you’ve got
1688&lt;p&gt;Sometimes I use a 10x10 grid, &lt;code&gt;View &amp;gt; Show Grid&lt;/code&gt; and &lt;code&gt;Edit &amp;gt; Preferences &amp;gt; Default Grid &amp;gt; Spacing&lt;/code&gt;, but that can get jarring, so I throw down a couple of guides, drag right or down from the left or top gutters for vertical and horizontal guides respectively.&lt;/p&gt; 2564too many pixels to work with!&lt;/p&gt;
2565&lt;p&gt;I would suggest starting out with anywhere between 100x100 and
2566200x200. &lt;a href="https://u.peppe.rs/u9.png"&gt;Here’s&lt;/a&gt; a sample
2567configuration.&lt;/p&gt;
2568&lt;p&gt;Sometimes I use a 10x10 grid, &lt;code&gt;View &amp;gt; Show Grid&lt;/code&gt; and
2569&lt;code&gt;Edit &amp;gt; Preferences &amp;gt; Default Grid &amp;gt; Spacing&lt;/code&gt;, but
2570that can get jarring, so I throw down a couple of guides, drag right or
2571down from the left or top gutters for vertical and horizontal guides
2572respectively.&lt;/p&gt;
1689&lt;h3 id="choosing-a-brush"&gt;Choosing a Brush&lt;/h3&gt; 2573&lt;h3 id="choosing-a-brush"&gt;Choosing a Brush&lt;/h3&gt;
1690&lt;p&gt;The most important part of our setup is the brush. Use the Pencil Tool (&lt;code&gt;n&lt;/code&gt; on the keyboard) for hard edge drawings. Here’s a small comparison if you don’t know the difference between a hard edge and a soft edge:&lt;/p&gt; 2574&lt;p&gt;The most important part of our setup is the brush. Use the Pencil
2575Tool (&lt;code&gt;n&lt;/code&gt; on the keyboard) for hard edge drawings. Here’s a
2576small comparison if you don’t know the difference between a hard edge
2577and a soft edge:&lt;/p&gt;
1691&lt;figure&gt; 2578&lt;figure&gt;
1692&lt;img src="https://u.peppe.rs/kz.png" alt="Hard edge vs Soft Edge" /&gt;&lt;figcaption aria-hidden="true"&gt;Hard edge vs Soft Edge&lt;/figcaption&gt; 2579&lt;img src="https://u.peppe.rs/kz.png" alt="Hard edge vs Soft Edge" /&gt;
2580&lt;figcaption aria-hidden="true"&gt;Hard edge vs Soft Edge&lt;/figcaption&gt;
1693&lt;/figure&gt; 2581&lt;/figure&gt;
1694&lt;p&gt;I turn the size down all the way to 1 (&lt;code&gt;[&lt;/code&gt; on the keyboard). Set &lt;code&gt;Dynamics&lt;/code&gt; off. &lt;a href="https://u.peppe.rs/Fs.png"&gt;Here’s&lt;/a&gt; a sample brush configuration.&lt;/p&gt; 2582&lt;p&gt;I turn the size down all the way to 1 (&lt;code&gt;[&lt;/code&gt; on the
2583keyboard). Set &lt;code&gt;Dynamics&lt;/code&gt; off. &lt;a
2584href="https://u.peppe.rs/Fs.png"&gt;Here’s&lt;/a&gt; a sample brush
2585configuration.&lt;/p&gt;
1695&lt;h3 id="laying-down-the-pixels"&gt;Laying down the pixels!&lt;/h3&gt; 2586&lt;h3 id="laying-down-the-pixels"&gt;Laying down the pixels!&lt;/h3&gt;
1696&lt;p&gt;With the boring stuff out of the way, we can start with our piece. I usually follow a three step process:&lt;/p&gt; 2587&lt;p&gt;With the boring stuff out of the way, we can start with our piece. I
2588usually follow a three step process:&lt;/p&gt;
1697&lt;ul&gt; 2589&lt;ul&gt;
1698&lt;li&gt;draw a rough outline&lt;/li&gt; 2590&lt;li&gt;draw a rough outline&lt;/li&gt;
1699&lt;li&gt;fill in the shadows&lt;/li&gt; 2591&lt;li&gt;fill in the shadows&lt;/li&gt;
1700&lt;li&gt;add highlights&lt;/li&gt; 2592&lt;li&gt;add highlights&lt;/li&gt;
1701&lt;/ul&gt; 2593&lt;/ul&gt;
1702&lt;p&gt;But this process is better explained with an example: an onigiri. Let us start off with a 100x100 canvas.&lt;/p&gt; 2594&lt;p&gt;But this process is better explained with an example: an onigiri. Let
2595us start off with a 100x100 canvas.&lt;/p&gt;
1703&lt;h4 id="drawing-the-outline"&gt;Drawing the outline&lt;/h4&gt; 2596&lt;h4 id="drawing-the-outline"&gt;Drawing the outline&lt;/h4&gt;
1704&lt;p&gt;For the most part, our figure will be symmetric. If you are on GIMP 2.10+, you can take advantage of the Symmetry Painting feature. Go ahead and enable vertical symmetry, &lt;code&gt;Window &amp;gt; Dockable Dialogs &amp;gt; Symmetry Painting&lt;/code&gt; and &lt;code&gt;Symmetry Painting &amp;gt; Symmetry &amp;gt; Mirror &amp;gt; Vertical&lt;/code&gt;.&lt;/p&gt; 2597&lt;p&gt;For the most part, our figure will be symmetric. If you are on GIMP
1705&lt;p&gt;If you are running an older version of GIMP, draw in the left side, duplicate the layer, flip it horizontally, and merge it with the original.&lt;/p&gt; 25982.10+, you can take advantage of the Symmetry Painting feature. Go ahead
2599and enable vertical symmetry,
2600&lt;code&gt;Window &amp;gt; Dockable Dialogs &amp;gt; Symmetry Painting&lt;/code&gt; and
2601&lt;code&gt;Symmetry Painting &amp;gt; Symmetry &amp;gt; Mirror &amp;gt; Vertical&lt;/code&gt;.&lt;/p&gt;
2602&lt;p&gt;If you are running an older version of GIMP, draw in the left side,
2603duplicate the layer, flip it horizontally, and merge it with the
2604original.&lt;/p&gt;
1706&lt;p&gt;Your outline might look something like this:&lt;/p&gt; 2605&lt;p&gt;Your outline might look something like this:&lt;/p&gt;
1707&lt;p&gt;&lt;img src="https://u.peppe.rs/mn.png" /&gt;&lt;/p&gt; 2606&lt;p&gt;&lt;img src="https://u.peppe.rs/mn.png" /&gt;&lt;/p&gt;
1708&lt;p&gt;Go ahead and fill it in with the fill tool (&lt;code&gt;Shift + b&lt;/code&gt; on the keyboard), add in some seaweed as well, preferably on a different layer. You can toggle symmetry on and off to save yourself some time.&lt;/p&gt; 2607&lt;p&gt;Go ahead and fill it in with the fill tool (&lt;code&gt;Shift + b&lt;/code&gt; on
2608the keyboard), add in some seaweed as well, preferably on a different
2609layer. You can toggle symmetry on and off to save yourself some
2610time.&lt;/p&gt;
1709&lt;p&gt;&lt;img src="https://u.peppe.rs/xu.png" /&gt;&lt;/p&gt; 2611&lt;p&gt;&lt;img src="https://u.peppe.rs/xu.png" /&gt;&lt;/p&gt;
1710&lt;h4 id="shadows"&gt;Shadows&lt;/h4&gt; 2612&lt;h4 id="shadows"&gt;Shadows&lt;/h4&gt;
1711&lt;p&gt;For now, let us focus on the shadows on the object itself, we’ll come back to the shadows cast by the object on the surface later.&lt;/p&gt; 2613&lt;p&gt;For now, let us focus on the shadows on the object itself, we’ll come
1712&lt;p&gt;Shadows on any surface always follow the shape of the surface. A spherical onigiri would have a circular shadow:&lt;/p&gt; 2614back to the shadows cast by the object on the surface later.&lt;/p&gt;
2615&lt;p&gt;Shadows on any surface always follow the shape of the surface. A
2616spherical onigiri would have a circular shadow:&lt;/p&gt;
1713&lt;p&gt;&lt;img src="https://u.peppe.rs/FU.png" /&gt;&lt;/p&gt; 2617&lt;p&gt;&lt;img src="https://u.peppe.rs/FU.png" /&gt;&lt;/p&gt;
1714&lt;p&gt;A couple of noticeable changes:&lt;/p&gt; 2618&lt;p&gt;A couple of noticeable changes:&lt;/p&gt;
1715&lt;p&gt;&lt;strong&gt;Layers&lt;/strong&gt;: The layer containing the seaweed has been hidden.&lt;br /&gt; 2619&lt;p&gt;&lt;strong&gt;Layers&lt;/strong&gt;: The layer containing the seaweed has been
1716&lt;strong&gt;Color&lt;/strong&gt;: The color of the shadow is just a slightly lighter version of the original object (reduce the Value on the HSV scale).&lt;br /&gt; 2620hidden.&lt;br /&gt;
1717&lt;strong&gt;Area&lt;/strong&gt;: The shadow does not go all the way (notice the bottom edges).&lt;/p&gt; 2621&lt;strong&gt;Color&lt;/strong&gt;: The color of the shadow is just a slightly
1718&lt;p&gt;The shadow does not go all the way because we will be filling in that area with another, darker shadow! An image might explain better:&lt;/p&gt; 2622lighter version of the original object (reduce the Value on the HSV
2623scale).&lt;br /&gt;
2624&lt;strong&gt;Area&lt;/strong&gt;: The shadow does not go all the way (notice the
2625bottom edges).&lt;/p&gt;
2626&lt;p&gt;The shadow does not go all the way because we will be filling in that
2627area with another, darker shadow! An image might explain better:&lt;/p&gt;
1719&lt;p&gt;&lt;img src="https://u.peppe.rs/Br.png" /&gt;&lt;/p&gt; 2628&lt;p&gt;&lt;img src="https://u.peppe.rs/Br.png" /&gt;&lt;/p&gt;
1720&lt;p&gt;To emulate soft lights, reduce the value by 2 to 3 points every iteration. Notice how area &lt;code&gt;1&lt;/code&gt; is much larger than area &lt;code&gt;4&lt;/code&gt;. This is because an onigiri resembles a bottom heavy oblate spheroid, a sphere that is slightly fatter around the lower bottom, and areas &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;2&lt;/code&gt; catch more light than areas &lt;code&gt;3&lt;/code&gt; and &lt;code&gt;4&lt;/code&gt;.&lt;/p&gt; 2629&lt;p&gt;To emulate soft lights, reduce the value by 2 to 3 points every
1721&lt;p&gt;Do the same with the seaweed. The seaweed, being a smaller, flatter object, doesn’t cast much of a shadow, so stop with 1 or 2 iterations of the gradient:&lt;/p&gt; 2630iteration. Notice how area &lt;code&gt;1&lt;/code&gt; is much larger than area
2631&lt;code&gt;4&lt;/code&gt;. This is because an onigiri resembles a bottom heavy
2632oblate spheroid, a sphere that is slightly fatter around the lower
2633bottom, and areas &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;2&lt;/code&gt; catch more light
2634than areas &lt;code&gt;3&lt;/code&gt; and &lt;code&gt;4&lt;/code&gt;.&lt;/p&gt;
2635&lt;p&gt;Do the same with the seaweed. The seaweed, being a smaller, flatter
2636object, doesn’t cast much of a shadow, so stop with 1 or 2 iterations of
2637the gradient:&lt;/p&gt;
1722&lt;p&gt;&lt;img src="https://u.peppe.rs/T3.png" /&gt;&lt;/p&gt; 2638&lt;p&gt;&lt;img src="https://u.peppe.rs/T3.png" /&gt;&lt;/p&gt;
1723&lt;p&gt;We’re getting there!&lt;/p&gt; 2639&lt;p&gt;We’re getting there!&lt;/p&gt;
1724&lt;h4 id="highlights"&gt;Highlights&lt;/h4&gt; 2640&lt;h4 id="highlights"&gt;Highlights&lt;/h4&gt;
1725&lt;p&gt;This step handles the details on the strongly illuminated portions of the object. Seaweed is a bit glossy, lighten the edges to make it seem shiny. The rice is not as shiny, but it does form an uneven surface. Add in some shadows to promote the idea of rice grains. Here is the finished result:&lt;/p&gt; 2641&lt;p&gt;This step handles the details on the strongly illuminated portions of
2642the object. Seaweed is a bit glossy, lighten the edges to make it seem
2643shiny. The rice is not as shiny, but it does form an uneven surface. Add
2644in some shadows to promote the idea of rice grains. Here is the finished
2645result:&lt;/p&gt;
1726&lt;p&gt;&lt;img src="https://u.peppe.rs/VE.png" /&gt;&lt;/p&gt; 2646&lt;p&gt;&lt;img src="https://u.peppe.rs/VE.png" /&gt;&lt;/p&gt;
1727&lt;h3 id="finishing-touches"&gt;Finishing Touches&lt;/h3&gt; 2647&lt;h3 id="finishing-touches"&gt;Finishing Touches&lt;/h3&gt;
1728&lt;p&gt;Some color correction and &lt;code&gt;a e s t h e t i c&lt;/code&gt; Japanese text later, our piece is complete!&lt;/p&gt; 2648&lt;p&gt;Some color correction and &lt;code&gt;a e s t h e t i c&lt;/code&gt; Japanese
2649text later, our piece is complete!&lt;/p&gt;
1729&lt;p&gt;&lt;img src="https://u.peppe.rs/cn.png" /&gt;&lt;/p&gt; 2650&lt;p&gt;&lt;img src="https://u.peppe.rs/cn.png" /&gt;&lt;/p&gt;
1730&lt;p&gt;Hold on, why is it so tiny? Well, that’s because our canvas was 100x100, head over to &lt;code&gt;Image &amp;gt; Scale Image&lt;/code&gt;, set &lt;code&gt;Quality &amp;gt; Interpolation&lt;/code&gt; to &lt;code&gt;None&lt;/code&gt; and scale it up to 700x700, et voilà!&lt;/p&gt; 2651&lt;p&gt;Hold on, why is it so tiny? Well, that’s because our canvas was
2652100x100, head over to &lt;code&gt;Image &amp;gt; Scale Image&lt;/code&gt;, set
2653&lt;code&gt;Quality &amp;gt; Interpolation&lt;/code&gt; to &lt;code&gt;None&lt;/code&gt; and scale
2654it up to 700x700, et voilà!&lt;/p&gt;
1731&lt;p&gt;&lt;img src="https://u.peppe.rs/CH.png" /&gt;&lt;/p&gt;</description> 2655&lt;p&gt;&lt;img src="https://u.peppe.rs/CH.png" /&gt;&lt;/p&gt;</description>
1732<link>https://peppe.rs/posts/pixel_art_in_GIMP/</link> 2656<link>https://peppe.rs/posts/pixel_art_in_GIMP/</link>
1733<pubDate>Wed, 08 Apr 2020 18:30:00 +0000</pubDate> 2657<pubDate>Wed, 08 Apr 2020 18:30:00 +0000</pubDate>
@@ -1735,9 +2659,14 @@ test tests::works ... ok&lt;/code&gt;&lt;/pre&gt;
1735</item> 2659</item>
1736<item> 2660<item>
1737<title>Rapid Refactoring With Vim</title> 2661<title>Rapid Refactoring With Vim</title>
1738<description>&lt;p&gt;Last weekend, I was tasked with refactoring the 96 unit tests on &lt;a href="https://github.com/ruma/ruma-events/pull/70"&gt;ruma-events&lt;/a&gt; to use strictly typed json objects using &lt;code&gt;serde_json::json!&lt;/code&gt; instead of raw strings. It was rather painless thanks to vim :)&lt;/p&gt; 2662<description>&lt;p&gt;Last weekend, I was tasked with refactoring the 96 unit tests on &lt;a
1739&lt;p&gt;Here’s a small sample of what had to be done (note the lines prefixed with the arrow):&lt;/p&gt; 2663href="https://github.com/ruma/ruma-events/pull/70"&gt;ruma-events&lt;/a&gt; to
1740&lt;div class="sourceCode" id="cb1"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;→ &lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;serde_json::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;from_str&lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt; 2664use strictly typed json objects using &lt;code&gt;serde_json::json!&lt;/code&gt;
2665instead of raw strings. It was rather painless thanks to vim :)&lt;/p&gt;
2666&lt;p&gt;Here’s a small sample of what had to be done (note the lines prefixed
2667with the arrow):&lt;/p&gt;
2668&lt;div class="sourceCode" id="cb1"&gt;&lt;pre
2669class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;→ &lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;serde_json::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;from_str&lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt;
1741&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;/span&gt; 2670&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;/span&gt;
1742&lt;span id="cb1-3"&gt;&lt;a href="#cb1-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="at"&gt;#[&lt;/span&gt;test&lt;span class="at"&gt;]&lt;/span&gt;&lt;/span&gt; 2671&lt;span id="cb1-3"&gt;&lt;a href="#cb1-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="at"&gt;#[&lt;/span&gt;test&lt;span class="at"&gt;]&lt;/span&gt;&lt;/span&gt;
1743&lt;span id="cb1-4"&gt;&lt;a href="#cb1-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;fn&lt;/span&gt; deserialize() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2672&lt;span id="cb1-4"&gt;&lt;a href="#cb1-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;fn&lt;/span&gt; deserialize() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
@@ -1747,7 +2676,8 @@ test tests::works ... ok&lt;/code&gt;&lt;/pre&gt;
1747&lt;span id="cb1-8"&gt;&lt;a href="#cb1-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; )&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2676&lt;span id="cb1-8"&gt;&lt;a href="#cb1-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; )&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1748&lt;span id="cb1-9"&gt;&lt;a href="#cb1-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2677&lt;span id="cb1-9"&gt;&lt;a href="#cb1-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1749&lt;p&gt;had to be converted to:&lt;/p&gt; 2678&lt;p&gt;had to be converted to:&lt;/p&gt;
1750&lt;div class="sourceCode" id="cb2"&gt;&lt;pre class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;→ &lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;serde_json::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;from_value&lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt; 2679&lt;div class="sourceCode" id="cb2"&gt;&lt;pre
2680class="sourceCode rust"&gt;&lt;code class="sourceCode rust"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;→ &lt;span class="kw"&gt;use&lt;/span&gt; &lt;span class="pp"&gt;serde_json::&lt;/span&gt;&lt;span class="op"&gt;{&lt;/span&gt;from_value&lt;span class="op"&gt;};&lt;/span&gt;&lt;/span&gt;
1751&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;/span&gt; 2681&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;/span&gt;
1752&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="at"&gt;#[&lt;/span&gt;test&lt;span class="at"&gt;]&lt;/span&gt;&lt;/span&gt; 2682&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="at"&gt;#[&lt;/span&gt;test&lt;span class="at"&gt;]&lt;/span&gt;&lt;/span&gt;
1753&lt;span id="cb2-4"&gt;&lt;a href="#cb2-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;fn&lt;/span&gt; deserialize() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt; 2683&lt;span id="cb2-4"&gt;&lt;a href="#cb2-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="kw"&gt;fn&lt;/span&gt; deserialize() &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
@@ -1757,19 +2687,38 @@ test tests::works ... ok&lt;/code&gt;&lt;/pre&gt;
1757&lt;span id="cb2-8"&gt;&lt;a href="#cb2-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; )&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt; 2687&lt;span id="cb2-8"&gt;&lt;a href="#cb2-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; )&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
1758&lt;span id="cb2-9"&gt;&lt;a href="#cb2-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2688&lt;span id="cb2-9"&gt;&lt;a href="#cb2-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1759&lt;h3 id="the-arglist"&gt;The arglist&lt;/h3&gt; 2689&lt;h3 id="the-arglist"&gt;The arglist&lt;/h3&gt;
1760&lt;p&gt;For the initial pass, I decided to handle imports, this was a simple find and replace operation, done to all the files containing tests. Luckily, modules (and therefore files) containing tests in Rust are annotated with the &lt;code&gt;#[cfg(test)]&lt;/code&gt; attribute. I opened all such files:&lt;/p&gt; 2690&lt;p&gt;For the initial pass, I decided to handle imports, this was a simple
1761&lt;div class="sourceCode" id="cb3"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# `grep -l pattern files` lists all the files&lt;/span&gt;&lt;/span&gt; 2691find and replace operation, done to all the files containing tests.
2692Luckily, modules (and therefore files) containing tests in Rust are
2693annotated with the &lt;code&gt;#[cfg(test)]&lt;/code&gt; attribute. I opened all
2694such files:&lt;/p&gt;
2695&lt;div class="sourceCode" id="cb3"&gt;&lt;pre
2696class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# `grep -l pattern files` lists all the files&lt;/span&gt;&lt;/span&gt;
1762&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# matching the pattern&lt;/span&gt;&lt;/span&gt; 2697&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# matching the pattern&lt;/span&gt;&lt;/span&gt;
1763&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2698&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1764&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;vim&lt;/span&gt; &lt;span class="va"&gt;$(&lt;/span&gt;&lt;span class="fu"&gt;grep&lt;/span&gt; &lt;span class="at"&gt;-l&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;cfg\(test\)&amp;#39;&lt;/span&gt; ./&lt;span class="pp"&gt;**&lt;/span&gt;/&lt;span class="pp"&gt;*&lt;/span&gt;.rs&lt;span class="va"&gt;)&lt;/span&gt;&lt;/span&gt; 2699&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;vim&lt;/span&gt; &lt;span class="va"&gt;$(&lt;/span&gt;&lt;span class="fu"&gt;grep&lt;/span&gt; &lt;span class="at"&gt;-l&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;cfg\(test\)&amp;#39;&lt;/span&gt; ./&lt;span class="pp"&gt;**&lt;/span&gt;/&lt;span class="pp"&gt;*&lt;/span&gt;.rs&lt;span class="va"&gt;)&lt;/span&gt;&lt;/span&gt;
1765&lt;span id="cb3-5"&gt;&lt;a href="#cb3-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 2700&lt;span id="cb3-5"&gt;&lt;a href="#cb3-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1766&lt;span id="cb3-6"&gt;&lt;a href="#cb3-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# expands to something like:&lt;/span&gt;&lt;/span&gt; 2701&lt;span id="cb3-6"&gt;&lt;a href="#cb3-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# expands to something like:&lt;/span&gt;&lt;/span&gt;
1767&lt;span id="cb3-7"&gt;&lt;a href="#cb3-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;vim&lt;/span&gt; push_rules.rs room/member.rs key/verification/lib.rs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 2702&lt;span id="cb3-7"&gt;&lt;a href="#cb3-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;vim&lt;/span&gt; push_rules.rs room/member.rs key/verification/lib.rs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1768&lt;p&gt;Starting vim with more than one file at the shell prompt populates the arglist. Hit &lt;code&gt;:args&lt;/code&gt; to see the list of files currently ready to edit. The square [brackets] indicate the current file. Navigate through the arglist with &lt;code&gt;:next&lt;/code&gt; and &lt;code&gt;:prev&lt;/code&gt;. I use tpope’s vim-unimpaired &lt;a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;, which adds &lt;code&gt;]a&lt;/code&gt; and &lt;code&gt;[a&lt;/code&gt;, mapped to &lt;code&gt;:next&lt;/code&gt; and &lt;code&gt;:prev&lt;/code&gt;.&lt;/p&gt; 2703&lt;p&gt;Starting vim with more than one file at the shell prompt populates
1769&lt;p&gt;All that’s left to do is the find and replace, for which we will be using vim’s &lt;code&gt;argdo&lt;/code&gt;, applying a substitution to every file in the arglist:&lt;/p&gt; 2704the arglist. Hit &lt;code&gt;:args&lt;/code&gt; to see the list of files currently
2705ready to edit. The square [brackets] indicate the current file. Navigate
2706through the arglist with &lt;code&gt;:next&lt;/code&gt; and &lt;code&gt;:prev&lt;/code&gt;. I
2707use tpope’s vim-unimpaired &lt;a href="#fn1" class="footnote-ref"
2708id="fnref1" role="doc-noteref"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;, which adds
2709&lt;code&gt;]a&lt;/code&gt; and &lt;code&gt;[a&lt;/code&gt;, mapped to &lt;code&gt;:next&lt;/code&gt; and
2710&lt;code&gt;:prev&lt;/code&gt;.&lt;/p&gt;
2711&lt;p&gt;All that’s left to do is the find and replace, for which we will be
2712using vim’s &lt;code&gt;argdo&lt;/code&gt;, applying a substitution to every file in
2713the arglist:&lt;/p&gt;
1770&lt;pre&gt;&lt;code&gt;:argdo s/from_str/from_value/g&lt;/code&gt;&lt;/pre&gt; 2714&lt;pre&gt;&lt;code&gt;:argdo s/from_str/from_value/g&lt;/code&gt;&lt;/pre&gt;
1771&lt;h3 id="the-quickfix-list"&gt;The quickfix list&lt;/h3&gt; 2715&lt;h3 id="the-quickfix-list"&gt;The quickfix list&lt;/h3&gt;
1772&lt;p&gt;Next up, replacing &lt;code&gt;r#" ... "#&lt;/code&gt; with &lt;code&gt;json!( ... )&lt;/code&gt;. I couldn’t search and replace that trivially, so I went with a macro call &lt;a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; instead, starting with the cursor on ‘r’, represented by the caret, in my attempt to breakdown the process:&lt;/p&gt; 2716&lt;p&gt;Next up, replacing &lt;code&gt;r#" ... "#&lt;/code&gt; with
2717&lt;code&gt;json!( ... )&lt;/code&gt;. I couldn’t search and replace that trivially,
2718so I went with a macro call &lt;a href="#fn2" class="footnote-ref"
2719id="fnref2" role="doc-noteref"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; instead, starting with
2720the cursor on ‘r’, represented by the caret, in my attempt to breakdown
2721the process:&lt;/p&gt;
1773&lt;pre&gt;&lt;code&gt;BUFFER: r#&amp;quot; ... &amp;quot;#; 2722&lt;pre&gt;&lt;code&gt;BUFFER: r#&amp;quot; ... &amp;quot;#;
1774 ^ 2723 ^
1775 2724
@@ -1786,42 +2735,80 @@ BUFFER: json!( ... &amp;quot;#;
1786ACTION: vhs)&amp;lt;esc&amp;gt; 2735ACTION: vhs)&amp;lt;esc&amp;gt;
1787 2736
1788BUFFER: json!( ... );&lt;/code&gt;&lt;/pre&gt; 2737BUFFER: json!( ... );&lt;/code&gt;&lt;/pre&gt;
1789&lt;p&gt;Here’s the recorded &lt;a href="#fn3" class="footnote-ref" id="fnref3" role="doc-noteref"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; macro in all its glory: &lt;code&gt;vllsjson!(&amp;lt;esc&amp;gt;$F#vhs)&amp;lt;esc&amp;gt;&lt;/code&gt;.&lt;/p&gt; 2738&lt;p&gt;Here’s the recorded &lt;a href="#fn3" class="footnote-ref" id="fnref3"
1790&lt;p&gt;Great! So now we just go ahead, find every occurrence of &lt;code&gt;r#&lt;/code&gt; and apply the macro right? Unfortunately, there were more than a few occurrences of raw strings that had to stay raw strings. Enter, the quickfix list.&lt;/p&gt; 2739role="doc-noteref"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; macro in all its glory:
1791&lt;p&gt;The idea behind the quickfix list is to jump from one position in a file to another (maybe in a different file), much like how the arglist lets you jump from one file to another.&lt;/p&gt; 2740&lt;code&gt;vllsjson!(&amp;lt;esc&amp;gt;$F#vhs)&amp;lt;esc&amp;gt;&lt;/code&gt;.&lt;/p&gt;
1792&lt;p&gt;One of the easiest ways to populate this list with a bunch of positions is to use &lt;code&gt;vimgrep&lt;/code&gt;:&lt;/p&gt; 2741&lt;p&gt;Great! So now we just go ahead, find every occurrence of
2742&lt;code&gt;r#&lt;/code&gt; and apply the macro right? Unfortunately, there were
2743more than a few occurrences of raw strings that had to stay raw strings.
2744Enter, the quickfix list.&lt;/p&gt;
2745&lt;p&gt;The idea behind the quickfix list is to jump from one position in a
2746file to another (maybe in a different file), much like how the arglist
2747lets you jump from one file to another.&lt;/p&gt;
2748&lt;p&gt;One of the easiest ways to populate this list with a bunch of
2749positions is to use &lt;code&gt;vimgrep&lt;/code&gt;:&lt;/p&gt;
1793&lt;pre&gt;&lt;code&gt;# basic usage 2750&lt;pre&gt;&lt;code&gt;# basic usage
1794:vimgrep pattern files 2751:vimgrep pattern files
1795 2752
1796# search for raw strings 2753# search for raw strings
1797:vimgrep &amp;#39;r#&amp;#39; ./**/*.rs&lt;/code&gt;&lt;/pre&gt; 2754:vimgrep &amp;#39;r#&amp;#39; ./**/*.rs&lt;/code&gt;&lt;/pre&gt;
1798&lt;p&gt;Like &lt;code&gt;:next&lt;/code&gt; and &lt;code&gt;:prev&lt;/code&gt;, you can navigate the quickfix list with &lt;code&gt;:cnext&lt;/code&gt; and &lt;code&gt;:cprev&lt;/code&gt;. Every time you move up or down the list, vim indicates your index:&lt;/p&gt; 2755&lt;p&gt;Like &lt;code&gt;:next&lt;/code&gt; and &lt;code&gt;:prev&lt;/code&gt;, you can navigate the
2756quickfix list with &lt;code&gt;:cnext&lt;/code&gt; and &lt;code&gt;:cprev&lt;/code&gt;. Every
2757time you move up or down the list, vim indicates your index:&lt;/p&gt;
1799&lt;pre&gt;&lt;code&gt;(1 of 131): r#&amp;quot;{&amp;quot;set_tweak&amp;quot;: &amp;quot;highlight&amp;quot;}&amp;quot;#;&lt;/code&gt;&lt;/pre&gt; 2758&lt;pre&gt;&lt;code&gt;(1 of 131): r#&amp;quot;{&amp;quot;set_tweak&amp;quot;: &amp;quot;highlight&amp;quot;}&amp;quot;#;&lt;/code&gt;&lt;/pre&gt;
1800&lt;p&gt;And just like &lt;code&gt;argdo&lt;/code&gt;, you can &lt;code&gt;cdo&lt;/code&gt; to apply commands to &lt;em&gt;every&lt;/em&gt; match in the quickfix list:&lt;/p&gt; 2759&lt;p&gt;And just like &lt;code&gt;argdo&lt;/code&gt;, you can &lt;code&gt;cdo&lt;/code&gt; to apply
2760commands to &lt;em&gt;every&lt;/em&gt; match in the quickfix list:&lt;/p&gt;
1801&lt;pre&gt;&lt;code&gt;:cdo norm! @q&lt;/code&gt;&lt;/pre&gt; 2761&lt;pre&gt;&lt;code&gt;:cdo norm! @q&lt;/code&gt;&lt;/pre&gt;
1802&lt;p&gt;But, I had to manually pick out matches, and it involved some button mashing.&lt;/p&gt; 2762&lt;p&gt;But, I had to manually pick out matches, and it involved some button
2763mashing.&lt;/p&gt;
1803&lt;h3 id="external-filtering"&gt;External Filtering&lt;/h3&gt; 2764&lt;h3 id="external-filtering"&gt;External Filtering&lt;/h3&gt;
1804&lt;p&gt;Some code reviews later, I was asked to format all the json inside the &lt;code&gt;json!&lt;/code&gt; macro. All you have to do is pass a visual selection through a pretty json printer. Select the range to be formatted in visual mode, and hit &lt;code&gt;:&lt;/code&gt;, you will notice the command line displaying what seems to be gibberish:&lt;/p&gt; 2765&lt;p&gt;Some code reviews later, I was asked to format all the json inside
2766the &lt;code&gt;json!&lt;/code&gt; macro. All you have to do is pass a visual
2767selection through a pretty json printer. Select the range to be
2768formatted in visual mode, and hit &lt;code&gt;:&lt;/code&gt;, you will notice the
2769command line displaying what seems to be gibberish:&lt;/p&gt;
1805&lt;pre&gt;&lt;code&gt;:&amp;#39;&amp;lt;,&amp;#39;&amp;gt;&lt;/code&gt;&lt;/pre&gt; 2770&lt;pre&gt;&lt;code&gt;:&amp;#39;&amp;lt;,&amp;#39;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
1806&lt;p&gt;&lt;code&gt;'&amp;lt;&lt;/code&gt; and &lt;code&gt;'&amp;gt;&lt;/code&gt; are &lt;em&gt;marks&lt;/em&gt; &lt;a href="#fn4" class="footnote-ref" id="fnref4" role="doc-noteref"&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt;. More specifically, they are marks that vim sets automatically every time you make a visual selection, denoting the start and end of the selection.&lt;/p&gt; 2771&lt;p&gt;&lt;code&gt;'&amp;lt;&lt;/code&gt; and &lt;code&gt;'&amp;gt;&lt;/code&gt; are &lt;em&gt;marks&lt;/em&gt; &lt;a
1807&lt;p&gt;A range is one or more line specifiers separated by a &lt;code&gt;,&lt;/code&gt;:&lt;/p&gt; 2772href="#fn4" class="footnote-ref" id="fnref4"
2773role="doc-noteref"&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt;. More specifically, they are marks
2774that vim sets automatically every time you make a visual selection,
2775denoting the start and end of the selection.&lt;/p&gt;
2776&lt;p&gt;A range is one or more line specifiers separated by a
2777&lt;code&gt;,&lt;/code&gt;:&lt;/p&gt;
1808&lt;pre&gt;&lt;code&gt;:1,7 lines 1 through 7 2778&lt;pre&gt;&lt;code&gt;:1,7 lines 1 through 7
1809:32 just line 32 2779:32 just line 32
1810:. the current line 2780:. the current line
1811:.,$ the current line to the last line 2781:.,$ the current line to the last line
1812:&amp;#39;a,&amp;#39;b mark &amp;#39;a&amp;#39; to mark &amp;#39;b&amp;#39;&lt;/code&gt;&lt;/pre&gt; 2782:&amp;#39;a,&amp;#39;b mark &amp;#39;a&amp;#39; to mark &amp;#39;b&amp;#39;&lt;/code&gt;&lt;/pre&gt;
1813&lt;p&gt;Most &lt;code&gt;:&lt;/code&gt; commands can be prefixed by ranges. &lt;code&gt;:help usr_10.txt&lt;/code&gt; for more on that.&lt;/p&gt; 2783&lt;p&gt;Most &lt;code&gt;:&lt;/code&gt; commands can be prefixed by ranges.
1814&lt;p&gt;Alright, lets pass json through &lt;code&gt;python -m json.tool&lt;/code&gt;, a json formatter that accepts &lt;code&gt;stdin&lt;/code&gt; (note the use of &lt;code&gt;!&lt;/code&gt; to make use of an external program):&lt;/p&gt; 2784&lt;code&gt;:help usr_10.txt&lt;/code&gt; for more on that.&lt;/p&gt;
2785&lt;p&gt;Alright, lets pass json through &lt;code&gt;python -m json.tool&lt;/code&gt;, a
2786json formatter that accepts &lt;code&gt;stdin&lt;/code&gt; (note the use of
2787&lt;code&gt;!&lt;/code&gt; to make use of an external program):&lt;/p&gt;
1815&lt;pre&gt;&lt;code&gt;:&amp;#39;&amp;lt;,&amp;#39;&amp;gt;!python -m json.tool&lt;/code&gt;&lt;/pre&gt; 2788&lt;pre&gt;&lt;code&gt;:&amp;#39;&amp;lt;,&amp;#39;&amp;gt;!python -m json.tool&lt;/code&gt;&lt;/pre&gt;
1816&lt;p&gt;Unfortunately that didn’t quite work for me because the range included some non-json text as well, a mix of regex and macros helped fix that. I think you get the drift.&lt;/p&gt; 2789&lt;p&gt;Unfortunately that didn’t quite work for me because the range
1817&lt;p&gt;Another fun filter I use from time to time is &lt;code&gt;:!sort&lt;/code&gt;, to sort css attributes, or &lt;code&gt;:!uniq&lt;/code&gt; to remove repeated imports.&lt;/p&gt; 2790included some non-json text as well, a mix of regex and macros helped
1818&lt;section class="footnotes" role="doc-endnotes"&gt; 2791fix that. I think you get the drift.&lt;/p&gt;
2792&lt;p&gt;Another fun filter I use from time to time is &lt;code&gt;:!sort&lt;/code&gt;, to
2793sort css attributes, or &lt;code&gt;:!uniq&lt;/code&gt; to remove repeated
2794imports.&lt;/p&gt;
2795&lt;section id="footnotes" class="footnotes footnotes-end-of-document"
2796role="doc-endnotes"&gt;
1819&lt;hr /&gt; 2797&lt;hr /&gt;
1820&lt;ol&gt; 2798&lt;ol&gt;
1821&lt;li id="fn1" role="doc-endnote"&gt;&lt;p&gt;https://github.com/tpope/vim-unimpaired It also handles various other mappings, &lt;code&gt;]q&lt;/code&gt; and &lt;code&gt;[q&lt;/code&gt; to navigate the quickfix list for example&lt;a href="#fnref1" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; 2799&lt;li id="fn1"&gt;&lt;p&gt;https://github.com/tpope/vim-unimpaired It also handles
1822&lt;li id="fn2" role="doc-endnote"&gt;&lt;p&gt;&lt;code&gt;:help recording&lt;/code&gt;&lt;a href="#fnref2" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; 2800various other mappings, &lt;code&gt;]q&lt;/code&gt; and &lt;code&gt;[q&lt;/code&gt; to navigate
1823&lt;li id="fn3" role="doc-endnote"&gt;&lt;p&gt;When I’m recording a macro, I prefer starting out by storing it in register &lt;code&gt;q&lt;/code&gt;, and then copying it over to another register if it works as intended. I think of &lt;code&gt;qq&lt;/code&gt; as ‘quick record’.&lt;a href="#fnref3" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; 2801the quickfix list for example&lt;a href="#fnref1" class="footnote-back"
1824&lt;li id="fn4" role="doc-endnote"&gt;&lt;p&gt;&lt;code&gt;:help mark-motions&lt;/code&gt;&lt;a href="#fnref4" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; 2802role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
2803&lt;li id="fn2"&gt;&lt;p&gt;&lt;code&gt;:help recording&lt;/code&gt;&lt;a href="#fnref2"
2804class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
2805&lt;li id="fn3"&gt;&lt;p&gt;When I’m recording a macro, I prefer starting out by
2806storing it in register &lt;code&gt;q&lt;/code&gt;, and then copying it over to
2807another register if it works as intended. I think of &lt;code&gt;qq&lt;/code&gt; as
2808‘quick record’.&lt;a href="#fnref3" class="footnote-back"
2809role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
2810&lt;li id="fn4"&gt;&lt;p&gt;&lt;code&gt;:help mark-motions&lt;/code&gt;&lt;a href="#fnref4"
2811class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
1825&lt;/ol&gt; 2812&lt;/ol&gt;
1826&lt;/section&gt;</description> 2813&lt;/section&gt;</description>
1827<link>https://peppe.rs/posts/rapid_refactoring_with_vim/</link> 2814<link>https://peppe.rs/posts/rapid_refactoring_with_vim/</link>
@@ -1830,34 +2817,75 @@ BUFFER: json!( ... );&lt;/code&gt;&lt;/pre&gt;
1830</item> 2817</item>
1831<item> 2818<item>
1832<title>Font Size Fallacies</title> 2819<title>Font Size Fallacies</title>
1833<description>&lt;p&gt;I am not an expert with fonts, but I do have some experience &lt;a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;, and common sense. This post aims to debunk some misconceptions about font sizes!&lt;/p&gt; 2820<description>&lt;p&gt;I am not an expert with fonts, but I do have some experience &lt;a
1834&lt;p&gt;11 px on your display is &lt;em&gt;probably not&lt;/em&gt; 11 px on my display. Let’s do some quick math. I have two displays, 1366x768 @ 21" and another with 1920x1080 @ 13", call them &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt; for now.&lt;/p&gt; 2821href="#fn1" class="footnote-ref" id="fnref1"
1835&lt;p&gt;Display &lt;code&gt;A&lt;/code&gt; has 1,049,088 pixels. A pixel is a square, of side say, &lt;code&gt;s&lt;/code&gt; cm. The total area covered by my 21" display is about 1,066 cm^2 (41x26). Thus,&lt;/p&gt; 2822role="doc-noteref"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;, and common sense. This post aims to
2823debunk some misconceptions about font sizes!&lt;/p&gt;
2824&lt;p&gt;11 px on your display is &lt;em&gt;probably not&lt;/em&gt; 11 px on my display.
2825Let’s do some quick math. I have two displays, 1366x768 @ 21” and
2826another with 1920x1080 @ 13”, call them &lt;code&gt;A&lt;/code&gt; and
2827&lt;code&gt;B&lt;/code&gt; for now.&lt;/p&gt;
2828&lt;p&gt;Display &lt;code&gt;A&lt;/code&gt; has 1,049,088 pixels. A pixel is a square, of
2829side say, &lt;code&gt;s&lt;/code&gt; cm. The total area covered by my 21” display is
2830about 1,066 cm^2 (41x26). Thus,&lt;/p&gt;
1836&lt;pre&gt;&lt;code&gt;Display A 2831&lt;pre&gt;&lt;code&gt;Display A
1837Dimensions: 1366x768 @ 21&amp;quot; (41x26 sq. cm) 2832Dimensions: 1366x768 @ 21&amp;quot; (41x26 sq. cm)
18381,049,088 s^2 = 1066 28331,049,088 s^2 = 1066
1839 s = 0.0318 cm (side of a pixel on Display A)&lt;/code&gt;&lt;/pre&gt; 2834 s = 0.0318 cm (side of a pixel on Display A)&lt;/code&gt;&lt;/pre&gt;
1840&lt;p&gt;Bear with me, as I repeat the number crunching for Display &lt;code&gt;B&lt;/code&gt;:&lt;/p&gt; 2835&lt;p&gt;Bear with me, as I repeat the number crunching for Display
2836&lt;code&gt;B&lt;/code&gt;:&lt;/p&gt;
1841&lt;pre&gt;&lt;code&gt;Display B 2837&lt;pre&gt;&lt;code&gt;Display B
1842Dimensions: 1920x1080 @ 13&amp;quot; (29.5x16.5 sq. cm) 2838Dimensions: 1920x1080 @ 13&amp;quot; (29.5x16.5 sq. cm)
18432,073,600 s^2 = 486.75 28392,073,600 s^2 = 486.75
1844 s = 0.0153 cm (side of a pixel on Display B)&lt;/code&gt;&lt;/pre&gt; 2840 s = 0.0153 cm (side of a pixel on Display B)&lt;/code&gt;&lt;/pre&gt;
1845&lt;p&gt;The width of a pixel on Display &lt;code&gt;A&lt;/code&gt; is &lt;em&gt;double&lt;/em&gt; the width of a pixel on Display &lt;code&gt;B&lt;/code&gt;. The area occupied by a pixel on Display &lt;code&gt;A&lt;/code&gt; is &lt;em&gt;4 times&lt;/em&gt; the area occupied by a pixel on Display &lt;code&gt;B&lt;/code&gt;.&lt;/p&gt; 2841&lt;p&gt;The width of a pixel on Display &lt;code&gt;A&lt;/code&gt; is &lt;em&gt;double&lt;/em&gt; the
2842width of a pixel on Display &lt;code&gt;B&lt;/code&gt;. The area occupied by a pixel
2843on Display &lt;code&gt;A&lt;/code&gt; is &lt;em&gt;4 times&lt;/em&gt; the area occupied by a
2844pixel on Display &lt;code&gt;B&lt;/code&gt;.&lt;/p&gt;
1846&lt;p&gt;&lt;em&gt;The size of a pixel varies from display to display!&lt;/em&gt;&lt;/p&gt; 2845&lt;p&gt;&lt;em&gt;The size of a pixel varies from display to display!&lt;/em&gt;&lt;/p&gt;
1847&lt;p&gt;A 5x11 bitmap font on Display &lt;code&gt;A&lt;/code&gt; would be around 4 mm tall whereas the same bitmap font on Display &lt;code&gt;B&lt;/code&gt; would be around 1.9 mm tall. A 11 px tall character on &lt;code&gt;B&lt;/code&gt; is visually equivalent to a 5 px character on &lt;code&gt;A&lt;/code&gt;. When you view a screenshot of Display &lt;code&gt;A&lt;/code&gt; on Display &lt;code&gt;B&lt;/code&gt;, the contents are shrunk down by a factor of 2!&lt;/p&gt; 2846&lt;p&gt;A 5x11 bitmap font on Display &lt;code&gt;A&lt;/code&gt; would be around 4 mm
1848&lt;p&gt;So screen resolution is not enough, how else do we measure size? Pixel Density! Keen readers will realize that the 5^th grade math problem we solved up there showcases pixel density, or, pixels per cm (PPCM). Usually we deal with pixels per inch (PPI).&lt;/p&gt; 2847tall whereas the same bitmap font on Display &lt;code&gt;B&lt;/code&gt; would be
1849&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; PPI is not to be confused with DPI &lt;a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; (dots per inch). DPI is defined for printers.&lt;/p&gt; 2848around 1.9 mm tall. A 11 px tall character on &lt;code&gt;B&lt;/code&gt; is visually
1850&lt;p&gt;In our example, &lt;code&gt;A&lt;/code&gt; is a 75 ppi display and &lt;code&gt;B&lt;/code&gt; is around 165 ppi &lt;a href="#fn3" class="footnote-ref" id="fnref3" role="doc-noteref"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;. A low ppi display appears to be ‘pixelated’, because the pixels are more prominent, much like Display &lt;code&gt;A&lt;/code&gt;. A higher ppi usually means you can view larger images and render crispier fonts. The average desktop display can stuff 100-200 pixels per inch. Smart phones usually fall into the 400-600 ppi (XXXHDPI) category. The human eye fails to differentiate detail past 300 ppi.&lt;/p&gt; 2849equivalent to a 5 px character on &lt;code&gt;A&lt;/code&gt;. When you view a
1851&lt;p&gt;&lt;em&gt;So … streaming an 8K video on a 60" TV provides the same clarity as a HD video on a smart phone?&lt;/em&gt;&lt;/p&gt; 2850screenshot of Display &lt;code&gt;A&lt;/code&gt; on Display &lt;code&gt;B&lt;/code&gt;, the
1852&lt;p&gt;Absolutely. Well, clarity is subjective, but the amount of detail you can discern on mobile displays has always been limited. Salty consumers of the Xperia 1 &lt;a href="#fn4" class="footnote-ref" id="fnref4" role="doc-noteref"&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; will say otherwise.&lt;/p&gt; 2851contents are shrunk down by a factor of 2!&lt;/p&gt;
1853&lt;p&gt;Maybe I will talk about font rendering in another post, but thats all for now. Don’t judge a font size by its screenshot.&lt;/p&gt; 2852&lt;p&gt;So screen resolution is not enough, how else do we measure size?
1854&lt;section class="footnotes" role="doc-endnotes"&gt; 2853Pixel Density! Keen readers will realize that the 5^th grade math
2854problem we solved up there showcases pixel density, or, pixels per cm
2855(PPCM). Usually we deal with pixels per inch (PPI).&lt;/p&gt;
2856&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; PPI is not to be confused with DPI &lt;a
2857href="#fn2" class="footnote-ref" id="fnref2"
2858role="doc-noteref"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; (dots per inch). DPI is defined for
2859printers.&lt;/p&gt;
2860&lt;p&gt;In our example, &lt;code&gt;A&lt;/code&gt; is a 75 ppi display and &lt;code&gt;B&lt;/code&gt;
2861is around 165 ppi &lt;a href="#fn3" class="footnote-ref" id="fnref3"
2862role="doc-noteref"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;. A low ppi display appears to be
2863‘pixelated’, because the pixels are more prominent, much like Display
2864&lt;code&gt;A&lt;/code&gt;. A higher ppi usually means you can view larger images
2865and render crispier fonts. The average desktop display can stuff 100-200
2866pixels per inch. Smart phones usually fall into the 400-600 ppi
2867(XXXHDPI) category. The human eye fails to differentiate detail past 300
2868ppi.&lt;/p&gt;
2869&lt;p&gt;&lt;em&gt;So … streaming an 8K video on a 60” TV provides the same clarity
2870as a HD video on a smart phone?&lt;/em&gt;&lt;/p&gt;
2871&lt;p&gt;Absolutely. Well, clarity is subjective, but the amount of detail you
2872can discern on mobile displays has always been limited. Salty consumers
2873of the Xperia 1 &lt;a href="#fn4" class="footnote-ref" id="fnref4"
2874role="doc-noteref"&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; will say otherwise.&lt;/p&gt;
2875&lt;p&gt;Maybe I will talk about font rendering in another post, but thats all
2876for now. Don’t judge a font size by its screenshot.&lt;/p&gt;
2877&lt;section id="footnotes" class="footnotes footnotes-end-of-document"
2878role="doc-endnotes"&gt;
1855&lt;hr /&gt; 2879&lt;hr /&gt;
1856&lt;ol&gt; 2880&lt;ol&gt;
1857&lt;li id="fn1" role="doc-endnote"&gt;&lt;p&gt;https://github.com/nerdypepper/scientifica&lt;a href="#fnref1" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; 2881&lt;li id="fn1"&gt;&lt;p&gt;https://github.com/nerdypepper/scientifica&lt;a
1858&lt;li id="fn2" role="doc-endnote"&gt;&lt;p&gt;https://en.wikipedia.org/wiki/Dots_per_inch&lt;a href="#fnref2" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; 2882href="#fnref1" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
1859&lt;li id="fn3" role="doc-endnote"&gt;&lt;p&gt;https://www.sven.de/dpi/&lt;a href="#fnref3" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; 2883&lt;li id="fn2"&gt;&lt;p&gt;https://en.wikipedia.org/wiki/Dots_per_inch&lt;a
1860&lt;li id="fn4" role="doc-endnote"&gt;&lt;p&gt;https://en.wikipedia.org/wiki/Sony_Xperia_1&lt;a href="#fnref4" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; 2884href="#fnref2" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
2885&lt;li id="fn3"&gt;&lt;p&gt;https://www.sven.de/dpi/&lt;a href="#fnref3"
2886class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
2887&lt;li id="fn4"&gt;&lt;p&gt;https://en.wikipedia.org/wiki/Sony_Xperia_1&lt;a
2888href="#fnref4" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
1861&lt;/ol&gt; 2889&lt;/ol&gt;
1862&lt;/section&gt;</description> 2890&lt;/section&gt;</description>
1863<link>https://peppe.rs/posts/font_size_fallacies/</link> 2891<link>https://peppe.rs/posts/font_size_fallacies/</link>
@@ -1866,87 +2894,153 @@ Dimensions: 1920x1080 @ 13&amp;quot; (29.5x16.5 sq. cm)
1866</item> 2894</item>
1867<item> 2895<item>
1868<title>Termux Tandem</title> 2896<title>Termux Tandem</title>
1869<description>&lt;p&gt;I learnt about &lt;code&gt;termux&lt;/code&gt; from a friend on IRC recently. It looked super gimmicky to me at first, but it eventually proved to be useful. Here’s what I use it for:&lt;/p&gt; 2897<description>&lt;p&gt;I learnt about &lt;code&gt;termux&lt;/code&gt; from a friend on IRC recently. It
2898looked super gimmicky to me at first, but it eventually proved to be
2899useful. Here’s what I use it for:&lt;/p&gt;
1870&lt;h3 id="rsync"&gt;rsync&lt;/h3&gt; 2900&lt;h3 id="rsync"&gt;rsync&lt;/h3&gt;
1871&lt;p&gt;Ever since I degoogled my android device, syncing files between my phone and my PC has always been a pain. I’m looking at you MTP. But, with &lt;code&gt;termux&lt;/code&gt; and &lt;code&gt;sshd&lt;/code&gt; all set up, it’s as simple as:&lt;/p&gt; 2901&lt;p&gt;Ever since I degoogled my android device, syncing files between my
2902phone and my PC has always been a pain. I’m looking at you MTP. But,
2903with &lt;code&gt;termux&lt;/code&gt; and &lt;code&gt;sshd&lt;/code&gt; all set up, it’s as
2904simple as:&lt;/p&gt;
1872&lt;pre&gt;&lt;code&gt;$ arp 2905&lt;pre&gt;&lt;code&gt;$ arp
1873Address HWtype HWad ... 2906Address HWtype HWad ...
1874192.168.43.187 ether d0:0 ... 2907192.168.43.187 ether d0:0 ...
1875 2908
1876$ rsync -avz 192.168.43.187:~/frogs ~/pics/frogs&lt;/code&gt;&lt;/pre&gt; 2909$ rsync -avz 192.168.43.187:~/frogs ~/pics/frogs&lt;/code&gt;&lt;/pre&gt;
1877&lt;h3 id="ssh-tmux"&gt;ssh &amp;amp; tmux&lt;/h3&gt; 2910&lt;h3 id="ssh-tmux"&gt;ssh &amp;amp; tmux&lt;/h3&gt;
1878&lt;p&gt;My phone doubles as a secondary view into my main machine with &lt;code&gt;ssh&lt;/code&gt; and &lt;code&gt;tmux&lt;/code&gt;. When I am away from my PC (read: sitting across the room), I check build status and IRC messages by &lt;code&gt;ssh&lt;/code&gt;ing into a tmux session running the said build or weechat.&lt;/p&gt; 2911&lt;p&gt;My phone doubles as a secondary view into my main machine with
2912&lt;code&gt;ssh&lt;/code&gt; and &lt;code&gt;tmux&lt;/code&gt;. When I am away from my PC (read:
2913sitting across the room), I check build status and IRC messages by
2914&lt;code&gt;ssh&lt;/code&gt;ing into a tmux session running the said build or
2915weechat.&lt;/p&gt;
1879&lt;h3 id="file-uploads"&gt;file uploads&lt;/h3&gt; 2916&lt;h3 id="file-uploads"&gt;file uploads&lt;/h3&gt;
1880&lt;p&gt;Not being able to access my (ssh-only) file host was crippling. With a &lt;code&gt;bash&lt;/code&gt; instance on my phone, I just copied over my ssh keys, and popped in a file upload script (a glorified &lt;code&gt;scp&lt;/code&gt;). Now I just have to figure out a way to clean up these file names …&lt;/p&gt; 2917&lt;p&gt;Not being able to access my (ssh-only) file host was crippling. With
2918a &lt;code&gt;bash&lt;/code&gt; instance on my phone, I just copied over my ssh
2919keys, and popped in a file upload script (a glorified &lt;code&gt;scp&lt;/code&gt;).
2920Now I just have to figure out a way to clean up these file names …&lt;/p&gt;
1881&lt;pre&gt;&lt;code&gt;~/storage/pictures/ $ ls 2921&lt;pre&gt;&lt;code&gt;~/storage/pictures/ $ ls
188202muf5g7b2i41.jpg 7alt3cwg77841.jpg cl4bsrge7id11.png 292202muf5g7b2i41.jpg 7alt3cwg77841.jpg cl4bsrge7id11.png
1883mtZabXG.jpg p8d5c584f2841.jpg vjUxGjq.jpg&lt;/code&gt;&lt;/pre&gt; 2923mtZabXG.jpg p8d5c584f2841.jpg vjUxGjq.jpg&lt;/code&gt;&lt;/pre&gt;
1884&lt;h3 id="cmus"&gt;cmus&lt;/h3&gt; 2924&lt;h3 id="cmus"&gt;cmus&lt;/h3&gt;
1885&lt;p&gt;Alright, I don’t really listen to music via &lt;code&gt;cmus&lt;/code&gt;, but I did use it a couple times when my default music player was acting up. &lt;code&gt;cmus&lt;/code&gt; is a viable option:&lt;/p&gt; 2925&lt;p&gt;Alright, I don’t really listen to music via &lt;code&gt;cmus&lt;/code&gt;, but I
1886&lt;p&gt;&lt;a href="https://u.peppe.rs/CP.jpg"&gt;&lt;img src="https://u.peppe.rs/CP.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;</description> 2926did use it a couple times when my default music player was acting up.
2927&lt;code&gt;cmus&lt;/code&gt; is a viable option:&lt;/p&gt;
2928&lt;p&gt;&lt;a href="https://u.peppe.rs/CP.jpg"&gt;&lt;img
2929src="https://u.peppe.rs/CP.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;</description>
1887<link>https://peppe.rs/posts/termux_tandem/</link> 2930<link>https://peppe.rs/posts/termux_tandem/</link>
1888<pubDate>Sat, 07 Mar 2020 18:30:00 +0000</pubDate> 2931<pubDate>Sat, 07 Mar 2020 18:30:00 +0000</pubDate>
1889<guid>https://peppe.rs/posts/termux_tandem/</guid> 2932<guid>https://peppe.rs/posts/termux_tandem/</guid>
1890</item> 2933</item>
1891<item> 2934<item>
1892<title>Call To ARMs</title> 2935<title>Call To ARMs</title>
1893<description>&lt;p&gt;My 4th semester involves ARM programming. And proprietary tooling (Keil C). But we don’t do that here.&lt;/p&gt; 2936<description>&lt;p&gt;My 4th semester involves ARM programming. And proprietary tooling
2937(Keil C). But we don’t do that here.&lt;/p&gt;
1894&lt;h3 id="building"&gt;Building&lt;/h3&gt; 2938&lt;h3 id="building"&gt;Building&lt;/h3&gt;
1895&lt;p&gt;Assembling and linking ARM binaries on non-ARM architecture devices is fairly trivial. I went along with the GNU cross bare metal toolchain binutils, which provides &lt;code&gt;arm-as&lt;/code&gt; and &lt;code&gt;arm-ld&lt;/code&gt; (among a bunch of other utils that I don’t care about for now).&lt;/p&gt; 2939&lt;p&gt;Assembling and linking ARM binaries on non-ARM architecture devices
2940is fairly trivial. I went along with the GNU cross bare metal toolchain
2941binutils, which provides &lt;code&gt;arm-as&lt;/code&gt; and &lt;code&gt;arm-ld&lt;/code&gt;
2942(among a bunch of other utils that I don’t care about for now).&lt;/p&gt;
1896&lt;p&gt;Assemble &lt;code&gt;.s&lt;/code&gt; files with:&lt;/p&gt; 2943&lt;p&gt;Assemble &lt;code&gt;.s&lt;/code&gt; files with:&lt;/p&gt;
1897&lt;pre class="shell"&gt;&lt;code&gt;arm-none-eabi-as main.s -g -march=armv8.1-a -o main.out&lt;/code&gt;&lt;/pre&gt; 2944&lt;pre class="shell"&gt;&lt;code&gt;arm-none-eabi-as main.s -g -march=armv8.1-a -o main.out&lt;/code&gt;&lt;/pre&gt;
1898&lt;p&gt;The &lt;code&gt;-g&lt;/code&gt; flag generates extra debugging information that &lt;code&gt;gdb&lt;/code&gt; picks up. The &lt;code&gt;-march&lt;/code&gt; option establishes target architecture.&lt;/p&gt; 2945&lt;p&gt;The &lt;code&gt;-g&lt;/code&gt; flag generates extra debugging information that
2946&lt;code&gt;gdb&lt;/code&gt; picks up. The &lt;code&gt;-march&lt;/code&gt; option establishes
2947target architecture.&lt;/p&gt;
1899&lt;p&gt;Link &lt;code&gt;.o&lt;/code&gt; files with:&lt;/p&gt; 2948&lt;p&gt;Link &lt;code&gt;.o&lt;/code&gt; files with:&lt;/p&gt;
1900&lt;pre class="shell"&gt;&lt;code&gt;arm-none-eabi-ld main.out -o main&lt;/code&gt;&lt;/pre&gt; 2949&lt;pre class="shell"&gt;&lt;code&gt;arm-none-eabi-ld main.out -o main&lt;/code&gt;&lt;/pre&gt;
1901&lt;h3 id="running-and-debugging"&gt;Running (and Debugging)&lt;/h3&gt; 2950&lt;h3 id="running-and-debugging"&gt;Running (and Debugging)&lt;/h3&gt;
1902&lt;p&gt;Things get interesting here. &lt;code&gt;gdb&lt;/code&gt; on your x86 machine cannot read nor execute binaries compiled for ARM. So, we simulate an ARM processor using &lt;code&gt;qemu&lt;/code&gt;. Now qemu allows you to run &lt;code&gt;gdbserver&lt;/code&gt; on startup. Connecting our local &lt;code&gt;gdb&lt;/code&gt; instance to &lt;code&gt;gdbserver&lt;/code&gt; gives us a view into the program’s execution. Easy!&lt;/p&gt; 2951&lt;p&gt;Things get interesting here. &lt;code&gt;gdb&lt;/code&gt; on your x86 machine
1903&lt;p&gt;Run &lt;code&gt;qemu&lt;/code&gt;, with &lt;code&gt;gdbserver&lt;/code&gt; on port &lt;code&gt;1234&lt;/code&gt;, with our ARM binary, &lt;code&gt;main&lt;/code&gt;:&lt;/p&gt; 2952cannot read nor execute binaries compiled for ARM. So, we simulate an
2953ARM processor using &lt;code&gt;qemu&lt;/code&gt;. Now qemu allows you to run
2954&lt;code&gt;gdbserver&lt;/code&gt; on startup. Connecting our local &lt;code&gt;gdb&lt;/code&gt;
2955instance to &lt;code&gt;gdbserver&lt;/code&gt; gives us a view into the program’s
2956execution. Easy!&lt;/p&gt;
2957&lt;p&gt;Run &lt;code&gt;qemu&lt;/code&gt;, with &lt;code&gt;gdbserver&lt;/code&gt; on port
2958&lt;code&gt;1234&lt;/code&gt;, with our ARM binary, &lt;code&gt;main&lt;/code&gt;:&lt;/p&gt;
1904&lt;pre class="shell"&gt;&lt;code&gt;qemu-arm -singlestep -g 1234 main&lt;/code&gt;&lt;/pre&gt; 2959&lt;pre class="shell"&gt;&lt;code&gt;qemu-arm -singlestep -g 1234 main&lt;/code&gt;&lt;/pre&gt;
1905&lt;p&gt;Start up &lt;code&gt;gdb&lt;/code&gt; on your machine, and connect to &lt;code&gt;qemu&lt;/code&gt;’s &lt;code&gt;gdbserver&lt;/code&gt;:&lt;/p&gt; 2960&lt;p&gt;Start up &lt;code&gt;gdb&lt;/code&gt; on your machine, and connect to
2961&lt;code&gt;qemu&lt;/code&gt;’s &lt;code&gt;gdbserver&lt;/code&gt;:&lt;/p&gt;
1906&lt;pre&gt;&lt;code&gt;(gdb) set architecture armv8-a 2962&lt;pre&gt;&lt;code&gt;(gdb) set architecture armv8-a
1907(gdb) target remote localhost:1234 2963(gdb) target remote localhost:1234
1908(gdb) file main 2964(gdb) file main
1909Reading symbols from main... # yay!&lt;/code&gt;&lt;/pre&gt; 2965Reading symbols from main... # yay!&lt;/code&gt;&lt;/pre&gt;
1910&lt;h3 id="gdb-enhanced"&gt;GDB Enhanced&lt;/h3&gt; 2966&lt;h3 id="gdb-enhanced"&gt;GDB Enhanced&lt;/h3&gt;
1911&lt;p&gt;&lt;code&gt;gdb&lt;/code&gt; is cool, but it’s not nearly as comfortable as well fleshed out emulators/IDEs like Keil. Watching registers, CPSR and memory chunks update &lt;em&gt;is&lt;/em&gt; pretty fun.&lt;/p&gt; 2967&lt;p&gt;&lt;code&gt;gdb&lt;/code&gt; is cool, but it’s not nearly as comfortable as well
1912&lt;p&gt;I came across &lt;code&gt;gdb&lt;/code&gt;’s TUI mode (hit &lt;code&gt;C-x C-a&lt;/code&gt; or type &lt;code&gt;tui enable&lt;/code&gt; at the prompt). TUI mode is a godsend. It highlights the current line of execution, shows you disassembly outputs, updated registers, active breakpoints and more.&lt;/p&gt; 2968fleshed out emulators/IDEs like Keil. Watching registers, CPSR and
2969memory chunks update &lt;em&gt;is&lt;/em&gt; pretty fun.&lt;/p&gt;
2970&lt;p&gt;I came across &lt;code&gt;gdb&lt;/code&gt;’s TUI mode (hit &lt;code&gt;C-x C-a&lt;/code&gt;
2971or type &lt;code&gt;tui enable&lt;/code&gt; at the prompt). TUI mode is a godsend.
2972It highlights the current line of execution, shows you disassembly
2973outputs, updated registers, active breakpoints and more.&lt;/p&gt;
1913&lt;p&gt;&lt;em&gt;But&lt;/em&gt;, it is an absolute eyesore.&lt;/p&gt; 2974&lt;p&gt;&lt;em&gt;But&lt;/em&gt;, it is an absolute eyesore.&lt;/p&gt;
1914&lt;p&gt;Say hello to &lt;a href="https://github.com/hugsy/gef"&gt;GEF&lt;/a&gt;! “GDB Enhanced Features” teaches our old dog some cool new tricks. Here are some additions that made my ARM debugging experience loads better:&lt;/p&gt; 2975&lt;p&gt;Say hello to &lt;a href="https://github.com/hugsy/gef"&gt;GEF&lt;/a&gt;! “GDB
2976Enhanced Features” teaches our old dog some cool new tricks. Here are
2977some additions that made my ARM debugging experience loads better:&lt;/p&gt;
1915&lt;ul&gt; 2978&lt;ul&gt;
1916&lt;li&gt;Memory watches&lt;/li&gt; 2979&lt;li&gt;Memory watches&lt;/li&gt;
1917&lt;li&gt;Register watches, with up to 7 levels of deref (overkill, I agree)&lt;/li&gt; 2980&lt;li&gt;Register watches, with up to 7 levels of deref (overkill, I
2981agree)&lt;/li&gt;
1918&lt;li&gt;Stack tracing&lt;/li&gt; 2982&lt;li&gt;Stack tracing&lt;/li&gt;
1919&lt;/ul&gt; 2983&lt;/ul&gt;
1920&lt;p&gt;And it’s pretty! See for yourself:&lt;/p&gt; 2984&lt;p&gt;And it’s pretty! See for yourself:&lt;/p&gt;
1921&lt;p&gt;&lt;a href="https://u.peppe.rs/wq.png"&gt;&lt;img src="https://u.peppe.rs/wq.png" /&gt;&lt;/a&gt;&lt;/p&gt; 2985&lt;p&gt;&lt;a href="https://u.peppe.rs/wq.png"&gt;&lt;img
2986src="https://u.peppe.rs/wq.png" /&gt;&lt;/a&gt;&lt;/p&gt;
1922&lt;h3 id="editing"&gt;Editing&lt;/h3&gt; 2987&lt;h3 id="editing"&gt;Editing&lt;/h3&gt;
1923&lt;p&gt;Vim, with &lt;code&gt;syntax off&lt;/code&gt; because it dosen’t handle GNU ARM syntax too well.&lt;/p&gt;</description> 2988&lt;p&gt;Vim, with &lt;code&gt;syntax off&lt;/code&gt; because it dosen’t handle GNU ARM
2989syntax too well.&lt;/p&gt;</description>
1924<link>https://peppe.rs/posts/call_to_ARMs/</link> 2990<link>https://peppe.rs/posts/call_to_ARMs/</link>
1925<pubDate>Fri, 07 Feb 2020 18:30:00 +0000</pubDate> 2991<pubDate>Fri, 07 Feb 2020 18:30:00 +0000</pubDate>
1926<guid>https://peppe.rs/posts/call_to_ARMs/</guid> 2992<guid>https://peppe.rs/posts/call_to_ARMs/</guid>
1927</item> 2993</item>
1928<item> 2994<item>
1929<title>Color Conundrum</title> 2995<title>Color Conundrum</title>
1930<description>&lt;p&gt;This piece aims to highlight (pun intended) some of the reasons behind my &lt;a href="https://u.peppe.rs/bF.png"&gt;color free&lt;/a&gt; editor setup.&lt;/p&gt; 2996<description>&lt;p&gt;This piece aims to highlight (pun intended) some of the reasons
1931&lt;p&gt;Imagine highlighting an entire book because &lt;em&gt;all&lt;/em&gt; of it is important. That is exactly what (most) syntax highlighting does. It is difficult for the human eye to filter out noise in rainbow barf. Use color to draw attention, not diverge it.&lt;/p&gt; 2997behind my &lt;a href="https://u.peppe.rs/bF.png"&gt;color free&lt;/a&gt; editor
1932&lt;p&gt;At the same time, a book devoid of color is &lt;em&gt;boring!&lt;/em&gt; What is the takeaway from this 10 line paragraph? What are the technical terms used?&lt;/p&gt; 2998setup.&lt;/p&gt;
1933&lt;p&gt;Prose and code are certainly different, but the fickle minded human eye is the same. The eye constantly looks for a frame of reference, a focal point. It grows tired when it can’t find one.&lt;/p&gt; 2999&lt;p&gt;Imagine highlighting an entire book because &lt;em&gt;all&lt;/em&gt; of it is
1934&lt;p&gt;The following comparison does a better job of explaining (none, ample and over-the-top highlighting, from left to right):&lt;/p&gt; 3000important. That is exactly what (most) syntax highlighting does. It is
1935&lt;p&gt;&lt;a href="https://u.peppe.rs/lt.png"&gt;&lt;img src="https://u.peppe.rs/lt.png" /&gt;&lt;/a&gt;&lt;/p&gt; 3001difficult for the human eye to filter out noise in rainbow barf. Use
1936&lt;p&gt;Without highlighting (far left), it is hard to differentiate between comments and code! The florid color scheme (far right) is no good either, it contains too many attention grabbers. The center sample is a healthy balance of both. Function calls and constants stand out, and repetitive keywords and other noise (&lt;code&gt;let&lt;/code&gt;, &lt;code&gt;as&lt;/code&gt;) are mildly dimmed out. Comments and non-code text (sign column, status text) are dimmed further.&lt;/p&gt; 3002color to draw attention, not diverge it.&lt;/p&gt;
1937&lt;p&gt;I’ll stop myself before I rant about color contrast and combinations.&lt;/p&gt;</description> 3003&lt;p&gt;At the same time, a book devoid of color is &lt;em&gt;boring!&lt;/em&gt; What is
3004the takeaway from this 10 line paragraph? What are the technical terms
3005used?&lt;/p&gt;
3006&lt;p&gt;Prose and code are certainly different, but the fickle minded human
3007eye is the same. The eye constantly looks for a frame of reference, a
3008focal point. It grows tired when it can’t find one.&lt;/p&gt;
3009&lt;p&gt;The following comparison does a better job of explaining (none, ample
3010and over-the-top highlighting, from left to right):&lt;/p&gt;
3011&lt;p&gt;&lt;a href="https://u.peppe.rs/lt.png"&gt;&lt;img
3012src="https://u.peppe.rs/lt.png" /&gt;&lt;/a&gt;&lt;/p&gt;
3013&lt;p&gt;Without highlighting (far left), it is hard to differentiate between
3014comments and code! The florid color scheme (far right) is no good
3015either, it contains too many attention grabbers. The center sample is a
3016healthy balance of both. Function calls and constants stand out, and
3017repetitive keywords and other noise (&lt;code&gt;let&lt;/code&gt;, &lt;code&gt;as&lt;/code&gt;)
3018are mildly dimmed out. Comments and non-code text (sign column, status
3019text) are dimmed further.&lt;/p&gt;
3020&lt;p&gt;I’ll stop myself before I rant about color contrast and
3021combinations.&lt;/p&gt;</description>
1938<link>https://peppe.rs/posts/color_conundrum/</link> 3022<link>https://peppe.rs/posts/color_conundrum/</link>
1939<pubDate>Mon, 30 Dec 2019 18:30:00 +0000</pubDate> 3023<pubDate>Mon, 30 Dec 2019 18:30:00 +0000</pubDate>
1940<guid>https://peppe.rs/posts/color_conundrum/</guid> 3024<guid>https://peppe.rs/posts/color_conundrum/</guid>
1941</item> 3025</item>
1942<item> 3026<item>
1943<title>Static Sites With Bash</title> 3027<title>Static Sites With Bash</title>
1944<description>&lt;p&gt;After going through a bunch of static site generators (&lt;a href="https://blog.getpelican.com/"&gt;pelican&lt;/a&gt;, &lt;a href="https://gohugo.io"&gt;hugo&lt;/a&gt;, &lt;a href="https://github.com/icyphox/vite"&gt;vite&lt;/a&gt;), I decided to roll my own. If you are more of the ‘show me the code’ kinda guy, &lt;a href="https://github.com/nerdypepper/site"&gt;here&lt;/a&gt; you go.&lt;/p&gt; 3028<description>&lt;p&gt;After going through a bunch of static site generators (&lt;a
3029href="https://blog.getpelican.com/"&gt;pelican&lt;/a&gt;, &lt;a
3030href="https://gohugo.io"&gt;hugo&lt;/a&gt;, &lt;a
3031href="https://github.com/icyphox/vite"&gt;vite&lt;/a&gt;), I decided to roll my
3032own. If you are more of the ‘show me the code’ kinda guy, &lt;a
3033href="https://github.com/nerdypepper/site"&gt;here&lt;/a&gt; you go.&lt;/p&gt;
1945&lt;h3 id="text-formatting"&gt;Text formatting&lt;/h3&gt; 3034&lt;h3 id="text-formatting"&gt;Text formatting&lt;/h3&gt;
1946&lt;p&gt;I chose to write in markdown, and convert to html with &lt;a href="https://kristaps.bsd.lv/lowdown/"&gt;lowdown&lt;/a&gt;.&lt;/p&gt; 3035&lt;p&gt;I chose to write in markdown, and convert to html with &lt;a
3036href="https://kristaps.bsd.lv/lowdown/"&gt;lowdown&lt;/a&gt;.&lt;/p&gt;
1947&lt;h3 id="directory-structure"&gt;Directory structure&lt;/h3&gt; 3037&lt;h3 id="directory-structure"&gt;Directory structure&lt;/h3&gt;
1948&lt;p&gt;I host my site on GitHub pages, so &lt;code&gt;docs/&lt;/code&gt; has to be the entry point. Markdown formatted posts go into &lt;code&gt;posts/&lt;/code&gt;, get converted into html, and end up in &lt;code&gt;docs/index.html&lt;/code&gt;, something like this:&lt;/p&gt; 3038&lt;p&gt;I host my site on GitHub pages, so &lt;code&gt;docs/&lt;/code&gt; has to be the
1949&lt;div class="sourceCode" id="cb1"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="va"&gt;posts&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="va"&gt;$(&lt;/span&gt;&lt;span class="fu"&gt;ls&lt;/span&gt; &lt;span class="at"&gt;-t&lt;/span&gt; ./posts&lt;span class="va"&gt;)&lt;/span&gt; &lt;span class="co"&gt;# chronological order!&lt;/span&gt;&lt;/span&gt; 3039entry point. Markdown formatted posts go into &lt;code&gt;posts/&lt;/code&gt;, get
3040converted into html, and end up in &lt;code&gt;docs/index.html&lt;/code&gt;,
3041something like this:&lt;/p&gt;
3042&lt;div class="sourceCode" id="cb1"&gt;&lt;pre
3043class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="va"&gt;posts&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="va"&gt;$(&lt;/span&gt;&lt;span class="fu"&gt;ls&lt;/span&gt; &lt;span class="at"&gt;-t&lt;/span&gt; ./posts&lt;span class="va"&gt;)&lt;/span&gt; &lt;span class="co"&gt;# chronological order!&lt;/span&gt;&lt;/span&gt;
1950&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;for&lt;/span&gt; f &lt;span class="kw"&gt;in&lt;/span&gt; &lt;span class="va"&gt;$posts&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt; &lt;span class="cf"&gt;do&lt;/span&gt;&lt;/span&gt; 3044&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;for&lt;/span&gt; f &lt;span class="kw"&gt;in&lt;/span&gt; &lt;span class="va"&gt;$posts&lt;/span&gt;&lt;span class="kw"&gt;;&lt;/span&gt; &lt;span class="cf"&gt;do&lt;/span&gt;&lt;/span&gt;
1951&lt;span id="cb1-3"&gt;&lt;a href="#cb1-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;file&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;./posts/&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$f&lt;/span&gt; &lt;span class="co"&gt;# `ls` mangled our file paths&lt;/span&gt;&lt;/span&gt; 3045&lt;span id="cb1-3"&gt;&lt;a href="#cb1-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;file&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;./posts/&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$f&lt;/span&gt; &lt;span class="co"&gt;# `ls` mangled our file paths&lt;/span&gt;&lt;/span&gt;
1952&lt;span id="cb1-4"&gt;&lt;a href="#cb1-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;generating post &lt;/span&gt;&lt;span class="va"&gt;$file&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; 3046&lt;span id="cb1-4"&gt;&lt;a href="#cb1-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;generating post &lt;/span&gt;&lt;span class="va"&gt;$file&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
@@ -1955,19 +3049,27 @@ Reading symbols from main... # yay!&lt;/code&gt;&lt;/pre&gt;
1955&lt;span id="cb1-7"&gt;&lt;a href="#cb1-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="at"&gt;-e&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;html&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;gt;&amp;gt;&lt;/span&gt; docs/index.html&lt;/span&gt; 3049&lt;span id="cb1-7"&gt;&lt;a href="#cb1-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="at"&gt;-e&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;html&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;gt;&amp;gt;&lt;/span&gt; docs/index.html&lt;/span&gt;
1956&lt;span id="cb1-8"&gt;&lt;a href="#cb1-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 3050&lt;span id="cb1-8"&gt;&lt;a href="#cb1-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="cf"&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1957&lt;h3 id="assets"&gt;Assets&lt;/h3&gt; 3051&lt;h3 id="assets"&gt;Assets&lt;/h3&gt;
1958&lt;p&gt;Most static site generators recommend dropping image assets into the site source itself. That does have it’s merits, but I prefer hosting images separately:&lt;/p&gt; 3052&lt;p&gt;Most static site generators recommend dropping image assets into the
1959&lt;div class="sourceCode" id="cb2"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# strip file extension&lt;/span&gt;&lt;/span&gt; 3053site source itself. That does have it’s merits, but I prefer hosting
3054images separately:&lt;/p&gt;
3055&lt;div class="sourceCode" id="cb2"&gt;&lt;pre
3056class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# strip file extension&lt;/span&gt;&lt;/span&gt;
1960&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="va"&gt;ext&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;${1&lt;/span&gt;&lt;span class="op"&gt;##&lt;/span&gt;&lt;span class="pp"&gt;*&lt;/span&gt;.&lt;span class="va"&gt;}&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; 3057&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="va"&gt;ext&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;${1&lt;/span&gt;&lt;span class="op"&gt;##&lt;/span&gt;&lt;span class="pp"&gt;*&lt;/span&gt;.&lt;span class="va"&gt;}&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
1961&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 3058&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1962&lt;span id="cb2-4"&gt;&lt;a href="#cb2-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# generate a random file name&lt;/span&gt;&lt;/span&gt; 3059&lt;span id="cb2-4"&gt;&lt;a href="#cb2-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# generate a random file name&lt;/span&gt;&lt;/span&gt;
1963&lt;span id="cb2-5"&gt;&lt;a href="#cb2-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="va"&gt;id&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="va"&gt;$(&lt;/span&gt; &lt;span class="fu"&gt;cat&lt;/span&gt; /dev/urandom &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;tr&lt;/span&gt; &lt;span class="at"&gt;-dc&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;a-zA-Z0-9&amp;#39;&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="ex"&gt;fold&lt;/span&gt; &lt;span class="at"&gt;-w&lt;/span&gt; 2 &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;head&lt;/span&gt; &lt;span class="at"&gt;-n&lt;/span&gt; 1 &lt;span class="va"&gt;)&lt;/span&gt;&lt;/span&gt; 3060&lt;span id="cb2-5"&gt;&lt;a href="#cb2-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="va"&gt;id&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="va"&gt;$(&lt;/span&gt; &lt;span class="fu"&gt;cat&lt;/span&gt; /dev/urandom &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;tr&lt;/span&gt; &lt;span class="at"&gt;-dc&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;a-zA-Z0-9&amp;#39;&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;fold&lt;/span&gt; &lt;span class="at"&gt;-w&lt;/span&gt; 2 &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;head&lt;/span&gt; &lt;span class="at"&gt;-n&lt;/span&gt; 1 &lt;span class="va"&gt;)&lt;/span&gt;&lt;/span&gt;
1964&lt;span id="cb2-6"&gt;&lt;a href="#cb2-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="va"&gt;id&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$id&lt;/span&gt;&lt;span class="st"&gt;.&lt;/span&gt;&lt;span class="va"&gt;$ext&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; 3061&lt;span id="cb2-6"&gt;&lt;a href="#cb2-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="va"&gt;id&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$id&lt;/span&gt;&lt;span class="st"&gt;.&lt;/span&gt;&lt;span class="va"&gt;$ext&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
1965&lt;span id="cb2-7"&gt;&lt;a href="#cb2-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt; 3062&lt;span id="cb2-7"&gt;&lt;a href="#cb2-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
1966&lt;span id="cb2-8"&gt;&lt;a href="#cb2-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# copy to my file host&lt;/span&gt;&lt;/span&gt; 3063&lt;span id="cb2-8"&gt;&lt;a href="#cb2-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# copy to my file host&lt;/span&gt;&lt;/span&gt;
1967&lt;span id="cb2-9"&gt;&lt;a href="#cb2-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;scp&lt;/span&gt; &lt;span class="at"&gt;-P&lt;/span&gt; 443 &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$1&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; emerald:files/&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$id&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; &lt;/span&gt; 3064&lt;span id="cb2-9"&gt;&lt;a href="#cb2-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;scp&lt;/span&gt; &lt;span class="at"&gt;-P&lt;/span&gt; 443 &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$1&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; emerald:files/&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$id&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; &lt;/span&gt;
1968&lt;span id="cb2-10"&gt;&lt;a href="#cb2-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://u.peppe.rs/&lt;/span&gt;&lt;span class="va"&gt;$id&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 3065&lt;span id="cb2-10"&gt;&lt;a href="#cb2-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;echo&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;https://u.peppe.rs/&lt;/span&gt;&lt;span class="va"&gt;$id&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
1969&lt;h3 id="templating"&gt;Templating&lt;/h3&gt; 3066&lt;h3 id="templating"&gt;Templating&lt;/h3&gt;
1970&lt;p&gt;&lt;a href="https://github.com/NerdyPepper/site/blob/master/generate.sh"&gt;&lt;code&gt;generate.sh&lt;/code&gt;&lt;/a&gt; brings the above bits and pieces together (with some extra cruft to avoid javascript). It uses &lt;code&gt;sed&lt;/code&gt; to produce nice titles from the file names (removes underscores, title-case), and &lt;code&gt;date(1)&lt;/code&gt; to add the date to each post listing!&lt;/p&gt;</description> 3067&lt;p&gt;&lt;a
3068href="https://github.com/NerdyPepper/site/blob/master/generate.sh"&gt;&lt;code&gt;generate.sh&lt;/code&gt;&lt;/a&gt;
3069brings the above bits and pieces together (with some extra cruft to
3070avoid javascript). It uses &lt;code&gt;sed&lt;/code&gt; to produce nice titles from
3071the file names (removes underscores, title-case), and
3072&lt;code&gt;date(1)&lt;/code&gt; to add the date to each post listing!&lt;/p&gt;</description>
1971<link>https://peppe.rs/posts/static_sites_with_bash/</link> 3073<link>https://peppe.rs/posts/static_sites_with_bash/</link>
1972<pubDate>Fri, 22 Nov 2019 18:30:00 +0000</pubDate> 3074<pubDate>Fri, 22 Nov 2019 18:30:00 +0000</pubDate>
1973<guid>https://peppe.rs/posts/static_sites_with_bash/</guid> 3075<guid>https://peppe.rs/posts/static_sites_with_bash/</guid>
@@ -1976,18 +3078,39 @@ Reading symbols from main... # yay!&lt;/code&gt;&lt;/pre&gt;
1976<title>My Setup</title> 3078<title>My Setup</title>
1977<description>&lt;p&gt;Decided to do one of these because everyone does one of these.&lt;/p&gt; 3079<description>&lt;p&gt;Decided to do one of these because everyone does one of these.&lt;/p&gt;
1978&lt;p&gt;&lt;img src="https://u.peppe.rs/Hb.png" /&gt;&lt;/p&gt; 3080&lt;p&gt;&lt;img src="https://u.peppe.rs/Hb.png" /&gt;&lt;/p&gt;
1979&lt;p&gt;My entire setup is managed with GNU &lt;code&gt;stow&lt;/code&gt;, making it easier to replicate on fresh installations. You can find my configuration files on &lt;a href="https://github.com/nerdypepper"&gt;GitHub&lt;/a&gt;.&lt;/p&gt; 3081&lt;p&gt;My entire setup is managed with GNU &lt;code&gt;stow&lt;/code&gt;, making it
1980&lt;p&gt;I run Void Linux (glibc) on my &lt;a href="https://store.hp.com/us/en/mdp/laptops/envy-13"&gt;HP Envy 13" (2018)&lt;/a&gt;. To keep things simple, I run a raw X session with &lt;code&gt;2bwm&lt;/code&gt; as my window manager, along with &lt;code&gt;dunst&lt;/code&gt; (notification daemon) and Sam’s &lt;a href="https://github.com/sdhand/compton"&gt;&lt;code&gt;compton&lt;/code&gt;&lt;/a&gt; (compositor) fork.&lt;/p&gt; 3082easier to replicate on fresh installations. You can find my
1981&lt;p&gt;I am a fan of GNU tools, so I use &lt;code&gt;bash&lt;/code&gt; as my shell, and &lt;code&gt;coreutils&lt;/code&gt; to manage files, archives, strings, paths etc. I edit files with &lt;code&gt;vim&lt;/code&gt;, chat with &lt;code&gt;weechat&lt;/code&gt;, listen to music with &lt;code&gt;cmus&lt;/code&gt;, monitor processes with &lt;code&gt;htop&lt;/code&gt;, manage sessions with &lt;code&gt;tmux&lt;/code&gt;, read pdfs in &lt;code&gt;zathura&lt;/code&gt;. I rarely ever leave the comfort of my terminal emulator, &lt;code&gt;urxvt&lt;/code&gt;.&lt;/p&gt; 3083configuration files on &lt;a
1982&lt;p&gt;Most of my academic typesetting is done with TeX, and compiled with &lt;code&gt;xelatex&lt;/code&gt;. Other &lt;em&gt;fun&lt;/em&gt; documents are made with GIMP :).&lt;/p&gt;</description> 3084href="https://github.com/nerdypepper"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
3085&lt;p&gt;I run Void Linux (glibc) on my &lt;a
3086href="https://store.hp.com/us/en/mdp/laptops/envy-13"&gt;HP Envy 13”
3087(2018)&lt;/a&gt;. To keep things simple, I run a raw X session with
3088&lt;code&gt;2bwm&lt;/code&gt; as my window manager, along with &lt;code&gt;dunst&lt;/code&gt;
3089(notification daemon) and Sam’s &lt;a
3090href="https://github.com/sdhand/compton"&gt;&lt;code&gt;compton&lt;/code&gt;&lt;/a&gt;
3091(compositor) fork.&lt;/p&gt;
3092&lt;p&gt;I am a fan of GNU tools, so I use &lt;code&gt;bash&lt;/code&gt; as my shell, and
3093&lt;code&gt;coreutils&lt;/code&gt; to manage files, archives, strings, paths etc. I
3094edit files with &lt;code&gt;vim&lt;/code&gt;, chat with &lt;code&gt;weechat&lt;/code&gt;, listen
3095to music with &lt;code&gt;cmus&lt;/code&gt;, monitor processes with
3096&lt;code&gt;htop&lt;/code&gt;, manage sessions with &lt;code&gt;tmux&lt;/code&gt;, read pdfs in
3097&lt;code&gt;zathura&lt;/code&gt;. I rarely ever leave the comfort of my terminal
3098emulator, &lt;code&gt;urxvt&lt;/code&gt;.&lt;/p&gt;
3099&lt;p&gt;Most of my academic typesetting is done with TeX, and compiled with
3100&lt;code&gt;xelatex&lt;/code&gt;. Other &lt;em&gt;fun&lt;/em&gt; documents are made with GIMP
3101:).&lt;/p&gt;</description>
1983<link>https://peppe.rs/posts/my_setup/</link> 3102<link>https://peppe.rs/posts/my_setup/</link>
1984<pubDate>Wed, 06 Nov 2019 18:30:00 +0000</pubDate> 3103<pubDate>Wed, 06 Nov 2019 18:30:00 +0000</pubDate>
1985<guid>https://peppe.rs/posts/my_setup/</guid> 3104<guid>https://peppe.rs/posts/my_setup/</guid>
1986</item> 3105</item>
1987<item> 3106<item>
1988<title>WPA Woes</title> 3107<title>WPA Woes</title>
1989<description>&lt;p&gt;I finally got around to installing Void GNU/Linux on my main computer. Rolling release, non-systemd, need I say more?&lt;/p&gt; 3108<description>&lt;p&gt;I finally got around to installing Void GNU/Linux on my main
1990&lt;p&gt;As with all GNU/Linux distributions, wireless networks had me in a fix. If you can see this post, it means I’ve managed to get online. It turns out, &lt;code&gt;wpa_supplicant&lt;/code&gt; was detecting the wrong interface by default (does it ever select the right one?). Let us fix that:&lt;/p&gt; 3109computer. Rolling release, non-systemd, need I say more?&lt;/p&gt;
3110&lt;p&gt;As with all GNU/Linux distributions, wireless networks had me in a
3111fix. If you can see this post, it means I’ve managed to get online. It
3112turns out, &lt;code&gt;wpa_supplicant&lt;/code&gt; was detecting the wrong interface
3113by default (does it ever select the right one?). Let us fix that:&lt;/p&gt;
1991&lt;pre&gt;&lt;code&gt;$ sudo rm -r /var/service/wpa_supplicant 3114&lt;pre&gt;&lt;code&gt;$ sudo rm -r /var/service/wpa_supplicant
1992$ sudo killall dhcpcd&lt;/code&gt;&lt;/pre&gt; 3115$ sudo killall dhcpcd&lt;/code&gt;&lt;/pre&gt;
1993&lt;p&gt;What is the right interface though?&lt;/p&gt; 3116&lt;p&gt;What is the right interface though?&lt;/p&gt;
@@ -1995,7 +3118,8 @@ $ sudo killall dhcpcd&lt;/code&gt;&lt;/pre&gt;
1995 ... 3118 ...
1996 Interface wlp2s0 3119 Interface wlp2s0
1997 ...&lt;/code&gt;&lt;/pre&gt; 3120 ...&lt;/code&gt;&lt;/pre&gt;
1998&lt;p&gt;Aha! Let us run &lt;code&gt;wpa_supplicant&lt;/code&gt; on that interface, as a background process:&lt;/p&gt; 3121&lt;p&gt;Aha! Let us run &lt;code&gt;wpa_supplicant&lt;/code&gt; on that interface, as a
3122background process:&lt;/p&gt;
1999&lt;pre&gt;&lt;code&gt;$ sudo wpa_supplicant -B -i wlp2s0 -c /etc/wpa_supplicant/wpa_supplicant.conf 3123&lt;pre&gt;&lt;code&gt;$ sudo wpa_supplicant -B -i wlp2s0 -c /etc/wpa_supplicant/wpa_supplicant.conf
2000$ sudo dhcpcd -B wlp2s0 3124$ sudo dhcpcd -B wlp2s0
2001$ ping google.com 3125$ ping google.com
@@ -2016,41 +3140,94 @@ $ sudo sv restart dhcpcd&lt;/code&gt;&lt;/pre&gt;</description>
2016</item> 3140</item>
2017<item> 3141<item>
2018<title>Bye Bye BDFs</title> 3142<title>Bye Bye BDFs</title>
2019<description>&lt;p&gt;Glyph Bitmap Distribution Format is no more, as the creators of &lt;a href="https://pango.org"&gt;Pango&lt;/a&gt;, one of the most widely used text rendering libraries, &lt;a href="https://blogs.gnome.org/mclasen/2019/05/25/pango-future-directions/"&gt;announced&lt;/a&gt; their plans for Pango 1.44.&lt;/p&gt; 3143<description>&lt;p&gt;Glyph Bitmap Distribution Format is no more, as the creators of &lt;a
2020&lt;p&gt;Until recently, Pango used FreeType to draw fonts. They will be moving over to &lt;a href="https://harfbuzz.org"&gt;Harfbuzz&lt;/a&gt;, an evolution of FreeType.&lt;/p&gt; 3144href="https://pango.org"&gt;Pango&lt;/a&gt;, one of the most widely used text
3145rendering libraries, &lt;a
3146href="https://blogs.gnome.org/mclasen/2019/05/25/pango-future-directions/"&gt;announced&lt;/a&gt;
3147their plans for Pango 1.44.&lt;/p&gt;
3148&lt;p&gt;Until recently, Pango used FreeType to draw fonts. They will be
3149moving over to &lt;a href="https://harfbuzz.org"&gt;Harfbuzz&lt;/a&gt;, an evolution
3150of FreeType.&lt;/p&gt;
2021&lt;p&gt;&lt;em&gt;Why?&lt;/em&gt;&lt;/p&gt; 3151&lt;p&gt;&lt;em&gt;Why?&lt;/em&gt;&lt;/p&gt;
2022&lt;p&gt;In short, FreeType was hard to work with. It required complex logic, and provided no advantage over Harfbuzz (other than being able to fetch opentype metrics with ease).&lt;/p&gt; 3152&lt;p&gt;In short, FreeType was hard to work with. It required complex logic,
2023&lt;p&gt;Upgrading to Pango v1.44 will break your GTK applications (if you use a &lt;code&gt;bdf&lt;/code&gt;/&lt;code&gt;pcf&lt;/code&gt; bitmap font). Harfbuzz &lt;em&gt;does&lt;/em&gt; support bitmap-only OpenType fonts, &lt;code&gt;otb&lt;/code&gt;s. Convert your existing fonts over to &lt;code&gt;otb&lt;/code&gt;s using &lt;a href="https://fontforge.github.io"&gt;FontForge&lt;/a&gt;. It is to be noted that applications such as &lt;code&gt;xterm&lt;/code&gt; and &lt;code&gt;rxvt&lt;/code&gt; use &lt;code&gt;xft&lt;/code&gt; (X FreeType) to render fonts, and will remain unaffected by the update.&lt;/p&gt; 3153and provided no advantage over Harfbuzz (other than being able to fetch
2024&lt;p&gt;Both &lt;a href="https://github.com/nerdypepper/scientifica"&gt;scientifica&lt;/a&gt; and &lt;a href="https://github.com/nerdypepper/curie"&gt;curie&lt;/a&gt; will soon ship with bitmap-only OpenType font formats.&lt;/p&gt;</description> 3154opentype metrics with ease).&lt;/p&gt;
3155&lt;p&gt;Upgrading to Pango v1.44 will break your GTK applications (if you use
3156a &lt;code&gt;bdf&lt;/code&gt;/&lt;code&gt;pcf&lt;/code&gt; bitmap font). Harfbuzz &lt;em&gt;does&lt;/em&gt;
3157support bitmap-only OpenType fonts, &lt;code&gt;otb&lt;/code&gt;s. Convert your
3158existing fonts over to &lt;code&gt;otb&lt;/code&gt;s using &lt;a
3159href="https://fontforge.github.io"&gt;FontForge&lt;/a&gt;. It is to be noted that
3160applications such as &lt;code&gt;xterm&lt;/code&gt; and &lt;code&gt;rxvt&lt;/code&gt; use
3161&lt;code&gt;xft&lt;/code&gt; (X FreeType) to render fonts, and will remain
3162unaffected by the update.&lt;/p&gt;
3163&lt;p&gt;Both &lt;a
3164href="https://github.com/nerdypepper/scientifica"&gt;scientifica&lt;/a&gt; and &lt;a
3165href="https://github.com/nerdypepper/curie"&gt;curie&lt;/a&gt; will soon ship
3166with bitmap-only OpenType font formats.&lt;/p&gt;</description>
2025<link>https://peppe.rs/posts/bye_bye_BDFs/</link> 3167<link>https://peppe.rs/posts/bye_bye_BDFs/</link>
2026<pubDate>Wed, 07 Aug 2019 17:26:00 +0000</pubDate> 3168<pubDate>Wed, 07 Aug 2019 17:26:00 +0000</pubDate>
2027<guid>https://peppe.rs/posts/bye_bye_BDFs/</guid> 3169<guid>https://peppe.rs/posts/bye_bye_BDFs/</guid>
2028</item> 3170</item>
2029<item> 3171<item>
2030<title>Onivim Sucks</title> 3172<title>Onivim Sucks</title>
2031<description>&lt;p&gt;&lt;a href="https://v2.onivim.io"&gt;Onivim&lt;/a&gt; is a ‘modern modal editor’, combining fancy interface and language features with vim-style modal editing. What’s wrong you ask?&lt;/p&gt; 3173<description>&lt;p&gt;&lt;a href="https://v2.onivim.io"&gt;Onivim&lt;/a&gt; is a ‘modern modal editor’,
2032&lt;p&gt;Apart from &lt;a href="https://github.com/onivim/oni2/issues/550"&gt;buggy syntax highlighting&lt;/a&gt;, &lt;a href="https://github.com/onivim/oni2/issues/519"&gt;broken scrolling&lt;/a&gt; and &lt;a href="https://github.com/onivim/oni2/issues?q=is%3Aissue+label%3A%22daily+editor+blocker%22+is%3Aopen"&gt;others&lt;/a&gt;, Onivim is &lt;strong&gt;proprietary&lt;/strong&gt; software. It is licensed under a commercial &lt;a href="https://github.com/onivim/oni1/blob/master/Outrun-Labs-EULA-v1.1.md"&gt;end user agreement license&lt;/a&gt;, which prohibits redistribution in both object code and source code formats.&lt;/p&gt; 3174combining fancy interface and language features with vim-style modal
2033&lt;p&gt;Onivim’s core editor logic (bits that belong to vim), have been separated from the interface, into &lt;a href="https://github.com/onivim/libvim"&gt;libvim&lt;/a&gt;. libvim is licensed under MIT, which means, this ‘extension’ of vim is perfectly in adherence to &lt;a href="http://vimdoc.sourceforge.net/htmldoc/uganda.html#license"&gt;vim’s license text&lt;/a&gt;! Outrun Labs are exploiting this loophole (distributing vim as a library) to commercialize Onivim.&lt;/p&gt; 3175editing. What’s wrong you ask?&lt;/p&gt;
2034&lt;p&gt;Onivim’s source code is available on &lt;a href="https://github.com/onivim/oni2"&gt;GitHub&lt;/a&gt;. They do mention that the source code trickles down to the &lt;a href="https://github.com/onivim/oni2-mit"&gt;oni2-mit&lt;/a&gt; repository, which (not yet) contains MIT-licensed code, &lt;strong&gt;18 months&lt;/strong&gt; after each commit to the original repository.&lt;/p&gt; 3176&lt;p&gt;Apart from &lt;a href="https://github.com/onivim/oni2/issues/550"&gt;buggy
2035&lt;p&gt;Want to contribute to Onivim? Don’t. They make a profit out of your contributions. Currently, Onivim is priced at $19.99, ‘pre-alpha’ pricing which is 80% off the final price! If you are on the lookout for an editor, I would suggest using &lt;a href="https://vim.org"&gt;Vim&lt;/a&gt;, charity ware that actually works, and costs $100 lesser.&lt;/p&gt;</description> 3177syntax highlighting&lt;/a&gt;, &lt;a
3178href="https://github.com/onivim/oni2/issues/519"&gt;broken scrolling&lt;/a&gt;
3179and &lt;a
3180href="https://github.com/onivim/oni2/issues?q=is%3Aissue+label%3A%22daily+editor+blocker%22+is%3Aopen"&gt;others&lt;/a&gt;,
3181Onivim is &lt;strong&gt;proprietary&lt;/strong&gt; software. It is licensed under a
3182commercial &lt;a
3183href="https://github.com/onivim/oni1/blob/master/Outrun-Labs-EULA-v1.1.md"&gt;end
3184user agreement license&lt;/a&gt;, which prohibits redistribution in both
3185object code and source code formats.&lt;/p&gt;
3186&lt;p&gt;Onivim’s core editor logic (bits that belong to vim), have been
3187separated from the interface, into &lt;a
3188href="https://github.com/onivim/libvim"&gt;libvim&lt;/a&gt;. libvim is licensed
3189under MIT, which means, this ‘extension’ of vim is perfectly in
3190adherence to &lt;a
3191href="http://vimdoc.sourceforge.net/htmldoc/uganda.html#license"&gt;vim’s
3192license text&lt;/a&gt;! Outrun Labs are exploiting this loophole (distributing
3193vim as a library) to commercialize Onivim.&lt;/p&gt;
3194&lt;p&gt;Onivim’s source code is available on &lt;a
3195href="https://github.com/onivim/oni2"&gt;GitHub&lt;/a&gt;. They do mention that
3196the source code trickles down to the &lt;a
3197href="https://github.com/onivim/oni2-mit"&gt;oni2-mit&lt;/a&gt; repository, which
3198(not yet) contains MIT-licensed code, &lt;strong&gt;18 months&lt;/strong&gt; after
3199each commit to the original repository.&lt;/p&gt;
3200&lt;p&gt;Want to contribute to Onivim? Don’t. They make a profit out of your
3201contributions. Currently, Onivim is priced at $19.99, ‘pre-alpha’
3202pricing which is 80% off the final price! If you are on the lookout for
3203an editor, I would suggest using &lt;a href="https://vim.org"&gt;Vim&lt;/a&gt;,
3204charity ware that actually works, and costs $100 lesser.&lt;/p&gt;</description>
2036<link>https://peppe.rs/posts/onivim_sucks/</link> 3205<link>https://peppe.rs/posts/onivim_sucks/</link>
2037<pubDate>Fri, 02 Aug 2019 16:32:00 +0000</pubDate> 3206<pubDate>Fri, 02 Aug 2019 16:32:00 +0000</pubDate>
2038<guid>https://peppe.rs/posts/onivim_sucks/</guid> 3207<guid>https://peppe.rs/posts/onivim_sucks/</guid>
2039</item> 3208</item>
2040<item> 3209<item>
2041<title>Bash Harder With Vim</title> 3210<title>Bash Harder With Vim</title>
2042<description>&lt;p&gt;Bash is tricky, don’t let your editor get in your way. Here’s a couple of neat additions you could make to your &lt;code&gt;vimrc&lt;/code&gt; for a better shell programming experience.&lt;/p&gt; 3211<description>&lt;p&gt;Bash is tricky, don’t let your editor get in your way. Here’s a
3212couple of neat additions you could make to your &lt;code&gt;vimrc&lt;/code&gt; for a
3213better shell programming experience.&lt;/p&gt;
2043&lt;h3 id="man-pages-inside-vim"&gt;Man pages inside vim&lt;/h3&gt; 3214&lt;h3 id="man-pages-inside-vim"&gt;Man pages inside vim&lt;/h3&gt;
2044&lt;p&gt;Source this script to get started:&lt;/p&gt; 3215&lt;p&gt;Source this script to get started:&lt;/p&gt;
2045&lt;pre&gt;&lt;code&gt;runtime ftplugin/man.vim&lt;/code&gt;&lt;/pre&gt; 3216&lt;pre&gt;&lt;code&gt;runtime ftplugin/man.vim&lt;/code&gt;&lt;/pre&gt;
2046&lt;p&gt;Now, you can open manpages inside vim with &lt;code&gt;:Man&lt;/code&gt;! It adds nicer syntax highlighting and the ability to jump around with &lt;code&gt;Ctrl-]&lt;/code&gt; and &lt;code&gt;Ctrl-T&lt;/code&gt;.&lt;/p&gt; 3217&lt;p&gt;Now, you can open manpages inside vim with &lt;code&gt;:Man&lt;/code&gt;! It adds
2047&lt;p&gt;By default, the manpage is opened in a horizontal split, I prefer using a new tab:&lt;/p&gt; 3218nicer syntax highlighting and the ability to jump around with
3219&lt;code&gt;Ctrl-]&lt;/code&gt; and &lt;code&gt;Ctrl-T&lt;/code&gt;.&lt;/p&gt;
3220&lt;p&gt;By default, the manpage is opened in a horizontal split, I prefer
3221using a new tab:&lt;/p&gt;
2048&lt;pre&gt;&lt;code&gt;let g:ft_man_open_mode = &amp;#39;tab&amp;#39;&lt;/code&gt;&lt;/pre&gt; 3222&lt;pre&gt;&lt;code&gt;let g:ft_man_open_mode = &amp;#39;tab&amp;#39;&lt;/code&gt;&lt;/pre&gt;
2049&lt;h3 id="scratchpad-to-test-your-commands"&gt;Scratchpad to test your commands&lt;/h3&gt; 3223&lt;h3 id="scratchpad-to-test-your-commands"&gt;Scratchpad to test your
2050&lt;p&gt;I often test my &lt;code&gt;sed&lt;/code&gt; substitutions, here is a sample from the script used to generate this site:&lt;/p&gt; 3224commands&lt;/h3&gt;
3225&lt;p&gt;I often test my &lt;code&gt;sed&lt;/code&gt; substitutions, here is a sample from
3226the script used to generate this site:&lt;/p&gt;
2051&lt;pre&gt;&lt;code&gt;# a substitution to convert snake_case to Title Case With Spaces 3227&lt;pre&gt;&lt;code&gt;# a substitution to convert snake_case to Title Case With Spaces
2052echo &amp;quot;$1&amp;quot; | sed -E -e &amp;quot;s/\..+$//g&amp;quot; -e &amp;quot;s/_(.)/ \u\1/g&amp;quot; -e &amp;quot;s/^(.)/\u\1/g&amp;quot;&lt;/code&gt;&lt;/pre&gt; 3228echo &amp;quot;$1&amp;quot; | sed -E -e &amp;quot;s/\..+$//g&amp;quot; -e &amp;quot;s/_(.)/ \u\1/g&amp;quot; -e &amp;quot;s/^(.)/\u\1/g&amp;quot;&lt;/code&gt;&lt;/pre&gt;
2053&lt;p&gt;Instead of dropping into a new shell, just test it out directly from vim!&lt;/p&gt; 3229&lt;p&gt;Instead of dropping into a new shell, just test it out directly from
3230vim!&lt;/p&gt;
2054&lt;ul&gt; 3231&lt;ul&gt;
2055&lt;li&gt;Yank the line into a register:&lt;/li&gt; 3232&lt;li&gt;Yank the line into a register:&lt;/li&gt;
2056&lt;/ul&gt; 3233&lt;/ul&gt;
@@ -2079,14 +3256,24 @@ Press ENTER or type command to continue&lt;/code&gt;&lt;/pre&gt;</description>
2079</item> 3256</item>
2080<item> 3257<item>
2081<title>Hold Position!</title> 3258<title>Hold Position!</title>
2082<description>&lt;p&gt;Often times, when I run a vim command that makes “big” changes to a file (a macro or a &lt;code&gt;:vimgrep&lt;/code&gt; command) I lose my original position and feel disoriented.&lt;/p&gt; 3259<description>&lt;p&gt;Often times, when I run a vim command that makes “big” changes to a
3260file (a macro or a &lt;code&gt;:vimgrep&lt;/code&gt; command) I lose my original
3261position and feel disoriented.&lt;/p&gt;
2083&lt;p&gt;&lt;em&gt;Save position with &lt;code&gt;winsaveview()&lt;/code&gt;!&lt;/em&gt;&lt;/p&gt; 3262&lt;p&gt;&lt;em&gt;Save position with &lt;code&gt;winsaveview()&lt;/code&gt;!&lt;/em&gt;&lt;/p&gt;
2084&lt;p&gt;The &lt;code&gt;winsaveview()&lt;/code&gt; command returns a &lt;code&gt;Dictionary&lt;/code&gt; that contains information about the view of the current window. This includes the cursor line number, cursor coloumn, the top most line in the window and a couple of other values, none of which concern us.&lt;/p&gt; 3263&lt;p&gt;The &lt;code&gt;winsaveview()&lt;/code&gt; command returns a
2085&lt;p&gt;Before running our command (one that jumps around the buffer, a lot), we save our view, and restore it once its done, with &lt;code&gt;winrestview&lt;/code&gt;.&lt;/p&gt; 3264&lt;code&gt;Dictionary&lt;/code&gt; that contains information about the view of the
3265current window. This includes the cursor line number, cursor coloumn,
3266the top most line in the window and a couple of other values, none of
3267which concern us.&lt;/p&gt;
3268&lt;p&gt;Before running our command (one that jumps around the buffer, a lot),
3269we save our view, and restore it once its done, with
3270&lt;code&gt;winrestview&lt;/code&gt;.&lt;/p&gt;
2086&lt;pre&gt;&lt;code&gt;let view = winsaveview() 3271&lt;pre&gt;&lt;code&gt;let view = winsaveview()
2087s/\s\+$//gc &amp;quot; find and (confirm) replace trailing blanks 3272s/\s\+$//gc &amp;quot; find and (confirm) replace trailing blanks
2088winrestview(view) &amp;quot; restore our original view!&lt;/code&gt;&lt;/pre&gt; 3273winrestview(view) &amp;quot; restore our original view!&lt;/code&gt;&lt;/pre&gt;
2089&lt;p&gt;It might seem a little overkill in the above example, just use `` (double backticks) instead, but it comes in handy when you run your file through heavier filtering.&lt;/p&gt;</description> 3274&lt;p&gt;It might seem a little overkill in the above example, just use ``
3275(double backticks) instead, but it comes in handy when you run your file
3276through heavier filtering.&lt;/p&gt;</description>
2090<link>https://peppe.rs/posts/hold_position!/</link> 3277<link>https://peppe.rs/posts/hold_position!/</link>
2091<pubDate>Tue, 30 Jul 2019 14:45:00 +0000</pubDate> 3278<pubDate>Tue, 30 Jul 2019 14:45:00 +0000</pubDate>
2092<guid>https://peppe.rs/posts/hold_position!/</guid> 3279<guid>https://peppe.rs/posts/hold_position!/</guid>
@@ -2095,7 +3282,8 @@ winrestview(view) &amp;quot; restore our original view!&lt;/code&gt;&lt;/
2095<title>Get Better At Yanking And Putting In Vim</title> 3282<title>Get Better At Yanking And Putting In Vim</title>
2096<description>&lt;p&gt;a couple of nifty tricks to help you copy-paste better:&lt;/p&gt; 3283<description>&lt;p&gt;a couple of nifty tricks to help you copy-paste better:&lt;/p&gt;
2097&lt;ol type="1"&gt; 3284&lt;ol type="1"&gt;
2098&lt;li&gt;&lt;p&gt;reselecting previously selected text (i use this to fix botched selections):&lt;/p&gt; 3285&lt;li&gt;&lt;p&gt;reselecting previously selected text (i use this to fix botched
3286selections):&lt;/p&gt;
2099&lt;pre&gt;&lt;code&gt;gv &amp;quot; :h gv for more 3287&lt;pre&gt;&lt;code&gt;gv &amp;quot; :h gv for more
2100 &amp;quot; you can use `o` in visual mode to go to the `Other` end of the selection 3288 &amp;quot; you can use `o` in visual mode to go to the `Other` end of the selection
2101 &amp;quot; use a motion to fix the selection&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt; 3289 &amp;quot; use a motion to fix the selection&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
diff --git a/docs/posts/SDL2_devlog/index.html b/docs/posts/SDL2_devlog/index.html
index 0e76515..e31f399 100644
--- a/docs/posts/SDL2_devlog/index.html
+++ b/docs/posts/SDL2_devlog/index.html
@@ -42,25 +42,60 @@
42 SDL2 Devlog 42 SDL2 Devlog
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>I have been working on an editor for the <a href="https://git.peppe.rs/graphics/obi/about">One Bit Image</a> file format in Rust and SDL2. This entry in my blog follows my progress on the editor. The days are listed in reverse chronological order, begin from the bottom, if this is your first time on this page.</p> 45 <p>I have been working on an editor for the <a
46href="https://git.peppe.rs/graphics/obi/about">One Bit Image</a> file
47format in Rust and SDL2. This entry in my blog follows my progress on
48the editor. The days are listed in reverse chronological order, begin
49from the bottom, if this is your first time on this page.</p>
46<h3 id="day-20">Day 20</h3> 50<h3 id="day-20">Day 20</h3>
47<p>More <code>lisp</code> stuff! I added a new brush, for rectangular selections. While selection doesn’t do much on its own, the selected area can be passed onto a <code>lisp</code> procedure, for example, a procedure to draw horizontal black and white lines:</p> 51<p>More <code>lisp</code> stuff! I added a new brush, for rectangular
52selections. While selection doesn’t do much on its own, the selected
53area can be passed onto a <code>lisp</code> procedure, for example, a
54procedure to draw horizontal black and white lines:</p>
48<figure> 55<figure>
49<video src="https://u.peppe.rs/frU.mp4" controls=""><a href="https://u.peppe.rs/frU.mp4">Day 20</a></video><figcaption aria-hidden="true">Day 20</figcaption> 56<video src="https://u.peppe.rs/frU.mp4" controls=""><a
57href="https://u.peppe.rs/frU.mp4">Day 20</a></video>
58<figcaption aria-hidden="true">Day 20</figcaption>
50</figure> 59</figure>
51<h3 id="day-19">Day 19</h3> 60<h3 id="day-19">Day 19</h3>
52<p>Attempted <a href="https://peppe.rs/art/conduit.png">some isometric art</a> within the editor. The angles displayed alongside the line brush are handly, however, having only a rectangular grid did not help. I implemented an isometric grid today. Isometric grids in pixel art differ in that the tangent of the isometric angle is exactly 0.5! For every pixel down, you go exactly two pixels sideways. The math works out really well in the drawing procedures too, dealing with floating points is a pain.</p> 61<p>Attempted <a href="https://peppe.rs/art/conduit.png">some isometric
62art</a> within the editor. The angles displayed alongside the line brush
63are handly, however, having only a rectangular grid did not help. I
64implemented an isometric grid today. Isometric grids in pixel art differ
65in that the tangent of the isometric angle is exactly 0.5! For every
66pixel down, you go exactly two pixels sideways. The math works out
67really well in the drawing procedures too, dealing with floating points
68is a pain.</p>
53<figure> 69<figure>
54<img src="https://u.peppe.rs/1Kb.png" alt="Day 19" /><figcaption aria-hidden="true">Day 19</figcaption> 70<img src="https://u.peppe.rs/1Kb.png" alt="Day 19" />
71<figcaption aria-hidden="true">Day 19</figcaption>
55</figure> 72</figure>
56<h3 id="day-18">Day 18</h3> 73<h3 id="day-18">Day 18</h3>
57<p>I added basic support for guides, they can be added and activated from the <code>lisp</code> REPL. Another long standing improvement I wanted to make was reworking the pixmap drawing procedure. The old procedure draws a square for each pixel in the pixmap, coloured according to its value in the pixmap. Naturally, this means, for an <strong>NxN</strong> pixmap, there are <strong>N²</strong> calls to SDL! I reworked this procedure to compress each line of the pixmap using RLE (run length encoding), and call out to SDL for each run in the line. This drastically improved drawing speeds on larger grids. The following is a comparison between the two procedures, the leftmost picture is the rendered image, the middle picture is the optimized drawing procedure (draws each run instead of pixel), and the right most picture is the primitive drawing procedure (draws each pixel):</p> 74<p>I added basic support for guides, they can be added and activated
75from the <code>lisp</code> REPL. Another long standing improvement I
76wanted to make was reworking the pixmap drawing procedure. The old
77procedure draws a square for each pixel in the pixmap, coloured
78according to its value in the pixmap. Naturally, this means, for an
79<strong>NxN</strong> pixmap, there are <strong>N²</strong> calls to SDL!
80I reworked this procedure to compress each line of the pixmap using RLE
81(run length encoding), and call out to SDL for each run in the line.
82This drastically improved drawing speeds on larger grids. The following
83is a comparison between the two procedures, the leftmost picture is the
84rendered image, the middle picture is the optimized drawing procedure
85(draws each run instead of pixel), and the right most picture is the
86primitive drawing procedure (draws each pixel):</p>
58<figure> 87<figure>
59<img src="https://u.peppe.rs/U4B.png" alt="Day 18" /><figcaption aria-hidden="true">Day 18</figcaption> 88<img src="https://u.peppe.rs/U4B.png" alt="Day 18" />
89<figcaption aria-hidden="true">Day 18</figcaption>
60</figure> 90</figure>
61<h3 id="day-17">Day 17</h3> 91<h3 id="day-17">Day 17</h3>
62<p>I decided to give the text-only statusline a touch up, by adding a active color and dither level preview. Aligning the “widget” to the right of statusline involved a lot more than I thought, so I created a ghetto CSS-like rectangle placement system to position containers inside containers:</p> 92<p>I decided to give the text-only statusline a touch up, by adding a
63<div class="sourceCode" id="cb1"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co">// roughly something like this</span></span> 93active color and dither level preview. Aligning the “widget” to the
94right of statusline involved a lot more than I thought, so I created a
95ghetto CSS-like rectangle placement system to position containers inside
96containers:</p>
97<div class="sourceCode" id="cb1"><pre
98class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co">// roughly something like this</span></span>
64<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> statusline <span class="op">=</span> </span> 99<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> statusline <span class="op">=</span> </span>
65<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="pp">Container::</span>new(<span class="pp">Offset::</span>Left(<span class="dv">0</span>)<span class="op">,</span> <span class="pp">Offset::</span>Bottom(<span class="dv">40</span>))</span> 100<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="pp">Container::</span>new(<span class="pp">Offset::</span>Left(<span class="dv">0</span>)<span class="op">,</span> <span class="pp">Offset::</span>Bottom(<span class="dv">40</span>))</span>
66<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>width(<span class="pp">Size::</span>Max)</span> 101<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>width(<span class="pp">Size::</span>Max)</span>
@@ -77,14 +112,20 @@
77<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>)<span class="op">;</span></span></code></pre></div> 112<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>)<span class="op">;</span></span></code></pre></div>
78<p>The result (brush preview on the bottom right):</p> 113<p>The result (brush preview on the bottom right):</p>
79<figure> 114<figure>
80<video src="https://u.peppe.rs/OtU.mp4" controls=""><a href="https://u.peppe.rs/OtU.mp4">Day 17</a></video><figcaption aria-hidden="true">Day 17</figcaption> 115<video src="https://u.peppe.rs/OtU.mp4" controls=""><a
116href="https://u.peppe.rs/OtU.mp4">Day 17</a></video>
117<figcaption aria-hidden="true">Day 17</figcaption>
81</figure> 118</figure>
82<h3 id="day-16">Day 16</h3> 119<h3 id="day-16">Day 16</h3>
83<p>The embedded lisp is coming along nicely, users can load a custom <code>rc.lisp</code>, which is evaluated on startup. To disable to grid on start, for example:</p> 120<p>The embedded lisp is coming along nicely, users can load a custom
84<div class="sourceCode" id="cb2"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co">;;; rc.lisp</span></span> 121<code>rc.lisp</code>, which is evaluated on startup. To disable to grid
122on start, for example:</p>
123<div class="sourceCode" id="cb2"><pre
124class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co">;;; rc.lisp</span></span>
85<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>(toggle-grid)</span></code></pre></div> 125<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>(toggle-grid)</span></code></pre></div>
86<p>Some aliases to switch between brushes:</p> 126<p>Some aliases to switch between brushes:</p>
87<div class="sourceCode" id="cb3"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">;;; rc.lisp</span></span> 127<div class="sourceCode" id="cb3"><pre
128class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">;;; rc.lisp</span></span>
88<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>(<span class="ex">define</span><span class="fu"> </span>(brush kind)</span> 129<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>(<span class="ex">define</span><span class="fu"> </span>(brush kind)</span>
89<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a> (<span class="kw">cond</span></span> 130<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a> (<span class="kw">cond</span></span>
90<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> ((<span class="kw">eq?</span> kind &#39;f) (brush-fill))</span> 131<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> ((<span class="kw">eq?</span> kind &#39;f) (brush-fill))</span>
@@ -92,90 +133,195 @@
92<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a> ((<span class="kw">eq?</span> kind &#39;l) (brush-line))</span> 133<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a> ((<span class="kw">eq?</span> kind &#39;l) (brush-line))</span>
93<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> ((<span class="kw">eq?</span> kind &#39;l+) (brush-line-extend))</span> 134<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> ((<span class="kw">eq?</span> kind &#39;l+) (brush-line-extend))</span>
94<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a> (<span class="kw">else</span> (brush-circle))))</span></code></pre></div> 135<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a> (<span class="kw">else</span> (brush-circle))))</span></code></pre></div>
95<p>The following script draws a straight line along a given axis, at a given distance from the canvas boundary:</p> 136<p>The following script draws a straight line along a given axis, at a
137given distance from the canvas boundary:</p>
96<figure> 138<figure>
97<video src="https://u.peppe.rs/b3i.mp4" controls=""><a href="https://u.peppe.rs/b3i.mp4">Day 16</a></video><figcaption aria-hidden="true">Day 16</figcaption> 139<video src="https://u.peppe.rs/b3i.mp4" controls=""><a
140href="https://u.peppe.rs/b3i.mp4">Day 16</a></video>
141<figcaption aria-hidden="true">Day 16</figcaption>
98</figure> 142</figure>
99<h3 id="day-15">Day 15</h3> 143<h3 id="day-15">Day 15</h3>
100<p>I began writing a standard library for the lisp, in lisp. It includes basic list operations: <code>car</code>, <code>cdr</code>, <code>null?</code>, <code>list</code>, higher order functions: <code>map</code>, <code>filter</code>, <code>fold</code>:</p> 144<p>I began writing a standard library for the lisp, in lisp. It includes
101<div class="sourceCode" id="cb4"><pre class="sourceCode lisp"><code class="sourceCode commonlisp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>(define (member? item ls)</span> 145basic list operations: <code>car</code>, <code>cdr</code>,
146<code>null?</code>, <code>list</code>, higher order functions:
147<code>map</code>, <code>filter</code>, <code>fold</code>:</p>
148<div class="sourceCode" id="cb4"><pre
149class="sourceCode lisp"><code class="sourceCode commonlisp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>(define (member? item ls)</span>
102<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> (fold <span class="dv">#f</span></span> 150<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> (fold <span class="dv">#f</span></span>
103<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a> (<span class="kw">lambda</span> (acc x) (<span class="kw">or</span> acc (eq? item x)))</span> 151<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a> (<span class="kw">lambda</span> (acc x) (<span class="kw">or</span> acc (eq? item x)))</span>
104<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a> ls))</span></code></pre></div> 152<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a> ls))</span></code></pre></div>
105<h3 id="day-14">Day 14</h3> 153<h3 id="day-14">Day 14</h3>
106<p>I attempted a <a href="https://peppe.rs/art/ramen_noodles.png">small art piece</a> using the editor, while it was largely usable, I felt a certain lack of feedback. The brushes just didn’t relay as much info as I’d have liked, for example, the approximate points of the line or the angle made by the line against the x-axis. Unfortunately, the existing infrastructure around brushes and line drawing didn’t easily allow for this either. I went ahead and reimplemented brushes, and added a new flood fill brush too:</p> 154<p>I attempted a <a href="https://peppe.rs/art/ramen_noodles.png">small
155art piece</a> using the editor, while it was largely usable, I felt a
156certain lack of feedback. The brushes just didn’t relay as much info as
157I’d have liked, for example, the approximate points of the line or the
158angle made by the line against the x-axis. Unfortunately, the existing
159infrastructure around brushes and line drawing didn’t easily allow for
160this either. I went ahead and reimplemented brushes, and added a new
161flood fill brush too:</p>
107<figure> 162<figure>
108<video src="https://u.peppe.rs/8q.mp4" controls=""><a href="https://u.peppe.rs/8q.mp4">Day 14</a></video><figcaption aria-hidden="true">Day 14</figcaption> 163<video src="https://u.peppe.rs/8q.mp4" controls=""><a
164href="https://u.peppe.rs/8q.mp4">Day 14</a></video>
165<figcaption aria-hidden="true">Day 14</figcaption>
109</figure> 166</figure>
110<h3 id="day-13">Day 13</h3> 167<h3 id="day-13">Day 13</h3>
111<p>I added a few more forms to the <code>lisp</code> evaluator. It handles recursion, definitions, variable mutation and more. The prelude contains 20 subroutines so far, including comparision and logic operators. The REPL interface on the SDL side requires some UX tweaks; environment based completion, readline motions sound doable.</p> 168<p>I added a few more forms to the <code>lisp</code> evaluator. It
169handles recursion, definitions, variable mutation and more. The prelude
170contains 20 subroutines so far, including comparision and logic
171operators. The REPL interface on the SDL side requires some UX tweaks;
172environment based completion, readline motions sound doable.</p>
112<figure> 173<figure>
113<video src="https://u.peppe.rs/u3.mp4" controls=""><a href="https://u.peppe.rs/u3.mp4">Day 13</a></video><figcaption aria-hidden="true">Day 13</figcaption> 174<video src="https://u.peppe.rs/u3.mp4" controls=""><a
175href="https://u.peppe.rs/u3.mp4">Day 13</a></video>
176<figcaption aria-hidden="true">Day 13</figcaption>
114</figure> 177</figure>
115<h3 id="day-12">Day 12</h3> 178<h3 id="day-12">Day 12</h3>
116<p>I lifted most of <a href="https://github.com/murarth/ketos">murarth/ketos</a> into the editor. <code>ketos</code>’s implementation of <code>lisp</code> is too vast for my use case. For example, the editor does not need data types to handle raw strings or byte strings. I have got a basic evaluator running inside the SDL2 context (notice the <code>lisp</code> REPL at the bottom of the window). Over the following days, I intend to create a set of prelude functions to manipulate the pixmap. Users can implement their own brushes, dithering patterns, keybinds and more (hopefully).</p> 179<p>I lifted most of <a
180href="https://github.com/murarth/ketos">murarth/ketos</a> into the
181editor. <code>ketos</code>’s implementation of <code>lisp</code> is too
182vast for my use case. For example, the editor does not need data types
183to handle raw strings or byte strings. I have got a basic evaluator
184running inside the SDL2 context (notice the <code>lisp</code> REPL at
185the bottom of the window). Over the following days, I intend to create a
186set of prelude functions to manipulate the pixmap. Users can implement
187their own brushes, dithering patterns, keybinds and more
188(hopefully).</p>
117<figure> 189<figure>
118<video src="https://u.peppe.rs/y0.mp4" controls=""><a href="https://u.peppe.rs/y0.mp4">Day 12</a></video><figcaption aria-hidden="true">Day 12</figcaption> 190<video src="https://u.peppe.rs/y0.mp4" controls=""><a
191href="https://u.peppe.rs/y0.mp4">Day 12</a></video>
192<figcaption aria-hidden="true">Day 12</figcaption>
119</figure> 193</figure>
120<h3 id="day-11">Day 11</h3> 194<h3 id="day-11">Day 11</h3>
121<p>I intend to supplement the editor with scripting language and an inbuilt REPL for the same. I began by implementing a text box widget from scratch, with history and readline like editing:</p> 195<p>I intend to supplement the editor with scripting language and an
196inbuilt REPL for the same. I began by implementing a text box widget
197from scratch, with history and readline like editing:</p>
122<figure> 198<figure>
123<video src="https://u.peppe.rs/Mh.mp4" controls=""><a href="https://u.peppe.rs/Mh.mp4">Day 11</a></video><figcaption aria-hidden="true">Day 11</figcaption> 199<video src="https://u.peppe.rs/Mh.mp4" controls=""><a
200href="https://u.peppe.rs/Mh.mp4">Day 11</a></video>
201<figcaption aria-hidden="true">Day 11</figcaption>
124</figure> 202</figure>
125<h3 id="day-10">Day 10</h3> 203<h3 id="day-10">Day 10</h3>
126<p>I started reading up on dithering methods and half-toning, I wanted to create a dithering brush that would automatically produce popular dithering patterns. The method that caught my eye (and also the one used most often in pixel art), was Bayer’s ordered dithering. When applied to a black and white image, each pixel, based on its intensity, is mapped to a 4x4 grid of pixels. A completely empty (completely black) 4x4 grid represents zero intensity, and a filled 4x4 grid represents full intensity. Bayer’s ordered dithering can produce 15 steps of intensity between zero and full (by switching on exactly 1 pixel more at each level), thus, being able to draw 17 “shades” from white to black. Creating a dithering brush from here was fairly trivial. Our pixmap is supposed to represent the final dithered image, it must be divided into 4x4 grids. Each grid is colored based on the intensity of the brush passing over it:</p> 204<p>I started reading up on dithering methods and half-toning, I wanted
205to create a dithering brush that would automatically produce popular
206dithering patterns. The method that caught my eye (and also the one used
207most often in pixel art), was Bayer’s ordered dithering. When applied to
208a black and white image, each pixel, based on its intensity, is mapped
209to a 4x4 grid of pixels. A completely empty (completely black) 4x4 grid
210represents zero intensity, and a filled 4x4 grid represents full
211intensity. Bayer’s ordered dithering can produce 15 steps of intensity
212between zero and full (by switching on exactly 1 pixel more at each
213level), thus, being able to draw 17 “shades” from white to black.
214Creating a dithering brush from here was fairly trivial. Our pixmap is
215supposed to represent the final dithered image, it must be divided into
2164x4 grids. Each grid is colored based on the intensity of the brush
217passing over it:</p>
127<figure> 218<figure>
128<img src="https://u.peppe.rs/Mn.png" alt="Day 10" /><figcaption aria-hidden="true">Day 10</figcaption> 219<img src="https://u.peppe.rs/Mn.png" alt="Day 10" />
220<figcaption aria-hidden="true">Day 10</figcaption>
129</figure> 221</figure>
130<h3 id="day-9">Day 9</h3> 222<h3 id="day-9">Day 9</h3>
131<p>I started working towards an interface. I like the idea of a largely read-only HUD, i. e., an interface that simply describes the state of the application. Changes to this state are initiated via keybinds or text commands. I am proud of the symmetry indicator; <code>-</code> for horizontal symmetry, <code>|</code> for vertical symmetry, <code>+</code> for radial symmetry.</p> 223<p>I started working towards an interface. I like the idea of a largely
224read-only HUD, i. e., an interface that simply describes the state of
225the application. Changes to this state are initiated via keybinds or
226text commands. I am proud of the symmetry indicator; <code>-</code> for
227horizontal symmetry, <code>|</code> for vertical symmetry,
228<code>+</code> for radial symmetry.</p>
132<figure> 229<figure>
133<img src="https://u.peppe.rs/hx.png" alt="Day 9" /><figcaption aria-hidden="true">Day 9</figcaption> 230<img src="https://u.peppe.rs/hx.png" alt="Day 9" />
231<figcaption aria-hidden="true">Day 9</figcaption>
134</figure> 232</figure>
135<h3 id="day-8">Day 8</h3> 233<h3 id="day-8">Day 8</h3>
136<p>One of my favourite features of GIMP was symmetric editing. I added some coordinate geometry primitives to my pixmap abstraction, allowing for mirroring and reflecting figures about lines or points. The result was an ergonomic function that applies symmetry to any painting operation, (undo/redo works as expected):</p> 234<p>One of my favourite features of GIMP was symmetric editing. I added
137<div class="sourceCode" id="cb5"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> line <span class="op">=</span> <span class="kw">self</span><span class="op">.</span>pixmap<span class="op">.</span>get_line(start<span class="op">,</span> end)<span class="op">;</span></span> 235some coordinate geometry primitives to my pixmap abstraction, allowing
236for mirroring and reflecting figures about lines or points. The result
237was an ergonomic function that applies symmetry to any painting
238operation, (undo/redo works as expected):</p>
239<div class="sourceCode" id="cb5"><pre
240class="sourceCode rust"><code class="sourceCode rust"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> line <span class="op">=</span> <span class="kw">self</span><span class="op">.</span>pixmap<span class="op">.</span>get_line(start<span class="op">,</span> end)<span class="op">;</span></span>
138<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> sym_line <span class="op">=</span> <span class="kw">self</span><span class="op">.</span>symmetry<span class="op">.</span>apply(<span class="op">&amp;</span>line)<span class="op">;</span></span> 241<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> sym_line <span class="op">=</span> <span class="kw">self</span><span class="op">.</span>symmetry<span class="op">.</span>apply(<span class="op">&amp;</span>line)<span class="op">;</span></span>
139<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="kw">for</span> point on line<span class="op">.</span>extend(sym_line) <span class="op">{</span></span> 242<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> point on line<span class="op">.</span>extend(sym_line) <span class="op">{</span></span>
140<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> <span class="co">// draw to window</span></span> 243<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> <span class="co">// draw to window</span></span>
141<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 244<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
142<figure> 245<figure>
143<video src="https://u.peppe.rs/B1.mp4" controls=""><a href="https://u.peppe.rs/B1.mp4">Day 8</a></video><figcaption aria-hidden="true">Day 8</figcaption> 246<video src="https://u.peppe.rs/B1.mp4" controls=""><a
247href="https://u.peppe.rs/B1.mp4">Day 8</a></video>
248<figcaption aria-hidden="true">Day 8</figcaption>
144</figure> 249</figure>
145<h3 id="day-7">Day 7</h3> 250<h3 id="day-7">Day 7</h3>
146<p>Bresenham saves the day again! This time, I implemented his line drawing algorithm, to, well, draw lines. Each point on the line is then “buffed” based on the active brush size. Today’s changes fit in very well with the undo system and the brush size feature. Creating the right abstractions, one at a time :)</p> 251<p>Bresenham saves the day again! This time, I implemented his line
252drawing algorithm, to, well, draw lines. Each point on the line is then
253“buffed” based on the active brush size. Today’s changes fit in very
254well with the undo system and the brush size feature. Creating the right
255abstractions, one at a time :)</p>
147<figure> 256<figure>
148<video src="https://u.peppe.rs/xt.mp4" controls=""><a href="https://u.peppe.rs/xt.mp4">Day 7</a></video><figcaption aria-hidden="true">Day 7</figcaption> 257<video src="https://u.peppe.rs/xt.mp4" controls=""><a
258href="https://u.peppe.rs/xt.mp4">Day 7</a></video>
259<figcaption aria-hidden="true">Day 7</figcaption>
149</figure> 260</figure>
150<h3 id="day-6">Day 6</h3> 261<h3 id="day-6">Day 6</h3>
151<p>I extended Bresenham’s algorithm to draw not just circle outlines, but also generate their fills. Unlike Bresenham’s algorithm, this variant generates points for two quadrants at once, these points are mirrored over the dividing axis to generate the other two quadrants.</p> 262<p>I extended Bresenham’s algorithm to draw not just circle outlines,
263but also generate their fills. Unlike Bresenham’s algorithm, this
264variant generates points for two quadrants at once, these points are
265mirrored over the dividing axis to generate the other two quadrants.</p>
152<figure> 266<figure>
153<img src="https://u.peppe.rs/f3.png" alt="Day 6" /><figcaption aria-hidden="true">Day 6</figcaption> 267<img src="https://u.peppe.rs/f3.png" alt="Day 6" />
268<figcaption aria-hidden="true">Day 6</figcaption>
154</figure> 269</figure>
155<h3 id="day-5">Day 5</h3> 270<h3 id="day-5">Day 5</h3>
156<p>I discovered and implemented Bresenham’s algorithm for efficient circle drawing. The algorithm allowed for sized circular brushes, something I really liked from GIMP. Very convenient that the Wikipedia page for Bresenham’s algorithm also includes a section about optimizing for integer based arithmetic. I managed to abstract out another giant component of the application, the pixmap. Any image is just a grid of pixels (a pixmap), where the pixel’s value is decided by the application (1-bit in my case). I could potentially extend the application to a 24-bit image editor!</p> 271<p>I discovered and implemented Bresenham’s algorithm for efficient
272circle drawing. The algorithm allowed for sized circular brushes,
273something I really liked from GIMP. Very convenient that the Wikipedia
274page for Bresenham’s algorithm also includes a section about optimizing
275for integer based arithmetic. I managed to abstract out another giant
276component of the application, the pixmap. Any image is just a grid of
277pixels (a pixmap), where the pixel’s value is decided by the application
278(1-bit in my case). I could potentially extend the application to a
27924-bit image editor!</p>
157<figure> 280<figure>
158<video src="https://u.peppe.rs/Kh.mp4" controls=""><a href="https://u.peppe.rs/Kh.mp4">Day 5</a></video><figcaption aria-hidden="true">Day 5</figcaption> 281<video src="https://u.peppe.rs/Kh.mp4" controls=""><a
282href="https://u.peppe.rs/Kh.mp4">Day 5</a></video>
283<figcaption aria-hidden="true">Day 5</figcaption>
159</figure> 284</figure>
160<h3 id="day-4">Day 4</h3> 285<h3 id="day-4">Day 4</h3>
161<p>I created a generic “undo stack” data structure that allows for infinite “undos” and “redos”. Every modification operation to the grid is persisted to the application state. A couple of keybinds allow the user to revert and re-apply these operations! I expect abstracting this component will come in handy down the line.</p> 286<p>I created a generic “undo stack” data structure that allows for
287infinite “undos” and “redos”. Every modification operation to the grid
288is persisted to the application state. A couple of keybinds allow the
289user to revert and re-apply these operations! I expect abstracting this
290component will come in handy down the line.</p>
162<figure> 291<figure>
163<video src="https://u.peppe.rs/w5.mp4" controls=""><a href="https://u.peppe.rs/w5.mp4">Day 4</a></video><figcaption aria-hidden="true">Day 4</figcaption> 292<video src="https://u.peppe.rs/w5.mp4" controls=""><a
293href="https://u.peppe.rs/w5.mp4">Day 4</a></video>
294<figcaption aria-hidden="true">Day 4</figcaption>
164</figure> 295</figure>
165<h3 id="day-3">Day 3</h3> 296<h3 id="day-3">Day 3</h3>
166<p>I implemented the bare minimum required to call the program an “editor”. The application displays a grid, tracks mouse events, paints white to the canvas on left click, and black to the canvas on right click. I created a make-shift MVC architecture à la Elm in Rust.</p> 297<p>I implemented the bare minimum required to call the program an
298“editor”. The application displays a grid, tracks mouse events, paints
299white to the canvas on left click, and black to the canvas on right
300click. I created a make-shift MVC architecture à la Elm in Rust.</p>
167<figure> 301<figure>
168<video src="https://u.peppe.rs/GF.mp4" controls=""><a href="https://u.peppe.rs/GF.mp4">Day 3</a></video><figcaption aria-hidden="true">Day 3</figcaption> 302<video src="https://u.peppe.rs/GF.mp4" controls=""><a
303href="https://u.peppe.rs/GF.mp4">Day 3</a></video>
304<figcaption aria-hidden="true">Day 3</figcaption>
169</figure> 305</figure>
170<h3 id="day-2">Day 2</h3> 306<h3 id="day-2">Day 2</h3>
171<p>I started figuring out event handling today. Implemented a couple of keybinds to zoom in/out of the drawing area. Conversions of SDL2 coordinates (measured in signed 32 bit integers) to my internal “drawing area” coordinates (measured in unsigned 32 bit integers) is very annoying. Hopefully the unchecked conversions won’t haunt me later.</p> 307<p>I started figuring out event handling today. Implemented a couple of
308keybinds to zoom in/out of the drawing area. Conversions of SDL2
309coordinates (measured in signed 32 bit integers) to my internal “drawing
310area” coordinates (measured in unsigned 32 bit integers) is very
311annoying. Hopefully the unchecked conversions won’t haunt me later.</p>
172<figure> 312<figure>
173<video src="https://u.peppe.rs/L4.mp4" controls=""><a href="https://u.peppe.rs/L4.mp4">Day 2</a></video><figcaption aria-hidden="true">Day 2</figcaption> 313<video src="https://u.peppe.rs/L4.mp4" controls=""><a
314href="https://u.peppe.rs/L4.mp4">Day 2</a></video>
315<figcaption aria-hidden="true">Day 2</figcaption>
174</figure> 316</figure>
175<h3 id="day-1">Day 1</h3> 317<h3 id="day-1">Day 1</h3>
176<p>Getting started with Rust and SDL2 is very straightforward. The <code>rust-sdl2</code> library contains some detailed examples that allowed me to get all the way to drawing a grid from a <code>Vec&lt;bool&gt;</code>:</p> 318<p>Getting started with Rust and SDL2 is very straightforward. The
319<code>rust-sdl2</code> library contains some detailed examples that
320allowed me to get all the way to drawing a grid from a
321<code>Vec&lt;bool&gt;</code>:</p>
177<figure> 322<figure>
178<img src="https://u.peppe.rs/Ma.png" alt="Day 1" /><figcaption aria-hidden="true">Day 1</figcaption> 323<img src="https://u.peppe.rs/Ma.png" alt="Day 1" />
324<figcaption aria-hidden="true">Day 1</figcaption>
179</figure> 325</figure>
180 326
181 </div> 327 </div>
diff --git a/docs/posts/WPA_woes/index.html b/docs/posts/WPA_woes/index.html
index 55b2630..0a2e44c 100644
--- a/docs/posts/WPA_woes/index.html
+++ b/docs/posts/WPA_woes/index.html
@@ -28,7 +28,7 @@
28 12/10 — 2019 28 12/10 — 2019
29 <div class="stats"> 29 <div class="stats">
30 <span class="stats-number"> 30 <span class="stats-number">
31 18.37 31 18.38
32 </span> 32 </span>
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
@@ -42,8 +42,12 @@
42 WPA Woes 42 WPA Woes
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>I finally got around to installing Void GNU/Linux on my main computer. Rolling release, non-systemd, need I say more?</p> 45 <p>I finally got around to installing Void GNU/Linux on my main
46<p>As with all GNU/Linux distributions, wireless networks had me in a fix. If you can see this post, it means I’ve managed to get online. It turns out, <code>wpa_supplicant</code> was detecting the wrong interface by default (does it ever select the right one?). Let us fix that:</p> 46computer. Rolling release, non-systemd, need I say more?</p>
47<p>As with all GNU/Linux distributions, wireless networks had me in a
48fix. If you can see this post, it means I’ve managed to get online. It
49turns out, <code>wpa_supplicant</code> was detecting the wrong interface
50by default (does it ever select the right one?). Let us fix that:</p>
47<pre><code>$ sudo rm -r /var/service/wpa_supplicant 51<pre><code>$ sudo rm -r /var/service/wpa_supplicant
48$ sudo killall dhcpcd</code></pre> 52$ sudo killall dhcpcd</code></pre>
49<p>What is the right interface though?</p> 53<p>What is the right interface though?</p>
@@ -51,7 +55,8 @@ $ sudo killall dhcpcd</code></pre>
51 ... 55 ...
52 Interface wlp2s0 56 Interface wlp2s0
53 ...</code></pre> 57 ...</code></pre>
54<p>Aha! Let us run <code>wpa_supplicant</code> on that interface, as a background process:</p> 58<p>Aha! Let us run <code>wpa_supplicant</code> on that interface, as a
59background process:</p>
55<pre><code>$ sudo wpa_supplicant -B -i wlp2s0 -c /etc/wpa_supplicant/wpa_supplicant.conf 60<pre><code>$ sudo wpa_supplicant -B -i wlp2s0 -c /etc/wpa_supplicant/wpa_supplicant.conf
56$ sudo dhcpcd -B wlp2s0 61$ sudo dhcpcd -B wlp2s0
57$ ping google.com 62$ ping google.com
diff --git a/docs/posts/a_reference_counted_afterlife/index.html b/docs/posts/a_reference_counted_afterlife/index.html
index 67016a6..a796393 100644
--- a/docs/posts/a_reference_counted_afterlife/index.html
+++ b/docs/posts/a_reference_counted_afterlife/index.html
@@ -28,7 +28,7 @@
28 02/08 — 2022 28 02/08 — 2022
29 <div class="stats"> 29 <div class="stats">
30 <span class="stats-number"> 30 <span class="stats-number">
31 19.57 31 19.58
32 </span> 32 </span>
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
@@ -42,9 +42,11 @@
42 A Reference Counted Afterlife 42 A Reference Counted Afterlife
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>I took interest in the Egyptian rendition of the afterlife recently.</p> 45 <p>I took interest in the Egyptian rendition of the afterlife
46recently.</p>
46<h3 id="parts-of-the-soul">Parts of the Soul</h3> 47<h3 id="parts-of-the-soul">Parts of the Soul</h3>
47<p>Ancient Egyptians believed that the soul comprised of several components:</p> 48<p>Ancient Egyptians believed that the soul comprised of several
49components:</p>
48<ul> 50<ul>
49<li><em>ren</em></li> 51<li><em>ren</em></li>
50<li><em>ka</em></li> 52<li><em>ka</em></li>
@@ -52,18 +54,34 @@
52<li><em>ba</em></li> 54<li><em>ba</em></li>
53<li><em>sheut</em></li> 55<li><em>sheut</em></li>
54</ul> 56</ul>
55<p>Egyptians emphasized on preserving the different parts of the soul. Mummification for example, served to preserve the physical part of the soul. The other components have their respective preservation strategies.</p> 57<p>Egyptians emphasized on preserving the different parts of the soul.
56<p>Of all of these bits, I find <em>ren</em>, which simply means <em>name</em>, to be the most interesting. <em>Ba</em>, the human-headed chicken that represents <em>personality</em>, is a close favourite.</p> 58Mummification for example, served to preserve the physical part of the
57<p><em>Ren</em> is the name given to a person at birth. Egyptians believed that this portion of the soul would continue to live on for as long as it was spoken. If you were someone worthy of continued existence, your name would be inscribed all over the place. If you were the type to snatch away bread from children, your name would be condemned from memory, forgotten.</p> 59soul. The other components have their respective preservation
60strategies.</p>
61<p>Of all of these bits, I find <em>ren</em>, which simply means
62<em>name</em>, to be the most interesting. <em>Ba</em>, the human-headed
63chicken that represents <em>personality</em>, is a close favourite.</p>
64<p><em>Ren</em> is the name given to a person at birth. Egyptians
65believed that this portion of the soul would continue to live on for as
66long as it was spoken. If you were someone worthy of continued
67existence, your name would be inscribed all over the place. If you were
68the type to snatch away bread from children, your name would be
69condemned from memory, forgotten.</p>
58<h3 id="garbage-collection">Garbage-collection</h3> 70<h3 id="garbage-collection">Garbage-collection</h3>
59<p>The concept of <em>ren</em> seems to be perfectly analogous to reference counted garbage-collection.</p> 71<p>The concept of <em>ren</em> seems to be perfectly analogous to
72reference counted garbage-collection.</p>
60<ul> 73<ul>
61<li>A name (<em>ren</em>) is assigned to an object (person) on initialization (at birth)</li> 74<li>A name (<em>ren</em>) is assigned to an object (person) on
75initialization (at birth)</li>
62<li>Names are used to refer to objects</li> 76<li>Names are used to refer to objects</li>
63<li>Objects go out of existence when there are no more references to them</li> 77<li>Objects go out of existence when there are no more references to
78them</li>
64</ul> 79</ul>
65<p>The concept of <em>ren</em> seems to model human-memory. The similarity with garbage-collection is now easily explained, because garbage-collection models a program’s memory.</p> 80<p>The concept of <em>ren</em> seems to model human-memory. The
66<p>Perhaps some cheeky Egyptian has attained immortality by creating a <em>ren</em>-cycle.</p> 81similarity with garbage-collection is now easily explained, because
82garbage-collection models a program’s memory.</p>
83<p>Perhaps some cheeky Egyptian has attained immortality by creating a
84<em>ren</em>-cycle.</p>
67 85
68 </div> 86 </div>
69 87
diff --git a/docs/posts/auto-currying_rust_functions/index.html b/docs/posts/auto-currying_rust_functions/index.html
index 0d6fc77..7b05aeb 100644
--- a/docs/posts/auto-currying_rust_functions/index.html
+++ b/docs/posts/auto-currying_rust_functions/index.html
@@ -28,7 +28,7 @@
28 09/05 — 2020 28 09/05 — 2020
29 <div class="stats"> 29 <div class="stats">
30 <span class="stats-number"> 30 <span class="stats-number">
31 356.43 31 356.44
32 </span> 32 </span>
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
@@ -42,13 +42,22 @@
42 Auto-currying Rust Functions 42 Auto-currying Rust Functions
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>This post contains a gentle introduction to procedural macros in Rust and a guide to writing a procedural macro to curry Rust functions. The source code for the entire library can be found <a href="https://github.com/nerdypepper/cutlass">here</a>. It is also available on <a href="https://crates.io/crates/cutlass">crates.io</a>.</p> 45 <p>This post contains a gentle introduction to procedural macros in Rust
46<p>The following links might prove to be useful before getting started:</p> 46and a guide to writing a procedural macro to curry Rust functions. The
47source code for the entire library can be found <a
48href="https://github.com/nerdypepper/cutlass">here</a>. It is also
49available on <a
50href="https://crates.io/crates/cutlass">crates.io</a>.</p>
51<p>The following links might prove to be useful before getting
52started:</p>
47<ul> 53<ul>
48<li><a href="https://doc.rust-lang.org/reference/procedural-macros.html">Procedural Macros</a></li> 54<li><a
55href="https://doc.rust-lang.org/reference/procedural-macros.html">Procedural
56Macros</a></li>
49<li><a href="https://en.wikipedia.org/wiki/Currying">Currying</a></li> 57<li><a href="https://en.wikipedia.org/wiki/Currying">Currying</a></li>
50</ul> 58</ul>
51<p>Or you can pretend you read them, because I have included a primer here :)</p> 59<p>Or you can pretend you read them, because I have included a primer
60here :)</p>
52<h3 id="contents">Contents</h3> 61<h3 id="contents">Contents</h3>
53<ol type="1"> 62<ol type="1">
54<li><a href="#currying">Currying</a><br /> 63<li><a href="#currying">Currying</a><br />
@@ -73,7 +82,12 @@
73<li><a href="#conclusion">Conclusion</a></li> 82<li><a href="#conclusion">Conclusion</a></li>
74</ol> 83</ol>
75<h3 id="currying">Currying</h3> 84<h3 id="currying">Currying</h3>
76<p>Currying is the process of transformation of a function call like <code>f(a, b, c)</code> to <code>f(a)(b)(c)</code>. A curried function returns a concrete value only when it receives all its arguments! If it does recieve an insufficient amount of arguments, say 1 of 3, it returns a <em>curried function</em>, that returns after receiving 2 arguments.</p> 85<p>Currying is the process of transformation of a function call like
86<code>f(a, b, c)</code> to <code>f(a)(b)(c)</code>. A curried function
87returns a concrete value only when it receives all its arguments! If it
88does recieve an insufficient amount of arguments, say 1 of 3, it returns
89a <em>curried function</em>, that returns after receiving 2
90arguments.</p>
77<pre><code>curry(f(a, b, c)) = h(a)(b)(c) 91<pre><code>curry(f(a, b, c)) = h(a)(b)(c)
78 92
79h(x) = g &lt;- curried function that takes upto 2 args (g) 93h(x) = g &lt;- curried function that takes upto 2 args (g)
@@ -82,49 +96,86 @@ k(z) = v &lt;- a value (v)
82 96
83Keen readers will conclude the following, 97Keen readers will conclude the following,
84h(x)(y)(z) = g(y)(z) = k(z) = v</code></pre> 98h(x)(y)(z) = g(y)(z) = k(z) = v</code></pre>
85<p>Mathematically, if <code>f</code> is a function that takes two arguments <code>x</code> and <code>y</code>, such that <code>x ϵ X</code>, and <code>y ϵ Y</code> , we write it as:</p> 99<p>Mathematically, if <code>f</code> is a function that takes two
100arguments <code>x</code> and <code>y</code>, such that
101<code>x ϵ X</code>, and <code>y ϵ Y</code> , we write it as:</p>
86<pre><code>f: (X × Y) -&gt; Z</code></pre> 102<pre><code>f: (X × Y) -&gt; Z</code></pre>
87<p>where <code>×</code> denotes the Cartesian product of set <code>X</code> and <code>Y</code>, and curried <code>f</code> (denoted by <code>h</code> here) is written as:</p> 103<p>where <code>×</code> denotes the Cartesian product of set
104<code>X</code> and <code>Y</code>, and curried <code>f</code> (denoted
105by <code>h</code> here) is written as:</p>
88<pre><code>h: X -&gt; (Y -&gt; Z)</code></pre> 106<pre><code>h: X -&gt; (Y -&gt; Z)</code></pre>
89<h3 id="procedural-macros">Procedural Macros</h3> 107<h3 id="procedural-macros">Procedural Macros</h3>
90<p>These are functions that take code as input and spit out modified code as output. Powerful stuff. Rust has three kinds of proc-macros:</p> 108<p>These are functions that take code as input and spit out modified
109code as output. Powerful stuff. Rust has three kinds of proc-macros:</p>
91<ul> 110<ul>
92<li>Function like macros<br /> 111<li>Function like macros<br />
93</li> 112</li>
94<li>Derive macros: <code>#[derive(...)]</code>, used to automatically implement traits for structs/enums<br /> 113<li>Derive macros: <code>#[derive(...)]</code>, used to automatically
114implement traits for structs/enums<br />
95</li> 115</li>
96<li>and Attribute macros: <code>#[test]</code>, usually slapped onto functions</li> 116<li>and Attribute macros: <code>#[test]</code>, usually slapped onto
117functions</li>
97</ul> 118</ul>
98<p>We will be using Attribute macros to convert a Rust function into a curried Rust function, which we should be able to call via: <code>function(arg1)(arg2)</code>.</p> 119<p>We will be using Attribute macros to convert a Rust function into a
120curried Rust function, which we should be able to call via:
121<code>function(arg1)(arg2)</code>.</p>
99<h3 id="definitions">Definitions</h3> 122<h3 id="definitions">Definitions</h3>
100<p>Being respectable programmers, we define the input to and the output from our proc-macro. Here’s a good non-trivial function to start out with:</p> 123<p>Being respectable programmers, we define the input to and the output
101<div class="sourceCode" id="cb4"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> y<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> z<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="dt">u32</span> <span class="op">{</span></span> 124from our proc-macro. Here’s a good non-trivial function to start out
102<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span> 125with:</p>
126<div class="sourceCode" id="cb4"><pre
127class="sourceCode rust"><code class="sourceCode rust"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> y<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> z<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="dt">u32</span> <span class="op">{</span></span>
128<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span>
103<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 129<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
104<p>Hmm, what would our output look like? What should our proc-macro generate ideally? Well, if we understood currying correctly, we should accept an argument and return a function that accepts an argument and returns … you get the point. Something like this should do:</p> 130<p>Hmm, what would our output look like? What should our proc-macro
105<div class="sourceCode" id="cb5"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add_curried1(x<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="op">?</span> <span class="op">{</span></span> 131generate ideally? Well, if we understood currying correctly, we should
106<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> <span class="kw">fn</span> add_curried2 (y<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="op">?</span> <span class="op">{</span></span> 132accept an argument and return a function that accepts an argument and
107<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> <span class="kw">fn</span> add_curried3 (z<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="dt">u32</span> <span class="op">{</span></span> 133returns … you get the point. Something like this should do:</p>
108<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span> 134<div class="sourceCode" id="cb5"><pre
135class="sourceCode rust"><code class="sourceCode rust"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add_curried1(x<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="op">?</span> <span class="op">{</span></span>
136<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="kw">fn</span> add_curried2 (y<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="op">?</span> <span class="op">{</span></span>
137<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="kw">fn</span> add_curried3 (z<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="dt">u32</span> <span class="op">{</span></span>
138<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span>
109<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> 139<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
110<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> 140<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
111<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 141<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
112<p>A couple of things to note:</p> 142<p>A couple of things to note:</p>
113<p><strong>Return types</strong><br /> 143<p><strong>Return types</strong><br />
114We have placed <code>?</code>s in place of return types. Let’s try to fix that. <code>add_curried3</code> returns the ‘value’, so <code>u32</code> is accurate. <code>add_curried2</code> returns <code>add_curried3</code>. What is the type of <code>add_curried3</code>? It is a function that takes in a <code>u32</code> and returns a <code>u32</code>. So a <code>fn(u32) -&gt; u32</code> will do right? No, I’ll explain why in the next point, but for now, we will make use of the <code>Fn</code> trait, our return type is <code>impl Fn(u32) -&gt; u32</code>. This basically tells the compiler that we will be returning something function-like, a.k.a, behaves like a <code>Fn</code>. Cool!</p> 144We have placed <code>?</code>s in place of return types. Let’s try to
115<p>If you have been following along, you should be able to tell that the return type of <code>add_curried1</code> is:</p> 145fix that. <code>add_curried3</code> returns the ‘value’, so
146<code>u32</code> is accurate. <code>add_curried2</code> returns
147<code>add_curried3</code>. What is the type of
148<code>add_curried3</code>? It is a function that takes in a
149<code>u32</code> and returns a <code>u32</code>. So a
150<code>fn(u32) -&gt; u32</code> will do right? No, I’ll explain why in
151the next point, but for now, we will make use of the <code>Fn</code>
152trait, our return type is <code>impl Fn(u32) -&gt; u32</code>. This
153basically tells the compiler that we will be returning something
154function-like, a.k.a, behaves like a <code>Fn</code>. Cool!</p>
155<p>If you have been following along, you should be able to tell that the
156return type of <code>add_curried1</code> is:</p>
116<pre><code>impl Fn(u32) -&gt; (impl Fn(u32) -&gt; u32)</code></pre> 157<pre><code>impl Fn(u32) -&gt; (impl Fn(u32) -&gt; u32)</code></pre>
117<p>We can drop the parentheses because <code>-&gt;</code> is right associative:</p> 158<p>We can drop the parentheses because <code>-&gt;</code> is right
159associative:</p>
118<pre><code>impl Fn(u32) -&gt; impl Fn(u32) -&gt; u32 160<pre><code>impl Fn(u32) -&gt; impl Fn(u32) -&gt; u32
119</code></pre> 161</code></pre>
120<p><strong>Accessing environment</strong><br /> 162<p><strong>Accessing environment</strong><br />
121A function cannot access it’s environment. Our solution will not work. <code>add_curried3</code> attempts to access <code>x</code>, which is not allowed! A closure<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> however, can. If we are returning a closure, our return type must be <code>impl Fn</code>, and not <code>fn</code>. The difference between the <code>Fn</code> trait and function pointers is beyond the scope of this post.</p> 163A function cannot access it’s environment. Our solution will not work.
164<code>add_curried3</code> attempts to access <code>x</code>, which is
165not allowed! A closure<a href="#fn1" class="footnote-ref" id="fnref1"
166role="doc-noteref"><sup>1</sup></a> however, can. If we are returning a
167closure, our return type must be <code>impl Fn</code>, and not
168<code>fn</code>. The difference between the <code>Fn</code> trait and
169function pointers is beyond the scope of this post.</p>
122<h3 id="refinement">Refinement</h3> 170<h3 id="refinement">Refinement</h3>
123<p>Armed with knowledge, we refine our expected output, this time, employing closures:</p> 171<p>Armed with knowledge, we refine our expected output, this time,
124<div class="sourceCode" id="cb8"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="dt">u32</span> <span class="op">{</span></span> 172employing closures:</p>
125<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> <span class="kw">move</span> <span class="op">|</span>y<span class="op">|</span> <span class="kw">move</span> <span class="op">|</span>z<span class="op">|</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span> 173<div class="sourceCode" id="cb8"><pre
174class="sourceCode rust"><code class="sourceCode rust"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="dt">u32</span> <span class="op">{</span></span>
175<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="kw">move</span> <span class="op">|</span>y<span class="op">|</span> <span class="kw">move</span> <span class="op">|</span>z<span class="op">|</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span>
126<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 176<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
127<p>Alas, that does not compile either! It errors out with the following message:</p> 177<p>Alas, that does not compile either! It errors out with the following
178message:</p>
128<pre><code>error[E0562]: `impl Trait` not allowed outside of function 179<pre><code>error[E0562]: `impl Trait` not allowed outside of function
129and inherent method return types 180and inherent method return types
130 --&gt; src/main.rs:17:37 181 --&gt; src/main.rs:17:37
@@ -132,21 +183,33 @@ and inherent method return types
132 | fn add(x: u32) -&gt; impl Fn(u32) -&gt; impl Fn(u32) -&gt; u32 183 | fn add(x: u32) -&gt; impl Fn(u32) -&gt; impl Fn(u32) -&gt; u32
133 | ^^^^^^^^^^^^^^^^^^^ 184 | ^^^^^^^^^^^^^^^^^^^
134</code></pre> 185</code></pre>
135<p>You are allowed to return an <code>impl Fn</code> only inside a function. We are currently returning it from another return! Or at least, that was the most I could make out of the error message.</p> 186<p>You are allowed to return an <code>impl Fn</code> only inside a
136<p>We are going to have to cheat a bit to fix this issue; with type aliases and a convenient nightly feature <a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>:</p> 187function. We are currently returning it from another return! Or at
137<div class="sourceCode" id="cb10"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="at">#![</span>feature<span class="at">(</span>type_alias_impl_trait<span class="at">)]</span> <span class="co">// allows us to use `impl Fn` in type aliases!</span></span> 188least, that was the most I could make out of the error message.</p>
189<p>We are going to have to cheat a bit to fix this issue; with type
190aliases and a convenient nightly feature <a href="#fn2"
191class="footnote-ref" id="fnref2"
192role="doc-noteref"><sup>2</sup></a>:</p>
193<div class="sourceCode" id="cb10"><pre
194class="sourceCode rust"><code class="sourceCode rust"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="at">#![</span>feature<span class="at">(</span>type_alias_impl_trait<span class="at">)]</span> <span class="co">// allows us to use `impl Fn` in type aliases!</span></span>
138<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a></span> 195<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a></span>
139<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span> <span class="co">// the return value when zero args are to be applied</span></span> 196<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span> <span class="co">// the return value when zero args are to be applied</span></span>
140<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> T0<span class="op">;</span> <span class="co">// the return value when one arg is to be applied</span></span> 197<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> T0<span class="op">;</span> <span class="co">// the return value when one arg is to be applied</span></span>
141<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T2 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> T1<span class="op">;</span> <span class="co">// the return value when two args are to be applied</span></span> 198<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T2 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> T1<span class="op">;</span> <span class="co">// the return value when two args are to be applied</span></span>
142<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a></span> 199<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a></span>
143<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> T2 <span class="op">{</span></span> 200<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> T2 <span class="op">{</span></span>
144<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> <span class="kw">move</span> <span class="op">|</span>y<span class="op">|</span> <span class="kw">move</span> <span class="op">|</span>z<span class="op">|</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span> 201<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="kw">move</span> <span class="op">|</span>y<span class="op">|</span> <span class="kw">move</span> <span class="op">|</span>z<span class="op">|</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span>
145<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 202<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
146<p>Drop that into a cargo project, call <code>add(4)(5)(6)</code>, cross your fingers, and run <code>cargo +nightly run</code>. You should see a 15 unless you forgot to print it!</p> 203<p>Drop that into a cargo project, call <code>add(4)(5)(6)</code>, cross
204your fingers, and run <code>cargo +nightly run</code>. You should see a
20515 unless you forgot to print it!</p>
147<h3 id="the-in-betweens">The In-Betweens</h3> 206<h3 id="the-in-betweens">The In-Betweens</h3>
148<p>Let us write the magical bits that take us from function to curried function.</p> 207<p>Let us write the magical bits that take us from function to curried
149<p>Initialize your workspace with <code>cargo new --lib currying</code>. Proc-macro crates are libraries with exactly one export, the macro itself. Add a <code>tests</code> directory to your crate root. Your directory should look something like this:</p> 208function.</p>
209<p>Initialize your workspace with <code>cargo new --lib currying</code>.
210Proc-macro crates are libraries with exactly one export, the macro
211itself. Add a <code>tests</code> directory to your crate root. Your
212directory should look something like this:</p>
150<pre><code>. 213<pre><code>.
151├── Cargo.toml 214├── Cargo.toml
152├── src 215├── src
@@ -156,9 +219,11 @@ and inherent method return types
156<h4 id="dependencies">Dependencies</h4> 219<h4 id="dependencies">Dependencies</h4>
157<p>We will be using a total of 3 external crates:</p> 220<p>We will be using a total of 3 external crates:</p>
158<ul> 221<ul>
159<li><a href="https://docs.rs/proc-macro2/1.0.12/proc_macro2/">proc_macro2</a></li> 222<li><a
223href="https://docs.rs/proc-macro2/1.0.12/proc_macro2/">proc_macro2</a></li>
160<li><a href="https://docs.rs/syn/1.0.18/syn/index.html">syn</a></li> 224<li><a href="https://docs.rs/syn/1.0.18/syn/index.html">syn</a></li>
161<li><a href="https://docs.rs/quote/1.0.4/quote/index.html">quote</a></li> 225<li><a
226href="https://docs.rs/quote/1.0.4/quote/index.html">quote</a></li>
162</ul> 227</ul>
163<p>Here’s a sample <code>Cargo.toml</code>:</p> 228<p>Here’s a sample <code>Cargo.toml</code>:</p>
164<pre><code># Cargo.toml 229<pre><code># Cargo.toml
@@ -173,10 +238,12 @@ features = [&quot;full&quot;]
173 238
174[lib] 239[lib]
175proc-macro = true # this is important!</code></pre> 240proc-macro = true # this is important!</code></pre>
176<p>We will be using an external <code>proc-macro2</code> crate as well as an internal <code>proc-macro</code> crate. Not confusing at all!</p> 241<p>We will be using an external <code>proc-macro2</code> crate as well
242as an internal <code>proc-macro</code> crate. Not confusing at all!</p>
177<h4 id="the-attribute-macro">The attribute macro</h4> 243<h4 id="the-attribute-macro">The attribute macro</h4>
178<p>Drop this into <code>src/lib.rs</code>, to get the ball rolling.</p> 244<p>Drop this into <code>src/lib.rs</code>, to get the ball rolling.</p>
179<div class="sourceCode" id="cb13"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> 245<div class="sourceCode" id="cb13"><pre
246class="sourceCode rust"><code class="sourceCode rust"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span>
180<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a></span> 247<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a></span>
181<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">proc_macro::</span>TokenStream<span class="op">;</span> <span class="co">// 1</span></span> 248<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">proc_macro::</span>TokenStream<span class="op">;</span> <span class="co">// 1</span></span>
182<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">quote::</span>quote<span class="op">;</span></span> 249<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">quote::</span>quote<span class="op">;</span></span>
@@ -190,17 +257,49 @@ proc-macro = true # this is important!</code></pre>
190<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a></span> 257<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a></span>
191<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> generate_curry(parsed<span class="op">:</span> ItemFn) <span class="op">-&gt;</span> <span class="pp">proc_macro2::</span>TokenStream <span class="op">{}</span></span></code></pre></div> 258<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> generate_curry(parsed<span class="op">:</span> ItemFn) <span class="op">-&gt;</span> <span class="pp">proc_macro2::</span>TokenStream <span class="op">{}</span></span></code></pre></div>
192<p><strong>1. Imports</strong></p> 259<p><strong>1. Imports</strong></p>
193<p>A <code>Tokenstream</code> holds (hopefully valid) Rust code, this is the type of our input and output. Note that we are importing this type from <code>proc_macro</code> and not <code>proc_macro2</code>.</p> 260<p>A <code>Tokenstream</code> holds (hopefully valid) Rust code, this is
194<p><code>quote!</code> from the <code>quote</code> crate is a macro that allows us to quickly produce <code>TokenStream</code>s. Much like the LISP <code>quote</code> procedure, you can use the <code>quote!</code> macro for symbolic transformations.</p> 261the type of our input and output. Note that we are importing this type
195<p><code>ItemFn</code> from the <code>syn</code> crate holds the parsed <code>TokenStream</code> of a Rust function. <code>parse_macro_input!</code> is a helper macro provided by <code>syn</code>.</p> 262from <code>proc_macro</code> and not <code>proc_macro2</code>.</p>
263<p><code>quote!</code> from the <code>quote</code> crate is a macro that
264allows us to quickly produce <code>TokenStream</code>s. Much like the
265LISP <code>quote</code> procedure, you can use the <code>quote!</code>
266macro for symbolic transformations.</p>
267<p><code>ItemFn</code> from the <code>syn</code> crate holds the parsed
268<code>TokenStream</code> of a Rust function.
269<code>parse_macro_input!</code> is a helper macro provided by
270<code>syn</code>.</p>
196<p><strong>2. The lone export</strong></p> 271<p><strong>2. The lone export</strong></p>
197<p>Annotate the only <code>pub</code> of our crate with <code>#[proc_macro_attribute]</code>. This tells rustc that <code>curry</code> is a procedural macro, and allows us to use it as <code>#[crate_name::curry]</code> in other crates. Note the signature of the <code>curry</code> function. <code>_attr</code> is the <code>TokenStream</code> representing the attribute itself, <code>item</code> refers to the thing we slapped our macro into, in this case a function (like <code>add</code>). The return value is a modified <code>TokenStream</code>, this will contain our curried version of <code>add</code>.</p> 272<p>Annotate the only <code>pub</code> of our crate with
273<code>#[proc_macro_attribute]</code>. This tells rustc that
274<code>curry</code> is a procedural macro, and allows us to use it as
275<code>#[crate_name::curry]</code> in other crates. Note the signature of
276the <code>curry</code> function. <code>_attr</code> is the
277<code>TokenStream</code> representing the attribute itself,
278<code>item</code> refers to the thing we slapped our macro into, in this
279case a function (like <code>add</code>). The return value is a modified
280<code>TokenStream</code>, this will contain our curried version of
281<code>add</code>.</p>
198<p><strong>3. The helper macro</strong></p> 282<p><strong>3. The helper macro</strong></p>
199<p>A <code>TokenStream</code> is a little hard to work with, which is why we have the <code>syn</code> crate, which provides types to represent Rust tokens. An <code>RArrow</code> struct to represent the return arrow on a function and so on. One of those types is <code>ItemFn</code>, that represents an entire Rust function. The <code>parse_macro_input!</code> automatically puts the input to our macro into an <code>ItemFn</code>. What a gentleman!</p> 283<p>A <code>TokenStream</code> is a little hard to work with, which is
284why we have the <code>syn</code> crate, which provides types to
285represent Rust tokens. An <code>RArrow</code> struct to represent the
286return arrow on a function and so on. One of those types is
287<code>ItemFn</code>, that represents an entire Rust function. The
288<code>parse_macro_input!</code> automatically puts the input to our
289macro into an <code>ItemFn</code>. What a gentleman!</p>
200<p><strong>4. Returning <code>TokenStream</code>s </strong></p> 290<p><strong>4. Returning <code>TokenStream</code>s </strong></p>
201<p>We haven’t filled in <code>generate_curry</code> yet, but we can see that it returns a <code>proc_macro2::TokenStream</code> and not a <code>proc_macro::TokenStream</code>, so drop a <code>.into()</code> to convert it.</p> 291<p>We haven’t filled in <code>generate_curry</code> yet, but we can see
202<p>Lets move on, and fill in <code>generate_curry</code>, I would suggest keeping the documentation for <a href="https://docs.rs/syn/1.0.19/syn/struct.ItemFn.html"><code>syn::ItemFn</code></a> and <a href="https://docs.rs/syn/1.0.19/syn/struct.Signature.html"><code>syn::Signature</code></a> open.</p> 292that it returns a <code>proc_macro2::TokenStream</code> and not a
203<div class="sourceCode" id="cb14"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> 293<code>proc_macro::TokenStream</code>, so drop a <code>.into()</code> to
294convert it.</p>
295<p>Lets move on, and fill in <code>generate_curry</code>, I would
296suggest keeping the documentation for <a
297href="https://docs.rs/syn/1.0.19/syn/struct.ItemFn.html"><code>syn::ItemFn</code></a>
298and <a
299href="https://docs.rs/syn/1.0.19/syn/struct.Signature.html"><code>syn::Signature</code></a>
300open.</p>
301<div class="sourceCode" id="cb14"><pre
302class="sourceCode rust"><code class="sourceCode rust"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span>
204<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a></span> 303<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a></span>
205<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> generate_curry(parsed<span class="op">:</span> ItemFn) <span class="op">-&gt;</span> <span class="pp">proc_macro2::</span>TokenStream <span class="op">{</span></span> 304<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> generate_curry(parsed<span class="op">:</span> ItemFn) <span class="op">-&gt;</span> <span class="pp">proc_macro2::</span>TokenStream <span class="op">{</span></span>
206<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_body <span class="op">=</span> parsed<span class="op">.</span>block<span class="op">;</span> <span class="co">// function body</span></span> 305<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_body <span class="op">=</span> parsed<span class="op">.</span>block<span class="op">;</span> <span class="co">// function body</span></span>
@@ -210,7 +309,9 @@ proc-macro = true # this is important!</code></pre>
210<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_args <span class="op">=</span> sig<span class="op">.</span>inputs<span class="op">;</span> <span class="co">// comma separated args</span></span> 309<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_args <span class="op">=</span> sig<span class="op">.</span>inputs<span class="op">;</span> <span class="co">// comma separated args</span></span>
211<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_return_type <span class="op">=</span> sig<span class="op">.</span>output<span class="op">;</span> <span class="co">// return type</span></span> 310<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_return_type <span class="op">=</span> sig<span class="op">.</span>output<span class="op">;</span> <span class="co">// return type</span></span>
212<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 311<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
213<p>We are simply extracting the bits of the function, we will be reusing the original function’s visibility and name. Take a look at what <code>syn::Signature</code> can tell us about a function:</p> 312<p>We are simply extracting the bits of the function, we will be reusing
313the original function’s visibility and name. Take a look at what
314<code>syn::Signature</code> can tell us about a function:</p>
214<pre><code> .-- syn::Ident (ident) 315<pre><code> .-- syn::Ident (ident)
215 / 316 /
216 fn add(x: u32, y: u32) -&gt; u32 317 fn add(x: u32, y: u32) -&gt; u32
@@ -220,42 +321,77 @@ syn::token::Fn --&#39; / \ (output)
220 Punctuated&lt;FnArg, Comma&gt; (inputs)</code></pre> 321 Punctuated&lt;FnArg, Comma&gt; (inputs)</code></pre>
221<p>Enough analysis, lets produce our first bit of Rust code.</p> 322<p>Enough analysis, lets produce our first bit of Rust code.</p>
222<h4 id="function-body">Function Body</h4> 323<h4 id="function-body">Function Body</h4>
223<p>Recall that the body of a curried <code>add</code> should look like this:</p> 324<p>Recall that the body of a curried <code>add</code> should look like
224<div class="sourceCode" id="cb16"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">return</span> <span class="kw">move</span> <span class="op">|</span>y<span class="op">|</span> <span class="kw">move</span> <span class="op">|</span>z<span class="op">|</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span></code></pre></div> 325this:</p>
326<div class="sourceCode" id="cb16"><pre
327class="sourceCode rust"><code class="sourceCode rust"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="cf">return</span> <span class="kw">move</span> <span class="op">|</span>y<span class="op">|</span> <span class="kw">move</span> <span class="op">|</span>z<span class="op">|</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span></code></pre></div>
225<p>And in general:</p> 328<p>And in general:</p>
226<div class="sourceCode" id="cb17"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="kw">return</span> <span class="kw">move</span> <span class="op">|</span>arg2<span class="op">|</span> <span class="kw">move</span> <span class="op">|</span>arg3<span class="op">|</span> <span class="op">...</span> <span class="op">|</span>argN<span class="op">|</span> <span class="op">&lt;</span>function body here<span class="op">&gt;</span></span></code></pre></div> 329<div class="sourceCode" id="cb17"><pre
227<p>We already have the function’s body, provided by <code>fn_body</code>, in our <code>generate_curry</code> function. All that’s left to add is the <code>move |arg2| move |arg3| ...</code> stuff, for which we need to extract the argument identifiers (doc: <a href="https://docs.rs/syn/1.0.18/syn/punctuated/struct.Punctuated.html">Punctuated</a>, <a href="https://docs.rs/syn/1.0.18/syn/enum.FnArg.html">FnArg</a>, <a href="https://docs.rs/syn/1.0.18/syn/struct.PatType.html">PatType</a>):</p> 330class="sourceCode rust"><code class="sourceCode rust"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="cf">return</span> <span class="kw">move</span> <span class="op">|</span>arg2<span class="op">|</span> <span class="kw">move</span> <span class="op">|</span>arg3<span class="op">|</span> <span class="op">...</span> <span class="op">|</span>argN<span class="op">|</span> <span class="op">&lt;</span>function body here<span class="op">&gt;</span></span></code></pre></div>
228<div class="sourceCode" id="cb18"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> 331<p>We already have the function’s body, provided by
332<code>fn_body</code>, in our <code>generate_curry</code> function. All
333that’s left to add is the <code>move |arg2| move |arg3| ...</code>
334stuff, for which we need to extract the argument identifiers (doc: <a
335href="https://docs.rs/syn/1.0.18/syn/punctuated/struct.Punctuated.html">Punctuated</a>,
336<a href="https://docs.rs/syn/1.0.18/syn/enum.FnArg.html">FnArg</a>, <a
337href="https://docs.rs/syn/1.0.18/syn/struct.PatType.html">PatType</a>):</p>
338<div class="sourceCode" id="cb18"><pre
339class="sourceCode rust"><code class="sourceCode rust"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span>
229<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">syn::punctuated::</span>Punctuated<span class="op">;</span></span> 340<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">syn::punctuated::</span>Punctuated<span class="op">;</span></span>
230<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">syn::</span><span class="op">{</span>parse_macro_input<span class="op">,</span> FnArg<span class="op">,</span> Pat<span class="op">,</span> ItemFn<span class="op">,</span> Block<span class="op">};</span></span> 341<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">syn::</span><span class="op">{</span>parse_macro_input<span class="op">,</span> FnArg<span class="op">,</span> Pat<span class="op">,</span> ItemFn<span class="op">,</span> Block<span class="op">};</span></span>
231<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a></span> 342<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a></span>
232<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_arg_idents(fn_args<span class="op">:</span> Punctuated<span class="op">&lt;</span>FnArg<span class="op">,</span> <span class="pp">syn::token::</span>Comma<span class="op">&gt;</span>) <span class="op">-&gt;</span> <span class="dt">Vec</span><span class="op">&lt;</span><span class="dt">Box</span><span class="op">&lt;</span>Pat<span class="op">&gt;&gt;</span> <span class="op">{</span> </span> 343<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_arg_idents(fn_args<span class="op">:</span> Punctuated<span class="op">&lt;</span>FnArg<span class="op">,</span> <span class="pp">syn::token::</span>Comma<span class="op">&gt;</span>) <span class="op">-&gt;</span> <span class="dt">Vec</span><span class="op">&lt;</span><span class="dt">Box</span><span class="op">&lt;</span>Pat<span class="op">&gt;&gt;</span> <span class="op">{</span> </span>
233<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> fn_args<span class="op">.</span>into_iter()<span class="op">.</span>map(extract_arg_pat)<span class="op">.</span><span class="pp">collect::</span><span class="op">&lt;</span><span class="dt">Vec</span><span class="op">&lt;</span>_<span class="op">&gt;&gt;</span>()<span class="op">;</span></span> 344<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> fn_args<span class="op">.</span>into_iter()<span class="op">.</span>map(extract_arg_pat)<span class="op">.</span><span class="pp">collect::</span><span class="op">&lt;</span><span class="dt">Vec</span><span class="op">&lt;</span>_<span class="op">&gt;&gt;</span>()<span class="op">;</span></span>
234<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 345<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
235<p>Alright, so we are iterating over function args (<code>Punctuated</code> is a collection that you can iterate over) and mapping an <code>extract_arg_pat</code> to every item. What’s <code>extract_arg_pat</code>?</p> 346<p>Alright, so we are iterating over function args
236<div class="sourceCode" id="cb19"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> 347(<code>Punctuated</code> is a collection that you can iterate over) and
348mapping an <code>extract_arg_pat</code> to every item. What’s
349<code>extract_arg_pat</code>?</p>
350<div class="sourceCode" id="cb19"><pre
351class="sourceCode rust"><code class="sourceCode rust"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span>
237<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a></span> 352<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a></span>
238<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_arg_pat(a<span class="op">:</span> FnArg) <span class="op">-&gt;</span> <span class="dt">Box</span><span class="op">&lt;</span>Pat<span class="op">&gt;</span> <span class="op">{</span></span> 353<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_arg_pat(a<span class="op">:</span> FnArg) <span class="op">-&gt;</span> <span class="dt">Box</span><span class="op">&lt;</span>Pat<span class="op">&gt;</span> <span class="op">{</span></span>
239<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">match</span> a <span class="op">{</span></span> 354<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">match</span> a <span class="op">{</span></span>
240<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a> <span class="pp">FnArg::</span>Typed(p) <span class="op">=&gt;</span> p<span class="op">.</span>pat<span class="op">,</span></span> 355<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a> <span class="pp">FnArg::</span>Typed(p) <span class="op">=&gt;</span> p<span class="op">.</span>pat<span class="op">,</span></span>
241<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a> _ <span class="op">=&gt;</span> <span class="pp">panic!</span>(<span class="st">&quot;Not supported on types with `self`!&quot;</span>)<span class="op">,</span></span> 356<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a> _ <span class="op">=&gt;</span> <span class="pp">panic!</span>(<span class="st">&quot;Not supported on types with `self`!&quot;</span>)<span class="op">,</span></span>
242<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> 357<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
243<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 358<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
244<p><code>FnArg</code> is an enum type as you might have guessed. The <code>Typed</code> variant encompasses args that are written as <code>name: type</code> and the other variant, <code>Reciever</code> refers to <code>self</code> types. Ignore those for now, keep it simple.</p> 359<p><code>FnArg</code> is an enum type as you might have guessed. The
245<p>Every <code>FnArg::Typed</code> value contains a <code>pat</code>, which is in essence, the name of the argument. The type of the arg is accessible via <code>p.ty</code> (we will be using this later).</p> 360<code>Typed</code> variant encompasses args that are written as
246<p>With that done, we should be able to write the codegen for the function body:</p> 361<code>name: type</code> and the other variant, <code>Reciever</code>
247<div class="sourceCode" id="cb20"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> 362refers to <code>self</code> types. Ignore those for now, keep it
363simple.</p>
364<p>Every <code>FnArg::Typed</code> value contains a <code>pat</code>,
365which is in essence, the name of the argument. The type of the arg is
366accessible via <code>p.ty</code> (we will be using this later).</p>
367<p>With that done, we should be able to write the codegen for the
368function body:</p>
369<div class="sourceCode" id="cb20"><pre
370class="sourceCode rust"><code class="sourceCode rust"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span>
248<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a></span> 371<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a></span>
249<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> generate_body(fn_args<span class="op">:</span> <span class="op">&amp;</span>[<span class="dt">Box</span><span class="op">&lt;</span>Pat<span class="op">&gt;</span>]<span class="op">,</span> body<span class="op">:</span> <span class="dt">Box</span><span class="op">&lt;</span>Block<span class="op">&gt;</span>) <span class="op">-&gt;</span> <span class="pp">proc_macro2::</span>TokenStream <span class="op">{</span></span> 372<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> generate_body(fn_args<span class="op">:</span> <span class="op">&amp;</span>[<span class="dt">Box</span><span class="op">&lt;</span>Pat<span class="op">&gt;</span>]<span class="op">,</span> body<span class="op">:</span> <span class="dt">Box</span><span class="op">&lt;</span>Block<span class="op">&gt;</span>) <span class="op">-&gt;</span> <span class="pp">proc_macro2::</span>TokenStream <span class="op">{</span></span>
250<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a> <span class="pp">quote!</span> <span class="op">{</span></span> 373<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a> <span class="pp">quote!</span> <span class="op">{</span></span>
251<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> #( <span class="kw">move</span> <span class="op">|</span>#fn_args<span class="op">|</span> )<span class="op">*</span> #body</span> 374<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> #( <span class="kw">move</span> <span class="op">|</span>#fn_args<span class="op">|</span> )<span class="op">*</span> #body</span>
252<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> 375<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
253<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 376<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
254<p>That is some scary looking syntax! Allow me to explain. The <code>quote!{ ... }</code> returns a <code>proc_macro2::TokenStream</code>, if we wrote <code>quote!{ let x = 1 + 2; }</code>, it wouldn’t create a new variable <code>x</code> with value 3, it would literally produce a stream of tokens with that expression.</p> 377<p>That is some scary looking syntax! Allow me to explain. The
255<p>The <code>#</code> enables variable interpolation. <code>#body</code> will look for <code>body</code> in the current scope, take its value, and insert it in the returned <code>TokenStream</code>. Kinda like quasi quoting in LISPs, you have written one.</p> 378<code>quote!{ ... }</code> returns a
256<p>What about <code>#( move |#fn_args| )*</code>? That is repetition. <code>quote</code> iterates through <code>fn_args</code>, and drops a <code>move</code> behind each one, it then places pipes (<code>|</code>), around it.</p> 379<code>proc_macro2::TokenStream</code>, if we wrote
257<p>Let us test our first bit of codegen! Modify <code>generate_curry</code> like so:</p> 380<code>quote!{ let x = 1 + 2; }</code>, it wouldn’t create a new variable
258<div class="sourceCode" id="cb21"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> 381<code>x</code> with value 3, it would literally produce a stream of
382tokens with that expression.</p>
383<p>The <code>#</code> enables variable interpolation. <code>#body</code>
384will look for <code>body</code> in the current scope, take its value,
385and insert it in the returned <code>TokenStream</code>. Kinda like quasi
386quoting in LISPs, you have written one.</p>
387<p>What about <code>#( move |#fn_args| )*</code>? That is repetition.
388<code>quote</code> iterates through <code>fn_args</code>, and drops a
389<code>move</code> behind each one, it then places pipes
390(<code>|</code>), around it.</p>
391<p>Let us test our first bit of codegen! Modify
392<code>generate_curry</code> like so:</p>
393<div class="sourceCode" id="cb21"><pre
394class="sourceCode rust"><code class="sourceCode rust"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span>
259<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a></span> 395<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a></span>
260<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">fn</span> generate_curry(parsed<span class="op">:</span> ItemFn) <span class="op">-&gt;</span> TokenStream <span class="op">{</span></span> 396<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">fn</span> generate_curry(parsed<span class="op">:</span> ItemFn) <span class="op">-&gt;</span> TokenStream <span class="op">{</span></span>
261<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_body <span class="op">=</span> parsed<span class="op">.</span>block<span class="op">;</span></span> 397<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_body <span class="op">=</span> parsed<span class="op">.</span>block<span class="op">;</span></span>
@@ -272,10 +408,11 @@ syn::token::Fn --&#39; / \ (output)
272<span id="cb21-15"><a href="#cb21-15" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="kw">let</span> curried_body <span class="op">=</span> generate_body(<span class="op">&amp;</span>arg_idents[<span class="dv">1</span><span class="op">..</span>]<span class="op">,</span> fn_body<span class="op">.</span>clone())<span class="op">;</span></span> 408<span id="cb21-15"><a href="#cb21-15" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="kw">let</span> curried_body <span class="op">=</span> generate_body(<span class="op">&amp;</span>arg_idents[<span class="dv">1</span><span class="op">..</span>]<span class="op">,</span> fn_body<span class="op">.</span>clone())<span class="op">;</span></span>
273<span id="cb21-16"><a href="#cb21-16" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="pp">println!</span>(<span class="st">&quot;{}&quot;</span><span class="op">,</span> curried_body)<span class="op">;</span></span> 409<span id="cb21-16"><a href="#cb21-16" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="pp">println!</span>(<span class="st">&quot;{}&quot;</span><span class="op">,</span> curried_body)<span class="op">;</span></span>
274<span id="cb21-17"><a href="#cb21-17" aria-hidden="true" tabindex="-1"></a></span> 410<span id="cb21-17"><a href="#cb21-17" aria-hidden="true" tabindex="-1"></a></span>
275<span id="cb21-18"><a href="#cb21-18" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> <span class="pp">TokenStream::</span>new()<span class="op">;</span></span> 411<span id="cb21-18"><a href="#cb21-18" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="pp">TokenStream::</span>new()<span class="op">;</span></span>
276<span id="cb21-19"><a href="#cb21-19" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div> 412<span id="cb21-19"><a href="#cb21-19" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div>
277<p>Add a little test to <code>tests/</code>:</p> 413<p>Add a little test to <code>tests/</code>:</p>
278<div class="sourceCode" id="cb22"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="co">// tests/smoke.rs</span></span> 414<div class="sourceCode" id="cb22"><pre
415class="sourceCode rust"><code class="sourceCode rust"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="co">// tests/smoke.rs</span></span>
279<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a></span> 416<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a></span>
280<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span><span class="pp">currying::</span>curry<span class="at">]</span></span> 417<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span><span class="pp">currying::</span>curry<span class="at">]</span></span>
281<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> y<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> z<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="dt">u32</span> <span class="op">{</span></span> 418<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> y<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> z<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="dt">u32</span> <span class="op">{</span></span>
@@ -286,17 +423,23 @@ syn::token::Fn --&#39; / \ (output)
286<span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> works() <span class="op">{</span></span> 423<span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> works() <span class="op">{</span></span>
287<span id="cb22-10"><a href="#cb22-10" aria-hidden="true" tabindex="-1"></a> <span class="pp">assert!</span>(<span class="cn">true</span>)<span class="op">;</span></span> 424<span id="cb22-10"><a href="#cb22-10" aria-hidden="true" tabindex="-1"></a> <span class="pp">assert!</span>(<span class="cn">true</span>)<span class="op">;</span></span>
288<span id="cb22-11"><a href="#cb22-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 425<span id="cb22-11"><a href="#cb22-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
289<p>You should find something like this in the output of <code>cargo test</code>:</p> 426<p>You should find something like this in the output of
427<code>cargo test</code>:</p>
290<pre><code>return move | y | move | z | { x + y + z }</code></pre> 428<pre><code>return move | y | move | z | { x + y + z }</code></pre>
291<p>Glorious <code>println!</code> debugging!</p> 429<p>Glorious <code>println!</code> debugging!</p>
292<h4 id="function-signature">Function signature</h4> 430<h4 id="function-signature">Function signature</h4>
293<p>This section gets into the more complicated bits of the macro, generating type aliases and the function signature. By the end of this section, we should have a full working auto-currying macro!</p> 431<p>This section gets into the more complicated bits of the macro,
294<p>Recall what our generated type aliases should look like, for our <code>add</code> function:</p> 432generating type aliases and the function signature. By the end of this
295<div class="sourceCode" id="cb24"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span> 433section, we should have a full working auto-currying macro!</p>
434<p>Recall what our generated type aliases should look like, for our
435<code>add</code> function:</p>
436<div class="sourceCode" id="cb24"><pre
437class="sourceCode rust"><code class="sourceCode rust"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span>
296<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> T0<span class="op">;</span></span> 438<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> T0<span class="op">;</span></span>
297<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T2 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> T1<span class="op">;</span></span></code></pre></div> 439<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T2 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> T1<span class="op">;</span></span></code></pre></div>
298<p>In general:</p> 440<p>In general:</p>
299<div class="sourceCode" id="cb25"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="op">&lt;</span><span class="kw">return</span> <span class="kw">type</span>&gt;<span class="op">;</span></span> 441<div class="sourceCode" id="cb25"><pre
442class="sourceCode rust"><code class="sourceCode rust"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="op">&lt;</span><span class="cf">return</span> <span class="kw">type</span>&gt;<span class="op">;</span></span>
300<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="op">&lt;</span><span class="kw">type</span> of arg N&gt;) -&gt; T0<span class="op">;</span></span> 443<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="op">&lt;</span><span class="kw">type</span> of arg N&gt;) -&gt; T0<span class="op">;</span></span>
301<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T2 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="op">&lt;</span><span class="kw">type</span> of arg N - 1&gt;) -&gt; T1<span class="op">;</span></span> 444<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T2 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="op">&lt;</span><span class="kw">type</span> of arg N - 1&gt;) -&gt; T1<span class="op">;</span></span>
302<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a><span class="op">.</span></span> 445<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a><span class="op">.</span></span>
@@ -308,42 +451,59 @@ syn::token::Fn --&#39; / \ (output)
308<li>all our inputs (arguments)</li> 451<li>all our inputs (arguments)</li>
309<li>the output (the return type)</li> 452<li>the output (the return type)</li>
310</ul> 453</ul>
311<p>To fetch the types of all our inputs, we can simply reuse the bits we wrote to fetch the names of all our inputs! (doc: <a href="https://docs.rs/syn/1.0.18/syn/enum.Type.html">Type</a>)</p> 454<p>To fetch the types of all our inputs, we can simply reuse the bits we
312<div class="sourceCode" id="cb26"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> 455wrote to fetch the names of all our inputs! (doc: <a
456href="https://docs.rs/syn/1.0.18/syn/enum.Type.html">Type</a>)</p>
457<div class="sourceCode" id="cb26"><pre
458class="sourceCode rust"><code class="sourceCode rust"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span>
313<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a></span> 459<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a></span>
314<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">syn::</span><span class="op">{</span>parse_macro_input<span class="op">,</span> Block<span class="op">,</span> FnArg<span class="op">,</span> ItemFn<span class="op">,</span> Pat<span class="op">,</span> ReturnType<span class="op">,</span> Type<span class="op">};</span></span> 460<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">syn::</span><span class="op">{</span>parse_macro_input<span class="op">,</span> Block<span class="op">,</span> FnArg<span class="op">,</span> ItemFn<span class="op">,</span> Pat<span class="op">,</span> ReturnType<span class="op">,</span> Type<span class="op">};</span></span>
315<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a></span> 461<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a></span>
316<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_type(a<span class="op">:</span> FnArg) <span class="op">-&gt;</span> <span class="dt">Box</span><span class="op">&lt;</span>Type<span class="op">&gt;</span> <span class="op">{</span></span> 462<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_type(a<span class="op">:</span> FnArg) <span class="op">-&gt;</span> <span class="dt">Box</span><span class="op">&lt;</span>Type<span class="op">&gt;</span> <span class="op">{</span></span>
317<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">match</span> a <span class="op">{</span></span> 463<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">match</span> a <span class="op">{</span></span>
318<span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a> <span class="pp">FnArg::</span>Typed(p) <span class="op">=&gt;</span> p<span class="op">.</span>ty<span class="op">,</span> <span class="co">// notice `ty` instead of `pat`</span></span> 464<span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a> <span class="pp">FnArg::</span>Typed(p) <span class="op">=&gt;</span> p<span class="op">.</span>ty<span class="op">,</span> <span class="co">// notice `ty` instead of `pat`</span></span>
319<span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a> _ <span class="op">=&gt;</span> <span class="pp">panic!</span>(<span class="st">&quot;Not supported on types with `self`!&quot;</span>)<span class="op">,</span></span> 465<span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a> _ <span class="op">=&gt;</span> <span class="pp">panic!</span>(<span class="st">&quot;Not supported on types with `self`!&quot;</span>)<span class="op">,</span></span>
320<span id="cb26-9"><a href="#cb26-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> 466<span id="cb26-9"><a href="#cb26-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
321<span id="cb26-10"><a href="#cb26-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> 467<span id="cb26-10"><a href="#cb26-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
322<span id="cb26-11"><a href="#cb26-11" aria-hidden="true" tabindex="-1"></a></span> 468<span id="cb26-11"><a href="#cb26-11" aria-hidden="true" tabindex="-1"></a></span>
323<span id="cb26-12"><a href="#cb26-12" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_arg_types(fn_args<span class="op">:</span> Punctuated<span class="op">&lt;</span>FnArg<span class="op">,</span> <span class="pp">syn::token::</span>Comma<span class="op">&gt;</span>) <span class="op">-&gt;</span> <span class="dt">Vec</span><span class="op">&lt;</span><span class="dt">Box</span><span class="op">&lt;</span>Type<span class="op">&gt;&gt;</span> <span class="op">{</span></span> 469<span id="cb26-12"><a href="#cb26-12" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_arg_types(fn_args<span class="op">:</span> Punctuated<span class="op">&lt;</span>FnArg<span class="op">,</span> <span class="pp">syn::token::</span>Comma<span class="op">&gt;</span>) <span class="op">-&gt;</span> <span class="dt">Vec</span><span class="op">&lt;</span><span class="dt">Box</span><span class="op">&lt;</span>Type<span class="op">&gt;&gt;</span> <span class="op">{</span></span>
324<span id="cb26-13"><a href="#cb26-13" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> fn_args<span class="op">.</span>into_iter()<span class="op">.</span>map(extract_type)<span class="op">.</span><span class="pp">collect::</span><span class="op">&lt;</span><span class="dt">Vec</span><span class="op">&lt;</span>_<span class="op">&gt;&gt;</span>()<span class="op">;</span></span> 470<span id="cb26-13"><a href="#cb26-13" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> fn_args<span class="op">.</span>into_iter()<span class="op">.</span>map(extract_type)<span class="op">.</span><span class="pp">collect::</span><span class="op">&lt;</span><span class="dt">Vec</span><span class="op">&lt;</span>_<span class="op">&gt;&gt;</span>()<span class="op">;</span></span>
325<span id="cb26-14"><a href="#cb26-14" aria-hidden="true" tabindex="-1"></a></span> 471<span id="cb26-14"><a href="#cb26-14" aria-hidden="true" tabindex="-1"></a></span>
326<span id="cb26-15"><a href="#cb26-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 472<span id="cb26-15"><a href="#cb26-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
327<p>A good reader would have looked at the docs for output member of the <code>syn::Signature</code> struct. It has the type <code>syn::ReturnType</code>. So there is no extraction to do here right? There are actually a couple of things we have to ensure here:</p> 473<p>A good reader would have looked at the docs for output member of the
474<code>syn::Signature</code> struct. It has the type
475<code>syn::ReturnType</code>. So there is no extraction to do here
476right? There are actually a couple of things we have to ensure here:</p>
328<ol type="1"> 477<ol type="1">
329<li><p>We need to ensure that the function returns! A function that does not return is pointless in this case, and I will tell you why, in the <a href="#notes">Notes</a> section.</p></li> 478<li><p>We need to ensure that the function returns! A function that does
330<li><p>A <code>ReturnType</code> encloses the arrow of the return as well, we need to get rid of that. Recall:</p> 479not return is pointless in this case, and I will tell you why, in the <a
331<div class="sourceCode" id="cb27"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span></span> 480href="#notes">Notes</a> section.</p></li>
481<li><p>A <code>ReturnType</code> encloses the arrow of the return as
482well, we need to get rid of that. Recall:</p>
483<div class="sourceCode" id="cb27"><pre
484class="sourceCode rust"><code class="sourceCode rust"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span></span>
332<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a><span class="co">// and not</span></span> 485<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a><span class="co">// and not</span></span>
333<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="op">-&gt;</span> <span class="dt">u32</span></span></code></pre></div></li> 486<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="op">-&gt;</span> <span class="dt">u32</span></span></code></pre></div></li>
334</ol> 487</ol>
335<p>Here is the snippet that handles extraction of the return type (doc: <a href="https://docs.rs/syn/1.0.19/syn/enum.ReturnType.html">syn::ReturnType</a>):</p> 488<p>Here is the snippet that handles extraction of the return type (doc:
336<div class="sourceCode" id="cb28"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> 489<a
490href="https://docs.rs/syn/1.0.19/syn/enum.ReturnType.html">syn::ReturnType</a>):</p>
491<div class="sourceCode" id="cb28"><pre
492class="sourceCode rust"><code class="sourceCode rust"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span>
337<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a></span> 493<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a></span>
338<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_return_type(a<span class="op">:</span> ReturnType) <span class="op">-&gt;</span> <span class="dt">Box</span><span class="op">&lt;</span>Type<span class="op">&gt;</span> <span class="op">{</span></span> 494<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> extract_return_type(a<span class="op">:</span> ReturnType) <span class="op">-&gt;</span> <span class="dt">Box</span><span class="op">&lt;</span>Type<span class="op">&gt;</span> <span class="op">{</span></span>
339<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">match</span> a <span class="op">{</span></span> 495<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">match</span> a <span class="op">{</span></span>
340<span id="cb28-5"><a href="#cb28-5" aria-hidden="true" tabindex="-1"></a> <span class="pp">ReturnType::</span>Type(_<span class="op">,</span> p) <span class="op">=&gt;</span> p<span class="op">,</span></span> 496<span id="cb28-5"><a href="#cb28-5" aria-hidden="true" tabindex="-1"></a> <span class="pp">ReturnType::</span>Type(_<span class="op">,</span> p) <span class="op">=&gt;</span> p<span class="op">,</span></span>
341<span id="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a> _ <span class="op">=&gt;</span> <span class="pp">panic!</span>(<span class="st">&quot;Not supported on functions without return types!&quot;</span>)<span class="op">,</span></span> 497<span id="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a> _ <span class="op">=&gt;</span> <span class="pp">panic!</span>(<span class="st">&quot;Not supported on functions without return types!&quot;</span>)<span class="op">,</span></span>
342<span id="cb28-7"><a href="#cb28-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> 498<span id="cb28-7"><a href="#cb28-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
343<span id="cb28-8"><a href="#cb28-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 499<span id="cb28-8"><a href="#cb28-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
344<p>You might notice that we are making extensive use of the <code>panic!</code> macro. Well, that is because it is a good idea to quit on receiving an unsatisfactory <code>TokenStream</code>.</p> 500<p>You might notice that we are making extensive use of the
345<p>With all our types ready, we can get on with generating type aliases:</p> 501<code>panic!</code> macro. Well, that is because it is a good idea to
346<div class="sourceCode" id="cb29"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> 502quit on receiving an unsatisfactory <code>TokenStream</code>.</p>
503<p>With all our types ready, we can get on with generating type
504aliases:</p>
505<div class="sourceCode" id="cb29"><pre
506class="sourceCode rust"><code class="sourceCode rust"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span>
347<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a></span> 507<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a></span>
348<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">quote::</span><span class="op">{</span>quote<span class="op">,</span> format_ident<span class="op">};</span></span> 508<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">quote::</span><span class="op">{</span>quote<span class="op">,</span> format_ident<span class="op">};</span></span>
349<span id="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a></span> 509<span id="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a></span>
@@ -357,7 +517,7 @@ syn::token::Fn --&#39; / \ (output)
357<span id="cb29-12"><a href="#cb29-12" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> <span class="kw">mut</span> type_aliases <span class="op">=</span> <span class="pp">vec!</span>[<span class="pp">quote!</span> <span class="op">{</span> <span class="kw">type</span> #type_t0 <span class="op">=</span> #fn_return_type <span class="op">}</span>]<span class="op">;</span></span> 517<span id="cb29-12"><a href="#cb29-12" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> <span class="kw">mut</span> type_aliases <span class="op">=</span> <span class="pp">vec!</span>[<span class="pp">quote!</span> <span class="op">{</span> <span class="kw">type</span> #type_t0 <span class="op">=</span> #fn_return_type <span class="op">}</span>]<span class="op">;</span></span>
358<span id="cb29-13"><a href="#cb29-13" aria-hidden="true" tabindex="-1"></a></span> 518<span id="cb29-13"><a href="#cb29-13" aria-hidden="true" tabindex="-1"></a></span>
359<span id="cb29-14"><a href="#cb29-14" aria-hidden="true" tabindex="-1"></a> <span class="co">// 3</span></span> 519<span id="cb29-14"><a href="#cb29-14" aria-hidden="true" tabindex="-1"></a> <span class="co">// 3</span></span>
360<span id="cb29-15"><a href="#cb29-15" aria-hidden="true" tabindex="-1"></a> <span class="kw">for</span> (i<span class="op">,</span> t) <span class="kw">in</span> (<span class="dv">1</span><span class="op">..</span>)<span class="op">.</span>zip(fn_arg_types<span class="op">.</span>into_iter()<span class="op">.</span>rev()) <span class="op">{</span></span> 520<span id="cb29-15"><a href="#cb29-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> (i<span class="op">,</span> t) <span class="kw">in</span> (<span class="dv">1</span><span class="op">..</span>)<span class="op">.</span>zip(fn_arg_types<span class="op">.</span>into_iter()<span class="op">.</span>rev()) <span class="op">{</span></span>
361<span id="cb29-16"><a href="#cb29-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> p <span class="op">=</span> <span class="pp">format_ident!</span>(<span class="st">&quot;_{}_{}&quot;</span><span class="op">,</span> fn_name<span class="op">,</span> <span class="pp">format!</span>(<span class="st">&quot;T{}&quot;</span><span class="op">,</span> i <span class="op">-</span> <span class="dv">1</span>))<span class="op">;</span></span> 521<span id="cb29-16"><a href="#cb29-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> p <span class="op">=</span> <span class="pp">format_ident!</span>(<span class="st">&quot;_{}_{}&quot;</span><span class="op">,</span> fn_name<span class="op">,</span> <span class="pp">format!</span>(<span class="st">&quot;T{}&quot;</span><span class="op">,</span> i <span class="op">-</span> <span class="dv">1</span>))<span class="op">;</span></span>
362<span id="cb29-17"><a href="#cb29-17" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> n <span class="op">=</span> <span class="pp">format_ident!</span>(<span class="st">&quot;_{}_{}&quot;</span><span class="op">,</span> fn_name<span class="op">,</span> <span class="pp">format!</span>(<span class="st">&quot;T{}&quot;</span><span class="op">,</span> i))<span class="op">;</span></span> 522<span id="cb29-17"><a href="#cb29-17" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> n <span class="op">=</span> <span class="pp">format_ident!</span>(<span class="st">&quot;_{}_{}&quot;</span><span class="op">,</span> fn_name<span class="op">,</span> <span class="pp">format!</span>(<span class="st">&quot;T{}&quot;</span><span class="op">,</span> i))<span class="op">;</span></span>
363<span id="cb29-18"><a href="#cb29-18" aria-hidden="true" tabindex="-1"></a></span> 523<span id="cb29-18"><a href="#cb29-18" aria-hidden="true" tabindex="-1"></a></span>
@@ -366,45 +526,70 @@ syn::token::Fn --&#39; / \ (output)
366<span id="cb29-21"><a href="#cb29-21" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span>)<span class="op">;</span></span> 526<span id="cb29-21"><a href="#cb29-21" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span>)<span class="op">;</span></span>
367<span id="cb29-22"><a href="#cb29-22" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> 527<span id="cb29-22"><a href="#cb29-22" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
368<span id="cb29-23"><a href="#cb29-23" aria-hidden="true" tabindex="-1"></a></span> 528<span id="cb29-23"><a href="#cb29-23" aria-hidden="true" tabindex="-1"></a></span>
369<span id="cb29-24"><a href="#cb29-24" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> type_aliases<span class="op">;</span></span> 529<span id="cb29-24"><a href="#cb29-24" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> type_aliases<span class="op">;</span></span>
370<span id="cb29-25"><a href="#cb29-25" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 530<span id="cb29-25"><a href="#cb29-25" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
371<p><strong>1. The return value</strong><br /> 531<p><strong>1. The return value</strong><br />
372We are returning a <code>Vec&lt;proc_macro2::TokenStream&gt;</code>, i. e., a list of <code>TokenStream</code>s, where each item is a type alias.</p> 532We are returning a <code>Vec&lt;proc_macro2::TokenStream&gt;</code>, i.
533e., a list of <code>TokenStream</code>s, where each item is a type
534alias.</p>
373<p><strong>2. Format identifier?</strong><br /> 535<p><strong>2. Format identifier?</strong><br />
374I’ve got some explanation to do on this line. Clearly, we are trying to write the first type alias, and initialize our <code>TokenStream</code> vector with <code>T0</code>, because it is different from the others:</p> 536I’ve got some explanation to do on this line. Clearly, we are trying to
375<div class="sourceCode" id="cb30"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> something</span> 537write the first type alias, and initialize our <code>TokenStream</code>
538vector with <code>T0</code>, because it is different from the
539others:</p>
540<div class="sourceCode" id="cb30"><pre
541class="sourceCode rust"><code class="sourceCode rust"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> something</span>
376<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a><span class="co">// the others are of the form</span></span> 542<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a><span class="co">// the others are of the form</span></span>
377<span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> Tr <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(something) <span class="op">-&gt;</span> something</span></code></pre></div> 543<span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> Tr <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(something) <span class="op">-&gt;</span> something</span></code></pre></div>
378<p><code>format_ident!</code> is similar to <code>format!</code>. Instead of returning a formatted string, it returns a <code>syn::Ident</code>. Therefore, <code>type_t0</code> is actually an identifier for, in the case of our <code>add</code> function, <code>_add_T0</code>. Why is this formatting important? Namespacing.</p> 544<p><code>format_ident!</code> is similar to <code>format!</code>.
379<p>Picture this, we have two functions, <code>add</code> and <code>subtract</code>, that we wish to curry with our macro:</p> 545Instead of returning a formatted string, it returns a
380<div class="sourceCode" id="cb31"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>curry<span class="at">]</span></span> 546<code>syn::Ident</code>. Therefore, <code>type_t0</code> is actually an
547identifier for, in the case of our <code>add</code> function,
548<code>_add_T0</code>. Why is this formatting important? Namespacing.</p>
549<p>Picture this, we have two functions, <code>add</code> and
550<code>subtract</code>, that we wish to curry with our macro:</p>
551<div class="sourceCode" id="cb31"><pre
552class="sourceCode rust"><code class="sourceCode rust"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>curry<span class="at">]</span></span>
381<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(<span class="op">...</span>) <span class="op">-&gt;</span> <span class="dt">u32</span> <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span> 553<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(<span class="op">...</span>) <span class="op">-&gt;</span> <span class="dt">u32</span> <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span>
382<span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a></span> 554<span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a></span>
383<span id="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>curry<span class="at">]</span></span> 555<span id="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>curry<span class="at">]</span></span>
384<span id="cb31-5"><a href="#cb31-5" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> sub(<span class="op">...</span>) <span class="op">-&gt;</span> <span class="dt">u32</span> <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span></code></pre></div> 556<span id="cb31-5"><a href="#cb31-5" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> sub(<span class="op">...</span>) <span class="op">-&gt;</span> <span class="dt">u32</span> <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span></code></pre></div>
385<p>Here is the same but with macros expanded:</p> 557<p>Here is the same but with macros expanded:</p>
386<div class="sourceCode" id="cb32"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span> 558<div class="sourceCode" id="cb32"><pre
559class="sourceCode rust"><code class="sourceCode rust"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span>
387<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> T0<span class="op">;</span></span> 560<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> T0<span class="op">;</span></span>
388<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add( <span class="op">...</span> ) <span class="op">-&gt;</span> T1 <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span> 561<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add( <span class="op">...</span> ) <span class="op">-&gt;</span> T1 <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span>
389<span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a></span> 562<span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a></span>
390<span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span> 563<span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span>
391<span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> T0<span class="op">;</span></span> 564<span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> T0<span class="op">;</span></span>
392<span id="cb32-7"><a href="#cb32-7" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> sub( <span class="op">...</span> ) <span class="op">-&gt;</span> T1 <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span></code></pre></div> 565<span id="cb32-7"><a href="#cb32-7" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> sub( <span class="op">...</span> ) <span class="op">-&gt;</span> T1 <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span></code></pre></div>
393<p>We end up with two definitions of <code>T0</code>! Now, if we do the little <code>format_ident!</code> dance we did up there:</p> 566<p>We end up with two definitions of <code>T0</code>! Now, if we do the
394<div class="sourceCode" id="cb33"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span> 567little <code>format_ident!</code> dance we did up there:</p>
568<div class="sourceCode" id="cb33"><pre
569class="sourceCode rust"><code class="sourceCode rust"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span>
395<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> _add_T0<span class="op">;</span></span> 570<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> _add_T0<span class="op">;</span></span>
396<span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add( <span class="op">...</span> ) <span class="op">-&gt;</span> _add_T1 <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span> 571<span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add( <span class="op">...</span> ) <span class="op">-&gt;</span> _add_T1 <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span>
397<span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a></span> 572<span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a></span>
398<span id="cb33-5"><a href="#cb33-5" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _sub_T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span> 573<span id="cb33-5"><a href="#cb33-5" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _sub_T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span>
399<span id="cb33-6"><a href="#cb33-6" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _sub_T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> _sub_T0<span class="op">;</span></span> 574<span id="cb33-6"><a href="#cb33-6" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _sub_T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> _sub_T0<span class="op">;</span></span>
400<span id="cb33-7"><a href="#cb33-7" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> sub( <span class="op">...</span> ) <span class="op">-&gt;</span> _sub_T1 <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span></code></pre></div> 575<span id="cb33-7"><a href="#cb33-7" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> sub( <span class="op">...</span> ) <span class="op">-&gt;</span> _sub_T1 <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span></code></pre></div>
401<p>Voilà! The type aliases don’t tread on each other. Remember to import <code>format_ident</code> from the <code>quote</code> crate.</p> 576<p>Voilà! The type aliases don’t tread on each other. Remember to import
577<code>format_ident</code> from the <code>quote</code> crate.</p>
402<p><strong>3. The TokenStream Vector</strong></p> 578<p><strong>3. The TokenStream Vector</strong></p>
403<p>We iterate over our types in reverse order (<code>T0</code> is the last return, <code>T1</code> is the second last, so on), assign a number to each iteration with <code>zip</code>, generate type names with <code>format_ident</code>, push a <code>TokenStream</code> with the help of <code>quote</code> and variable interpolation.</p> 579<p>We iterate over our types in reverse order (<code>T0</code> is the
404<p>If you are wondering why we used <code>(1..).zip()</code> instead of <code>.enumerate()</code>, it’s because we wanted to start counting from 1 instead of 0 (we are already done with <code>T0</code>!).</p> 580last return, <code>T1</code> is the second last, so on), assign a number
581to each iteration with <code>zip</code>, generate type names with
582<code>format_ident</code>, push a <code>TokenStream</code> with the help
583of <code>quote</code> and variable interpolation.</p>
584<p>If you are wondering why we used <code>(1..).zip()</code> instead of
585<code>.enumerate()</code>, it’s because we wanted to start counting from
5861 instead of 0 (we are already done with <code>T0</code>!).</p>
405<h4 id="getting-it-together">Getting it together</h4> 587<h4 id="getting-it-together">Getting it together</h4>
406<p>I promised we’d have a fully working macro by the end of last section. I lied, we have to tie everything together in our <code>generate_curry</code> function:</p> 588<p>I promised we’d have a fully working macro by the end of last
407<div class="sourceCode" id="cb34"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span> 589section. I lied, we have to tie everything together in our
590<code>generate_curry</code> function:</p>
591<div class="sourceCode" id="cb34"><pre
592class="sourceCode rust"><code class="sourceCode rust"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="co">// src/lib.rs</span></span>
408<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a></span> 593<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a></span>
409<span id="cb34-3"><a href="#cb34-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">fn</span> generate_curry(parsed<span class="op">:</span> ItemFn) <span class="op">-&gt;</span> <span class="pp">proc_macro2::</span>TokenStream <span class="op">{</span></span> 594<span id="cb34-3"><a href="#cb34-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">fn</span> generate_curry(parsed<span class="op">:</span> ItemFn) <span class="op">-&gt;</span> <span class="pp">proc_macro2::</span>TokenStream <span class="op">{</span></span>
410<span id="cb34-4"><a href="#cb34-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_body <span class="op">=</span> parsed<span class="op">.</span>block<span class="op">;</span></span> 595<span id="cb34-4"><a href="#cb34-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> fn_body <span class="op">=</span> parsed<span class="op">.</span>block<span class="op">;</span></span>
@@ -428,20 +613,39 @@ I’ve got some explanation to do on this line. Clearly, we are trying to write
428<span id="cb34-22"><a href="#cb34-22" aria-hidden="true" tabindex="-1"></a></span> 613<span id="cb34-22"><a href="#cb34-22" aria-hidden="true" tabindex="-1"></a></span>
429<span id="cb34-23"><a href="#cb34-23" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="kw">let</span> return_type <span class="op">=</span> <span class="pp">format_ident!</span>(<span class="st">&quot;_{}_{}&quot;</span><span class="op">,</span> <span class="op">&amp;</span>fn_name<span class="op">,</span> <span class="pp">format!</span>(<span class="st">&quot;T{}&quot;</span><span class="op">,</span> type_aliases<span class="op">.</span>len() <span class="op">-</span> <span class="dv">1</span>))<span class="op">;</span></span> 614<span id="cb34-23"><a href="#cb34-23" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="kw">let</span> return_type <span class="op">=</span> <span class="pp">format_ident!</span>(<span class="st">&quot;_{}_{}&quot;</span><span class="op">,</span> <span class="op">&amp;</span>fn_name<span class="op">,</span> <span class="pp">format!</span>(<span class="st">&quot;T{}&quot;</span><span class="op">,</span> type_aliases<span class="op">.</span>len() <span class="op">-</span> <span class="dv">1</span>))<span class="op">;</span></span>
430<span id="cb34-24"><a href="#cb34-24" aria-hidden="true" tabindex="-1"></a></span> 615<span id="cb34-24"><a href="#cb34-24" aria-hidden="true" tabindex="-1"></a></span>
431<span id="cb34-25"><a href="#cb34-25" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="kw">return</span> <span class="pp">quote!</span> <span class="op">{</span></span> 616<span id="cb34-25"><a href="#cb34-25" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="cf">return</span> <span class="pp">quote!</span> <span class="op">{</span></span>
432<span id="cb34-26"><a href="#cb34-26" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> #(#type_aliases)<span class="op">;*</span> <span class="op">;</span></span> 617<span id="cb34-26"><a href="#cb34-26" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> #(#type_aliases)<span class="op">;*</span> <span class="op">;</span></span>
433<span id="cb34-27"><a href="#cb34-27" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> #vis <span class="kw">fn</span> #fn_name (#first_ident<span class="op">:</span> #first_type) <span class="op">-&gt;</span> #return_type <span class="op">{</span></span> 618<span id="cb34-27"><a href="#cb34-27" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> #vis <span class="kw">fn</span> #fn_name (#first_ident<span class="op">:</span> #first_type) <span class="op">-&gt;</span> #return_type <span class="op">{</span></span>
434<span id="cb34-28"><a href="#cb34-28" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> #curried_body <span class="op">;</span></span> 619<span id="cb34-28"><a href="#cb34-28" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> #curried_body <span class="op">;</span></span>
435<span id="cb34-29"><a href="#cb34-29" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="op">}</span></span> 620<span id="cb34-29"><a href="#cb34-29" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="op">}</span></span>
436<span id="cb34-30"><a href="#cb34-30" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="op">};</span></span> 621<span id="cb34-30"><a href="#cb34-30" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="op">};</span></span>
437<span id="cb34-31"><a href="#cb34-31" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div> 622<span id="cb34-31"><a href="#cb34-31" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div>
438<p>Most of the additions are self explanatory, I’ll go through the return statement with you. We are returning a <code>quote!{ ... }</code>, so a <code>proc_macro2::TokenStream</code>. We are iterating through the <code>type_aliases</code> variable, which you might recall, is a <code>Vec&lt;TokenStream&gt;</code>. You might notice the sneaky semicolon before the <code>*</code>. This basically tells <code>quote</code>, to insert an item, then a semicolon, and then the next one, another semicolon, and so on. The semicolon is a separator. We need to manually insert another semicolon at the end of it all, <code>quote</code> doesn’t insert a separator at the end of the iteration.</p> 623<p>Most of the additions are self explanatory, I’ll go through the
439<p>We retain the visibility and name of our original function. Our curried function takes as args, just the first argument of our original function. The return type of our curried function is actually, the last type alias we create. If you think back to our manually curried <code>add</code> function, we returned <code>T2</code>, which was in fact, the last type alias we created.</p> 624return statement with you. We are returning a
440<p>I am sure, at this point, you are itching to test this out, but before that, let me introduce you to some good methods of debugging proc-macro code.</p> 625<code>quote!{ ... }</code>, so a <code>proc_macro2::TokenStream</code>.
626We are iterating through the <code>type_aliases</code> variable, which
627you might recall, is a <code>Vec&lt;TokenStream&gt;</code>. You might
628notice the sneaky semicolon before the <code>*</code>. This basically
629tells <code>quote</code>, to insert an item, then a semicolon, and then
630the next one, another semicolon, and so on. The semicolon is a
631separator. We need to manually insert another semicolon at the end of it
632all, <code>quote</code> doesn’t insert a separator at the end of the
633iteration.</p>
634<p>We retain the visibility and name of our original function. Our
635curried function takes as args, just the first argument of our original
636function. The return type of our curried function is actually, the last
637type alias we create. If you think back to our manually curried
638<code>add</code> function, we returned <code>T2</code>, which was in
639fact, the last type alias we created.</p>
640<p>I am sure, at this point, you are itching to test this out, but
641before that, let me introduce you to some good methods of debugging
642proc-macro code.</p>
441<h3 id="debugging-and-testing">Debugging and Testing</h3> 643<h3 id="debugging-and-testing">Debugging and Testing</h3>
442<p>Install <code>cargo-expand</code> via:</p> 644<p>Install <code>cargo-expand</code> via:</p>
443<pre><code>cargo install cargo-expand</code></pre> 645<pre><code>cargo install cargo-expand</code></pre>
444<p><code>cargo-expand</code> is a neat little tool that expands your macro in places where it is used, and lets you view the generated code! For example:</p> 646<p><code>cargo-expand</code> is a neat little tool that expands your
647macro in places where it is used, and lets you view the generated code!
648For example:</p>
445<pre class="shell"><code># create a bin package hello 649<pre class="shell"><code># create a bin package hello
446$ cargo new hello 650$ cargo new hello
447 651
@@ -463,10 +667,18 @@ fn main() {
463 )); 667 ));
464 }; 668 };
465}</code></pre> 669}</code></pre>
466<p>Writing proc-macros without <code>cargo-expand</code> is tantamount to driving a vehicle without rear view mirrors! Keep an eye on what is going on behind your back.</p> 670<p>Writing proc-macros without <code>cargo-expand</code> is tantamount
467<p>Now, your macro won’t always compile, you might just recieve the bee movie script as an error. <code>cargo-expand</code> will not work in such cases. I would suggest printing out your variables to inspect them. <code>TokenStream</code> implements <code>Display</code> as well as <code>Debug</code>. We don’t always have to be respectable programmers. Just print it.</p> 671to driving a vehicle without rear view mirrors! Keep an eye on what is
672going on behind your back.</p>
673<p>Now, your macro won’t always compile, you might just recieve the bee
674movie script as an error. <code>cargo-expand</code> will not work in
675such cases. I would suggest printing out your variables to inspect them.
676<code>TokenStream</code> implements <code>Display</code> as well as
677<code>Debug</code>. We don’t always have to be respectable programmers.
678Just print it.</p>
468<p>Enough of that, lets get testing:</p> 679<p>Enough of that, lets get testing:</p>
469<div class="sourceCode" id="cb37"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a><span class="co">// tests/smoke.rs</span></span> 680<div class="sourceCode" id="cb37"><pre
681class="sourceCode rust"><code class="sourceCode rust"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a><span class="co">// tests/smoke.rs</span></span>
470<span id="cb37-2"><a href="#cb37-2" aria-hidden="true" tabindex="-1"></a></span> 682<span id="cb37-2"><a href="#cb37-2" aria-hidden="true" tabindex="-1"></a></span>
471<span id="cb37-3"><a href="#cb37-3" aria-hidden="true" tabindex="-1"></a><span class="at">#![</span>feature<span class="at">(</span>type_alias_impl_trait<span class="at">)]</span></span> 683<span id="cb37-3"><a href="#cb37-3" aria-hidden="true" tabindex="-1"></a><span class="at">#![</span>feature<span class="at">(</span>type_alias_impl_trait<span class="at">)]</span></span>
472<span id="cb37-4"><a href="#cb37-4" aria-hidden="true" tabindex="-1"></a></span> 684<span id="cb37-4"><a href="#cb37-4" aria-hidden="true" tabindex="-1"></a></span>
@@ -479,55 +691,81 @@ fn main() {
479<span id="cb37-11"><a href="#cb37-11" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> works() <span class="op">{</span></span> 691<span id="cb37-11"><a href="#cb37-11" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> works() <span class="op">{</span></span>
480<span id="cb37-12"><a href="#cb37-12" aria-hidden="true" tabindex="-1"></a> <span class="pp">assert_eq!</span>(<span class="dv">15</span><span class="op">,</span> add(<span class="dv">4</span>)(<span class="dv">5</span>)(<span class="dv">6</span>))<span class="op">;</span></span> 692<span id="cb37-12"><a href="#cb37-12" aria-hidden="true" tabindex="-1"></a> <span class="pp">assert_eq!</span>(<span class="dv">15</span><span class="op">,</span> add(<span class="dv">4</span>)(<span class="dv">5</span>)(<span class="dv">6</span>))<span class="op">;</span></span>
481<span id="cb37-13"><a href="#cb37-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 693<span id="cb37-13"><a href="#cb37-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
482<p>Run <code>cargo +nightly test</code>. You should see a pleasing message:</p> 694<p>Run <code>cargo +nightly test</code>. You should see a pleasing
695message:</p>
483<pre><code>running 1 test 696<pre><code>running 1 test
484test tests::works ... ok</code></pre> 697test tests::works ... ok</code></pre>
485<p>Take a look at the expansion for our curry macro, via <code>cargo +nightly expand --tests smoke</code>:</p> 698<p>Take a look at the expansion for our curry macro, via
486<div class="sourceCode" id="cb39"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span> 699<code>cargo +nightly expand --tests smoke</code>:</p>
700<div class="sourceCode" id="cb39"><pre
701class="sourceCode rust"><code class="sourceCode rust"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T0 <span class="op">=</span> <span class="dt">u32</span><span class="op">;</span></span>
487<span id="cb39-2"><a href="#cb39-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> _add_T0<span class="op">;</span></span> 702<span id="cb39-2"><a href="#cb39-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T1 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> _add_T0<span class="op">;</span></span>
488<span id="cb39-3"><a href="#cb39-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T2 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> _add_T1<span class="op">;</span></span> 703<span id="cb39-3"><a href="#cb39-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _add_T2 <span class="op">=</span> <span class="kw">impl</span> <span class="bu">Fn</span>(<span class="dt">u32</span>) <span class="op">-&gt;</span> _add_T1<span class="op">;</span></span>
489<span id="cb39-4"><a href="#cb39-4" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> _add_T2 <span class="op">{</span></span> 704<span id="cb39-4"><a href="#cb39-4" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> add(x<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> _add_T2 <span class="op">{</span></span>
490<span id="cb39-5"><a href="#cb39-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> (<span class="kw">move</span> <span class="op">|</span>y<span class="op">|</span> <span class="op">{</span></span> 705<span id="cb39-5"><a href="#cb39-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> (<span class="kw">move</span> <span class="op">|</span>y<span class="op">|</span> <span class="op">{</span></span>
491<span id="cb39-6"><a href="#cb39-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">move</span> <span class="op">|</span>z<span class="op">|</span> <span class="op">{</span></span> 706<span id="cb39-6"><a href="#cb39-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">move</span> <span class="op">|</span>z<span class="op">|</span> <span class="op">{</span></span>
492<span id="cb39-7"><a href="#cb39-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span> 707<span id="cb39-7"><a href="#cb39-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> x <span class="op">+</span> y <span class="op">+</span> z<span class="op">;</span></span>
493<span id="cb39-8"><a href="#cb39-8" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> 708<span id="cb39-8"><a href="#cb39-8" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
494<span id="cb39-9"><a href="#cb39-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span>)<span class="op">;</span></span> 709<span id="cb39-9"><a href="#cb39-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span>)<span class="op">;</span></span>
495<span id="cb39-10"><a href="#cb39-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> 710<span id="cb39-10"><a href="#cb39-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
496<span id="cb39-11"><a href="#cb39-11" aria-hidden="true" tabindex="-1"></a></span> 711<span id="cb39-11"><a href="#cb39-11" aria-hidden="true" tabindex="-1"></a></span>
497<span id="cb39-12"><a href="#cb39-12" aria-hidden="true" tabindex="-1"></a><span class="co">// a bunch of other stuff generated by #[test] and assert_eq!</span></span></code></pre></div> 712<span id="cb39-12"><a href="#cb39-12" aria-hidden="true" tabindex="-1"></a><span class="co">// a bunch of other stuff generated by #[test] and assert_eq!</span></span></code></pre></div>
498<p>A sight for sore eyes.</p> 713<p>A sight for sore eyes.</p>
499<p>Here is a more complex example that generates ten multiples of the first ten natural numbers:</p> 714<p>Here is a more complex example that generates ten multiples of the
500<div class="sourceCode" id="cb40"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb40-1"><a href="#cb40-1" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>curry<span class="at">]</span></span> 715first ten natural numbers:</p>
716<div class="sourceCode" id="cb40"><pre
717class="sourceCode rust"><code class="sourceCode rust"><span id="cb40-1"><a href="#cb40-1" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>curry<span class="at">]</span></span>
501<span id="cb40-2"><a href="#cb40-2" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> product(x<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> y<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="dt">u32</span> <span class="op">{</span></span> 718<span id="cb40-2"><a href="#cb40-2" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> product(x<span class="op">:</span> <span class="dt">u32</span><span class="op">,</span> y<span class="op">:</span> <span class="dt">u32</span>) <span class="op">-&gt;</span> <span class="dt">u32</span> <span class="op">{</span></span>
502<span id="cb40-3"><a href="#cb40-3" aria-hidden="true" tabindex="-1"></a> x <span class="op">*</span> y</span> 719<span id="cb40-3"><a href="#cb40-3" aria-hidden="true" tabindex="-1"></a> x <span class="op">*</span> y</span>
503<span id="cb40-4"><a href="#cb40-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> 720<span id="cb40-4"><a href="#cb40-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
504<span id="cb40-5"><a href="#cb40-5" aria-hidden="true" tabindex="-1"></a></span> 721<span id="cb40-5"><a href="#cb40-5" aria-hidden="true" tabindex="-1"></a></span>
505<span id="cb40-6"><a href="#cb40-6" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> multiples() <span class="op">-&gt;</span> <span class="dt">Vec</span><span class="op">&lt;</span><span class="dt">Vec</span><span class="op">&lt;</span><span class="dt">u32</span><span class="op">&gt;&gt;{</span></span> 722<span id="cb40-6"><a href="#cb40-6" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> multiples() <span class="op">-&gt;</span> <span class="dt">Vec</span><span class="op">&lt;</span><span class="dt">Vec</span><span class="op">&lt;</span><span class="dt">u32</span><span class="op">&gt;&gt;{</span></span>
506<span id="cb40-7"><a href="#cb40-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> v <span class="op">=</span> (<span class="dv">1</span><span class="op">..=</span><span class="dv">10</span>)<span class="op">.</span>map(product)<span class="op">;</span></span> 723<span id="cb40-7"><a href="#cb40-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> v <span class="op">=</span> (<span class="dv">1</span><span class="op">..=</span><span class="dv">10</span>)<span class="op">.</span>map(product)<span class="op">;</span></span>
507<span id="cb40-8"><a href="#cb40-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span> (<span class="dv">1</span><span class="op">..=</span><span class="dv">10</span>)</span> 724<span id="cb40-8"><a href="#cb40-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> (<span class="dv">1</span><span class="op">..=</span><span class="dv">10</span>)</span>
508<span id="cb40-9"><a href="#cb40-9" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>map(<span class="op">|</span>x<span class="op">|</span> v<span class="op">.</span>clone()<span class="op">.</span>map(<span class="op">|</span>f<span class="op">|</span> f(x))<span class="op">.</span>collect())</span> 725<span id="cb40-9"><a href="#cb40-9" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>map(<span class="op">|</span>x<span class="op">|</span> v<span class="op">.</span>clone()<span class="op">.</span>map(<span class="op">|</span>f<span class="op">|</span> f(x))<span class="op">.</span>collect())</span>
509<span id="cb40-10"><a href="#cb40-10" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>collect()<span class="op">;</span></span> 726<span id="cb40-10"><a href="#cb40-10" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>collect()<span class="op">;</span></span>
510<span id="cb40-11"><a href="#cb40-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 727<span id="cb40-11"><a href="#cb40-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
511<h3 id="notes">Notes</h3> 728<h3 id="notes">Notes</h3>
512<p>I didn’t quite explain why we use <code>move |arg|</code> in our closure. This is because we want to take ownership of the variable supplied to us. Take a look at this example:</p> 729<p>I didn’t quite explain why we use <code>move |arg|</code> in our
513<div class="sourceCode" id="cb41"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb41-1"><a href="#cb41-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> v <span class="op">=</span> add(<span class="dv">5</span>)<span class="op">;</span></span> 730closure. This is because we want to take ownership of the variable
731supplied to us. Take a look at this example:</p>
732<div class="sourceCode" id="cb41"><pre
733class="sourceCode rust"><code class="sourceCode rust"><span id="cb41-1"><a href="#cb41-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> v <span class="op">=</span> add(<span class="dv">5</span>)<span class="op">;</span></span>
514<span id="cb41-2"><a href="#cb41-2" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> g<span class="op">;</span></span> 734<span id="cb41-2"><a href="#cb41-2" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> g<span class="op">;</span></span>
515<span id="cb41-3"><a href="#cb41-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span> 735<span id="cb41-3"><a href="#cb41-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
516<span id="cb41-4"><a href="#cb41-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> x <span class="op">=</span> <span class="dv">5</span><span class="op">;</span></span> 736<span id="cb41-4"><a href="#cb41-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> x <span class="op">=</span> <span class="dv">5</span><span class="op">;</span></span>
517<span id="cb41-5"><a href="#cb41-5" aria-hidden="true" tabindex="-1"></a> g <span class="op">=</span> v(x)<span class="op">;</span></span> 737<span id="cb41-5"><a href="#cb41-5" aria-hidden="true" tabindex="-1"></a> g <span class="op">=</span> v(x)<span class="op">;</span></span>
518<span id="cb41-6"><a href="#cb41-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> 738<span id="cb41-6"><a href="#cb41-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
519<span id="cb41-7"><a href="#cb41-7" aria-hidden="true" tabindex="-1"></a><span class="pp">println!</span>(<span class="st">&quot;{}&quot;</span><span class="op">,</span> g(<span class="dv">2</span>))<span class="op">;</span></span></code></pre></div> 739<span id="cb41-7"><a href="#cb41-7" aria-hidden="true" tabindex="-1"></a><span class="pp">println!</span>(<span class="st">&quot;{}&quot;</span><span class="op">,</span> g(<span class="dv">2</span>))<span class="op">;</span></span></code></pre></div>
520<p>Variable <code>x</code> goes out of scope before <code>g</code> can return a concrete value. If we take ownership of <code>x</code> by <code>move</code>ing it into our closure, we can expect this to work reliably. In fact, rustc understands this, and forces you to use <code>move</code>.</p> 740<p>Variable <code>x</code> goes out of scope before <code>g</code> can
521<p>This usage of <code>move</code> is exactly why <strong>a curried function without a return is useless</strong>. Every variable we pass to our curried function gets moved into its local scope. Playing with these variables cannot cause a change outside this scope. Returning is our only method of interaction with anything beyond this function.</p> 741return a concrete value. If we take ownership of <code>x</code> by
742<code>move</code>ing it into our closure, we can expect this to work
743reliably. In fact, rustc understands this, and forces you to use
744<code>move</code>.</p>
745<p>This usage of <code>move</code> is exactly why <strong>a curried
746function without a return is useless</strong>. Every variable we pass to
747our curried function gets moved into its local scope. Playing with these
748variables cannot cause a change outside this scope. Returning is our
749only method of interaction with anything beyond this function.</p>
522<h3 id="conclusion">Conclusion</h3> 750<h3 id="conclusion">Conclusion</h3>
523<p>Currying may not seem to be all that useful. Curried functions are unwieldy in Rust because the standard library is not built around currying. If you enjoy the possibilities posed by currying, consider taking a look at Haskell or Scheme.</p> 751<p>Currying may not seem to be all that useful. Curried functions are
524<p>My original intention with <a href="https://peppe.rs">peppe.rs</a> was to post condensed articles, a micro blog, but this one turned out extra long.</p> 752unwieldy in Rust because the standard library is not built around
753currying. If you enjoy the possibilities posed by currying, consider
754taking a look at Haskell or Scheme.</p>
755<p>My original intention with <a href="https://peppe.rs">peppe.rs</a>
756was to post condensed articles, a micro blog, but this one turned out
757extra long.</p>
525<p>Perhaps I should call it a ‘macro’ blog :)</p> 758<p>Perhaps I should call it a ‘macro’ blog :)</p>
526<section class="footnotes" role="doc-endnotes"> 759<section id="footnotes" class="footnotes footnotes-end-of-document"
760role="doc-endnotes">
527<hr /> 761<hr />
528<ol> 762<ol>
529<li id="fn1" role="doc-endnote"><p><a href="https://doc.rust-lang.org/book/ch13-01-closures.html">https://doc.rust-lang.org/book/ch13-01-closures.html</a><a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li> 763<li id="fn1"><p><a
530<li id="fn2" role="doc-endnote"><p><a href="https://caniuse.rs">caniuse.rs</a> contains an indexed list of features and their status.<a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li> 764href="https://doc.rust-lang.org/book/ch13-01-closures.html">https://doc.rust-lang.org/book/ch13-01-closures.html</a><a
765href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
766<li id="fn2"><p><a href="https://caniuse.rs">caniuse.rs</a> contains an
767indexed list of features and their status.<a href="#fnref2"
768class="footnote-back" role="doc-backlink">↩︎</a></p></li>
531</ol> 769</ol>
532</section> 770</section>
533 771
diff --git a/docs/posts/bash_harder_with_vim/index.html b/docs/posts/bash_harder_with_vim/index.html
index 099733a..96210d5 100644
--- a/docs/posts/bash_harder_with_vim/index.html
+++ b/docs/posts/bash_harder_with_vim/index.html
@@ -28,7 +28,7 @@
28 31/07 — 2019 28 31/07 — 2019
29 <div class="stats"> 29 <div class="stats">
30 <span class="stats-number"> 30 <span class="stats-number">
31 24.37 31 24.38
32 </span> 32 </span>
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
@@ -42,18 +42,26 @@
42 Bash Harder With Vim 42 Bash Harder With Vim
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>Bash is tricky, don’t let your editor get in your way. Here’s a couple of neat additions you could make to your <code>vimrc</code> for a better shell programming experience.</p> 45 <p>Bash is tricky, don’t let your editor get in your way. Here’s a
46couple of neat additions you could make to your <code>vimrc</code> for a
47better shell programming experience.</p>
46<h3 id="man-pages-inside-vim">Man pages inside vim</h3> 48<h3 id="man-pages-inside-vim">Man pages inside vim</h3>
47<p>Source this script to get started:</p> 49<p>Source this script to get started:</p>
48<pre><code>runtime ftplugin/man.vim</code></pre> 50<pre><code>runtime ftplugin/man.vim</code></pre>
49<p>Now, you can open manpages inside vim with <code>:Man</code>! It adds nicer syntax highlighting and the ability to jump around with <code>Ctrl-]</code> and <code>Ctrl-T</code>.</p> 51<p>Now, you can open manpages inside vim with <code>:Man</code>! It adds
50<p>By default, the manpage is opened in a horizontal split, I prefer using a new tab:</p> 52nicer syntax highlighting and the ability to jump around with
53<code>Ctrl-]</code> and <code>Ctrl-T</code>.</p>
54<p>By default, the manpage is opened in a horizontal split, I prefer
55using a new tab:</p>
51<pre><code>let g:ft_man_open_mode = &#39;tab&#39;</code></pre> 56<pre><code>let g:ft_man_open_mode = &#39;tab&#39;</code></pre>
52<h3 id="scratchpad-to-test-your-commands">Scratchpad to test your commands</h3> 57<h3 id="scratchpad-to-test-your-commands">Scratchpad to test your
53<p>I often test my <code>sed</code> substitutions, here is a sample from the script used to generate this site:</p> 58commands</h3>
59<p>I often test my <code>sed</code> substitutions, here is a sample from
60the script used to generate this site:</p>
54<pre><code># a substitution to convert snake_case to Title Case With Spaces 61<pre><code># a substitution to convert snake_case to Title Case With Spaces
55echo &quot;$1&quot; | sed -E -e &quot;s/\..+$//g&quot; -e &quot;s/_(.)/ \u\1/g&quot; -e &quot;s/^(.)/\u\1/g&quot;</code></pre> 62echo &quot;$1&quot; | sed -E -e &quot;s/\..+$//g&quot; -e &quot;s/_(.)/ \u\1/g&quot; -e &quot;s/^(.)/\u\1/g&quot;</code></pre>
56<p>Instead of dropping into a new shell, just test it out directly from vim!</p> 63<p>Instead of dropping into a new shell, just test it out directly from
64vim!</p>
57<ul> 65<ul>
58<li>Yank the line into a register:</li> 66<li>Yank the line into a register:</li>
59</ul> 67</ul>
diff --git a/docs/posts/bye_bye_BDFs/index.html b/docs/posts/bye_bye_BDFs/index.html
index 4b2682c..8b9584f 100644
--- a/docs/posts/bye_bye_BDFs/index.html
+++ b/docs/posts/bye_bye_BDFs/index.html
@@ -42,12 +42,30 @@
42 Bye Bye BDFs 42 Bye Bye BDFs
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>Glyph Bitmap Distribution Format is no more, as the creators of <a href="https://pango.org">Pango</a>, one of the most widely used text rendering libraries, <a href="https://blogs.gnome.org/mclasen/2019/05/25/pango-future-directions/">announced</a> their plans for Pango 1.44.</p> 45 <p>Glyph Bitmap Distribution Format is no more, as the creators of <a
46<p>Until recently, Pango used FreeType to draw fonts. They will be moving over to <a href="https://harfbuzz.org">Harfbuzz</a>, an evolution of FreeType.</p> 46href="https://pango.org">Pango</a>, one of the most widely used text
47rendering libraries, <a
48href="https://blogs.gnome.org/mclasen/2019/05/25/pango-future-directions/">announced</a>
49their plans for Pango 1.44.</p>
50<p>Until recently, Pango used FreeType to draw fonts. They will be
51moving over to <a href="https://harfbuzz.org">Harfbuzz</a>, an evolution
52of FreeType.</p>
47<p><em>Why?</em></p> 53<p><em>Why?</em></p>
48<p>In short, FreeType was hard to work with. It required complex logic, and provided no advantage over Harfbuzz (other than being able to fetch opentype metrics with ease).</p> 54<p>In short, FreeType was hard to work with. It required complex logic,
49<p>Upgrading to Pango v1.44 will break your GTK applications (if you use a <code>bdf</code>/<code>pcf</code> bitmap font). Harfbuzz <em>does</em> support bitmap-only OpenType fonts, <code>otb</code>s. Convert your existing fonts over to <code>otb</code>s using <a href="https://fontforge.github.io">FontForge</a>. It is to be noted that applications such as <code>xterm</code> and <code>rxvt</code> use <code>xft</code> (X FreeType) to render fonts, and will remain unaffected by the update.</p> 55and provided no advantage over Harfbuzz (other than being able to fetch
50<p>Both <a href="https://github.com/nerdypepper/scientifica">scientifica</a> and <a href="https://github.com/nerdypepper/curie">curie</a> will soon ship with bitmap-only OpenType font formats.</p> 56opentype metrics with ease).</p>
57<p>Upgrading to Pango v1.44 will break your GTK applications (if you use
58a <code>bdf</code>/<code>pcf</code> bitmap font). Harfbuzz <em>does</em>
59support bitmap-only OpenType fonts, <code>otb</code>s. Convert your
60existing fonts over to <code>otb</code>s using <a
61href="https://fontforge.github.io">FontForge</a>. It is to be noted that
62applications such as <code>xterm</code> and <code>rxvt</code> use
63<code>xft</code> (X FreeType) to render fonts, and will remain
64unaffected by the update.</p>
65<p>Both <a
66href="https://github.com/nerdypepper/scientifica">scientifica</a> and <a
67href="https://github.com/nerdypepper/curie">curie</a> will soon ship
68with bitmap-only OpenType font formats.</p>
51 69
52 </div> 70 </div>
53 71
diff --git a/docs/posts/call_to_ARMs/index.html b/docs/posts/call_to_ARMs/index.html
index 3331107..1b13213 100644
--- a/docs/posts/call_to_ARMs/index.html
+++ b/docs/posts/call_to_ARMs/index.html
@@ -33,7 +33,7 @@
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
35 <span class="stats-number"> 35 <span class="stats-number">
36 2.2 36 2.3
37 </span> 37 </span>
38 <span class="stats-unit">min</span> 38 <span class="stats-unit">min</span>
39 </div> 39 </div>
@@ -42,37 +42,60 @@
42 Call To ARMs 42 Call To ARMs
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>My 4th semester involves ARM programming. And proprietary tooling (Keil C). But we don’t do that here.</p> 45 <p>My 4th semester involves ARM programming. And proprietary tooling
46(Keil C). But we don’t do that here.</p>
46<h3 id="building">Building</h3> 47<h3 id="building">Building</h3>
47<p>Assembling and linking ARM binaries on non-ARM architecture devices is fairly trivial. I went along with the GNU cross bare metal toolchain binutils, which provides <code>arm-as</code> and <code>arm-ld</code> (among a bunch of other utils that I don’t care about for now).</p> 48<p>Assembling and linking ARM binaries on non-ARM architecture devices
49is fairly trivial. I went along with the GNU cross bare metal toolchain
50binutils, which provides <code>arm-as</code> and <code>arm-ld</code>
51(among a bunch of other utils that I don’t care about for now).</p>
48<p>Assemble <code>.s</code> files with:</p> 52<p>Assemble <code>.s</code> files with:</p>
49<pre class="shell"><code>arm-none-eabi-as main.s -g -march=armv8.1-a -o main.out</code></pre> 53<pre class="shell"><code>arm-none-eabi-as main.s -g -march=armv8.1-a -o main.out</code></pre>
50<p>The <code>-g</code> flag generates extra debugging information that <code>gdb</code> picks up. The <code>-march</code> option establishes target architecture.</p> 54<p>The <code>-g</code> flag generates extra debugging information that
55<code>gdb</code> picks up. The <code>-march</code> option establishes
56target architecture.</p>
51<p>Link <code>.o</code> files with:</p> 57<p>Link <code>.o</code> files with:</p>
52<pre class="shell"><code>arm-none-eabi-ld main.out -o main</code></pre> 58<pre class="shell"><code>arm-none-eabi-ld main.out -o main</code></pre>
53<h3 id="running-and-debugging">Running (and Debugging)</h3> 59<h3 id="running-and-debugging">Running (and Debugging)</h3>
54<p>Things get interesting here. <code>gdb</code> on your x86 machine cannot read nor execute binaries compiled for ARM. So, we simulate an ARM processor using <code>qemu</code>. Now qemu allows you to run <code>gdbserver</code> on startup. Connecting our local <code>gdb</code> instance to <code>gdbserver</code> gives us a view into the program’s execution. Easy!</p> 60<p>Things get interesting here. <code>gdb</code> on your x86 machine
55<p>Run <code>qemu</code>, with <code>gdbserver</code> on port <code>1234</code>, with our ARM binary, <code>main</code>:</p> 61cannot read nor execute binaries compiled for ARM. So, we simulate an
62ARM processor using <code>qemu</code>. Now qemu allows you to run
63<code>gdbserver</code> on startup. Connecting our local <code>gdb</code>
64instance to <code>gdbserver</code> gives us a view into the program’s
65execution. Easy!</p>
66<p>Run <code>qemu</code>, with <code>gdbserver</code> on port
67<code>1234</code>, with our ARM binary, <code>main</code>:</p>
56<pre class="shell"><code>qemu-arm -singlestep -g 1234 main</code></pre> 68<pre class="shell"><code>qemu-arm -singlestep -g 1234 main</code></pre>
57<p>Start up <code>gdb</code> on your machine, and connect to <code>qemu</code>’s <code>gdbserver</code>:</p> 69<p>Start up <code>gdb</code> on your machine, and connect to
70<code>qemu</code>’s <code>gdbserver</code>:</p>
58<pre><code>(gdb) set architecture armv8-a 71<pre><code>(gdb) set architecture armv8-a
59(gdb) target remote localhost:1234 72(gdb) target remote localhost:1234
60(gdb) file main 73(gdb) file main
61Reading symbols from main... # yay!</code></pre> 74Reading symbols from main... # yay!</code></pre>
62<h3 id="gdb-enhanced">GDB Enhanced</h3> 75<h3 id="gdb-enhanced">GDB Enhanced</h3>
63<p><code>gdb</code> is cool, but it’s not nearly as comfortable as well fleshed out emulators/IDEs like Keil. Watching registers, CPSR and memory chunks update <em>is</em> pretty fun.</p> 76<p><code>gdb</code> is cool, but it’s not nearly as comfortable as well
64<p>I came across <code>gdb</code>’s TUI mode (hit <code>C-x C-a</code> or type <code>tui enable</code> at the prompt). TUI mode is a godsend. It highlights the current line of execution, shows you disassembly outputs, updated registers, active breakpoints and more.</p> 77fleshed out emulators/IDEs like Keil. Watching registers, CPSR and
78memory chunks update <em>is</em> pretty fun.</p>
79<p>I came across <code>gdb</code>’s TUI mode (hit <code>C-x C-a</code>
80or type <code>tui enable</code> at the prompt). TUI mode is a godsend.
81It highlights the current line of execution, shows you disassembly
82outputs, updated registers, active breakpoints and more.</p>
65<p><em>But</em>, it is an absolute eyesore.</p> 83<p><em>But</em>, it is an absolute eyesore.</p>
66<p>Say hello to <a href="https://github.com/hugsy/gef">GEF</a>! “GDB Enhanced Features” teaches our old dog some cool new tricks. Here are some additions that made my ARM debugging experience loads better:</p> 84<p>Say hello to <a href="https://github.com/hugsy/gef">GEF</a>! “GDB
85Enhanced Features” teaches our old dog some cool new tricks. Here are
86some additions that made my ARM debugging experience loads better:</p>
67<ul> 87<ul>
68<li>Memory watches</li> 88<li>Memory watches</li>
69<li>Register watches, with up to 7 levels of deref (overkill, I agree)</li> 89<li>Register watches, with up to 7 levels of deref (overkill, I
90agree)</li>
70<li>Stack tracing</li> 91<li>Stack tracing</li>
71</ul> 92</ul>
72<p>And it’s pretty! See for yourself:</p> 93<p>And it’s pretty! See for yourself:</p>
73<p><a href="https://u.peppe.rs/wq.png"><img src="https://u.peppe.rs/wq.png" /></a></p> 94<p><a href="https://u.peppe.rs/wq.png"><img
95src="https://u.peppe.rs/wq.png" /></a></p>
74<h3 id="editing">Editing</h3> 96<h3 id="editing">Editing</h3>
75<p>Vim, with <code>syntax off</code> because it dosen’t handle GNU ARM syntax too well.</p> 97<p>Vim, with <code>syntax off</code> because it dosen’t handle GNU ARM
98syntax too well.</p>
76 99
77 </div> 100 </div>
78 101
diff --git a/docs/posts/color_conundrum/index.html b/docs/posts/color_conundrum/index.html
index 6c493c2..eeba49b 100644
--- a/docs/posts/color_conundrum/index.html
+++ b/docs/posts/color_conundrum/index.html
@@ -33,7 +33,7 @@
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
35 <span class="stats-number"> 35 <span class="stats-number">
36 1.3 36 1.4
37 </span> 37 </span>
38 <span class="stats-unit">min</span> 38 <span class="stats-unit">min</span>
39 </div> 39 </div>
@@ -42,14 +42,32 @@
42 Color Conundrum 42 Color Conundrum
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>This piece aims to highlight (pun intended) some of the reasons behind my <a href="https://u.peppe.rs/bF.png">color free</a> editor setup.</p> 45 <p>This piece aims to highlight (pun intended) some of the reasons
46<p>Imagine highlighting an entire book because <em>all</em> of it is important. That is exactly what (most) syntax highlighting does. It is difficult for the human eye to filter out noise in rainbow barf. Use color to draw attention, not diverge it.</p> 46behind my <a href="https://u.peppe.rs/bF.png">color free</a> editor
47<p>At the same time, a book devoid of color is <em>boring!</em> What is the takeaway from this 10 line paragraph? What are the technical terms used?</p> 47setup.</p>
48<p>Prose and code are certainly different, but the fickle minded human eye is the same. The eye constantly looks for a frame of reference, a focal point. It grows tired when it can’t find one.</p> 48<p>Imagine highlighting an entire book because <em>all</em> of it is
49<p>The following comparison does a better job of explaining (none, ample and over-the-top highlighting, from left to right):</p> 49important. That is exactly what (most) syntax highlighting does. It is
50<p><a href="https://u.peppe.rs/lt.png"><img src="https://u.peppe.rs/lt.png" /></a></p> 50difficult for the human eye to filter out noise in rainbow barf. Use
51<p>Without highlighting (far left), it is hard to differentiate between comments and code! The florid color scheme (far right) is no good either, it contains too many attention grabbers. The center sample is a healthy balance of both. Function calls and constants stand out, and repetitive keywords and other noise (<code>let</code>, <code>as</code>) are mildly dimmed out. Comments and non-code text (sign column, status text) are dimmed further.</p> 51color to draw attention, not diverge it.</p>
52<p>I’ll stop myself before I rant about color contrast and combinations.</p> 52<p>At the same time, a book devoid of color is <em>boring!</em> What is
53the takeaway from this 10 line paragraph? What are the technical terms
54used?</p>
55<p>Prose and code are certainly different, but the fickle minded human
56eye is the same. The eye constantly looks for a frame of reference, a
57focal point. It grows tired when it can’t find one.</p>
58<p>The following comparison does a better job of explaining (none, ample
59and over-the-top highlighting, from left to right):</p>
60<p><a href="https://u.peppe.rs/lt.png"><img
61src="https://u.peppe.rs/lt.png" /></a></p>
62<p>Without highlighting (far left), it is hard to differentiate between
63comments and code! The florid color scheme (far right) is no good
64either, it contains too many attention grabbers. The center sample is a
65healthy balance of both. Function calls and constants stand out, and
66repetitive keywords and other noise (<code>let</code>, <code>as</code>)
67are mildly dimmed out. Comments and non-code text (sign column, status
68text) are dimmed further.</p>
69<p>I’ll stop myself before I rant about color contrast and
70combinations.</p>
53 71
54 </div> 72 </div>
55 73
diff --git a/docs/posts/curing_a_case_of_git-UX/index.html b/docs/posts/curing_a_case_of_git-UX/index.html
index 9c4761c..140436a 100644
--- a/docs/posts/curing_a_case_of_git-UX/index.html
+++ b/docs/posts/curing_a_case_of_git-UX/index.html
@@ -33,7 +33,7 @@
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
35 <span class="stats-number"> 35 <span class="stats-number">
36 9.5 36 9.6
37 </span> 37 </span>
38 <span class="stats-unit">min</span> 38 <span class="stats-unit">min</span>
39 </div> 39 </div>
@@ -42,51 +42,86 @@
42 Curing A Case Of Git-UX 42 Curing A Case Of Git-UX
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>Git worktrees are great, but they fall behind the venerable <code>git checkout</code> sometimes. I attempted to fix that with <a href="https://github.com/junegunn/fzf">fzf</a> and a bit of bash.</p> 45 <p>Git worktrees are great, but they fall behind the venerable
46<p><a href="https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps"><img src="https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps.svg" /></a></p> 46<code>git checkout</code> sometimes. I attempted to fix that with <a
47<p>Fear not if you haven’t heard of “worktrees”, I have included a primer here.<br /> 47href="https://github.com/junegunn/fzf">fzf</a> and a bit of bash.</p>
48<p><a href="https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps"><img
49src="https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps.svg" /></a></p>
50<p>Fear not if you haven’t heard of “worktrees”, I have included a
51primer here.<br />
48<a href="#what-makes-them-clunky">Skip the primer -&gt;</a>.</p> 52<a href="#what-makes-them-clunky">Skip the primer -&gt;</a>.</p>
49<h3 id="why-worktrees">Why Worktrees?</h3> 53<h3 id="why-worktrees">Why Worktrees?</h3>
50<p>Picture this. You are whacking away on a feature branch. Halfway there, in fact. Your friend asks you fix something urgently. You proceed to do one of three things:</p> 54<p>Picture this. You are whacking away on a feature branch. Halfway
55there, in fact. Your friend asks you fix something urgently. You proceed
56to do one of three things:</p>
51<ul> 57<ul>
52<li>create a temporary branch, make a WIP commit, begin working on the fix</li> 58<li>create a temporary branch, make a WIP commit, begin working on the
59fix</li>
53<li>stash away your changes, begin working on the fix</li> 60<li>stash away your changes, begin working on the fix</li>
54<li>unfriend said friend for disturbing your flow</li> 61<li>unfriend said friend for disturbing your flow</li>
55</ul> 62</ul>
56<p>All of these options are … subpar. With the temporary branch, you are forced to create a partial, non-working commit, and then reset said commit once done with the fix. With the stash approach, you are required to now keep a mental model of the stash, be aware of untracked files that don’t get stashed by default, etc. Why won’t git just let you work on two things at the same time without <em>thinking</em> so much?</p> 63<p>All of these options are … subpar. With the temporary branch, you are
57<p>That is exactly what worktrees let you do. Worktrees let you have more than one checkout at a time, each checkout in a separate directory. Like creating a new clone, but safer (it disallows checking out the same branch twice) and a lot more space efficient (the new working tree is “linked” to the “main” worktree, and a good amount of stuff is shared). When your friend asks you to make the fix, you proceed like so:</p> 64forced to create a partial, non-working commit, and then reset said
65commit once done with the fix. With the stash approach, you are required
66to now keep a mental model of the stash, be aware of untracked files
67that don’t get stashed by default, etc. Why won’t git just let you work
68on two things at the same time without <em>thinking</em> so much?</p>
69<p>That is exactly what worktrees let you do. Worktrees let you have
70more than one checkout at a time, each checkout in a separate directory.
71Like creating a new clone, but safer (it disallows checking out the same
72branch twice) and a lot more space efficient (the new working tree is
73“linked” to the “main” worktree, and a good amount of stuff is shared).
74When your friend asks you to make the fix, you proceed like so:</p>
58<ol type="1"> 75<ol type="1">
59<li>Create a new working tree with:</li> 76<li>Create a new working tree with:</li>
60</ol> 77</ol>
61<div class="sourceCode" id="cb1"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co"># git worktree add -b &lt;branch-name&gt; &lt;path&gt; &lt;from&gt;</span></span> 78<div class="sourceCode" id="cb1"><pre
79class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co"># git worktree add -b &lt;branch-name&gt; &lt;path&gt; &lt;from&gt;</span></span>
62<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="fu">git</span> worktree add <span class="at">-b</span> fix-stuff /path/to/tree master</span></code></pre></div> 80<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="fu">git</span> worktree add <span class="at">-b</span> fix-stuff /path/to/tree master</span></code></pre></div>
63<ol start="2" type="1"> 81<ol start="2" type="1">
64<li><code>cd</code> into <code>/path/to/tree</code></li> 82<li><code>cd</code> into <code>/path/to/tree</code></li>
65<li>Fix, test, commit, push, party</li> 83<li>Fix, test, commit, push, party</li>
66<li>Go back to your work, <code>cd -</code></li> 84<li>Go back to your work, <code>cd -</code></li>
67</ol> 85</ol>
68<p>Easy as cake. You didn’t have to settle for a partially working commit, you didn’t to deal with this “stash” thing, <em>and</em> you didn’t have to unfriend your friend. Treating each branch as a directory just <em>feels</em> more intuitive, more UNIX-y.</p> 86<p>Easy as cake. You didn’t have to settle for a partially working
69<p>A few weeks later, you find yourself singing in praise of worktrees, working on several things simultaneously. And at the same time, cursing them for being a little … clunky.</p> 87commit, you didn’t to deal with this “stash” thing, <em>and</em> you
88didn’t have to unfriend your friend. Treating each branch as a directory
89just <em>feels</em> more intuitive, more UNIX-y.</p>
90<p>A few weeks later, you find yourself singing in praise of worktrees,
91working on several things simultaneously. And at the same time, cursing
92them for being a little … clunky.</p>
70<h3 id="what-makes-them-clunky">What makes them clunky?</h3> 93<h3 id="what-makes-them-clunky">What makes them clunky?</h3>
71<p>Worktrees are great at what they claim to do. They stay out of the way when you need a checkout posthaste. However, as you start using them regularly, you realize they are not as flexible as <code>git checkout</code> or <code>git switch</code>.</p> 94<p>Worktrees are great at what they claim to do. They stay out of the
95way when you need a checkout posthaste. However, as you start using them
96regularly, you realize they are not as flexible as
97<code>git checkout</code> or <code>git switch</code>.</p>
72<h4 id="branch-hopping">Branch-hopping</h4> 98<h4 id="branch-hopping">Branch-hopping</h4>
73<p>You can <code>git checkout &lt;branch&gt;</code> from anywhere within a git repository. You can’t “jump” to a worktree in the same fashion. The closest you can get, is to run <code>git worktree list</code>, copy the path corresponding to your branch, and <code>cd</code> into it.</p> 99<p>You can <code>git checkout &lt;branch&gt;</code> from anywhere within
100a git repository. You can’t “jump” to a worktree in the same fashion.
101The closest you can get, is to run <code>git worktree list</code>, copy
102the path corresponding to your branch, and <code>cd</code> into it.</p>
74<p>Branch-hopping with the good ol’ git-checkout:</p> 103<p>Branch-hopping with the good ol’ git-checkout:</p>
75<div class="sourceCode" id="cb2"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co"># anywhere, anytime</span></span> 104<div class="sourceCode" id="cb2"><pre
105class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co"># anywhere, anytime</span></span>
76<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout feature/is-ascii-octdigit</span></code></pre></div> 106<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout feature/is-ascii-octdigit</span></code></pre></div>
77<p>Meanwhile, in worktree world:</p> 107<p>Meanwhile, in worktree world:</p>
78<div class="sourceCode" id="cb3"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co"># keeping these paths in your head is hard</span></span> 108<div class="sourceCode" id="cb3"><pre
109class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co"># keeping these paths in your head is hard</span></span>
79<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git worktree list</span> 110<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git worktree list</span>
80<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/master</span> eac6c33bc63 [master]</span> 111<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/master</span> eac6c33bc63 <span class="pp">[</span><span class="ss">master</span><span class="pp">]</span></span>
81<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/improve-std-char-docs</span> 94cba88553e [improve-std-char-docs]</span> 112<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/improve-std-char-docs</span> 94cba88553e <span class="pp">[</span><span class="ss">improve</span><span class="pp">-</span><span class="ss">std</span><span class="pp">-</span><span class="ss">char</span><span class="pp">-</span><span class="ss">docs</span><span class="pp">]</span></span>
82<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/is-ascii-octdigit</span> bc57be3af7a [feature/is-ascii-octdigit]</span> 113<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/is-ascii-octdigit</span> bc57be3af7a <span class="pp">[</span><span class="ss">feature/is</span><span class="pp">-</span><span class="ss">ascii</span><span class="pp">-</span><span class="ss">octdigit</span><span class="pp">]</span></span>
83<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="ex">~/my/other/path/oh/god</span> op57or3ns7n [fix/some-error]</span> 114<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="ex">~/my/other/path/oh/god</span> op57or3ns7n <span class="pp">[</span><span class="ss">fix/some</span><span class="pp">-</span><span class="ss">error</span><span class="pp">]</span></span>
84<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a></span> 115<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a></span>
85<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> cd ~/worktrees/rustc/is-ascii-octdigit</span></code></pre></div> 116<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> cd ~/worktrees/rustc/is-ascii-octdigit</span></code></pre></div>
86<h4 id="branch-previewing">Branch-previewing</h4> 117<h4 id="branch-previewing">Branch-previewing</h4>
87<p>You can “preview” branches with <code>git branch -v</code>. However, to get an idea of what “recent activity” on a worktree looks like, you might need some juggling. You can’t glean much info about a worktree in a jiffy.</p> 118<p>You can “preview” branches with <code>git branch -v</code>. However,
119to get an idea of what “recent activity” on a worktree looks like, you
120might need some juggling. You can’t glean much info about a worktree in
121a jiffy.</p>
88<p>Branch-previewing with the good ol’ git-branch:</p> 122<p>Branch-previewing with the good ol’ git-branch:</p>
89<div class="sourceCode" id="cb4"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git branch <span class="at">-v</span></span> 123<div class="sourceCode" id="cb4"><pre
124class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git branch <span class="at">-v</span></span>
90<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="ex">+</span> feature/is-ascii-octdigit bc57be3af7a introduce {char, u8}::is_ ...</span> 125<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="ex">+</span> feature/is-ascii-octdigit bc57be3af7a introduce {char, u8}::is_ ...</span>
91<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="ex">+</span> improve-std-char-docs 94cba88553e add whitespace in assert ...</span> 126<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="ex">+</span> improve-std-char-docs 94cba88553e add whitespace in assert ...</span>
92<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="ex">*</span> master eac6c33bc63 Auto merge of <span class="co">#100869 - n ...</span></span></code></pre></div> 127<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="ex">*</span> master eac6c33bc63 Auto merge of <span class="co">#100869 - n ...</span></span></code></pre></div>
@@ -105,41 +140,60 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
105 140
106# extra work to make the branch &lt;-&gt; worktree correspondence</code></pre> 141# extra work to make the branch &lt;-&gt; worktree correspondence</code></pre>
107<h4 id="shell-completions">Shell completions</h4> 142<h4 id="shell-completions">Shell completions</h4>
108<p>Lastly, you can bank on shell completions to fill in your branch whilst using <code>git checkout</code>. Worktrees have no such conveniences.</p> 143<p>Lastly, you can bank on shell completions to fill in your branch
144whilst using <code>git checkout</code>. Worktrees have no such
145conveniences.</p>
109<p>We can mend these minor faults with fzf.</p> 146<p>We can mend these minor faults with fzf.</p>
110<h3 id="unclunkifying-worktrees">Unclunkifying worktrees</h3> 147<h3 id="unclunkifying-worktrees">Unclunkifying worktrees</h3>
111<p>I’d suggest looking up <a href="https://github.com/junegunn/fzf">fzf</a> (or <a href="https://github.com/lotabout/skim">skim</a> or <a href="https://github.com/jhawthorn/fzy">fzy</a>). These things make it cake-easy to add interactivity to your shell. Onto fixing the first minor fault, the inability to “jump” to a worktree from anywhere within a git repository.</p> 148<p>I’d suggest looking up <a
112<p>I have a little function called <code>gwj</code> which stands for “git worktree jump”. The idea is to list all the worktrees, select one with fzf, and <code>cd</code> to it upon selection:</p> 149href="https://github.com/junegunn/fzf">fzf</a> (or <a
113<div class="sourceCode" id="cb6"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="fu">gwj ()</span> <span class="kw">{</span></span> 150href="https://github.com/lotabout/skim">skim</a> or <a
151href="https://github.com/jhawthorn/fzy">fzy</a>). These things make it
152cake-easy to add interactivity to your shell. Onto fixing the first
153minor fault, the inability to “jump” to a worktree from anywhere within
154a git repository.</p>
155<p>I have a little function called <code>gwj</code> which stands for
156“git worktree jump”. The idea is to list all the worktrees, select one
157with fzf, and <code>cd</code> to it upon selection:</p>
158<div class="sourceCode" id="cb6"><pre
159class="sourceCode bash"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="fu">gwj ()</span> <span class="kw">{</span></span>
114<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">local</span> <span class="va">out</span></span> 160<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">local</span> <span class="va">out</span></span>
115<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a> <span class="va">out</span><span class="op">=</span><span class="va">$(</span><span class="fu">git</span> worktree list <span class="kw">|</span> <span class="ex">fzf</span> <span class="kw">|</span> <span class="fu">awk</span> <span class="st">&#39;{print $1}&#39;</span><span class="va">)</span></span> 161<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a> <span class="va">out</span><span class="op">=</span><span class="va">$(</span><span class="fu">git</span> worktree list <span class="kw">|</span> <span class="ex">fzf</span> <span class="kw">|</span> <span class="fu">awk</span> <span class="st">&#39;{print $1}&#39;</span><span class="va">)</span></span>
116<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a> <span class="bu">cd</span> <span class="va">$out</span></span> 162<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a> <span class="bu">cd</span> <span class="va">$out</span></span>
117<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre></div> 163<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre></div>
118<p>That is all of it really. Head into a git repository:</p> 164<p>That is all of it really. Head into a git repository:</p>
119<div class="sourceCode" id="cb7"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="co"># here, &quot;master&quot; is a directory, which contains my main</span></span> 165<div class="sourceCode" id="cb7"><pre
166class="sourceCode bash"><code class="sourceCode bash"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="co"># here, &quot;master&quot; is a directory, which contains my main</span></span>
120<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="co"># worktree: a checkout of the master branch on rust-lang/rust </span></span> 167<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="co"># worktree: a checkout of the master branch on rust-lang/rust </span></span>
121<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> cd ~/worktrees/rustc/master/library/core/src</span> 168<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> cd ~/worktrees/rustc/master/library/core/src</span>
122<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> <span class="co"># hack away</span></span></code></pre></div> 169<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> <span class="co"># hack away</span></span></code></pre></div>
123<p>Preferably one with a few worktrees:</p> 170<p>Preferably one with a few worktrees:</p>
124<div class="sourceCode" id="cb8"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git worktree list</span> 171<div class="sourceCode" id="cb8"><pre
125<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/master</span> eac6c33bc63 [master]</span> 172class="sourceCode bash"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git worktree list</span>
126<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/improve-std-char-docs</span> 94cba88553e [improve-std-char-docs]</span> 173<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/master</span> eac6c33bc63 <span class="pp">[</span><span class="ss">master</span><span class="pp">]</span></span>
127<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/is-ascii-octdigit</span> bc57be3af7a [feature/is-ascii-octdigit]</span></code></pre></div> 174<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/improve-std-char-docs</span> 94cba88553e <span class="pp">[</span><span class="ss">improve</span><span class="pp">-</span><span class="ss">std</span><span class="pp">-</span><span class="ss">char</span><span class="pp">-</span><span class="ss">docs</span><span class="pp">]</span></span>
128<p>And hit <code>gwj</code> (pretend that the pipe, |, is your cursor):</p> 175<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/is-ascii-octdigit</span> bc57be3af7a <span class="pp">[</span><span class="ss">feature/is</span><span class="pp">-</span><span class="ss">ascii</span><span class="pp">-</span><span class="ss">octdigit</span><span class="pp">]</span></span></code></pre></div>
129<div class="sourceCode" id="cb9"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj</span> 176<p>And hit <code>gwj</code> (pretend that the pipe, |, is your
177cursor):</p>
178<div class="sourceCode" id="cb9"><pre
179class="sourceCode bash"><code class="sourceCode bash"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj</span>
130<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="kw">|</span></span> 180<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="kw">|</span></span>
131<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> <span class="ex">4/4</span></span> 181<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> <span class="ex">4/4</span></span>
132<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> ~/worktrees/rustc/master <span class="ex">eac6c33bc63</span> [master]</span> 182<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> ~/worktrees/rustc/master <span class="ex">eac6c33bc63</span> <span class="pp">[</span><span class="ss">master</span><span class="pp">]</span></span>
133<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a> <span class="ex">~/worktrees/rustc/improve-std-char-docs</span> 94cba88553e [improve-std-char-docs]</span> 183<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a> <span class="ex">~/worktrees/rustc/improve-std-char-docs</span> 94cba88553e <span class="pp">[</span><span class="ss">improve</span><span class="pp">-</span><span class="ss">std</span><span class="pp">-</span><span class="ss">char</span><span class="pp">-</span><span class="ss">docs</span><span class="pp">]</span></span>
134<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a> <span class="ex">~/worktrees/rustc/is-ascii-octdigit</span> bc57be3af7a [feature/is-ascii-octdigit]</span></code></pre></div> 184<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a> <span class="ex">~/worktrees/rustc/is-ascii-octdigit</span> bc57be3af7a <span class="pp">[</span><span class="ss">feature/is</span><span class="pp">-</span><span class="ss">ascii</span><span class="pp">-</span><span class="ss">octdigit</span><span class="pp">]</span></span></code></pre></div>
135<p>Approximately type in your branch of choice:</p> 185<p>Approximately type in your branch of choice:</p>
136<div class="sourceCode" id="cb10"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj</span> 186<div class="sourceCode" id="cb10"><pre
187class="sourceCode bash"><code class="sourceCode bash"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj</span>
137<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> docs<span class="kw">|</span></span> 188<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> docs<span class="kw">|</span></span>
138<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> <span class="ex">4/4</span></span> 189<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> <span class="ex">4/4</span></span>
139<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> ~/worktrees/rustc/improve-std-char-docs <span class="ex">94cba88553e</span> [improve-std-char-docs]</span></code></pre></div> 190<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> ~/worktrees/rustc/improve-std-char-docs <span class="ex">94cba88553e</span> <span class="pp">[</span><span class="ss">improve</span><span class="pp">-</span><span class="ss">std</span><span class="pp">-</span><span class="ss">char</span><span class="pp">-</span><span class="ss">docs</span><span class="pp">]</span></span></code></pre></div>
140<p>And hit enter. You should find yourself in the selected worktree.</p> 191<p>And hit enter. You should find yourself in the selected worktree.</p>
141<p>Onward, to the next fault, lack of preview-bility. We can utilize fzf’s aptly named <code>--preview</code> flag, to, well, preview our worktree before performing a selection:</p> 192<p>Onward, to the next fault, lack of preview-bility. We can utilize
142<div class="sourceCode" id="cb11"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="fu">gwj ()</span> <span class="kw">{</span></span> 193fzf’s aptly named <code>--preview</code> flag, to, well, preview our
194worktree before performing a selection:</p>
195<div class="sourceCode" id="cb11"><pre
196class="sourceCode bash"><code class="sourceCode bash"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="fu">gwj ()</span> <span class="kw">{</span></span>
143<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">local</span> <span class="va">out</span></span> 197<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">local</span> <span class="va">out</span></span>
144<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a> <span class="va">out</span><span class="op">=</span><span class="va">$(</span></span> 198<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a> <span class="va">out</span><span class="op">=</span><span class="va">$(</span></span>
145<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">git</span> worktree list <span class="kw">|</span></span> 199<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">git</span> worktree list <span class="kw">|</span></span>
@@ -148,8 +202,10 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
148<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a> <span class="va">)</span></span> 202<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a> <span class="va">)</span></span>
149<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a> <span class="bu">cd</span> <span class="va">$out</span></span> 203<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a> <span class="bu">cd</span> <span class="va">$out</span></span>
150<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre></div> 204<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre></div>
151<p>Once again, hit <code>gwj</code> inside a git repository with linked worktrees:</p> 205<p>Once again, hit <code>gwj</code> inside a git repository with linked
152<div class="sourceCode" id="cb12"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj</span> 206worktrees:</p>
207<div class="sourceCode" id="cb12"><pre
208class="sourceCode bash"><code class="sourceCode bash"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj</span>
153<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="ex">╭─────────────────────────────────────────────────────────╮</span></span> 209<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="ex">╭─────────────────────────────────────────────────────────╮</span></span>
154<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> eac6c33bc63 Auto merge of 100869 nnethercote:replace... │</span> 210<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> eac6c33bc63 Auto merge of 100869 nnethercote:replace... │</span>
155<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> b32223fec10 Auto merge of 100707 dzvon:fix-typo, r=d... │</span> 211<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> b32223fec10 Auto merge of 100707 dzvon:fix-typo, r=d... │</span>
@@ -167,9 +223,16 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
167<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> /home/np/worktrees/compiler/master <span class="ex">eac6c...</span></span> 223<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> /home/np/worktrees/compiler/master <span class="ex">eac6c...</span></span>
168<span id="cb12-17"><a href="#cb12-17" aria-hidden="true" tabindex="-1"></a> <span class="ex">/home/np/worktrees/compiler/improve-std-char-docs</span> 94cba...</span> 224<span id="cb12-17"><a href="#cb12-17" aria-hidden="true" tabindex="-1"></a> <span class="ex">/home/np/worktrees/compiler/improve-std-char-docs</span> 94cba...</span>
169<span id="cb12-18"><a href="#cb12-18" aria-hidden="true" tabindex="-1"></a> <span class="ex">/home/np/worktrees/compiler/is-ascii-octdigit</span> bc57b...</span></code></pre></div> 225<span id="cb12-18"><a href="#cb12-18" aria-hidden="true" tabindex="-1"></a> <span class="ex">/home/np/worktrees/compiler/is-ascii-octdigit</span> bc57b...</span></code></pre></div>
170<p>A fancy preview of the last 10 commits on the branch that the selected worktree corresponds to. In other words, sight for sore eyes. Our little script is already shaping up to be useful, you hit <code>gwj</code>, browse through your worktrees, preview each one and automatically <code>cd</code> to your selection. But we are not done yet.</p> 226<p>A fancy preview of the last 10 commits on the branch that the
171<p>The last fault was lack shell completions. A quick review of what a shell completion really does:</p> 227selected worktree corresponds to. In other words, sight for sore eyes.
172<div class="sourceCode" id="cb13"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout f<span class="op">&lt;</span>tab<span class="op">&gt;</span></span> 228Our little script is already shaping up to be useful, you hit
229<code>gwj</code>, browse through your worktrees, preview each one and
230automatically <code>cd</code> to your selection. But we are not done
231yet.</p>
232<p>The last fault was lack shell completions. A quick review of what a
233shell completion really does:</p>
234<div class="sourceCode" id="cb13"><pre
235class="sourceCode bash"><code class="sourceCode bash"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout f<span class="op">&lt;</span>tab<span class="op">&gt;</span></span>
173<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="ex">feature/is-ascii-octdigit</span></span> 236<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="ex">feature/is-ascii-octdigit</span></span>
174<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="ex">fix/some-error</span></span> 237<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="ex">fix/some-error</span></span>
175<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="ex">format-doc-tests</span></span> 238<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="ex">format-doc-tests</span></span>
@@ -177,16 +240,22 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
177<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout feat<span class="op">&lt;</span>tab<span class="op">&gt;</span></span> 240<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout feat<span class="op">&lt;</span>tab<span class="op">&gt;</span></span>
178<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a></span> 241<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a></span>
179<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout feature/is-ascii-octdigit</span></code></pre></div> 242<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout feature/is-ascii-octdigit</span></code></pre></div>
180<p>Each time you hit “tab”, the shell produces a few “completion candidates”, and once you have just a single candidate left, the shell inserts that for you directly into your edit line. Of course, this process varies from shell to shell.</p> 243<p>Each time you hit “tab”, the shell produces a few “completion
181<p>fzf narrows down your options as you type into the prompt, but you still have to:</p> 244candidates”, and once you have just a single candidate left, the shell
245inserts that for you directly into your edit line. Of course, this
246process varies from shell to shell.</p>
247<p>fzf narrows down your options as you type into the prompt, but you
248still have to:</p>
182<ol type="1"> 249<ol type="1">
183<li>Type <code>gwj</code></li> 250<li>Type <code>gwj</code></li>
184<li>Hit enter</li> 251<li>Hit enter</li>
185<li>Type out a query and narrow down your search</li> 252<li>Type out a query and narrow down your search</li>
186<li>Hit enter</li> 253<li>Hit enter</li>
187</ol> 254</ol>
188<p>We can speed that up a bit, have fzf narrow down the candidates on startup, just like our shell does:</p> 255<p>We can speed that up a bit, have fzf narrow down the candidates on
189<div class="sourceCode" id="cb14"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="fu">gwj ()</span> <span class="kw">{</span></span> 256startup, just like our shell does:</p>
257<div class="sourceCode" id="cb14"><pre
258class="sourceCode bash"><code class="sourceCode bash"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="fu">gwj ()</span> <span class="kw">{</span></span>
190<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">local</span> <span class="va">out</span> <span class="va">query</span></span> 259<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">local</span> <span class="va">out</span> <span class="va">query</span></span>
191<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a> <span class="va">query</span><span class="op">=</span><span class="st">&quot;</span><span class="va">${1</span><span class="op">:-</span> <span class="va">}</span><span class="st">&quot;</span></span> 260<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a> <span class="va">query</span><span class="op">=</span><span class="st">&quot;</span><span class="va">${1</span><span class="op">:-</span> <span class="va">}</span><span class="st">&quot;</span></span>
192<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a> <span class="va">out</span><span class="op">=</span><span class="va">$(</span></span> 261<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a> <span class="va">out</span><span class="op">=</span><span class="va">$(</span></span>
@@ -196,8 +265,12 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
196<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a> <span class="va">)</span></span> 265<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a> <span class="va">)</span></span>
197<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a> <span class="bu">cd</span> <span class="va">$out</span></span> 266<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a> <span class="bu">cd</span> <span class="va">$out</span></span>
198<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre></div> 267<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre></div>
199<p>The change is extremely tiny, blink-and-you’ll-miss-it kinda tiny. We added a little <code>--query</code> flag, that allows you to prefill the prompt, and the <code>-1</code> flag, that avoids the interactive finder if only one match exists on startup:</p> 268<p>The change is extremely tiny, blink-and-you’ll-miss-it kinda tiny. We
200<div class="sourceCode" id="cb15"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="co"># skip through the fzf prompt:</span></span> 269added a little <code>--query</code> flag, that allows you to prefill the
270prompt, and the <code>-1</code> flag, that avoids the interactive finder
271if only one match exists on startup:</p>
272<div class="sourceCode" id="cb15"><pre
273class="sourceCode bash"><code class="sourceCode bash"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="co"># skip through the fzf prompt:</span></span>
201<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj master</span> 274<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj master</span>
202<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="co"># cd -- ~/worktrees/rustc/master</span></span> 275<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="co"># cd -- ~/worktrees/rustc/master</span></span>
203<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a></span> 276<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a></span>
@@ -212,8 +285,11 @@ aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
212<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a> <span class="ex">2/2</span></span> 285<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a> <span class="ex">2/2</span></span>
213<span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> /home/np/worktrees/compiler/improve-const-perf <span class="ex">eac6c...</span></span> 286<span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> /home/np/worktrees/compiler/improve-const-perf <span class="ex">eac6c...</span></span>
214<span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a> <span class="ex">/home/np/worktrees/compiler/improve-std-char-docs</span> 94cba...</span></code></pre></div> 287<span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a> <span class="ex">/home/np/worktrees/compiler/improve-std-char-docs</span> 94cba...</span></code></pre></div>
215<p>Throw some error handling in there, hook up a similar script to improve the UX of <code>git worktree remove</code>, go wild. A few more helpers I’ve got:</p> 288<p>Throw some error handling in there, hook up a similar script to
216<div class="sourceCode" id="cb16"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="co"># gwa /path/to/branch-name</span></span> 289improve the UX of <code>git worktree remove</code>, go wild. A few more
290helpers I’ve got:</p>
291<div class="sourceCode" id="cb16"><pre
292class="sourceCode bash"><code class="sourceCode bash"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="co"># gwa /path/to/branch-name</span></span>
217<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="co"># creates a new branch and &quot;switches&quot; to it</span></span> 293<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="co"># creates a new branch and &quot;switches&quot; to it</span></span>
218<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a><span class="kw">function</span><span class="fu"> gwa ()</span> <span class="kw">{</span></span> 294<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a><span class="kw">function</span><span class="fu"> gwa ()</span> <span class="kw">{</span></span>
219<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">git</span> worktree add <span class="st">&quot;</span><span class="va">$1</span><span class="st">&quot;</span> <span class="kw">&amp;&amp;</span> <span class="bu">cd</span> <span class="st">&quot;</span><span class="va">$1</span><span class="st">&quot;</span></span> 295<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">git</span> worktree add <span class="st">&quot;</span><span class="va">$1</span><span class="st">&quot;</span> <span class="kw">&amp;&amp;</span> <span class="bu">cd</span> <span class="st">&quot;</span><span class="va">$1</span><span class="st">&quot;</span></span>
diff --git a/docs/posts/font_size_fallacies/index.html b/docs/posts/font_size_fallacies/index.html
index 9577376..51f5b4b 100644
--- a/docs/posts/font_size_fallacies/index.html
+++ b/docs/posts/font_size_fallacies/index.html
@@ -28,12 +28,12 @@
28 17/03 — 2020 28 17/03 — 2020
29 <div class="stats"> 29 <div class="stats">
30 <span class="stats-number"> 30 <span class="stats-number">
31 32.36 31 32.37
32 </span> 32 </span>
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
35 <span class="stats-number"> 35 <span class="stats-number">
36 3.2 36 3.3
37 </span> 37 </span>
38 <span class="stats-unit">min</span> 38 <span class="stats-unit">min</span>
39 </div> 39 </div>
@@ -42,34 +42,75 @@
42 Font Size Fallacies 42 Font Size Fallacies
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>I am not an expert with fonts, but I do have some experience <a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>, and common sense. This post aims to debunk some misconceptions about font sizes!</p> 45 <p>I am not an expert with fonts, but I do have some experience <a
46<p>11 px on your display is <em>probably not</em> 11 px on my display. Let’s do some quick math. I have two displays, 1366x768 @ 21" and another with 1920x1080 @ 13", call them <code>A</code> and <code>B</code> for now.</p> 46href="#fn1" class="footnote-ref" id="fnref1"
47<p>Display <code>A</code> has 1,049,088 pixels. A pixel is a square, of side say, <code>s</code> cm. The total area covered by my 21" display is about 1,066 cm^2 (41x26). Thus,</p> 47role="doc-noteref"><sup>1</sup></a>, and common sense. This post aims to
48debunk some misconceptions about font sizes!</p>
49<p>11 px on your display is <em>probably not</em> 11 px on my display.
50Let’s do some quick math. I have two displays, 1366x768 @ 21” and
51another with 1920x1080 @ 13”, call them <code>A</code> and
52<code>B</code> for now.</p>
53<p>Display <code>A</code> has 1,049,088 pixels. A pixel is a square, of
54side say, <code>s</code> cm. The total area covered by my 21” display is
55about 1,066 cm^2 (41x26). Thus,</p>
48<pre><code>Display A 56<pre><code>Display A
49Dimensions: 1366x768 @ 21&quot; (41x26 sq. cm) 57Dimensions: 1366x768 @ 21&quot; (41x26 sq. cm)
501,049,088 s^2 = 1066 581,049,088 s^2 = 1066
51 s = 0.0318 cm (side of a pixel on Display A)</code></pre> 59 s = 0.0318 cm (side of a pixel on Display A)</code></pre>
52<p>Bear with me, as I repeat the number crunching for Display <code>B</code>:</p> 60<p>Bear with me, as I repeat the number crunching for Display
61<code>B</code>:</p>
53<pre><code>Display B 62<pre><code>Display B
54Dimensions: 1920x1080 @ 13&quot; (29.5x16.5 sq. cm) 63Dimensions: 1920x1080 @ 13&quot; (29.5x16.5 sq. cm)
552,073,600 s^2 = 486.75 642,073,600 s^2 = 486.75
56 s = 0.0153 cm (side of a pixel on Display B)</code></pre> 65 s = 0.0153 cm (side of a pixel on Display B)</code></pre>
57<p>The width of a pixel on Display <code>A</code> is <em>double</em> the width of a pixel on Display <code>B</code>. The area occupied by a pixel on Display <code>A</code> is <em>4 times</em> the area occupied by a pixel on Display <code>B</code>.</p> 66<p>The width of a pixel on Display <code>A</code> is <em>double</em> the
67width of a pixel on Display <code>B</code>. The area occupied by a pixel
68on Display <code>A</code> is <em>4 times</em> the area occupied by a
69pixel on Display <code>B</code>.</p>
58<p><em>The size of a pixel varies from display to display!</em></p> 70<p><em>The size of a pixel varies from display to display!</em></p>
59<p>A 5x11 bitmap font on Display <code>A</code> would be around 4 mm tall whereas the same bitmap font on Display <code>B</code> would be around 1.9 mm tall. A 11 px tall character on <code>B</code> is visually equivalent to a 5 px character on <code>A</code>. When you view a screenshot of Display <code>A</code> on Display <code>B</code>, the contents are shrunk down by a factor of 2!</p> 71<p>A 5x11 bitmap font on Display <code>A</code> would be around 4 mm
60<p>So screen resolution is not enough, how else do we measure size? Pixel Density! Keen readers will realize that the 5^th grade math problem we solved up there showcases pixel density, or, pixels per cm (PPCM). Usually we deal with pixels per inch (PPI).</p> 72tall whereas the same bitmap font on Display <code>B</code> would be
61<p><strong>Note:</strong> PPI is not to be confused with DPI <a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a> (dots per inch). DPI is defined for printers.</p> 73around 1.9 mm tall. A 11 px tall character on <code>B</code> is visually
62<p>In our example, <code>A</code> is a 75 ppi display and <code>B</code> is around 165 ppi <a href="#fn3" class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a>. A low ppi display appears to be ‘pixelated’, because the pixels are more prominent, much like Display <code>A</code>. A higher ppi usually means you can view larger images and render crispier fonts. The average desktop display can stuff 100-200 pixels per inch. Smart phones usually fall into the 400-600 ppi (XXXHDPI) category. The human eye fails to differentiate detail past 300 ppi.</p> 74equivalent to a 5 px character on <code>A</code>. When you view a
63<p><em>So … streaming an 8K video on a 60" TV provides the same clarity as a HD video on a smart phone?</em></p> 75screenshot of Display <code>A</code> on Display <code>B</code>, the
64<p>Absolutely. Well, clarity is subjective, but the amount of detail you can discern on mobile displays has always been limited. Salty consumers of the Xperia 1 <a href="#fn4" class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a> will say otherwise.</p> 76contents are shrunk down by a factor of 2!</p>
65<p>Maybe I will talk about font rendering in another post, but thats all for now. Don’t judge a font size by its screenshot.</p> 77<p>So screen resolution is not enough, how else do we measure size?
66<section class="footnotes" role="doc-endnotes"> 78Pixel Density! Keen readers will realize that the 5^th grade math
79problem we solved up there showcases pixel density, or, pixels per cm
80(PPCM). Usually we deal with pixels per inch (PPI).</p>
81<p><strong>Note:</strong> PPI is not to be confused with DPI <a
82href="#fn2" class="footnote-ref" id="fnref2"
83role="doc-noteref"><sup>2</sup></a> (dots per inch). DPI is defined for
84printers.</p>
85<p>In our example, <code>A</code> is a 75 ppi display and <code>B</code>
86is around 165 ppi <a href="#fn3" class="footnote-ref" id="fnref3"
87role="doc-noteref"><sup>3</sup></a>. A low ppi display appears to be
88‘pixelated’, because the pixels are more prominent, much like Display
89<code>A</code>. A higher ppi usually means you can view larger images
90and render crispier fonts. The average desktop display can stuff 100-200
91pixels per inch. Smart phones usually fall into the 400-600 ppi
92(XXXHDPI) category. The human eye fails to differentiate detail past 300
93ppi.</p>
94<p><em>So … streaming an 8K video on a 60” TV provides the same clarity
95as a HD video on a smart phone?</em></p>
96<p>Absolutely. Well, clarity is subjective, but the amount of detail you
97can discern on mobile displays has always been limited. Salty consumers
98of the Xperia 1 <a href="#fn4" class="footnote-ref" id="fnref4"
99role="doc-noteref"><sup>4</sup></a> will say otherwise.</p>
100<p>Maybe I will talk about font rendering in another post, but thats all
101for now. Don’t judge a font size by its screenshot.</p>
102<section id="footnotes" class="footnotes footnotes-end-of-document"
103role="doc-endnotes">
67<hr /> 104<hr />
68<ol> 105<ol>
69<li id="fn1" role="doc-endnote"><p>https://github.com/nerdypepper/scientifica<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li> 106<li id="fn1"><p>https://github.com/nerdypepper/scientifica<a
70<li id="fn2" role="doc-endnote"><p>https://en.wikipedia.org/wiki/Dots_per_inch<a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li> 107href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
71<li id="fn3" role="doc-endnote"><p>https://www.sven.de/dpi/<a href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li> 108<li id="fn2"><p>https://en.wikipedia.org/wiki/Dots_per_inch<a
72<li id="fn4" role="doc-endnote"><p>https://en.wikipedia.org/wiki/Sony_Xperia_1<a href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li> 109href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
110<li id="fn3"><p>https://www.sven.de/dpi/<a href="#fnref3"
111class="footnote-back" role="doc-backlink">↩︎</a></p></li>
112<li id="fn4"><p>https://en.wikipedia.org/wiki/Sony_Xperia_1<a
113href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
73</ol> 114</ol>
74</section> 115</section>
75 116
diff --git a/docs/posts/get_better_at_yanking_and_putting_in_vim/index.html b/docs/posts/get_better_at_yanking_and_putting_in_vim/index.html
index 469afe5..c6d3368 100644
--- a/docs/posts/get_better_at_yanking_and_putting_in_vim/index.html
+++ b/docs/posts/get_better_at_yanking_and_putting_in_vim/index.html
@@ -28,7 +28,7 @@
28 30/07 — 2019 28 30/07 — 2019
29 <div class="stats"> 29 <div class="stats">
30 <span class="stats-number"> 30 <span class="stats-number">
31 10.78 31 10.79
32 </span> 32 </span>
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
@@ -44,7 +44,8 @@
44 <div class="post-text"> 44 <div class="post-text">
45 <p>a couple of nifty tricks to help you copy-paste better:</p> 45 <p>a couple of nifty tricks to help you copy-paste better:</p>
46<ol type="1"> 46<ol type="1">
47<li><p>reselecting previously selected text (i use this to fix botched selections):</p> 47<li><p>reselecting previously selected text (i use this to fix botched
48selections):</p>
48<pre><code>gv &quot; :h gv for more 49<pre><code>gv &quot; :h gv for more
49 &quot; you can use `o` in visual mode to go to the `Other` end of the selection 50 &quot; you can use `o` in visual mode to go to the `Other` end of the selection
50 &quot; use a motion to fix the selection</code></pre></li> 51 &quot; use a motion to fix the selection</code></pre></li>
diff --git a/docs/posts/gripes_with_go/index.html b/docs/posts/gripes_with_go/index.html
index 1551fe6..74d6995 100644
--- a/docs/posts/gripes_with_go/index.html
+++ b/docs/posts/gripes_with_go/index.html
@@ -28,7 +28,7 @@
28 01/08 — 2020 28 01/08 — 2020
29 <div class="stats"> 29 <div class="stats">
30 <span class="stats-number"> 30 <span class="stats-number">
31 76.71 31 76.72
32 </span> 32 </span>
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
@@ -42,17 +42,24 @@
42 Gripes With Go 42 Gripes With Go
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>You’ve read a lot of posts about the shortcomings of the Go programming language, so what’s one more.</p> 45 <p>You’ve read a lot of posts about the shortcomings of the Go
46programming language, so what’s one more.</p>
46<ol type="1"> 47<ol type="1">
47<li><a href="#lack-of-sum-types">Lack of sum types</a></li> 48<li><a href="#lack-of-sum-types">Lack of sum types</a></li>
48<li><a href="#type-assertions">Type assertions</a></li> 49<li><a href="#type-assertions">Type assertions</a></li>
49<li><a href="#date-and-time">Date and Time</a></li> 50<li><a href="#date-and-time">Date and Time</a></li>
50<li><a href="#statements-over-expressions">Statements over Expressions</a></li> 51<li><a href="#statements-over-expressions">Statements over
51<li><a href="#erroring-out-on-unused-variables">Erroring out on unused variables</a></li> 52Expressions</a></li>
53<li><a href="#erroring-out-on-unused-variables">Erroring out on unused
54variables</a></li>
52<li><a href="#error-handling">Error handling</a></li> 55<li><a href="#error-handling">Error handling</a></li>
53</ol> 56</ol>
54<h3 id="lack-of-sum-types">Lack of Sum types</h3> 57<h3 id="lack-of-sum-types">Lack of Sum types</h3>
55<p>A “Sum” type is a data type that can hold one of many states at a given time, similar to how a boolean can hold a true or a false, not too different from an <code>enum</code> type in C. Go lacks <code>enum</code> types unfortunately, and you are forced to resort to crafting your own substitute.</p> 58<p>A “Sum” type is a data type that can hold one of many states at a
59given time, similar to how a boolean can hold a true or a false, not too
60different from an <code>enum</code> type in C. Go lacks
61<code>enum</code> types unfortunately, and you are forced to resort to
62crafting your own substitute.</p>
56<p>A type to represent gender for example:</p> 63<p>A type to represent gender for example:</p>
57<div class="sourceCode" id="cb1"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> Gender <span class="dt">int</span></span> 64<div class="sourceCode" id="cb1"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> Gender <span class="dt">int</span></span>
58<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span> 65<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
@@ -67,17 +74,18 @@
67<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="co">// Oops! We have to implement String() for Gender ...</span></span> 74<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="co">// Oops! We have to implement String() for Gender ...</span></span>
68<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a></span> 75<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a></span>
69<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="kw">func</span> <span class="op">(</span>g Gender<span class="op">)</span> String<span class="op">()</span> <span class="dt">string</span> <span class="op">{</span></span> 76<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="kw">func</span> <span class="op">(</span>g Gender<span class="op">)</span> String<span class="op">()</span> <span class="dt">string</span> <span class="op">{</span></span>
70<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a> <span class="kw">switch</span> <span class="op">(</span>g<span class="op">)</span> <span class="op">{</span></span> 77<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span> <span class="op">(</span>g<span class="op">)</span> <span class="op">{</span></span>
71<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a> <span class="kw">case</span> <span class="dv">0</span><span class="op">:</span> <span class="kw">return</span> <span class="st">&quot;Male&quot;</span></span> 78<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="dv">0</span><span class="op">:</span> <span class="cf">return</span> <span class="st">&quot;Male&quot;</span></span>
72<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">case</span> <span class="dv">1</span><span class="op">:</span> <span class="kw">return</span> <span class="st">&quot;Female&quot;</span></span> 79<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="dv">1</span><span class="op">:</span> <span class="cf">return</span> <span class="st">&quot;Female&quot;</span></span>
73<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a> <span class="kw">default</span><span class="op">:</span> <span class="kw">return</span> <span class="st">&quot;Other&quot;</span></span> 80<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">default</span><span class="op">:</span> <span class="cf">return</span> <span class="st">&quot;Other&quot;</span></span>
74<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> 81<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
75<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> 82<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
76<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a></span> 83<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a></span>
77<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a><span class="co">// You can accidentally do stupid stuff like:</span></span> 84<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a><span class="co">// You can accidentally do stupid stuff like:</span></span>
78<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a>gender <span class="op">:=</span> Male <span class="op">+</span> <span class="dv">1</span></span></code></pre></div> 85<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a>gender <span class="op">:=</span> Male <span class="op">+</span> <span class="dv">1</span></span></code></pre></div>
79<p>The Haskell equivalent of the same:</p> 86<p>The Haskell equivalent of the same:</p>
80<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Gender</span> <span class="ot">=</span> <span class="dt">Male</span></span> 87<div class="sourceCode" id="cb2"><pre
88class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Gender</span> <span class="ot">=</span> <span class="dt">Male</span></span>
81<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="dt">Female</span></span> 89<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="dt">Female</span></span>
82<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="dt">Other</span></span> 90<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="dt">Other</span></span>
83<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> (<span class="dt">Show</span>)</span> 91<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> (<span class="dt">Show</span>)</span>
@@ -88,7 +96,7 @@
88<p>Type assertions in Go allow you to do:</p> 96<p>Type assertions in Go allow you to do:</p>
89<div class="sourceCode" id="cb3"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">var</span> x <span class="kw">interface</span><span class="op">{}</span> <span class="op">=</span> <span class="dv">7</span></span> 97<div class="sourceCode" id="cb3"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">var</span> x <span class="kw">interface</span><span class="op">{}</span> <span class="op">=</span> <span class="dv">7</span></span>
90<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>y<span class="op">,</span> goodToGo <span class="op">:=</span> x<span class="op">.(</span><span class="dt">int</span><span class="op">)</span></span> 98<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>y<span class="op">,</span> goodToGo <span class="op">:=</span> x<span class="op">.(</span><span class="dt">int</span><span class="op">)</span></span>
91<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="kw">if</span> goodToGo <span class="op">{</span></span> 99<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> goodToGo <span class="op">{</span></span>
92<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> fmt<span class="op">.</span>Println<span class="op">(</span>y<span class="op">)</span></span> 100<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> fmt<span class="op">.</span>Println<span class="op">(</span>y<span class="op">)</span></span>
93<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 101<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
94<p>The error check however is optional:</p> 102<p>The error check however is optional:</p>
@@ -98,18 +106,32 @@
98<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="co">// results in a runtime error:</span></span> 106<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="co">// results in a runtime error:</span></span>
99<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="co">// panic: interface conversion: interface {} is int, not float64</span></span></code></pre></div> 107<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="co">// panic: interface conversion: interface {} is int, not float64</span></span></code></pre></div>
100<h3 id="date-and-time">Date and Time</h3> 108<h3 id="date-and-time">Date and Time</h3>
101<p>Anyone that has written Go previously, will probably already know what I am getting at here. For the uninitiated, parsing and formatting dates in Go requires a “layout”. This “layout” is based on magical reference date:</p> 109<p>Anyone that has written Go previously, will probably already know
110what I am getting at here. For the uninitiated, parsing and formatting
111dates in Go requires a “layout”. This “layout” is based on magical
112reference date:</p>
102<pre><code>Mon Jan 2 15:04:05 MST 2006</code></pre> 113<pre><code>Mon Jan 2 15:04:05 MST 2006</code></pre>
103<p>Which is the date produced when you write the first seven natural numbers like so:</p> 114<p>Which is the date produced when you write the first seven natural
115numbers like so:</p>
104<pre><code>01/02 03:04:05 &#39;06 -0700</code></pre> 116<pre><code>01/02 03:04:05 &#39;06 -0700</code></pre>
105<p>Parsing a string in <code>YYYY-MM-DD</code> format would look something like:</p> 117<p>Parsing a string in <code>YYYY-MM-DD</code> format would look
118something like:</p>
106<div class="sourceCode" id="cb7"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> layout <span class="op">=</span> <span class="st">&quot;2006-01-02&quot;</span></span> 119<div class="sourceCode" id="cb7"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> layout <span class="op">=</span> <span class="st">&quot;2006-01-02&quot;</span></span>
107<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>time<span class="op">.</span>Parse<span class="op">(</span>layout<span class="op">,</span> <span class="st">&quot;2020-08-01&quot;</span><span class="op">)</span></span></code></pre></div> 120<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>time<span class="op">.</span>Parse<span class="op">(</span>layout<span class="op">,</span> <span class="st">&quot;2020-08-01&quot;</span><span class="op">)</span></span></code></pre></div>
108<p>This so-called “intuitive” method of formatting dates doesn’t allow you to print <code>0000 hrs</code> as <code>2400 hrs</code>, it doesn’t allow you to omit the leading zero in 24 hour formats. It is rife with inconveniences, if only there were a <a href="https://man7.org/linux/man-pages/man3/strftime.3.html">tried and tested</a> date formatting convention …</p> 121<p>This so-called “intuitive” method of formatting dates doesn’t allow
122you to print <code>0000 hrs</code> as <code>2400 hrs</code>, it doesn’t
123allow you to omit the leading zero in 24 hour formats. It is rife with
124inconveniences, if only there were a <a
125href="https://man7.org/linux/man-pages/man3/strftime.3.html">tried and
126tested</a> date formatting convention …</p>
109<h3 id="statements-over-expressions">Statements over Expressions</h3> 127<h3 id="statements-over-expressions">Statements over Expressions</h3>
110<p>Statements have side effects, expressions return values. More often than not, expressions are easier to understand at a glance: evaluate the LHS and assign the same to the RHS.</p> 128<p>Statements have side effects, expressions return values. More often
111<p>Rust allows you to create local namespaces, and treats blocks (<code>{}</code>) as expressions:</p> 129than not, expressions are easier to understand at a glance: evaluate the
112<div class="sourceCode" id="cb8"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> twenty_seven <span class="op">=</span> <span class="op">{</span></span> 130LHS and assign the same to the RHS.</p>
131<p>Rust allows you to create local namespaces, and treats blocks
132(<code>{}</code>) as expressions:</p>
133<div class="sourceCode" id="cb8"><pre
134class="sourceCode rust"><code class="sourceCode rust"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> twenty_seven <span class="op">=</span> <span class="op">{</span></span>
113<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> three <span class="op">=</span> <span class="dv">1</span> <span class="op">+</span> <span class="dv">2</span><span class="op">;</span></span> 135<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> three <span class="op">=</span> <span class="dv">1</span> <span class="op">+</span> <span class="dv">2</span><span class="op">;</span></span>
114<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> nine <span class="op">=</span> three <span class="op">*</span> three<span class="op">;</span></span> 136<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> nine <span class="op">=</span> three <span class="op">*</span> three<span class="op">;</span></span>
115<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> nine <span class="op">*</span> three</span> 137<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> nine <span class="op">*</span> three</span>
@@ -120,17 +142,25 @@
120<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>three <span class="op">:=</span> <span class="dv">1</span> <span class="op">+</span> <span class="dv">2</span></span> 142<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>three <span class="op">:=</span> <span class="dv">1</span> <span class="op">+</span> <span class="dv">2</span></span>
121<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>nine <span class="op">:=</span> three <span class="op">*</span> three</span> 143<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>nine <span class="op">:=</span> three <span class="op">*</span> three</span>
122<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>twenty_seven <span class="op">=</span> nine <span class="op">*</span> three</span></code></pre></div> 144<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>twenty_seven <span class="op">=</span> nine <span class="op">*</span> three</span></code></pre></div>
123<h3 id="erroring-out-on-unused-variables">Erroring out on unused variables</h3> 145<h3 id="erroring-out-on-unused-variables">Erroring out on unused
124<p>Want to quickly prototype something? Go says no! In all seriousness, a warning would suffice, I don’t want to have to go back and comment each unused import out, only to come back and uncomment them a few seconds later.</p> 146variables</h3>
147<p>Want to quickly prototype something? Go says no! In all seriousness,
148a warning would suffice, I don’t want to have to go back and comment
149each unused import out, only to come back and uncomment them a few
150seconds later.</p>
125<h3 id="error-handling">Error handling</h3> 151<h3 id="error-handling">Error handling</h3>
126<div class="sourceCode" id="cb10"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">if</span> err <span class="op">!=</span> <span class="ot">nil</span> <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span></code></pre></div> 152<div class="sourceCode" id="cb10"><pre
153class="sourceCode go"><code class="sourceCode go"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> err <span class="op">!=</span> <span class="ot">nil</span> <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span></code></pre></div>
127<p>Need I say more? I will, for good measure:</p> 154<p>Need I say more? I will, for good measure:</p>
128<ol type="1"> 155<ol type="1">
129<li>Error handling is optional</li> 156<li>Error handling is optional</li>
130<li>Errors are propagated via a clunky <code>if</code> + <code>return</code> statement</li> 157<li>Errors are propagated via a clunky <code>if</code> +
158<code>return</code> statement</li>
131</ol> 159</ol>
132<p>I prefer Haskell’s “Monadic” error handling, which is employed by Rust as well:</p> 160<p>I prefer Haskell’s “Monadic” error handling, which is employed by
133<div class="sourceCode" id="cb11"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="co">// 1. error handling is compulsory</span></span> 161Rust as well:</p>
162<div class="sourceCode" id="cb11"><pre
163class="sourceCode rust"><code class="sourceCode rust"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="co">// 1. error handling is compulsory</span></span>
134<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="co">// 2. errors are propagated with the `?` operator</span></span> 164<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="co">// 2. errors are propagated with the `?` operator</span></span>
135<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> foo() <span class="op">-&gt;</span> <span class="dt">Result</span><span class="op">&lt;</span><span class="dt">String</span><span class="op">,</span> <span class="pp">io::</span><span class="bu">Error</span><span class="op">&gt;</span> <span class="op">{</span></span> 165<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> foo() <span class="op">-&gt;</span> <span class="dt">Result</span><span class="op">&lt;</span><span class="dt">String</span><span class="op">,</span> <span class="pp">io::</span><span class="bu">Error</span><span class="op">&gt;</span> <span class="op">{</span></span>
136<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> <span class="kw">mut</span> f <span class="op">=</span> <span class="pp">File::</span>open(<span class="st">&quot;foo.txt&quot;</span>)<span class="op">?;</span> <span class="co">// return if error</span></span> 166<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> <span class="kw">mut</span> f <span class="op">=</span> <span class="pp">File::</span>open(<span class="st">&quot;foo.txt&quot;</span>)<span class="op">?;</span> <span class="co">// return if error</span></span>
@@ -144,13 +174,16 @@
144<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> main() <span class="op">{</span></span> 174<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> main() <span class="op">{</span></span>
145<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a> <span class="co">// `contents` is an enum known as Result:</span></span> 175<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a> <span class="co">// `contents` is an enum known as Result:</span></span>
146<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> contents <span class="op">=</span> foo()<span class="op">;</span></span> 176<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> contents <span class="op">=</span> foo()<span class="op">;</span></span>
147<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a> <span class="kw">match</span> contents <span class="op">{</span></span> 177<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">match</span> contents <span class="op">{</span></span>
148<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></a> <span class="cn">Ok</span>(c) <span class="op">=&gt;</span> <span class="pp">println!</span>(c)<span class="op">,</span></span> 178<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></a> <span class="cn">Ok</span>(c) <span class="op">=&gt;</span> <span class="pp">println!</span>(c)<span class="op">,</span></span>
149<span id="cb11-17"><a href="#cb11-17" aria-hidden="true" tabindex="-1"></a> <span class="cn">Err</span>(e) <span class="op">=&gt;</span> <span class="pp">eprintln!</span>(e)</span> 179<span id="cb11-17"><a href="#cb11-17" aria-hidden="true" tabindex="-1"></a> <span class="cn">Err</span>(e) <span class="op">=&gt;</span> <span class="pp">eprintln!</span>(e)</span>
150<span id="cb11-18"><a href="#cb11-18" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> 180<span id="cb11-18"><a href="#cb11-18" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
151<span id="cb11-19"><a href="#cb11-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 181<span id="cb11-19"><a href="#cb11-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
152<h3 id="conclusion">Conclusion</h3> 182<h3 id="conclusion">Conclusion</h3>
153<p>I did not want to conclude without talking about stylistic choices, lack of metaprogramming, bizzare export rules, but, I am too busy converting my <code>interface{}</code> types into actual generic code for Go v2.</p> 183<p>I did not want to conclude without talking about stylistic choices,
184lack of metaprogramming, bizzare export rules, but, I am too busy
185converting my <code>interface{}</code> types into actual generic code
186for Go v2.</p>
154 187
155 </div> 188 </div>
156 189
diff --git a/docs/posts/hold_position!/index.html b/docs/posts/hold_position!/index.html
index ec63508..68955fe 100644
--- a/docs/posts/hold_position!/index.html
+++ b/docs/posts/hold_position!/index.html
@@ -28,7 +28,7 @@
28 30/07 — 2019 28 30/07 — 2019
29 <div class="stats"> 29 <div class="stats">
30 <span class="stats-number"> 30 <span class="stats-number">
31 9.18 31 9.19
32 </span> 32 </span>
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
@@ -42,14 +42,24 @@
42 Hold Position! 42 Hold Position!
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>Often times, when I run a vim command that makes “big” changes to a file (a macro or a <code>:vimgrep</code> command) I lose my original position and feel disoriented.</p> 45 <p>Often times, when I run a vim command that makes “big” changes to a
46file (a macro or a <code>:vimgrep</code> command) I lose my original
47position and feel disoriented.</p>
46<p><em>Save position with <code>winsaveview()</code>!</em></p> 48<p><em>Save position with <code>winsaveview()</code>!</em></p>
47<p>The <code>winsaveview()</code> command returns a <code>Dictionary</code> that contains information about the view of the current window. This includes the cursor line number, cursor coloumn, the top most line in the window and a couple of other values, none of which concern us.</p> 49<p>The <code>winsaveview()</code> command returns a
48<p>Before running our command (one that jumps around the buffer, a lot), we save our view, and restore it once its done, with <code>winrestview</code>.</p> 50<code>Dictionary</code> that contains information about the view of the
51current window. This includes the cursor line number, cursor coloumn,
52the top most line in the window and a couple of other values, none of
53which concern us.</p>
54<p>Before running our command (one that jumps around the buffer, a lot),
55we save our view, and restore it once its done, with
56<code>winrestview</code>.</p>
49<pre><code>let view = winsaveview() 57<pre><code>let view = winsaveview()
50s/\s\+$//gc &quot; find and (confirm) replace trailing blanks 58s/\s\+$//gc &quot; find and (confirm) replace trailing blanks
51winrestview(view) &quot; restore our original view!</code></pre> 59winrestview(view) &quot; restore our original view!</code></pre>
52<p>It might seem a little overkill in the above example, just use `` (double backticks) instead, but it comes in handy when you run your file through heavier filtering.</p> 60<p>It might seem a little overkill in the above example, just use ``
61(double backticks) instead, but it comes in handy when you run your file
62through heavier filtering.</p>
53 63
54 </div> 64 </div>
55 65
diff --git a/docs/posts/index.html b/docs/posts/index.html
index 48452c0..8caab03 100644
--- a/docs/posts/index.html
+++ b/docs/posts/index.html
@@ -35,7 +35,7 @@
35 </td> 35 </td>
36 <td class=table-stats> 36 <td class=table-stats>
37 <span class="stats-number"> 37 <span class="stats-number">
38 9.5 38 9.6
39 </span> 39 </span>
40 <span class=stats-unit>min</span> 40 <span class=stats-unit>min</span>
41 </td> 41 </td>
@@ -86,7 +86,7 @@
86 </td> 86 </td>
87 <td class=table-stats> 87 <td class=table-stats>
88 <span class="stats-number"> 88 <span class="stats-number">
89 4.7 89 4.8
90 </span> 90 </span>
91 <span class=stats-unit>min</span> 91 <span class=stats-unit>min</span>
92 </td> 92 </td>
@@ -103,7 +103,7 @@
103 </td> 103 </td>
104 <td class=table-stats> 104 <td class=table-stats>
105 <span class="stats-number"> 105 <span class="stats-number">
106 8.5 106 8.6
107 </span> 107 </span>
108 <span class=stats-unit>min</span> 108 <span class=stats-unit>min</span>
109 </td> 109 </td>
@@ -171,7 +171,7 @@
171 </td> 171 </td>
172 <td class=table-stats> 172 <td class=table-stats>
173 <span class="stats-number"> 173 <span class="stats-number">
174 3.3 174 3.4
175 </span> 175 </span>
176 <span class=stats-unit>min</span> 176 <span class=stats-unit>min</span>
177 </td> 177 </td>
@@ -273,7 +273,7 @@
273 </td> 273 </td>
274 <td class=table-stats> 274 <td class=table-stats>
275 <span class="stats-number"> 275 <span class="stats-number">
276 3.2 276 3.3
277 </span> 277 </span>
278 <span class=stats-unit>min</span> 278 <span class=stats-unit>min</span>
279 </td> 279 </td>
@@ -307,7 +307,7 @@
307 </td> 307 </td>
308 <td class=table-stats> 308 <td class=table-stats>
309 <span class="stats-number"> 309 <span class="stats-number">
310 2.2 310 2.3
311 </span> 311 </span>
312 <span class=stats-unit>min</span> 312 <span class=stats-unit>min</span>
313 </td> 313 </td>
@@ -324,7 +324,7 @@
324 </td> 324 </td>
325 <td class=table-stats> 325 <td class=table-stats>
326 <span class="stats-number"> 326 <span class="stats-number">
327 1.3 327 1.4
328 </span> 328 </span>
329 <span class=stats-unit>min</span> 329 <span class=stats-unit>min</span>
330 </td> 330 </td>
diff --git a/docs/posts/lightweight_linting/index.html b/docs/posts/lightweight_linting/index.html
index 9bc84f2..b30c719 100644
--- a/docs/posts/lightweight_linting/index.html
+++ b/docs/posts/lightweight_linting/index.html
@@ -28,12 +28,12 @@
28 26/01 — 2022 28 26/01 — 2022
29 <div class="stats"> 29 <div class="stats">
30 <span class="stats-number"> 30 <span class="stats-number">
31 170.62 31 170.63
32 </span> 32 </span>
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
35 <span class="stats-number"> 35 <span class="stats-number">
36 8.5 36 8.6
37 </span> 37 </span>
38 <span class="stats-unit">min</span> 38 <span class="stats-unit">min</span>
39 </div> 39 </div>
@@ -42,14 +42,23 @@
42 Lightweight Linting 42 Lightweight Linting
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p><a href="https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries">Tree-sitter</a> queries allow you to search for patterns in syntax trees, much like a regex would, in text. Combine that with some Rust glue to write simple, custom linters.</p> 45 <p><a
46href="https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries">Tree-sitter</a>
47queries allow you to search for patterns in syntax trees, much like a
48regex would, in text. Combine that with some Rust glue to write simple,
49custom linters.</p>
46<h3 id="tree-sitter-syntax-trees">Tree-sitter syntax trees</h3> 50<h3 id="tree-sitter-syntax-trees">Tree-sitter syntax trees</h3>
47<p>Here is a quick crash course on syntax trees generated by tree-sitter. Syntax trees produced by tree-sitter are represented by S-expressions. The generated S-expression for the following Rust code,</p> 51<p>Here is a quick crash course on syntax trees generated by
48<div class="sourceCode" id="cb1"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> main() <span class="op">{</span></span> 52tree-sitter. Syntax trees produced by tree-sitter are represented by
53S-expressions. The generated S-expression for the following Rust
54code,</p>
55<div class="sourceCode" id="cb1"><pre
56class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> main() <span class="op">{</span></span>
49<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> x <span class="op">=</span> <span class="dv">2</span><span class="op">;</span></span> 57<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> x <span class="op">=</span> <span class="dv">2</span><span class="op">;</span></span>
50<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 58<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
51<p>would be:</p> 59<p>would be:</p>
52<div class="sourceCode" id="cb2"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>(source_file</span> 60<div class="sourceCode" id="cb2"><pre
61class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>(source_file</span>
53<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> (function_item</span> 62<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> (function_item</span>
54<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> name: (identifier)</span> 63<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> name: (identifier)</span>
55<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a> parameters: (parameters)</span> 64<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a> parameters: (parameters)</span>
@@ -58,13 +67,19 @@
58<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a> (let_declaration </span> 67<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a> (let_declaration </span>
59<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a> pattern: (identifier)</span> 68<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a> pattern: (identifier)</span>
60<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a> value: (integer_literal)))))</span></code></pre></div> 69<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a> value: (integer_literal)))))</span></code></pre></div>
61<p>Syntax trees generated by tree-sitter have a couple of other cool properties: they are <em>lossless</em> syntax trees. Given a lossless syntax tree, you can regenerate the original source code in its entirety. Consider the following addition to our example:</p> 70<p>Syntax trees generated by tree-sitter have a couple of other cool
62<div class="sourceCode" id="cb3"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a> <span class="kw">fn</span> main() <span class="op">{</span></span> 71properties: they are <em>lossless</em> syntax trees. Given a lossless
72syntax tree, you can regenerate the original source code in its
73entirety. Consider the following addition to our example:</p>
74<div class="sourceCode" id="cb3"><pre
75class="sourceCode rust"><code class="sourceCode rust"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a> <span class="kw">fn</span> main() <span class="op">{</span></span>
63<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="co">// a comment goes here</span></span> 76<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="co">// a comment goes here</span></span>
64<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> x <span class="op">=</span> <span class="dv">2</span><span class="op">;</span></span> 77<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> x <span class="op">=</span> <span class="dv">2</span><span class="op">;</span></span>
65<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div> 78<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div>
66<p>The tree-sitter syntax tree preserves the comment, while the typical abstract syntax tree wouldn’t:</p> 79<p>The tree-sitter syntax tree preserves the comment, while the typical
67<div class="sourceCode" id="cb4"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a> (source_file</span> 80abstract syntax tree wouldn’t:</p>
81<div class="sourceCode" id="cb4"><pre
82class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a> (source_file</span>
68<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> (function_item</span> 83<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> (function_item</span>
69<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a> name: (identifier)</span> 84<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a> name: (identifier)</span>
70<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a> parameters: (parameters)</span> 85<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a> parameters: (parameters)</span>
@@ -75,25 +90,34 @@
75<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a> pattern: (identifier)</span> 90<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a> pattern: (identifier)</span>
76<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a> value: (integer_literal)))))</span></code></pre></div> 91<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a> value: (integer_literal)))))</span></code></pre></div>
77<h3 id="tree-sitter-queries">Tree-sitter queries</h3> 92<h3 id="tree-sitter-queries">Tree-sitter queries</h3>
78<p>Tree-sitter provides a DSL to match over CSTs. These queries resemble our S-expression syntax trees, here is a query to match all line comments in a Rust CST:</p> 93<p>Tree-sitter provides a DSL to match over CSTs. These queries resemble
79<div class="sourceCode" id="cb5"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>(line_comment)</span> 94our S-expression syntax trees, here is a query to match all line
95comments in a Rust CST:</p>
96<div class="sourceCode" id="cb5"><pre
97class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>(line_comment)</span>
80<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a></span> 98<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a></span>
81<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="co">; matches the following rust code</span></span> 99<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="co">; matches the following rust code</span></span>
82<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="co">; // a comment goes here</span></span></code></pre></div> 100<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="co">; // a comment goes here</span></span></code></pre></div>
83<p>Neat, eh? But don’t take my word for it, give it a go on the <a href="https://tree-sitter.github.io/tree-sitter/playground">tree-sitter playground</a>. Type in a query like so:</p> 101<p>Neat, eh? But don’t take my word for it, give it a go on the <a
84<div class="sourceCode" id="cb6"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="co">; the web playground requires you to specify a &quot;capture&quot;</span></span> 102href="https://tree-sitter.github.io/tree-sitter/playground">tree-sitter
103playground</a>. Type in a query like so:</p>
104<div class="sourceCode" id="cb6"><pre
105class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="co">; the web playground requires you to specify a &quot;capture&quot;</span></span>
85<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="co">; you will notice the capture and the nodes it captured</span></span> 106<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="co">; you will notice the capture and the nodes it captured</span></span>
86<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="co">; turn blue</span></span> 107<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="co">; turn blue</span></span>
87<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>(line_comment) @capture</span></code></pre></div> 108<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>(line_comment) @capture</span></code></pre></div>
88<p>Here’s another to match <code>let</code> expressions that bind an integer to an identifier:</p> 109<p>Here’s another to match <code>let</code> expressions that bind an
89<div class="sourceCode" id="cb7"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>(let_declaration</span> 110integer to an identifier:</p>
111<div class="sourceCode" id="cb7"><pre
112class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>(let_declaration</span>
90<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a> pattern: (identifier)</span> 113<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a> pattern: (identifier)</span>
91<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> value: (integer_literal))</span> 114<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> value: (integer_literal))</span>
92<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a> </span> 115<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a> </span>
93<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="co">; matches:</span></span> 116<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="co">; matches:</span></span>
94<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="co">; let foo = 2;</span></span></code></pre></div> 117<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="co">; let foo = 2;</span></span></code></pre></div>
95<p>We can <em>capture</em> nodes into variables:</p> 118<p>We can <em>capture</em> nodes into variables:</p>
96<div class="sourceCode" id="cb8"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>(let_declaration </span> 119<div class="sourceCode" id="cb8"><pre
120class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>(let_declaration </span>
97<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a> pattern: (identifier) @my-capture</span> 121<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a> pattern: (identifier) @my-capture</span>
98<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a> value: (integer_literal))</span> 122<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a> value: (integer_literal))</span>
99<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> </span> 123<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> </span>
@@ -103,7 +127,8 @@
103<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a><span class="co">; captures:</span></span> 127<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a><span class="co">; captures:</span></span>
104<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a><span class="co">; foo</span></span></code></pre></div> 128<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a><span class="co">; foo</span></span></code></pre></div>
105<p>And apply certain <em>predicates</em> to captures:</p> 129<p>And apply certain <em>predicates</em> to captures:</p>
106<div class="sourceCode" id="cb9"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>((let_declaration</span> 130<div class="sourceCode" id="cb9"><pre
131class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>((let_declaration</span>
107<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a> pattern: (identifier) @my-capture</span> 132<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a> pattern: (identifier) @my-capture</span>
108<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> value: (integer_literal))</span> 133<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> value: (integer_literal))</span>
109<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a> (<span class="sc">#e</span>q? @my-capture <span class="st">&quot;foo&quot;</span>))</span> 134<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a> (<span class="sc">#e</span>q? @my-capture <span class="st">&quot;foo&quot;</span>))</span>
@@ -113,8 +138,10 @@
113<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a></span> 138<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a></span>
114<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a><span class="co">; and not:</span></span> 139<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a><span class="co">; and not:</span></span>
115<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a><span class="co">; let bar = 2;</span></span></code></pre></div> 140<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a><span class="co">; let bar = 2;</span></span></code></pre></div>
116<p>The <code>#match?</code> predicate checks if a capture matches a regex:</p> 141<p>The <code>#match?</code> predicate checks if a capture matches a
117<div class="sourceCode" id="cb10"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>((let_declaration</span> 142regex:</p>
143<div class="sourceCode" id="cb10"><pre
144class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>((let_declaration</span>
118<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a> pattern: (identifier) @my-capture</span> 145<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a> pattern: (identifier) @my-capture</span>
119<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> value: (integer_literal))</span> 146<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> value: (integer_literal))</span>
120<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a> (#match? @my-capture <span class="st">&quot;foo|bar&quot;</span>))</span> 147<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a> (#match? @my-capture <span class="st">&quot;foo|bar&quot;</span>))</span>
@@ -122,8 +149,10 @@
122<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="co">; matches both `foo` and `bar`:</span></span> 149<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="co">; matches both `foo` and `bar`:</span></span>
123<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="co">; let foo = 2;</span></span> 150<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="co">; let foo = 2;</span></span>
124<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a><span class="co">; let bar = 2;</span></span></code></pre></div> 151<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a><span class="co">; let bar = 2;</span></span></code></pre></div>
125<p>Exhibit indifference, as a stoic programmer would, with the <em>wildcard</em> pattern:</p> 152<p>Exhibit indifference, as a stoic programmer would, with the
126<div class="sourceCode" id="cb11"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>(let_declaration</span> 153<em>wildcard</em> pattern:</p>
154<div class="sourceCode" id="cb11"><pre
155class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>(let_declaration</span>
127<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a> pattern: (identifier)</span> 156<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a> pattern: (identifier)</span>
128<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a> value: (<span class="op">_</span>))</span> 157<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a> value: (<span class="op">_</span>))</span>
129<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> </span> 158<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> </span>
@@ -131,73 +160,106 @@
131<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a><span class="co">; let foo = &quot;foo&quot;;</span></span> 160<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a><span class="co">; let foo = &quot;foo&quot;;</span></span>
132<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a><span class="co">; let foo = 42;</span></span> 161<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a><span class="co">; let foo = 42;</span></span>
133<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a><span class="co">; let foo = bar;</span></span></code></pre></div> 162<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a><span class="co">; let foo = bar;</span></span></code></pre></div>
134<p><a href="https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries">The documentation</a> does the tree-sitter query DSL more justice, but we now know enough to write our first lint.</p> 163<p><a
164href="https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries">The
165documentation</a> does the tree-sitter query DSL more justice, but we
166now know enough to write our first lint.</p>
135<h3 id="write-you-a-tree-sitter-lint">Write you a tree-sitter lint</h3> 167<h3 id="write-you-a-tree-sitter-lint">Write you a tree-sitter lint</h3>
136<p>Strings in <code>std::env</code> functions are error prone:</p> 168<p>Strings in <code>std::env</code> functions are error prone:</p>
137<div class="sourceCode" id="cb12"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="pp">std::env::</span>remove_var(<span class="st">&quot;RUST_BACKTACE&quot;</span>)<span class="op">;</span></span> 169<div class="sourceCode" id="cb12"><pre
170class="sourceCode rust"><code class="sourceCode rust"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="pp">std::env::</span>remove_var(<span class="st">&quot;RUST_BACKTACE&quot;</span>)<span class="op">;</span></span>
138<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// ^^^^ &quot;TACE&quot; instead of &quot;TRACE&quot;</span></span></code></pre></div> 171<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// ^^^^ &quot;TACE&quot; instead of &quot;TRACE&quot;</span></span></code></pre></div>
139<p>I prefer this instead:</p> 172<p>I prefer this instead:</p>
140<div class="sourceCode" id="cb13"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="co">// somewhere in a module that is well spellchecked</span></span> 173<div class="sourceCode" id="cb13"><pre
174class="sourceCode rust"><code class="sourceCode rust"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="co">// somewhere in a module that is well spellchecked</span></span>
141<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="kw">static</span> BACKTRACE<span class="op">:</span> <span class="op">&amp;</span><span class="dt">str</span> <span class="op">=</span> <span class="st">&quot;RUST_BACKTRACE&quot;</span><span class="op">;</span></span> 175<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="kw">static</span> BACKTRACE<span class="op">:</span> <span class="op">&amp;</span><span class="dt">str</span> <span class="op">=</span> <span class="st">&quot;RUST_BACKTRACE&quot;</span><span class="op">;</span></span>
142<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a></span> 176<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a></span>
143<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="co">// rest of the codebase</span></span> 177<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="co">// rest of the codebase</span></span>
144<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a><span class="pp">std::env::</span>remove_var(BACKTRACE)<span class="op">;</span></span></code></pre></div> 178<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a><span class="pp">std::env::</span>remove_var(BACKTRACE)<span class="op">;</span></span></code></pre></div>
145<p>Let’s write a lint to find <code>std::env</code> functions that use strings. Put aside the effectiveness of this lint for the moment, and take a stab at writing a tree-sitter query. For reference, a function call like so:</p> 179<p>Let’s write a lint to find <code>std::env</code> functions that use
146<div class="sourceCode" id="cb14"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>remove_var(<span class="st">&quot;RUST_BACKTRACE&quot;</span>)</span></code></pre></div> 180strings. Put aside the effectiveness of this lint for the moment, and
181take a stab at writing a tree-sitter query. For reference, a function
182call like so:</p>
183<div class="sourceCode" id="cb14"><pre
184class="sourceCode rust"><code class="sourceCode rust"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>remove_var(<span class="st">&quot;RUST_BACKTRACE&quot;</span>)</span></code></pre></div>
147<p>Produces the following S-expression:</p> 185<p>Produces the following S-expression:</p>
148<div class="sourceCode" id="cb15"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a>(call_expression</span> 186<div class="sourceCode" id="cb15"><pre
187class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a>(call_expression</span>
149<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a> function: (identifier)</span> 188<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a> function: (identifier)</span>
150<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a> arguments: (arguments (string_literal)))</span></code></pre></div> 189<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a> arguments: (arguments (string_literal)))</span></code></pre></div>
151<p>We are definitely looking for a <code>call_expression</code>:</p> 190<p>We are definitely looking for a <code>call_expression</code>:</p>
152<div class="sourceCode" id="cb16"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>(call_expression) @raise</span></code></pre></div> 191<div class="sourceCode" id="cb16"><pre
153<p>Whose function name matches <code>std::env::var</code> or <code>std::env::remove_var</code> at the very least (I know, I know, this isn’t the most optimal regex):</p> 192class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>(call_expression) @raise</span></code></pre></div>
154<div class="sourceCode" id="cb17"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a>((call_expression</span> 193<p>Whose function name matches <code>std::env::var</code> or
194<code>std::env::remove_var</code> at the very least (I know, I know,
195this isn’t the most optimal regex):</p>
196<div class="sourceCode" id="cb17"><pre
197class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a>((call_expression</span>
155<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a> function: (<span class="op">_</span>) @fn-name) @raise</span> 198<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a> function: (<span class="op">_</span>) @fn-name) @raise</span>
156<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a> (#match? @fn-name <span class="st">&quot;std::env::(var|remove_var)&quot;</span>))</span></code></pre></div> 199<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a> (#match? @fn-name <span class="st">&quot;std::env::(var|remove_var)&quot;</span>))</span></code></pre></div>
157<p>Let’s turn that <code>std::</code> prefix optional:</p> 200<p>Let’s turn that <code>std::</code> prefix optional:</p>
158<div class="sourceCode" id="cb18"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a>((call_expression</span> 201<div class="sourceCode" id="cb18"><pre
202class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a>((call_expression</span>
159<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a> function: (<span class="op">_</span>) @fn-name) @raise</span> 203<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a> function: (<span class="op">_</span>) @fn-name) @raise</span>
160<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a> (#match? @fn-name <span class="st">&quot;(std::|)env::(var|remove_var)&quot;</span>))</span></code></pre></div> 204<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a> (#match? @fn-name <span class="st">&quot;(std::|)env::(var|remove_var)&quot;</span>))</span></code></pre></div>
161<p>And ensure that <code>arguments</code> is a string:</p> 205<p>And ensure that <code>arguments</code> is a string:</p>
162<div class="sourceCode" id="cb19"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a>((call_expression</span> 206<div class="sourceCode" id="cb19"><pre
207class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a>((call_expression</span>
163<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a> function: (<span class="op">_</span>) @fn-name</span> 208<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a> function: (<span class="op">_</span>) @fn-name</span>
164<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a> arguments: (arguments (string_literal)))</span> 209<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a> arguments: (arguments (string_literal)))</span>
165<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a> (#match? @fn-name <span class="st">&quot;(std::|)env::(var|remove_var)&quot;</span>))</span></code></pre></div> 210<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a> (#match? @fn-name <span class="st">&quot;(std::|)env::(var|remove_var)&quot;</span>))</span></code></pre></div>
166<h3 id="running-our-linter">Running our linter</h3> 211<h3 id="running-our-linter">Running our linter</h3>
167<p>We could always plug our query into the web playground, but let’s go a step further:</p> 212<p>We could always plug our query into the web playground, but let’s go
168<div class="sourceCode" id="cb20"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="ex">cargo</span> new <span class="at">--bin</span> toy-lint</span></code></pre></div> 213a step further:</p>
169<p>Add <code>tree-sitter</code> and <code>tree-sitter-rust</code> to your dependencies:</p> 214<div class="sourceCode" id="cb20"><pre
170<div class="sourceCode" id="cb21"><pre class="sourceCode toml"><code class="sourceCode toml"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="co"># within Cargo.toml</span></span> 215class="sourceCode bash"><code class="sourceCode bash"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="ex">cargo</span> new <span class="at">--bin</span> toy-lint</span></code></pre></div>
216<p>Add <code>tree-sitter</code> and <code>tree-sitter-rust</code> to
217your dependencies:</p>
218<div class="sourceCode" id="cb21"><pre
219class="sourceCode toml"><code class="sourceCode toml"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="co"># within Cargo.toml</span></span>
171<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a><span class="kw">[</span><span class="dt">dependencies</span><span class="kw">]</span></span> 220<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a><span class="kw">[</span><span class="dt">dependencies</span><span class="kw">]</span></span>
172<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a><span class="dt">tree-sitter</span> <span class="op">=</span> <span class="st">&quot;0.20&quot;</span></span> 221<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a><span class="dt">tree-sitter</span> <span class="op">=</span> <span class="st">&quot;0.20&quot;</span></span>
173<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a></span> 222<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a></span>
174<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a><span class="kw">[</span><span class="dt">dependencies</span><span class="kw">.</span><span class="dt">tree-sitter-rust</span><span class="kw">]</span></span> 223<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a><span class="kw">[</span><span class="dt">dependencies</span><span class="kw">.</span><span class="dt">tree-sitter-rust</span><span class="kw">]</span></span>
175<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a><span class="dt">git</span> <span class="op">=</span> <span class="st">&quot;https://github.com/tree-sitter/tree-sitter-rust&quot;</span></span></code></pre></div> 224<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a><span class="dt">git</span> <span class="op">=</span> <span class="st">&quot;https://github.com/tree-sitter/tree-sitter-rust&quot;</span></span></code></pre></div>
176<p>Let’s load in some Rust code to work with. As <a href="https://en.wikipedia.org/wiki/Self-reference">an ode to Gödel</a> (G<code>ode</code>l?), why not load in our linter itself:</p> 225<p>Let’s load in some Rust code to work with. As <a
177<div class="sourceCode" id="cb22"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> main() <span class="op">{</span></span> 226href="https://en.wikipedia.org/wiki/Self-reference">an ode to Gödel</a>
227(G<code>ode</code>l?), why not load in our linter itself:</p>
228<div class="sourceCode" id="cb22"><pre
229class="sourceCode rust"><code class="sourceCode rust"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> main() <span class="op">{</span></span>
178<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> src <span class="op">=</span> <span class="pp">include_str!</span>(<span class="st">&quot;main.rs&quot;</span>)<span class="op">;</span></span> 230<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> src <span class="op">=</span> <span class="pp">include_str!</span>(<span class="st">&quot;main.rs&quot;</span>)<span class="op">;</span></span>
179<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 231<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
180<p>Most tree-sitter APIs require a reference to a <code>Language</code> struct, we will be working with Rust if you haven’t already guessed:</p> 232<p>Most tree-sitter APIs require a reference to a <code>Language</code>
181<div class="sourceCode" id="cb23"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">tree_sitter::</span>Language<span class="op">;</span></span> 233struct, we will be working with Rust if you haven’t already guessed:</p>
234<div class="sourceCode" id="cb23"><pre
235class="sourceCode rust"><code class="sourceCode rust"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">tree_sitter::</span>Language<span class="op">;</span></span>
182<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a></span> 236<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a></span>
183<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> rust_lang<span class="op">:</span> Language <span class="op">=</span> <span class="pp">tree_sitter_rust::</span>language()<span class="op">;</span></span></code></pre></div> 237<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> rust_lang<span class="op">:</span> Language <span class="op">=</span> <span class="pp">tree_sitter_rust::</span>language()<span class="op">;</span></span></code></pre></div>
184<p>Enough scaffolding, let’s parse some Rust:</p> 238<p>Enough scaffolding, let’s parse some Rust:</p>
185<div class="sourceCode" id="cb24"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">tree_sitter::</span>Parser<span class="op">;</span></span> 239<div class="sourceCode" id="cb24"><pre
240class="sourceCode rust"><code class="sourceCode rust"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">tree_sitter::</span>Parser<span class="op">;</span></span>
186<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a></span> 241<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a></span>
187<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> <span class="kw">mut</span> parser <span class="op">=</span> <span class="pp">Parser::</span>new()<span class="op">;</span></span> 242<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> <span class="kw">mut</span> parser <span class="op">=</span> <span class="pp">Parser::</span>new()<span class="op">;</span></span>
188<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a>parser<span class="op">.</span>set_language(rust_lang)<span class="op">.</span>unwrap()<span class="op">;</span></span> 243<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a>parser<span class="op">.</span>set_language(rust_lang)<span class="op">.</span>unwrap()<span class="op">;</span></span>
189<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a></span> 244<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a></span>
190<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> parse_tree <span class="op">=</span> parser<span class="op">.</span>parse(<span class="op">&amp;</span>src<span class="op">,</span> <span class="cn">None</span>)<span class="op">.</span>unwrap()<span class="op">;</span></span></code></pre></div> 245<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> parse_tree <span class="op">=</span> parser<span class="op">.</span>parse(<span class="op">&amp;</span>src<span class="op">,</span> <span class="cn">None</span>)<span class="op">.</span>unwrap()<span class="op">;</span></span></code></pre></div>
191<p>The second argument to <code>Parser::parse</code> may be of interest. Tree-sitter has this cool feature that allows for quick reparsing of existing parse trees if they contain edits. If you do happen to want to reparse a source file, you can pass in the old tree:</p> 246<p>The second argument to <code>Parser::parse</code> may be of interest.
192<div class="sourceCode" id="cb25"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="co">// if you wish to reparse instead of parse</span></span> 247Tree-sitter has this cool feature that allows for quick reparsing of
248existing parse trees if they contain edits. If you do happen to want to
249reparse a source file, you can pass in the old tree:</p>
250<div class="sourceCode" id="cb25"><pre
251class="sourceCode rust"><code class="sourceCode rust"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="co">// if you wish to reparse instead of parse</span></span>
193<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a>old_tree<span class="op">.</span>edit(<span class="co">/* redacted */</span>)<span class="op">;</span></span> 252<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a>old_tree<span class="op">.</span>edit(<span class="co">/* redacted */</span>)<span class="op">;</span></span>
194<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a></span> 253<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a></span>
195<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a><span class="co">// generate shiny new reparsed tree</span></span> 254<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a><span class="co">// generate shiny new reparsed tree</span></span>
196<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> new_tree <span class="op">=</span> parser<span class="op">.</span>parse(<span class="op">&amp;</span>src<span class="op">,</span> <span class="cn">Some</span>(old_tree))<span class="op">.</span>unwrap()</span></code></pre></div> 255<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> new_tree <span class="op">=</span> parser<span class="op">.</span>parse(<span class="op">&amp;</span>src<span class="op">,</span> <span class="cn">Some</span>(old_tree))<span class="op">.</span>unwrap()</span></code></pre></div>
197<p>Anyhow (<a href="http://github.com/dtolnay/anyhow">hah!</a>), now that we have a parse tree, we can inspect it:</p> 256<p>Anyhow (<a href="http://github.com/dtolnay/anyhow">hah!</a>), now
198<div class="sourceCode" id="cb26"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="pp">println!</span>(<span class="st">&quot;{}&quot;</span><span class="op">,</span> parse_tree<span class="op">.</span>root_node()<span class="op">.</span>to_sexp())<span class="op">;</span></span></code></pre></div> 257that we have a parse tree, we can inspect it:</p>
258<div class="sourceCode" id="cb26"><pre
259class="sourceCode rust"><code class="sourceCode rust"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="pp">println!</span>(<span class="st">&quot;{}&quot;</span><span class="op">,</span> parse_tree<span class="op">.</span>root_node()<span class="op">.</span>to_sexp())<span class="op">;</span></span></code></pre></div>
199<p>Or better yet, run a query on it:</p> 260<p>Or better yet, run a query on it:</p>
200<div class="sourceCode" id="cb27"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">tree_sitter::</span>Query<span class="op">;</span></span> 261<div class="sourceCode" id="cb27"><pre
262class="sourceCode rust"><code class="sourceCode rust"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">tree_sitter::</span>Query<span class="op">;</span></span>
201<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a></span> 263<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a></span>
202<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> query <span class="op">=</span> <span class="pp">Query::</span>new(</span> 264<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> query <span class="op">=</span> <span class="pp">Query::</span>new(</span>
203<span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a> rust_lang<span class="op">,</span></span> 265<span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a> rust_lang<span class="op">,</span></span>
@@ -209,8 +271,11 @@
209<span id="cb27-10"><a href="#cb27-10" aria-hidden="true" tabindex="-1"></a><span class="st"> &quot;#</span></span> 271<span id="cb27-10"><a href="#cb27-10" aria-hidden="true" tabindex="-1"></a><span class="st"> &quot;#</span></span>
210<span id="cb27-11"><a href="#cb27-11" aria-hidden="true" tabindex="-1"></a>)</span> 272<span id="cb27-11"><a href="#cb27-11" aria-hidden="true" tabindex="-1"></a>)</span>
211<span id="cb27-12"><a href="#cb27-12" aria-hidden="true" tabindex="-1"></a><span class="op">.</span>unwrap()<span class="op">;</span></span></code></pre></div> 273<span id="cb27-12"><a href="#cb27-12" aria-hidden="true" tabindex="-1"></a><span class="op">.</span>unwrap()<span class="op">;</span></span></code></pre></div>
212<p>A <code>QueryCursor</code> is tree-sitter’s way of maintaining state as we iterate through the matches or captures produced by running a query on the parse tree. Observe:</p> 274<p>A <code>QueryCursor</code> is tree-sitter’s way of maintaining state
213<div class="sourceCode" id="cb28"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">tree_sitter::</span>QueryCursor<span class="op">;</span></span> 275as we iterate through the matches or captures produced by running a
276query on the parse tree. Observe:</p>
277<div class="sourceCode" id="cb28"><pre
278class="sourceCode rust"><code class="sourceCode rust"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">tree_sitter::</span>QueryCursor<span class="op">;</span></span>
214<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a></span> 279<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a></span>
215<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> <span class="kw">mut</span> query_cursor <span class="op">=</span> <span class="pp">QueryCursor::</span>new()<span class="op">;</span></span> 280<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> <span class="kw">mut</span> query_cursor <span class="op">=</span> <span class="pp">QueryCursor::</span>new()<span class="op">;</span></span>
216<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> all_matches <span class="op">=</span> query_cursor<span class="op">.</span>matches(</span> 281<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> all_matches <span class="op">=</span> query_cursor<span class="op">.</span>matches(</span>
@@ -218,15 +283,22 @@
218<span id="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a> parse_tree<span class="op">.</span>root_node()<span class="op">,</span></span> 283<span id="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a> parse_tree<span class="op">.</span>root_node()<span class="op">,</span></span>
219<span id="cb28-7"><a href="#cb28-7" aria-hidden="true" tabindex="-1"></a> src<span class="op">.</span>as_bytes()<span class="op">,</span></span> 284<span id="cb28-7"><a href="#cb28-7" aria-hidden="true" tabindex="-1"></a> src<span class="op">.</span>as_bytes()<span class="op">,</span></span>
220<span id="cb28-8"><a href="#cb28-8" aria-hidden="true" tabindex="-1"></a>)<span class="op">;</span></span></code></pre></div> 285<span id="cb28-8"><a href="#cb28-8" aria-hidden="true" tabindex="-1"></a>)<span class="op">;</span></span></code></pre></div>
221<p>We begin by passing our query to the cursor, followed by the “root node”, which is another way of saying, “start from the top”, and lastly, the source itself. If you have already taken a look at the C API, you will notice that the last argument, the source (known as the <code>TextProvider</code>), is not required. The Rust bindings seem to require this argument to provide predicate functionality such as <code>#match?</code> and <code>#eq?</code>.</p> 286<p>We begin by passing our query to the cursor, followed by the “root
287node”, which is another way of saying, “start from the top”, and lastly,
288the source itself. If you have already taken a look at the C API, you
289will notice that the last argument, the source (known as the
290<code>TextProvider</code>), is not required. The Rust bindings seem to
291require this argument to provide predicate functionality such as
292<code>#match?</code> and <code>#eq?</code>.</p>
222<p>Do something with the matches:</p> 293<p>Do something with the matches:</p>
223<div class="sourceCode" id="cb29"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="co">// get the index of the capture named &quot;raise&quot;</span></span> 294<div class="sourceCode" id="cb29"><pre
295class="sourceCode rust"><code class="sourceCode rust"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="co">// get the index of the capture named &quot;raise&quot;</span></span>
224<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> raise_idx <span class="op">=</span> query<span class="op">.</span>capture_index_for_name(<span class="st">&quot;raise&quot;</span>)<span class="op">.</span>unwrap()<span class="op">;</span></span> 296<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> raise_idx <span class="op">=</span> query<span class="op">.</span>capture_index_for_name(<span class="st">&quot;raise&quot;</span>)<span class="op">.</span>unwrap()<span class="op">;</span></span>
225<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a></span> 297<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a></span>
226<span id="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a><span class="kw">for</span> each_match <span class="kw">in</span> all_matches <span class="op">{</span></span> 298<span id="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> each_match <span class="kw">in</span> all_matches <span class="op">{</span></span>
227<span id="cb29-5"><a href="#cb29-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// iterate over all captures called &quot;raise&quot;</span></span> 299<span id="cb29-5"><a href="#cb29-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// iterate over all captures called &quot;raise&quot;</span></span>
228<span id="cb29-6"><a href="#cb29-6" aria-hidden="true" tabindex="-1"></a> <span class="co">// ignore captures such as &quot;fn-name&quot;</span></span> 300<span id="cb29-6"><a href="#cb29-6" aria-hidden="true" tabindex="-1"></a> <span class="co">// ignore captures such as &quot;fn-name&quot;</span></span>
229<span id="cb29-7"><a href="#cb29-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">for</span> capture <span class="kw">in</span> each_match</span> 301<span id="cb29-7"><a href="#cb29-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> capture <span class="kw">in</span> each_match</span>
230<span id="cb29-8"><a href="#cb29-8" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>captures</span> 302<span id="cb29-8"><a href="#cb29-8" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>captures</span>
231<span id="cb29-9"><a href="#cb29-9" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>iter()</span> 303<span id="cb29-9"><a href="#cb29-9" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>iter()</span>
232<span id="cb29-10"><a href="#cb29-10" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>filter(<span class="op">|</span>c<span class="op">|</span> c<span class="op">.</span>idx <span class="op">==</span> raise_idx)</span> 304<span id="cb29-10"><a href="#cb29-10" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>filter(<span class="op">|</span>c<span class="op">|</span> c<span class="op">.</span>idx <span class="op">==</span> raise_idx)</span>
@@ -241,8 +313,10 @@
241<span id="cb29-19"><a href="#cb29-19" aria-hidden="true" tabindex="-1"></a> )<span class="op">;</span></span> 313<span id="cb29-19"><a href="#cb29-19" aria-hidden="true" tabindex="-1"></a> )<span class="op">;</span></span>
242<span id="cb29-20"><a href="#cb29-20" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> 314<span id="cb29-20"><a href="#cb29-20" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
243<span id="cb29-21"><a href="#cb29-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> 315<span id="cb29-21"><a href="#cb29-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
244<p>Lastly, add the following line to your source code, to get the linter to catch something:</p> 316<p>Lastly, add the following line to your source code, to get the linter
245<div class="sourceCode" id="cb30"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="pp">env::</span>remove_var(<span class="st">&quot;RUST_BACKTRACE&quot;</span>)<span class="op">;</span></span></code></pre></div> 317to catch something:</p>
318<div class="sourceCode" id="cb30"><pre
319class="sourceCode rust"><code class="sourceCode rust"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="pp">env::</span>remove_var(<span class="st">&quot;RUST_BACKTRACE&quot;</span>)<span class="op">;</span></span></code></pre></div>
246<p>And <code>cargo run</code>:</p> 320<p>And <code>cargo run</code>:</p>
247<pre class="shell"><code>λ cargo run 321<pre class="shell"><code>λ cargo run
248 Compiling toy-lint v0.1.0 (/redacted/path/to/toy-lint) 322 Compiling toy-lint v0.1.0 (/redacted/path/to/toy-lint)
@@ -251,17 +325,33 @@
251[Line: 40, Col: 4] Offending source code: `env::remove_var(&quot;RUST_BACKTRACE&quot;)`</code></pre> 325[Line: 40, Col: 4] Offending source code: `env::remove_var(&quot;RUST_BACKTRACE&quot;)`</code></pre>
252<p>Thank you tree-sitter!</p> 326<p>Thank you tree-sitter!</p>
253<h3 id="bonus">Bonus</h3> 327<h3 id="bonus">Bonus</h3>
254<p>Keen readers will notice that I avoided <code>std::env::set_var</code>. Because <code>set_var</code> is called with two arguments, a “key” and a “value”, unlike <code>env::var</code> and <code>env::remove_var</code>. As a result, it requires more juggling:</p> 328<p>Keen readers will notice that I avoided
255<div class="sourceCode" id="cb32"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a>((call_expression</span> 329<code>std::env::set_var</code>. Because <code>set_var</code> is called
330with two arguments, a “key” and a “value”, unlike <code>env::var</code>
331and <code>env::remove_var</code>. As a result, it requires more
332juggling:</p>
333<div class="sourceCode" id="cb32"><pre
334class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a>((call_expression</span>
256<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a> function: (<span class="op">_</span>) @fn-name</span> 335<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a> function: (<span class="op">_</span>) @fn-name</span>
257<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a> arguments: (arguments <span class="op">.</span> (string_literal)<span class="op">?</span> <span class="op">.</span> (string_literal) <span class="op">.</span>)) @raise</span> 336<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a> arguments: (arguments <span class="op">.</span> (string_literal)<span class="op">?</span> <span class="op">.</span> (string_literal) <span class="op">.</span>)) @raise</span>
258<span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a> (#match? @fn-name <span class="st">&quot;(std::|)env::(var|remove_var|set_var)&quot;</span>))</span></code></pre></div> 337<span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a> (#match? @fn-name <span class="st">&quot;(std::|)env::(var|remove_var|set_var)&quot;</span>))</span></code></pre></div>
259<p>The interesting part of this query is the humble <code>.</code>, the <em>anchor</em> operator. Anchors help constrain child nodes in certain ways. In this case, it ensures that we match exactly two <code>string_literal</code>s who are siblings or exactly one <code>string_literal</code> with no siblings. Unfortunately, this query also matches the following invalid Rust code:</p> 338<p>The interesting part of this query is the humble <code>.</code>, the
260<div class="sourceCode" id="cb33"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="co">// remove_var accepts only 1 arg!</span></span> 339<em>anchor</em> operator. Anchors help constrain child nodes in certain
340ways. In this case, it ensures that we match exactly two
341<code>string_literal</code>s who are siblings or exactly one
342<code>string_literal</code> with no siblings. Unfortunately, this query
343also matches the following invalid Rust code:</p>
344<div class="sourceCode" id="cb33"><pre
345class="sourceCode rust"><code class="sourceCode rust"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="co">// remove_var accepts only 1 arg!</span></span>
261<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a><span class="pp">std::env::</span>remove_var(<span class="st">&quot;RUST_BACKTRACE&quot;</span><span class="op">,</span> <span class="st">&quot;1&quot;</span>)<span class="op">;</span></span></code></pre></div> 346<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a><span class="pp">std::env::</span>remove_var(<span class="st">&quot;RUST_BACKTRACE&quot;</span><span class="op">,</span> <span class="st">&quot;1&quot;</span>)<span class="op">;</span></span></code></pre></div>
262<h3 id="notes">Notes</h3> 347<h3 id="notes">Notes</h3>
263<p>All-in-all, the query DSL does a great job in lowering the bar to writing language tools. The knowledge gained from mastering the query DSL can be applied to other languages that have tree-sitter grammars too. This query detects <code>to_json</code> methods that do not accept additional arguments, in Ruby:</p> 348<p>All-in-all, the query DSL does a great job in lowering the bar to
264<div class="sourceCode" id="cb34"><pre class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a>((method</span> 349writing language tools. The knowledge gained from mastering the query
350DSL can be applied to other languages that have tree-sitter grammars
351too. This query detects <code>to_json</code> methods that do not accept
352additional arguments, in Ruby:</p>
353<div class="sourceCode" id="cb34"><pre
354class="sourceCode scheme"><code class="sourceCode scheme"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a>((method</span>
265<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a> name: (identifier) @fn</span> 355<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a> name: (identifier) @fn</span>
266<span id="cb34-3"><a href="#cb34-3" aria-hidden="true" tabindex="-1"></a> !parameters)</span> 356<span id="cb34-3"><a href="#cb34-3" aria-hidden="true" tabindex="-1"></a> !parameters)</span>
267<span id="cb34-4"><a href="#cb34-4" aria-hidden="true" tabindex="-1"></a> (<span class="sc">#i</span>s? @fn <span class="st">&quot;to_json&quot;</span>))</span></code></pre></div> 357<span id="cb34-4"><a href="#cb34-4" aria-hidden="true" tabindex="-1"></a> (<span class="sc">#i</span>s? @fn <span class="st">&quot;to_json&quot;</span>))</span></code></pre></div>
diff --git a/docs/posts/lotus58/index.html b/docs/posts/lotus58/index.html
index 44a3c96..f4a07a2 100644
--- a/docs/posts/lotus58/index.html
+++ b/docs/posts/lotus58/index.html
@@ -33,7 +33,7 @@
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
35 <span class="stats-number"> 35 <span class="stats-number">
36 4.7 36 4.8
37 </span> 37 </span>
38 <span class="stats-unit">min</span> 38 <span class="stats-unit">min</span>
39 </div> 39 </div>
@@ -42,29 +42,46 @@
42 Lotus58 42 Lotus58
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>Earlier this month, I decided that I would laugh at Indian customs in the face by building a split-ergo mechanical keyboard from scratch rather than purchasing a Moonlander.</p> 45 <p>Earlier this month, I decided that I would laugh at Indian customs in
46the face by building a split-ergo mechanical keyboard from scratch
47rather than purchasing a Moonlander.</p>
46<figure> 48<figure>
47<img src="https://u.peppe.rs/i8k.jpg" alt="The finished product" /><figcaption aria-hidden="true">The finished product</figcaption> 49<img src="https://u.peppe.rs/i8k.jpg" alt="The finished product" />
50<figcaption aria-hidden="true">The finished product</figcaption>
48</figure> 51</figure>
49<h2 id="sourcing-the-parts">Sourcing the parts</h2> 52<h2 id="sourcing-the-parts">Sourcing the parts</h2>
50<p>If you, like me, live in India, you might find this section useful. My approach to finding parts:</p> 53<p>If you, like me, live in India, you might find this section useful.
54My approach to finding parts:</p>
51<ul> 55<ul>
52<li>Check reputed, local online stores</li> 56<li>Check reputed, local online stores</li>
53<li>Check physical hardware stores</li> 57<li>Check physical hardware stores</li>
54<li>Import the part</li> 58<li>Import the part</li>
55</ul> 59</ul>
56<h3 id="pcbs">PCBs</h3> 60<h3 id="pcbs">PCBs</h3>
57<p>This was by far the hardest component to procure. Fabrication services have certain <em>capabilities</em>. Capabilities are the limitations of a fabrication service. For example, a service may be capable of drilling holes no smaller than 0.3mm in diameter. Most sites have a verification process to check if their capabilities meet your design’s requirements. I tried a few local PCB fabrication services:</p> 61<p>This was by far the hardest component to procure. Fabrication
62services have certain <em>capabilities</em>. Capabilities are the
63limitations of a fabrication service. For example, a service may be
64capable of drilling holes no smaller than 0.3mm in diameter. Most sites
65have a verification process to check if their capabilities meet your
66design’s requirements. I tried a few local PCB fabrication services:</p>
58<ul> 67<ul>
59<li>Lion PCB: Capabilities did not meet my requirements</li> 68<li>Lion PCB: Capabilities did not meet my requirements</li>
60<li>PCBPower: Capabilities did not meet my requirements</li> 69<li>PCBPower: Capabilities did not meet my requirements</li>
61<li>Circuitwala: Capabilities did not meet my requirements</li> 70<li>Circuitwala: Capabilities did not meet my requirements</li>
62</ul> 71</ul>
63<p>I settled for JLCPCB, a Chinese service. PCBs themselves were 16 USD, shipping was another 35 USD, and customs was another 3.5K INR (ouch).</p> 72<p>I settled for JLCPCB, a Chinese service. PCBs themselves were 16 USD,
73shipping was another 35 USD, and customs was another 3.5K INR
74(ouch).</p>
64<h3 id="case-material">Case material</h3> 75<h3 id="case-material">Case material</h3>
65<p>I don’t really have a case for the Lotus58, it is more of a “plastic sandwich”. I purchased acrylic plates from Robu. Cheap, fast, solid, and customizable. I cannot recommend Robu enough. A full set of plates (2 top plates and 2 bottom plates) cost me about 500 INR. I also bought a pair of laptop height raisers on Amazon to create a budget tenting setup.</p> 76<p>I don’t really have a case for the Lotus58, it is more of a “plastic
77sandwich”. I purchased acrylic plates from Robu. Cheap, fast, solid, and
78customizable. I cannot recommend Robu enough. A full set of plates (2
79top plates and 2 bottom plates) cost me about 500 INR. I also bought a
80pair of laptop height raisers on Amazon to create a budget tenting
81setup.</p>
66<h3 id="electronics">Electronics</h3> 82<h3 id="electronics">Electronics</h3>
67<p>You’ll need a few rather specific electronic components such as hotswap sockets and TRRS mounts, the rest are commonly available:</p> 83<p>You’ll need a few rather specific electronic components such as
84hotswap sockets and TRRS mounts, the rest are commonly available:</p>
68<ul> 85<ul>
69<li>Hotswap sockets: StacksKB</li> 86<li>Hotswap sockets: StacksKB</li>
70<li>TRRS mounts (PJ 320A): StacksKB</li> 87<li>TRRS mounts (PJ 320A): StacksKB</li>
@@ -73,7 +90,8 @@
73<li>M2 spacers: ThinkRobotics</li> 90<li>M2 spacers: ThinkRobotics</li>
74<li>Arduino Pro Micro: Robu</li> 91<li>Arduino Pro Micro: Robu</li>
75</ul> 92</ul>
76<p>I skimped out on optional components such as OLEDs and rotary encoders.</p> 93<p>I skimped out on optional components such as OLEDs and rotary
94encoders.</p>
77<h3 id="switches-and-keycaps">Switches and Keycaps</h3> 95<h3 id="switches-and-keycaps">Switches and Keycaps</h3>
78<p>Arguably the most fun part of the build:</p> 96<p>Arguably the most fun part of the build:</p>
79<ul> 97<ul>
@@ -81,30 +99,57 @@
81<li>DSA blanks: Meckeys</li> 99<li>DSA blanks: Meckeys</li>
82</ul> 100</ul>
83<h2 id="building-the-keyboard">Building the keyboard</h2> 101<h2 id="building-the-keyboard">Building the keyboard</h2>
84<p>The the build is extremely straightforward. Through hole components are easy to solder. Be wary of component placement and orientation. Check thrice, solder once. Few debugging tips:</p> 102<p>The the build is extremely straightforward. Through hole components
103are easy to solder. Be wary of component placement and orientation.
104Check thrice, solder once. Few debugging tips:</p>
85<ul> 105<ul>
86<li>if a single key does not actuate, check the hotswap for poor soldering (reflow the joint), and the switch pins for deformation during installation</li> 106<li>if a single key does not actuate, check the hotswap for poor
87<li>if an entire column or row activates on a single key-press, a connection has been shorted</li> 107soldering (reflow the joint), and the switch pins for deformation during
88<li>if only some of the keys on a given row actuate, a diode has been soldered on the wrong way</li> 108installation</li>
109<li>if an entire column or row activates on a single key-press, a
110connection has been shorted</li>
111<li>if only some of the keys on a given row actuate, a diode has been
112soldered on the wrong way</li>
89</ul> 113</ul>
90<h2 id="the-typing-experience">The typing experience</h2> 114<h2 id="the-typing-experience">The typing experience</h2>
91<p>I decidede to give QWERTY the boot and learn Colemak along with the new keyboard. The first few weeks were terrible because I could neither type QWERTY nor Colemak, but I got the hang of it pretty quickly. Typing websites do help, but it is best to simply use it in your daily workflow. No site can help you get accustomed to the various things you use your keyboard for such as switching windows or navigating vim/tmux.</p> 115<p>I decidede to give QWERTY the boot and learn Colemak along with the
116new keyboard. The first few weeks were terrible because I could neither
117type QWERTY nor Colemak, but I got the hang of it pretty quickly. Typing
118websites do help, but it is best to simply use it in your daily
119workflow. No site can help you get accustomed to the various things you
120use your keyboard for such as switching windows or navigating
121vim/tmux.</p>
92<h3 id="colemak">Colemak</h3> 122<h3 id="colemak">Colemak</h3>
93<p>Alt layouts such as Colemak are definitely worth it. I find that Colemak reduces finger movement a lot, a good portion of the keys on the left hand are the same as QWERTY, it is fairly easy to pick up as well.</p> 123<p>Alt layouts such as Colemak are definitely worth it. I find that
124Colemak reduces finger movement a lot, a good portion of the keys on the
125left hand are the same as QWERTY, it is fairly easy to pick up as
126well.</p>
94<h3 id="vim">Vim</h3> 127<h3 id="vim">Vim</h3>
95<p>Using an alt layout means most programs with keyboard shortcuts are not going to work as expected, <code>HJKL</code> on vim for movements being one of them. I took the short route out by creating a new layer with arrow keys on the home row:</p> 128<p>Using an alt layout means most programs with keyboard shortcuts are
129not going to work as expected, <code>HJKL</code> on vim for movements
130being one of them. I took the short route out by creating a new layer
131with arrow keys on the home row:</p>
96<pre><code>default homerow: 132<pre><code>default homerow:
97H N E I 133H N E I
98 134
99&quot;nav&quot; layer: 135&quot;nav&quot; layer:
100&lt; v ^ &gt;</code></pre> 136&lt; v ^ &gt;</code></pre>
101<p>The remaining commands in vim are largely mnemonics. Navigating with home-row arrow keys also means that I can use “HJKL” globally, to scroll a website, for example.</p> 137<p>The remaining commands in vim are largely mnemonics. Navigating with
138home-row arrow keys also means that I can use “HJKL” globally, to scroll
139a website, for example.</p>
102<h3 id="cutting-down-to-34-keys">Cutting down to 34 keys</h3> 140<h3 id="cutting-down-to-34-keys">Cutting down to 34 keys</h3>
103<p>A couple months into my ergo journey, I realized that I could get away by moving my fingers even lesser. I moved modifiers such as <code>Super</code>, <code>Ctrl</code>, <code>Alt</code> and <code>Shift</code> to the home-row as QMK Mod Taps. The rest of the keys are cleverly placed in layers, not too much unlike the Miryoku layout. Even for someone that writes Rust (a symbol-heavy grammar), I find 34-keys to be sufficient.</p> 141<p>A couple months into my ergo journey, I realized that I could get
142away by moving my fingers even lesser. I moved modifiers such as
143<code>Super</code>, <code>Ctrl</code>, <code>Alt</code> and
144<code>Shift</code> to the home-row as QMK Mod Taps. The rest of the keys
145are cleverly placed in layers, not too much unlike the Miryoku layout.
146Even for someone that writes Rust (a symbol-heavy grammar), I find
14734-keys to be sufficient.</p>
104<h2 id="conclusion">Conclusion</h2> 148<h2 id="conclusion">Conclusion</h2>
105<p>I have been bitten by the ergomech bug.</p> 149<p>I have been bitten by the ergomech bug.</p>
106<figure> 150<figure>
107<img src="https://u.peppe.rs/XM3.jpg" alt="The Lotus58 in action" /><figcaption aria-hidden="true">The Lotus58 in action</figcaption> 151<img src="https://u.peppe.rs/XM3.jpg" alt="The Lotus58 in action" />
152<figcaption aria-hidden="true">The Lotus58 in action</figcaption>
108</figure> 153</figure>
109 154
110 </div> 155 </div>
diff --git a/docs/posts/my_setup/index.html b/docs/posts/my_setup/index.html
index 34d07af..e35a33c 100644
--- a/docs/posts/my_setup/index.html
+++ b/docs/posts/my_setup/index.html
@@ -44,10 +44,27 @@
44 <div class="post-text"> 44 <div class="post-text">
45 <p>Decided to do one of these because everyone does one of these.</p> 45 <p>Decided to do one of these because everyone does one of these.</p>
46<p><img src="https://u.peppe.rs/Hb.png" /></p> 46<p><img src="https://u.peppe.rs/Hb.png" /></p>
47<p>My entire setup is managed with GNU <code>stow</code>, making it easier to replicate on fresh installations. You can find my configuration files on <a href="https://github.com/nerdypepper">GitHub</a>.</p> 47<p>My entire setup is managed with GNU <code>stow</code>, making it
48<p>I run Void Linux (glibc) on my <a href="https://store.hp.com/us/en/mdp/laptops/envy-13">HP Envy 13" (2018)</a>. To keep things simple, I run a raw X session with <code>2bwm</code> as my window manager, along with <code>dunst</code> (notification daemon) and Sam’s <a href="https://github.com/sdhand/compton"><code>compton</code></a> (compositor) fork.</p> 48easier to replicate on fresh installations. You can find my
49<p>I am a fan of GNU tools, so I use <code>bash</code> as my shell, and <code>coreutils</code> to manage files, archives, strings, paths etc. I edit files with <code>vim</code>, chat with <code>weechat</code>, listen to music with <code>cmus</code>, monitor processes with <code>htop</code>, manage sessions with <code>tmux</code>, read pdfs in <code>zathura</code>. I rarely ever leave the comfort of my terminal emulator, <code>urxvt</code>.</p> 49configuration files on <a
50<p>Most of my academic typesetting is done with TeX, and compiled with <code>xelatex</code>. Other <em>fun</em> documents are made with GIMP :).</p> 50href="https://github.com/nerdypepper">GitHub</a>.</p>
51<p>I run Void Linux (glibc) on my <a
52href="https://store.hp.com/us/en/mdp/laptops/envy-13">HP Envy 13”
53(2018)</a>. To keep things simple, I run a raw X session with
54<code>2bwm</code> as my window manager, along with <code>dunst</code>
55(notification daemon) and Sam’s <a
56href="https://github.com/sdhand/compton"><code>compton</code></a>
57(compositor) fork.</p>
58<p>I am a fan of GNU tools, so I use <code>bash</code> as my shell, and
59<code>coreutils</code> to manage files, archives, strings, paths etc. I
60edit files with <code>vim</code>, chat with <code>weechat</code>, listen
61to music with <code>cmus</code>, monitor processes with
62<code>htop</code>, manage sessions with <code>tmux</code>, read pdfs in
63<code>zathura</code>. I rarely ever leave the comfort of my terminal
64emulator, <code>urxvt</code>.</p>
65<p>Most of my academic typesetting is done with TeX, and compiled with
66<code>xelatex</code>. Other <em>fun</em> documents are made with GIMP
67:).</p>
51 68
52 </div> 69 </div>
53 70
diff --git a/docs/posts/nixOS/index.html b/docs/posts/nixOS/index.html
index 75be58f..9650bdd 100644
--- a/docs/posts/nixOS/index.html
+++ b/docs/posts/nixOS/index.html
@@ -33,7 +33,7 @@
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
35 <span class="stats-number"> 35 <span class="stats-number">
36 3.3 36 3.4
37 </span> 37 </span>
38 <span class="stats-unit">min</span> 38 <span class="stats-unit">min</span>
39 </div> 39 </div>
@@ -42,11 +42,24 @@
42 NixOS 42 NixOS
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>I have been eyeing operating systems with functional package managers for a while now, aka, NixOS or Guix. Reproducible builds, declarative and rollback-able system configuration, system consistency, all sound pretty cool. I have been using NixOS for about a month now.</p> 45 <p>I have been eyeing operating systems with functional package managers
46for a while now, aka, NixOS or Guix. Reproducible builds, declarative
47and rollback-able system configuration, system consistency, all sound
48pretty cool. I have been using NixOS for about a month now.</p>
46<h3 id="installation">Installation</h3> 49<h3 id="installation">Installation</h3>
47<p>I went with their minimal installation ISO. The installation was pretty smooth from start to end, no hitches there. The entire <a href="https://nixos.org/manual/nixos/stable/">manual</a> is available offline, and is accessible during the installation. Very handy.</p> 50<p>I went with their minimal installation ISO. The installation was
51pretty smooth from start to end, no hitches there. The entire <a
52href="https://nixos.org/manual/nixos/stable/">manual</a> is available
53offline, and is accessible during the installation. Very handy.</p>
48<h3 id="setup">Setup</h3> 54<h3 id="setup">Setup</h3>
49<p>The entire system is configured via <code>/etc/nixos/configuration.nix</code>. Wifi, <code>libinput</code> gestures, audio, locale settings, there are options for literally everything. You can declaratively write down the packages you want installed too. With fresh installs of most distros, I usually fumble with getting things like screen backlight and media keys to work. If I do manage to fix it, I can’t carry it forward to future installations trivially. Getting all my hardware to work on NixOS is as easy as:</p> 55<p>The entire system is configured via
56<code>/etc/nixos/configuration.nix</code>. Wifi, <code>libinput</code>
57gestures, audio, locale settings, there are options for literally
58everything. You can declaratively write down the packages you want
59installed too. With fresh installs of most distros, I usually fumble
60with getting things like screen backlight and media keys to work. If I
61do manage to fix it, I can’t carry it forward to future installations
62trivially. Getting all my hardware to work on NixOS is as easy as:</p>
50<pre><code>{ 63<pre><code>{
51 server.xserver.libinput.enable = true; # touchpad 64 server.xserver.libinput.enable = true; # touchpad
52 programs.light.enable = true; # backlight 65 programs.light.enable = true; # backlight
@@ -54,20 +67,53 @@
54 networking.wireless.enable = true; # wifi 67 networking.wireless.enable = true; # wifi
55}</code></pre> 68}</code></pre>
56<h3 id="developing-with-nix">Developing with Nix</h3> 69<h3 id="developing-with-nix">Developing with Nix</h3>
57<p>Nix makes it easy to enter environments that aren’t affected by your system configuration using <code>nix-shell</code>.</p> 70<p>Nix makes it easy to enter environments that aren’t affected by your
58<p>Builds may be generated by specifying a <code>default.nix</code> file, and running <code>nix-build</code>. Conventional package managers require you to specify a dependency list, but there is no guarantee that this list is complete. The package will build on your machine even if you forget a dependency. However, with Nix, packages are installed to <code>/nix/store</code>, and not global paths such as <code>/usr/bin/...</code>, if your project builds, it means you have included every last one.</p> 71system configuration using <code>nix-shell</code>.</p>
59<p>Issues on most my projects have been “unable to build because <code>libxcb</code> is missing”, or “this version of <code>openssl</code> is too old”. Tools like <code>cargo</code> and <code>pip</code> are poor package managers. While they <em>can</em> guarantee that Rust or Python dependencies are met, they make assumptions about the target system.</p> 72<p>Builds may be generated by specifying a <code>default.nix</code>
60<p>For example, <a href="https://github.com/nerdypepper/site">this website</a> is now built using Nix, anyone using Nix may simply, clone the repository and run <code>./generate.sh</code>, and it would <em>just work</em>, while keeping your global namespace clean™:</p> 73file, and running <code>nix-build</code>. Conventional package managers
61<div class="sourceCode" id="cb2"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co">#! /usr/bin/env nix-shell</span></span> 74require you to specify a dependency list, but there is no guarantee that
75this list is complete. The package will build on your machine even if
76you forget a dependency. However, with Nix, packages are installed to
77<code>/nix/store</code>, and not global paths such as
78<code>/usr/bin/...</code>, if your project builds, it means you have
79included every last one.</p>
80<p>Issues on most my projects have been “unable to build because
81<code>libxcb</code> is missing”, or “this version of
82<code>openssl</code> is too old”. Tools like <code>cargo</code> and
83<code>pip</code> are poor package managers. While they <em>can</em>
84guarantee that Rust or Python dependencies are met, they make
85assumptions about the target system.</p>
86<p>For example, <a href="https://github.com/nerdypepper/site">this
87website</a> is now built using Nix, anyone using Nix may simply, clone
88the repository and run <code>./generate.sh</code>, and it would <em>just
89work</em>, while keeping your global namespace clean™:</p>
90<div class="sourceCode" id="cb2"><pre
91class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co">#! /usr/bin/env nix-shell</span></span>
62<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="co">#! nix-shell -i bash -p eva pandoc esh</span></span> 92<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="co">#! nix-shell -i bash -p eva pandoc esh</span></span>
63<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span> 93<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
64<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="co"># some bash magic ;)</span></span></code></pre></div> 94<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="co"># some bash magic ;)</span></span></code></pre></div>
65<p>Dependencies are included with the <code>-p</code> flag, the shell script is executed with an interpreter, specified with the <code>-i</code> flag.</p> 95<p>Dependencies are included with the <code>-p</code> flag, the shell
96script is executed with an interpreter, specified with the
97<code>-i</code> flag.</p>
66<h3 id="impressions">Impressions</h3> 98<h3 id="impressions">Impressions</h3>
67<p>NixOS is by no means, simple. As a newcomer, using Nix was not easy, heck, I had to learn a purely functional, lazy language to just build programs. There is a lot to be desired on the tooling front as well. A well fleshed out LSP plugin would be nice (<a href="https://github.com/nix-community/rnix-lsp">rnix-lsp looks promising</a>).</p> 99<p>NixOS is by no means, simple. As a newcomer, using Nix was not easy,
68<p>Being able to rollback changes at a system level is cool. Package broke something? Just <code>nixos-rebuild switch --rollback</code>! Deleted <code>nix</code> by mistake? Find the binary in <code>/nix/store</code> and rollback! You aren’t punished for not thinking twice.</p> 100heck, I had to learn a purely functional, lazy language to just build
69<p>I don’t see myself switching to anything else in the near future, NixOS does a lot of things right. If I ever need to reinstall NixOS, I can generate an <a href="https://github.com/nix-community/nixos-generators">image of my current system</a>.</p> 101programs. There is a lot to be desired on the tooling front as well. A
70<p><a href="https://u.peppe.rs/6m.png"><img src="https://u.peppe.rs/6m.png" /></a></p> 102well fleshed out LSP plugin would be nice (<a
103href="https://github.com/nix-community/rnix-lsp">rnix-lsp looks
104promising</a>).</p>
105<p>Being able to rollback changes at a system level is cool. Package
106broke something? Just <code>nixos-rebuild switch --rollback</code>!
107Deleted <code>nix</code> by mistake? Find the binary in
108<code>/nix/store</code> and rollback! You aren’t punished for not
109thinking twice.</p>
110<p>I don’t see myself switching to anything else in the near future,
111NixOS does a lot of things right. If I ever need to reinstall NixOS, I
112can generate an <a
113href="https://github.com/nix-community/nixos-generators">image of my
114current system</a>.</p>
115<p><a href="https://u.peppe.rs/6m.png"><img
116src="https://u.peppe.rs/6m.png" /></a></p>
71 117
72 </div> 118 </div>
73 119
diff --git a/docs/posts/novice_nix:_flake_templates/index.html b/docs/posts/novice_nix:_flake_templates/index.html
index 480f85d..302bafe 100644
--- a/docs/posts/novice_nix:_flake_templates/index.html
+++ b/docs/posts/novice_nix:_flake_templates/index.html
@@ -42,13 +42,25 @@
42 Novice Nix: Flake Templates 42 Novice Nix: Flake Templates
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>Flakes are very handy to setup entirely pure, project-specific dependencies (not just dependencies, but build steps, shell environments and more) in a declarative way. Writing Flake expressions can get repetitive though, oftentimes, you’d much rather start off with a skeleton. Luckily, <code>nix</code> already supports templates!</p> 45 <p>Flakes are very handy to setup entirely pure, project-specific
46<p>You might already be familiar with <code>nix flake init</code>, that drops a “default” flake expression into your current working directory. If you head over to the manpage:</p> 46dependencies (not just dependencies, but build steps, shell environments
47<div class="sourceCode" id="cb1"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">nix</span> flake init <span class="at">--help</span></span></code></pre></div> 47and more) in a declarative way. Writing Flake expressions can get
48<p>You will read that <code>nix flake init</code> creates a flake using the “default template”. Additionally, you can create a flake from a specific template by passing the <code>-t</code> flag. Where does this default originate from?</p> 48repetitive though, oftentimes, you’d much rather start off with a
49skeleton. Luckily, <code>nix</code> already supports templates!</p>
50<p>You might already be familiar with <code>nix flake init</code>, that
51drops a “default” flake expression into your current working directory.
52If you head over to the manpage:</p>
53<div class="sourceCode" id="cb1"><pre
54class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">nix</span> flake init <span class="at">--help</span></span></code></pre></div>
55<p>You will read that <code>nix flake init</code> creates a flake using
56the “default template”. Additionally, you can create a flake from a
57specific template by passing the <code>-t</code> flag. Where does this
58default originate from?</p>
49<h2 id="flake-registries">Flake Registries</h2> 59<h2 id="flake-registries">Flake Registries</h2>
50<p>Quick detour into registries! Registries are a way to alias popular flakes using identifiers:</p> 60<p>Quick detour into registries! Registries are a way to alias popular
51<div class="sourceCode" id="cb2"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co"># list a few predefined registries</span></span> 61flakes using identifiers:</p>
62<div class="sourceCode" id="cb2"><pre
63class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co"># list a few predefined registries</span></span>
52<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix registry list</span> 64<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix registry list</span>
53<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="bu">.</span> . . </span> 65<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="bu">.</span> . . </span>
54<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="ex">global</span> flake:nixpkgs github:NixOS/nixpkgs</span> 66<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="ex">global</span> flake:nixpkgs github:NixOS/nixpkgs</span>
@@ -66,8 +78,11 @@
66<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a></span> 78<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a></span>
67<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a><span class="co"># which is short for</span></span> 79<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a><span class="co"># which is short for</span></span>
68<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake show git+https://github.com/tweag/nickel</span></code></pre></div> 80<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake show git+https://github.com/tweag/nickel</span></code></pre></div>
69<p>You might notice a registry called <code>templates</code> aliased to <code>github:NixOS/templates</code>. Take a peek with <code>nix flake show</code>:</p> 81<p>You might notice a registry called <code>templates</code> aliased to
70<div class="sourceCode" id="cb3"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake show templates</span> 82<code>github:NixOS/templates</code>. Take a peek with
83<code>nix flake show</code>:</p>
84<div class="sourceCode" id="cb3"><pre
85class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake show templates</span>
71<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="ex">github:NixOS/templates/79f48a7b822f35c068c5e235da2e9fbd154cecee</span></span> 86<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="ex">github:NixOS/templates/79f48a7b822f35c068c5e235da2e9fbd154cecee</span></span>
72<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="ex">├───defaultTemplate:</span> template: A very basic flake</span> 87<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="ex">├───defaultTemplate:</span> template: A very basic flake</span>
73<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="ex">└───templates</span></span> 88<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="ex">└───templates</span></span>
@@ -76,8 +91,12 @@
76<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> <span class="ex">├───rust-web-server:</span> template: A Rust web server including a NixOS module</span> 91<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> <span class="ex">├───rust-web-server:</span> template: A Rust web server including a NixOS module</span>
77<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a> <span class="ex">├───simpleContainer:</span> template: A NixOS container running apache-httpd</span> 92<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a> <span class="ex">├───simpleContainer:</span> template: A NixOS container running apache-httpd</span>
78<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a> <span class="ex">└───trivial:</span> template: A very basic flake</span></code></pre></div> 93<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a> <span class="ex">└───trivial:</span> template: A very basic flake</span></code></pre></div>
79<p>Aha! There is a flake output called <code>defaultTemplate</code>. This is the template being sourced when you run <code>nix flake init</code>. Astute readers may conclude the following:</p> 94<p>Aha! There is a flake output called <code>defaultTemplate</code>.
80<div class="sourceCode" id="cb4"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake init</span> 95This is the template being sourced when you run
96<code>nix flake init</code>. Astute readers may conclude the
97following:</p>
98<div class="sourceCode" id="cb4"><pre
99class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake init</span>
81<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span> 100<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
82<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="co"># is equivalent to</span></span> 101<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="co"># is equivalent to</span></span>
83<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake init <span class="at">-t</span> templates#defaultTemplate</span> 102<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake init <span class="at">-t</span> templates#defaultTemplate</span>
@@ -88,7 +107,8 @@
88<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="co"># which is short for</span></span> 107<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="co"># which is short for</span></span>
89<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake init <span class="at">-t</span> git+https://github.com/NixOS/templates#defaultTemplate</span></code></pre></div> 108<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake init <span class="at">-t</span> git+https://github.com/NixOS/templates#defaultTemplate</span></code></pre></div>
90<p>Similarly, the other templates can be accessed via:</p> 109<p>Similarly, the other templates can be accessed via:</p>
91<div class="sourceCode" id="cb5"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake init <span class="at">-t</span> templates#c-hello</span> 110<div class="sourceCode" id="cb5"><pre
111class="sourceCode bash"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake init <span class="at">-t</span> templates#c-hello</span>
92<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake init <span class="at">-t</span> templates#simpleContainer</span> 112<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake init <span class="at">-t</span> templates#simpleContainer</span>
93<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="co"># I think you get the drift ...</span></span></code></pre></div> 113<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="co"># I think you get the drift ...</span></span></code></pre></div>
94<h2 id="rolling-your-own-templates">Rolling your own templates</h2> 114<h2 id="rolling-your-own-templates">Rolling your own templates</h2>
@@ -96,38 +116,52 @@
96<ul> 116<ul>
97<li>create a flake with a <code>templates</code> output</li> 117<li>create a flake with a <code>templates</code> output</li>
98<li>populate our template directories with content</li> 118<li>populate our template directories with content</li>
99<li>(<strong>optionally</strong>) alias our custom templates flake to an identifier using registries, for easier access</li> 119<li>(<strong>optionally</strong>) alias our custom templates flake to an
120identifier using registries, for easier access</li>
100</ul> 121</ul>
101<p>Start off by creating a directory to store your templates in (we will be converting this to a registry later):</p> 122<p>Start off by creating a directory to store your templates in (we will
102<div class="sourceCode" id="cb6"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> mkdir ~/mytemplates</span></code></pre></div> 123be converting this to a registry later):</p>
103<p>A flake that exposes a “template” as its output looks something like this:</p> 124<div class="sourceCode" id="cb6"><pre
104<div class="sourceCode" id="cb7"><pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="co"># inside ~/mytemplates/flake.nix</span></span> 125class="sourceCode bash"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> mkdir ~/mytemplates</span></code></pre></div>
126<p>A flake that exposes a “template” as its output looks something like
127this:</p>
128<div class="sourceCode" id="cb7"><pre
129class="sourceCode nix"><code class="sourceCode nix"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="co"># inside ~/mytemplates/flake.nix</span></span>
105<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a></span> 130<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a></span>
106<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="kw">{</span></span> 131<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
107<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a> <span class="ex">description</span> = <span class="st">&quot;Pepper&#39;s flake templates&quot;</span><span class="kw">;</span></span> 132<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a> <span class="va">description</span> <span class="op">=</span> <span class="st">&quot;Pepper&#39;s flake templates&quot;</span><span class="op">;</span></span>
108<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a></span> 133<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a></span>
109<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> <span class="ex">outputs</span> = { self, ... }: {</span> 134<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> <span class="va">outputs</span> <span class="op">=</span> <span class="op">{</span> <span class="va">self</span><span class="op">,</span> <span class="op">...</span> <span class="op">}</span>: <span class="op">{</span></span>
110<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a> <span class="ex">templates</span> = {</span> 135<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a> <span class="va">templates</span> <span class="op">=</span> <span class="op">{</span></span>
111<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a> <span class="ex">latex-report</span> = {</span> 136<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a> <span class="va">latex-report</span> <span class="op">=</span> <span class="op">{</span></span>
112<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a> <span class="ex">path</span> = ./latex-report-template<span class="kw">;</span></span> 137<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a> <span class="va">path</span> <span class="op">=</span> <span class="ss">./latex-report-template</span><span class="op">;</span></span>
113<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a> <span class="ex">description</span> = <span class="st">&quot;A latex whitepaper project&quot;</span><span class="kw">;</span></span> 138<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a> <span class="va">description</span> <span class="op">=</span> <span class="st">&quot;A latex whitepaper project&quot;</span><span class="op">;</span></span>
114<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a> <span class="kw">};</span></span> 139<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
115<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a> <span class="ex">rust-hello</span> = {</span> 140<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a> <span class="va">rust-hello</span> <span class="op">=</span> <span class="op">{</span></span>
116<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a> <span class="ex">path</span> = ./rust-hello-template<span class="kw">;</span></span> 141<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a> <span class="va">path</span> <span class="op">=</span> <span class="ss">./rust-hello-template</span><span class="op">;</span></span>
117<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a> <span class="ex">description</span> = <span class="st">&quot;Simple Hello World in Rust&quot;</span><span class="kw">;</span></span> 142<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a> <span class="va">description</span> <span class="op">=</span> <span class="st">&quot;Simple Hello World in Rust&quot;</span><span class="op">;</span></span>
118<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a> <span class="er">}</span><span class="kw">;</span></span> 143<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
119<span id="cb7-16"><a href="#cb7-16" aria-hidden="true" tabindex="-1"></a> <span class="er">}</span><span class="kw">;</span></span> 144<span id="cb7-16"><a href="#cb7-16" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
120<span id="cb7-17"><a href="#cb7-17" aria-hidden="true" tabindex="-1"></a> <span class="er">}</span><span class="kw">;</span></span> 145<span id="cb7-17"><a href="#cb7-17" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
121<span id="cb7-18"><a href="#cb7-18" aria-hidden="true" tabindex="-1"></a><span class="er">}</span></span></code></pre></div> 146<span id="cb7-18"><a href="#cb7-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
122<p>The <code>path</code> attribute to each template is what gets copied over when you initialize a flake. Running <code>nix flake init -t .#latex-report</code> will initialize the current directory with the contents of <code>./latex-report-template</code> (we are yet to populate these directories).</p> 147<p>The <code>path</code> attribute to each template is what gets copied
123<p>The output of <code>nix flake show</code> should be something like:</p> 148over when you initialize a flake. Running
124<div class="sourceCode" id="cb8"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake show</span> 149<code>nix flake init -t .#latex-report</code> will initialize the
150current directory with the contents of
151<code>./latex-report-template</code> (we are yet to populate these
152directories).</p>
153<p>The output of <code>nix flake show</code> should be something
154like:</p>
155<div class="sourceCode" id="cb8"><pre
156class="sourceCode bash"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake show</span>
125<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="ex">path:/home/np/code/nix-stuff/template-tests?narHash=sha256-{...}</span></span> 157<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="ex">path:/home/np/code/nix-stuff/template-tests?narHash=sha256-{...}</span></span>
126<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="ex">└───templates</span></span> 158<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="ex">└───templates</span></span>
127<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> <span class="ex">├───latex-report:</span> template: A latex whitepaper project</span> 159<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> <span class="ex">├───latex-report:</span> template: A latex whitepaper project</span>
128<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a> <span class="ex">└───rust-hello:</span> template: Simple Hello World in Rust</span></code></pre></div> 160<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a> <span class="ex">└───rust-hello:</span> template: Simple Hello World in Rust</span></code></pre></div>
129<p>Populate your template directories with content, here are my template directories for example:</p> 161<p>Populate your template directories with content, here are my template
130<div class="sourceCode" id="cb9"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> tree mytemplates</span> 162directories for example:</p>
163<div class="sourceCode" id="cb9"><pre
164class="sourceCode bash"><code class="sourceCode bash"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> tree mytemplates</span>
131<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="ex">mytemplates/</span></span> 165<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="ex">mytemplates/</span></span>
132<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="ex">├──</span> flake.nix</span> 166<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="ex">├──</span> flake.nix</span>
133<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="ex">├──</span> latex-report-template</span> 167<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="ex">├──</span> latex-report-template</span>
@@ -142,15 +176,18 @@
142<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a> <span class="ex">└──</span> src</span> 176<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a> <span class="ex">└──</span> src</span>
143<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a> <span class="ex">└──</span> main.rs</span></code></pre></div> 177<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a> <span class="ex">└──</span> main.rs</span></code></pre></div>
144<p>And that’s it! Start using your templates with:</p> 178<p>And that’s it! Start using your templates with:</p>
145<div class="sourceCode" id="cb10"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake init <span class="at">-t</span> ~/mytemplates#rust-hello</span> 179<div class="sourceCode" id="cb10"><pre
180class="sourceCode bash"><code class="sourceCode bash"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake init <span class="at">-t</span> ~/mytemplates#rust-hello</span>
146<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> tree .</span> 181<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> tree .</span>
147<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="bu">.</span></span> 182<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="bu">.</span></span>
148<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="ex">├──</span> Cargo.toml</span> 183<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="ex">├──</span> Cargo.toml</span>
149<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="ex">├──</span> flake.nix</span> 184<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="ex">├──</span> flake.nix</span>
150<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="ex">└──</span> src</span> 185<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="ex">└──</span> src</span>
151<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a> <span class="ex">└──</span> main.rs</span></code></pre></div> 186<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a> <span class="ex">└──</span> main.rs</span></code></pre></div>
152<p>To avoid writing <code>~/mytemplates</code> each time, simply alias it to a registry:</p> 187<p>To avoid writing <code>~/mytemplates</code> each time, simply alias
153<div class="sourceCode" id="cb11"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="co"># alias it to `biscuits`</span></span> 188it to a registry:</p>
189<div class="sourceCode" id="cb11"><pre
190class="sourceCode bash"><code class="sourceCode bash"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="co"># alias it to `biscuits`</span></span>
154<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix registry add biscuits ~/mytemplates</span> 191<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix registry add biscuits ~/mytemplates</span>
155<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a></span> 192<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a></span>
156<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a><span class="co"># you will see it listed under `user` registries</span></span> 193<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a><span class="co"># you will see it listed under `user` registries</span></span>
@@ -160,34 +197,42 @@
160<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a><span class="bu">.</span> . .</span> 197<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a><span class="bu">.</span> . .</span>
161<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a></span> 198<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a></span>
162<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake init <span class="at">-t</span> biscuits#latex-report</span></code></pre></div> 199<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> nix flake init <span class="at">-t</span> biscuits#latex-report</span></code></pre></div>
163<h2 id="extending-the-official-templates">Extending the official templates</h2> 200<h2 id="extending-the-official-templates">Extending the official
164<p>I personally, would like the <code>biscuits</code> registry to include not just my homemade templates, but also the templates from <code>NixOS/templates</code> (and maybe a couple of other repositories in the wild):</p> 201templates</h2>
165<div class="sourceCode" id="cb12"><pre class="sourceCode nix"><code class="sourceCode bash"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a> <span class="kw">{</span></span> 202<p>I personally, would like the <code>biscuits</code> registry to
166<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a> <span class="ex">description</span> = <span class="st">&quot;Pepper&#39;s flake templates&quot;</span><span class="kw">;</span></span> 203include not just my homemade templates, but also the templates from
204<code>NixOS/templates</code> (and maybe a couple of other repositories
205in the wild):</p>
206<div class="sourceCode" id="cb12"><pre
207class="sourceCode nix"><code class="sourceCode nix"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a> <span class="op">{</span></span>
208<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a> <span class="va">description</span> <span class="op">=</span> <span class="st">&quot;Pepper&#39;s flake templates&quot;</span><span class="op">;</span></span>
167<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a> </span> 209<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a> </span>
168<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="ex">+</span> inputs = {</span> 210<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>+ <span class="va">inputs</span> <span class="op">=</span> <span class="op">{</span></span>
169<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a><span class="ex">+</span> official-templates.url = github:NixOS/templates<span class="kw">;</span></span> 211<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>+ <span class="va">official-templates</span>.<span class="va">url</span> <span class="op">=</span> <span class="va">github</span><span class="op">:</span><span class="ss">NixOS/templates</span><span class="op">;</span></span>
170<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a><span class="ex">+</span> other-templates.url = github:some-other/templates<span class="kw">;</span></span> 212<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>+ <span class="va">other-templates</span>.<span class="va">url</span> <span class="op">=</span> <span class="va">github</span><span class="op">:</span><span class="ss">some-other/templates</span><span class="op">;</span></span>
171<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a><span class="ex">+</span> }<span class="kw">;</span></span> 213<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>+ <span class="op">};</span></span>
172<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a> </span> 214<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a> </span>
173<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a> <span class="ex">outputs</span> = { self, official-templates, other-templates ... }: {</span> 215<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a> <span class="va">outputs</span> <span class="op">=</span> <span class="op">{</span> <span class="va">self</span><span class="op">,</span> <span class="va">official-templates</span><span class="op">,</span> <span class="va">other-templates</span> <span class="op">...</span> <span class="op">}</span>: <span class="op">{</span></span>
174<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a> </span> 216<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a> </span>
175<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a> <span class="ex">templates</span> = {</span> 217<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a> <span class="va">templates</span> <span class="op">=</span> <span class="op">{</span></span>
176<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a> <span class="ex">latex-report</span> = {</span> 218<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a> <span class="va">latex-report</span> <span class="op">=</span> <span class="op">{</span></span>
177<span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a> <span class="ex">path</span> = ./latex-report-template<span class="kw">;</span></span> 219<span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a> <span class="va">path</span> <span class="op">=</span> <span class="ss">./latex-report-template</span><span class="op">;</span></span>
178<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a> <span class="ex">description</span> = <span class="st">&quot;A latex whitepaper project&quot;</span><span class="kw">;</span></span> 220<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a> <span class="va">description</span> <span class="op">=</span> <span class="st">&quot;A latex whitepaper project&quot;</span><span class="op">;</span></span>
179<span id="cb12-15"><a href="#cb12-15" aria-hidden="true" tabindex="-1"></a> <span class="kw">};</span></span> 221<span id="cb12-15"><a href="#cb12-15" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
180<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a> <span class="ex">rust-hello</span> = {</span> 222<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a> <span class="va">rust-hello</span> <span class="op">=</span> <span class="op">{</span></span>
181<span id="cb12-17"><a href="#cb12-17" aria-hidden="true" tabindex="-1"></a> <span class="ex">path</span> = ./rust-hello-template<span class="kw">;</span></span> 223<span id="cb12-17"><a href="#cb12-17" aria-hidden="true" tabindex="-1"></a> <span class="va">path</span> <span class="op">=</span> <span class="ss">./rust-hello-template</span><span class="op">;</span></span>
182<span id="cb12-18"><a href="#cb12-18" aria-hidden="true" tabindex="-1"></a> <span class="ex">description</span> = <span class="st">&quot;Simple Hello World in Rust, with overloaded Rust toolchain&quot;</span><span class="kw">;</span></span> 224<span id="cb12-18"><a href="#cb12-18" aria-hidden="true" tabindex="-1"></a> <span class="va">description</span> <span class="op">=</span> <span class="st">&quot;Simple Hello World in Rust, with overloaded Rust toolchain&quot;</span><span class="op">;</span></span>
183<span id="cb12-19"><a href="#cb12-19" aria-hidden="true" tabindex="-1"></a> <span class="er">}</span><span class="kw">;</span></span> 225<span id="cb12-19"><a href="#cb12-19" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
184<span id="cb12-20"><a href="#cb12-20" aria-hidden="true" tabindex="-1"></a> <span class="er">}</span></span> 226<span id="cb12-20"><a href="#cb12-20" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
185<span id="cb12-21"><a href="#cb12-21" aria-hidden="true" tabindex="-1"></a><span class="ex">+</span> // official-templates.templates</span> 227<span id="cb12-21"><a href="#cb12-21" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="op">//</span> official<span class="op">-</span>templates.templates</span>
186<span id="cb12-22"><a href="#cb12-22" aria-hidden="true" tabindex="-1"></a><span class="ex">+</span> // other-templates.templates<span class="kw">;</span></span> 228<span id="cb12-22"><a href="#cb12-22" aria-hidden="true" tabindex="-1"></a><span class="op">+</span> <span class="op">//</span> other<span class="op">-</span>templates.templates<span class="op">;</span></span>
187<span id="cb12-23"><a href="#cb12-23" aria-hidden="true" tabindex="-1"></a> </span> 229<span id="cb12-23"><a href="#cb12-23" aria-hidden="true" tabindex="-1"></a> </span>
188<span id="cb12-24"><a href="#cb12-24" aria-hidden="true" tabindex="-1"></a> <span class="er">}</span><span class="kw">;</span></span> 230<span id="cb12-24"><a href="#cb12-24" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
189<span id="cb12-25"><a href="#cb12-25" aria-hidden="true" tabindex="-1"></a> <span class="er">}</span></span></code></pre></div> 231<span id="cb12-25"><a href="#cb12-25" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div>
190<p>Running <code>nix flake show biscuits</code> will now list templates from the <code>biscuits</code> registry as well as the ones from <code>NixOS/templates</code>. Ensure that the names don’t collide though.</p> 232<p>Running <code>nix flake show biscuits</code> will now list templates
233from the <code>biscuits</code> registry as well as the ones from
234<code>NixOS/templates</code>. Ensure that the names don’t collide
235though.</p>
191 236
192 </div> 237 </div>
193 238
diff --git a/docs/posts/onivim_sucks/index.html b/docs/posts/onivim_sucks/index.html
index 0f10018..23bbedc 100644
--- a/docs/posts/onivim_sucks/index.html
+++ b/docs/posts/onivim_sucks/index.html
@@ -28,7 +28,7 @@
28 02/08 — 2019 28 02/08 — 2019
29 <div class="stats"> 29 <div class="stats">
30 <span class="stats-number"> 30 <span class="stats-number">
31 11.18 31 11.19
32 </span> 32 </span>
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
@@ -42,11 +42,38 @@
42 Onivim Sucks 42 Onivim Sucks
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p><a href="https://v2.onivim.io">Onivim</a> is a ‘modern modal editor’, combining fancy interface and language features with vim-style modal editing. What’s wrong you ask?</p> 45 <p><a href="https://v2.onivim.io">Onivim</a> is a ‘modern modal editor’,
46<p>Apart from <a href="https://github.com/onivim/oni2/issues/550">buggy syntax highlighting</a>, <a href="https://github.com/onivim/oni2/issues/519">broken scrolling</a> and <a href="https://github.com/onivim/oni2/issues?q=is%3Aissue+label%3A%22daily+editor+blocker%22+is%3Aopen">others</a>, Onivim is <strong>proprietary</strong> software. It is licensed under a commercial <a href="https://github.com/onivim/oni1/blob/master/Outrun-Labs-EULA-v1.1.md">end user agreement license</a>, which prohibits redistribution in both object code and source code formats.</p> 46combining fancy interface and language features with vim-style modal
47<p>Onivim’s core editor logic (bits that belong to vim), have been separated from the interface, into <a href="https://github.com/onivim/libvim">libvim</a>. libvim is licensed under MIT, which means, this ‘extension’ of vim is perfectly in adherence to <a href="http://vimdoc.sourceforge.net/htmldoc/uganda.html#license">vim’s license text</a>! Outrun Labs are exploiting this loophole (distributing vim as a library) to commercialize Onivim.</p> 47editing. What’s wrong you ask?</p>
48<p>Onivim’s source code is available on <a href="https://github.com/onivim/oni2">GitHub</a>. They do mention that the source code trickles down to the <a href="https://github.com/onivim/oni2-mit">oni2-mit</a> repository, which (not yet) contains MIT-licensed code, <strong>18 months</strong> after each commit to the original repository.</p> 48<p>Apart from <a href="https://github.com/onivim/oni2/issues/550">buggy
49<p>Want to contribute to Onivim? Don’t. They make a profit out of your contributions. Currently, Onivim is priced at $19.99, ‘pre-alpha’ pricing which is 80% off the final price! If you are on the lookout for an editor, I would suggest using <a href="https://vim.org">Vim</a>, charity ware that actually works, and costs $100 lesser.</p> 49syntax highlighting</a>, <a
50href="https://github.com/onivim/oni2/issues/519">broken scrolling</a>
51and <a
52href="https://github.com/onivim/oni2/issues?q=is%3Aissue+label%3A%22daily+editor+blocker%22+is%3Aopen">others</a>,
53Onivim is <strong>proprietary</strong> software. It is licensed under a
54commercial <a
55href="https://github.com/onivim/oni1/blob/master/Outrun-Labs-EULA-v1.1.md">end
56user agreement license</a>, which prohibits redistribution in both
57object code and source code formats.</p>
58<p>Onivim’s core editor logic (bits that belong to vim), have been
59separated from the interface, into <a
60href="https://github.com/onivim/libvim">libvim</a>. libvim is licensed
61under MIT, which means, this ‘extension’ of vim is perfectly in
62adherence to <a
63href="http://vimdoc.sourceforge.net/htmldoc/uganda.html#license">vim’s
64license text</a>! Outrun Labs are exploiting this loophole (distributing
65vim as a library) to commercialize Onivim.</p>
66<p>Onivim’s source code is available on <a
67href="https://github.com/onivim/oni2">GitHub</a>. They do mention that
68the source code trickles down to the <a
69href="https://github.com/onivim/oni2-mit">oni2-mit</a> repository, which
70(not yet) contains MIT-licensed code, <strong>18 months</strong> after
71each commit to the original repository.</p>
72<p>Want to contribute to Onivim? Don’t. They make a profit out of your
73contributions. Currently, Onivim is priced at $19.99, ‘pre-alpha’
74pricing which is 80% off the final price! If you are on the lookout for
75an editor, I would suggest using <a href="https://vim.org">Vim</a>,
76charity ware that actually works, and costs $100 lesser.</p>
50 77
51 </div> 78 </div>
52 79
diff --git a/docs/posts/pixel_art_in_GIMP/index.html b/docs/posts/pixel_art_in_GIMP/index.html
index a095961..a9cc1b4 100644
--- a/docs/posts/pixel_art_in_GIMP/index.html
+++ b/docs/posts/pixel_art_in_GIMP/index.html
@@ -28,7 +28,7 @@
28 09/04 — 2020 28 09/04 — 2020
29 <div class="stats"> 29 <div class="stats">
30 <span class="stats-number"> 30 <span class="stats-number">
31 55.53 31 55.54
32 </span> 32 </span>
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
@@ -42,54 +42,105 @@
42 Pixel Art In GIMP 42 Pixel Art In GIMP
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>I’ve always been an admirer of pixel art, because of it’s simplicity and it’s resemblance to bitmap font design. Recently, I decided to take the dive and make some art of my own.</p> 45 <p>I’ve always been an admirer of pixel art, because of it’s simplicity
46<p>I used GIMP because I am fairly familiar with it. Aseprite seems to be the editor of choice for animated pixel art though.</p> 46and it’s resemblance to bitmap font design. Recently, I decided to take
47the dive and make some art of my own.</p>
48<p>I used GIMP because I am fairly familiar with it. Aseprite seems to
49be the editor of choice for animated pixel art though.</p>
47<h3 id="setting-up-the-canvas">Setting up the canvas</h3> 50<h3 id="setting-up-the-canvas">Setting up the canvas</h3>
48<p>Picking a canvas size is daunting. Too small, and you won’t be able to fit in enough detail to make a legible piece. Too big and you’ve got too many pixels to work with!</p> 51<p>Picking a canvas size is daunting. Too small, and you won’t be able
49<p>I would suggest starting out with anywhere between 100x100 and 200x200. <a href="https://u.peppe.rs/u9.png">Here’s</a> a sample configuration.</p> 52to fit in enough detail to make a legible piece. Too big and you’ve got
50<p>Sometimes I use a 10x10 grid, <code>View &gt; Show Grid</code> and <code>Edit &gt; Preferences &gt; Default Grid &gt; Spacing</code>, but that can get jarring, so I throw down a couple of guides, drag right or down from the left or top gutters for vertical and horizontal guides respectively.</p> 53too many pixels to work with!</p>
54<p>I would suggest starting out with anywhere between 100x100 and
55200x200. <a href="https://u.peppe.rs/u9.png">Here’s</a> a sample
56configuration.</p>
57<p>Sometimes I use a 10x10 grid, <code>View &gt; Show Grid</code> and
58<code>Edit &gt; Preferences &gt; Default Grid &gt; Spacing</code>, but
59that can get jarring, so I throw down a couple of guides, drag right or
60down from the left or top gutters for vertical and horizontal guides
61respectively.</p>
51<h3 id="choosing-a-brush">Choosing a Brush</h3> 62<h3 id="choosing-a-brush">Choosing a Brush</h3>
52<p>The most important part of our setup is the brush. Use the Pencil Tool (<code>n</code> on the keyboard) for hard edge drawings. Here’s a small comparison if you don’t know the difference between a hard edge and a soft edge:</p> 63<p>The most important part of our setup is the brush. Use the Pencil
64Tool (<code>n</code> on the keyboard) for hard edge drawings. Here’s a
65small comparison if you don’t know the difference between a hard edge
66and a soft edge:</p>
53<figure> 67<figure>
54<img src="https://u.peppe.rs/kz.png" alt="Hard edge vs Soft Edge" /><figcaption aria-hidden="true">Hard edge vs Soft Edge</figcaption> 68<img src="https://u.peppe.rs/kz.png" alt="Hard edge vs Soft Edge" />
69<figcaption aria-hidden="true">Hard edge vs Soft Edge</figcaption>
55</figure> 70</figure>
56<p>I turn the size down all the way to 1 (<code>[</code> on the keyboard). Set <code>Dynamics</code> off. <a href="https://u.peppe.rs/Fs.png">Here’s</a> a sample brush configuration.</p> 71<p>I turn the size down all the way to 1 (<code>[</code> on the
72keyboard). Set <code>Dynamics</code> off. <a
73href="https://u.peppe.rs/Fs.png">Here’s</a> a sample brush
74configuration.</p>
57<h3 id="laying-down-the-pixels">Laying down the pixels!</h3> 75<h3 id="laying-down-the-pixels">Laying down the pixels!</h3>
58<p>With the boring stuff out of the way, we can start with our piece. I usually follow a three step process:</p> 76<p>With the boring stuff out of the way, we can start with our piece. I
77usually follow a three step process:</p>
59<ul> 78<ul>
60<li>draw a rough outline</li> 79<li>draw a rough outline</li>
61<li>fill in the shadows</li> 80<li>fill in the shadows</li>
62<li>add highlights</li> 81<li>add highlights</li>
63</ul> 82</ul>
64<p>But this process is better explained with an example: an onigiri. Let us start off with a 100x100 canvas.</p> 83<p>But this process is better explained with an example: an onigiri. Let
84us start off with a 100x100 canvas.</p>
65<h4 id="drawing-the-outline">Drawing the outline</h4> 85<h4 id="drawing-the-outline">Drawing the outline</h4>
66<p>For the most part, our figure will be symmetric. If you are on GIMP 2.10+, you can take advantage of the Symmetry Painting feature. Go ahead and enable vertical symmetry, <code>Window &gt; Dockable Dialogs &gt; Symmetry Painting</code> and <code>Symmetry Painting &gt; Symmetry &gt; Mirror &gt; Vertical</code>.</p> 86<p>For the most part, our figure will be symmetric. If you are on GIMP
67<p>If you are running an older version of GIMP, draw in the left side, duplicate the layer, flip it horizontally, and merge it with the original.</p> 872.10+, you can take advantage of the Symmetry Painting feature. Go ahead
88and enable vertical symmetry,
89<code>Window &gt; Dockable Dialogs &gt; Symmetry Painting</code> and
90<code>Symmetry Painting &gt; Symmetry &gt; Mirror &gt; Vertical</code>.</p>
91<p>If you are running an older version of GIMP, draw in the left side,
92duplicate the layer, flip it horizontally, and merge it with the
93original.</p>
68<p>Your outline might look something like this:</p> 94<p>Your outline might look something like this:</p>
69<p><img src="https://u.peppe.rs/mn.png" /></p> 95<p><img src="https://u.peppe.rs/mn.png" /></p>
70<p>Go ahead and fill it in with the fill tool (<code>Shift + b</code> on the keyboard), add in some seaweed as well, preferably on a different layer. You can toggle symmetry on and off to save yourself some time.</p> 96<p>Go ahead and fill it in with the fill tool (<code>Shift + b</code> on
97the keyboard), add in some seaweed as well, preferably on a different
98layer. You can toggle symmetry on and off to save yourself some
99time.</p>
71<p><img src="https://u.peppe.rs/xu.png" /></p> 100<p><img src="https://u.peppe.rs/xu.png" /></p>
72<h4 id="shadows">Shadows</h4> 101<h4 id="shadows">Shadows</h4>
73<p>For now, let us focus on the shadows on the object itself, we’ll come back to the shadows cast by the object on the surface later.</p> 102<p>For now, let us focus on the shadows on the object itself, we’ll come
74<p>Shadows on any surface always follow the shape of the surface. A spherical onigiri would have a circular shadow:</p> 103back to the shadows cast by the object on the surface later.</p>
104<p>Shadows on any surface always follow the shape of the surface. A
105spherical onigiri would have a circular shadow:</p>
75<p><img src="https://u.peppe.rs/FU.png" /></p> 106<p><img src="https://u.peppe.rs/FU.png" /></p>
76<p>A couple of noticeable changes:</p> 107<p>A couple of noticeable changes:</p>
77<p><strong>Layers</strong>: The layer containing the seaweed has been hidden.<br /> 108<p><strong>Layers</strong>: The layer containing the seaweed has been
78<strong>Color</strong>: The color of the shadow is just a slightly lighter version of the original object (reduce the Value on the HSV scale).<br /> 109hidden.<br />
79<strong>Area</strong>: The shadow does not go all the way (notice the bottom edges).</p> 110<strong>Color</strong>: The color of the shadow is just a slightly
80<p>The shadow does not go all the way because we will be filling in that area with another, darker shadow! An image might explain better:</p> 111lighter version of the original object (reduce the Value on the HSV
112scale).<br />
113<strong>Area</strong>: The shadow does not go all the way (notice the
114bottom edges).</p>
115<p>The shadow does not go all the way because we will be filling in that
116area with another, darker shadow! An image might explain better:</p>
81<p><img src="https://u.peppe.rs/Br.png" /></p> 117<p><img src="https://u.peppe.rs/Br.png" /></p>
82<p>To emulate soft lights, reduce the value by 2 to 3 points every iteration. Notice how area <code>1</code> is much larger than area <code>4</code>. This is because an onigiri resembles a bottom heavy oblate spheroid, a sphere that is slightly fatter around the lower bottom, and areas <code>1</code> and <code>2</code> catch more light than areas <code>3</code> and <code>4</code>.</p> 118<p>To emulate soft lights, reduce the value by 2 to 3 points every
83<p>Do the same with the seaweed. The seaweed, being a smaller, flatter object, doesn’t cast much of a shadow, so stop with 1 or 2 iterations of the gradient:</p> 119iteration. Notice how area <code>1</code> is much larger than area
120<code>4</code>. This is because an onigiri resembles a bottom heavy
121oblate spheroid, a sphere that is slightly fatter around the lower
122bottom, and areas <code>1</code> and <code>2</code> catch more light
123than areas <code>3</code> and <code>4</code>.</p>
124<p>Do the same with the seaweed. The seaweed, being a smaller, flatter
125object, doesn’t cast much of a shadow, so stop with 1 or 2 iterations of
126the gradient:</p>
84<p><img src="https://u.peppe.rs/T3.png" /></p> 127<p><img src="https://u.peppe.rs/T3.png" /></p>
85<p>We’re getting there!</p> 128<p>We’re getting there!</p>
86<h4 id="highlights">Highlights</h4> 129<h4 id="highlights">Highlights</h4>
87<p>This step handles the details on the strongly illuminated portions of the object. Seaweed is a bit glossy, lighten the edges to make it seem shiny. The rice is not as shiny, but it does form an uneven surface. Add in some shadows to promote the idea of rice grains. Here is the finished result:</p> 130<p>This step handles the details on the strongly illuminated portions of
131the object. Seaweed is a bit glossy, lighten the edges to make it seem
132shiny. The rice is not as shiny, but it does form an uneven surface. Add
133in some shadows to promote the idea of rice grains. Here is the finished
134result:</p>
88<p><img src="https://u.peppe.rs/VE.png" /></p> 135<p><img src="https://u.peppe.rs/VE.png" /></p>
89<h3 id="finishing-touches">Finishing Touches</h3> 136<h3 id="finishing-touches">Finishing Touches</h3>
90<p>Some color correction and <code>a e s t h e t i c</code> Japanese text later, our piece is complete!</p> 137<p>Some color correction and <code>a e s t h e t i c</code> Japanese
138text later, our piece is complete!</p>
91<p><img src="https://u.peppe.rs/cn.png" /></p> 139<p><img src="https://u.peppe.rs/cn.png" /></p>
92<p>Hold on, why is it so tiny? Well, that’s because our canvas was 100x100, head over to <code>Image &gt; Scale Image</code>, set <code>Quality &gt; Interpolation</code> to <code>None</code> and scale it up to 700x700, et voilà!</p> 140<p>Hold on, why is it so tiny? Well, that’s because our canvas was
141100x100, head over to <code>Image &gt; Scale Image</code>, set
142<code>Quality &gt; Interpolation</code> to <code>None</code> and scale
143it up to 700x700, et voilà!</p>
93<p><img src="https://u.peppe.rs/CH.png" /></p> 144<p><img src="https://u.peppe.rs/CH.png" /></p>
94 145
95 </div> 146 </div>
diff --git a/docs/posts/programming_on_34_keys/index.html b/docs/posts/programming_on_34_keys/index.html
index 8667701..37ccfe6 100644
--- a/docs/posts/programming_on_34_keys/index.html
+++ b/docs/posts/programming_on_34_keys/index.html
@@ -28,7 +28,7 @@
28 28/08 — 2022 28 28/08 — 2022
29 <div class="stats"> 29 <div class="stats">
30 <span class="stats-number"> 30 <span class="stats-number">
31 63.53 31 63.54
32 </span> 32 </span>
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
@@ -42,79 +42,164 @@
42 Programming On 34 Keys 42 Programming On 34 Keys
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>Minimizing your keyboard layout is a slippery slope. A few months ago, I built the <a href="https://github.com/icyphox/ferricy">Ferricy</a>, a 34-key-split-ortho-ergo keyboard. The Ferricy is a fork of the <a href="https://github.com/davidphilipbarr/Sweep/tree/main/Sweep%20Bling%20MX">Ferris Sweep MX Bling</a>.</p> 45 <p>Minimizing your keyboard layout is a slippery slope. A few months
46ago, I built the <a
47href="https://github.com/icyphox/ferricy">Ferricy</a>, a
4834-key-split-ortho-ergo keyboard. The Ferricy is a fork of the <a
49href="https://github.com/davidphilipbarr/Sweep/tree/main/Sweep%20Bling%20MX">Ferris
50Sweep MX Bling</a>.</p>
46<figure> 51<figure>
47<img src="https://u.peppe.rs/otz.jpg" alt="The Ferricy, designed by icyphox" /><figcaption aria-hidden="true">The Ferricy, designed by <a href="https://icyphox.sh">icyphox</a></figcaption> 52<img src="https://u.peppe.rs/otz.jpg"
53alt="The Ferricy, designed by icyphox" />
54<figcaption aria-hidden="true">The Ferricy, designed by <a
55href="https://icyphox.sh">icyphox</a></figcaption>
48</figure> 56</figure>
49<p>My daily use consists of a bit of prose and a lot of program, my layout has evolved accordingly.</p> 57<p>My daily use consists of a bit of prose and a lot of program, my
58layout has evolved accordingly.</p>
50<h1 id="base-layer">Base Layer</h1> 59<h1 id="base-layer">Base Layer</h1>
51<figure> 60<figure>
52<img src="https://u.peppe.rs/base.png" alt="Colemak with no mods" /><figcaption aria-hidden="true">Colemak with no mods</figcaption> 61<img src="https://u.peppe.rs/base.png" alt="Colemak with no mods" />
62<figcaption aria-hidden="true">Colemak with no mods</figcaption>
53</figure> 63</figure>
54<p>The base layer contains alphabets, four symbols and four whitespace keys:</p> 64<p>The base layer contains alphabets, four symbols and four whitespace
65keys:</p>
55<ul> 66<ul>
56<li>Alphas: Stock Colemak, with no modifications whatsoever</li> 67<li>Alphas: Stock Colemak, with no modifications whatsoever</li>
57<li>Symbols: <code>. , / ;</code></li> 68<li>Symbols: <code>. , / ;</code></li>
58<li>Whitespace: tab, space, enter, backspace (from left to right)</li> 69<li>Whitespace: tab, space, enter, backspace (from left to right)</li>
59</ul> 70</ul>
60<h1 id="layers">Layers</h1> 71<h1 id="layers">Layers</h1>
61<p>Keyboard input is complex and it is impossible to skirt around it. You can either use a keyboard with enough keys to supply all possible inputs (a mechanical burden), or you can use firmware to supply all possible inputs (a cognitive burden). Layers are a cognitive burden.</p> 72<p>Keyboard input is complex and it is impossible to skirt around it.
62<p>I use 3 layers, heavily inspired by <a href="https://github.com/manna-harbour/miryoku">Miryoku</a>, but tuned for programming. Excluding the base Colemak layer:</p> 73You can either use a keyboard with enough keys to supply all possible
74inputs (a mechanical burden), or you can use firmware to supply all
75possible inputs (a cognitive burden). Layers are a cognitive burden.</p>
76<p>I use 3 layers, heavily inspired by <a
77href="https://github.com/manna-harbour/miryoku">Miryoku</a>, but tuned
78for programming. Excluding the base Colemak layer:</p>
63<ul> 79<ul>
64<li><code>NAV</code>: activated on holding <code>space</code> (left thumb)</li> 80<li><code>NAV</code>: activated on holding <code>space</code> (left
65<li><code>NUM</code>: activated on holding <code>tab</code> (left thumb)</li> 81thumb)</li>
66<li><code>SYM</code>: activated on holding <code>enter</code> (right thumb)</li> 82<li><code>NUM</code>: activated on holding <code>tab</code> (left
83thumb)</li>
84<li><code>SYM</code>: activated on holding <code>enter</code> (right
85thumb)</li>
67</ul> 86</ul>
68<h2 id="the-nav-layer">The <code>NAV</code> Layer</h2> 87<h2 id="the-nav-layer">The <code>NAV</code> Layer</h2>
69<p>As the name suggests, this layer is focused on navigation. Arrow keys and the likes.</p> 88<p>As the name suggests, this layer is focused on navigation. Arrow keys
89and the likes.</p>
70<figure> 90<figure>
71<img src="https://u.peppe.rs/nav.png" alt="NAV, on holding space" /><figcaption aria-hidden="true"><code>NAV</code>, on holding <code>space</code></figcaption> 91<img src="https://u.peppe.rs/nav.png" alt="NAV, on holding space" />
92<figcaption aria-hidden="true"><code>NAV</code>, on holding
93<code>space</code></figcaption>
72</figure> 94</figure>
73<p>Using Vim and Colemak means you lose out on HJKL navigation. However, on activating the <code>NAV</code> layer, the right home-row is converted into arrow keys. In essence, by holding space, I can navigate Vim with the home-row, or Firefox, or my PDF reader. I no longer need to look for software that allows Vim navigation keys, because it is baked into the firmware!</p> 95<p>Using Vim and Colemak means you lose out on HJKL navigation. However,
74<p>My Vim motions are not limited to HJKL. In fact, my Vim motions are rarely HJKL. I tend to use <code>}</code> (next paragraph) and <code>)</code> (next sentence) more often. As a result, these have found their way into my <code>NAV</code> layer, over the likes of <code>PgDown</code> and <code>End</code>. Having brackets at my index and middle fingers is nice for programming too.</p> 96on activating the <code>NAV</code> layer, the right home-row is
97converted into arrow keys. In essence, by holding space, I can navigate
98Vim with the home-row, or Firefox, or my PDF reader. I no longer need to
99look for software that allows Vim navigation keys, because it is baked
100into the firmware!</p>
101<p>My Vim motions are not limited to HJKL. In fact, my Vim motions are
102rarely HJKL. I tend to use <code>}</code> (next paragraph) and
103<code>)</code> (next sentence) more often. As a result, these have found
104their way into my <code>NAV</code> layer, over the likes of
105<code>PgDown</code> and <code>End</code>. Having brackets at my index
106and middle fingers is nice for programming too.</p>
75<h2 id="the-sym-layer">The <code>SYM</code> Layer</h2> 107<h2 id="the-sym-layer">The <code>SYM</code> Layer</h2>
76<figure> 108<figure>
77<img src="https://u.peppe.rs/sym.png" alt="SYM, on holding enter" /><figcaption aria-hidden="true"><code>SYM</code>, on holding <code>enter</code></figcaption> 109<img src="https://u.peppe.rs/sym.png" alt="SYM, on holding enter" />
110<figcaption aria-hidden="true"><code>SYM</code>, on holding
111<code>enter</code></figcaption>
78</figure> 112</figure>
79<p>This layer contains all the symbols that you would find by hitting <code>Shift</code> and a key on the number row. Probably noteworthy to Vim users: the symbols are arranged in the form of a mirrored numpad for exactly one reason: to move <code>$</code> to the left of <code>^</code>. It has always annoyed me that <code>$</code> moves the cursor to the end of the line and <code>^</code> moves it to the beginning, but their position on a typical number row are reversed, 4 comes before 6.</p> 113<p>This layer contains all the symbols that you would find by hitting
114<code>Shift</code> and a key on the number row. Probably noteworthy to
115Vim users: the symbols are arranged in the form of a mirrored numpad for
116exactly one reason: to move <code>$</code> to the left of
117<code>^</code>. It has always annoyed me that <code>$</code> moves the
118cursor to the end of the line and <code>^</code> moves it to the
119beginning, but their position on a typical number row are reversed, 4
120comes before 6.</p>
80<h2 id="the-num-layer">The <code>NUM</code> layer</h2> 121<h2 id="the-num-layer">The <code>NUM</code> layer</h2>
81<figure> 122<figure>
82<img src="https://u.peppe.rs/num.png" alt="NUM, on holding tab" /><figcaption aria-hidden="true"><code>NUM</code>, on holding <code>tab</code></figcaption> 123<img src="https://u.peppe.rs/num.png" alt="NUM, on holding tab" />
124<figcaption aria-hidden="true"><code>NUM</code>, on holding
125<code>tab</code></figcaption>
83</figure> 126</figure>
84<p>Another deviation from Miryoku, the numpad just feels <em>right</em> on my <em>right</em> hand.</p> 127<p>Another deviation from Miryoku, the numpad just feels <em>right</em>
128on my <em>right</em> hand.</p>
85<h1 id="zmk-combos">ZMK Combos</h1> 129<h1 id="zmk-combos">ZMK Combos</h1>
86<p>If you have been paying close attention, you might have noticed that <code>escape</code> didn’t make it to any layer. <code>escape</code> is too crucial to put on a non-base layer, but at the same time, not as important to deserve a place on the base layer. That is where ZMK’s combos come in. Combos let you tap any number of keys, and combine them to form a single key. I have combos set up for underscore, minus, escape and caps-word (more on caps-word later):</p> 130<p>If you have been paying close attention, you might have noticed that
131<code>escape</code> didn’t make it to any layer. <code>escape</code> is
132too crucial to put on a non-base layer, but at the same time, not as
133important to deserve a place on the base layer. That is where ZMK’s
134combos come in. Combos let you tap any number of keys, and combine them
135to form a single key. I have combos set up for underscore, minus, escape
136and caps-word (more on caps-word later):</p>
87<figure> 137<figure>
88<img src="https://u.peppe.rs/combos.png" alt="Combos are almost piano-like" /><figcaption aria-hidden="true">Combos are almost piano-like</figcaption> 138<img src="https://u.peppe.rs/combos.png"
139alt="Combos are almost piano-like" />
140<figcaption aria-hidden="true">Combos are almost piano-like</figcaption>
89</figure> 141</figure>
90<h1 id="home-row-mods">Home-row Mods</h1> 142<h1 id="home-row-mods">Home-row Mods</h1>
91<p>Inherited from Miryoku, I have home-row mods for activating <code>Super</code>, <code>Alt</code>, <code>Shift</code>, <code>Ctrl</code> and <code>Hyper</code> (<code>Ctrl + Shift + Alt + Super</code>). The idea is to send <code>T</code> on tap and <code>Ctrl</code> on hold. Home-row mods are fairly popular, so I’ll not go into the details.</p> 143<p>Inherited from Miryoku, I have home-row mods for activating
144<code>Super</code>, <code>Alt</code>, <code>Shift</code>,
145<code>Ctrl</code> and <code>Hyper</code>
146(<code>Ctrl + Shift + Alt + Super</code>). The idea is to send
147<code>T</code> on tap and <code>Ctrl</code> on hold. Home-row mods are
148fairly popular, so I’ll not go into the details.</p>
92<figure> 149<figure>
93<img src="https://u.peppe.rs/homerow.png" alt="Super, Alt, Shift, Ctrl, Hyper; on the left half, and mirrored on the right half" /><figcaption aria-hidden="true">Super, Alt, Shift, Ctrl, Hyper; on the left half, and mirrored on the right half</figcaption> 150<img src="https://u.peppe.rs/homerow.png"
151alt="Super, Alt, Shift, Ctrl, Hyper; on the left half, and mirrored on the right half" />
152<figcaption aria-hidden="true">Super, Alt, Shift, Ctrl, Hyper; on the
153left half, and mirrored on the right half</figcaption>
94</figure> 154</figure>
95<p><code>Hyper</code> bridges the gap between firmware and software. You can never configure key combination that, opens Firefox, for example, through firmware alone. However, with the <code>Hyper</code> key, and some <code>sxhkd</code> magic, you can emulate that. Pressing <code>Hyper + F</code> on a keyboard is just two keys, but the key codes sent are <code>Ctrl + Shift + Alt + Super + F</code>. That key combination is not intercepted by any application as a shortcut, except for the following <code>sxhkd</code> stanza:</p> 155<p><code>Hyper</code> bridges the gap between firmware and software. You
96<div class="sourceCode" id="cb1"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">super</span> + alt + shift + ctrl + f</span> 156can never configure key combination that, opens Firefox, for example,
157through firmware alone. However, with the <code>Hyper</code> key, and
158some <code>sxhkd</code> magic, you can emulate that. Pressing
159<code>Hyper + F</code> on a keyboard is just two keys, but the key codes
160sent are <code>Ctrl + Shift + Alt + Super + F</code>. That key
161combination is not intercepted by any application as a shortcut, except
162for the following <code>sxhkd</code> stanza:</p>
163<div class="sourceCode" id="cb1"><pre
164class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">super</span> + alt + shift + ctrl + f</span>
97<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> <span class="ex">xdotool</span> search <span class="st">&quot;Mozilla Firefox&quot;</span> windowactivate</span></code></pre></div> 165<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> <span class="ex">xdotool</span> search <span class="st">&quot;Mozilla Firefox&quot;</span> windowactivate</span></code></pre></div>
98<p>Alternatively, you can intercept unused <code>F</code> keys: <code>F13</code> through <code>F24</code>.</p> 166<p>Alternatively, you can intercept unused <code>F</code> keys:
99<p>Home-row mods are mirrored on each half because it would be impossible to hit <code>Ctrl + T</code> if not; they lie on the same key.</p> 167<code>F13</code> through <code>F24</code>.</p>
168<p>Home-row mods are mirrored on each half because it would be
169impossible to hit <code>Ctrl + T</code> if not; they lie on the same
170key.</p>
100<h1 id="caps-word">Caps-word</h1> 171<h1 id="caps-word">Caps-word</h1>
101<p>Caps-word is a clever caps-lock, built into ZMK. Typing out constants such as <code>PORT</code> with home-row mods would look like this:</p> 172<p>Caps-word is a clever caps-lock, built into ZMK. Typing out constants
173such as <code>PORT</code> with home-row mods would look like this:</p>
102<ul> 174<ul>
103<li>hold <code>e</code> (shift) on left hand, and tap <code>p</code> on right hand</li> 175<li>hold <code>e</code> (shift) on left hand, and tap <code>p</code> on
104<li>hold <code>e</code> (shift) on left hand, and tap <code>o</code> on right hand</li> 176right hand</li>
105<li>hold <code>s</code> (shift) on right hand, and tap <code>r</code> on left hand</li> 177<li>hold <code>e</code> (shift) on left hand, and tap <code>o</code> on
106<li>hold <code>s</code> (shift) on right hand, and tap <code>t</code> on left hand</li> 178right hand</li>
179<li>hold <code>s</code> (shift) on right hand, and tap <code>r</code> on
180left hand</li>
181<li>hold <code>s</code> (shift) on right hand, and tap <code>t</code> on
182left hand</li>
107</ul> 183</ul>
108<p>This hold-alternate-hold dance gets tiring quickly. With caps-word, however:</p> 184<p>This hold-alternate-hold dance gets tiring quickly. With caps-word,
185however:</p>
109<ul> 186<ul>
110<li>toggle <code>caps_word</code></li> 187<li>toggle <code>caps_word</code></li>
111<li>type out <code>p</code>, <code>o</code>, <code>r</code>, <code>t</code></li> 188<li>type out <code>p</code>, <code>o</code>, <code>r</code>,
189<code>t</code></li>
112<li>hit a <em>break</em> character (space, enter will do)</li> 190<li>hit a <em>break</em> character (space, enter will do)</li>
113<li>continue</li> 191<li>continue</li>
114</ul> 192</ul>
115<p>Caps-word automatically disables capitalization upon encountering a breaking character, (which are space, enter or any modifier, by default) right in the firmware!</p> 193<p>Caps-word automatically disables capitalization upon encountering a
194breaking character, (which are space, enter or any modifier, by default)
195right in the firmware!</p>
116<h1 id="findings">Findings</h1> 196<h1 id="findings">Findings</h1>
117<p>34-keys has been reasonably comfortable to use, for both prose and program. My palms do not move across the desk at all, as I reach for keys. I mostly write Rust and Bash, and my layout has evolved to accomodate special characters from their grammars (angled brackets and hyphens, specifically). If you are on a similar journey, I would suggest focusing on accuracy and comfort over speed. Speed comes with time.</p> 197<p>34-keys has been reasonably comfortable to use, for both prose and
198program. My palms do not move across the desk at all, as I reach for
199keys. I mostly write Rust and Bash, and my layout has evolved to
200accomodate special characters from their grammars (angled brackets and
201hyphens, specifically). If you are on a similar journey, I would suggest
202focusing on accuracy and comfort over speed. Speed comes with time.</p>
118 203
119 </div> 204 </div>
120 205
diff --git a/docs/posts/rapid_refactoring_with_vim/index.html b/docs/posts/rapid_refactoring_with_vim/index.html
index 3d867a3..e240da7 100644
--- a/docs/posts/rapid_refactoring_with_vim/index.html
+++ b/docs/posts/rapid_refactoring_with_vim/index.html
@@ -42,9 +42,14 @@
42 Rapid Refactoring With Vim 42 Rapid Refactoring With Vim
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>Last weekend, I was tasked with refactoring the 96 unit tests on <a href="https://github.com/ruma/ruma-events/pull/70">ruma-events</a> to use strictly typed json objects using <code>serde_json::json!</code> instead of raw strings. It was rather painless thanks to vim :)</p> 45 <p>Last weekend, I was tasked with refactoring the 96 unit tests on <a
46<p>Here’s a small sample of what had to be done (note the lines prefixed with the arrow):</p> 46href="https://github.com/ruma/ruma-events/pull/70">ruma-events</a> to
47<div class="sourceCode" id="cb1"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>→ <span class="kw">use</span> <span class="pp">serde_json::</span><span class="op">{</span>from_str<span class="op">};</span></span> 47use strictly typed json objects using <code>serde_json::json!</code>
48instead of raw strings. It was rather painless thanks to vim :)</p>
49<p>Here’s a small sample of what had to be done (note the lines prefixed
50with the arrow):</p>
51<div class="sourceCode" id="cb1"><pre
52class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>→ <span class="kw">use</span> <span class="pp">serde_json::</span><span class="op">{</span>from_str<span class="op">};</span></span>
48<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> </span> 53<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> </span>
49<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="at">#[</span>test<span class="at">]</span></span> 54<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="at">#[</span>test<span class="at">]</span></span>
50<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">fn</span> deserialize() <span class="op">{</span></span> 55<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">fn</span> deserialize() <span class="op">{</span></span>
@@ -54,7 +59,8 @@
54<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a> )<span class="op">;</span></span> 59<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a> )<span class="op">;</span></span>
55<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div> 60<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div>
56<p>had to be converted to:</p> 61<p>had to be converted to:</p>
57<div class="sourceCode" id="cb2"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>→ <span class="kw">use</span> <span class="pp">serde_json::</span><span class="op">{</span>from_value<span class="op">};</span></span> 62<div class="sourceCode" id="cb2"><pre
63class="sourceCode rust"><code class="sourceCode rust"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>→ <span class="kw">use</span> <span class="pp">serde_json::</span><span class="op">{</span>from_value<span class="op">};</span></span>
58<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> </span> 64<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> </span>
59<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> <span class="at">#[</span>test<span class="at">]</span></span> 65<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> <span class="at">#[</span>test<span class="at">]</span></span>
60<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">fn</span> deserialize() <span class="op">{</span></span> 66<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">fn</span> deserialize() <span class="op">{</span></span>
@@ -64,19 +70,38 @@
64<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a> )<span class="op">;</span></span> 70<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a> )<span class="op">;</span></span>
65<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div> 71<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div>
66<h3 id="the-arglist">The arglist</h3> 72<h3 id="the-arglist">The arglist</h3>
67<p>For the initial pass, I decided to handle imports, this was a simple find and replace operation, done to all the files containing tests. Luckily, modules (and therefore files) containing tests in Rust are annotated with the <code>#[cfg(test)]</code> attribute. I opened all such files:</p> 73<p>For the initial pass, I decided to handle imports, this was a simple
68<div class="sourceCode" id="cb3"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co"># `grep -l pattern files` lists all the files</span></span> 74find and replace operation, done to all the files containing tests.
75Luckily, modules (and therefore files) containing tests in Rust are
76annotated with the <code>#[cfg(test)]</code> attribute. I opened all
77such files:</p>
78<div class="sourceCode" id="cb3"><pre
79class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co"># `grep -l pattern files` lists all the files</span></span>
69<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="co"># matching the pattern</span></span> 80<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="co"># matching the pattern</span></span>
70<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a></span> 81<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a></span>
71<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="ex">vim</span> <span class="va">$(</span><span class="fu">grep</span> <span class="at">-l</span> <span class="st">&#39;cfg\(test\)&#39;</span> ./<span class="pp">**</span>/<span class="pp">*</span>.rs<span class="va">)</span></span> 82<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="ex">vim</span> <span class="va">$(</span><span class="fu">grep</span> <span class="at">-l</span> <span class="st">&#39;cfg\(test\)&#39;</span> ./<span class="pp">**</span>/<span class="pp">*</span>.rs<span class="va">)</span></span>
72<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a></span> 83<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a></span>
73<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="co"># expands to something like:</span></span> 84<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="co"># expands to something like:</span></span>
74<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="ex">vim</span> push_rules.rs room/member.rs key/verification/lib.rs</span></code></pre></div> 85<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="ex">vim</span> push_rules.rs room/member.rs key/verification/lib.rs</span></code></pre></div>
75<p>Starting vim with more than one file at the shell prompt populates the arglist. Hit <code>:args</code> to see the list of files currently ready to edit. The square [brackets] indicate the current file. Navigate through the arglist with <code>:next</code> and <code>:prev</code>. I use tpope’s vim-unimpaired <a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>, which adds <code>]a</code> and <code>[a</code>, mapped to <code>:next</code> and <code>:prev</code>.</p> 86<p>Starting vim with more than one file at the shell prompt populates
76<p>All that’s left to do is the find and replace, for which we will be using vim’s <code>argdo</code>, applying a substitution to every file in the arglist:</p> 87the arglist. Hit <code>:args</code> to see the list of files currently
88ready to edit. The square [brackets] indicate the current file. Navigate
89through the arglist with <code>:next</code> and <code>:prev</code>. I
90use tpope’s vim-unimpaired <a href="#fn1" class="footnote-ref"
91id="fnref1" role="doc-noteref"><sup>1</sup></a>, which adds
92<code>]a</code> and <code>[a</code>, mapped to <code>:next</code> and
93<code>:prev</code>.</p>
94<p>All that’s left to do is the find and replace, for which we will be
95using vim’s <code>argdo</code>, applying a substitution to every file in
96the arglist:</p>
77<pre><code>:argdo s/from_str/from_value/g</code></pre> 97<pre><code>:argdo s/from_str/from_value/g</code></pre>
78<h3 id="the-quickfix-list">The quickfix list</h3> 98<h3 id="the-quickfix-list">The quickfix list</h3>
79<p>Next up, replacing <code>r#" ... "#</code> with <code>json!( ... )</code>. I couldn’t search and replace that trivially, so I went with a macro call <a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a> instead, starting with the cursor on ‘r’, represented by the caret, in my attempt to breakdown the process:</p> 99<p>Next up, replacing <code>r#" ... "#</code> with
100<code>json!( ... )</code>. I couldn’t search and replace that trivially,
101so I went with a macro call <a href="#fn2" class="footnote-ref"
102id="fnref2" role="doc-noteref"><sup>2</sup></a> instead, starting with
103the cursor on ‘r’, represented by the caret, in my attempt to breakdown
104the process:</p>
80<pre><code>BUFFER: r#&quot; ... &quot;#; 105<pre><code>BUFFER: r#&quot; ... &quot;#;
81 ^ 106 ^
82 107
@@ -93,42 +118,80 @@ BUFFER: json!( ... &quot;#;
93ACTION: vhs)&lt;esc&gt; 118ACTION: vhs)&lt;esc&gt;
94 119
95BUFFER: json!( ... );</code></pre> 120BUFFER: json!( ... );</code></pre>
96<p>Here’s the recorded <a href="#fn3" class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a> macro in all its glory: <code>vllsjson!(&lt;esc&gt;$F#vhs)&lt;esc&gt;</code>.</p> 121<p>Here’s the recorded <a href="#fn3" class="footnote-ref" id="fnref3"
97<p>Great! So now we just go ahead, find every occurrence of <code>r#</code> and apply the macro right? Unfortunately, there were more than a few occurrences of raw strings that had to stay raw strings. Enter, the quickfix list.</p> 122role="doc-noteref"><sup>3</sup></a> macro in all its glory:
98<p>The idea behind the quickfix list is to jump from one position in a file to another (maybe in a different file), much like how the arglist lets you jump from one file to another.</p> 123<code>vllsjson!(&lt;esc&gt;$F#vhs)&lt;esc&gt;</code>.</p>
99<p>One of the easiest ways to populate this list with a bunch of positions is to use <code>vimgrep</code>:</p> 124<p>Great! So now we just go ahead, find every occurrence of
125<code>r#</code> and apply the macro right? Unfortunately, there were
126more than a few occurrences of raw strings that had to stay raw strings.
127Enter, the quickfix list.</p>
128<p>The idea behind the quickfix list is to jump from one position in a
129file to another (maybe in a different file), much like how the arglist
130lets you jump from one file to another.</p>
131<p>One of the easiest ways to populate this list with a bunch of
132positions is to use <code>vimgrep</code>:</p>
100<pre><code># basic usage 133<pre><code># basic usage
101:vimgrep pattern files 134:vimgrep pattern files
102 135
103# search for raw strings 136# search for raw strings
104:vimgrep &#39;r#&#39; ./**/*.rs</code></pre> 137:vimgrep &#39;r#&#39; ./**/*.rs</code></pre>
105<p>Like <code>:next</code> and <code>:prev</code>, you can navigate the quickfix list with <code>:cnext</code> and <code>:cprev</code>. Every time you move up or down the list, vim indicates your index:</p> 138<p>Like <code>:next</code> and <code>:prev</code>, you can navigate the
139quickfix list with <code>:cnext</code> and <code>:cprev</code>. Every
140time you move up or down the list, vim indicates your index:</p>
106<pre><code>(1 of 131): r#&quot;{&quot;set_tweak&quot;: &quot;highlight&quot;}&quot;#;</code></pre> 141<pre><code>(1 of 131): r#&quot;{&quot;set_tweak&quot;: &quot;highlight&quot;}&quot;#;</code></pre>
107<p>And just like <code>argdo</code>, you can <code>cdo</code> to apply commands to <em>every</em> match in the quickfix list:</p> 142<p>And just like <code>argdo</code>, you can <code>cdo</code> to apply
143commands to <em>every</em> match in the quickfix list:</p>
108<pre><code>:cdo norm! @q</code></pre> 144<pre><code>:cdo norm! @q</code></pre>
109<p>But, I had to manually pick out matches, and it involved some button mashing.</p> 145<p>But, I had to manually pick out matches, and it involved some button
146mashing.</p>
110<h3 id="external-filtering">External Filtering</h3> 147<h3 id="external-filtering">External Filtering</h3>
111<p>Some code reviews later, I was asked to format all the json inside the <code>json!</code> macro. All you have to do is pass a visual selection through a pretty json printer. Select the range to be formatted in visual mode, and hit <code>:</code>, you will notice the command line displaying what seems to be gibberish:</p> 148<p>Some code reviews later, I was asked to format all the json inside
149the <code>json!</code> macro. All you have to do is pass a visual
150selection through a pretty json printer. Select the range to be
151formatted in visual mode, and hit <code>:</code>, you will notice the
152command line displaying what seems to be gibberish:</p>
112<pre><code>:&#39;&lt;,&#39;&gt;</code></pre> 153<pre><code>:&#39;&lt;,&#39;&gt;</code></pre>
113<p><code>'&lt;</code> and <code>'&gt;</code> are <em>marks</em> <a href="#fn4" class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a>. More specifically, they are marks that vim sets automatically every time you make a visual selection, denoting the start and end of the selection.</p> 154<p><code>'&lt;</code> and <code>'&gt;</code> are <em>marks</em> <a
114<p>A range is one or more line specifiers separated by a <code>,</code>:</p> 155href="#fn4" class="footnote-ref" id="fnref4"
156role="doc-noteref"><sup>4</sup></a>. More specifically, they are marks
157that vim sets automatically every time you make a visual selection,
158denoting the start and end of the selection.</p>
159<p>A range is one or more line specifiers separated by a
160<code>,</code>:</p>
115<pre><code>:1,7 lines 1 through 7 161<pre><code>:1,7 lines 1 through 7
116:32 just line 32 162:32 just line 32
117:. the current line 163:. the current line
118:.,$ the current line to the last line 164:.,$ the current line to the last line
119:&#39;a,&#39;b mark &#39;a&#39; to mark &#39;b&#39;</code></pre> 165:&#39;a,&#39;b mark &#39;a&#39; to mark &#39;b&#39;</code></pre>
120<p>Most <code>:</code> commands can be prefixed by ranges. <code>:help usr_10.txt</code> for more on that.</p> 166<p>Most <code>:</code> commands can be prefixed by ranges.
121<p>Alright, lets pass json through <code>python -m json.tool</code>, a json formatter that accepts <code>stdin</code> (note the use of <code>!</code> to make use of an external program):</p> 167<code>:help usr_10.txt</code> for more on that.</p>
168<p>Alright, lets pass json through <code>python -m json.tool</code>, a
169json formatter that accepts <code>stdin</code> (note the use of
170<code>!</code> to make use of an external program):</p>
122<pre><code>:&#39;&lt;,&#39;&gt;!python -m json.tool</code></pre> 171<pre><code>:&#39;&lt;,&#39;&gt;!python -m json.tool</code></pre>
123<p>Unfortunately that didn’t quite work for me because the range included some non-json text as well, a mix of regex and macros helped fix that. I think you get the drift.</p> 172<p>Unfortunately that didn’t quite work for me because the range
124<p>Another fun filter I use from time to time is <code>:!sort</code>, to sort css attributes, or <code>:!uniq</code> to remove repeated imports.</p> 173included some non-json text as well, a mix of regex and macros helped
125<section class="footnotes" role="doc-endnotes"> 174fix that. I think you get the drift.</p>
175<p>Another fun filter I use from time to time is <code>:!sort</code>, to
176sort css attributes, or <code>:!uniq</code> to remove repeated
177imports.</p>
178<section id="footnotes" class="footnotes footnotes-end-of-document"
179role="doc-endnotes">
126<hr /> 180<hr />
127<ol> 181<ol>
128<li id="fn1" role="doc-endnote"><p>https://github.com/tpope/vim-unimpaired It also handles various other mappings, <code>]q</code> and <code>[q</code> to navigate the quickfix list for example<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li> 182<li id="fn1"><p>https://github.com/tpope/vim-unimpaired It also handles
129<li id="fn2" role="doc-endnote"><p><code>:help recording</code><a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li> 183various other mappings, <code>]q</code> and <code>[q</code> to navigate
130<li id="fn3" role="doc-endnote"><p>When I’m recording a macro, I prefer starting out by storing it in register <code>q</code>, and then copying it over to another register if it works as intended. I think of <code>qq</code> as ‘quick record’.<a href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li> 184the quickfix list for example<a href="#fnref1" class="footnote-back"
131<li id="fn4" role="doc-endnote"><p><code>:help mark-motions</code><a href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li> 185role="doc-backlink">↩︎</a></p></li>
186<li id="fn2"><p><code>:help recording</code><a href="#fnref2"
187class="footnote-back" role="doc-backlink">↩︎</a></p></li>
188<li id="fn3"><p>When I’m recording a macro, I prefer starting out by
189storing it in register <code>q</code>, and then copying it over to
190another register if it works as intended. I think of <code>qq</code> as
191‘quick record’.<a href="#fnref3" class="footnote-back"
192role="doc-backlink">↩︎</a></p></li>
193<li id="fn4"><p><code>:help mark-motions</code><a href="#fnref4"
194class="footnote-back" role="doc-backlink">↩︎</a></p></li>
132</ol> 195</ol>
133</section> 196</section>
134 197
diff --git a/docs/posts/self-hosting_git/index.html b/docs/posts/self-hosting_git/index.html
index f41a591..d927e95 100644
--- a/docs/posts/self-hosting_git/index.html
+++ b/docs/posts/self-hosting_git/index.html
@@ -28,7 +28,7 @@
28 17/10 — 2020 28 17/10 — 2020
29 <div class="stats"> 29 <div class="stats">
30 <span class="stats-number"> 30 <span class="stats-number">
31 87.90 31 87.91
32 </span> 32 </span>
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
@@ -42,11 +42,21 @@
42 Self-hosting Git 42 Self-hosting Git
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>Earlier this week, I began migrating my repositories from Github to <a href="https://git.zx2c4.com/cgit/about/">cgit</a>. If you care at all about big corporates turning open-source into a T-shirt farming service, this is the way to go.</p> 45 <p>Earlier this week, I began migrating my repositories from Github to
46<a href="https://git.zx2c4.com/cgit/about/">cgit</a>. If you care at all
47about big corporates turning open-source into a T-shirt farming service,
48this is the way to go.</p>
46<h3 id="offerings">Offerings</h3> 49<h3 id="offerings">Offerings</h3>
47<p>cgit is <em>very</em> bare bones. It is <a href="https://tools.ietf.org/html/rfc3875">cgi-based</a> web interface to git, and nothing more. You may browse repositories, view diffs, commit logs and even clone via http. If you are looking to replace Github with cgit, keep in mind that cgit does not handle issues or pull/merge requests. If people wish to contribute to your work, they would have to send you a patch via email.</p> 50<p>cgit is <em>very</em> bare bones. It is <a
51href="https://tools.ietf.org/html/rfc3875">cgi-based</a> web interface
52to git, and nothing more. You may browse repositories, view diffs,
53commit logs and even clone via http. If you are looking to replace
54Github with cgit, keep in mind that cgit does not handle issues or
55pull/merge requests. If people wish to contribute to your work, they
56would have to send you a patch via email.</p>
48<h3 id="setup">Setup</h3> 57<h3 id="setup">Setup</h3>
49<p>Installing cgit is fairly straightforward, if you would like to compile it from source:</p> 58<p>Installing cgit is fairly straightforward, if you would like to
59compile it from source:</p>
50<div class="sourceCode" id="cb1"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co"># fetch</span></span> 60<div class="sourceCode" id="cb1"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co"># fetch</span></span>
51<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="fu">git</span> clone https://git.zx2c4.com <span class="kw">&amp;&amp;</span> <span class="bu">cd</span> cgit</span> 61<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="fu">git</span> clone https://git.zx2c4.com <span class="kw">&amp;&amp;</span> <span class="bu">cd</span> cgit</span>
52<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="fu">git</span> submodule init</span> 62<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="fu">git</span> submodule init</span>
@@ -55,9 +65,16 @@
55<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="co"># install</span></span> 65<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="co"># install</span></span>
56<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="fu">make</span> NO_LUA=1</span> 66<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="fu">make</span> NO_LUA=1</span>
57<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> make install</span></code></pre></div> 67<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> make install</span></code></pre></div>
58<p>This would drop the cgit cgi script (and the default css) into <code>/var/www/htdocs/cgit</code>. You may configure cgit by editing <code>/etc/cgitrc</code>. I specify the <code>NO_LUA</code> flag to compile without lua support, exclude that flag if you would like to extend cgit via lua scripts.</p> 68<p>This would drop the cgit cgi script (and the default css) into
69<code>/var/www/htdocs/cgit</code>. You may configure cgit by editing
70<code>/etc/cgitrc</code>. I specify the <code>NO_LUA</code> flag to
71compile without lua support, exclude that flag if you would like to
72extend cgit via lua scripts.</p>
59<h3 id="going-live">Going live</h3> 73<h3 id="going-live">Going live</h3>
60<p>You might want to use, <a href="https://github.com/gnosek/fcgiwrap">fcgiwrap</a>, a <a href="http://www.nongnu.org/fastcgi">fastcgi</a> wrapper for <code>cgi</code> scripts,</p> 74<p>You might want to use, <a
75href="https://github.com/gnosek/fcgiwrap">fcgiwrap</a>, a <a
76href="http://www.nongnu.org/fastcgi">fastcgi</a> wrapper for
77<code>cgi</code> scripts,</p>
61<div class="sourceCode" id="cb2"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> apt install fcgiwrap</span> 78<div class="sourceCode" id="cb2"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> apt install fcgiwrap</span>
62<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> systemctl start fcgiwrap.socket</span></code></pre></div> 79<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> systemctl start fcgiwrap.socket</span></code></pre></div>
63<p>Expose the cgit cgi script to the web via <code>nginx</code>:</p> 80<p>Expose the cgit cgi script to the web via <code>nginx</code>:</p>
@@ -81,15 +98,21 @@ server {
81<p>Point cgit to your git repositories:</p> 98<p>Point cgit to your git repositories:</p>
82<pre><code># /etc/cgitrc 99<pre><code># /etc/cgitrc
83scan-path=/path/to/git/repos</code></pre> 100scan-path=/path/to/git/repos</code></pre>
84<p><strong><em>Note</em></strong>: <em><code>scan-path</code> works best if you stick it at the end of your <code>cgitrc</code></em>.</p> 101<p><strong><em>Note</em></strong>: <em><code>scan-path</code> works best
85<p>You may now create remote repositories at <code>/path/to/git/repos</code>, via:</p> 102if you stick it at the end of your <code>cgitrc</code></em>.</p>
103<p>You may now create remote repositories at
104<code>/path/to/git/repos</code>, via:</p>
86<pre><code>git init --bare</code></pre> 105<pre><code>git init --bare</code></pre>
87<p>Add the remote to your local repository:</p> 106<p>Add the remote to your local repository:</p>
88<pre><code>git remote set-url origin user@remote:/above/path 107<pre><code>git remote set-url origin user@remote:/above/path
89git push origin master</code></pre> 108git push origin master</code></pre>
90<h3 id="configuration">Configuration</h3> 109<h3 id="configuration">Configuration</h3>
91<p>cgit is fairly easy to configure, all configuration options can be found <a href="https://git.zx2c4.com/cgit/tree/cgitrc.5.txt">in the manual</a>, here are a couple of cool ones though:</p> 110<p>cgit is fairly easy to configure, all configuration options can be
92<p><strong>enable-commit-graph</strong>: Generates a text based graphical representation of the commit history, similar to <code>git log --graph --oneline</code>.</p> 111found <a href="https://git.zx2c4.com/cgit/tree/cgitrc.5.txt">in the
112manual</a>, here are a couple of cool ones though:</p>
113<p><strong>enable-commit-graph</strong>: Generates a text based
114graphical representation of the commit history, similar to
115<code>git log --graph --oneline</code>.</p>
93<pre><code>| * | Add support for configuration file 116<pre><code>| * | Add support for configuration file
94* | | simplify command parsing logic 117* | | simplify command parsing logic
95* | | Refactor parsers 118* | | Refactor parsers
@@ -110,7 +133,11 @@ git push origin master</code></pre>
110| | * | Merge branch &#39;fix/duplicate-habits&#39; 133| | * | Merge branch &#39;fix/duplicate-habits&#39;
111| | |\ \ 134| | |\ \
112| | | * | move duplicate check to command parsing blo...</code></pre> 135| | | * | move duplicate check to command parsing blo...</code></pre>
113<p><strong>section-from-path</strong>: This option paired with <code>scan-path</code> will automatically generate sections in your cgit index page, from the path to each repo. For example, the directory structure used to generate sections on <a href="https://git.peppe.rs">my cgit instance</a> looks like this:</p> 136<p><strong>section-from-path</strong>: This option paired with
137<code>scan-path</code> will automatically generate sections in your cgit
138index page, from the path to each repo. For example, the directory
139structure used to generate sections on <a href="https://git.peppe.rs">my
140cgit instance</a> looks like this:</p>
114<pre><code>├── cli 141<pre><code>├── cli
115│ ├── dijo 142│ ├── dijo
116│ ├── eva 143│ ├── eva
@@ -134,11 +161,18 @@ git push origin master</code></pre>
134└── web 161└── web
135 └── isostatic</code></pre> 162 └── isostatic</code></pre>
136<h3 id="ease-of-use">Ease of use</h3> 163<h3 id="ease-of-use">Ease of use</h3>
137<p>As I mentioned before, <code>cgit</code> is simply a view into your git repositories, you will have to manually create new repositories by entering your remote and using <code>git init --bare</code>. Here are a couple of scripts I wrote to perform actions on remotes, think of it as a smaller version of Github’s <code>gh</code> program.</p> 164<p>As I mentioned before, <code>cgit</code> is simply a view into your
138<p>You may save these scripts as <code>git-script-name</code> and drop them in your <code>$PATH</code>, and git will automatically add an alias called <code>script-name</code>, callable via:</p> 165git repositories, you will have to manually create new repositories by
166entering your remote and using <code>git init --bare</code>. Here are a
167couple of scripts I wrote to perform actions on remotes, think of it as
168a smaller version of Github’s <code>gh</code> program.</p>
169<p>You may save these scripts as <code>git-script-name</code> and drop
170them in your <code>$PATH</code>, and git will automatically add an alias
171called <code>script-name</code>, callable via:</p>
139<pre><code>git script-name</code></pre> 172<pre><code>git script-name</code></pre>
140<h4 id="git-new-repo">git-new-repo</h4> 173<h4 id="git-new-repo">git-new-repo</h4>
141<p>Creates a new repository on your remote, the first arg may be a path (section/repo-name) or just the repo name:</p> 174<p>Creates a new repository on your remote, the first arg may be a path
175(section/repo-name) or just the repo name:</p>
142<pre><code>#! /usr/bin/env bash 176<pre><code>#! /usr/bin/env bash
143# 177#
144# usage: 178# usage:
@@ -155,7 +189,10 @@ fi
155 189
156ssh user@remote git init --bare &quot;$1&quot;;</code></pre> 190ssh user@remote git init --bare &quot;$1&quot;;</code></pre>
157<h4 id="git-set-desc">git-set-desc</h4> 191<h4 id="git-set-desc">git-set-desc</h4>
158<p>To set a one line repository description. It simply copies the local <code>.git/description</code>, into <code>remote/description</code>. <code>cgit</code> displays the contents of this file on the index page:</p> 192<p>To set a one line repository description. It simply copies the local
193<code>.git/description</code>, into <code>remote/description</code>.
194<code>cgit</code> displays the contents of this file on the index
195page:</p>
159<pre><code>#! /usr/bin/env bash 196<pre><code>#! /usr/bin/env bash
160# 197#
161# usage: 198# usage:
diff --git a/docs/posts/static_sites_with_bash/index.html b/docs/posts/static_sites_with_bash/index.html
index 07313be..6921529 100644
--- a/docs/posts/static_sites_with_bash/index.html
+++ b/docs/posts/static_sites_with_bash/index.html
@@ -28,7 +28,7 @@
28 23/11 — 2019 28 23/11 — 2019
29 <div class="stats"> 29 <div class="stats">
30 <span class="stats-number"> 30 <span class="stats-number">
31 21.17 31 21.18
32 </span> 32 </span>
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
@@ -42,12 +42,22 @@
42 Static Sites With Bash 42 Static Sites With Bash
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>After going through a bunch of static site generators (<a href="https://blog.getpelican.com/">pelican</a>, <a href="https://gohugo.io">hugo</a>, <a href="https://github.com/icyphox/vite">vite</a>), I decided to roll my own. If you are more of the ‘show me the code’ kinda guy, <a href="https://github.com/nerdypepper/site">here</a> you go.</p> 45 <p>After going through a bunch of static site generators (<a
46href="https://blog.getpelican.com/">pelican</a>, <a
47href="https://gohugo.io">hugo</a>, <a
48href="https://github.com/icyphox/vite">vite</a>), I decided to roll my
49own. If you are more of the ‘show me the code’ kinda guy, <a
50href="https://github.com/nerdypepper/site">here</a> you go.</p>
46<h3 id="text-formatting">Text formatting</h3> 51<h3 id="text-formatting">Text formatting</h3>
47<p>I chose to write in markdown, and convert to html with <a href="https://kristaps.bsd.lv/lowdown/">lowdown</a>.</p> 52<p>I chose to write in markdown, and convert to html with <a
53href="https://kristaps.bsd.lv/lowdown/">lowdown</a>.</p>
48<h3 id="directory-structure">Directory structure</h3> 54<h3 id="directory-structure">Directory structure</h3>
49<p>I host my site on GitHub pages, so <code>docs/</code> has to be the entry point. Markdown formatted posts go into <code>posts/</code>, get converted into html, and end up in <code>docs/index.html</code>, something like this:</p> 55<p>I host my site on GitHub pages, so <code>docs/</code> has to be the
50<div class="sourceCode" id="cb1"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="va">posts</span><span class="op">=</span><span class="va">$(</span><span class="fu">ls</span> <span class="at">-t</span> ./posts<span class="va">)</span> <span class="co"># chronological order!</span></span> 56entry point. Markdown formatted posts go into <code>posts/</code>, get
57converted into html, and end up in <code>docs/index.html</code>,
58something like this:</p>
59<div class="sourceCode" id="cb1"><pre
60class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="va">posts</span><span class="op">=</span><span class="va">$(</span><span class="fu">ls</span> <span class="at">-t</span> ./posts<span class="va">)</span> <span class="co"># chronological order!</span></span>
51<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> f <span class="kw">in</span> <span class="va">$posts</span><span class="kw">;</span> <span class="cf">do</span></span> 61<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> f <span class="kw">in</span> <span class="va">$posts</span><span class="kw">;</span> <span class="cf">do</span></span>
52<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="va">file</span><span class="op">=</span><span class="st">&quot;./posts/&quot;</span><span class="va">$f</span> <span class="co"># `ls` mangled our file paths</span></span> 62<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="va">file</span><span class="op">=</span><span class="st">&quot;./posts/&quot;</span><span class="va">$f</span> <span class="co"># `ls` mangled our file paths</span></span>
53<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="bu">echo</span> <span class="st">&quot;generating post </span><span class="va">$file</span><span class="st">&quot;</span></span> 63<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="bu">echo</span> <span class="st">&quot;generating post </span><span class="va">$file</span><span class="st">&quot;</span></span>
@@ -56,19 +66,27 @@
56<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a> <span class="bu">echo</span> <span class="at">-e</span> <span class="st">&quot;html&quot;</span> <span class="op">&gt;&gt;</span> docs/index.html</span> 66<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a> <span class="bu">echo</span> <span class="at">-e</span> <span class="st">&quot;html&quot;</span> <span class="op">&gt;&gt;</span> docs/index.html</span>
57<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="cf">done</span></span></code></pre></div> 67<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="cf">done</span></span></code></pre></div>
58<h3 id="assets">Assets</h3> 68<h3 id="assets">Assets</h3>
59<p>Most static site generators recommend dropping image assets into the site source itself. That does have it’s merits, but I prefer hosting images separately:</p> 69<p>Most static site generators recommend dropping image assets into the
60<div class="sourceCode" id="cb2"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co"># strip file extension</span></span> 70site source itself. That does have it’s merits, but I prefer hosting
71images separately:</p>
72<div class="sourceCode" id="cb2"><pre
73class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co"># strip file extension</span></span>
61<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="va">ext</span><span class="op">=</span><span class="st">&quot;</span><span class="va">${1</span><span class="op">##</span><span class="pp">*</span>.<span class="va">}</span><span class="st">&quot;</span></span> 74<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="va">ext</span><span class="op">=</span><span class="st">&quot;</span><span class="va">${1</span><span class="op">##</span><span class="pp">*</span>.<span class="va">}</span><span class="st">&quot;</span></span>
62<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span> 75<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
63<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="co"># generate a random file name</span></span> 76<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="co"># generate a random file name</span></span>
64<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="va">id</span><span class="op">=</span><span class="va">$(</span> <span class="fu">cat</span> /dev/urandom <span class="kw">|</span> <span class="fu">tr</span> <span class="at">-dc</span> <span class="st">&#39;a-zA-Z0-9&#39;</span> <span class="kw">|</span> <span class="ex">fold</span> <span class="at">-w</span> 2 <span class="kw">|</span> <span class="fu">head</span> <span class="at">-n</span> 1 <span class="va">)</span></span> 77<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="va">id</span><span class="op">=</span><span class="va">$(</span> <span class="fu">cat</span> /dev/urandom <span class="kw">|</span> <span class="fu">tr</span> <span class="at">-dc</span> <span class="st">&#39;a-zA-Z0-9&#39;</span> <span class="kw">|</span> <span class="fu">fold</span> <span class="at">-w</span> 2 <span class="kw">|</span> <span class="fu">head</span> <span class="at">-n</span> 1 <span class="va">)</span></span>
65<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="va">id</span><span class="op">=</span><span class="st">&quot;</span><span class="va">$id</span><span class="st">.</span><span class="va">$ext</span><span class="st">&quot;</span></span> 78<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="va">id</span><span class="op">=</span><span class="st">&quot;</span><span class="va">$id</span><span class="st">.</span><span class="va">$ext</span><span class="st">&quot;</span></span>
66<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a></span> 79<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a></span>
67<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="co"># copy to my file host</span></span> 80<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="co"># copy to my file host</span></span>
68<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="fu">scp</span> <span class="at">-P</span> 443 <span class="st">&quot;</span><span class="va">$1</span><span class="st">&quot;</span> emerald:files/<span class="st">&quot;</span><span class="va">$id</span><span class="st">&quot;</span> </span> 81<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="fu">scp</span> <span class="at">-P</span> 443 <span class="st">&quot;</span><span class="va">$1</span><span class="st">&quot;</span> emerald:files/<span class="st">&quot;</span><span class="va">$id</span><span class="st">&quot;</span> </span>
69<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="bu">echo</span> <span class="st">&quot;https://u.peppe.rs/</span><span class="va">$id</span><span class="st">&quot;</span></span></code></pre></div> 82<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="bu">echo</span> <span class="st">&quot;https://u.peppe.rs/</span><span class="va">$id</span><span class="st">&quot;</span></span></code></pre></div>
70<h3 id="templating">Templating</h3> 83<h3 id="templating">Templating</h3>
71<p><a href="https://github.com/NerdyPepper/site/blob/master/generate.sh"><code>generate.sh</code></a> brings the above bits and pieces together (with some extra cruft to avoid javascript). It uses <code>sed</code> to produce nice titles from the file names (removes underscores, title-case), and <code>date(1)</code> to add the date to each post listing!</p> 84<p><a
85href="https://github.com/NerdyPepper/site/blob/master/generate.sh"><code>generate.sh</code></a>
86brings the above bits and pieces together (with some extra cruft to
87avoid javascript). It uses <code>sed</code> to produce nice titles from
88the file names (removes underscores, title-case), and
89<code>date(1)</code> to add the date to each post listing!</p>
72 90
73 </div> 91 </div>
74 92
diff --git a/docs/posts/termux_tandem/index.html b/docs/posts/termux_tandem/index.html
index 9f2e708..71c4731 100644
--- a/docs/posts/termux_tandem/index.html
+++ b/docs/posts/termux_tandem/index.html
@@ -28,7 +28,7 @@
28 08/03 — 2020 28 08/03 — 2020
29 <div class="stats"> 29 <div class="stats">
30 <span class="stats-number"> 30 <span class="stats-number">
31 19.17 31 19.18
32 </span> 32 </span>
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
@@ -42,24 +42,39 @@
42 Termux Tandem 42 Termux Tandem
43 </h1> 43 </h1>
44 <div class="post-text"> 44 <div class="post-text">
45 <p>I learnt about <code>termux</code> from a friend on IRC recently. It looked super gimmicky to me at first, but it eventually proved to be useful. Here’s what I use it for:</p> 45 <p>I learnt about <code>termux</code> from a friend on IRC recently. It
46looked super gimmicky to me at first, but it eventually proved to be
47useful. Here’s what I use it for:</p>
46<h3 id="rsync">rsync</h3> 48<h3 id="rsync">rsync</h3>
47<p>Ever since I degoogled my android device, syncing files between my phone and my PC has always been a pain. I’m looking at you MTP. But, with <code>termux</code> and <code>sshd</code> all set up, it’s as simple as:</p> 49<p>Ever since I degoogled my android device, syncing files between my
50phone and my PC has always been a pain. I’m looking at you MTP. But,
51with <code>termux</code> and <code>sshd</code> all set up, it’s as
52simple as:</p>
48<pre><code>$ arp 53<pre><code>$ arp
49Address HWtype HWad ... 54Address HWtype HWad ...
50192.168.43.187 ether d0:0 ... 55192.168.43.187 ether d0:0 ...
51 56
52$ rsync -avz 192.168.43.187:~/frogs ~/pics/frogs</code></pre> 57$ rsync -avz 192.168.43.187:~/frogs ~/pics/frogs</code></pre>
53<h3 id="ssh-tmux">ssh &amp; tmux</h3> 58<h3 id="ssh-tmux">ssh &amp; tmux</h3>
54<p>My phone doubles as a secondary view into my main machine with <code>ssh</code> and <code>tmux</code>. When I am away from my PC (read: sitting across the room), I check build status and IRC messages by <code>ssh</code>ing into a tmux session running the said build or weechat.</p> 59<p>My phone doubles as a secondary view into my main machine with
60<code>ssh</code> and <code>tmux</code>. When I am away from my PC (read:
61sitting across the room), I check build status and IRC messages by
62<code>ssh</code>ing into a tmux session running the said build or
63weechat.</p>
55<h3 id="file-uploads">file uploads</h3> 64<h3 id="file-uploads">file uploads</h3>
56<p>Not being able to access my (ssh-only) file host was crippling. With a <code>bash</code> instance on my phone, I just copied over my ssh keys, and popped in a file upload script (a glorified <code>scp</code>). Now I just have to figure out a way to clean up these file names …</p> 65<p>Not being able to access my (ssh-only) file host was crippling. With
66a <code>bash</code> instance on my phone, I just copied over my ssh
67keys, and popped in a file upload script (a glorified <code>scp</code>).
68Now I just have to figure out a way to clean up these file names …</p>
57<pre><code>~/storage/pictures/ $ ls 69<pre><code>~/storage/pictures/ $ ls
5802muf5g7b2i41.jpg 7alt3cwg77841.jpg cl4bsrge7id11.png 7002muf5g7b2i41.jpg 7alt3cwg77841.jpg cl4bsrge7id11.png
59mtZabXG.jpg p8d5c584f2841.jpg vjUxGjq.jpg</code></pre> 71mtZabXG.jpg p8d5c584f2841.jpg vjUxGjq.jpg</code></pre>
60<h3 id="cmus">cmus</h3> 72<h3 id="cmus">cmus</h3>
61<p>Alright, I don’t really listen to music via <code>cmus</code>, but I did use it a couple times when my default music player was acting up. <code>cmus</code> is a viable option:</p> 73<p>Alright, I don’t really listen to music via <code>cmus</code>, but I
62<p><a href="https://u.peppe.rs/CP.jpg"><img src="https://u.peppe.rs/CP.jpg" /></a></p> 74did use it a couple times when my default music player was acting up.
75<code>cmus</code> is a viable option:</p>
76<p><a href="https://u.peppe.rs/CP.jpg"><img
77src="https://u.peppe.rs/CP.jpg" /></a></p>
63 78
64 </div> 79 </div>
65 80
diff --git a/docs/posts/turing_complete_type_systems/index.html b/docs/posts/turing_complete_type_systems/index.html
index 1f6fd4c..2a9361e 100644
--- a/docs/posts/turing_complete_type_systems/index.html
+++ b/docs/posts/turing_complete_type_systems/index.html
@@ -28,7 +28,7 @@
28 18/06 — 2020 28 18/06 — 2020
29 <div class="stats"> 29 <div class="stats">
30 <span class="stats-number"> 30 <span class="stats-number">
31 9.18 31 9.19
32 </span> 32 </span>
33 <span class="stats-unit">cm</span> 33 <span class="stats-unit">cm</span>
34 &nbsp 34 &nbsp
@@ -44,12 +44,26 @@
44 <div class="post-text"> 44 <div class="post-text">
45 <p>Rust’s type system is Turing complete:</p> 45 <p>Rust’s type system is Turing complete:</p>
46<ul> 46<ul>
47<li><a href="https://github.com/doctorn/trait-eval/">FizzBuzz with Rust Traits</a></li> 47<li><a href="https://github.com/doctorn/trait-eval/">FizzBuzz with Rust
48<li><a href="https://github.com/Ashymad/fortraith">A Forth implementation with Rust Traits</a></li> 48Traits</a></li>
49<li><a href="https://github.com/Ashymad/fortraith">A Forth
50implementation with Rust Traits</a></li>
49</ul> 51</ul>
50<p>It is impossible to determine if a program written in a generally Turing complete system will ever stop. That is, it is impossible to write a program <code>f</code> that determines if a program <code>g</code>, where <code>g</code> is written in a Turing complete programming language, will ever halt. The <a href="https://en.wikipedia.org/wiki/Halting_problem">Halting Problem</a> is in fact, an <a href="https://en.wikipedia.org/wiki/Undecidable_problem">undecidable problem</a>.</p> 52<p>It is impossible to determine if a program written in a generally
53Turing complete system will ever stop. That is, it is impossible to
54write a program <code>f</code> that determines if a program
55<code>g</code>, where <code>g</code> is written in a Turing complete
56programming language, will ever halt. The <a
57href="https://en.wikipedia.org/wiki/Halting_problem">Halting Problem</a>
58is in fact, an <a
59href="https://en.wikipedia.org/wiki/Undecidable_problem">undecidable
60problem</a>.</p>
51<p><em>How is any of this relevant?</em></p> 61<p><em>How is any of this relevant?</em></p>
52<p>Rust performs compile-time type inference. The type checker, in turn, compiles and infers types, I would describe it as a compiler inside a compiler. It is possible that <code>rustc</code> may never finish compiling your Rust program! I lied, <code>rustc</code> stops after a while, after hitting the recursion limit.</p> 62<p>Rust performs compile-time type inference. The type checker, in turn,
63compiles and infers types, I would describe it as a compiler inside a
64compiler. It is possible that <code>rustc</code> may never finish
65compiling your Rust program! I lied, <code>rustc</code> stops after a
66while, after hitting the recursion limit.</p>
53<p>I understand that this post lacks content.</p> 67<p>I understand that this post lacks content.</p>
54 68
55 </div> 69 </div>