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.

Move to the beginning of a line the smart way

I’ve moved away from using my recommended setup, prelude in favour of completely writing my own customisation file. I would still recommend prelude for beginner and intermediate Emacs users, but I wanted full control for myself. I have missed a few things from prelude, but happily the author provides some of his useful functions in a stand alone package called crux.

One of my favourite tools from crux is crux-move-beginning-of-line, which I use in place of the normal C-a to move to the start of the line. The crux version has the extra benefit that the first time you use it, it moves the point to the first non-whitespace character on the line. Repeating it moves to the start of the line, and more repeats toggle back and forth.

Here’s how I install and configure crux to do this.

(use-package crux
  :bind (("C-a" . crux-move-beginning-of-line)))

Crux has lots of other useful tools, so go and check them out.

Find and open files from anywhere with helm-for-files

Helm is an extremely powerful package that provides a search interface that narrows the matches as you type. What makes it powerful is the range of back-ends that you can access through helm. I don’t use it for a lot of things (I slightly prefer ivy in general), but one of my favourites is helm-for-files. This gives you a search interface where you start typing the name of a file and it narrows a list of files from multiple useful sources: currently opened files; recent files; bookmarked files; files in the current directory; and files anywhere on your system using your system’s locate command. Basically, it find any file anywhere on your system, showing you the most likely matches first. Hitting RET to select a file opens it in Emacs as usual.

Here is how I install and configure helm for this purpose

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; helm                                                                   ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(use-package helm
  :ensure t
  :init
  (progn
    (require 'helm-config)
    ;; limit max number of matches displayed for speed
    (setq helm-candidate-number-limit 100)
    ;; ignore boring files like .o and .a
    (setq helm-ff-skip-boring-files t)
    ;; replace locate with spotlight on Mac
    (setq helm-locate-command "mdfind -name %s %s"))
  :bind (("C-x f" . helm-for-files)))

Since I use a Mac, I tell helm to use mdfind which is the command line interface to the spotlight indexer in place of the normal locate command. Finally, I bind the command to C-x f to serve as a memorable alternative for C-x C-f (the default interface for opening files).

Cycle through windows across all frames

There are lots of ways to switch between windows in Emacs. I recently discovered that s-' (i.e. super and ' where super is the command key on a Mac) runs the command next-multiframe-window which cycles you through all the current windows regardless of which frame they are in. This is a nice quick way to switch to another window.

Aside: in Emacs terminology a frame is what most programmes call a window – the floating box containing the programme. In Emacs a frame can be split into several windows such as when you have several buffers open at the same time.

Macro Counters

I’ve posted about using keyboard macros to record and play back repetitive tasks. Macros include a counter which lets you insert numerical values that increment each time the macro is called.

For example, go to a new line and start a macro with C-x ( and then hit C-a to move to the start of the line, C-x C-k C-i to insert the macro counter (initially zero) and then RET to go to a new line and C-x ) to stop the recording. Run the macro a few times with C-x e and then just e to repeat the macro and you’ll get something like this:

0
1
2
3
4

The counter starts at zero every time you define a new macro. To set it to another value, use C-x C-k C-c before defining or invoking a macro.

Insert file name

Here is a simple function from the emacs wiki to insert the name of a file into the current buffer. The convenient thing is that it uses the normal find-file prompt with whatever your completion setting is, so it works very easily. I bind it to C-c b i and as the documentation says, by default it inserts a relative path but called with a prefix (C-u C-c b i) it inserts the full path.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; insert file name at point                                              ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; https://www.emacswiki.org/emacs/InsertFileName
(defun bjm/insert-file-name (filename &optional args)
  "Insert name of file FILENAME into buffer after point.

  Prefixed with \\[universal-argument], expand the file name to
  its fully canocalized path.  See `expand-file-name'.

  Prefixed with \\[negative-argument], use relative path to file
  name from current directory, `default-directory'.  See
  `file-relative-name'.

  The default with no prefix is to insert the file name exactly as
  it appears in the minibuffer prompt."
  ;; Based on insert-file in Emacs -- ashawley 20080926
  (interactive "*fInsert file name: \nP")
  (cond ((eq '- args)
         (insert (expand-file-name filename)))
        ((not (null args))
         (insert filename))
        (t
         (insert (file-relative-name filename)))))

;; bind it
(global-set-key (kbd "C-c b i") 'bjm/insert-file-name)

Weather in Emacs

I recently came across this very nice emacs config file which has lots of neat bits and pieces. One fun thing that caught my eye was getting the weather forecast using the wttrin.el package. To install the package use

;; weather from wttr.in
(use-package wttrin
  :ensure t
  :commands (wttrin)
  :init
  (setq wttrin-default-cities '("Cheltenham"
                                "Bristol")))

This sets the list of available cities. You can then use M-x wttrin to see the weather. This will prompt for the city and then show a buffer with the forecast. You can use g to change city and q to quit.

Here is a screenshot:

wttrin.png

The only problem is that if the Emacs frame is not wide enough and the lines in the wttrin buffer wrap, it becomes unreadable. My solution is to save the window and frame configuration, then resize the frame to be big enough for the wttrin buffer. The previous configuration is then restored when exiting wttrin. These functions take care of that for us:

;;advise wttrin to save frame arrangement
;;requires frame-cmds package
(defun bjm/wttrin-save-frame ()
  "Save frame and window configuration and then expand frame for wttrin."
  ;;save window arrangement to a register
  (window-configuration-to-register :pre-wttrin)
  (delete-other-windows)
  ;;save frame setup and resize
  (save-frame-config)
  (set-frame-width (selected-frame) 130)
  (set-frame-height (selected-frame) 48)
  )
(advice-add 'wttrin :before #'bjm/wttrin-save-frame)

(defun bjm/wttrin-restore-frame ()
  "Restore frame and window configuration saved prior to launching wttrin."
  (interactive)
  (jump-to-frame-config-register)
  (jump-to-register :pre-wttrin)
  )
(advice-add 'wttrin-exit :after #'bjm/wttrin-restore-frame)

Update: open wttrin with default city

By default wttrin prompts you to chose the city from your list when it starts. This function starts wttrin with the first city on your list. You can always change this by hitting g.

;; function to open wttrin with first city on list
(defun bjm/wttrin ()
    "Open `wttrin' without prompting, using first city in `wttrin-default-cities'"
    (interactive)
    ;; save window arrangement to register 
    (window-configuration-to-register :pre-wttrin)
    (delete-other-windows)
    ;; save frame setup
    (save-frame-config)
    (set-frame-width (selected-frame) 130)
    (set-frame-height (selected-frame) 48)
    ;; call wttrin
    (wttrin-query (car wttrin-default-cities))
    )

Auto Save and Backup Every Save

Emacs has two useful ways of protecting you from data loss. The first is auto save, which saves a copy of a file every so often while you are editing it. If some catastrophe caused you to close Emacs or shut down your machine without saving the file then you can use M-x recover-file to recover the file from its auto save. By default, the auto save files are saved in the same directory as the original file, and are given a name of the form #file#. This is fine for me, but you can configure this.

I like to make auto saves often, so I make the following tweaks to my emacs config file:

;; auto save often
;; save every 20 characters typed (this is the minimum)
(setq auto-save-interval 20)

When you save a file, the auto save file is deleted.

The other way Emacs protects you is to make backups of your files. By default the backup file is made in the same directory as the original with a name like file~. The way the backup works is that Emacs makes a copy of a file the first time you save it in an Emacs session. It only makes that one backup though, so this is not very useful if you keep your session running for a long time and want to recover an earlier version of a file.

The following code sets some general backup options and then configures Emacs to make a backup of a file every time you save it. The code builds on bits from here and here, and the comments should be quite self-explanatory.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; backup settings                                                        ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; https://www.emacswiki.org/emacs/BackupFiles
(setq
 backup-by-copying t     ; don't clobber symlinks
 kept-new-versions 10    ; keep 10 latest versions
 kept-old-versions 0     ; don't bother with old versions
 delete-old-versions t   ; don't ask about deleting old versions
 version-control t       ; number backups
 vc-make-backup-files t) ; backup version controlled files

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; backup every save                                                      ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; http://stackoverflow.com/questions/151945/how-do-i-control-how-emacs-makes-backup-files
;; https://www.emacswiki.org/emacs/backup-each-save.el
(defvar bjm/backup-file-size-limit (* 5 1024 1024)
  "Maximum size of a file (in bytes) that should be copied at each savepoint.

If a file is greater than this size, don't make a backup of it.
Default is 5 MB")

(defvar bjm/backup-location (expand-file-name "~/emacs-backups")
  "Base directory for backup files.")

(defvar bjm/backup-trash-dir (expand-file-name "~/.Trash")
  "Directory for unwanted backups.")

(defvar bjm/backup-exclude-regexp "\\[Gmail\\]"
  "Don't back up files matching this regexp.

Files whose full name matches this regexp are backed up to `bjm/backup-trash-dir'. Set to nil to disable this.")

;; Default and per-save backups go here:
;; N.B. backtick and comma allow evaluation of expression
;; when forming list
(setq backup-directory-alist
      `(("" . ,(expand-file-name "per-save" bjm/backup-location))))

;; add trash dir if needed
(if bjm/backup-exclude-regexp
    (add-to-list 'backup-directory-alist `(,bjm/backup-exclude-regexp . ,bjm/backup-trash-dir)))

(defun bjm/backup-every-save ()
  "Backup files every time they are saved.

Files are backed up to `bjm/backup-location' in subdirectories \"per-session\" once per Emacs session, and \"per-save\" every time a file is saved.

Files whose names match the REGEXP in `bjm/backup-exclude-regexp' are copied to `bjm/backup-trash-dir' instead of the normal backup directory.

Files larger than `bjm/backup-file-size-limit' are not backed up."

  ;; Make a special "per session" backup at the first save of each
  ;; emacs session.
  (when (not buffer-backed-up)
    ;;
    ;; Override the default parameters for per-session backups.
    ;;
    (let ((backup-directory-alist
           `(("." . ,(expand-file-name "per-session" bjm/backup-location))))
          (kept-new-versions 3))
      ;;
      ;; add trash dir if needed
      ;;
      (if bjm/backup-exclude-regexp
          (add-to-list
           'backup-directory-alist
           `(,bjm/backup-exclude-regexp . ,bjm/backup-trash-dir)))
      ;;
      ;; is file too large?
      ;;
      (if (<= (buffer-size) bjm/backup-file-size-limit)
          (progn
            (message "Made per session backup of %s" (buffer-name))
            (backup-buffer))
        (message "WARNING: File %s too large to backup - increase value of bjm/backup-file-size-limit" (buffer-name)))))
  ;;
  ;; Make a "per save" backup on each save.  The first save results in
  ;; both a per-session and a per-save backup, to keep the numbering
  ;; of per-save backups consistent.
  ;;
  (let ((buffer-backed-up nil))
    ;;
    ;; is file too large?
    ;;
    (if (<= (buffer-size) bjm/backup-file-size-limit)
        (progn
          (message "Made per save backup of %s" (buffer-name))
          (backup-buffer))
      (message "WARNING: File %s too large to backup - increase value of bjm/backup-file-size-limit" (buffer-name)))))

;; add to save hook
(add-hook 'before-save-hook 'bjm/backup-every-save)

Files are backed up to a customisable directory in subdirectories per-session once per Emacs session, and per-save every time a file is saved. You can specify a maximum file size for files that will be backed up, and a regular expression to specify files that will not be backed up. I use the latter to avoid making backups of my emails by using the regular expression \\[Gmail\\] which matches emails I compose with mu4e. You can set this to nil if you want to disable this.