summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@sbcglobal.net>2014-11-27 20:06:16 -0500
committerLuke Shumaker <lukeshu@sbcglobal.net>2014-11-27 20:06:16 -0500
commita971938946dd61a3468263908988363dbdd87a3d (patch)
treec3cc9ef949523199b81f8f7799c3c1863b59554c
initial commit of my emacs scripts, after some cleanup
-rw-r--r--.gitignore6
-rw-r--r--Makefile36
-rw-r--r--common.sh86
-rw-r--r--ediff.sh.in62
-rw-r--r--emacsmail.sh.in57
-rw-r--r--emacsterm.sh.in145
6 files changed, 392 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..58eb704
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+ediff
+emacsmail
+emacsterm
+
+*.sh
+!common.sh
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..bbb19d1
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,36 @@
+DESTDIR=
+prefix=/usr/local
+exec_prefix=$(prefix)
+bindir=$(exec_prefix)/bin
+
+bash=/bin/bash
+
+EDIT = { m4 -P | sed 's|@bash@|$(bash)|g'; }
+INSTALL_PROGRAM = install -Dm755
+RM = rm -f
+
+
+
+targets = ediff emacsmail emacsterm
+
+all: PHONY $(targets)
+install: PHONY $(addprefix $(DESTDIR)$(bindir)/,$(targets))
+uninstall: PHONY
+ $(RM) -- $(addprefix $(DESTDIR)$(bindir)/,$(targets))
+clean: PHONY
+ $(RM) -- $(addsuffix .sh,$(targets))
+distclean: PHONY clean
+ $(RM) -- $(targets)
+
+
+
+%.sh: %.sh.in common.sh
+ $(EDIT) < $< > $@
+
+$(DESTDIR)$(bindir)/%: %
+ $(INSTALL_PROGRAM) $< $@
+
+
+
+.PHONY: PHONY
+.DELETE_ON_ERROR:
diff --git a/common.sh b/common.sh
new file mode 100644
index 0000000..93f8851
--- /dev/null
+++ b/common.sh
@@ -0,0 +1,86 @@
+if type gettext &>/dev/null; then
+ _() { gettext "$@"; }
+else
+ _() { echo "$@"; }
+fi
+
+print() {
+ printf -- "$(_ "$1")\n" "${@:2}"
+}
+
+flag() {
+ if [[ -z "$_flag_indent" ]]; then
+ local str=$(emacsclient --help |
+ sed -rn '/^-.*\s\s/{ s/(\s\s)\S.*/\1/p; q; }' |
+ expand)
+ declare -gi _flag_indent=${#str}
+ fi
+ printf -- "%- ${_flag_indent}s%s\n" "$1" "$(print "${@:2}")"
+}
+
+error() {
+ printf -- "%s: %s\n" "$0" "$(print "$@")" >&2
+}
+
+emacs_quote() {
+ declare -a args=("$@")
+ args=("${args[@]//\\/\\\\}") # \ -> \\
+ args=("${args[@]//\"/\\\"}") # " -> \"
+ printf -- '"%s" ' "${args[@]}" # wrap them in quotes, return
+}
+
+bash_quote() {
+ printf -- '%q ' "$@"
+}
+
+version() {
+ print '%s (Emacs utils) %s, %s' \
+ "${0##*/}" 0.9 "$(emacsclient --version)"
+}
+
+# Sets the global variables:
+# - emacs_getopt_o
+# - emacs_getopt_l
+# - emacs_getopt_1
+# - emacs_getopt_2
+emacs_getopt_init() {
+ declare ifs="$IFS"
+
+ declare -a a_flags
+ IFS=$'\n' a_flags=($(
+ LC_ALL=C emacsclient --help |
+ grep ^- |
+ sed -e 's/\s\s.*//' -e 's/, /\n/g' |
+ sed -e 's/[ =].*/:/' -e 's/^-*//' |
+ grep -vEx 'e|eval'))
+
+ declare -a a_flags_o a_flags_l a_flags_1 a_flags_2
+ IFS=$'\n' a_flags_o=($(printf '%s\n' "${a_flags[@]}"|grep -v '^.[^:]'))
+ IFS=$'\n' a_flags_l=($(printf '%s\n' "${a_flags[@]}"|grep '^.[^:]'))
+ IFS=$'\n' a_flags_1=($(printf '%s\n' "${a_flags[@]}"|sed -rn -e 's/^(.)$/-\1/p' -e 's/^([^-].*[^:])$/--\1/p'))
+ IFS=$'\n' a_flags_2=($(printf '%s\n' "${a_flags[@]}"|sed -rn -e 's/^(.):$/-\1/p' -e 's/^([^-].*):$/--\1/p'))
+
+ printf -v emacs_getopt_o -- '%s' "${a_flags_o[@]}"
+ IFS=',' emacs_getopt_l=${a_flags_l[*]}
+ IFS='|' emacs_getopt_2="^(${a_flags_2[*]})\$"
+
+ IFS=$ifs
+}
+
+# Sets the global variable:
+# - args
+emacs_getopt() {
+ declare o="$1"
+ declare l="$2"
+ shift 2
+ emacs_getopt_init
+ args="$(getopt -a \
+ -n "$0" \
+ -o "${emacs_getopt_o}${o}" \
+ -l "${emacs_getopt_l}${l:+,$l}" \
+ -- "$@")"
+}
+
+emacs_usage() {
+ emacsclient --help | grep -E '^(\s|-)'
+}
diff --git a/ediff.sh.in b/ediff.sh.in
new file mode 100644
index 0000000..5ecba70
--- /dev/null
+++ b/ediff.sh.in
@@ -0,0 +1,62 @@
+#!@bash@
+
+m4_include(common.sh)
+
+usage() {
+ print 'Usage: %q [OPTIONS] FILE_A FILE_B' "$0"
+ print 'Usage: %q -3 [OPTIONS] FILE_A FILE_B FILE_C' "$0"
+ print "Use Emacs' ediff-mode to compare two files"
+ echo
+ print 'The following OPTIONS are accepted:'
+ emacs_usage
+ flag '-3' 'Do a 3-way diff instead of 2-way'
+ flag '-r, --recursive' 'Diff directories recursively'
+}
+
+main() {
+ declare -a flags=()
+ declare -a files=()
+ declare -i cnt=2
+ declare error=false
+ declare mode=normal
+ declare cmd=ediff
+
+ declare args=
+ emacs_getopt 3r recursive "$@" || error=true
+ eval set -- "$args"
+ while true; do
+ case "$1" in
+ -V|--version) shift; mode=version;;
+ -H|--help) shift; mode=usage
+ -r|--recursive) shift; cmd=edirs;;
+ -3) shift; cnt=3;;
+ --) shift; break;;
+ *)
+ if [[ $1 =~ $emacs_getopt_2 ]]; then
+ flags+=("$1" "$2"); shift 2
+ else
+ flags+=("$1"); shift 1
+ fi
+ ;;
+ esac
+ done
+ files=("$@")
+ if [[ $mode == normal ]]; then
+ [[ ${#files[@]} = ${cnt} ]] || error=true
+ fi
+
+ if $error; then
+ usage >&2
+ return 1
+ fi
+ case "$mode" in
+ usage) usage; return 0;;
+ version) version; return 0;;
+ esac
+
+ emacsclient "${flags[@]}" --eval \
+ '(select-frame (make-frame))' \
+ "(${cmd}${cnt#2} $(emacs_quote "${files[@]}"))"
+}
+
+main "$@"
diff --git a/emacsmail.sh.in b/emacsmail.sh.in
new file mode 100644
index 0000000..e5eef50
--- /dev/null
+++ b/emacsmail.sh.in
@@ -0,0 +1,57 @@
+#!@bash@
+
+m4_include(common.sh)
+
+usage() {
+ print 'Usage: %q [OPTIONS] MAILTO_URL' "$0"
+ print 'Use Emacs to open RFC 2368 "mailto:" URLs'
+ echo
+ print 'Yes, I know that RFC 2368 is obsoleted by RFC 6068.'
+ print 'emacs-devel@gnu.org would *love* a patch to browse-url.el'
+ echo
+ print 'The following OPTIONS are accepted:'
+ emacs_usage
+}
+
+main() {
+ declare -a flags=()
+ declare error=false
+ declare mode=normal
+
+ declare args=
+ emacs_getopt '' '' "$@" || error=true
+ eval set -- "$args"
+ while true; do
+ case "$1" in
+ -V|--version) shift; mode=version;;
+ -H|--help) shift; mode=usage;;
+ --) shift; break;;
+ *)
+ if [[ $1 =~ $emacs_getopt_2 ]]; then
+ flags+=("$1" "$2"); shift 2
+ else
+ flags+=("$1"); shift 1
+ fi
+ ;;
+ esac
+ done
+ urls=("$@")
+ if [[ $mode == normal ]]; then
+ [[ ${#urls[@]} = 1 ]] || error=true
+ fi
+
+ if $error; then
+ usage >&2
+ return 1
+ fi
+ case "$mode" in
+ usage) usage; return 0;;
+ version) version; return 0;;
+ esac
+
+ emacsclient "${flags[@]}" --eval \
+ '(select-frame (make-frame))' \
+ "(browse-url-mail $(emacs_quote "${urls[@]}"))"
+}
+
+main "$@"
diff --git a/emacsterm.sh.in b/emacsterm.sh.in
new file mode 100644
index 0000000..e199f95
--- /dev/null
+++ b/emacsterm.sh.in
@@ -0,0 +1,145 @@
+#!@bash@
+
+m4_include(common.sh)
+
+usage() {
+ print "Usage: %q [OPTIONS] [SHELL]" "$0"
+ echo
+ print 'This utility does NOT support option combining.'
+ echo
+ print 'The following OPTIONS are accepted:'
+ emacs_usage
+ flag '-r' 'Use rxvt-style parsing of CMD for -e (~execve)'
+ flag '-x' 'Use xterm-style parsing of CMD for -e (~system)'
+ flag "-e $(_ CMD)" 'Execute CMD instead of ${SHELL:-/bin/sh}'
+}
+
+
+main() {
+ declare mimic
+ declare cmd
+ declare -a flags
+ parse "$@"
+
+ emacsclient "${flags[@]}" --eval \
+ '(select-frame (make-frame))' \
+ "(term $(emacs_quote "${cmd}"))" \
+ '(set-window-dedicated-p (selected-window) t)'
+}
+
+# Sets the 'global' variables:
+# - mode
+# - mimic
+# - cmd
+# - flags (array)
+parse() {
+ mimic=rxvt
+ cmd=
+ flags=()
+
+ local mode=normal
+ local error=false
+ emacs_getopt_init
+
+ while [[ $# -gt 0 ]]; do
+ case "$1" in
+ -V|--version) shift; mode=version;;
+ -H|--help) shift; mode=usage;;
+ -r) shift; mimic=rxvt;;
+ -x) shift; mimic=xterm;;
+ -e) shift; parse_cmd "$@"; set --;;
+ --) shift; parse_shell "$@"; set --;;
+ -*) parse_emacs_getopt "$@"; shift $?;;
+ *) parse_shell "$@"; set --;;
+ esac
+ done
+
+ if $error; then
+ usage >&2
+ exit 1
+ fi
+ case "$mode" in
+ usage) usage; exit 0;;
+ version) version; exit 0;;
+ esac
+
+ if [[ -z "$cmd" ]]; then
+ # This matches rxvt's behavior.
+ # This is simpler than xterm's behavior.
+ cmd="${cmd:-${SHELL:-/bin/sh}}"
+ fi
+}
+
+# Return status is the number of things to shift
+parse_emacs_getopt() {
+ declare -a flag
+ if eval "flag=($(getopt -a \
+ -n "$0" \
+ -o "${emacs_getopt_o//:/}" \
+ -l "${emacs_getopt_l//:/}" \
+ -- "$1" 2>/dev/null))" &&
+ [[ ${#flag[@]} == 2 ]]
+ then
+ # getopt worked
+ if [[ $flag =~ $emacs_getopt_2 ]]; then
+ # flag takes an argument
+ if [[ $# -gt 1 ]]; then
+ flags+=("$flag" "$2")
+ return 2
+ else
+ # Missing the required 2nd part
+ getopt -a \
+ -n "$0" \
+ -o "$emacs_getopt_o" \
+ -l "$emacs_getopt_l" \
+ -- "$flag" >/dev/null
+ error=true
+ return 1
+ fi
+ else
+ # pass the flag along to emacs
+ flags+=("$flag")
+ return 1
+ fi
+ else
+ # getopt either didn't work, or did combined flags
+ # Have getopt display its own error message:
+ getopt -a -n "$0" -o '' -l '' -- "$1" >/dev/null
+ error=true
+ return 1
+ fi
+}
+
+parse_cmd() {
+ cmd="$(mktemp -t -- "${0##*/}.XXXXXXXXXX")"
+ trap "$(printf 'rm -f -- %q' "$cmd")" EXIT
+ {
+ echo '#!/bin/sh'
+ case "$mimic" in
+ xterm)
+ if [[ $# == 1 ]]; then
+ printf '%s' "$1"
+ else
+ printf -- '%q ' exec "$@"
+ fi
+ ;;
+ rxvt)
+ printf -- '%q ' exec "$@"
+ ;;
+ esac
+ echo
+ } > "$cmd"
+ chmod 755 "$cmd"
+}
+
+parse_shell() {
+ if [[ $# == 1 ]]; then
+ cmd=$1
+ else
+ shift
+ error "extra arguments: %s" "$*"
+ error=true
+ fi
+}
+
+main "$@"