A problem with fonts and unicode is that many of the characters have no glyphs in a given font. This is going to bite us immediately unless we address it somehow. Our solution, inspired by Ergo Emacs, is to switch to a different font when rendering emoji. I've chosen to use Google Noto as my font for this, since it is dedicated to full Unicode coverage:
(defun mak::ghost-or-percent () (interactive) ; Allow call via M-x or binding (let ((ghost "👻") ; My desired prompt (percent "%")) ; My fallback prompt (if (and (display-graphic-p) ; Are we in the GUI? (member "Noto Emoji" (font-family-list))) ; Do we have the emoji font? (progn (set-fontset-font t ?👻 "Noto Emoji" nil 'prepend) ; Use the emoji font for the ghost ghost) ; Return desired prompt percent))) ; Return fallback prompt
I like my prompts simple. Prior to this, my prompt has been a lone percent sign for the last decade. I'm keeping the percent sign as a fallback in case I'm on a terminal, or a host missing the Noto Emoji font.
set-fontset-font call is the heart of the above function, so let's look at its description:
(set-fontset-font NAME TARGET FONT-SPEC &optional FRAME ADD)
Modify fontset NAME to use FONT-SPEC for TARGET characters.
NAME is … t for the default fontset.
TARGET may be a single character to use FONT-SPEC for.
FONT-SPEC may one of these:
* A font name string.
Optional 4th argument FRAME is a frame or nil for the selected frame that is concerned in the case that NAME is nil.
Optional 5th argument ADD, if non-nil, specifies how to add FONT-SPEC to the font specifications for TARGET previously set. If it is ‘prepend’, FONT-SPEC is prepended. If it is ‘append’, FONT-SPEC is appended. By default, FONT-SPEC overrides the previous settings.
The end result of this is that we've configured Emacs to always display the ghost emoji in the Noto Emoji font.
(defun mak::eshell-prompt () (interactive) (concat (if (not (eq 0 (current-column))) "\n" "") (mak::ghost-or-percent) " ")) (setq eshell-prompt-function 'mak::eshell-prompt)
Eshell has special behaviour when you have the point after the prompt, honouring input as commands, so we need to explain to it how to recognize our newly-customized prompt.
(setq eshell-prompt-regexp (format "^%s " (mak::ghost-or-percent)))
Finally, we'll expand my war on welcome messages into Eshell:
(setq eshell-banner-message "")
From here I can run
M-x eshell and have a functional shell inside Emacs.