Init-Files/.emacs.d/elpa/indent-guide-1.0.1/indent-guide.el
2013-07-20 22:21:29 -07:00

180 lines
5.9 KiB
EmacsLisp

;;; indent-guide.el --- show vertical lines to guide indentation
;; Copyright (C) 2013 zk_phi
;; 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 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, write to the Free Software
;; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
;; Author: zk_phi
;; URL: http://hins11.yu-yake.com/
;; Version: 1.0.1
;;; Commentary:
;; Require this script
;;
;; (require 'indent-guide)
;;
;; then indent-guide appears automatically.
;; To set delay until the indent-guide appears, use function
;; "indent-guide-set-delay".
;;
;; (indent-guide-set-delay 1.0)
;;
;; Now indent-guide appears after 1.0 sec of idle time.
;;; Change Log:
;; 1.0.0 first released
;; 1.0.1 cleaned and optimized
;; works better for the file without trailing-whitespaces
;;; Known limitations, bugs:
;; o works not perfectly with "hl-line".
;;; Code:
(defconst indent-guide-version "1.0.1")
;; * variables / faces
(defvar indent-guide-timer-object
(run-with-idle-timer 0.6 t 'indent-guide-update))
(make-face 'indent-guide-face)
(set-face-attribute 'indent-guide-face nil
:foreground "#535353")
(defun indent-guide-set-delay (sec)
"change delay until the indent-guide appears"
(timer-set-idle-time indent-guide-timer-object
sec t))
;; * private functions
(defun indent-guide--indent-list (beg end)
(save-excursion
(let ((lst nil))
(goto-char end)
(while (< beg (point))
(back-to-indentation)
(setq lst (cons (if (eolp) nil (current-column))
lst))
(vertical-motion -1))
(back-to-indentation)
(setq lst (cons (current-column) lst)))))
(defun indent-guide--guide-strings (indent-list)
(flet ((set-nth (n lst val)
(if (zerop n)
(setcar lst val)
(set-nth (1- n) (cdr lst) val)))
(guides (indent-list)
(let ((active nil)
(coming indent-list)
(guides nil))
(dotimes (n (length indent-list))
(let ((current (car coming)))
(if (null current)
(setq guides (cons active guides))
(setq active (delq nil
(mapcar (lambda (x) (and (< x current) x))
active)))
(setq guides (cons active guides))
(add-to-list 'active current t))
(setq coming (cdr coming))))
(reverse guides)))
(guide-string (guide)
(if (null guide) ""
(let* ((length (1+ (eval `(max ,@guide))))
(str (make-list length " ")))
(dolist (n guide)
(set-nth n str "|"))
(eval `(concat ,@str))))))
(let ((guides (guides indent-list)))
(mapcar 'guide-string guides))))
;; * show or hide indent-guides
(defun indent-guide-overlays (beg end)
(delq nil
(mapcar
(lambda (ov)
(and (eq (overlay-get ov 'category) 'indent-guide) ov))
(overlays-in beg end))))
(defun indent-guide-show (beg end)
(unless (indent-guide-overlays beg end)
(save-excursion
(let* ((indent-list (indent-guide--indent-list beg end))
(string-list (indent-guide--guide-strings indent-list))
ov)
(goto-char beg)
(dotimes (n (1- (length indent-list)))
(setq indent-list (cdr indent-list)
string-list (cdr string-list))
(cond ((null (car indent-list))
(vertical-motion 1)
(setq ov (make-overlay (1- (point)) (point))))
(t
(vertical-motion (cons (length (car string-list)) 1))
(setq ov (make-overlay (point-at-bol) (point)))
(overlay-put ov 'invisible t)))
(overlay-put ov 'category 'indent-guide)
(overlay-put ov 'after-string
(propertize (car string-list) 'face 'indent-guide-face)))))))
(defun indent-guide-remove (beg end)
(dolist (ov (indent-guide-overlays beg end))
(delete-overlay ov)))
;; * triggers
(defun indent-guide-beginning-of-defun ()
(or (search-backward-regexp "^[^\s\t\n]" nil t)
(goto-char (point-min))))
(defun indent-guide-end-of-defun ()
(or (and (ignore-errors (forward-char) t)
(or (search-forward-regexp "^[^\s\t\n]" nil t)
(goto-char (point-max)))
(or (search-backward-regexp "^[\s\t]" nil t)
(goto-char (point-min)))
(progn (end-of-line) (point)))
(goto-char (point-max))))
(defun indent-guide-update ()
(unless (active-minibuffer-window)
(save-excursion
(ignore-errors (forward-char)) ; *FIXME*
(let* ((beg (indent-guide-beginning-of-defun))
(end (indent-guide-end-of-defun)))
(indent-guide-show beg end)))))
(defun indent-guide-pre-command ()
(save-excursion
(ignore-errors (forward-char)) ; *FIXME*
(let* ((beg (indent-guide-beginning-of-defun))
(end (indent-guide-end-of-defun)))
(indent-guide-remove beg end))))
(add-hook 'pre-command-hook 'indent-guide-pre-command)
;; * provide
(provide 'indent-guide)
;;; indent-guide.el ends here