-;;; js.el --- Major mode for editing JavaScript
+;;; js.el --- Major mode for editing JavaScript -*- lexical-binding: t -*-
-;; Copyright (C) 2008-2011 Free Software Foundation, Inc.
+;; Copyright (C) 2008-2012 Free Software Foundation, Inc.
;; Author: Karl Landstrom <karl.landstrom@brgeight.se>
;; Daniel Colascione <dan.colascione@gmail.com>
(defvar inferior-moz-buffer)
(defvar moz-repl-name)
(defvar ido-cur-list)
+(defvar electric-layout-rules)
(declare-function ido-mode "ido")
(declare-function inferior-moz-process "ext:mozrepl" ())
;; must be h-end.
;;
;; js--pitem instances are never modified (with the exception
-;; of the b-end field). Instead, modified copies are added at subseqnce parse points.
+;; of the b-end field). Instead, modified copies are added at
+;; subsequence parse points.
;; (The exception for b-end and its caveats is described below.)
;;
(defvar js-mode-map
(let ((keymap (make-sparse-keymap)))
- (mapc (lambda (key)
- (define-key keymap key #'js-insert-and-indent))
- '("{" "}" "(" ")" ":" ";" ","))
(define-key keymap [(control ?c) (meta ?:)] #'js-eval)
(define-key keymap [(control ?c) (control ?j)] #'js-set-js-context)
(define-key keymap [(control meta ?x)] #'js-eval-defun)
keymap)
"Keymap for `js-mode'.")
-(defun js-insert-and-indent (key)
- "Run the command bound to KEY, and indent if necessary.
-Indentation does not take place if point is in a string or
-comment."
- (interactive (list (this-command-keys)))
- (call-interactively (lookup-key (current-global-map) key))
- (let ((syntax (save-restriction (widen) (syntax-ppss))))
- (when (or (and (not (nth 8 syntax))
- js-auto-indent-flag)
- (and (nth 4 syntax)
- (eq (current-column)
- (1+ (current-indentation)))))
- (indent-according-to-mode))))
-
-
;;; Syntax table and parsing
(defvar js-mode-syntax-table
(c-save-buffer-state
(open-items
- orig-match-start
- orig-match-end
- orig-depth
parse
prev-parse-point
name
case-fold-search
filtered-class-styles
- new-item
- goal-point
- end-prop)
+ goal-point)
;; Figure out which class styles we need to look for
(setq filtered-class-styles
;; Like (up-list -1), but only considers lists that end nearby"
(defun js--up-nearby-list ()
(save-restriction
- ;; Look at a very small region so our compuation time doesn't
+ ;; Look at a very small region so our computation time doesn't
;; explode in pathological cases.
(narrow-to-region (max (point-min) (- (point) 500)) (point))
(up-list -1)))
(defun js-syntactic-context ()
"Return the JavaScript syntactic context at point.
-When called interatively, also display a message with that
+When called interactively, also display a message with that
context."
(interactive)
(let* ((syntactic-context (js--syntactic-context-from-pstate
js--font-lock-keywords-3)
"Font lock keywords for `js-mode'. See `font-lock-keywords'.")
-;; XXX: Javascript can continue a regexp literal across lines so long
-;; as the newline is escaped with \. Account for that in the regexp
-;; below.
-(eval-and-compile
- (defconst js--regexp-literal
- "[=(,:]\\(?:\\s-\\|\n\\)*\\(/\\)\\(?:\\\\.\\|[^/*\\]\\)\\(?:\\\\.\\|[^/\\]\\)*\\(/\\)"
- "Regexp matching a JavaScript regular expression literal.
-Match groups 1 and 2 are the characters forming the beginning and
-end of the literal."))
-
-(defconst js-syntax-propertize-function
- (syntax-propertize-rules
- ;; We want to match regular expressions only at the beginning of
- ;; expressions.
- (js--regexp-literal (1 "\"") (2 "\""))))
+(defun js-syntax-propertize-regexp (end)
+ (when (eq (nth 3 (syntax-ppss)) ?/)
+ ;; A /.../ regexp.
+ (when (re-search-forward "\\(?:\\=\\|[^\\]\\)\\(?:\\\\\\\\\\)*/" end 'move)
+ (put-text-property (1- (point)) (point)
+ 'syntax-table (string-to-syntax "\"/")))))
+
+(defun js-syntax-propertize (start end)
+ ;; Javascript allows immediate regular expression objects, written /.../.
+ (goto-char start)
+ (js-syntax-propertize-regexp end)
+ (funcall
+ (syntax-propertize-rules
+ ;; Distinguish /-division from /-regexp chars (and from /-comment-starter).
+ ;; FIXME: Allow regexps after infix ops like + ...
+ ;; https://developer.mozilla.org/en/JavaScript/Reference/Operators
+ ;; We can probably just add +, -, !, <, >, %, ^, ~, |, &, ?, : at which
+ ;; point I think only * and / would be missing which could also be added,
+ ;; but need care to avoid affecting the // and */ comment markers.
+ ("\\(?:^\\|[=([{,:;]\\)\\(?:[ \t]\\)*\\(/\\)[^/*]"
+ (1 (ignore
+ (forward-char -1)
+ (when (or (not (memq (char-after (match-beginning 0)) '(?\s ?\t)))
+ ;; If the / is at the beginning of line, we have to check
+ ;; the end of the previous text.
+ (save-excursion
+ (goto-char (match-beginning 0))
+ (forward-comment (- (point)))
+ (memq (char-before)
+ (eval-when-compile (append "=({[,:;" '(nil))))))
+ (put-text-property (match-beginning 1) (match-end 1)
+ 'syntax-table (string-to-syntax "\"/"))
+ (js-syntax-propertize-regexp end))))))
+ (point) end))
;;; Indentation
(defun js-c-fill-paragraph (&optional justify)
"Fill the paragraph with `c-fill-paragraph'."
(interactive "*P")
- (flet ((c-forward-sws
- (&optional limit)
- (js--forward-syntactic-ws limit))
- (c-backward-sws
- (&optional limit)
- (js--backward-syntactic-ws limit))
- (c-beginning-of-macro
- (&optional limit)
- (js--beginning-of-macro limit)))
+ (letf (((symbol-function 'c-forward-sws)
+ (lambda (&optional limit)
+ (js--forward-syntactic-ws limit)))
+ ((symbol-function 'c-backward-sws)
+ (lambda (&optional limit)
+ (js--backward-syntactic-ws limit)))
+ ((symbol-function 'c-beginning-of-macro)
+ (lambda (&optional limit)
+ (js--beginning-of-macro limit))))
(let ((fill-paragraph-function 'c-fill-paragraph))
(c-fill-paragraph justify))))
(ido-mode -1))
(with-js
- (lexical-let ((tabs (js--get-tabs)) selected-tab-cname
- selected-tab prev-hitab)
+ (let ((tabs (js--get-tabs)) selected-tab-cname
+ selected-tab prev-hitab)
;; Disambiguate names
(setq tabs (loop with tab-names = (make-hash-table :test 'equal)
'(js> ((fifth hitab) "selectedTab") (fourth hitab))
cmds)))
- ;; Hilighting whole window
+ ;; Highlighting whole window
((third hitab)
(push '(js! ((third hitab) "document"
"documentElement" "setAttribute")
"gBrowser"
"selectedTab")
- with index = 0
for match in ido-matches
for candidate-tab = (find-tab-by-cname match)
if (eq (fourth candidate-tab) tab-to-match)
(set (make-local-variable 'font-lock-defaults)
(list js--font-lock-keywords))
(set (make-local-variable 'syntax-propertize-function)
- js-syntax-propertize-function)
+ #'js-syntax-propertize)
(set (make-local-variable 'parse-sexp-ignore-comments) t)
(set (make-local-variable 'parse-sexp-lookup-properties) t)
#'js--which-func-joiner)
;; Comments
- (setq comment-start "// ")
- (setq comment-end "")
+ (set (make-local-variable 'comment-start) "// ")
+ (set (make-local-variable 'comment-end) "")
(set (make-local-variable 'fill-paragraph-function)
'js-c-fill-paragraph)
c-comment-start-regexp "/[*/]\\|\\s!"
comment-start-skip "\\(//+\\|/\\*+\\)\\s *")
+ (set (make-local-variable 'electric-indent-chars)
+ (append "{}():;," electric-indent-chars)) ;FIXME: js2-mode adds "[]*".
+ (set (make-local-variable 'electric-layout-rules)
+ '((?\; . after) (?\{ . after) (?\} . before)))
+
(let ((c-buffer-is-cc-mode t))
;; FIXME: These are normally set by `c-basic-common-init'. Should
;; we call it instead? (Bug#6071)
;; etc. and produce maddening "unbalanced parenthesis" errors.
;; When we attempt to find the error and scroll to the portion of
;; the buffer containing the problem, JIT-lock will apply the
- ;; correct syntax to the regular expresion literal and the problem
+ ;; correct syntax to the regular expression literal and the problem
;; will mysteriously disappear.
;; FIXME: We should actually do this fontification lazily by adding
;; calls to syntax-propertize wherever it's really needed.