prog-modes / javascript-mode.el

Full commit
;;; javascript-mode.el --- major mode for editing JavaScript code

;; Copyright (C) 1997-2001 Steven Champeon
;;               2002      Ville Skyttä

;; Author:     1997 Steven Champeon <>
;; Maintainer: Ville Skyttä <>
;; Keywords:   languages javascript

;; This file is part of XEmacs.

;; XEmacs is free software; you can redistribute it and/or modify it
;; under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; XEmacs is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with XEmacs; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;; Synched up with: not in GNU Emacs.

;;; Commentary:

;; javascript-mode was originally derived from java-cust.el
;; (by Jonathan Payne) by Steven Champeon. It has been modified
;; a lot afterwards by Ville Skyttä.

;; Contributors:
;;   Sreng Truong      (bug fix for 21.1)
;;   Sebastian Delmont (fix for prototype function indentation problems)

;; TODO:
;; - Multiple font-lock/highlight levels.
;; - Investigate if Semantic Bovinator should be used.
;; - Check syntax-table stuff.

;;; Code:

(require 'cc-mode)
(require 'comint)

  (require 'regexp-opt)
  (require 'font-lock)
  (require 'speedbar)

;; ------------------------------------------------------------------------ ;;

(defconst javascript-mode-version "1.5" "Version of `javascript-mode'.")

;; ------------------------------------------------------------------------ ;;

(defgroup javascript nil
  "Major mode for editing JavaScript code."
  :group 'languages
  :prefix "javascript-")

(defcustom javascript-mode-hook nil
  "Hook for customizing `javascript-mode'."
  :group 'javascript
  :type 'hook)

(defgroup javascript-shell nil
  "JavaScript shell options."
  :group 'javascript
  :prefix "javascript-shell-")

(defcustom javascript-shell-command "jsshell"
  "*Command for starting `javascript-shell'.
Set arguments for this command in `javascript-shell-command-args'."
  :type 'string
  :group 'javascript-shell)

(defcustom javascript-shell-command-args '()
  "*Command line arguments for `javascript-shell-command'."
  :type '(repeat (string :tag "Argument"))
  :group 'javascript-shell)

(defcustom javascript-shell-prompt-pattern "^js> *"
  "*JavaScript shell prompt pattern."
  :type 'regexp
  :group 'javascript-shell)

(defcustom javascript-shell-mode-hook nil
  "Hook for customizing `javascript-shell-mode'."
  :type 'hook
  :group 'javascript-shell)

;; ------------------------------------------------------------------------ ;;

(defvar javascript-mode-abbrev-table nil
  "Abbrev table in use in `javascript-mode' buffers.")
(define-abbrev-table 'javascript-mode-abbrev-table ())

;; ------------------------------------------------------------------------ ;;

(defvar javascript-mode-map nil
  "Keymap used in `javascript-mode' buffers.")
(if javascript-mode-map
  (setq javascript-mode-map (copy-keymap c++-mode-map))
  (define-key javascript-mode-map '(meta backspace) 'backward-kill-word)
  (define-key javascript-mode-map '(meta backward)  'backward-kill-word)
  (define-key javascript-mode-map '(meta delete)    'backward-kill-word)
  (define-key javascript-mode-map '(meta control h) 'backward-kill-word)

;; ------------------------------------------------------------------------ ;;

;; Reserved words in JavaScript.
(defconst javascript-reserved-words
       ) t))
  "Expression for matching reserved words in `javascript-mode' buffers.

From Core JavaScript Reference 1.5, Appendix A (Reserved Words):

;; JavaScript identifiers
;; This one is intentionally not too strict...
(defconst javascript-identifier
  "Expression for matching identifiers in `javascript-mode' buffers.

From Core JavaScript Guide 1.5, Chapter 2 (Values, Variables and Literals):

;; ------------------------------------------------------------------------ ;;

;; Font lock keywords
(defconst javascript-font-lock-keywords

   ;; Reserved words.
   (list (concat
          "\\(^\\|[ \t;{]\\)\\("
          "\\)[ \t\n(){};,]")

   ;; Function declarations.
   (list (concat
          "\\(^\\|[ \t;{]\\)function[ \t]+\\("
   ; This would catch both declarations and calls.
   ;(list (concat
   ;       "\\(^\\|[ \t.;{(]\\)\\("
   ;       javascript-identifier
   ;       "\\)[ \t]*(")
   ;      2
   ;      'font-lock-function-name-face)

   ;; Variables and constants.
   (list (concat
          "\\(^\\|[ \t;{(]\\)\\(const\\|var\\)[ \t]+\\("
   ; This would catch more of them and properties as well.
   ;(list (concat
   ;       "\\(^\\|[ \t(\\[\\.{;]\\)\\("
   ;       javascript-identifier
   ;       "\\)[ \t]*[^(]")
   ;      2
   ;      'font-lock-variable-name-face)

  "Highlighting rules for `javascript-mode' buffers.")

;; ------------------------------------------------------------------------ ;;

(defun javascript-mode ()
  "Major mode for editing JavaScript code.

See the documentation for `c++-mode': JavaScript mode is an extension of it.
Use the hook `javascript-mode-hook' to execute custom code when entering
JavaScript mode.

  (let ((current-c++-mode-hook (and (boundp 'c++-mode-hook) c++-mode-hook)))

    ; Temporarily disable the c++-mode hook; don't wanna run
    ; it when loading up c++-mode.
    (setq c++-mode-hook nil)

    ; Do our stuff.
    (setq major-mode 'javascript-mode mode-name "JavaScript")
    (use-local-map javascript-mode-map)
    (setq local-abbrev-table javascript-mode-abbrev-table)
    (c-set-offset 'inher-cont '+)

    ; cc-mode does not handle JavaScript prototype function declarations well.
    ; Thanks to Sebastian Delmont.
    (set (make-local-variable 'c-lambda-key) "function")
    (c-set-offset 'inlambda 0)

    ; Restore the original c++-mode-hook.
    (setq c++-mode-hook current-c++-mode-hook)

    (run-hooks 'javascript-mode-hook)

;; ------------------------------------------------------------------------ ;;

(defun javascript-shell ()
  "Run a JavaScript shell as an inferior process.

Use the `javascript-shell-command' variable to set the command and
`javascript-shell-command-args' for its arguments to specify the
command line that invokes your preferred JavaScript shell.

Free JavaScript shell implementations are available for example from

Usage examples:        command    arguments
 Mozilla SpiderMonkey  jsshell
 Mozilla Rhino         java       -jar /path/to/js.jar"


  (unless (comint-check-proc "*JavaScript*")
     (apply 'make-comint "JavaScript"
            javascript-shell-command nil javascript-shell-command-args))

  (pop-to-buffer "*JavaScript*")

(defun javascript-shell-mode ()
  "Major mode for interacting with a JavaScript shell."
  (setq comint-prompt-regexp javascript-shell-prompt-pattern)
  (setq mode-name 'javascript-shell-mode)
  (setq mode-name "JavaScript Shell")
  (setq mode-line-process '(":%s"))
  (run-hooks 'javascript-shell-mode-hook)

;; ------------------------------------------------------------------------ ;;

(add-to-list 'auto-mode-alist '("\\.js$" . javascript-mode))

;; Speedbar handling
(if (fboundp 'speedbar-add-supported-extension)
    (speedbar-add-supported-extension ".js"))

;; ------------------------------------------------------------------------ ;;

(provide 'javascript-mode)

;;; javascript-mode.el ends here