1 ;;; gpr-skel.el --- an extension to Gpr mode for inserting statement skeletons
4 ;; Free Software Foundation, Inc.
6 ;; Authors: Stephen Leake <stephen_leake@stephe-leake.org>
8 ;; This file is part of GNU Emacs.
10 ;; GNU Emacs is free software: you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
25 ;; The primary user command is `gpr-skel-expand', which inserts the
26 ;; skeleton associated with the previous word (possibly skipping a
29 ;; We don't define skeletons that prompt for most of the content; it
30 ;; is easier just to type in the buffer.
32 ;; These skeletons are not intended to teach a novice the language,
33 ;; just to make it easier to write code that the gpr-wisi parser
34 ;; likes, and handle repeated names nicely.
43 ;;;;; user variables, example skeletons intended to be overwritten
45 (defcustom gpr-skel-initial-string "header\nproject"
46 "*String to insert in empty buffer.
47 This could end in a token recognized by `gpr-skel-expand'."
52 (define-skeleton gpr-skel-user-restricted
53 "Example copyright/license skeleton, with automatic year and owner."
55 "-- Copyright (C) " (format-time-string "%Y ") user-full-name " All Rights Reserved.\n"
58 (define-skeleton gpr-skel-gpl
59 "Example copyright/license skeleton, with automatic year and owner, GPLv3."
61 "-- Copyright (C) " (format-time-string "%Y ") user-full-name " All Rights Reserved.\n"
63 "-- This program is free software; you can redistribute it and/or\n"
64 "-- modify it under terms of the GNU General Public License as\n"
65 "-- published by the Free Software Foundation; either version 3, or (at\n"
66 "-- your option) any later version. This program is distributed in the\n"
67 "-- hope that it will be useful, but WITHOUT ANY WARRANTY; without even\n"
68 "-- the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\n"
69 "-- PURPOSE. See the GNU General Public License for more details. You\n"
70 "-- should have received a copy of the GNU General Public License\n"
71 "-- distributed with this program; see file COPYING. If not, write to\n"
72 "-- the Free Software Foundation, 51 Franklin Street, Suite 500, Boston,\n"
73 "-- MA 02110-1335, USA.\n"
76 ;;;;; Gpr skeletons (alphabetical)
78 (define-skeleton gpr-skel-case
79 "Insert case statement."
85 (define-skeleton gpr-skel-header
86 "Insert a file header comment, with automatic copyright year and prompt for copyright owner/license.
87 Each user will probably want to override this."
93 "{copyright_license}\n"
96 (define-skeleton gpr-skel-package
97 "Insert a package with name from `str'."
99 "package " str " is\n"
103 (define-skeleton gpr-skel-project
104 "Insert a project with name from `str'."
106 "project " str " is\n"
110 ;;;;; skeleton extensions
112 ;; FIXME: code below should be in skeleton.el
114 (defvar-local skeleton-token-alist nil
115 "Symbol giving skeleton token alist of elements (STRING ELEMENT).
116 See `skeleton-expand'.
117 STRING must be a symbol in the current syntax, and is normally
118 the first keyword in the skeleton. All strings must be
119 lowercase; `skeleton-expand' converts user inputs.
122 - a skeleton, which is inserted
123 - an alist of (string . skeleton). User is prompted with `completing-read', selected skeleton is inserted. ")
125 (defun skeleton-add-skeleton (token skel alist &optional where)
126 "Add an element (TOKEN . SKEL) to ALIST by side-effect.
127 If WHERE is nil, prepend to ALIST; otherwise, prepend to sublist
130 (setf alist (cons (cons token skel) alist))
131 (setf (cdr (assoc where alist))
132 (cons (cons token skel) (cdr (assoc where alist))))
135 (defvar skeleton-test-input nil
136 "When non-nil, bypasses prompt in alist token expansions - used for unit testing.")
138 (defun skeleton-build-prompt (alist count)
139 "Build a prompt from the keys of the ALIST.
140 The prompt consists of the first COUNT keys from the alist, separated by `|', with
141 trailing `...' if there are more keys."
142 (if (>= count (length alist))
143 (concat (mapconcat 'car alist " | ") " : ")
144 (let ((alist-1 (butlast alist (- (length alist) count))))
145 (concat (mapconcat 'car alist-1 " | ") " | ... : "))
149 (defun skeleton-expand (&optional name)
150 "Expand the token or placeholder before point to a skeleton, as defined by `skeleton-token-alist'.
151 A token is a symbol in the current syntax.
152 A placeholder is a symbol enclosed in generic comment delimiters.
153 If the word before point is not in `gpr-skel-token-alist', assume
154 it is a name, and use the word before that as the token."
157 ;; Skip trailing space, newline, and placeholder delimiter.
158 ;; Standard comment end included for languages where that is newline.
159 (skip-syntax-backward " !>")
161 ;; include punctuation here, in case is is an identifier, to allow Gpr.Text_IO
162 (let* ((end (prog1 (point) (skip-syntax-backward "w_.")))
163 (token (downcase (buffer-substring-no-properties (point) end)))
164 (skel (assoc-string token (symbol-value skeleton-token-alist)))
169 (when (listp (cdr skel))
170 (let* ((alist (cdr skel))
171 (prompt (skeleton-build-prompt alist 4)))
172 (setq skel (assoc-string
173 (or skeleton-test-input
174 (completing-read prompt alist))
176 (setq skeleton-test-input nil) ;; don't reuse input on recursive call
179 ;; delete placeholder delimiters around token, token, and
180 ;; name. point is currently before token.
181 (skip-syntax-backward "!")
185 (skip-syntax-forward "!w_")
187 (skip-syntax-forward " ")
188 (skip-syntax-forward "w_."))
190 (funcall (cdr skel) name)
193 ;; word in point .. end is not a token; assume it is a name
195 ;; avoid infinite recursion
197 ;; Do this now, because skeleton insert won't.
199 ;; We didn't do it above, because we don't want to adjust case
200 ;; on tokens and placeholders.
201 ;; FIXME: hook for Ada case adjust
203 (setq token (buffer-substring-no-properties (point) end))
205 (skeleton-expand token)
209 (error "undefined skeleton token: %s" name))
212 (defun skeleton-hippie-try (old)
213 "For `hippie-expand-try-functions-list'. OLD is ignored."
215 ;; hippie is asking us to try the "next" completion; we don't have one
224 ;; undo hook action, motion
230 ;;;;; token alist, setup
232 (defconst gpr-skel-token-alist
233 '(("case" . gpr-skel-case)
235 ("GPL" . gpr-skel-gpl)
236 ("restricted" . gpr-skel-user-restricted))
237 ("header" . gpr-skel-header)
238 ("package" . gpr-skel-package)
239 ("project" . gpr-skel-project))
240 "For skeleton-token-alist")
242 (defun gpr-skel-setup ()
243 "Setup a buffer gpr-skel."
244 (setq skeleton-token-alist 'gpr-skel-token-alist)
245 (add-hook 'skeleton-end-hook 'gpr-indent-statement nil t)
246 (when (and gpr-skel-initial-string
248 (insert gpr-skel-initial-string))
251 (provide 'gpr-skeletons)
254 (setq gpr-expand 'skeleton-expand)
256 (add-hook 'gpr-mode-hook 'gpr-skel-setup)