diff options
author | Tom Ryder <tom@sanctum.geek.nz> | 2017-07-07 08:47:53 +1200 |
---|---|---|
committer | Tom Ryder <tom@sanctum.geek.nz> | 2017-07-07 08:47:53 +1200 |
commit | 53ebb4a269b8155346a535b8a24b991093a59a90 (patch) | |
tree | 23f3c3d8e937ef6b2dd045c1d2dfc9cd1194fd48 | |
parent | Merge branch 'master' into port/sunos/illumos/openindiana (diff) | |
parent | Escape % signs in prompt command output (diff) | |
download | dotfiles-53ebb4a269b8155346a535b8a24b991093a59a90.tar.gz dotfiles-53ebb4a269b8155346a535b8a24b991093a59a90.zip |
Merge branch 'master' into port/sunos/illumos/openindiana
60 files changed, 1407 insertions, 262 deletions
@@ -67,6 +67,9 @@ bin/motd bin/murl bin/mw bin/nlbr +bin/oii +bin/oii.sh +bin/oii.m4 bin/onl bin/osc bin/p @@ -92,8 +95,6 @@ bin/rnda bin/rndf bin/rndi bin/rndl -bin/rndl.sh -bin/rndl.m4 bin/rnds bin/sd2u bin/sec @@ -148,6 +149,8 @@ games/chkl games/dr games/drakon games/kvlt +games/philsay +games/pks games/rndn games/rot13 games/squ @@ -159,5 +162,4 @@ git/gitconfig.m4 gnupg/gpg.conf gnupg/gpg.conf.m4 include/mktd.m4 -man/man7/dotfiles.7df urxvt/ext/select diff --git a/ISSUES.markdown b/ISSUES.markdown index a69e07df..48007919 100644 --- a/ISSUES.markdown +++ b/ISSUES.markdown @@ -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 @@ -23,3 +20,5 @@ Known issues 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 @@ -9,7 +9,6 @@ install-bin \ install-bin-man \ install-curl \ - install-dotfiles-man \ install-dunst \ install-ex \ install-finger \ @@ -42,6 +41,7 @@ install-vim-gui-config \ install-vim-pathogen \ install-vim-plugins \ + install-wget \ install-x \ install-zsh \ check \ @@ -137,6 +137,7 @@ BINS = bin/ap \ bin/murl \ bin/mw \ bin/nlbr \ + bin/oii \ bin/onl \ bin/osc \ bin/pa \ @@ -202,8 +203,8 @@ BINS = bin/ap \ BINS_M4 = bin/chn.m4 \ bin/edda.m4 \ + bin/oii.m4 \ bin/pst.m4 \ - bin/rndl.m4 \ bin/swr.m4 \ bin/tlcs.m4 \ bin/try.m4 \ @@ -211,8 +212,8 @@ BINS_M4 = bin/chn.m4 \ BINS_SH = bin/chn.sh \ bin/edda.sh \ + bin/oii.sh \ bin/pst.sh \ - bin/rndl.sh \ bin/swr.sh \ bin/tlcs.sh \ bin/try.sh \ @@ -225,6 +226,8 @@ GAMES = games/aaf \ games/dr \ games/drakon \ games/kvlt \ + games/philsay \ + games/pks \ games/rndn \ games/rot13 \ games/squ \ @@ -276,8 +279,8 @@ clean distclean: 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/rndl.sh: bin/rndl.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 @@ -295,14 +298,9 @@ KEYSERVER = hkps://hkps.pool.sks-keyservers.net gnupg/gpg.conf: gnupg/gpg.conf.m4 m4 \ - -D HOME=$(HOME) \ -D KEYSERVER=$(KEYSERVER) \ gnupg/gpg.conf.m4 > $@ -man/man7/dotfiles.7df: README.markdown man/man7/dotfiles.7df.header - cat man/man7/dotfiles.7df.header README.markdown | \ - pandoc -sS -t man -o $@ - MAILDIR = $(HOME)/Mail install: install-bin \ @@ -315,6 +313,9 @@ install: install-bin \ install-readline \ install-vim +install-conf: + sh install/install-conf.sh + install-abook: mkdir -p -- $(HOME)/.abook cp -p -- abook/abookrc $(HOME)/.abook @@ -341,10 +342,6 @@ install-bin-man: install-curl: cp -p -- curl/curlrc $(HOME)/.curlrc -install-dotfiles-man: man/man7/dotfiles.7df - mkdir -p -- $(HOME)/.local/share/man/man7 - cp -p -- man/man7/*.7df $(HOME)/.local/share/man/man7 - install-dunst: install-x mkdir -p -- $(HOME)/.config/dunst cp -p -- dunst/dunstrc $(HOME)/.config/dunst @@ -370,9 +367,8 @@ install-git: git/gitconfig cp -p -- git/gitconfig $(HOME)/.gitconfig install-gnupg: gnupg/gpg.conf - mkdir -m 0700 -p -- $(HOME)/.gnupg $(HOME)/.gnupg/sks-keyservers.net + mkdir -m 0700 -p -- $(HOME)/.gnupg cp -p -- gnupg/*.conf $(HOME)/.gnupg - cp -p -- gnupg/sks-keyservers.net/* $(HOME)/.gnupg/sks-keyservers.net install-gtk: mkdir -p -- $(HOME)/.config/gtk-3.0 @@ -393,7 +389,7 @@ install-less: install-mpd: install-sh mkdir -p -- $(HOME)/.mpd/playlists - cp -p .. mpd/profile.d/* $(HOME)/.profile.d + cp -p -- mpd/profile.d/* $(HOME)/.profile.d cp -p -- mpd/mpdconf $(HOME)/.mpdconf install-mutt: @@ -483,6 +479,9 @@ 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 \ diff --git a/README.markdown b/README.markdown index bd4d482a..adc4c73a 100644 --- a/README.markdown +++ b/README.markdown @@ -203,8 +203,6 @@ 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 if @@ -499,6 +497,7 @@ Installed by the `install-bin` target: * `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. @@ -555,6 +554,8 @@ There's some silly stuff in `install-games`: * `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. @@ -566,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 ------- diff --git a/bash/bashrc.d/prompt.bash b/bash/bashrc.d/prompt.bash index 782af287..a6506a60 100644 --- a/bash/bashrc.d/prompt.bash +++ b/bash/bashrc.d/prompt.bash @@ -167,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 @@ -193,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 @@ -210,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 @@ -224,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 @@ -233,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 diff --git a/bin/csmw.awk b/bin/csmw.awk index 4479d8f8..351fc749 100644 --- a/bin/csmw.awk +++ b/bin/csmw.awk @@ -1,4 +1,5 @@ # Print an English comma-separated list of monospace-quoted words (backticks) +BEGIN { wc = 0 } { for (i = 1; i <= NF; i++) ws[++wc] = "`" $i "`" 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/gwp.awk b/bin/gwp.awk index f1e3b3bd..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,15 +18,17 @@ 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" +function fail(msg) { + stderr = "cat >&2" + printf "%s: %s\n", self, msg | stderr + close(stderr) exit(2) } diff --git a/bin/hms.awk b/bin/hms.awk index 3054db44..2aa492a1 100644 --- a/bin/hms.awk +++ b/bin/hms.awk @@ -1,19 +1,23 @@ # 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]/ { - print "hms: Bad number" | "cat >&2" - err = 1 + 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 = $0 + s = int($0 + 0) h = int(s / 3600) s %= 3600 m = int(s / 60) @@ -29,4 +33,8 @@ BEGIN { } # 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/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.sh b/bin/maybe.sh index 6e5c8658..bda7bbc0 100644 --- a/bin/maybe.sh +++ b/bin/maybe.sh @@ -19,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) } @@ -37,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 index 48d71657..7acb6f3b 100644 --- a/bin/mi5.awk +++ b/bin/mi5.awk @@ -4,19 +4,14 @@ BEGIN { # You can change any of these, but while changing these is still relatively # sane... - if (!length(open)) - open = "<%" - if (!length(shut)) - shut = "%>" + open = "<%" + shut = "%>" # ... changing these probably isn't, and should compel you to rethink your # code, or quite possibly your entire life thus far. - if (!length(quote)) - quote = "`" - if (!length(unquote)) - unquote = "'" - if (!length(dnl)) - dnl = "dnl" + quote = "`" + unquote = "'" + dnl = "dnl" # We do not start in a block bmac = 0 @@ -24,7 +19,9 @@ BEGIN { # Fatal error function function fatal(str) { - printf "%s: %s\n", self, str | "cat >&2" + stderr = "cat >&2" + printf "%s: %s\n", self, str | stderr + close(stderr) exit(1) } diff --git a/bin/mktd.sh b/bin/mktd.sh index 62b10396..89cdc7c3 100644 --- a/bin/mktd.sh +++ b/bin/mktd.sh @@ -1,11 +1,8 @@ # 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") +dn=${TMPDIR:-/tmp}/${1:-mktd}.$$.$(rndi 1 2147483648) # Create the directory and print its name if successful mkdir -m 700 -- "$dn" && printf '%s\n' "$dn" @@ -1,10 +1,10 @@ # Crude approach to get alphabetic words one per line from input, not sorted or # deduplicated BEGIN { - RS = "(--|['_-]*[^[:alnum:]'_-]+['_-]*)" + FS = "(--|['_-]*[^[:alnum:]'_-]+['_-]*)" } { for (i = 1; i <= NF; i++) - if ($i ~ /[[:alpha:]]/) + 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..15e4f46d 100644 --- a/bin/onl.awk +++ b/bin/onl.awk @@ -2,8 +2,8 @@ # For each line of input ... { - # Strip out non-printable characters and rebuild the fields - gsub(/[[:cntrl:]]/, "") + # Strip out whitespace characters and rebuild the fields + gsub(/[\n\t\r ]+/, "") # Print each field, without a newline; add a leading space if it's not the # very first one diff --git a/bin/rnda.sh b/bin/rnda.sh index b09a8b6f..6a755305 100644 --- a/bin/rnda.sh +++ b/bin/rnda.sh @@ -6,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/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.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/rndl.mi5 b/bin/rndl.mi5 deleted file mode 100644 index f99ccbea..00000000 --- a/bin/rndl.mi5 +++ /dev/null @@ -1,38 +0,0 @@ -# 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 - -<% -include(`include/mktd.m4') -%> - - # 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/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) +} @@ -5,7 +5,7 @@ if [ "$#" -gt 0 ] ; then : # If a session exists, just attach to it -elif command tmux has-session 2>/dev/null ; then +elif tmux has-session 2>/dev/null ; then set -- attach-session -d # Create a new session with an appropriate name 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 index 5966c520..fbb7eeba 100644 --- a/bin/trs.awk +++ b/bin/trs.awk @@ -1,11 +1,8 @@ -# Substitute one string for another in input (no regex) +# Substitute one string for another in input (no newlines, no regex) BEGIN { # Name self self = "trs" - # No wordsplitting required - FS = "" - # Two and only two arguments required if (ARGC != 3) fail("Need a string and a replacement") @@ -21,8 +18,10 @@ BEGIN { } # Bailout function -function fail(str) { - printf "%s: %s\n", self, str | "cat >&2" +function fail(msg) { + stderr = "cat >&2" + printf "%s: %s\n", self, msg | stderr + close(stderr) exit(2) } diff --git a/bin/unf.awk b/bin/unf.awk index ac6172f7..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)) diff --git a/bin/xrq.awk b/bin/xrq.awk index 686cf677..ffd5f124 100644 --- a/bin/xrq.awk +++ b/bin/xrq.awk @@ -8,19 +8,22 @@ BEGIN { # Check we have at least one resource name if (ARGC < 2) { - print "xrq: Need at least one resource name" | "cat >&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 - while ("xrdb -query" | getline) { - for (i in ARGV) { + 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/games/drakon.awk b/games/drakon.awk index ce619585..ebca4e95 100644 --- a/games/drakon.awk +++ b/games/drakon.awk @@ -6,7 +6,7 @@ tog = 0 for (i = 1; i <= len; i++) { chr = substr($0, i, 1) - if (chr ~ /[[:alpha:]]/) + if (chr ~ /[a-zA-Z]/) chr = (tog = !tog) ? tolower(chr) : toupper(chr) lin = lin chr } diff --git a/games/philsay.sh b/games/philsay.sh new file mode 100644 index 00000000..9270c52e --- /dev/null +++ b/games/philsay.sh @@ -0,0 +1,46 @@ +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/gnupg/gpg.conf.mi5 b/gnupg/gpg.conf.mi5 index c6793b64..1617a979 100644 --- a/gnupg/gpg.conf.mi5 +++ b/gnupg/gpg.conf.mi5 @@ -26,7 +26,7 @@ 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=<% 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/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/keychain/profile.d/keychain.sh b/keychain/profile.d/keychain.sh index f3d25c62..c0319d49 100644 --- a/keychain/profile.d/keychain.sh +++ b/keychain/profile.d/keychain.sh @@ -2,4 +2,4 @@ command -v keychain >/dev/null 2>&1 || return eval "$(TERM=${TERM:-ansi} keychain \ --eval --ignore-missing --quick --quiet \ - id_dsa id_rsa id_ecsda)" + id_dsa id_rsa id_ecsda id_ed25519)" diff --git a/ksh/kshrc.d/prompt.ksh b/ksh/kshrc.d/prompt.ksh index 866cf79e..c5f3ee1b 100644 --- a/ksh/kshrc.d/prompt.ksh +++ b/ksh/kshrc.d/prompt.ksh @@ -30,9 +30,7 @@ function prompt { (*'MIRBSD KSH'*) ksh=mksh ;; esac case ${SHELL##*/} in - ('') ;; - (ksh) ;; - ("$ksh") ;; + (''|ksh|"$ksh") ;; (*) PS1=$ksh:$PS1 ;; esac diff --git a/man/man1/mi5.1df b/man/man1/mi5.1df index 6466f35d..53d98bf1 100644 --- a/man/man1/mi5.1df +++ b/man/man1/mi5.1df @@ -7,7 +7,7 @@ FILE > out.m4 .br .B mi5 --v open='{{{' -v shut='}}}' FILE > out.m4 +open='{{{' shut='}}}' FILE > out.m4 .br .B mi5 FILE1 FILE2 > out.m4 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/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/trs.1df b/man/man1/trs.1df index fa5d2d19..93b2cad3 100644 --- a/man/man1/trs.1df +++ b/man/man1/trs.1df @@ -19,5 +19,7 @@ implementations. It is thereby the string complement for tr(1). 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/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/man7/dotfiles.7df b/man/man7/dotfiles.7df new file mode 100644 index 00000000..831af06d --- /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.markdown +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/profile.d/mpd.sh b/mpd/profile.d/mpd.sh index daa55af6..5a14aef2 100644 --- a/mpd/profile.d/mpd.sh +++ b/mpd/profile.d/mpd.sh @@ -1,3 +1,3 @@ # Start an mpd process if one isn't already running -command mpd >/dev/null 2>&1 || return +command -v mpd >/dev/null 2>&1 || return [ -s "$HOME"/.mpd/pid ] || mpd diff --git a/sh/profile.d/games.sh b/sh/profile.d/games.sh index ee56c593..956d1de1 100644 --- a/sh/profile.d/games.sh +++ b/sh/profile.d/games.sh @@ -1,3 +1,3 @@ # Add ~/.local/games to PATH if it exists [ -d "$HOME"/.local/games ] || return -PATH=$HOME/.local/games:$PATH +PATH=$PATH:$HOME/.local/games diff --git a/sh/shrc.d/ed.sh b/sh/shrc.d/ed.sh index a2b7818e..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() { 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/hgrep.sh b/sh/shrc.d/hgrep.sh index fe297ab3..9d7542b4 100644 --- a/sh/shrc.d/hgrep.sh +++ b/sh/shrc.d/hgrep.sh @@ -9,7 +9,7 @@ hgrep() { return 2 fi if [ -z "$HISTFILE" ] ; then - printf >&2 'hgrep(): No HISTFILE\n' + printf >&2 'hgrep(): HISTFILE unset or null\n' return 2 fi grep "$@" "$HISTFILE" diff --git a/sh/shrc.d/prompt.sh b/sh/shrc.d/prompt.sh index 6f1e8e1f..30e4e9d8 100644 --- a/sh/shrc.d/prompt.sh +++ b/sh/shrc.d/prompt.sh @@ -7,5 +7,5 @@ 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)'$ ' + PS1=$(hostname -s)'$ ' fi diff --git a/tmux/tmux.conf b/tmux/tmux.conf index 09ba0251..4e277515 100644 --- a/tmux/tmux.conf +++ b/tmux/tmux.conf @@ -13,7 +13,7 @@ set-environment -gru WINDOWID set-option -g update-environment '' # Setting this makes each new pane a non-login shell, which suits me better -set-option -g default-command '$SHELL' +set-option -g default-command "$SHELL" # Expect a 256-color terminal set-option -g default-terminal 'screen-256color' diff --git a/vim/bundle/unimpaired b/vim/bundle/unimpaired -Subproject 7bbbca73233b1492a8c3d16f91f34340eccc9b3 +Subproject e1e0cc3859323f354b8d905ca177e172c7d69f0 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/zsh/zshrc.d/prompt.zsh b/zsh/zshrc.d/prompt.zsh index 7c695e25..b612c704 100644 --- a/zsh/zshrc.d/prompt.zsh +++ b/zsh/zshrc.d/prompt.zsh @@ -125,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 @@ -151,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 @@ -168,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 @@ -182,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 @@ -191,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 |