]> rtime.felk.cvut.cz Git - sojka/company-mode.git/blob - company-template.el
company-template: Hold off on removing the template until point leaves
[sojka/company-mode.git] / company-template.el
1 ;;; company-template.el
2
3 ;; Copyright (C) 2009, 2010 Free Software Foundation, Inc.
4
5 ;; Author: Nikolaj Schumacher
6
7 ;; This file is part of GNU Emacs.
8
9 ;; GNU Emacs is free software: you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation, either version 3 of the License, or
12 ;; (at your option) any later version.
13
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 ;; GNU General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
21
22 ;;; Code:
23
24 (eval-when-compile (require 'cl))
25
26 (defface company-template-field
27   '((((background dark)) (:background "yellow" :foreground "black"))
28     (((background light)) (:background "orange" :foreground "black")))
29   "Face used for editable text in template fields."
30   :group 'company)
31
32 (defvar company-template-nav-map
33   (let ((keymap (make-sparse-keymap)))
34     (define-key keymap [tab] 'company-template-forward-field)
35     keymap))
36
37 ;; interactive ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
38
39 (defun company-template-templates-at (pos)
40   (let (os)
41     (dolist (o (overlays-at pos))
42       ;; FIXME: Always return the whole list of templates?
43       ;; We remove templates not at point after every command.
44       (when (memq o company-template--buffer-templates)
45         (push o os)))
46     os))
47
48 (defun company-template-move-to-first (templ)
49   (interactive)
50   (let ((fields (overlay-get templ 'company-template-fields)))
51     (push-mark)
52     (goto-char (apply 'min (mapcar 'overlay-start fields)))))
53
54 (defun company-template-forward-field ()
55   (interactive)
56   (let* ((start (point))
57          (templates (company-template-templates-at (point)))
58          (minimum (apply 'max (mapcar 'overlay-end templates)))
59          (fields (loop for templ in templates
60                        append (overlay-get templ 'company-template-fields))))
61     (dolist (pos (mapcar 'overlay-start fields))
62       (and pos
63            (> pos (point))
64            (< pos minimum)
65            (setq minimum pos)))
66     (push-mark)
67     (goto-char minimum)
68     (let ((field (loop for ovl in (overlays-at start)
69                        when (overlay-get ovl 'company-template-parent)
70                        return ovl)))
71       (company-template-remove-field field))))
72
73 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
74
75 (defvar company-template--buffer-templates nil)
76 (make-variable-buffer-local 'company-template--buffer-templates)
77
78 (defun company-template-declare-template (beg end)
79   (let ((ov (make-overlay beg end)))
80     ;; (overlay-put ov 'face 'highlight)
81     (overlay-put ov 'keymap company-template-nav-map)
82     (overlay-put ov 'priority 101)
83     (overlay-put ov 'evaporate t)
84     (push ov company-template--buffer-templates)
85     (add-hook 'post-command-hook 'company-template-post-command nil t)
86     ov))
87
88 (defun company-template-remove-template (templ)
89   (mapc 'company-template-remove-field
90         (overlay-get templ 'company-template-fields))
91   (setq company-template--buffer-templates
92         (delq templ company-template--buffer-templates))
93   (delete-overlay templ))
94
95 (defun company-template-add-field (templ pos text)
96   (assert templ)
97   (save-excursion
98     (save-excursion
99       (goto-char pos)
100       (insert text)
101       (when (> (point) (overlay-end templ))
102         (move-overlay templ (overlay-start templ) (point))))
103     (let ((ov (make-overlay pos (+ pos (length text))))
104           (siblings (overlay-get templ 'company-template-fields)))
105       ;; (overlay-put ov 'evaporate t)
106       (overlay-put ov 'intangible t)
107       (overlay-put ov 'face 'company-template-field)
108       (overlay-put ov 'company-template-parent templ)
109       (overlay-put ov 'insert-in-front-hooks '(company-template-insert-hook))
110       (push ov siblings)
111       (overlay-put templ 'company-template-fields siblings))))
112
113 (defun company-template-remove-field (ovl &optional clear)
114   (when (overlayp ovl)
115     (when (overlay-buffer ovl)
116       (when clear
117         (delete-region (overlay-start ovl) (overlay-end ovl)))
118       (delete-overlay ovl))
119     (let* ((templ (overlay-get ovl 'company-template-parent))
120            (siblings (overlay-get templ 'company-template-fields)))
121       (setq siblings (delq ovl siblings))
122       (overlay-put templ 'company-template-fields siblings))))
123
124 (defun company-template-clean-up (&optional pos)
125   "Clean up all templates that don't contain POS."
126   (let ((local-ovs (overlays-at (or pos (point)))))
127     (dolist (templ company-template--buffer-templates)
128       (unless (memq templ local-ovs)
129         (company-template-remove-template templ)))))
130
131 ;; hooks ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
132
133 (defun company-template-insert-hook (ovl after-p &rest ignore)
134   "Called when a snippet input prompt is modified."
135   (unless after-p
136     (company-template-remove-field ovl t)))
137
138 (defun company-template-post-command ()
139   (company-template-clean-up)
140   (unless company-template--buffer-templates
141     (remove-hook 'post-command-hook 'company-template-post-command t)))
142
143 (provide 'company-template)
144 ;;; company-template.el ends here