1
Fork 0
mirror of https://github.com/RGBCube/Site synced 2025-08-03 06:27:46 +00:00

Compare commits

..

No commits in common. "e65991c1c9d8a3453ed7c5255fde77f9ffe4d936" and "77382569550b689c606e2f6af20fc6a53ce66f7f" have entirely different histories.

17 changed files with 4336 additions and 1153 deletions

File diff suppressed because it is too large Load diff

View file

@ -15,11 +15,9 @@ 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 directory is licensed under [CC BY-NC-ND 4.0](https://creativecommons.org/licenses/by-nc-nd/4.0/).
[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 The other HTML and templating code is licensed under the GPU General Public License (`LICENSE_GPL.md`):
License (`LICENSE_GPL.md`):
``` ```
Copyright (C) 2023-present RGBCube Copyright (C) 2023-present RGBCube

View file

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

View file

@ -2,6 +2,7 @@
def --wrapped sync [...arguments] { def --wrapped sync [...arguments] {
(rsync (rsync
--rsh "ssh -q"
--compress --compress
--delete --recursive --force --delete --recursive --force
--delete-excluded --delete-excluded
@ -26,18 +27,19 @@ def main [] {
cd _site cd _site
let host = "root@best"; for host in [cube, disk] {
ssh -qtt $host "sudo nu -c '
mkdir /var/www
chown nginx:users -R /var/www
chmod 775 -R /var/www
'"
sync --chown nginx:users ./ ($host + ":/var/www/site")
ssh -qtt $host " ssh -qtt $host "sudo nu -c '
rm --force --recursive /var/www/site chown nginx:users -R /var/www
mkdir /var/www/site chmod 775 -R /var/www
" '"
sync --chown nginx:users ./ ($host + ":/var/www/site") }
ssh -qtt $host "
chown nginx:users -R /var/www
chmod 775 -R /var/www
"
cd - cd -

View file

@ -1,24 +1,18 @@
{ {
"compilerOptions": { "compilerOptions": {
"jsx": "react-jsx", "jsx": "react-jsx",
"jsxImportSource": "lume", "jsxImportSource": "npm:react",
"types": [ "types": [
"lume/types.ts" "lume/types.ts",
"https://unpkg.com/@types/react@18.2.37/index.d.ts"
] ]
}, },
"tasks": { "tasks": {
"lume": "echo \"import 'lume/cli.ts'\" | deno run --allow-all -", "build": "echo \"import 'lume/cli.ts'\" | deno run --allow-all -",
"build": "deno task lume", "serve": "deno task build --serve"
"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@v3.0.2/", "lume/": "https://deno.land/x/lume@v2.1.0/"
"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,3 +1,7 @@
import React, { ReactNode as Node } from "npm:react";
const empty: Node = <></>;
interface CubeProps { interface CubeProps {
front?: Node; front?: Node;
back?: Node; back?: Node;
@ -101,12 +105,12 @@ const Cube = (props: CubeProps) => (
<div className="scene"> <div className="scene">
<div className="cube"> <div className="cube">
<div className="face front">{props.front}</div> <div className="face front">{props.front || empty}</div>
<div className="face back">{props.back}</div> <div className="face back">{props.back || empty}</div>
<div className="face left">{props.left}</div> <div className="face left">{props.left || empty}</div>
<div className="face right">{props.right}</div> <div className="face right">{props.right || empty}</div>
<div className="face top">{props.top}</div> <div className="face top">{props.top || empty}</div>
<div className="face bottom">{props.bottom}</div> <div className="face bottom">{props.bottom || empty}</div>
</div> </div>
</div> </div>

View file

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Before After
Before After

View file

@ -9,18 +9,17 @@ tags:
- unix-timestamps - unix-timestamps
--- ---
So, every day I wake up at 6:55, get dressed by 7, walk to the bus stop by 7:13 So, every day I wake up at 6:55, get dressed by 7, walk to the bus stop
and board the bus around 7:17. Today was different. by 7:13 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 My alarm that I have set for 6:55 rang at 7:12 and as a result, I missed the bus.
bus.
> No, I didn't sleep in. There was no note in the UI saying this was a repeat > No, I didn't sleep in. There was no note in the UI saying this was a repeat alarm,
> alarm, which there is if you snooze it or let it expire. > 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 mostly deterministic. And I doubt Samsung engineers wrote code to delay the alarm
alarm by 12 minutes on the date after April 1st. 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:
@ -34,8 +33,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 the > Since I'm using a Samsung SM-B310E, I assumed it uses seconds to store
> time. You can't even see seconds noted anywhere so I feel this is a normal > the 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).
@ -51,15 +50,13 @@ 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 a Aha! So the 11th bit got flipped by something. And that something was probably
cosmic ray. a cosmic ray.
EDIT: It was not a cosmic ray. As pointed out by 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)
[@BenjaminRi's comment on lobste.rs](https://lobste.rs/s/jb1o6q/cosmic_drift#c_1ztluj) it was either a bug or storage corruption as the alarm ran late the next day. You should
it was either a bug or storage corruption as the alarm ran late the next day. still create more than one alarm just in case if you are using a phone prone to this, however.
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 My main takeaway from this event is to create more than one alarm, for extra redundancy.
redundancy. Who knew being prone to sleeping in could save you from your alarm Who knew being prone to sleeping in could save you from your alarm getting
getting shifted 12 minutes into the future :^). 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`, `poetry init` and You just started a new project. You ran `cargo init`,
`go mod init`. `poetry init` and `go mod init`.
Those commands created the necessary files to work, it also added the following Those commands created the necessary files to work, it
lines to your .gitignore: also added the following lines to your .gitignore:
```text ```text
target target
@ -23,23 +23,27 @@ __pycache__
bin bin
``` ```
All great. You continue implementing features, and when the time comes, you All great. You continue implementing features, and when
publish your project to your Git hosting platform of choice. the time comes, you publish your project to your Git
hosting platform of choice.
People start to get interested in your project. One even decides that he's going People start to get interested in your project. One even
to implement a new feature! Literally free work done for you! decides that he's going to implement a new feature!
Literally free work done for you!
Alright. That person uses his code editor and tools bundled with his operating Alright. That person uses his code editor and tools bundled
system to implement a very cool new feature. He then submits the merge request. with his operating system to implement a very cool
new feature. He then submits the merge request.
You start reviewing the code and notice a file quite out of place: `.DS_Store`. You start reviewing the code and notice a file quite
You ask the person what it is, he says he has no clue. out of place: `.DS_Store`. You ask the person what
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 add the file's name to Whatever. You just delete the file from the branch and
the repositories gitignore: add the file's name to the repositories gitignore:
```text ```text
target target
@ -48,13 +52,15 @@ bin
.DS_Store .DS_Store
``` ```
Nice. Now the code is on master, and your repository only contains relevant
information.
Then, someone using an IDE created using web technologies submits another merge Nice. Now the code is on master, and your repository
request. You look at it, and see that there is a whole directory that is only contains relevant information.
irrelevant. You tell that person to delete the directory from the branch and add
it to the gitignore. The gitignore lives on: Then, someone using an IDE created using web technologies
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
@ -64,8 +70,8 @@ bin
.vscode .vscode
``` ```
Then, someone that uses IntelliJ IDEA commits five hundred XML files and the Then, someone that uses IntelliJ IDEA commits five hundred
`.idea` directory. You repeat this process: XML files and the `.idea` directory. You repeat this process:
```text ```text
target target
@ -76,24 +82,27 @@ bin
.idea .idea
``` ```
Years pass. Now your gitignore is hundreds of lines long, yet people keep Years pass. Now your gitignore is hundreds of lines long,
accidentally committing in test scripts, foo, a, qux, data.tar.gz, start.sh, yet people keep accidentally committing in test scripts,
bin-release, cat, asd, fgsgskfh. foo, a, qux, data.tar.gz, start.sh, bin-release,
cat, asd, fgsgskfh.
Hell. You feel like a mythic god undergoing punishment for cheating death and Hell. You feel like a mythic god undergoing punishment
deceiving the underworld. for cheating death and 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 that sneak in? Maybe by How do you escape this endless loop of ignoring files
educating every single merge request author? Nope, that definitely won't work, that sneak in? Maybe by educating every single merge
there should be a way to automatically handle this with tooling, rather than request author? Nope, that definitely won't work, there
subjective human communication. should be a way to automatically handle this with tooling,
rather than subjective human communication.
Luckily, you realize that you can turn the blacklist of files (the gitignore) to Luckily, you realize that you can turn the blacklist
a whitelist, by just ignoring everything and manually un-ignoring desired files. of files (the gitignore) to a whitelist, by just
You change your gitignore to this: ignoring everything and manually un-ignoring desired
files. You change your gitignore to this:
```text ```text
* *
@ -114,10 +123,12 @@ You change your gitignore to this:
!docs/*.md !docs/*.md
``` ```
Now, nobody can accidentally commit undesired files, as git automatically Now, nobody can accidentally commit undesired files,
ignores them all and only allows the files that are explicitly whitelisted. It's as git automatically ignores them all and only
also future proof, future proof until an IDE decides to use the `src/ide.rs` allows the files that are explicitly whitelisted.
file as a convenient way of storing project specific configuration. And It's also future proof, future proof until an IDE
hopefully that future never comes. decides to use the `src/ide.rs` file as a convenient
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 So, you may have seen the [HTMNIX](https://github.com/RGBCube/HTMNIX) project I've
I've been working on the last few weeks. If not, no worries. Here is a Nix been working on the last few weeks. If not, no worries. Here is a Nix snippet
snippet that uses it: that uses it:
```nix ```nix
<html> <html>
@ -26,8 +26,7 @@ snippet that uses it:
<.html> <.html>
``` ```
> (hightlight.js shits the bed while highlighting this abomination - just ignore > (hightlight.js shits the bed while highlighting this abomination - just ignore it)
> 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:
@ -37,13 +36,11 @@ 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 > That means you have to add hundreds of elements to your Nix Path to make this work?
> 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 Nix `<foo>` expressions actually boil down to a call of the builtin `__findFile`, like so:
`__findFile`, like so:
```shell ```shell
nix-instantiate --parse --expr "<foo>" nix-instantiate --parse --expr "<foo>"
@ -51,13 +48,11 @@ Nix `<foo>` expressions actually boil down to a call of the builtin
(__findFile __nixPath "foo") (__findFile __nixPath "foo")
``` ```
> In case you didn't know, > In case you didn't know, [`nix-instantiate`](https://nixos.org/manual/nix/stable/command-ref/nix-instantiate.html)
> [`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.
> 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 Aha! So this means we can override the builtin `__findFile` and put whatever we would like in
would like in its place. So this will work: its place. So this will work:
```nix ```nix
let let
@ -68,16 +63,14 @@ in
<foo> <foo>
``` ```
Evaluating this (by running `nix eval -f test.nix`), we get Evaluating this (by running `nix eval -f test.nix`), we get `{ content = "<foo>"; }`
`{ 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 Another hack! We need to set the [magic `__functor` attribute](https://noogle.dev/md/tutorials/functors)
[magic `__functor` attribute](https://noogle.dev/md/tutorials/functors) of the of the attrset we return, so we can call our set and have it store the tags inside it (while also
attrset we return, so we can call our set and have it store the tags inside it preserving its callability!).
(while also preserving its callability!).
We can do that like so: We can do that like so:
@ -95,11 +88,9 @@ in
"baz" "baz"
``` ```
Great news! When we evaluate this, we get Great news! When we evaluate this, we get `{ __functor = <LAMBDA>; content = "<foo>barbaz"; }`.
`{ __functor = <LAMBDA>; content = "<foo>barbaz"; }`.
We can also add a case to check if the next element is a tag, and use its We can also add a case to check if the next element is a tag, and use its content if it is:
content if it is:
```nix ```nix
let let
@ -116,9 +107,8 @@ in
<endfoo> <endfoo>
``` ```
Enter another hack! We can utilize the `outPath` property that exists on Enter another hack! We can utilize the `outPath` property that exists on derivations
derivations and gets returned whenever you call `toString` with an attrset that and gets returned whenever you call `toString` with an attrset that has the property to make our code a little simpler:
has the property to make our code a little simpler:
```nix ```nix
let let
@ -138,17 +128,15 @@ 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 These are all the hidden builtins that [HTMNIX](https://github.com/RGBCube/HTMNIX) depends on
[HTMNIX](https://github.com/RGBCube/HTMNIX) depends on and extends upon, making and extends upon, making HTML in Nix an actually usable reality. It also
HTML in Nix an actually usable reality. It also has extra logic like turning has extra logic like turning attribute sets into HTML tags, which is fairly trivial
attribute sets into HTML tags, which is fairly trivial compared to actaully compared to actaully discovering these hidden builtins in the first place.
discovering these hidden builtins in the first place.
You can read more about it in the project's README and see You can read more about it in the project's README and
[an example site using it](https://github.com/RGBCube/NixSite). see [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 I might even try to port this site to HTMNIX to ensure it is usable with more complex setups :-)
complex setups :-)
Soon, maybe... Soon, maybe...

View file

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

View file

@ -9,39 +9,38 @@ tags:
- modal-editors - modal-editors
--- ---
If you have ever used a Turkish-Q keyboard in combination with a modal editor If you have ever used a Turkish-Q keyboard in combination with a modal
before, you might have noticed that the `i` key is pretty far off to the side: editor before, you might have noticed that the `i` key is pretty far off
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 (but This blog post will guide you on how to swap the `ı` key with the `i` key
not the `I` and `İ` keys). This will be a great change if you write primarily in (but not the `I` and `İ` keys). This will be a great change if you write primarily
English but need the Turkish symbols sometimes. in English but need the Turkish symbols sometimes.
> There is `tr(us)` in the `xkeyboard_config` package that does something > There is `tr(us)` in the `xkeyboard_config` package that does something similar to this:
> similar to this: >
>
> ```cpp > ```cpp
> // The basic Turkish layout with "i" and "ı" swapped. > // The basic Turkish layout with "i" and "ı" swapped.
> // Originally by Ali Riza KESKIN <parduscix@yandex.ru>, 2021. > // Originally by Ali Riza KESKIN <parduscix@yandex.ru>, 2021.
> partial > partial
> xkb_symbols "us" { > xkb_symbols "us" {
> >
> include "tr(basic)" > include "tr(basic)"
> >
> name[Group1]="Turkish (i and ı swapped)"; > name[Group1]="Turkish (i and ı swapped)";
> >
> key <AC11> { type[group1] = "FOUR_LEVEL_SEMIALPHABETIC", > key <AC11> { type[group1] = "FOUR_LEVEL_SEMIALPHABETIC",
> [ i, I, paragraph, none ]}; > [ i, I, paragraph, none ]};
> key <AD08> { type[group1] = "FOUR_LEVEL_SEMIALPHABETIC", > key <AD08> { type[group1] = "FOUR_LEVEL_SEMIALPHABETIC",
> [ idotless, Iabovedot, apostrophe, dead_caron ]}; > [ idotless, Iabovedot, apostrophe, dead_caron ]};
> }; > };
> ``` > ```
> >
> However, this only swaps the uppercase letters, so the `i` key is unchanged > However, this only swaps the uppercase letters, so the `i` key is unchanged but
> but the uppercase of that key is `I` like in English. However, this is usually > the uppercase of that key is `I` like in English. However, this is usually not
> not desired as this still reduces your typing speed (as the `iI` key is too > desired as this still reduces your typing speed (as the `iI` key is too far).
> 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:
@ -61,8 +60,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 to Save this to `~/.config/xkb/symbols/tr-swapped-i` and you can tell your WM/DE
use the `tr-swapped-i` XKB layout. to 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:
@ -73,15 +72,14 @@ input {
} }
``` ```
That should swap the `ı` and `i` keys on your WM/DE successfully. However, we That should swap the `ı` and `i` keys on your WM/DE successfully. However, we are not done
are not done yet. yet.
The TTY (swap to TTY 2 by doing `CTRL-ALT-F2`) still doesn't use this layout, The TTY (swap to TTY 2 by doing `CTRL-ALT-F2`) still doesn't use this layout, which is a problem.
which is a problem. And it seems that the format the TTY uses is a little And it seems that the format the TTY uses is a little different.
different. Looking at the `kbd` package, it uses a format called `.map`. 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` Here is a `.map` file that overrides the `trq` layout and swaps the `ı` and `i` keys:
keys:
```cpp ```cpp
include "/usr/share/keymaps/i386/qwerty/trq.map" include "/usr/share/keymaps/i386/qwerty/trq.map"
@ -98,8 +96,7 @@ 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 After that, consult your distro's docs on how to change the system keyboard locale.
locale.
This is how it is done on NixOS: This is how it is done on NixOS: