]> code.delx.au - gnu-emacs-elpa/blob - packages/ada-mode/gpr-mode.el
Merge commit '0cda39255827f283e7578cd469ae42daad9556a2' from js2-mode
[gnu-emacs-elpa] / packages / ada-mode / gpr-mode.el
1 ;; gpr-mode --- Major mode for editing GNAT project files -*- lexical-binding:t -*-
2
3 ;; Copyright (C) 2004, 2007, 2008, 2012-2015 Free Software Foundation, Inc.
4
5 ;; Author: Stephen Leake <stephen_leake@member.fsf.org>
6 ;; Maintainer: Stephen Leake <stephen_leake@member.fsf.org>
7
8 ;; This file is part of GNU Emacs.
9
10 ;; gpr-mode 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, or (at your option)
13 ;; any later version.
14
15 ;; gpr-mode 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.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24 ;;
25 ;;; Commentary:
26 ;;
27 ;;; History:
28 ;;
29 ;; The first gpr-mode was written by Rolf Ebert
30 ;; <rolf.ebert_nosp...@gmx.net> in 2004.
31 ;;
32 ;; Stephen Leake <stephen_leake@member.fsf.org> rewrote it in 2013 to
33 ;; use the wisi indentation engine.
34 ;;
35 ;;;;; Code:
36
37 ;; we reuse several ada-mode functions
38 (require 'ada-mode)
39 (require 'cl-lib)
40
41 (defvar gpr-mode-map
42 (let ((map (make-sparse-keymap)))
43 ;; C-c <letter> are reserved for users
44
45 ;; global-map has C-x ` 'next-error
46 (define-key map [return] 'ada-indent-newline-indent)
47 (define-key map "\C-c`" 'ada-show-secondary-error)
48 ;; comment-dwim is in global map on M-;
49 (define-key map "\C-c\C-c" 'ada-build-make)
50 (define-key map "\C-c\C-e" 'gpr-expand)
51 (define-key map "\C-c\C-f" 'gpr-show-parse-error)
52 (define-key map "\C-c\C-i" 'gpr-indent-statement)
53 (define-key map "\C-c\C-o" 'ff-find-other-file)
54 (define-key map "\C-c\C-P" 'gpr-set-as-project)
55 (define-key map "\C-c\C-t" 'ada-case-read-all-exceptions)
56 (define-key map "\C-c\C-w" 'ada-case-adjust-at-point)
57 (define-key map "\C-c\C-y" 'ada-case-create-exception)
58 (define-key map "\C-c\C-\M-y" 'ada-case-create-partial-exception)
59 (define-key map "\M-n" 'skeleton-next-placeholder)
60 (define-key map "\M-p" 'skeleton-prev-placeholder)
61 map
62 ) "Local keymap used for GPR mode.")
63
64 (defvar gpr-mode-menu (make-sparse-keymap "gpr"))
65 (easy-menu-define gpr-mode-menu gpr-mode-map "Menu keymap for gpr mode"
66 '("gpr"
67 ("Help"
68 ["gpr Mode" (info "gpr-mode") t]
69 ["GNAT Reference Manual" (info "gnat_rm") t]
70 ["GNAT User Guide" (info "gnat_ugn") t]
71 ["Key bindings" describe-bindings t]
72 )
73
74 ["Customize" (customize-group 'ada)];; we reuse the Ada indentation options
75 ["------" nil nil]
76 ["Build current project" ada-build-make t]
77 ["Find and select project ..." ada-build-prompt-select-prj-file t]
78 ["Select project ..." ada-prj-select t]
79 ["Parse and select current file" gpr-set-as-project t]
80 ["Show current project" ada-prj-show t]
81 ["Show project search path" ada-prj-show-path t]
82 ["Next compilation error" next-error t]
83 ["Show secondary error" ada-show-secondary-error t]
84 ["Show last parse error" gpr-show-parse-error t]
85 ["Other file" ff-find-other-file t]
86 ("Edit"
87 ["Indent Line or selection" indent-for-tab-command t]
88 ["Indent current statement" gpr-indent-statement t]
89 ["Indent Lines in File" (indent-region (point-min) (point-max)) t]
90 ["Expand skeleton" gpr-expand t]
91 ["Next skeleton placeholder" skeleton-next-placeholder t]
92 ["Previous skeleton placeholder" skeleton-prev-placeholder t]
93 ["Comment/uncomment selection" comment-dwim t]
94 ["Fill Comment Paragraph" fill-paragraph t]
95
96 ["Fill Comment Paragraph Justify" ada-fill-comment-paragraph-justify t]
97 ["Fill Comment Paragraph Postfix" ada-fill-comment-paragraph-postfix t]
98 )
99 ))
100
101 (defvar gpr-show-parse-error nil
102 ;; Supplied by indentation engine parser
103 "Function to show last error reported by indentation parser."
104 )
105
106 (defun gpr-show-parse-error ()
107 (interactive)
108 (when gpr-show-parse-error
109 (funcall gpr-show-parse-error)))
110
111 (defvar gpr-expand nil
112 ;; skeleton function
113 "Function to call to expand tokens (ie insert skeletons).")
114
115 (defun gpr-expand ()
116 "Expand previous word into a statement skeleton."
117 (interactive)
118 (when gpr-expand
119 (funcall gpr-expand)))
120
121 (defvar gpr-indent-statement nil
122 ;; indentation function
123 "Function to indent the statement/declaration point is in or after.
124 Function is called with no arguments.")
125
126 (defun gpr-indent-statement ()
127 "Indent current statement."
128 (interactive)
129 (when gpr-indent-statement
130 (funcall gpr-indent-statement)))
131
132 (defconst gpr-casing-keywords
133 '(
134 "abstract"
135 "aggregate"
136 "case"
137 "configuration"
138 "end"
139 "extends"
140 "external"
141 "external_as_list"
142 "for"
143 "is"
144 "library"
145 "limited"
146 "null"
147 "others"
148 "package"
149 "project"
150 "renames"
151 "standard"
152 "type"
153 "use"
154 "when"
155 "with"
156 )
157 "List of gpr mode keywords for auto-casing.")
158
159 (defvar gpr-font-lock-keywords
160 (progn
161 (list
162 ;;
163 ;; keyword plus name. FIXME: move to grammar action, use gpr-keywords here (see ada-font-lock-keywords).
164 (list (concat
165 "\\<\\("
166 "package\\|"
167 "project\\|"
168 "for"
169 "\\)\\>[ \t]*"
170 "\\(\\sw+\\(\\.\\sw*\\)*\\)?")
171 '(1 font-lock-keyword-face) '(2 font-lock-function-name-face nil t))
172 ;;
173 ;; Main keywords
174 (list (concat "\\<"
175 (regexp-opt
176 '("abstract" "aggregate" "case" "configuration" "extends"
177 "external" "external_as_list" "is" "library" "null"
178 "others" "renames" "standard" "type" "use" "when" "with")
179 t)
180 "\\>")
181 '(1 font-lock-keyword-face))
182 ;;
183 ;; Anything following end and not already fontified is a body name.
184 '("\\<\\(end\\)\\>\\([ \t]+\\)?\\(\\(\\sw\\|[_.]\\)+\\)?"
185 (1 font-lock-keyword-face) (3 font-lock-function-name-face nil t))
186 ;;
187 ))
188 "Expressions to highlight in gpr mode.")
189
190 (defun gpr-ff-special-with ()
191 (ada-require-project-file)
192 (let ((project-path (match-string 1)))
193 ;; project-path may be any of "foo", "foo.gpr", "../foo.gpr"
194 ;;
195 ;; The result of ff-special-constructs is used by
196 ;; ff-find-the-other-file with ff-search-directories and nil
197 ;; suffix list, so it must contain the relative path and the
198 ;; suffix
199 (if (file-name-extension project-path)
200 project-path
201 (concat project-path ".gpr"))
202 ))
203
204 (defun gpr-set-ff-special-constructs ()
205 "Add gpr-specific pairs to `ff-special-constructs'."
206 (set (make-local-variable 'ff-special-constructs) nil)
207 (mapc (lambda (pair) (add-to-list 'ff-special-constructs pair))
208 ;; Each car is a regexp; if it matches at point, the cdr is
209 ;; invoked. Each cdr should return the absolute file name to
210 ;; go to.
211 (list
212 ;; A "with" clause; allow "foo_bar.gpr" and "../foo"
213 (cons "^with[ \t]+\"\\(\\(?:\\(?:\\sw\\|\\s.\\)\\|\\s_\\)+\\)\";"
214 'gpr-ff-special-with)
215 )))
216
217 (defvar gpr-which-function nil
218 ;; supplied by the indentation engine
219 "Function called with no parameters; it should return the name
220 of the package or project point is in or just after, or nil.")
221
222 (defun gpr-which-function ()
223 "See `gpr-which-function' variable."
224 (when gpr-which-function
225 (funcall gpr-which-function)))
226
227 (defun gpr-add-log-current-function ()
228 "For `add-log-current-defun-function'. Returns enclosing package or project name."
229 ;; add-log-current-defun is typically called with point at the start
230 ;; of an ediff change section, which is before the start of the
231 ;; declaration of a new item. So go to the end of the current line
232 ;; first
233 (save-excursion
234 (end-of-line 1)
235 (gpr-which-function)))
236
237 (declare-function gpr-query-kill-all-sessions "gpr-query.el" nil)
238 (defun gpr-set-as-project (&optional file)
239 "Set FILE (default current buffer file) as Emacs project file."
240 (interactive)
241 (save-some-buffers t)
242 ;; Kill sessions to catch changed env vars
243 ;; FIXME: need dispatching kill single session
244 (cl-ecase ada-xref-tool
245 (gnat nil)
246 (gpr_query (gpr-query-kill-all-sessions))
247 )
248 (ada-parse-prj-file (or file (buffer-file-name)))
249 (ada-select-prj-file (or file (buffer-file-name))))
250
251 ;;;;
252 ;;;###autoload
253 (defun gpr-mode ()
254 "The major mode for editing GNAT project files."
255
256 (interactive)
257 (kill-all-local-variables)
258 (setq major-mode 'gpr-mode)
259 (setq mode-name "GNAT Project")
260 (use-local-map gpr-mode-map)
261 (set-syntax-table ada-mode-syntax-table)
262 (when (boundp 'syntax-begin-function)
263 ;; obsolete in emacs-25.1
264 (set (make-local-variable 'syntax-begin-function) nil))
265 (set 'case-fold-search t); gpr is case insensitive; the syntax parsing requires this setting
266 (set (make-local-variable 'comment-start) "--")
267 (set (make-local-variable 'comment-end) "")
268 (set (make-local-variable 'comment-start-skip) "---*[ \t]*")
269 (set (make-local-variable 'comment-multi-line) nil)
270
271 (set (make-local-variable 'require-final-newline) t)
272
273 (ada-case-activate-keys gpr-mode-map)
274 (set (make-local-variable 'ada-keywords) gpr-casing-keywords)
275
276 (set (make-local-variable 'font-lock-defaults)
277 '(gpr-font-lock-keywords
278 nil t
279 ((?\_ . "w"))))
280
281 (gpr-set-ff-special-constructs)
282 (setq ff-search-directories 'compilation-search-path);; includes project search path
283
284 (set (make-local-variable 'add-log-current-defun-function)
285 'gpr-add-log-current-function)
286
287 (run-hooks 'gpr-mode-hook)
288
289 )
290
291 ;;;###autoload
292 (add-to-list 'auto-mode-alist '("\\.gpr\\'" . gpr-mode)) ; GNAT project files
293
294 (provide 'gpr-mode)
295
296 (unless (featurep 'gpr-indent-engine)
297 (require 'gpr-wisi))
298
299 (unless (featurep 'gpr-skeletons)
300 (require 'gpr-skel))
301
302 ;;; end of file