update
[configs.git] / .emacs.d / lisp / yang / yang-mode.el
1 ;;; yang-mode.el --- major mode for editing YANG files
2
3 ;; This program is free software; you can redistribute it and/or modify
4 ;; it under the terms of the GNU General Public License as published by
5 ;; the Free Software Foundation; either version 2 of the License, or
6 ;; (at your option) any later version.
7 ;;
8 ;; This program is distributed in the hope that it will be useful,
9 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
10 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 ;; GNU General Public License for more details.
12 ;;
13 ;; You should have received a copy of the GNU General Public License
14 ;; along with this program; see the file COPYING.  If not, write to
15 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 ;; Boston, MA 02111-1307, USA.
17
18 ;; Author: Martin Bjorklund <mbj4668@gmail.com>
19 ;; Version: 0.9.7
20
21 ;;; Commentary:
22
23 ;; Note: The interface used in this file requires CC Mode 5.30 or
24 ;; later.
25
26 ;; History:
27 ;;   0.9.7 - 2017-03-23
28 ;;        one more autoload fix
29 ;;   0.9.6 - 2017-03-21
30 ;;        autoload fix, tested with use-package
31 ;;   0.9.5 - 2017-02-13
32 ;;        autoload fix
33 ;;   0.9.4 - 2016-12-20
34 ;;        derive from prog-mode if available, otherwise nil
35 ;;        use proper syntax-table
36 ;;   0.9.3 - 2016-12-13
37 ;;        derive from nil
38 ;;   0.9.2 - 2016-12-13
39 ;;        derive mode from prog-mode in order to get correct hook behavior
40 ;;   0.9.1 - 2016-12-12
41 ;;        use define-derived-mode
42 ;;        yang-fill-paragraph now works in Emacs 23
43 ;;   0.9 - 2016-12-09
44 ;;        workaround Emacs bug #18845 (for 24.4+)
45 ;;   00.8 - 2016-10-27
46 ;;        rfc7950 compliant
47 ;;        added yang-fill-paragraph for better string fill
48 ;;   00.7 - 2016-03-15
49 ;;        draft-ietf-netmod-rfc6020bis-11 compliant
50 ;;        added support for new 1.1 keywords
51 ;;   00.6 - 2012-02-01
52 ;;        removed unused defcustom yang-font-lock-extra-types
53 ;;          made emacs24 to give a warning
54 ;;   00.5 - 2010-10-07
55 ;;        rfc6020 compliant
56 ;;        classify all keywords as decl-start gives better indentation
57 ;;   00.4 - 2010-04-30
58 ;;        draft-ietf-netmod-yang-12 compliant,
59 ;;        added instructions for Emacs 23
60 ;;   00.3 - 2009-12-19
61 ;;        draft-ietf-netmod-yang-09 compliant,
62 ;;   00.2 - 2008-11-04
63 ;;        draft-ietf-netmod-yang-02 compliant.
64 ;;   00.1 - 2007-11-14
65 ;;        Initial version, draft-bjorklund-netconf-yang-00 compliant.
66
67 ;; Useful tips:
68 ;;
69 ;;   If you're using use-package, put this in your .emacs:
70 ;;     (use-package yang-mode
71 ;;       :ensure t)
72 ;;
73 ;;   Otherwise, put this in your .emacs:
74 ;;     (require 'yang-mode)
75 ;;
76 ;;   For use with Emacs 23, put this in your .emacs:
77 ;;     (autoload 'yang-mode "yang-mode" "Major mode for editing YANG modules."
78 ;;               t)
79 ;;     (add-to-list 'auto-mode-alist '("\\.yang$" . yang-mode))
80 ;;
81 ;;   Some users have reported other errors with Emacs 23, and have found
82 ;;   that removing the byte-compiled cc-mode.elc file fixes these problems.
83 ;;   (e.g. /usr/share/emacs/23.1/lisp/progmodes/cc-mode.elc)
84 ;;
85 ;;
86 ;;   For editing somewhat larger YANG modules, add this to your .emacs
87 ;;     (setq blink-matching-paren-distance nil)
88 ;;
89 ;;   Common YANG layout:
90 ;;     (defun my-yang-mode-hook ()
91 ;;       "Configuration for YANG Mode.  Add this to `yang-mode-hook'."
92 ;;       (if window-system
93 ;;         (progn
94 ;;           (c-set-style "BSD")
95 ;;           (setq indent-tabs-mode nil)
96 ;;           (setq c-basic-offset 2)
97 ;;           (setq font-lock-maximum-decoration t)
98 ;;           (font-lock-mode t))))
99 ;;
100 ;;     (add-hook 'yang-mode-hook 'my-yang-mode-hook)
101 ;;
102 ;;   Using the oultine minor mode for YANG is very useful to get a
103 ;;   good overview of the structure of a module.
104 ;;
105 ;;   Put this in your .emacs:
106 ;;
107 ;;     (defun show-onelevel ()
108 ;;       "show entry and children in outline mode"
109 ;;       (interactive)
110 ;;       (show-entry)
111 ;;       (show-children))
112 ;;
113 ;;     (defun my-outline-bindings ()
114 ;;       "sets shortcut bindings for outline minor mode"
115 ;;       (interactive)
116 ;;       (local-set-key [?\C-,] 'hide-body)
117 ;;       (local-set-key [?\C-.] 'show-all)
118 ;;       (local-set-key [C-up] 'outline-previous-visible-heading)
119 ;;       (local-set-key [C-down] 'outline-next-visible-heading)
120 ;;       (local-set-key [C-left] 'hide-subtree)
121 ;;       (local-set-key [C-right] 'show-onelevel)
122 ;;       (local-set-key [M-up] 'outline-backward-same-level)
123 ;;       (local-set-key [M-down] 'outline-forward-same-level)
124 ;;       (local-set-key [M-left] 'hide-subtree)
125 ;;       (local-set-key [M-right] 'show-subtree))
126 ;;
127 ;;     (add-hook
128 ;;      'outline-minor-mode-hook
129 ;;      'my-outline-bindings)
130 ;;
131 ;;     (defconst sort-of-yang-identifier-regexp "[-a-zA-Z0-9_\\.:]*")
132 ;;
133 ;;     (add-hook
134 ;;      'yang-mode-hook
135 ;;      '(lambda ()
136 ;;         (outline-minor-mode)
137 ;;         (setq outline-regexp
138 ;;           (concat "^ *" sort-of-yang-identifier-regexp " *"
139 ;;                   sort-of-yang-identifier-regexp
140 ;;                   " *{"))))
141
142 ;;; Code:
143
144 (require 'cc-mode)
145
146 ;; These are only required at compile time to get the sources for the
147 ;; language constants.  (The cc-fonts require and the font-lock
148 ;; related constants could additionally be put inside an
149 ;; (eval-after-load "font-lock" ...) but then some trickery is
150 ;; necessary to get them compiled.)
151 (eval-when-compile
152   (require 'cc-langs)
153   (require 'cc-fonts))
154
155 (eval-and-compile
156   ;; Make our mode known to the language constant system.  Use Java
157   ;; mode as the fallback for the constants we don't change here.
158   ;; This needs to be done also at compile time since the language
159   ;; constants are evaluated then.
160   (c-add-language 'yang-mode 'java-mode))
161
162 ;; Work around Emacs bug #18845, cc-mode expects cl to be loaded
163 (eval-and-compile
164   (if (and (= emacs-major-version 24) (>= emacs-minor-version 4))
165     (require 'cl)))
166
167 ;; YANG has no primitive types in the C/Java sense.
168 (c-lang-defconst c-primitive-type-kwds
169   yang '())
170
171 (c-lang-defconst c-modifier-kwds
172   yang '())
173
174 (c-lang-defconst c-label-kwds
175   yang '())
176
177 (c-lang-defconst c-before-label-kwds
178   yang '())
179
180 (c-lang-defconst c-class-decl-kwds
181   yang '())
182
183 (c-lang-defconst c-decl-start-kwds
184   yang '(
185          "action"
186          "anydata"
187          "anyxml"
188          "argument"
189          "augment"
190          "base"
191          "belongs-to"
192          "bit"
193          "case"
194          "choice"
195          "config"
196          "contact"
197          "container"
198          "default"
199          "description"
200          "deviate"
201          "deviation"
202          "enum"
203          "error-app-tag"
204          "error-message"
205          "extension"
206          "feature"
207          "fraction-digits"
208          "grouping"
209          "identity"
210          "if-feature"
211          "import"
212          "include"
213          "input"
214          "key"
215          "leaf"
216          "leaf-list"
217          "length"
218          "list"
219          "mandatory"
220          "max-elements"
221          "min-elements"
222          "modifier"
223          "module"
224          "must"
225          "namespace"
226          "notification"
227          "ordered-by"
228          "organization"
229          "output"
230          "path"
231          "pattern"
232          "position"
233          "prefix"
234          "presence"
235          "range"
236          "reference"
237          "refine"
238          "require-instance"
239          "revision"
240          "revision-date"
241          "rpc"
242          "status"
243          "submodule"
244          "type"
245          "typedef"
246          "unique"
247          "units"
248          "uses"
249          "value"
250          "when"
251          "yang-version"
252          "yin-element"
253          ))
254
255 ;; No cpp in this language. (The definitions for the extra keywords
256 ;; above are enough to incorporate them into the fontification regexps
257 ;; for types and keywords, so no additional font-lock patterns are
258 ;; required.)
259 (c-lang-defconst c-cpp-matchers
260   yang
261       ;; There are some other things in `c-cpp-matchers' besides the
262       ;; preprocessor support, so include it.
263       (c-lang-const c-cpp-matchers))
264
265 ;; '-' is part of an identifier in YANG
266 ;; FIXME: how do I make '.' part of the identifier?
267 (c-lang-defconst c-identifier-syntax-modifications
268   yang (append '((?- . "w") (?: . "w"))
269                (c-lang-const c-identifier-syntax-modifications)))
270
271 (c-lang-defconst c-symbol-chars
272   yang (concat c-alnum ":_-"))
273
274 ;; YANG does not have labels
275 (c-lang-defconst c-recognize-colon-labels
276   yang nil)
277
278 (defconst yang-font-lock-keywords-1 (c-lang-const c-matchers-1 yang)
279   "Minimal highlighting for YANG mode.")
280
281 (defconst yang-font-lock-keywords-2 (c-lang-const c-matchers-2 yang)
282   "Fast normal highlighting for YANG mode.")
283
284 (defconst yang-font-lock-keywords-3 (c-lang-const c-matchers-3 yang)
285   "Accurate normal highlighting for YANG mode.")
286
287 (defvar yang-font-lock-keywords yang-font-lock-keywords-3
288   "Default expressions to highlight in YANG mode.")
289
290 (defvar yang-mode-syntax-table nil
291   "Syntax table used in `yang-mode' buffers.")
292 (or yang-mode-syntax-table
293     (setq yang-mode-syntax-table
294           (funcall (c-lang-const c-make-mode-syntax-table yang))))
295
296 (defvar yang-mode-map (let ((map (c-make-inherited-keymap)))
297                       ;; Add bindings which are only useful for YANG
298                       map)
299   "Keymap used in `yang-mode' buffers.")
300
301 (easy-menu-define yang-menu yang-mode-map "YANG Mode Commands"
302   ;; Can use `yang' as the language for `c-mode-menu'
303   ;; since its definition covers any language.  In
304   ;; this case the language is used to adapt to the
305   ;; nonexistence of a cpp pass and thus removing some
306   ;; irrelevant menu alternatives.
307   (cons "YANG" (c-lang-const c-mode-menu yang)))
308
309 (defun yang-fill-paragraph (&optional arg)
310   "Like \\[c-fill-paragraph] but handles first line in strings properly.
311
312    Optional prefix ARG means justify paragraph as well."
313   ;; c-fill-paragraph narrows the region to the contents of a string
314   ;; before filling, and this means that the start quote character
315   ;; will be in column 1 in the narrowed region.  Thus the first line
316   ;; line will not be filled properly.
317   ;; This function handles this by temporarily inserting a newline
318   ;; followed by whitespaces to line up the first line before filling.
319   (interactive)
320   (save-excursion
321     (let ((limits (c-literal-limits))
322           (tmppoint nil)
323           (col nil))
324       (if (eq (c-literal-type limits) 'string)
325           (let ((curpoint (point)))
326             (backward-paragraph)
327             (if (< (point) (car limits))
328                 ;; do this in the first paragraph of a string
329                 (let ((first-char (+ 1 (car limits))))
330                   (goto-char first-char)
331                   (beginning-of-line)
332                   (setq col (- first-char (point)))
333                   (goto-char first-char)
334                   (setq tmppoint (point))
335                   (insert-char ?\n 1)
336                   (insert-char ?\s col))
337               (goto-char curpoint))))
338       (c-fill-paragraph arg)
339       (if tmppoint
340           (progn
341             (goto-char tmppoint)
342             (delete-char (+ 1 col))))))
343   ;; Always return t.  This has the effect that if filling isn't done
344   ;; above, it isn't done at all, and it's therefore effectively
345   ;; disabled in normal code.
346   t)
347
348 ;; It doesn't suffice to put `yang-fill-paragraph' on
349 ;; `fill-paragraph-function' since `yang-fill-paragraph' must be called
350 ;; before any fill prefix adaption is done.
351 (substitute-key-definition 'c-fill-paragraph 'yang-fill-paragraph
352                            yang-mode-map c-mode-map)
353
354 ;; derive from prog-mode if it is defined
355 (if (fboundp 'prog-mode)
356     (defmacro yang-define-derived-mode (mode &rest args)
357       `(define-derived-mode ,mode prog-mode ,@args))
358   (defmacro yang-define-derived-mode (mode &rest args)
359     `(define-derived-mode ,mode nil ,@args)))
360
361 ;;;###autoload(autoload 'yang-mode "yang-mode" "" t nil)
362 (yang-define-derived-mode yang-mode "YANG"
363   "Major mode for editing YANG modules.
364
365 The hook `c-mode-common-hook' is run with no args at mode
366 initialization, then `yang-mode-hook'.
367
368 Key bindings:
369 \\{yang-mode-map}"
370   :syntax-table yang-mode-syntax-table
371   (c-initialize-cc-mode t)
372   (c-init-language-vars yang-mode)
373   (c-common-init 'yang-mode)
374
375   ;; Allow auto-fill in strings
376   (setq c-ignore-auto-fill '(cpp code))
377
378   ;; Install `yang-fill-paragraph' on `fill-paragraph-function' so
379   ;; that a direct call to `fill-paragraph' behaves better.
380   (make-local-variable fill-paragraph-function)
381   (setq fill-paragraph-function 'yang-fill-paragraph)
382   ;; we derive from prog-mode/nil rather than c-mode in order to not run
383   ;; c-mode-hooks; this means that we need to run c-mode-common-hook
384   ;; explicitly.
385   (c-run-mode-hooks 'c-mode-common-hook))
386
387 ;;;###autoload
388 (add-to-list 'auto-mode-alist '("\\.yang\\'" . yang-mode))
389
390 (provide 'yang-mode)
391
392 ;;; yang-mode.el ends here