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.
e65991c1c9
...
7738256955
17 changed files with 4336 additions and 1153 deletions
970
LICENSE_GPL.md
970
LICENSE_GPL.md
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||||
|
|
21
_config.ts
21
_config.ts
|
@ -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;
|
||||||
|
|
24
apply.nu
24
apply.nu
|
@ -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 -
|
||||||
|
|
||||||
|
|
18
deno.json
18
deno.json
|
@ -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"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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).
|
|
||||||
|
|
|
@ -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 |
|
@ -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 :^).
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||

|
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.
|
||||||
|
|
||||||

|
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.
|
||||||
|
|
|
@ -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...
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
@ -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`
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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:
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue