I've setup a custom prompt for eShell but, on doing tab completion (and pressing enter), the shell gets stuck at being read-only.

I've noticed that, if I tab-complete something and then move the cursor (say, back one character) before pressing enter, it won't enter this state, however.

I thought it might be an issue with how I was setting eshell-prompt-regexp but, other than there supposedly being a tab character at the end, I think it's a perfect regexp match.

Running emacs -q and then loading the below elisp recreates the problem; you can then open an eShell buffer, do something like ls ~/ and then tabbing to complete, hit enter, and then experience the same issue.

(require 'cl)

(defun trim-string (string)
  "Remove white spaces in beginning and end of STRING.
White space here is any of: space, tab, emacs newline (line feed, ASCII 10)."
  (replace-regexp-in-string "\\`[ \t\n]*" "" (replace-regexp-in-string
                                               "[ \t\n]*\\'"

(defconst number-to-string-approx-suffixes
  '("k" "M" "G" "T" "P" "E" "Z" "Y"))
(defun number-to-string-approx-suffix (n &optional binary)
  "Return an approximate decimal representation of NUMBER as a string,
followed by a multiplier suffix (k, M, G, T, P, E, Z, Y). The representation
is at most 5 characters long for numbers between 0 and 10^19-5*10^16.
Uses a minus sign if negative.
NUMBER may be an integer or a floating point number.
If the optional argument BINARY is non-nil, use 1024 instead of 1000 as
the base multiplier."
  (if (zerop n)
    (let ((sign                                          "")
          (b                          (if binary 1024 1000))
          (suffix                                        "")
          (bigger-suffixes number-to-string-approx-suffixes))
      (when (< n 0)
        (setq n    (- n)
              sign   "-"))
      (while (and (>= n b) (consp bigger-suffixes))
        (setq n                             (/ n b) ; TODO: this is rounding down; nearest would be better
              suffix          (car bigger-suffixes)
              bigger-suffixes (cdr bigger-suffixes)))
      (concat sign (if (integerp n)
                       (int-to-string n)
                     (number-to-string (floor n))) suffix))))

(setq eshell-prompt-regexp "
├\\(\\[.*\\]─\\)?([0-9]+ file[s]?, [0-9]+[kMGTPEZY]+iB)─(.*@.*)
└─> ")
(setq eshell-prompt-function (lambda ()
                               (let ((purple     '(:foreground "#622f7d"))
                                     (gray       '(:foreground "#434541"))
                                     (white      '(:foreground "#FFFFFF"))
                                     (bold-white '(:foreground "#FFFFFF" :weight bold))
                                     (off-white  '(:foreground "#d1d1d1"))
                                     (cyan       '(:foreground "#00d1e0"))
                                     (green      '(:foreground "#7BE128"))
                                     (yellow     '(:foreground "#eab700"))
                                     (red        '(:foreground "#F52749")))
                                   (propertize "┌(" 'face gray)
                                     (propertize default-directory 'face purple)
                                     (propertize ")\n"             'face   gray)
                                   (propertize "├"  'face gray)
                                     (propertize "(" 'face gray)
                                       (let ((num-of-files (-
                                           (propertize (number-to-string num-of-files) 'face     white)
                                           (propertize " file"                         'face off-white)
                                           (propertize (if (= num-of-files 1) "" "s")  'face off-white)
                                           (propertize ", "                            'face off-white)))
                                             '(lambda (result newCar)
                                                  (if (string= (car newCar) "..")
                                                    (car (cdr (cdr (cdr (cdr (cddddr newCar)))))))
                                             :initial-value 0))
                                       (propertize "iB" 'face off-white)
                                       (propertize ")─" 'face      gray)
                                     (propertize "(" 'face gray)
                                       (propertize (getenv "USER")            'face      cyan)
                                       (propertize "@"                        'face off-white)
                                       (propertize (trim-string
                                                       "hostname"))           'face     green)
                                       (propertize ")\n"                      'face      gray)
                                   (propertize "└─>" 'face gray) (propertize " " 'face white)))))

1 Answer 1


Finally figured it out; I've seen this come up in a few places but no one ever seems to provide an answer so for future people who run into the issue.

eshell-prompt-regexp isn't looking to match the whole prompt, it seems, but just the line that cursor/text will be (inputted) on.


(setq eshell-prompt-regexp "└─> ")

would've been the answer to my problem; introducing a newline to this variable immediately causes its behavior and functionality to break.

This single line, targeting the last line of my prompt, provides perfect performance and functionality.

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.