Clickable telephone numbers in mu4e messages
Posted November 04, 2015 at 12:45 PM | categories: emacs | tags:
We recently updated our university phone system to a VoIP system that uses Cisco Jabber. I am excited about that because finally I can make phone calls from Emacs with a little applescript automation! So, spoiler alert, this post mostly only applies to Macs, unless you know how to automate a Jabber client to make calls. How to make the telephone numbers clickable is general though, and could be used to do other things as well.
(defun cisco-call (phone-number) (interactive "sPhone number: ") (do-applescript (format "tell application \"Cisco Jabber\" activate tell application \"System Events\" to keystroke \"n\" using {shift down, command down} tell application \"System Events\" to keystroke \"%s\" tell application \"System Events\" to key code 36 #return end tell" phone-number)))
cisco-call
I would like to go a step further, and make clickable phone numbers in my Emacs buffers. Let's take a look at some options.
1 org-mode phone link
This is a no-brainer approach. We can define an org-mode link that runs the cisco-call function.
(org-add-link-type "phone" (lambda (phone-number) (cisco-call phone-number)))
lambda | (phone-number) | (cisco-call phone-number) |
This makes simple link that just calls the number in the path of the link.
2 Clickable text with button-lock
I have used the button-lock package very often to make clickable text. Here we use it to highlight phone numbers matching a regular expression that seems to match most US numbers. This seems to work great in org-mode buffers.
(require 'rx) (defvar highlight-phone-numbers nil "Button for `highlight-phone-numbers'") (defun highlight-phone-numbers () "Make phone numbers of the following types clickable: (xxx) xxx-xxxx xxx.xxx.xxx xxxxxxxxxx xxx-xxx-xxxx" (interactive) (let ((inhibit-read-only t)) (setq highlight-phone-numbers (button-lock-set-button (rx ;; optional () around area code (optional "(") (= 3 digit) (optional ")") ;; delimiters (or (optional "-") (optional ".") (optional " ")) (= 3 digit) (or (optional "-") (optional ".") (optional " ")) (= 4 digit)) (lambda () (interactive) (cisco-call (get-surrounding-text-with-property 'phone-number))) :face '((:background "Darkolivegreen2") (:underline t)) :help-echo "click to call" :keyboard-binding (kbd "RET") :additional-property 'phone-number)))) (add-hook 'text-mode 'highlight-phone-numbers)
highlight-phone-numbers |
3 Phone numbers in mu4e messages
For some reason, the button-lock package doesn't seem to work in mu4e message buffers, Maybe it is because . The highlight-regexp package does work though, so for these special buffers we use a new approach. We will just put text properties where we want them, and use those properties to make the text clickable.
The messages are in read-only buffers, but we can inhibit that so we can modify the properties. All we need to do is create a little key map as a copy of the existing map, define some keys on it, then search through the buffer adding properties to every phone number we find. I wrote a function that does that, and put that function in a hook to run each time I open a message. Whammo, now I have clickable phone numbers in email! It works pretty well for me.
(defface mu4e-phone-face '((t (:foreground "SteelBlue4" :background "Darkolivegreen2" :underline t))) "Phone number directive face.") (defun mu4e-highlight-phone-numbers () "Make phone numbers clickable in mu4e-view buffers." (interactive) (let ((phone-regex (rx ;; optional () around area code (optional "(") (= 3 digit) (optional ")") ;; delimiters (or (optional "-") (optional ".") (optional " ")) (= 3 digit) (or (optional "-") (optional ".") (optional " ")) (= 4 digit)))) (save-excursion (let ((inhibit-read-only t)) (goto-char (point-min)) (while (re-search-forward phone-regex nil t) (let ((map (copy-keymap mu4e-view-mode-map)) (start (match-beginning 0)) (end (match-end 0))) ;; set file to be clickable to open the source (define-key map [mouse-1] `(lambda () (interactive) (cisco-call ,(match-string 0)))) ;; let letter c also make the call (define-key map "c" `(lambda () (interactive) (cisco-call ,(match-string 0)))) (set-text-properties start end `(local-map, map face mu4e-phone-face mouse-face highlight help-echo "mouse-1: click to call")))))))) (add-hook 'mu4e-view-mode-hook 'mu4e-highlight-phone-numbers)
4 Summary
That works pretty well for me overall. The phone number regex is not perfect, e.g. it makes any 10 digit number clickable, and it doesn't recognize international numbers. I am not sure I can call those through the Jabber client anyway. This is purely convenience for me to easily make calls from emails, or other kinds of documents I might read in Emacs.
I don't use phone calls very often, but an interesting thing might be to open a phone log in org-mode, or open the contact that has that phone number to log that you called them, and provide some notes for them. Alternatively, open a new capture for a phone log that could be refiled later.
Copyright (C) 2015 by John Kitchin. See the License for information about copying.
Org-mode version = 8.2.10