add a tagging system to the website
This commit is contained in:
parent
701da6bc4b
commit
e1b6578b2a
97 changed files with 1025 additions and 979 deletions
|
@ -1,4 +1,6 @@
|
|||
%% title = "Advent of Code feels"
|
||||
%% id = "b?01JDZKAP3KT4AD36F6HPJTEM4Z"
|
||||
title = "Advent of Code feels"
|
||||
tags = ["all", "programming", "shower"]
|
||||
|
||||
% id = "01JDZKMFQZS2VVNQ3R9WDS81TS"
|
||||
- I wonder if I'm the only one who can never get into [Advent of Code](https://adventofcode.com).
|
||||
|
@ -35,7 +37,7 @@ there is always something to work on.
|
|||
|
||||
% id = "01JDZKMFQZP2723GMYB2HMJFR2"
|
||||
- I like to build my software to solve real world problems---mostly my own, but I like to imagine it could one day become useful for someone else, too.
|
||||
|
||||
|
||||
% id = "01JDZKMFQZWF0F0G6822298N5Z"
|
||||
- egoistic altruism, y'know.
|
||||
it's why all the code I write outside of work is open source.
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
%% title = "not quite buildless"
|
||||
%% id = "b?01J7C1KBZ58BR21AVFA1PMWV68"
|
||||
title = "not quite buildless"
|
||||
tags = ["all", "programming", "treehouse"]
|
||||
|
||||
% id = "01J7BYKQGYPF50050K67N2MP1G"
|
||||
- ...buildsome?
|
||||
|
@ -56,7 +58,7 @@ enjoy!
|
|||
% id = "01J7BYKQGY7QEAN677Q9AT4T0V"
|
||||
- I'll put _probably_ the most interesting bit right at the start.
|
||||
the treehouse is _not quite_ buildless.
|
||||
|
||||
|
||||
% id = "01J7BYKQGYRV6TKEACZ0DXNDG4"
|
||||
- one might even call it... buildsome?
|
||||
I mean, it's not quite buildful, and definitely not buildless...?
|
||||
|
@ -147,7 +149,7 @@ enjoy!
|
|||
|
||||
% id = "01J7BYKQGY0PR13G71PK163976"
|
||||
- if I _wanted_ to implement incremental builds, I feel like the dependency tracking would get pretty hellish pretty quickly.
|
||||
|
||||
|
||||
% id = "01J7BYKQGY75XN1HBVZ110D16P"
|
||||
- say a `.tree` file uses the `include_static` template directive to include some file into itself.
|
||||
now in addition to compiling the `.tree` file when it changes, I'd also need to recompile the `.tree` file when that `include`d`_static` file changes too---and that sort of dependency tracking is ripe for bugs as the codebase grows more complex!
|
||||
|
@ -223,7 +225,7 @@ enjoy!
|
|||
|
||||
% id = "01J7EMBKN42WH0BKXKDQ020F8M"
|
||||
- you can also provide source maps to transfer optimal minified sources by default, and let your browser's DevTools display your original sources to the user upon their request.
|
||||
|
||||
|
||||
% id = "01J7EMJYX91P3RE3PEBM2M3MR1"
|
||||
- the important part is that having _some_ form of readable sources _right on your page_ is really nice!
|
||||
|
||||
|
@ -237,7 +239,7 @@ enjoy!
|
|||
- the reason is that I don't want to waste time testing my website separately on release mode, so having it behave differently in subtle ways means more bugs!
|
||||
|
||||
% id = "01J7BYKQGY6KJ6ZZX4EREEAB79"
|
||||
- there are only two parts of the treehouse that behaves differently between debug and release mode.
|
||||
- there are only two parts of the treehouse that behaves differently between debug and release mode.
|
||||
|
||||
% id = "01J7BYKQGYB4G0J7TZQCF4X7W6"
|
||||
- generation speed, and...
|
||||
|
@ -316,7 +318,7 @@ enjoy!
|
|||
|
||||
async fn back_up() -> String {
|
||||
"".into()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
% id = "01J7BYKQGYDY8E84BEM5V7MMGB"
|
||||
|
@ -333,7 +335,7 @@ enjoy!
|
|||
|
||||
% id = "01J7BYKQGYVS4CZGVC4ZHGJ7KF"
|
||||
- also, `tower-livereload` also has a couple disadvantages compared to the solution I've shown here.
|
||||
|
||||
|
||||
% id = "01J7BYKQGY3P95RM10ZZGRP2Y3"
|
||||
- it's slow, because it only polls the server's `/back-up` endpoint every second, which increases reload latency.
|
||||
I've bumped that up to polling every 100ms in my script, because I don't like slow.
|
||||
|
@ -377,7 +379,7 @@ enjoy!
|
|||
|
||||
% id = "01J7BYKQGYM9HD00VY2BVEZPZ0"
|
||||
- _customized built-in elements_, which extend _any_ built-in element.
|
||||
these are applied using the `is=""` attribute on a base built-in element, like `<li is="your-element"></li>`.
|
||||
these are applied using the `is=""` attribute on a base built-in element, like `<li is="your-element"></li>`.
|
||||
|
||||
% id = "01J7BYKQGY90D6C0KF9CFSMF1A"
|
||||
- unfortunately customized built-in elements are practically useless, because Safari doesn't implement them, [and doesn't even plan to do so](https://github.com/WICG/webcomponents/issues/509#issuecomment-222860736)...
|
||||
|
@ -408,7 +410,7 @@ enjoy!
|
|||
```
|
||||
|
||||
and off we go!
|
||||
|
||||
|
||||
% id = "01J7BYKQGY6YE329DB9PMY8KNW"
|
||||
- I've found a couple useful idioms for working with custom elements.
|
||||
|
||||
|
@ -476,7 +478,7 @@ enjoy!
|
|||
|
||||
% id = "01J7BYKQGYYBY9RDFJG8BP61QP"
|
||||
- and that's it! the actual value of the `?cache` parameter is never interpreted by anyone, anyhow.
|
||||
it's only there so that whenever something _does_ change, we change the URL, and the browser thinks that "hey, that's a different asset! gotta download it."
|
||||
it's only there so that whenever something _does_ change, we change the URL, and the browser thinks that "hey, that's a different asset! gotta download it."
|
||||
|
||||
that way, the browser only ever downloads files that changed since your last visit.
|
||||
|
||||
|
@ -540,7 +542,7 @@ enjoy!
|
|||
|
||||
% id = "01J7C16RSZ7NHE5N3KV57NGWT0"
|
||||
- okay cool we're getting somewhere,
|
||||
|
||||
|
||||
% id = "01J7C16RSZQPMABF0SBDH1RHA7"
|
||||
- "and then we could even cache that import map with a `?cache` parameter too---"
|
||||
|
||||
|
@ -589,10 +591,10 @@ enjoy!
|
|||
|
||||
% id = "01J7BYKQGYMMCAKQX9S8JCTJW6"
|
||||
- as time went on though, I discovered another light markup language: [_Djot_](https://djot.net/), made by the same person who made Markdown, with _lots_ of lessons learned from his previous attempt.
|
||||
|
||||
|
||||
% id = "01J7BYKQGYQQP0YSWA1TEHRB9S"
|
||||
- I initially didn't wanna go through with it, because "_sigh_ am I really gonna have to rewrite my entire content to use Djot?"
|
||||
|
||||
|
||||
% id = "01J7BYKQGYSKJNTB7BGKTED4S0"
|
||||
+ but then I did it anyways, because life's too short to have to deal with poorly designed markup languages :hat_smug:
|
||||
|
||||
|
@ -638,7 +640,7 @@ enjoy!
|
|||
|
||||
% id = "01J7C16RSZAECM1G9CD57WX1M6"
|
||||
- I am pushing into a string, that literally cannot fail! (other than with an OOM, but that's a panic)
|
||||
|
||||
|
||||
% id = "01J7BYKQGYJMRC7DY7SNMAQ538"
|
||||
- the HTML generation code got cleaner, because the crate I'm using---[`jotdown`](https://lib.rs/crates/jotdown)---does not use a callback for filling in broken links.
|
||||
a pattern that's best known under the moniker "yeah, don't do that" in the Rust world.
|
||||
|
@ -676,14 +678,14 @@ enjoy!
|
|||
|
||||
% id = "01J7BYKQGYV3H2WX6VVSR9EFEF"
|
||||
- what's funny is that it dies dropping a `rustc-ice-YYYY-MM-DDTHH_MM_SS-NNNNN.txt` file into your current working directory, and combined with `cargo-watch` this has the super funny effect of generating tens of those files in the treehouse repo.
|
||||
|
||||
|
||||
% id = "01J7C16RT0H84KPGJMBK1QT84E"
|
||||
- I have forgotten to remove these before checking in at least once before.
|
||||
I don't think I ever ended up pushing that commit though, so I can't show you... [but you can see the ICE I have stored in my local Git history here](/static/text/rustc-ice-2024-07-20T21_00_23-69819.txt).
|
||||
|
||||
% id = "01J7C16RT0R80J7KN516B06Q05"
|
||||
- an annoying side effect is that to fix this, I have to `^C` out of `cargo-watch`, run `cargo clean`, run `cargo-watch` again, and wait until the whole project compiles.
|
||||
|
||||
|
||||
% id = "01J7C16RT0XX4PZYRXAAV2M7P9"
|
||||
- at least it's a debug build...
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
%% title = "prefix matches with C strings"
|
||||
%% id = "b?01JCGAM553TJJCEJ96ADEWETQC"
|
||||
title = "prefix matches with C strings"
|
||||
tags = ["all", "programming", "c", "cxx"]
|
||||
|
||||
% id = "01JCGAM55352EF247HZ358BAJ8"
|
||||
- one thing I realised while reading some code at work that worked with C strings: it's surprising how easy it is to match a prefix on a C string.
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
%% title = "C++ without Classes"
|
||||
%% id = "b?01JN72M4EXSR6M120A6CW2D0X7"
|
||||
title = "C++ without Classes"
|
||||
tags = ["all", "programming", "cxx"]
|
||||
|
||||
% id = "01JN6EFWCPWY65AQ27BGFDT2DV"
|
||||
- one thing I often see in people's code in C++ is putting _everything_ into a class.
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
%% title = "C++ syntactic pitfall: access modifiers as labels"
|
||||
%% id = "b?01H9R1KJES6FC89NMC7J0FJT6P"
|
||||
title = "C++ syntactic pitfall: access modifiers as labels"
|
||||
tags = ["all", "programming", "cxx"]
|
||||
|
||||
% id = "01H9R1KJES39Z6RBCKY4E71PYD"
|
||||
- although Java and C#'s approach to symbol privacy may be verbose, it has one great advantage: it is stateless.
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
%% title = "freeing C memory automatically using `std::unique_ptr` and `std::shared_ptr`"
|
||||
%% id = "b?01J0VNHPTRNC1HFXAQ790Y1EZB"
|
||||
title = "freeing C memory automatically using `std::unique_ptr` and `std::shared_ptr`"
|
||||
tags = ["all", "programming", "cxx"]
|
||||
|
||||
% id = "01J0VN48B2E9WZ4QW0X69N2KB8"
|
||||
- say you need to interface with a C library such as SDL2 in your C++ code
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
%% title = "haku - writing a little programming language for fun"
|
||||
%% id = "b?01J4J5N6WZQ03VTB3TZ51J7QZK"
|
||||
title = "haku - writing a little programming language for fun"
|
||||
scripts = ["treehouse/vendor/codejar.js", "treehouse/components/literate-programming.js"]
|
||||
tags = ["all", "programming", "plt"]
|
||||
|
||||
% id = "01J3K8A0D1774SFDPKDK5G9GPV"
|
||||
- I've had this idea on my mind as of late, of a little pure functional programming language that would run in your browser.
|
||||
|
@ -85,7 +87,7 @@ scripts = ["treehouse/vendor/codejar.js", "treehouse/components/literate-program
|
|||
| identifier | 9 | 21 | `s-expression` |
|
||||
| ) | 21 | 22 | `)` |
|
||||
| end of file | 22 | 22 | |
|
||||
|
||||
|
||||
% id = "01J3K8A0D1GGQ292D4MQBCGHWC"
|
||||
- to lex the input into tokens, we'll need to know the input string (of course), and where we currently are in the string.
|
||||
|
||||
|
@ -185,7 +187,7 @@ scripts = ["treehouse/vendor/codejar.js", "treehouse/components/literate-program
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
printTokens(`()((()))`);
|
||||
```
|
||||
|
||||
|
@ -376,7 +378,7 @@ scripts = ["treehouse/vendor/codejar.js", "treehouse/components/literate-program
|
|||
|
||||
lexer.advance(state);
|
||||
return "error";
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
% id = "01J3K8A0D1DKA8YCBCJVZXXGR4"
|
||||
|
@ -859,7 +861,7 @@ scripts = ["treehouse/vendor/codejar.js", "treehouse/components/literate-program
|
|||
```
|
||||
|
||||
that's... the same string.
|
||||
|
||||
|
||||
% id = "01J3K8A0D1XP4FQB2HZR9GV5CJ"
|
||||
- let's try something more complicated, with comments and such.
|
||||
|
||||
|
@ -887,10 +889,10 @@ scripts = ["treehouse/vendor/codejar.js", "treehouse/components/literate-program
|
|||
|
||||
% id = "01J3K8A0D10DRSP49WF8YH5WSH"
|
||||
- of course this is hardly the _prettiest_ printer in the world.
|
||||
|
||||
|
||||
% id = "01J3K8A0D1VCJ7TV6CN7M07N5J"
|
||||
- for one, it does not even preserve your comments.
|
||||
|
||||
|
||||
% id = "01J3K8A0D1K3M9223YM96PS68B"
|
||||
- it does not add indentation either, it just blindly dumps a minimal S-expression into the console.
|
||||
|
||||
|
@ -950,7 +952,7 @@ scripts = ["treehouse/vendor/codejar.js", "treehouse/components/literate-program
|
|||
% id = "01J3K8A0D1F4R8KPHETV9N08YP"
|
||||
- it's definitely not how I would write a parser nowadays.
|
||||
it's pretty similar, but the syntax tree structures are quite different - it doesn't use the [lazy parsing][branch:01J3K8A0D1FYBKJ6X2W17QAK3Z] trick I talked about before.
|
||||
|
||||
|
||||
% id = "01J3K8A0D178J6W49AFCE9HEQ6"
|
||||
- I mean, it's only a trick I learned last year!
|
||||
|
||||
|
@ -1008,7 +1010,7 @@ scripts = ["treehouse/vendor/codejar.js", "treehouse/components/literate-program
|
|||
```
|
||||
|
||||
for now we'll leave it empty.
|
||||
|
||||
|
||||
% id = "01J3NVV2RX2T5K473GGY3K5VBX"
|
||||
- in the meantime, let's prepare a couple convenient little wrappers to run our code:
|
||||
|
||||
|
@ -1092,7 +1094,7 @@ scripts = ["treehouse/vendor/codejar.js", "treehouse/components/literate-program
|
|||
{:program=haku}
|
||||
```javascript
|
||||
export const builtins = {};
|
||||
|
||||
|
||||
treewalk.eval = (state, node) => {
|
||||
switch (node.kind) {
|
||||
case "integer":
|
||||
|
@ -1862,7 +1864,7 @@ scripts = ["treehouse/vendor/codejar.js", "treehouse/components/literate-program
|
|||
|
||||
{:program=haku}
|
||||
```javascript
|
||||
treewalk.eval = (state, node) => {
|
||||
treewalk.eval = (state, node) => {
|
||||
switch (node.kind) {
|
||||
case "integer":
|
||||
let sourceString = state.input.substring(node.start, node.end);
|
||||
|
@ -2032,7 +2034,7 @@ scripts = ["treehouse/vendor/codejar.js", "treehouse/components/literate-program
|
|||
throw new Error(`unhandled node kind: ${node.kind}`);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
builtins.fn = (state, node) => {
|
||||
if (node.children.length != 3)
|
||||
throw new Error("an `fn` must have an argument list and a result expression");
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
%% title = "JavaScript is not as bad as people make it out to be"
|
||||
%% id = "b?01J293BFEBT15W0Z3XF1HEFGZT"
|
||||
title = "JavaScript is not as bad as people make it out to be"
|
||||
scripts = [
|
||||
"treehouse/components/literate-programming.js",
|
||||
"treehouse/vendor/codejar.js",
|
||||
]
|
||||
tags = ["all", "programming", "javascript", "plt"]
|
||||
|
||||
% id = "01J291S06DS12DCFTNKJ27BNSQ"
|
||||
- _ooh I'm sure this one is gonna be really controversial but here I go_
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
%% title = "Lua - a scripting language you can like"
|
||||
%% id = "b?01HRG3VN091V715A8T54QK5PVX"
|
||||
title = "Lua - a scripting language you can like"
|
||||
tags = ["all", "programming", "plt", "lua"]
|
||||
|
||||
% id = "01HRG2RJC1BATZJSGSSSF1XNFZ"
|
||||
- TODO: this page could really use an interactive Lua interpreter. can we have that?
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
title = "Classes in Lua"
|
||||
id = "b?01JKKQZRSG5ZRNH530D75E2660"
|
||||
tags = ["all", "programming", "lua"]
|
||||
|
||||
+++
|
||||
|
||||
|
|
|
@ -301,7 +301,7 @@ local Player = Entity:inherit()
|
|||
```lua
|
||||
local Cat = {}
|
||||
-- We still need to override __index, so that the metatable we set in our own constructor
|
||||
-- has our overridden `speak()` method.
|
||||
-- has our overridden `speak()` method.
|
||||
Cat.__index = Cat
|
||||
-- To be able to call `Animal` methods from `Cat`, we set it as its metatable.
|
||||
-- Remember that `Animal.__index == Animal`.
|
||||
|
@ -380,7 +380,7 @@ local Player = Entity:inherit()
|
|||
-- insert below the `end` of `function Class:inherit()`
|
||||
|
||||
-- By default, let's make the base `Class` impossible to instantiate.
|
||||
-- This should catch bugs if a subclass forgets to override `initialize`.
|
||||
-- This should catch bugs if a subclass forgets to override `initialize`.
|
||||
function Class:initialize()
|
||||
error("this class cannot be initialized")
|
||||
end
|
||||
|
@ -462,7 +462,7 @@ local Player = Entity:inherit()
|
|||
|
||||
% id = "01JKKQHG5DQW7G1HDWYGX4WEYC"
|
||||
- our class library implements a Ruby-style `Object:new(args)` function for constructing new instances of our class.
|
||||
Python however, uses the syntax `Object(args)` for constructing instances of objects.
|
||||
Python however, uses the syntax `Object(args)` for constructing instances of objects.
|
||||
can you think of a way to make our class library use the Python-style syntax?
|
||||
|
||||
% id = "01JKKQHG5D7QN029A3F1B6SYC2"
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
%% title = "places, or what is up with `*x` not always meaning the same thing in different contexts"
|
||||
%% id = "b?01HY5R1ZW2PYZSSP2J2KAA23DA"
|
||||
title = "places, or what is up with `*x` not always meaning the same thing in different contexts"
|
||||
tags = ["all", "programming", "c", "cxx", "plt"]
|
||||
|
||||
% id = "01HY5R1ZV9DD7BV0F66Y0DHAEA"
|
||||
- I recently got a question from my someone telling me they doesn't understand why `*x` does not read from the pointer `x` when on the left-hand side of an assignment.
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
%% title = "on changing the Firefox New Tab, and software freedom"
|
||||
%% id = "b?01JX0GYB1D4W3A6FRPBG738N4F"
|
||||
title = "on changing the Firefox New Tab, and software freedom"
|
||||
tags = ["all", "programming"]
|
||||
|
||||
% id = "01JX0G5CN5H8S7S3M4619R112A"
|
||||
- the date is 4th of June, 2025.
|
||||
|
@ -69,7 +71,7 @@
|
|||
"chrome_settings_overrides": {
|
||||
"homepage": "index.html"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
% id = "01JX0G5CN5SSANM732FB8M6ZSV"
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
%% title = "OR-types"
|
||||
%% id = "b?01HTWNETT2S5NSBF3QR4HYA7HN"
|
||||
title = "OR-types"
|
||||
tags = ["all", "programming", "plt"]
|
||||
|
||||
% id = "01HTWN4XAD7C41X8XKRBFZMHJ8"
|
||||
- last night I couldn't fall asleep because I was thinking how sites like [Anilist](https://anilist.co) implement their tag-based search systems.
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
%% title = "systems are just a bunch of code"
|
||||
%% id = "b?01HV1DGFHZ65GJVQRSREKR67J9"
|
||||
title = "systems are just a bunch of code"
|
||||
tags = ["all", "programming", "shower"]
|
||||
|
||||
% id = "01HV1DGFGNV3DXD8A3CW2J4RZP"
|
||||
- often enough I see people scared to dive deep into the internals of their favorite technologies
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
%% title = "tairu - an interactive exploration of 2D autotiling techniques"
|
||||
%% id = "b?01HQ6G30PTVT5H0Z04VVRHEZQF"
|
||||
title = "tairu - an interactive exploration of 2D autotiling techniques"
|
||||
scripts = [
|
||||
"treehouse/components/literate-programming.js",
|
||||
"treehouse/vendor/codejar.js",
|
||||
]
|
||||
styles = ["page/tairu.css"]
|
||||
tags = ["all", "programming", "graphics", "javascript"]
|
||||
|
||||
% id = "01HPD4XQPWM8ECT2QM6AT9YRWB"
|
||||
- I remember since my early days doing programming, I've been interested in how games like Terraria handle automatically tiling their terrain.
|
||||
|
@ -209,7 +211,7 @@ styles = ["page/tairu.css"]
|
|||
borderWidth: 4,
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
{:program=tairu :placeholder=01HQ49TJZFMK719KSE16SG3F7B}
|
||||
```output
|
||||
```
|
||||
|
@ -436,7 +438,7 @@ styles = ["page/tairu.css"]
|
|||
```
|
||||
|
||||
{:program=tairu :placeholder=01HQ49X8Z57FNMN3E79FYF8CMG}
|
||||
```output
|
||||
```output
|
||||
```
|
||||
|
||||
% id = "01HQ162WWA03JAGJYCT0DRZP24"
|
||||
|
@ -461,7 +463,7 @@ styles = ["page/tairu.css"]
|
|||
```
|
||||
|
||||
{:program=tairu :placeholder=01HQ49YDPQXYSAT5N6P241DG3C}
|
||||
```output
|
||||
```output
|
||||
```
|
||||
|
||||
% id = "01HQ162WWAB0AYSPGB4AEVT03Z"
|
||||
|
@ -490,7 +492,7 @@ styles = ["page/tairu.css"]
|
|||
```
|
||||
|
||||
{:program=tairu :placeholder=01HQ49Z8JWR75D85DGHCB34K8E}
|
||||
```output
|
||||
```output
|
||||
```
|
||||
|
||||
% id = "01HQ1K39AS4VDW7DVTAGQ03WFM"
|
||||
|
@ -514,7 +516,7 @@ styles = ["page/tairu.css"]
|
|||
% classes.branch = "tileset-four-to-eight-demo"
|
||||
id = "01HQ1K39ASR81NWMW8Q0MF8QMP"
|
||||
- enhance!
|
||||
|
||||
|
||||
{% NOTE djot: I don't there's a way to achieve this in Djot alone %}
|
||||
``` =html
|
||||
<ul class="directions-square bend">
|
||||
|
@ -599,7 +601,7 @@ styles = ["page/tairu.css"]
|
|||
```
|
||||
|
||||
{:program=tairu :placeholder=01HQ4A01MPE6JT5ZZFEN9S635W}
|
||||
```output
|
||||
```output
|
||||
```
|
||||
|
||||
% id = "01HQ1K39AS7CRBZ67N1VVHCVME"
|
||||
|
@ -953,7 +955,7 @@ styles = ["page/tairu.css"]
|
|||
```
|
||||
|
||||
{:program=tairu :placeholder=01HQ4A11RRXEQ850598GFBJN0B}
|
||||
```output
|
||||
```output
|
||||
```
|
||||
|
||||
% id = "01HQ1M84GSCXTPGVPXY840WCQ6"
|
||||
|
@ -984,7 +986,7 @@ new TilesetTileEditor({
|
|||
```
|
||||
|
||||
{:program=tairu :placeholder=01HQ4A45WNAEJGCT2WDMQJHK14}
|
||||
```output
|
||||
```output
|
||||
```
|
||||
|
||||
:nap: <!--
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
%% title = "composable virtual file systems"
|
||||
%% id = "b?01JDJJSEWASRWJGKMBNYMFD9B5"
|
||||
title = "composable virtual file systems"
|
||||
tags = ["programming", "treehouse"]
|
||||
|
||||
% id = "01JDJGVC7BRZDSYTZCH0S357B8"
|
||||
- you know what I hate?
|
||||
|
@ -92,7 +94,7 @@ like... you know. a _virtual_ file system?
|
|||
|
||||
% id = "01JDJGVC7BPEW2NAT7XSB5F97E"
|
||||
- first of all, from the perspective of the program, do we _really_ need to differentiate between directories and files?
|
||||
|
||||
|
||||
% id = "01JDJGVC7BHQWZDS17DY0096F6"
|
||||
- from a GUI design standpoint, they're a useful abstraction for us humans---the more concrete an object, the easier it is to grasp.
|
||||
_files_ and _folders_ seem a lot more easy to grasp than abstract _entries_ which _may_ represent documents, folders, or both.
|
||||
|
@ -201,7 +203,7 @@ like... you know. a _virtual_ file system?
|
|||
% id = "01JDJGVC7BQZAY4TP1WG5N6QR3"
|
||||
- having a design in mind, I thought it would be interesting to integrate it into a real project.
|
||||
the treehouse seemed like the right thing to test it out on, since it's effectively a compiler---it transforms a set of source directories into a target directory.
|
||||
|
||||
|
||||
% id = "01JDJH59SN5219QPGJPZS7FMA6"
|
||||
- and I have to say: so far, I'm liking it!
|
||||
|
||||
|
@ -339,23 +341,23 @@ like... you know. a _virtual_ file system?
|
|||
`Edit`s take many shapes and forms, but the most important one for us is `Write`: it allows you to write a file to the disk.
|
||||
|
||||
the other ones are for composing `Edit`s together into larger ones.
|
||||
|
||||
|
||||
% id = "01JDJGVC7BCT46CXXVKMXATAA3"
|
||||
- `Seq` can be used to implement transactions, where all edits have to succeed for the parent edit to be considered successful.
|
||||
|
||||
% id = "01JDJHDZ8XWEZAA94AW1VS4P53"
|
||||
- I use this for writing backups.
|
||||
if writing a backup fails, we wouldn't want to overwrite the original file, because we wouldn't be able to restore it!
|
||||
|
||||
|
||||
% id = "01JDJGVC7B05H6079QHXAXC8Y4"
|
||||
- `All` can be used to aggregate independent edits together and execute them in parallel.
|
||||
|
||||
|
||||
% id = "01JDJGVC7BKXXJSWYTGX7XA979"
|
||||
- `Dry` can be used to implement a `--dry-run` command, only printing an edit instead of applying it.
|
||||
|
||||
% id = "01JDJGVC7B7MNC3CA5DEP1HXM6"
|
||||
+ `NoOp` can be used when you need to produce an `Edit`, but don't actually want to perform any operations.
|
||||
|
||||
|
||||
% id = "01JDJGVC7BJRSMS1E4NQRVZ1H2"
|
||||
- this runs contrary to [my opinion on `None` enums][branch:01HCG7KTGGAFS07QYJXZG6WHJJ], for one reason: would you rather have to handle `Option<Edit>` everywhere, or just assume whatever `Edit` you're being passed is valid?
|
||||
|
||||
|
@ -373,7 +375,7 @@ like... you know. a _virtual_ file system?
|
|||
|
||||
% id = "01JDJGVC7BGJQXTVZ6Z9BK12BG"
|
||||
- of course then you cannot create directories.
|
||||
|
||||
|
||||
% id = "01JDJGVC7B2JTWKJVEE1VP6P68"
|
||||
- also, [TOCTOU](https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use) bugs are a thing, but I disregard those as they don't really fit into a compiler's threat model.
|
||||
|
||||
|
@ -389,7 +391,7 @@ like... you know. a _virtual_ file system?
|
|||
|
||||
% id = "01JDJGVC7BCG0W3SWSYR647ZCC"
|
||||
- `TreehouseDir` is a file system which renders `.tree` files into HTML lazily.
|
||||
|
||||
|
||||
% id = "01JDJGVC7BBJCR1TQCBKBHMBNS"
|
||||
- since generating all this HTML is an expensive operation, I have it wrapped in a `ContentCache` adapter, which caches any successfully generated pages in memory.
|
||||
|
||||
|
@ -452,7 +454,7 @@ like... you know. a _virtual_ file system?
|
|||
|
||||
% id = "01JDJGVC7BVV81GF2GRTQVCK7E"
|
||||
- there is one flaw I want to point out with the current implementation of `Dir`: it uses trait methods to add new resource forks.
|
||||
|
||||
|
||||
% id = "01JDJGVC7BJS79G1VJN1G29GRK"
|
||||
- any time you add a new resource fork that's implemented only by one or two `Dir`s, you have to duplicate a stub across all existing adapters!
|
||||
this means introducing a new fork means performing up to `N` edits, where `N` is the number of implementers of `Dir`.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue