1 ;;; arduino-mode.el --- Major mode for editing Arduino code -*- lexical-binding: t; -*-
3 ;; Copyright (C) 2008 Christopher Grim
4 ;; Authors: Christopher Grim <christopher.grim@gmail.com>
5 ;; Maintainer: stardiviner <numbchild@gmail.com>
6 ;; Keywords: languages, arduino
7 ;; Package-Requires: ((emacs "25.1") (spinner "1.7.3"))
9 ;; homepage: https://repo.or.cz/arduino-mode.git
11 ;; This file is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 3, or (at your option)
16 ;; This file is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to
23 ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 ;; Boston, MA 02110-1301, USA.
28 ;; Arduino IDE for Emacs developer.
42 ;; fall back on c-mode
43 (c-add-language 'arduino-mode
'c-mode
))
45 ;; (require 'flycheck-arduino)
47 (defgroup arduino-mode nil
48 "Customize arduino-mode."
49 :prefix
"arduino-mode-"
52 (defcustom arduino-mode-home
"~/Arduino"
53 "The path of ARDUINO_HOME."
57 (c-lang-defconst c-primitive-type-kwds
58 arduino
(append '(;; Data Types
60 "int" "long" "short" "double" "float"
62 "unsigned char" "unsigned int" "unsigned long"
64 ;; Variable Scope & Qualifiers
65 "const" "scope" "static" "volatile"
70 "break" "continue" "do" "while" "else" "for" "goto" "if"
71 "return" "switch" "case"
74 (c-lang-const c-primitive-type-kwds
)))
76 (c-lang-defconst c-constant-kwds
79 "INPUT" "OUTPUT" "INPUT_PULLUP"
82 (c-lang-const c-constant-kwds
)))
84 (c-lang-defconst c-simple-stmt-kwds
87 '(;; Operator Utilities
90 "pinMode" "digitalWrite" "digitalRead" ; Digital I/O
91 "analogReference" "analogRead" "analogWrite" ; Analog I/O
92 "analogReadResolution" "analogWriteResolution" ; Zero, Due & MKR Family
93 "tone" "noTone" "shiftIn" "shiftOut" "pulseIn" "pulseInLong" ; Advanced I/O
94 "millis" "micros" "delay" "delayMicroseconds" ; Time
95 "min" "max" "abs" "constrain" "map" "pow" "sq" "sqrt" ; Math
96 "sin" "cos" "tan" ; Trigonometry
97 "randomSeed" "random" ; Random Numbers
98 "bit" "bitRead" "bitWrite" "bitSet" "bitClear" "lowByte" "highByte" ; Bits and Bytes
99 "attachInterrupt" "detachInterrupt" ; External Interrupts
100 "interrupts" "noInterrupts" ; Interrupts
101 "serial" "stream" ; Serial Communication
103 "isAlpha" "isAlphaNumeric"
104 "isAscii" "isControl" "isDigit" "isGraph" "isHexadecimalDigit"
105 "isLowerCase" "isUpperCase"
106 "isPrintable" "isPunct" "isSpace" "isWhitespace"
107 ;; USB Devices like Keyboard functions
110 "begin" "end" "available" "read" "flush" "peek"
112 "write" "press" "release" "releaseAll"
114 "click" "move" "isPressed")
115 (c-lang-const c-simple-stmt-kwds
)))
117 (c-lang-defconst c-primary-expr-kwds
121 ;; USB (Leonoardo based boards and Due only)
124 (c-lang-const c-primary-expr-kwds
)))
126 (defgroup arduino nil
"Arduino mode customizations"
129 (defcustom arduino-font-lock-extra-types nil
130 "List of extra types (aside from type keywords) to recognize in Arduino mode.
131 Each list item should be a regexp matching a single identifier."
135 (defcustom arduino-executable
"arduino"
136 "The arduino program executable name."
140 (defcustom arduino-spinner-type
'progress-bar
141 "The spinner type for arduino processes.
143 Value is a symbol. The possible values are the symbols in the
144 `spinner-types' variable."
149 (defconst arduino-font-lock-keywords-1
(c-lang-const c-matchers-1 arduino
)
150 "Minimal highlighting for Arduino mode.")
152 (defconst arduino-font-lock-keywords-2
(c-lang-const c-matchers-2 arduino
)
153 "Fast normal highlighting for Arduino mode.")
155 (defconst arduino-font-lock-keywords-3
(c-lang-const c-matchers-3 arduino
)
156 "Accurate normal highlighting for Arduino mode.")
158 (defvar arduino-font-lock-keywords arduino-font-lock-keywords-3
159 "Default expressions to highlight in ARDUINO mode.")
161 (defvar arduino-mode-syntax-table nil
162 "Syntax table used in arduino-mode buffers.")
164 (or arduino-mode-syntax-table
165 (setq arduino-mode-syntax-table
(make-syntax-table c-mode-syntax-table
)))
167 (defvar arduino-mode-abbrev-table nil
168 "Abbreviation table used in arduino-mode buffers.")
170 (c-define-abbrev-table 'arduino-mode-abbrev-table
171 ;; Keywords that if they occur first on a line might alter the
172 ;; syntactic context, and which therefore should trigger
173 ;; reindentation when they are completed.
174 '(("else" "else" c-electric-continued-statement
0)
175 ("while" "while" c-electric-continued-statement
0)))
177 (defvar arduino-mode-map
178 (let ((map (make-sparse-keymap)))
179 (set-keymap-parent map c-mode-base-map
)
180 (define-key map
(kbd "C-c C-c") #'arduino-upload
)
181 (define-key map
(kbd "C-c C-v") #'arduino-verify
)
182 (define-key map
(kbd "C-c C-m") #'arduino-serial-monitor
)
183 (define-key map
(kbd "C-c C-x") #'arduino-open-with-arduino
)
185 "Keymap used in arduino-mode buffers.")
187 (easy-menu-define arduino-menu arduino-mode-map
"Arduino Mode Commands"
188 (cons "Arduino" (c-lang-const c-mode-menu arduino
)))
190 (easy-menu-add-item arduino-menu
191 (list "Micro-controller") ["Upload" arduino-upload t
])
192 (easy-menu-add-item arduino-menu
193 nil
["----" nil nil
])
194 (easy-menu-add-item arduino-menu
195 nil
["Upload" arduino-upload t
])
196 (easy-menu-add-item arduino-menu
197 nil
["Verify" arduino-verify t
])
198 (easy-menu-add-item arduino-menu
199 nil
["Open with Arduino" arduino-open-with-arduino t
])
200 (easy-menu-add-item arduino-menu
201 nil
["Serial monitor" arduino-serial-monitor t
])
203 (defvar arduino-upload-process-buf nil
)
205 (defun arduino-upload ()
206 "Build and upload the sketch to an Arduino board."
208 (setq arduino-upload-process-buf
(buffer-name))
209 (let* ((proc-name "arduino-upload")
210 (proc-buffer "*arduino-upload*"))
212 :command
(list arduino-executable
"--upload" (buffer-file-name))
215 :sentinel
(lambda (_proc event
)
216 (if (string= event
"finished\n")
218 (with-current-buffer arduino-upload-process-buf
219 (setq mode-line-process nil
))
220 (message "Arduino upload succeed."))
221 (with-current-buffer arduino-upload-process-buf
222 (display-buffer "*arduino-upload*")))
223 (setq-local mode-line-process nil
)
224 (with-current-buffer arduino-upload-process-buf
225 (when spinner-current
(spinner-stop)))))
226 (spinner-start arduino-spinner-type
)
227 (setq mode-line-process proc-name
)))
229 (defvar arduino-verify-process-buf nil
)
231 (defun arduino-verify ()
232 "Verify the sketch by building it."
234 (setq arduino-verify-process-buf
(buffer-name))
235 (let* ((proc-name "arduino-verify")
236 (proc-buffer "*arduino-verify*"))
237 ;; FIXME: Reduce redundancy with `arduino-upload' and
238 ;; `arduino-open-with-arduino'.
240 :command
(list arduino-executable
"--verify" (buffer-file-name))
243 :sentinel
(lambda (_proc event
)
244 (if (string= event
"finished\n")
246 (with-current-buffer arduino-verify-process-buf
247 (setq mode-line-process nil
))
248 (message "Arduino verify build succeed."))
249 (display-buffer "*arduino-verify*"))
250 (setq-local mode-line-process nil
)
251 (with-current-buffer arduino-verify-process-buf
252 (when spinner-current
(spinner-stop)))))
253 (spinner-start arduino-spinner-type
)
254 (setq mode-line-process proc-name
)))
256 (defvar arduino-open-process-buf nil
)
258 (defun arduino-open-with-arduino ()
259 "Open the sketch with the Arduino IDE."
261 (setq arduino-open-process-buf
(buffer-name))
262 (let* ((proc-name "arduino-open")
263 (proc-buffer "*arduino-open*"))
265 :command
(list arduino-executable
(buffer-file-name))
268 :sentinel
(lambda (_proc event
)
269 (if (string= event
"finished\n")
271 (with-current-buffer arduino-open-process-buf
272 (setq mode-line-process nil
))
273 (message "Opened with Arduino succeed.")))
274 (setq-local mode-line-process nil
)
275 (with-current-buffer arduino-open-process-buf
276 (when spinner-current
(spinner-stop)))))
277 (spinner-start arduino-spinner-type
)
278 (setq mode-line-process proc-name
)))
280 ;; NOTE: Because command-line arduino does not support search and list out
281 ;; boards and libraries. So I will not write a sentinel for installing process.
282 (defun arduino-install-boards (board)
283 "Install `BOARD' support for Arduino."
284 (interactive (list (read-string "Arduino install board: "
287 "arduino-install-boards"
288 "*arduino-install-boards*"
289 arduino-executable
"--install-boards" board
))
291 (defun arduino-install-library (library)
292 "Install `LIBRARY' support for Arduino."
293 (interactive (list (read-string "Arduino install library: "
296 "arduino-install-library"
297 "*arduino-install-library*"
298 arduino-executable
"--install-library" library
))
301 (defun arduino-serial-monitor (port speed
)
302 "Monitor the `SPEED' on serial connection on `PORT' to the Arduino."
303 (interactive (list (serial-read-name) nil
))
304 (if (get-buffer-process port
)
305 (switch-to-buffer port
)
306 (serial-term port
(or speed
(serial-read-speed)))))
309 (defun arduino-sketch-new (sketch)
310 "A command to create new `SKETCH' in ARDUINO_HOME (~/Arduino)."
311 (interactive (list (read-from-minibuffer "Arduino new sketch file: ")))
312 (let ((default-directory (expand-file-name arduino-mode-home
)))
315 ;;; generate .clang_complete file for `irony-mode' and `company-irony-c-headers'.
316 (defun arduino-generate-include-path-file ()
317 "Generate .clang_complete file for `irony-mode' and `company-irony-c-headers'."
319 (let ((default-directory (expand-file-name arduino-mode-home
))
320 (filename ".clang_complete"))
321 (if (file-exists-p filename
)
322 (if (y-or-n-p ".clang_complete file already exist, do you want to edit it? ")
323 (find-file filename
))
324 (with-temp-file filename
325 (insert "-I/home/stardiviner/Arduino/libraries/")))))
329 (define-derived-mode arduino-mode c-mode
"arduino"
330 "Major mode for editing Arduino code."
331 ;; For `cc-mode' initialize.
332 (c-initialize-cc-mode t
)
333 ;; `c-init-language-vars' is a macro that is expanded at compile time to a
334 ;; large `setq' with all the language variables and their customized values
336 (c-init-language-vars arduino-mode
)
337 ;; `c-common-init' initializes most of the components of a CC Mode buffer,
338 ;; including setup of the mode menu, font-lock, etc. There's also a lower
339 ;; level routine `c-basic-common-init' that only makes the necessary
340 ;; initialization to get the syntactic analysis and similar things working.
341 (c-common-init 'arduino-mode
)
343 (set (make-local-variable 'c-basic-offset
) 2)
344 (set (make-local-variable 'tab-width
) 2)
346 (if (fboundp 'flycheck-mode
) (flycheck-arduino-setup)))
349 (add-to-list 'auto-mode-alist
'("\\.pde\\'" . arduino-mode
))
351 (add-to-list 'auto-mode-alist
'("\\.ino\\'" . arduino-mode
))
353 (provide 'arduino-mode
)
354 ;;; arduino-mode.el ends here