1
Fork 0
mirror of https://github.com/RGBCube/Site synced 2025-07-30 20:47:46 +00:00

lume: move to 3.0

This commit is contained in:
RGBCube 2025-05-29 01:19:31 +03:00
parent f49df20c46
commit 7974d7a806
Signed by: RGBCube
SSH key fingerprint: SHA256:CzqbPcfwt+GxFYNnFVCqoN5Itn4YFrshg1TrnACpA5M
15 changed files with 1142 additions and 4323 deletions

File diff suppressed because it is too large Load diff

View file

@ -15,9 +15,11 @@ and the site contents will be under the `_site/` directory.
## License ## License
All the human writing (non-HTML and not templating related) under the `site/` All the human writing (non-HTML and not templating related) under the `site/`
directory is licensed under [CC BY-NC-ND 4.0](https://creativecommons.org/licenses/by-nc-nd/4.0/). directory is licensed under
[CC BY-NC-ND 4.0](https://creativecommons.org/licenses/by-nc-nd/4.0/).
The other HTML and templating code is licensed under the GPU General Public License (`LICENSE_GPL.md`): The other HTML and templating code is licensed under the GPU General Public
License (`LICENSE_GPL.md`):
``` ```
Copyright (C) 2023-present RGBCube Copyright (C) 2023-present RGBCube

View file

@ -9,12 +9,15 @@ import sitemap from "lume/plugins/sitemap.ts";
const site = lume({ const site = lume({
src: "./site", src: "./site",
server: {
debugBar: false,
},
}); });
site.use(codeHighlight()); site.add(".");
site.use(esbuild());
site.use(jsx()); site.use(jsx());
site.use(minifyHTML());
site.process([".html"], (pages) => { site.process([".html"], (pages) => {
pages.forEach((page) => { pages.forEach((page) => {
@ -30,7 +33,7 @@ site.process([".html"], (pages) => {
div.appendChild(table); div.appendChild(table);
}); });
document.querySelectorAll(".hljs").forEach((code) => { document.querySelectorAll("pre code").forEach((code) => {
const pre = code.parentElement!; const pre = code.parentElement!;
const div = document.createElement("div"); const div = document.createElement("div");
@ -66,10 +69,14 @@ site.use(feed({
})); }));
site.use(sitemap({ site.use(sitemap({
// @ts-ignore: We don't want lastmods. items: {
lastmod: null, // @ts-ignore: We don't want lastmods.
lastmod: null,
},
})); }));
site.copyRemainingFiles(); site.use(esbuild());
site.use(codeHighlight());
site.use(minifyHTML());
export default site; export default site;

View file

@ -1,18 +1,24 @@
{ {
"compilerOptions": { "compilerOptions": {
"jsx": "react-jsx", "jsx": "react-jsx",
"jsxImportSource": "npm:react", "jsxImportSource": "lume",
"types": [ "types": [
"lume/types.ts", "lume/types.ts"
"https://unpkg.com/@types/react@18.2.37/index.d.ts"
] ]
}, },
"tasks": { "tasks": {
"build": "echo \"import 'lume/cli.ts'\" | deno run --allow-all -", "lume": "echo \"import 'lume/cli.ts'\" | deno run --allow-all -",
"serve": "deno task build --serve" "build": "deno task lume",
"serve": "deno task lume --serve"
}, },
"imports": { "imports": {
"std/": "https://deno.land/std@0.217.0/", "std/": "https://deno.land/std@0.217.0/",
"lume/": "https://deno.land/x/lume@v2.1.0/" "lume/": "https://deno.land/x/lume@v3.0.2/",
"lume/jsx-runtime": "https://deno.land/x/ssx@v0.1.9/jsx-runtime.ts"
},
"lint": {
"plugins": [
"https://deno.land/x/lume@v3.0.1/lint.ts"
]
} }
} }

3780
deno.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,3 @@
import React, { ReactNode as Node } from "npm:react";
const empty: Node = <></>;
interface CubeProps { interface CubeProps {
front?: Node; front?: Node;
back?: Node; back?: Node;
@ -105,12 +101,12 @@ const Cube = (props: CubeProps) => (
<div className="scene"> <div className="scene">
<div className="cube"> <div className="cube">
<div className="face front">{props.front || empty}</div> <div className="face front">{props.front}</div>
<div className="face back">{props.back || empty}</div> <div className="face back">{props.back}</div>
<div className="face left">{props.left || empty}</div> <div className="face left">{props.left}</div>
<div className="face right">{props.right || empty}</div> <div className="face right">{props.right}</div>
<div className="face top">{props.top || empty}</div> <div className="face top">{props.top}</div>
<div className="face bottom">{props.bottom || empty}</div> <div className="face bottom">{props.bottom}</div>
</div> </div>
</div> </div>

View file

@ -5,26 +5,27 @@ title: About
## Hi. ## Hi.
I'm yet another high schooler that is interested in programming. I'm yet another high schooler that is interested in programming. I'm from
I'm from Türkiye 🇹🇷. Türkiye 🇹🇷.
I primarily use [Rust](https://rust-lang.org) and I primarily use [Rust](https://rust-lang.org) and also know quite a bit of
also know quite a bit of Python, [**Nix**](https://nixos.org/), Python, [**Nix**](https://nixos.org/), [Nushell](https://nushell.sh/), a little
[Nushell](https://nushell.sh/), a little bit of Java, Kotlin, Go, bit of Java, Kotlin, Go, and JavaScript (No frameworks, though!).
and JavaScript (No frameworks, though!).
I created this site using [Lume](https://lume.land/). It is served I created this site using [Lume](https://lume.land/). It is served by Nginx on
by Nginx on my small VPS that runs [NixOS](https://nixos.org/). my small VPS that runs [NixOS](https://nixos.org/).
I also host other services like Synapse (Matrix homeserver), Forgejo, I also host other services like Synapse (Matrix homeserver), Forgejo, Nextcloud
Nextcloud and Grafana on the VPS, which are all configured using Nix. and Grafana on the VPS, which are all configured using Nix.
Historically, this blog was made using Rust, [Axum](https://lib.rs/crates/axum), Historically, this blog was made using Rust, [Axum](https://lib.rs/crates/axum),
[Maud](https://maud.lambda.xyz/) and a bunch of other neat crates (some which [Maud](https://maud.lambda.xyz/) and a bunch of other neat crates (some which I
I created, like [embd-rs](https://github.com/RGBCube/embd-rs), which sped up created, like [embd-rs](https://github.com/RGBCube/embd-rs), which sped up
development). But I decided to abandon this strategy as I was reinventing too much development). But I decided to abandon this strategy as I was reinventing too
for just a simple static website. Development was also *really* slow on a i5 from much for just a simple static website. Development was also _really_ slow on a
2015 so I decided to ditch it and use Lume. i5 from 2015 so I decided to ditch it and use Lume.
Here is the up to date [GitHub repository for said site](https://github.com/RGBCube/Site), Here is the up to date
and here is the [historical version written in Rust](https://github.com/RGBCube/Site/tree/rust-legacy). [GitHub repository for said site](https://github.com/RGBCube/Site), and here is
the
[historical version written in Rust](https://github.com/RGBCube/Site/tree/rust-legacy).

View file

@ -156,7 +156,7 @@ const handleMove = (event: MouseEvent) => {
const newMouse = new Vec3(event.clientX, event.clientY, 0); const newMouse = new Vec3(event.clientX, event.clientY, 0);
const timeDelta = (window.performance.now() - mouse.lastMove) / 1000; const timeDelta = (globalThis.performance.now() - mouse.lastMove) / 1000;
if (timeDelta > 0.1) { if (timeDelta > 0.1) {
// This is a fresh scroll. // This is a fresh scroll.
@ -166,7 +166,7 @@ const handleMove = (event: MouseEvent) => {
const delta = Vec3.sub(newMouse, mouse.previous); const delta = Vec3.sub(newMouse, mouse.previous);
mouse.previous = newMouse; mouse.previous = newMouse;
mouse.lastMove = window.performance.now(); mouse.lastMove = globalThis.performance.now();
const axis = new Vec3(-delta.y, delta.x, 0) const axis = new Vec3(-delta.y, delta.x, 0)
.normalize() .normalize()
@ -221,7 +221,7 @@ const updateFrame = (timestamp: number) => {
velocity.z = 0; velocity.z = 0;
} }
if (window.performance.now() - mouse.lastMove > 10000) { if (globalThis.performance.now() - mouse.lastMove > 10000) {
const impulse = new Vec3(0.7, 0.7, -0.7); const impulse = new Vec3(0.7, 0.7, -0.7);
velocity = Vec3.sum(impulse.scale(effectiveDelta * 3), velocity); velocity = Vec3.sum(impulse.scale(effectiveDelta * 3), velocity);
} }

View file

@ -9,17 +9,18 @@ tags:
- unix-timestamps - unix-timestamps
--- ---
So, every day I wake up at 6:55, get dressed by 7, walk to the bus stop So, every day I wake up at 6:55, get dressed by 7, walk to the bus stop by 7:13
by 7:13 and board the bus around 7:17. Today was different. and board the bus around 7:17. Today was different.
My alarm that I have set for 6:55 rang at 7:12 and as a result, I missed the bus. My alarm that I have set for 6:55 rang at 7:12 and as a result, I missed the
bus.
> No, I didn't sleep in. There was no note in the UI saying this was a repeat alarm, > No, I didn't sleep in. There was no note in the UI saying this was a repeat
> which there is if you snooze it or let it expire. > alarm, which there is if you snooze it or let it expire.
Surely something was happening. Machines don't break whenever they want, they're Surely something was happening. Machines don't break whenever they want, they're
mostly deterministic. And I doubt Samsung engineers wrote code to delay the alarm mostly deterministic. And I doubt Samsung engineers wrote code to delay the
by 12 minutes on the date after April 1st. alarm by 12 minutes on the date after April 1st.
So, _what_ was happening? I entered the Python repl to test out a theory: So, _what_ was happening? I entered the Python repl to test out a theory:
@ -33,8 +34,8 @@ So, _what_ was happening? I entered the Python repl to test out a theory:
The total time was off by about 1020 seconds. Give or take 60, as my phone The total time was off by about 1020 seconds. Give or take 60, as my phone
doesn't display the seconds of the time. doesn't display the seconds of the time.
> Since I'm using a Samsung SM-B310E, I assumed it uses seconds to store > Since I'm using a Samsung SM-B310E, I assumed it uses seconds to store the
> the time. You can't even see seconds noted anywhere so I feel this is a normal > time. You can't even see seconds noted anywhere so I feel this is a normal
> assumption. Even if it is false, the math still adds up for milliseconds. > assumption. Even if it is false, the math still adds up for milliseconds.
Wow, I thought. That's really close to 1024 (which is 2 to the power of 10). Wow, I thought. That's really close to 1024 (which is 2 to the power of 10).
@ -50,13 +51,15 @@ Maybe the 11th bit got flipped, making it increment 1024?
-4 -4
``` ```
Aha! So the 11th bit got flipped by something. And that something was probably Aha! So the 11th bit got flipped by something. And that something was probably a
a cosmic ray. cosmic ray.
EDIT: It was not a cosmic ray. As pointed out by [@BenjaminRi's comment on lobste.rs](https://lobste.rs/s/jb1o6q/cosmic_drift#c_1ztluj) EDIT: It was not a cosmic ray. As pointed out by
it was either a bug or storage corruption as the alarm ran late the next day. You should [@BenjaminRi's comment on lobste.rs](https://lobste.rs/s/jb1o6q/cosmic_drift#c_1ztluj)
still create more than one alarm just in case if you are using a phone prone to this, however. it was either a bug or storage corruption as the alarm ran late the next day.
You should still create more than one alarm just in case if you are using a
phone prone to this, however.
My main takeaway from this event is to create more than one alarm, for extra redundancy. My main takeaway from this event is to create more than one alarm, for extra
Who knew being prone to sleeping in could save you from your alarm getting redundancy. Who knew being prone to sleeping in could save you from your alarm
shifted 12 minutes into the future :^). getting shifted 12 minutes into the future :^).

View file

@ -11,11 +11,11 @@ tags:
- vcs - vcs
--- ---
You just started a new project. You ran `cargo init`, You just started a new project. You ran `cargo init`, `poetry init` and
`poetry init` and `go mod init`. `go mod init`.
Those commands created the necessary files to work, it Those commands created the necessary files to work, it also added the following
also added the following lines to your .gitignore: lines to your .gitignore:
```text ```text
target target
@ -23,27 +23,23 @@ __pycache__
bin bin
``` ```
All great. You continue implementing features, and when All great. You continue implementing features, and when the time comes, you
the time comes, you publish your project to your Git publish your project to your Git hosting platform of choice.
hosting platform of choice.
People start to get interested in your project. One even People start to get interested in your project. One even decides that he's going
decides that he's going to implement a new feature! to implement a new feature! Literally free work done for you!
Literally free work done for you!
Alright. That person uses his code editor and tools bundled Alright. That person uses his code editor and tools bundled with his operating
with his operating system to implement a very cool system to implement a very cool new feature. He then submits the merge request.
new feature. He then submits the merge request.
You start reviewing the code and notice a file quite You start reviewing the code and notice a file quite out of place: `.DS_Store`.
out of place: `.DS_Store`. You ask the person what You ask the person what it is, he says he has no clue.
it is, he says he has no clue.
![Hundreds of thousands of merge requests on GitHub trying ![Hundreds of thousands of merge requests on GitHub trying
to gitignore .DS_Store](/assets/github-ds-store-mr-list.webp) to gitignore .DS_Store](/assets/github-ds-store-mr-list.webp)
Whatever. You just delete the file from the branch and Whatever. You just delete the file from the branch and add the file's name to
add the file's name to the repositories gitignore: the repositories gitignore:
```text ```text
target target
@ -52,15 +48,13 @@ bin
.DS_Store .DS_Store
``` ```
Nice. Now the code is on master, and your repository only contains relevant
information.
Nice. Now the code is on master, and your repository Then, someone using an IDE created using web technologies submits another merge
only contains relevant information. request. You look at it, and see that there is a whole directory that is
irrelevant. You tell that person to delete the directory from the branch and add
Then, someone using an IDE created using web technologies it to the gitignore. The gitignore lives on:
submits another merge request. You look at it, and
see that there is a whole directory that is irrelevant.
You tell that person to delete the directory from the
branch and add it to the gitignore. The gitignore lives on:
```text ```text
target target
@ -70,8 +64,8 @@ bin
.vscode .vscode
``` ```
Then, someone that uses IntelliJ IDEA commits five hundred Then, someone that uses IntelliJ IDEA commits five hundred XML files and the
XML files and the `.idea` directory. You repeat this process: `.idea` directory. You repeat this process:
```text ```text
target target
@ -82,27 +76,24 @@ bin
.idea .idea
``` ```
Years pass. Now your gitignore is hundreds of lines long, Years pass. Now your gitignore is hundreds of lines long, yet people keep
yet people keep accidentally committing in test scripts, accidentally committing in test scripts, foo, a, qux, data.tar.gz, start.sh,
foo, a, qux, data.tar.gz, start.sh, bin-release, bin-release, cat, asd, fgsgskfh.
cat, asd, fgsgskfh.
Hell. You feel like a mythic god undergoing punishment Hell. You feel like a mythic god undergoing punishment for cheating death and
for cheating death and deceiving the underworld. deceiving the underworld.
![Sisyphus pushing up a boulder that has .DS_Store written ![Sisyphus pushing up a boulder that has .DS_Store written
on it](/assets/sisyphus-ds-store.webp) on it](/assets/sisyphus-ds-store.webp)
How do you escape this endless loop of ignoring files How do you escape this endless loop of ignoring files that sneak in? Maybe by
that sneak in? Maybe by educating every single merge educating every single merge request author? Nope, that definitely won't work,
request author? Nope, that definitely won't work, there there should be a way to automatically handle this with tooling, rather than
should be a way to automatically handle this with tooling, subjective human communication.
rather than subjective human communication.
Luckily, you realize that you can turn the blacklist Luckily, you realize that you can turn the blacklist of files (the gitignore) to
of files (the gitignore) to a whitelist, by just a whitelist, by just ignoring everything and manually un-ignoring desired files.
ignoring everything and manually un-ignoring desired You change your gitignore to this:
files. You change your gitignore to this:
```text ```text
* *
@ -123,12 +114,10 @@ files. You change your gitignore to this:
!docs/*.md !docs/*.md
``` ```
Now, nobody can accidentally commit undesired files, Now, nobody can accidentally commit undesired files, as git automatically
as git automatically ignores them all and only ignores them all and only allows the files that are explicitly whitelisted. It's
allows the files that are explicitly whitelisted. also future proof, future proof until an IDE decides to use the `src/ide.rs`
It's also future proof, future proof until an IDE file as a convenient way of storing project specific configuration. And
decides to use the `src/ide.rs` file as a convenient hopefully that future never comes.
way of storing project specific configuration.
And hopefully that future never comes.
You feel relieved. You feel relieved.

View file

@ -9,9 +9,9 @@ tags:
- nix - nix
--- ---
So, you may have seen the [HTMNIX](https://github.com/RGBCube/HTMNIX) project I've So, you may have seen the [HTMNIX](https://github.com/RGBCube/HTMNIX) project
been working on the last few weeks. If not, no worries. Here is a Nix snippet I've been working on the last few weeks. If not, no worries. Here is a Nix
that uses it: snippet that uses it:
```nix ```nix
<html> <html>
@ -26,7 +26,8 @@ that uses it:
<.html> <.html>
``` ```
> (hightlight.js shits the bed while highlighting this abomination - just ignore it) > (hightlight.js shits the bed while highlighting this abomination - just ignore
> it)
You are probably thinking furiously right now, maybe you've noticed something: You are probably thinking furiously right now, maybe you've noticed something:
@ -36,11 +37,13 @@ You are probably thinking furiously right now, maybe you've noticed something:
> import <nixpkgs> {} > import <nixpkgs> {}
> ``` > ```
> >
> That means you have to add hundreds of elements to your Nix Path to make this work? > That means you have to add hundreds of elements to your Nix Path to make this
> work?
You are somewhat correct. But not quite. You are somewhat correct. But not quite.
Nix `<foo>` expressions actually boil down to a call of the builtin `__findFile`, like so: Nix `<foo>` expressions actually boil down to a call of the builtin
`__findFile`, like so:
```shell ```shell
nix-instantiate --parse --expr "<foo>" nix-instantiate --parse --expr "<foo>"
@ -48,11 +51,13 @@ Nix `<foo>` expressions actually boil down to a call of the builtin `__findFile`
(__findFile __nixPath "foo") (__findFile __nixPath "foo")
``` ```
> In case you didn't know, [`nix-instantiate`](https://nixos.org/manual/nix/stable/command-ref/nix-instantiate.html) > In case you didn't know,
> is a nice tool to see what your Nix code is desugared and un-precedence'd into. > [`nix-instantiate`](https://nixos.org/manual/nix/stable/command-ref/nix-instantiate.html)
> is a nice tool to see what your Nix code is desugared and un-precedence'd
> into.
Aha! So this means we can override the builtin `__findFile` and put whatever we would like in Aha! So this means we can override the builtin `__findFile` and put whatever we
its place. So this will work: would like in its place. So this will work:
```nix ```nix
let let
@ -63,14 +68,16 @@ in
<foo> <foo>
``` ```
Evaluating this (by running `nix eval -f test.nix`), we get `{ content = "<foo>"; }` Evaluating this (by running `nix eval -f test.nix`), we get
`{ content = "<foo>"; }`
So, then. How do we make it work for multiple tags, all coming after one another So, then. How do we make it work for multiple tags, all coming after one another
(and attribute sets, strings, etc.)? (and attribute sets, strings, etc.)?
Another hack! We need to set the [magic `__functor` attribute](https://noogle.dev/md/tutorials/functors) Another hack! We need to set the
of the attrset we return, so we can call our set and have it store the tags inside it (while also [magic `__functor` attribute](https://noogle.dev/md/tutorials/functors) of the
preserving its callability!). attrset we return, so we can call our set and have it store the tags inside it
(while also preserving its callability!).
We can do that like so: We can do that like so:
@ -88,9 +95,11 @@ in
"baz" "baz"
``` ```
Great news! When we evaluate this, we get `{ __functor = <LAMBDA>; content = "<foo>barbaz"; }`. Great news! When we evaluate this, we get
`{ __functor = <LAMBDA>; content = "<foo>barbaz"; }`.
We can also add a case to check if the next element is a tag, and use its content if it is: We can also add a case to check if the next element is a tag, and use its
content if it is:
```nix ```nix
let let
@ -107,8 +116,9 @@ in
<endfoo> <endfoo>
``` ```
Enter another hack! We can utilize the `outPath` property that exists on derivations Enter another hack! We can utilize the `outPath` property that exists on
and gets returned whenever you call `toString` with an attrset that has the property to make our code a little simpler: derivations and gets returned whenever you call `toString` with an attrset that
has the property to make our code a little simpler:
```nix ```nix
let let
@ -128,15 +138,17 @@ in
We also got support for other types for free, as well! We also got support for other types for free, as well!
These are all the hidden builtins that [HTMNIX](https://github.com/RGBCube/HTMNIX) depends on These are all the hidden builtins that
and extends upon, making HTML in Nix an actually usable reality. It also [HTMNIX](https://github.com/RGBCube/HTMNIX) depends on and extends upon, making
has extra logic like turning attribute sets into HTML tags, which is fairly trivial HTML in Nix an actually usable reality. It also has extra logic like turning
compared to actaully discovering these hidden builtins in the first place. attribute sets into HTML tags, which is fairly trivial compared to actaully
discovering these hidden builtins in the first place.
You can read more about it in the project's README and You can read more about it in the project's README and see
see [an example site using it](https://github.com/RGBCube/NixSite). [an example site using it](https://github.com/RGBCube/NixSite).
I might even try to port this site to HTMNIX to ensure it is usable with more complex setups :-) I might even try to port this site to HTMNIX to ensure it is usable with more
complex setups :-)
Soon, maybe... Soon, maybe...

View file

@ -9,8 +9,7 @@ tags:
- nix - nix
--- ---
I was surfing the web a few weeks ago, and I came across I was surfing the web a few weeks ago, and I came across this iceberg chart:
this iceberg chart:
![The Nix Iceberg](/assets/nix-iceberg.webp) ![The Nix Iceberg](/assets/nix-iceberg.webp)
@ -18,8 +17,8 @@ this iceberg chart:
created by @leftpaddotpy, @puckipedia, created by @leftpaddotpy, @puckipedia,
@wiggles and @qyriad on cohost.](https://cohost.org/leftpaddotpy/post/3885451-the-nix-iceberg) @wiggles and @qyriad on cohost.](https://cohost.org/leftpaddotpy/post/3885451-the-nix-iceberg)
In this post, I'll be explaining every item in this In this post, I'll be explaining every item in this iceberg with sufficient
iceberg with sufficient depth. Let's start: depth. Let's start:
# Tier 1: I use NixOS (BTW) # Tier 1: I use NixOS (BTW)
@ -27,8 +26,7 @@ iceberg with sufficient depth. Let's start:
> IFD stands for import-from-derivation. > IFD stands for import-from-derivation.
IFD is when you import a Nix expression IFD is when you import a Nix expression from a derivation in the Nix store.
from a derivation in the Nix store.
For example: For example:
@ -49,19 +47,19 @@ This will evaluate to `"b"`.
So, what are we doing in this snippet? So, what are we doing in this snippet?
1. Importing `<nixpkgs>` and getting the packages out of it. 1. Importing `<nixpkgs>` and getting the packages out of it.
2. Creating a derivation that runs an echo command, which 2. Creating a derivation that runs an echo command, which writes a Nix
writes a Nix expression to the output file. expression to the output file.
3. Then we import the expression, forcing the derivation to 3. Then we import the expression, forcing the derivation to be realized as we
be realized as we accessed the contents of it. accessed the contents of it.
> Wait, what does _realization_ mean? > Wait, what does _realization_ mean?
It means to actually build a `.drv` file, using the builder, It means to actually build a `.drv` file, using the builder, arguments and
arguments and inputs described in it. inputs described in it.
Nix does not realize derivations until you access the Nix does not realize derivations until you access the contents of them or force
contents of them or force them to be evaluated using the `:b` them to be evaluated using the `:b` command in the Nix REPL, see these two
command in the Nix REPL, see these two examples: examples:
```nix ```nix
nix-repl> pkgs = import <nixpkgs> {} nix-repl> pkgs = import <nixpkgs> {}
@ -71,8 +69,8 @@ nix-repl> pkgs.runCommand "foo" {} "echo 'bar' > $out"
``` ```
Here, it did create a `.drv` file. But that's it. There is no Here, it did create a `.drv` file. But that's it. There is no
`/nix/store/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-foo` with contents `/nix/store/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-foo` with contents `bar` to be
`bar` to be seen. seen.
```nix ```nix
nix-repl> :b pkgs.runCommand "foo" {} "echo 'bar' > $out" nix-repl> :b pkgs.runCommand "foo" {} "echo 'bar' > $out"
@ -87,46 +85,44 @@ Where were we again? Right, the 3rd point:
`Then we import the expression, forcing the derivation to `Then we import the expression, forcing the derivation to
be realized as we accessed the contents of it.` be realized as we accessed the contents of it.`
The 3rd point is the important part. A typical Nix expression does The 3rd point is the important part. A typical Nix expression does not depend on
not depend on the output contents of any derivation, which in turn the output contents of any derivation, which in turn makes evaluating a Nix
makes evaluating a Nix expression not require realizing _any_ derivations. expression not require realizing _any_ derivations.
But with IFD, you have to realize a derivation to even finish the But with IFD, you have to realize a derivation to even finish the evaluation of
evaluation of your Nix expression. This will block Nix evaluation your Nix expression. This will block Nix evaluation for a long time, as Nix is
for a long time, as Nix is evaluated on a single thread and evaluated on a single thread and realizing the derivation needed takes a
realizing the derivation needed takes a non-trivial amount of time. non-trivial amount of time.
TL;DR: IFD blocks evaluation because: TL;DR: IFD blocks evaluation because:
1. Evaluation is single threaded, so naturally everything blocks it. 1. Evaluation is single threaded, so naturally everything blocks it.
2. You're trying to access a derivation _output_, so obviously 2. You're trying to access a derivation _output_, so obviously you need to
you need to realize (build) it first. realize (build) it first.
## `nix-shell` and `nix shell` are completely different ## `nix-shell` and `nix shell` are completely different
`nix-shell` is the legacy version of `nix develop`, which `nix-shell` is the legacy version of `nix develop`, which enters a devshell
enters a devshell created by a Nix expression. It was (and created by a Nix expression. It was (and still is) very useful.
still is) very useful.
People then realized getting a devshell by passing in the packages People then realized getting a devshell by passing in the packages you wanted as
you wanted as command line arguments was really convenient, command line arguments was really convenient, which resulted in the creation of
which resulted in the creation of the `--packages/-p` argument for `nix-shell` the `--packages/-p` argument for `nix-shell`
`nix-shell -p` is similar to `nix shell`. But they are not the same. `nix-shell -p` is similar to `nix shell`. But they are not the same.
`nix-shell -p` creates a shell using the stdenv by calling `pkgs.mkShell`, `nix-shell -p` creates a shell using the stdenv by calling `pkgs.mkShell`, which
which includes all packages in the nixpkgs stdenv plus the ones you specified. includes all packages in the nixpkgs stdenv plus the ones you specified.
`nix shell` only appends the packages you passed in to the `PATH` environment `nix shell` only appends the packages you passed in to the `PATH` environment
variable. It is much lighter, as a natural result of not using the stdenv. variable. It is much lighter, as a natural result of not using the stdenv. It
It also isn't a questionable templated Nix expression and is implemented in also isn't a questionable templated Nix expression and is implemented in the Nix
the Nix CLI natively. CLI natively.
## Hydra is 17,000 lines of Perl ## Hydra is 17,000 lines of Perl
As the title says, [Hydra](http://github.com/NixOS/hydra), As the title says, [Hydra](http://github.com/NixOS/hydra), the Nix-based
the Nix-based continuous build system is almost 17,000 continuous build system is almost 17,000 lines of Perl.
lines of Perl.
Here is the `tokei` output for its GitHub repository: Here is the `tokei` output for its GitHub repository:
@ -157,19 +153,19 @@ Here is the `tokei` output for its GitHub repository:
From <https://nixos.org/guides/nix-pills/>: From <https://nixos.org/guides/nix-pills/>:
> This is a ported version of the Nix Pills, a series of blog posts written > This is a ported version of the Nix Pills, a series of blog posts written by
> by Luca Bruno (aka Lethalman) and originally published in 2014 and 2015. > Luca Bruno (aka Lethalman) and originally published in 2014 and 2015. It
> It provides a tutorial introduction into the Nix package manager and Nixpkgs > provides a tutorial introduction into the Nix package manager and Nixpkgs
> package collection, in the form of short chapters called 'pills'. > package collection, in the form of short chapters called 'pills'.
> >
> Since the Nix Pills are considered a classic introduction to Nix, an effort > Since the Nix Pills are considered a classic introduction to Nix, an effort to
> to port them to the current format was led by Graham Christensen (aka grahamc > port them to the current format was led by Graham Christensen (aka grahamc /
> / gchristensen) and other contributors in 2017. > gchristensen) and other contributors in 2017.
## `inherit` ## `inherit`
`inherit` is a keyword in the Nix language that brings a variable `inherit` is a keyword in the Nix language that brings a variable into an
into an attribute set. It can also be used in `let in`s. attribute set. It can also be used in `let in`s.
Check out the Check out the
[Nix reference page](https://nixos.org/manual/nix/stable/language/constructs.html#inheriting-attributes) [Nix reference page](https://nixos.org/manual/nix/stable/language/constructs.html#inheriting-attributes)
@ -182,35 +178,34 @@ browse dependency graphs of derivations. Made in Haskell, of course.
## `nix-diff` ## `nix-diff`
[`nix-diff`](https://github.com/Gabriella439/nix-diff) is a tool to see how [`nix-diff`](https://github.com/Gabriella439/nix-diff) is a tool to see how two
two derivations differ with colored output. Again, in Haskell. derivations differ with colored output. Again, in Haskell.
## `nix-shell -p` gives you a compiler ## `nix-shell -p` gives you a compiler
As mentioned in the `nix-shell and nix shell are completely different` As mentioned in the `nix-shell and nix shell are completely different` section,
section, `nix-shell -p` is the nixpkgs stdenv plus your packages. `nix-shell -p` is the nixpkgs stdenv plus your packages.
And since the stdenv includes a C compiler, so does the shell And since the stdenv includes a C compiler, so does the shell you enter after
you enter after calling `nix-shell -p hello`. calling `nix-shell -p hello`.
## `nix-output-monitor` ## `nix-output-monitor`
[`nix-output-monitor`](https://github.com/maralorn/nix-output-monitor), [`nix-output-monitor`](https://github.com/maralorn/nix-output-monitor), also
also known as `NOM` is a neat visualizer for Nix builds. known as `NOM` is a neat visualizer for Nix builds. See it in action:
See it in action: <https://asciinema.org/a/604200> <https://asciinema.org/a/604200>
It is also programmed in Haskell. Whew. It is also programmed in Haskell. Whew.
## `nix-top` ## `nix-top`
[`nix-top`] is a simple Ruby script to help people [`nix-top`] is a simple Ruby script to help people see what is building in the
see what is building in the local Nix daemon. to help people local Nix daemon. to help people see what is building in the local Nix daemon.
see what is building in the local Nix daemon.
## `--debugger` ## `--debugger`
The `--debugger` flag is used to halt evaulation and The `--debugger` flag is used to halt evaulation and enter the Nix REPL when
enter the Nix REPL when evaluating a Nix file or expression. evaluating a Nix file or expression.
You set breakpoints using the `builtins.break` function: You set breakpoints using the `builtins.break` function:
@ -229,34 +224,34 @@ in builtins.break {
> Evaulate this file with `nix eval --debugger --file <filename>` and see. > Evaulate this file with `nix eval --debugger --file <filename>` and see.
It is also _supposed_ to bring the variables in the scope `break` It is also _supposed_ to bring the variables in the scope `break` was called
was called into the Nix REPL. However, this does not work. Keep on into the Nix REPL. However, this does not work. Keep on reading and you'll see
reading and you'll see why & what do to do bypass this bug! why & what do to do bypass this bug!
## `tvix` ## `tvix`
[Tvix](https://tvix.dev/) is an alternate implementation of Nix written in Rust. [Tvix](https://tvix.dev/) is an alternate implementation of Nix written in Rust.
It aims to have a modular implementation while also reusing already-written It aims to have a modular implementation while also reusing already-written Nix
Nix crates in the Rust ecosystem so other people can reuse code instead of crates in the Rust ecosystem so other people can reuse code instead of
reimplementing it! It is licensed under the GPLv3 license. reimplementing it! It is licensed under the GPLv3 license.
## Eelco's Thesis ## Eelco's Thesis
Eelco's thesis is about The Purely Functional Software Eelco's thesis is about The Purely Functional Software Deployment Model. Which
Deployment Model. Which also happens to be about Nix. also happens to be about Nix.
You can read the thesis [here](https://edolstra.github.io/pubs/phd-thesis.pdf). You can read the thesis [here](https://edolstra.github.io/pubs/phd-thesis.pdf).
## Fixed-Output derivations do not rebuild with a changed URL ## Fixed-Output derivations do not rebuild with a changed URL
Fixed output derivations (also called FODs) do not get rebuilt Fixed output derivations (also called FODs) do not get rebuilt even if you
even if you change any inputs passed to them (a URL string is change any inputs passed to them (a URL string is also an input). The reason for
also an input). The reason for this is simple. this is simple.
Nix will see that the output is the same, and since there already Nix will see that the output is the same, and since there already is a
is a derivation with the same output in the Nix store, it will derivation with the same output in the Nix store, it will assume it is cached
assume it is cached and will use that derivation. and will use that derivation.
# Tier 2: Package Maintainer # Tier 2: Package Maintainer
@ -271,14 +266,14 @@ following Nix CLI invokation:
nix run github:me/hello-world nix run github:me/hello-world
``` ```
This is great, you are able to run the binary. But, there is no way for a flake to This is great, you are able to run the binary. But, there is no way for a flake
accept any configuration arguments. If you wanted to run in debug mode, you have to accept any configuration arguments. If you wanted to run in debug mode, you
to create another output (like `packages.x86_64-linux.{release,debug}`). have to create another output (like `packages.x86_64-linux.{release,debug}`).
Same for compiling without support for X/Y/Z. This results in two to the N power Same for compiling without support for X/Y/Z. This results in two to the N power
of outputs, where N is the feature toggle count. of outputs, where N is the feature toggle count.
A dumb flake input like `github:boolean-option/true` fixes this, even though A dumb flake input like `github:boolean-option/true` fixes this, even though it
it is an ugly hack. You can do this in your flake: is an ugly hack. You can do this in your flake:
```nix ```nix
{ {
@ -301,22 +296,22 @@ And override the `debug-mode` input like so, to run a debug binary instead:
nix run github:me/hello-world --override debug-mode github:boolean-option/true nix run github:me/hello-world --override debug-mode github:boolean-option/true
``` ```
[`nix-systems`](https://github.com/nix-systems/nix-systems) is the same idea [`nix-systems`](https://github.com/nix-systems/nix-systems) is the same idea as
as `boolean-option`, but for systems instead. `boolean-option`, but for systems instead.
[See some example usages here.](https://github.com/search?q=boolean-option+language%3ANix&type=code&l=Nix) [See some example usages here.](https://github.com/search?q=boolean-option+language%3ANix&type=code&l=Nix)
These hacks wouldn't be needed if Nix allowed users to put arbitrary values in These hacks wouldn't be needed if Nix allowed users to put arbitrary values in
inputs - [in fact, there is an open issue from _2021_ that is still being actively inputs -
[in fact, there is an open issue from _2021_ that is still being actively
discussed](https://github.com/NixOS/nix/issues/5663) - but here we are. discussed](https://github.com/NixOS/nix/issues/5663) - but here we are.
## `''foo''\n'' == "foo\n"` ## `''foo''\n'' == "foo\n"`
The Nix parser is very buggy, and this is one bug. The Nix parser is very buggy, and this is one bug.
`''` is the character set used to escape `${` in `''` is the character set used to escape `${` in Nix indent strings (No, not
Nix indent strings (No, not multiline strings! All strings in Nix multiline strings! All strings in Nix are multiline.):
are multiline.):
```nix ```nix
'' ''
@ -328,20 +323,19 @@ This results in the literal string `"export BAR_OR_BAZ=${BAR:-BAZ}"`, without
string interpolation. string interpolation.
Nix will ignore an invalid `\` escape after the `''` escape in an indent string. Nix will ignore an invalid `\` escape after the `''` escape in an indent string.
Or if it is a valid one, it will just append the `\` escape to Or if it is a valid one, it will just append the `\` escape to the string,
the string, ignoring the `''` escape. ignoring the `''` escape.
## `(x: x x) (x: x x)` ## `(x: x x) (x: x x)`
This expression is a way to make Nix recurse forever This expression is a way to make Nix recurse forever and stack overflow. Nix
and stack overflow. Nix can't detect it either, as the can't detect it either, as the evaluated thunk is always different.
evaluated thunk is always different.
## Derivations are just memoized `execve` ## Derivations are just memoized `execve`
Derivations include all required information to build themselves. Derivations include all required information to build themselves. This also
This also includes output directories (except when they are content-addressed, includes output directories (except when they are content-addressed, but that is
but that is for a future blog post!). You can dump a `.drv` file as JSON with the for a future blog post!). You can dump a `.drv` file as JSON with the
`nix derivation show` command, like so: `nix derivation show` command, like so:
<details> <details>
@ -442,12 +436,13 @@ but that is for a future blog post!). You can dump a `.drv` file as JSON with th
} }
} }
``` ```
</details> </details>
## `nixos-rebuild --fast --target-host` ## `nixos-rebuild --fast --target-host`
The `--fast` flag in `nixos-rebuild` is an alias to `--no-build-nix` The `--fast` flag in `nixos-rebuild` is an alias to `--no-build-nix` which is
which is explained in the man page like so: explained in the man page like so:
> Normally, nixos-rebuild first builds the `nixUnstable` attribute in Nixpkgs, > Normally, nixos-rebuild first builds the `nixUnstable` attribute in Nixpkgs,
> and uses the resulting instance of the Nix package manager to build the new > and uses the resulting instance of the Nix package manager to build the new
@ -457,29 +452,29 @@ which is explained in the man page like so:
And the `--target-host` flag is also documented (rare!), like so: And the `--target-host` flag is also documented (rare!), like so:
> Specifies the NixOS target host. By setting this to something other than > Specifies the NixOS target host. By setting this to something other than an
> an empty string, the system activation will happen on the remote host > empty string, the system activation will happen on the remote host instead of
> instead of the local machine. The remote host needs to be accessible over > the local machine. The remote host needs to be accessible over ssh, and for
> ssh, and for the commands switch, boot and test you need root access. > the commands switch, boot and test you need root access.
> >
> If `--build-host` is not explicitly specified or empty, building will take > If `--build-host` is not explicitly specified or empty, building will take
> place locally. > place locally.
> >
> You can include a remote user name in the host name (user@host). You can > You can include a remote user name in the host name (user@host). You can also
> also set ssh options by defining the `NIX_SSHOPTS` environment variable. > set ssh options by defining the `NIX_SSHOPTS` environment variable.
> >
> Note that nixos-rebuild honors the nixpkgs.crossSystem setting of the > Note that nixos-rebuild honors the nixpkgs.crossSystem setting of the given
> given configuration but disregards the true architecture of the target > configuration but disregards the true architecture of the target host. Hence
> host. Hence the nixpkgs.crossSystem setting has to match the target platform > the nixpkgs.crossSystem setting has to match the target platform or else
> or else activation will fail. > activation will fail.
## Nix supports floats ## Nix supports floats
Yup, you heard it. Nix has floats, too! Yup, you heard it. Nix has floats, too!
Though, note that not every number in Nix is a float. Though, note that not every number in Nix is a float. Integers in Nix are stored
Integers in Nix are stored as 64-bit integers. Floats are also as 64-bit integers. Floats are also 64-bit.
64-bit. [Here's the Nix source code that denotes this](https://github.com/NixOS/nix/blob/d2a07a96ba6275e570b7d84092d08cbe85a2091b/src/libexpr/value.hh#L77-L78) [Here's the Nix source code that denotes this](https://github.com/NixOS/nix/blob/d2a07a96ba6275e570b7d84092d08cbe85a2091b/src/libexpr/value.hh#L77-L78)
```nix ```nix
nix-repl> 0.1 + 0.2 nix-repl> 0.1 + 0.2
@ -494,8 +489,7 @@ true
## `attrset ? key` and `attrset ? "key"` ## `attrset ? key` and `attrset ? "key"`
This syntax is a way to check for the existence of a key This syntax is a way to check for the existence of a key in an attribute set.
in an attribute set.
`{ foo = 42; } ? foo` evaulates to `true`. The same applies for `{ foo = 42; } ? foo` evaulates to `true`. The same applies for
`{ foo = 42; } ? "foo"`, which is just using a string identifier instead. `{ foo = 42; } ? "foo"`, which is just using a string identifier instead.
@ -512,31 +506,31 @@ in an attribute set.
#!/usr/bin/env nix-shell #!/usr/bin/env nix-shell
#!nix-shell -i python3 -p python3 #!nix-shell -i python3 -p python3
``` ```
</h2> </h2>
_(taken verbatim from `man nix-shell`)_ _(taken verbatim from `man nix-shell`)_
You can use nix-shell as a script interpreter You can use nix-shell as a script interpreter to allow scripts written in
to allow scripts written in arbitrary languages arbitrary languages to obtain their own dependencies via Nix. This is done by
to obtain their own dependencies via Nix. This starting the script with the following lines:
is done by starting the script with the following lines:
```shell ```shell
#!/usr/bin/env nix-shell #!/usr/bin/env nix-shell
#!nix-shell -i real-interpreter --packages packages #!nix-shell -i real-interpreter --packages packages
``` ```
Where `real-interpreter` is the "real" script interpreter Where `real-interpreter` is the "real" script interpreter that will be invoked
that will be invoked by nix-shell after it has obtained the by nix-shell after it has obtained the dependencies and initialised the
dependencies and initialised the environment, and packages environment, and packages are the attribute names of the dependencies in
are the attribute names of the dependencies in `<nixpkgs>`. `<nixpkgs>`.
The lines starting with `#!nix-shell` specify nix-shell options The lines starting with `#!nix-shell` specify nix-shell options (see above).
(see above). Note that you cannot write `#!/usr/bin/env nix-shell -i ...` Note that you cannot write `#!/usr/bin/env nix-shell -i ...` because many
because many operating systems only allow one argument in `#!` lines. operating systems only allow one argument in `#!` lines.
For example, here is a Python script that For example, here is a Python script that depends on Python and the prettytable
depends on Python and the prettytable package: package:
```python ```python
#!/usr/bin/env nix-shell #!/usr/bin/env nix-shell
@ -556,12 +550,11 @@ TODO
## Zilch ## Zilch
ZilchOS is a decidedly tiny Nix-based distro. It is a great project ZilchOS is a decidedly tiny Nix-based distro. It is a great project to see how
to see how NixOS actually works behind the scenes without too much NixOS actually works behind the scenes without too much noise to distract.
noise to distract.
It was created by [t184256](https://github.com/t184256) on GitHub, It was created by [t184256](https://github.com/t184256) on GitHub, here is the
here is the [ZilchOS GitHub organization](https://github.com/ZilchOS). [ZilchOS GitHub organization](https://github.com/ZilchOS).
## `set.a or "meow"` is set-specific ## `set.a or "meow"` is set-specific
@ -571,8 +564,8 @@ TODO
I find it weird that this is in the 3rd tier. It's actually pretty simple: I find it weird that this is in the 3rd tier. It's actually pretty simple:
Nix converts `true` to `"1"` and `false` to `"" (empty string)` when Nix converts `true` to `"1"` and `false` to `"" (empty string)` when asked to
asked to convert a boolean to a string. convert a boolean to a string.
And when you convert a list to a string, it converts individual items and then And when you convert a list to a string, it converts individual items and then
joins them with a space character (0xA). joins them with a space character (0xA).
@ -581,10 +574,9 @@ So `builtins.toString [true false true]` makes `1 1`
## `__structuredAttrs` ## `__structuredAttrs`
`__structuredAttrs`, when set to `true` in a derivation argument, `__structuredAttrs`, when set to `true` in a derivation argument, will set the
will set the `NIX_ATTRS_JSON_FILE` and `NIX_ATTRS_SH_FILE` file `NIX_ATTRS_JSON_FILE` and `NIX_ATTRS_SH_FILE` file paths to that arguments
paths to that arguments contents serialized in the respective contents serialized in the respective format.
format.
Here is an example: Here is an example:
@ -643,14 +635,14 @@ get something similar to this:
"system": "x86_64-linux" "system": "x86_64-linux"
} }
``` ```
</details> </details>
## `__functor` ## `__functor`
`__functor` is a magic attribute you can add on a set to make it `__functor` is a magic attribute you can add on a set to make it callable. The
callable. The lambda you assign to it must "accept 2 arguments". lambda you assign to it must "accept 2 arguments". The first being itself
The first being itself (commonly named "self") and the second (commonly named "self") and the second being the argument that was passed in.
being the argument that was passed in.
Here's an example: Here's an example:
@ -677,17 +669,17 @@ This outputs the following:
(later renamed to `--output-format`) (later renamed to `--output-format`)
You know how the new `nix-command` CLI has that bar at the bottom, You know how the new `nix-command` CLI has that bar at the bottom, which looks
which looks like `[4/0/804 built, 7.7/112.5 MiB DL] downloading '...'`? like `[4/0/804 built, 7.7/112.5 MiB DL] downloading '...'`?
This option allows you to have that output format in the old CLI by This option allows you to have that output format in the old CLI by passing in
passing in `--log-format bar-with-logs`. `--log-format bar-with-logs`.
## `traceVerbose` ## `traceVerbose`
`builtins.traceVerbose` behaves like `builtins.trace` when you pass `builtins.traceVerbose` behaves like `builtins.trace` when you pass
`--trace-verbose` to the Nix CLI. If you don't pass in that option, `--trace-verbose` to the Nix CLI. If you don't pass in that option, it
it completely ignores the first argument and returns the second one. completely ignores the first argument and returns the second one.
# Tier 4: Nix is Easy We Promise # Tier 4: Nix is Easy We Promise
@ -695,13 +687,12 @@ it completely ignores the first argument and returns the second one.
This evaluates to `[ false true ]`. Why? This evaluates to `[ false true ]`. Why?
Normally, Functions in Nix cannot be compared. Comparing Normally, Functions in Nix cannot be compared. Comparing two functions will
two functions will _always_ return false, at least when done _always_ return false, at least when done directly.
directly.
But if two attribute sets that are compared have the same address, But if two attribute sets that are compared have the same address, Nix ignores
Nix ignores this and does a pointer comparision, totally ignoring this and does a pointer comparision, totally ignoring all members. This is a
all members. This is a hack. hack.
[Link to code that does this.](https://github.com/NixOS/nix/blob/aa165301d1ae3b306319a6a834dc1d4e340a7112/src/libexpr/eval.cc#L2525-L2528) [Link to code that does this.](https://github.com/NixOS/nix/blob/aa165301d1ae3b306319a6a834dc1d4e340a7112/src/libexpr/eval.cc#L2525-L2528)
Here's the snippet: Here's the snippet:
@ -718,74 +709,77 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
if (&v1 == &v2) return true; if (&v1 == &v2) return true;
``` ```
This "temporary hack" was commited in 14 years ago. You can do whatever This "temporary hack" was commited in 14 years ago. You can do whatever you want
you want with this information. with this information.
## Nix Plugins ## Nix Plugins
As suprising as it sounds, Nix does indeed supports plugins. You can load plugins As suprising as it sounds, Nix does indeed supports plugins. You can load
using the [`plugin-files`](https://nix.dev/manual/nix/2.22/command-ref/conf-file#conf-plugin-files) plugins using the
[`plugin-files`](https://nix.dev/manual/nix/2.22/command-ref/conf-file#conf-plugin-files)
configuration option. configuration option.
From the configuration reference: From the configuration reference:
> A list of plugin files to be loaded by Nix. Each of these files will be dlopened by > A list of plugin files to be loaded by Nix. Each of these files will be
> Nix. If they contain the symbol nix_plugin_entry(), this symbol will be called. > dlopened by Nix. If they contain the symbol nix_plugin_entry(), this symbol
> Alternatively, they can affect execution through static initialization. In particular, > will be called. Alternatively, they can affect execution through static
> these plugins may construct static instances of RegisterPrimOp to add new primops > initialization. In particular, these plugins may construct static instances of
> or constants to the expression language, RegisterStoreImplementation to add new > RegisterPrimOp to add new primops or constants to the expression language,
> store implementations, RegisterCommand to add new subcommands to the nix command, > RegisterStoreImplementation to add new store implementations, RegisterCommand
> and RegisterSetting to add new nix config settings. See the constructors for those > to add new subcommands to the nix command, and RegisterSetting to add new nix
> types for more details. > config settings. See the constructors for those types for more details.
> >
> Warning! These APIs are inherently unstable and may change from release to release. > Warning! These APIs are inherently unstable and may change from release to
> release.
> >
> Since these files are loaded into the same address space as Nix itself, they must > Since these files are loaded into the same address space as Nix itself, they
> be DSOs compatible with the instance of Nix running at the time (i.e. compiled > must be DSOs compatible with the instance of Nix running at the time (i.e.
> against the same headers, not linked to any incompatible libraries). They should > compiled against the same headers, not linked to any incompatible libraries).
> not be linked to any Nix libs directly, as those will be available already at load time. > They should not be linked to any Nix libs directly, as those will be available
> already at load time.
> >
> If an entry in the list is a directory, all files in the directory are loaded > If an entry in the list is a directory, all files in the directory are loaded
> as plugins (non-recursively). > as plugins (non-recursively).
Some example plugins are [`nix-doc`](https://github.com/lf-/nix-doc) Some example plugins are [`nix-doc`](https://github.com/lf-/nix-doc) and
and [`nix-extra-builtins`](https://github.com/shlevy/nix-plugins). [`nix-extra-builtins`](https://github.com/shlevy/nix-plugins).
## `/bin/sh` and sandbox impurity ## `/bin/sh` and sandbox impurity
By setting the [`sandbox-paths`](https://nix.dev/manual/nix/2.22/command-ref/conf-file#conf-sandbox-paths) By setting the
option to `/bin/sh=/bin/sh`, Nix will bind the `/bin/sh` path in the [`sandbox-paths`](https://nix.dev/manual/nix/2.22/command-ref/conf-file#conf-sandbox-paths)
build sandbox (left) to the `/bin/sh` path in the host (right). option to `/bin/sh=/bin/sh`, Nix will bind the `/bin/sh` path in the build
This is of course impure, but is useful for bootstrapping from sandbox (left) to the `/bin/sh` path in the host (right). This is of course
absolute scratch without copying impure binaries to the Nix store. impure, but is useful for bootstrapping from absolute scratch without copying
impure binaries to the Nix store.
## `rec { a = 5; b = a + 1; __overrides.a = 6; }` ## `rec { a = 5; b = a + 1; __overrides.a = 6; }`
There is a special field named `__overrides` in recursive attrset expressions, There is a special field named `__overrides` in recursive attrset expressions,
which simply overrides the parent attribute set with the keys inside it. This which simply overrides the parent attribute set with the keys inside it. This is
is different from the update operator (`//`) because that will not override the different from the update operator (`//`) because that will not override the
self-referneces in the recursive attribute set. self-referneces in the recursive attribute set.
`rec { a = 5; b = a + 1; __overrides.a = 6; }.b` will evaluate to 7, `rec { a = 5; b = a + 1; __overrides.a = 6; }.b` will evaluate to 7, while
while `(rec { a = 5; b = a + 1; } // { a = 6; }).b` will evaluate to 6. `(rec { a = 5; b = a + 1; } // { a = 6; }).b` will evaluate to 6.
## `let __div = c: map (__mul c); in 2 / [ 1 2 3 ]` ## `let __div = c: map (__mul c); in 2 / [ 1 2 3 ]`
As mentioned in my [HTMNIX blog post](/blog/htmnix), Nix operators get As mentioned in my [HTMNIX blog post](/blog/htmnix), Nix operators get desugared
desugared into normal function calls before execution. All operators into normal function calls before execution. All operators have their "hidden"
have their "hidden" equivalents that they get desugared into (`__div` is for `/`, etc.), equivalents that they get desugared into (`__div` is for `/`, etc.), so you can
so you can override them using `let in`. override them using `let in`.
`let __div = c: map (__mul c); in 2 / [ 1 2 3 ]` is equivalent to `let __div = c: map (__mul c); in 2 / [ 1 2 3 ]` is equivalent to
`map (x: 2 * x) [ 1 2 3 ]` which evaluates to `[ 2 4 6 ]`. `map (x: 2 * x) [ 1 2 3 ]` which evaluates to `[ 2 4 6 ]`.
You can also check what a Nix snippet desugars into You can also check what a Nix snippet desugars into using
using `nix-instantiate --parse --expr 'expression here'` `nix-instantiate --parse --expr 'expression here'`
## `let __lessThan = a: b: b - a; in 1 > 2` ## `let __lessThan = a: b: b - a; in 1 > 2`
As mentioned above, this expression will desugar into As mentioned above, this expression will desugar into
`let __lessThan = a: b: b - a; in __lessThan 1 2` which `let __lessThan = a: b: b - a; in __lessThan 1 2` which will evaluate to 1.
will evaluate to 1.
## `__impure` ## `__impure`

View file

@ -9,17 +9,17 @@ tags:
- modal-editors - modal-editors
--- ---
If you have ever used a Turkish-Q keyboard in combination with a modal If you have ever used a Turkish-Q keyboard in combination with a modal editor
editor before, you might have noticed that the `i` key is pretty far off before, you might have noticed that the `i` key is pretty far off to the side:
to the side:
![The placement of the `i` key on the Turkish-Q layout](/assets/turkish-q-i.webp) ![The placement of the `i` key on the Turkish-Q layout](/assets/turkish-q-i.webp)
This blog post will guide you on how to swap the `ı` key with the `i` key This blog post will guide you on how to swap the `ı` key with the `i` key (but
(but not the `I` and `İ` keys). This will be a great change if you write primarily not the `I` and `İ` keys). This will be a great change if you write primarily in
in English but need the Turkish symbols sometimes. English but need the Turkish symbols sometimes.
> There is `tr(us)` in the `xkeyboard_config` package that does something similar to this: > There is `tr(us)` in the `xkeyboard_config` package that does something
> similar to this:
> >
> ```cpp > ```cpp
> // The basic Turkish layout with "i" and "ı" swapped. > // The basic Turkish layout with "i" and "ı" swapped.
@ -38,9 +38,10 @@ in English but need the Turkish symbols sometimes.
> }; > };
> ``` > ```
> >
> However, this only swaps the uppercase letters, so the `i` key is unchanged but > However, this only swaps the uppercase letters, so the `i` key is unchanged
> the uppercase of that key is `I` like in English. However, this is usually not > but the uppercase of that key is `I` like in English. However, this is usually
> desired as this still reduces your typing speed (as the `iI` key is too far). > not desired as this still reduces your typing speed (as the `iI` key is too
> far).
Let's create our own layout that does something similar but swaps the lowercase Let's create our own layout that does something similar but swaps the lowercase
letters instead. Here is the code for that: letters instead. Here is the code for that:
@ -60,8 +61,8 @@ xkb_symbols "basic" {
``` ```
The `default` key is needed because we are going to make this a standalone file. The `default` key is needed because we are going to make this a standalone file.
Save this to `~/.config/xkb/symbols/tr-swapped-i` and you can tell your WM/DE Save this to `~/.config/xkb/symbols/tr-swapped-i` and you can tell your WM/DE to
to use the `tr-swapped-i` XKB layout. use the `tr-swapped-i` XKB layout.
In Hyprland (The WM I use) you can do it like this: In Hyprland (The WM I use) you can do it like this:
@ -72,14 +73,15 @@ input {
} }
``` ```
That should swap the `ı` and `i` keys on your WM/DE successfully. However, we are not done That should swap the `ı` and `i` keys on your WM/DE successfully. However, we
yet. are not done yet.
The TTY (swap to TTY 2 by doing `CTRL-ALT-F2`) still doesn't use this layout, which is a problem. The TTY (swap to TTY 2 by doing `CTRL-ALT-F2`) still doesn't use this layout,
And it seems that the format the TTY uses is a little different. which is a problem. And it seems that the format the TTY uses is a little
Looking at the `kbd` package, it uses a format called `.map`. different. Looking at the `kbd` package, it uses a format called `.map`.
Here is a `.map` file that overrides the `trq` layout and swaps the `ı` and `i` keys: Here is a `.map` file that overrides the `trq` layout and swaps the `ı` and `i`
keys:
```cpp ```cpp
include "/usr/share/keymaps/i386/qwerty/trq.map" include "/usr/share/keymaps/i386/qwerty/trq.map"
@ -96,7 +98,8 @@ Save it to the directory where you store your maps.
Note that the path `/usr/share/keymaps` might differ based on your distro. You Note that the path `/usr/share/keymaps` might differ based on your distro. You
can check what it is it by doing `man loadkeys` and scrolling to the bottom. can check what it is it by doing `man loadkeys` and scrolling to the bottom.
After that, consult your distro's docs on how to change the system keyboard locale. After that, consult your distro's docs on how to change the system keyboard
locale.
This is how it is done on NixOS: This is how it is done on NixOS: