+## open : string -> unit
+##
+## Fork xdg-open so we don't block current terminal session when opening
+## things like pdf files. For example:
+##
+## open book.pdf
+##
+open() {
+ (xdg-open "$1" &) &
+}
+
+## notify_done : unit -> unit
+notify_done() {
+ local -r _status_code="$?"
+ local -r _program="$1"
+ local _timestamp
+ _timestamp="$(timestamp)"
+ local -r _msg="$_timestamp [$_program] done "
+ if [[ "$_status_code" -eq 0 ]]
+ then
+ notify-send -u normal "$_msg OK: $_status_code"
+ else
+ notify-send -u critical "$_msg ERROR: $_status_code"
+ fi
+}
+
+## p : string -> unit
+p() {
+ awk \
+ -v _s="$1" \
+ '
+ BEGIN {_s = tolower(_s)}
+
+ # TODO fzf/dmenu select instead of searching:
+ /^[a-zA-Z]/ && tolower($1) ~ _s && NF >= 2 {
+ n++
+ s = $1
+ p = $NF
+ if (NF == 2) {
+ e = ""
+ u = ""
+ } else if (NF == 3) {
+ e = $2
+ u = ""
+ } else {
+ e = $2
+ u = $3
+ } # TODO What would NF > 4 mean?
+
+ printf("%d [O] s:\"%s\", e:\"%s\", u:\"%s\"\n", n, s, e, u) > "/dev/stderr"
+ if (match(u, "@")) {
+ tmp = e
+ e = u
+ u = tmp
+ printf("%d [C] s:\"%s\", e:\"%s\", u:\"%s\"\n", n, s, e, u) > "/dev/stderr"
+ }
+
+ printf "%s", p # XXX Intentionally avoiding newline in the result.
+ }
+
+ END {
+ if (n == 1) {
+ exit 0
+ } else if (n == 0) {
+ printf "[ERROR] Found nothing.\n" > "/dev/stderr"
+ exit 1
+ } else if (n > 1) {
+ # TODO fzf-select which of the records the user (ahem, me) wants.
+ printf "[WARNING] Found more than one record.\n" > "/dev/stderr"
+ exit 0
+ }
+ }
+ ' \
+ ~/._p/p \
+ | xsel -i -b -t 30000
+}
+
+## web search
+## ws : string -> unit
+ws() {
+ local line search_string0 search_string
+
+ search_string0="$*"
+ case "$search_string0" in
+ '')
+ while read -r line; do
+ search_string="${search_string} ${line}"
+ done;;
+ *)
+ search_string="$search_string0";;
+ esac
+
+ firefox --search "$search_string"
+}
+
+
+## dictionary
+## d : string -> string list