最近对 EmacsScript 颇有兴趣,刚好翻看 Emacs Lisp Manual 的时候看到 Desktop Notifications 这一章,于是突发奇想,尝试实现一个 Emacs 版的 notify-send.
notify-send是一个可以用来发送桌面通知的命令, 我经常在脚本中用它来通知一些值得关注的消息.
简单起见,我们这次只实现 notify-send 常用的那几个选项:
| -t | 设置超时时间 |
| -u | 设置通知级别 |
| -i | 设置显示图标 |
若Emacs编译时开启了D-Bus支持,则通过加载`notifications'库,Emacs可以给某些操作系统发送"通知"
(notifications-notify &rest params)
通过D-Bus,使用Freedesktop notification protocol发送通知,该函数返回一个整数作为通知的id
参数params可以是如下keyword参数
(defun my-on-action-function (id key)
(message "Message %d, key \"%s\" pressed" id key))
;; => my-on-action-function
(defun my-on-close-function (id reason)
(message "Message %d, closed due to \"%s\"" id reason))
;; => my-on-close-function
(notifications-notify
:title "Title"
:body "This is <b>important</b>."
:actions '("Confirm" "I agree" "Refuse" "I disagree")
:on-action 'my-on-action-function
:on-close 'my-on-close-function)
;; => 22
这时会弹出一个message window. 按下 "I agree"
;; => Message 22, key "Confirm" pressed
;; Message 22, closed due to "dismissed"
有了 notifications 库,实现起来就异常的简单了,基本上只需要调用 notifications-notify 这个函数就 OK 了。
首先是固定的起手式:
#!/bin/sh
":"; exec emacs --quick --script "$0" -- "$@" # -*- mode: emacs-lisp; lexical-binding: t; -*-
(pop command-line-args-left)
使用 notifications-notify 前当然是要先加载notifications库了:
(require 'notifications)
现在开始需要将传递给命令行的参数转换成传递给 notifications-notify 函数的参数.
(defvar notify-send-args nil
"存放传递给notification-notify函数的参数")
(defvar notify-send-map '(("-t" . :timeout)
("-u" . :urgency)
("-i" . :app-icon))
"命令行参数与notifications-notify参数的对应关系")
;; 将命令行参数转换成对应的函数参数
(catch :DONE
(while command-line-args-left
(let ((arg (pop command-line-args-left)))
(cond ((assoc arg notify-send-map)
(let ((arg (cdr (assoc arg notify-send-map)))
(val (pop command-line-args-left)))
(when (eq arg :timeout)
(setq val (string-to-number val)))
(setq notify-send-args `(,arg ,val ,@notify-send-args) )))
((string= arg "--")
(let ((title (pop command-line-args-left))
(body (pop command-line-args-left)))
(setq notify-send-args `(:title ,title :body ,body ,@notify-send-args))
(throw :DONE :DONE)))
(t
(let ((title arg)
(body (pop command-line-args-left)))
(setq notify-send-args `(:title ,title :body ,body ,@notify-send-args))
(throw :DONE :DONE)))))))
;; 调用notifications-notify发送消息
(apply #'notifications-notify notify-send-args)
最后将 command-line-args-left 清空,防止报错。
(setq command-line-args-left nil)
