├── ealiasrc.example ├── README.org └── ealias /ealiasrc.example: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ealias rgrep='rgrep %^ %* \"$PWD\"' 4 | ealias lgrep='grep \"grep --color -nH -e $*\"' 5 | ealias eman='man %*' 6 | ealias woman='woman %1' 7 | ealias ediff='diff %^ %^ %*' 8 | ealias eediff='ediff %1 %2' 9 | ealias vcdir='vc-dir \"${1:-$PWD}\"' 10 | ealias gnus='gnus-other-frame' 11 | ealias dired='dired-other-window \"${1:-$PWD}\"' 12 | ealias sdired='dired-other-window \"/sudo::$(readlink -f "${1:-$PWD}")\"' 13 | ealias ff='find-file-other-window %* t' 14 | ealias sff='find-file-other-window \"/sudo::$(readlink -f "$1")\"' 15 | ealias find-dired='find-dired %^ %*' 16 | 17 | complete -d dired 18 | complete -d sdired 19 | complete -d vcdir 20 | 21 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | #+TITLE: ealias README 2 | #+AUTHOR: Andreas Politz 3 | #+EMAIL: politza@fh-trier.de 4 | 5 | * Description 6 | 7 | The ealias command is in effect a wrapper around emacsclient for the 8 | Bash shell. It's a simple way of defining a shell function, which 9 | will in turn call a specific Emacs function with a number of given 10 | arguments. It gives a little bit of eshell feeling and is 11 | especially useful for mapping terminal-loving commands like ~man~ to 12 | their Emacs equivalents when using an M-x shell. 13 | 14 | * Installation 15 | 16 | Somehow download the file ~ealias~ in some directory and source it 17 | either from your ~/.bashrc, for access in any shell, or your 18 | ~/.emacs_bash, if you prefer it only being active in the M-x shell. 19 | 20 | * Usage 21 | 22 | After proper installation you should have access to a new command 23 | called ~ealias~. See the output of 24 | #+BEGIN_SRC sh 25 | $ ealias --help 26 | #+END_SRC 27 | for a complete description and the [[Examples]] section below. 28 | 29 | ** Environment Variables 30 | 31 | There are a couple of variables which influence the behavior of 32 | the ~ealias~ command. They are listed in the following table and 33 | further described below. 34 | 35 | | Variable | Default | Description | 36 | |---------------+--------------------+------------------------------------------| 37 | | EALIAS_RC | ~/.config/ealiasrc | Filename to use for the -w/-r/-e options | 38 | | EALIAS_CLIENT | emacsclient | Program to use as emacsclient | 39 | |---------------+--------------------+------------------------------------------| 40 | 41 | For convenience the ~ealias~ options ~-w~, ~-r~ and ~-e~ let you 42 | write, resp. read, resp. edit the file ~EALIAS_RC~ . This is just 43 | an easy way to write your possibly interactively defined aliases to 44 | a file and read them back in later. 45 | 46 | * Examples 47 | 48 | A ~ealias~ definition looks pretty much like a normal alias, except 49 | it 50 | + may contain a number of special format codes and 51 | + it is called much like a function, i.e. it accepts parameter. 52 | 53 | Let's start with a simple example and redefine the ~man~ command, 54 | which is pretty useless in an M-x shell. 55 | #+BEGIN_SRC sh 56 | $ ealias man='man %*' 57 | #+END_SRC 58 | 59 | The ~%*~ construct takes the remaining arguments (in this case all) 60 | and concatenates them into a single string. We can examine what 61 | would be executed with the ~-n~ option. 62 | #+BEGIN_SRC sh 63 | $ man -n 3 printf 64 | emacsclient --eval (man "3 printf") 65 | $ man 3 printf 66 | # 67 | #+END_SRC 68 | 69 | The next alias utilizes the ~diff~ command, which takes 3 arguments, 70 | namely the 2 files to find the differences for and which options to 71 | use. 72 | #+BEGIN_SRC sh 73 | $ ealias ediff='diff %^ %^ %*' 74 | #+END_SRC 75 | The ~%^~ code pops an argument and wraps it, like all 76 | ~%~-constructs, in double-quotes, thereby transforming the shell 77 | word into a Lisp string. 78 | #+BEGIN_SRC sh 79 | $ ediff -n file1 file2 -w -c 80 | emacsclient --eval (diff "file1" "file2" "-w -c") 81 | #+END_SRC 82 | The last example finds a file and edits it as the root user. 83 | #+BEGIN_SRC sh 84 | $ ealias redit='find-file-other-window \"/sudo::$(readlink -f "$1")\"' 85 | #+END_SRC 86 | Note, that this alias uses regular parameters only. Since the whole 87 | expression is evaluated, we need to escape the quotes. 88 | #+BEGIN_SRC sh 89 | $ redit -n /etc/bashrc 90 | emacsclient --eval (find-file-other-window "/sudo::/etc/bashrc") 91 | #+END_SRC 92 | See the file ~ealiasrc.example~ for more examples. 93 | 94 | 95 | -------------------------------------------------------------------------------- /ealias: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## Copyright (C) 2016 Andreas Politz 3 | 4 | ## Author: Andreas Politz 5 | 6 | ## This program is free software; you can redistribute it and/or modify 7 | ## it under the terms of the GNU General Public License as published by 8 | ## the Free Software Foundation, either version 3 of the License, or 9 | ## (at your option) any later version. 10 | 11 | ## This program is distributed in the hope that it will be useful, 12 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ## GNU General Public License for more details. 15 | 16 | ## You should have received a copy of the GNU General Public License 17 | ## along with this program. If not, see . 18 | 19 | # An ealias is an alias, which expands to an invocation of 20 | # `emacsclient --eval' with an appropriate arguments. See function 21 | # _ealias_help. 22 | 23 | 24 | # File aliases saved with the -w flag. 25 | EALIAS_RC=${EALIAS_RC-~/.config/ealiasrc}; 26 | 27 | # Hash with ealias names as keys and their expansion as values. 28 | if [ -z "${EALIAS_ALIASES[*]}" ]; then 29 | declare -A EALIAS_ALIASES 30 | EALIAS_ALIASES=() 31 | fi 32 | 33 | # Define an Emacs alias. 34 | ealias() 35 | { 36 | 37 | local name=${1%%=*} 38 | local spec=${1#*=} 39 | 40 | if [ $# -gt 1 ] ; then 41 | _ealias_usage 42 | return 1 43 | elif [ $# -eq 0 ] || [ "$1" = "-p" ]; then 44 | _ealias_print 45 | return 0 46 | elif [ "$1" = "--help" ]; then 47 | _ealias_help 48 | return 0 49 | elif [[ "$1" == -[ewr] ]]; then 50 | if [ -z "$EALIAS_RC" ]; then 51 | echo "\$EALIAS_RC is not set" >&2 52 | return 1 53 | fi 54 | if [ "$1" = "-e" ]; then 55 | "${EALIAS_CLIENT:-emacsclient}" "$EALIAS_RC" 56 | return 0 57 | elif [ "$1" = "-w" ]; then 58 | echo '#!/bin/bash' > "$EALIAS_RC" && \ 59 | _ealias_print >> "$EALIAS_RC" && echo "Wrote $EALIAS_RC" >&2 60 | return $? 61 | elif [ "$1" = "-r" ]; then 62 | PATH= source "$EALIAS_RC" && echo "Read $EALIAS_RC" >&2 63 | return $? 64 | fi 65 | elif [ "${name:0:1}" = "-" ]; then 66 | _ealias_usage 67 | return 1 68 | elif [ "$name" = "$1" ]; then 69 | _ealias_print "$name" 70 | return $? 71 | fi 72 | 73 | EALIAS_ALIASES[$name]=$spec 74 | eval "_ealias_fn_$name() { _ealias_execute '$name' \"\$@\"; }" 75 | alias "$name"="_ealias_fn_$name" 76 | 77 | return 0 78 | } 79 | 80 | _ealias_usage() 81 | { 82 | cat <<'EOF' 83 | usage:ealias [-[pnws] | --help | name | name=spec] 84 | EOF 85 | } 86 | 87 | _ealias_help() 88 | { 89 | _ealias_usage 90 | cat << 'EOF' 91 | 92 | Define or display Emacs aliases. 93 | 94 | Without arguments, `ealias' prints the list of Emacs aliases in 95 | the reusable form `ealias NAME=SPEC' to standard output. 96 | 97 | If only NAME is given, print just it's definition. 98 | 99 | Otherwise, an alias is defined for NAME according to SPEC in the 100 | following way: The first word is taken as the function, which is 101 | to be called with the remaining string as arguments. These 102 | arguments are evaluated when emacsclient is invoked. SPEC may 103 | contain special format codes, all starting with a `%', similar to 104 | printf. These are substituted for various constructs at the time 105 | the alias is executed with a given argument list, as follows: 106 | 107 | %^ Pop the next argument and use it as a string. 108 | 109 | %@ Use the remaining arguments as a list of strings. 110 | 111 | %* Use the remaining arguments as a single string. 112 | 113 | %1 .. %9 Use the nth argument as a string. 114 | 115 | %% Insert a literal `%'. 116 | 117 | Every alias defines a Bash function, which will invoke the 118 | emacsclient program with arguments according to SPEC. Unless the 119 | first argument is `-n', in which case the resulting command is 120 | only printed. 121 | 122 | The program to use as emacsclient may be set via the environment 123 | variable EALIAS_CLIENT. 124 | 125 | Options: 126 | 127 | -p Print all defined Emacs aliases in a reusable format. 128 | -n Only print what would be executed (dry-run). 129 | -r Read ealias definitions from file $EALIAS_RC . 130 | -w Write current definitions to file $EALIAS_RC, overwriting it. 131 | -e Edit the $EALIAS_RC file. 132 | --help Print this message. 133 | 134 | Example: 135 | 136 | ealias rgrep='rgrep %^ %* \"$PWD\"' 137 | 138 | Use the first argument as REGEXP, the rest as FILES and $PWD as 139 | DIR argument (see rgrep Emacs function). Note that the quotes 140 | need to be escaped, since the whole SPEC is evaluated. 141 | 142 | After this definition a command like 143 | 144 | rgrep printf \*.c \*.h 145 | 146 | will expand into 147 | 148 | emacsclient --eval "(rgrep \"printf\" \"*.c *.h\" \"$PWD\")" 149 | 150 | The following, slightly silly, example creates an alias, which 151 | adds up all arguments as numbers. 152 | 153 | ealias eplus='apply '\''+ $* nil' 154 | 155 | Since this alias does not pass any strings, the regular shell 156 | parameter substitution is sufficient. Let's see if it works as 157 | expected: 158 | 159 | $ eplus -n $(seq 1 4) 160 | emacsclient --eval (apply '+ 1 2 3 4 nil) 161 | $ eplus $(seq 1 4) 162 | 10 163 | 164 | Exit Status: 165 | 166 | ealias returns true, unless trying to print an undefined alias or 167 | some other error happened. 168 | 169 | See also: 170 | 171 | `eunalias' to remove a defined Emacs alias. 172 | EOF 173 | } 174 | 175 | # Remove an Emacs alias 176 | eunalias() 177 | { 178 | if [ $# -ne 1 ]; then 179 | echo "usage:eunalias NAME" 180 | return 1; 181 | fi 182 | 183 | local name=$1 184 | 185 | if [ -n "${EALIAS_ALIASES[$name]}" ]; then 186 | unset EALIAS_ALIASES[$name] 187 | unset -f "$name" 188 | unalias $name 189 | return 0 190 | fi 191 | echo "No such alias: $name" >&2 192 | return 1 193 | } 194 | 195 | 196 | _ealias_print() 197 | { 198 | if [ $# -gt 1 ]; then 199 | echo "usage:$FUNCNAME [name]" >&2 200 | return 1 201 | fi 202 | 203 | if [ $# -eq 0 ]; then 204 | set -- "${!EALIAS_ALIASES[@]}" 205 | fi 206 | 207 | for name ; do 208 | spec="${EALIAS_ALIASES[$name]}" 209 | if [ -z "$spec" ]; then 210 | echo "No such alias: $name" >&2 211 | return 1 212 | fi 213 | echo "ealias $name='${spec/\'/\'\\\'\'}'" 214 | done | sort 215 | return 0 216 | } 217 | 218 | _ealias_execute() 219 | { 220 | local spec eargs fn s i 221 | local noexec # Just print what would be executed. 222 | 223 | name=$1; shift 224 | spec=${EALIAS_ALIASES[$name]} 225 | 226 | if [ -z "$spec" ]; then 227 | echo "No such alias: $name" >&2 228 | return 1; 229 | fi 230 | 231 | fn=${spec%% *} 232 | eargs=${spec#* } 233 | if [ "$fn" == "$spec" ]; then 234 | eargs= 235 | fi 236 | i=1 237 | 238 | # Process and shift our arguments. 239 | while [ $# -gt 0 ]; do 240 | case $1 in 241 | -n) 242 | noexec=1 ;; 243 | --) 244 | shift 245 | break ;; 246 | --help) 247 | _ealias_print "$name" 248 | return 0 ;; 249 | *) 250 | break ;; 251 | esac 252 | shift 253 | done 254 | 255 | i=0 256 | # Substitue %x formats 257 | while [ $i -lt ${#eargs} ]; do 258 | if [ "${eargs:$i:1}" = "%" ]; then 259 | local fmt=${eargs:$i + 1:1} 260 | local arg= 261 | case $fmt in 262 | [@]) 263 | local rest=() 264 | for arg; do 265 | rest+=("\\\"$arg\\\"") 266 | done 267 | arg="'(${rest[*]})" 268 | ;; 269 | [*]) 270 | arg="\\\"$*\\\"" ;; 271 | [0-9]) 272 | arg="\\\"${!fmt}\\\"" ;; 273 | [\^]) 274 | arg="\\\"$1\\\"" 275 | shift 276 | ;; 277 | [%]) 278 | arg=% ;; 279 | *) 280 | echo "Invalid format code: \`${eargs:$i:2}'" 281 | return 1 282 | ;; 283 | esac 284 | # Delete format, insert arg and skip over it. 285 | eargs=${eargs:0:$i}$arg${eargs:$i + 2} 286 | let i+=${#arg}-1 287 | fi 288 | let ++i 289 | done 290 | 291 | if [ -n "$noexec" ]; then 292 | eval "echo ${EALIAS_CLIENT:-emacsclient} --eval \"($fn ${eargs})\"" 293 | else 294 | eval "${EALIAS_CLIENT:-emacsclient} --eval \"($fn ${eargs})\"" 295 | fi 296 | } 297 | 298 | _ealias() 299 | { 300 | COMPREPLY=("${!EALIAS_ALIASES[@]}") 301 | } 302 | 303 | complete -F _ealias ealias 304 | complete -F _ealias eunalias 305 | --------------------------------------------------------------------------------