18 Jan 2015
My interest in org-download
was renewed today with
this thread on
org-mode
's mailing list.
org-download
allows you to drag-and-drop an image from e.g. Firefox
or your own file system to an org-mode
buffer. When I originally
wrote it, I was taking a Chemistry course on
edX, which included homework and exams with a
lot of images. Doing the homework in a literate style with org-mode
,
I wanted the problems to be completely self-contained, and for that I
needed to save all the images from the website, preferably quickly, to
an org-mode
buffer. With a few hacks and some advice and
contributions from more experienced hackers, org-download
came to
be.
Today's commits
The main contribution from today's commits was adding the code that
un-aliases images that point to HTML. I see a lot of these from the
people that I'm following on my Twitter,
@_abo_abo. Here's the code:
(defcustom org-download-img-regex-list
'("<img +src=\"" "<img +\\(class=\"[^\"]+\"\\)? *src=\"")
"This regex is used to unalias links that look like images.
The html to which the links points will be searched for these
regexes, one by one, until one succeeds. The found image address
will be used."
:group 'org-download)
and in (org-download-image link)
:
(unless (image-type-from-file-name link)
(with-current-buffer
(url-retrieve-synchronously link t)
(let ((regexes org-download-img-regex-list)
lnk)
(while (and (not lnk) regexes)
(goto-char (point-min))
(when (re-search-forward (pop regexes) nil t)
(backward-char)
(setq lnk (read (current-buffer)))))
(if lnk
(setq link lnk)
(error "link %s does not point to an image" link)))))
Here, image-type-from-file-name
is a built-in from image.el
that
decides if link
looks like an image file or not.
As you can see, since I intend to use link
right after to be
transformed right now, I'm using url-retrieve-synchronously
, instead
of the asynchronous url-retrieve
. The other one is used by default
to download the actual image.
Note the use of the while
/ pop
combination for traversing a list.
I've seen it used in some places in the Emacs core, and I think it's
pretty neat.
Arranging the regular expressions into a list is necessary to give
priority to some regexes. For instance, the first element of
org-download-img-regex-list
should match e.g. an actual referred
image on Twitter, while the second element will match at least a
profile picture in the case when there is no referred image.
Visual demo
I think that I might have over-engineered the custom options of
org-download
a bit. Just to keep you motivated enough to figure them
out, here's a link to
a Youtube demo of the
fast clickety-clicking (the mouse usage), that comes after some
clackety-clacking (the customization).
17 Jan 2015
Once you make Ediff bearable, it becomes wonderful. At least this was
my experience. It's a very good tool, but some of the defaults look
very poor to me.
Customizing the customize
First of all, I'll list a macro that I've started to use for setting
custom variables:
(defmacro csetq (variable value)
`(funcall (or (get ',variable 'custom-set)
'set-default)
',variable ,value))
This macro I've put together myself after searching though the code
base and not finding something similar; custom-set-variables
comes
close to what I want, or maybe custom-initialize-changed
. Basically
all I want is a setq
that is aware of the custom-set
property of a
variable. If you know such a macro, please let me know.
Changing some Ediff options
Now, that I've explained the custom setter (by the way, using
custom-set-variables
is absolutely equivalent to csetq
), here are
my changes:
Don't use the weird setup with the control panel in a separate
frame. I can manage windows in Emacs much better than my desktop
(Unity or Gnome Shell) can manage the Emacs frames.
(csetq ediff-window-setup-function 'ediff-setup-windows-plain)
Split the windows horizontally instead of vertically. This way, it's
much easier to follow the changes.
(csetq ediff-split-window-function 'split-window-horizontally)
Ignore white space. I don't write a lot of Python, so I don't care
about the white space in the diffs. At the same time, I re-format any
LISP code that I edit to my liking, and I want to see only the
important changes in the diff, and not the whitespace nonsense.
(csetq ediff-diff-options "-w")
Changing some Ediff key bindings
This is just the standard stuff that I like to do for each mode that
does not self-insert: assign j to move down, and
k to move up.
(defun ora-ediff-hook ()
(ediff-setup-keymap)
(define-key ediff-mode-map "j" 'ediff-next-difference)
(define-key ediff-mode-map "k" 'ediff-previous-difference))
(add-hook 'ediff-mode-hook 'ora-ediff-hook)
Restoring the windows after Ediff quits
When you quit an Ediff session with q, it just leaves the
two diff windows around, instead of restoring the window configuration
from when Ediff was started. Here's the (slightly hacky) code to
restore the old window configuration:
(winner-mode)
(add-hook 'ediff-after-quit-hook-internal 'winner-undo)
List of ways that I use to invoke Ediff
from magit
In 80% of the cases, I call Ediff with e (magit-ediff
) from
magit-status-mode
. This gives me a better overview of the changes,
especially when I want to revert stuff with either a
(ediff-copy-A-to-B
) or b (ediff-copy-B-to-A
). Probably
with a, since magit seems
to consistently put the @{index}
file into the A
diff window, and
the current file into the B
window.
So if I'm looking at a diff (to which I navigated with
j/k), I can revert it with a. At this
point, the diff region in the current file will become equal to that
of the index file. But it will not be saved yet. If I want to save the
current file in the B
window, I can do it with wb
(ediff-save-buffer
). After a revert, it's also useful to call
!(ediff-update-diffs
), which will remove the zero-length
diffs and update the diff-count in the mode-line.
other methods
ediff-buffers
will diff two (different) buffers. If you happen to
have only two windows open with the appropriate buffers, you get them
as defaults and can choose them quickly with RET RET.
ediff-files
is similar, but works on files instead. I like to just mark the appropriate files
in dired
with m, then they also get auto-selected by ediff-files
.
ediff-current-file
is useful to see the unsaved changes to the current file.
I rarely use it, since I have a compulsion to save every file every chance I get. There is little hope
to recover from this addiction, unless someone implements an analogue of guru-mode
that annoys you when you try to save a file. Actually, it's not a bad idea - C-x C-s:
Oleh, you have saved this file 40 times
in the last hour; the last
save was 0 minutes 34 seconds ago
; since then, you've changed 27
bytes
of information. Are you sure you want to save [y/N]
?
16 Jan 2015
Here's a very simplistic function that I was using for a while:
(defun save-and-compile ()
(interactive)
(save-buffer)
(compile "make -j4")
(pop-to-buffer next-error-last-buffer))
It will save the current buffer, run compile
and switch to
compilation buffer.
Compilation customization
Turns out that there's no need to save, since I get away with this:
(setq compilation-ask-about-save nil)
The documentation says:
Non-nil means M-x compile
asks which buffers to save before
compiling. Otherwise, it saves all modified buffers without asking.
Select compilation target
A year ago, I wrote a package that looks for a Makefile
in the
current directory, parses the available targets and allows you to
choose one with helm. It's
called helm-make. It's almost
the same as M-x compile
(which also has completion for
targets), and it wraps around compile
, but I just find it to be more
convenient.
This package is as simple as it sounds, the only customization that
you can do is to set helm-make-do-save
to save all open buffers
visiting the Makefile
's directory. It also provides, in addition to
the plain helm-make
command, a helm-make-projectile
command, which
is almost the same, except the Makefile
should come not from the
current directory but from projectile-project-root
.
Some error navigation to go with your compilation
I've had these bindings for a very long time, just making sure
that you're aware of these commands:
(global-set-key [f6] 'next-error)
(global-set-key [C-f6] 'previous-error)
These bindings work for M-x occur
and rgrep
as well.
15 Jan 2015
It is very much in the spirit of C++ to pull an object into existence
with e.g. a constructor definition and then poke and prod it with
various method calls. Most of the time, the dot will have the object
name on the left. So why not automatically insert the object name each
time I press the dot? Below, I'll show a code that does exactly that.
The dot command
(defun c++-smart-dot ()
"Insert a dot or an object name plus dot when appropriate."
(interactive)
(let (var-name)
(if (and (looking-back "^[ \t]*")
(setq var-name (c++-get-recent-var)))
(insert var-name ".")
(insert "."))))
This one is pretty simple: if we are at the beginning of the line,
optionally with some spaces or (ugh) tabs before the point, then try
to insert the object name along with a dot.
Here's how to bind it:
(eval-after-load "cc-mode"
`(define-key c++-mode-map "." 'c++-smart-dot))
How to get the recent variable
This code doesn't aim to be thorough, it's just a hack that
works reasonably well.
(defconst c++-var-regex "[A-Za-z][A-Za-z0-9_]*"
"The regex for C++ variable name.")
(defun c++-get-recent-var ()
"Return the closest thing that looks like an object.
The search is performed backwards through code."
(save-excursion
(when (or
;; variable dot chain
(looking-back
(format " \\(%s\\)\\.%s.*\n[\t ]*"
c++-var-regex
c++-var-regex))
;; variable constructor init
(looking-back
(format "[\t ]+\\(%s\\)\\(?:([^)]*)\\)?;[\t\n ]*"
c++-var-regex))
;; variable dot, first on line
(re-search-backward
(format "^[ \t]*\\(%s\\)\\." c++-var-regex) nil t))
(match-string-no-properties 1))))
If you're a stickler for performance and you don't want to call format a bunch of times,
you can amend the code like this:
(defalias 'c++-get-recent-var
(byte-compile
`(lambda ()
(save-excursion
(when
(or
;; variable dot chain
(looking-back
,(format
" \\(%s\\)\\.%s.*\n[\t ]*"
c++-var-regex
c++-var-regex))
;; variable constructor init
(looking-back
,(format
"[\t ]+\\(%s\\)\\(?:([^)]*)\\)?;[\t\n ]*"
c++-var-regex))
;; variable dot, first on line
(re-search-backward
,(format "^[ \t]*\\(%s\\)\\." c++-var-regex) nil t))
(match-string-no-properties 1)))))
"Return the closest thing that looks like an object.
The search is performed backwards through code.")
The thing above looks slightly ugly. I'm open to suggestions to make
it look nicer.
The sample application
For the happy people that have never seen C++:
DataOut<dim> data_out;
data_out.attach_dof_handler(dof_handler);
data_out.add_data_vector(solution, "u");
data_out.build_patches();
Here, after defining an object data_out
, I insert it subsequently
with just ..
14 Jan 2015
I don't usually zoom a lot, typically I do it to size up other
people's functions. Then, I zoom-out a couple times in a row until the
function fits on the screen. Sometimes, I overshoot the zoom-out, and
I have to zoom-in instead. I have text-scale-increase
bound to
<f2> g and text-scale-decrease
bound to
<f2> l.
Below, I'll demonstrate how to call those two commands interchangeably
with e.g. <f2> g g g l g g l, i.e. omitting the
<f2> prefix.
Define repeatable command
(defun def-rep-command (alist)
"Return a lambda that calls the first function of ALIST.
It sets the transient map to all functions of ALIST."
(lexical-let ((keymap (make-sparse-keymap))
(func (cdar alist)))
(mapc (lambda (x)
(define-key keymap (car x) (cdr x)))
alist)
(lambda (arg)
(interactive "p")
(funcall func arg)
(set-transient-map keymap t))))
This is a pretty simple function that takes an alist of keys and
commands, and returns a lambda that calls the first command and sets
the transient map to call the first and other commands. The way the
transient map works, it takes priority over almost all maps, but
disappears as soon as you press something that doesn't belong to it.
The zoom-in / zoom-out use case
(global-set-key (kbd "<f2> g")
(def-rep-command
'(("g" . text-scale-increase)
("l" . text-scale-decrease))))
(global-set-key (kbd "<f2> l")
(def-rep-command
'(("l" . text-scale-decrease)
("g" . text-scale-increase))))
And this is it. A nice thing about this setup is that I don't have to
think about the zoom state and quitting it: I'll quit it automatically
as soon as I press anything other than l or g.
Moreover, the command that exited the zoom state will be executed as
usual.