+;;; spray.el --- a speed reading mode
+
+;; Copyright (C) 2014 Ian Kelling <ian@iankelling.org>
+
+;; 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
+
+;; Maintainer: Ian Kelling <ian@iankelling.org>
+;; Author: Ian Kelling <ian@iankelling.org>
+;; Author: zk_phi
+;; Created: 18 Jun 2014
+;; Version: 0.0.2
+;; URL: https://github.com/ian-kelling/spray
+;; Mailing list: https://lists.iankelling.org/listinfo/spray
+;; Keywords: convenience
+
+;;; Commentary:
+
+;; For speed reading, or just more enjoyable reading. Narrows the buffer to show
+;; one word at a time. Adjust speed / pause as needed.
+;;
+;; Download from Melpa or put this script into a "load-path"ed directory, and
+;; load it in your init file:
+
+;; (require 'spray)
+
+;; Then you may run spray with "M-x spray-mode". Binding some keys may
+;; also be useful.
+
+;; (global-set-key (kbd "<f6>") 'spray-mode)
+
+;; In spray-mode buffers, following commands are available.
+
+;; - =spray-start/stop= (SPC) ::
+;; pause or resume spraying
+
+;; - =spray-backward-word= (h, <left>) ::
+;; pause and back to the last word
+
+;; - =spray-forward-word= (l, <right>) ::
+;; inverse of =spray-backward-word=
+
+;; - =spray-faster= (f) ::
+;; increases speed
+
+;; - =spray-slower= (s) ::
+;; decreases speed
+
+;; - =spray-quit= (q, <return>) ::
+;; quit =spray-mode=
+
+;; You may customize spray by modifying following items:
+
+;; - [Variable] spray-wpm
+;; - [Variable] spray-height
+;; - [Variable] spray-margin-top
+;; - [Variable] spray-margin-left
+;; - [Variable] spray-ramp
+;; - [Keymap] spray-mode-map
+;; - [Face] spray-base-face
+;; - [Face] spray-accent-face
+
+;; Readme.org from the package repository has some additional information:
+;; A gif screencast.
+;; Algorithm specification.
+;; Comparison with similar projects.
+
+;;; Known bugs:
+
+;; repeated words are indistinguishable, for example
+;; "going, going, gone" reads like going, gone, with a slight delay.
+;;
+;; sentences (like this) should trigger a pause for ( and )
+
+;;; Change Log:
+
+;; 0.0.0 test release
+;; 0.0.1 add spray-set-margins
+;; 0.0.2 margin options, speed control, better quit
+
+;;; Code:
+
+(require 'face-remap)
+
+;; * customizable vars
+
+(defcustom spray-wpm 400
+ "Words per minute"
+ :group 'spray
+ :type 'integer)
+
+(defcustom spray-save-point nil
+ "Set to true and then exiting spray mode will restore the point"
+ :group 'spray
+ :type 'boolean)
+
+
+(defcustom spray-height 400
+ "Height of characters"
+ :group 'spray
+ :type 'integer)
+
+(defcustom spray-margin-top 1
+ "Character margin at top of buffer. Characters are as big as
+ spray text characters."
+ :group 'spray
+ :type 'integer)
+
+(defcustom spray-margin-left 1
+ "Character margin at left of buffer. Characters are as big as
+ spray text characters."
+ :group 'spray
+ :type 'integer)
+
+(defcustom spray-ramp 2
+ "Initial words before ramping up to full speed. Pauses for
+this multiple of wpm on the first word,
+decreasing by one for each subsequent word."
+ :group 'spray
+ :type 'integer)
+
+(defcustom spray-unsupported-minor-modes
+ '(buffer-face-mode smartparens-mode highlight-symbol-mode
+ column-number-mode)
+ "Minor modes to toggle off when in spray mode."
+ :group 'spray
+ :type '(list symbol))
+
+
+;; * faces
+
+(defface spray-base-face
+ '((t (:inherit default)))
+ "Face for non-accent characters."
+ :group 'spray)
+
+(defface spray-accent-face
+ '((t (:foreground "red" :inherit spray-base-face)))
+ "Face for accent character."
+ :group 'spray)
+
+
+;; keymap
+
+(defvar spray-mode-map
+ (let ((km (make-sparse-keymap)))
+ (define-key km (kbd "SPC") 'spray-start/stop)
+ (define-key km (kbd "h") 'spray-backward-word)
+ (define-key km (kbd "l") 'spray-forward-word)
+ (define-key km (kbd "<left>") 'spray-backward-word)
+ (define-key km (kbd "<right>") 'spray-forward-word)
+ (define-key km (kbd "f") 'spray-faster)
+ (define-key km (kbd "s") 'spray-slower)
+ (define-key km (kbd "q") 'spray-quit)
+ (define-key km (kbd "<return>") 'spray-quit)
+ (define-key km [remap forward-char] 'spray-forward-word)
+ (define-key km [remap backward-char] 'spray-backward-word)
+ (define-key km [remap forward-word] 'spray-forward-word)
+ (define-key km [remap backward-word] 'spray-backward-word)
+ (define-key km [remap keyboard-quit] 'spray-quit)
+ km)
+ "keymap for spray-mode buffers")
+
+
+;; * internal vars
+
+(defvar spray--margin-string "")