Finally Got My Emacs Setup Just How I Like It
Posted on 24th of February 2023 | 745 wordsSo in recent days, I have stumbled upon some REALLY NICE (at least in my own standards) Emacs tweaks, which I wanted to share with you.
First, something very trivial, I knew that Emacs had some sort of jump
to previous location etc., type of feature available, but I never got
into using it. Turns out there’s is a built-in keybinding for that or
a couple. First, one was C-x C-x
, which jumps to the last position
and selects the text from your current position. So, e.g. you jump to
the beginning of a file and press that combination, it selects the
text from the beginning to the last position. Which was cool for me,
but I rarely need something like that.
That was enough for me for some time, but I wanted to tweak it slightly. I didn’t care about selection and wanted to centre the screen after the jump. Thankfully, this is relatively trivial to implement in Emacs with a single function:
(defun jump-to-mark-and-center (arg) (interactive "*p") (goto-char (mark)) (recenter)) (global-set-key (kbd "C-x C-x") 'jump-to-mark-and-center)
So I bound the old keybinding to that new function, which does exactly what I want. Lovely!
To the second lovely new configuration! I had longed for a feature in
Emacs, where I could find a file based on the format of
FILENAME:LINENUMBER
. So, if I would have a file, let’s say file.cc
and I would immediately jump to the line number 14 in that file, I
would want to open that file with file.cc:14
like most of the Unix
tools print these file locations, but I just couldn’t do it in Emacs.
Thankfully, after some searching throughout the interwebs, I found
some nice defadvice
that fixes this for me:
(defadvice find-file (around find-file-line-number (filename &optional wildcards) activate) (save-match-data (let* ((matched (string-match "^\\(.*\\):\\([0-9]+\\):?$" filename)) (line-number (and matched (match-string 2 filename) (string-to-number (match-string 2 filename)))) (filename (if matched (match-string 1 filename) filename))) ad-do-it (when line-number ;; goto-line is for interactive use (goto-char (point-min)) (forward-line (1- line-number))))))
And BAM! It works just like that!
And the last lovely new feature! I use mainly vterm
inside my Emacs
for my terminal needs. I always wanted to use it so that when I’m
inside a certain directory in the terminal, I could just open some
file in that directory, but unfortunately, by default, vterm
only
knows the directory where it was opened at.
Thankfully, after reading some documentation about vterm
, it turns
out you’re able to send certain character codes to emacs from your
vterm
session. So you’re able to make it so that when you open
vterm
in directory x
and proceed to change the directory inside
the vterm
with many different cd
commands etc. to something like
x/many/different/subdirs
, when I run something like C-x C-f
in
that vterm
buffer, the minibuffer inside Emacs, would know that I
want to file directory in the directory where vterm
currently is,
instead of the directory where it was initially opened.
This can be done by doing some shell tweaking. I use zsh
myself, if
you use something else, refer to vterm
README
.
# Enable the shell to send information to vterm via properly escaped # sequences. vterm_printf() { printf "\e]%s\e\\" "$1" } vterm_prompt_end() { vterm_printf "51;A$(whoami)@$(hostname):$(pwd)" } Let vterm know what dir I'm in setopt PROMPT_SUBST PROMPT=$PROMPT'%{$(vterm_prompt_end)%}'
If you happen to use screen
or tmux
, you might need to do some
other tweaks in there, but these are mentioned in the vterm
README.
In any case, when you define those to your .zshrc
, vterm
sends the
information of the current directory straight to Emacs, so it knows
where you’re currently at. Which is great!
To make that even better, I often noticed that I wanted to open files
straight from the command line instead of running some Emacs command
to open the files. Fortunately, vterm
covers this also:
vterm_cmd() { local vterm_elisp vterm_elisp="" while [ $# -gt 0 ]; do vterm_elisp="$vterm_elisp""$(printf '"%s" ' "$(printf "%s" "$1" | sed -e 's|\\|\\\\|g' -e 's|"|\\"|g')")" shift done vterm_printf "51;E$vterm_elisp" } find_file() { vterm_cmd find-file "$(realpath "${@:-.}")" } alias e="find_file"
With these functions inside your .zshrc
, I can run find_file
inside vterm
, and it opens the file in your current Emacs session. I
just use short alias to run e somefile
inside the terminal; it opens
a new buffer for the file.
I have used Emacs for a long time, but these recent additions made it so much nicer. Hopefully, these are helpful for you too.