(or emacs irrelevant)

Sprucing up org-download

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).

Setting up Ediff

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:

  1. 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)
    
  2. 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)
    
  3. 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

  1. 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.
  2. 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.
  3. 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]?

Save before compile

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.

C++ - a dot inserts last var plus dot

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 ..

Zoom in / out with style

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.