Counsel-yank-pop with a tweak

Abo Abo’s counsel package (part of swiper/ivy) puts together a set of replacements for Emacs commands that leverages the power of the ivy completion library.

One of my favourites is counsel-yank-pop which replaces the standard clipboard history (kill-ring in Emacs terminology) with an ivy-powered version. You can then type search strings to filter your clipboard history dynamically.

I use the following code to configure counsel-yank-pop to replace the standard yank-pop on M-y. The only thing I missed about the vanilla yank-pop was that repeatedly pressing M-y cycled through the entries. The counsel version doesn’t do this by default but this is easy to add by binding M-y to ivy-next-line in the ivy-minibuffer-map.

(use-package counsel
  :bind
  (("M-y" . counsel-yank-pop)
   :map ivy-minibuffer-map
   ("M-y" . ivy-next-line)))

Automatically copy text selected with the mouse

I’m not much of a mouse user, but a colleague using emacs for OS X wanted to replicate the normal X11 behaviour that linux users are familiar with – text selected with the mouse is automatically copied to the system clipboard. It turns out to be as easy as adding one line to your emacs config file:

(setq mouse-drag-copy-region t)

From the help for the variable (C-h v mouse-drag-copy-region)

If non-nil, copy to kill-ring upon mouse adjustments of the region.

In other words, highlight a block of text and it is copied to the kill-ring (Emacs’ internal clipboard). This also copies to the system clipboard on the Mac so you can then paste to other apps.

Even better email contact completion in mu4e

I have written previously about my tweaks to improve contact completion when composing emails with mu4e. Thanks to some help from abo-abo, the author of the fantastic ivy completion library, with the code below you can hit a comma to complete the current choice of email address and start searching for the next one. This matches the behaviour of many other email clients like Gmail or Thunderbird.

This won’t change anybody’s world, but gives you a nice little thrill of efficiency when entering several recipients to an email!

Here is the updated code (see my previous post for more details):

;;need this for hash access
(require 'subr-x)

;;my favourite contacts - these will be put at front of list
(setq bjm/contact-file "/homeb/bjm/docs/fave-contacts.txt")

(defun bjm/read-contact-list ()
  "Return a list of email addresses"
  (with-temp-buffer
    (insert-file-contents bjm/contact-file)
    (split-string (buffer-string) "\n" t)))

;; code from https://github.com/abo-abo/swiper/issues/596
(defun bjm/counsel-email-action (contact)
  (with-ivy-window
    (insert contact)))

;; bind comma to launch new search
(defvar bjm/counsel-email-map
  (let ((map (make-sparse-keymap)))
    (define-key map "," 'bjm/counsel-email-more)
    map))

(defun bjm/counsel-email-more ()
  "Insert email address and prompt for another."
  (interactive)
  (ivy-call)
  (with-ivy-window
    (insert ", "))
  (delete-minibuffer-contents)
  (setq ivy-text ""))

;; ivy contacts
;; based on http://kitchingroup.cheme.cmu.edu/blog/2015/03/14/A-helm-mu4e-contact-selector/
(defun bjm/ivy-select-and-insert-contact (&optional start)
  (interactive)
  ;; make sure mu4e contacts list is updated - I was having
  ;; intermittent problems that this was empty but couldn't see why
  (mu4e~request-contacts)
  (let ((eoh ;; end-of-headers
         (save-excursion
           (goto-char (point-min))
           (search-forward-regexp mail-header-separator nil t)))
        ;; append full sorted contacts list to favourites and delete duplicates
        (contacts-list
         (delq nil (delete-dups (append (bjm/read-contact-list) (mu4e~sort-contacts-for-completion (hash-table-keys mu4e~contacts)))))))

    ;; only run if we are in the headers section
    (when (and eoh (> eoh (point)) (mail-abbrev-in-expansion-header-p))
      (let* ((end (point))
           (start
            (or start
                (save-excursion
                  (re-search-backward "\\(\\`\\|[\n:,]\\)[ \t]*")
                  (goto-char (match-end 0))
                  (point))))
           (initial-input (buffer-substring-no-properties start end)))

      (kill-region start end)

      (ivy-read "Contact: "
                contacts-list
                :re-builder #'ivy--regex
                :sort nil
                :initial-input initial-input
                :action 'bjm/counsel-email-action
                :keymap bjm/counsel-email-map)
      ))))

A tweak to elfeed filtering

I wrote recently about my enthusiasm for the elfeed feed reader. Here is a microscopic tweak to the way elfeed search filters work to better suit my use.

By default, if I switch to a bookmarked filter to view e.g. my feeds tagged with Emacs (as discussed in the previous post), and then hit s to run a live filter, I can type something like “Xah” to dynamically narrow the list of stories to those containing that string. The only problem is I actually have to type ” Xah”, i.e. with a space before the filter text, since it is appended to the filter that is already present “+unread +emacs” in this case.

Since life is too short to type extra spaces, I wrote a simple wrapper for the elfeed filter command:

;;insert space before elfeed filter
(defun bjm/elfeed-search-live-filter-space ()
  "Insert space when running elfeed filter"
  (interactive)
  (let ((elfeed-search-filter (concat elfeed-search-filter " ")))
    (elfeed-search-live-filter)))

I add this to the elfeed keybindings when I initialise the package

(use-package elfeed
  :ensure t
  :bind (:map elfeed-search-mode-map
              ("A" . bjm/elfeed-show-all)
              ("E" . bjm/elfeed-show-emacs)
              ("D" . bjm/elfeed-show-daily)
              ("/" . bjm/elfeed-search-live-filter-space)
              ("q" . bjm/elfeed-save-db-and-bury)))

and now I can use / to filter my articles without needing the extra space.

Search or swipe for the current word

It is often handy to search for the word at the current cursor position. By default, you can do this by starting a normal isearch with C-s and then hitting C-w to search for the current word. Keep hitting C-w to add subsequent words to the search.

If, like me, you use swiper for your searches, you can obtain the same effect using M-j after you start swiper.

This is all very nice, but both of those solutions above search for the string from the cursor position to the end of the word, so if “|” marks the cursor position in the word prag|matic, then either method above would search for matic. I made a small tweak to the relevant function in the ivy library that powers swiper so that the whole of the word is used, so in the example above M-j would search for the full pragmatic string.

Here is the code:

;; version of ivy-yank-word to yank from start of word
(defun bjm/ivy-yank-whole-word ()
  "Pull next word from buffer into search string."
  (interactive)
  (let (amend)
    (with-ivy-window
      ;;move to last word boundary
      (re-search-backward "\\b")
      (let ((pt (point))
            (le (line-end-position)))
        (forward-word 1)
        (if (> (point) le)
            (goto-char pt)
          (setq amend (buffer-substring-no-properties pt (point))))))
    (when amend
      (insert (replace-regexp-in-string "  +" " " amend)))))

;; bind it to M-j
(define-key ivy-minibuffer-map (kbd "M-j") 'bjm/ivy-yank-whole-word)

Update

An offline commenter pointed out that Xah Lee has a nice alternative implementation of this functionality using isearch.

Read your RSS feeds in emacs with elfeed

The package elfeed is an excellent feed reader for Emacs. The project web page has great documentation, and you should read that to cover the basics. I thought I’d share some of the details of my setup. I’ll split this up into a few posts, but today I’ll cover my basic setup and some teaks to give me shortcut keys to groups of feeds, and to help with the syncing of my feeds between multiple machines.

First I have an org-mode file with my list of feeds. Here is an excerpt.

* blogs                                                        :elfeed:
** daily                                                        :daily:
*** http://telescoper.wordpress.com/feed/
*** http://xkcd.com/rss.xml
*** http://timharford.com/feed/
*** http://understandinguncertainty.org/rss.xml
** emacs                                                        :emacs:
*** http://www.reddit.com/r/emacs/.rss
*** http://planet.emacsen.org/atom.xml
*** http://feeds.feedburner.com/XahsEmacsBlog
*** http://pragmaticemacs.com/feed/
*** [[http://emacs.stackexchange.com/feeds][SX]]

We need to use the package elfeed-org to tell elfeed to use the org file above:

;; use an org file to organise feeds
(use-package elfeed-org
  :ensure t
  :config
  (elfeed-org)
  (setq rmh-elfeed-org-files (list "/path/to/elfeed.org")))

Note how in the org file I have used an org-mode link to the stack exchange feed; the description part of the link (SX in this case) will be used as the feed title in elfeed. I have also collected some feeds together, under the tags “daily” and “emacs”. These tags are used by elfeed to let you view sets of feeds. The first time we run elfeed we will add bookmarks to allow us to jump to those sets of feeds, and to do that we’ll need some simple helper functions, which we need to add to our emacs config file.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; elfeed feed reader                                                     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;shortcut functions
(defun bjm/elfeed-show-all ()
  (interactive)
  (bookmark-maybe-load-default-file)
  (bookmark-jump "elfeed-all"))
(defun bjm/elfeed-show-emacs ()
  (interactive)
  (bookmark-maybe-load-default-file)
  (bookmark-jump "elfeed-emacs"))
(defun bjm/elfeed-show-daily ()
  (interactive)
  (bookmark-maybe-load-default-file)
  (bookmark-jump "elfeed-daily"))

Now, I use elfeed on two machines and I keep the elfeed database (stored in ~/.elfeed by default) synchronised between those machines. (I use unison, but you could use dropbox etc). For this to work well we need to make sure elfeed updates its database whenever we quit it, and reads it again when we resume. Here are some helper functions for this:

;;functions to support syncing .elfeed between machines
;;makes sure elfeed reads index from disk before launching
(defun bjm/elfeed-load-db-and-open ()
  "Wrapper to load the elfeed db from disk before opening"
  (interactive)
  (elfeed-db-load)
  (elfeed)
  (elfeed-search-update--force))

;;write to disk when quiting
(defun bjm/elfeed-save-db-and-bury ()
  "Wrapper to save the elfeed db to disk before burying buffer"
  (interactive)
  (elfeed-db-save)
  (quit-window))

Now let’s install and configure elfeed

(use-package elfeed
  :ensure t
  :bind (:map elfeed-search-mode-map
              ("A" . bjm/elfeed-show-all)
              ("E" . bjm/elfeed-show-emacs)
              ("D" . bjm/elfeed-show-daily)
              ("q" . bjm/elfeed-save-db-and-bury)))

With that, we can launch elfeed with M-x bjm/elfeed-load-db-and-open and (for the first time only) create the bookmarks to our tags. Hit G to refresh the feeds and then create a bookmark with C-x r m and name it elfeed-all to match the name we used in the function above. Now hit s to edit the search filter and add +emacs to the filter string. This should show only your emacs feeds. Create a bookmark named elfeed-emacs for this filter and do the same for any other tags you have used.

With the bookmarks saved, you can now use E in the elfeed window to jump to your Emacs feeds and so on.

If you use q to quit elfeed when you are done, then the database will be saved and your latest changes will be synced to any other machines.

In future posts I’ll look at starring and saving articles with org-mode and a nice simple tweak to feed filtering.

Update

Thanks to the commenters for pointing out I initially forgot to mention elfeed-org – this has been fixed now.

Use bookmarks to jump to files or directories

In Emacs you can bookmark files and directories (and lots of other things) so that you can quickly jump to them (similar to a browser’s bookmarks).

The basics are easy. Use C-x r m to make a bookmark to the file or directory you are currently visiting. You’ll be prompted for an optional name for your bookmark. For example, I use names starting dir- for bookmarks to directories so that they all appear together in the bookmark list.

You can use C-x r b to go to a bookmark, and you’ll prompted for the name of the bookmark. Use C-x r l to list all of the bookmarks.

There is a bookmarks+ package which adds extra features to the normal bookmarks, but I’ve not found that I need those extras so far.

Insert today’s date

Here’s a simple bit of code from the Emacs wiki to insert the current date. I’ve set the default to be in the format YYYY-MM-DD, but if you use a prefix C-u then you get DD-MM-YYYY.

;; from http://emacswiki.org/emacs/InsertingTodaysDate
(defun insert-todays-date (arg)
  (interactive "P")
  (insert (if arg
              (format-time-string "%d-%m-%Y")
            (format-time-string "%Y-%m-%d"))))

Google search from inside emacs

Artur Malabarba, of endless parentheses, has a nice package called google this which provides a set of functions for querying google from emacs.

Here is my code to install google-this

;; google-this
(use-package google-this
  :config
  (google-this-mode 1))

The package provides a set of functions under the prefix C-c /. The simplest is C-c / RET which prompts you for a search in the minibuffer, with a default search string based on the text around the point. This sounds trivial, but I find myself using it all the time as it is more efficient than switching to my browser, moving to the search box and trying the search string.

The full list of commands is:

C-c / SPC google-this-region
C-c / a google-this-ray
C-c / c google-this-translate-query-or-region
C-c / e google-this-error
C-c / f google-this-forecast
C-c / g google-this-lucky-search
C-c / i google-this-lucky-and-insert-url
C-c / l google-this-line
C-c / m google-maps
C-c / n google-this-noconfirm
C-c / r google-this-cpp-reference
C-c / s google-this-symbol
C-c / t google-this
C-c / w google-this-word
C-c / <return> google-this-search

Use visible bookmarks to quickly jump around a file

The visible bookmarks package lets you bookmark positions in the current buffer and then jump between them. This is really useful if you are working on large files and have a few common locations you want to keep returning to. It is more efficient than jumping around the mark ring or moving through edit points.

Here is my code to install and configure visible bookmarks with the recommended key bindings:

(use-package bm
  :bind (("<C-f2>" . bm-toggle)
         ("<f2>" . bm-next)
         ("<S-f2>" . bm-previous)))

Here is a trivial illustration where I use <C-f2> to place three bookmarks (causing those lines to be highlighted) and then <f2> and <S-f2> to move up and down through them, before using <C-f2> again to toggle the bookmarks off.

visible-bookmarks.gif

The package will also let you cycle through bookmarks in multiple buffers, and move in order of “last in first out”. See the documentation for more information.