elisp/stack-mode/checklist.el
author Luke Hoersten <luke@hoersten.org>
Wed, 16 Sep 2015 16:53:07 -0500
changeset 80 e848f1863d6b
permissions -rw-r--r--
Trying stack-ide-mode.

;;; checklist.el --- Simple checklist UI functionality

;; Copyright (c) 2015 Chris Done. All rights reserved.

;; 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 this program.  If not, see <http://www.gnu.org/licenses/>.

;;; Code:

(defvar checklist-read-checklist-result nil)
(make-variable-buffer-local 'checklist-read-checklist-result)

(defun checklist-read-checklist (prompt choices)
  "Prompt with PROMPT to choose one or more from the list of CHOICES."
  (switch-to-buffer (generate-new-buffer-name "checklist"))
  (let ((inhibit-read-only t))
    (special-mode)
    (setq buffer-read-only t)
    (setq cursor-type 'box)
    (insert (concat prompt "\n\n"))
    (use-local-map (copy-keymap special-mode-map))
    (local-set-key "n" 'next-line)
    (local-set-key "p" 'previous-line)
    (local-set-key (kbd "RET") 'checklist-checklist-choose)
    (local-set-key (kbd "SPC") 'checklist-checklist-choose)
    (local-set-key (kbd "C-c C-c") 'checklist-checklist-done)
    (save-excursion
      (cl-loop for choice in choices
               do (insert (propertize (concat "[ ] " (cdr choice) "\n")
                                      'checklist-check-item (car choice))))
      (insert "\n")
      (insert "Hit " (propertize "C-c C-c" 'face 'bold) " to finish."))
    (add-hook 'post-command-hook #'checklist-highlight-section t t)
    (setq checklist-read-checklist-result nil)
    (recursive-edit)
    (let ((result  checklist-read-checklist-result)
          (kill-buffer-query-functions nil))
      (kill-buffer (current-buffer))
      result)))

(defun checklist-checklist-done ()
  "Done with the checklist, return the result."
  (interactive)
  (throw 'exit nil))

(defun checklist-highlight-section ()
  "Highlight the item at point."
  (remove-overlays)
  (when (get-text-property (point) 'checklist-check-item)
    (let ((o (make-overlay (line-beginning-position)
                           (1+ (line-end-position)))))
      (overlay-put o 'face 'secondary-selection))))

(defun checklist-checklist-choose ()
  "Choose the current item at point."
  (interactive)
  (let ((inhibit-read-only t)
        (checked (get-text-property (point) 'checklist-item-checked)))
    (when (get-text-property (point) 'checklist-check-item)
      (if checked
          (setq checklist-read-checklist-result
                (delete (get-text-property (point) 'checklist-check-item)
                        checklist-read-checklist-result))
          (add-to-list 'checklist-read-checklist-result
                       (get-text-property (point) 'checklist-check-item)
                       t))
      (save-excursion (goto-char (line-beginning-position))
                      (delete-region (line-beginning-position)
                                     (+ (line-beginning-position) (length "[ ]")))
                      (if checked
                          (insert "[ ]")
                        (insert "[x]")))
      (put-text-property (line-beginning-position)
                         (1+ (line-end-position))
                         'checklist-item-checked (not checked))
      (put-text-property (line-beginning-position)
                         (1+ (line-end-position))
                         'face (if checked nil 'bold))
      (put-text-property (line-beginning-position)
                         (1+ (line-end-position))
                         'checklist-check-item t)
      (checklist-highlight-section))))

(provide 'checklist)