]> code.delx.au - gnu-emacs-elpa/blob - packages/ada-mode/gpr-mode.el
22f9c5e4b318100cb08010144131c2f3f6cef773
[gnu-emacs-elpa] / packages / ada-mode / gpr-mode.el
1 ;;; gpr-mode --- major-mode for editing GNAT project files
2
3 ;; Copyright (C) 2004, 2007, 2008, 2012-2014 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
40 (defvar gpr-mode-map
41 (let ((map (make-sparse-keymap)))
42 ;; C-c <letter> are reserved for users
43
44 ;; global-map has C-x ` 'next-error
45 (define-key map [return] 'ada-indent-newline-indent)
46 (define-key map "\C-c`" 'ada-show-secondary-error)
47 (define-key map "\C-c\C-c" 'compile)
48 (define-key map "\C-c\C-e" 'gpr-expand)
49 (define-key map "\C-c\C-f" 'gpr-show-parse-error)
50 (define-key map "\C-c\C-i" 'gpr-indent-statement)
51 ;; FIXME (later): implement?
52 ;; (define-key map "\C-c\C-n" 'ada-next-statement-keyword)
53 ;; (define-key map "\C-c\C-p" 'ada-prev-statement-keyword)
54 (define-key map "\C-c\C-o" 'ff-find-other-file)
55 (define-key map "\C-c\C-S-p" 'gpr-set-as-project)
56 (define-key map "\C-c\C-t" 'ada-case-read-all-exceptions)
57 (define-key map "\C-c\C-w" 'ada-case-adjust-at-point)
58 (define-key map "\C-c\C-y" 'ada-case-create-exception)
59 (define-key map "\C-c\C-\M-y" (lambda () (ada-case-create-exception nil nil t)))
60 map
61 ) "Local keymap used for GPR mode.")
62
63 (defvar gpr-mode-menu (make-sparse-keymap "gpr"))
64 (easy-menu-define gpr-mode-menu gpr-mode-map "Menu keymap for gpr mode"
65 '("gpr"
66 ("Help"
67 ["gpr Mode" (info "gpr-mode") t]
68 ["GNAT Reference Manual" (info "gnat_rm") t]
69 ["GNAT User Guide" (info "gnat_ugn") t]
70 ["Key bindings" describe-bindings t]
71 )
72
73 ["Customize" (customize-group 'ada)];; we reuse the Ada indentation options
74 ["------" nil nil]
75 ["Find and select project ..." ada-build-prompt-select-prj-file t]
76 ["Select project ..." ada-prj-select t]
77 ["Set as current project" gpr-set-as-project t]
78 ["Show current project" ada-prj-show t]
79 ["Next compilation error" next-error t]
80 ["Show secondary error" ada-show-secondary-error t]
81 ["Show last parse error" gpr-show-parse-error t]
82 ["Other file" ff-find-other-file t]
83 ("Edit"
84 ["Indent Line or selection" indent-for-tab-command t]
85 ["Indent current statement" gpr-indent-statement t]
86 ["Indent Lines in File" (indent-region (point-min) (point-max)) t]
87 ["Expand skeleton" gpr-expand t] ;; FIXME: only if skeleton
88 ["Comment/uncomment selection" comment-dwim t]
89 ["Fill Comment Paragraph" fill-paragraph t]
90
91 ["Fill Comment Paragraph Justify" ada-fill-comment-paragraph-justify t]
92 ["Fill Comment Paragraph Postfix" ada-fill-comment-paragraph-postfix t]
93 )
94 ))
95
96 (defvar gpr-show-parse-error nil
97 ;; Supplied by indentation engine parser
98 "Function to show last error reported by indentation parser."
99 )
100
101 (defun gpr-show-parse-error ()
102 (interactive)
103 (when gpr-show-parse-error
104 (funcall gpr-show-parse-error)))
105
106 (defvar gpr-expand nil
107 ;; skeleton function
108 "Function to call to expand tokens (ie insert skeletons).")
109
110 (defun gpr-expand ()
111 "Expand previous word into a statement skeleton."
112 (interactive)
113 (when gpr-expand
114 (funcall gpr-expand)))
115
116 (defvar gpr-indent-statement nil
117 ;; indentation function
118 "Function to indent the statement/declaration point is in or after.
119 Function is called with no arguments.")
120
121 (defun gpr-indent-statement ()
122 "Indent current statement."
123 (interactive)
124 (when gpr-indent-statement
125 (funcall gpr-indent-statement)))
126
127 (defvar gpr-font-lock-keywords
128 (progn
129 (list
130 ;;
131 ;; keyword plus name.
132 (list (concat
133 "\\<\\("
134 "package\\|"
135 "project\\|"
136 "for"
137 "\\)\\>[ \t]*"
138 "\\(\\sw+\\(\\.\\sw*\\)*\\)?")
139 '(1 font-lock-keyword-face) '(2 font-lock-function-name-face nil t))
140 ;;
141 ;; Main keywords
142 (list (concat "\\<"
143 (regexp-opt
144 '("abstract" "aggregate" "case" "configuration" "external" "is" "library" "null" "others"
145 "renames" "standard" "type" "use" "when" "with") t)
146 "\\>")
147 '(1 font-lock-keyword-face))
148 ;;
149 ;; Anything following end and not already fontified is a body name.
150 '("\\<\\(end\\)\\>\\([ \t]+\\)?\\(\\(\\sw\\|[_.]\\)+\\)?"
151 (1 font-lock-keyword-face) (3 font-lock-function-name-face nil t))
152 ;;
153 ))
154 "Expressions to highlight in gpr mode.")
155
156 (defun gpr-ff-special-with ()
157 (ada-require-project-file)
158 (let ((project-path (match-string 1)))
159 ;; project-path may be any of "foo", "foo.gpr", "../foo.gpr"
160 ;;
161 ;; The result of ff-special-constructs is used by
162 ;; ff-find-the-other-file with ff-search-directories and nil
163 ;; suffix list, so it must contain the relative path and the
164 ;; suffix
165 (if (file-name-extension project-path)
166 project-path
167 (concat project-path ".gpr"))
168 ))
169
170 (defun gpr-set-ff-special-constructs ()
171 "Add gpr-specific pairs to `ff-special-constructs'."
172 (set (make-local-variable 'ff-special-constructs) nil)
173 (mapc (lambda (pair) (add-to-list 'ff-special-constructs pair))
174 ;; Each car is a regexp; if it matches at point, the cdr is
175 ;; invoked. Each cdr should return the absolute file name to
176 ;; go to.
177 (list
178 ;; A "with" clause; allow "foo_bar.gpr" and "../foo"
179 (cons "^with[ \t]+\"\\(\\(?:\\(?:\\sw\\|\\s.\\)\\|\\s_\\)+\\)\";"
180 'gpr-ff-special-with)
181 )))
182
183 (defvar gpr-which-function nil
184 ;; supplied by the indentation engine
185 "Function called with no parameters; it should return the name
186 of the package or project point is in or just after, or nil.")
187
188 (defun gpr-which-function ()
189 "See `gpr-which-function' variable."
190 (when gpr-which-function
191 (funcall gpr-which-function)))
192
193 (defun gpr-add-log-current-function ()
194 "For `add-log-current-defun-function'. Returns enclosing package or project name."
195 ;; add-log-current-defun is typically called with point at the start
196 ;; of an ediff change section, which is before the start of the
197 ;; declaration of a new item. So go to the end of the current line
198 ;; first
199 (save-excursion
200 (end-of-line 1)
201 (gpr-which-function)))
202
203 (defun gpr-set-as-project (&optional file)
204 "Set FILE (default current buffer file) as Emacs project file."
205 (interactive)
206 (ada-parse-prj-file (or file (buffer-file-name)))
207 (ada-select-prj-file (or file (buffer-file-name))))
208
209 ;;;;
210 ;;;###autoload
211 (defun gpr-mode ()
212 "The major mode for editing GNAT project files."
213
214 (interactive)
215 (kill-all-local-variables)
216 (setq major-mode 'gpr-mode)
217 (setq mode-name "GNAT Project")
218 (use-local-map gpr-mode-map)
219 (set-syntax-table ada-mode-syntax-table)
220 (set (make-local-variable 'syntax-begin-function) nil)
221 (set 'case-fold-search t); gpr is case insensitive; the syntax parsing requires this setting
222 (set (make-local-variable 'comment-start) "--")
223 (set (make-local-variable 'comment-end) "")
224 (set (make-local-variable 'comment-start-skip) "---*[ \t]*")
225 (set (make-local-variable 'comment-multi-line) nil)
226
227 (set (make-local-variable 'require-final-newline) t)
228
229 (set (make-local-variable 'font-lock-defaults)
230 '(gpr-font-lock-keywords
231 nil t
232 ((?\_ . "w"))))
233
234 (gpr-set-ff-special-constructs)
235 (setq ff-search-directories 'ada-project-search-path)
236
237 (set (make-local-variable 'add-log-current-defun-function)
238 'gpr-add-log-current-function)
239
240 ;; used by autofill to break a comment line and continue it on
241 ;; another line. The reason we need this one is that the default
242 ;; behavior does not work correctly with the definition of
243 ;; paragraph-start above when the comment is right after a
244 ;; multi-line subprogram declaration (the comments are aligned under
245 ;; the latest parameter, not under the declaration start).
246 ;; FIXME: need test - should be in gpr-wisi?
247 (set (make-local-variable 'comment-line-break-function)
248 (lambda (&optional soft) (let ((fill-prefix nil))
249 (indent-new-comment-line soft))))
250
251 (run-hooks 'gpr-mode-hook)
252
253 )
254
255 ;;;###autoload
256 (add-to-list 'auto-mode-alist '("\\.gpr\\'" . gpr-mode)) ; GNAT project files
257
258 (provide 'gpr-mode)
259
260 (unless (featurep 'gpr-indent-engine)
261 (require 'gpr-wisi))
262
263 (unless (featurep 'gpr-skeletons)
264 (require 'gpr-skel))
265
266 ;;; end of file