03 Jan 2015
This is the 15th post on this blog. Thankfully, no heart attacks after
the 13th one or anything. So I'll commemorate it with a post on
dealing with dates in calc
.
How much time has passed since I started this blog?
Open calc
with C-x **:
--- Emacs Calculator Mode ---
.
Enter 20 Dec 2014
with '<12 20 14RET:
--- Emacs Calculator Mode ---
1: <Sat Dec 20, 2014>
.
Enter current time with tN:
--- Emacs Calculator Mode ---
2: <Sat Dec 20, 2014>
1: <11:56:27am Sat Jan 3, 2015>
.
Subtract with -:
--- Emacs Calculator Mode ---
1: -14.498044
.
This means that, if I want to maintain my one-post-per-day streak, I
still have half of a day to post this. Unfortunately, I have only an
old version of the blog repository on this machine, and the current
one is on a laptop at home. So I'll post this in the evening.
Did you know what 2015 looks like in binary?
In your current calc
session,
Enter 2015 SPC:
--- Emacs Calculator Mode ---
2: -14.498044
1: 2015
.
Switch to binary with d2:
--- Emacs Calculator Mode ---
2: -2#1110.011111110111111111001111110001
1: 2#11111011111
.
Wow, a palindrome. It's too spooky, switch back to decimal with d0:
--- Emacs Calculator Mode ---
2: -14.498044
1: 2015
.
If you're new to calc
, you'll probably wonder why you can't enter
negative numbers with -. It can be done with _,
just like in
J. Find
out more in the
info;
the
interactive tutorial
is absolutely excellent.
02 Jan 2015
Prompted by this StackOverflow question,
I wrote down a new package called latex-wrap.
It's only a few hours old, but I like it a lot.
I've grepped the sources of AUCTeX, and it doesn't seem to have this functionality.
Here's how it works
You start with an active region:
Homer
Marge
Bart
Lisa
Maggie
After calling M-x latex-wrap-region
and selecting
enumerate from the list of environments (others being itemize,
center etc.), you get this:
\begin{enumerate}
\item Homer
\item Marge
\item Bart
\item Lisa
\item Maggie
\end{enumerate}
Let's mark everything, M-x latex-wrap-region
, and select
center:
\begin{center}
\begin{enumerate}
\item Homer
\item Marge
\item Bart
\item Lisa
\item Maggie
\end{enumerate}
\end{center}
As you can see, I want to make sure that it's possible to conveniently
continue by always placing the point on the end of the last line of
the inserted environment.
How it works with no active region
If (looking-back "^ *")
is true, the current line is used as if it was
the region. Otherwise, an empty environment is inserted after the
current line.
Using the code
If you like the idea, you can check out the code at
github and test it out. If
you know of another package that already does this, do let me know,
otherwise I'll post the package on MELPA soon. And if you have some
ideas, or want to add a few environments that I forgot to mention to
the list, just post
an issue, I don't
bite.
01 Jan 2015
Tip #1
There's no reason not to have /bin/bash
instead of /bin/sh
as the
default choice when you M-x term
.
(setq explicit-shell-file-name "/bin/bash")
Tip #2
After you close the terminal, you get a useless buffer with no
process. It's probably left there for you to have a history of what
you did. I find it not useful, so here's a way to kill that buffer
automatically:
(defun oleh-term-exec-hook ()
(let* ((buff (current-buffer))
(proc (get-buffer-process buff)))
(set-process-sentinel
proc
`(lambda (process event)
(if (string= event "finished\n")
(kill-buffer ,buff))))))
(add-hook 'term-exec-hook 'oleh-term-exec-hook)
Tip #3
By default, C-y calls term's own yank
, which is different
from Emacs's yank
. So, until recently, I was using
S-<insert> to paste stuff into *term*
. Here's a
more ergonomic way:
(eval-after-load "term"
'(define-key term-raw-map (kbd "C-c C-y") 'term-paste))
31 Dec 2014
Sometimes new Emacs packages have to fight for their place in the sun,
as all the good bindings and huge keymap areas are already taken by
the older packages. This post will cover some practical problems that
you may encounter when your package needs to be aware of another
active package.
ace-window
vs. helm
helm is a wonderful package,
it's my goto-package when I need completion. All of the following
packages use it:
But helm
is super-greedy: once you're in the helm
-minibuffer,
there's no way out except either a successful completion or a cancel.
But exiting the minibuffer for a short while may be useful. For
instance, you could copy some text and yank it in the
helm
-minibuffer. The default minibuffer functions, as well as ido
easily allow it.
I started to investigate into this when I got
issue #15: Does not work with helm in minibuffer
for ace-window
. I checked it, and indeed you could not ace-window
out of a helm
-minibuffer. In fact, it was not possible to exit with
other-window
either. This looked like good news, since I had an
inkling that it used to work at some point. So I checked out a
year-old version of helm
and it did work.
magit-bisect
to the rescue!
It's very simple:
- Check out the master of
helm
- Call
magit-bisect-start
and mark HEAD
as bad
magit
will automatically check out a revision that is halfway
between a bad state and the initial commit. Now I exit Emacs and try
helm
again to see if I can exit from the minibuffer.
It's kind of lame to have to exit Emacs, but somehow I don't trust
unload-feature
to do the right thing. Anyway, if the thing works,
move to helm
's repository and call magit-bisect-good
, otherwise
call magit-bisect-bad
.
- Continue this process until termination. I needed 10 iterations
in this case.
The culprit commit was this one:
(let* ((source (helm-get-current-source))
(kmap (and (listp source) ; Check if source is empty.
(assoc-default 'keymap source))))
- (when kmap (setq overriding-local-map kmap)))))
+ (when kmap (set-transient-map kmap)))))
the priority of maps
In Emacs, set-transient-map
has priority over
overriding-local-map
, which was exactly what ace-window
was using.
It's also funny that ace-window
used to work with helm
for a week,
since it was published on Mar 26
and helm
switched to
set-transient-map
on Apr 2
. And I found out that it's not working only
now.
Here's what helm
is using currently:
(if (fboundp 'set-transient-map)
(set-transient-map it)
(set-temporary-overlay-map it))
So I've amended ace-window
with similar code. The way
set-transient-map
works, the last call to it overrides the previous
one, so I thought that it would work out since ace-window
is always
called after helm
.
It didn't work out, because helm
adds the code that calls
set-transient-map
to post-command-hook
.
In the end, this finally worked:
(remove-hook 'post-command-hook 'helm--maybe-update-keymap)
lispy
vs. SLIME
and CIDER
I thought that enabling lispy-mode
for slime-repl-mode
and
cider-repl-mode
might be a good idea.
Extra navigation options are always good, and the ability to
call raise
is just so useful.
For instance, you start with:
; SLIME 2014-11-28
CL-USER> (expt (expt 2 10) 3)
1073741824
CL-USER>
With lispy-mode
on you can:
- M-p to get the previous input
- f to move the cursor after
(expt 2 10)
- r to raise
(expt 2 10)
Here's the final state:
; SLIME 2014-11-28
CL-USER> (expt (expt 2 10) 3)
1073741824
CL-USER> (expt 2 10)
But the problem was that SLIME has slime-repl-map-mode
minor mode on
that competes for lispy
's shortcuts, and CIDER has something similar
as well.
When two minor modes bind the same keys, which one wins?
The answer is the first one on minor-mode-map-alist
.
This function I've found on the wiki:
(defun lispy-raise-minor-mode (mode)
"Make MODE the first on `minor-mode-map-alist'."
(let ((x (assq mode minor-mode-map-alist)))
(when x
(setq minor-mode-map-alist
(cons x (delq mode minor-mode-map-alist))))))
I didn't want lispy-mode
to mess with minor-mode-map-alist
too
actively, so I went with this approach: if lispy-mode
is called
interactively, i.e. via a key binding or M-x, put it ahead:
(when (and lispy-mode (called-interactively-p 'any))
(mapc #'lispy-raise-minor-mode
(cons 'lispy-mode lispy-known-verbs)))
It's still a work in progress, currently only lispy
's RET
properly yields to call cider-repl-return
and slime-repl-return
respectively. I'll see if there are more key bindings that need to
yield. Happy coding in the New Year!
30 Dec 2014
Emacs goodness incoming
I've discovered a nice Emacs-related blog -
Content AND Presentation.
Unlike The Axis of Eval, the blog
that I mentioned yesterday, this one is pretty self-contained, i.e. it
doesn't link to many external information sources. So I thought that
it's perfect for trying EWW to read it.
For modes that don't require to self-insert (and even for some that
do), I like to navigate with
h/j/k/l as arrows. These
arrows are on the home row, so navigation becomes a pleasant and
relaxed experience. But for EWW I decided to add a little twist: if
the point is in the first column, j/k will move
down/up not by one line, but by one paragraph. This is great for
concentration: I navigate to a paragraph, read it, navigate to the
next one. The point shows me the paragraph that I'm reading,
everything before the point I've already read. So every time I press
j, I get a tiny warm feeling of accomplishment.
I can also pair this with v, which I bind to recenter the
current line to the top.
So here's what my key setup currently looks like:
(defun oleh-eww-hook ()
(define-key eww-mode-map "j" 'oww-down)
(define-key eww-mode-map "k" 'oww-up)
(define-key eww-mode-map "l" 'forward-char)
(define-key eww-mode-map "L" 'eww-back-url)
(define-key eww-mode-map "h" 'backward-char)
(define-key eww-mode-map "v" 'recenter-top-bottom)
(define-key eww-mode-map "V" 'eww-view-source)
(define-key eww-mode-map "m" 'eww-follow-link)
(define-key eww-mode-map "a" 'move-beginning-of-line)
(define-key eww-mode-map "e" 'move-end-of-line)
(define-key eww-mode-map "o" 'ace-link-eww)
(define-key eww-mode-map "y" 'eww))
(add-hook 'eww-mode-hook 'oleh-eww-hook)
As you see, I was careful to re-assign eww-back-url
and
eww-view-source
- the commands that I've displaced from l
and v. And here's the implementation of the arrows:
(defun oww-down (arg)
(interactive "p")
(if (bolp)
(progn
(forward-paragraph arg)
(forward-line 1))
(line-move arg)))
(defun oww-up (arg)
(interactive "p")
(if (bolp)
(progn
(forward-line -1)
(backward-paragraph arg)
(forward-line 1))
(line-move (- arg))))
Cherry on the top
And while I was at it, I've added ace-link support for EWW. It was
pretty easy, basically the same routine as for help-mode
and
info-mode
. The only hard part was to figure out what part of the
code keeps binding shr-save-contents
to o, my preferred
binding for ace-link
. Turns out it was eww-link-keymap
, and not
shr-map
. So here's the new key binding code:
(defun ace-link-setup-default ()
"Setup the defualt shortcuts."
(eval-after-load "info"
'(define-key Info-mode-map "o" 'ace-link-info))
(eval-after-load "help-mode"
'(define-key help-mode-map "o" 'ace-link-help))
(eval-after-load "eww"
'(progn
(define-key eww-link-keymap "o" 'ace-link-eww)
(define-key eww-mode-map "o" 'ace-link-eww))))
If you haven't tried ace-link
before, you can get it from MELPA. The minimal configuration that you
need is this:
Here's the setup that I'm actually using:
(use-package ace-link
:load-path "~/git/ace-link"
:init (ace-link-setup-default))
I'm using it from my git folder since when I want to edit a project, I
like to use smex's
jump-to-definition.
And use-package is useful
for the cases when my ~/git/
happens not to contain ace-link
. In
that case, instead of getting a debugger error on starting Emacs, I
get only a polite "Could not load package ace-link" in my *Messages*
buffer.