How I Do
environment software practicesSometimes people ask me how I do things digitally. They can read this.
Introduction #
This document provides a view into how I use computers with a focus on software. It is organized into major software categories with subsections for each important package.
It also serves as notebook of documentation to remind me of some details. Expect some incomplete sections and to see changes over time.
The extensive configuration files are not available but I have some intention to rectify that at some point.
Typography #
In this document, the prompts used in examples are as:
# command run as root
$ command run as user in bash
❯ command run as user in fish
A command
is written like that.
Hardware #
Hardware interests me less than software so I do not go into detail other than to give hostnames to four hardware roles:
hometop
- personal laptop (thinkpad x1e gen2)
worktop
- work laptop (thinkpad x1c gen5)
homestation
- personal workstation (custom build)
workstation
- work workstation (ASLab Marquis)
homeserver
- personal server with ports exposed to the Internet
For the last one, I maintain a dynamic DNS subdomain from the great folks at afraid.
Configuration #
Configuration files (“dotfiles”) are stored in a private Gitea instance and most clones are managed with vcsh and myrepos with pass and etckeeper managing its own.
The vcsh
git
repo manager allows multiple git
repos to supply files into $HOME
without any actual .git/
directory there. It allows for the target filesystem space to be interleaved with files managed in separate git repos. Seems crazy, works great.
My vcsh
repos include config for: bash, bbdb, emacs, git, mr (myrepos), nixpkgs, sawfish, scripts, ssh, systemd, tmux, weechat bbdb for contacts in BBDB and a consolidated “dots” for all the dot files. I started with many fine-grained repos and mr to help do bootstrap but this was more work with no perceived benefit. I kept bbdb separate as one day I may make the “dots” repo public. Some setup of individual things are described in following sections but first how vcsh
is handled.
Initialize #
Each repo needs a one time setup like:
# apt install vcsh
$ vcsh init bbdb
$ vcsh bbdb add .bbdb
$ vcsh bbdb commit -m "First commit"
$ vcsh bbdb remote add origin gogs@homeserver:bv/dot-bbdb.git
$ vcsh bbdb push -u origin master
Multiple repositories #
There is built-in support for multiple repositories in vcsh
, eg:
$ vcsh status
$ vcsh pull
$ vcsh push
Bootstrap new account #
A new account can clone individual repos:
$ vcsh clone gogs@homeserver:bv/dot-bbdb.git bbdb
Ignoring #
Any git
command run through vcsh
uses $HOME
as the Git working dir.
$ vcsh bbdb status
[... long list of untracked files ...]
You can have vcsh
Git command ignore anything not explicitly committed to a vcsh
Git repository:
$ vcsh write-gitignore bbdb
$ vcsh bbdb status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
The write-gitignore
command will create a file like:
$ cat ~/.gitignore.d/bbdb
*
!/.bbdb
In the case of sub-directories of interest which exist among siblings to ignore one has to add exhaustive paths to the allow list. For example,
*
!/.local
!/.local/share
!/.local/share/applications
!/.local/share/applications/*.desktop
Making updates #
Here we make a change to the omnibus dots package
❯ emacs -nw .config/kitty/(hostname).conf
❯ vcsh dots add .config/kitty/(hostname).conf
❯ vcsh dots commit -am "customize for "(hostname)
❯ vcsh dots push
Applying updates #
❯ vcsh dots pull
❯ vcsh pull # en masse
Checking for updates #
I want my prompt to tell me when a local account has modified, is behind the remote vcsh
or ahead of it (made a commit but not push). To check the remote takes time and also needs SSH credentials. The functionality is in vcsh-extra with commands hooks
, probe
and cron
which call both and fetch
.
- fetch
- the
fetch
command simply does a:
vcsh foreach fetch
- probe
- the
probe
command will runvcsh status --terse
and parse it for state to touch fileslast-{ahead,behind,modified}
(removing any stale ones). - hooks
- the
hooks
command install vcsh hooks which will run theprobe
command named after an action. Ie in:post-{pull,push,commit,enter,run}
is:
vcsh-extra probe
- cron
- the
cron
command bundles calls the three commands in sequence after
eval $(keychain --quiet --noask --eval id_rsa)
In summary, the cron job runs once per hour, fetching but not applying any changes and doing the probe
to summarize what state that leaves the local vcsh
repositories.
When doing vcsh
commands the hooks run to repeat the probe
(which is fast enough).
Noticing changes #
In the shell prompts I add an indicator of the vcsh state.
For bash
the PROMPT_COMMAND
will check for the existence last-{ahead,behind,modified}
files and prepend a little marker to the prompt. If all three types of “dirty” occur, the prompt looks like:
{ABM}bv@hal:~
$
For fish
, a _tide_item_vcsh()
function is defined to do similar.
Editor #
Emacs #
I use Emacs for Email (GNUS), Contacts (BBDB), software development, document and presentation production (orgmode and LaTeX), bookmark management (org-protocol
and org-capture
) and web form text entry (atomic-chrome
). Emacs 27 is soon to be released but I can’t wait so I build it from source (see Source). It now allows XDG_CONFIG_HOME
which I make use of by conceptually doing:
$ rm -rf .emacs*
$ mkdir .config/emacs
Typing emacs
then uses $XDG_CONFIG_HOME/emacs/init.el
. There’s lots of fashionable ways to configure init.el
. I don’t follow then except to break up the config into many init-*.el
and (require)
them in a big list.
Emacs packages #
I heavily use use-package and in two modes. I want the ability to blow away any emacs.d/elpa/
area and rebuild it any time but normally don’t want to spend the extra load time to query for package state. This is in init-package.el
:
(require 'package)
(setq package-archives
'(("org" . "https://orgmode.org/elpa/")
("gnu" . "https://elpa.gnu.org/packages/")
("melpa" . "https://melpa.org/packages/")))
(package-initialize)
;; uncomment this block and restart emacs to get new packages
;;;;;
;; (setq use-package-always-ensure t)
;; (package-refresh-contents)
;; (unless (package-installed-p 'use-package)
;; (package-install 'use-package))
;;;;;;
(require 'use-package)
(provide 'init-packages)
Modular config #
I factor my Emacs configuration as par modular-config
with “modules” in ~/.config/emacs/init/*.el
and some top level configs listed like:
(use-package modular-config
:custom
(modular-config-list
'(
(full (base gui orgmode dired smex spelling markdown lisp cpp python jsonnet tail))
(email (base gui orgmode email))
(empty ())
(plain (base))
(main (base gui orgmode))
;; Used from EDITOR
(cmdline (base cli))
;; Used from $VISUAL
(visual (base gui))
(blog (base gui orgpub dired smex spelling markdown cpp python))
(prog (base gui orgmode dired smex spelling markdown cpp python))
;; for calling from GhostText, except we still do it
;; through init-atomic-chrome.el
(ghost (base gui dired ivy smex spelling markdown))
;; for calling from $EDITOR
(shell (base gui dired ivy smex spelling))
))
(modular-config-default 'full)
(modular-config-path "~/.config/emacs/init")
:config
(modular-config-command-line-args-process))
I then may select a configuration on the command line like:
$ emacs --config plain [...]
GNUS/BBDB #
t.b.d.
Emacs servers #
To support bookmark capture (Firefox + org-protocol + a script) and text entry editing (GhostText + atomic-chrome) I have dedicated Emacs server configuration as well. These servers are started via supervisord
which itself starts from cron:
$ crontab -l|grep supervisord
@reboot supervisord -c /home/bv/scripts/supervisor.conf
That =~/scripts/~ directory is in vcsh
. The two Emacs servers are started like:
[program:emacs-capture]
command=%(ENV_HOME)s/scripts/emacs-start-server capture
directory=%(ENV_HOME)s
autorestart = false
[program:emacs-atomic-chrome]
command=%(ENV_HOME)s/scripts/emacs-start-server atomic-chrome
directory=%(ENV_HOME)s
autorestart = false
This emacs-start-server
script is mostly to remind me how to start Emacs properly. It boils down to running:
exec emacs -q --fg-daemon=${name} -l ~/.config/emacs/init-${name}.el
As such the nominal init.el
is not sourced. Each server is self
contained including its custom.el
and its elpa/
area.
For bookmark capture I configure Firefox to call ~/scripts/emacs-capture
script for any org-protocol://
links. Effectively it calls:
emacsclient -n -c -s capture \
-F "((name . \"emacs-capture\") (height . 20) (width . 80))" \
"org-protocol://capture://w/<encoded-url>/"
This runs on the “capture” server and since it uses emacsclient
it starts very fast.
Terminal #
Kitty #
I’ve tried many terminals over the years and for about the last year I have been very happily using the Kitty terminal. I mean the one written in Python/OpenGL and not the on derived from Putty. Some reasons why I like it:
- emoji support!
C-S-h
to load scrollback intoless
- fast, beautiful text, Free Software
It also has sub-programs called “kittens” such as kitten icat foo.png
to show a graphic in the terminal. Or kitten diff
to show a pretty side-by-side diff. These are nice but I rarely use them.
Here is an install command:
python3 setup.py --prefix=/usr/local/stow/kitty-0.19.3 linux-package
See kitty build instructions and Stow for more info.
No particularly fancy config. It lives in .config/kitty/kitty.conf
and ends with:
include local.conf
And that file is made locally, once per account:
❯ ln -sf ~/.config/kitty/{(hostname),local}.conf
I start weechat
in a special kitty:
❯ kitty -o 'map kitty_mod+e kitten hints --customize-processing weechat_hints.py' weechat
Where that Python script is from https://github.com/GermainZ/kitty-weechat-hints. I can then give C-S-e
to kitty followed a number matching one of the found URLs to open. The weechat_hints.py
does the heavy lifting to form the URL in the face of possible line splitting by weechat.
I tell kitty
to open URLs or other hyperlinks via:
open_url_with kitty-open
Which merely redirects to my personal open
command, described below.
Shells #
I have moved to the fish
shell but have been a long time and still sometimes user of bash
. From fish
sessions I will sometimes still start bash
to do some complex command which I’ve yet to master in fish
. In this mixed environment it is sometimes necessary to explicitly set SHELL
to either fish
or bash
as some commands are sensitive to the value.
Fish #
Fish is a really amazing shell which requires very little configuration to make it “feel right” (unlike bash
). Here are a few things I do with fish.
I use the tide prompt which is very nice, easy and popular. Amazingly, it is as I like it out of the box and I do very little customization. The vcsh
customization described above is one exception.
I use this fzf
/ Fish integration:
$ fisher add PatricF1/fzf.fish
Only customization is to override the C-f
keybinding as it’s needed for my Emacs-trained fingers for character-forward. In config.fish
# override fzf bindings
bind --erase \cf
bind \co '__fzf_search_current_dir'
To use direnv
I add per docs, conf.d/direnv.fish
with
eval (direnv hook fish)
When I started learning Fish, I ported my shell implemenation shist of ash to fishql. This gave a nice vehicle to dive into Fish programming. However, I’ve stopped using it because I find I almost never actually use the SQL query functionality.
As kitty
has support for ls --hyperlink
I modify fish’s ls
command to add it. I did not see a “right” way to do this so I copied ls.fish
from a recent install to .config/fish/functions/ls.fish
and added a __fish_ls_opts
variable to the final command call and then run
❯ set -U __fish_ls_opts --hyperlink=auto
This now gives me the dubious pleasure of clicking on Kitty’s rendering of the ls
command and having open
handle that. More on opening files below.
Bash #
Though I have moved to fish
, I keep my bash
setup alive as I sometimes will start bash
from a fish
session.
My .bashrc
is run for login or subshells. It delegates configuration to scripts under /.bash/{functions,variables,apps}/*.sh
and “mounts” some git subtrees under /.bash/subtrees
.
One subtree of note is shist which is my Bash implementation of advanced shell history. This integrates with Bash prompting to record history in an Sqlite3 database.
I strongly avoid using alias
(eg, no ll
for ls -l
) as I think inventing my own Unix command set is an anti-pattern. I do capture some larger commands in Bash functions so that tab-completion can remind me of the (eg, a bunch of emacs-server-*
functions to manage different Emacs servers).
I used to loop over $HOME/opt/*/{bin,lib,man,lib/pkgconfig}
to set PATH, LD_LIBRARY_PATH, MANPATH, PKG_CONFIG_PATH
. This I now deprecate in favor of a Stow-based install for common software and a per-development area governed by direnv
. See Source for more info on this aspect.
Desktop Environment #
By which I mean what the X11 (and not wayland) server manages.
I have fully migrated from the really great Sawfish to the equally delightful though different Herbsluftwm. I’ve used Sawfish since it was the official Gnome WM back in the 90’s (back before Gnome put sugar before protein). Sawfish is really a terrific stacking/floating WM but I wanted to move to a tiling paradigm. Sawfish has some rudimentary support for tiling and I initially toyed with contributing to its development but figured I should first try some “real” tiling WMs. Along came Herbsluftwm which I chose over the others initially because it had these nice graph diagrams right in the man page. I’ve since looked at others (awesome, i3, dwm) and they are nice but I got lucky on the first draw and have fallen deeply for it. So, I bid Sawfish a fond farewell and wish the community all the best (there are tens of us!).
Herbsluftwm #
Herbstluftwm [German for autumn wind(ow manager)] is configured by issuing commands from the client application herbstclient
(hc
). These commands are typically captured in two files:
autostart
- main configuration holding keybindings, theme settings and starting any “panels”
panel.sh
- a long running process transforming WM events (via
hc --idel
) and others into input piped to a “bar” program (dzen2
is default and nice but I moved to usingbarpyrus
which is started directly instead of apanel.sh
)
A lot of great shell hackery exists in this space including the default event-driven panel.sh
which taught me a thing or three. But, I wanted to rely on something more “formal” so created herbie. It contains Python reimplementations of a lot of Herbsluftwm community shell hackery as well as a few new things. It’s documentation describes how to configure and integrate into autostart
.
Barpyrus #
Also from author of herbstluftm, this provies a Python wrapper around lemonbar and replaces the default panel.sh
driving dzen
. It is configured with Python and my config is hugely inspired by barpyrus.py
from https://github.com/the-compiler/dotfiles. My minor improvement was to add some unicode icons and a few additional metrics.
Setting the fonts is an important detail. In main()
:
bar = lemonbar.Lemonbar(
geometry=geom,
cmd="/usr/local/bin/lemonbar",
font=f'DejaVu Sans-{font_height}',
symbol_font=f'FantasqueSansMono Nerd Font-{font_height}',
foreground=Gruv.FG, background=Gruv.BG)
Where font_height
is determined based on host and monitor size. Toward the top of main()
:
import socket
host = socket.getfqdn()
monitor = int(sys.argv[1]) if len(sys.argv) >= 2 else 0
x, y, monitor_w, monitor_h = hc.monitor_rect(monitor)
if int(monitor_h) <= 1080:
height = 16
font_height = 12
elif host == "hometop":
height = 24
font_height = 12
elif ...
Rofi #
I use rofi
for various things. herbie
calls it and is called by it and it is called by various herbstluftwm
keybindings.
rofi-screenshot
custom script to take screen shots and optionally upload them to a popular image host with help ofmaim
andrephile
. See Photos.rofi-pass
for accessing my password store (see Passwords)- built in launcher with nice icons
- global and per tag window selection
- herbstluftwm “task based” tag management via herbie
- herbstluftwm tag layout management via herbie
Like with kitty
, a ~/.config/rofi/config-(hostname).rasi
file which is symlinked to config-host.rasi
holds the per host customization. Mostly this is to set a font size that works well for the host’s monitor(s). For example, for a 4k 15" laptop monitor screen.
configuration {
font: "FantasqueSansMono Nerd Font 44";
}
Sawfish #
The Sawfish X11 window manager was at one time the official WM for Gnome. That is the time when I first started using it, moving from TWM and then FVWM. I’ve tried a few since but always come back. Sawfish is configured and largely written in its own flavor of lisp (rep) and so can reasonably be considered the Emacs of window managers. For configuration, it does an even better job than Emacs of providing both a programmable and a GUI configuration method and the two work largely well together. Some of the reasons I use Sawfish:
- hugely configurable but sane defaults
- my fingers have learned the key bindings I chose years (decades!) ago
- I bake the configuration into a git repo
- I can run an arbitrary program from a command line without opening a terminal
- tab-like navigation between virtual desktops
- window “filling” which I find a better compromise between stacking and tiling idioms
- window dressing with themes and per matched windows (eg, Firefox has no borders)
Desktop environment #
I largely have moved away from using a full DE. I used MATE (Gnome 2) with Sawfish up until switching to Herbstluftwm. All the MATE-provided bits now get replaced piecemeal. Some of note:
rofi
for starting apps and various other menu-oriented actionsbarpyrus
for indicators and “workspace” tabs (Herbstluftwm “tags”)nmtui
replaces the Network Manager appletcaja
I still keep around for rare times I want a GUI to browse a directory
Web #
Firefox #
Firefox is the least worse web browser despite how Mozilla tries so hard to kill off its user base. Not much to say except how I battle some of its worse behavior:
Load URL via remote without grabbing attention #
Set browser.tabs.loadDivertedInBackground
to true
in about:config
. Otherwise sending a URL via remote open will have Firefox grab focus, possibly switching to it on a different virtual desktop. This is super annoying when doing important things like loading the morning’s web comics from liferea
.
Emacs-like keybindings in firefox #
This is one of the most frustrating things and most of the things found online are wrong. What to do depends on the desktop environment and its version and maybe the distribution.
Debian buster
and MATE 1.20.
gsettings set org.mate.interface gtk-key-theme 'Emacs'
Or,
~/.config/gtk-3.0/settings.ini:
# Get firefox to use emacs keybindings
[Settings]
gtk-key-theme-name = Emacs
For editor about:config
and
devtools.editor.keymap emacs
Using Emacs to edit text #
There used to be ItsAllText. Now there is Edit with Emacs and GhostText. The former I could not make work and the latter seems fine.
GhostText needs atomic-chrome
to be running on Emacs. It’s available from the Emacs package sites. In Emacs servers I describe how the Emacs server for atomic-chrome to talk to get started. The main Emacs parts in init-atomic-chrome.el
are:
(setq server-name "atomic-chrome")
(use-package markdown-mode
:ensure t
:config
(setq markdown-command "/usr/bin/markdown"))
(use-package markdown-preview-mode
:ensure t)
(use-package atomic-chrome
:ensure t
:config
(setq atomic-chrome-default-major-mode 'markdown-mode)
(setq atomic-chrome-url-major-mode-alist
'(("github\\.com" . gfm-mode)
("reddit\\.com" . markdown-mode)
("redmine" . textile-mode)))
(setq atomic-chrome-buffer-open-style 'frame)
)
(atomic-chrome-start-server)
To use, I click the GhostText icon, sometimes it prompts me for which text area to edit, then an Emacs frame pops us. As I type in Emacs the text entry updates.
- TODO get nice rendered preview for GitHub and Reddit text entries
Bookmark capture #
I want to capture bookmarks to Emacs Org files. I mainly use https://github.com/karlicoss/grasp for that. It uses a Firefox add-on to send info to a grasp server written in Python. The add-on does a better job actually working on all sites (eg, GitHub causes problems with org-protocol
described below). While this is an Emacs-free capture system, the resulting files are in good org-mode markup.
The other method I tried is with a Firefox bookmarklet to initiate org-protocol
based capture:
javascript:location.href='org-protocol://capture://w/'+encodeURIComponent(location.href)+'/'+encodeURIComponent(document.title)+'/'+encodeURIComponent(window.getSelection())
The /w/
corresponds to an org capture template
(setq org-capture-templates
(quote
(("w" "Web Bookmark" entry
(file+headline "~/org/webcapture.org" "Bookmarks")
"* %a :website:%^G\n:PROPERTIES:\n:CREATED: %U\n:END:\n%i\n %?"
:empty-lines 1 :immediate-finish nil)))
org-agenda-files (list "~/org/webcapture.org"))
Some frame management is done with:
(defadvice org-capture
(after make-full-window-frame activate)
"Advise capture to be the only window when used as a popup"
(if (equal "emacs-capture" (frame-parameter nil 'name))
(delete-other-windows)))
(defadvice org-capture-finalize
(after delete-capture-frame activate)
"Advise capture-finalize to close the frame"
(if (equal "emacs-capture" (frame-parameter nil 'name))
(delete-frame)))
Kill Sticky #
The web is mostly festering garbage and getting worse over time. Many web sites, even ones that should know batter (stack overflow) put up so much obscuring crap that it can be hard to see the content. Enter Kill Sticky (not a Tarantino movie, but better). It is this bookmarklet:
javascript:(function()%7B(function%20()%20%7Bvar%20i%2C%20elements%20%3D%20document.querySelectorAll('body%20*')%3Bfor%20(i%20%3D%200%3B%20i%20%3C%20elements.length%3B%20i%2B%2B)%20%7Bif%20(getComputedStyle(elements%5Bi%5D).position%20%3D%3D%3D%20'fixed')%20%7Belements%5Bi%5D.parentNode.removeChild(elements%5Bi%5D)%3B%7D%7D%7D)()%7D)()
Click is not select all #
One of the more infuriating things which changed in somewhat recent Firefox versions is that clicking on the urlbar selects the damn content. This is such disgusting reprehensible behavior that I would not be surprised if its existence is evidence that Chrome developers are operating as moles inside the Firefox organization.
Thank ioctl for the work of https://github.com/SebastianSimon/firefox-omni-tweaks.
Running this nicely written bash script will munge some omni.ja
files
in the FF install to undo the mess.
❯ wget -O scripts/fix-firefox-omni 'https://raw.githubusercontent.com/SebastianSimon/firefox-omni-tweaks/master/fixfx.sh'
❯ chmod +x scripts/fix-firefox-omni
❯ fix-firefox-omni -f /usr/lib/firefox-esr -o preventClickSelectsAll
Finally, restart FF and sigh with deep contentment.
Audio/Video #
mpv #
I use mpv
for just about all A/V. I also try to make it run for YouTube and the like as it is less resource intensive than YT’s web page on FF. See the section Open below for how things are routed to mpv. Calling
mpv --profile=yt <youtube-url>
Will invoke this section of ~/.config/mpv/mpv.conf
[yt]
script-opts=ytdl_hook-ytdl_path=yt-dlp
ytdl-format=137+251
This requires yt-dlp
installed. It also does not always work for reasons I do not understand. Either YT does not have the formats and the command fails outright or YT sends data so damn slowly that the stream constantly pauses to buffer. Outright failure is checked for in web-browser
(see Open below) and the URL is fail-over dispatched to x-www-browser
.
Source #
See also Configuration and individual package sections. Here I describe ways I install software locally which means outside of Debian’s package management.
DIY opt #
For some development dependencies, I will build and install using $HOME/opt/<pkg>
as the install “prefix”. I try to avoid making these part of day-to-day environment.
Stow #
I used to follow the DIY opt method to provide software that is built from source until I had a weird time traveling revelation. I’m essentially the only user on most machines where I need what was in DIY opt so why not just install to /usr/local
. The one thing that was lacking was pristine uninstallation. To get that I started using the venerable GNU Stow package.
Even though implemented in Perl, GNU Stow works great (joke)! One-time setup
# mkdir /usr/local/stow
# chgrp staff /usr/local/stow
# chmod g+s /usr/local/stow
# sudo adduser bv staff
I then install from source to a location under the Stow directory with a name based on the package name and version. Eg
$ ./configure --prefix=/usr/local/stow/rofi-1.6.1/
$ make -j (nproc)
$ make install
Then finish with
# cd /usr/local/stow
# stow rofi-1.6.1
Common source setup reminders #
CMake #
$ mkdir ~/opt
$ cd pkg
$ mkdir build && cd build
$ cmake -G Ninja .. -DCMAKE_INSTALL_PREFIX=$HOME/opt/pkg [...]
$ cmake --build . -- -j$(nproc)
$ cmake --build . --target install
autoconf #
$ mkdir ~/opt
$ cd pkg
$ ./autogen
$ ./configure --prefix=$HOME/opt/pkg
$ make -j$(nproc)
$ make install
Python #
When I work on a Python package I use direnv
(see also Shells) do:
# apt install direnv
$ cd a-python-package/
$ echo layout python3 > .envrc
$ direnv allow
$ pip install -e .
A lesser way but which does not require direnv
$ python3 -m venv venv
$ source venv/bin/activate
$ pip install -e .
Things I explicitly don’t use #
Spack #
Spack is great for managing complex and shared software deployments. From time to time I have used it for managing personal software. That has been modus hiatus for a while due to various minor annoyances related to personal usage. A lot has changed with Spack since then and I have some plans to revisit this approach.
Nix/Guix #
I have used Nix and Guix to provide add-on environments. They always start out great but turn horrible. In part, I just can not get a handle on the Nix language. Guix’s use of guile is much better but it’s like learning Emacs, it’s a deep rabbit hole. Like Spack, this remains an anti-use.
Photos #
See also Syncthing for how photos are extracted off my phone.
Rephile #
I used to dump photos from scans, cameras or phones into various directories. This grew organic and I’ve lost chunks of memories when directories went missing. So I got “serious” and wrote rephile. It still allows a distributed store sprinkled around various directories and it supports git-annex repositories. It keeps an sqlite
database of metadata and has some extras such as uploads to a popular image host.
Sync #
Syncthing #
Syncthing is a jewel of a system. It’s your own personal peer-to-peer (which here means you-to-you or you-to-friends not you-to-anonymous-strangers) file transfer system. Encryption, distribute hash table, UDP hole punching, simple beautiful web interface, cross platform. What more can you ask for?
I run it on my android phone and all Linux machines, home and at work.
For the phone I sync photos and org files. For Linux machines various
things but in particular a ~/sync/
is shared between all and holds
mostly my talks. My ~/org/
holds my personal “wiki” where I hold
proto-documents, notes, etc as well as bookmarks grabbed as described
above.
One caution: the optional use of relay for data is safe and can be useful to get around tricky routing problems (both ends behind very strict firewalls) but take note that some hosts that provide Syncthing relay are also TOR nodes. Despite these being wholly separate data streams, some idiot “security” mechanisms will flag your Syncthing as a TOR node because it happens to connect to an Internet host which also happens to provide a TOR service.
Git annex #
tbd. git + big files + sync rules + metadata. Used for photos and other.
Passwords #
Pass #
I use pass to manage my passwords and distribute them via a private repo in my personal Gitea instance. I almost never use the same password for different endpoints and almost always use high character random passwords which I never bother to remember. pass
makes that possible and easy.
Time #
arbtt #
At work we have to “track” our time even though we don’t get payed hourly. It feels to me a very annoying and demeaning thing. I “protest” by keeping hugely, massively, stupidly pedantic track of my time. I know, it’s nonsensical and weird but it allows me to comply without raising my blood pressure. Fight idiocy with lunacy, I always say.
I do this by running arbtt on my work computers. It starts with cron
$ crontab -l |grep arbtt
@reboot /home/bv/scripts/start-arbtt-capture
When my employer nags me to enter this very crucial data I run a script
$ time-sheet
...
heather,Sat,2020-05-02,0.87,1.45
heather,Sun,2020-05-03,1.68,1.68
heather,Mon,2020-05-04,2.24,6.77
heather,Tue,2020-05-05,2.80,7.89
heather,Wed,2020-05-06,2.99,5.79
heather,Thu,2020-05-07,8.47,9.47
heather,Fri,2020-05-08,3.49,9.16
heather,Sun,2020-05-10,2.30,3.24
Second to last column shows total hours my session was active, last column is time diff between last action and first in the day (MTW I was on “vacation” so less than nominal eight).
Time zones #
I have a hacked scrip to help me with timezones
$ time-to-meet tomorrow
February 10, 2021
Here 08 09 10 11 12 13 14 15 16 17 18 19 20
UTC 13 14 15 16 17 18 19 20 21 22 23 24 25 (+5)
Los_Angeles 05 06 07 08 09 10 11 12 13 14 15 16 17 (-3)
Chicago 07 08 09 10 11 12 13 14 15 16 17 18 19 (-1)
London 13 14 15 16 17 18 19 20 21 22 23 24 25 (+5)
Zurich 14 15 16 17 18 19 20 21 22 23 24 25 26 (+6)
Japan 22 23 24 25 26 27 28 29 30 31 32 33 34 (+14)
I’ve since redone this in Python at https://github.com/brettviren/titome
❯ titome
today: Friday 11/26 09:00 (2 hours ago)
┏━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┓
┃ local ┃ 9:00 ┃ 10:00 ┃ 11:00 ┃ 12:00 ┃ 13:00 ┃ 14:00 ┃ 15:00 ┃ 16:00 ┃ 17:00 ┃ 18:00 ┃
┡━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━┩
│ LBNL │ 6:00 │ 7:00 │ 8:00 │ 9:00 │ 10:00 │ 11:00 │ 12:00 │ 13:00 │ 14:00 │ 15:00 │
│ FNAL │ 8:00 │ 9:00 │ 10:00 │ 11:00 │ 12:00 │ 13:00 │ 14:00 │ 15:00 │ 16:00 │ 17:00 │
│ BNL │ 9:00 │ 10:00 │ 11:00 │ 12:00 │ 13:00 │ 14:00 │ 15:00 │ 16:00 │ 17:00 │ 18:00 │
│ RAL │ 14:00 │ 15:00 │ 16:00 │ 17:00 │ 18:00 │ 19:00 │ 20:00 │ 21:00 │ 22:00 │ 23:00 │
│ CERN │ 15:00 │ 16:00 │ 17:00 │ 18:00 │ 19:00 │ 20:00 │ 21:00 │ 22:00 │ 23:00 │ 0:00 │
│ KEK │ 23:00 │ 0:00 │ 1:00 │ 2:00 │ 3:00 │ 4:00 │ 5:00 │ 6:00 │ 7:00 │ 8:00 │
└───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┘
Meetings #
Most people around me use “doodle” which is kind of a pain. when2meet is far superior.
Open #
The whole story surrounding opening files is insane, especially once one leaves the manicured gardens of big name DEs (Gnome and the like). Thankfully others are as fed up as me and have come up with good solutions. Central to mine is using https://github.com/chmln/handlr. I call handlr open
through my own open
script which I used on the CLI or set to be called from kitty, liferea, etc.
Via handlr
commands I manually set an explicit mapping from mime types to .desktop
files. The former in ~/.config/mimeapps.list
and the latter under ~/.local/share/applications/
. All of this goes into the vcsh
repo dots
.
The handlr open
call can also handle URLs which I map to a web-browser.desktop
that simply calls my web-browser
script and that dispatches the URL to an application based on pattern matching. Some of the more used dispatching:
- video looking URLs go to
mpv --profile=yt
(see section onmpv
) - twitter looking URLs get rewritten to nitter.net
Todo #
- factor vcsh repos to move non-secret dotfiles to github and link to them from here
- section on operating system, Debian GNU/Linux
- section on ssh (many tips/tricks, jsonnet-based config)
- section on vpn (nord, linux, phone, router)
- section on router (tomato firmware)
- rss
- videos