Commit b78daa0f authored by Dave Cooper's avatar Dave Cooper

added new emacs libraries

parent 7905285b
Alert is a Growl-workalike for Emacs which uses a common notification
interface and multiple, selectable "styles", whose use is fully customizable
by the user.
# For module writers
Just use =alert= instead of =message= as follows:
(require 'alert)
;; This is the most basic form usage
(alert "This is an alert")
;; You can adjust the severity for more important messages
(alert "This is an alert" :severity 'high)
;; Or decrease it for purely informative ones
(alert "This is an alert" :severity 'trivial)
;; Alerts can have optional titles. Otherwise, the title is the
;; buffer-name of the (current-buffer) where the alert originated.
(alert "This is an alert" :title "My Alert")
;; Further, alerts can have categories. This allows users to
;; selectively filter on them.
(alert "This is an alert" :title "My Alert" :category 'debug)
# For users
For the user, there are several variables to control when and how alerts
are presented. By default, they appear in the minibuffer much the same
as a normal Emacs message. But there are many more possibilities:
- =alert-fade-time= ::
Normally alerts disappear after this many seconds, if the style
supports it. The default is 5 seconds.
- =alert-default-style= ::
Pick the style to use if no other config rule matches. The
default is =message=, but =growl= works well too.
- =alert-reveal-idle-time= ::
If a config rule choose to match on =idle=, this is how many
seconds idle the user has to be. Defaults to 5 so that users
don't miss any alerts, but 120 is also good.
- =alert-persist-idle-time= ::
After this many idle seconds, alerts will become sticky, and not
fade away more. The default is 15 minutes.
- =alert-log-messages= ::
By default, all alerts are logged to *Alerts* (and to *Messages*,
if the =message= style is being used). Set to nil to disable.
- =alert-hide-all-notifications= ::
Want alerts off entirely? They still get logged, however, unless
you've turned that off too.
- =alert-user-configuration= ::
This variable lets you control exactly how and when a particular
alert, a class of alerts, or all alerts, get reported -- or if at
all. Use this to make some alerts use Growl, while others are
completely silent.
# Programmatically adding rules
Users can also programmatically add configuration rules, in addition to
customizing =alert-user-configuration=. Here is one that the author
currently uses with ERC, so that the fringe gets colored whenever people
chat on BitlBee:
(alert-add-rule :status '(buried visible idle)
:severity '(moderate high urgent)
:mode 'erc-mode
:predicate
#'(lambda (info)
(string-match (concat "\\`[^&].*@BitlBee\\'")
(erc-format-target-and/or-network)))
:persistent
#'(lambda (info)
;; If the buffer is buried, or the user has been
;; idle for `alert-reveal-idle-time' seconds,
;; make this alert persistent. Normally, alerts
;; become persistent after
;; `alert-persist-idle-time' seconds.
(memq (plist-get info :status) '(buried idle)))
:style 'fringe
:continue t)
# Builtin alert styles
There are several builtin styles, and it is trivial to create new ones.
The builtins are:
| message | Uses the Emacs =message= facility |
| log | Logs the alert text to *Alerts*, with a timestamp |
| ignore | Ignores the alert entirely |
| fringe | Changes the current frame's fringe background color |
| growl | Uses Growl on OS X, if growlnotify is on the PATH |
# Defining new styles
To create a new style, you need to at least write a "notifier", which is
a function that receives the details of the alert. These details are
given in a plist which uses various keyword to identify the parts of the
alert. Here is a prototypical style definition:
(alert-define-style 'style-name :title "My Style's title"
:notifier
(lambda (info)
;; The message text is :message
(plist-get info :message)
;; The :title of the alert
(plist-get info :title)
;; The :category of the alert
(plist-get info :category)
;; The major-mode this alert relates to
(plist-get info :mode)
;; The buffer the alert relates to
(plist-get info :buffer)
;; Severity of the alert. It is one of:
;; `urgent'
;; `high'
;; `moderate'
;; `normal'
;; `low'
;; `trivial'
(plist-get info :severity)
;; Whether this alert should persist, or fade away
(plist-get info :persistent)
;; Data which was passed to `alert'. Can be
;; anything.
(plist-get info :data))
;; Removers are optional. Their job is to remove
;; the visual or auditory effect of the alert.
:remover
(lambda (info)
;; It is the same property list that was passed to
;; the notifier function.
))
This diff is collapsed.
This diff is collapsed.
Org-Pomodoro
============
This adds very basic support for
[Pomodoro technique](http://www.pomodorotechnique.com/)
in Emacs' org-mode.
With default customs:
You can start a pomodoro for the task at point or select one of the
last tasks that you clocked time for. Each clocked-in pomodoro
starts a timer of 25 minutes and after each pomodoro a break timer of
5 minutes is started automatically. Every 4 breaks a long break is
started with 20 minutes. All values are customizable.
Installation
============
Install from MELPA:
* Add MELPA to your EMACS installation:
(add-to-list 'package-archives
'("melpa" . "http://melpa.milkbox.net/packages/") t)
* Install the package via `M-x package-install RET org-pomodoro`
Usage
=====
1. Move point to a task as you would do with `org-clock-in`.
Call `org-pomodoro` the task will be clocked-in.
2. When there's time for break, the task will be `org-clock-out`'ed
3. If you call `org-pomodoro` during a pomodoro, you'll be asked to reset
a pomodoro.
4. If you call `org-pomodoro` outside org-mode, you'll be presented
with list of recent tasks, as `C-u org-clock-in` would.
License
=======
This file is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
;; -*- lexical-binding: t; -*-
;;; org-pomodoro-pidgin.el --- Integrate org-pomodoro and Pidgin
;;
;; Copyright (C) 2013 Damien Cassou
;;
;; Author: Damien Cassou <damien.cassou@gmail.com>
;; Created: 2013-07-11
;; Keywords: emacs package elisp pidgin pomodoro org-mode
;;
;; This file is NOT part of GNU Emacs.
;;
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation; either version 2, or (at
;; your option) any later version.
;;
;; This program is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program ; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;
;;; commentary:
;;
;; Update Pidgin status as the Pomodoro progresses.
;;
;; (require 'org-pomodoro-pidgin)
;;
;;; code:
;;
;; The following code uses the "org-pompid" prefix for all "private"
;; functions (and an addition dash "-") and the "org-pomodoro-pidgin"
;; prefix for all "public" functions.
(require 'org-pomodoro)
(defgroup org-pomodoro-pidgin nil
"Customization group for the Pidgin integration with
org-pomodoro."
:group 'org-pomodoro)
(defcustom org-pomodoro-pidgin-busy-status
"Pomodoro ends at %s"
"Status message when a pomodoro is in progress.
The string will be passed to `format' with the time when pomodoro
ends."
:group 'org-pomodoro-pidgin)
(defcustom org-pomodoro-pidgin-break-status
"Available"
"Status message when a pomodoro is in progress."
:group 'org-pomodoro-pidgin)
(defun org-pompid--status-type-to-id (type)
"Convert the symbol TYPE to the correspond int32.
https://developer.pidgin.im/wiki/DbusHowto#CallingPidginmethods."
(case type
(offline 1)
(available 2)
(unavailable 3)
(invisible 4)
(away 5)
(mobile 7)
(tune 8)))
(defun org-pompid--call-method (method handler &rest args)
"Call METHOD with D-Bus and execute HANDLER upon answer.
ARGS lists additional parameters for METHOD."
(when
(member "im.pidgin.purple.PurpleService" (dbus-list-known-names :session))
(apply #'dbus-call-method-asynchronously
:session
"im.pidgin.purple.PurpleService"
"/im/pidgin/purple/PurpleObject"
"im.pidgin.purple.PurpleInterface"
method
handler
args)))
(defun org-pompid--set-status-message (status message)
"Update STATUS with the MESSAGE."
(org-pompid--call-method
"PurpleSavedstatusSetMessage"
nil
:int32 status
message))
(defun org-pompid--new-transient-status (type handler)
"Create a new status of TYPE and execute HANDLER when created."
(org-pompid--call-method
"PurpleSavedstatusNew"
handler
""
:int32 (org-pompid--status-type-to-id type)))
(defun org-pompid--activate (status)
"Make STATUS the current one in Piding."
(org-pompid--call-method
"PurpleSavedstatusActivate"
nil
:int32 status))
(defun org-pompid--change-status-message (type message)
"Create a new status of TYPE with MESSAGE.
TYPE must be valid for `org-pompid--status-type-to-id'."
(org-pompid--new-transient-status
type
(lambda (status)
(org-pompid--set-status-message status message)
(org-pompid--activate status))))
(defun org-pompid--format-message (message)
"Replace the %s in MESSAGE with the time when pomodoro ends."
(format
message
(format-time-string
"%H:%M"
(time-add (current-time) (seconds-to-time org-pomodoro-countdown)))))
(add-hook
'org-pomodoro-started-hook
(lambda ()
(org-pompid--change-status-message
'unavailable
(org-pompid--format-message org-pomodoro-pidgin-busy-status))))
(add-hook
'org-pomodoro-finished-hook
(lambda ()
(org-pompid--change-status-message
'available
org-pomodoro-pidgin-break-status)))
(add-hook
'org-pomodoro-killed-hook
(lambda ()
(org-pompid--change-status-message
'available
org-pomodoro-pidgin-break-status)))
(provide 'org-pomodoro-pidgin)
;;; org-pomodoro-pidgin.el ends here
;;; org-pomodoro-tests.el --- Org-pomodoro tests
;;; Commentary:
;; All tests for org-pomodoro.el.
;;; Code:
(ert-deftest org-pomodoro-expires-when-last-clockin-too-old ()
"Test the return value is true when org-pomodoro-last-clock-in is too old."
(let ((org-pomodoro-last-clock-in '(0 120 0 0))
(org-pomodoro-expiry-time 120))
(should (equal t (org-pomodoro-expires-p)))))
(ert-deftest org-pomodoro-expires-when-last-clockin-is-new ()
"Test the return value is false when org-pomodoro-last-clock-in is new."
(let ((org-pomodoro-last-clock-in (current-time))
(org-pomodoro-expiry-time 120))
(should (equal nil (org-pomodoro-expires-p)))))
;;; org-pomodoro-tests.el ends here
;;; org-pomodoro.el --- Pomodoro implementation for org-mode.
;; Author: Arthur Leonard Andersen <leoc.git@gmail.com>, Marcin Koziej <marcin at lolownia dot org>
;; Created: May 10, 2013
;; Version: 1.3.1
;; Package-Requires: ((alert "0.5.10"))
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;; Org-pomodoro introduces an easy way to clock time in org-mode with
;; the pomodoro technique. You can clock into tasks with starting a
;; pomodoro time automatically. Each finished pomodoro is followed by
;; a break timer. If you completed 4 pomodoros in a row the break is
;; longer that the shorter break between each pomodoro.
;;
;; For a full explanation of the pomodoro technique, have a look at:
;; http://www.pomodorotechnique.com
;;; Code:
(require 'timer)
(require 'org)
(require 'org-clock)
(require 'org-timer)
(require 'alert)
;;; Custom Variables
(defgroup org-pomodoro nil
"Org pomodoro customization"
:tag "Org Pomodoro"
:group 'org-progress)
(defcustom org-pomodoro-long-break-frequency 4
"The maximum number of pomodoros until a long break is started."
:group 'org-pomodoro
:type 'integer)
(defcustom org-pomodoro-play-sounds t
"Determines whether sounds are played or not."
:group 'org-pomodoro
:type 'boolean)
(defcustom org-pomodoro-play-ticking-sounds nil
"Determines whether ticking clock sounds are played or not."
:group 'org-pomodoro
:type 'boolean)
;; Pomodoro Values
(defcustom org-pomodoro-length 25
"The length of a pomodoro in minutes."
:group 'org-pomodoro
:type 'integer)
(defcustom org-pomodoro-time-format "%.2m:%.2s"
"Defines the format of the time representation in the modeline."
:group 'org-pomodoro
:type 'boolean)
(defcustom org-pomodoro-format "Pomodoro~%s"
"The format of the mode line string during a long break."
:group 'org-pomodoro
:type 'string)
(defcustom org-pomodoro-ticking-sound (when load-file-name
(concat (file-name-directory load-file-name) "resources/tick.wav"))
"The path to a sound file that´s to be played while a pomodoro is running."
:group 'org-pomodoro
:type 'file)
(defcustom org-pomodoro-sound (when load-file-name
(concat (file-name-directory load-file-name) "resources/bell.wav"))
"The path to a sound file that´s to be played when a pomodoro was finished."
:group 'org-pomodoro
:type 'file)
(defcustom org-pomodoro-killed-sound nil
"The path to a sound file, that´s to be played when a pomodoro is killed."
:group 'org-pomodoro
:type 'file)
(defcustom org-pomodoro-expiry-time 120
"The time in minutes for which a pomodoro group is valid.
If you do not clock in for this period of time you will be prompted
whether to reset the pomodoro count next time you call `org-pomodoro'."
:group 'org-pomodoro
:type 'integer)
;; Break Values
(defcustom org-pomodoro-short-break-length 5
"The length of a break in minutes."
:group 'org-pomodoro
:type 'integer)
(defcustom org-pomodoro-short-break-format "Short Break~%s"
"The format of the mode line string during a long break."
:group 'org-pomodoro
:type 'string)
(defcustom org-pomodoro-short-break-sound (when load-file-name
(concat (file-name-directory load-file-name)
"resources/bell.wav"))
"The path to a sound file that´s to be played when a break was finished."
:group 'org-pomodoro
:type 'file)
(defcustom org-pomodoro-long-break-length 20
"The length of a long break in minutes."
:group 'org-pomodoro
:type 'integer)
(defcustom org-pomodoro-long-break-format "Long Break~%s"
"The format of the mode line string during a long break."
:group 'org-pomodoro
:type 'string)
(defcustom org-pomodoro-long-break-sound (when load-file-name
(concat (file-name-directory load-file-name)
"resources/bell_multiple.wav"))
"The path to a sound file that´s to be played when a long break is finished."
:group 'org-pomodoro
:type 'file)
(defcustom org-pomodoro-audio-player (or (executable-find "aplay")
(executable-find "afplay"))
"Music player used to play sounds."
:group 'org-pomodoro
:type 'string)
;; Hooks
(defvar org-pomodoro-started-hook nil
"Hooks run when a pomodoro is started.")
(defvar org-pomodoro-finished-hook nil
"Hooks run when a pomodoro is finished.")
(defvar org-pomodoro-killed-hook nil
"Hooks run when a pomodoro is killed.")
(defvar org-pomodoro-break-finished-hook nil
"Hook run after any break has finished.
Run before a break's specific hook.")
(defvar org-pomodoro-long-break-finished-hook nil
"Hooks run when a long break is finished.")
(defvar org-pomodoro-short-break-finished-hook nil
"Hooks run when short break is finished.")
;; Faces
(defface org-pomodoro-mode-line
'((t (:foreground "tomato1")))
"Face of a pomodoro in the modeline."
:group 'faces)
(defface org-pomodoro-mode-line-break
'((t (:foreground "#2aa198")))
"Face of a pomodoro break in the modeline ."
:group 'faces)
;; Temporary Variables
(defvar org-pomodoro-mode-line "")
(put 'org-pomodoro-mode-line 'risky-local-variable t)
(defvar org-pomodoro-timer nil
"The timer while a pomodoro or a break.")
(defvar org-pomodoro-countdown 0
"The actual countdown value for a phase in seconds.")
(defvar org-pomodoro-state :none
"The current state of `org-pomodoro`.
It changes to :pomodoro when starting a pomodoro and to :longbreak
or :break when starting a break.")
(defvar org-pomodoro-count 0
"The number of pomodoros since the last long break.")
(defvar org-pomodoro-last-clock-in nil
"The last time the pomodoro was set.")
;;; Internal
;; Helper Functions
(defun org-pomodoro-active-p ()
"Retrieve whether org-pomodoro is active or not."
(not (eq org-pomodoro-state :none)))
(defun org-pomodoro-expires-p ()
"Return true when the last clock-in was more than `org-pomodoro-expiry-time`."
(let* ((current-time-secs (nth 1 (current-time)))
(last-clock-in-secs (nth 1 org-pomodoro-last-clock-in))
(delta-minutes (/ (- current-time-secs last-clock-in-secs) 60)))
(< org-pomodoro-expiry-time delta-minutes)))
(defun org-pomodoro-play-sound (type)
"Play an audio file specified by TYPE (:pomodoro, :short-break, :long-break)."
(let ((sound (cl-case type
(:pomodoro org-pomodoro-sound)
(:short-break org-pomodoro-short-break-sound)
(:long-break org-pomodoro-long-break-sound)
(t (error "Unknown org-pomodoro sound: %S" type)))))
(when (and org-pomodoro-play-sounds sound org-pomodoro-audio-player)
(call-process org-pomodoro-audio-player nil 0 nil (expand-file-name sound)))))
(defun org-pomodoro-format-seconds ()
"Format the countdown with the format specified in org-pomodoro-time-format."
(format-seconds org-pomodoro-time-format org-pomodoro-countdown))
(defun org-pomodoro-update-mode-line ()
"Set the modeline accordingly to the current state."
(let ((s (cl-case org-pomodoro-state
(:pomodoro
(propertize org-pomodoro-format 'face 'org-pomodoro-mode-line))
(:short-break
(propertize org-pomodoro-short-break-format
'face 'org-pomodoro-mode-line-break))
(:long-break
(propertize org-pomodoro-long-break-format
'face 'org-pomodoro-mode-line-break)))))
(setq org-pomodoro-mode-line
(if (org-pomodoro-active-p)
(list "[" (format s (org-pomodoro-format-seconds)) "] ")
nil)))
(force-mode-line-update))
(defun org-pomodoro-kill ()
"Kill the current timer, reset the phase and update the modeline."
(org-pomodoro-reset)
(org-pomodoro-killed))
(defun org-pomodoro-tick ()
"A callback that is invoked by the running timer each second.
It checks whether we reached the duration of the current phase, when 't it
invokes the handlers for finishing."
(if (and (equal org-pomodoro-state :none) org-pomodoro-timer)
(org-pomodoro-reset)
(progn
(setq org-pomodoro-countdown (- org-pomodoro-countdown 1))
(when (< org-pomodoro-countdown 1)
(cl-case org-pomodoro-state
(:pomodoro (org-pomodoro-finished))
(:short-break (org-pomodoro-short-break-finished))
(:long-break (org-pomodoro-long-break-finished))))))
(when (and org-pomodoro-play-sounds
org-pomodoro-play-ticking-sounds
org-pomodoro-audio-player
org-pomodoro-ticking-sound
(eq :pomodoro org-pomodoro-state))
(call-process org-pomodoro-audio-player nil 0 nil
(expand-file-name org-pomodoro-ticking-sound)))
(org-pomodoro-update-mode-line))
(defun org-pomodoro-start (&optional state)
"Start the `org-pomodoro` timer.
The argument STATE is optional. The default state is `:pomodoro`."
(when org-pomodoro-timer (cancel-timer org-pomodoro-timer))
;; add the org-pomodoro-mode-line to the global-mode-string
(unless global-mode-string (setq global-mode-string '("")))
(unless (memq 'org-pomodoro-mode-line