aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2017-10-28 15:13:46 +1300
committerTom Ryder <tom@sanctum.geek.nz>2017-10-28 15:13:46 +1300
commitfb7557b2feaa210c4987e4ce8faf3d2c3b4b16ba (patch)
treef0ef90c4e095cc0693bd2253326d9d3bbe7172e7
parentMerge branch 'master' into port/bsd/dragonfly-bsd (diff)
parentMerge branch 'port/sunos/illumos/openindiana' (diff)
downloaddotfiles-fb7557b2feaa210c4987e4ce8faf3d2c3b4b16ba.tar.gz
dotfiles-fb7557b2feaa210c4987e4ce8faf3d2c3b4b16ba.zip
Merge branch 'master' into port/bsd/dragonfly-bsd
-rw-r--r--.gitignore134
-rw-r--r--.gitmodules6
-rw-r--r--IDEAS.markdown10
-rw-r--r--IDEAS.md21
-rw-r--r--ISSUES.md (renamed from ISSUES.markdown)10
-rw-r--r--Makefile764
-rw-r--r--README.md (renamed from README.markdown)231
-rw-r--r--TABS.md26
-rw-r--r--X/Xresources3
-rw-r--r--X/Xresources.d/xterm9
-rw-r--r--X/sxhkdrc47
-rw-r--r--X/xbindkeysrc32
-rw-r--r--X/xinitrc3
-rw-r--r--X/xinitrc.d/shlvl.sh2
-rw-r--r--X/xinitrc.d/sxhkd.sh3
-rw-r--r--X/xinitrc.d/xbackground.sh3
-rw-r--r--X/xinitrc.d/xbindkeys.sh3
-rw-r--r--X/xinitrc.d/xrbg.sh2
-rw-r--r--bash/bash_completion.d/_abook_addresses.bash10
-rw-r--r--bash/bash_completion.d/ad.bash2
-rw-r--r--bash/bash_completion.d/chgrp.bash20
-rw-r--r--bash/bash_completion.d/dig.bash2
-rw-r--r--bash/bash_completion.d/finger.bash2
-rw-r--r--bash/bash_completion.d/ftp.bash8
-rw-r--r--bash/bash_completion.d/git.bash39
-rw-r--r--bash/bash_completion.d/gpg.bash8
-rw-r--r--bash/bash_completion.d/host.bash2
-rw-r--r--bash/bash_completion.d/mail.bash10
-rw-r--r--bash/bash_completion.d/make.bash8
-rw-r--r--bash/bash_completion.d/man.bash8
-rw-r--r--bash/bash_completion.d/mutt.bash10
-rw-r--r--bash/bash_completion.d/mysql.bash8
-rw-r--r--bash/bash_completion.d/nc.bash2
-rw-r--r--bash/bash_completion.d/netcat.bash2
-rw-r--r--bash/bash_completion.d/nmap.bash2
-rw-r--r--bash/bash_completion.d/openssl.bash32
-rw-r--r--bash/bash_completion.d/path.bash4
-rw-r--r--bash/bash_completion.d/ping.bash2
-rw-r--r--bash/bash_completion.d/sd.bash2
-rw-r--r--bash/bash_completion.d/sftp.bash8
-rw-r--r--bash/bash_completion.d/source.bash2
-rw-r--r--bash/bash_completion.d/ssh-copy-id.bash8
-rw-r--r--bash/bash_completion.d/ssh.bash8
-rw-r--r--bash/bash_completion.d/td.bash15
-rw-r--r--bash/bash_completion.d/telnet.bash2
-rw-r--r--bash/bash_profile7
-rw-r--r--bash/bashrc52
-rw-r--r--bash/bashrc.d/completion.bash15
-rw-r--r--bash/bashrc.d/keep.bash4
-rw-r--r--bash/bashrc.d/prompt.bash39
-rw-r--r--[-rwxr-xr-x]bin/ap.sh (renamed from bin/ap)1
-rw-r--r--[-rwxr-xr-x]bin/apf.sh (renamed from bin/apf)1
-rw-r--r--[-rwxr-xr-x]bin/ax.sh (renamed from bin/ax)1
-rwxr-xr-xbin/bcq4
-rw-r--r--bin/bcq.sh3
-rw-r--r--[-rwxr-xr-x]bin/bel.sh (renamed from bin/bel)1
-rw-r--r--[-rwxr-xr-x]bin/bl.sh (renamed from bin/bl)1
-rw-r--r--[-rwxr-xr-x]bin/bp.sh (renamed from bin/bp)1
-rw-r--r--[-rwxr-xr-x]bin/br.sh (renamed from bin/br)1
-rw-r--r--[-rwxr-xr-x]bin/ca.sh (renamed from bin/ca)1
-rw-r--r--[-rwxr-xr-x]bin/cf.sh (renamed from bin/cf)1
-rw-r--r--[-rwxr-xr-x]bin/cfr.sh (renamed from bin/cfr)1
-rw-r--r--[-rwxr-xr-x]bin/chc.sh (renamed from bin/chc)8
-rw-r--r--bin/chn.mi557
-rwxr-xr-xbin/clog10
-rw-r--r--bin/clog.sh17
-rw-r--r--[-rwxr-xr-x]bin/clrd.sh (renamed from bin/clrd)1
-rw-r--r--[-rwxr-xr-x]bin/clwr.sh (renamed from bin/clwr)1
-rw-r--r--bin/csmw.awk9
-rw-r--r--[-rwxr-xr-x]bin/d2u.sh (renamed from bin/d2u)1
-rw-r--r--bin/dam.sed8
-rw-r--r--bin/ddup.awk6
-rw-r--r--[-rwxr-xr-x]bin/dmp.sh (renamed from bin/dmp)2
-rwxr-xr-xbin/dub32
-rw-r--r--bin/dub.sh27
-rw-r--r--bin/edda.mi521
-rw-r--r--[-rwxr-xr-x]bin/eds.sh (renamed from bin/eds)1
-rw-r--r--bin/exm.sh9
-rw-r--r--[-rwxr-xr-x]bin/fgscr.sh (renamed from bin/fgscr)1
-rw-r--r--[-rwxr-xr-x]bin/finc.sh (renamed from bin/finc)1
-rw-r--r--[-rwxr-xr-x]bin/fnl.sh (renamed from bin/fnl)7
-rw-r--r--bin/fnp.sh23
-rw-r--r--[-rwxr-xr-x]bin/gms.sh (renamed from bin/gms)1
-rw-r--r--[-rwxr-xr-x]bin/grc.sh (renamed from bin/grc)1
-rw-r--r--bin/grec.sh2
-rw-r--r--bin/gred.sh2
-rw-r--r--[-rwxr-xr-x]bin/gscr.sh (renamed from bin/gscr)1
-rw-r--r--bin/gwp.awk13
-rw-r--r--bin/han.bash4
-rw-r--r--bin/hms.awk40
-rw-r--r--bin/htref.sed2
-rw-r--r--[-rwxr-xr-x]bin/hurl.sh (renamed from bin/hurl)1
-rw-r--r--[-rwxr-xr-x]bin/igex.sh (renamed from bin/igex)2
-rw-r--r--[-rwxr-xr-x]bin/isgr.sh (renamed from bin/isgr)1
-rw-r--r--[-rwxr-xr-x]bin/ix.sh (renamed from bin/ix)1
-rw-r--r--[-rwxr-xr-x]bin/jfc.sh (renamed from bin/jfc)1
-rw-r--r--[-rwxr-xr-x]bin/jfcd.sh (renamed from bin/jfcd)2
-rw-r--r--bin/jfp.sed1
-rw-r--r--[-rwxr-xr-x]bin/loc.sh (renamed from bin/loc)1
-rw-r--r--bin/max.awk6
-rw-r--r--[-rwxr-xr-x]bin/maybe.sh (renamed from bin/maybe)4
-rw-r--r--bin/mean.awk3
-rw-r--r--bin/med.awk10
-rw-r--r--[-rwxr-xr-x]bin/mex.sh (renamed from bin/mex)7
-rw-r--r--bin/mftl.awk12
-rw-r--r--bin/mi5.awk133
-rw-r--r--[-rwxr-xr-x]bin/mkcp.sh (renamed from bin/mkcp)1
-rw-r--r--[-rwxr-xr-x]bin/mkmv.sh (renamed from bin/mkmv)1
-rw-r--r--[-rwxr-xr-x]bin/mktd.sh (renamed from bin/mktd)7
-rw-r--r--[-rwxr-xr-x]bin/motd.sh (renamed from bin/motd)1
-rw-r--r--[-rwxr-xr-x]bin/murl.sh (renamed from bin/murl)1
-rw-r--r--bin/mw.awk10
-rw-r--r--bin/oii.mi519
-rw-r--r--bin/onl.awk5
-rw-r--r--bin/osc.sh91
-rw-r--r--bin/p.sh2
-rw-r--r--[-rwxr-xr-x]bin/pa.sh (renamed from bin/pa)1
-rw-r--r--[-rwxr-xr-x]bin/paz.sh (renamed from bin/paz)1
-rw-r--r--bin/ped.sh2
-rw-r--r--[-rwxr-xr-x]bin/pit.sh (renamed from bin/pit)2
-rw-r--r--[-rwxr-xr-x]bin/plmu.sh (renamed from bin/plmu)4
-rw-r--r--[-rwxr-xr-x]bin/pp.sh (renamed from bin/pp)1
-rwxr-xr-xbin/pph5
-rw-r--r--bin/pph.sh5
-rw-r--r--bin/pst.mi519
-rw-r--r--bin/pvi.sh2
-rw-r--r--[-rwxr-xr-x]bin/pwg.sh (renamed from bin/pwg)1
-rw-r--r--bin/quo.sed3
-rw-r--r--bin/rep.sh25
-rwxr-xr-xbin/rfcf12
-rw-r--r--bin/rfcf.sh13
-rwxr-xr-xbin/rfcr18
-rw-r--r--bin/rfcr.sh19
-rw-r--r--bin/rfct.awk15
-rw-r--r--[-rwxr-xr-x]bin/rgl.sh (renamed from bin/rgl)1
-rw-r--r--[-rwxr-xr-x]bin/rnda.sh (renamed from bin/rnda)8
-rw-r--r--[-rwxr-xr-x]bin/rndf.sh (renamed from bin/rndf)1
-rw-r--r--bin/rndi.awk38
-rwxr-xr-xbin/rndl51
-rw-r--r--bin/rndl.awk39
-rw-r--r--[-rwxr-xr-x]bin/rnds.sh (renamed from bin/rnds)1
-rw-r--r--bin/sd2u.awk2
-rw-r--r--bin/sec.awk18
-rw-r--r--[-rwxr-xr-x]bin/shb.sh (renamed from bin/shb)18
-rw-r--r--[-rwxr-xr-x]bin/slow.sh (renamed from bin/slow)1
-rw-r--r--[-rwxr-xr-x]bin/sls.sh (renamed from bin/sls)1
-rw-r--r--[-rwxr-xr-x]bin/sqs.sh (renamed from bin/sqs)1
-rw-r--r--[-rwxr-xr-x]bin/sra.sh (renamed from bin/sra)1
-rw-r--r--[-rwxr-xr-x]bin/sshi.sh (renamed from bin/sshi)1
-rw-r--r--[-rwxr-xr-x]bin/sta.sh (renamed from bin/sta)1
-rw-r--r--[-rwxr-xr-x]bin/stbl.sh (renamed from bin/stbl)1
-rw-r--r--[-rwxr-xr-x]bin/stex.sh (renamed from bin/stex)1
-rw-r--r--[-rwxr-xr-x]bin/stws.sh (renamed from bin/stws)1
-rw-r--r--bin/su2d.awk2
-rw-r--r--[-rwxr-xr-x]bin/sue.sh (renamed from bin/sue)1
-rw-r--r--[-rwxr-xr-x]bin/supp.sh (renamed from bin/supp)1
-rw-r--r--[-rwxr-xr-x]bin/swr.mi5 (renamed from bin/swr)21
-rw-r--r--[-rwxr-xr-x]bin/td.sh (renamed from bin/td)1
-rw-r--r--[-rwxr-xr-x]bin/tl.sh (renamed from bin/tl)1
-rw-r--r--[-rwxr-xr-x]bin/tlcs.mi5 (renamed from bin/tlcs)19
-rw-r--r--bin/tm.sh17
-rw-r--r--bin/tot.awk1
-rw-r--r--bin/trs.awk35
-rw-r--r--[-rwxr-xr-x]bin/try.mi5 (renamed from bin/try)19
-rw-r--r--[-rwxr-xr-x]bin/u2d.sh (renamed from bin/u2d)1
-rw-r--r--[-rwxr-xr-x]bin/umake.sh (renamed from bin/umake)1
-rw-r--r--bin/unf.awk4
-rw-r--r--[-rwxr-xr-x]bin/urlc.mi5 (renamed from bin/urlc)19
-rw-r--r--[-rwxr-xr-x]bin/urlh.sh (renamed from bin/urlh)10
-rw-r--r--[-rwxr-xr-x]bin/urlmt.sh (renamed from bin/urlmt)1
-rw-r--r--[-rwxr-xr-x]bin/vest.sh (renamed from bin/vest)3
-rw-r--r--[-rwxr-xr-x]bin/vex.sh (renamed from bin/vex)1
-rw-r--r--bin/wro.sh30
-rw-r--r--[-rwxr-xr-x]bin/xgo.sh (renamed from bin/xgo)24
-rw-r--r--[-rwxr-xr-x]bin/xgoc.sh (renamed from bin/xgoc)1
-rw-r--r--bin/xrbg.sh3
-rw-r--r--bin/xrq.awk30
-rw-r--r--[-rwxr-xr-x]check/bash.sh (renamed from check/bash)1
-rwxr-xr-xcheck/bin14
-rw-r--r--check/bin.sh4
-rwxr-xr-xcheck/games14
-rw-r--r--check/games.sh4
-rw-r--r--[-rwxr-xr-x]check/ksh.sh (renamed from check/ksh)1
-rw-r--r--check/login-shell.sh10
-rw-r--r--[-rwxr-xr-x]check/man.sh (renamed from check/man)1
-rwxr-xr-xcheck/sh6
-rw-r--r--check/sh.sh11
-rwxr-xr-xcheck/urxvt9
-rw-r--r--check/urxvt.sh4
-rw-r--r--check/xinit.sh4
-rwxr-xr-xcheck/yash6
-rw-r--r--[-rwxr-xr-x]check/zsh.sh (renamed from check/zsh)1
-rw-r--r--ex/exrc6
-rw-r--r--[-rwxr-xr-x]games/aaf.sh (renamed from games/aaf)2
-rw-r--r--games/acq.sed3
-rw-r--r--games/chkl.sed1
-rw-r--r--[-rwxr-xr-x]games/dr.sh (renamed from games/dr)6
-rw-r--r--games/drakon.awk17
-rw-r--r--games/kvlt.sed4
-rw-r--r--games/philsay.sh47
-rw-r--r--games/pks.awk53
-rw-r--r--[-rwxr-xr-x]games/rndn.sh (renamed from games/rndn)1
-rw-r--r--games/squ.awk7
-rw-r--r--games/strik.sed64
-rw-r--r--[-rwxr-xr-x]games/xyzzy.sh (renamed from games/xyzzy)2
-rw-r--r--git/gitconfig.mi5 (renamed from git/gitconfig.m4)8
-rw-r--r--gnupg/gpg.conf.mi5 (renamed from gnupg/gpg.conf.m4)4
-rw-r--r--gnupg/sks-keyservers.net/README.markdown9
-rw-r--r--gnupg/sks-keyservers.net/crl.pem27
-rw-r--r--gnupg/sks-keyservers.net/sks-keyservers.netCA.pem32
-rw-r--r--gnupg/sks-keyservers.net/sks-keyservers.netCA.pem.asc16
-rw-r--r--gtk/gtk-3.0/settings.ini (renamed from gtk/gtkrc-3.0/settings.ini)0
-rw-r--r--i3/config3
-rw-r--r--[-rwxr-xr-x]include/mktd.mi5 (renamed from bin/edda)19
-rw-r--r--install/install-conf.sh10
-rw-r--r--install/install-login-shell.sh10
-rw-r--r--irssi/aliases1
-rw-r--r--keychain/profile.d/keychain.sh5
-rw-r--r--keychain/shrc.d/keychain.sh (renamed from sh/shrc.d/keychain.sh)2
-rw-r--r--ksh/kshrc1
-rw-r--r--ksh/kshrc.d/bind.ksh17
-rw-r--r--ksh/kshrc.d/prompt.ksh41
-rw-r--r--ksh/shrc.d/ksh.sh8
-rw-r--r--[-rwxr-xr-x]lint/bash.sh (renamed from lint/bash)1
-rwxr-xr-xlint/bin11
-rw-r--r--lint/bin.sh1
-rwxr-xr-xlint/games11
-rw-r--r--lint/games.sh1
-rw-r--r--[-rwxr-xr-x]lint/ksh.sh (renamed from lint/ksh)1
-rwxr-xr-xlint/sh2
-rw-r--r--lint/sh.sh6
-rw-r--r--[-rwxr-xr-x]lint/urxvt.sh (renamed from lint/urxvt)1
-rw-r--r--lint/xinit.sh1
-rwxr-xr-xlint/yash2
-rw-r--r--man/man1/bcq.1df2
-rw-r--r--man/man1/br.1df3
-rw-r--r--man/man1/chn.1df48
-rw-r--r--man/man1/clog.1df2
-rw-r--r--man/man1/csmw.1df3
-rw-r--r--man/man1/dam.1df16
-rw-r--r--man/man1/dub.1df4
-rw-r--r--man/man1/edda.1df21
-rw-r--r--man/man1/exm.1df19
-rw-r--r--man/man1/fgscr.1df3
-rw-r--r--man/man1/fnl.1df2
-rw-r--r--man/man1/fnp.1df24
-rw-r--r--man/man1/grec.1df14
-rw-r--r--man/man1/gred.1df14
-rw-r--r--man/man1/hms.1df23
-rw-r--r--man/man1/htref.1df20
-rw-r--r--man/man1/maybe.1df4
-rw-r--r--man/man1/mex.1df7
-rw-r--r--man/man1/mi5.1df70
-rw-r--r--man/man1/murl.1df2
-rw-r--r--man/man1/mw.1df25
-rw-r--r--man/man1/oii.1df21
-rw-r--r--man/man1/osc.1df22
-rw-r--r--man/man1/p.1df44
-rw-r--r--man/man1/ped.1df19
-rw-r--r--man/man1/pp.1df2
-rw-r--r--man/man1/pph.1df8
-rw-r--r--man/man1/pst.1df25
-rw-r--r--man/man1/pvi.1df19
-rw-r--r--man/man1/quo.1df25
-rw-r--r--man/man1/rep.1df15
-rw-r--r--man/man1/rndi.1df15
-rw-r--r--man/man1/rndl.1df2
-rw-r--r--man/man1/sec.1df6
-rw-r--r--man/man1/shb.1df16
-rw-r--r--man/man1/swr.1df5
-rw-r--r--man/man1/tl.1df3
-rw-r--r--man/man1/tm.1df12
-rw-r--r--man/man1/trs.1df25
-rw-r--r--man/man1/try.1df2
-rw-r--r--man/man1/wro.1df24
-rw-r--r--man/man1/xrbg.1df19
-rw-r--r--man/man1/xrq.1df16
-rw-r--r--man/man6/philsay.6df28
-rw-r--r--man/man6/pks.6df29
-rw-r--r--man/man6/squ.6df30
-rw-r--r--man/man6/strik.6df10
-rw-r--r--man/man7/dotfiles.7df947
-rw-r--r--man/man7/dotfiles.7df.header3
-rw-r--r--mpd/mpdconf15
-rw-r--r--mpd/profile.d/mpd.sh3
-rw-r--r--mutt/muttrc (renamed from mutt/muttrc.m4)41
-rwxr-xr-xmutt/muttrc.d/src6
-rw-r--r--mutt/signature2
-rw-r--r--mysql/my.cnf1
-rw-r--r--ncmpcpp/config25
-rw-r--r--newsbeuter/config9
-rw-r--r--perlcritic/perlcriticrc22
-rw-r--r--plenv/profile.d/plenv.sh5
-rw-r--r--plenv/shrc.d/plenv.sh17
-rw-r--r--readline/inputrc7
-rw-r--r--sh/profile.d/downloads.sh31
-rw-r--r--sh/profile.d/editor.sh26
-rw-r--r--sh/profile.d/games.sh3
-rw-r--r--sh/profile.d/keychain.sh5
-rw-r--r--sh/profile.d/lang.sh4
-rw-r--r--sh/profile.d/options.sh36
-rw-r--r--sh/profile.d/visual.sh2
-rw-r--r--sh/shrc3
-rw-r--r--sh/shrc.d/ad.sh80
-rw-r--r--sh/shrc.d/bc.sh4
-rw-r--r--sh/shrc.d/bd.sh99
-rw-r--r--sh/shrc.d/ed.sh6
-rw-r--r--sh/shrc.d/env.sh8
-rw-r--r--sh/shrc.d/gd.sh4
-rw-r--r--sh/shrc.d/grep.sh19
-rw-r--r--sh/shrc.d/gt.sh26
-rw-r--r--sh/shrc.d/hgrep.sh8
-rw-r--r--sh/shrc.d/la.sh2
-rw-r--r--sh/shrc.d/less.sh2
-rw-r--r--sh/shrc.d/lgt.sh28
-rw-r--r--sh/shrc.d/ll.sh2
-rw-r--r--sh/shrc.d/ls.sh50
-rw-r--r--sh/shrc.d/md.sh13
-rw-r--r--sh/shrc.d/mysql.sh25
-rw-r--r--sh/shrc.d/path.sh102
-rw-r--r--sh/shrc.d/pd.sh49
-rw-r--r--sh/shrc.d/pmd.sh4
-rw-r--r--sh/shrc.d/prompt.sh11
-rw-r--r--sh/shrc.d/rd.sh47
-rw-r--r--sh/shrc.d/sd.sh110
-rw-r--r--sh/shrc.d/tmux.sh19
-rw-r--r--sh/shrc.d/tree.sh2
-rw-r--r--sh/shrc.d/ud.sh61
-rw-r--r--sh/shrc.d/vim.sh13
-rw-r--r--sh/shrc.d/vr.sh15
-rw-r--r--sh/shrc.d/xd.sh2
-rw-r--r--share/sample1.mi59
-rw-r--r--share/sample2.mi57
-rw-r--r--tmux/tmux.conf (renamed from tmux/tmux.conf.m4)49
-rw-r--r--vim/after/ftdetect/muttrc.vim12
-rw-r--r--vim/after/ftdetect/xdefaults.vim6
m---------vim/bundle/abolish0
m---------vim/bundle/commentary0
m---------vim/bundle/html50
m---------vim/bundle/lion0
m---------vim/bundle/nagios0
m---------vim/bundle/pathogen0
m---------vim/bundle/repeat0
m---------vim/bundle/targets0
m---------vim/bundle/tmux0
m---------vim/bundle/unimpaired0
-rw-r--r--vim/vimrc4
-rw-r--r--wget/wgetrc14
-rw-r--r--wyrd/wyrdrc167
-rw-r--r--yash/yash_profile2
-rw-r--r--yash/yashrc9
-rw-r--r--yash/yashrc.d/ver.yash4
-rw-r--r--zsh/zshrc10
-rw-r--r--zsh/zshrc.d/completion.zsh19
-rw-r--r--zsh/zshrc.d/prompt.zsh39
355 files changed, 4526 insertions, 2051 deletions
diff --git a/.gitignore b/.gitignore
index a9f181be..deccfe5e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,39 +1,165 @@
+bin/ap
+bin/apf
+bin/ax
+bin/bcq
+bin/bel
+bin/bl
+bin/bp
+bin/br
bin/brnl
+bin/ca
+bin/cf
+bin/cfr
+bin/chc
+bin/chn
+bin/chn.sh
+bin/chn.m4
+bin/clog
+bin/clrd
+bin/clwr
bin/csmw
+bin/d2u
+bin/dam
bin/ddup
+bin/dmp
+bin/dub
+bin/edda
+bin/edda.sh
+bin/edda.m4
+bin/eds
+bin/exm
+bin/fgscr
+bin/finc
+bin/fnl
+bin/fnp
+bin/gms
+bin/grc
+bin/grec
+bin/gred
+bin/gscr
bin/gwp
-bin/jfp
bin/han
+bin/hms
bin/htdec
bin/htenc
+bin/htref
+bin/hurl
+bin/igex
+bin/isgr
+bin/ix
+bin/jfc
+bin/jfcd
+bin/jfp
+bin/loc
bin/max
+bin/maybe
bin/mean
bin/med
+bin/mex
bin/mftl
+bin/mi5
bin/min
+bin/mkcp
+bin/mkmv
+bin/mktd
bin/mode
+bin/motd
+bin/murl
+bin/mw
bin/nlbr
+bin/oii
+bin/oii.sh
+bin/oii.m4
bin/onl
+bin/osc
+bin/p
+bin/pa
+bin/paz
+bin/ped
+bin/pit
+bin/plmu
+bin/pp
+bin/pph
+bin/pst
+bin/pst.sh
+bin/pst.m4
+bin/pvi
+bin/pwg
+bin/quo
+bin/rep
+bin/rfcf
+bin/rfcr
bin/rfct
+bin/rgl
+bin/rnda
+bin/rndf
bin/rndi
+bin/rndl
+bin/rnds
bin/sd2u
bin/sec
+bin/shb
+bin/slow
+bin/sls
bin/slsf
+bin/sqs
+bin/sra
+bin/sshi
+bin/sta
+bin/stbl
+bin/stex
+bin/stws
bin/su2d
+bin/sue
+bin/supp
+bin/swr
+bin/swr.sh
+bin/swr.m4
+bin/td
+bin/tl
+bin/tlcs
+bin/tlcs.sh
+bin/tlcs.m4
+bin/tm
bin/tot
+bin/trs
+bin/try
+bin/try.sh
+bin/try.m4
+bin/u2d
+bin/umake
bin/unf
+bin/urlc
+bin/urlc.sh
+bin/urlc.m4
+bin/urlh
+bin/urlmt
bin/uts
+bin/vest
+bin/vex
+bin/wro
+bin/xgo
+bin/xgoc
+bin/xrbg
+bin/xrq
+games/aaf
games/acq
games/aesth
games/chkl
+games/dr
games/drakon
games/kvlt
+games/philsay
+games/pks
+games/rndn
games/rot13
+games/squ
games/strik
+games/xyzzy
games/zs
git/gitconfig
+git/gitconfig.m4
gnupg/gpg.conf
-man/man7/dotfiles.7df
-mutt/muttrc
-tmux/tmux.conf
+gnupg/gpg.conf.m4
+include/mktd.m4
urxvt/ext/select
diff --git a/.gitmodules b/.gitmodules
index 49bda51f..5f908d04 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,9 +13,6 @@
[submodule "vim/bundle/lion"]
path = vim/bundle/lion
url = https://sanctum.geek.nz/clone/vim-lion.git
-[submodule "vim/bundle/nagios"]
- path = vim/bundle/nagios
- url = https://sanctum.geek.nz/code/vim-nagios.git
[submodule "vim/bundle/pathogen"]
path = vim/bundle/pathogen
url = https://sanctum.geek.nz/clone/vim-pathogen.git
@@ -31,9 +28,6 @@
[submodule "vim/bundle/targets"]
path = vim/bundle/targets
url = https://sanctum.geek.nz/clone/targets.vim.git
-[submodule "vim/bundle/tmux"]
- path = vim/bundle/tmux
- url = https://sanctum.geek.nz/code/vim-tmux.git
[submodule "vim/bundle/unimpaired"]
path = vim/bundle/unimpaired
url = https://sanctum.geek.nz/clone/vim-unimpaired.git
diff --git a/IDEAS.markdown b/IDEAS.markdown
deleted file mode 100644
index 7f94b027..00000000
--- a/IDEAS.markdown
+++ /dev/null
@@ -1,10 +0,0 @@
-Ideas
-=====
-
-* I can probably share my psql() completions/shortcuts after sanitizing them
- a bit
-* sxhkd(1) might be nicer than xbindkeys; it's in Debian Testing now
-* Wouldn't be too hard to add some HTTP BASIC auth to ix(1df) to make pastes
- manageable
-* Have eds(1df) accept stdin with the "starting content" for the script
-* Convert all the manual pages to mandoc maybe? <https://en.wikipedia.org/wiki/Mandoc>
diff --git a/IDEAS.md b/IDEAS.md
new file mode 100644
index 00000000..bba9e314
--- /dev/null
+++ b/IDEAS.md
@@ -0,0 +1,21 @@
+Ideas
+=====
+
+* A wrapper ksw(1df) (kill-switch) that traps SIGINT to kill a called program
+ or loop immediately, rather than aborting a loop (is this possible?)
+* A wrapper sil(1df) or nec(1df) to turn stty -echo off for the duration of a
+ paste?
+* I can probably share my psql() completions/shortcuts after sanitizing them
+ a bit
+* Wouldn't be too hard to add some HTTP BASIC auth to ix(1df) to make pastes
+ manageable
+* Have eds(1df) accept stdin with the "starting content" for the script
+* Convert all the manual pages to mandoc maybe? <https://en.wikipedia.org/wiki/Mandoc>
+* qmp(1df)--quick man page
+* The solution to chn(1df) not running in parallel is probably backgrounded
+ processes and mkfifo(1).
+* Write something like hcat(1df) or tcat(1df) that includes filename headings
+ for each concatenated file.
+* I can probably get rid of all that nasty templated shell by writing
+ something that wraps around td(1df) and generates shell script to run, and
+ calls that via `eval`.
diff --git a/ISSUES.markdown b/ISSUES.md
index 383d7906..48007919 100644
--- a/ISSUES.markdown
+++ b/ISSUES.md
@@ -4,9 +4,6 @@ Known issues
* man(1) completion doesn't work on OpenBSD as manpath(1) isn't a thing on
that system; need to find some way of finding which manual directories
should be searched at runtime, if there is one.
-* OpenBSD doesn't have a `pandoc` package at all. It would be nice to find
- some way of converting the README.markdown into a palatable troff format
- with some more readily available (and preferably less heavyweight) tool.
* The checks gscr(1df) makes to determine where it is are a bit naïve (don't
work with bare repos) and could probably be improved with some appropriate
git-reflog(1) calls
@@ -18,3 +15,10 @@ Known issues
* I can't find a clean way of detecting a restricted shell for ksh instances
to prevent trying to load anything fancy (works for Bash)
* Zsh, either! $options[restricted] is "off" within the startup file
+* Would be good to complete the Makefile variables for NAME, EMAIL etc with
+ educated guesses (`id -u`@`cat /etc/mailname`) etc rather than hardcoding
+ my own stuff in there
+* Completion for custom functions e.g. `sd` should ideally respect
+ `completion-ignore-case` setting
+* Document `install-conf` target once I'm sure it's not a dumb idea
+* Need to decide whether I care about XDG, and implement it if I do
diff --git a/Makefile b/Makefile
index 06d5adf3..6cfee7a1 100644
--- a/Makefile
+++ b/Makefile
@@ -1,15 +1,16 @@
-.PHONY : all \
+.POSIX:
+
+.PHONY: all \
clean \
distclean \
install \
install-abook \
install-bash \
- install-bash-completion \
install-bin \
install-bin-man \
install-curl \
- install-dotfiles-man \
install-dunst \
+ install-ex \
install-finger \
install-games \
install-games-man \
@@ -17,439 +18,550 @@
install-gnupg \
install-gtk \
install-i3 \
+ install-ksh \
install-less \
- install-maildir \
+ install-login-shell \
+ install-mpd \
install-mutt \
+ install-mysql \
install-ncmcpp \
install-newsbeuter \
- install-mysql \
- install-ksh \
install-perlcritic \
install-perltidy \
install-psql \
install-readline \
install-sh \
install-subversion \
+ install-terminfo \
install-tmux \
install-urxvt \
install-vim \
- install-gvim \
install-vim-config \
- install-gvim-config \
- install-vim-plugins \
+ install-vim-gui \
+ install-vim-gui-config \
install-vim-pathogen \
- install-wyrd \
+ install-vim-plugins \
+ install-wget \
install-x \
- install-yash \
install-zsh \
check \
check-bash \
check-bin \
check-games \
check-ksh \
+ check-login-shell \
+ check-man \
check-sh \
check-urxvt \
- check-yash \
+ check-xinit \
check-zsh \
lint \
lint-bash \
lint-bin \
lint-games \
lint-ksh \
- lint-yash \
lint-sh \
- lint-urxvt
-
-.SUFFIXES: .awk .bash .pl .sed
-
-NAME := Tom Ryder
-EMAIL := tom@sanctum.geek.nz
-KEY := 0xC14286EA77BB8872
-SENDMAIL := msmtp
-
-BINS = bin/brnl \
+ lint-urxvt \
+ lint-xinit
+
+.SUFFIXES:
+.SUFFIXES: .awk .bash .m4 .mi5 .pl .sed .sh
+
+NAME = 'Tom Ryder'
+EMAIL = tom@sanctum.geek.nz
+KEY = 0xC14286EA77BB8872
+SENDMAIL = msmtp
+
+BINS = bin/ap \
+ bin/apf \
+ bin/ax \
+ bin/bcq \
+ bin/bel \
+ bin/bl \
+ bin/bp \
+ bin/br \
+ bin/brnl \
+ bin/ca \
+ bin/cf \
+ bin/cfr \
+ bin/chc \
+ bin/chn \
+ bin/clog \
+ bin/clrd \
+ bin/clwr \
bin/csmw \
+ bin/dam \
+ bin/d2u \
bin/ddup \
+ bin/dmp \
+ bin/dub \
+ bin/edda \
+ bin/eds \
+ bin/exm \
+ bin/fgscr \
+ bin/finc \
+ bin/fnl \
+ bin/fnp \
+ bin/gms \
+ bin/grc \
+ bin/grec \
+ bin/gred \
+ bin/gscr \
bin/gwp \
bin/han \
+ bin/hms \
bin/htdec \
bin/htenc \
+ bin/htref \
+ bin/hurl \
+ bin/igex \
+ bin/isgr \
+ bin/ix \
+ bin/jfc \
+ bin/jfcd \
bin/jfp \
+ bin/loc \
+ bin/mi5 \
bin/max \
+ bin/maybe \
bin/mean \
bin/med \
+ bin/mex \
bin/mftl \
bin/min \
+ bin/mkcp \
+ bin/mkmv \
+ bin/mktd \
bin/mode \
+ bin/motd \
+ bin/murl \
+ bin/mw \
bin/nlbr \
+ bin/oii \
bin/onl \
+ bin/osc \
+ bin/pa \
+ bin/paz \
+ bin/ped \
+ bin/pit \
+ bin/plmu \
+ bin/p \
+ bin/pp \
+ bin/pph \
+ bin/pst \
+ bin/pvi \
+ bin/pwg \
+ bin/quo \
+ bin/rep \
+ bin/rfcf \
+ bin/rfcr \
bin/rfct \
+ bin/rgl \
+ bin/rnda \
+ bin/rndf \
bin/rndi \
+ bin/rndl \
+ bin/rnds \
bin/sd2u \
bin/sec \
+ bin/shb \
+ bin/slow \
+ bin/sls \
bin/slsf \
+ bin/sqs \
+ bin/sra \
+ bin/sshi \
+ bin/sta \
+ bin/stbl \
+ bin/stex \
+ bin/stws \
bin/su2d \
+ bin/sue \
+ bin/supp \
+ bin/swr \
+ bin/td \
+ bin/tl \
+ bin/tlcs \
+ bin/tm \
bin/tot \
+ bin/trs \
+ bin/try \
+ bin/u2d \
+ bin/umake \
bin/unf \
+ bin/urlc \
+ bin/urlh \
+ bin/urlmt \
bin/uts \
-
-GAMES = games/acq \
+ bin/vest \
+ bin/vex \
+ bin/wro \
+ bin/xgo \
+ bin/xgoc \
+ bin/xrbg \
+ bin/xrq
+
+BINS_M4 = bin/chn.m4 \
+ bin/edda.m4 \
+ bin/oii.m4 \
+ bin/pst.m4 \
+ bin/swr.m4 \
+ bin/tlcs.m4 \
+ bin/try.m4 \
+ bin/urlc.m4
+
+BINS_SH = bin/chn.sh \
+ bin/edda.sh \
+ bin/oii.sh \
+ bin/pst.sh \
+ bin/swr.sh \
+ bin/tlcs.sh \
+ bin/try.sh \
+ bin/urlc.sh
+
+GAMES = games/aaf \
+ games/acq \
games/aesth \
games/chkl \
+ games/dr \
games/drakon \
games/kvlt \
+ games/philsay \
+ games/pks \
+ games/rndn \
games/rot13 \
+ games/squ \
games/strik \
+ games/xyzzy \
games/zs
-all : $(BINS) git/gitconfig gnupg/gpg.conf
+all: $(BINS) git/gitconfig gnupg/gpg.conf
-clean distclean :
- rm -f \
+clean distclean:
+ rm -f -- \
$(BINS) \
+ $(BINS_M4) \
+ $(BINS_SH) \
$(GAMES) \
git/gitconfig \
+ git/gitconfig.m4 \
gnupg/gpg.conf \
- man/man7/dotfiles.7df \
- mutt/muttrc \
- tmux/tmux.conf \
+ gnupg/gpg.conf.m4 \
+ include/mktd.m4 \
+ man/man8/dotfiles.7df \
urxvt/ext/select
-git/gitconfig : git/gitconfig.m4
- m4 \
- -D DOTFILES_NAME="$(NAME)" \
- -D DOTFILES_EMAIL="$(EMAIL)" \
- -D DOTFILES_KEY="$(KEY)" \
- -D DOTFILES_SENDMAIL="$(SENDMAIL)" \
- git/gitconfig.m4 > git/gitconfig
+.awk:
+ sh bin/shb.sh awk -f < $< > $@
+ chmod +x ./$@
-gnupg/gpg.conf : gnupg/gpg.conf.m4
- m4 -D DOTFILES_HOME="$(HOME)" \
- gnupg/gpg.conf.m4 > gnupg/gpg.conf
+.bash:
+ sh bin/shb.sh bash < $< > $@
+ chmod +x ./$@
-man/man7/dotfiles.7df : README.markdown man/man7/dotfiles.7df.header
- cat man/man7/dotfiles.7df.header README.markdown | \
- pandoc -sS -t man -o "$@"
+.pl:
+ sh bin/shb.sh perl < $< > $@
+ chmod +x ./$@
-mutt/muttrc : mutt/muttrc.m4
- m4 \
- -D DOTFILES_SENDMAIL="$(SENDMAIL)" \
- mutt/muttrc.m4 > mutt/muttrc
+.sed:
+ sh bin/shb.sh sed -f < $< > $@
+ chmod +x ./$@
-TMUX_COLOR := colour237
+.sh:
+ sh bin/shb.sh sh < $< > $@
+ chmod +x ./$@
-tmux/tmux.conf : tmux/tmux.conf.m4
- m4 -D TMUX_COLOR="$(TMUX_COLOR)" \
- tmux/tmux.conf.m4 > tmux/tmux.conf
+.mi5.m4:
+ awk -f bin/mi5.awk < $< > $@
-.awk :
- bin/shb "$<" awk -f > "$@"
- chmod +x "$@"
+.m4.sh:
+ m4 < $< > $@
-.bash :
- bin/shb "$<" bash > "$@"
- chmod +x "$@"
+bin/chn.sh: bin/chn.m4 include/mktd.m4
+bin/edda.sh: bin/edda.m4 include/mktd.m4
+bin/oii.sh: bin/oii.m4 include/mktd.m4
+bin/pst.sh: bin/pst.m4 include/mktd.m4
+bin/swr.sh: bin/swr.m4 include/mktd.m4
+bin/tlcs.sh: bin/tlcs.m4 include/mktd.m4
+bin/try.sh: bin/try.m4 include/mktd.m4
+bin/urlc.sh: bin/urlc.m4 include/mktd.m4
-.pl :
- bin/shb "$<" perl > "$@"
- chmod +x "$@"
+git/gitconfig: git/gitconfig.m4
+ m4 \
+ -D NAME=$(NAME) \
+ -D EMAIL=$(EMAIL) \
+ -D KEY=$(KEY) \
+ -D SENDMAIL=$(SENDMAIL) \
+ git/gitconfig.m4 > $@
-.sed :
- bin/shb "$<" sed -f > "$@"
- chmod +x "$@"
+KEYSERVER = hkps://hkps.pool.sks-keyservers.net
-install : install-bash \
- install-bash-completion \
- install-bin \
+gnupg/gpg.conf: gnupg/gpg.conf.m4
+ m4 \
+ -D KEYSERVER=$(KEYSERVER) \
+ gnupg/gpg.conf.m4 > $@
+
+MAILDIR = $(HOME)/Mail
+
+install: install-bin \
install-curl \
+ install-ex \
install-git \
install-gnupg \
install-less \
+ install-login-shell \
install-readline \
- install-sh \
install-vim
-install-abook :
- install -m 0755 -d -- \
- "$(HOME)"/.abook
- install -pm 0644 -- abook/abookrc "$(HOME)"/.abook
-
-install-bash : check-bash install-sh
- install -m 0755 -d -- \
- "$(HOME)"/.config \
- "$(HOME)"/.bashrc.d
- install -pm 0644 -- bash/bashrc "$(HOME)"/.bashrc
- install -pm 0644 -- bash/bashrc.d/* "$(HOME)"/.bashrc.d
- install -pm 0644 -- bash/bash_profile "$(HOME)"/.bash_profile
- install -pm 0644 -- bash/bash_logout "$(HOME)"/.bash_logout
-
-install-bash-completion : install-bash
- install -m 0755 -d -- "$(HOME)"/.bash_completion.d
- install -pm 0644 -- bash/bash_completion "$(HOME)"/.config/bash_completion
- install -pm 0644 -- bash/bash_completion.d/* "$(HOME)"/.bash_completion.d
-
-install-bin : $(BINS) install-bin-man
- install -m 0755 -d -- "$(HOME)"/.local/bin
- for name in bin/* ; do \
- [ -x "$$name" ] || continue ; \
- install -m 0755 -- "$$name" "$(HOME)"/.local/bin ; \
- done
-
-install-bin-man :
- install -m 0755 -d -- \
- "$(HOME)"/.local/share/man/man1 \
- "$(HOME)"/.local/share/man/man8
- install -pm 0644 -- man/man1/*.1df "$(HOME)"/.local/share/man/man1
- install -pm 0644 -- man/man8/*.8df "$(HOME)"/.local/share/man/man8
-
-install-curl :
- install -pm 0644 -- curl/curlrc "$(HOME)"/.curlrc
-
-install-dotfiles-man : man/man7/dotfiles.7df
- install -m 0755 -d -- "$(HOME)"/.local/share/man/man7
- install -pm 0644 -- man/man7/*.7df "$(HOME)"/.local/share/man/man7
-
-install-dunst : install-x
- install -m 0755 -d -- "$(HOME)"/.config/dunst
- install -pm 0644 -- dunst/dunstrc "$(HOME)"/.config/dunst
-
-install-finger :
- install -pm 0644 -- finger/plan "$(HOME)"/.plan
- install -pm 0644 -- finger/project "$(HOME)"/.project
- install -pm 0644 -- finger/pgpkey "$(HOME)"/.pgpkey
-
-install-games : $(GAMES) install-games-man
- install -m 0755 -d -- "$(HOME)"/.local/games
- for name in games/* ; do \
- [ -x "$$name" ] || continue ; \
- install -m 0755 -- "$$name" "$(HOME)"/.local/games ; \
- done
-
-install-games-man :
- install -m 0755 -d -- "$(HOME)"/.local/share/man/man6
- install -pm 0644 -- man/man6/*.6df "$(HOME)"/.local/share/man/man6
-
-install-git : git/gitconfig
- install -pm 0644 -- git/gitconfig "$(HOME)"/.gitconfig
-
-install-gnupg : gnupg/gpg.conf
- install -m 0700 -d -- \
- "$(HOME)"/.gnupg \
- "$(HOME)"/.gnupg/sks-keyservers.net
- install -pm 0600 -- gnupg/*.conf "$(HOME)"/.gnupg
- install -pm 0644 -- gnupg/sks-keyservers.net/* \
- "$(HOME)"/.gnupg/sks-keyservers.net
-
-install-gtk :
- install -m 0755 -d -- \
- "$(HOME)"/.config/gtkrc-3.0
- install -pm 0644 -- gtk/gtkrc-2.0 "$(HOME)"/.gtkrc-2.0
- install -pm 0644 -- gtk/gtkrc-3.0/settings.ini "$(HOME)"/.config/gtkrc-3.0
-
-install-i3 : install-x
- install -m 0755 -d -- "$(HOME)"/.i3
- install -pm 0644 -- i3/* "$(HOME)"/.i3
-
-install-less :
- install -pm 0644 -- less/lesskey "$(HOME)"/.lesskey
- command -v lesskey && lesskey
-
-install-maildir :
- install -m 0755 -d -- \
- "$(HOME)"/Mail/inbox/cur \
- "$(HOME)"/Mail/inbox/new \
- "$(HOME)"/Mail/inbox/tmp \
- "$(HOME)"/Mail/sent/cur \
- "$(HOME)"/Mail/sent/new \
- "$(HOME)"/Mail/sent/tmp
-
-install-mutt : mutt/muttrc install-maildir
- install -m 0755 -d -- \
- "$(HOME)"/.mutt \
- "$(HOME)"/.cache/mutt
- install -pm 0644 -- mutt/muttrc "$(HOME)"/.muttrc
- install -pm 0644 -- mutt/signature "$(HOME)"/.signature
-
-install-ncmcpp :
- install -m 0755 -d -- "$(HOME)"/.ncmpcpp
- install -pm 0644 -- ncmpcpp/config "$(HOME)"/.ncmpcpp/config
-
-install-newsbeuter :
- install -m 0755 -d -- \
- "$(HOME)"/.config/newsbeuter \
- "$(HOME)"/.local/share/newsbeuter
- install -pm 0644 -- newsbeuter/config "$(HOME)"/.config/newsbeuter/config
-
-install-mysql :
- install -pm 0644 -- mysql/my.cnf "$(HOME)"/.my.cnf
-
-install-ksh : check-ksh install-sh
- install -m 0755 -d -- \
- "$(HOME)"/.shrc.d \
- "$(HOME)"/.kshrc.d
- install -pm 0644 -- ksh/shrc.d/* "$(HOME)"/.shrc.d
- install -pm 0644 -- ksh/kshrc "$(HOME)"/.kshrc
- install -pm 0644 -- ksh/kshrc.d/* "$(HOME)"/.kshrc.d
-
-install-perlcritic :
- install -pm 0644 -- perlcritic/perlcriticrc "$(HOME)"/.perlcriticrc
-
-install-perltidy :
- install -pm 0644 -- perltidy/perltidyrc "$(HOME)"/.perltidyrc
-
-install-psql :
- install -pm 0644 -- psql/psqlrc "$(HOME)"/.psqlrc
-
-install-readline :
- install -pm 0644 -- readline/inputrc "$(HOME)"/.inputrc
-
-install-sh : check-sh
- install -m 0755 -d -- \
- "$(HOME)"/.profile.d \
- "$(HOME)"/.shrc.d
- install -pm 0644 -- sh/profile "$(HOME)"/.profile
- install -pm 0644 -- sh/profile.d/* "$(HOME)"/.profile.d
- install -pm 0644 -- sh/shinit "$(HOME)"/.shinit
- install -pm 0644 -- sh/shrc "$(HOME)"/.shrc
- install -pm 0644 -- sh/shrc.d/* "$(HOME)"/.shrc.d
-
-install-subversion :
- install -m 0755 -d -- "$(HOME)"/.subversion
- install -pm 0644 -- subversion/config "$(HOME)"/.subversion/config
-
-install-terminfo :
- for info in terminfo/*.info ; do \
- tic -- "$$info" ; \
- done
-
-install-tmux : tmux/tmux.conf install-terminfo
- install -pm 0644 -- tmux/tmux.conf "$(HOME)"/.tmux.conf
-
-install-urxvt : urxvt/ext/select check-urxvt
- install -m 0755 -d -- "$(HOME)"/.urxvt/ext
- for name in urxvt/ext/* ; do \
- case $$name in \
- *.pl) ;; \
- *) install -m 0644 -- "$$name" "$(HOME)"/.urxvt/ext ;; \
- esac \
- done
-
-install-vim : install-vim-config \
+install-conf:
+ sh install/install-conf.sh
+
+install-abook:
+ mkdir -p -- $(HOME)/.abook
+ cp -p -- abook/abookrc $(HOME)/.abook
+
+install-bash: check-bash install-sh
+ mkdir -p -- $(HOME)/.bashrc.d $(HOME)/.bash_completion.d $(HOME)/.config
+ cp -p -- bash/bashrc $(HOME)/.bashrc
+ cp -p -- bash/bashrc.d/* $(HOME)/.bashrc.d
+ cp -p -- bash/bash_profile $(HOME)/.bash_profile
+ cp -p -- bash/bash_logout $(HOME)/.bash_logout
+ cp -p -- bash/bash_completion $(HOME)/.config
+ cp -p -- bash/bash_completion.d/* $(HOME)/.bash_completion.d
+
+install-bin: $(BINS) install-bin-man
+ mkdir -p -- $(HOME)/.local/bin
+ find bin -type f -perm -u=x \
+ -exec cp -p -- {} $(HOME)/.local/bin \;
+
+install-bin-man:
+ mkdir -p -- $(HOME)/.local/share/man/man1 $(HOME)/.local/share/man/man8
+ cp -p -- man/man1/*.1df $(HOME)/.local/share/man/man1
+ cp -p -- man/man8/*.8df $(HOME)/.local/share/man/man8
+
+install-curl:
+ cp -p -- curl/curlrc $(HOME)/.curlrc
+
+install-dunst: install-x
+ mkdir -p -- $(HOME)/.config/dunst
+ cp -p -- dunst/dunstrc $(HOME)/.config/dunst
+
+install-ex:
+ cp -p -- ex/exrc $(HOME)/.exrc
+
+install-finger:
+ cp -p -- finger/plan $(HOME)/.plan
+ cp -p -- finger/project $(HOME)/.project
+ cp -p -- finger/pgpkey $(HOME)/.pgpkey
+
+install-games: $(GAMES) install-games-man
+ mkdir -p -- $(HOME)/.local/games
+ find games -type f -perm -u=x \
+ -exec cp -p -- {} $(HOME)/.local/games \;
+
+install-games-man:
+ mkdir -p -- $(HOME)/.local/share/man/man6
+ cp -p -- man/man6/*.6df $(HOME)/.local/share/man/man6
+
+install-git: git/gitconfig
+ cp -p -- git/gitconfig $(HOME)/.gitconfig
+
+install-gnupg: gnupg/gpg.conf
+ mkdir -m 0700 -p -- $(HOME)/.gnupg
+ cp -p -- gnupg/*.conf $(HOME)/.gnupg
+
+install-gtk:
+ mkdir -p -- $(HOME)/.config/gtk-3.0
+ cp -p -- gtk/gtkrc-2.0 $(HOME)/.gtkrc-2.0
+ cp -p -- gtk/gtk-3.0/settings.ini $(HOME)/.config/gtk-3.0
+
+install-i3: install-x
+ mkdir -p -- $(HOME)/.i3
+ cp -p -- i3/* $(HOME)/.i3
+
+install-keychain: install-sh
+ cp -p -- keychain/profile.d/* $(HOME)/.profile.d
+ cp -p -- keychain/shrc.d/* $(HOME)/.shrc.d
+
+install-less:
+ cp -p -- less/lesskey $(HOME)/.lesskey
+ lesskey
+
+install-mpd: install-sh
+ mkdir -p -- $(HOME)/.mpd/playlists
+ cp -p -- mpd/profile.d/* $(HOME)/.profile.d
+ cp -p -- mpd/mpdconf $(HOME)/.mpdconf
+
+install-mutt:
+ mkdir -p -- $(HOME)/.muttrc.d $(HOME)/.cache/mutt
+ cp -p -- mutt/muttrc $(HOME)/.muttrc
+ cp -p -- mutt/muttrc.d/src $(HOME)/.muttrc.d
+
+install-ncmcpp: install-mpd
+ mkdir -p -- $(HOME)/.ncmpcpp
+ cp -p -- ncmpcpp/config $(HOME)/.ncmpcpp
+
+install-newsbeuter:
+ mkdir -p -- $(HOME)/.config/newsbeuter $(HOME)/.local/share/newsbeuter
+ cp -p -- newsbeuter/config $(HOME)/.config/newsbeuter
+
+install-mysql:
+ cp -p -- mysql/my.cnf $(HOME)/.my.cnf
+
+install-ksh: check-ksh install-sh
+ mkdir -p -- $(HOME)/.kshrc.d
+ cp -p -- ksh/shrc.d/* $(HOME)/.shrc.d
+ cp -p -- ksh/kshrc $(HOME)/.kshrc
+ cp -p -- ksh/kshrc.d/* $(HOME)/.kshrc.d
+
+install-login-shell: check-login-shell
+ sh install/install-login-shell.sh
+
+install-perlcritic:
+ cp -p -- perlcritic/perlcriticrc $(HOME)/.perlcriticrc
+
+install-perltidy:
+ cp -p -- perltidy/perltidyrc $(HOME)/.perltidyrc
+
+install-plenv: install-sh
+ cp -p -- plenv/profile.d/* $(HOME)/.profile.d
+ cp -p -- plenv/shrc.d/* $(HOME)/.shrc.d
+
+install-psql:
+ cp -p -- psql/psqlrc $(HOME)/.psqlrc
+
+install-readline:
+ cp -p -- readline/inputrc $(HOME)/.inputrc
+
+install-sh: check-sh
+ mkdir -p -- $(HOME)/.profile.d $(HOME)/.shrc.d
+ cp -p -- sh/profile $(HOME)/.profile
+ cp -p -- sh/profile.d/* $(HOME)/.profile.d
+ cp -p -- sh/shinit $(HOME)/.shinit
+ cp -p -- sh/shrc $(HOME)/.shrc
+ cp -p -- sh/shrc.d/* $(HOME)/.shrc.d
+
+install-subversion:
+ mkdir -p -- $(HOME)/.subversion
+ cp -p -- subversion/config $(HOME)/.subversion
+
+install-terminfo:
+ find terminfo -type f -name '*.info' \
+ -exec tic -- {} \;
+
+install-tmux: tmux/tmux.conf install-terminfo
+ cp -p -- tmux/tmux.conf $(HOME)/.tmux.conf
+
+install-urxvt: urxvt/ext/select
+ mkdir -p -- $(HOME)/.urxvt/ext
+ find urxvt/ext -type f ! -name '*.pl' \
+ -exec cp -p -- {} $(HOME)/.urxvt/ext \;
+
+install-vim: install-vim-config \
install-vim-plugins \
install-vim-pathogen
-install-gvim : install-vim \
- install-gvim-config
+install-vim-config:
+ cp -p -- vim/vimrc $(HOME)/.vimrc
-install-vim-config :
- install -pm 0644 -- vim/vimrc "$(HOME)"/.vimrc
+install-vim-gui: install-vim \
+ install-vim-gui-config
-install-gvim-config :
- install -pm 0644 -- vim/gvimrc "$(HOME)"/.gvimrc
+install-vim-gui-config:
+ cp -p -- vim/gvimrc $(HOME)/.gvimrc
-install-vim-plugins : install-vim-config
+install-vim-plugins: install-vim-config
find vim/after vim/bundle -name .git -prune -o \
- -type d -exec sh -c 'install -m 0755 -d -- \
- "$(HOME)"/."$$1"' _ {} \; -o \
- -type f -exec sh -c 'install -m 0644 -- \
- "$$1" "$(HOME)"/."$$1"' _ {} \;
-
-install-vim-pathogen : install-vim-plugins
- install -m 0755 -d -- "$(HOME)"/.vim/autoload
- rm -f -- "$(HOME)"/.vim/autoload/pathogen.vim
- ln -s -- ../bundle/pathogen/autoload/pathogen.vim \
- "$(HOME)"/.vim/autoload/pathogen.vim
-
-install-wyrd :
- install -pm 0644 -- wyrd/wyrdrc "$(HOME)"/.wyrdrc
-
-install-x :
- install -m 0755 -d -- \
- "$(HOME)"/.config \
- "$(HOME)"/.xinitrc.d \
- "$(HOME)"/.Xresources.d
- install -pm 0644 -- X/redshift.conf "$(HOME)"/.config/redshift.conf
- install -pm 0644 -- X/xbindkeysrc "$(HOME)"/.xbindkeysrc
- install -pm 0644 -- X/xinitrc "$(HOME)"/.xinitrc
- install -pm 0644 -- X/xinitrc.d/* "$(HOME)"/.xinitrc.d
- install -pm 0644 -- X/Xresources "$(HOME)"/.Xresources
- install -pm 0644 -- X/Xresources.d/* "$(HOME)"/.Xresources.d
-
-install-yash : check-yash install-sh
- install -m 0755 -d -- "$(HOME)"/.yashrc.d
- install -pm 0644 -- yash/yash_profile "$(HOME)"/.yash_profile
- install -pm 0644 -- yash/yashrc "$(HOME)"/.yashrc
- install -pm 0644 -- yash/yashrc.d/* "$(HOME)"/.yashrc.d
-
-install-zsh : check-zsh install-sh
- install -m 0755 -d -- \
- "$(HOME)"/.profile.d \
- "$(HOME)"/.zshrc.d
- install -pm 0644 -- zsh/profile.d/* "$(HOME)"/.profile.d
- install -pm 0644 -- zsh/zprofile "$(HOME)"/.zprofile
- install -pm 0644 -- zsh/zshrc "$(HOME)"/.zshrc
- install -pm 0644 -- zsh/zshrc.d/* "$(HOME)"/.zshrc.d
-
-check : check-bash \
- check-bin \
- check-games \
+ -type d -exec sh -c 'mkdir -p -- $(HOME)/."$$1"' _ {} \; -o \
+ -type f -exec sh -c 'cp -p -- "$$1" $(HOME)/."$$1"' _ {} \;
+
+install-vim-pathogen: install-vim-plugins
+ mkdir -p -- $(HOME)/.vim/autoload
+ ln -fs -- ../bundle/pathogen/autoload/pathogen.vim $(HOME)/.vim/autoload
+
+install-wget:
+ cp -p -- wget/wgetrc $(HOME)/.wgetrc
+
+install-x: check-xinit
+ mkdir -p -- \
+ $(HOME)/.config \
+ $(HOME)/.config/sxhkdrc \
+ $(HOME)/.xinitrc.d \
+ $(HOME)/.Xresources.d
+ cp -p -- X/redshift.conf $(HOME)/.config
+ cp -p -- X/sxhkdrc $(HOME)/.config/sxhkd
+ cp -p -- X/xinitrc $(HOME)/.xinitrc
+ cp -p -- X/xinitrc.d/* $(HOME)/.xinitrc.d
+ cp -p -- X/Xresources $(HOME)/.Xresources
+ cp -p -- X/Xresources.d/* $(HOME)/.Xresources.d
+
+install-zsh: check-zsh install-sh
+ mkdir -p -- $(HOME)/.profile.d $(HOME)/.zshrc.d
+ cp -p -- zsh/profile.d/* $(HOME)/.profile.d
+ cp -p -- zsh/zprofile $(HOME)/.zprofile
+ cp -p -- zsh/zshrc $(HOME)/.zshrc
+ cp -p -- zsh/zshrc.d/* $(HOME)/.zshrc.d
+
+check: check-bin \
+ check-login-shell \
check-man \
- check-sh \
- check-urxvt
+ check-sh
+
+check-bash:
+ sh check/bash.sh
-check-bash :
- check/bash
+check-bin: $(BINS_SH)
+ sh check/bin.sh
-check-bin : $(BINS)
- check/bin
+check-games:
+ sh check/games.sh
-check-games : $(GAMES)
- check/games
+check-man:
+ sh check/man.sh
-check-man :
- check/man
+check-ksh:
+ sh check/ksh.sh
-check-ksh :
- check/ksh
+check-login-shell:
+ sh check/login-shell.sh
-check-sh :
- check/sh
+check-sh:
+ sh check/sh.sh
-check-urxvt :
- check/urxvt
+check-urxvt:
+ sh check/urxvt.sh
-check-yash :
- check/yash
+check-xinit:
+ sh check/xinit.sh
-check-zsh :
- check/zsh
+check-zsh:
+ sh check/zsh.sh
-lint : check \
- lint-bash \
- lint-bin \
- lint-games \
- lint-ksh \
- lint-sh \
+lint: lint-bash \
+ lint-bin \
+ lint-games \
+ lint-ksh \
+ lint-sh \
lint-urxvt \
- lint-yash
+ lint-xinit
-lint-bash :
- lint/bash
+lint-bash: check-bash
+ sh lint/bash.sh
-lint-bin : $(BINS)
- lint/bin
+lint-bin: check-bin
+ sh lint/bin.sh
-lint-games : $(GAMES)
- lint/games
+lint-games: check-games
+ sh lint/games.sh
-lint-ksh :
- lint/ksh
+lint-ksh: check-ksh
+ sh lint/ksh.sh
-lint-sh :
- lint/sh
+lint-sh: check-sh
+ sh lint/sh.sh
-lint-urxvt :
- lint/urxvt
+lint-urxvt: check-urxvt
+ sh lint/urxvt.sh
-lint-yash :
- lint/yash
+lint-xinit: check-xinit
+ sh lint/xinit.sh
diff --git a/README.markdown b/README.md
index 97823267..f1b254f0 100644
--- a/README.markdown
+++ b/README.md
@@ -4,6 +4,10 @@ Dotfiles (Tom Ryder)
This is my personal repository of configuration files and scripts for `$HOME`,
including most of the settings that migrate well between machines.
+This repository began as a simple way to share Vim and tmux configuration, but
+over time a lot of scripts and shell configuration have been added, making it
+into a personal suite of custom Unix tools.
+
Installation
------------
@@ -15,8 +19,8 @@ Installation
$ make -n install
$ make install
-For the default `all` target, you'll need `bash(1)`, `git(1)`, `install(1)`,
-`make(1)`, and `m4(1)`.
+For the default `all` target, you'll need a POSIX-fearing userland, including
+`make(1)` and `m4(1)`.
The installation `Makefile` will overwrite things standing in the way of its
installed files without backing them up, so read the output of `make -n
@@ -26,26 +30,41 @@ directory so you can explore:
$ tmpdir=$(mktemp -d)
$ make install HOME="$tmpdir"
- $ env -i HOME="$tmpdir" TERM="$TERM" bash -l
-
-The default target will install the core terminal-only files: cURL, Git, GnuPG,
-Vim, shell scripts and functions, and shell and terminal setup files. The
-remaining dotfiles can be installed with the other targets. Take a look at the
-`Makefile` to see what's available.
+ $ env -i HOME="$tmpdir" TERM="$TERM" "$SHELL" -l
+
+The default `install` target will install these targets and all their
+dependencies. Note that you don't actually have to have any of this except `sh`
+installed.
+
+* `install-bin`
+* `install-bin-man`
+* `install-curl`
+* `install-ex`
+* `install-git`
+* `install-gnupg`
+* `install-less`
+* `install-login-shell`
+* `install-readline`
+* `install-vim`
+
+The `install-login-shell` looks at your `SHELL` environment variable and tries
+to figure out which shell’s configuration files to install, falling back on
+`install-sh`.
+
+The remaining dotfiles can be installed with the other `install-*` targets. Try
+`awk -f bin/mftl.awk Makefile` in the project's root directory to see a list.
Tools
-----
Configuration is included for:
-* Bourne-style POSIX shells, sharing an `ENV` file and functions:
+* Bourne-style POSIX shells, sharing a `.profile`, an `ENV` file, and
+ some helper functions:
* [GNU Bash](https://www.gnu.org/software/bash/) (2.05a or higher)
- * [Korn shell](http://www.kornshell.com/) (including `pdksh`, `mksh`)
- * [Yash](https://yash.osdn.jp/index.html.en)
+ * [Korn shell](http://www.kornshell.com/) (`ksh93`, `pdksh`, `mksh`)
* [Z shell](https://www.zsh.org/)
* [Abook](http://abook.sourceforge.net/) -- curses address book program
- including a `~/.profile` configured to work with most Bourne-compatible
- shells
* [cURL](https://curl.haxx.se/) -- Command-line tool for transferring data
with URL syntax
* [Dunst](http://knopwob.org/dunst/) -- A lightweight X11 notification daemon
@@ -54,15 +73,15 @@ Configuration is included for:
* [Git](https://git-scm.com/) -- Distributed version control system
* [GnuPG](https://www.gnupg.org/) -- GNU Privacy Guard, for private
communication and file encryption
-* [GTK+](http://www.gtk.org/) -- GIMP Toolkit, for graphical user interface
+* [GTK+](https://www.gtk.org/) -- GIMP Toolkit, for graphical user interface
elements
* [i3](https://i3wm.org/) -- Tiling window manager
* [less](https://www.gnu.org/software/less/) -- Terminal pager
* [Mutt](http://www.mutt.org/) -- Terminal mail user agent
-* [`mysql(1)`](http://linux.die.net/man/1/mysql) -- Command-line MySQL client
+* [`mysql(1)`](https://linux.die.net/man/1/mysql) -- Command-line MySQL client
* [Ncmpcpp](https://rybczak.net/ncmpcpp/) -- ncurses music player client
* [Newsbeuter](https://www.newsbeuter.org/) -- Terminal RSS/Atom feed reader
-* [`psql(1)`](http://linux.die.net/man/1/psql) -- Command-line PostgreSQL
+* [`psql(1)`](https://linux.die.net/man/1/psql) -- Command-line PostgreSQL
client
* [Perl::Critic](http://perlcritic.com/) -- static source code analysis
engine for Perl
@@ -77,8 +96,6 @@ Configuration is included for:
* [tmux](https://tmux.github.io/) -- Terminal multiplexer similar to GNU
Screen
* [Vim](http://www.vim.org/) -- Vi IMproved, a text editor
-* [Wyrd](https://packages.debian.org/sid/wyrd) -- a `curses` calendar
- frontend for [Remind](https://www.roaringpenguin.com/products/remind)
* [X11](https://www.x.org/wiki/) -- Windowing system with network
transparency for Unix
@@ -124,34 +141,33 @@ after testing `BASH_VERSINFO` appropriately.
A terminal session with my prompt looks something like this:
~$ ssh remote
- tom@remote:~$ bash
- >tom@remote:~$ cd .dotfiles
- >tom@remote:~/.dotfiles(master+!)$ git status
- M README.markdown
+ remote:~$ cd .dotfiles
+ remote:~/.dotfiles(master+!)$ git status
+ M README.md
M bash/bashrc.d/prompt.bash
A init
- >tom@remote:~/.dotfiles(master+!)$ foobar
+ remote:~/.dotfiles(master+!)$ foobar
foobar: command not found
- >tom@remote:~/.dotfiles(master+!)<127>$ sleep 5 &
+ remote:~/.dotfiles(master+!)<127>$ sleep 5 &
[1] 28937
- >tom@remote:~/.dotfiles(master+!){1}$
+ remote:~/.dotfiles(master+!){1}$
-If `SHLVL` is greater than one, right angle brackets are added to show how many
-`bash` instances deep into the process tree we are, taking into account `tmux`.
-The username and hostname are elided if not connected via SSH. The working
-directory is always shown. The rest of the prompt expands based on context to
-include these elements in this order:
+The hostname is elided if not connected via SSH. The working directory with
+tilde abbreviation for `$HOME` is always shown. The rest of the prompt expands
+based on context to include these elements in this order:
* Whether in a Git repository if applicable, and punctuation to show
repository status including reference to upstreams at a glance. Subversion
support can also be enabled (I need it at work), in which case a `git:` or
- `svn:` prefix is added appropriately
-* The number of running background jobs, if non-zero
-* The exit status of the last command, if non-zero
+ `svn:` prefix is added appropriately.
+* The number of running background jobs, if non-zero.
+* The exit status of the last command, if non-zero.
You can set `PROMPT_COLOR`, `PROMPT_PREFIX`, and `PROMPT_SUFFIX` too, which all
-do about what you'd expect. `PROMPT_PREFIX` will appear after the `SHLVL` angle
-brackets.
+do about what you'd expect.
+
+If you start up Bash, Ksh, or Zsh and it detects that it's not normally your
+`$SHELL`, the prompt will display an appropriate prefix.
This is all managed within the `prompt` function. There's some mildly hacky
logic on `tput` codes included such that it should work correctly for most
@@ -170,10 +186,10 @@ in `sh/shrc.d` to be loaded by any POSIX interactive shell. Those include:
* `gd()` goes to the marked directory.
* `pmd()` prints the marked directory.
* `xd()` swaps the current and marked directories.
-* Nine other directory management and navigation functions:
- * `ad()` is a `cd` shortcut accepting targets like `/u/l/b` for
- `/usr/local/bin`, as long as they are unique.
+* Ten other directory management and navigation functions:
* `bd()` changes into a named ancestor of the current directory.
+ * `gt()` changes into a directory or into a file's directory.
+ * `lgt()` runs `gt()` on the first result from a `loc(1df)` search.
* `mkcd()` creates a directory and changes into it.
* `pd()` changes to the argument's parent directory.
* `rd()` replaces the first instance of its first argument with its
@@ -187,29 +203,22 @@ in `sh/shrc.d` to be loaded by any POSIX interactive shell. Those include:
* `bc()` silences startup messages from GNU `bc(1)`.
* `ed()` tries to get verbose error messages, a prompt, and a Readline
environment for `ed(1)`.
-* `env()` sorts the output of `env(1)` if it was invoked with no arguments,
- just for convenience when running it interactively.
* `gdb()` silences startup messages from `gdb(1)`.
* `gpg()` quietens `gpg(1)` down for most commands.
-* `grep()` tries to apply color and other options good for interactive use,
- depending on the capabilities of the system `grep(1)`.
+* `grep()` tries to apply color and other options good for interactive use if
+ available.
* `hgrep()` allows searching `$HISTFILE`.
* `keychain()` keeps `$GPG_TTY` up to date if a GnuPG agent is available.
-* `ls()` tries to apply color to `ls(1)` for interactive use if available.
+* `ls()` tries to apply color and other options good for interactive use if
+ available.
* `la()` runs `ls -A` if it can, or `ls -a` otherwise.
* `ll()` runs `ls -Al` if it can, or `ls -al` otherwise.
-* `mysql()` allows shortcuts to MySQL configuration files stored in
- `~/.mysql`.
* `path()` manages the contents of `PATH` conveniently.
* `scp()` tries to detect forgotten hostnames in `scp(1)` command calls.
* `sudo()` forces `-H` for `sudo(8)` calls so that `$HOME` is never
preserved; I hate having `root`-owned files in my home directory.
-* `tmux()` changes the default command for `tmux(1)` to `attach-session -d`
- if a session exists, or creates a new session if one doesn't.
* `tree()` colorizes GNU `tree(1)` output if possible (without having
`LS_COLORS` set).
-* `vim()` defines three functions to always use `vim(1)` as my `ex(1)`,
- `vi(1)` and `view(1)` implementation if it's available.
* `x()` is a one-key shortcut for `exec startx`.
There are a few other little tricks defined for other shells providing
@@ -223,7 +232,7 @@ non-POSIX features, as compatibility allows:
* `vared()` allows interactively editing a variable with Readline, emulating
a Zsh function I like by the same name (Bash).
* `ver()` prints the current shell's version information (Bash, Korn Shell,
- Yash, Z shell).
+ Z shell).
#### Completion
@@ -242,7 +251,6 @@ files, for things I really do get tired of typing repeatedly:
* `gpg(1)` long options
* `make(1)` targets read from a `Makefile`
* `man(1)` page titles
-* `mysql(1)` databases from `~/.mysql/*.cnf`
* `pass(1)` entries
* `ssh(1)` hostnames from `~/.ssh/config`
@@ -261,10 +269,6 @@ These are experimental; they are mostly used to tinker with MirBSD `mksh`, AT&T
`ksh93`, and OpenBSD `pdksh`. All shells in this family default to a yellow
prompt if detected.
-#### Yash
-
-Just enough configuration to coax it into reading `~/.profile` and `~/.shrc`.
-
#### Zsh
These are experimental; I do not like Zsh much at the moment. The files started
@@ -274,7 +278,7 @@ as a joke (`exec bash`). `zsh` shells default to having a prompt coloured cyan.
The configuration for GnuPG is intended to follow [RiseUp's OpenPGP best
practices](https://riseup.net/en/security/message-security/openpgp/best-practices).
-The configuration file is rebuilt using `m4(1)` and `make(1)` because it
+The configuration file is rebuilt using `mi5(1df)` and `make(1)` because it
requires hard-coding a path to the SKS keyserver certificate authority, and
neither tilde nor `$HOME` expansion works for this.
@@ -283,7 +287,7 @@ neither tilde nor `$HOME` expansion works for this.
My mail is kept in individual Maildirs under `~/Mail`, with `inbox` being where
most unfiltered mail is sent. I use
[Getmail](http://pyropus.ca/software/getmail/),
-[maildrop](http://www.courier-mta.org/maildrop/), and
+[maildrop](https://www.courier-mta.org/maildrop/), and
[MSMTP](http://msmtp.sourceforge.net/); the configurations for these are not
included here. I sign whenever I have some indication that the recipient might
be using a PGP implementation, and I encrypt whenever I have a public key
@@ -309,7 +313,7 @@ Perl extensions. If you're missing functionality, try changing
My choice of font is [Ubuntu Mono](http://font.ubuntu.com/), but the file
should allow falling back to the more common [Deja Vu Sans
-Mono](http://dejavu-fonts.org/wiki/Main_Page). I've found
+Mono](https://dejavu-fonts.github.io/). I've found
[Terminus](http://terminus-font.sourceforge.net/) works well too, but bitmap
fonts are not really my cup of tea. The Lohit Kannada font bit is purely to
make ಠ\_ಠ work correctly. ( ͡° ͜ʖ ͡°) seems to work out of the box.
@@ -321,16 +325,10 @@ Note that the configuration presently uses a hard-coded 256-color colorscheme,
and uses non-login shells, with an attempt to control the environment to stop
shells thinking they have access to an X display.
-The configuration file is created with `m4(1)` to allow specifying a color
-theme. This is just because I use a different color for my work session. The
-default is a dark grey.
-
-The configuration for Bash includes a `tmux` function designed to make `attach`
-into the default command if no arguments are given and sessions do already
-exist. The default command is normally `new-session`.
-
-My `~/.inputrc` file binds Alt+M to attach to or create a `tmux` session, and
-Tmux in turn binds the same key combination to detach.
+The shell scripts in `bin` include `tm(1df)`, a shortcut to make `attach` into
+the default command if no arguments are given and sessions do already exist. My
+`~/.inputrc` file binds Alt+M to run that, and Tmux in turn binds the same key
+combination to detach.
### Vim
@@ -409,11 +407,34 @@ Installed by the `install-bin` target:
* `min(1df)` prints the minimum.
* `mode(1df)` prints the first encountered mode.
* `tot(1df)` totals the set.
-* Two quick-and-dirty HTML text node content encoding tools:
+* Three quick-and-dirty HTML tools:
* `htenc(1df)` encodes.
* `htdec(1df)` decodes.
+ * `htrec(1df)` wraps `a` tags around URLs.
+* Two internet message quoting tools:
+ * `quo(1df)` indents with quoting right angle-brackets.
+ * `wro(1df)` adds a quote attribution header to its input.
+* Six Git-related tools:
+ * `fgscr(1df)` finds Git repositories in a directory root and scrubs them
+ with `gscr(1df)`.
+ * `grc(1df)` quietly tests whether the given directory appears to be a
+ Git repository with pending changes.
+ * `gscr(1df)` scrubs Git repositories.
+ * `isgr(1df)` quietly tests whether the given directory appears to be a
+ Git repository.
+ * `jfc(1df)` adds and commits lazily to a Git repository.
+ * `jfcd(1df)` watches a directory for changes and runs `jfc(1df)` if it
+ sees any.
+* Two time duration functions:
+ * `hms(1df)` converts seconds to `hh:mm:ss` or `mm:ss` timestamps.
+ * `sec(1df)` converts `hh:mm:ss` or `mm:ss` timestamps to seconds.
+* Three pipe interaction tools:
+ * `pst(1df)` runs an interactive program on data before passing it along
+ a pipeline.
+ * `ped(1df)` runs `pst(1df)` with `$EDITOR` or `ed(1)`.
+ * `pvi(1df)` runs `pvi(1df)` with `$VISUAL` or `vi(1)`.
* `ap(1df)` reads arguments for a given command from the standard input,
- prompting if appropriate
+ prompting if appropriate.
* `apf(1df)` prepends arguments to a command with ones read from a file,
intended as a framework for shell wrappers or functions.
* `ax(1df)` evaluates an awk expression given on the command line; this is
@@ -421,20 +442,21 @@ Installed by the `install-bin` target:
* `bcq(1df)` runs `bc(1)`, quieting it down if need be.
* `bel(1df)` prints a terminal bell character.
* `bl(1df)` generates a given number of blank lines.
-* `bp(1df)` runs `br(1df)` after prompting for an URL
-* `br(1df)` launches `$BROWSER`, or a more suitable application for an URL if
- it knows of one.
+* `bp(1df)` runs `br(1df)` after prompting for an URL.
+* `br(1df)` launches `$BROWSER`.
* `ca(1df)` prints a count of its given arguments.
* `cf(1df)` prints a count of entries in a given directory.
* `cfr(1df)` does the same as `cf(1df)`, but recurses into subdirectories as
well.
* `chc(1df)` caches the output of a command.
+* `chn(1df)` runs a filter over its input a given number of times.
* `clog(1df)` is a tiny timestamped log system.
* `clrd(1df)` sets up a per-line file read, clearing the screen first.
* `clwr(1df)` sets up a per-line file write, clearing the screen before each
- line
+ line.
* `csmw(1df)` prints an English list of monospace-quoted words read from the
- input
+ input.
+* `dam(1df)` buffers all its input before emitting it as output.
* `ddup(1df)` removes duplicate lines from unsorted input.
* `dmp(1df)` copies a pass(1) entry selected by `dmenu(1)` to the X
CLIPBOARD.
@@ -443,40 +465,44 @@ Installed by the `install-bin` target:
any options, mostly useful for scripts.
* `eds(1df)` edits executable script files in `EDSPATH`, defaulting to
`~/.local/bin`, for personal scripting snippets.
-* `fgscr(1df)` finds Git repositories in a directory root and scrubs them
- with `gscr(1df)`.
+* `exm(1df)` works around a screen-clearing quirk of Vim's `ex` mode.
* `finc(1df)` counts the number of results returned from a set of given
`find(1)` conditions.
* `fnl(1df)` runs a command and saves its output and error into temporary
- files, printing their paths and line counts
+ files, printing their paths and line counts.
+* `fnp(1df)` prints the given files to stdout, each with a plaintext heading
+ with the filename in it.
* `gms(1df)` runs a set of `getmailrc` files; does much the same thing as the
script `getmails` in the `getmail` suite, but runs the requests in parallel
and does up to three silent retries using `try(1df)`.
-* `grc(1df)` quietly tests whether the given directory appears to be a Git
- repository with pending changes.
-* `gscr(1df)` scrubs Git repositories.
+* `grec(1df)` is a more logically-named `grep -c`.
+* `gred(1df)` is a more logically-named `grep -v`.
* `gwp(1df)` searches for alphanumeric words in a similar way to `grep(1)`.
* `han(1df)` provides a `keywordprg` for Vim's Bash script filetype that will
look for `help` topics. You could use it from the shell too.
* `igex(1df)` wraps around a command to allow you to ignore error conditions
that don't actually worry you, exiting with 0 anyway.
-* `isgr(1df)` quietly tests whether the given directory appears to be a Git
- repository.
* `ix(1df)` posts its input to the ix.io pastebin.
-* `jfc(1df)` adds and commits lazily to a Git repository.
* `jfp(1df)` prints its input, excluding any shebang on the first line only.
-* `jfcd(1df)` watches a directory for changes and runs `jfc(1df)` if it sees
- any.
* `loc(1df)` is a quick-search wrapped around `find(1)`.
* `maybe(1df)` is like `true(1)` or `false(1)`; given a probability of
success,
it exits with success or failure. Good for quick tests.
* `mex(1df)` makes given filenames in `$PATH` executable.
+* `mi5(1df)` pre-processes a crude but less painful macro expansion file
+ format into `m4` input.
* `mftl(1df)` finds usable-looking targets in Makefiles.
* `mkcp(1df)` creates a directory and copies preceding arguments into it.
* `mkmv(1df)` creates a directory and moves preceding arguments into it.
* `motd(1df)` shows the system MOTD.
+* `mw(1df)` prints alphabetic space-delimited words from the input one per
+ line.
+* `oii(1df)` runs a command on input only if there is any.
* `onl(1df)` crunches input down to one printable line.
+* `osc(1df)` implements a `netcat(1)`-like wrapper for `openssl(1)`'s
+ `s_client` subcommand.
+* `p(1df)` prints concatenated standard input; `cat(1)` as it should always
+ have been.
* `pa(1df)` prints its arguments, one per line.
* `pp(1df)` prints the full path of each argument using `$PWD`.
* `pph(1df)` runs `pp(1df)` and includes a leading `$HOSTNAME:`.
@@ -487,10 +513,10 @@ Installed by the `install-bin` target:
[`plenv`](https://github.com/tokuhirom/plenv), filters out any modules in
`~/.plenv/non-cpan-modules`, and updates them all.
* `pwg(1df)` generates just one decent password with `pwgen(1)`.
+* `rep(1df)` repeats a command a given number of times.
* `rgl(1df)` is a very crude interactive `grep(1)` loop.
* `shb(1df)` attempts to build shebang lines for scripts from the system
paths.
-* `sec(1df)` converts `hh:mm:ss` or `mm:ss` timestamps to seconds.
* `sqs(1df)` chops off query strings from filenames, usually downloads.
* `sshi(1df)` prints human-readable SSH connection details.
* `stex(1df)` strips extensions from filenames.
@@ -501,6 +527,9 @@ Installed by the `install-bin` target:
`scp(1)`'s HOST:PATH format.
* `td(1df)` manages a to-do file for you with `$EDITOR` and `git(1)`; I used
to use Taskwarrior, but found it too complex and buggy.
+* `tm(1df)` runs `tmux(1)` with `attach-session -d` if a session exists, and
+ `new-session` if it doesn't.
+* `trs(1df)` replaces strings (not regular expression) in its input.
* `try(1df)` repeats a command up to a given number of times until it
succeeds, only printing error output if all three attempts failed. Good for
tolerating blips or temporary failures in `cron(8)` scripts.
@@ -511,6 +540,9 @@ Installed by the `install-bin` target:
* `vest(1df)` runs `test(1)` but fails with explicit output via `vex(1df)`.
* `vex(1df)` runs a command and prints `true` or `false` explicitly to
`stdout` based on the exit value.
+* `xrbg(1df)` applies the same randomly-selected background to each X screen.
+* `xrq(1df)` gets the values of specific resources out of `xrdb -query`
+ output.
There's some silly stuff in `install-games`:
@@ -519,8 +551,11 @@ There's some silly stuff in `install-games`:
* `acq(6df)` allows you to interrogate AC, the interplanetary computer.
* `aesth(6df)` converts English letters to their fullwidth CJK analogues, for
AESTHETIC PURPOSES.
+* `squ(6df)` makes a reduced Latin square out of each line of input.
* `kvlt(6df)` translates input to emulate a style of typing unique to black
metal communities on the internet.
+* `philsay(6df)` shows a picture to accompany `pks(6df)` output.
+* `pks(6df)` laughs at a randomly selected word.
* `rndn(6df)` implements an esoteric random number generation algorithm.
* `strik(6df)` outputs s̶t̶r̶i̶k̶e̶d̶ ̶o̶u̶t̶ struck out text.
* `rot13(6df)` rotates the Latin letters in its input.
@@ -532,13 +567,9 @@ Manuals
-------
The `install-bin` and `install-games` targets install manuals for each script
-they install. There's also an `install-dotfiles-man` target that uses
-`pandoc(1)` to reformat this document as a manual page for section 7
-(`dotfiles(7df)`) if you want that. I haven't made that install by default,
-because `pandoc(1)` is a bit heavy.
-
-If you want to use the manuals, you may need to add `~/.local/share/man` to
-your `~/.manpath` or `/etc/manpath` configuration, depending on your system.
+they install. If you want to use the manuals, you may need to add
+`~/.local/share/man` to your `~/.manpath` or `/etc/manpath` configuration,
+depending on your system.
Testing
-------
@@ -558,15 +589,6 @@ Known issues
See ISSUES.markdown.
-Note for previous visitors
---------------------------
-
-Most of this repository's five-year history was rewritten shortly after I moved
-it from GitHub to cgit, taking advantage of the upheaval to reduce its size and
-remove useless binary blobs and third-party stuff that I never should have
-versioned anyway. If you've checked this out before, you'll probably need to do
-it again, and per-commit links are likely to be broken. Sorry about that.
-
License
-------
@@ -576,5 +598,6 @@ If you're feeling generous, please join and/or donate to a free software
advocacy group, and let me know you did it because of this project:
* [Free Software Foundation](https://www.fsf.org/)
-* [Software in the Public Interest](http://www.spi-inc.org/)
+* [Software in the Public Interest](https://www.spi-inc.org/)
+* [FreeBSD Foundation](https://www.freebsdfoundation.org/)
* [OpenBSD Foundation](http://www.openbsdfoundation.org/)
diff --git a/TABS.md b/TABS.md
new file mode 100644
index 00000000..feeee631
--- /dev/null
+++ b/TABS.md
@@ -0,0 +1,26 @@
+Spaces to tabs
+==============
+
+If you prefer tabs to spaces, the following recipe seems to convert everything
+pretty nicely:
+
+ $ find . -name .git -prune -o -name vim -prune -o -type f \
+ -exec sh -c \
+ 'for f;do unexpand -t4 "$f">"$f".tmp;mv "$f" "$f".tmp;done' \
+ _ {} +
+
+ $ find vim -name bundle -prune -o -type f \
+ -exec sh -c \
+ 'for f;do unexpand -t2 "$f">"$f".tmp;mv "$f" "$f".tmp;done' \
+ _ {} +
+
+If you have GNU unexpand(1) and can add `--first-only` to each of those calls,
+the results seem perfect.
+
+You can configure Vim to accommodate this by removing the settings for:
+
+* `expandtab`
+* `shiftround`
+* `shiftwidth`
+* `smarttab`
+* `softtabstop`
diff --git a/X/Xresources b/X/Xresources
index 487c6ab0..d7d7556f 100644
--- a/X/Xresources
+++ b/X/Xresources
@@ -1,2 +1,3 @@
-#include ".Xresources.d/Xft"
#include ".Xresources.d/URxvt"
+#include ".Xresources.d/Xft"
+#include ".Xresources.d/xterm"
diff --git a/X/Xresources.d/xterm b/X/Xresources.d/xterm
new file mode 100644
index 00000000..ffa29689
--- /dev/null
+++ b/X/Xresources.d/xterm
@@ -0,0 +1,9 @@
+! XTerm
+xterm*bellIsUrgent : true
+xterm*internalBorder : 0
+xterm*colorMode : false
+xterm*eightBitInput : false
+xterm*faceName : Ubuntu Mono:size=12
+xterm*locale : true
+xterm*metaSendsEscape : true
+xterm*termName : xterm-mono
diff --git a/X/sxhkdrc b/X/sxhkdrc
new file mode 100644
index 00000000..7816208f
--- /dev/null
+++ b/X/sxhkdrc
@@ -0,0 +1,47 @@
+super + Return
+ urxvtcd
+
+super + control + Return
+ urxvtcd -e sh
+
+super + shift + Return
+ urxvtcd -e ksh
+
+super + alt + Return
+ urxvtcd -e zsh
+
+super + b
+ br
+
+super + d
+ dmenu_run
+
+super + g
+ xgoc
+
+super + i
+ gimp
+
+super + m
+ urxvtcd -e tm
+
+super + p
+ dmp
+
+super + v
+ urxvtcd -e "$VISUAL"
+
+super + slash
+ i3lock --color=#000000 --image ~/.i3/lock.png --nofork
+
+XF86AudioMute
+ amixer -q sset Master toggle
+
+XF86AudioRaiseVolume
+ amixer -q sset Master 5%+ unmute
+
+XF86AudioLowerVolume
+ amixer -q sset Master 5%- unmute
+
+XF86Calculator
+ urxvtcd -e bcq
diff --git a/X/xbindkeysrc b/X/xbindkeysrc
deleted file mode 100644
index 00855b09..00000000
--- a/X/xbindkeysrc
+++ /dev/null
@@ -1,32 +0,0 @@
-"exec urxvtcd"
- Mod4 + Return
-
-"exec br"
- Mod4 + b
-
-"exec dmenu_run"
- Mod4 + d
-
-"exec xgoc"
- Mod4 + g
-
-"exec gimp"
- Mod4 + i
-
-"exec dmp"
- Mod4 + p
-
-"exec i3lock --color=#000000 --image ~/.i3/lock.png --nofork"
- Mod4 + slash
-
-"exec amixer -q sset Master toggle"
- XF86AudioMute
-
-"exec amixer -q sset Master 5%+ unmute"
- XF86AudioRaiseVolume
-
-"exec amixer -q sset Master 5%- unmute"
- XF86AudioLowerVolume
-
-"exec urxvtcd -e bcq"
- XF86Calculator
diff --git a/X/xinitrc b/X/xinitrc
index e0b3d661..6f2ad45f 100644
--- a/X/xinitrc
+++ b/X/xinitrc
@@ -1,3 +1,6 @@
+# If a file ~/.xrandrrc exists for monitor setup, source that first
+[ -e "$HOME"/.xrandrrc ] && . "$HOME"/.xrandrrc
+
# Read X resources
xrdb "$HOME"/.Xresources
diff --git a/X/xinitrc.d/shlvl.sh b/X/xinitrc.d/shlvl.sh
deleted file mode 100644
index 0e3bad04..00000000
--- a/X/xinitrc.d/shlvl.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-# Reset SHLVL
-unset SHLVL
diff --git a/X/xinitrc.d/sxhkd.sh b/X/xinitrc.d/sxhkd.sh
new file mode 100644
index 00000000..132d8f8a
--- /dev/null
+++ b/X/xinitrc.d/sxhkd.sh
@@ -0,0 +1,3 @@
+# Start sxhkd(1)
+command -v sxhkd >/dev/null 2>&1 || return
+sxhkd &
diff --git a/X/xinitrc.d/xbackground.sh b/X/xinitrc.d/xbackground.sh
deleted file mode 100644
index 7f2bc8c3..00000000
--- a/X/xinitrc.d/xbackground.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-# Apply a random background image
-command -v feh >/dev/null 2>&1 || return
-feh --bg-scale --no-fehbg --randomize -- "${XBACKGROUNDS:-"$HOME"/.xbackgrounds}"
diff --git a/X/xinitrc.d/xbindkeys.sh b/X/xinitrc.d/xbindkeys.sh
deleted file mode 100644
index a21bd995..00000000
--- a/X/xinitrc.d/xbindkeys.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-# Start xbindkeys(1)
-command -v xbindkeys >/dev/null 2>&1 || return
-xbindkeys -n &
diff --git a/X/xinitrc.d/xrbg.sh b/X/xinitrc.d/xrbg.sh
new file mode 100644
index 00000000..0e4ec278
--- /dev/null
+++ b/X/xinitrc.d/xrbg.sh
@@ -0,0 +1,2 @@
+# Apply a random background image
+xrbg
diff --git a/bash/bash_completion.d/_abook_addresses.bash b/bash/bash_completion.d/_abook_addresses.bash
new file mode 100644
index 00000000..8e341172
--- /dev/null
+++ b/bash/bash_completion.d/_abook_addresses.bash
@@ -0,0 +1,10 @@
+# Email addresses from abook(1)
+_abook_addresses() {
+ while IFS=$'\t' read -r address _ ; do
+ case $address in
+ "${COMP_WORDS[COMP_CWORD]}"*)
+ COMPREPLY[${#COMPREPLY[@]}]=$address
+ ;;
+ esac
+ done < <(abook --mutt-query \@)
+}
diff --git a/bash/bash_completion.d/ad.bash b/bash/bash_completion.d/ad.bash
deleted file mode 100644
index 390fcb00..00000000
--- a/bash/bash_completion.d/ad.bash
+++ /dev/null
@@ -1,2 +0,0 @@
-# Completion function for ad(); just directories
-complete -A directory ad
diff --git a/bash/bash_completion.d/chgrp.bash b/bash/bash_completion.d/chgrp.bash
new file mode 100644
index 00000000..d047f97f
--- /dev/null
+++ b/bash/bash_completion.d/chgrp.bash
@@ -0,0 +1,20 @@
+# Complete group names for first non-option chgrp(1) argument
+_chgrp() {
+ local i
+ for ((i = 1; i < COMP_CWORD; i++)) ; do
+ case ${COMP_WORDS[i]} in
+ -*) ;;
+ *) return 1 ;;
+ esac
+ done
+ while read -r group ; do
+ COMPREPLY[${#COMPREPLY[@]}]=$group
+ done < <(compgen -A group -- "${COMP_WORDS[COMP_CWORD]}")
+}
+
+# bashdefault requires Bash >=3.0
+if ((BASH_VERSINFO[0] >= 3)) ; then
+ complete -F _chgrp -o bashdefault -o default chgrp
+else
+ complete -F _chgrp -o default chgrp
+fi
diff --git a/bash/bash_completion.d/dig.bash b/bash/bash_completion.d/dig.bash
new file mode 100644
index 00000000..bdbd1cd8
--- /dev/null
+++ b/bash/bash_completion.d/dig.bash
@@ -0,0 +1,2 @@
+# Complete dig(1) with hostnames
+complete -A hostname dig
diff --git a/bash/bash_completion.d/finger.bash b/bash/bash_completion.d/finger.bash
new file mode 100644
index 00000000..5594adde
--- /dev/null
+++ b/bash/bash_completion.d/finger.bash
@@ -0,0 +1,2 @@
+# Completion for finger(1)
+complete -A user finger
diff --git a/bash/bash_completion.d/ftp.bash b/bash/bash_completion.d/ftp.bash
index e6d292a9..335d711a 100644
--- a/bash/bash_completion.d/ftp.bash
+++ b/bash/bash_completion.d/ftp.bash
@@ -30,4 +30,10 @@ _ftp() {
COMPREPLY[${#COMPREPLY[@]}]=$machine
done
}
-complete -F _ftp -o default ftp
+
+# bashdefault requires Bash >=3.0
+if ((BASH_VERSINFO[0] >= 3)) ; then
+ complete -F _ftp -o bashdefault -o default ftp
+else
+ complete -F _ftp -o default ftp
+fi
diff --git a/bash/bash_completion.d/git.bash b/bash/bash_completion.d/git.bash
index bde515ee..2bee169a 100644
--- a/bash/bash_completion.d/git.bash
+++ b/bash/bash_completion.d/git.bash
@@ -69,23 +69,6 @@ _git() {
done
return
;;
-
- # Untracked files
- untracked_files)
- local file
- while IFS= read -rd '' file ; do
- [[ -n $file ]] || continue
- COMPREPLY[${#COMPREPLY[@]}]=$file
- done < <(git ls-files \
- --directory \
- --exclude-standard \
- --no-empty-directory \
- --others \
- -z \
- -- "${COMP_WORDS[COMP_CWORD]}"'*' \
- 2>/dev/null)
- return
- ;;
esac
# Try to find the index of the Git subcommand
@@ -109,23 +92,17 @@ _git() {
# Complete initial subcommand or alias
if ((sci == COMP_CWORD)) ; then
- _git subcommands
- _git aliases
+ "${FUNCNAME[0]}" subcommands
+ "${FUNCNAME[0]}" aliases
return
fi
# Test subcommand to choose completions
case ${COMP_WORDS[sci]} in
- # Complete with untracked, unignored files
- add)
- _git untracked_files
- return
- ;;
-
# Help on real subcommands (not aliases)
help)
- _git subcommands
+ "${FUNCNAME[0]}" subcommands
return
;;
@@ -149,7 +126,7 @@ _git() {
update
' -- "${COMP_WORDS[COMP_CWORD]}")
else
- _git remotes
+ "${FUNCNAME[0]}" remotes
fi
return
;;
@@ -199,15 +176,15 @@ _git() {
# Complete with remotes and then refs
fetch|pull|push)
if ((COMP_CWORD == 2)) ; then
- _git remotes
+ "${FUNCNAME[0]}" remotes
else
- _git refs
+ "${FUNCNAME[0]}" refs
fi
;;
# Commands for which I'm likely to want a ref
branch|checkout|merge|rebase|tag)
- _git refs
+ "${FUNCNAME[0]}" refs
;;
# I normally only want a refspec for "reset" if I'm using the --hard or
@@ -215,7 +192,7 @@ _git() {
reset)
case ${COMP_WORDS[COMP_CWORD-1]} in
--hard|--soft)
- _git refs
+ "${FUNCNAME[0]}" refs
;;
esac
;;
diff --git a/bash/bash_completion.d/gpg.bash b/bash/bash_completion.d/gpg.bash
index fcb48b91..6d4cf345 100644
--- a/bash/bash_completion.d/gpg.bash
+++ b/bash/bash_completion.d/gpg.bash
@@ -14,4 +14,10 @@ _gpg() {
COMPREPLY[${#COMPREPLY[@]}]=$option
done < <(gpg --dump-options 2>/dev/null)
}
-complete -F _gpg -o default gpg
+
+# bashdefault requires Bash >=3.0
+if ((BASH_VERSINFO[0] >= 3)) ; then
+ complete -F _gpg -o bashdefault -o default gpg
+else
+ complete -F _gpg -o default gpg
+fi
diff --git a/bash/bash_completion.d/host.bash b/bash/bash_completion.d/host.bash
new file mode 100644
index 00000000..e49e76c4
--- /dev/null
+++ b/bash/bash_completion.d/host.bash
@@ -0,0 +1,2 @@
+# Complete host(1) with hostnames
+complete -A hostname host
diff --git a/bash/bash_completion.d/mail.bash b/bash/bash_completion.d/mail.bash
new file mode 100644
index 00000000..4476df12
--- /dev/null
+++ b/bash/bash_completion.d/mail.bash
@@ -0,0 +1,10 @@
+# Completion for mail(1) with abook(1) email addresses
+declare -F _abook_addresses >/dev/null ||
+ source "$HOME"/.bash_completion.d/_abook_addresses.bash
+
+# bashdefault requires Bash >=3.0
+if ((BASH_VERSINFO[0] >= 3)) ; then
+ complete -F _abook_addresses -o bashdefault -o default mail
+else
+ complete -F _abook_addresses -o default mail
+fi
diff --git a/bash/bash_completion.d/make.bash b/bash/bash_completion.d/make.bash
index b3314e21..bb01b36a 100644
--- a/bash/bash_completion.d/make.bash
+++ b/bash/bash_completion.d/make.bash
@@ -48,4 +48,10 @@ _make() {
esac
done < "$mf"
}
-complete -F _make -o default make
+
+# bashdefault requires Bash >=3.0
+if ((BASH_VERSINFO[0] >= 3)) ; then
+ complete -F _make -o bashdefault -o default make
+else
+ complete -F _make -o default make
+fi
diff --git a/bash/bash_completion.d/man.bash b/bash/bash_completion.d/man.bash
index f779d203..658b5eb7 100644
--- a/bash/bash_completion.d/man.bash
+++ b/bash/bash_completion.d/man.bash
@@ -69,4 +69,10 @@ _man() {
fi
)
}
-complete -F _man -o default man
+
+# bashdefault requires Bash >=3.0
+if ((BASH_VERSINFO[0] >= 3)) ; then
+ complete -F _man -o bashdefault -o default man
+else
+ complete -F _man -o default man
+fi
diff --git a/bash/bash_completion.d/mutt.bash b/bash/bash_completion.d/mutt.bash
new file mode 100644
index 00000000..d8bcc15d
--- /dev/null
+++ b/bash/bash_completion.d/mutt.bash
@@ -0,0 +1,10 @@
+# Completion for mutt(1) with abook(1) email addresses
+declare -F _abook_addresses >/dev/null ||
+ source "$HOME"/.bash_completion.d/_abook_addresses.bash
+
+# bashdefault requires Bash >=3.0
+if ((BASH_VERSINFO[0] >= 3)) ; then
+ complete -F _abook_addresses -o bashdefault -o default mutt
+else
+ complete -F _abook_addresses -o default mutt
+fi
diff --git a/bash/bash_completion.d/mysql.bash b/bash/bash_completion.d/mysql.bash
index 9755f033..2886f62e 100644
--- a/bash/bash_completion.d/mysql.bash
+++ b/bash/bash_completion.d/mysql.bash
@@ -35,4 +35,10 @@ _mysql() {
fi
)
}
-complete -F _mysql -o default mysql
+
+# bashdefault requires Bash >=3.0
+if ((BASH_VERSINFO[0] >= 3)) ; then
+ complete -F _mysql -o bashdefault -o default mysql
+else
+ complete -F _mysql -o default mysql
+fi
diff --git a/bash/bash_completion.d/nc.bash b/bash/bash_completion.d/nc.bash
new file mode 100644
index 00000000..8ef1fe69
--- /dev/null
+++ b/bash/bash_completion.d/nc.bash
@@ -0,0 +1,2 @@
+# Complete nc(1) with hostnames
+complete -A hostname nc
diff --git a/bash/bash_completion.d/netcat.bash b/bash/bash_completion.d/netcat.bash
new file mode 100644
index 00000000..60b9d614
--- /dev/null
+++ b/bash/bash_completion.d/netcat.bash
@@ -0,0 +1,2 @@
+# Complete netcat(1) with hostnames
+complete -A hostname netcat
diff --git a/bash/bash_completion.d/nmap.bash b/bash/bash_completion.d/nmap.bash
new file mode 100644
index 00000000..7126ca68
--- /dev/null
+++ b/bash/bash_completion.d/nmap.bash
@@ -0,0 +1,2 @@
+# Complete nmap(1) with hostnames
+complete -A hostname nmap
diff --git a/bash/bash_completion.d/openssl.bash b/bash/bash_completion.d/openssl.bash
new file mode 100644
index 00000000..b2bc1b7d
--- /dev/null
+++ b/bash/bash_completion.d/openssl.bash
@@ -0,0 +1,32 @@
+# Some simple completion for openssl(1ssl)
+_openssl() {
+
+ # Only complete the first word: OpenSSL subcommands
+ case $COMP_CWORD in
+ 1)
+ while read -r subcmd ; do
+ case $subcmd in
+ '') ;;
+ "${COMP_WORDS[COMP_CWORD]}"*)
+ COMPREPLY[${#COMPREPLY[@]}]=$subcmd
+ ;;
+ esac
+ done < <(
+ for arg in \
+ list-cipher-commands \
+ list-standard-commands \
+ list-message-digest-commands ; do
+ printf '%s\n' "$arg"
+ openssl "$arg"
+ done
+ )
+ ;;
+ esac
+}
+
+# bashdefault requires Bash >=3.0
+if ((BASH_VERSINFO[0] >= 3)) ; then
+ complete -F _openssl -o bashdefault -o default openssl
+else
+ complete -F _openssl -o default openssl
+fi
diff --git a/bash/bash_completion.d/path.bash b/bash/bash_completion.d/path.bash
index e0e7732d..ba2dcb79 100644
--- a/bash/bash_completion.d/path.bash
+++ b/bash/bash_completion.d/path.bash
@@ -6,7 +6,7 @@ _path() {
# Complete operation as first word
local cmd
- for cmd in list insert append remove check help ; do
+ for cmd in list insert append remove shift pop check help ; do
[[ $cmd == "${COMP_WORDS[COMP_CWORD]}"* ]] || continue
COMPREPLY[${#COMPREPLY[@]}]=$cmd
done
@@ -49,7 +49,7 @@ _path() {
local part
for part in "${promptarr[@]}" ; do
[[ $part == "${COMP_WORDS[COMP_CWORD]}"* ]] || continue
- COMPREPLY[${#COMPREPLY[@]}]=$(printf '%q\0' "$part")
+ COMPREPLY[${#COMPREPLY[@]}]=$(printf '%q' "$part")
done
;;
diff --git a/bash/bash_completion.d/ping.bash b/bash/bash_completion.d/ping.bash
new file mode 100644
index 00000000..8dc27673
--- /dev/null
+++ b/bash/bash_completion.d/ping.bash
@@ -0,0 +1,2 @@
+# Complete ping(8) with hostnames
+complete -A hostname ping
diff --git a/bash/bash_completion.d/sd.bash b/bash/bash_completion.d/sd.bash
index aeee1615..aeb76fa0 100644
--- a/bash/bash_completion.d/sd.bash
+++ b/bash/bash_completion.d/sd.bash
@@ -7,7 +7,7 @@ _sd() {
# Current directory can't be root directory
[[ $PWD != / ]] || return 1
- # Build list of matching sibiling directories
+ # Build list of matching sibling directories
local dirname
while IFS= read -rd '' dirname ; do
[[ -n $dirname ]] || continue
diff --git a/bash/bash_completion.d/sftp.bash b/bash/bash_completion.d/sftp.bash
index 5d52c739..60044e41 100644
--- a/bash/bash_completion.d/sftp.bash
+++ b/bash/bash_completion.d/sftp.bash
@@ -1,4 +1,10 @@
# Completion for sftp(1) with ssh_config(5) hostnames
declare -F _ssh_config_hosts >/dev/null ||
source "$HOME"/.bash_completion.d/_ssh_config_hosts.bash
-complete -F _ssh_config_hosts -o default sftp
+
+# bashdefault requires Bash >=3.0
+if ((BASH_VERSINFO[0] >= 3)) ; then
+ complete -F _ssh_config_hosts -o bashdefault -o default sftp
+else
+ complete -F _ssh_config_hosts -o default sftp
+fi
diff --git a/bash/bash_completion.d/source.bash b/bash/bash_completion.d/source.bash
index abd468af..de608813 100644
--- a/bash/bash_completion.d/source.bash
+++ b/bash/bash_completion.d/source.bash
@@ -1,4 +1,4 @@
-# Completion for source(1) with files that look editable
+# Completion for `source` with files that look like plain text
declare -F _text_filenames >/dev/null ||
source "$HOME"/.bash_completion.d/_text_filenames.bash
complete -F _text_filenames -o filenames source
diff --git a/bash/bash_completion.d/ssh-copy-id.bash b/bash/bash_completion.d/ssh-copy-id.bash
index daf52751..5e4fe99b 100644
--- a/bash/bash_completion.d/ssh-copy-id.bash
+++ b/bash/bash_completion.d/ssh-copy-id.bash
@@ -1,4 +1,10 @@
# Completion for ssh-copy-id(1) with ssh_config(5) hostnames
declare -F _ssh_config_hosts >/dev/null ||
source "$HOME"/.bash_completion.d/_ssh_config_hosts.bash
-complete -F _ssh_config_hosts -o default ssh-copy-id
+
+# bashdefault requires Bash >=3.0
+if ((BASH_VERSINFO[0] >= 3)) ; then
+ complete -F _ssh_config_hosts -o bashdefault -o default ssh-copy-id
+else
+ complete -F _ssh_config_hosts -o default ssh-copy-id
+fi
diff --git a/bash/bash_completion.d/ssh.bash b/bash/bash_completion.d/ssh.bash
index 03745eaa..c8212614 100644
--- a/bash/bash_completion.d/ssh.bash
+++ b/bash/bash_completion.d/ssh.bash
@@ -1,4 +1,10 @@
# Completion for ssh(1) with ssh_config(5) hostnames
declare -F _ssh_config_hosts >/dev/null ||
source "$HOME"/.bash_completion.d/_ssh_config_hosts.bash
-complete -F _ssh_config_hosts -o default ssh
+
+# bashdefault requires Bash >=3.0
+if ((BASH_VERSINFO[0] >= 3)) ; then
+ complete -F _ssh_config_hosts -o bashdefault -o default ssh
+else
+ complete -F _ssh_config_hosts -o default ssh
+fi
diff --git a/bash/bash_completion.d/td.bash b/bash/bash_completion.d/td.bash
index eb29992b..db232dd6 100644
--- a/bash/bash_completion.d/td.bash
+++ b/bash/bash_completion.d/td.bash
@@ -4,16 +4,23 @@ _td() {
dir=${TODO_DIR:-"$HOME"/Todo}
local fn
while IFS= read -rd '' fn ; do
+ [[ -n $fn ]] || continue
COMPREPLY[${#COMPREPLY[@]}]=$fn
done < <(
shopt -s extglob nullglob
shopt -u dotglob
- local -a fns
+ declare -a fns
fns=("$dir"/"${COMP_WORDS[COMP_CWORD]}"*)
fns=("${fns[@]#"$dir"/}")
- ((${#fns[@]})) || exit 1
- printf '%s\0' "${fns[@]##"$dir"/}"
+
+ # Print quoted entries, null-delimited, if there was at least one;
+ # otherwise, just print a null character to stop this hanging in Bash
+ # 4.4
+ if ((${#fns[@]})) ; then
+ printf '%q\0' "${fns[@]}"
+ else
+ printf '\0'
+ fi
)
- return
}
complete -F _td td
diff --git a/bash/bash_completion.d/telnet.bash b/bash/bash_completion.d/telnet.bash
new file mode 100644
index 00000000..eacf552d
--- /dev/null
+++ b/bash/bash_completion.d/telnet.bash
@@ -0,0 +1,2 @@
+# Complete telnet(1) with hostnames
+complete -A hostname telnet
diff --git a/bash/bash_profile b/bash/bash_profile
index a520f051..0376ee57 100644
--- a/bash/bash_profile
+++ b/bash/bash_profile
@@ -1,6 +1,13 @@
# Load ~/.profile regardless of shell version
[ -e "$HOME"/.profile ] && . "$HOME"/.profile
+# If POSIXLY_CORRECT is set after doing that, force the `posix` option on and
+# don't load the rest of this stuff--so, just ~/.profile and ENV
+if [ -n "$POSIXLY_CORRECT" ] ; then
+ set -o posix
+ return
+fi
+
# If ~/.bashrc exists, source that too; the tests for both interactivity and
# >=2.05a (for features like [[) are in there
[ -f "$HOME"/.bashrc ] && . "$HOME"/.bashrc
diff --git a/bash/bashrc b/bash/bashrc
index 3070c00c..7748b864 100644
--- a/bash/bashrc
+++ b/bash/bashrc
@@ -9,6 +9,11 @@ esac
# shellcheck disable=SC2128
[ -n "$BASH_VERSINFO" ] && shopt -q restricted_shell && return
+# Clear away all aliases; we do this here rather than in the $ENV file shared
+# between POSIX shells, because ksh relies on aliases to implement certain
+# POSIX utilities, like fc(1) and type(1)
+unalias -a
+
# If ENV is set, source it to get all the POSIX-compatible interactive stuff;
# we should be able to do this even if we're running a truly ancient Bash
[ -n "$ENV" ] && . "$ENV"
@@ -22,64 +27,69 @@ esac
((10#${BASH_VERSINFO[1]%%[!0-9]*} < 5)) &&
return
+# Clear away command_not_found_handle if a system bashrc file set it up
+unset -f command_not_found_handle
+
# Keep around 32K lines of history in file
HISTFILESIZE=$((1 << 15))
-# Ignore duplicate commands and whitespace in history
-HISTCONTROL=ignoreboth
+# Ignore duplicate commands
+HISTCONTROL=ignoredups
# Keep the times of the commands in history
HISTTIMEFORMAT='%F %T '
-# Use a more compact format for the time builtin's output
+# Use a more compact format for the `time` builtin's output
TIMEFORMAT='real:%lR user:%lU sys:%lS'
-# Autocorrect fudged paths in cd calls
+# Correct small errors in directory names given to the `cd` buildtin
shopt -s cdspell
-# Update the hash table properly
+# Check that hashed commands still exist before running them
shopt -s checkhash
-# Update columns and rows if window size changes
+# Update LINES and COLUMNS after each command if necessary
shopt -s checkwinsize
-# Put multi-line commands onto one line of history
+# Put multi-line commands into one history entry
shopt -s cmdhist
-# Include dotfiles in pattern matching
+# Include filenames with leading dots in pattern matching
shopt -s dotglob
-# Enable advanced pattern matching
+# Enable extended globbing: !(foo), ?(bar|baz)...
shopt -s extglob
-# Append rather than overwrite Bash history
+# Append history to $HISTFILE rather than overwriting it
shopt -s histappend
-# Repeat the line on failed history expansion
+# If history expansion fails, reload the command to try again
shopt -s histreedit
-# Repeat the expanded line on successful history expansion
+# Load history expansion result as the next command, don't run them directly
shopt -s histverify
-# Don't use Bash's builtin host completion
+# Don't assume a word with a @ in it is a hostname
shopt -u hostcomplete
# Don't change newlines to semicolons in history
shopt -s lithist
-# Don't warn me about new mail all the time
+# Don't try to tell me when my mail is read
shopt -u mailwarn
-# Ignore me if I try to complete an empty line
+# Don't complete a Tab press on an empty line with every possible command
shopt -s no_empty_cmd_completion
# Use programmable completion, if available
shopt -s progcomp
-# Warn me if I try to shift when there's nothing there
+# Warn me if I try to shift nonexistent values off an array
shopt -s shift_verbose
-# Don't use PATH to find files to source
+# Don't search $PATH to find files for the `source` builtin
shopt -u sourcepath
# These options only exist since Bash 4.0-alpha
if ((BASH_VERSINFO[0] >= 4)) ; then
- # Autocorrect fudged paths during completion
+ # Correct small errors in directory names during completion
shopt -s dirspell
- # Enable double-starring paths
+ # Allow double-star globs to match files and recursive paths
shopt -s globstar
- # Warn me about stopped jobs when exiting; only if >=4.1 due to bug
+ # Warn me about stopped jobs when exiting
+ # Available since 4.0, but only set it if >=4.1 due to bug:
# <https://lists.gnu.org/archive/html/bug-bash/2009-02/msg00176.html>
((BASH_VERSINFO[1] >= 1)) && shopt -s checkjobs
- # Expand variables in directory completion; only available since 4.3
+ # Expand variables in directory completion
+ # Only available since 4.3
((BASH_VERSINFO[1] >= 3)) && shopt -s direxpand
fi
diff --git a/bash/bashrc.d/completion.bash b/bash/bashrc.d/completion.bash
index 0d8dbb13..51de24b8 100644
--- a/bash/bashrc.d/completion.bash
+++ b/bash/bashrc.d/completion.bash
@@ -1,11 +1,15 @@
-# Various easy completions for Bash builtins; more specific stuff goes in
-# ~/.bash_completion.d
+# Simple completions for Bash builtins and POSIX utilities; more specific or
+# complex stuff goes in ~/.bash_completion.d, for possible dynamic loading
# If COMP_WORDBREAKS has a value, strip all colons from it; this allows
-# completing filenames correctly, since an unquoted colon is not a syntactic
-# character: <http://tiswww.case.edu/php/chet/bash/FAQ> (E13)
+# completing filenames correctly, since a colon is not a shell metacharacter:
+# <http://tiswww.case.edu/php/chet/bash/FAQ> (E13)
[[ -n $COMP_WORDBREAKS ]] && COMP_WORDBREAKS=${COMP_WORDBREAKS//:}
+# If ~/.hosts exists, use that as the host completion file rather than
+# /etc/hosts, so I can populate the list myself
+[[ -f $HOME/.hosts ]] && HOSTFILE=$HOME/.hosts
+
# Aliases
complete -A alias unalias
@@ -18,7 +22,8 @@ complete -A disabled enable
complete -A setopt set
# Commands
-complete -A command alias command complete compopt coproc exec if hash time type until while
+complete -A command alias command complete compopt coproc exec if hash time \
+ type until while
# Directories
complete -A directory cd pushd mkdir rmdir
diff --git a/bash/bashrc.d/keep.bash b/bash/bashrc.d/keep.bash
index a13fec12..da7ff558 100644
--- a/bash/bashrc.d/keep.bash
+++ b/bash/bashrc.d/keep.bash
@@ -46,8 +46,8 @@ keep() {
# -h given; means show help
h)
cat <<EOF
-${FUNCNAME[0]}: Keep variables and functions in shell permanently by writing them to
-named scripts iterated on shell start, in \$BASHKEEP (defaults to
+${FUNCNAME[0]}: Keep variables and functions in shell permanently by writing
+them to named scripts iterated on shell start, in \$BASHKEEP (defaults to
~/.bashkeep.d).
USAGE:
diff --git a/bash/bashrc.d/prompt.bash b/bash/bashrc.d/prompt.bash
index 123c4146..a6506a60 100644
--- a/bash/bashrc.d/prompt.bash
+++ b/bash/bashrc.d/prompt.bash
@@ -15,25 +15,25 @@ prompt() {
# Basic prompt shape depends on whether we're in SSH or not
PS1=
if [[ -n $SSH_CLIENT || -n $SSH_CONNECTION ]] ; then
- PS1=$PS1'\u@\h:'
+ PS1=$PS1'\h:'
fi
PS1=$PS1'\w'
# Add sub-commands; VCS, job, and return status checks
PS1=$PS1'$(ret=$?;prompt vcs;prompt job;prompt ret)'
+ # Add a helpful prefix if this shell appears to be exotic
+ case ${SHELL##*/} in
+ (bash) ;;
+ (*) PS1=bash:$PS1 ;;
+ esac
+
# Add prefix and suffix
PS1='${PROMPT_PREFIX}'$PS1'${PROMPT_SUFFIX}'
# Add terminating "$" or "#" sign
PS1=$PS1'\$'
- # Add > symbols to show nested shells
- local shlvl
- for ((shlvl = 1; shlvl < SHLVL; shlvl++)) ; do
- PS1='>'$PS1
- done
-
# Declare variables to contain terminal control strings
local format reset
@@ -81,10 +81,13 @@ prompt() {
# Revert to simple inexpensive prompts
off)
unset -v PROMPT_COMMAND PROMPT_DIRTRIM
- PS1='\$ '
+ PS1='$ '
PS2='> '
PS3='? '
PS4='+ '
+ if [[ -n $SSH_CLIENT || -n $SSH_CONNECTION ]] ; then
+ PS1=$(hostname -s)'$ '
+ fi
;;
# Git prompt function
@@ -110,7 +113,7 @@ prompt() {
git describe --tags --exact-match HEAD ||
git rev-parse --short HEAD
) || return
- name=${name##*/}
+ name=${name#refs/*/}
[[ -n $name ]] || return
# Check various files in .git to flag processes
@@ -164,7 +167,10 @@ prompt() {
# Print the status in brackets; add a git: prefix only if there
# might be another VCS prompt (because PROMPT_VCS is set)
printf '(%s%s%s%s)' \
- "${PROMPT_VCS:+git:}" "$name" "${proc:+:"$proc"}" "$state"
+ "${PROMPT_VCS:+git:}" \
+ "${name//\\/\\\\}" \
+ "${proc:+:"${proc//\\/\\\\}"}" \
+ "${state//\\/\\\\}"
;;
# Subversion prompt function
@@ -190,6 +196,7 @@ prompt() {
branch=${branch#/}
branch=${branch#branches/}
branch=${branch%%/*}
+ [[ -n $branch ]] || branch=unknown
# Parse the output of svn status to determine working copy state
local symbol
@@ -207,7 +214,9 @@ prompt() {
((untracked)) && state=${state}'?'
# Print the state in brackets with an svn: prefix
- printf '(svn:%s%s)' "${branch:-unknown}" "$state"
+ printf '(svn:%s%s)' \
+ "${branch//\\/\\\\}" \
+ "${state//\\/\\\\}"
;;
# VCS wrapper prompt function; print the first relevant prompt, if any
@@ -221,7 +230,7 @@ prompt() {
# Show return status of previous command in angle brackets, if not zero
ret)
# shellcheck disable=SC2154
- ((ret)) && printf '<%u>' "$ret"
+ ((ret)) && printf '<%u>' "${ret//\\/\\\\}"
;;
# Show the count of background jobs in curly brackets, if not zero
@@ -230,7 +239,7 @@ prompt() {
while read -r ; do
((jobc++))
done < <(jobs -p)
- ((jobc)) && printf '{%u}' "$jobc"
+ ((jobc)) && printf '{%u}' "${jobc//\\/\\\\}"
;;
# No argument given, print prompt strings and vars
@@ -246,5 +255,5 @@ prompt() {
esac
}
-# Start with full-fledged prompt
-prompt on
+# Default to a full-featured prompt, but use PROMPT_MODE if that's set
+prompt "${PROMPT_MODE:-on}"
diff --git a/bin/ap b/bin/ap.sh
index b6ee36d4..1d6376cc 100755..100644
--- a/bin/ap
+++ b/bin/ap.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Run a program with args read from standard input, prompted if from term
if [ "$#" -eq 0 ] ; then
printf >&2 'ap: Need at least one argument (command name)\n'
diff --git a/bin/apf b/bin/apf.sh
index 39bc0720..5e40e9b8 100755..100644
--- a/bin/apf
+++ b/bin/apf.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Prepend arguments from a file to the given arguments for a command
self=apf
diff --git a/bin/ax b/bin/ax.sh
index 8dea72da..6ce1e9ea 100755..100644
--- a/bin/ax
+++ b/bin/ax.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Evaluate an Awk expression given on the command line with an optional format
# Count arguments
diff --git a/bin/bcq b/bin/bcq
deleted file mode 100755
index 7b950b56..00000000
--- a/bin/bcq
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-# Fire up bc(1), hushing it if it looks like GNU
-[ -e "$HOME"/.cache/bc/quiet ] && set -- --quiet "$@"
-exec bc "$@"
diff --git a/bin/bcq.sh b/bin/bcq.sh
new file mode 100644
index 00000000..a6c0fe60
--- /dev/null
+++ b/bin/bcq.sh
@@ -0,0 +1,3 @@
+# Fire up bc(1), hushing it if it looks like GNU
+[ -e "$HOME"/.cache/sh/opt/bc/quiet ] && set -- --quiet "$@"
+exec bc "$@"
diff --git a/bin/bel b/bin/bel.sh
index c1c2ce1c..e87eceda 100755..100644
--- a/bin/bel
+++ b/bin/bel.sh
@@ -1,3 +1,2 @@
-#!/bin/sh
# Print a terminal bell
printf '\a'
diff --git a/bin/bl b/bin/bl.sh
index b1831387..6dd3d687 100755..100644
--- a/bin/bl
+++ b/bin/bl.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Generate blank lines
if [ "$#" -ne 1 ] || [ "$1" -lt 0 ] ; then
printf >&2 'bl: Non-negative line count needed as sole argument\n'
diff --git a/bin/bp b/bin/bp.sh
index 6b78fbbc..34065ca3 100755..100644
--- a/bin/bp
+++ b/bin/bp.sh
@@ -1,3 +1,2 @@
-#!/bin/sh
# Read an URL and then browse to it, saving the annoyance of quoting URLs
ap br URL
diff --git a/bin/br b/bin/br.sh
index 399c6038..72507528 100755..100644
--- a/bin/br
+++ b/bin/br.sh
@@ -1,3 +1,2 @@
-#!/bin/sh
# Just launch $BROWSER with any given arguments
exec "$BROWSER" "$@"
diff --git a/bin/ca b/bin/ca.sh
index 836299ce..1d6333ad 100755..100644
--- a/bin/ca
+++ b/bin/ca.sh
@@ -1,3 +1,2 @@
-#!/bin/sh
# Print a count of the number of arguments
printf '%u\n' "$#"
diff --git a/bin/cf b/bin/cf.sh
index 347481f1..ea3a2887 100755..100644
--- a/bin/cf
+++ b/bin/cf.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Count entries in a given set of directories
# Iterate over remaining non-option arguments (directories); default to current
diff --git a/bin/cfr b/bin/cfr.sh
index d49ab3d9..9d13785c 100755..100644
--- a/bin/cfr
+++ b/bin/cfr.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Count entries in a given set of directories
# Iterate over remaining non-option arguments (directories); default to current
diff --git a/bin/chc b/bin/chc.sh
index b1e4000d..ee030f5f 100755..100644
--- a/bin/chc
+++ b/bin/chc.sh
@@ -1,6 +1,12 @@
-#!/bin/sh
# Cache the output of a command and emit it straight from the cache if not
# expired on each run
+self=chc
+
+# Check arguments for sanity
+if [ "$#" -lt 3 ] ; then
+ printf >&2 '%s: Need a cache path, a duration, and a command\n' "$self"
+ exit 2
+fi
# First argument is the cache path, second is the duration in seconds
cac=$1 dur=$2
diff --git a/bin/chn.mi5 b/bin/chn.mi5
new file mode 100644
index 00000000..dfc1000c
--- /dev/null
+++ b/bin/chn.mi5
@@ -0,0 +1,57 @@
+# Repeat a command to filter input several times
+self=chn
+
+# Check arguments.
+if [ "$#" -lt 2 ] ; then
+ printf >&2 '%s: Need a count and a program name\n' "$self"
+ exit 2
+fi
+
+# Shift off the repetition count.
+c=$1
+shift
+
+# Check the repetition count looks sane. Zero is fine!
+if [ "$c" -lt 0 ] ; then
+ printf >&2 '%s: Nonsensical negative count\n' "$self"
+ exit 2
+fi
+
+# If the count is zero, just run the input straight through!
+if [ "$c" -eq 0 ] ; then
+ cat
+ exit
+fi
+
+<%
+include(`include/mktd.m4')
+%>
+
+# Define and create input and output files
+if=$td/if of=$td/of
+touch -- "$if" "$of"
+
+# Iterate through the count
+while [ "${n=1}" -le "$c" ] ; do
+
+ # Start a subshell so we can deal with FDs cleanly
+ (
+ # If this isn't the first iteration, our input comes from $if
+ [ "$n" -eq 1 ] ||
+ exec <"$if"
+
+ # If this isn't the last iteration, our output goes to $of
+ [ "$n" -eq "$c" ] ||
+ exec >"$of"
+
+ # Run the command with the descriptors above; if the command fails, the
+ # subshell will exit, which will in turn exit the program
+ "$@"
+ ) || exit
+
+ # Copy the output file over the input one
+ cp -- "$of" "$if"
+
+ # Increment the counter for the next while loop run
+ n=$((n+1))
+done
diff --git a/bin/clog b/bin/clog
deleted file mode 100755
index 037f24c7..00000000
--- a/bin/clog
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-# Record a timestamped message to a logfile, defaulting to ~/.clog
-self=clog
-command -v rlwrap >/dev/null 2>&1 &&
- set -- rlwrap -C "$self" "$@"
-{
- date
- "$@" cat -
- printf '%s\n' --
-} >>"${CLOG:-"$HOME"/.clog}"
diff --git a/bin/clog.sh b/bin/clog.sh
new file mode 100644
index 00000000..1b612d68
--- /dev/null
+++ b/bin/clog.sh
@@ -0,0 +1,17 @@
+# Record a timestamped message to a logfile, defaulting to ~/.clog
+self=clog
+
+# Ignore arguments
+set --
+
+# If we have rlwrap, quietly use it
+command -v rlwrap >/dev/null 2>&1 &&
+ set -- rlwrap --history-filename=/dev/null -C "$self" "$@"
+
+# Write the date, the standard input (rlwrapped if applicable), and two dashes
+# to $CLOG, defaulting to ~/.clog.
+{
+ date
+ "$@" cat -
+ printf '%s\n' --
+} >>"${CLOG:-"$HOME"/.clog}"
diff --git a/bin/clrd b/bin/clrd.sh
index 0b460671..bf239033 100755..100644
--- a/bin/clrd
+++ b/bin/clrd.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Clear the screen and read a file as it's written line-by-line
self=clrd
diff --git a/bin/clwr b/bin/clwr.sh
index dc045e9d..897c1a01 100755..100644
--- a/bin/clwr
+++ b/bin/clwr.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Write lines of terminal input into a file, clearing in between each one
self=clwr
diff --git a/bin/csmw.awk b/bin/csmw.awk
index b1cd20cb..351fc749 100644
--- a/bin/csmw.awk
+++ b/bin/csmw.awk
@@ -1,14 +1,15 @@
# Print an English comma-separated list of monospace-quoted words (backticks)
+BEGIN { wc = 0 }
{
for (i = 1; i <= NF; i++)
- ws[++wc] = $i
+ ws[++wc] = "`" $i "`"
}
END {
if (wc > 2)
for (i = 1; i <= wc; i++)
- printf (i < wc) ? "`%s`, " : "and `%s`\n", ws[i]
+ printf (i < wc) ? "%s, " : "and %s\n", ws[i]
else if (wc == 2)
- printf "`%s` and `%s`\n", ws[1], ws[2]
+ printf "%s and %s\n", ws[1], ws[2]
else if (wc == 1)
- printf "`%s`\n", ws[1]
+ printf "%s\n", ws[1]
}
diff --git a/bin/d2u b/bin/d2u.sh
index 6fe362b7..22c8e16b 100755..100644
--- a/bin/d2u
+++ b/bin/d2u.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Convert DOS line endings to UNIX ones
# Check arguments
diff --git a/bin/dam.sed b/bin/dam.sed
new file mode 100644
index 00000000..86fb03f9
--- /dev/null
+++ b/bin/dam.sed
@@ -0,0 +1,8 @@
+# Store up all input before emitting it unchanged as output
+1h
+1!H
+$ {
+ g
+ p
+}
+d
diff --git a/bin/ddup.awk b/bin/ddup.awk
index 2dec1d00..63381cfb 100644
--- a/bin/ddup.awk
+++ b/bin/ddup.awk
@@ -1,2 +1,6 @@
# Skip duplicate lines (without requiring sorted input)
-!seen[$0]++
+$0 in seen { next }
+length($0) {
+ seen[$0] = 1
+ print
+}
diff --git a/bin/dmp b/bin/dmp.sh
index 4299771d..ab09c20e 100755..100644
--- a/bin/dmp
+++ b/bin/dmp.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+# Pick a pass(1) password with dmenu(1)
# Get the password store directory, bail if we can't
pwsd=${PASSWORD_STORE_DIR:-"$HOME"/.password-store}
diff --git a/bin/dub b/bin/dub
deleted file mode 100755
index 36d787a4..00000000
--- a/bin/dub
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-# List the biggest files in a directory
-
-# First optional argument is the directory, defaulting to the
-# current dir; second optional argument is the number of files to
-# show, defaulting to 20
-dir=${1:-.} lines=${2:-10}
-
-# Enter the target dir or bail
-cd -- "$dir" || exit
-
-# Add files matching glob, shift them off if unexpanded (first and
-# only entry doesn't exist)
-set -- *
-[ -e "$1" ] || shift
-
-# Add dot files, shift off the "." and ".." entries (sh(1)
-# implementations seem to vary on whether they include these)
-set -- .* "$@"
-[ -e "$1" ] || shift
-[ "$1" = . ] && shift
-[ "$1" = .. ] && shift
-
-# Run du(1) with POSIX compatible flags -k for kilobyte unit and
-# -s for total over the arguments
-du -ks -- "$@" |
-
-# Sort the first field (the sizes) numerically, in reverse
-sort -k1,1nr |
-
-# Limit the output to the given number of lines
-sed "$lines"q
diff --git a/bin/dub.sh b/bin/dub.sh
new file mode 100644
index 00000000..2dfd77f0
--- /dev/null
+++ b/bin/dub.sh
@@ -0,0 +1,27 @@
+# List the biggest files in a directory
+self=dub
+
+# First optional argument is the directory, defaulting to the
+# current dir; second optional argument is the number of files to
+# show, defaulting to 20
+dir=${1:-.} lim=${2:-10}
+
+# Enter the target dir or bail
+cd -- "$dir" || exit
+
+# Some find(1) devilry to deal with newlines as safely as possible. The idea is
+# not even to touch them, and warn about their presence; better the results are
+# wrong than malformed
+nl=$(printf '\n/')
+find . ! -name . -prune \( \
+ -name '*'"${nl%/}"'*' \
+ -exec sh -c '
+ printf >&2 '\''%s: warning: skipped newline filename\n'\'' "$1"
+ ' _ "$self" \; \
+ -o -exec du -ksx -- {} + \) |
+
+# Sort the first field (the sizes) numerically, in reverse
+sort -k1,1nr |
+
+# Limit the output to the given number of lines
+awk -v lim="$lim" 'NR<=lim'
diff --git a/bin/edda.mi5 b/bin/edda.mi5
new file mode 100644
index 00000000..aaf974cf
--- /dev/null
+++ b/bin/edda.mi5
@@ -0,0 +1,21 @@
+# Run ed(1) over multiple files, duplicating stdin.
+self=edda
+
+# Need at least one file
+if [ "$#" -eq 0 ] ; then
+ printf >&2 'edda: Need at least one file\n'
+ exit 2
+fi
+
+<%
+include(`include/mktd.m4')
+%>
+
+# Duplicate stdin into a file
+script=$td/script
+cat >"$script" || exit
+
+# Run ed(1) over each file with the stdin given
+for file ; do
+ ed -- "$file" <"$script"
+done
diff --git a/bin/eds b/bin/eds.sh
index e39215d4..c85069c6 100755..100644
--- a/bin/eds
+++ b/bin/eds.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Create and edit executable scripts in a directory EDSPATH (defaults to ~/.local/bin)
# Need at least one script name
diff --git a/bin/exm.sh b/bin/exm.sh
new file mode 100644
index 00000000..378b5baf
--- /dev/null
+++ b/bin/exm.sh
@@ -0,0 +1,9 @@
+# Prevent Vim's ex(1) implementation from clearing the screen
+if [ -t 0 ] ; then
+
+ # Lie to Vim; tell it it's a dumb terminal, and that its required "cm"
+ # feature is invoked with a carriage return.
+ cmd=$(printf 'set t_cm=\r|')
+ set -- -T dumb --cmd "${cmd%|}" "$@"
+fi
+exec ex "$@"
diff --git a/bin/fgscr b/bin/fgscr.sh
index 7d5ff4c5..137e0dd8 100755..100644
--- a/bin/fgscr
+++ b/bin/fgscr.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Find all the Git repositories in a directory and scrub them all
# Check we have gscr(1df) first
diff --git a/bin/finc b/bin/finc.sh
index 109f02b3..2bbb9ae8 100755..100644
--- a/bin/finc
+++ b/bin/finc.sh
@@ -1,3 +1,2 @@
-#!/bin/sh
# Count the number of entries from a find(1) condition
find "${@:-.}" -exec printf .%sx {} + | wc -c
diff --git a/bin/fnl b/bin/fnl.sh
index 6969665b..e8a5f071 100755..100644
--- a/bin/fnl
+++ b/bin/fnl.sh
@@ -1,16 +1,17 @@
-#!/bin/sh
# Run a command and save its output and error to temporary files
# Check we have at least one argument
if [ "$#" -eq 0 ] ; then
printf >&2 'fnl: Command needed\n'
- return 2
+ exit 2
fi
# Create a temporary directory; note that we *don't* clean it up on exit
dir=$(mktd fnl) || exit
-# Run the command; keep its exit status
+# Run the command; keep its exit status; wrap the command in braces so that the
+# out files are always opened even if the command is not found or otherwise
+# can't be run; some BSD shells require this, I forget which ones
{ "$@" ; } >"$dir"/stdout 2>"$dir"/stderr
ret=$?
diff --git a/bin/fnp.sh b/bin/fnp.sh
new file mode 100644
index 00000000..ec68e51f
--- /dev/null
+++ b/bin/fnp.sh
@@ -0,0 +1,23 @@
+# Print input, but include filenames as headings
+
+# Assume stdin if no options given
+[ "$#" -gt 0 ] || set -- -
+
+# Iterate through arguments
+for arg ; do
+
+ # We'll print the filename "-stdin-" rather than - just to be slightly more
+ # explicit
+ case $arg in
+ -) fn=-stdin- ;;
+ *) fn=$arg ;;
+ esac
+
+ [ -n "$tail" ] && printf '\n'
+ tail=1
+
+ # Form the underline; is there a nicer way to do this in POSIX sh?
+ ul=$(printf %s "$fn"|tr '[:print:]' -)
+ printf '%s\n%s\n\n' "$fn" "$ul"
+ cat -- "$arg"
+done
diff --git a/bin/gms b/bin/gms.sh
index 01cdaa2f..b77da6fa 100755..100644
--- a/bin/gms
+++ b/bin/gms.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Run getmail(1) over every getmailrc.* file in ~/.getmail
# Trap to remove whatever's set in lockdir if we're killed
diff --git a/bin/grc b/bin/grc.sh
index 0db91afa..184baf8e 100755..100644
--- a/bin/grc
+++ b/bin/grc.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Check whether a directory is a Git repository with uncommitted changes
# Enter given directory or bail
diff --git a/bin/grec.sh b/bin/grec.sh
new file mode 100644
index 00000000..035b7cce
--- /dev/null
+++ b/bin/grec.sh
@@ -0,0 +1,2 @@
+# g/re/c
+grep -c "$@"
diff --git a/bin/gred.sh b/bin/gred.sh
new file mode 100644
index 00000000..46de5dce
--- /dev/null
+++ b/bin/gred.sh
@@ -0,0 +1,2 @@
+# g/re/d
+grep -v "$@"
diff --git a/bin/gscr b/bin/gscr.sh
index cac969fe..2fbee05a 100755..100644
--- a/bin/gscr
+++ b/bin/gscr.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Scrub and pack Git repositories
# Iterate through given directories; default to the current one
diff --git a/bin/gwp.awk b/bin/gwp.awk
index 976b5b84..6b558388 100644
--- a/bin/gwp.awk
+++ b/bin/gwp.awk
@@ -7,6 +7,9 @@ BEGIN {
# Words are separated by any non-alphanumeric characters
FS = "[^a-zA-Z0-9]+"
+ # Nothing found yet
+ found = 0
+
# First argument is the word required; push its case downward so we can
# match case-insensitively
word = tolower(ARGV[1])
@@ -15,16 +18,18 @@ BEGIN {
ARGV[1] = ""
# Bail out if we don't have a suitable word
- if (!word)
+ if (!length(word))
fail("Need a single non-null alphanumeric string as a search word")
if (word ~ FS)
fail("Word contains non-alphanumeric characters; use grep(1)")
}
# Bailout function
-function fail(str) {
- printf "%s: %s\n", self, str | "cat >&2"
- exit(1)
+function fail(msg) {
+ stderr = "cat >&2"
+ printf "%s: %s\n", self, msg | stderr
+ close(stderr)
+ exit(2)
}
# If there's more than one filename, precede the print of the current line with
diff --git a/bin/han.bash b/bin/han.bash
index 97dc3a19..3c4f6637 100644
--- a/bin/han.bash
+++ b/bin/han.bash
@@ -5,10 +5,10 @@ self=han
# due to leading zeroes and trailing letters in some 2.x version numbers (e.g.
# 2.05a).
# shellcheck disable=SC2128
-[ -n "$BASH_VERSINFO" ] || return
+[ -n "$BASH_VERSINFO" ] || exit
((BASH_VERSINFO[0] == 2)) &&
((10#${BASH_VERSINFO[1]%%[![:digit:]]*} < 5)) &&
- return
+ exit
# Figure out the options with which we can call help; Bash >=4.0 has an -m
# option which prints the help output in a man-page like format
diff --git a/bin/hms.awk b/bin/hms.awk
new file mode 100644
index 00000000..2aa492a1
--- /dev/null
+++ b/bin/hms.awk
@@ -0,0 +1,40 @@
+# Convert seconds to colon-delimited durations
+BEGIN {
+ OFS = ":"
+ ex = 0
+ stderr = ""
+}
+
+# Refuse to deal with anything that's not a positive (unsigned) integer
+/[^0-9]/ {
+ if (!stderr)
+ stderr = "cat >&2"
+ print "hms: Bad number" | stderr
+ ex = 1
+ next
+}
+
+# Integer looks valid
+{
+ # Break it down into hours, minutes, and seconds
+ s = int($0 + 0)
+ h = int(s / 3600)
+ s %= 3600
+ m = int(s / 60)
+ s %= 60
+
+ # Print it, with the biggest number without a leading zero
+ if (h)
+ printf "%u:%02u:%02u\n", h, m, s
+ else if (m)
+ printf "%u:%02u\n", m, s
+ else
+ printf "%u\n", s
+}
+
+# Done, exit 1 if we had any errors on the way
+END {
+ if (stderr)
+ close(stderr)
+ exit(ex)
+}
diff --git a/bin/htref.sed b/bin/htref.sed
new file mode 100644
index 00000000..f2e943ca
--- /dev/null
+++ b/bin/htref.sed
@@ -0,0 +1,2 @@
+# Quick-and-dirty HTML linkifier
+s_https*://[^ \t<>]*_<a href="&">&</a>_
diff --git a/bin/hurl b/bin/hurl.sh
index 16ea48f8..0680c5ce 100755..100644
--- a/bin/hurl
+++ b/bin/hurl.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Extract <a href="..."> URLs from an HTML document or documents
# Input is either stdin or the given arguments concatenated
diff --git a/bin/igex b/bin/igex.sh
index c514006d..b8ef3092 100755..100644
--- a/bin/igex
+++ b/bin/igex.sh
@@ -1,9 +1,9 @@
-#!/bin/sh
# Run a command and ignore specified exit values
# There should be at least two arguments
if [ "$#" -eq 0 ] ; then
printf >&2 'igs: Need an ignore list x,y,z and a command\n';
+ exit 2
fi
# The list of values to ignore is the first argument; add a trailing comma for
diff --git a/bin/isgr b/bin/isgr.sh
index 029b5352..9d3e97a8 100755..100644
--- a/bin/isgr
+++ b/bin/isgr.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Return an exit status for whether the current directory appears to be in a
# Git working copy
diff --git a/bin/ix b/bin/ix.sh
index 45c1f860..cffc186c 100755..100644
--- a/bin/ix
+++ b/bin/ix.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Convenience script for posting to ix.io pastebin
cat -- "${@:--}" |
curl -F 'f:1=<-' http://ix.io/
diff --git a/bin/jfc b/bin/jfc.sh
index 33d0fe5d..3d155aca 100755..100644
--- a/bin/jfc
+++ b/bin/jfc.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Commit all changes to a Git repository with a stock message message
# Enter the given directory, default to the current one
diff --git a/bin/jfcd b/bin/jfcd.sh
index 8bd54e3b..25bf03fd 100755..100644
--- a/bin/jfcd
+++ b/bin/jfcd.sh
@@ -1,5 +1,3 @@
-#!/bin/sh
-
# Watch a directory for changes and commit them with jfc(1d) if there are any;
# requires inotifywait(1)
self=jfcd
diff --git a/bin/jfp.sed b/bin/jfp.sed
index 938c4e4d..1237bcbc 100644
--- a/bin/jfp.sed
+++ b/bin/jfp.sed
@@ -1,4 +1,3 @@
-#!/bin/sed -f
1 {
/^\#\!/d
}
diff --git a/bin/loc b/bin/loc.sh
index d92dc886..995c6932 100755..100644
--- a/bin/loc
+++ b/bin/loc.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Convenience find(1) wrapper for path substrings
# Require at least one search term
diff --git a/bin/max.awk b/bin/max.awk
index 11d4efd9..f6b84ead 100644
--- a/bin/max.awk
+++ b/bin/max.awk
@@ -1,8 +1,6 @@
# Get the maximum of a list of numbers
-{
- if (NR == 1 || $1 > max)
- max = $1
-}
+BEGIN { max = 0 }
+NR == 1 || $1 > max { max = $1 + 0 }
END {
if (!NR)
exit(1)
diff --git a/bin/maybe b/bin/maybe.sh
index a2de17dd..bda7bbc0 100755..100644
--- a/bin/maybe
+++ b/bin/maybe.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Exit with success or failure with a given probability
self=maybe
@@ -20,5 +19,4 @@ if [ "$((num >= 0 || den >= 1))" -ne 1 ] ; then
fi
# Perform the test; that's our exit value
-seed=$(rnds)
-test "$(rndi 1 "$den" "$seed")" -le "$num"
+test "$(rndi 1 "$den")" -le "$num"
diff --git a/bin/mean.awk b/bin/mean.awk
index b34dc111..98060389 100644
--- a/bin/mean.awk
+++ b/bin/mean.awk
@@ -1,5 +1,6 @@
# Get the mean of a list of numbers
-{ tot += $1 }
+BEGIN { tot = 0 }
+{ tot += $1 + 0 }
END {
# Error out if we read no values at all
if (!NR)
diff --git a/bin/med.awk b/bin/med.awk
index aee120cb..0f4d6086 100644
--- a/bin/med.awk
+++ b/bin/med.awk
@@ -1,7 +1,13 @@
# Get the median of a list of numbers
+BEGIN {
+ self = "med"
+ stderr = "cat >&2"
+}
{ vals[NR] = $1 }
NR > 1 && vals[NR] < vals[NR-1] && !warn++ {
- printf "med: Input not sorted!\n" | "cat >&2"
+ if (!stderr)
+ stderr = "cat >&2"
+ printf "%s: Input not sorted!\n", self | stderr
}
END {
# Error out if we read no values at all
@@ -12,6 +18,8 @@ END {
else
med = (vals[NR/2] + vals[NR/2+1]) / 2
print med
+ if (stderr)
+ close(stderr)
if (warn)
exit(1)
}
diff --git a/bin/mex b/bin/mex.sh
index 005149d8..cf4e07e7 100755..100644
--- a/bin/mex
+++ b/bin/mex.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Make the first non-executable instance of files with the given names in $PATH
# executable
self=mex
@@ -38,7 +37,11 @@ for name ; do
# If the "found" variable was defined to something, we'll try to change its
# permissions
if [ -n "$found" ] ; then
- chmod +x -- "$found" || ex=1
+ case $found in
+ /*) ;;
+ *) found=$PWD/$found ;;
+ esac
+ chmod +x "$found" || ex=1
# If not, we'll report that we couldn't find it, and flag an error for the
# exit status
diff --git a/bin/mftl.awk b/bin/mftl.awk
index 21976337..916348b2 100644
--- a/bin/mftl.awk
+++ b/bin/mftl.awk
@@ -19,7 +19,7 @@ BEGIN { FS = "[ \t:]" }
}
# Check lines matching expected "targets:dependencies" format
-/^[a-zA-Z0-9][a-zA-Z0-9 \t_-]+:([^=]|$)/ {
+/^[a-zA-Z0-9][a-zA-Z0-9./ \t_-]+:([^=]|$)/ {
# Iterate through the targets that don't look like substitutions or
# inference rules and stack them up into an array's keys to keep them
@@ -31,6 +31,12 @@ BEGIN { FS = "[ \t:]" }
# Print unique determined targets, sorted
END {
- for (t in ats)
- print t | "sort"
+ sort = ""
+ for (t in ats) {
+ if (!sort)
+ sort = "sort"
+ print t | sort
+ }
+ if (sort)
+ close(sort)
}
diff --git a/bin/mi5.awk b/bin/mi5.awk
new file mode 100644
index 00000000..7acb6f3b
--- /dev/null
+++ b/bin/mi5.awk
@@ -0,0 +1,133 @@
+# Crude m4 preprocessor
+BEGIN {
+ self = "mi5"
+
+ # You can change any of these, but while changing these is still relatively
+ # sane...
+ open = "<%"
+ shut = "%>"
+
+ # ... changing these probably isn't, and should compel you to rethink your
+ # code, or quite possibly your entire life thus far.
+ quote = "`"
+ unquote = "'"
+ dnl = "dnl"
+
+ # We do not start in a block
+ bmac = 0
+}
+
+# Fatal error function
+function fatal(str) {
+ stderr = "cat >&2"
+ printf "%s: %s\n", self, str | stderr
+ close(stderr)
+ exit(1)
+}
+
+# Print an m4 opener as the first byte
+NR == 1 { printf "%s", quote }
+
+# Blocks
+NF == 1 && $1 == open && !bmac++ {
+ printf "%s", unquote
+ next
+}
+NF == 1 && $1 == shut && bmac-- {
+ printf "%s", quote
+ next
+}
+
+# If in a block, print each line with any content on it after stripping leading
+# and trailing whitespace
+bmac && NF {
+ gsub(/(^ +| +$)/, "")
+ print $0 dnl
+}
+
+# If not in a block, look for inlines to process
+!bmac {
+
+ # We'll parse one variable into another.
+ src = $0
+ dst = ""
+
+ # Start off neither quoting nor macroing.
+ iquo = imac = 0
+
+ # Crude and slow, clansman. Your parser was no better than that of a clumsy
+ # child.
+ for (i = 1; i <= length(src); ) {
+
+ # Inline macro expansion: commented
+ # Look for end of comment and tip flag accordingly
+ if (iquo)
+ iquo = (substr(src, i, length(unquote)) != unquote)
+
+ # Inline macro expansion
+ else if (imac) {
+
+ # Close the current inline macro expansion if a close tag is found
+ # (in m4 terms: open a new quote), looking ahead past any spaces
+ # from this point first
+ for (j = i; substr(src, j, 1) ~ /[ \t]/; j++)
+ continue
+ if (substr(src, j, length(shut)) == shut) {
+ dst = dst quote
+ i = j + length(shut)
+ imac = 0
+ continue
+ }
+
+ # Look for start of comment and tip flag accordingly
+ iquo = (substr(src, i, length(quote)) == quote)
+ }
+
+ # Plain text mode
+ else {
+
+ # Open a new inline macro expansion if an open tag is found (in m4
+ # terms: close the quote), and then look ahead past any spaces from
+ # that point afterward
+ if (substr(src, i, length(open)) == open) {
+ dst = dst unquote
+ imac = 1
+ for (i += length(open); substr(src, i, 1) ~ /[ \t]/; i++)
+ continue
+ continue
+ }
+
+ # Escape quote terminators
+ if (substr(src, i, length(unquote)) == unquote) {
+
+ # Dear Mr. President. There are too many variables nowadays.
+ # Please eliminate three. I am NOT a crackpot.
+ dst = dst unquote unquote quote
+
+ i += length(unquote)
+ continue
+ }
+ }
+
+ # If we got down here, we can just add the next character and move on
+ dst = dst substr(src, i++, 1)
+ }
+
+ # If we're still in a macro expansion or quote by this point, something's
+ # wrong; say so and stop, rather than print anything silly.
+ if (iquo)
+ fatal("Unterminated inline quote")
+ else if (imac)
+ fatal("Unterminated inline macro")
+ else
+ print dst
+}
+
+# Print an m4 closer and newline deleter as the last bytes if we've correctly
+# stopped all our blocks
+END {
+ if (bmac)
+ fatal("Unterminated block macro")
+ else
+ print unquote dnl
+}
diff --git a/bin/mkcp b/bin/mkcp.sh
index 37bc87c0..10308263 100755..100644
--- a/bin/mkcp
+++ b/bin/mkcp.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Copy files into created directory in one call
# Check we have at least two arguments
diff --git a/bin/mkmv b/bin/mkmv.sh
index 803ef05c..53b5aa8f 100755..100644
--- a/bin/mkmv
+++ b/bin/mkmv.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Move files into created directory in one call
# Check we have at least two arguments
diff --git a/bin/mktd b/bin/mktd.sh
index 75bbb4b3..72375873 100755..100644
--- a/bin/mktd
+++ b/bin/mktd.sh
@@ -1,12 +1,9 @@
-#!/bin/sh
# Try to make a random temp directory
-# Get a random seed from rnds(1df); if it's empty, that's still workable
-seed=$(rnds)
-
# Build the intended directory name, with the last element a random integer
# from 1..2^31
-dn=${TMPDIR:-/tmp}/${1:-mktd}.$$.$(rndi 1 2147483648 "$seed")
+lim=$((2 << 31))
+dn=${TMPDIR:-/tmp}/${1:-mktd}.$$.$(rndi 1 "$lim")
# Create the directory and print its name if successful
mkdir -m 700 -- "$dn" && printf '%s\n' "$dn"
diff --git a/bin/motd b/bin/motd.sh
index ee60ad03..4ac88081 100755..100644
--- a/bin/motd
+++ b/bin/motd.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Show the system MOTD
motd=${MOTD:-/etc/motd}
[ -f "$motd" ] || exit
diff --git a/bin/murl b/bin/murl.sh
index 95db92c9..91304aa1 100755..100644
--- a/bin/murl
+++ b/bin/murl.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Format markdown and pass it to hurl to extract URLs from it.
# Pipe the output of pandoc(1) on our args into hurl(1df)
diff --git a/bin/mw.awk b/bin/mw.awk
new file mode 100644
index 00000000..8af28312
--- /dev/null
+++ b/bin/mw.awk
@@ -0,0 +1,10 @@
+# Crude approach to get alphabetic words one per line from input, not sorted or
+# deduplicated
+BEGIN {
+ FS = "(--|['_-]*[^a-zA-Z0-9_'_-]+['_-]*)"
+}
+{
+ for (i = 1; i <= NF; i++)
+ if ($i ~ /[a-zA-Z]/)
+ print $i
+}
diff --git a/bin/oii.mi5 b/bin/oii.mi5
new file mode 100644
index 00000000..51f37fb4
--- /dev/null
+++ b/bin/oii.mi5
@@ -0,0 +1,19 @@
+# Only run a command on input if there was at least one byte
+self=oii
+
+# Need at least a command name
+if [ "$#" -eq 0 ] ; then
+ printf >&2 '%s: Need a command\n' "$self"
+ exit 2
+fi
+
+<%
+include(`include/mktd.m4')
+%>
+
+# There is probably a way better way to do this than writing the whole file to
+# disk and then reading it off again, but until I think of something better,
+# this works and is byte-safe.
+cat - > "$td"/in
+[ -s "$td"/in ] || exit
+"$@" < "$td"/in
diff --git a/bin/onl.awk b/bin/onl.awk
index 466b8451..89469f3c 100644
--- a/bin/onl.awk
+++ b/bin/onl.awk
@@ -2,8 +2,9 @@
# For each line of input ...
{
- # Strip out non-printable characters and rebuild the fields
- gsub(/[[:cntrl:]]/, "")
+ # Replace groups of spaces and control characters with one space,
+ # implicitly re-splitting the fields
+ gsub(/[\a\b\f\n\r\t\v ]+/, " ")
# Print each field, without a newline; add a leading space if it's not the
# very first one
diff --git a/bin/osc.sh b/bin/osc.sh
new file mode 100644
index 00000000..b145b5cd
--- /dev/null
+++ b/bin/osc.sh
@@ -0,0 +1,91 @@
+# Sane and safe OpenSSL s_client(1ssl) connection
+self=osc
+
+# Check we have openssl(1); we need to fail early lest we go setting up FIFOs
+# needlessly
+if ! command -v openssl >/dev/null 2>&1 ; then
+ printf >&2 '%s: openssl(1) not found\n' "$self"
+ exit 1
+fi
+
+# Hostname is first argument; assume localhost if empty/unset
+host=${1:-localhost}
+# Service name or port is second argument; assume HTTPS if empty/unset
+serv=${2:-https}
+
+# Start building the command-line string
+set --
+## If we have rlwrap, use it, but don't complain if we don't
+if command -v rlwrap >/dev/null 2>&1 ; then
+ set -- "$@" rlwrap --history-filename=/dev/null
+fi
+## The actual openssl(1ssl) and subcommand call
+set -- "$@" openssl s_client
+## No insecure SSL methods
+set -- "$@" -no_ssl2 -no_ssl3
+## Don't dump nonsense to terminal, and don't renegotiate on R or quit on Q
+set -- "$@" -quiet
+## But do cut the connection if I issue ^D, even though I just set -quiet
+set -- "$@" -no_ign_eof
+## Do verify the certificate chain and don't connect if we can't
+set -- "$@" -verify 5 -verify_return_error
+## We might add STARTTLS for the supported services:
+case $serv in
+ ftp|21)
+ set -- "$@" -starttls ftp
+ ;;
+ smtp|25)
+ set -- "$@" -starttls smtp
+ ;;
+ pop3|110)
+ set -- "$@" -starttls pop3
+ ;;
+ imap|143)
+ set -- "$@" -starttls imap
+ ;;
+ xmpp-client|5222)
+ set -- "$@" -starttls xmpp
+ ;;
+esac
+## Send the host parameter as the server name (SNI)
+set -- "$@" -servername "$host"
+## Finally, add the host and service to connect to
+set -- "$@" -connect "$host":"$serv"
+
+# Do the POSIX dance to kill child processes and clean up temp files even if
+# killed by a signal
+td='' fil=''
+cleanup() {
+ trap - EXIT "$1"
+ [ -n "$fil" ] && kill -TERM "$fil"
+ [ -n "$td" ] && rm -fr -- "$td"
+ if [ "$1" != EXIT ] ; then
+ kill -"$1" "$$"
+ fi
+}
+for sig in EXIT HUP INT TERM ; do
+ # shellcheck disable=SC2064
+ trap "cleanup $sig" "$sig"
+done
+
+# Create a temporary directory and a FIFO in it
+td=$(mktd "$self") || exit
+mkfifo -- "$td"/verify-filter || exit
+
+# Open a read-write file descriptor onto the FIFO
+exec 3<>"$td"/verify-filter || exit
+
+# Start a background filter process on the FIFO to get rid of the leading
+# verification output set to stderr; as soon as we find a single line that
+# doesn't look like that routine output, print all future lines to stderr as
+# normal
+awk '
+body{print;next}
+/^verify depth is [0-9]+$/{next}
+/^depth=[0-9]+ /{next}
+/^verify return:[0-9]+$/{next}
+{body=1;print}
+' <&3 >&2 & fil=$!
+
+# Start the process with the options we stacked up
+"$@" 2>&3
diff --git a/bin/p.sh b/bin/p.sh
new file mode 100644
index 00000000..fec69e95
--- /dev/null
+++ b/bin/p.sh
@@ -0,0 +1,2 @@
+# cat(1) as it always should have been
+cat -- "${@:--}"
diff --git a/bin/pa b/bin/pa.sh
index e03e1bb0..4cfa9dce 100755..100644
--- a/bin/pa
+++ b/bin/pa.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Print arguments, one per line. Compare paz(1df).
[ "$#" -gt 0 ] || exit 0
printf '%s\n' "$@"
diff --git a/bin/paz b/bin/paz.sh
index b1f09ca9..e9b81bd7 100755..100644
--- a/bin/paz
+++ b/bin/paz.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Print arguments, terminated by null chars. Compare pa(1df).
[ "$#" -gt 0 ] || exit 0
printf '%s\0' "$@"
diff --git a/bin/ped.sh b/bin/ped.sh
new file mode 100644
index 00000000..ba2f7e66
--- /dev/null
+++ b/bin/ped.sh
@@ -0,0 +1,2 @@
+# Use pst(1df) to edit a pipe partway through, like vipe(1)
+pst "${EDITOR:-ed}"
diff --git a/bin/pit b/bin/pit.sh
index d3068e76..418732d0 100755..100644
--- a/bin/pit
+++ b/bin/pit.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+# Show arguments or output in a pager if stdout looks like a terminal
# If no arguments, we'll use stdin
if [ "$#" -eq 0 ] ; then
diff --git a/bin/plmu b/bin/plmu.sh
index cf9b7eae..78778920 100755..100644
--- a/bin/plmu
+++ b/bin/plmu.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+# Upgrade plenv modules with cpanm(1)
# Set up exceptions file if it exists
ef=$HOME/.plenv/non-cpanm-modules
@@ -14,7 +14,7 @@ fi
# the existing sorting
plenv list-modules | sort |
-# Exclude any modules in ~.plenv/non-cpanm-modules if it exists
+# Exclude any modules in ~/.plenv/non-cpanm-modules if it exists
comm -23 -- - "$ef" |
# Read that list of modules to upgrade and upgrade them one by one
diff --git a/bin/pp b/bin/pp.sh
index d9fe6488..b472a012 100755..100644
--- a/bin/pp
+++ b/bin/pp.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Print the full path to each argument; path need not exist
for arg ; do
case $arg in
diff --git a/bin/pph b/bin/pph
deleted file mode 100755
index 684aaafd..00000000
--- a/bin/pph
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-# Run pp(1df) on args, prefix with machine hostname
-hostname=$(hostname -s) || exit
-pp "$@" |
-sed 's_^_'"$hostname":'_'
diff --git a/bin/pph.sh b/bin/pph.sh
new file mode 100644
index 00000000..ce516c16
--- /dev/null
+++ b/bin/pph.sh
@@ -0,0 +1,5 @@
+# Run pp(1df) on args, prefix with machine hostname
+hn=$(hostname -s) || exit
+pp "$@" | while IFS= read -r path ; do
+ printf '%s:%s\n' "$hn" "$path"
+done
diff --git a/bin/pst.mi5 b/bin/pst.mi5
new file mode 100644
index 00000000..34ffbd8c
--- /dev/null
+++ b/bin/pst.mi5
@@ -0,0 +1,19 @@
+# Interrupt a pipe with manual /dev/tty input to a program
+self=pst
+
+# Don't accept terminal as stdin
+if [ -t 0 ] ; then
+ printf >&2 '%s: stdin is a term\n' "$self"
+ exit 2
+fi
+
+<%
+include(`include/mktd.m4')
+%>
+
+# Run the interactive command on the temporary file forcing /dev/tty as
+# input/output
+tf=$td/data
+cat - > "$tf" || exit
+"${@:-"${PAGER:-more}"}" "$tf" </dev/tty >/dev/tty
+cat -- "$tf" || exit
diff --git a/bin/pvi.sh b/bin/pvi.sh
new file mode 100644
index 00000000..85fc5671
--- /dev/null
+++ b/bin/pvi.sh
@@ -0,0 +1,2 @@
+# Use pst(1df) to edit a pipe partway through, like vipe(1)
+pst "${VISUAL:-vi}"
diff --git a/bin/pwg b/bin/pwg.sh
index 97af3df4..e73ae97a 100755..100644
--- a/bin/pwg
+++ b/bin/pwg.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Shortcut to generate just one strong password with pwgen(1)
# If any arguments are provided, those are used instead
if [ "$#" -eq 0 ] ; then
diff --git a/bin/quo.sed b/bin/quo.sed
new file mode 100644
index 00000000..87bdbfda
--- /dev/null
+++ b/bin/quo.sed
@@ -0,0 +1,3 @@
+# Quote or re-quote input in an email style
+/^[^>]/s/^/ /
+s/^/>/
diff --git a/bin/rep.sh b/bin/rep.sh
new file mode 100644
index 00000000..e53cbac3
--- /dev/null
+++ b/bin/rep.sh
@@ -0,0 +1,25 @@
+# Repeat a command
+self=rep
+
+# Check arguments.
+if [ "$#" -lt 2 ] ; then
+ printf >&2 '%s: Need a count and a program name\n' "$self"
+ exit 2
+fi
+
+# Shift off the repetition count.
+c=$1
+shift
+
+# Check the repetition count looks sane. Zero is fine!
+if [ "$c" -lt 0 ] ; then
+ printf >&2 '%s: Nonsensical negative count\n' "$self"
+ exit 2
+fi
+
+# Run the command the specified number of times. Stop immediately as soon as a
+# run fails.
+while [ "${n=1}" -le "$c" ] ; do
+ "$@" || exit
+ n=$((n+1))
+done
diff --git a/bin/rfcf b/bin/rfcf
deleted file mode 100755
index 633eaace..00000000
--- a/bin/rfcf
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh
-
-# Figure out RFC number
-self=rfcf
-if ! [ "$1" ] ; then
- printf >&2 '%s: Need an RFC number\n' "$self"
- exit 2
-fi
-rn=$1
-
-# Retrieve the RFC with curl(1)
-curl -fsSL https://tools.ietf.org/rfc/rfc"$rn".txt
diff --git a/bin/rfcf.sh b/bin/rfcf.sh
new file mode 100644
index 00000000..214f4e64
--- /dev/null
+++ b/bin/rfcf.sh
@@ -0,0 +1,13 @@
+# Fetch an RFC from the IETF site and write it to stdout
+
+# Check arguments
+if [ "$#" -ne 1 ] ; then
+ printf >&2 'rfcf: Need one RFC number\n'
+ exit 2
+fi
+
+# Argument is RFC number
+rn=$1
+
+# Retrieve the RFC with curl(1)
+curl -fsSL https://tools.ietf.org/rfc/rfc"$rn".txt
diff --git a/bin/rfcr b/bin/rfcr
deleted file mode 100755
index 03de898d..00000000
--- a/bin/rfcr
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/sh
-
-# Figure out RFC number
-self=rfcr
-if ! [ "$1" ] ; then
- printf >&2 '%s: Need an RFC number\n' "$self"
- exit 2
-fi
-rn=$1
-
-# Retrieve the RFC with rfcf(1df)
-rfcf "$rn" |
-
-# Pipe it through rfct(1df) to format it as text
-rfct |
-
-# Either spit it directly or through a pager
-pit
diff --git a/bin/rfcr.sh b/bin/rfcr.sh
new file mode 100644
index 00000000..30954154
--- /dev/null
+++ b/bin/rfcr.sh
@@ -0,0 +1,19 @@
+# Fetch and format an RFC from the IETF website and view it on a terminal
+
+# Check arguments
+if [ "$#" -ne 1 ] ; then
+ printf >&2 'rfcf: Need one RFC number\n'
+ exit 2
+fi
+
+# Argument is RFC number
+rn=$1
+
+# Retrieve the RFC with rfcf(1df)
+rfcf "$rn" |
+
+# Pipe it through rfct(1df) to format it as text
+rfct |
+
+# Either spit it directly or through a pager
+pit
diff --git a/bin/rfct.awk b/bin/rfct.awk
index 256841a7..3d942b58 100644
--- a/bin/rfct.awk
+++ b/bin/rfct.awk
@@ -6,11 +6,12 @@ BEGIN {
ORS = "\n\n"
}
-{
- # Strip out control characters, except tab and newline
- gsub(/[^[:print:]\n\t]/, "")
+# Skip paragraphs with ^L chars in them, as they likely contain headers and
+# footers
+/\f/ { next }
- # If there's anything left, print it
- if (length)
- print
-}
+# Strip out other control characters, but allow newline and tab
+{ gsub(/[\a\b\r\v]/, "") }
+
+# If there's anything left after that, print it
+length($0)
diff --git a/bin/rgl b/bin/rgl.sh
index a06ecd0a..630d38b6 100755..100644
--- a/bin/rgl
+++ b/bin/rgl.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Read grep(1) patterns from input and search for them in the given files
self=rgl
diff --git a/bin/rnda b/bin/rnda.sh
index 5af4a3bd..6a755305 100755..100644
--- a/bin/rnda
+++ b/bin/rnda.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Choose a random argument using rndi(1df)
# Check we have at least one argument
@@ -7,11 +6,8 @@ if [ "$#" -eq 0 ] ; then
exit 2
fi
-# Get a random seed from rnds(1df); if it's empty, that's still workable
-seed=$(rnds)
-
-# Get a random integet from 1 to the number of arguments
-argi=$(rndi 1 "$#" "$seed") || exit
+# Get a random integer from 1 to the number of arguments
+argi=$(rndi 1 "$#") || exit
# Shift until that argument is the first argument
shift "$((argi-1))"
diff --git a/bin/rndf b/bin/rndf.sh
index 67f9d997..21aa76a6 100755..100644
--- a/bin/rndf
+++ b/bin/rndf.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Choose a random file from a given directory using rnda(1df); ignores dot
# files
diff --git a/bin/rndi.awk b/bin/rndi.awk
index 49df4398..7d5a5b96 100644
--- a/bin/rndi.awk
+++ b/bin/rndi.awk
@@ -1,20 +1,44 @@
# Get a low-quality random number between two integers. Depending on the awk
-# implementation, if you don't provide a third argument (a seed), you might get
-# very predictable random numbers based on the current epoch second.
+# implementation, if you don't have rnds(1df) available to generate a seed of
+# sufficient quality, you might get very predictable random numbers based on
+# the current epoch second.
BEGIN {
+ self = "rndi"
- # Seed with the third argument if given
- if (ARGV[3])
- srand(ARGV[3])
+ # Check we have two arguments
+ if (ARGC != 3)
+ fail("Need a lower and upper bound")
- # If not, just seed with what is probably a date/time-derived value
+ # Floor args and check for sanity
+ lower = int(ARGV[1] + 0)
+ upper = int(ARGV[2] + 0)
+ if (lower >= upper)
+ fail("Bounds must be numeric, first lower than second")
+
+ # Get a random seed if rnds(1df) available
+ rnds = "rnds 2>/dev/null"
+ rnds | getline seed
+ close(rnds)
+
+ # Truncate the seed to 8 characters because mawk might choke on it
+ seed = substr(seed,1,8)
+ if (length(seed))
+ srand(seed + 0)
else
srand()
# Print a random integer bounded by the first and second arguments
- print int(ARGV[1] + rand() * (ARGV[2] - ARGV[1] + 1))
+ print int(lower + rand() * (upper - lower + 1))
# Bail before processing any lines
exit
}
+
+# Bailout function
+function fail(str) {
+ stderr = "cat >&2"
+ printf "%s: %s\n", self, str | stderr
+ close(stderr)
+ exit(2)
+}
diff --git a/bin/rndl b/bin/rndl
deleted file mode 100755
index c09c2c78..00000000
--- a/bin/rndl
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/bin/sh
-# Print a random line from input
-self=rndl
-
-# If there are no arguments, we're checking stdin; this is more complicated
-# than checking file arguments because we have to count the lines in order to
-# correctly choose a random one, and two passes means we require a temporary
-# file if we don't want to read all of the input into memory (!)
-if [ "$#" -eq 0 ] ; then
-
- # Create a temporary directory with name in $td, and handle POSIX-ish traps to
- # remove it when the script exits.
- td=
- cleanup() {
- [ -n "$td" ] && rm -fr -- "$td"
- if [ "$1" != EXIT ] ; then
- trap - "$1"
- kill "-$1" "$$"
- fi
- }
- for sig in EXIT HUP INT TERM ; do
- # shellcheck disable=SC2064
- trap "cleanup $sig" "$sig"
- done
- td=$(mktd "$self") || exit
-
- # We'll operate on stdin in the temp directory; write the script's stdin to
- # it with cat(1)
- set -- "$td"/stdin
- cat >"$td"/stdin
-fi
-
-# Count the number of lines in the input
-lc=$(sed -- '$=;d' "$@") || exit
-
-# If there were none, bail
-case $lc in
- ''|0)
- printf >&2 'rndl: No lines found on input\n'
- exit 2
- ;;
-esac
-
-# Try to get a random seed from rnds(1df) for rndi(1df)
-seed=$(rnds)
-
-# Get a random line number from rndi(1df)
-ri=$(rndi 1 "$lc" "$seed") || exit
-
-# Print the line using sed(1)
-sed -- "$ri"'!d' "$@"
diff --git a/bin/rndl.awk b/bin/rndl.awk
new file mode 100644
index 00000000..99f5b4e1
--- /dev/null
+++ b/bin/rndl.awk
@@ -0,0 +1,39 @@
+# Print a random line from input
+
+# Process arguments
+BEGIN {
+
+ # Name self
+ self = "rndl"
+
+ # Get a random seed if rnds(1df) available
+ rnds = "rnds 2>/dev/null"
+ rnds | getline seed
+ close(rnds)
+
+ # Truncate the seed to 8 characters because mawk might choke on it
+ seed = substr(seed,1,8)
+ if (length(seed))
+ srand(seed + 0)
+ else
+ srand()
+}
+
+# Iterate over the lines, randomly assigning the first field of each one with a
+# decreasing probability
+rand() * NR < 1 { ln = $0 }
+
+# Check and print
+END {
+
+ # Check that we processed at least one line
+ if (!NR) {
+ stderr = "cat >&2"
+ printf "%s: No lines found on input\n", self | stderr
+ close(stderr)
+ exit(1)
+ }
+
+ # Print the line
+ print ln
+}
diff --git a/bin/rnds b/bin/rnds.sh
index c5ffabe4..6b3ac904 100755..100644
--- a/bin/rnds
+++ b/bin/rnds.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Try to get a low-quality random seed from a random device if possible
# Sole optional argument is the bytes to read; 32 is the default
diff --git a/bin/sd2u.awk b/bin/sd2u.awk
index 87f710b2..02584952 100644
--- a/bin/sd2u.awk
+++ b/bin/sd2u.awk
@@ -1,3 +1,3 @@
# Convert DOS line endings to UNIX ones
{ sub(/\r$/, "") }
-1
+{ print }
diff --git a/bin/sec.awk b/bin/sec.awk
index 001b017d..645df147 100644
--- a/bin/sec.awk
+++ b/bin/sec.awk
@@ -1,13 +1,19 @@
# Convert [[[hh:]mm:]ss] timestamps to seconds
# Separator is :, strip out leading zeroes
-BEGIN { FS = ":0*" }
+BEGIN {
+ FS = ":0*"
+ stderr = ""
+ ex = 0
+}
# If no fields, too many fields, or illegal characters, warn, skip line, accrue
# errors
!NF || NF > 3 || /[^0-9:]/ {
- print "sec: Bad format" | "cat >&2"
- err = 1
+ if (!stderr)
+ stderr = "cat >&2"
+ print "sec: Bad format" | stderr
+ ex = 1
next
}
@@ -21,4 +27,8 @@ NF == 2 { printf "%u\n", $1 * 60 + $2 }
NF == 1 { printf "%u\n", $1 }
# Done, exit 1 if we had any errors on the way
-END { exit(err > 0) }
+END {
+ if (stderr)
+ close(stderr)
+ exit(ex)
+}
diff --git a/bin/shb b/bin/shb.sh
index 49894b0f..d0279ce3 100755..100644
--- a/bin/shb
+++ b/bin/shb.sh
@@ -1,17 +1,15 @@
-#!/bin/sh
# Use PATH to build a shebang for a script given on stdin
self=shb
-# Need at least two arguments
-if [ "$#" -lt 2 ] ; then
- printf >&2 '%s: Need input file and command\n' "$self"
- exit 1
+# Need at least one argument
+if [ "$#" -lt 1 ] ; then
+ printf >&2 '%s: Need interpreter command\n' "$self"
+ exit 2
fi
-# First argument is the script (might be - for stdin), second argument is the
-# name of the interpreter
-scr=$1 intn=$2
-shift 2
+# First argument is the name of the interpreter
+intn=$1
+shift
# Try and find the path to the interpreter command, bail out if we can't
if ! intp=$(command -v "$intn" 2>/dev/null) ; then
@@ -25,4 +23,4 @@ set -- "$intp" "$@"
printf '#!%s\n' "$*"
# Emit the rest of the input
-cat -- "$scr"
+cat -
diff --git a/bin/slow b/bin/slow.sh
index a7bdae76..b0047829 100755..100644
--- a/bin/slow
+++ b/bin/slow.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Convert uppercase letters in a stream to lowercase
cat "${@:--}" |
tr '[:upper:]' '[:lower:]'
diff --git a/bin/sls b/bin/sls.sh
index 770b8ec0..55c1dfc7 100755..100644
--- a/bin/sls
+++ b/bin/sls.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Print hostnames from ssh_config(5) files, defaulting to the usual paths
# If we weren't given a file explicitly, we'll try to read both /etc/ssh_config
diff --git a/bin/sqs b/bin/sqs.sh
index d0b3023f..e00797e3 100755..100644
--- a/bin/sqs
+++ b/bin/sqs.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Chop a trailing query string off filenames
self=sqs
diff --git a/bin/sra b/bin/sra.sh
index 7f072dfb..f3ed6f71 100755..100644
--- a/bin/sra
+++ b/bin/sra.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Run ssh(1) with an optional command on every host in sls(1df) output
# Use FD3 to keep a reference to the script's stdin for the ssh(1) calls
exec 3<&0
diff --git a/bin/sshi b/bin/sshi.sh
index 80e00a10..0d1591f1 100755..100644
--- a/bin/sshi
+++ b/bin/sshi.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Print some human-readable information from SSH_CONNECTION
# Check we have an SSH_CONNECTION variable
diff --git a/bin/sta b/bin/sta.sh
index 848d9740..5736842a 100755..100644
--- a/bin/sta
+++ b/bin/sta.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Print list of sls(1df) hostnames that exit 0 when a connection is attempted
# and the optional given command is run. Discard stdout, but preserve stderr.
sls | while read -r hostname ; do
diff --git a/bin/stbl b/bin/stbl.sh
index 34a06251..23d77703 100755..100644
--- a/bin/stbl
+++ b/bin/stbl.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Strip a trailing blank line from the given files with ed(1)
# Check arguments
diff --git a/bin/stex b/bin/stex.sh
index f1f9c029..14d2cabf 100755..100644
--- a/bin/stex
+++ b/bin/stex.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Strip an extension from the given filenames
self=stex
diff --git a/bin/stws b/bin/stws.sh
index 2ceae935..ce2c14d0 100755..100644
--- a/bin/stws
+++ b/bin/stws.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Strip trailing spaces on one or more files
# Check arguments
diff --git a/bin/su2d.awk b/bin/su2d.awk
index f9160ab0..34a8c5ae 100644
--- a/bin/su2d.awk
+++ b/bin/su2d.awk
@@ -1,3 +1,3 @@
# Convert UNIX line endings to DOS ones
!/\r$/ { $0 = $0 "\r" }
-1
+{ print }
diff --git a/bin/sue b/bin/sue.sh
index 64d566f7..654c041f 100755..100644
--- a/bin/sue
+++ b/bin/sue.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Run sudoedit(8) with an appropriate user on a set of files
# Blank out the user variable
diff --git a/bin/supp b/bin/supp.sh
index 1ba6c850..5ddbadc3 100755..100644
--- a/bin/supp
+++ b/bin/supp.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Convert lowercase letters in a stream to uppercase
cat "${@:--}" |
tr '[:lower:]' '[:upper:]'
diff --git a/bin/swr b/bin/swr.mi5
index 56ab5919..9b73b6d6 100755..100644
--- a/bin/swr
+++ b/bin/swr.mi5
@@ -1,22 +1,9 @@
-#!/bin/sh
-# Transparently wrap scp(1) targets on the command line
+# Transparently wrap scp(1) targets to read (not write) on the command line
self=swr
-# Create a temporary directory with name in $td, and handle POSIX-ish traps to
-# remove it when the script exits.
-td=
-cleanup() {
- [ -n "$td" ] && rm -fr -- "$td"
- if [ "$1" != EXIT ] ; then
- trap - "$1"
- kill "-$1" "$$"
- fi
-}
-for sig in EXIT HUP INT TERM ; do
- # shellcheck disable=SC2064
- trap "cleanup $sig" "$sig"
-done
-td=$(mktd "$self") || exit
+<%
+include(`include/mktd.m4')
+%>
# Set a flag to manage resetting the positional parameters at the start of the
# loop
diff --git a/bin/td b/bin/td.sh
index 69077a8d..eaae1fd6 100755..100644
--- a/bin/td
+++ b/bin/td.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Manage to-do files with just $EDITOR and git(1)
# Specify the path and file
diff --git a/bin/tl b/bin/tl.sh
index baa6fb2b..86bca469 100755..100644
--- a/bin/tl
+++ b/bin/tl.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Tag lines from files or stdin with a string prefix or suffix
self=tl
diff --git a/bin/tlcs b/bin/tlcs.mi5
index aa0d2f25..a3e17c82 100755..100644
--- a/bin/tlcs
+++ b/bin/tlcs.mi5
@@ -1,4 +1,3 @@
-#!/bin/sh
# Execute a command and tag the output of the stdout and stderr streams.
self=tlcs
@@ -68,21 +67,9 @@ if [ "$((color_count >= 8))" -eq 1 ] ; then
fi
fi
-# Create a temporary directory with name in $td, and handle POSIX-ish traps to
-# remove it when the script exits.
-td=
-cleanup() {
- [ -n "$td" ] && rm -fr -- "$td"
- if [ "$1" != EXIT ] ; then
- trap - "$1"
- kill "-$1" "$$"
- fi
-}
-for sig in EXIT HUP INT TERM ; do
- # shellcheck disable=SC2064
- trap "cleanup $sig" "$sig"
-done
-td=$(mktd "$self") || exit
+<%
+include(`include/mktd.m4')
+%>
# Execute the command, passing stdout and stderr to tl(1df) calls as appropriate
# via named pipes
diff --git a/bin/tm.sh b/bin/tm.sh
new file mode 100644
index 00000000..d5422869
--- /dev/null
+++ b/bin/tm.sh
@@ -0,0 +1,17 @@
+# Attach to existing tmux session rather than create a new one if possible
+
+# If given any arguments, just use them as they are
+if [ "$#" -gt 0 ] ; then
+ :
+
+# If a session exists, just attach to it
+elif tmux has-session 2>/dev/null ; then
+ set -- attach-session -d
+
+# Create a new session with an appropriate name
+else
+ set -- new-session -s "${TMUX_SESSION:-default}"
+fi
+
+# Execute with concluded arguments
+tmux "$@"
diff --git a/bin/tot.awk b/bin/tot.awk
index eda25724..add5f00e 100644
--- a/bin/tot.awk
+++ b/bin/tot.awk
@@ -1,3 +1,4 @@
# Total a list of numbers
+BEGIN { tot = 0 }
{ tot += $1 }
END { print tot }
diff --git a/bin/trs.awk b/bin/trs.awk
new file mode 100644
index 00000000..fbb7eeba
--- /dev/null
+++ b/bin/trs.awk
@@ -0,0 +1,35 @@
+# Substitute one string for another in input (no newlines, no regex)
+BEGIN {
+ # Name self
+ self = "trs"
+
+ # Two and only two arguments required
+ if (ARGC != 3)
+ fail("Need a string and a replacement")
+
+ # Get arguments and blank them so awk doesn't try to read them as files
+ str = ARGV[1]
+ rep = ARGV[2]
+ ARGV[1] = ARGV[2] = ""
+
+ # String length is relevant here
+ if (!(len = length(str)))
+ fail("String to replace cannot be null")
+}
+
+# Bailout function
+function fail(msg) {
+ stderr = "cat >&2"
+ printf "%s: %s\n", self, msg | stderr
+ close(stderr)
+ exit(2)
+}
+
+# Run on each line
+{
+ lin = ""
+ for (buf = $0; ind = index(buf, str); buf = substr(buf, ind + len))
+ lin = lin substr(buf, 1, ind - 1) rep
+ lin = lin buf
+ print lin
+}
diff --git a/bin/try b/bin/try.mi5
index 7d6d57a8..ea39d717 100755..100644
--- a/bin/try
+++ b/bin/try.mi5
@@ -1,4 +1,3 @@
-#!/bin/sh
# Attempt a certain number of times to perform a task, buffer stderr unless and
# until all command attempts fail
self=try
@@ -26,21 +25,9 @@ if [ "$#" -eq 0 ] ; then
exit 2
fi
-# Create a temporary directory with name in $td, and handle POSIX-ish traps to
-# remove it when the script exits.
-td=
-cleanup() {
- [ -n "$td" ] && rm -fr -- "$td"
- if [ "$1" != EXIT ] ; then
- trap - "$1"
- kill "-$1" "$$"
- fi
-}
-for sig in EXIT HUP INT TERM ; do
- # shellcheck disable=SC2064
- trap "cleanup $sig" "$sig"
-done
-td=$(mktd "$self") || exit
+<%
+include(`include/mktd.m4')
+%>
# Open a filehandle to the error buffer, just to save on file operations
errbuff=$td/errbuff
diff --git a/bin/u2d b/bin/u2d.sh
index 505b3d04..9f4e800a 100755..100644
--- a/bin/u2d
+++ b/bin/u2d.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Convert UNIX line endings to DOS ones
# Check arguments
diff --git a/bin/umake b/bin/umake.sh
index e8de7ae6..21073328 100755..100644
--- a/bin/umake
+++ b/bin/umake.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Keep going up the tree until we find a Makefile, and then run make(1) with
# any given args
while [ "$PWD" != / ] ; do
diff --git a/bin/unf.awk b/bin/unf.awk
index a9837a8a..7acb09c2 100644
--- a/bin/unf.awk
+++ b/bin/unf.awk
@@ -1,5 +1,7 @@
# Unfold header lines in an internet message, don't touch the body
+BEGIN { buf = "" }
+
# Function to write and empty the buffer
function wrbuf() {
if (length(buf))
@@ -8,7 +10,7 @@ function wrbuf() {
}
# Flag to stop processing once we hit the first blank line
-!length {
+!length($0) {
wrbuf()
body = 1
}
diff --git a/bin/urlc b/bin/urlc.mi5
index a949f50d..55dac171 100755..100644
--- a/bin/urlc
+++ b/bin/urlc.mi5
@@ -1,25 +1,12 @@
-#!/bin/sh
# Try to find erroneous or insecure URLs
self=urlc
# cURL request timeout
tm=${URLCHECK_TIMEOUT:-8}
-# Create a temporary directory with name in $td, and handle POSIX-ish traps to
-# remove it when the script exits.
-td=
-cleanup() {
- [ -n "$td" ] && rm -fr -- "$td"
- if [ "$1" != EXIT ] ; then
- trap - "$1"
- kill "-$1" "$$"
- fi
-}
-for sig in EXIT HUP INT TERM ; do
- # shellcheck disable=SC2064
- trap "cleanup $sig" "$sig"
-done
-td=$(mktd "$self") || exit
+<%
+include(`include/mktd.m4')
+%>
# Create buffer files for the headers and body content, to be cleaned up on
# exit
diff --git a/bin/urlh b/bin/urlh.sh
index 8e9463e7..9f517fe9 100755..100644
--- a/bin/urlh
+++ b/bin/urlh.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Get values for HTTP headers for the given URL
# Check arguments
@@ -18,13 +17,10 @@ unf |
sd2u |
# Use awk to find any values for the header case-insensitively
-awk -v header="$header" '
-BEGIN {
- FS=": *"
- header = tolower(header)
-}
+awk -F ': *' -v header="$header" '
+BEGIN { header = tolower(header) }
tolower($1) == header {
- sub(/^[^ ]*: */, "")
+ sub(/^[^:]*: */, "")
print
}
'
diff --git a/bin/urlmt b/bin/urlmt.sh
index b209f26a..cd71b0fd 100755..100644
--- a/bin/urlmt
+++ b/bin/urlmt.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Get the MIME type for a given URL
urlh "$1" Content-Type |
diff --git a/bin/vest b/bin/vest.sh
index d80c24d1..7dd65f0b 100755..100644
--- a/bin/vest
+++ b/bin/vest.sh
@@ -1,5 +1,4 @@
-#!/bin/sh
-# Run a test(1) command a print a string to stdout showing pass/fail
+# Run a test(1) command and print a string to stdout showing pass/fail
if [ "$#" -eq 0 ] ; then
printf >&2 'vest: Need test(1) arguments\n'
exit 2
diff --git a/bin/vex b/bin/vex.sh
index 908288ba..8a696577 100755..100644
--- a/bin/vex
+++ b/bin/vex.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Run a command and print a string to stdout showing pass/fail
if [ "$#" -eq 0 ] ; then
printf >&2 'vex: Need a command\n'
diff --git a/bin/wro.sh b/bin/wro.sh
new file mode 100644
index 00000000..3888c526
--- /dev/null
+++ b/bin/wro.sh
@@ -0,0 +1,30 @@
+# Add an email-style quote header to input
+self=wro
+
+# Check arguments
+if [ "$#" -gt 2 ] ; then
+ printf >&2 '%s: Too many arguments\n' "$self"
+ exit 2
+fi
+
+# Check first argument for the person to quote; if blank, try to form a
+# reasonable-looking name from the system
+if [ -n "$1" ] ; then
+ from=$1
+else
+ un=$(id -nu)
+ if [ -f /etc/mailname ] ; then
+ read -r hn < /etc/mailname
+ else
+ hn=$(uname -n)
+ fi
+ from="$un"@"$hn"
+fi
+
+# Check second argument for the date; if blank, get the system date in whatever
+# format it cares to give us
+date=${2:-"$(date)"}
+
+# Print the header and then the input
+printf 'On %s, %s wrote:\n' "$date" "$from"
+cat
diff --git a/bin/xgo b/bin/xgo.sh
index 46d90f2e..3fb11fde 100755..100644
--- a/bin/xgo
+++ b/bin/xgo.sh
@@ -1,9 +1,9 @@
-#!/bin/sh
# Test and open a clipboard URL with an apt program
# Check arguments
if [ "$#" -eq 0 ] ; then
printf >&2 'xgo: At least one URL required\n'
+ exit 2
fi
# Iterate over the URL arguments
@@ -13,12 +13,12 @@ for url ; do (
case $url in
# If this is a GitHub or GitLab link, swap "blob" for "raw" to get the actual file
- *://github.com/*/blob/*|*://gitlab.com/*/blob/*)
+ (*://github.com/*/blob/*|*://gitlab.com/*/blob/*)
url=$(printf '%s\n' "$url" | sed 's_/blob/_/raw/_')
;;
# Dig out the plain text for pastebin.com links
- *://pastebin.com/*)
+ (*://pastebin.com/*)
# shellcheck disable=SC2016
url=$(printf '%s\n' "$url" | sed 's_/[A-Za-z0-9][A-Za-z0-9]*$_/raw&_')
;;
@@ -26,14 +26,14 @@ for url ; do (
# If this is a not-direct imgur link and not to an album, swap URL
# elements to get to the actual file (it may not actually be a JPEG;
# the MIME type will tell us)
- *://imgur.com/a/*) ;;
- *://imgur.com/*)
+ (*://imgur.com/a/*) ;;
+ (*://imgur.com/*)
url=$(printf '%s\n' "$url" | sed 's_imgur\.com_i.imgur.com_;s/$/.jpg/')
;;
# If this is a YouTube video without a given start time, load it in mpv(1)
- *[/.]youtube.com/watch*[?\&]t=) ;;
- *[/.]youtube.com/watch*)
+ (*[/.]youtube.com/watch*[?\&]t=) ;;
+ (*[/.]youtube.com/watch*)
mpv -- "$url" && exit
;;
esac
@@ -46,7 +46,7 @@ for url ; do (
# Open PDFs in xpdf(1); download them first as xpdf(1) does not seem to
# have a way to handle stdin files
- application/pdf)
+ (application/pdf)
(
cd -- "$HOME"/Downloads || exit
curl -O -- "$url" || exit
@@ -56,18 +56,18 @@ for url ; do (
# Open audio and video in mpv(1); force a window even for audio so I
# can control it
- audio/*|video/*)
+ (audio/*|video/*)
mpv --force-window -- "$url" && exit
;;
# If the MIME type is an image that is not a GIF, load it in feh(1)
- image/gif) ;;
- image/*)
+ (image/gif) ;;
+ (image/*)
curl -- "$url" | feh - && exit
;;
# Open plain text in a terminal view(1)
- text/plain)
+ (text/plain)
# shellcheck disable=SC2016
urxvt -e sh -c 'curl -- "$1" | view -' _ "$url" && exit
;;
diff --git a/bin/xgoc b/bin/xgoc.sh
index 516f7028..42e04e2d 100755..100644
--- a/bin/xgoc
+++ b/bin/xgoc.sh
@@ -1,3 +1,2 @@
-#!/bin/sh
# Run xgo(1df) with the contents of the X clipboard
xgo "$(xsel)"
diff --git a/bin/xrbg.sh b/bin/xrbg.sh
new file mode 100644
index 00000000..617a9b43
--- /dev/null
+++ b/bin/xrbg.sh
@@ -0,0 +1,3 @@
+# Apply a random background image. Requires rndf(1df) and feh(1).
+bg=$(rndf "${XBACKGROUNDS:-"$HOME"/.xbackgrounds}") || exit
+feh --bg-scale --no-fehbg -- "$bg"
diff --git a/bin/xrq.awk b/bin/xrq.awk
new file mode 100644
index 00000000..ffd5f124
--- /dev/null
+++ b/bin/xrq.awk
@@ -0,0 +1,30 @@
+# Run xrdb(1) to query specific resources from it
+# I thought xrdb -query would do this, but it doesn't seem to, maybe I'm doing
+# it wrong
+BEGIN {
+
+ # Separator is a colon followed by a tab
+ FS = ":\t"
+
+ # Check we have at least one resource name
+ if (ARGC < 2) {
+ stderr = "cat >&2"
+ print "xrq: Need at least one resource name" | stderr
+ close(stderr)
+ exit(2)
+ }
+
+ # Run `xrdb -query` and search for instances of the requested resource
+ xrdb = "xrdb -query"
+ found = 0
+ while (xrdb | getline)
+ for (i in ARGV)
+ if ($1 == ARGV[i]) {
+ found = 1
+ print $2
+ }
+ close(xrdb)
+
+ # Exit successfully if we found at least one result
+ exit(!found)
+}
diff --git a/check/bash b/check/bash.sh
index 525bec34..a3efccb1 100755..100644
--- a/check/bash
+++ b/check/bash.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
for bash in bash/* bash/bashrc.d/* ; do
[ -f "$bash" ] || continue
bash -n "$bash" || exit
diff --git a/check/bin b/check/bin
deleted file mode 100755
index 2fc4e767..00000000
--- a/check/bin
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/sh
-for bin in bin/* ; do
- [ -x "$bin" ] || continue
- hb=$(sed 1q "$bin") || exit
- case $hb in
- *bash)
- bash -n "$bin" || exit
- ;;
- *sh)
- sh -n "$bin" || exit
- ;;
- esac
-done
-printf 'All shell scripts in bin parsed successfully.\n'
diff --git a/check/bin.sh b/check/bin.sh
new file mode 100644
index 00000000..04b0da6b
--- /dev/null
+++ b/check/bin.sh
@@ -0,0 +1,4 @@
+for bin in bin/*.sh ; do
+ sh -n "$bin" || exit
+done
+printf 'All shell scripts in bin parsed successfully.\n'
diff --git a/check/games b/check/games
deleted file mode 100755
index d3b5feac..00000000
--- a/check/games
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/sh
-for game in games/* ; do
- [ -x "$game" ] || continue
- hb=$(sed 1q "$game") || exit
- case $hb in
- *bash)
- bash -n "$game" || exit
- ;;
- *sh)
- sh -n "$game" || exit
- ;;
- esac
-done
-printf 'All shell scripts in games parsed successfully.\n'
diff --git a/check/games.sh b/check/games.sh
new file mode 100644
index 00000000..79d53ed5
--- /dev/null
+++ b/check/games.sh
@@ -0,0 +1,4 @@
+for game in games/*.sh ; do
+ sh -n "$game" || exit
+done
+printf 'All shell scripts in games parsed successfully.\n'
diff --git a/check/ksh b/check/ksh.sh
index 3136c413..51e71e19 100755..100644
--- a/check/ksh
+++ b/check/ksh.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
for ksh in ksh/* ksh/kshrc.d/* ; do
[ -f "$ksh" ] || continue
ksh -n "$ksh" || exit
diff --git a/check/login-shell.sh b/check/login-shell.sh
new file mode 100644
index 00000000..2972d98d
--- /dev/null
+++ b/check/login-shell.sh
@@ -0,0 +1,10 @@
+target=check-sh
+case ${SHELL##*/} in
+ bash)
+ target=check-bash ;;
+ ksh|ksh88|ksh93|mksh|pdksh)
+ target=check-ksh ;;
+ zsh)
+ target=check-zsh ;;
+esac
+make "$target"
diff --git a/check/man b/check/man.sh
index ca1c248c..89c03890 100755..100644
--- a/check/man
+++ b/check/man.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Check that manual pages and logical binaries match up
# Need some scripts from the source directory
diff --git a/check/sh b/check/sh
deleted file mode 100755
index ec3ba339..00000000
--- a/check/sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/sh
-for sh in sh/* sh/profile.d/* sh/shrc.d/* ; do
- [ -f "$sh" ] || continue
- sh -n "$sh" || exit
-done
-printf 'All sh(1) scripts parsed successfully.\n'
diff --git a/check/sh.sh b/check/sh.sh
new file mode 100644
index 00000000..c5a86955
--- /dev/null
+++ b/check/sh.sh
@@ -0,0 +1,11 @@
+for sh in \
+ sh/* sh/profile.d/* sh/shrc.d/* \
+ keychain/profile.d/* keychain/shrc.d/* \
+ ksh/shrc.d/* \
+ mpd/profile.d/* \
+ plenv/profile.d/* plenv/shrc.d/* \
+; do
+ [ -f "$sh" ] || continue
+ sh -n "$sh" || exit
+done
+printf 'All sh(1) scripts parsed successfully.\n'
diff --git a/check/urxvt b/check/urxvt
deleted file mode 100755
index a40f8559..00000000
--- a/check/urxvt
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh
-for perl in urxvt/ext/* ; do
- [ -f "$perl" ] || continue
- case $perl in
- *.pl) ;;
- *) perl -c "$perl" >/dev/null || exit ;;
- esac
-done
-printf 'All Perl scripts in urxvt/ext parsed successfully.\n'
diff --git a/check/urxvt.sh b/check/urxvt.sh
new file mode 100644
index 00000000..ee39e6c9
--- /dev/null
+++ b/check/urxvt.sh
@@ -0,0 +1,4 @@
+for perl in urxvt/ext/*.pl ; do
+ perl -c "$perl" || exit
+done
+printf 'All Perl scripts in urxvt/ext parsed successfully.\n'
diff --git a/check/xinit.sh b/check/xinit.sh
new file mode 100644
index 00000000..f8116908
--- /dev/null
+++ b/check/xinit.sh
@@ -0,0 +1,4 @@
+for xinit in X/xinitrc X/xinitrc.d/*.sh ; do
+ sh -n "$xinit" || exit
+done
+printf 'X/xinitrc and all shell scripts in X/xinitrc.d parsed successfully.\n'
diff --git a/check/yash b/check/yash
deleted file mode 100755
index fb737596..00000000
--- a/check/yash
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/sh
-for yash in yash/* ; do
- [ -f "$yash" ] || continue
- yash -n "$yash" || exit
-done
-printf 'All yash scripts parsed successfully.\n'
diff --git a/check/zsh b/check/zsh.sh
index 39a6c1e9..50335d56 100755..100644
--- a/check/zsh
+++ b/check/zsh.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
for zsh in zsh/* zsh/zshrc.d/* ; do
[ -f "$zsh" ] || continue
zsh -n "$zsh" || exit
diff --git a/ex/exrc b/ex/exrc
new file mode 100644
index 00000000..0c001f36
--- /dev/null
+++ b/ex/exrc
@@ -0,0 +1,6 @@
+" POSIX ex/vi settings
+set autoindent
+set report=0
+set shiftwidth=4
+set showmode
+set tabstop=4
diff --git a/games/aaf b/games/aaf.sh
index 4f1825c6..24094a73 100755..100644
--- a/games/aaf
+++ b/games/aaf.sh
@@ -1,3 +1,3 @@
-#!/bin/sh
+# Print a random ASCII Art Fart
curl http://www.asciiartfarts.com/random.cgi |
pup -p 'table[cellpadding]' pre text{}
diff --git a/games/acq.sed b/games/acq.sed
index 650fdedb..b6051c14 100644
--- a/games/acq.sed
+++ b/games/acq.sed
@@ -1,2 +1,3 @@
# Interrogate the interplanetary computer.
-s/.*/THERE IS INSUFFICIENT DATA FOR MEANINGFUL ANSWER./
+c\
+THERE IS INSUFFICIENT DATA FOR A MEANINGFUL ANSWER.
diff --git a/games/chkl.sed b/games/chkl.sed
index 40c35cee..6e4b1c77 100644
--- a/games/chkl.sed
+++ b/games/chkl.sed
@@ -1,4 +1,3 @@
-#!/bin/sed -f
# Change an ASCII checklist with [/], [x], and [ ] boxes to a Unicode one
/^#/d
s_^\[ \]_☐_
diff --git a/games/dr b/games/dr.sh
index e1db163d..df21d7a5 100755..100644
--- a/games/dr
+++ b/games/dr.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Roll D&D-style dice in a ndn+n formula, e.g. 10d6+2
# Need exactly one argument
@@ -16,15 +15,14 @@ d=${nd#*d}
# Check this is a real die you can actually roll
case $d in
- 4|6|8|10|12|20) : ;;
+ 4|6|8|10|12|20) ;;
*) exit 2 ;;
esac
# Roll the dice the appropriate number of times using rndi(1df)
i=0 t=0
while [ "$i" -lt "$n" ] ; do
- seed=$(rnds)
- r=$(rndi 1 "$d" "$seed")
+ r=$(rndi 1 "$d")
t=$((t + r))
i=$((i + 1))
done
diff --git a/games/drakon.awk b/games/drakon.awk
index 4b8c35c5..ebca4e95 100644
--- a/games/drakon.awk
+++ b/games/drakon.awk
@@ -1,13 +1,14 @@
# TyPe lIkE AnDoR DrAkOn fRoM AnCiEnT DoMaInS Of mYsTeRy
# <http://www.adomgb.info/adomgb-4.html>
{
- line = ""
- toggle = 0
- for (i = 1; i <= length; i++) {
- char = substr($0, i, 1)
- if (char ~ /[a-zA-Z]/)
- char = (toggle = !toggle) ? tolower(char) : toupper(char)
- line = line char
+ len = length($0)
+ lin = ""
+ tog = 0
+ for (i = 1; i <= len; i++) {
+ chr = substr($0, i, 1)
+ if (chr ~ /[a-zA-Z]/)
+ chr = (tog = !tog) ? tolower(chr) : toupper(chr)
+ lin = lin chr
}
- print line
+ print lin
}
diff --git a/games/kvlt.sed b/games/kvlt.sed
index e2905a35..461fc04f 100644
--- a/games/kvlt.sed
+++ b/games/kvlt.sed
@@ -53,10 +53,10 @@ s,C\([^H]\),K\1,g
# -S[^H] -> Z (so "sharp" doesn't become "ZHARP")
s,S\([^H]\),Z\1,g
-# consant-I-consonant -> -Y-
+# consonant-I-consonant -> -Y-
s,\([B-DF-HJ-NP-TV-XZ]\)I\([B-DF-HJ-NP-TV-XZ]\),\1Y\2,g
-# consant-U-consonant -> -V-
+# consonant-U-consonant -> -V-
s,\([B-DF-HJ-NP-TV-XZ]\)U\([B-DF-HJ-NP-TV-XZ]\),\1V\2,g
# THE -> DER
diff --git a/games/philsay.sh b/games/philsay.sh
new file mode 100644
index 00000000..1c02bf57
--- /dev/null
+++ b/games/philsay.sh
@@ -0,0 +1,47 @@
+# Ha, ha, ha! ASCII!
+speech=$(pks "$@") || exit
+printf '\n%066s\n' '( '"$speech"' )'
+cat <<'EOF'
+ /
+
+ .''''''''''''''''''''''..
+ .'''''''''''''''''''''''''''
+ .'''''''''''''''''''''''''''''
+ ,'''''''''''''''''''''''''''''''
+ '''''''''''''''''''''''''''''''':
+ ,'''''''''''##`'''''''''''''''.'''`
+ ;''''''''.###########,'''''',###'''
+ ;'''''';#################:'#####.''
+ `:''''''#########################'.
+ ::` ,'+########################';
+ ''''''': .#####################''
+ ''''''''.####` `;#############;##'
+ ;''''''',####,###: +############.
+ ,###''''''#############` ;##:#######
+ ,#:##''';+#####+ :###### +##+ +
+ ,'#;#,''#####',+###` ;####`+
+ ,#'#,#';############++. ,`##
+ :#####+:#######,@,``@@,#####'
+ ;#+#+#############++++##.#+## +
+ ###+################'####'##
+ #######+###################.# :.
+ ######'########################'
+ ,+#####;#######################
+ ,#######;############'####+###:
+ ,#######################+#####'
+ ,###############' ` #'# +'#
+ #,##.###########'##+##'###'####
+ ``@.############## `+#@@@@@######
+ +```@@################ ,,. . ####.
+ ;````@@,##.##############':..:######
+ ;`````@@@########.##################
+ +````````@@@@#####;####################:
+ +`````.`````@@@@######`###################```+
+ +````````,`````'@@@@@##'#####################`````.
++ ``````````.``````@@@@@@##'###'################```````` +
+```````````````````@@@@@@@'#####;##########,##'`````````````.+
+```````````````````@@@@@@@@@+#####':####+:+'````````````````````,
+```````````````````,@@@@@@@@@#:#########'@@@``````````````````````
+```````````.````````@@@@@@@@@@@@#'#####@@@@@```````````````````````
+```````````.````````@@@@@@@@@@@@@@' @@@@@@@.``````````````````````
+EOF
diff --git a/games/pks.awk b/games/pks.awk
new file mode 100644
index 00000000..1a441980
--- /dev/null
+++ b/games/pks.awk
@@ -0,0 +1,53 @@
+# Ha, ha, ha! Awk!
+
+# Process arguments
+BEGIN {
+
+ # If no arguments left, assume a dictionary file
+ if (ARGC == 1) {
+ ARGC = 2
+ if ("DICT" in ENVIRON)
+ ARGV[1] = ENVIRON["DICT"]
+ else
+ ARGV[1] = "/usr/share/dict/words"
+ }
+
+ # Get a random seed if rnds(1df) available
+ rnds = "rnds 2>/dev/null"
+ rnds | getline seed
+ close(rnds)
+
+ # Truncate the seed to 8 characters because mawk might choke on it
+ seed = substr(seed,1,8)
+ if (length(seed))
+ srand(seed + 0)
+ else
+ srand()
+}
+
+# Iterate over the lines, randomly assigning the first field of each one with a
+# decreasing probability; this method allows a single pass over the input,
+# though it requires a lot of random numbers
+$1 ~ /[a-zA-Z]/ && rand() * ++n < 1 { wr = $1 }
+
+# Ha, ha! Conclusion!
+END {
+
+ # Check that we processed at least one line
+ if (!NR)
+ exit 1
+
+ # Strip trailing possessives and punctuation
+ sub(/[^a-zA-Z]+s*$/, "", wr)
+
+ # Two or three "ha"s? Important decisions here folks
+ hr = int(rand()*2+1)
+ for (ha = "Ha"; hi < hr; hi++)
+ ha = ha ", ha"
+
+ # Capitalise the word
+ wr = toupper(substr(wr,1,1)) substr(wr,2)
+
+ # Print the laughter and the word
+ printf "%s! %s!\n", ha, wr
+}
diff --git a/games/rndn b/games/rndn.sh
index 18c34218..bcde9c3c 100755..100644
--- a/games/rndn
+++ b/games/rndn.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
# Esoteric random number generator
# Single optional argument is a random seed, otherwise use rnds(1df)
diff --git a/games/squ.awk b/games/squ.awk
new file mode 100644
index 00000000..be72a3b6
--- /dev/null
+++ b/games/squ.awk
@@ -0,0 +1,7 @@
+# Make a reduced Latin square out of each line of input
+l = length($0) {
+ str = toupper($0)
+ for (j = 0; j < l; j++)
+ for (k = 0; k < l; k++)
+ printf (k < l - 1) ? "%s " : "%s\n", substr(str, (k + j) % l + 1, 1)
+}
diff --git a/games/strik.sed b/games/strik.sed
index bc1cbdc5..cda6b797 100644
--- a/games/strik.sed
+++ b/games/strik.sed
@@ -1,64 +1,2 @@
# Strike out text
-s/a/a̶/g
-s/b/b̶/g
-s/c/c̶/g
-s/d/d̶/g
-s/e/e̶/g
-s/f/f̶/g
-s/g/g̶/g
-s/h/h̶/g
-s/i/i̶/g
-s/j/j̶/g
-s/k/k̶/g
-s/l/l̶/g
-s/m/m̶/g
-s/n/n̶/g
-s/o/o̶/g
-s/p/p̶/g
-s/q/q̶/g
-s/r/r̶/g
-s/s/s̶/g
-s/t/t̶/g
-s/u/u̶/g
-s/v/v̶/g
-s/w/w̶/g
-s/x/x̶/g
-s/y/y̶/g
-s/z/z̶/g
-s/A/A̶/g
-s/B/B̶/g
-s/C/C̶/g
-s/D/D̶/g
-s/E/E̶/g
-s/F/F̶/g
-s/G/G̶/g
-s/H/H̶/g
-s/I/I̶/g
-s/J/J̶/g
-s/K/K̶/g
-s/L/L̶/g
-s/M/M̶/g
-s/N/N̶/g
-s/O/O̶/g
-s/P/P̶/g
-s/Q/Q̶/g
-s/R/R̶/g
-s/S/S̶/g
-s/T/T̶/g
-s/U/U̶/g
-s/V/V̶/g
-s/W/W̶/g
-s/X/X̶/g
-s/Y/Y̶/g
-s/Z/Z̶/g
-s/0/0̶/g
-s/1/1̶/g
-s/2/2̶/g
-s/3/3̶/g
-s/4/4̶/g
-s/5/5̶/g
-s/6/6̶/g
-s/7/7̶/g
-s/8/8̶/g
-s/9/9̶/g
-s/ / ̶/g
+s/./&̶/g
diff --git a/games/xyzzy b/games/xyzzy.sh
index d262c0e6..5cc03278 100755..100644
--- a/games/xyzzy
+++ b/games/xyzzy.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+# ADVENTURE
if [ -e "$HOME"/.xyzzy ] ; then
printf >&2 '%s\n' 'Nothing happens.'
exit 1
diff --git a/git/gitconfig.m4 b/git/gitconfig.mi5
index d13e7fdb..5a50c13c 100644
--- a/git/gitconfig.m4
+++ b/git/gitconfig.mi5
@@ -52,13 +52,13 @@
[sendemail]
confirm = compose
- smtpServer = DOTFILES_SENDMAIL
+ smtpServer = <% SENDMAIL %>
[status]
short = true
showUntrackedFiles = all
[user]
- name = DOTFILES_NAME
- email = DOTFILES_EMAIL
- signingKey = DOTFILES_KEY
+ name = <% NAME %>
+ email = <% EMAIL %>
+ signingKey = <% KEY %>
diff --git a/gnupg/gpg.conf.m4 b/gnupg/gpg.conf.mi5
index 8531a742..1617a979 100644
--- a/gnupg/gpg.conf.m4
+++ b/gnupg/gpg.conf.mi5
@@ -22,11 +22,11 @@ fixed-list-mode
keyid-format 0xlong
# Use a pool of servers which support HKPS (encrypted key retrieval)
-keyserver hkps://hkps.pool.sks-keyservers.net
+keyserver <% KEYSERVER %>
# Retrieve keys automatically; check the keyserver port cert; use whichever
# server is proffered from the pool
-keyserver-options auto-key-retrieve check-cert no-honor-keyserver-url ca-certfile=DOTFILES_HOME/.gnupg/sks-keyservers.net/sks-keyservers.netCA.pem
+keyserver-options auto-key-retrieve no-honor-keyserver-url
# Include trust/validity for UIDs in listings
list-options show-uid-validity
diff --git a/gnupg/sks-keyservers.net/README.markdown b/gnupg/sks-keyservers.net/README.markdown
deleted file mode 100644
index bb19e80e..00000000
--- a/gnupg/sks-keyservers.net/README.markdown
+++ /dev/null
@@ -1,9 +0,0 @@
-sks-keyservers.net CA, CRL, and signature
-=========================================
-
-These files are downloaded from links on the [sks-keyservers.net][1] overview
-page. I've included both their signature file and the revocation list, but it's
-your responsibility to make sure that everything here is verified to your
-satisfaction.
-
-[1]: https://sks-keyservers.net/overview-of-pools.php
diff --git a/gnupg/sks-keyservers.net/crl.pem b/gnupg/sks-keyservers.net/crl.pem
deleted file mode 100644
index ce8cd7a8..00000000
--- a/gnupg/sks-keyservers.net/crl.pem
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN X509 CRL-----
-MIIEhzCCAm8CAQEwDQYJKoZIhvcNAQELBQAwXDELMAkGA1UEBhMCTk8xDTALBgNV
-BAgMBE9zbG8xHjAcBgNVBAoMFXNrcy1rZXlzZXJ2ZXJzLm5ldCBDQTEeMBwGA1UE
-AwwVc2tzLWtleXNlcnZlcnMubmV0IENBFw0xNjA4MDgxOTMwMjdaFw0xNzAyMDQx
-OTMwMjdaMIIBzDASAgEBFw0xMjEwMDkwMTAyMDVaMBICAQIXDTEyMTAwOTAxMDIw
-NVowEgIBAxcNMTQwNTAxMTEyMDU2WjASAgEEFw0xMjEwMDkwMTAyMDVaMBICAQgX
-DTE0MDUwNjE4MjQzMVowEgIBDBcNMTQwNjI4MTI0NTU2WjASAgERFw0xNDA0MjYx
-MjU4MjdaMBICARMXDTEzMTExMzE5MzczM1owEgIBFBcNMTQwNDI5MTczNDA0WjAS
-AgEYFw0xNDA1MDYxODIyMDVaMBICASEXDTE0MDUwMjEyNDQ1MlowEgIBIhcNMTQw
-NDI5MTczNDA0WjASAgEjFw0xMzExMTMxOTM3MzNaMBICASQXDTE0MDUwNzIwMTIy
-OFowEgIBKBcNMTQwNDI5MjAwNjAyWjASAgEpFw0xNDA0MjYxNDI0MjRaMBICASsX
-DTE0MDUwMzE0NDgwNlowEgIBLRcNMTQwNDMwMDgxNTU4WjASAgEuFw0xNDA0MzAw
-ODE2MTdaMBICAS8XDTE0MDQyNjEzMDIxNlowEgIBMxcNMTQwNDI5MTczNjIwWjAS
-AgE0Fw0xNDA1MTIxODQwNThaMBICAWsXDTE1MTEyNTE5MjkyNlqgDzANMAsGA1Ud
-FAQEAgIQJzANBgkqhkiG9w0BAQsFAAOCAgEAKbyM6U6B+RleyuF4O1t/G7SVhvHl
-Yc6bqeV4zNj6B2j9Qw9YtO14USsxVw7RKZPhNvzSJhgBxxRtAOks0tVuGOkjN57V
-qMc9Hiwd/d5WQOkDvaJv44yT5tUq3NhaV8c8bQzeogjXW4h5I0+YsLT84phAnwXK
-Gj95A50vmjXZX7zUbS0TT6GVMjI0RBUIoRu5Ueax4gyX9WOKu0RQ4gZONzlYvbMk
-exX+VWD9JWaA3pWKsxyUrRnDR1e7tUsnDXsh3i5krQinEQ1JYf3/lpGWMOygJV40
-9L0PhZB7cX4xDV2Vg0kBfKU7gr/C0uEF9fZJut8tqwe2LKj54dYa3ktX9Jbjq53F
-WZthON6mMJxtTtjAdWyhQbbM+zy7hOE3cc4aivm9ZAXl30UNBWlPQsJRk3hTScMd
-ye+A9RDRmG68qsoIWbTn/W5PBdiQ+MIxzO8fYwzs8yywQ1/VHHvbS1q0YC1PNono
-6ayc9vHbghGc/RK67BTa1Oj9fqOVgy4XVxzPPzl4JAc4b6ELASS3owzuwUE8CrxP
-drmYWn5ZII+w+0DNn9H5lPasxR5RQ/qPW7T5a8xpuNz+Uj/X4Baedl2DU4wzSP1m
-nvntH0EgqgVXKFpxUT94CSRSiSOReElUZ17j7v28d8IhHCW3rou/JFxMgTIqmIg4
-jyCyTTMl3V9xWCw=
------END X509 CRL-----
diff --git a/gnupg/sks-keyservers.net/sks-keyservers.netCA.pem b/gnupg/sks-keyservers.net/sks-keyservers.netCA.pem
deleted file mode 100644
index 24a2ad2e..00000000
--- a/gnupg/sks-keyservers.net/sks-keyservers.netCA.pem
+++ /dev/null
@@ -1,32 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFizCCA3OgAwIBAgIJAK9zyLTPn4CPMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNV
-BAYTAk5PMQ0wCwYDVQQIDARPc2xvMR4wHAYDVQQKDBVza3Mta2V5c2VydmVycy5u
-ZXQgQ0ExHjAcBgNVBAMMFXNrcy1rZXlzZXJ2ZXJzLm5ldCBDQTAeFw0xMjEwMDkw
-MDMzMzdaFw0yMjEwMDcwMDMzMzdaMFwxCzAJBgNVBAYTAk5PMQ0wCwYDVQQIDARP
-c2xvMR4wHAYDVQQKDBVza3Mta2V5c2VydmVycy5uZXQgQ0ExHjAcBgNVBAMMFXNr
-cy1rZXlzZXJ2ZXJzLm5ldCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
-ggIBANdsWy4PXWNUCkS3L//nrd0GqN3dVwoBGZ6w94Tw2jPDPifegwxQozFXkG6I
-6A4TK1CJLXPvfz0UP0aBYyPmTNadDinaB9T4jIwd4rnxl+59GiEmqkN3IfPsv5Jj
-MkKUmJnvOT0DEVlEaO1UZIwx5WpfprB3mR81/qm4XkAgmYrmgnLXd/pJDAMk7y1F
-45b5zWofiD5l677lplcIPRbFhpJ6kDTODXh/XEdtF71EAeaOdEGOvyGDmCO0GWqS
-FDkMMPTlieLA/0rgFTcz4xwUYj/cD5e0ZBuSkYsYFAU3hd1cGfBue0cPZaQH2HYx
-Qk4zXD8S3F4690fRhr+tki5gyG6JDR67aKp3BIGLqm7f45WkX1hYp+YXywmEziM4
-aSbGYhx8hoFGfq9UcfPEvp2aoc8u5sdqjDslhyUzM1v3m3ZGbhwEOnVjljY6JJLx
-MxagxnZZSAY424ZZ3t71E/Mn27dm2w+xFRuoy8JEjv1d+BT3eChM5KaNwrj0IO/y
-u8kFIgWYA1vZ/15qMT+tyJTfyrNVV/7Df7TNeWyNqjJ5rBmt0M6NpHG7CrUSkBy9
-p8JhimgjP5r0FlEkgg+lyD+V79H98gQfVgP3pbJICz0SpBQf2F/2tyS4rLm+49rP
-fcOajiXEuyhpcmzgusAj/1FjrtlynH1r9mnNaX4e+rLWzvU5AgMBAAGjUDBOMB0G
-A1UdDgQWBBTkwyoJFGfYTVISTpM8E+igjdq28zAfBgNVHSMEGDAWgBTkwyoJFGfY
-TVISTpM8E+igjdq28zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQAR
-OXnYwu3g1ZjHyley3fZI5aLPsaE17cOImVTehC8DcIphm2HOMR/hYTTL+V0G4P+u
-gH+6xeRLKSHMHZTtSBIa6GDL03434y9CBuwGvAFCMU2GV8w92/Z7apkAhdLToZA/
-X/iWP2jeaVJhxgEcH8uPrnSlqoPBcKC9PrgUzQYfSZJkLmB+3jEa3HKruy1abJP5
-gAdQvwvcPpvYRnIzUc9fZODsVmlHVFBCl2dlu/iHh2h4GmL4Da2rRkUMlbVTdioB
-UYIvMycdOkpH5wJftzw7cpjsudGas0PARDXCFfGyKhwBRFY7Xp7lbjtU5Rz0Gc04
-lPrhDf0pFE98Aw4jJRpFeWMjpXUEaG1cq7D641RpgcMfPFvOHY47rvDTS7XJOaUT
-BwRjmDt896s6vMDcaG/uXJbQjuzmmx3W2Idyh3s5SI0GTHb0IwMKYb4eBUIpQOnB
-cE77VnCYqKvN1NVYAqhWjXbY7XasZvszCRcOG+W3FqNaHOK/n/0ueb0uijdLan+U
-f4p1bjbAox8eAOQS/8a3bzkJzdyBNUKGx1BIK2IBL9bn/HravSDOiNRSnZ/R3l9G
-ZauX0tu7IIDlRCILXSyeazu0aj/vdT3YFQXPcvt5Fkf5wiNTo53f72/jYEJd6qph
-WrpoKqrwGwTpRUCMhYIUt65hsTxCiJJ5nKe39h46sg==
------END CERTIFICATE-----
diff --git a/gnupg/sks-keyservers.net/sks-keyservers.netCA.pem.asc b/gnupg/sks-keyservers.net/sks-keyservers.netCA.pem.asc
deleted file mode 100644
index 5f11bc56..00000000
--- a/gnupg/sks-keyservers.net/sks-keyservers.netCA.pem.asc
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN PGP SIGNATURE-----
-
-iQIcBAABCgAGBQJUCZzxAAoJEPw7F94F4Tag/Z8P/jUOTbsCYT+bG7L+/D9s1KCz
-G2H9X4fV/fBeeAFWjgV6iNBEzZuFx9FYxmECyR1JzRektfWa3JR+rt2pipGO2UQ2
-Il2Ti6K7mVNyEnsgfq5otky7UDewmW+p5u1I7PNVcnHmArE7EueX5WB1vYhY2faY
-B4xsFuaLacQVIz9JFyKiTGu0WSkpnlByaCoMPJgifwwGhPNK8X23isKDY8U9hahh
-xWHRf/57Z+g407d6dEG/1ax8ELf68KRLGalZv9fOcZfRbFT4JV4bq/rsZuNptAqf
-8A5RDnsgXFyIgDptWnYYpra/HCPNOKdL/TxcASTsEH6s9NNw9mvNpE//JWYMV4FM
-N6h9aTezSEwAnD781JrPPZ8BlpRYWtnd3UaSbBbOdb6mze0Oh39yvYEcEO8edvC1
-RLH5OJyJIIkkO46B8cYBtokjRlcAeBgFf5GLlwdh6zGcERqsTRHtA8FmLbl1v3w1
-Xj1tUAoex27ke+z+QKBOp06t6eeNavDeN0/jDidSPQ4Q6QVy8KP9eeMDAQkd9+1F
-aCMvSxEkbuiy05grzQC0jqOXAIVwfu33kcFr2Z7boxVNEjM/ng6Ty4WXWWWbADaH
-nXGamvmUrCiODMRl4DYTB65H27tSv2J9j8WyA+IiokJOglH63nyJJy+XWbRmlgmI
-+ds5RCeuq2/uVOGhSP7t
-=O9Kt
------END PGP SIGNATURE-----
diff --git a/gtk/gtkrc-3.0/settings.ini b/gtk/gtk-3.0/settings.ini
index 4f93dfe4..4f93dfe4 100644
--- a/gtk/gtkrc-3.0/settings.ini
+++ b/gtk/gtk-3.0/settings.ini
diff --git a/i3/config b/i3/config
index b7c5dd5b..3c063c94 100644
--- a/i3/config
+++ b/i3/config
@@ -7,6 +7,9 @@ font pango:Verdana 7
# Use Mouse+$mod to drag floating windows to their wanted position
floating_modifier $mod
+# No title bar
+new_window 1pixel
+
# Mod+Shift+r restarts i3wm
bindsym $mod+Shift+r restart
diff --git a/bin/edda b/include/mktd.mi5
index 6af88a5f..388eb9be 100755..100644
--- a/bin/edda
+++ b/include/mktd.mi5
@@ -1,13 +1,3 @@
-#!/bin/sh
-# Run ed(1) over multiple files, duplicating stdin.
-self=edda
-
-# Need at least one file
-if [ "$#" -eq 0 ] ; then
- printf >&2 'edda: Need at least one file\n'
- exit 2
-fi
-
# Create a temporary directory with name in $td, and handle POSIX-ish traps to
# remove it when the script exits.
td=
@@ -23,12 +13,3 @@ for sig in EXIT HUP INT TERM ; do
trap "cleanup $sig" "$sig"
done
td=$(mktd "$self") || exit
-
-# Duplicate stdin into a file
-script=$td/script
-cat >"$script" || exit
-
-# Run ed(1) over each file with the stdin given
-for file ; do
- ed -- "$file" <"$script"
-done
diff --git a/install/install-conf.sh b/install/install-conf.sh
new file mode 100644
index 00000000..f50cde73
--- /dev/null
+++ b/install/install-conf.sh
@@ -0,0 +1,10 @@
+# Read extra targets from an optional ~/.dotfiles.conf file
+if [ -e "$HOME"/.dotfiles.conf ] ; then
+ while read -r line ; do
+ case $line in
+ '#'*|'') ;;
+ *) set -- "$@" "$line" ;;
+ esac
+ done < "$HOME"/.dotfiles.conf
+fi
+make install "$@"
diff --git a/install/install-login-shell.sh b/install/install-login-shell.sh
new file mode 100644
index 00000000..f38aa0c1
--- /dev/null
+++ b/install/install-login-shell.sh
@@ -0,0 +1,10 @@
+target=install-sh
+case ${SHELL##*/} in
+ bash)
+ target=install-bash ;;
+ ksh|ksh88|ksh93|mksh|pdksh)
+ target=install-ksh ;;
+ zsh)
+ target=install-zsh ;;
+esac
+make "$target"
diff --git a/irssi/aliases b/irssi/aliases
index b22da923..65e80c13 100644
--- a/irssi/aliases
+++ b/irssi/aliases
@@ -10,5 +10,6 @@ alias aesth exec - -out printf %s "$*" | aesth
alias drakon exec - -out printf %s "$*" | drakon
alias kvlt exec - -out printf %s "$*" | kvlt
alias rot13 exec - -out printf %s "$*" | rot13
+alias squ exec - -out printf %s "$*" | squ
alias strik exec - -out printf %s "$*" | strik
alias zs exec - -out printf %s "$*" | zs
diff --git a/keychain/profile.d/keychain.sh b/keychain/profile.d/keychain.sh
new file mode 100644
index 00000000..63eb613a
--- /dev/null
+++ b/keychain/profile.d/keychain.sh
@@ -0,0 +1,5 @@
+# keychain setup
+command -v keychain >/dev/null 2>&1 || return
+eval "$(TERM=${TERM:-ansi} keychain \
+ --eval --ignore-missing --quick --quiet \
+ id_dsa id_rsa id_ecdsa id_ed25519)"
diff --git a/sh/shrc.d/keychain.sh b/keychain/shrc.d/keychain.sh
index d9aaf63f..9a732384 100644
--- a/sh/shrc.d/keychain.sh
+++ b/keychain/shrc.d/keychain.sh
@@ -1,4 +1,4 @@
# If GPG_AGENT_INFO is set, update GPG_TTY for clean use of pinentry(1) etc
[ -n "$GPG_AGENT_INFO" ] || return
-GPG_TTY=$(command -p tty)
+GPG_TTY=$(command -p tty) || return
export GPG_TTY
diff --git a/ksh/kshrc b/ksh/kshrc
index 5d481bb4..43ac14da 100644
--- a/ksh/kshrc
+++ b/ksh/kshrc
@@ -18,7 +18,6 @@ set -o trackall
# Save history
HISTFILE=$HOME/.ksh_history
-HISTSIZE=$((1 << 10))
# Load any supplementary scripts
for kshrc in "$HOME"/.kshrc.d/*.ksh ; do
diff --git a/ksh/kshrc.d/bind.ksh b/ksh/kshrc.d/bind.ksh
index 34cb5f5a..a1999731 100644
--- a/ksh/kshrc.d/bind.ksh
+++ b/ksh/kshrc.d/bind.ksh
@@ -1,28 +1,17 @@
-# Try to bind ^I to complete words and ^L to clear the screen
+# Try to bind tab to complete words and Ctrl-Alt-L to clear the screen
+# Already done in ksh93
case $KSH_VERSION in
- # ksh93 is lovely, but complex; rebind ^L so it does the same as Alt-^L
- *'93'*)
- keybd_trap() {
- # shellcheck disable=SC2154
- case ${.sh.edchar} in
- $'\f') .sh.edchar=$'\e\f' ;;
- esac
- }
- trap keybd_trap KEYBD
- ;;
-
# More straightforward with mksh; bind keys to the appropriate emacs mode
# editing commands
*'MIRBSD KSH'*)
bind '^I'='complete'
- bind '^L'='clear-screen'
;;
# Similar with pdksh; there's a "complete" command, but not a "clear" one,
# so we fake it with clear(1) and some yanking
*'PD KSH'*)
bind '^I'='complete'
- bind -m '^L'='^Uclear^J^Y'
+ bind -m '^[^L'='^Uclear^J^Y'
;;
esac
diff --git a/ksh/kshrc.d/prompt.ksh b/ksh/kshrc.d/prompt.ksh
index 84129efc..c5f3ee1b 100644
--- a/ksh/kshrc.d/prompt.ksh
+++ b/ksh/kshrc.d/prompt.ksh
@@ -15,27 +15,31 @@ function prompt {
# Basic prompt shape depends on whether we're in SSH or not
PS1=
if [[ -n $SSH_CLIENT ]] || [[ -n $SSH_CONNECTION ]] ; then
- PS1=$PS1'$USER@${HOSTNAME%%.*}:'
+ PS1=$PS1'${HOSTNAME%%.*}:'
fi
# Add sub-commands; working directory with ~ abbreviation, VCS, job
# count, and previous command return value
PS1=$PS1'$(ret=$?;jobc=$(jobs -p|sed -n '\''$='\'');prompt pwd;prompt vcs;prompt job;prompt ret;:)'
+ # Add a helpful prefix if this shell appears to be exotic
+ typeset ksh
+ case $KSH_VERSION in
+ (*'93'*) ksh=ksh93 ;;
+ (*'PD KSH'*) ksh=pdksh ;;
+ (*'MIRBSD KSH'*) ksh=mksh ;;
+ esac
+ case ${SHELL##*/} in
+ (''|ksh|"$ksh") ;;
+ (*) PS1=$ksh:$PS1 ;;
+ esac
+
# Add prefix and suffix
PS1='${PROMPT_PREFIX}'$PS1'${PROMPT_SUFFIX}'
# Add terminating "$" or "#" sign
PS1=$PS1'\$'
- # Add > symbols to show nested shells
- typeset shlvl
- shlvl=1
- while ((shlvl < SHLVL)); do
- PS1='>'$PS1
- ((shlvl++))
- done
-
# Declare variables to contain terminal control strings
typeset format reset
@@ -74,12 +78,12 @@ function prompt {
} >/dev/null 2>&1
# Play ball with ksh's way of escaping non-printing characters
- typeset es nl
- es=$(printf '\00')
- nl=$(printf '\n')
+ typeset es cr
+ es=$(printf '\01')
+ cr=$(printf '\r')
# String it all together
- PS1="${es}${nl}${es}${format}${es}${PS1}${es}${reset}${es}"' '
+ PS1="${es}${cr}${es}${format}${es}${PS1}${es}${reset}${es}"' '
PS2='> '
PS3='? '
PS4='+<$?> $LINENO:'
@@ -108,7 +112,7 @@ function prompt {
git describe --tags --exact-match HEAD ||
git rev-parse --short HEAD
) || return
- name=${name##*/}
+ name=${name#refs/*/}
[[ -n $name ]] || return
# Check various files in .git to flag processes
@@ -182,10 +186,13 @@ function prompt {
# Revert to simple inexpensive prompts
off)
- PS1='\$ '
+ PS1='$ '
PS2='> '
PS3='? '
PS4='+ '
+ if [[ -n $SSH_CLIENT || -n $SSH_CONNECTION ]] ; then
+ PS1=$(hostname -s)'$ '
+ fi
;;
# Abbreviated working directory
@@ -225,5 +232,5 @@ function prompt {
esac
}
-# Start with full-fledged prompt
-prompt on
+# Default to a full-featured prompt, but use PROMPT_MODE if that's set
+prompt "${PROMPT_MODE:-on}"
diff --git a/ksh/shrc.d/ksh.sh b/ksh/shrc.d/ksh.sh
index 8e33da7c..b591f37c 100644
--- a/ksh/shrc.d/ksh.sh
+++ b/ksh/shrc.d/ksh.sh
@@ -9,7 +9,7 @@
# makes other shells throw tantrums.
# Does the name of our shell have "ksh" in it at all? This is in no way
-# guaranteed. It's just a heuristic that e.g. Bash and Yash shouldn't pass.
+# guaranteed. It's just a heuristic that e.g. Bash shouldn't pass.
case $0 in
*ksh*) ;;
*) return ;;
@@ -21,15 +21,11 @@ if [ -z "$KSH_VERSION" ] ; then
# Test whether we have content in the .sh.version variable. Suppress errors
# and run it in a subshell to work around parsing error precedence.
- # shellcheck disable=SC2154
( test -n "${.sh.version}" ) 2>/dev/null || return
# If that peculiarly named variable was set, then that's our KSH_VERSION
KSH_VERSION=${.sh.version}
fi
-# If KSH_ENV isn't already set, set it
-[ -n "$KSH_ENV" ] || KSH_ENV=$HOME/.kshrc
-
# If ENV_EXT isn't already set, set it
-[ -n "$ENV_EXT" ] || ENV_EXT=$KSH_ENV
+[ -n "$ENV_EXT" ] || ENV_EXT=$HOME/.kshrc
diff --git a/lint/bash b/lint/bash.sh
index 771f2a89..2fe1ba13 100755..100644
--- a/lint/bash
+++ b/lint/bash.sh
@@ -1,2 +1 @@
-#!/bin/sh
find bash -type f -print -exec shellcheck -e SC1090 -s bash -- {} +
diff --git a/lint/bin b/lint/bin
deleted file mode 100755
index 1130e432..00000000
--- a/lint/bin
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-for bin in bin/* ; do
- [ -f "$bin" ] || continue
- hb=$(sed 1q "$bin") || exit
- case $hb in
- *sh)
- printf '%s\n' "$bin"
- shellcheck -- "$bin"
- ;;
- esac
-done
diff --git a/lint/bin.sh b/lint/bin.sh
new file mode 100644
index 00000000..0fe82d7a
--- /dev/null
+++ b/lint/bin.sh
@@ -0,0 +1 @@
+find bin -type f -name '*.sh' -print -exec shellcheck -e SC1090 -s sh -- {} +
diff --git a/lint/games b/lint/games
deleted file mode 100755
index ef451f4e..00000000
--- a/lint/games
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-for game in games/* ; do
- [ -f "$game" ] || continue
- hb=$(sed 1q "$game") || exit
- case $hb in
- *sh)
- printf '%s\n' "$game"
- shellcheck -- "$game"
- ;;
- esac
-done
diff --git a/lint/games.sh b/lint/games.sh
new file mode 100644
index 00000000..6e3e3024
--- /dev/null
+++ b/lint/games.sh
@@ -0,0 +1 @@
+find games -type f -name '*.sh' -print -exec shellcheck -e SC1090 -s sh -- {} +
diff --git a/lint/ksh b/lint/ksh.sh
index ee49d178..4cedc6f7 100755..100644
--- a/lint/ksh
+++ b/lint/ksh.sh
@@ -1,4 +1,3 @@
-#!/bin/sh
find ksh \
-type f -name '*.sh' -exec shellcheck -e SC1090 -s sh -- {} + -o \
-type f -exec shellcheck -e SC1090 -s ksh -- {} +
diff --git a/lint/sh b/lint/sh
deleted file mode 100755
index 18f2f551..00000000
--- a/lint/sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-find sh -type f -print -exec shellcheck -e SC1090 -s sh -- {} +
diff --git a/lint/sh.sh b/lint/sh.sh
new file mode 100644
index 00000000..89704c0b
--- /dev/null
+++ b/lint/sh.sh
@@ -0,0 +1,6 @@
+find sh \
+ keychain/profile.d keychain/shrc.d \
+ ksh/shrc.d \
+ mpd/profile.d \
+ plenv/profile.d plenv/shrc.d \
+ -type f -print -exec shellcheck -e SC1090 -s sh -- {} +
diff --git a/lint/urxvt b/lint/urxvt.sh
index 9fd6193d..507034be 100755..100644
--- a/lint/urxvt
+++ b/lint/urxvt.sh
@@ -1,2 +1 @@
-#!/bin/sh
find urxvt/ext -type f ! -name '*.pl' -print -exec perlcritic --brutal -- {} \;
diff --git a/lint/xinit.sh b/lint/xinit.sh
new file mode 100644
index 00000000..b5ff6937
--- /dev/null
+++ b/lint/xinit.sh
@@ -0,0 +1 @@
+find X -type f \( -name xinitrc -o -name '*.sh' \) -print -exec shellcheck -e SC1090 -s sh -- {} +
diff --git a/lint/yash b/lint/yash
deleted file mode 100755
index 1397f9f1..00000000
--- a/lint/yash
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-find yash -type f -print -exec shellcheck -e SC1090 -s sh -- {} +
diff --git a/man/man1/bcq.1df b/man/man1/bcq.1df
index 55b44a69..64e2048b 100644
--- a/man/man1/bcq.1df
+++ b/man/man1/bcq.1df
@@ -6,7 +6,7 @@
.B bcq
.SH DESCRIPTION
.B bcq
-starts bc(1), checking ~/.cache/bc/quiet to see if a --quiet option is
+starts bc(1), checking ~/.cache/sh/opt/bc/quiet to see if a --quiet option is
available, adding it if so to elide the annoying GNU boilerplate for an
interactive session.
.SH AUTHOR
diff --git a/man/man1/br.1df b/man/man1/br.1df
index af9645fb..05d662bc 100644
--- a/man/man1/br.1df
+++ b/man/man1/br.1df
@@ -14,9 +14,6 @@ BROWSER=firefox
.B br
just execs the program in the $BROWSER environment variable with the given
arguments. That's it.
-.P
-It was written to have a clean way to launch $BROWSER from ~/.xbindkeysrc. It
-has no other reason to exist.
.SH SEE ALSO
bp(1df), xgo(1df), xgoc(1df)
.SH AUTHOR
diff --git a/man/man1/chn.1df b/man/man1/chn.1df
new file mode 100644
index 00000000..5e9c702d
--- /dev/null
+++ b/man/man1/chn.1df
@@ -0,0 +1,48 @@
+.TH CHN 1df "January 2017" "Manual page for chn"
+.SH NAME
+.B chn
+\- filter standard input through multiple runs of a command
+.SH USAGE
+.B chn
+COUNT
+COMMAND [ARG1...]
+.SH DESCRIPTION
+Run the given command the specified number of times, passing the standard
+output of each run into the standard input of the next.
+.P
+As an example, to quote some text with quo(1df) repeatedly:
+.P
+ $ cat msg
+ Hello!
+ $ chn 2 quo < msg
+ >> Hello!
+ $ chn 5 quo < msg
+ >>>> Hello!
+.P
+Zero is a valid count; in this case the input is passed untouched to output:
+.P
+ $ chn 0 quo < msg
+ Hello!
+.P
+Don't confuse this with simply repeating a command--use rep(1df) for that..
+This happens to do what you might expect:
+.P
+ $ chn 5 sync
+.P
+But this won't:
+.P
+ $ chn 5 echo foo
+.SH CAVEATS
+It's slow.
+.P
+It's not a real pipe. The commands are run successively, not in parallel. That
+means you can't pass one line to it and have it return another line before
+sending EOF, for unbuffered (e.g. linewise) tools.
+.P
+There's almost certainly a better way to do this, fixing one or both of the
+above issues, and possibly even in shell; maybe with curlier file descriptor
+logic to save unneeded open(2) syscalls. I smell `eval` usage on the horizon.
+.SH SEE ALSO
+maybe(1df), rep(1df), try(1df)
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/clog.1df b/man/man1/clog.1df
index 0e3e7b87..43193076 100644
--- a/man/man1/clog.1df
+++ b/man/man1/clog.1df
@@ -13,7 +13,7 @@ getting real tired of all this overengineering
receives a message on stdin, timestamps it with a leading date(1), and writes
it to the file with path in environment variable CLOG, defaulting to ~/.clog,
terminating each entry with two hyphens.
-,P
+.P
If rlwrap(1) is found, it will be used for the line editing. If not, just the
terminal's cooked mode will be used.
.SH AUTHOR
diff --git a/man/man1/csmw.1df b/man/man1/csmw.1df
index e7ef7284..787c2da4 100644
--- a/man/man1/csmw.1df
+++ b/man/man1/csmw.1df
@@ -13,7 +13,8 @@ program |
.B csmw
.SH DESCRIPTION
Reads a list of whitespace-separated words and prints an English
-comma-and-"and" separated list:
+comma-and-"and" separated list, with each word between backticks with the
+expectation it'll be used in Markdown.
.P
$ csmw
foo
diff --git a/man/man1/dam.1df b/man/man1/dam.1df
new file mode 100644
index 00000000..78f5210c
--- /dev/null
+++ b/man/man1/dam.1df
@@ -0,0 +1,16 @@
+.TH DAM 1df "May 2017" "Manual page for dam"
+.SH NAME
+.B dam
+\- read all input before emitting as output
+.SH SYNOPSIS
+prog1 |
+.B
+dam
+| prog2
+.SH DESCRIPTION
+.B dam
+buffers all its input before emitting it as output. Useful if you don't
+actually want a line-by-line flow between programs, such as pasting a complete
+document into a sed(1) pipeline on the terminal.
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/dub.1df b/man/man1/dub.1df
index 52900a36..69a4c8e0 100644
--- a/man/man1/dub.1df
+++ b/man/man1/dub.1df
@@ -15,6 +15,10 @@
lists the biggest entries in a given directory, defaulting to the current
directory. It defaults to printing 10 entries unless a second argument is
given.
+.SH CAVEATS
+Skips filenames with newlines in them with an explicit warning to stderr, for
+the least dangerous POSIX-compatible approach. Even so, you probably shouldn't
+use this in critical scripts.
.SH SEE ALSO
du(1)
.SH AUTHOR
diff --git a/man/man1/edda.1df b/man/man1/edda.1df
index c501e571..0f968d8a 100644
--- a/man/man1/edda.1df
+++ b/man/man1/edda.1df
@@ -3,25 +3,26 @@
.B edda
\- run ed(1) over multiple files
.SH SYNOPSIS
-.B edda FILE1 [FILE2...]
+.B edda
+FILE1 [FILE2...] < script.ed
.SH DESCRIPTION
Duplicate any data on stdin into a temporary file, and run ed(1) options over
each of the files given as arguments. Example:
.P
- $ edda /etc/app.d/*.conf <<'EOF'
- ,s/foo/bar/g
- w
- EOF
+ $ edda /etc/app.d/*.conf <<'EOF'
+ ,s/foo/bar/g
+ w
+ EOF
.SH WISDOM
-"Each man who is wise and would wise be called,
+ Each man who is wise and would wise be called,
.br
- Must ask and answer aright.
+ Must ask and answer aright.
.br
- Let one know thy secret, but never a second;
+ Let one know thy secret, but never a second;
.br
- If three, a thousand shall know."
+ If three, a thousand shall know."
.P
- -- Poetic Edda, Hávamál, 63
+ -- Poetic Edda, Hávamál, 63
.br
.SH SEE ALSO
ed(1)
diff --git a/man/man1/exm.1df b/man/man1/exm.1df
new file mode 100644
index 00000000..25b3cf4a
--- /dev/null
+++ b/man/man1/exm.1df
@@ -0,0 +1,19 @@
+.TH EXM 1df "March 2017" "Manual page for exm"
+.SH NAME
+.B exm
+\- invoke Vim's ex(1) with a dumb terminal
+.SH SYNOPSIS
+.B exm
+[EX_OPTIONS...] [FILES]
+.SH DESCRIPTION
+.B exm
+works around a quirk of Vim that causes it to clear the screen when invoked as
+ex(1) interactively. It applies Vim's -T option to force the terminal to a
+"dumb" terminal.
+.SH CAVEATS
+This breaks switching to visual mode with :visual completely, as the terminal
+will persist in its dumb state. I'm not sure there's a way to fix this. If
+there were a Vim :autocmd for mode switching, it might be possible, or perhaps
+by wrapping :visual somehow to :set terminal=$TERM before the switch.
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/fgscr.1df b/man/man1/fgscr.1df
index 80da3798..cc273b89 100644
--- a/man/man1/fgscr.1df
+++ b/man/man1/fgscr.1df
@@ -5,7 +5,8 @@
.SH SYNOPSIS
.B fgscr
.br
-.B fgscr /path1 /path2
+.B fgscr
+/path1 /path2
.SH DESCRIPTION
.B fgscr
searches for Git repositories recursively with the given ancestor directory
diff --git a/man/man1/fnl.1df b/man/man1/fnl.1df
index 6c34f19c..d085df6b 100644
--- a/man/man1/fnl.1df
+++ b/man/man1/fnl.1df
@@ -1,7 +1,7 @@
.TH FNL 1df "August 2016" "Manual page for fnl"
.SH NAME
.B fnl
-\- list the biggest files in the given directory
+\- run a command and put stdout and stderr into temporary files
.SH SYNOPSIS
.B fnl
command arg1 ...
diff --git a/man/man1/fnp.1df b/man/man1/fnp.1df
new file mode 100644
index 00000000..dc8a07c4
--- /dev/null
+++ b/man/man1/fnp.1df
@@ -0,0 +1,24 @@
+.TH FNP 1df "June 2017" "Manual page for fnp"
+.SH NAME
+.B fnp
+\- print input with filename headings
+.SH SYNOPSIS
+.B fnp
+FILE1 [FILE2...]
+.br
+prog1 |
+.B
+fnp
+.br
+prog1 |
+.B
+fnp
+FILE1 - FILE2
+.SH DESCRIPTION
+.B fnp
+prints concatenated standard input from files to standard output, prepending a
+filename title with an underline made of hyphen characters to each one.
+.SH SEE ALSO
+p(1df), pp(1df), pph(1df)
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/grec.1df b/man/man1/grec.1df
new file mode 100644
index 00000000..b1f70193
--- /dev/null
+++ b/man/man1/grec.1df
@@ -0,0 +1,14 @@
+.TH GREC 1df "April 2017" "Manual page for grec"
+.SH NAME
+.B grec
+\- saner name for grep -c
+.SH SYNOPSIS
+.B grec
+PATTERN [FILE...]
+.br
+.SH DESCRIPTION
+.B grec
+is the same as grep(1) when run with a a -c option, because the name always
+bugged me a bit--"g/re/p, except don't print it, count it"?
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/gred.1df b/man/man1/gred.1df
new file mode 100644
index 00000000..e3dbce87
--- /dev/null
+++ b/man/man1/gred.1df
@@ -0,0 +1,14 @@
+.TH GRED 1df "April 2017" "Manual page for gred"
+.SH NAME
+.B gred
+\- saner name for grep -v
+.SH SYNOPSIS
+.B gred
+PATTERN [FILE...]
+.br
+.SH DESCRIPTION
+.B gred
+is the same as grep(1) when run with a a -v option, because the name always
+bugged me a bit--"g/re/p, except don't print it, delete it"?
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/hms.1df b/man/man1/hms.1df
new file mode 100644
index 00000000..5c1a287c
--- /dev/null
+++ b/man/man1/hms.1df
@@ -0,0 +1,23 @@
+.TH HMS 1df "February 2017" "Manual page for hms"
+.SH NAME
+.B hms
+\- convert seconds to colon-delimited durations
+.SH USAGE
+.B hms
+FILE1 [FILE2 ...]
+.br
+.B hms
+< FILE
+.br
+printf '1:02:54\\n' |
+.B hms
+.br
+hms=$(printf '%s\\n' "$seconds" | hms)
+.SH DESCRIPTION
+Applies awk(1) to convert counts of seconds into hh:mm:ss or mm:ss timestamps.
+Exits zero if all lines were successfully recognised and converted, non-zero
+otherwise.
+.SH SEE ALSO
+sec(1df)
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/htref.1df b/man/man1/htref.1df
new file mode 100644
index 00000000..922188dc
--- /dev/null
+++ b/man/man1/htref.1df
@@ -0,0 +1,20 @@
+.TH HTREF 1df "January 2017" "Manual page for htref"
+.SH NAME
+.B htref
+\- turn URLs into HTML links
+.SH SYNOPSIS
+htenc urls |
+.B htref
+| nlbr > urls.html
+.SH DESCRIPTION
+.B htref
+looks for http:// and https:// URLs, and wraps <a href="..."> tags around them
+pointing to the same URL. HTML encoding of the URL should be done before this
+step.
+.P
+All characters that are not spaces, tabs, or angle brackets are included in the
+URL.
+.SH SEE ALSO
+htenc(1df)
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/maybe.1df b/man/man1/maybe.1df
index e313eb17..a8658c71 100644
--- a/man/man1/maybe.1df
+++ b/man/man1/maybe.1df
@@ -15,13 +15,13 @@ Like true(1) or false(1), but exits with success randomly with a given
probability. Good for using in tests. Exits with 2 rather than 1 on usage
errors.
.P
-The numerator default to 1 and the denominator to 2 for a roughly equal chance
+The numerator defaults to 1 and the denominator to 2 for a roughly equal chance
of success or failure. rndi(1df) is used for the randomness.
.P
$ maybe
$ maybe 3
$ maybe 2 5
.SH SEE ALSO
-true(1), false(1), try(1df), rndi(1df)
+true(1), false(1), chn(1df), try(1df), rndi(1df)
.SH AUTHOR
Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/mex.1df b/man/man1/mex.1df
index 0fa584da..5c387594 100644
--- a/man/man1/mex.1df
+++ b/man/man1/mex.1df
@@ -10,12 +10,13 @@ name
name1 name2 name3
.br
PATH=/foo:/bar/baz
+.B mex
name
.SH DESCRIPTION
-Iterate through the contents of the PATH variable looking for files with any of
+Iterate through the directories named in $PATH looking for files with any of
the specified names that do not have the executable permissions bit set, and
-try to set it if found. Exit nonzero if any of the names were not found, or if
-any of the permissions changes failed.
+attempt to set them if any such files are found. Exit nonzero if any of the
+names were not found, or if any of the permissions changes failed.
.SH SEE ALSO
chmod(1), eds(1df)
.SH AUTHOR
diff --git a/man/man1/mi5.1df b/man/man1/mi5.1df
new file mode 100644
index 00000000..53d98bf1
--- /dev/null
+++ b/man/man1/mi5.1df
@@ -0,0 +1,70 @@
+.TH MI5 1df "June 2017" "Manual page for mi5"
+.SH NAME
+.B mi5
+\- m4 inverted preprocessor
+.SH SYNOPSIS
+.B mi5
+FILE > out.m4
+.br
+.B mi5
+open='{{{' shut='}}}' FILE > out.m4
+.br
+.B mi5
+FILE1 FILE2 > out.m4
+.br
+prog |
+.B mi5
+> out.m4
+.br
+.SH DESCRIPTION
+.B mi5
+is a simple and crude m4 preprocessor to make using m4 slightly more bearable
+and predictable for its author, who wants badly to like m4 but doesn't. It's
+primarily intended for situations where the majority of a file is simple static
+text, and only a few simple macros need to be defined and expanded, which
+covers almost every usage case for the author. It's written to work with any
+POSIX awk and to generate output for any POSIX m4.
+.P
+mi5 inverts m4's usual approach by approaching most of the file as if it were
+part of an m4 quote, with <% and %> as the (default) delimiters to specify
+markers in which macro expansion should occur. This is therefore a way to
+shoehorn m4 into working in a way reminiscent of templating libraries or
+languages like PHP.
+.P
+Macros can be expanded as blocks:
+.P
+ <%
+
+ define(`FOO', `bar')
+ define(`BAZ', include(`include/quux.inc'))
+
+ %>
+.P
+For this format, `dnl' macros to delete newlines for each declaration are
+inserted for you. Blank lines are skipped, and leading and trailing spaces are
+ignored. The above code therefore produces no actual output, as it only has two
+define calls.
+.P
+For inline expansion, the syntax is similar, but the behaviour slightly different:
+.P
+ The value of the FOO macro is <% FOO %>.
+.P
+Spaces immediately after the opening delimiter and before the closing delimiter
+are ignored, but spaces produced within the macro are preserved. `dnl` macros
+are not inserted for inline blocks.
+.P
+Ideally, you do your complex macro definition in a block at the top of your
+file, and your simple macro expansion of those results in an inline.
+.SH CAVEATS
+There's no way to escape the delimiters.
+.P
+Inline expansions cannot span multiple lines. Use blocks for that.
+.P
+Doesn't cope at all with `changequote'. If you need to specify different ones
+from this tool's point of view, you can change the "quote" and "unquote" vars
+in the same way as "open" and "shut", but if you're getting to that point then
+you should probably write raw m4.
+.SH SEE ALSO
+m4(1)
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/murl.1df b/man/man1/murl.1df
index f022152b..088158b0 100644
--- a/man/man1/murl.1df
+++ b/man/man1/murl.1df
@@ -4,7 +4,7 @@
\- convert Markdown to HTML with pandoc(1) and extract URLs from it with hurl(1df)
.SH SYNOPSIS
.B murl
-README.markdown
+README.md
.br
.B murl
page1.md page2.md
diff --git a/man/man1/mw.1df b/man/man1/mw.1df
new file mode 100644
index 00000000..51623600
--- /dev/null
+++ b/man/man1/mw.1df
@@ -0,0 +1,25 @@
+.TH MW 1df "May 2017" "Manual page for mw"
+.SH NAME
+.B mw
+\- get space-delimited alphabetic words from input, one per line
+.SH SYNOPSIS
+.B mw FILE1
+[FILE2...]
+.br
+prog1 |
+.B mw
+.SH DESCRIPTION
+.B mw
+separates the input into space-delimited words and prints them one per line,
+with no deduplication or sorting. It's a fairly naïve approach to the problem
+but it works fine as a crude initial approach.
+.SH NOTES
+This was written after watching that lovely old AT&T video where members of the
+Unix team (specifically Brian Kernighan and Lorinda Cherry) demonstrate piping
+programs together; Kernighan demonstrates `makewords` during his example.
+.P
+<https://www.youtube.com/watch?v=tc4ROCJYbm0&t=5m30s>
+.SH SEE ALSO
+ddup(1df), sort(1), uniq(1)
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/oii.1df b/man/man1/oii.1df
new file mode 100644
index 00000000..f5bb2678
--- /dev/null
+++ b/man/man1/oii.1df
@@ -0,0 +1,21 @@
+.TH OII 1df "June 2017" "Manual page for oii"
+.SH NAME
+.B oii
+\- run a command on input only if there's at least one byte of input
+.SH USAGE
+.B oii
+CMD [ARGS ...] < file
+.br
+program |
+.B oii
+CMD [ARGS ...]
+.SH DESCRIPTION
+Run the given program passing in stdin but only if at least one byte of input
+is actually received, rather like the -E switch to mail(1) behaves on
+bsd-mailx. If no input is received, exit silently with an error status.
+.SH CAVEATS
+It's slow, and doesn't work as a pipe. The entire input is written to disk and
+then tested for filesize before being re-emitted. There's almost certainly a
+more efficient way to do this while still remaining byte-safe.
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/osc.1df b/man/man1/osc.1df
new file mode 100644
index 00000000..9fb61dde
--- /dev/null
+++ b/man/man1/osc.1df
@@ -0,0 +1,22 @@
+.TH OSC 1df "February 2017" "Manual page for osc"
+.SH NAME
+.B osc
+\- netcat-like wrapper for openssl s_client
+.SH SYNOPSIS
+.B osc [HOST [SERVICE]]
+.SH DESCRIPTION
+.B osc
+runs openssl(1ssl)'s s_client subcommand with some options to make it behave a
+bit like netcat(1), quieting errors and even handling STARTTLS if it knows how,
+but still forcing correct verification of certificates and only connecting with
+TLS (not SSL).
+.P
+If rlwrap(1) is available, the client will be run within that to allow line
+editing.
+.P
+It's intended to be run as an interactive tool for cases where you want to
+focus more on debugging the data exchange with the actual server, and not
+debugging the OpenSSL negotiation itself. The author finds it handy for poking
+his STARTTLS SMTP mailserver.
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/p.1df b/man/man1/p.1df
new file mode 100644
index 00000000..2f9f3c45
--- /dev/null
+++ b/man/man1/p.1df
@@ -0,0 +1,44 @@
+.TH P 1df "May 2017" "Manual page for p"
+.SH NAME
+.B p
+\- print standard input to standard output
+.SH SYNOPSIS
+.B p
+FILE1 [FILE2...]
+.br
+prog1 |
+.B
+p
+.br
+prog1 |
+.B
+p
+FILE1 - FILE2
+.SH DESCRIPTION
+.B p
+prints concatenated standard input from files to standard output, and nothing
+else; cat(1) as it always should have been--no flags, and hence no need for
+end-of-options for filenames that start with a dash.
+.P
+Quicker to type, too.
+.P
+Still treats an "-" argument as a shorthand for "standard input" though,
+because I like that and it's POSIX.
+.SH POETRY
+ "Prophet!" said I, "thing of evil!--prophet still, if bird or devil!--
+.br
+ Whether Tempter sent, or whether tempest tossed thee here ashore,
+.br
+ Desolate yet all undaunted, on this desert land enchanted--
+.br
+ On this home by Horror haunted--tell me truly, I implore--
+.br
+ Is there--is there balm in Gilead?--tell me--tell me, I implore!"
+.br
+ Quoth the Raven "Nevermore."
+.P
+ -- Poe
+.SH SEE ALSO
+cat(1)
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/ped.1df b/man/man1/ped.1df
new file mode 100644
index 00000000..fba85943
--- /dev/null
+++ b/man/man1/ped.1df
@@ -0,0 +1,19 @@
+.TH PED 1df "May 2017" "Manual page for ped"
+.SH NAME
+.B ped
+\- stop a pipe for $EDITOR intervention
+.SH SYNOPSIS
+prog1 |
+.B
+ped
+| prog2
+.SH DESCRIPTION
+.B ped
+saves all its standard input into a temporary file and runs $EDITOR, or ed(1)
+if unset, on that file. Once the editor exits, it emits the contents of the
+same file (changed or unchanged). This can be used as a way to edit data
+manually as it goes through a pipe.
+.SH SEE ALSO
+pst(1df), pvi(1df)
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/pp.1df b/man/man1/pp.1df
index 322e7b48..0bb55cd1 100644
--- a/man/man1/pp.1df
+++ b/man/man1/pp.1df
@@ -15,5 +15,7 @@ The path need not actually exist.
Newlines in filenames will still work, but the results won't really make sense
as they'll be indistinguishable from newlines separating the files. This is for
generating human-readable file lists, not for machines.
+.SH SEE ALSO
+pph(1df)
.SH AUTHOR
Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/pph.1df b/man/man1/pph.1df
index 0ad98fc5..f68b394d 100644
--- a/man/man1/pph.1df
+++ b/man/man1/pph.1df
@@ -1,9 +1,9 @@
-.TH PPH 1df "January 2017" "Manual page for pp"
+.TH PPH 1df "January 2017" "Manual page for pph"
.SH NAME
-.B pp
+.B pph
\- print the full path to each argument, hostname prepended
.SH SYNOPSIS
-.B pp
+.B pph
/arg arg2 ./arg3
.SH DESCRIPTION
.B pph
@@ -12,5 +12,7 @@ prepends the machine's hostname and a colon to each line.
.SH CAVEATS
Newlines in filenames will mess this up. This is for generating human-readable
file lists, not for machines.
+.SH SEE ALSO
+pp(1df)
.SH AUTHOR
Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/pst.1df b/man/man1/pst.1df
new file mode 100644
index 00000000..cf3ce281
--- /dev/null
+++ b/man/man1/pst.1df
@@ -0,0 +1,25 @@
+.TH PST 1df "May 2017" "Manual page for pst"
+.SH NAME
+.B pst
+\- stop a pipe for manual viewing or intervention
+.SH SYNOPSIS
+prog1 |
+.B
+pst
+| prog2
+.br
+prog1 |
+.B
+pst ed
+| prog2
+.SH DESCRIPTION
+.B pst
+saves all its standard input into a temporary file and runs the interactive
+command given, defaulting to a suitable pager, and then emits the contents of
+the same file (changed or unchanged) after the program exits. This can be used
+as a way to watch the progress of data as it goes through the pipe, or to
+manually edit it.
+.SH SEE ALSO
+ped(1df), pvi(1df)
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/pvi.1df b/man/man1/pvi.1df
new file mode 100644
index 00000000..6a21e6e8
--- /dev/null
+++ b/man/man1/pvi.1df
@@ -0,0 +1,19 @@
+.TH PVI 1df "May 2017" "Manual page for pvi"
+.SH NAME
+.B pvi
+\- stop a pipe for $EDITOR intervention
+.SH SYNOPSIS
+prog1 |
+.B
+pvi
+| prog2
+.SH DESCRIPTION
+.B pvi
+saves all its standard input into a temporary file and runs $VISUAL, or vi(1)
+if unset, on that file. Once the editor exits, it emits the contents of the
+same file (changed or unchanged). This can be used as a way to edit data
+manually as it goes through a pipe.
+.SH SEE ALSO
+pst(1df), ped(1df)
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/quo.1df b/man/man1/quo.1df
new file mode 100644
index 00000000..56cf685a
--- /dev/null
+++ b/man/man1/quo.1df
@@ -0,0 +1,25 @@
+.TH QUO 1df "January 2017" "Manual page for quo"
+.SH NAME
+.B quo
+\- quote the input with right-angle brackets
+.SH SYNOPSIS
+.B quo
+.br
+Text on standard input.
+.br
+^D
+.br
+.B quo
+FILE1 [FILE2...]
+.br
+.B quo
+< FILE
+.SH DESCRIPTION
+.B quo
+quotes its input by inserting a right-angle bracket followed by a space at the
+start of every unquoted line. If the line was already quoted, it adds another
+level of right-angle brackets.
+.SH SEE ALSO
+wro(1df)
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/rep.1df b/man/man1/rep.1df
new file mode 100644
index 00000000..8971f392
--- /dev/null
+++ b/man/man1/rep.1df
@@ -0,0 +1,15 @@
+.TH REP 1df "August 2017" "Manual page for rep"
+.SH NAME
+.B rep
+\- run a command repeatedly
+.SH USAGE
+.B rep
+COUNT
+COMMAND [ARG1...]
+.SH DESCRIPTION
+Run the given command the specified number of times. Zero is a valid count;
+nothing happens.
+.SH SEE ALSO
+chn(1df), maybe(1df), try(1df), watch(1)
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/rndi.1df b/man/man1/rndi.1df
index 767ad148..e9588ab7 100644
--- a/man/man1/rndi.1df
+++ b/man/man1/rndi.1df
@@ -5,20 +5,15 @@
.SH SYNOPSIS
.B rndi
0 10
-.br
-.B rndi
-0 10 "$(rnds)"
.SH DESCRIPTION
.B rndi
returns a random integer ranging from the first argument to the second argument
-in a POSIX-compliant way (using awk), using the optional third argument as a
-seed.
+in a POSIX-compliant way (using awk), using rnds(1df) if available for a seed.
.P
-The answer returned is low-quality; given some implementations of awk and no
-properly random seed, it may even return the same result if run within the same
-second. This should not be used in any sort of security or statistical context.
-The author wrote it to support scripts to choose a random background image from
-a directory.
+The answer returned is low-quality; on some platforms, it may even return the
+same result if run within the same second. This should not be used in any sort
+of security or statistical context. The author wrote it to support scripts to
+choose a random background image from a directory.
.SH SEE ALSO
rnda(1df), rndf(1df), rndl(1df), rnds(1df), rndn(6df)
.SH AUTHOR
diff --git a/man/man1/rndl.1df b/man/man1/rndl.1df
index ec44564a..0e952724 100644
--- a/man/man1/rndl.1df
+++ b/man/man1/rndl.1df
@@ -13,7 +13,7 @@ command |
.B rndl
.SH DESCRIPTION
.B rndl
-prints a random line from its input, using rndi(1df) to choose it. This is
+prints a random line from its input, using rnds(1df) as a seed. This is
probably not a high-quality source, but should differ within seconds and
between runs on most systems.
.SH SEE ALSO
diff --git a/man/man1/sec.1df b/man/man1/sec.1df
index 589b6a74..d0011b38 100644
--- a/man/man1/sec.1df
+++ b/man/man1/sec.1df
@@ -10,12 +10,14 @@ FILE1 [FILE2 ...]
< FILE
.br
printf '1:02:54\\n' |
-.br
-sec=$(printf '%s\n' "$timestamp" | sec)
.B sec
+.br
+sec=$(printf '%s\\n' "$timestamp" | sec)
.SH DESCRIPTION
Applies awk(1) to convert hh:mm:ss or mm:ss timestamps into a count of seconds.
Exits zero if all lines were successfully recognised and converted, non-zero
otherwise.
+.SH SEE ALSO
+hms(1df)
.SH AUTHOR
Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/shb.1df b/man/man1/shb.1df
index 1970dbde..a1cb884a 100644
--- a/man/man1/shb.1df
+++ b/man/man1/shb.1df
@@ -4,20 +4,16 @@
\- insert a shebang line above a file
.SH SYNOPSIS
.B shb
-script bash
+bash < foo.bash > foo
.br
+cat *.sed |
.B shb
-script sed -f
-.br
-command |
-.B shb
-- awk -f
+sed -f > sedbatch
.SH DESCRIPTION
.B shb
-searches the system paths to find a suitable program with the name given in the
-second argument, forms a "shebang" line from it and any arguments beyond the
-second, and then emits the contents of the first argument ('-' can be used for
-stdin).
+searches the system paths to find a suitable program with the name given in its
+first argument, forms a "shebang" line from it and any remaining arguments, and
+then emits the contents of stdin.
.P
This is intended as a minimal way to make portable shebang lines for Makefiles
or other building or installation frameworks, handling subtleties like sed(1)
diff --git a/man/man1/swr.1df b/man/man1/swr.1df
index 8792b0ed..4c40a6f0 100644
--- a/man/man1/swr.1df
+++ b/man/man1/swr.1df
@@ -1,7 +1,7 @@
.TH SWR 1df "January 2017" "Manual page for swr"
.SH NAME
.B swr
-\- run a command including remote file arguments for scp(1) retrieval
+\- run a command including remote file arguments for scp(1) reading
.SH SYNOPSIS
.B swr
cat remote:.ssh/authorized_keys
@@ -18,6 +18,9 @@ circumstances.
This even works for the first argument (i.e. the command), provided that it
will run on the local system once copied in.
.SH CAVEATS
+You can't write to remote files with it. The arguments only work as input
+streams, so e.g. "cp .vimrc remote:.vimrc" won't do what you expect.
+.P
This only works for simple commands; you can't put shell syntax into any of the
arguments.
.P
diff --git a/man/man1/tl.1df b/man/man1/tl.1df
index eee3bc98..0c686b8b 100644
--- a/man/man1/tl.1df
+++ b/man/man1/tl.1df
@@ -3,7 +3,8 @@
.B tl
\- tag lines with a string prefix and/or suffix
.SH USAGE
-.B tl [-p PREFIX] [-s SUFFIX] [--] [FILE1 FILE2 ...]
+.B tl
+[-p PREFIX] [-s SUFFIX] [--] [FILE1 FILE2 ...]
.SH DESCRIPTION
Tag lines from files or stdin with a string prefix or suffix before writing
them to stdout. Specifying neither prefix nor suffix is acceptable, in which
diff --git a/man/man1/tm.1df b/man/man1/tm.1df
new file mode 100644
index 00000000..125d69c1
--- /dev/null
+++ b/man/man1/tm.1df
@@ -0,0 +1,12 @@
+.TH TM 1df "January 2017" "Manual page for tm"
+.SH NAME
+.B tm
+\- tmux shortcut
+.SH SYNOPSIS
+.B tm
+.SH DESCRIPTION
+If arguments are given, pass them to tmux(1) unchanged. If not, check if a tmux
+session exists; if it does, attach to it. If not, create a new session with
+name given in environment variable $TMUX_SESSION, default "default".
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/trs.1df b/man/man1/trs.1df
new file mode 100644
index 00000000..93b2cad3
--- /dev/null
+++ b/man/man1/trs.1df
@@ -0,0 +1,25 @@
+.TH TRS 1df "May 2017" "Manual page for trs"
+.SH NAME
+.B trs
+\- string version of tr(1)
+.SH SYNOPSIS
+.B trs
+STRING REPLACEMENT
+< file
+.br
+program |
+.B trs
+STRING REPLACEMENT
+.SH DESCRIPTION
+.B trs
+replaces the string given in its first argument with the string given in its
+second, with no regex metacharacters, in a way that should work on all POSIX
+implementations. It is thereby the string complement for tr(1).
+.P
+The first argument cannot be a null string. The second argument can be blank
+(but must still be specified) to implicitly delete all occurrences of the
+string.
+.SH CAVEATS
+It can't replace newlines.
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/try.1df b/man/man1/try.1df
index d982c1d3..63db5209 100644
--- a/man/man1/try.1df
+++ b/man/man1/try.1df
@@ -17,6 +17,6 @@ run.
$ try maybe
$ try -n5 -s10 gms
.SH SEE ALSO
-maybe(1df)
+maybe(1df), chn(1df)
.SH AUTHOR
Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/wro.1df b/man/man1/wro.1df
new file mode 100644
index 00000000..dc64046b
--- /dev/null
+++ b/man/man1/wro.1df
@@ -0,0 +1,24 @@
+.TH WRO 1df "January 2017" "Manual page for wro"
+.SH NAME
+.B wro
+\- add a quote header to the standard input
+.SH SYNOPSIS
+$
+.B wro
+luser@example.com < file
+.br
+$
+.B wro
+luser@example.com '2017-01-15 9:00am'
+.br
+Text on standard input.
+.br
+^D
+.SH DESCRIPTION
+.B wro
+adds an email-style quote lead-in to its standard input. It's intended to
+receive input from quo(1df).
+.SH SEE ALSO
+quo(1df)
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/xrbg.1df b/man/man1/xrbg.1df
new file mode 100644
index 00000000..481c9185
--- /dev/null
+++ b/man/man1/xrbg.1df
@@ -0,0 +1,19 @@
+.TH XRBG 1df "March 2016" "Manual page for xrbg"
+.SH NAME
+.B xrbg
+\- apply a random X background image with feh(1)
+.SH SYNOPSIS
+.B xrbg
+.br
+XBACKGROUNDS=/path/to/images
+.B xrbg
+.SH DESCRIPTION
+.B xrbg
+searches for images in the directory named in the XBACKGROUNDS environment
+variable (defaults to ~/.xbackgrounds), chooses a random one with rndf(1df),
+and applies it with feh(1). It's designed for use in ~/.xinitrc, but it seems
+to work when called manually from within an X session too.
+.SH SEE ALSO
+feh(1), rndf(1df)
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/xrq.1df b/man/man1/xrq.1df
new file mode 100644
index 00000000..d0bdeeb3
--- /dev/null
+++ b/man/man1/xrq.1df
@@ -0,0 +1,16 @@
+.TH XRQ 1df "January 2017" "Manual page for xrq"
+.SH NAME
+.B xrq
+\- query X resource values
+.SH SYNOPSIS
+.B xrq
+Xft.hintstyle
+.br
+.B xrq
+URxvt.color0 URxvt.color9
+.SH DESCRIPTION
+.B xrq
+runs xrdb(1) with the -query option and filters for the values of the named
+keys. It exits successfully if at least one of the named keys was found.
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man6/philsay.6df b/man/man6/philsay.6df
new file mode 100644
index 00000000..4de7c476
--- /dev/null
+++ b/man/man6/philsay.6df
@@ -0,0 +1,28 @@
+.TH PHILSAY 6df "July 2017" "Manual page for philsay"
+.SH NAME
+.B philsay
+\- Ha, ha, ha! ASCII art!
+.SH USAGE
+.B philsay
+.br
+.B philsay
+FILE1 FILE2
+.br
+program |
+.B philsay
+-
+.br
+DICT=$HOME/dict
+.B philsay
+.SH DESCRIPTION
+.B philsay
+shows a picture of our founder, Phil Ken Sebben, saying the first word of a
+line randomly chosen from the input using pks(6df).
+.P
+A hyphen character "-" can be given as an argument to select standard input.
+.SH SEE ALSO
+pks(6df), cowsay(1df)
+.br
+<https://www.youtube.com/watch?v=F8ID1KJQxB8>
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man6/pks.6df b/man/man6/pks.6df
new file mode 100644
index 00000000..dc430eff
--- /dev/null
+++ b/man/man6/pks.6df
@@ -0,0 +1,29 @@
+.TH PKS 6df "July 2017" "Manual page for pks"
+.SH NAME
+.B pks
+\- select and laugh at a random word from a system dictionary or fileset
+.SH USAGE
+.B pks
+.br
+.B pks
+FILE1 FILE2
+.br
+program |
+.B pks
+-
+.br
+DICT=$HOME/dict
+.B pks
+.SH DESCRIPTION
+.B pks
+picks the first word from a random line on a set of files and laughs at it. If
+no files are given, it defaults to /usr/share/dict/words, or the value of DICT
+(ha, ha!) if specified in the environment.
+.P
+A hyphen character "-" can be given as an argument to select standard input.
+.SH SEE ALSO
+philsay(6df)
+.br
+<https://www.youtube.com/watch?v=F8ID1KJQxB8>
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man6/squ.6df b/man/man6/squ.6df
new file mode 100644
index 00000000..f836f2cd
--- /dev/null
+++ b/man/man6/squ.6df
@@ -0,0 +1,30 @@
+.TH SQU 6df "May 2017" "Manual page for squ"
+.SH NAME
+.B squ
+\- print a reduced Latin square made out of each line of input
+.SH USAGE
+.B squ
+.br
+london
+.br
+^D
+.br
+L O N D O N
+.br
+O N D O N L
+.br
+N D O N L O
+.br
+D O N L O N
+.br
+O N L O N D
+.br
+N L O N D O
+.SH DESCRIPTION
+.B squ
+makes a reduced Latin square [1] out of the characters on each line of input,
+uppercasing them first.
+.SH SEE ALSO
+[1]: https://en.wikipedia.org/wiki/Latin_square#Reduced_form
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man6/strik.6df b/man/man6/strik.6df
index 3d5840a7..92b92074 100644
--- a/man/man6/strik.6df
+++ b/man/man6/strik.6df
@@ -10,10 +10,10 @@ lynx -dump https://sanctum.geek.nz/ |
.B strik
.SH DESCRIPTION
.B strik
-converts the 26 letters of the English alphabet, both upper and lower case, the
-Arabic numerals, and the space character to their equivalents with a Unicode
-strikethrough.
-.P
-The results are printed in UTF-8; they're hard-coded within the script.
+adds a Unicode combining strikethrough character COMBINING LONG STROKE OVERLAY
+(U+0036) after each character of input, giving the appearance of struck-out
+text with appropriate glyph support.
+.SH SEE ALSO
+<http://www.fileformat.info/info/unicode/char/0036/index.htm>
.SH AUTHOR
Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man7/dotfiles.7df b/man/man7/dotfiles.7df
new file mode 100644
index 00000000..5538fdd2
--- /dev/null
+++ b/man/man7/dotfiles.7df
@@ -0,0 +1,947 @@
+.\" Automatically generated by Pandoc 1.17.2
+.\"
+.TH "DOTFILES" "7" "June 2016" "Tom Ryder's personal scripts and configuration" ""
+.hy
+.SH Dotfiles (Tom Ryder)
+.PP
+This is my personal repository of configuration files and scripts for
+\f[C]$HOME\f[], including most of the settings that migrate well between
+machines.
+.PP
+This repository began as a simple way to share Vim and tmux
+configuration, but over time a lot of scripts and shell configuration
+have been added, making it into a personal suite of custom Unix tools.
+.SS Installation
+.IP
+.nf
+\f[C]
+$\ git\ clone\ https://sanctum.geek.nz/code/dotfiles.git\ ~/.dotfiles
+$\ cd\ ~/.dotfiles
+$\ git\ submodule\ init
+$\ git\ submodule\ update
+$\ make
+$\ make\ \-n\ install
+$\ make\ install
+\f[]
+.fi
+.PP
+For the default \f[C]all\f[] target, you'll need a POSIX\-fearing
+userland, including \f[C]make(1)\f[] and \f[C]m4(1)\f[].
+.PP
+The installation \f[C]Makefile\f[] will overwrite things standing in the
+way of its installed files without backing them up, so read the output
+of \f[C]make\ \-n\ install\f[] before running \f[C]make\ install\f[] to
+make sure you aren't going to lose anything unexpected.
+If you're still not sure, install it in a temporary directory so you can
+explore:
+.IP
+.nf
+\f[C]
+$\ tmpdir=$(mktemp\ \-d)
+$\ make\ install\ HOME="$tmpdir"
+$\ env\ \-i\ HOME="$tmpdir"\ TERM="$TERM"\ "$SHELL"\ \-l
+\f[]
+.fi
+.PP
+The default \f[C]install\f[] target will install these targets and all
+their dependencies.
+Note that you don't actually have to have any of this except \f[C]sh\f[]
+installed.
+.IP \[bu] 2
+\f[C]install\-bin\f[]
+.IP \[bu] 2
+\f[C]install\-bin\-man\f[]
+.IP \[bu] 2
+\f[C]install\-curl\f[]
+.IP \[bu] 2
+\f[C]install\-ex\f[]
+.IP \[bu] 2
+\f[C]install\-git\f[]
+.IP \[bu] 2
+\f[C]install\-gnupg\f[]
+.IP \[bu] 2
+\f[C]install\-less\f[]
+.IP \[bu] 2
+\f[C]install\-login\-shell\f[]
+.IP \[bu] 2
+\f[C]install\-readline\f[]
+.IP \[bu] 2
+\f[C]install\-vim\f[]
+.PP
+The \f[C]install\-login\-shell\f[] looks at your \f[C]SHELL\f[]
+environment variable and tries to figure out which shell's configuration
+files to install, falling back on \f[C]install\-sh\f[].
+.PP
+The remaining dotfiles can be installed with the other
+\f[C]install\-*\f[] targets.
+Try \f[C]awk\ \-f\ bin/mftl.awk\ Makefile\f[] in the project's root
+directory to see a list.
+.SS Tools
+.PP
+Configuration is included for:
+.IP \[bu] 2
+Bourne\-style POSIX shells, sharing a \f[C]\&.profile\f[], an
+\f[C]ENV\f[] file, and some helper functions:
+.RS 2
+.IP \[bu] 2
+GNU Bash (https://www.gnu.org/software/bash/) (2.05a or higher)
+.IP \[bu] 2
+Korn shell (http://www.kornshell.com/) (\f[C]ksh93\f[], \f[C]pdksh\f[],
+\f[C]mksh\f[])
+.IP \[bu] 2
+Z shell (https://www.zsh.org/)
+.RE
+.IP \[bu] 2
+Abook (http://abook.sourceforge.net/) \[en] curses address book program
+.IP \[bu] 2
+cURL (https://curl.haxx.se/) \[en] Command\-line tool for transferring
+data with URL syntax
+.IP \[bu] 2
+Dunst (http://knopwob.org/dunst/) \[en] A lightweight X11 notification
+daemon that works with \f[C]libnotify\f[]
+.IP \[bu] 2
+\f[C]finger(1)\f[] \[en] User information lookup program
+.IP \[bu] 2
+Git (https://git-scm.com/) \[en] Distributed version control system
+.IP \[bu] 2
+GnuPG (https://www.gnupg.org/) \[en] GNU Privacy Guard, for private
+communication and file encryption
+.IP \[bu] 2
+GTK+ (https://www.gtk.org/) \[en] GIMP Toolkit, for graphical user
+interface elements
+.IP \[bu] 2
+i3 (https://i3wm.org/) \[en] Tiling window manager
+.IP \[bu] 2
+less (https://www.gnu.org/software/less/) \[en] Terminal pager
+.IP \[bu] 2
+Mutt (http://www.mutt.org/) \[en] Terminal mail user agent
+.IP \[bu] 2
+\f[C]mysql(1)\f[] (https://linux.die.net/man/1/mysql) \[en]
+Command\-line MySQL client
+.IP \[bu] 2
+Ncmpcpp (https://rybczak.net/ncmpcpp/) \[en] ncurses music player client
+.IP \[bu] 2
+Newsbeuter (https://www.newsbeuter.org/) \[en] Terminal RSS/Atom feed
+reader
+.IP \[bu] 2
+\f[C]psql(1)\f[] (https://linux.die.net/man/1/psql) \[en] Command\-line
+PostgreSQL client
+.IP \[bu] 2
+Perl::Critic (http://perlcritic.com/) \[en] static source code analysis
+engine for Perl
+.IP \[bu] 2
+Perl::Tidy (http://perltidy.sourceforge.net/) \[en] Perl indenter and
+reformatter
+.IP \[bu] 2
+Readline (https://cnswww.cns.cwru.edu/php/chet/readline/rltop.html)
+\[en] GNU library for user input used by Bash, MySQL, and others
+.IP \[bu] 2
+rxvt\-unicode (http://software.schmorp.de/pkg/rxvt-unicode.html) \[en]
+Fork of the rxvt terminal emulator with Unicode support
+.IP \[bu] 2
+Subversion (https://subversion.apache.org/) \[en] Apache Subversion, a
+version control system
+.IP \[bu] 2
+tmux (https://tmux.github.io/) \[en] Terminal multiplexer similar to GNU
+Screen
+.IP \[bu] 2
+Vim (http://www.vim.org/) \[en] Vi IMproved, a text editor
+.IP \[bu] 2
+X11 (https://www.x.org/wiki/) \[en] Windowing system with network
+transparency for Unix
+.PP
+The configurations for shells, GnuPG, Mutt, tmux, and Vim are the most
+expansive, and most likely to be of interest.
+The i3 configuration is mostly changed to make window switching behave
+like Vim windows and tmux panes do, and there's a fair few resources
+defined for rxvt\-unicode.
+.SS Shell
+.PP
+My \f[C]\&.profile\f[] and other files in \f[C]sh\f[] are written in
+POSIX shell script, so they should work in most \f[C]sh(1)\f[]
+implementations.
+Individual scripts called by \f[C]\&.profile\f[] are saved in
+\f[C]\&.profile.d\f[] and iterated on login for ease of management.
+Most of these boil down to exporting variables appropriate to the system
+and the software it has available.
+.PP
+Configuration that should be sourced for all POSIX\-fearing interactive
+shells is kept in \f[C]~/.shrc\f[], with subscripts read from
+\f[C]~/.shrc.d\f[].
+There's a shim in \f[C]~/.shinit\f[] to act as \f[C]ENV\f[].
+I make an effort to target POSIX for my functions and scripts where I
+can so that the same files can be loaded for all shells.
+.PP
+On GNU/Linux I use Bash, on BSD I use some variant of Korn Shell,
+preferably \f[C]ksh93\f[] if it's available.
+.PP
+As I occasionally have work on very old internal systems, my Bash is
+written to work with any version 2.05a or
+newer (http://wiki.bash-hackers.org/scripting/bashchanges).
+This is why I use older syntax for certain things such as appending
+items to arrays:
+.IP
+.nf
+\f[C]
+array[${#array[\@]}]=$item
+\f[]
+.fi
+.PP
+Compare this to the much nicer syntax available since 3.1\-alpha1, which
+actually works for arrays with sparse indices, unlike the above syntax:
+.IP
+.nf
+\f[C]
+array+=("$item")
+\f[]
+.fi
+.PP
+Where I do use features that are only available in versions of Bash
+newer than 2.05a, such as newer \f[C]shopt\f[] options or
+\f[C]PROMPT_DIRTRIM\f[], they are only run after testing
+\f[C]BASH_VERSINFO\f[] appropriately.
+.SS Prompt
+.PP
+A terminal session with my prompt looks something like this:
+.IP
+.nf
+\f[C]
+~$\ ssh\ remote
+remote:~$\ cd\ .dotfiles
+remote:~/.dotfiles(master+!)$\ git\ status
+\ M\ README.md
+M\ \ bash/bashrc.d/prompt.bash
+A\ \ init
+remote:~/.dotfiles(master+!)$\ foobar
+foobar:\ command\ not\ found
+remote:~/.dotfiles(master+!)<127>$\ sleep\ 5\ &
+[1]\ 28937
+remote:~/.dotfiles(master+!){1}$
+\f[]
+.fi
+.PP
+The hostname is elided if not connected via SSH.
+The working directory with tilde abbreviation for \f[C]$HOME\f[] is
+always shown.
+The rest of the prompt expands based on context to include these
+elements in this order:
+.IP \[bu] 2
+Whether in a Git repository if applicable, and punctuation to show
+repository status including reference to upstreams at a glance.
+Subversion support can also be enabled (I need it at work), in which
+case a \f[C]git:\f[] or \f[C]svn:\f[] prefix is added appropriately.
+.IP \[bu] 2
+The number of running background jobs, if non\-zero.
+.IP \[bu] 2
+The exit status of the last command, if non\-zero.
+.PP
+You can set \f[C]PROMPT_COLOR\f[], \f[C]PROMPT_PREFIX\f[], and
+\f[C]PROMPT_SUFFIX\f[] too, which all do about what you'd expect.
+.PP
+If you start up Bash, Ksh, or Zsh and it detects that it's not normally
+your \f[C]$SHELL\f[], the prompt will display an appropriate prefix.
+.PP
+This is all managed within the \f[C]prompt\f[] function.
+There's some mildly hacky logic on \f[C]tput\f[] codes included such
+that it should work correctly for most common terminals using both
+\f[C]termcap(5)\f[] and \f[C]terminfo(5)\f[], including *BSD systems.
+It's also designed to degrade gracefully for eight\-color and no\-color
+terminals.
+.SS Functions
+.PP
+If a function can be written in POSIX \f[C]sh\f[] without too much
+hackery, I put it in \f[C]sh/shrc.d\f[] to be loaded by any POSIX
+interactive shell.
+Those include:
+.IP \[bu] 2
+Four functions for using a \[lq]marked\[rq] directory, which I find a
+more manageable concept than the \f[C]pushd\f[]/\f[C]popd\f[] directory
+stack:
+.RS 2
+.IP \[bu] 2
+\f[C]md()\f[] marks a given (or the current) directory.
+.IP \[bu] 2
+\f[C]gd()\f[] goes to the marked directory.
+.IP \[bu] 2
+\f[C]pmd()\f[] prints the marked directory.
+.IP \[bu] 2
+\f[C]xd()\f[] swaps the current and marked directories.
+.RE
+.IP \[bu] 2
+Ten other directory management and navigation functions:
+.RS 2
+.IP \[bu] 2
+\f[C]bd()\f[] changes into a named ancestor of the current directory.
+.IP \[bu] 2
+\f[C]gt()\f[] changes into a directory or into a file's directory.
+.IP \[bu] 2
+\f[C]lgt()\f[] runs \f[C]gt()\f[] on the first result from a
+\f[C]loc(1df)\f[] search.
+.IP \[bu] 2
+\f[C]mkcd()\f[] creates a directory and changes into it.
+.IP \[bu] 2
+\f[C]pd()\f[] changes to the argument's parent directory.
+.IP \[bu] 2
+\f[C]rd()\f[] replaces the first instance of its first argument with its
+second argument in \f[C]$PWD\f[], emulating a feature of the Zsh
+\f[C]cd\f[] builtin that I like.
+.IP \[bu] 2
+\f[C]scr()\f[] creates a temporary directory and changes into it.
+.IP \[bu] 2
+\f[C]sd()\f[] changes into a sibling of the current directory.
+.IP \[bu] 2
+\f[C]ud()\f[] changes into an indexed ancestor of a directory.
+.IP \[bu] 2
+\f[C]vr()\f[] tries to change to the root directory of a source control
+repository.
+.RE
+.IP \[bu] 2
+\f[C]bc()\f[] silences startup messages from GNU \f[C]bc(1)\f[].
+.IP \[bu] 2
+\f[C]ed()\f[] tries to get verbose error messages, a prompt, and a
+Readline environment for \f[C]ed(1)\f[].
+.IP \[bu] 2
+\f[C]env()\f[] sorts the output of \f[C]env(1)\f[] if it was invoked
+with no arguments, just for convenience when running it interactively.
+.IP \[bu] 2
+\f[C]gdb()\f[] silences startup messages from \f[C]gdb(1)\f[].
+.IP \[bu] 2
+\f[C]gpg()\f[] quietens \f[C]gpg(1)\f[] down for most commands.
+.IP \[bu] 2
+\f[C]grep()\f[] tries to apply color and other options good for
+interactive use if available.
+.IP \[bu] 2
+\f[C]hgrep()\f[] allows searching \f[C]$HISTFILE\f[].
+.IP \[bu] 2
+\f[C]keychain()\f[] keeps \f[C]$GPG_TTY\f[] up to date if a GnuPG agent
+is available.
+.IP \[bu] 2
+\f[C]ls()\f[] tries to apply color and other options good for
+interactive use if available.
+.RS 2
+.IP \[bu] 2
+\f[C]la()\f[] runs \f[C]ls\ \-A\f[] if it can, or \f[C]ls\ \-a\f[]
+otherwise.
+.IP \[bu] 2
+\f[C]ll()\f[] runs \f[C]ls\ \-Al\f[] if it can, or \f[C]ls\ \-al\f[]
+otherwise.
+.RE
+.IP \[bu] 2
+\f[C]path()\f[] manages the contents of \f[C]PATH\f[] conveniently.
+.IP \[bu] 2
+\f[C]scp()\f[] tries to detect forgotten hostnames in \f[C]scp(1)\f[]
+command calls.
+.IP \[bu] 2
+\f[C]sudo()\f[] forces \f[C]\-H\f[] for \f[C]sudo(8)\f[] calls so that
+\f[C]$HOME\f[] is never preserved; I hate having \f[C]root\f[]\-owned
+files in my home directory.
+.IP \[bu] 2
+\f[C]tree()\f[] colorizes GNU \f[C]tree(1)\f[] output if possible
+(without having \f[C]LS_COLORS\f[] set).
+.IP \[bu] 2
+\f[C]x()\f[] is a one\-key shortcut for \f[C]exec\ startx\f[].
+.PP
+There are a few other little tricks defined for other shells providing
+non\-POSIX features, as compatibility allows:
+.IP \[bu] 2
+\f[C]keep()\f[] stores ad\-hoc shell functions and variables (Bash, Korn
+Shell 93, Z shell).
+.IP \[bu] 2
+\f[C]prompt()\f[] sets up my interactive prompt (Bash, Korn Shell, Z
+shell).
+.IP \[bu] 2
+\f[C]pushd()\f[] adds a default destination of \f[C]$HOME\f[] to the
+\f[C]pushd\f[] builtin (Bash).
+.IP \[bu] 2
+\f[C]vared()\f[] allows interactively editing a variable with Readline,
+emulating a Zsh function I like by the same name (Bash).
+.IP \[bu] 2
+\f[C]ver()\f[] prints the current shell's version information (Bash,
+Korn Shell, Z shell).
+.SS Completion
+.PP
+I find the \f[C]bash\-completion\f[] package a bit too heavy for my
+tastes, and turn it off using a stub file installed in
+\f[C]~/.config/bash_completion\f[].
+The majority of the time I just want to complete paths anyway, and this
+makes for a quicker startup without a lot of junk functions in my Bash
+namespace.
+.PP
+I do make some exceptions with completions defined in
+\f[C]\&.bash_completion.d\f[] files, for things I really do get tired of
+typing repeatedly:
+.IP \[bu] 2
+Bash builtins: commands, help topics, shell options, variables, etc.
+.IP \[bu] 2
+\f[C]find(1)\f[]'s more portable options
+.IP \[bu] 2
+\f[C]ftp(1)\f[] hostnames from \f[C]~/.netrc\f[]
+.IP \[bu] 2
+\f[C]git(1)\f[] subcommands, remotes, branches, tags, and addable files
+.IP \[bu] 2
+\f[C]gpg(1)\f[] long options
+.IP \[bu] 2
+\f[C]make(1)\f[] targets read from a \f[C]Makefile\f[]
+.IP \[bu] 2
+\f[C]man(1)\f[] page titles
+.IP \[bu] 2
+\f[C]pass(1)\f[] entries
+.IP \[bu] 2
+\f[C]ssh(1)\f[] hostnames from \f[C]~/.ssh/config\f[]
+.PP
+For commands that pretty much always want to operate on text, such as
+text file or stream editors, I exclude special file types and extensions
+I know are binary.
+I don't actually read the file, so this is more of a heuristic thing,
+and sometimes it will get things wrong.
+.PP
+I also add completions for my own scripts and functions where useful.
+The completions are dynamically loaded if Bash is version 4.0 or
+greater.
+Otherwise, they're all loaded on startup.
+.SS Korn shell
+.PP
+These are experimental; they are mostly used to tinker with MirBSD
+\f[C]mksh\f[], AT&T \f[C]ksh93\f[], and OpenBSD \f[C]pdksh\f[].
+All shells in this family default to a yellow prompt if detected.
+.SS Zsh
+.PP
+These are experimental; I do not like Zsh much at the moment.
+The files started as a joke (\f[C]exec\ bash\f[]).
+\f[C]zsh\f[] shells default to having a prompt coloured cyan.
+.SS GnuPG
+.PP
+The configuration for GnuPG is intended to follow RiseUp's OpenPGP best
+practices (https://riseup.net/en/security/message-security/openpgp/best-practices).
+The configuration file is rebuilt using \f[C]mi5(1df)\f[] and
+\f[C]make(1)\f[] because it requires hard\-coding a path to the SKS
+keyserver certificate authority, and neither tilde nor \f[C]$HOME\f[]
+expansion works for this.
+.SS Mutt
+.PP
+My mail is kept in individual Maildirs under \f[C]~/Mail\f[], with
+\f[C]inbox\f[] being where most unfiltered mail is sent.
+I use Getmail (http://pyropus.ca/software/getmail/),
+maildrop (https://www.courier-mta.org/maildrop/), and
+MSMTP (http://msmtp.sourceforge.net/); the configurations for these are
+not included here.
+I sign whenever I have some indication that the recipient might be using
+a PGP implementation, and I encrypt whenever I have a public key
+available for them.
+The GnuPG and S/MIME interfacing is done with
+GPGme (https://www.gnupg.org/related_software/gpgme/), rather than
+defining commands for each crypto operation.
+I wrote an article about this
+setup (https://sanctum.geek.nz/arabesque/linux-crypto-email/) if it
+sounds appealing.
+.PP
+You'll need Abook (http://abook.sourceforge.net/) installed if you want
+to use the \f[C]query_command\f[] I have defined, and
+msmtp (http://msmtp.sourceforge.net/) for the \f[C]sendmail\f[] command.
+.SS rxvt\-unicode
+.PP
+I've butchered the URxvt Perl extensions
+\f[C]selection\-to\-clipboard\f[] and \f[C]selection\f[] into a single
+\f[C]select\f[] extension in \f[C]~/.urxvt/ext\f[], which is the only
+extension I define in \f[C]~/.Xresources\f[].
+.PP
+The included \f[C]\&.Xresources\f[] file assumes that \f[C]urxvt\f[] can
+use 256 colors and Perl extensions.
+If you're missing functionality, try changing \f[C]perl\-ext\-common\f[]
+to \f[C]default\f[].
+.PP
+My choice of font is Ubuntu Mono (http://font.ubuntu.com/), but the file
+should allow falling back to the more common Deja Vu Sans
+Mono (https://dejavu-fonts.github.io/).
+I've found Terminus (http://terminus-font.sourceforge.net/) works well
+too, but bitmap fonts are not really my cup of tea.
+The Lohit Kannada font bit is purely to make ಠ_ಠ work correctly.
+( ͡° ͜ʖ ͡°) seems to work out of the box.
+.SS tmux
+.PP
+These are just generally vi\-friendly settings, not much out of the
+ordinary.
+Note that the configuration presently uses a hard\-coded 256\-color
+colorscheme, and uses non\-login shells, with an attempt to control the
+environment to stop shells thinking they have access to an X display.
+.PP
+The shell scripts in \f[C]bin\f[] include \f[C]tm(1df)\f[], a shortcut
+to make \f[C]attach\f[] into the default command if no arguments are
+given and sessions do already exist.
+My \f[C]~/.inputrc\f[] file binds Alt+M to run that, and Tmux in turn
+binds the same key combination to detach.
+.SS Vim
+.PP
+The majority of the \f[C]\&.vimrc\f[] file is just setting options, with
+a few mappings.
+I try not to deviate too much from the Vim defaults behaviour in terms
+of interactive behavior and keybindings.
+.PP
+The configuration is extensively commented, mostly because I was reading
+through it one day and realised I'd forgotten what half of it did.
+Plugins are loaded using \@tpope's
+pathogen.vim (https://github.com/tpope/vim-pathogen).
+.SS Scripts
+.PP
+Where practical, I make short scripts into POSIX (but not Bourne)
+\f[C]sh(1)\f[], \f[C]awk(1)\f[], or \f[C]sed(1)\f[] scripts in
+\f[C]~/.local/bin\f[].
+I try to use shell functions only when I actually need to, which tends
+to be when I need to tinker with the namespace of the user's current
+shell.
+.PP
+Installed by the \f[C]install\-bin\f[] target:
+.IP \[bu] 2
+Three SSH\-related scripts:
+.RS 2
+.IP \[bu] 2
+\f[C]sls(1df)\f[] prints hostnames read from a \f[C]ssh_config(5)\f[]
+file.
+It uses \f[C]slsf(1df)\f[] to read each one.
+.IP \[bu] 2
+\f[C]sra(1df)\f[] runs a command on multiple hosts read from
+\f[C]sls(1df)\f[] and prints output.
+.IP \[bu] 2
+\f[C]sta(1df)\f[] runs a command on multiple hosts read from
+\f[C]sls(1df)\f[] and prints the hostname if the command returns zero.
+.RE
+.IP \[bu] 2
+Five URL\-related shortcut scripts:
+.RS 2
+.IP \[bu] 2
+\f[C]hurl(1df)\f[] extracts values of \f[C]href\f[] attributes of
+\f[C]<a>\f[] tags, sorts them uniquely, and writes them to
+\f[C]stdout\f[]; it requires pup (https://github.com/ericchiang/pup).
+.IP \[bu] 2
+\f[C]murl(1df)\f[] converts Markdown documents to HTML with
+\f[C]pandoc(1)\f[] and runs the output through \f[C]hurl(1df)\f[].
+.IP \[bu] 2
+\f[C]urlc(1df)\f[] accepts a list of URLs on \f[C]stdin\f[] and writes
+error messages to \f[C]stderr\f[] if any of the URLs are broken,
+redirecting, or are insecure and have working secure versions; requires
+\f[C]curl(1)\f[].
+.IP \[bu] 2
+\f[C]urlh(1df)\f[] prints the values for a given HTTP header from a HEAD
+response.
+.IP \[bu] 2
+\f[C]urlmt(1df)\f[] prints the MIME type from the \f[C]Content\-Type\f[]
+header as retrieved by \f[C]urlh(1df)\f[].
+.RE
+.IP \[bu] 2
+Three RFC\-related shortcut scripts:
+.RS 2
+.IP \[bu] 2
+\f[C]rfcf(1df)\f[] fetches ASCII RFCs from the IETF website.
+.IP \[bu] 2
+\f[C]rfct(1df)\f[] formats ASCII RFCs.
+.IP \[bu] 2
+\f[C]rfcr(1df)\f[] does both, displaying in a pager if appropriate, like
+a \f[C]man(1)\f[] reader for RFCs.
+.RE
+.IP \[bu] 2
+Five toy random\-number scripts (not for sensitive/dead\-serious use):
+.RS 2
+.IP \[bu] 2
+\f[C]rndi(1df)\f[] gets a random integer within two bounds.
+.IP \[bu] 2
+\f[C]rnds(1df)\f[] attempts to get an optional random seed for
+\f[C]rndi(1df)\f[].
+.IP \[bu] 2
+\f[C]rnda(1df)\f[] uses \f[C]rndi(1df)\f[] to choose a random argument.
+.IP \[bu] 2
+\f[C]rndf(1df)\f[] uses \f[C]rnda(1df)\f[] to choose a random file from
+a directory.
+.IP \[bu] 2
+\f[C]rndl(1df)\f[] uses \f[C]rndi(1df)\f[] to choose a random line from
+files.
+.RE
+.IP \[bu] 2
+Four file formatting scripts:
+.RS 2
+.IP \[bu] 2
+\f[C]d2u(1df)\f[] converts DOS line endings in files to UNIX ones.
+.IP \[bu] 2
+\f[C]u2d(1df)\f[] converts UNIX line endings in files to DOS ones.
+.IP \[bu] 2
+\f[C]stbl(1df)\f[] strips a trailing blank line from the files in its
+arguments.
+.IP \[bu] 2
+\f[C]stws(1df)\f[] strips trailing spaces from the ends of lines of the
+files in its arguments.
+.RE
+.IP \[bu] 2
+Seven stream formatting scripts:
+.RS 2
+.IP \[bu] 2
+\f[C]sd2u(1df)\f[] converts DOS line endings in streams to UNIX ones.
+.IP \[bu] 2
+\f[C]su2d(1df)\f[] converts UNIX line endings in streams to DOS ones.
+.IP \[bu] 2
+\f[C]slow(1df)\f[] converts uppercase to lowercase.
+.IP \[bu] 2
+\f[C]supp(1df)\f[] converts lowercase to uppercase.
+.IP \[bu] 2
+\f[C]tl(1df)\f[] tags input lines with a prefix or suffix, basically a
+\f[C]sed(1)\f[] shortcut.
+.IP \[bu] 2
+\f[C]tlcs(1df)\f[] executes a command and uses \f[C]tl(1df)\f[] to tag
+stdout and stderr lines, and color them if you want.
+.IP \[bu] 2
+\f[C]unf(1df)\f[] joins lines with leading spaces to the previous line.
+Intended for unfolding HTTP headers, but it should work for most RFC 822
+formats.
+.RE
+.IP \[bu] 2
+Six simple aggregators for numbers:
+.RS 2
+.IP \[bu] 2
+\f[C]max(1df)\f[] prints the maximum.
+.IP \[bu] 2
+\f[C]mean(1df)\f[] prints the mean.
+.IP \[bu] 2
+\f[C]med(1df)\f[] prints the median.
+.IP \[bu] 2
+\f[C]min(1df)\f[] prints the minimum.
+.IP \[bu] 2
+\f[C]mode(1df)\f[] prints the first encountered mode.
+.IP \[bu] 2
+\f[C]tot(1df)\f[] totals the set.
+.RE
+.IP \[bu] 2
+Three quick\-and\-dirty HTML tools:
+.RS 2
+.IP \[bu] 2
+\f[C]htenc(1df)\f[] encodes.
+.IP \[bu] 2
+\f[C]htdec(1df)\f[] decodes.
+.IP \[bu] 2
+\f[C]htrec(1df)\f[] wraps \f[C]a\f[] tags around URLs.
+.RE
+.IP \[bu] 2
+Two internet message quoting tools:
+.RS 2
+.IP \[bu] 2
+\f[C]quo(1df)\f[] indents with quoting right angle\-brackets.
+.IP \[bu] 2
+\f[C]wro(1df)\f[] adds a quote attribution header to its input.
+.RE
+.IP \[bu] 2
+Six Git\-related tools:
+.RS 2
+.IP \[bu] 2
+\f[C]fgscr(1df)\f[] finds Git repositories in a directory root and
+scrubs them with \f[C]gscr(1df)\f[].
+.IP \[bu] 2
+\f[C]grc(1df)\f[] quietly tests whether the given directory appears to
+be a Git repository with pending changes.
+.IP \[bu] 2
+\f[C]gscr(1df)\f[] scrubs Git repositories.
+.IP \[bu] 2
+\f[C]isgr(1df)\f[] quietly tests whether the given directory appears to
+be a Git repository.
+.IP \[bu] 2
+\f[C]jfc(1df)\f[] adds and commits lazily to a Git repository.
+.IP \[bu] 2
+\f[C]jfcd(1df)\f[] watches a directory for changes and runs
+\f[C]jfc(1df)\f[] if it sees any.
+.RE
+.IP \[bu] 2
+Two time duration functions:
+.RS 2
+.IP \[bu] 2
+\f[C]hms(1df)\f[] converts seconds to \f[C]hh:mm:ss\f[] or
+\f[C]mm:ss\f[] timestamps.
+.IP \[bu] 2
+\f[C]sec(1df)\f[] converts \f[C]hh:mm:ss\f[] or \f[C]mm:ss\f[]
+timestamps to seconds.
+.RE
+.IP \[bu] 2
+Three pipe interaction tools:
+.RS 2
+.IP \[bu] 2
+\f[C]pst(1df)\f[] runs an interactive program on data before passing it
+along a pipeline.
+.IP \[bu] 2
+\f[C]ped(1df)\f[] runs \f[C]pst(1df)\f[] with \f[C]$EDITOR\f[] or
+\f[C]ed(1)\f[].
+.IP \[bu] 2
+\f[C]pvi(1df)\f[] runs \f[C]pvi(1df)\f[] with \f[C]$VISUAL\f[] or
+\f[C]vi(1)\f[].
+.RE
+.IP \[bu] 2
+\f[C]ap(1df)\f[] reads arguments for a given command from the standard
+input, prompting if appropriate.
+.IP \[bu] 2
+\f[C]apf(1df)\f[] prepends arguments to a command with ones read from a
+file, intended as a framework for shell wrappers or functions.
+.IP \[bu] 2
+\f[C]ax(1df)\f[] evaluates an awk expression given on the command line;
+this is intended as a quick way to test how Awk would interpret a given
+expression.
+.IP \[bu] 2
+\f[C]bcq(1df)\f[] runs \f[C]bc(1)\f[], quieting it down if need be.
+.IP \[bu] 2
+\f[C]bel(1df)\f[] prints a terminal bell character.
+.IP \[bu] 2
+\f[C]bl(1df)\f[] generates a given number of blank lines.
+.IP \[bu] 2
+\f[C]bp(1df)\f[] runs \f[C]br(1df)\f[] after prompting for an URL.
+.IP \[bu] 2
+\f[C]br(1df)\f[] launches \f[C]$BROWSER\f[].
+.IP \[bu] 2
+\f[C]ca(1df)\f[] prints a count of its given arguments.
+.IP \[bu] 2
+\f[C]cf(1df)\f[] prints a count of entries in a given directory.
+.IP \[bu] 2
+\f[C]cfr(1df)\f[] does the same as \f[C]cf(1df)\f[], but recurses into
+subdirectories as well.
+.IP \[bu] 2
+\f[C]chc(1df)\f[] caches the output of a command.
+.IP \[bu] 2
+\f[C]chn(1df)\f[] runs a filter over its input a given number of times.
+.IP \[bu] 2
+\f[C]clog(1df)\f[] is a tiny timestamped log system.
+.IP \[bu] 2
+\f[C]clrd(1df)\f[] sets up a per\-line file read, clearing the screen
+first.
+.IP \[bu] 2
+\f[C]clwr(1df)\f[] sets up a per\-line file write, clearing the screen
+before each line.
+.IP \[bu] 2
+\f[C]csmw(1df)\f[] prints an English list of monospace\-quoted words
+read from the input.
+.IP \[bu] 2
+\f[C]dam(1df)\f[] buffers all its input before emitting it as output.
+.IP \[bu] 2
+\f[C]ddup(1df)\f[] removes duplicate lines from unsorted input.
+.IP \[bu] 2
+\f[C]dmp(1df)\f[] copies a pass(1) entry selected by \f[C]dmenu(1)\f[]
+to the X CLIPBOARD.
+.IP \[bu] 2
+\f[C]dub(1df)\f[] lists the biggest entries in a directory.
+.IP \[bu] 2
+\f[C]edda(1df)\f[] provides a means to run \f[C]ed(1)\f[] over a set of
+files preserving any options, mostly useful for scripts.
+.IP \[bu] 2
+\f[C]eds(1df)\f[] edits executable script files in \f[C]EDSPATH\f[],
+defaulting to \f[C]~/.local/bin\f[], for personal scripting snippets.
+.IP \[bu] 2
+\f[C]exm(1df)\f[] works around a screen\-clearing quirk of Vim's
+\f[C]ex\f[] mode.
+.IP \[bu] 2
+\f[C]finc(1df)\f[] counts the number of results returned from a set of
+given \f[C]find(1)\f[] conditions.
+.IP \[bu] 2
+\f[C]fnl(1df)\f[] runs a command and saves its output and error into
+temporary files, printing their paths and line counts.
+.IP \[bu] 2
+\f[C]fnp(1df)\f[] prints the given files to stdout, each with a
+plaintext heading with the filename in it.
+.IP \[bu] 2
+\f[C]gms(1df)\f[] runs a set of \f[C]getmailrc\f[] files; does much the
+same thing as the script \f[C]getmails\f[] in the \f[C]getmail\f[]
+suite, but runs the requests in parallel and does up to three silent
+retries using \f[C]try(1df)\f[].
+.IP \[bu] 2
+\f[C]grec(1df)\f[] is a more logically\-named \f[C]grep\ \-c\f[].
+.IP \[bu] 2
+\f[C]gred(1df)\f[] is a more logically\-named \f[C]grep\ \-v\f[].
+.IP \[bu] 2
+\f[C]gwp(1df)\f[] searches for alphanumeric words in a similar way to
+\f[C]grep(1)\f[].
+.IP \[bu] 2
+\f[C]han(1df)\f[] provides a \f[C]keywordprg\f[] for Vim's Bash script
+filetype that will look for \f[C]help\f[] topics.
+You could use it from the shell too.
+.IP \[bu] 2
+\f[C]igex(1df)\f[] wraps around a command to allow you to ignore error
+conditions that don't actually worry you, exiting with 0 anyway.
+.IP \[bu] 2
+\f[C]ix(1df)\f[] posts its input to the ix.io pastebin.
+.IP \[bu] 2
+\f[C]jfp(1df)\f[] prints its input, excluding any shebang on the first
+line only.
+.IP \[bu] 2
+\f[C]loc(1df)\f[] is a quick\-search wrapped around \f[C]find(1)\f[].
+.IP \[bu] 2
+\f[C]maybe(1df)\f[] is like \f[C]true(1)\f[] or \f[C]false(1)\f[]; given
+a probability of success, it exits with success or failure.
+Good for quick tests.
+.IP \[bu] 2
+\f[C]mex(1df)\f[] makes given filenames in \f[C]$PATH\f[] executable.
+.IP \[bu] 2
+\f[C]mi5(1df)\f[] pre\-processes a crude but less painful macro
+expansion file format into \f[C]m4\f[] input.
+.IP \[bu] 2
+\f[C]mftl(1df)\f[] finds usable\-looking targets in Makefiles.
+.IP \[bu] 2
+\f[C]mkcp(1df)\f[] creates a directory and copies preceding arguments
+into it.
+.IP \[bu] 2
+\f[C]mkmv(1df)\f[] creates a directory and moves preceding arguments
+into it.
+.IP \[bu] 2
+\f[C]motd(1df)\f[] shows the system MOTD.
+.IP \[bu] 2
+\f[C]mw(1df)\f[] prints alphabetic space\-delimited words from the input
+one per line.
+.IP \[bu] 2
+\f[C]oii(1df)\f[] runs a command on input only if there is any.
+.IP \[bu] 2
+\f[C]onl(1df)\f[] crunches input down to one printable line.
+.IP \[bu] 2
+\f[C]osc(1df)\f[] implements a \f[C]netcat(1)\f[]\-like wrapper for
+\f[C]openssl(1)\f[]'s \f[C]s_client\f[] subcommand.
+.IP \[bu] 2
+\f[C]p(1df)\f[] prints concatenated standard input; \f[C]cat(1)\f[] as
+it should always have been.
+.IP \[bu] 2
+\f[C]pa(1df)\f[] prints its arguments, one per line.
+.IP \[bu] 2
+\f[C]pp(1df)\f[] prints the full path of each argument using
+\f[C]$PWD\f[].
+.IP \[bu] 2
+\f[C]pph(1df)\f[] runs \f[C]pp(1df)\f[] and includes a leading
+\f[C]$HOSTNAME:\f[].
+.IP \[bu] 2
+\f[C]paz(1df)\f[] print its arguments terminated by NULL chars.
+.IP \[bu] 2
+\f[C]pit(1df)\f[] runs its input through a pager if its standard output
+looks like a terminal.
+.IP \[bu] 2
+\f[C]plmu(1df)\f[] retrieves a list of installed modules from
+\f[C]plenv\f[] (https://github.com/tokuhirom/plenv), filters out any
+modules in \f[C]~/.plenv/non\-cpan\-modules\f[], and updates them all.
+.IP \[bu] 2
+\f[C]pwg(1df)\f[] generates just one decent password with
+\f[C]pwgen(1)\f[].
+.IP \[bu] 2
+\f[C]rep(1df)\f[] repeats a command a given number of times.
+.IP \[bu] 2
+\f[C]rgl(1df)\f[] is a very crude interactive \f[C]grep(1)\f[] loop.
+.IP \[bu] 2
+\f[C]shb(1df)\f[] attempts to build shebang lines for scripts from the
+system paths.
+.IP \[bu] 2
+\f[C]sqs(1df)\f[] chops off query strings from filenames, usually
+downloads.
+.IP \[bu] 2
+\f[C]sshi(1df)\f[] prints human\-readable SSH connection details.
+.IP \[bu] 2
+\f[C]stex(1df)\f[] strips extensions from filenames.
+.IP \[bu] 2
+\f[C]sue(8df)\f[] execs \f[C]sudoedit(8)\f[] as the owner of all the
+file arguments given, perhaps in cases where you may not necessarily
+have \f[C]root\f[] \f[C]sudo(8)\f[] privileges.
+.IP \[bu] 2
+\f[C]swr(1df)\f[] allows you to run commands locally specifying remote
+files in \f[C]scp(1)\f[]'s HOST:PATH format.
+.IP \[bu] 2
+\f[C]td(1df)\f[] manages a to\-do file for you with \f[C]$EDITOR\f[] and
+\f[C]git(1)\f[]; I used to use Taskwarrior, but found it too complex and
+buggy.
+.IP \[bu] 2
+\f[C]tm(1df)\f[] runs \f[C]tmux(1)\f[] with
+\f[C]attach\-session\ \-d\f[] if a session exists, and
+\f[C]new\-session\f[] if it doesn't.
+.IP \[bu] 2
+\f[C]trs(1df)\f[] replaces strings (not regular expression) in its
+input.
+.IP \[bu] 2
+\f[C]try(1df)\f[] repeats a command up to a given number of times until
+it succeeds, only printing error output if all three attempts failed.
+Good for tolerating blips or temporary failures in \f[C]cron(8)\f[]
+scripts.
+.IP \[bu] 2
+\f[C]umake(1df)\f[] iterates upwards through the directory tree from
+\f[C]$PWD\f[] until it finds a Makefile for which to run
+\f[C]make(1)\f[] with the given arguments.
+.IP \[bu] 2
+\f[C]uts(1df)\f[] gets the current UNIX timestamp in an unorthodox way
+that should work on all POSIX\-compliant operating systems.
+.IP \[bu] 2
+\f[C]vest(1df)\f[] runs \f[C]test(1)\f[] but fails with explicit output
+via \f[C]vex(1df)\f[].
+.IP \[bu] 2
+\f[C]vex(1df)\f[] runs a command and prints \f[C]true\f[] or
+\f[C]false\f[] explicitly to \f[C]stdout\f[] based on the exit value.
+.IP \[bu] 2
+\f[C]xrbg(1df)\f[] applies the same randomly\-selected background to
+each X screen.
+.IP \[bu] 2
+\f[C]xrq(1df)\f[] gets the values of specific resources out of
+\f[C]xrdb\ \-query\f[] output.
+.PP
+There's some silly stuff in \f[C]install\-games\f[]:
+.IP \[bu] 2
+\f[C]aaf(6df)\f[] gets a random ASCII Art
+Farts (http://www.asciiartfarts.com/) comic.
+.IP \[bu] 2
+\f[C]acq(6df)\f[] allows you to interrogate AC, the interplanetary
+computer.
+.IP \[bu] 2
+\f[C]aesth(6df)\f[] converts English letters to their fullwidth CJK
+analogues, for AESTHETIC PURPOSES.
+.IP \[bu] 2
+\f[C]squ(6df)\f[] makes a reduced Latin square out of each line of
+input.
+.IP \[bu] 2
+\f[C]kvlt(6df)\f[] translates input to emulate a style of typing unique
+to black metal communities on the internet.
+.IP \[bu] 2
+\f[C]rndn(6df)\f[] implements an esoteric random number generation
+algorithm.
+.IP \[bu] 2
+\f[C]strik(6df)\f[] outputs s̶t̶r̶i̶k̶e̶d̶ ̶o̶u̶t̶ struck out text.
+.IP \[bu] 2
+\f[C]rot13(6df)\f[] rotates the Latin letters in its input.
+.IP \[bu] 2
+\f[C]xyzzy(6df)\f[] teleports to a marked location on the filesystem.
+.IP \[bu] 2
+\f[C]zs(6df)\f[] prepends \[lq]z\[rq] case\-appropriately to every
+occurrence of \[lq]s\[rq] in the text on its standard input.
+.SS Manuals
+.PP
+The \f[C]install\-bin\f[] and \f[C]install\-games\f[] targets install
+manuals for each script they install.
+There's also an \f[C]install\-dotfiles\-man\f[] target that uses
+\f[C]pandoc(1)\f[] to reformat this document as a manual page for
+section 7 (\f[C]dotfiles(7df)\f[]) if you want that.
+I haven't made that install by default, because \f[C]pandoc(1)\f[] is a
+bit heavy.
+.PP
+If you want to use the manuals, you may need to add
+\f[C]~/.local/share/man\f[] to your \f[C]~/.manpath\f[] or
+\f[C]/etc/manpath\f[] configuration, depending on your system.
+.SS Testing
+.PP
+You can check that both sets of shell scripts are syntactically correct
+with \f[C]make\ check\-bash\f[], \f[C]make\ check\-sh\f[], or
+\f[C]make\ check\f[] for everything including the scripts in
+\f[C]bin\f[] and \f[C]games\f[].
+There's no proper test suite for the actual functionality (yet).
+.PP
+If you have ShellCheck (https://www.shellcheck.net/) and/or
+Perl::Critic (http://perlcritic.com/), there's a \f[C]lint\f[] target
+for the shell script files and Perl files respectively.
+The files don't need to pass that check to be installed.
+.SS Known issues
+.PP
+See ISSUES.markdown.
+.SS License
+.PP
+Public domain; see the included \f[C]UNLICENSE\f[] file.
+It's just configuration and simple scripts, so do whatever you like with
+it if any of it's useful to you.
+If you're feeling generous, please join and/or donate to a free software
+advocacy group, and let me know you did it because of this project:
+.IP \[bu] 2
+Free Software Foundation (https://www.fsf.org/)
+.IP \[bu] 2
+Software in the Public Interest (https://www.spi-inc.org/)
+.IP \[bu] 2
+FreeBSD Foundation (https://www.freebsdfoundation.org/)
+.IP \[bu] 2
+OpenBSD Foundation (http://www.openbsdfoundation.org/)
+.SH AUTHORS
+Tom Ryder.
diff --git a/man/man7/dotfiles.7df.header b/man/man7/dotfiles.7df.header
deleted file mode 100644
index cc8aef57..00000000
--- a/man/man7/dotfiles.7df.header
+++ /dev/null
@@ -1,3 +0,0 @@
-% DOTFILES(7) Tom Ryder's personal scripts and configuration
-% Tom Ryder
-% June 2016
diff --git a/mpd/mpdconf b/mpd/mpdconf
new file mode 100644
index 00000000..3dca8b6d
--- /dev/null
+++ b/mpd/mpdconf
@@ -0,0 +1,15 @@
+bind_to_address "~/.mpd/socket"
+
+db_file "~/.mpd/database"
+log_file "~/.mpd/log"
+
+music_directory "/mnt/media/shares/music"
+playlist_directory "~/.mpd/playlists"
+pid_file "~/.mpd/pid"
+state_file "~/.mpd/state"
+sticker_file "~/.mpd/sticker.sql"
+
+audio_output {
+ type "pulse"
+ name "PulseAudio"
+}
diff --git a/mpd/profile.d/mpd.sh b/mpd/profile.d/mpd.sh
new file mode 100644
index 00000000..5a14aef2
--- /dev/null
+++ b/mpd/profile.d/mpd.sh
@@ -0,0 +1,3 @@
+# Start an mpd process if one isn't already running
+command -v mpd >/dev/null 2>&1 || return
+[ -s "$HOME"/.mpd/pid ] || mpd
diff --git a/mutt/muttrc.m4 b/mutt/muttrc
index 587d879e..953ab418 100644
--- a/mutt/muttrc.m4
+++ b/mutt/muttrc
@@ -1,27 +1,8 @@
-# Person-specific settings
-# (Define 'from', 'realname', and specify alternate addresses in here)
-source ~/.mutt/muttrc.local
-
-# Names
-set use_domain = yes
-set use_from = yes
-set reverse_name = yes
-
-# SMTP implementation
-set sendmail = 'DOTFILES_SENDMAIL'
-
-# Mailbox type and location
-set mbox_type = 'Maildir'
-set folder = '~/Mail/'
-
-# Submailboxes
-set spoolfile = '+inbox'
-set postponed = '+drafts'
-set record = '+sent'
-mailboxes !
-
# Addresses
set query_command = 'abook --mutt-query %s'
+set reverse_name = yes
+set use_domain = yes
+set use_from = yes
# Alerts
set beep_new = yes
@@ -117,7 +98,7 @@ set strict_threads = yes
set thorough_search = yes
# SSH
-set time_inc=250
+set time_inc = 250
# Encryption settings
set crypt_replysign = yes
@@ -127,6 +108,9 @@ set crypt_use_gpgme = yes
set crypt_use_pka = yes
set crypt_verify_sig = yes
+# Do decode classic PGP messages, though we'll never write them
+set pgp_auto_decode = yes
+
# Vim-ish bindings
bind index gg first-entry
bind index G last-entry
@@ -140,15 +124,14 @@ bind generic,index,browser,pager \Cb previous-page
# Turn off annoying mailbox lock feature
bind index '%' noop
-# Jump to mailboxes
-macro generic,index,browser,pager gi '<change-folder>=inbox<enter>' 'Change to inbox folder'
-macro generic,index,browser,pager gs '<change-folder>=sent<enter>' 'Change to sent folder'
-
# Blindly save message to whatever box is suggested
macro index,pager S 's<enter>' 'Save message blindly'
# Run gms to retrieve all mail
-macro generic,index,browser,pager gm '!gms --quiet &<enter>' 'Run gms'
+macro generic,index,browser,pager gm '!gms --quiet &<enter>' 'Run gms(1df)'
# Shortcut to add addresses to abook
-macro index,pager A '<pipe-message>abook --add-email<enter>' 'Add sender address to abook'
+macro index,pager A '<pipe-message>abook --add-email-quiet<enter>' 'Add sender address to abook'
+
+# Machine or account specific settings
+source ~/.muttrc.d/src|
diff --git a/mutt/muttrc.d/src b/mutt/muttrc.d/src
new file mode 100755
index 00000000..584a2785
--- /dev/null
+++ b/mutt/muttrc.d/src
@@ -0,0 +1,6 @@
+#!/bin/sh
+# Helper script to emit the source all muttrc subfiles, in LC_COLLATE order
+for rc in "$HOME"/.muttrc.d/*.rc ; do
+ [ -e "$rc" ] || continue
+ cat -- "$rc"
+done
diff --git a/mutt/signature b/mutt/signature
deleted file mode 100644
index a229b5f5..00000000
--- a/mutt/signature
+++ /dev/null
@@ -1,2 +0,0 @@
-Tom Ryder <https://sanctum.geek.nz/>
-The next 1<<10 years are ours.
diff --git a/mysql/my.cnf b/mysql/my.cnf
index e0df3c23..900cf1a9 100644
--- a/mysql/my.cnf
+++ b/mysql/my.cnf
@@ -3,3 +3,4 @@ default-character-set=utf8
no-auto-rehash
prompt='(\u@\h:\d) mysql> '
safe-updates
+skip-pager
diff --git a/ncmpcpp/config b/ncmpcpp/config
index eb4f2120..7e865a8f 100644
--- a/ncmpcpp/config
+++ b/ncmpcpp/config
@@ -2,30 +2,7 @@
ncmpcpp_directory = "~/.ncmpcpp"
# Server specifics
-mpd_host = "localhost"
-mpd_port = "6600"
-mpd_communication_mode = "notifications"
-mpd_connection_timeout = "5"
-mpd_crossfade_time = "5"
+mpd_host = "~/.mpd/socket"
# No mouse, it confuses tmux/urxvt, and I never use it anyway
mouse_support = "no"
-
-# Visualization
-visualizer_fifo_path = "/tmp/mpd.fifo"
-visualizer_in_stereo = "yes"
-visualizer_look = "*|"
-visualizer_output_name = "FIFO"
-visualizer_sync_interval = "30"
-visualizer_type = "spectrum"
-
-# Use columns everywhere
-browser_display_mode = "columns"
-playlist_display_mode = "columns"
-playlist_editor_display_mode = "columns"
-search_engine_display_mode = "columns"
-song_columns_list_format = "(40)[]{t|f} (25)[blue]{a} (25)[red]{b} (10)[green]{lr}"
-
-# Don't let me actually delete anything
-allow_physical_directories_deletion = "no"
-allow_physical_files_deletion = "no"
diff --git a/newsbeuter/config b/newsbeuter/config
index 48f4110a..affbaa43 100644
--- a/newsbeuter/config
+++ b/newsbeuter/config
@@ -1,7 +1,8 @@
-auto-reload yes
-confirm-exit yes
-reload-threads 5
-reload-time 30
+auto-reload yes
+confirm-exit yes
+keep-articles-days 180
+reload-threads 5
+reload-time 30
bind-key j next
bind-key k prev
diff --git a/perlcritic/perlcriticrc b/perlcritic/perlcriticrc
index ed1d9064..bc8453f8 100644
--- a/perlcritic/perlcriticrc
+++ b/perlcritic/perlcriticrc
@@ -1,5 +1,23 @@
+# No mercy!
severity = brutal
-exclude = Bangs::ProhibitBitwiseOperators
+# I flatly disagree with this policy; sometimes bitwise operators are in fact
+# what I want, and I don't have the problem of using | instead of || as the
+# policy documentation suggests
+[-Bangs::ProhibitBitwiseOperators]
+
+# Add some networking terms to the list of legal numbered names
[Bangs::ProhibitNumberedNames]
-exceptions = inet4 inet6 ipv4 ipv6 md5 sha1 sha256 sha512 x11 utf8
+add_exceptions = inet4 inet6 ipv4 ipv6
+
+# I'll keep code running for old Perls, but users are on their own with
+# documentation, so allow e.g. L<http://...> on Perl 5.6
+[-Compatibility::PodMinimumVersion]
+
+# This one causes more trouble than it's worth, too
+[-Documentation::RequirePODUseEncodingUTF8]
+
+# Soften this policy a bit; tolerate all the single-digit integers as literals,
+# and also three powers of 10 (for percentages, milliseconds etc)
+[ValuesAndExpressions::ProhibitMagicNumbers]
+allowed_values = 0..9 10 100 1000
diff --git a/plenv/profile.d/plenv.sh b/plenv/profile.d/plenv.sh
new file mode 100644
index 00000000..b2b491e1
--- /dev/null
+++ b/plenv/profile.d/plenv.sh
@@ -0,0 +1,5 @@
+# Add plenv to PATH and MANPATH if it appears to be in use
+[ -d "$HOME"/.plenv ] || return
+PATH=$HOME/.plenv/shims:$HOME/.plenv/bin:$PATH
+MANPATH=$HOME/.plenv/versions/$(perl -e 'print substr($^V,1)')/man:$MANPATH
+export MANPATH
diff --git a/plenv/shrc.d/plenv.sh b/plenv/shrc.d/plenv.sh
new file mode 100644
index 00000000..6e03618e
--- /dev/null
+++ b/plenv/shrc.d/plenv.sh
@@ -0,0 +1,17 @@
+# POSIX-compatible version of the plenv Bash shell wrapper
+[ -d "$HOME"/.plenv ] || return
+plenv() {
+ case $1 in
+ rehash)
+ shift
+ eval "$(plenv sh-rehash "$@")"
+ ;;
+ shell)
+ shift
+ eval "$(plenv sh-shell "$@")"
+ ;;
+ *)
+ command plenv "$@"
+ ;;
+ esac
+}
diff --git a/readline/inputrc b/readline/inputrc
index 5254656e..7e4b500d 100644
--- a/readline/inputrc
+++ b/readline/inputrc
@@ -62,6 +62,9 @@ $if Bash
# Alt+A cycles through completion options
"\ea": menu-complete
+ # Ctrl-Alt-L to clear screen; more ksh-like
+ "\e\C-l": clear-screen
+
# Alt-E (for exec) to prepend "exec " to a command and return to the end of
# the line
"\ee": "\C-aexec \C-e"
@@ -71,8 +74,8 @@ $if Bash
# Alt-S (for set) to wrap current command in (set -x ; ...)
"\es": "\C-a(set -x ; \C-e)\C-b"
- # Alt-M (for muxer) to run tmux
- "\em": "\C-utmux\C-j\C-y"
+ # Alt-M (for muxer) to run tm(1df)
+ "\em": "\C-utm\C-j\C-y"
# Ctrl-Alt-B to move backward a shell-quoted word
"\e\C-b": shell-backward-word
diff --git a/sh/profile.d/downloads.sh b/sh/profile.d/downloads.sh
new file mode 100644
index 00000000..865cb859
--- /dev/null
+++ b/sh/profile.d/downloads.sh
@@ -0,0 +1,31 @@
+# Only if shell is interactive
+case $- in
+ *i*) ;;
+ *) return ;;
+esac
+
+# Only if not in a tmux window
+[ -z "$TMUX" ] || return
+
+# Not if ~/.hushlogin exists
+[ -e "$HOME"/.hushlogin ] && return
+
+# Not if ~/.downloads doesn't
+[ -f "$HOME"/.downloads ] || return
+
+# Count files in each directory, report if greater than zero
+(
+ lc=0
+ while IFS= read -r dir ; do
+ case $dir in
+ '#'*) continue ;;
+ esac
+ [ -d "$dir" ] || continue
+ set -- "$dir"/*
+ [ -e "$1" ] || shift
+ [ "$#" -gt 0 ] || continue
+ printf 'You have %u unsorted files in %s.\n' "$#" "$dir"
+ lc=$((lc+1))
+ done < "$HOME"/.downloads
+ [ "$((lc > 0))" -eq 1 ] && printf '\n'
+)
diff --git a/sh/profile.d/editor.sh b/sh/profile.d/editor.sh
index ee0da70b..debb93b6 100644
--- a/sh/profile.d/editor.sh
+++ b/sh/profile.d/editor.sh
@@ -1,3 +1,25 @@
-# Set command-line editor
-EDITOR=ed
+# Ideally, we'd use plain old ed(1), but many Linux distributions don't install
+# it by default
+if command -v ed >/dev/null 2>&1 ; then
+ EDITOR=ed
+
+# Failing that, if the system's implementation of ex(1) looks like Vim and we
+# have exm(1df) in our $PATH, use the latter to work around Vim's ex mode
+# screen-clearing
+elif (
+ command -v ex >/dev/null 2>&1 || exit 1
+ command -v exm >/dev/null 2>&1 || exit 1
+ ver=$(ex --version 2>/dev/null | awk 'NR==1{print $1;exit}')
+ case $ver in
+ (VIM) exit 0 ;;
+ (*) exit 1 ;;
+ esac
+) >/dev/null 2>&1 ; then
+ EDITOR=exm
+
+# Otherwise, we can just call ex(1) directly
+else
+ EDITOR=ex
+fi
+
export EDITOR
diff --git a/sh/profile.d/games.sh b/sh/profile.d/games.sh
index 58db3487..956d1de1 100644
--- a/sh/profile.d/games.sh
+++ b/sh/profile.d/games.sh
@@ -1,2 +1,3 @@
# Add ~/.local/games to PATH if it exists
-[ -d "$HOME"/.local/games ] && PATH=$HOME/.local/games:$PATH
+[ -d "$HOME"/.local/games ] || return
+PATH=$PATH:$HOME/.local/games
diff --git a/sh/profile.d/keychain.sh b/sh/profile.d/keychain.sh
deleted file mode 100644
index 9213de7f..00000000
--- a/sh/profile.d/keychain.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-# keychain setup
-command -v keychain >/dev/null 2>&1 &&
- eval "$(TERM=${TERM:-ansi} keychain \
- --eval --ignore-missing --quick --quiet \
- id_dsa id_rsa id_ecsda)"
diff --git a/sh/profile.d/lang.sh b/sh/profile.d/lang.sh
new file mode 100644
index 00000000..21f67d5b
--- /dev/null
+++ b/sh/profile.d/lang.sh
@@ -0,0 +1,4 @@
+# Always use bytewise sorting if not already set
+[ -z "$LC_COLLATE" ] || return
+LC_COLLATE=C
+export LC_COLLATE
diff --git a/sh/profile.d/options.sh b/sh/profile.d/options.sh
index aa7e9ace..89b5d245 100644
--- a/sh/profile.d/options.sh
+++ b/sh/profile.d/options.sh
@@ -1,31 +1,32 @@
# Cache the options available to certain programs. Run all this in a subshell
# (none of its state needs to endure in the session)
(
-options() (
+options() {
# Check or create the directory to cache the options
- dir=$HOME/.cache/$1
+ # Shift the program name off; remaining arguments are the options to check
+ dir=$HOME/.cache/sh/opt/$1
+ prog=$1
+ shift
# Directory already exists; bail out
- [ -d "$dir" ] && exit
+ [ -d "$dir" ] && return
# Create the directory and step into it
- command -p mkdir -p -- "$dir" || exit
- cd -- "$dir" || exit
+ command -p mkdir -p -- "$dir" || return
+ cd -- "$dir" || return
# Write the program's --help output to a file, even if it's empty
- "$1" --help </dev/null >help 2>/dev/null || exit
-
- # Shift the program name off; remaining arguments are the options to check
- shift
+ # This probably only works with GNU tools in general
+ "$prog" --help </dev/null >help 2>/dev/null || return
- # Iterate through some useful options and create files to show they're
- # available if found in the help output
+ # Iterate through remaining arguments (desired options), creating files to
+ # show they're available if found in the help output
for opt ; do
command -p grep -q -- '[^[:alnum:]]--'"$opt"'[^[:alnum:]]' help &&
touch -- "$opt"
done
-)
+}
# Cache options for bc(1)
options bc \
@@ -46,12 +47,9 @@ options grep \
# Cache options for ls(1)
options ls \
- almost-all \
- block-size \
- classify \
- color \
- format \
- hide-control-chars \
- human-readable \
+ almost-all \
+ block-size \
+ color \
+ human-readable \
time-style
)
diff --git a/sh/profile.d/visual.sh b/sh/profile.d/visual.sh
index 95eb1d5d..38ab9893 100644
--- a/sh/profile.d/visual.sh
+++ b/sh/profile.d/visual.sh
@@ -1,3 +1,3 @@
-# Set visual editor
+# Use first found implementation of vi(1)
VISUAL=vi
export VISUAL
diff --git a/sh/shrc b/sh/shrc
index 879c8947..33c55e8f 100644
--- a/sh/shrc
+++ b/sh/shrc
@@ -20,5 +20,6 @@ for sh in "$HOME"/.shrc.d/*.sh ; do
done
unset -v sh
-# If ENV_EXT was set and exists, source that too
+# If ENV_EXT was set and exists, source that too, then clean it away
[ -e "$ENV_EXT" ] && . "$ENV_EXT"
+unset -v ENV_EXT
diff --git a/sh/shrc.d/ad.sh b/sh/shrc.d/ad.sh
deleted file mode 100644
index 55866683..00000000
--- a/sh/shrc.d/ad.sh
+++ /dev/null
@@ -1,80 +0,0 @@
-# Find an abbreviated path
-ad() {
-
- # Check argument count
- if [ "$#" -ne 1 ] ; then
- printf >&2 'ad(): Need just one argument\n'
- return 2
- fi
-
- # Change the positional parameters from the abbreviated request
- # to any matched directory
- set -- "$(
-
- # Clean up and anchor the request
- req=${1%/}/
- case $req in
- (/*) ;;
- (*) req=${PWD%/}/${req#/} ;;
- esac
-
- # Start building the target directory; go through the request piece by
- # piece until it is used up
- dir=
- while [ -n "$req" ] ; do
-
- # Chop the next front bit off the request and add it to the dir
- dir=${dir%/}/${req%%/*}
- req=${req#*/}
-
- # If that exists, all is well and we can keep iterating
- [ -d "$dir" ] && continue
-
- # Set the positional parameters to a glob expansion of the
- # abbreviated directory given
- set -- "$dir"*
-
- # Iterate through the positional parameters filtering out
- # directories; we need to run right through the whole list to check
- # that we have at most one match
- entd=
- for ent ; do
- [ -d "$ent" ] || continue
-
- # If we already found a match and have found another one, bail
- # out
- if [ -n "$entd" ] ; then
- printf >&2 'ad(): More than one matching dir for %s*:\n' \
- "$dir"
- printf >&2 '%s\n' "$@"
- exit 1
- fi
-
- # Otherwise, this can be our first one
- entd=$ent
- done
-
- # If we found no match, bail out
- if [ -z "$entd" ] ; then
- printf >&2 'ad(): No matching dirs: %s*\n' "$dir"
- exit 1
- fi
-
- # All is well, tack on what we have found and keep going
- dir=$entd
-
- done
-
- # Print the target with trailing slash to work around newline stripping
- printf '%s/' "${dir%/}"
- )"
-
- # Remove trailing slash
- set -- "${1%/}"
-
- # If the subshell printed nothing, return with failure
- [ -n "$1" ] || return
-
- # Try to change into the determined directory
- command cd -- "$@"
-}
diff --git a/sh/shrc.d/bc.sh b/sh/shrc.d/bc.sh
index 41331ff9..aee88e09 100644
--- a/sh/shrc.d/bc.sh
+++ b/sh/shrc.d/bc.sh
@@ -1,12 +1,12 @@
# Our ~/.profile should already have made a directory with the supported
# options for us; if not, we won't be wrapping bc(1) with a function at all
-[ -d "$HOME"/.cache/bc ] || return
+[ -d "$HOME"/.cache/sh/opt/bc ] || return
# Define function proper
bc() {
# Add --quiet to stop the annoying welcome banner
- [ -e "$HOME"/.cache/bc/quiet ] &&
+ [ -e "$HOME"/.cache/sh/opt/bc/quiet ] &&
set -- --quiet "$@"
# Run bc(1) with the concluded arguments
diff --git a/sh/shrc.d/bd.sh b/sh/shrc.d/bd.sh
index bf64a9aa..29bde513 100644
--- a/sh/shrc.d/bd.sh
+++ b/sh/shrc.d/bd.sh
@@ -1,70 +1,47 @@
# Move back up the directory tree to the first directory matching the name
bd() {
- # Check argument count
+ # Check arguments; default to ".."
if [ "$#" -gt 1 ] ; then
- printf >&2 'bd(): Too many arguments'
+ printf >&2 'bd(): Too many arguments\n'
return 2
fi
-
- # Set positional parameters to an option terminator and what will hopefully
- # end up being a target directory
- set -- "$(
-
- # The requested pattern is the first argument, defaulting to just the
- # parent directory
- req=${1:-..}
-
- # Strip trailing slashes if a trailing slash is not the whole pattern
- [ "$req" = / ] || req=${req%/}
-
- # What to do now depends on the request
- case $req in
-
- # Just go straight to the root or dot directories if asked
- (/|.|..)
- dirname=$req
- ;;
-
- # Anything with a leading / needs to anchor to the start of the
- # path. A strange request though. Why not just use cd?
- (/*)
- dirname=$req
- case $PWD in
- ("$dirname"/*) ;;
- (*) dirname='' ;;
+ set -- "${1:-..}"
+
+ # Look at argument given; default to going up one level
+ case $1 in
+
+ # If it's slash, dot, or dot-dot, we'll just go there, like `cd` would
+ /|.|..) ;;
+
+ # Anything else with a slash anywhere is an error
+ */*)
+ printf >&2 'bd(): Illegal slash\n'
+ return 2
+ ;;
+
+ # Otherwise, add and keep chopping at the current directory until it's
+ # empty or it matches the request, then shift the request off
+ *)
+ set -- "$1" "$PWD"
+ while : ; do
+ case $2 in
+ */"$1"|'') break ;;
+ */) set -- "$1" "${2%/}" ;;
+ */*) set -- "$1" "${2%/*}" ;;
+ *) set -- "$1" '' ;;
esac
- ;;
-
- # In all other cases, iterate through the PWD to find a match, or
- # whittle the target down to an empty string trying
- (*)
- dirname=$PWD
- while [ -n "$dirname" ] ; do
- dirname=${dirname%/*}
- case $dirname in
- (*/"$req") break ;;
- esac
- done
- ;;
- esac
-
- # Check we have a target after all that
- if [ -z "$dirname" ] ; then
- printf >&2 'bd(): Directory name not in path\n'
- exit 1
- fi
-
- # Print the target with trailing slash to work around newline stripping
- printf '%s/' "${dirname%/}"
- )"
-
- # Remove trailing slash
- set -- "${1%/}"
-
- # If the subshell printed nothing, return with failure
- [ -n "$1" ] || return
+ done
+ shift
+ ;;
+ esac
+
+ # If we have nothing to change into, there's an error
+ if [ -z "$1" ] ; then
+ printf >&2 'bd(): No match\n'
+ return 1
+ fi
- # Try to change into the determined directory
- command cd -- "$@"
+ # We have a match; try and change into it
+ command cd -- "$1"
}
diff --git a/sh/shrc.d/ed.sh b/sh/shrc.d/ed.sh
index d7d3fa2f..e6b6eee8 100644
--- a/sh/shrc.d/ed.sh
+++ b/sh/shrc.d/ed.sh
@@ -1,3 +1,7 @@
+# Our ~/.profile should already have made a directory with the supported
+# options for us; if not, we won't be wrapping ed(1) with a function at all
+[ -d "$HOME"/.cache/sh/opt/ed ] || return
+
# Define function proper
ed() {
@@ -8,7 +12,7 @@ ed() {
fi
# Add --verbose to explain errors
- [ -e "$HOME"/.cache/ed/verbose ] &&
+ [ -e "$HOME"/.cache/sh/opt/ed/verbose ] &&
set -- --verbose "$@"
# Add an asterisk prompt (POSIX feature)
diff --git a/sh/shrc.d/env.sh b/sh/shrc.d/env.sh
deleted file mode 100644
index 4fa980f2..00000000
--- a/sh/shrc.d/env.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-# Sort the output of env(1) for me
-env() {
- if [ "$#" -eq 0 ] ; then
- command env | sort
- else
- command env "$@"
- fi
-}
diff --git a/sh/shrc.d/gd.sh b/sh/shrc.d/gd.sh
index 5a3f54b0..9f6a43e7 100644
--- a/sh/shrc.d/gd.sh
+++ b/sh/shrc.d/gd.sh
@@ -8,9 +8,9 @@ gd() {
fi
# Complain if mark not actually set yet
- if ! [ -n "$PMD" ] ; then
+ if [ -z "$PMD" ] ; then
printf >&2 'gd(): Mark not set\n'
- return 2
+ return 1
fi
# Go to the marked directory
diff --git a/sh/shrc.d/grep.sh b/sh/shrc.d/grep.sh
index a52b6f90..3df1ee9a 100644
--- a/sh/shrc.d/grep.sh
+++ b/sh/shrc.d/grep.sh
@@ -1,36 +1,39 @@
# Our ~/.profile should already have made a directory with the supported
# options for us; if not, we won't be wrapping grep(1) with a function at all
-[ -d "$HOME"/.cache/grep ] || return
+[ -d "$HOME"/.cache/sh/opt/grep ] || return
+
+# Discard GNU grep(1) environment variables if the environment set them
+unset -v GREP_OPTIONS
# Define function proper
grep() {
# Add --binary-files=without-match to gracefully skip binary files
- [ -e "$HOME"/.cache/grep/binary-files ] &&
+ [ -e "$HOME"/.cache/sh/opt/grep/binary-files ] &&
set -- --binary-files=without-match "$@"
# Add --color=auto if the terminal has at least 8 colors
- [ -e "$HOME"/.cache/grep/color ] &&
- [ "$({ tput colors || tput Co ; } 2>/dev/null)" -ge 8 ] &&
+ [ -e "$HOME"/.cache/sh/opt/grep/color ] &&
+ [ "$({ tput colors||tput Co||echo 0; } 2>/dev/null)" -ge 8 ] &&
set -- --color=auto "$@"
# Add --devices=skip to gracefully skip devices
- [ -e "$HOME"/.cache/grep/devices ] &&
+ [ -e "$HOME"/.cache/sh/opt/grep/devices ] &&
set -- --devices=skip "$@"
# Add --directories=skip to gracefully skip directories
- [ -e "$HOME"/.cache/grep/directories ] &&
+ [ -e "$HOME"/.cache/sh/opt/grep/directories ] &&
set -- --directories=skip "$@"
# Add --exclude to ignore .gitignore and .gitmodules files
- [ -e "$HOME"/.cache/grep/exclude ] &&
+ [ -e "$HOME"/.cache/sh/opt/grep/exclude ] &&
set -- \
--exclude=.gitignore \
--exclude=.gitmodules \
"$@"
# Add --exclude-dir to ignore version control dot-directories
- [ -e "$HOME"/.cache/grep/exclude-dir ] &&
+ [ -e "$HOME"/.cache/sh/opt/grep/exclude-dir ] &&
set -- \
--exclude-dir=.cvs \
--exclude-dir=.git \
diff --git a/sh/shrc.d/gt.sh b/sh/shrc.d/gt.sh
new file mode 100644
index 00000000..95ab4c2f
--- /dev/null
+++ b/sh/shrc.d/gt.sh
@@ -0,0 +1,26 @@
+# If the argument is a directory, change to it. If it's a file, change to its
+# parent. Stands for "get to".
+gt() {
+
+ # Check argument count
+ if [ "$#" -ne 1 ] ; then
+ printf >&2 'gt(): Need one argument\n'
+ return 2
+ fi
+
+ # Make certain there are no trailing slashes to foul us up, and anchor path
+ # if relative
+ while : ; do
+ case $1 in
+ */) set -- "${1%/}" ;;
+ /*) break ;;
+ *) set -- "$PWD"/"$1" ;;
+ esac
+ done
+
+ # If target isn't a directory, chop to its parent
+ [ -d "$1" ] || set -- "${1%/*}"
+
+ # Try to change into the determined directory, or root if empty
+ command cd -- "${1:-/}"
+}
diff --git a/sh/shrc.d/hgrep.sh b/sh/shrc.d/hgrep.sh
index 1c4c3ec5..9d7542b4 100644
--- a/sh/shrc.d/hgrep.sh
+++ b/sh/shrc.d/hgrep.sh
@@ -6,11 +6,11 @@
hgrep() {
if [ "$#" -eq 0 ] ; then
printf >&2 'hgrep(): Need a pattern\n'
- exit 2
+ return 2
fi
- if ! [ -n "$HISTFILE" ] ; then
- printf >&2 'hgrep(): No HISTFILE\n'
- exit 2
+ if [ -z "$HISTFILE" ] ; then
+ printf >&2 'hgrep(): HISTFILE unset or null\n'
+ return 2
fi
grep "$@" "$HISTFILE"
}
diff --git a/sh/shrc.d/la.sh b/sh/shrc.d/la.sh
index e21ad8fb..1ac44b8e 100644
--- a/sh/shrc.d/la.sh
+++ b/sh/shrc.d/la.sh
@@ -1,7 +1,7 @@
# Run ls -A if we can (-A is not POSIX), ls -a otherwise
la() {
# Prefer --almost-all (exclude "." and "..") if available
- if [ -e "$HOME"/.cache/ls/almost-all ] ; then
+ if [ -e "$HOME"/.cache/sh/opt/ls/almost-all ] ; then
set -- -A "$@"
else
set -- -a "$@"
diff --git a/sh/shrc.d/less.sh b/sh/shrc.d/less.sh
new file mode 100644
index 00000000..2778ce65
--- /dev/null
+++ b/sh/shrc.d/less.sh
@@ -0,0 +1,2 @@
+# Unset stupid env vars to avoid interfering with my less(1) setup
+unset -v LESS LESSOPEN
diff --git a/sh/shrc.d/lgt.sh b/sh/shrc.d/lgt.sh
new file mode 100644
index 00000000..fbe43369
--- /dev/null
+++ b/sh/shrc.d/lgt.sh
@@ -0,0 +1,28 @@
+# Run loc(1df) with given arguments and then run gt() to get to the first
+# argument found
+lgt() {
+
+ # Check argument count
+ if [ "$#" -eq 0 ] ; then
+ printf >&2 'lgt(): Need a search term\n'
+ return 2
+ fi
+
+ # Change the positional parameters from the loc(1df) arguments to the first
+ # result with a trailing slash
+ set -- "$(
+ loc "$@" | {
+ IFS= read -r target
+ printf '%s/' "$target"
+ }
+ )"
+
+ # Strip the trailing slash
+ set -- "${1%/}"
+
+ # If the subshell printed nothing, return with failure
+ [ -n "$1" ] || return
+
+ # Run gt() with the new arguments
+ gt "$@"
+}
diff --git a/sh/shrc.d/ll.sh b/sh/shrc.d/ll.sh
index c8c95d3b..e9737c62 100644
--- a/sh/shrc.d/ll.sh
+++ b/sh/shrc.d/ll.sh
@@ -1,7 +1,7 @@
# Run ls -Al if we can (-A is not POSIX), ls -al otherwise
ll() {
# Prefer -A/--almost-all (exclude "." and "..") if available
- if [ -e "$HOME"/.cache/ls/almost-all ] ; then
+ if [ -e "$HOME"/.cache/sh/opt/ls/almost-all ] ; then
set -- -Al "$@"
else
set -- -al "$@"
diff --git a/sh/shrc.d/ls.sh b/sh/shrc.d/ls.sh
index 7e916239..7e843cc7 100644
--- a/sh/shrc.d/ls.sh
+++ b/sh/shrc.d/ls.sh
@@ -1,38 +1,48 @@
# Our ~/.profile should already have made a directory with the supported
# options for us; if not, we won't be wrapping ls(1) with a function at all
-[ -d "$HOME"/.cache/ls ] || return
+[ -d "$HOME"/.cache/sh/opt/ls ] || return
+
+# If the system has already aliased ls(1) for us, like Slackware or OpenBSD
+# does, just get rid of it
+unalias ls >/dev/null 2>&1
+
+# Discard GNU ls(1) environment variables if the environment set them
+unset -v LS_OPTIONS LS_COLORS
# Define function proper
ls() {
+ # -F to show trailing indicators of the filetype
+ # -q to replace control chars with '?'
+ set -- -Fq "$@"
+
+ # If output is to a terminal, add -x to format entries across, not down
+ [ -t 1 ] && set -- -x "$@"
+
# Add --block-size=K to always show the filesize in kibibytes
- [ -e "$HOME"/.cache/ls/block-size ] &&
+ [ -e "$HOME"/.cache/sh/opt/ls/block-size ] &&
set -- --block-size=1024 "$@"
- # Add --classify to show trailing indicators of the filetype
- [ -e "$HOME"/.cache/ls/classify ] &&
- set -- --classify "$@"
-
# Add --color if the terminal has at least 8 colors
- [ -e "$HOME"/.cache/ls/color ] &&
- [ "$({ tput colors || tput Co ; } 2>/dev/null)" -ge 8 ] &&
+ [ -e "$HOME"/.cache/sh/opt/ls/color ] &&
+ [ "$({ tput colors||tput Co||echo 0; } 2>/dev/null)" -ge 8 ] &&
set -- --color=auto "$@"
- # Add --format=horizontal to print entries in a saner way
- [ -e "$HOME"/.cache/ls/format ] &&
- set -- --format=horizontal "$@"
-
- # Add --hide-control-chars if present; we always want this interactively,
- # even if the output is to a pager; we shouldn't be trying to script ls(1)
- # output anyway
- [ -e "$HOME"/.cache/ls/hide-control-chars ] &&
- set -- --hide-control-chars "$@"
-
# Add --time-style='+%Y-%m-%d %H:%M:%S' to show the date in my preferred
- # format
- [ -e "$HOME"/.cache/ls/time-style ] &&
+ # (fixed) format
+ [ -e "$HOME"/.cache/sh/opt/ls/time-style ] &&
set -- --time-style='+%Y-%m-%d %H:%M:%S' "$@"
+ # If the operating system is FreeBSD, there are some specific options we
+ # can add that might mean different things to e.g. GNU ls(1)
+ case $OS in
+ FreeBSD)
+ # -D: Timestamp format
+ # -G: Use color
+ set -- -D '%Y-%m-%d %H:%M:%S' -G "$@"
+ ;;
+ esac
+
# Run ls(1) with the concluded arguments
command ls "$@"
}
diff --git a/sh/shrc.d/md.sh b/sh/shrc.d/md.sh
index 6fd3d7ca..a7134931 100644
--- a/sh/shrc.d/md.sh
+++ b/sh/shrc.d/md.sh
@@ -7,11 +7,14 @@ md() {
return 2
fi
- # If first arg unset or empty, assume the user means the current dir
- [ -n "$1" ] || set -- "$PWD"
-
- # Jump to the dir and emit PWD from a subshell to get an absolute path
- set -- "$(cd -- "$1" && printf %s "$PWD")"
+ # If argument given, change to it in subshell to get absolute path.
+ # If not, use current working directory.
+ if [ -n "$1" ] ; then
+ set -- "$(cd -- "$1" && printf '%s/' "$PWD")"
+ set -- "${1%%/}"
+ else
+ set -- "$PWD"
+ fi
# If that turned up empty, we have failed; the cd call probably threw an
# error for us too
diff --git a/sh/shrc.d/mysql.sh b/sh/shrc.d/mysql.sh
deleted file mode 100644
index abb496d2..00000000
--- a/sh/shrc.d/mysql.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-# If a file ~/.mysql/$1.cnf exists, call mysql(1) using that file, discarding
-# the rest of the arguments. Otherwise just run MySQL with given args. Use
-# restrictive permissions on these files. Doesn't allow filenames beginning
-# with hyphens.
-#
-# Examples:
-#
-# [client]
-# host=dbhost.example.com
-# user=foo
-# password=SsJ2pICe226jM
-#
-# [mysql]
-# database=bar
-#
-mysql() {
- case $1 in
- -*) ;;
- *)
- [ -f "$HOME/.mysql/$1".cnf ] &&
- set -- --defaults-extra-file="$HOME/.mysql/$1".cnf
- ;;
- esac
- command mysql "$@"
-}
diff --git a/sh/shrc.d/path.sh b/sh/shrc.d/path.sh
index 3caabbc9..b6b1820f 100644
--- a/sh/shrc.d/path.sh
+++ b/sh/shrc.d/path.sh
@@ -1,20 +1,11 @@
# Function to manage contents of PATH variable within the current shell
path() {
- # The second argument, the directory, can never have a colon
- case $2 in
- *:*)
- printf >&2 'path(): %s illegal colon\n' "$2"
- return 2
- ;;
- esac
-
# Check first argument to figure out operation
case $1 in
# List current directories in PATH
list|'') (
- # shellcheck disable=SC2030
path=$PATH:
while [ -n "$path" ] ; do
dir=${path%%:*}
@@ -24,10 +15,28 @@ path() {
done
) ;;
+ # Helper function checks directory argument makes sense
+ _argcheck)
+ shift
+ if [ "$#" -gt 2 ] ; then
+ printf >&2 'path(): %s: too many arguments\n' "$1"
+ return 2
+ fi
+ case $2 in
+ *:*)
+ printf >&2 'path(): %s: %s contains colon\n' "$@"
+ return 2
+ ;;
+ esac
+ return 0
+ ;;
+
# Add a directory at the start of $PATH
insert)
+ [ "$#" -eq 2 ] || set -- "$1" "$PWD"
+ path _argcheck "$@" || return
if path check "$2" ; then
- printf >&2 'path(): %s already in PATH\n' "$2"
+ printf >&2 'path(): %s: %s already in PATH\n' "$@"
return 1
fi
PATH=${2}${PATH:+:"$PATH"}
@@ -35,8 +44,10 @@ path() {
# Add a directory to the end of $PATH
append)
+ [ "$#" -eq 2 ] || set -- "$1" "$PWD"
+ path _argcheck "$@" || return
if path check "$2" ; then
- printf >&2 'path(): %s already in PATH\n' "$2"
+ printf >&2 'path(): %s: %s already in PATH\n' "$@"
return 1
fi
PATH=${PATH:+"$PATH":}${2}
@@ -44,21 +55,59 @@ path() {
# Remove a directory from $PATH
remove)
+ [ "$#" -eq 2 ] || set -- "$1" "$PWD"
+ path _argcheck "$@" || return
if ! path check "$2" ; then
- printf >&2 'path(): %s not in PATH\n' "$2"
+ printf >&2 'path(): %s: %s not in PATH\n' "$@"
return 1
fi
PATH=$(
path=:$PATH:
path=${path%%:"$2":*}:${path#*:"$2":}
path=${path#:}
- path=${path%:}
- printf '%s\n' "$path"
+ printf '%s:' "$path"
)
+ PATH=${PATH%%:}
+ ;;
+
+ # Remove the first directory in $PATH
+ shift)
+ case $PATH in
+ '')
+ printf >&2 'path(): %s: PATH is empty!\n' "$@"
+ return 1
+ ;;
+ *:*)
+ PATH=${PATH#*:}
+ ;;
+ *)
+ # shellcheck disable=SC2123
+ PATH=
+ ;;
+ esac
+ ;;
+
+ # Remove the last directory in $PATH
+ pop)
+ case $PATH in
+ '')
+ printf >&2 'path(): %s: PATH is empty!\n' "$@"
+ return 1
+ ;;
+ *:*)
+ PATH=${PATH%:*}
+ ;;
+ *)
+ # shellcheck disable=SC2123
+ PATH=
+ ;;
+ esac
;;
# Check whether a directory is in PATH
check)
+ path _argcheck "$@" || return
+ [ "$#" -eq 2 ] || set -- "$1" "$PWD"
case :$PATH: in
*:"$2":*) return 0 ;;
esac
@@ -73,23 +122,26 @@ path(): Manage contents of PATH variable
USAGE:
path [list]
Print the current directories in PATH, one per line (default command)
- path insert DIR
- Add a directory to the front of PATH
- path append DIR
- Add a directory to the end of PATH
- path remove DIR
- Remove directory from PATH
- path check DIR
- Return whether DIR is a component of PATH
+ path insert [DIR]
+ Add directory DIR (default $PWD) to the front of PATH
+ path append [DIR]
+ Add directory DIR (default $PWD) to the end of PATH
+ path remove [DIR]
+ Remove directory DIR (default $PWD) from PATH
+ path shift
+ Remove the first directory from PATH
+ path pop
+ Remove the last directory from PATH
+ path check [DIR]
+ Return whether directory DIR (default $PWD) is a component of PATH
path help
- Print this help message (also done if command not found)
+ Print this help message
EOF
;;
# Command not found
*)
- printf >&2 'path(): Unknown command\n'
- path help >&2
+ printf >&2 'path(): %s: Unknown command (try "help")\n' "$1"
return 2
;;
esac
diff --git a/sh/shrc.d/pd.sh b/sh/shrc.d/pd.sh
index ce43837b..e3a6daaa 100644
--- a/sh/shrc.d/pd.sh
+++ b/sh/shrc.d/pd.sh
@@ -2,39 +2,30 @@
# use when you've got a file path in a variable, or in history, or in Alt+.,
# and want to quickly move to its containing directory. In the absence of an
# argument, this just shifts up a directory, i.e. `cd ..`
+#
+# Note this is equivalent to `ud 1`.
pd() {
- # Check argument count
+ # Check arguments; default to $PWD
if [ "$#" -gt 1 ] ; then
printf >&2 'pd(): Too many arguments\n'
return 2
fi
-
- # Change the positional parameters from the target to its containing
- # directory
- set -- "$(
-
- # Figure out target dirname
- dirname=${1:-..}
- dirname=${dirname%/}
- dirname=${dirname%/*}
-
- # Check we have a target after that
- if [ -z "$dirname" ] ; then
- printf >&2 'ud(): Destination construction failed\n'
- exit 1
- fi
-
- # Print the target with trailing slash to work around newline stripping
- printf '%s/' "${dirname%/}"
- )"
-
- # Remove trailing slash
- set -- "${1%/}"
-
- # If the subshell printed nothing, return with failure
- [ -n "$1" ] || return
-
- # Try to change into the determined directory
- command cd -- "$@"
+ set -- "${1:-"$PWD"}"
+
+ # Make certain there are no trailing slashes to foul us up, and anchor path
+ # if relative
+ while : ; do
+ case $1 in
+ */) set -- "${1%/}" ;;
+ /*) break ;;
+ *) set -- "$PWD"/"$1" ;;
+ esac
+ done
+
+ # Strip a path element
+ set -- "${1%/*}"
+
+ # Try to change into the determined directory, or root if empty
+ command cd -- "${1:-/}"
}
diff --git a/sh/shrc.d/pmd.sh b/sh/shrc.d/pmd.sh
index 03f18b7b..4b0cd5bd 100644
--- a/sh/shrc.d/pmd.sh
+++ b/sh/shrc.d/pmd.sh
@@ -1,8 +1,8 @@
# Print the marked directory
pmd() {
- if ! [ -n "$PMD" ] ; then
+ if [ -z "$PMD" ] ; then
printf >&2 'pmd(): Mark not set\n'
- return 2
+ return 1
fi
printf '%s\n' "$PMD"
}
diff --git a/sh/shrc.d/prompt.sh b/sh/shrc.d/prompt.sh
new file mode 100644
index 00000000..30e4e9d8
--- /dev/null
+++ b/sh/shrc.d/prompt.sh
@@ -0,0 +1,11 @@
+# Some systems' /etc/profile setups export PS1, which really fouls things up
+# when switching between non-login shells; let's put things right by unsetting
+# it to break the export and then just setting them as simple variables
+unset PS1 PS2 PS3 PS4
+PS1='$ ' PS2='> ' PS3='? ' PS4='+ '
+
+# If we have an SSH_CLIENT or SSH_CONNECTION environment variable, put the
+# hostname in PS1 too.
+if [ -n "$SSH_CLIENT" ] || [ -n "$SSH_CONNECTION" ] ; then
+ PS1=$(hostname -s)'$ '
+fi
diff --git a/sh/shrc.d/rd.sh b/sh/shrc.d/rd.sh
index 3b699c0d..9633713a 100644
--- a/sh/shrc.d/rd.sh
+++ b/sh/shrc.d/rd.sh
@@ -1,4 +1,3 @@
-#
# Replace the first instance of the first argument string with the second
# argument string in $PWD, and make that the target of the cd builtin. This is
# to emulate a feature of the `cd` builtin in Zsh that I like, but that I think
@@ -12,7 +11,6 @@
# $ rd usr opt
# $ pwd
# /opt/bin
-#
rd() {
# Check argument count
@@ -25,42 +23,17 @@ rd() {
;;
esac
- # Set the positional parameters to an option terminator and what will
- # hopefully end up being the substituted directory name
- set -- "$(
-
- # Current path: e.g. /foo/ayy/bar/ayy
- cur=$PWD
- # Pattern to replace: e.g. ayy
- pat=$1
- # Text with which to replace pattern: e.g. lmao
- # This can be a null string or unset, in order to *remove* the pattern
- rep=$2
-
- # /foo/
- curtc=${cur%%"$pat"*}
- # /bar/ayy
- curlc=${cur#*"$pat"}
- # /foo/lmao/bar/ayy
- new=${curtc}${rep}${curlc}
-
- # Check that a substitution resulted in an actual change and that we
- # ended up with a non-null target, or print an error to stderr
- if [ "$cur" = "$curtc" ] || [ -z "$new" ] ; then
+ # Check there's something to substitute, and do it
+ case $PWD in
+ *"$1"*)
+ set -- "${PWD%%"$1"*}""$2""${PWD#*"$1"}"
+ ;;
+ *)
printf >&2 'rd(): Substitution failed\n'
- exit 1
- fi
-
- # Print the target with trailing slash to work around newline stripping
- printf '%s/' "${new%/}"
- )"
-
- # Remove trailing slash
- set -- "${1%/}"
-
- # If the subshell printed nothing, return with failure
- [ -n "$1" ] || return
+ return 1
+ ;;
+ esac
# Try to change into the determined directory
- command cd -- "$@"
+ command cd -- "$1"
}
diff --git a/sh/shrc.d/sd.sh b/sh/shrc.d/sd.sh
index 4d63b7d6..8b12c170 100644
--- a/sh/shrc.d/sd.sh
+++ b/sh/shrc.d/sd.sh
@@ -1,4 +1,3 @@
-#
# Shortcut to switch to another directory with the same parent, i.e. a sibling
# of the current directory.
#
@@ -31,7 +30,6 @@
# /tmp/tmp.ZSunna5Eup/a
#
# Seems to work for symbolic links.
-#
sd() {
# Check argument count
@@ -40,48 +38,80 @@ sd() {
return 2
fi
- # Change positional parameters to what will hopefully be a completed
- # substitution
- set -- "$(
+ # Read sole optional argument
+ case $1 in
+
+ # Slashes aren't allowed
+ */*)
+ printf >&2 'bd(): Illegal slash\n'
+ return 2
+ ;;
+
+ # If blank, we try to find if there's just one sibling, and change to
+ # that if so
+ '')
+ # First a special case: root dir
+ case $PWD in
+ *[!/]*) ;;
+ *)
+ printf >&2 'sd(): No siblings\n'
+ return 1
+ ;;
+ esac
+
+ # Get a full list of directories at this level; include dotfiles,
+ # but not the . and .. entries, using glob tricks to avoid Bash
+ # ruining things with `dotglob`
+ set -- ../[!.]*/
+ [ -e "$1" ] || shift
+ set -- ../.[!.]*/ "$@"
+ [ -e "$1" ] || shift
+ set -- ../..?*/ "$@"
+ [ -e "$1" ] || shift
+
+ # Check the number of matches
+ case $# in
+
+ # One match? Must be $PWD, so no siblings--throw in 0 just in
+ # case, but that Shouldn't Happen (TM)
+ 0|1)
+ printf >&2 'sd(): No siblings\n'
+ return 1
+ ;;
- # Set the positional parameters to either the requested directory, or
- # all siblings of the current directory if no request
- spec=$1
- set --
- if [ -n "$spec" ] ; then
- set -- "$@" ../"$spec"
- else
- for sib in ../.* ../* ; do
- case ${sib#../} in
- (.|..|"${PWD##*/}") continue ;;
- esac
- set -- "$@" "$sib"
- done
- fi
+ # Two matches; hopefully just one sibling, but which is it?
+ 2)
- # We should have exactly one sibling
- case $# in
- (1) ;;
- (0)
- printf >&2 'sd(): No siblings\n'
- exit 1
- ;;
- (*)
- printf >&2 'sd(): More than one sibling\n'
- exit 1
- ;;
- esac
+ # Push PWD onto the stack, strip trailing slashes
+ set -- "$1" "$2" "$PWD"
+ while : ; do
+ case $3 in
+ */) set -- "$1" "$2" "${3%/}" ;;
+ *) break ;;
+ esac
+ done
- # Print the target with trailing slash to work around newline stripping
- printf '%s/' "${1%/}"
- )"
+ # Pick whichever of our two parameters doesn't look like
+ # PWD as our sole parameter
+ case $1 in
+ ../"${3##*/}"/) set -- "$2" ;;
+ *) set -- "$1" ;;
+ esac
+ ;;
- # Remove trailing slash
- set -- "${1%/}"
+ # Anything else? Multiple siblings--user will need to specify
+ *)
+ printf >&2 'sd(): Multiple siblings\n'
+ return 1
+ ;;
+ esac
+ ;;
- # If the subshell printed nothing, return with failure
- [ -n "$1" ] || return
+ # If not, simply set our target to that directory, and let `cd` do the
+ # complaining if it doesn't exist
+ *) set -- ../"$1" ;;
+ esac
- # Try to change into the determined directory
- command cd -- "$@"
+ # Try and change into the first parameter
+ command cd -- "$1"
}
diff --git a/sh/shrc.d/tmux.sh b/sh/shrc.d/tmux.sh
deleted file mode 100644
index bd954be8..00000000
--- a/sh/shrc.d/tmux.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-# Attach to existing tmux session rather than create a new one if possible
-tmux() {
-
- # If given any arguments, just use them as they are
- if [ "$#" -gt 0 ] ; then
- :
-
- # If a session exists, just attach to it
- elif command tmux has-session 2>/dev/null ; then
- set -- attach-session -d
-
- # Create a new session with an appropriate name
- else
- set -- new-session -s "${TMUX_SESSION:-default}"
- fi
-
- # Execute with concluded arguments
- command tmux "$@"
-}
diff --git a/sh/shrc.d/tree.sh b/sh/shrc.d/tree.sh
index b4f91df8..ca134fe2 100644
--- a/sh/shrc.d/tree.sh
+++ b/sh/shrc.d/tree.sh
@@ -21,7 +21,7 @@ tree() {
[ -t 1 ] || exit
# Not if output terminal doesn't have at least 8 colors
- [ "$({ tput colors || tput Co ; } 2>/dev/null)" -ge 8 ] || exit
+ [ "$({ tput colors||tput Co||echo 0; } 2>/dev/null)" -ge 8 ]
) ; then
set -- -C "$@"
diff --git a/sh/shrc.d/ud.sh b/sh/shrc.d/ud.sh
index 79f4b5e7..06234569 100644
--- a/sh/shrc.d/ud.sh
+++ b/sh/shrc.d/ud.sh
@@ -2,48 +2,45 @@
# like cd .., cd ../.., etc
ud() {
- # Check argument count
- if [ "$#" -gt 1 ] ; then
+ # Check arguments; default to 1 and $PWD
+ if [ "$#" -gt 2 ] ; then
printf >&2 'ud(): Too many arguments\n'
return 2
fi
+ set -- "${1:-1}" "${2:-"$PWD"}"
- # Check first argument, number of steps upward, default to 1.
- # "0" is weird, but valid; "-1" however makes no sense at all
- if [ "${1:-1}" -lt 0 ] ; then
+ # Check first argument, number of steps upward. "0" is weird, but valid;
+ # "-1" however makes no sense at all
+ if [ "$1" -lt 0 ] ; then
printf >&2 'ud(): Invalid step count\n'
return 2
fi
- # Change the positional parameters from the number of steps given to a
- # "../../.." string
- set -- "$(
-
- # Append /.. to the target (default PWD) the specified number of times
- dirname=${2:-"$PWD"}
- i=0
- steps=${1:-1}
- while [ "$i" -lt "$steps" ] ; do
- dirname=${dirname%/}/..
- i=$((i+1))
+ # Check second argument, starting path, for relativity and anchor it if
+ # need be
+ case $2 in
+ /*) ;;
+ *) set -- "$1" "$PWD"/"$2" ;;
+ esac
+
+ # Chop an element off the target the specified number of times
+ while [ "$1" -gt 0 ] ; do
+
+ # Make certain there are no trailing slashes to foul us up
+ while : ; do
+ case $2 in
+ */) set -- "$1" "${2%/}" ;;
+ *) break ;;
+ esac
done
- # Check we have a target after all that
- if [ -z "$dirname" ] ; then
- printf >&2 'ud(): Destination construction failed\n'
- exit 1
- fi
+ # Strip a path element
+ set -- "$(($1-1))" "${2%/*}"
+ done
- # Print the target with trailing slash to work around newline stripping
- printf '%s/' "${dirname%/}"
- )"
+ # Shift off the count, which should now be zero
+ shift
- # Remove trailing slash
- set -- "${1%/}"
-
- # If the subshell printed nothing, return with failure
- [ -n "$1" ] || return
-
- # Try to change into the determined directory
- command cd -- "$@"
+ # Try to change into the determined directory, or the root if blank
+ command cd -- "${1:-/}"
}
diff --git a/sh/shrc.d/vim.sh b/sh/shrc.d/vim.sh
deleted file mode 100644
index e9174082..00000000
--- a/sh/shrc.d/vim.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-# If Vim exists on the system, use it instead of ex, vi, and view
-command -v vim >/dev/null 2>&1 || return
-
-# Define functions proper
-ex() {
- vim -e "$@"
-}
-vi() {
- vim "$@"
-}
-view() {
- vim -R "$@"
-}
diff --git a/sh/shrc.d/vr.sh b/sh/shrc.d/vr.sh
index 1902e3ba..8b35357c 100644
--- a/sh/shrc.d/vr.sh
+++ b/sh/shrc.d/vr.sh
@@ -19,10 +19,16 @@ vr() {
cd -- "$path" || exit
# Ask Git the top level (good)
- git rev-parse --show-toplevel 2>/dev/null && exit
+ if git rev-parse --show-toplevel 2>/dev/null ; then
+ printf /
+ exit
+ fi
# Ask Mercurial the top level (great)
- hg root 2>/dev/null && exit
+ if hg root 2>/dev/null ; then
+ printf /
+ exit
+ fi
# If we can get SVN info, iterate upwards until we cannot; hopefully
# that is the root (bad)
@@ -32,7 +38,7 @@ vr() {
cd .. || exit
done
if [ -n "$root" ] ; then
- printf '%s\n' "$root"
+ printf '%s\n/' "$root"
exit
fi
@@ -41,6 +47,9 @@ vr() {
exit 1
)"
+ # Chop the trailing newline and slash
+ set -- "${1%?/}"
+
# Check we figured out a target, or bail
[ -n "$1" ] || return
diff --git a/sh/shrc.d/xd.sh b/sh/shrc.d/xd.sh
index 01b8fd3a..40319cf2 100644
--- a/sh/shrc.d/xd.sh
+++ b/sh/shrc.d/xd.sh
@@ -10,7 +10,7 @@ xd() {
# Complain if mark not actually set yet
if ! [ -n "$PMD" ] ; then
printf >&2 'gd(): Mark not set\n'
- return 2
+ return 1
fi
# Put the current and marked directories into positional params
diff --git a/share/sample1.mi5 b/share/sample1.mi5
new file mode 100644
index 00000000..1e134d8e
--- /dev/null
+++ b/share/sample1.mi5
@@ -0,0 +1,9 @@
+<%
+
+ define(`FOO', `foo')
+
+%>
+FOO is <% FOO %>. Happy? Here it is again: <% FOO %>.
+If I quote it, though, it doesn't evaluate: <% `FOO' %>.
+I hope this has been enlightening for you.
+I can safely comment the opening tags within an inline block, too, look: <% `<%' `%>' %>. Cool, huh?
diff --git a/share/sample2.mi5 b/share/sample2.mi5
new file mode 100644
index 00000000..6e964a23
--- /dev/null
+++ b/share/sample2.mi5
@@ -0,0 +1,7 @@
+{{{
+
+ define(`BAR', `bar')
+
+}}}
+BAR is {{{ BAR }}}. Happy? Here it is again: {{{ BAR }}}.
+You need to change the mi5 delimiter for that to work.
diff --git a/tmux/tmux.conf.m4 b/tmux/tmux.conf
index 9f1aa80f..4e277515 100644
--- a/tmux/tmux.conf.m4
+++ b/tmux/tmux.conf
@@ -8,16 +8,12 @@ set-environment -gru SSH_CONNECTION
set-environment -gru SSH_TTY
set-environment -gru WINDOWID
-# Reset SHLVL
-set-environment -gru SHLVL
-
# Otherwise, use the environment we had when we started; don't touch it during
# a session unless I specifically ask
set-option -g update-environment ''
# Setting this makes each new pane a non-login shell, which suits me better
-# Clear away SHLVL again first to stop it getting incremented twice
-set-option -g default-command "unset SHLVL ; exec $SHELL"
+set-option -g default-command "$SHELL"
# Expect a 256-color terminal
set-option -g default-terminal 'screen-256color'
@@ -45,6 +41,8 @@ bind-key Tab last-pane
# Use the vi mode for tmux interaction behaviour in copy and choice modes
set-window-option -g mode-keys vi
+bind-key -T copy-mode-vi v send -X begin-selection
+bind-key -T copy-mode-vi y send -X copy-selection-and-cancel
# Detach with Alt-M, no prefix required
bind-key -n M-m detach
@@ -61,13 +59,8 @@ bind-key j select-pane -D
bind-key k select-pane -U
bind-key l select-pane -R
-# Vim-like keys for visual mode and yanking therefrom
-bind-key -t vi-copy 'v' begin-selection
-bind-key -t vi-copy 'y' copy-selection
-bind-key -t vi-copy Escape cancel
-
# Join and break panes
-bind-key J choose-window "join-pane -h -s '%%'"
+bind-key J choose-window 'join-pane -h -s "%%"'
bind-key B break-pane -d
# Select only sessions in the choose-tree menu, not the whole tree of sessions
@@ -78,7 +71,7 @@ bind-key s choose-session
set-option -g status-left '[#S] '
# Username, hostname, and the current date on the right side of the status bar
-set-option -g status-right ' [#(whoami)@#H] #(date +"%F %T")'
+set-option -g status-right ' [#H] %F %T'
# Update the status bar every second
set-option -g status-interval 1
@@ -108,31 +101,33 @@ set-window-option -g allow-rename off
# Window titles are the window index, a colon, the window or command name, and
# any activity or alert indicators
-set-window-option -g window-status-format "#I:#W#F"
+set-window-option -g window-status-format '#I:#W#F'
# Message dialogs are white on blue
-set-option -g message-style "bg=colour18,fg=colour231"
+set-option -g message-style 'bg=colour18,fg=colour231'
# Window choosers are white on blue
-set-window-option -g mode-style "bg=colour18,fg=colour231"
+set-window-option -g mode-style 'bg=colour18,fg=colour231'
-# Pane borders are always in dark gray
-set-option -g pane-border-style "fg=TMUX_COLOR"
-set-option -g pane-active-border-style "fg=TMUX_COLOR"
+# Pane borders are always in the background color
+set-option -g pane-border-style 'fg=colour237'
+set-option -g pane-active-border-style 'fg=colour237'
-# Inactive windows have a slightly grayed-out background and default text
-set-option -g window-style "bg=colour232,fg=colour248"
-set-option -g window-active-style "bg=colour0,fg=colour15"
+# Inactive windows have slightly washed-out system colours
+set-option -g window-style 'bg=colour232,fg=colour248'
+set-option -g window-active-style 'bg=colour0,fg=colour15'
-# The status bar defaults to light gray on dark gray, which applies to the left
-# and right status bar sections described in status-left and status-right above
-set-option -g status-style "bg=TMUX_COLOR,fg=colour248"
+# The status bar has the defined background and foreground colours
+set-option -g status-style 'bg=colour237,fg=colour248'
# Titles of windows default to black text with no embellishment
-set-window-option -g window-status-style "fg=colour16"
+set-window-option -g window-status-style 'fg=colour16'
# The title of the active window is in white rather than black
-set-window-option -g window-status-current-style "fg=colour231"
+set-window-option -g window-status-current-style 'fg=colour231'
# A window with a bell has a title with a red background until cleared
-set-window-option -g window-status-bell-style "bg=colour9"
+set-window-option -g window-status-bell-style 'bg=colour9'
+
+# Source any configuration in the subdir if there is any
+source-file -q ~/.tmux.conf.d/*.conf
diff --git a/vim/after/ftdetect/muttrc.vim b/vim/after/ftdetect/muttrc.vim
new file mode 100644
index 00000000..ff3776b5
--- /dev/null
+++ b/vim/after/ftdetect/muttrc.vim
@@ -0,0 +1,12 @@
+" Add automatic commands to detect .muttrc files
+augroup dfmuttrc
+
+ autocmd BufNewFile,BufRead
+ \ **/.dotfiles/mutt/muttrc.d/*.rc
+ \ setlocal filetype=muttrc
+
+ autocmd BufNewFile,BufRead
+ \ **/.muttrc.d/*.rc
+ \ setlocal filetype=muttrc
+
+augroup END
diff --git a/vim/after/ftdetect/xdefaults.vim b/vim/after/ftdetect/xdefaults.vim
new file mode 100644
index 00000000..f0ee7b81
--- /dev/null
+++ b/vim/after/ftdetect/xdefaults.vim
@@ -0,0 +1,6 @@
+" Add automatic commands to find Xresources subfiles
+augroup dfxdefaults
+ autocmd BufNewFile,BufRead
+ \ **/.Xresources.d/*
+ \ setlocal filetype=xdefaults
+augroup END
diff --git a/vim/bundle/abolish b/vim/bundle/abolish
-Subproject 05c7d31f6b3066582017edf5198502a94f6a7cb
+Subproject b6a8b49e2173ba5a1b34d00e68e0ed8addac3eb
diff --git a/vim/bundle/commentary b/vim/bundle/commentary
-Subproject 73e0d9a9d1f51b6cc9dc965f62669194ae851cb
+Subproject 89f43af18692d22ed999c3097e449f12fdd8b29
diff --git a/vim/bundle/html5 b/vim/bundle/html5
-Subproject 93144aea5adee78e008be4d3c8a40a84bc22138
+Subproject 916085df16ad6bd10ecbd37bc5d44b62f062572
diff --git a/vim/bundle/lion b/vim/bundle/lion
-Subproject 9b1a923d51a7d0a8efdbb2289ce1e763038f965
+Subproject 80de27aa2849b42d8f9cec6ac362858651677d9
diff --git a/vim/bundle/nagios b/vim/bundle/nagios
deleted file mode 160000
-Subproject 3a9d5c4a1428d193a4d2db97f042fa9afccdd26
diff --git a/vim/bundle/pathogen b/vim/bundle/pathogen
-Subproject 7ba2e1b67a8f8bcbafedaf6763580390dfd9343
+Subproject e7857bed4e0705f91f781dbe99706f07d08d104
diff --git a/vim/bundle/repeat b/vim/bundle/repeat
-Subproject 7a6675f092842c8f81e71d5345bd7cdbf375941
+Subproject 070ee903245999b2b79f7386631ffd29ce9b8e9
diff --git a/vim/bundle/targets b/vim/bundle/targets
-Subproject c12d4ea9e5032c9e5b88e2115a80b8772d15d0d
+Subproject dec6409fb80ec1554bad582652f7511aa28c4ed
diff --git a/vim/bundle/tmux b/vim/bundle/tmux
deleted file mode 160000
-Subproject 663130a00e6d96b8e5d56051e8fe01d89521e31
diff --git a/vim/bundle/unimpaired b/vim/bundle/unimpaired
-Subproject 11dc568dbfd7a56866a4354c737515769f08e9f
+Subproject 3a7759075cca5b0dc29ce81f2747489b6c8e36a
diff --git a/vim/vimrc b/vim/vimrc
index 1c1f2b26..87cf7868 100644
--- a/vim/vimrc
+++ b/vim/vimrc
@@ -47,8 +47,8 @@ endif
if has('syntax')
" Use syntax highlighting with 100 lines of context
- syntax enable
- syntax sync minlines=100
+ silent! syntax enable
+ silent! syntax sync minlines=100
" Use my custom color scheme if possible, otherwise I'm happy with whatever
" the default is, and it usually cares about my background
diff --git a/wget/wgetrc b/wget/wgetrc
new file mode 100644
index 00000000..eb3f20ba
--- /dev/null
+++ b/wget/wgetrc
@@ -0,0 +1,14 @@
+# No, no, dig UP, stupid
+no_parent = on
+
+# Don't take no for an answer
+retry_connrefused = on
+
+# It's the only thing that works against the machines
+robots = off
+
+# Shorten default timeout
+timeout = 60
+
+# Reduce default number of attempts
+tries = 3
diff --git a/wyrd/wyrdrc b/wyrd/wyrdrc
deleted file mode 100644
index 86eae455..00000000
--- a/wyrd/wyrdrc
+++ /dev/null
@@ -1,167 +0,0 @@
-# Wyrd run-configuration file
-
-# command for the Remind executable
-set remind_command="remind"
-# the default reminder file to display
-set reminders_file="$HOME/.reminders"
-# command for editing an old appointment, given a line number %line% and filename %file%
-set edit_old_command="${VISUAL:-$EDITOR} +%line% %file%"
-# command for editing a new appointment, given a filename %file%
-set edit_new_command="${VISUAL:-$EDITOR} +999999 %file%"
-# command for free editing of the reminders file, given a filename %file%
-set edit_any_command="${VISUAL:-$EDITOR} %file%"
-
-
-# templates for creating new appointments
-# %monname% -> month name, %mon% -> month number, %mday% -> day of the month,
-# %year% -> year, %hour% -> hour, %min% -> minute, %wdayname% -> weekday name
-# %wday% -> weekday number
-set timed_template="REM %monname% %mday% %year% AT %hour%:%min% DURATION 1:00 MSG "
-set untimed_template="REM %monname% %mday% %year% MSG "
-
-# weekly recurrence
-set template0="REM %wdayname% AT %hour%:%min% DURATION 1:00 MSG "
-set template1="REM %wdayname% MSG "
-
-# monthly recurrence
-set template2="REM %mday% AT %hour%:%min% DURATION 1:00 MSG "
-set template3="REM %mday% MSG "
-
-
-# algorithm to use for determining busy level
-# "1" -> count the number of reminders in each day
-# "2" -> count the number of hours of reminders in each day
-set busy_algorithm="1"
-# for busy_algorithm="2", assume that untimed reminders occupy this many minutes
-set untimed_duration="60"
-
-# if busy_algorithm="1", number of reminders per day allowed for each calendar
-# colorization level; if busy_algorithm="2", use number of hours of reminders
-# per day
-set busy_level1="1" # level1 color
-set busy_level2="3" # level2 color
-set busy_level3="5" # level2 color, bold
-set busy_level4="7" # level3 color
- # (everything else is level3 color, bold)
-
-
-# first day of the week is Monday
-set week_starts_monday="true"
-
-# 12/24 hour time settings
-set schedule_12_hour="false"
-set selection_12_hour="true"
-set status_12_hour="true"
-set description_12_hour="true"
-
-# whether or not to keep the cursor centered when scrolling through timed
-# reminders
-set center_cursor="false"
-
-# date syntax for the 'go to date' command can be big or little endian
-set goto_big_endian="true"
-# date syntax for the "quick reminder" command can be US style
-# (6/1 -> June 1) or non-US style (6/1 -> January 6)
-set quick_date_US="false"
-
-# whether or not to number weeks within the month calendar
-set number_weeks="false"
-
-# whether or not the cursor should follow the current time
-# after pressing the "home" key
-set home_sticky="true"
-
-# whether or not to display advance warnings
-set advance_warning="false"
-
-# width of the untimed reminders window
-set untimed_window_width="40"
-
-# whether or not to render untimed reminders in boldface
-set untimed_bold="true"
-
-
-# key bindings
-bind "j" scroll_down
-bind "<down>" scroll_down
-bind "k" scroll_up
-bind "<up>" scroll_up
-bind "h" switch_window
-bind "l" switch_window
-bind "<left>" switch_window
-bind "<right>" switch_window
-bind "<pageup>" previous_day
-bind "4" previous_day
-bind "<" previous_day
-bind "H" previous_day
-bind "<pagedown>" next_day
-bind "6" next_day
-bind ">" next_day
-bind "L" next_day
-bind "8" previous_week
-bind "[" previous_week
-bind "K" previous_week
-bind "2" next_week
-bind "]" next_week
-bind "J" next_week
-bind "{" previous_month
-bind "}" next_month
-bind "<home>" home
-bind "g" goto
-bind "z" zoom
-bind "<return>" edit
-bind "<enter>" edit
-bind "e" edit_any
-bind "y" copy
-bind "X" cut
-bind "p" paste
-bind "P" paste_dialog
-bind "d" scroll_description_up
-bind "D" scroll_description_down
-#bind "q" quick_add
-bind "t" new_timed
-bind "T" new_timed_dialog
-bind "u" new_untimed
-bind "U" new_untimed_dialog
-bind "w" new_template0
-bind "W" new_template1
-bind "m" new_template2
-bind "M" new_template3
-bind "n" search_next
-bind "/" begin_search
-bind "<tab>" next_reminder
-bind "r" view_remind
-bind "R" view_remind_all
-bind "c" view_week
-bind "C" view_month
-bind "?" help
-bind "\\Cl" refresh
-#bind "Q" quit
-bind "q" quit
-
-bind "<return>" entry_complete
-bind "<enter>" entry_complete
-bind "<backspace>" entry_backspace
-bind "<esc>" entry_cancel
-
-
-# set up the colors
-color help white magenta
-color timed_default white black
-color timed_current white magenta
-color timed_reminder1 white blue
-color timed_reminder2 white red
-color timed_reminder3 white green
-color timed_reminder4 yellow magenta
-color untimed_reminder white black
-color timed_date magenta black
-color selection_info white magenta
-color description white black
-color status white magenta
-color calendar_labels white black
-color calendar_level1 white black
-color calendar_level2 magenta black
-color calendar_level3 red black
-color calendar_today magenta white
-color left_divider magenta magenta
-color right_divider magenta magenta
diff --git a/yash/yash_profile b/yash/yash_profile
deleted file mode 100644
index d37f35a1..00000000
--- a/yash/yash_profile
+++ /dev/null
@@ -1,2 +0,0 @@
-# Load ~/.profile, because Yash won't by itself, no matter how you invoke it
-[ -e "$HOME"/.profile ] && . "$HOME"/.profile
diff --git a/yash/yashrc b/yash/yashrc
deleted file mode 100644
index a731c80b..00000000
--- a/yash/yashrc
+++ /dev/null
@@ -1,9 +0,0 @@
-# Load POSIX interactive shell startup files, because Yash won't do it if not
-# invoked as sh(1)
-[ -e "$ENV" ] && . "$ENV"
-
-# Load Bash-specific startup files
-for sh in "$HOME"/.yashrc.d/*.yash ; do
- [ -e "$sh" ] && . "$sh"
-done
-unset -v sh
diff --git a/yash/yashrc.d/ver.yash b/yash/yashrc.d/ver.yash
deleted file mode 100644
index 8bd06e4d..00000000
--- a/yash/yashrc.d/ver.yash
+++ /dev/null
@@ -1,4 +0,0 @@
-# Shortcut to show current shell version
-ver() {
- printf '%s\n' "${YASH_VERSION:-unknown}"
-}
diff --git a/zsh/zshrc b/zsh/zshrc
index a97c0a73..fa4186d4 100644
--- a/zsh/zshrc
+++ b/zsh/zshrc
@@ -1,9 +1,15 @@
-# Emacs keybindings even if EDITOR is vi(1)
-bindkey -e
+# Clear away all aliases; we do this here rather than in $ENV because the ksh
+# family of shells relies on aliases to implement certain POSIX utilities like
+# `fc` and `type`. Ignore output, as older Zsh seems not to implement this
+# (quelle surprise).
+unalias -a >/dev/null 2>&1
# If ENV is set, source it to get all the POSIX-compatible interactive stuff
[[ -n $ENV ]] && source "$ENV"
+# Emacs keybindings even if EDITOR is vi(1)
+bindkey -e
+
# History settings
setopt histignorealldups sharehistory
HISTFILE=$HOME/.zsh_history
diff --git a/zsh/zshrc.d/completion.zsh b/zsh/zshrc.d/completion.zsh
new file mode 100644
index 00000000..233a1b91
--- /dev/null
+++ b/zsh/zshrc.d/completion.zsh
@@ -0,0 +1,19 @@
+# Use modern completion system
+autoload -Uz compinit
+compinit
+
+# Taken from Debian's stock .zshrc as a start
+zstyle ':completion:*' auto-description 'specify: %d'
+zstyle ':completion:*' completer _expand _complete _correct _approximate
+zstyle ':completion:*' format 'Completing %d'
+zstyle ':completion:*' group-name ''
+zstyle ':completion:*' menu select=2
+zstyle ':completion:*' list-colors ''
+zstyle ':completion:*' list-prompt %SAt %p: Hit TAB for more, or the character to insert%s
+zstyle ':completion:*' matcher-list '' 'm:{a-z}={A-Z}' 'm:{a-zA-Z}={A-Za-z}' 'r:|[._-]=* r:|=* l:|=*'
+zstyle ':completion:*' menu select=long
+zstyle ':completion:*' select-prompt %SScrolling active: current selection at %p%s
+zstyle ':completion:*' use-compctl false
+zstyle ':completion:*' verbose true
+zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#)*=0=01;31'
+zstyle ':completion:*:kill:*' command 'ps -u $USER -o pid,%cpu,tty,cputime,cmd'
diff --git a/zsh/zshrc.d/prompt.zsh b/zsh/zshrc.d/prompt.zsh
index 898031ea..b612c704 100644
--- a/zsh/zshrc.d/prompt.zsh
+++ b/zsh/zshrc.d/prompt.zsh
@@ -11,25 +11,25 @@ prompt() {
# Basic prompt shape depends on whether we're in SSH or not
PS1=
if [[ -n $SSH_CLIENT ]] || [[ -n $SSH_CONNECTION ]] ; then
- PS1=$PS1'%n@%m:'
+ PS1=$PS1'%m:'
fi
PS1=$PS1'%~'
# Add sub-commands; VCS, job, and return status checks
PS1=$PS1'$(ret=$?;prompt vcs;prompt job;prompt ret)'
+ # Add a helpful prefix if this shell appears to be exotic
+ case ${SHELL##*/} in
+ (zsh) ;;
+ (*) PS1=zsh:$PS1 ;;
+ esac
+
# Add prefix and suffix
PS1='${PROMPT_PREFIX}'$PS1'${PROMPT_SUFFIX}'
# Add terminating "$" or "#" sign
PS1=$PS1'%#'
- # Add > symbols to show nested shells
- local shlvl
- for ((shlvl = 1; shlvl < SHLVL; shlvl++)) ; do
- PS1='>'$PS1
- done
-
# Bold and color the prompt if it looks like we can
if (( $({ tput colors || tput Co ; } 2>/dev/null) >= 8 )) ; then
PS1='%B%F{cyan}'$PS1'%f%b'
@@ -44,10 +44,13 @@ prompt() {
# Revert to simple inexpensive prompts
off)
- PS1='\$ '
+ PS1='$ '
PS2='> '
PS3='? '
PS4='+ '
+ if [[ -n $SSH_CLIENT || -n $SSH_CONNECTION ]] ; then
+ PS1=$(hostname -s)'$ '
+ fi
;;
# Git prompt function
@@ -73,7 +76,7 @@ prompt() {
git describe --tags --exact-match HEAD ||
git rev-parse --short HEAD
) || return
- name=${name##*/}
+ name=${name#refs/*/}
[[ -n $name ]] || return
# Check various files in .git to flag processes
@@ -122,7 +125,10 @@ prompt() {
# Print the status in brackets; add a git: prefix only if there
# might be another VCS prompt (because PROMPT_VCS is set)
printf '(%s%s%s%s)' \
- "${PROMPT_VCS:+git:}" "$name" "${proc:+:"$proc"}" "$state"
+ "${PROMPT_VCS:+git:}" \
+ "${name//\%/%%}" \
+ "${proc:+:"${proc//\%/%%}"}" \
+ "${state//\%/%%}"
;;
# Subversion prompt function
@@ -148,6 +154,7 @@ prompt() {
branch=${branch#/}
branch=${branch#branches/}
branch=${branch%%/*}
+ [[ -n $branch ]] || branch=unknown
# Parse the output of svn status to determine working copy state
local symbol
@@ -165,7 +172,9 @@ prompt() {
((untracked)) && state=${state}'?'
# Print the state in brackets with an svn: prefix
- printf '(svn:%s%s)' "${branch:-unknown}" "$state"
+ printf '(svn:%s%s)' \
+ "${branch//\%/%%}" \
+ "${state//\%/%%}"
;;
# VCS wrapper prompt function; print the first relevant prompt, if any
@@ -179,7 +188,7 @@ prompt() {
# Show return status of previous command in angle brackets, if not zero
ret)
# shellcheck disable=SC2154
- ((ret)) && printf '<%u>' "$ret"
+ ((ret)) && printf '<%u>' "${ret//\%/%%}"
;;
# Show the count of background jobs in curly brackets, if not zero
@@ -188,7 +197,7 @@ prompt() {
while read -r ; do
((jobc++))
done < <(jobs -p)
- ((jobc)) && printf '{%u}' "$jobc"
+ ((jobc)) && printf '{%u}' "${jobc//\%/%%}"
;;
# No argument given, print prompt strings and vars
@@ -204,5 +213,5 @@ prompt() {
esac
}
-# Start with full-fledged prompt
-prompt on
+# Default to a full-featured prompt, but use PROMPT_MODE if that's set
+prompt "${PROMPT_MODE:-on}"