๐พ Archived View for gemini.omarpolo.com โบ dots โบ shells.gmi captured on 2021-12-17 at 13:26:06. Gemini links have been rewritten to link to archived content
โฌ ๏ธ Previous capture (2021-12-03)
-=-=-=-=-=-=-
I don't know how "portable" a `.profile' can be, but let's try!
Although I'm not using acme as my go-to text editor anymore, I still like to use it from time to time, and have the rest of the plan9 ports at hand.
I manually fetched and installed the ports in `/usr/local/plan9', and need to define `$PLAN9' in order for the various tooling to work.
PLAN9=/usr/local/plan9 export PLAN9
I also tend to have an abnormal `$PATH':
PATH=$HOME/bin:$HOME/opt/emacs/bin:$HOME/opt/gcc10/bin:$HOME/go/bin:$HOME/opt/unnethack/bin:$HOME/.local/bin:$HOME/.node_modules/bin:/home/ports/infrastructure/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin:/usr/games:/usr/local/jdk-11/bin:$PLAN9/bin export PATH HOME TERM
Let's split it:
Just in case I want to play with lua again:
if which luarocks-5.3 2>/dev/null >/dev/null; then eval "$(luarocks-5.3 path --bin)" fi
Tell npm to install things globally in the right directory:
export npm_config_prefix=~/.node_modules
ksh doesn't have a "deafult" configuration file (like `~/.zshrc' for zsh or `~/.bashrc' for bash); instead, if called interactively it loads the file pointed by `$ENV'. Tell ksh to load `~/.kshrc' then:
export ENV=$HOME/.kshrc
An UTF-8 locale is almost mandatory, and since we're there use `en_US' as the language, even if it's not my main tongue
export LANG=en_US.UTF-8
Got is quickly becoming my favourite version control system. It should be able to load the author data from a config file, but I still keep this variable, just in case
export GOT_AUTHOR="Omar Polo <op@omarpolo.com>"
Sometimes I need to do stuff with Docker. I have a virtual machine running alpine with docker configured, and this bit here will allow docker-cli to transparently talk to the VM:
export DOCKER_HOST=ssh://op@100.64.2.3:22
I like to use `mg' as my default editor, but under `vterm' is a bit of a pain in the ass to use, since the various `C-c' and `C-x' command are intercepted by Emacs. Thus, use `vi' as the editor when `INSIDE_EMACS' (which sound strange, but for programs like `got' that spawns an editor it's the best choice I found)
if [ -z "$INSIDE_EMACS" ]; then VISUAL=mg EDITOR=mg else VISUAL=vi EDITOR=ed fi export VISUAL EDITOR
less should be the default pager pretty most everywhere, but ensure that!
export MANPAGER=less
I've found a cool pager for PostgreSQL, [pspg]. It's designed explicitly for tabular data. Extra points for having some cool light themes! Tao light theme (the number 20) is my favourite.
export PSQL_PAGER='pspg -s20'
I'm using reposync to manage my local clone of the OpenBSD source tree. Technically this isn't needed, because now `/home/ports' is a checkout from `/home/cvs/...', but anyway
export CVSROOT=/home/cvs
This is just to make some command outputs a bit nicer:
export BLOCKSIZE=1m
I don't particularly like colored outputs when I'm in front of a terminal, so I tend to disable them:
export NO_COLOR='yes, please' export CMAKE_COLOR_MAKEFILE='OFF' export WG_COLOR_MODE=never
As an exception to the "no colors" rules, I'm trying to enabling some colors in `tog', but cautiously, and see how it goes:
export TOG_COLORS=yes export TOG_COLOR_DIFF_MINUS=magenta export TOG_COLOR_DIFF_PLUS=blue export TOG_COLOR_DIFF_CHUNK_HEADER=green export TOG_COLOR_DIFF_META=default export TOG_COLOR_COMMIT=default export TOG_COLOR_AUTHOR=default export TOG_COLOR_DATE=default export TOG_COLOR_REFS_REMOTES=red
Then disable the colors in boot (a clojure build tool I'm not using anymore) and fix its `gpg' command:
export BOOT_COLOR=no export BOOT_GPG_COMMAND=gpg2
At some point I had a problem with leiningen that required this workaround. I've mostly switched to `deps.edn' now, but it's useful to keep this around:
export SHASUM_CMD='cksum -a sha256'
At least on OpenBSD, automake and autoconf requires these variables to be set to work
export AUTOCONF_VERSION=2.69 export AUTOMAKE_VERSION=1.16
Some time ago I played with [gerbil], a scheme dialect, and I should still have it installed.
GERBIL_HOME=/usr/local/gerbil PATH=$PATH:$GERBIL_HOME/bin export GERBIL_HOME PATH
I also played a bit with chicken. Don't remember why I set all these variables, but for the time being, keep 'em
#export CHICKEN_INSTALL_REPOSITORY=$HOME/.local/lib/chicken chicken=$HOME/.chicken/11/ CHICKEN_REPOSITORY_PATH=$chicken:/usr/local/lib/chicken/11 CHICKEN_INSTALL_REPOSITORY=$chicken CHICKEN_INCLUDE_PATH=$chicken CHICKEN_DOC_REPOSITORY=$chicken/chicken-doc export CHICKEN_REPOSITORY_PATH CHICKEN_INSTALL_REPOSITORY export CHICKEN_INCLUDE_PATH CHICKEN_DOC_REPOSITORY
I don't use ripgrep, grep is fine for me, but I remember I was particularly annoyed by the format of its output. Just in case I need to use it again, here's what I did: first define an env variable that points to a configuration file:
export RIPGREP_CONFIG_PATH=$HOME/.ripgreprc
then put the following in `~/.ripgreprc':
# disable colors --color=never # decent output format, like grep -Hn --vimgrep # use smart case --smart-case
Finally, load the specific profile for this machine, if it exists:
if [ -f "$HOME/.profile-local" ]; then . $HOME/.profile-local fi
OpenBSD ksh (sometimes called opdksh or oksh) is the default shell on OpenBSD, and is generally my go-to choice on other systems too. It has a good ratio of feature and simplicity.
if [ "$TERM" = dumb ]; then PS1='$ ' return fi
Enable emacs-like command editing and csh-like history expansion with `!'
set -o emacs set -o csh-history
Talking about history, by default ksh won't store any. I don't know how I could live without it, so please enable it!
HISTCONTROL=ignoredups:ignorespace HISTFILE=$HOME/.history HISTSIZE=10000
`reset' doesn't work as expected inside tmux, the old output can still be consulted when scrolling. If I bother to type `reset' I want to be sure that the history was cleared, otherwise I'd use `clear'.
if [ -n "$TMUX" ]; then alias reset='reset && tmux clear-history' fi
`CDPATH' is super-useful! I wrote [a post about it], also.
export CDPATH=.:$HOME/w:/home/ports:/home/ports/mystuff:$HOME/quicklisp/local-projects
I love to hate gpg! It needs some special treatments to work, and this should also fix pinentry over ssh. I'm not sure it works though, it's been a while since I connected remotely to my desktop:
export GPG_TTY=$(tty) if [ -n "$SSH_CONNECTION" ]; then export PINENTRY_USER_DATA="USE_CURSES=1" fi
The BSDs have this incredibly useful signal available, `SIGINFO', that it's a shame not to use it!
stty status ^T
I really like my prompt to be as minimal as possible. For some time I used a single colon `;' as prompt, it's really nice! At the moment though, I'm using a plan9-esque `%':
PS1='% '
I got tired of trying to remember the set of flags for `nc' to talk to Gemini serves, so here we are
# gemini host [port] # "post" stdin to the given gemini server gemini() { host=${1:?missing host} port=${2:-1965} nc -c -Tnoverify "${host}" "${port}" }
`vterm' can recognize special escape sequence to pass information (like the current directory) back to Emacs.
This is an utility function to print things for vterm:
vterm_printf() { if [ -n "$TMUX" ]; then printf '\ePtmux;\e\e]%s\007\e\\' "$1" elif [ "${TERM%%-*}" = "screen" ]; then printf '\eP\e]%s\007\e\\' "$1" else printf '\e]%s\e\\' "$1" fi }
I like to improve the default vterm experience. The following will set the hostname and path every time the `$PS1' is printed, so the vterm buffer name can stay in sync, and also overrides the `cd' command:
clear() { vterm_printf '51;Evterm-clear-scrollback' tput clear } vterm_set_title() { printf '\033]0;%s\007' "$(hostname):$PWD" } vterm_prompt_end() { vterm_printf "51;A$USER@$(hostname):$PWD"; } function cd { builtin cd "$@" vterm_set_title } vterm_set_title PS1=${PS1%% }'$(vterm_prompt_end) '
but do this only when `$INSIDE_EMACS' is equal to `vterm'!
if [[ "$INSIDE_EMACS" = 'vterm' ]]; then fi
OpenBSD ksh has a limited support for programmed completions! The idea is that completions are provided via a `complete_$programname' array. It's possible to provide specific completion for the nth argument via the array `complete_$progname_$nth'.
I mean, it's not `zsh' or `fish', but it's more than enough!
Here's a completion for ssh and scp:
HOST_LIST=$(awk '/Host /{print $2}' ~/.ssh/config | xargs echo) set -A complete_ssh -- $HOST_LIST set -A complete_scp -- $HOST_LIST
and another simple one for kill and pkill
set -A complete_kill_1 -- -9 -HUP -INFO -KILL -TERM set -A complete_pkill_2 -- -SIGHUP -SIGUSR1 -SIGUSR2 -SIGTERM -SIGKILL
If we're on a machine with `vmd(8)', the following will add completions for the subcommands and for the virtual machines:
if pgrep -fq /usr/sbin/vmd; then set -A complete_vmctl_1 -- console load reload start stop reset \ status send receive set -A complete_vmctl -- \ $(vmctl status | awk '!/NAME/ { printf "%s ", $NF }') fi
Completions for ifconfig are also nice:
set -A complete_ifconfig_1 -- $(ifconfig | grep ^[a-z] | cut -d: -f1)
Add some for Got and Git:
set -A complete_got_1 -- \ bl blame \ bo backout \ br branch \ ci commit \ co checkout \ cy cherrypick \ di diff \ he histedit \ im import \ in init \ log \ rb rebase \ ref \ rm remove \ rv revert \ sg stage \ st status \ tr tree \ ug unstage \ up update set -A complete_git_1 -- \ checkout cherry-pick clean clone commit config \ mpull mpush \ pull push \ status
Some misc aliases:
alias ls="ls -F" alias serve="python3 -m http.server" alias ec='emacsclient -nw -c' # colors ain't welcome here! alias nim="nim --colors=off"
What follows are functions that aren't big enough to be worth a whole file.
I think I stealed this two from someone. They make a backup copy of the file and then launch an editor on that, super useful when porting. The first uses `mg' and elevates the privileges with `doas'
mgdiff() { if [ -z "$1" ]; then printf "%s\n" "USAGE: mgdiff <file>" >&2 return fi doas cp -p "$1" "$1.orig" doas mg "$1" }
The second one uses `vi' without `doas':
vdiff() { if [ -z "$1" ]; then printf "%s\n" "USAGE: vdiff <file>" >&2 return fi cp -p "$1" "$1.orig" vi "$1" }
`hist' is a quick wrapper around `history' and `grep', to quickly search for a previous command:
hist() { if [ -z "$1" ]; then printf "%s\n" "USAGE: hist <pattern>" >&2 return 1 fi history 0 | grep "$1" }
`nnn' is a quick and useful file manager for the terminal. One useful feature is "auto-cd", where one can navigate the filesystem with `nnn' and upon exit, the shell will change directory to the last visited. It's pretty simple to setup, albeit probably prone to races. While there, also define some bookmarks:
export NNN_BMS="h:$HOME;t:/tmp" export NNN_USE_EDITOR=1 bind -m '^O'='^U ncd^J^Y' ncd() { # block nesting of nnn in subshells if [ "${NNNLVL:-0}" -ge 1 ]; then echo nnn is aready running return fi export NNN_TMPFILE=$HOME/.config/nnn/.lastd nnn "$@" if [ -f "$NNN_TMPFILE" ]; then . "$NNN_TMPFILE" rm "$NNN_TMPFILE" fi }
`goman' is a small wrapper to invoke `go doc' with a pager, which is useful when reading documentation on xterm:
goman() { if [ -z "$1" ]; then echo "USAGE: goman terms..." >&2 return 1 fi go doc "$@" 2>&1 | ${MANPAGER:-less} }
`rebuild_gerbil_doc' rebuilds the website with the gerbil documentation from the source shipped with the package into `/var/www/cons.local'
rebuild_gerbil_doc() { rm -rf /tmp/build_gerbil_doc mkdir /tmp/build_gerbil_doc || return 1 cp -R /usr/local/gerbil/doc /tmp/build_gerbil_doc/ || return 1 cd /tmp/build_gerbil_doc/doc/ ./build.sh || return 1 rm -rf /var/www/cons.local/* cp -R .vuepress/dist/* /var/www/cons.local/ }
One of these days I'll spend some time to split and document each bit, and maybe drop unused stuff
# ports stuff alias portsql='sqlite3 /usr/local/share/sqlports' alias portslol='make 2>&1 | /home/ports/infrastructure/bin/portslogger .' alias portspldc='make port-lib-depends-check' alias portsldc='make lib-depends-check' alias portsplif='diff -up pkg/PLIST.orig pkg/PLIST' alias portstsilp='mv pkg/PLIST.orig pkg/PLIST' alias portspy3plist='FLAVOR=python3 make plist' alias portsrc='cd `make show=WRKSRC`' alias portsfast='MAKE_JOBS=6 make' portsdiff() { cvs diff > /home/ports/mystuff/${PWD##*/}.diff ; less /home/ports/mystuff/${PWD##*/}.diff ;} portslessdiff() { less /home/ports/mystuff/${PWD##*/}.diff ; } # portscp() { scp /home/ports/mystuff/${PWD##*/}.diff virtie:/var/www/iota/ports/ && echo https://chown.me/iota/ports/${PWD##*/}.diff ;} portspy3() { FLAVOR="python3" make "$@" ;} portspy3and2() { make "$@" ; FLAVOR="python3" make "$@" ;} portspygrep() { (cd /home/ports && grep "$@" */py-*/Makefile ) ;} portslib() { nm -g "$1" | cut -c10- | grep -e^T > /tmp/"$(pwd |xargs basename)" ;} portsfind() { find /home/ports -iname "${1}" -exec grep -iH ${2} {} \; ;} portsgrep() { ( cd /home/ports && grep "$@" */*/Makefile */*/*/Makefile ) ;} alias mup="make update-patches" alias pfast="MAKE_JOBS=7 make" alias m="make" alias mpldc="make port-lib-depends-check" pclear() { doas find /home/ports/packages/ -iname "*${1:?}*" -delete doas find /home/ports/plist/ -iname "*${1:?}*" -delete }
Although it's not my interactive shell, I do like plan9' rc.
My configuration file is pretty small:
prompt=('% ' '') user=$USER home=$HOME fn % { $* } fn git { env git --no-pager $* }
I use the following for the plumber, although it probably can be improved:
addr=':(#?[0-9]+)' protocol='(https?|ftp|file|gopher|mailto|news|nntp|telnet|wais)' domain='[a-zA-Z0-9_@]+([.:][a-zA-Z0-9_@]+)*/?[a-zA-Z0-9_?,%#~&/\-]+' file='([:.][a-zA-Z0-9_?,%#~&/\-]+)*' # open http urls. data regexps is the same for file plus : type is text data matches $protocol://$domain$file plumb to web plumb start web $0 # RFC's from one of the nicer-looking repositories. type is text data matches 'RFC:([0-9]+)' plumb to web plumb start browser https://tools.ietf.org/html/rfc$1 # open python error message type is text data matches ' *File "([a-zA-Z0-9_\.\/]*)", line ([0-9]*).*' plumb to edit arg isfile $1 data set $file attr add addr=$2 plumb client $editor # open pdf with xdg-open type is text data matches '[a-zA-Zยก-๏ฟฟ0-9_\-./]+' data matches '([a-zA-Zยก-๏ฟฟ0-9_\-./]+)\.(ps|PS|eps|EPS|pdf|PDF|dvi|DVI)' arg isfile $0 plumb to postscript plumb start xdg-open $file # show git log type is text data matches 'commit ([a-z0-9]*)' arg isdir . data set $dir plumb start sh -c 'cd '$dir'; git show '$1' | 9p write acme/new/body' # show git log type is text data matches 'commit ([a-z0-9]*)' arg isdir . data set $dir plumb start sh -c 'cd '$dir'; git show '$1' | 9p write acme/new/body' # git pull type is text data matches '.*[pP][uU][lL][lL].*#([0-9]*)' arg isdir . data set $dir plumb start sh -c 'cd '$dir'; browser $(git remote get-url origin | sed "s/\.git//")/pull/'$1 # git issue type is text data matches '[iI][sS][sS][uU][eE] #([0-9]*)' arg isdir . data set $dir plumb start sh -c 'cd '$dir'; browser $(git remote get-url origin | sed "s/\.git//")/issues/'$1 # git issue type is text data matches '.*fix.*#([0-9]*)' arg isdir . data set $dir plumb start sh -c 'cd '$dir'; browser $(git remote get-url origin | sed "s/\.git//")/issues/'$1
SQLite has a configuration file that gets executed every time is launched. I like to change the default glyph for the `NULL' value
.nullvalue 'โฅ'
and enable the `box' mode. This is kinda new, so it may not work in some older version
.mode box
It looks like this:
.mode box select 42 as response;
,----
| โโโโโโโโโโโโ
| โ response โ
| โโโโโโโโโโโโค
| โ 42 โ
| โโโโโโโโโโโโ
`----
By default psql renders `NULL' values as empty strings. This makes it harder to "see" if a column is `NULL' or an empty string, so change the default `NULL' glyph:
\pset null 'โฅ'
I also use to connect to databases to different hosts, so to be extra sure I made `psql' print the connection info right away:
\conninfo
I use the following script to launch acme in all its glory.
#!/usr/bin/env rc . $home/lib/profile if (~ $PLAN9 '') { echo '$PLAN9 is not defined!' exit 1 } NAMESPACE=/tmp/ns.$user.$pid SHELL=rc PAGER=nobs MANPAGER=nobs EDITOR=editinacme VISUAL=editinacme mkdir -p $"NAMESPACE plumber fontsrv & fontsrvpid=$apid font=/mnt/font/GoMono/10a/font FONT=/mnt/font/InputSans-Regular/10a/font $PLAN9/bin/acme -a -f $font -F $FONT $* & acmepid=$apid { sleep 1 winid=1 exec acmeeval 'autoacme '$home'/bin/acmeconfig' } & acmeevalpid=$apid wait $acmepid kill $acmeevalpid kill $fontsrvpid wait # just in case rm -rf $"NAMESPACE
The `browser' script is my default browser. It launches the correct browser depending on what is currently running
#!/bin/sh if pgrep firefox >/dev/null 2>&1; then exec firefox "$1" fi if pgrep iridium >/dev/null 2>&1; then exec iridium "$1" fi exec firefox "$1"
Posts its input to clbin
#!/bin/sh exec curl -F 'clbin=<-' https://clbin.com
This generates a menu for a `dmenu' like program. In particular, it uses my own mymenu.
#!/bin/ksh a-menu() { mymenu -f 'Go Mono-11' -l vertical -p '% ' \ -W 50% -H 30% -P 10 -x center -y center \ -C '#ffffea' -c '#000' -T '#ffffea' \ -t '#000' -S '#000' -s '#fff' -b 3 \ -a } # pass p() { prefix=${PASSWORD_STORE_DIR:-~/.password-store} typeit=${1:-no} sleep 1 p=$(find "$prefix" -type f -iname '*.gpg' | \ sort | \ sed -e 's/\.gpg$//' -e "s,^$prefix/,," | \ a-menu) if [ $? -eq 0 ]; then if [ "$typeit" = yes ]; then pass show "$p" | { IFS= read -r pass; printf %s "$pass"; } | xdotool type --clearmodifiers --file - else pass show --clip "$password" fi fi } # exec e() { if ! x=$(a-menu); then return elif [ "$x" = "pass" ]; then p yes elif [ "$x" = "pass copy" ]; then p nope elif [ "$x" = "keep" ]; then exec keepassxc else exec $x fi } ( echo audacity echo blender echo chrome echo dino echo emacs echo emacsclient -c echo firefox echo gajim echo gimp echo godot echo inkscape echo iridium echo keep echo lagrange echo libreoffice echo links -g -mode 800x600 echo lmms echo luakit echo lxappearance echo mumble echo netsurf-gtk3 echo obs echo pass echo pass copy # not "copy pass" so it's after pass echo pixelorama echo poedit echo spectral echo tor-browser echo xfe echo zathura ) | e
Record, as the name suggest, records a portion of the screen to a file.
#!/bin/ksh if ! s=$(slop -f "%x %y %w %h"); then exit 1 fi set -A s -- $s x=${s[0]} y=${s[1]} w=${s[2]} h=${s[3]} exec ffmpeg -y \ -f x11grab \ -s ${w}x${h} \ -framerate 30 \ -i $DISPLAY+${x},${y} \ ${1:?missing output file}
I like to jump between stumpwm and cwm, but I haven't found a way to do `exec cwm' from lisp, hence I'm using this script from `cwm' to switch to `stumpwm'.
#!/bin/sh stumpwm exec cwm
Time ago I decided to just stop even trying to tame `xdg-open' and fix the problem at the root, that is, by getting rid of it.
I have an `xdg-open' scripts that implements the rules that *I* want, not some coincidences decided by the order in which the package were installed.
<2021-06-20 Sun> I've installed `pdf-tools', so there isn't any need for zathura.
#!/bin/sh case "$@" in *://*) exec browser "$@" ;; *jpg|*jpeg) exec gpicview "$@" ;; *mp4|*mkv) exec mpv "$@" ;; *m4a) exec mpv --force-window --lavfi-complex='[aid1] asplit [ao] [v] ; [v] showwaves=mode=line:split_channels=1 [vo]' "$@" ;; *svg) exec inkscape "$@" ;; *core) ;; # do nothing *png) exec gpicview "$@" ;; *gif) exec gpicview "$@" ;; *webp) exec gpicview "$@" ;; *) exec emacsclient -c "$@" ;; esac