Finally Got My Emacs Setup Just How I Like It
Posted on 24th of February 2023 | 744 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.