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

lume: move to 3.0

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

3780
deno.lock generated

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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