4

I like to keep my configuration as self-contained as possible, and I'm wondering whether there's a way to manage eshell aliases in my .emacs file. Is it possible to set up aliases with a function call kept in my .emacs rather than a separate file in .emacs.d/eshell/aliases?

The problem I am ultimately trying to solve is to get ff when entered in command position in eshell to reliably behave identically to find-file. I am assuming that the easiest, most direct way to do this is an eshell alias.

The alias below, with single quotes, exactly as written, does the trick and behaves like find-file does. I'm just trying to manage my aliases in the same place as the rest of my customization.

alias ff 'find-file $1'

Here are some attempted solutions to the problem that don't work and the steps to reproduce. The fact that they don't Just Work suggests to me that some work is needed to "wire up" a function so that it's usable from eshell.

Non-Solution 1, eshell/ff function

  1. $ emacs -q -no-site-file
  2. within emacs, C-x b *scratch* C-m
  3. write wrapper function in scratch buffer.
(defun eshell/ff (&rest args)
  (apply #'find-file args))
  1. C-x h M-x eval-region C-m then C-g to deselect
  2. C-h f eshell/ff to verify that the function exists.
  3. M-x eshell C-m
  4. within eshell, type find-file /etc/hosts and visit the buffer. Then go back to eshell
  5. within eshell, type ff /etc/hosts. The error message below shows us that eshell found our definition, but is somehow treating it differently than find-file.
~ $ ff /etc/hosts
Wrong number of arguments: (1 . 2), 0

Non-Solution 2 (defalias 'ff 'find-file)

  1. $ emacs -q -no-site-file
  2. within emacs, C-x b *scratch* C-m
  3. write wrapper function in scratch buffer.
(defalias 'ff 'find-file)
  1. C-x h M-x eval-region C-m then C-g to deselect
  2. C-h f eshell/ff to verify that the function exists.
  3. M-x eshell C-m
  4. within eshell, type find-file /etc/hosts as before to verify that find-file still works
  5. within eshell, type ff /etc/hosts. The error message is the same as in Non-Solution 1.
2
  • I can't reproduce your errors following Non-Solution 1 or 2. What Emacs version are you running? Perhaps you're hitting some bug that was fixed.
    – npostavs
    Commented Apr 10, 2019 at 0:55
  • @npostavs ... 26.1 . I think I just mistyped ff by itself instead of ff /etc/hosts because now I can't reproduce it either. :/ Commented Apr 10, 2019 at 6:04

3 Answers 3

3

As pointed out by @npostavs in a comment underneath the original question, the following solution proposed by the original poster should work -- at least in a current version of Emacs that is -- tested with Emacs 26.1:

(defun eshell/ff (&rest args)
  (apply #'find-file args))

Alternative Solution:

(defun eshell-add-aliases ()
"Doc-string."
  (dolist (var '(("ff" "find-file $1")
                 ("wget" "/Users/HOME/.0.data/.0.emacs/.0.macports/bin/wget $*")
                 ("cvs" "/Users/HOME/.0.data/.0.emacs/.0.macports/bin/cvs $*")
                 ("curl" "/Users/HOME/.0.data/.0.emacs/.0.macports/bin/curl $*")
                 ("git" "/Users/HOME/.0.data/.0.emacs/.0.macports/bin/git $*")))
    (add-to-list 'eshell-command-aliases-list var)))

(add-hook 'eshell-post-command-hook 'eshell-add-aliases)

Please be aware that this answer defies the admonishment in the doc-string. [Therefore, this solution is only for the rebellious / adventurous souls....]

eshell-command-aliases-list is a variable defined in ‘em-alias.el’.

Its value is

(("git" "/Users/HOME/.0.data/.0.emacs/.0.macports/bin/git $*")
 ("curl" "/Users/HOME/.0.data/.0.emacs/.0.macports/bin/curl $*")
 ("cvs" "/Users/HOME/.0.data/.0.emacs/.0.macports/bin/cvs $*")
 ("wget" "/Users/HOME/.0.data/.0.emacs/.0.macports/bin/wget $*")
 ("ff" "find-file $1"))

  This variable may be risky if used as a file-local variable.

Documentation:
A list of command aliases currently defined by the user.
Each element of this alias is a list of the form:

  (NAME DEFINITION)

Where NAME is the textual name of the alias, and DEFINITION is the
command string to replace that command with.

Note: this list should not be modified in your init file.
Rather, any desired alias definitions should be declared using
the ‘alias’ command, which will automatically write them to the
file named by ‘eshell-aliases-file’.
1
  • and it does work. I made a mistake when testing. Commented Apr 10, 2019 at 6:06
0

eshell looks for its aliases in the directory specified by the eshell-aliases-file variable, which by default is $HOME/.emacs.d/eshell/alias

In that file, you can just write:

alias foo bar

Then, either start a new eshell instance, which will read in your aliases from the alias file on startup, or you can issue the eshell-read-aliases-list command from within eshell and it will re-read the alias file.

0

Another alternative solution is to define the alias with eshell/alias if the alias is not yet existent. I have the following code in the :config section of a (use-package eshell ...) block in my init file:

(defun my-eshell-alias (name definition)
  "Define eshell alias NAME with DEFINITION unless it's defined."
  (unless (eshell-lookup-alias name)
    (eshell/alias name definition)))

(add-hook 'eshell-mode-hook
          (lambda ()
            "Initialize custom eshell aliases."
            (my-eshell-alias "e" "find-file $1")
            (my-eshell-alias "ll" "ls -hal $*")
            (my-eshell-alias "mcd" "mkdir -p \"$1\" && cd \"$1\"")))

This code runs after the aliases file has been loaded. You can override these aliases on a machine with the alias command.

Downside: If an alias foo is changed in the init file, you need to remove it with the eshell command alias foo and restart Emacs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.