1 ;;; dts-mode.el --- Major mode for Device Tree source files
3 ;; Copyright (C) 2014-2015 Free Software Foundation, Inc.
6 ;; Author: Ben Gamari <ben@smart-cactus.org>
9 ;; This program 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.
14 ;; This program 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.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
28 (defconst dts-re-ident "\\([[:alpha:]_][[:alnum:]_,-]*\\)")
30 (defvar dts-mode-font-lock-keywords
32 ;; Names like `name: hi {`
33 (,(concat dts-re-ident ":") 1 font-lock-variable-name-face)
35 (,(concat dts-re-ident "\\(@[[:xdigit:]]+\\)?[[:space:]]*{")
36 (1 font-lock-type-face))
38 (,(concat dts-re-ident "[[:space:]]*=") 1 font-lock-variable-name-face)
39 (,(concat dts-re-ident "[[:space:]]*;") 1 font-lock-variable-name-face)
41 (,(concat "&" dts-re-ident) 1 font-lock-variable-name-face)
45 (defvar dts-mode-syntax-table
46 (let ((table (make-syntax-table)))
47 (modify-syntax-entry ?< "(>" table)
48 (modify-syntax-entry ?> ")<" table)
50 (modify-syntax-entry ?& "." table)
51 (modify-syntax-entry ?| "." table)
52 (modify-syntax-entry ?~ "." table)
54 ;; _ and , are both symbol constituents.
55 (modify-syntax-entry ?, "_" table)
56 (modify-syntax-entry ?_ "_" table)
59 (modify-syntax-entry ?\" "\"" table)
60 (modify-syntax-entry ?\\ "\\" table)
63 (modify-syntax-entry ?/ ". 124b" table)
64 (modify-syntax-entry ?* ". 23" table)
65 (modify-syntax-entry ?\n "> b" table)
66 (modify-syntax-entry ?\^m "> b" table)
70 ;;;; Original manual indentation code.
72 (defun dts--calculate-indentation ()
75 (let ((end (point-at-eol))
77 (initial-point (point)))
79 (while (re-search-forward "\\([{}]\\)" end t)
80 (if (string= (match-string-no-properties 0) "{")
83 ;; subtract one if the current line has an opening brace since we
84 ;; shouldn't add the indentation level until the following line
85 (goto-char initial-point)
87 (when (re-search-forward "{" (point-at-eol) t)
91 (defun dts-indent-line ()
93 (let ((indent (dts--calculate-indentation)))
94 (indent-line-to (* indent tab-width))))
96 ;;;; New SMIE-based indentation code.
100 (defvar dts-use-smie (fboundp 'smie-prec2->grammar))
102 (defconst dts-grammar
103 ;; FIXME: The syntax-table gives symbol-constituent syntax to the comma,
104 ;; but the comma is also used as a separator!
105 (when (fboundp 'smie-prec2->grammar)
108 '((id) (val ("<" val ">"))
110 ;; The "foo,bar = toto" can be handled either by considering
111 ;; "foo,bar" as a single token or as 3 tokens.
112 ;; Currently I consider it as 3 tokens, so the LHS of "=" can't be
113 ;; just `id' but has to be `vals'.
115 (exps (exp) (exps ";" exps))
116 (vals (val "," val)))
117 '((assoc ";")) '((assoc ","))))))
119 (defun dts-indent-rules (kind token)
120 (pcase (cons kind token)
121 (`(:elem . basic) tab-width)
122 ;; (`(:elem . args) 0)
123 (`(:list-intro . "") ;FIXME: Not sure why we get "" here!
124 ;; After < we either have a plain list of data, as in: "operating-points =
125 ;; <1008000 1400000 ...>" or we have sometimes "refs with args" as in
126 ;; "clocks = <&apb1_gates 6>;".
127 (and (eq (char-before) ?<) (not (looking-at "&"))))
128 (`(:before . "{") (smie-rule-parent))
129 (`(:after . "=") (dts-indent-rules :elem 'basic))
132 ;;;; The major mode itself.
134 (defalias 'dts-parent-mode
135 (if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode))
138 (define-derived-mode dts-mode dts-parent-mode "Devicetree"
139 "Major mode for editing Device Tree source files."
142 (set (make-local-variable 'font-lock-defaults)
143 '(dts-mode-font-lock-keywords nil nil nil nil))
145 (set (make-local-variable 'comment-start) "/* ")
146 (set (make-local-variable 'comment-end) " */")
147 (set (make-local-variable 'comment-multi-line) t)
148 (set (make-local-variable 'syntax-propertize-function)
149 (syntax-propertize-rules
150 ("#include[ \t]+\\(<\\).*\\(>\\)" (1 "|") (2 "|"))))
152 (smie-setup dts-grammar #'dts-indent-rules)
153 (set (make-local-variable 'indent-line-function) #'dts-indent-line)))
156 (add-to-list 'auto-mode-alist '("\\.dtsi?\\'" . dts-mode))
159 ;;; dts-mode.el ends here