Month: May 2016

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

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.

Uniquify your buffer names

If you open more than one file that has the same name (say test.txt), then by default Emacs will add a number to the end of the buffer name to distinguish them, so you would see test.txt <1> and test.txt <2> and so on. This is not very useful as it is easy to lose track of which file is which.

Luckily it is easy to fix with some simple tweaks (I’ve taken these from the configuration files for prelude). Add these to your emacs config file and your buffer names will be made unique by adding just enough of the path to the file. So you might see docs/test.txt and scratch/test.txt. Much nicer!

;; meaningful names for buffers with the same name
;; from prelude
;; https://github.com/bbatsov/prelude
(require 'uniquify)
(setq uniquify-buffer-name-style 'forward)
(setq uniquify-separator "/")
(setq uniquify-after-kill-buffer-p t)    ; rename after killing uniquified
(setq uniquify-ignore-buffers-re "^\\*") ; don't muck with special buffers

Volatile Highlights

The package volatile highlights temporarily highlights changes to the buffer associated with certain commands that add blocks of text at once. An example is that if you paste (yank) a block of text, it will be highlighted until you press the next key. This is just a small tweak, but gives a nice bit of visual feedback.

You can install it in the normal way:

;; volatile highlights - temporarily highlight changes from pasting etc
(use-package volatile-highlights
  :config
  (volatile-highlights-mode t))