aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2016-09-06 15:27:01 +1200
committerTom Ryder <tom@sanctum.geek.nz>2016-09-06 15:27:01 +1200
commitb1bedf82010e14f74c680b63654652096e4fa1cc (patch)
tree4fa1cfeedd3559254330b9e50ca8693d3da86062
parentMerge branch 'master' into openbsd (diff)
parentTidy .inputrc bc section (diff)
downloaddotfiles-b1bedf82010e14f74c680b63654652096e4fa1cc.tar.gz
dotfiles-b1bedf82010e14f74c680b63654652096e4fa1cc.zip
Merge branch 'master' into openbsd
-rw-r--r--.gitignore2
-rw-r--r--ISSUES.markdown4
-rw-r--r--Makefile11
-rw-r--r--README.markdown152
-rw-r--r--bash/bash_completion.d/find.bash89
-rw-r--r--bash/bash_completion.d/kill.bash15
-rw-r--r--bash/bash_completion.d/make.bash1
-rw-r--r--bash/bashrc.d/completion.bash13
-rw-r--r--bash/bashrc.d/prompt.bash57
-rwxr-xr-xbin/bl11
-rwxr-xr-xbin/cf32
-rwxr-xr-xbin/cfr13
-rw-r--r--bin/mftl.awk38
-rwxr-xr-xbin/rmrej3
-rwxr-xr-xbin/tl22
-rwxr-xr-xbin/umake11
-rwxr-xr-xbin/xgo16
-rw-r--r--man/man1/bl.1df16
-rw-r--r--man/man1/cf.1df10
-rw-r--r--man/man1/cfr.1df9
-rw-r--r--man/man1/mftl.1df30
-rw-r--r--man/man1/rmrej.1df17
-rw-r--r--man/man1/umake.1df15
-rw-r--r--man/man6/rndn.6df6
-rw-r--r--mutt/muttrc.m438
-rw-r--r--readline/inputrc10
26 files changed, 469 insertions, 172 deletions
diff --git a/.gitignore b/.gitignore
index 6deb9bd6..bab3eb65 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
bin/han
bin/mean
bin/med
+bin/mftl
bin/mode
bin/rfct
bin/rndi
@@ -15,5 +16,6 @@ games/zs
git/gitconfig
gnupg/gpg.conf
man/man7/dotfiles.7df
+mutt/muttrc
tmux/tmux.conf
urxvt/ext/select
diff --git a/ISSUES.markdown b/ISSUES.markdown
index f58d7572..22cca775 100644
--- a/ISSUES.markdown
+++ b/ISSUES.markdown
@@ -30,6 +30,4 @@ Known issues
* sxhkd(1) might be nicer than xbindkeys; it's in Debian Testing now
* Maybe I should port some of the prompt functions to POSIX sh so I don't
have to maintain parallel versions for bash, pdksh, and zsh
-* The Mutt configuration is not very standalone; relies quite a lot on
- Debian's /etc/Muttrc and /etc/Muttrc.d, most of which can probably be
- included in my own configuration files.
+* PID completion for `kill` builtin
diff --git a/Makefile b/Makefile
index c1afe191..6353688c 100644
--- a/Makefile
+++ b/Makefile
@@ -64,11 +64,12 @@
NAME := Tom Ryder
EMAIL := tom@sanctum.geek.nz
KEY := 0xC14286EA77BB8872
-SENDMAIL := /usr/bin/msmtp
+SENDMAIL := msmtp
all : bin/han \
bin/mean \
bin/med \
+ bin/mftl \
bin/mode \
bin/rfct \
bin/rndi \
@@ -78,14 +79,14 @@ all : bin/han \
bin/tot \
bin/unf \
git/gitconfig \
- gnupg/gpg.conf \
- urxvt/ext/select
+ gnupg/gpg.conf
clean distclean :
rm -f \
bin/han \
bin/mean \
bin/med \
+ bin/mftl \
bin/mode \
bin/rfct \
bin/rndi \
@@ -177,8 +178,8 @@ install-bash-completion : install-bash
install -pm 0644 -- bash/bash_completion "$(HOME)"/.config/bash_completion
install -pm 0644 -- bash/bash_completion.d/* "$(HOME)"/.bash_completion.d
-install-bin : bin/han bin/sd2u bin/su2d bin/mean bin/med bin/mode \
- bin/tot bin/unf check-bin install-bin-man
+install-bin : bin/han bin/mean bin/med bin/mftl bin/mode bin/rfct \
+ bin/rndi bin/sd2u bin/slsf bin/su2d bin/tot bin/unf install-bin-man
install -m 0755 -d -- "$(HOME)"/.local/bin
for name in bin/* ; do \
[ -x "$$name" ] || continue ; \
diff --git a/README.markdown b/README.markdown
index 9717cae3..27bdfccb 100644
--- a/README.markdown
+++ b/README.markdown
@@ -42,8 +42,8 @@ Configuration is included for:
* [Bash](https://www.gnu.org/software/bash/) -- GNU Bourne-Again Shell,
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
+* [cURL](https://curl.haxx.se/) -- Command-line tool for transferring data
+ with URL syntax
* [Dunst](http://knopwob.org/dunst/) -- A lightweight X11 notification daemon
that works with `libnotify`
* `finger(1)` -- User information lookup program
@@ -62,49 +62,48 @@ Configuration is included for:
of the Korn shell
* [`psql(1)`](http://linux.die.net/man/1/psql) -- Command-line PostgreSQL
client
-* [Perl::Critic](http://perlcritic.com/) -- static source code analysis engine
- for Perl
+* [Perl::Critic](http://perlcritic.com/) -- static source code analysis
+ engine for Perl
* [Perl::Tidy](http://perltidy.sourceforge.net/) -- Perl indenter and
reformatter
* [Readline](https://cnswww.cns.cwru.edu/php/chet/readline/rltop.html) -- GNU
library for user input used by Bash, MySQL, and others
* [rxvt-unicode](http://software.schmorp.de/pkg/rxvt-unicode.html) -- Fork of
the rxvt terminal emulator with Unicode support
-* [Subversion](https://subversion.apache.org/) -- Apache Subversion, a version
- control system
+* [Subversion](https://subversion.apache.org/) -- Apache Subversion, a
+ version control system
* [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
+* [X11](https://www.x.org/wiki/) -- Windowing system with network
+ transparency for Unix
* [Yash](https://yash.osdn.jp/index.html.en) -- Yet another shell; just
enough configuration to make it read the portable POSIX stuff
* [Zsh](https://www.zsh.org/) -- Bourne-style shell designed for interactive
use
-The configurations for Bash, 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. Otherwise, the rest of the
-configuration isn't too distant from the defaults.
+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.
### Shell
My `.profile` and other files in `sh` are written in POSIX shell script, so
they should work in most `sh(1)` implementations. Individual scripts called by
`.profile` are saved in `.profile.d` and iterated on login for ease of
-management. All of these boil down to exporting variables appropriate to the
+management. Most of these boil down to exporting variables appropriate to the
system and the software it has available.
-I make an effort to target POSIX for my functions and scripts where I can, but
-Bash is my interactive shell of choice.
+Configuration that should be sourced for all POSIX-fearing shells is kept in
+`~/.shrc`, with subscripts read from `~/.shrc.d`.
-My `.bash_profile` calls `.profile`, and then `.bashrc`, which only applies for
-interactive shells. Subscripts for `.bashrc` are loaded from `.bashrc.d`. The
-contents of the `*.d` directories changes depending on the host, so only
-specific scripts in it are versioned.
+I make an effort to target POSIX for my functions and scripts where I can, but
+Bash is my interactive shell of choice. My `.bash_profile` calls `.profile`,
+and then `.bashrc`, which only applies for interactive shells. Subscripts for
+`.bashrc` are loaded from `.bashrc.d`.
As I occasionally have work on very old internal systems, my Bash is written to
work with [any version 2.05a or
@@ -124,9 +123,6 @@ after testing `BASH_VERSINFO` appropriately.
#### Prompt
-When I use any other Bourne-compatible shell, I'm generally happy to accept its
-defaults for interactive behavior.
-
A terminal session with my prompt looks something like this:
~$ ssh remote
@@ -141,8 +137,9 @@ A terminal session with my prompt looks something like this:
[1] 28937
tom@remote:~/.dotfiles(master+!){1}$
-The username and hostname are skipped if not connected via SSH. The right side
-of the prompt expands based on context to include these elements in this order:
+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:
* Whether in a Git repository if applicable, and punctuation to show
repository status including reference to upstreams at a glance. Subversion
@@ -223,14 +220,15 @@ There are a few other little tricks defined for other shells, mostly in
#### Completion
I find the `bash-completion` package a bit too heavy for my tastes, and turn it
-off using a stub file installed in `.config/bash_completion`. The majority of
+off using a stub file installed in `~/.config/bash_completion`. 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.
I do make some exceptions with completions defined in `.bash_completion.d`
-files for things I really do get tired of typing repeatedly:
+files, for things I really do get tired of typing repeatedly:
-* Builtins, commands, help topics, shell options, and variables
+* Bash builtins: commands, help topics, shell options, variables, etc.
+* `find(1)`'s more portable options
* `ftp(1)` hostnames from `~/.netrc`
* `git(1)` branch names
* `gpg(1)` long options
@@ -251,6 +249,10 @@ Bash ones. They're tested on OpenBSD and FreeBSD pdksh implementations, but the
former is the primary system for which I'm maintaining them, and there are some
feature differences.
+#### 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
@@ -273,7 +275,7 @@ most unfiltered mail is sent. I use
[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 interfacing is done with
+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
@@ -315,6 +317,9 @@ 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.
+
### Vim
The majority of the `.vimrc` file is just setting options, with a few mappings.
@@ -329,20 +334,19 @@ Scripts
-------
Where practical, I make short scripts into POSIX (but not Bourne) `sh(1)`,
-`awk(1)`, or `sed(1)` scripts in `~/.local/bin`. A few of them still have
-Bashisms for various reasons. 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.
+`awk(1)`, or `sed(1)` scripts in `~/.local/bin`. 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.
Installed by the `install-bin` target:
* Three SSH-related scripts:
* `sls(1df)` prints hostnames read from a `ssh_config(5)` file. It uses
`slsf(1df)` to read each one.
- * `sra(1df)` runs a command on multiple hosts read from `sls(1df)` and prints
- output.
- * `sta(1df)` runs a command on multiple hosts read from `sls(1df)` and prints
- the hostname if the command returns zero.
+ * `sra(1df)` runs a command on multiple hosts read from `sls(1df)` and
+ prints output.
+ * `sta(1df)` runs a command on multiple hosts read from `sls(1df)` and
+ prints the hostname if the command returns zero.
* Five URL-related shortcut scripts:
* `hurl(1df)` extracts values of `href` attributes of `<a>` tags, sorts
them uniquely, and writes them to `stdout`; it requires
@@ -370,41 +374,51 @@ Installed by the `install-bin` target:
* Four file formatting scripts:
* `d2u(1df)` converts DOS line endings in files to UNIX ones.
* `u2d(1df)` converts UNIX line endings in files to DOS ones.
- * `stbl(1df)` strips a trailing blank line from the files in its arguments.
- * `stws(1df)` strips trailing spaces from the ends of lines of the files in
- its arguments.
+ * `stbl(1df)` strips a trailing blank line from the files in its
+ arguments.
+ * `stws(1df)` strips trailing spaces from the ends of lines of the files
+ in its arguments.
* Five stream formatting scripts:
* `sd2u(1df)` converts DOS line endings in streams to UNIX ones.
* `su2d(1df)` converts UNIX line endings in streams to DOS ones.
- * `tl(1df)` tags input lines with a prefix or suffix, basically a `sed(1)`
- shortcut.
- * `tlcs(1df)` executes a command and uses `tl(1df)` to tag stdout and stderr
- lines, and color them if you want.
- * `unf(1df)` joins lines with leading spaces to the previous line. Intended
- for unfolding HTTP headers, but it should work for most RFC 822
- formats.
+ * `tl(1df)` tags input lines with a prefix or suffix, basically a
+ `sed(1)` shortcut.
+ * `tlcs(1df)` executes a command and uses `tl(1df)` to tag stdout and
+ stderr lines, and color them if you want.
+ * `unf(1df)` joins lines with leading spaces to the previous line.
+ Intended for unfolding HTTP headers, but it should work for most RFC
+ 822 formats.
+* Four simple aggregators for integer data:
+ * `mean(1df)` prints the mean.
+ * `med(1df)` prints the median.
+ * `mode(1df)` prints the first encountered mode.
+ * `tot(1df)` totals the set.
* `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
intended as a quick way to test how Awk would interpret a given expression.
* `bel(1df)` prints a terminal bell character.
+* `bl(1df)` generates a given number of blank lines.
* `br(1df)` launches `$BROWSER`, or a more suitable application for an URL if
it knows of one.
* `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.
+* `cfr(1df)` does the same as `cf(1df)`, but recurses into subdirectories as
+ well.
* `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
-* `dmp(1df)` copies a pass(1) entry selected by `dmenu(1)` to the X CLIPBOARD.
+* `clwr(1df)` sets up a per-line file write, clearing the screen before each
+ line
+* `dmp(1df)` copies a pass(1) entry selected by `dmenu(1)` to the X
+ CLIPBOARD.
* `dub(1df)` lists the biggest entries in a directory.
* `edda(1df)` provides a means to run `ed(1)` over a set of files preserving
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)`.
-* `fnl(1df)` runs a command and saves its output and error into temporary files,
- printing their paths and line counts
+* `fgscr(1df)` finds Git repositories in a directory root and scrubs them
+ with `gscr(1df)`.
+* `fnl(1df)` runs a command and saves its output and error into temporary
+ files, printing their paths and line counts
* `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)`.
@@ -418,23 +432,22 @@ Installed by the `install-bin` target:
* `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.
-* `maybe(1df)` is like `true(1)` or `false(1)`; given a probability of success,
+* `jfcd(1df)` watches a directory for changes and runs `jfc(1df)` if it sees
+ any.
+* `maybe(1df)` is like `true(1)` or `false(1)`; given a probability of
+ success,
it exits with success or failure. Good for quick tests.
-* `mean(1df)` prints the mean of a list of integers.
-* `med(1df)` prints the median of a list of integers.
-* `mode(1df)` prints the first encountered mode of a list of integers.
+* `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.
* `pa(1df)` prints its arguments, one per line.
* `paz(1df)` print its arguments terminated by NULL chars.
-* `pit(1df)` runs its input through a pager if its standard output looks like a
- terminal.
+* `pit(1df)` runs its input through a pager if its standard output looks like
+ a terminal.
* `plmu(1df)` retrieves a list of installed modules from
[`plenv`](https://github.com/tokuhirom/plenv), filters out any modules in
`~/.plenv/non-cpan-modules`, and updates them all.
-* `rmrej(1df)` deletes rejected hunks from a failed `patch(1)` run.
* `shb(1df)` attempts to build shebang lines for scripts from `$PATH`.
* `spr(1df)` posts its input to the sprunge.us pastebin.
* `sshi(1df)` prints human-readable SSH connection details.
@@ -442,12 +455,13 @@ Installed by the `install-bin` target:
* `sue(8df)` execs `sudoedit(8)` as the owner of all the file arguments given,
perhaps in cases where you may not necessarily have `root` `sudo(8)`
privileges.
-* `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.
-* `tot(1df)` adds up a list of integers.
-* `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
+* `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.
+* `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.
+* `umake(1df)` iterates upwards through the directory tree from `$PWD` until
+ it finds a Makefile for which to run `make(1)` with the given arguments.
There's some silly stuff in `install-games`:
@@ -466,12 +480,12 @@ 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 7df
+`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 `/etc/manpath` configuration, depending on your system.
+your `~/.manpath` or `/etc/manpath` configuration, depending on your system.
Testing
-------
diff --git a/bash/bash_completion.d/find.bash b/bash/bash_completion.d/find.bash
new file mode 100644
index 00000000..74dc17ad
--- /dev/null
+++ b/bash/bash_completion.d/find.bash
@@ -0,0 +1,89 @@
+# compopt requires Bash >=4.0, and I don't think it's worth making a compatible
+# version
+((BASH_VERSINFO[0] >= 4)) || return
+
+# Semi-intelligent completion for find(1); nothing too crazy
+_find() {
+
+ # Backtrack through words so far; if none of them look like options, we're
+ # still completing directory names
+ local -i opts
+ for ((i = COMP_CWORD; i >= 0; i--)) ; do
+ case ${COMP_WORDS[i]} in
+ -*)
+ opts=1
+ break
+ ;;
+ esac
+ done
+ if ! ((opts)) ; then
+ compopt -o dirnames
+ return
+ fi
+
+ # For the rest of this, if we end up with an empty COMPREPLY, we should
+ # just do what Bash would normally do
+ compopt -o bashdefault -o default
+
+ # Iterate through whatever the subshell gives us; don't add blank items, though
+ while read -r item ; do
+ [[ -n $item ]] || continue
+ COMPREPLY[${#COMPREPLY[@]}]=$item
+ done < <(
+
+ # If the word being completed starts with a dash, just complete it as
+ # an option; crude, but simple, and will be right the vast majority of
+ # the time
+ case ${COMP_WORDS[COMP_CWORD]} in
+ (-*)
+ compgen -W '
+ -atime
+ -ctime
+ -depth
+ -exec
+ -group
+ -links
+ -mtime
+ -name
+ -newer
+ -nogroup
+ -nouser
+ -ok
+ -perm
+ -print
+ -prune
+ -size
+ -type
+ -user
+ -xdev
+ ' -- "${COMP_WORDS[COMP_CWORD]}"
+ ;;
+ esac
+
+ # Otherwise, look at the word *before* this one to figure out what to
+ # complete
+ case "${COMP_WORDS[COMP_CWORD-1]}" in
+
+ # Args to -exec and -execdir should be commands
+ (-exec|-execdir)
+ compgen -A command -- "${COMP_WORDS[COMP_CWORD]}"
+ ;;
+
+ # Args to -group should complete group names
+ (-group)
+ compgen -A group -- "${COMP_WORDS[COMP_CWORD]}"
+ ;;
+
+ # Legal POSIX flags for -type
+ (-type)
+ compgen -W 'b c d f l p s' -- "${COMP_WORDS[COMP_CWORD]}"
+ ;;
+
+ # Args to -user should complete usernames
+ (-user)
+ compgen -A user -- "${COMP_WORDS[COMP_CWORD]}"
+ ;;
+ esac
+ )
+}
+complete -F _find find
diff --git a/bash/bash_completion.d/kill.bash b/bash/bash_completion.d/kill.bash
new file mode 100644
index 00000000..0aca041f
--- /dev/null
+++ b/bash/bash_completion.d/kill.bash
@@ -0,0 +1,15 @@
+# Complete kill builtin with jobspecs (prefixed with % so it will accept them)
+# and this user's PIDs (requires pgrep(1))
+_kill() {
+ while read -r pid ; do
+ case $pid in
+ "${COMP_WORDS[COMP_CWORD]}"*)
+ COMPREPLY[${#COMPREPLY[@]}]=$pid
+ ;;
+ esac
+ done < <( {
+ compgen -A job -P%
+ pgrep -u "$USER" .
+ } 2>/dev/null )
+}
+complete -F _kill kill
diff --git a/bash/bash_completion.d/make.bash b/bash/bash_completion.d/make.bash
index bf4ed268..c157bdc1 100644
--- a/bash/bash_completion.d/make.bash
+++ b/bash/bash_completion.d/make.bash
@@ -9,6 +9,7 @@ _make() {
case $line in
# We're looking for targets but not variable assignments
+ \#*) ;;
$'\t'*) ;;
*:=*) ;;
*:*)
diff --git a/bash/bashrc.d/completion.bash b/bash/bashrc.d/completion.bash
index 0ddb1b55..3e1c7bac 100644
--- a/bash/bashrc.d/completion.bash
+++ b/bash/bashrc.d/completion.bash
@@ -8,18 +8,22 @@
# Bash builtins
complete -A builtin builtin
+complete -A enabled disable
+complete -A disabled enable
# Bash options
complete -A setopt set
# Commands
-complete -A command command complete coproc exec hash type
+complete -A command command complete compopt coproc exec if hash time type until while
# Directories
complete -A directory cd pushd mkdir rmdir
-# Functions
+# Functions and variables
complete -A function function
+complete -A function -A variable declare export local readonly typeset unset
+complete -A variable for getopts let read select
# Help topics
complete -A helptopic help
@@ -37,11 +41,8 @@ complete -A shopt shopt
# Signal names
complete -A signal trap
-# Both functions and variables
-complete -A function -A variable declare export readonly typeset unset
-
# The `mapfile` builtin in Bash >= 4.0
-((BASH_VERSINFO[0] >= 4)) && complete -A arrayvar mapfile
+((BASH_VERSINFO[0] >= 4)) && complete -A arrayvar mapfile readarray
# If we have dynamic completion loading (Bash>=4.0), use it
if ((BASH_VERSINFO[0] >= 4)) ; then
diff --git a/bash/bashrc.d/prompt.bash b/bash/bashrc.d/prompt.bash
index 55c33282..3b99cc12 100644
--- a/bash/bashrc.d/prompt.bash
+++ b/bash/bashrc.d/prompt.bash
@@ -45,37 +45,32 @@ prompt() {
# Decide prompt color formatting based on color availability
local format
- case $colors in
-
- # Check if we have non-bold bright green available
- 256)
- format=$( {
- : "${PROMPT_COLOR:=10}"
- tput setaf "$PROMPT_COLOR" ||
- tput setaf "$PROMPT_COLOR" 0 0 ||
- tput AF "$PROMPT_COLOR" ||
- tput AF "$PROMPT_COLOR" 0 0
- } 2>/dev/null )
- ;;
-
- # If we have only eight colors, use bold green
- 8)
- format=$( {
- : "${PROMPT_COLOR:=2}"
- tput setaf "$PROMPT_COLOR" ||
- tput AF "$PROMPT_COLOR"
- tput bold || tput md
- } 2>/dev/null )
- ;;
-
- # For all other terminals, we assume non-color (!), and we just
- # use bold
- *)
- format=$( {
- tput bold || tput md
- } 2>/dev/null )
- ;;
- esac
+
+ # Check if we have non-bold bright green available
+ if ((colors >= 16)) ; then
+ format=$( {
+ : "${PROMPT_COLOR:=10}"
+ tput setaf "$PROMPT_COLOR" ||
+ tput setaf "$PROMPT_COLOR" 0 0 ||
+ tput AF "$PROMPT_COLOR" ||
+ tput AF "$PROMPT_COLOR" 0 0
+ } 2>/dev/null )
+
+ # If we have only eight colors, use bold green
+ elif ((colors >= 8)) ; then
+ format=$( {
+ : "${PROMPT_COLOR:=2}"
+ tput setaf "$PROMPT_COLOR" ||
+ tput AF "$PROMPT_COLOR"
+ tput bold || tput md
+ } 2>/dev/null )
+
+ # Otherwise, we just try bold
+ else
+ format=$( {
+ tput bold || tput md
+ } 2>/dev/null )
+ fi
# String it all together
PS1='\['"$format"'\]'"$PS1"'\['"$reset"'\] '
diff --git a/bin/bl b/bin/bl
new file mode 100755
index 00000000..b1831387
--- /dev/null
+++ b/bin/bl
@@ -0,0 +1,11 @@
+#!/bin/sh
+# Generate blank lines
+if [ "$#" -ne 1 ] || [ "$1" -lt 0 ] ; then
+ printf >&2 'bl: Non-negative line count needed as sole argument\n'
+ exit 2
+fi
+n=0
+while [ "$n" -lt "${1:-0}" ] ; do
+ printf '\n'
+ n=$((n+1))
+done
diff --git a/bin/cf b/bin/cf
index 3ff60156..d245fec1 100755
--- a/bin/cf
+++ b/bin/cf
@@ -1,10 +1,32 @@
#!/bin/sh
# Count entries in a given set of directories
+self=cf
+
+# Parse options out
+while getopts 'o' opt ; do
+ case $opt in
+
+ # Print only the count, not the filename
+ o) only=1 ;;
+
+ # Unknown option
+ \?)
+ printf >&2 '%s: Unknown option %s\n' \
+ "$self" "$opt"
+ exit 2
+ ;;
+ esac
+done
+shift "$((OPTIND-1))"
+
+# Iterate over remaining non-option arguments (directories); default to current
+# directory if none given
for dir in "${@:-.}" ; do
# Warn if a non-directory was given, flag errors, but continue
if ! [ -d "$dir" ] ; then
- printf >&2 'cf: %s: not a directory\n' "$dir"
+ printf >&2 '%s: %s: not a directory\n' \
+ "$self" "$dir"
ex=1
continue
fi
@@ -21,8 +43,12 @@ for dir in "${@:-.}" ; do
[ "$1" = "$dir"/. ] && shift
[ "$1" = "$dir"/.. ] && shift
- # Print number of parameters
- printf '%u\t%s\n' "$#" "$dir"
+ # Print either just the count, or the count and the dirname
+ if [ -n "$only" ] ; then
+ printf '%u\n' "$#"
+ else
+ printf '%u\t%s\n' "$#" "$dir"
+ fi
done
# Exit non-zero if a non-directory was given as an argument
diff --git a/bin/cfr b/bin/cfr
index 896126f5..f5eafef5 100755
--- a/bin/cfr
+++ b/bin/cfr
@@ -1,8 +1,13 @@
#!/bin/sh
# Count all descendants of given directories; don't follow symlinks
for dir in "${@:-.}" ; do
- tot=$(find "$dir" -type d \
- -exec sh -c 'cd -- "$1" && cf' _ {} \; |
- cut -f1 | tot)
- printf '%u\t%s\n' "$tot" "$dir"
+ if ! [ -d "$dir" ] ; then
+ printf >&2 'cfr: %s: Not a directory\n' "$dir"
+ ex=1
+ continue
+ fi
+ printf '%u\t%s\n' \
+ "$(find "$dir" -type d -exec cf -o -- {} \; | tot)" \
+ "$dir"
done
+exit "${ex:-0}"
diff --git a/bin/mftl.awk b/bin/mftl.awk
new file mode 100644
index 00000000..ee6ff022
--- /dev/null
+++ b/bin/mftl.awk
@@ -0,0 +1,38 @@
+# Try to find the targets in a Makefile that look like they're targets the user
+# could be reasonably expected to call directly
+
+# Separators are space, tab, or colon
+BEGIN {
+ FS = "[ \t:]"
+}
+
+# Skip comments
+/^#/ { next }
+
+# Join backslash-broken lines
+/\\$/ {
+ sub(/\\$/, "")
+ line = line $0
+ next
+}
+{
+ $0 = line $0
+ line = ""
+}
+
+# Check lines matching expected "targets:dependencies" format
+/^[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
+ # unique; this probably needs refinement
+ for (i = 1; i < NF; i++)
+ if ($i ~ /^[a-zA-Z0-9][a-zA-Z0-9./_-]*$/)
+ ats[$i]
+}
+
+# Print unique determined targets, sorted
+END {
+ for (t in ats)
+ print t | "sort"
+}
diff --git a/bin/rmrej b/bin/rmrej
deleted file mode 100755
index 8ecbd2c1..00000000
--- a/bin/rmrej
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-# Delete all rejected hunks from patch(1)
-find "${1:-.}" -type f -name \*.rej -print -exec rm -- {} \;
diff --git a/bin/tl b/bin/tl
index 5d494f5a..baa6fb2b 100755
--- a/bin/tl
+++ b/bin/tl
@@ -1,17 +1,21 @@
#!/bin/sh
-# Tag lines from files or stdin with a string prefix or suffix.
+# Tag lines from files or stdin with a string prefix or suffix
+self=tl
-# Parse options out, give help if necessary
+# Parse options out
while getopts 'p:s:' opt ; do
case $opt in
- p)
- pref=$OPTARG
- ;;
- s)
- suff=$OPTARG
- ;;
+
+ # Prefix
+ p) pref=$OPTARG ;;
+
+ # Suffix
+ s) suff=$OPTARG ;;
+
+ # Unknown option
\?)
- usage >&2
+ printf >&2 '%s: Unknown option %s\n' \
+ "$self" "$opt"
exit 2
;;
esac
diff --git a/bin/umake b/bin/umake
new file mode 100755
index 00000000..8c8d4850
--- /dev/null
+++ b/bin/umake
@@ -0,0 +1,11 @@
+#!/bin/sh
+# Keep going up the tree until we find a Makefile, and then run make(1) with
+# any given args
+while [ "$PWD" != / ] ; do
+ if [ -f Makefile ] ; then
+ exec make "$@" || exit
+ fi
+ cd .. || exit
+done
+printf >&2 'umake: No Makefile found in ancestors\n'
+exit 1
diff --git a/bin/xgo b/bin/xgo
index 6cbcaedb..6b354ac9 100755
--- a/bin/xgo
+++ b/bin/xgo
@@ -12,12 +12,18 @@ for url ; do (
# If it's a YouTube video without a given start time, load it in mpv(1)
case $url in
- # If it's a GitHub link, swap "blob" for "raw" to get the actual file
- *://github.com/*/blob/*)
+ # If this is a GitHub or GitLab link, swap "blob" for "raw" to get the actual file
+ *://github.com/*/blob/*|*://gitlab.com/*/blob/*)
url=$(printf '%s\n' "$url" | sed 's_/blob/_/raw/_')
;;
- # If it's a not-direct imgur link and not to an album, swap URL
+ # Dig out the plain text for pastebin.com links
+ *://pastebin.com/*)
+ # shellcheck disable=SC2016
+ url=$(printf '%s\n' "$url" | sed 's_/[A-Za-z0-9][A-Za-z0-9]*$_/raw&_')
+ ;;
+
+ # 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/*) ;;
@@ -25,7 +31,7 @@ for url ; do (
url=$(printf '%s\n' "$url" | sed 's_imgur\.com_i.imgur.com_;s/$/.jpg/')
;;
- # If it's a YouTube video without a given start time, load it in mpv(1)
+ # If this is a YouTube video without a given start time, load it in mpv(1)
*[/.]youtube.com/watch*[?\&]t=) ;;
*[/.]youtube.com/watch*)
mpv -- "$url" && exit
@@ -38,7 +44,7 @@ for url ; do (
# Switch on media type
case $mt in
- # Open PDFs in xpdf(1); download them first as xpdf(1) doesn't seem to
+ # Open PDFs in xpdf(1); download them first as xpdf(1) does not seem to
# have a way to handle stdin files
application/pdf)
(
diff --git a/man/man1/bl.1df b/man/man1/bl.1df
new file mode 100644
index 00000000..2edaec38
--- /dev/null
+++ b/man/man1/bl.1df
@@ -0,0 +1,16 @@
+.TH BL 1df "July 2016" "Manual page for bl"
+.SH NAME
+.B bl
+\- generate the given number of blank lines
+.SH SYNOPSIS
+.B bl
+10
+.B bl
+0
+.B bl
+237481728
+.SH DESCRIPTION
+.B bl
+generates the given number of blank lines and prints them to stdout.
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/cf.1df b/man/man1/cf.1df
index ab1338ba..9ced3c20 100644
--- a/man/man1/cf.1df
+++ b/man/man1/cf.1df
@@ -10,10 +10,20 @@
.br
.B cf
dir1 dir2
+.br
+.B cf
+-o dir1 dir2
.SH DESCRIPTION
.B cf
counts all the entries in the given directories using glob expansion and prints
the count. It defaults to the current directory.
+.P
+Giving the -o option omits printing the directory name (i.e., prints only the
+count); this is intended for use in scripts such as cfr(1df).
+.P
+It uses globs to do the counting, so it will give you unexpected results if
+you're counting a directory that has more than ARG_MAX entries in it. You'll
+have to resort to find(1) loops in that case.
.SH SEE ALSO
cfr(1df)
.SH AUTHOR
diff --git a/man/man1/cfr.1df b/man/man1/cfr.1df
index 2ec636bf..37dac2ad 100644
--- a/man/man1/cfr.1df
+++ b/man/man1/cfr.1df
@@ -14,15 +14,16 @@ dir1 dir2
.B cf
counts all the entries in the directory trees rooted at the given arguments,
and prints the total. It defaults to the current directory. It should correctly
-handle corner cases like files with newlines in them. It will count but will
-not follow symbolic links.
+handle corner cases like filenames with newlines in them. It will count but
+will not follow symbolic links.
.SH NOTES
You might think this would be better; it's certainly faster:
.P
- $ find . | wc -l
+ $ find . -mindepth 1 -print | wc -l
.P
However, it's subtly wrong; it will double-count anything with a path that
-contains a newline!
+contains a newline! You could use -print0 and count null characters instead,
+but then you've broken POSIX already.
.P
cfr(1df) and cf(1df) are POSIX-fearing as far as I can tell (please correct
me), but there are faster but less compatible ways to do this, while still
diff --git a/man/man1/mftl.1df b/man/man1/mftl.1df
new file mode 100644
index 00000000..efb2b486
--- /dev/null
+++ b/man/man1/mftl.1df
@@ -0,0 +1,30 @@
+.TH MFTL 1df "September 2016" "Manual page for mftl"
+.SH NAME
+.B mftl
+\- find and list usable-looking targets in Makefiles
+.SH SYNOPSIS
+.B
+mftl
+Makefile
+.br
+.B
+mftl
+Makefile1 Makefile2
+.br
+grep -v foo Makefile |
+.B
+mftl
+.SH DESCRIPTION
+.B mftl
+searches for targets in a Makefile specified as either targets or dependencies.
+Any targets it finds that are simple strings or filenames that look like they
+should be referenced by the user, are printed uniquely sorted to stdout.
+.P
+This is not 100% accurate (and probably can't be); GNU Make's heresies make it
+particularly complicated. For simple POSIX-ish Makefiles, it should work well.
+The idea is to get an overview of what's accessible in a Makefile without
+having to page through the whole thing.
+.SH SEE ALSO
+make(1)
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/rmrej.1df b/man/man1/rmrej.1df
deleted file mode 100644
index 9af77837..00000000
--- a/man/man1/rmrej.1df
+++ /dev/null
@@ -1,17 +0,0 @@
-.TH RMREJ 1df "August 2016" "Manual page for rmrej"
-.SH NAME
-.B rmrej
-\- delete all rejected hunks from a failed patch(1)
-.SH SYNOPSIS
-.B rmrej
-.br
-.B rmrej
-dir
-.SH DESCRIPTION
-.B rmrej
-uses find(1) to find rejected patch hunks (.rej) in the given directory
-(defaulting to the current directory), print their names, and delete them.
-.SH SEE ALSO
-patch(1)
-.SH AUTHOR
-Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man1/umake.1df b/man/man1/umake.1df
new file mode 100644
index 00000000..247ea50e
--- /dev/null
+++ b/man/man1/umake.1df
@@ -0,0 +1,15 @@
+.TH UMAKE 1df "September 2016" "Manual page for umake"
+.SH NAME
+.B umake
+\- run make(1) with the closest Makefile in current working directory ancestry
+.SH USAGE
+.B umake
+.br
+.B umake
+prefix=/foo/bar install
+.SH DESCRIPTION
+Iterate up through the directory tree starting with the current directory,
+looking for a Makefile, and run make(1) with the given arguments as soon as one
+is found.
+.SH AUTHOR
+Tom Ryder <tom@sanctum.geek.nz>
diff --git a/man/man6/rndn.6df b/man/man6/rndn.6df
index 97fbe30a..25a30513 100644
--- a/man/man6/rndn.6df
+++ b/man/man6/rndn.6df
@@ -6,14 +6,14 @@
.B rndn
.br
.B rndn
--s 381290
+381290
.br
business-critical-process -t "$(\fBrndn\fR)"
.SH DESCRIPTION
.B rndn
uses an advanced but somewhat esoteric algorithm derived by Adams (2001) to
-return a random number. The seed can be derived internally or specified with
-the -s option.
+return a random number. The seed can be derived internally or specified as an
+argument.
.P
While rndn(6df) has proven robust in the author's production usage, its algorithm
has not been formally verified.
diff --git a/mutt/muttrc.m4 b/mutt/muttrc.m4
index 44883c32..6211fb85 100644
--- a/mutt/muttrc.m4
+++ b/mutt/muttrc.m4
@@ -26,14 +26,28 @@ set query_command = 'abook --mutt-query %s'
# Alerts
set beep_new = yes
+# Attachments
+attachments +A */.*
+attachments -A text/x-vcard application/pgp.*
+attachments -A application/x-pkcs7-.*
+attachments +I text/plain
+attachments -A message/external-body
+attachments -I message/external-body
+
# Caching
set header_cache = '~/.cache/mutt/headers'
# Colors
-color indicator black white
-color normal default default
-color status white color22
-color tree default default
+color attachment brightyellow default
+color hdrdefault cyan default
+color indicator black white
+color markers brightred default
+color normal default default
+color quoted green default
+color signature cyan default
+color status default color22
+color tilde blue default
+color tree default default
# Completion
bind editor <Tab> complete-query
@@ -47,7 +61,9 @@ set move = no
set mark_old = no
# Headers
-hdr_order Date From To Cc
+ignore *
+unignore Date From: To Cc Subject
+hdr_order Date From: To Cc Subject
set edit_headers = yes
# Index
@@ -68,6 +84,9 @@ set confirmcreate = yes
# Menus
set menu_context = 1
+# MIME
+mime_lookup application/octet-stream
+
# Pager
set pager_context = 1
set pager_format = '%4C %Z %[!%b %e at %I:%M %p] %.20n %s%* -- (%P)'
@@ -81,6 +100,9 @@ set tilde = yes
alternative_order text/plain text/html *
auto_view text/html
+# Quoting
+set quote_regexp = '^(>[ \t]*)+'
+
# Responses
set fast_reply = yes
set forward_format = 'Fw: %s'
@@ -93,6 +115,9 @@ set sort_aux = 'last-date-received'
set strict_threads = yes
set thorough_search = yes
+# SSH
+set time_inc=250
+
# Encryption settings
set crypt_replysign = yes
set crypt_replyencrypt = yes
@@ -113,6 +138,9 @@ bind index,pager \Cd half-down
bind generic,index,browser,pager \Cf next-page
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'
diff --git a/readline/inputrc b/readline/inputrc
index dd284f0b..3f98c08d 100644
--- a/readline/inputrc
+++ b/readline/inputrc
@@ -8,9 +8,6 @@ set bell-style none
# Let readline do stuff like word killing, not stty(1)
set bind-tty-special-chars off
-# Jump to the matching parenthesis briefly when closing one
-set blink-matching-paren on
-
# Ignore case when matching and completing paths
set completion-ignore-case on
@@ -85,7 +82,10 @@ $if Bash
$endif
-# Don't let bc complete filenames (!?)
+# bc macros
$if bc
- Tab:
+
+ # Don't let bc complete filenames (!?)
+ Tab:
+
$endif