Month: January 2017

Customise the reply quote string in mu4e

You know the bit of text that appears before the quoted email when you reply to someone? Of course you can customise this in mu4e. By default a quoted reply will be preceded with something like

"On Mon, 30 Jan 2017, Joe Bloggs wrote:"

I wanted to include the time and email address of the sender, so I customised the variable message-citation-line-format as follows

;; customize the reply-quote-string
(setq message-citation-line-format "On %a %d %b %Y at %R, %f wrote:\n")
;; choose to use the formatted string
(setq message-citation-line-function 'message-insert-formatted-citation-line)

which translates to something like this

On Mon 30 Jan 2017 at 19:17, Joe Bloggs <joebloggs@domain.com> wrote:

The formatting options can be found by looking up the help for the variable with C-h v message-citation-line-format.

Sadly, this change broke my function to extract the sender name for my email template. Here is an updated version:

;; function to return first name of email recipients
;; used by yasnippet
;; inspired by
;;http://blog.binchen.org/posts/how-to-use-yasnippets-to-produce-email-templates-in-emacs.html
(defun bjm/mu4e-get-names-for-yasnippet ()
  "Return comma separated string of names for an email"
  (interactive)
  (let ((email-name "") str email-string email-list email-name2 tmpname)
    (save-excursion
      (goto-char (point-min))
      ;; first line in email could be some hidden line containing NO to field
      (setq str (buffer-substring-no-properties (point-min) (point-max))))
    ;; take name from TO field - match series of names
    (when (string-match "^To: \"?\\(.+\\)" str)
      (setq email-string (match-string 1 str)))
    ;;split to list by comma
    (setq email-list (split-string email-string " *, *"))
    ;;loop over emails
    (dolist (tmpstr email-list)
      ;;get first word of email string
      (setq tmpname (car (split-string tmpstr " ")))
      ;;remove whitespace or ""
      (setq tmpname (replace-regexp-in-string "[ \"]" "" tmpname))
      ;;join to string
      (setq email-name
            (concat email-name ", " tmpname)))
    ;;remove initial comma
    (setq email-name (replace-regexp-in-string "^, " "" email-name))

    ;;see if we want to use the name in the FROM field
    ;;get name in FROM field if available, but only if there is only
    ;;one name in TO field
    (if (< (length email-list) 2)
        (when (string-match "^On.+, \\([^ ,\n]+\\).+wrote:$" str)
          (progn
            (setq email-name2 (match-string 1 str))
            ;;prefer name in FROM field if TO field has "@"
            (when (string-match "@" email-name)
              (setq email-name email-name2))
            )))
    email-name))
Advertisement

A shortcut to my favourite org-mode agenda view

As I have mentioned before in my tutorial about todo lists and scheduled tasks in org-mode, my preferred way to view my agenda is to use C-c a n to view a list of my scheduled tasks with unscheduled tasks below that.

I wanted to make a shorter keybinding for this view and I found this advice on how to achieve this. We just need to define a simple helper function like so

;;keybinding for favourite agenda view
;; http://emacs.stackexchange.com/questions/864/how-to-bind-a-key-to-a-specific-agenda-command-list-in-org-mode
(defun org-agenda-show-agenda-and-todo (&optional arg)
  (interactive "P")
  (org-agenda arg "n"))

I then add this to my personal key map

(define-key bjm-map (kbd "a") 'org-agenda-show-agenda-and-todo)

and I can pull up my agenda with C-1 a. You might not want to use the same keybinding as me, but maybe you’ll find the idea helpful.

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