| 1 |
;;; javascript-mode.el --- major mode for editing JavaScript code |
|---|
| 2 |
|
|---|
| 3 |
;; Copyright (C) 1997-2001 Steven Champeon |
|---|
| 4 |
;; 2002 Ville Skytt? |
|---|
| 5 |
|
|---|
| 6 |
;; Author: 1997 Steven Champeon <schampeo@hesketh.com> |
|---|
| 7 |
;; Maintainer: Ville Skytt? <scop@xemacs.org> |
|---|
| 8 |
;; Keywords: languages javascript |
|---|
| 9 |
|
|---|
| 10 |
;; This file is part of XEmacs. |
|---|
| 11 |
|
|---|
| 12 |
;; XEmacs is free software; you can redistribute it and/or modify it |
|---|
| 13 |
;; under the terms of the GNU General Public License as published by |
|---|
| 14 |
;; the Free Software Foundation; either version 2, or (at your option) |
|---|
| 15 |
;; any later version. |
|---|
| 16 |
|
|---|
| 17 |
;; XEmacs is distributed in the hope that it will be useful, but |
|---|
| 18 |
;; WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 19 |
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 20 |
;; General Public License for more details. |
|---|
| 21 |
|
|---|
| 22 |
;; You should have received a copy of the GNU General Public License |
|---|
| 23 |
;; along with XEmacs; see the file COPYING. If not, write to |
|---|
| 24 |
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|---|
| 25 |
;; Boston, MA 02111-1307, USA. |
|---|
| 26 |
|
|---|
| 27 |
;; Synched up with: not in GNU Emacs. |
|---|
| 28 |
|
|---|
| 29 |
;;; Commentary: |
|---|
| 30 |
|
|---|
| 31 |
;; javascript-mode was originally derived from java-cust.el |
|---|
| 32 |
;; (by Jonathan Payne) by Steven Champeon. It has been modified |
|---|
| 33 |
;; a lot afterwards by Ville Skytt?. |
|---|
| 34 |
|
|---|
| 35 |
;; Contributors: |
|---|
| 36 |
;; Sreng Truong (bug fix for 21.1) |
|---|
| 37 |
;; Sebastian Delmont (fix for prototype function indentation problems) |
|---|
| 38 |
;; Stefan Schlee (GNU Emacs compatibility fixes) |
|---|
| 39 |
|
|---|
| 40 |
;; TODO: |
|---|
| 41 |
;; - Multiple font-lock/highlight levels. |
|---|
| 42 |
;; - Investigate if Semantic Bovinator should be used. |
|---|
| 43 |
;; - Check syntax-table stuff. |
|---|
| 44 |
|
|---|
| 45 |
;;; Code: |
|---|
| 46 |
|
|---|
| 47 |
(require 'cc-mode) |
|---|
| 48 |
(require 'comint) |
|---|
| 49 |
|
|---|
| 50 |
(eval-when-compile |
|---|
| 51 |
(require 'regexp-opt) |
|---|
| 52 |
(require 'font-lock) |
|---|
| 53 |
(require 'speedbar) |
|---|
| 54 |
) |
|---|
| 55 |
|
|---|
| 56 |
;; ------------------------------------------------------------------------ ;; |
|---|
| 57 |
|
|---|
| 58 |
(defconst javascript-mode-version "1.7" "Version of `javascript-mode'.") |
|---|
| 59 |
|
|---|
| 60 |
;; ------------------------------------------------------------------------ ;; |
|---|
| 61 |
|
|---|
| 62 |
(defgroup javascript nil |
|---|
| 63 |
"Major mode for editing JavaScript code." |
|---|
| 64 |
:tag "JavaScript" |
|---|
| 65 |
:group 'languages |
|---|
| 66 |
:prefix "javascript-") |
|---|
| 67 |
|
|---|
| 68 |
(defcustom javascript-mode-hook nil |
|---|
| 69 |
"Hook for customizing `javascript-mode'." |
|---|
| 70 |
:group 'javascript |
|---|
| 71 |
:type 'hook) |
|---|
| 72 |
|
|---|
| 73 |
(defgroup javascript-shell nil |
|---|
| 74 |
"JavaScript shell options." |
|---|
| 75 |
:group 'javascript |
|---|
| 76 |
:prefix "javascript-shell-") |
|---|
| 77 |
|
|---|
| 78 |
(defcustom javascript-shell-command "jsshell" |
|---|
| 79 |
"*Command for starting `javascript-shell'. |
|---|
| 80 |
Set arguments for this command in `javascript-shell-command-args'." |
|---|
| 81 |
:type 'string |
|---|
| 82 |
:group 'javascript-shell) |
|---|
| 83 |
|
|---|
| 84 |
(defcustom javascript-shell-command-args '() |
|---|
| 85 |
"*Command line arguments for `javascript-shell-command'." |
|---|
| 86 |
:type '(repeat (string :tag "Argument")) |
|---|
| 87 |
:group 'javascript-shell) |
|---|
| 88 |
|
|---|
| 89 |
(defcustom javascript-shell-prompt-pattern "^js> *" |
|---|
| 90 |
"*JavaScript shell prompt pattern." |
|---|
| 91 |
:type 'regexp |
|---|
| 92 |
:group 'javascript-shell) |
|---|
| 93 |
|
|---|
| 94 |
(defcustom javascript-shell-mode-hook nil |
|---|
| 95 |
"Hook for customizing `javascript-shell-mode'." |
|---|
| 96 |
:type 'hook |
|---|
| 97 |
:group 'javascript-shell) |
|---|
| 98 |
|
|---|
| 99 |
;; ------------------------------------------------------------------------ ;; |
|---|
| 100 |
|
|---|
| 101 |
(defvar javascript-mode-abbrev-table nil |
|---|
| 102 |
"Abbrev table in use in `javascript-mode' buffers.") |
|---|
| 103 |
(define-abbrev-table 'javascript-mode-abbrev-table ()) |
|---|
| 104 |
|
|---|
| 105 |
;; ------------------------------------------------------------------------ ;; |
|---|
| 106 |
|
|---|
| 107 |
(defvar javascript-mode-map nil |
|---|
| 108 |
"Keymap used in `javascript-mode' buffers.") |
|---|
| 109 |
(if javascript-mode-map |
|---|
| 110 |
() |
|---|
| 111 |
(setq javascript-mode-map (copy-keymap c++-mode-map)) |
|---|
| 112 |
(define-key javascript-mode-map [(meta backspace)] 'backward-kill-word) |
|---|
| 113 |
(define-key javascript-mode-map [(meta backward)] 'backward-kill-word) |
|---|
| 114 |
(define-key javascript-mode-map [(meta delete)] 'backward-kill-word) |
|---|
| 115 |
(define-key javascript-mode-map [(meta control h)] 'backward-kill-word) |
|---|
| 116 |
) |
|---|
| 117 |
|
|---|
| 118 |
;; ------------------------------------------------------------------------ ;; |
|---|
| 119 |
|
|---|
| 120 |
;; Reserved words in JavaScript. |
|---|
| 121 |
(defconst javascript-reserved-words |
|---|
| 122 |
(eval-when-compile |
|---|
| 123 |
(regexp-opt |
|---|
| 124 |
'( |
|---|
| 125 |
"abstract" |
|---|
| 126 |
"boolean" |
|---|
| 127 |
"break" |
|---|
| 128 |
"byte" |
|---|
| 129 |
"case" |
|---|
| 130 |
"catch" |
|---|
| 131 |
"char" |
|---|
| 132 |
"class" |
|---|
| 133 |
"const" |
|---|
| 134 |
"continue" |
|---|
| 135 |
"debugger" |
|---|
| 136 |
"default" |
|---|
| 137 |
"delete" |
|---|
| 138 |
"do" |
|---|
| 139 |
"double" |
|---|
| 140 |
"else" |
|---|
| 141 |
"enum" |
|---|
| 142 |
"export" |
|---|
| 143 |
"extends" |
|---|
| 144 |
"false" |
|---|
| 145 |
"final" |
|---|
| 146 |
"finally" |
|---|
| 147 |
"float" |
|---|
| 148 |
"for" |
|---|
| 149 |
"function" |
|---|
| 150 |
"goto" |
|---|
| 151 |
"if" |
|---|
| 152 |
"implements" |
|---|
| 153 |
"import" |
|---|
| 154 |
"in" |
|---|
| 155 |
"instanceof" |
|---|
| 156 |
"int" |
|---|
| 157 |
"interface" |
|---|
| 158 |
"long" |
|---|
| 159 |
"native" |
|---|
| 160 |
"new" |
|---|
| 161 |
"null" |
|---|
| 162 |
"package" |
|---|
| 163 |
"private" |
|---|
| 164 |
"protected" |
|---|
| 165 |
"public" |
|---|
| 166 |
"return" |
|---|
| 167 |
"short" |
|---|
| 168 |
"static" |
|---|
| 169 |
"super" |
|---|
| 170 |
"switch" |
|---|
| 171 |
"synchronized" |
|---|
| 172 |
"this" |
|---|
| 173 |
"throw" |
|---|
| 174 |
"throws" |
|---|
| 175 |
"transient" |
|---|
| 176 |
"true" |
|---|
| 177 |
"try" |
|---|
| 178 |
"typeof" |
|---|
| 179 |
"var" |
|---|
| 180 |
"void" |
|---|
| 181 |
"volatile" |
|---|
| 182 |
"while" |
|---|
| 183 |
"with" |
|---|
| 184 |
) t)) |
|---|
| 185 |
"Expression for matching reserved words in `javascript-mode' buffers. |
|---|
| 186 |
|
|---|
| 187 |
From Core JavaScript Reference 1.5, Appendix A (Reserved Words): |
|---|
| 188 |
<http://developer.netscape.com/docs/manuals/js/core/jsref15/keywords.html>") |
|---|
| 189 |
|
|---|
| 190 |
|
|---|
| 191 |
;; JavaScript identifiers |
|---|
| 192 |
;; This one is intentionally not too strict... |
|---|
| 193 |
(defconst javascript-identifier |
|---|
| 194 |
"[a-zA-Z_\\$][a-zA-Z0-9_\\$]*" |
|---|
| 195 |
"Expression for matching identifiers in `javascript-mode' buffers. |
|---|
| 196 |
|
|---|
| 197 |
From Core JavaScript Guide 1.5, Chapter 2 (Values, Variables and Literals): |
|---|
| 198 |
<http://developer.netscape.com/docs/manuals/js/core/jsguide15/ident.html>") |
|---|
| 199 |
|
|---|
| 200 |
;; ------------------------------------------------------------------------ ;; |
|---|
| 201 |
|
|---|
| 202 |
;; Font lock keywords |
|---|
| 203 |
(defconst javascript-font-lock-keywords |
|---|
| 204 |
(list |
|---|
| 205 |
|
|---|
| 206 |
;; Reserved words. |
|---|
| 207 |
(cons (concat |
|---|
| 208 |
"\\(^\\|[ \t;{(]\\)\\(" |
|---|
| 209 |
javascript-reserved-words |
|---|
| 210 |
"\\)[ \t\n(){};,]") |
|---|
| 211 |
'(2 'font-lock-keyword-face)) |
|---|
| 212 |
|
|---|
| 213 |
;; Function declarations. |
|---|
| 214 |
(cons (concat |
|---|
| 215 |
"\\(^\\|[ \t;{]\\)function[ \t]+\\(" |
|---|
| 216 |
javascript-identifier |
|---|
| 217 |
"\\)") |
|---|
| 218 |
'(2 'font-lock-function-name-face)) |
|---|
| 219 |
;; This would catch both declarations and calls. |
|---|
| 220 |
;(cons (concat |
|---|
| 221 |
; "\\(^\\|[ \t.;{(]\\)\\(" |
|---|
| 222 |
; javascript-identifier |
|---|
| 223 |
; "\\)[ \t]*(") |
|---|
| 224 |
; '(2 'font-lock-function-name-face)) |
|---|
| 225 |
|
|---|
| 226 |
;; Variables and constants. |
|---|
| 227 |
(cons (concat |
|---|
| 228 |
"\\(^\\|[ \t;{(]\\)\\(const\\|var\\)[ \t]+\\(" |
|---|
| 229 |
javascript-identifier |
|---|
| 230 |
"\\)") |
|---|
| 231 |
'(3 'font-lock-variable-name-face)) |
|---|
| 232 |
;; This would catch more of them and properties as well. |
|---|
| 233 |
;(cons (concat |
|---|
| 234 |
; "\\(^\\|[ \t(\\[\\.{;]\\)\\(" |
|---|
| 235 |
; javascript-identifier |
|---|
| 236 |
; "\\)[ \t]*[^(]") |
|---|
| 237 |
; '(2 'font-lock-variable-name-face)) |
|---|
| 238 |
|
|---|
| 239 |
) |
|---|
| 240 |
"Highlighting rules for `javascript-mode' buffers.") |
|---|
| 241 |
|
|---|
| 242 |
;; ------------------------------------------------------------------------ ;; |
|---|
| 243 |
|
|---|
| 244 |
;;;###autoload |
|---|
| 245 |
(defun javascript-mode () |
|---|
| 246 |
"Major mode for editing JavaScript code. |
|---|
| 247 |
|
|---|
| 248 |
See the documentation for `c++-mode': JavaScript mode is an extension of it. |
|---|
| 249 |
Use the hook `javascript-mode-hook' to execute custom code when entering |
|---|
| 250 |
JavaScript mode. |
|---|
| 251 |
|
|---|
| 252 |
\\{javascript-mode-map}" |
|---|
| 253 |
(interactive) |
|---|
| 254 |
|
|---|
| 255 |
(let ((current-c++-mode-hook (and (boundp 'c++-mode-hook) c++-mode-hook))) |
|---|
| 256 |
|
|---|
| 257 |
;; Temporarily disable the c++-mode hook; don't wanna run |
|---|
| 258 |
;; it when loading up c++-mode. |
|---|
| 259 |
(setq c++-mode-hook nil) |
|---|
| 260 |
(c++-mode) |
|---|
| 261 |
|
|---|
| 262 |
;; Do our stuff. |
|---|
| 263 |
(setq major-mode 'javascript-mode mode-name "JavaScript") |
|---|
| 264 |
(use-local-map javascript-mode-map) |
|---|
| 265 |
(setq local-abbrev-table javascript-mode-abbrev-table) |
|---|
| 266 |
(c-set-offset 'inher-cont '+) |
|---|
| 267 |
|
|---|
| 268 |
;; Change menu name. Kudos to Geert Ribbers. |
|---|
| 269 |
(easy-menu-remove '("C++")) |
|---|
| 270 |
(easy-menu-add (c-mode-menu "JavaScript") javascript-mode-map) |
|---|
| 271 |
|
|---|
| 272 |
;; GNU Emacs reportedly needs this for font locking to work properly. |
|---|
| 273 |
(unless (featurep 'xemacs) |
|---|
| 274 |
(set (make-local-variable 'font-lock-defaults) |
|---|
| 275 |
'(javascript-font-lock-keywords nil nil))) |
|---|
| 276 |
|
|---|
| 277 |
;; cc-mode does not handle JavaScript prototype function declarations well. |
|---|
| 278 |
;; Thanks to Sebastian Delmont. |
|---|
| 279 |
(set (make-local-variable 'c-lambda-key) "function") |
|---|
| 280 |
(c-set-offset 'inlambda 0) |
|---|
| 281 |
|
|---|
| 282 |
;; Restore the original c++-mode-hook. |
|---|
| 283 |
(setq c++-mode-hook current-c++-mode-hook) |
|---|
| 284 |
|
|---|
| 285 |
(run-hooks 'javascript-mode-hook))) |
|---|
| 286 |
|
|---|
| 287 |
;; ------------------------------------------------------------------------ ;; |
|---|
| 288 |
|
|---|
| 289 |
;;;###autoload |
|---|
| 290 |
(defun javascript-shell () |
|---|
| 291 |
"Run a JavaScript shell as an inferior process. |
|---|
| 292 |
|
|---|
| 293 |
Use the `javascript-shell-command' variable to set the command and |
|---|
| 294 |
`javascript-shell-command-args' for its arguments to specify the |
|---|
| 295 |
command line that invokes your preferred JavaScript shell. |
|---|
| 296 |
|
|---|
| 297 |
Free JavaScript shell implementations are available for example from |
|---|
| 298 |
<http://www.mozilla.org/js/>. |
|---|
| 299 |
|
|---|
| 300 |
Usage examples: command arguments |
|---|
| 301 |
Mozilla SpiderMonkey jsshell |
|---|
| 302 |
Mozilla Rhino java -jar /path/to/js.jar" |
|---|
| 303 |
|
|---|
| 304 |
(interactive) |
|---|
| 305 |
|
|---|
| 306 |
(unless (comint-check-proc "*JavaScript*") |
|---|
| 307 |
(set-buffer |
|---|
| 308 |
(apply 'make-comint "JavaScript" |
|---|
| 309 |
javascript-shell-command nil javascript-shell-command-args)) |
|---|
| 310 |
(javascript-shell-mode) |
|---|
| 311 |
) |
|---|
| 312 |
|
|---|
| 313 |
(pop-to-buffer "*JavaScript*") |
|---|
| 314 |
) |
|---|
| 315 |
|
|---|
| 316 |
|
|---|
| 317 |
(defun javascript-shell-mode () |
|---|
| 318 |
"Major mode for interacting with a JavaScript shell." |
|---|
| 319 |
(comint-mode) |
|---|
| 320 |
(setq comint-prompt-regexp javascript-shell-prompt-pattern) |
|---|
| 321 |
(setq mode-name 'javascript-shell-mode) |
|---|
| 322 |
(setq mode-name "JavaScript Shell") |
|---|
| 323 |
(setq mode-line-process '(":%s")) |
|---|
| 324 |
(run-hooks 'javascript-shell-mode-hook) |
|---|
| 325 |
) |
|---|
| 326 |
|
|---|
| 327 |
;; ------------------------------------------------------------------------ ;; |
|---|
| 328 |
|
|---|
| 329 |
;;;###autoload |
|---|
| 330 |
(add-to-list 'auto-mode-alist '("\\.js$" . javascript-mode)) |
|---|
| 331 |
|
|---|
| 332 |
;; Speedbar handling |
|---|
| 333 |
(if (fboundp 'speedbar-add-supported-extension) |
|---|
| 334 |
(speedbar-add-supported-extension ".js")) |
|---|
| 335 |
|
|---|
| 336 |
;; ------------------------------------------------------------------------ ;; |
|---|
| 337 |
|
|---|
| 338 |
(provide 'javascript-mode) |
|---|
| 339 |
|
|---|
| 340 |
;;; javascript-mode.el ends here |
|---|