17 Feb 2015
As usual, I'll just re-state the
release notes,
while maybe adding a bit of flavor.
New features
Define Hydra heads that don't show up in the hint at all
This can be done by setting the head's hint explicitly to nil
, instead of the usual string. For
instance, if you always tend to bind the arrows to hjkl, there's no point to show a hint
for them.
Use a dedicated window for Hydra hints
Since version 0.10.0
, setting hydra-lv
to t
(the default setting) will make it use a dedicated
window right above the Echo Area for hints. This has the advantage that you can immediately see any
message
output from the functions that you call, since Hydra no longer uses message
to display
the hint. You can still have the old behavior by setting hydra-lv
to nil
.
How it looks like:
Here, an error was triggered by previous-line
and the message is displayed without interrupting
the hint.
Allow duplicate functions in heads
Duplicate functions will be concatenated in the hint.
This was already covered in yesterday's post
Add option to font-lock defhydra
If you want to nicely font-lock your defhydra
statements, just add this to your config:
(require 'hydra)
(hydra-add-font-lock)
Additionally, defhydra
is now to be indented as a defun
, so it will be indented like this:
(defhydra hydra-goto-line (global-map "M-g"
:pre (linum-mode 1)
:post (linum-mode -1)
:color blue)
("g" goto-line "line")
("c" goto-char "char"))
Note that the indentation of the body argument is as if it was data
and not code, i.e. the proper one. As you see, I even added defhydra
to the blog's Pygments list for Elisp.
Incompatible changes
The macro hydra-create
, as well as the variables that were supposed
to be used with it (hydra-example-text-scale
,
hydra-example-move-window-splitter
, hydra-example-goto-error
,
hydra-example-windmove
) were removed. All the functionality is still
there in hydra-examples.el with the better defhydra
macro.
Outro
I hope that you like the new changes. And if you're byte-compiling
your code that uses defhydra
, don't forget to re-compile. Also, the
latest version of ace-window
will ignore *LV*
buffer while
switching, as it did for *Calc Trail*
before.
16 Feb 2015
Here's a recent feature that's now available in hydra:
(defhydra hydra-zoom (global-map "<f2>")
"zoom"
("g" text-scale-increase "in")
("l" text-scale-decrease "out")
("0" (text-scale-set 0) "reset")
("1" (text-scale-set 0) :bind nil)
("2" (text-scale-set 0) :bind nil :color blue))
Here, the entry points are <f2> g, <f2> l, and <f2> 0, the
others aren't bound in the global map.
You can also have the same function in both red and blue versions. Here's how the hint will look like:
The multiply-defined functions will be neatly grouped together.
If you remember, (text-scale-set 0)
uses a sexp syntax for a Hydra
head: it will be wrapped in (lambda () (interactive) ...)
automatically.
15 Feb 2015
Somehow, I accumulated a few files owned by root that should have been
owned by me. Below, I'll describe a solution to get rid of them based
on dired
and tramp
.
Step one: open the directory with sudo privileges
I'll obviously need the sudo privilege to change the owner of a file owned
by root. Might as well start with that.
Thankfully, I do have a shortcut:
(defun sudired ()
(interactive)
(require 'tramp)
(let ((dir (expand-file-name default-directory)))
(if (string-match "^/sudo:" dir)
(user-error "Already in sudo")
(dired (concat "/sudo::" dir)))))
(define-key dired-mode-map "!" 'sudired)
The function above will open the current directory in sudo mode. I
decided to bind it to !, since the default &
seems strictly better than !. The function will ask you for
the password once. Afterwards, you can open other directories without
having to enter the password.
Step two: find-dired
So now, while in sudo mode of the directory in question:
- Call M-x
find-dired
. It's not bound by default, and I
don't bind it myself since it's quite situational (I do bind
find-name-dired
to F in dired-mode
though).
- It prompts you for the directory. I just press RET, since the default one is what I need.
- Next, it prompts for
find
args. These are the arguments to the
UNIX command find
. Here, I need to pass -user root
.
- The command has finished and I can see the results. I can select
some of them by pressing m (
dired-mark
) a few times, or
mark them all at once with t (dired-toggle-marks
).
- Finally, call O (
dired-do-chown
) on the marked files and enter oleh
.
Done. I'm sure that the admin types can cook up some find
-exec
-chown
combo to do the same thing,
but the find-dired
approach is both simpler and more flexible, since I can confirm and edit the list
of files being changed.
14 Feb 2015
Today, I'll share my keyboard layout, based on QWERTY, that
facilitates all tech-related activities, especially Emacs. I've been
using a version of this for about three years now, and only a single
key has been changed in the last two years. Without further ado,
here it is:
The most visible change
I've made ; stop inserting ;
and instead act as
Mode_switch
: a modifier similar to control or meta.
- I'm pressing ;-j to enter ;
- I'm pressing ;-d to enter :
So I'm giving up the ability to press ; with a single key,
and remapping : from one two-key combination to another
two-key combination.
In return, I'm getting a QWERTY with all these wonderful shortcuts.
The RSI-savers
The general ones are:
- RET on ;-v (symmetric with C-m)
- DEL on ;-o
If you're writing a bunch of C++, _ on ;-s is very good.
Likewise, - on ;-a is great for LISP.
For LaTeX, \ on ;-w is good since I switched from
a keyboard that had it near z to a keyboard that has it near RET.
I'm guessing ~ on ;-t isn't bad for shell, but I don't use it that much.
The basic remaps
These are just char-for-char remaps. They are composable, for instance
I have dired-jump
on C-:, which means that I'm pressing
C-;-d.
Some math symbols are mnemonic: e-equal,
l-lesser, g-greater.
If you're using lispy, it might become more clear for you
why I've put lispy-slurp
on > and lispy-barf
on <. Although
pressing these keys with a shift isn't the worst thing, having them on the home row is pretty cool.
The pairs
Here are the translations meant for pairs:
q - θ,
f - φ,
r - ρ,
c - σ.
These are meant for Emacs and .inputrc
. In both cases, e.g. φ should insert ()
and
go backward one char. Here's my .inputrc
:
set input-meta on
set output-meta on
set convert-meta off
"θ":""\C-b""
"ω":"'\C-b'"
"\e\C-l":"\C-e | less\C-m"
"υ":">\C-b<"
"σ":"}\C-b{"
"φ":")\C-b("
"ρ":"]\C-b["
set completion-ignore-case on
With this .inputrc
, it's like I have some kind of electric mode in my bash.
In Emacs, the pairs are bound in a straightforward way:
(defun ins-brackets ()
(interactive)
(cond ((eq major-mode 'term-mode)
(term-send-raw-string "[]")
(term-send-raw-string "^B"))
((region-active-p)
(lispy--surround-region "[" "]"))
(t
(insert "[]")
(backward-char))))
(global-set-key "ρ" 'ins-brackets)
For LISP, I use lispy
-specific bindings:
(define-key lispy-mode-map (kbd "φ") 'lispy-parens)
(define-key lispy-mode-map (kbd "σ") 'lispy-braces)
(define-key lispy-mode-map (kbd "ρ") 'lispy-brackets)
(define-key lispy-mode-map (kbd "θ") 'lispy-quotes)
(define-key lispy-mode-map (kbd "χ") 'lispy-right)
The rest of the Greek chars
These are bound to various Emacs functions. In fact, I initially started with all Greek chars, and
bound e.g.:
(global-set-key (kbd "ε") "=")
When these remap-type bindings became mature, I've put them directly
into .Xmodmap
, which gave the advantage of being able to compose the
keys.
These bindings are as good and usable as the control plus lower case
chars. Use them wisely and you can get a very ergonomic setup. Some
ideas:
- switching buffers on ;-h
- switching windows on ;-n
- jumping to bookmarks on ;-m
The shifted digits
I find it much easier to press e.g. ;-4 to insert $
,
rather than S-4. I also restored the justice of 0
coming before 1
by mapping
;-` to 0
.
Outro
I hope that you'll find some use and enjoyment in these ramappings, if
you're not afraid to experiment a little. The cost of losing the
semicolon is pretty minor, the bigger issue is in finding the
unmodified QWERTY extremely sluggish after using this approach.
13 Feb 2015
I discovered today that I was using declare-function
in a wrong way.
So I'll share how to use it properly.
declare-function
I was just using it to shut up the byte compiler's "not known to be
defined"
warning. Turns out that it can also be used to check if the
functions actually exist in the file to which they point to. You can
use check-declare-file
to check one file, or
check-declare-directory
to recursively check the whole directory.
Here's an example output:
Warning (check-declare): helm-info.el said `Info-goto-node' was defined in info.el.gz: arglist mismatch
Warning (check-declare): helm-info.el said `Info-find-node' was defined in info.el.gz: arglist mismatch
Warning (check-declare): helm-plugin.el said `Info-goto-node' was defined in info.el.gz: arglist mismatch
Warning (check-declare): helm-plugin.el said `Info-find-node' was defined in info.el.gz: arglist mismatch
Warning (check-declare): helm-emms.el said `with-current-emms-playlist' was defined in emms.el: function not found
Warning (check-declare): projectile.el said `ggtags-ensure-project' was defined in ggtags.el: file not found
Warning (check-declare): projectile.el said `ggtags-update-tags' was defined in ggtags.el: file not found
Warning (check-declare): async-bytecomp.el said `package-desc-reqs' was defined in package.el.gz: function not found
My mistake was assuming that the FILE
argument of declare-function
was somehow related to require
. But of course it had to be simply
the name of the file that contains the said function. If the referenced file is in an external package,
e.g. (declare-function cider-repl-return "ext:cider-repl")
can be used.
checkdoc
This one is actually very useful once you embrace it. It will
tsk-tsk you until all your functions are documented. And since
you're already writing a docstring, might as well make it
good. Sometimes this leads me to removing a function that's called
only once, just so that I don't have to document it.
byte-compile-file
Leaving the obvious for last. This will speed up the code in addition to checking for errors.
In dired
you can use:
- several m (
dired-mark
) followed by B (dired-do-byte-compile
).
- a single *% (
dired-mark-files-regexp
) el$
followed by B.
I even have a compile
target in lispy
's Makefile:
compile:
$(CASK) exec $(EMACS) -batch $(LOAD) -l lispy-test.el -l compile.elt
Here are the contents of compile.elt:
(require 'check-declare)
(setq check-declare-ext-errors t)
(setq files '("lispy.el"
"lispy-inline.el"
"le-clojure.el"
"le-scheme.el"
"le-lisp.el"))
(mapc #'byte-compile-file files)
(ert t)
(apply #'check-declare-files files)