page =
url = https://leahneukirchen.org/blog
leah blogs
There are two essential kinds of markup howm cares about: note titles and links. By default, titles are marked up by putting a ‘ = ’ at the beginning of the line, but this can be configured (and must be done so before loading howm-mode (!)). The benefit of adding a title to a note is that you can have the summary buffer show titles instead of matching lines, which can be helpful to get a better overview of search results. (The creator of howm is sceptical of titling all notes, I think it very much depends the average length of your notes. There is no requirement to use titles.)
Pressing return on this line when howm-mode is enabled will show a list of all occurences of the word howm in your notes directory.
And this will cause the word howm in any howm-mode buffer to be underlined and trigger a search where the buffer with <<< howm will appear first.
It is straightforward to implement something like #tags or WikiWords using these features, if you wish to do so.
Additionally, howm provides an inline link syntax [[...]] that works like >>> but can appear within a line. I make a suggestion below how to turn it into a direct link to the first page with the given title; but for now I decided not to use this very much.
The line-based nature of the >>> syntax prevents usage for “inline” links. After giving it some thought, I consider it a strength for a note-taking system to make forward links related to a paragraph and not part of a sentence. Additionally, it also makes the plain text easier to read as the link target is not interleaved into the text. (Compare with the use of reference-style links in Markdown.)
An aside: howm actually supports multiple notes per file by having multiple title lines in a file. The search summary will always show the title directly before the matching line. You can use C-c , C to create a new note in the current buffer. I don’t use this much, but I think it could be useful for glossary files that contain many short notes. Some people also use this for keeping multiple daily notes in a single file.
Howm provides two main features to access notes: the menu and the summary buffer. The howm menu (shown with C-c , , ) provides a very customizable view into your howm notes. By default it shows your schedule, recent notes, and random notes. You can access many howm features with a single keypress from the menu. Since I don’t use the scheduling feature, I mostly access howm from the summary buffer instead.
The howm summary buffer shows the result of a search ( C-c , g ), a list of recent notes ( C-c , l ), or an overview of all notes ( C-c , a ). It is very convenient to see the matches and you get a preview of the note when you move the cursor to a search result. Typing RET will open the note for editing. Typing T will toggle between displaying matching lines or the titles of notes with matches.
In the summary buffer, you can also type @ and read all matching notes in a concatenated way, so you get the full context of all notes at once.
Here, we decide that ~/prj/howm is the base directory for our howm notes, and we also put the two auxiliary files howm uses there. Additionally, we change the default name format to end with .md (which also turns on markdown-mode by default).
The next addition is interactive search with ripgrep ( C-c , r ). This is the most useful feature I added to howm myself. I think it provides a great way to interact with your notes, as you get instant feedback from your search terms, and can stop searching as soon as you found what you were looking for. I used counsel-rg as an inspiration for this, and we turn the ripgrep matches into a regular howm summary buffer for further consumption.
A great usability enhancement is buffer renaming: since howm file names are a bit unwieldy (like ~/prj/howm/2022/03/2022-03-25-162227.md ) you can use these two lines to rename note buffers according to their title, which makes switching between multiple notes more convenient.
My configuration ends with three definitions of action-lock , the howm mechanism for marking text active and do something on RET. Two of them are related to the reference management software Zotero , which I use for organizing papers, and enable me to link to articles in my Zotero database by URL or BibTeX identifier:
Finally, as mentioned above, this is how to make [[...]] wiki-links directly point to the first page with that title, skipping the summary buffer:
One thing I want to implement but didn’t yet get around to is support for searching notes using ugrep , which has a nifty boolean search mode that applies to whole files, so you can do searches that are not limited to a line context (e.g. hoge|fuga -piyo finds all notes that mention hoge or fuga, but don’t contain piyo).
A dozen years ago, the Unix textbook answer to this would have been: well, if its process id (pid) is 1, then it is init by definition.
These days, things are not that simple anymore. Containerization creates situations where pid is 1, but the process runs, well, in a container. In Linux, this is realized by using a feature called “pid namespaces”. The clone(2) syscall can take the flag CLONE_NEWPID (“since Linux 2.6.24”), which puts the new process into a new pid namespace. This means that this process will have pid 1 inside the pid namespace, but outside (i.e. in the parent pid namespace), the process has a regular pid. Various Linux API transparently translate pids between these namespaces.
We can try to find some evidence that we’re a freshly booted init , but none of it is really conclusive:
$TERM should be linux ; trivial to override.
$BOOT_IMAGE is set, but this depends on the boot loader.
System uptime is “low”, but it takes the initrd boot time into account. Our non-root init could be spawned in a container at boot time.
There are also some indicators the process runs in a container using one of the popular solutions such as docker or podman :
If we were put inside a cgroup, reading /proc/1/cgroup will indicate it.
The file /.dockerenv exists.
But there are still situations, such as the unshare call above, where all of these things may not be true.
I started to research this and quickly found the ioctl(2) NS_GET_PARENT which seemed to be useful: “Returns a file descriptor that refers to the parent namespace of the namespace referred to by fd.” However, it is useless for this purpose:
So, we need to bring out bigger guns in. I searched the kernel source for occurrences of init_pid_ns , as this namespace is called in the Linux source code. There are not too many occurrences we can rely on. The taskstats module limits the TASKSTATS_CMD_ATTR_REGISTER_CPUMASK command to the initial pid namespace only, but to use this requires speaking the netlink interface, which is terrible. Also, the behavior could change in future versions.
One interesting, and viable approach, is this limitation of the reboot(2) syscall: only some LINUX_REBOOT_CMD_* commands are allowed to be sent inside a nested pid namespace. Now, we need to find a “harmless” command to call reboot(2) with to test this! (Obviously, only being able to suspend the machine from the initial pid namespace is not a very useful check…) There are two commands that do not do much harm: LINUX_REBOOT_CMD_CAD_{ON,OFF} will toggle the action that Ctrl-Alt-Delete performs. Unfortunately, it is impossible to read the state of this flag, making this test a destructive operation still. (But if you are pid 1, you may want to set it anyway, so you get pid namespace detection for free.)
So I kept looking for other ways until I realized there’s a quite natural property to check for, and that is to find out if there are kernel threads in the pid namespace. Kernel threads are spawned by the kernel in the initial pid namespace and help perform certain asynchronous actions the kernel has to do, subject to process scheduling. As far as I know, kernel threads never occur in a nested pid namespace, and at least the parent process of kernel threads, kthreadd , will always exist. Conveniently, it also always has pid 2.
/proc/PID/cmdline is empty (not a good indicator, user space processes can clear it too).
kernel threads have parent pid 0 (requires parsing /proc/PID/stat , which everyone gets wrong the first time, or /proc/PID/status ).
kernel threads have no Vm* data in /proc/PID/status .
kernel threads have the flag PF_KTHREAD set (requires parsing /proc/PID/stat again).
kernel threads have an empty symlink for /proc/PID/exe .
On a regular file system, using lstat(2) would have filled st_size with the length of the symlink. But on a procfs , lstat is not to be trusted, and even non-empty symlinks have st_size equal to 0. We thus really need to use the readlink(2) syscall to read the link. After doing this, you will notice that it returns ENOENT … exactly the same as if pid 2 did not exist!
We therefore need another check, to verify that pid 2 does exist. Luckily, here a lstat on /proc/2/exe file is fine. It must return zero.
Note that you need to do these operations in exactly this order , else you are subject to race conditions again: the only reason this works is that if pid 2 is kthreadd , it will not have terminated before the lstat check (because it cannot terminate).
Therefore, readlink(2) failing with ENOENT and lstat(2) succeeding is exactly the combination required to check pid 2 is kthreadd , which implies there are kernel threads in our pid namespace, which implies that we are in the initial namespace.
We subtract the ASCII lines from the character 0 to get numerical rows. The merge function ( > ) then converts this list-of-lists into a 2-dimensional array. For the sample data, we get:
By default, shifting ( « , » ) in BQN inserts zeroes for numerical arrays. But since we are looking for the minimum, we need to shift in a value that is higher than any. We can simply use ∞ .
So, to shift in ∞ from the left, we use:
We need would need to make a list of ∞ long enough to agree with the array width:
How do we “rotate” a matrix? We reverse the rows ( ⌽ ) and then transpose ( ⍉ ) it.
By using the repeat modifier ( ⍟ ) we can easily rotate several times.
Finally, we perform the shift operation under ( ⌾ ) the rotation, that is, BQN rotates the array, does the shift, and knows how to undo the rotation!
Now we insert ( ´ ) the minimum function ( ⌊ ) between these arrays and compute the minimum at each position:
The positions where the original array d is still smaller are the low points, and we store them for part 2.
Finally, we compute the end result by deshaping ( ⥊ ) the array into a single long list and summing it up:
In BQN, the shape ( ≢ ) of an array is the list of sizes for each axis:
Here’s the main idea how to solve part 2: we incrementally grow these areas by adding their neighbors until the whole array is filled. For one step, we do this with a function Rise :
Here, shifting in zeroes is good enough, so we can use the monadic shift functions. The train at the end computes the maximum ( ⌈ ) of the four shifted versions and the array itself ( ⊣ ). We multiply it with a matrix that is 0 where the depth is 9, so the basin limits will be constantly zero.
Now we could just iterate this step a often enough, or actually only until we reach a fixpoint; that is, applying Rise again doesn’t change the value anymore.
With the nice group indices function ( ⊔ ), we can count how often each value appears:
Finally, let’s compute the three largest values by sorting in descending order ( ∨ ) and taking the first three entries ( ↑ ):
First, let’s convert the sample input data into a histogram: For reasons that will be obvious in a minute, we compare each input element with the list of numbers from 0 to 8 ( ↕9 ).
Next, we need to figure out what happens in a step. We can model one part (number decreases by 1, or becomes 8 when it was 0) by rotating ( ⌽ ) the array to the left:
Now we can scale this vector by the first element ( ⊑ ):
Finally, we put both things together. We can use a hook if we bind ( ⊸ ) the argument of the rotation to the operator:
Now, we simply need to repeat ( ⍟ ) this step 80 (resp. 256) times and count up the results to solve the puzzle!
The key realization is that Step is a linear function, which means:
We can thus compute Step for every basis vector of our 9-dimensional histogram space; let’s take the unit vectors here:
We can also compute step256 faster by using a bit of matrix theory. Since we know the operation of step on the basis vectors, we can compute the matrix m corresponding to this linear operator:
Note how we just applied Step for every column of the identity matrix.
Naively, we can compute the power like this (we already have m to the power of 1!):
Now multiply d to it, and sum up:
Note that step256 is just the sum of rows, so we can precompute that:
This yields an asymptotically faster algorithm to compute the step vector for higher powers. For non-powers of two you need to implement a square-and-multiply algorithm, or look up the optimal result . This is left as an exercise to the reader.
In theory, you could optimize this even further and compute a closed form from the eigenvectors of m , but you’ll end up with nonic roots and I have not found a way to compute them precise enough to be useful. So let’s leave it at that for now.
I first came across David when I researched the history of the QED editor, the direct predecessor of the Unix standard text editor ed . The history of QED is well documented by Dennis Ritchie . However, for a long time the QED source code was hard to find, and I heard that David still maintained a version.
Looking at these tools was instructive; many are obsoleted now because the features have been added to standard tools, or we can afford using more general, inefficient tools now. But for example, his go tool directly influenced the user interface of my nq tool, and reading about rls , lls , fexists , and ftest inspired my lr . His rpl lives on as my mend .
We can run this using the convenient -x flag:
So, how does it work? First, we switch to buffer a of QED’s 56 available buffers ( ba ). By default we are in the script buffer named ~ due to the -x flag, which made me scratch my head in the beginning because the script always printed its own source at first!
Next, we set up a loop. QED provides structured programming in the form of a while loop, but that requires fitting the loop body on the same line. Instead, we will use jumps. We start with a label "loop and increment the c register using zc#+1 . The # enables arithmetic mode for registers, they also can be strings. Since the register is empty, it will be regarded as zero. The end of the loop is the zc#=100 yf`loop line, which checks whether the c register equals 100, and if not ( yf ) jumps back to the label loop . Curiously, QED has different commands for jumping forwards ( ' ) and backwards ( ` ). Having explicit directions is, I assume, an implementation detail of the buffer-based program storage, but compare with Unix’s goto or TECO’s O command , which both search from the top.
Inside the loop, we first append an empty line ( a\N\N. ) This works like in ed:
But QED allows using \N as a newline, so we can save some screen space.
Then, we need to do the fizzbuzz logic. The command za#:\zc%3=0 will copy the c register to the a register (we need to do this, as all arithmetic operations store their result in a register), then we take the a register modulo 3 and check if the register is then zero. If it isn’t, we jump a line forward ( yf ). If we didn’t jump, we append fizz to the line, using the s command (pretty much like in ed).
We deal with the buzz case the same way, but modulo 5.
If the line is still empty, we have to say the number, so we append it using s again and this time insert the c register into the input stream using \zc . Note that this not interpolated by the s command, but by QED itself. You can write \zc (or \N ) essentially everywhere and it will work as if you’d have typed it in! A \ can be quoted as \c , so we can do this:
Note how the insertion of the a register resulted in the b register being inserted as well! Luckily, the people involved with QED did better when they wrote shells later.
At the end of the loop, we have the fizzbuzz output in the buffer, so we can just print out the whole thing ( ,p ) and quit QED with no questions asked ( Q ).
So I started to dig around in the SAILDART archives, and quickly found Donald Knuth’s TeX working directory , because this actually was the system TeX initially was developed on! Not only the early TeX78 can be found there (look for the TEX*.SAI files), but also the source code of TeX82 , written in literate Pascal, which essentially still is the core of today’s TeX setups.
The most popular editor of WAITS, called E ( manual as PDF , reference , source ), had a better approach: big text files were split into pages , separated by form feeds ( ^L ), and the editor could only load some of these pages into main memory. It was recommended to keep pages less than 200 lines, which roughly are 3 kilowords. Finally, E edited files in-place and only wrote out changed pages, so fixing a single character typo, for example, just required a quick write.
In order to know where the pages start, E maintained a directory page , which was the first page of a file, starting with COMMENT (click on some links above to see an example) and then the list of pages and their offset. Thus, seeking to a specific page was very quick, and the directory page doubled as a table of contents for bigger files, which improved the user experience.
This directory page was part of the file . Compilers and tools had to be adjusted to ignore it if needed (well, FORTRAN ignored lines with C anyway…), but for example TeX had modifications (see “Reading the first line of a file”) to skip the directory page.
If you got curious now, it’s actually possible to run WAITS on your own machine! Grab SIMH and a WAITS image and you can get it running pretty easily. I recommend having a Monitor Command Manual handy. (Also note that currently there is a bug in the SIMH repository which makes graphical login impossible. I can vouch that commit c062c7589 works.)
Remapping the mouse button can be done with xinput :
Touching the trackball will also wake up my notebook by default, but this can be changed by putting disabled into the associated /sys/bus/usb/devices/*/power/wakeup .
I have been using Emacs since 2001, any only really learned Vim in 2007. Of course, I did quick admin edit tasks with it before, but in 2007 I had a small job where I had to develop on machines across the ocean, with only vim installed. As latency was high (and mosh didn’t exist yet), efficient use of Vim was essential. After the summer of 2007, I was fairly familiar with Vim. I still use Emacs for my main editing and programming tasks, but on remote machines and for small edit tasks I primarily use Vim.
I always found reading other people’s .vimrc (and analyses ) interesting, so today I’ll share mine. Well, I actually have two .vimrc , a “big” one (233 lines) and a minimal one.
Why do you need a .vimrc at all? Well, since Vim 8, a defaults.vim is loaded else with some annoying settings (such as enabling mouse and colors), so you have two options:
Run Vim as vi , but then you are in compatible mode which disables some useful things.
Create a .vimrc —even if it’s empty—to start vim in non-compatible mode. But then I can also can fetch my minimal one and set some defaults I prefer.
My minimal .vimrc is only 64 bytes long and does 80% of the job, so let’s dissect it:
As you can see, it only sets a few things in a single set command:
nocp : nocompatible ; disable Vi compatible mode and enable a bunch of features. This is superfluous if you save the file as .vimrc , but not if you want to try it with vim -u .vimrc.minimal .
bs=2 : backspace=indent,eol,start ; allow backspace to delete the autoindent, linebreaks or the start of insert mode. This is just convenient sometimes.
cot= : completeopt= ; this disables the popup menu for, e.g., ^X^F (filename completion). I never want popups to hide the text in my buffer.
hid : hidden ; this allows having open buffers that are not displayed, and really should be the default.
is : incsearch ; search as you type, pretty convenient.
ru : ruler ; show the current line number.
sm : showmatch ; quickly jump to the matching open bracket when typing the closing bracket.
t_te= t_ti= ; unset the terminfo sequences that usually (de-)activate the alternate screen—I want the screen contents to stay after editing.
vb : visualbell : flash the display instead of beeping.
wim=longest,list : wildmode=longest,list : In command-line mode, complete the longest common string, then list alternatives. This is the default in bash / readline and how I configured my zsh .