Category Archives: emacs

How I view my google calendar agenda in Emacs

JCS over on Irreal describes a couple of ways of syncing a google calendar with your org-mode agenda. I prefer to keep my google calendar separate from my agenda, as I use the latter to track tasks rather than appointments. I still want to see my google calendar agenda in Emacs though so I have a fairly simple work around.

I use gcalcli to access my google calendar from the command line, and run it as a cron job using gcalcli agenda and redirecting the output to a file. Then in Emacs I have a simple function to display the contents of that file.

Firstly though, the output of gcalcli contains ansi colour codes to colour-code the calendars in the agenda. Emacs won’t display these colours unless we tell it to. We use the following code to define a function display-ansi-colors to do this for us (source):

;; define function to display ansi colours for a buffer
;; http://stackoverflow.com/questions/23378271/how-do-i-display-ansi-color-codes-in-emacs-for-any-mode
(require 'ansi-color)
(defun display-ansi-colors ()
  (interactive)
  (ansi-color-apply-on-region (point-min) (point-max)))

Now, here is the code to display the agenda:

(defun bjm/open-gcal-agenda ()
  "Open my google calendar agenda file. The agenda is displayed in the buffer *gcal*."
  (interactive)
  ;; set name of calendar buffer and location of file containing my agenda
  (let ((tmp-buff-name "*gcal*") (cal-file (expand-file-name "/homeb/bjm/tmp/gcal")))
    ;; switch to calendar buffer
    (switch-to-buffer tmp-buff-name)
    ;; turn off read only to overwrite if buffer exists
    (read-only-mode -1)
    ;; clear buffer
    (erase-buffer)
    ;; insert agenda file
    (insert-file-contents cal-file)
    ;; turn on colours
    (display-ansi-colors)
    ;; turn on special mode
    (special-mode)
    ;; turn off line wrapping
    (visual-line-mode -1)))

There are a couple of points worth noting here…

Firstly, I could easily just call gcalcli on a timer in Emacs, but I use the agenda file for other things so it is helpful to do that externally.

Secondly, after inserting the contents of the agenda file to the buffer I set it to special mode, which is basically a read only mode with some common key bindings, and is useful for buffers that are not associated with editing files. Related to this, I call the buffer *gcal*, which follows the convention that buffers not associated with files have names starting and ending with *.

Now by calling my bjm/open-gcal-agenda function, I see something like this:

gcal-agenda.png

Use your digits and a personal key map for super shortcuts

Lots of commands in Emacs behave differently if called with a prefix argument C-u. For example, by default C-s runs the command isearch which searches for text as you type. If you use a prefix argument C-u C-s then isearch searches with regular expressions instead of literal string text.

You can also pass numerical arguments to commands, which for many simple commands will cause the command to repeat that number of times, so for example C-u 3 C-p passes the argument 3 to the command C-p which then runs previous-line three times. What is more, you can also pass these numerical arguments with the form C-3 C-p, where C-3 is equivalent to C-u 3. Of course this works for any digit 0-9, not just 3!

By default, Emacs uses the combinations C-3, M-3, C-M-3 all for this purpose, again for all digits 0-9. The thing is, I simply never use them in this way, and this is a huge waste of really useful keyboard shortcuts you could be using for other things.

To reclaim them, add the following to your emacs config file, with credit to this reddit post:

;; unset C- and M- digit keys
(dotimes (n 10)
  (global-unset-key (kbd (format "C-%d" n)))
  (global-unset-key (kbd (format "M-%d" n)))
  )

You can then still access the digit prefixes with C-M-3 and similar but you now have all the C- and M- digit combinations to play with.

One great way to make use of this is to set up your own key map using one of these newly freed-up combinations. I set C-1 as the prefix key for my own map:

;; set up my own map
(define-prefix-command 'bjm-map)
(global-set-key (kbd "C-1") 'bjm-map)

Then I assign some keys to that map, for example

(define-key bjm-map (kbd "m") 'mu4e)
(define-key bjm-map (kbd "g") 'bjm/open-gcal-agenda)

Now I can use C-1 m to open mu4e for my email, and C-1 g to view my google calendar.

Resize your windows to the golden ratio

If you prefer to use a single large emacs frame with multiple windows inside, you might like the golden ratio package. This automatically resizes your windows so that the window containing the point is the largest (size determined by the mathematical golden ratio). This means that the window you are working in is nice and large but you can still see what is going on in the other windows.

Install the package with the following:

(use-package golden-ratio
  :ensure t
  :diminish golden-ratio-mode
  :init
  (golden-ratio-mode 1))

Whizz between windows with windmove

First up, a reminder: in Emacs’ terminology the thing we usually call a window in other apps (the main display of an app with the menus etc at the top) is called a frame, and the individual panes within that (usually displaying different buffers side by side) are called windows.

Once you have been using Emacs for a while, you might find it more efficient to have a single large frame with several windows open inside displaying different buffers. It is then really easy to move between them using the built-in library windmove.

Activate windmove by adding the following to your emacs config file:

(use-package windmove
  ;; :defer 4
  :ensure t
  :config
  ;; use command key on Mac
  (windmove-default-keybindings 'super)
  ;; wrap around at edges
  (setq windmove-wrap-around t))

Now you can hold down the super key (Command on a Mac) and press arrow keys to move to windows in any direction. Note that the default key is shift plus arrow, but this conflicts rather painfully with org-mode, so I prefer super.

Sorting an org-mode table

You can quickly sort tables in org-mode by using C-c ^ with the point inside a table. You’ll be prompted for a sorting type, where you can choose e.g. a for alphabetic or n for numeric. You can use capital letter versions of these options to reverse the sort.

The table is sorted based on the column that the point is in, and from the documentation:

The range of lines is the range between the nearest horizontal separator lines, or the entire table of no such lines exist.

Use org-mode tables and structures in emails and elsewhere

I love the way that org-mode allows you to add simple clean structures to your text, with lists and tables. You can get some of that functionality in other modes by using orgstruct-mode and orgtbl-mode, which are part of org-mode.

Enable these minor modes in any major mode for one-off use with M-x orgstruct++-mode or M-x orgtbl-mode and you can use the normal org-mode commands to create lists and tables. I find this especially useful in emails, so I use this code in my emacs config file to automatically enable these for message-mode

;; use org structures and tables in message mode
(add-hook 'message-mode-hook 'turn-on-orgtbl)
(add-hook 'message-mode-hook 'turn-on-orgstruct++)

Cancel all timers calling some function

This is a bit of a niche post but I recently found I had accidentally started a bunch of duplicate timers all running the same function. I hadn’t recorded the timer objects for them so couldn’t use cancel-timer to kill them. After a bit of searching I discovered the function cancel-function-timers which will cancel all timers that call a particular function.

Not something you’ll be using every day, but might be useful one day!

A persistent scratch buffer

The *scratch* buffer is useful for dumping temporary bits of text, or trying out bits of lisp code. By default the contents are not saved, but it can be handy to have the scratch buffer saved and restored when you start a new Emacs session. This is easy with the persistent-scratch package, just add the following to your emacs config file:

;; persistent-scratch
(use-package persistent-scratch
  :config
  (persistent-scratch-setup-default))