bump version for package update info
[arduino-mode.git] / arduino-mode.el
blob76516264047fd92a93c0b33a96a2286e358977b9
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"))
8 ;; Version: 1.3.1
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)
14 ;; any later version.
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.
26 ;;; Commentary:
28 ;; Arduino IDE for Emacs developer.
30 ;;; Code:
31 (require 'cc-mode)
32 (require 'spinner)
34 (eval-when-compile
35 (require 'cl-lib)
36 (require 'cc-langs)
37 (require 'cc-fonts)
38 (require 'cc-menus)
39 (require 'term))
41 (eval-and-compile
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-"
50 :group 'arduino)
52 (defcustom arduino-mode-home "~/Arduino"
53 "The path of ARDUINO_HOME."
54 :type 'directory
55 :group 'arduino-mode)
57 (c-lang-defconst c-primitive-type-kwds
58 arduino (append '(;; Data Types
59 "boolean" "byte"
60 "int" "long" "short" "double" "float"
61 "char" "string"
62 "unsigned char" "unsigned int" "unsigned long"
63 "void" "word"
64 ;; Variable Scope & Qualifiers
65 "const" "scope" "static" "volatile"
66 ;; Structure
67 ;; Sketch
68 "loop" "setup"
69 ;; Control Structure
70 "break" "continue" "do" "while" "else" "for" "goto" "if"
71 "return" "switch" "case"
72 ;; Utilities
73 "PROGMEM")
74 (c-lang-const c-primitive-type-kwds)))
76 (c-lang-defconst c-constant-kwds
77 arduino (append
78 '("HIGH" "LOW"
79 "INPUT" "OUTPUT" "INPUT_PULLUP"
80 "LED_BUILTIN"
81 "true" "false")
82 (c-lang-const c-constant-kwds)))
84 (c-lang-defconst c-simple-stmt-kwds
85 arduino
86 (append
87 '(;; Operator Utilities
88 "sizeof"
89 ;; Functions
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
102 ;; Characters
103 "isAlpha" "isAlphaNumeric"
104 "isAscii" "isControl" "isDigit" "isGraph" "isHexadecimalDigit"
105 "isLowerCase" "isUpperCase"
106 "isPrintable" "isPunct" "isSpace" "isWhitespace"
107 ;; USB Devices like Keyboard functions
108 "print" "println"
109 ;; Serial
110 "begin" "end" "available" "read" "flush" "peek"
111 ;; Keyboard
112 "write" "press" "release" "releaseAll"
113 ;; Mouse
114 "click" "move" "isPressed")
115 (c-lang-const c-simple-stmt-kwds)))
117 (c-lang-defconst c-primary-expr-kwds
118 arduino (append
119 '(;; Communication
120 "Serial"
121 ;; USB (Leonoardo based boards and Due only)
122 "Keyboard"
123 "Mouse")
124 (c-lang-const c-primary-expr-kwds)))
126 (defgroup arduino nil "Arduino mode customizations"
127 :group 'languages)
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."
132 :group 'arduino
133 :type 'list)
135 (defcustom arduino-executable "arduino"
136 "The arduino program executable name."
137 :group 'arduino
138 :type 'string)
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."
145 :type 'symbol
146 :safe #'symbolp
147 :group 'arduino)
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)
184 map)
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."
207 (interactive)
208 (setq arduino-upload-process-buf (buffer-name))
209 (let* ((proc-name "arduino-upload")
210 (proc-buffer "*arduino-upload*"))
211 (make-process
212 :command (list arduino-executable "--upload" (buffer-file-name))
213 :name proc-name
214 :buffer proc-buffer
215 :sentinel (lambda (_proc event)
216 (if (string= event "finished\n")
217 (progn
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."
233 (interactive)
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'.
239 (make-process
240 :command (list arduino-executable "--verify" (buffer-file-name))
241 :name proc-name
242 :buffer proc-buffer
243 :sentinel (lambda (_proc event)
244 (if (string= event "finished\n")
245 (progn
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."
260 (interactive)
261 (setq arduino-open-process-buf (buffer-name))
262 (let* ((proc-name "arduino-open")
263 (proc-buffer "*arduino-open*"))
264 (make-process
265 :command (list arduino-executable (buffer-file-name))
266 :name proc-name
267 :buffer proc-buffer
268 :sentinel (lambda (_proc event)
269 (if (string= event "finished\n")
270 (progn
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: "
285 "arduino:sam")))
286 (start-process
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: "
294 "Bridge:1.0.0")))
295 (start-process
296 "arduino-install-library"
297 "*arduino-install-library*"
298 arduino-executable "--install-library" library))
300 (require 'term)
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)))))
308 ;;;###autoload
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)))
313 (find-file sketch)))
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'."
318 (interactive)
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/")))))
328 ;;;###autoload
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
335 ;; for our language.
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)))
348 ;;;###autoload
349 (add-to-list 'auto-mode-alist '("\\.pde\\'" . arduino-mode))
350 ;;;###autoload
351 (add-to-list 'auto-mode-alist '("\\.ino\\'" . arduino-mode))
353 (provide 'arduino-mode)
354 ;;; arduino-mode.el ends here