1 ;;; espresso.el --- Major mode for editing JavaScript source text
2 ;; Copyright (C) 2008 Free Software Foundation, Inc.
3 ;; Copyright (C) 2009 Daniel Colascione <dan.colascione@gmail.com>
4 ;; Author: Karl Landstrom <karl.landstrom@brgeight.se>
5 ;; Author: Daniel Colascione <dan.colascione@gmail.com>
6 ;; Maintainer: Daniel Colascione <dan.colascione@gmail.com>
9 ;; Keywords: languages, oop, javascript
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., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
28 ;; This is based on Karl Landstrom's barebones javascript-mode. This
29 ;; is much more robust and works with cc-mode's comment filling
32 ;; The main features of this JavaScript mode are syntactic
33 ;; highlighting (enabled with `font-lock-mode' or
34 ;; `global-font-lock-mode'), automatic indentation and filling of
35 ;; comments, and C preprocessor fontification.
37 ;; This package has (only) been tested with GNU Emacs 22 (the latest
42 ;; Put this file in a directory where Emacs can find it (`C-h v
43 ;; load-path' for more info). Then add the following lines to your
44 ;; Emacs initialization file:
46 ;; (add-to-list 'auto-mode-alist '("\\.js\\'" . espresso-mode))
47 ;; (autoload 'espresso-mode "espresso" nil t)
51 ;; XXX: This mode assumes that block comments are not nested inside block
52 ;; XXX: comments and that strings do not contain line breaks.
54 ;; Exported names start with "espresso-" whereas private names start
68 ;;; User customization
70 (defgroup espresso nil
71 "Customization variables for `espresso-mode'."
72 :tag "JavaScript - Espresso-Mode"
75 (defcustom espresso-indent-level 4
76 "Number of spaces for each indentation step."
80 (defcustom espresso-expr-indent-offset 0
81 "Number of additional spaces used for indentation of continued
82 expressions. The value must be no less than minus
83 `espresso-indent-level'."
87 (defcustom espresso-auto-indent-flag t
88 "Automatic indentation with punctuation characters. If non-nil, the
89 current line is indented when certain punctuations are inserted."
95 (defvar espresso-mode-map nil
96 "Keymap used in Espresso mode.")
98 (unless espresso-mode-map
99 (setq espresso-mode-map (make-sparse-keymap)))
101 (when espresso-auto-indent-flag
103 (define-key espresso-mode-map key 'espresso-insert-and-indent))
104 '("{" "}" "(" ")" ":" ";" ",")))
106 (defun espresso-insert-and-indent (key)
107 "Runs the command bound to KEY in the global keymap, and if
108 we're not in a string or comment, indents the current line."
109 (interactive (list (this-command-keys)))
110 (call-interactively (lookup-key (current-global-map) key))
111 (let ((syntax (save-restriction (widen) (syntax-ppss))))
112 (unless (nth 8 syntax)
113 (indent-according-to-mode))))
115 ;;; Syntax table and parsing
117 (defvar espresso-mode-syntax-table
118 (let ((table (make-syntax-table)))
119 (c-populate-syntax-table table)
120 (modify-syntax-entry ?$ "_" table)
122 "Syntax table used in Espresso mode.")
124 (defconst espresso--name-start-re "[a-zA-Z_$]"
125 "Matches the first character of a Espresso identifier. No grouping")
127 (defconst espresso--stmt-delim-chars "^;{}?:")
129 (defconst espresso--name-re (concat espresso--name-start-re
130 "\\(?:\\s_\\|\\sw\\)*")
131 "Matches a Javascript name. No grouping.")
133 (defconst espresso--dotted-name-re
134 (concat espresso--name-re "\\(?:\\." espresso--name-re "\\)*")
135 "Matches a dot-separated sequence of Javascript names")
137 (defconst espresso--cpp-name-re espresso--name-re
138 "Matches a C preprocessor name")
140 (defconst espresso--opt-cpp-start "^\\s-*#\\s-*\\([[:alnum:]]+\\)"
141 " Regexp matching the prefix of a cpp directive including the directive
142 name, or nil in languages without preprocessor support. The first
143 submatch surrounds the directive name.")
146 (defconst espresso--class-decls
147 `(; var NewClass = BaseClass.extend(
148 ,(concat "^\\s-*\\_<var\\_>\\s-+"
149 "\\(" espresso--dotted-name-re "\\)"
151 "\\(" espresso--dotted-name-re
152 "\\)\\.extend\\(?:Final\\)?\\s-*(")
154 ; NewClass: BaseClass.extend( ; for nested classes
156 "\\(" espresso--dotted-name-re "\\):"
157 "\\s-*\\(" espresso--dotted-name-re
158 "\\)\\.extend\\(?:Finak\\)?\\s-*("))
159 "List of regular expressions that can match class definitions.
160 Each one must set match group 1 to the name of the class being
161 defined, and optionally, group 2 to the name of the base class.")
163 (defun espresso--regexp-opt-symbol (list)
164 "Like regexp-opt, but surround the optimized regular expression
165 with `\\\\_<' and `\\\\_>'."
166 (concat "\\_<" (regexp-opt list t) "\\_>"))
168 (defun espresso--re-search-forward-inner (regexp &optional bound count)
169 "Auxiliary function for `espresso--re-search-forward'."
171 (orig-macro-end (save-excursion
172 (when (espresso--beginning-of-macro)
175 (saved-point (point-min)))
177 (re-search-forward regexp bound)
178 (setq parse (parse-partial-sexp saved-point (point)))
181 (concat "\\([^\\]\\|^\\)" (string (nth 3 parse)))
182 (save-excursion (end-of-line) (point)) t))
186 (and (eq (char-before) ?\/) (eq (char-after) ?\*)))
187 (re-search-forward "\\*/"))
188 ((and (not (and orig-macro-end
189 (<= (point) orig-macro-end)))
190 (espresso--beginning-of-macro))
193 (setq count (1- count))))
194 (setq saved-point (point))))
198 (defun espresso--re-search-forward (regexp &optional bound noerror count)
199 "Search forward but ignore strings, cpp macros, and comments.
200 Invokes `re-search-forward' but treats the buffer as if strings,
201 cpp macros, and comments have been removed.
203 If invoked while inside a macro, treat the contents of the macro
207 (let ((saved-point (point))
210 '(espresso--re-search-forward-inner regexp bound 1))
212 '(espresso--re-search-backward-inner regexp bound (- count)))
214 '(espresso--re-search-forward-inner regexp bound count)))))
218 (goto-char saved-point)
220 (error (error-message-string err)))))))
223 (defun espresso--re-search-backward-inner (regexp &optional bound count)
224 "Auxiliary function for `espresso--re-search-backward'."
228 (and (espresso--beginning-of-macro)
230 (saved-point (point-min)))
232 (re-search-backward regexp bound)
233 (when (and (> (point) (point-min))
234 (save-excursion (backward-char) (looking-at "/[/*]")))
236 (setq parse (parse-partial-sexp saved-point (point)))
239 (concat "\\([^\\]\\|^\\)" (string (nth 3 parse)))
240 (save-excursion (beginning-of-line) (point)) t))
242 (goto-char (nth 8 parse)))
244 (and (eq (char-before) ?/) (eq (char-after) ?*)))
245 (re-search-backward "/\\*"))
246 ((and (not (and orig-macro-start
247 (>= (point) orig-macro-start)))
248 (espresso--beginning-of-macro)))
250 (setq count (1- count))))))
254 (defun espresso--re-search-backward (regexp &optional bound noerror count)
255 "Search backward but ignore strings, preprocessor macros, and
256 comments. Invokes `re-search-backward' but treats the buffer as
257 if strings, preprocessor macros, and comments have been removed.
259 If inside a macro when called, treat the macro as normal text.
261 (let ((saved-point (point))
264 '(espresso--re-search-backward-inner regexp bound 1))
266 '(espresso--re-search-forward-inner regexp bound (- count)))
268 '(espresso--re-search-backward-inner regexp bound count)))))
272 (goto-char saved-point)
274 (error (error-message-string err)))))))
277 (defun espresso--forward-function-decl ()
278 (assert (looking-at "\\_<function\\_>"))
280 (forward-comment most-positive-fixnum)
281 (skip-chars-forward "^(")
284 (forward-comment most-positive-fixnum)
285 (skip-chars-forward "^{"))
288 (defun espresso--beginning-of-defun ()
289 (cond ((espresso--re-search-backward "\\_<function\\_>" (point-min) t)
293 (when (looking-at espresso--function-heading-2-re)
294 (setq pos (match-beginning 1))))
298 (goto-char (point-min)))))
300 (defun espresso--end-of-defun ()
301 ;; look for function backward. if we're inside it, go to that
302 ;; function's end. otherwise, search for the next function's end and
304 (unless (looking-at "\\_<")
305 (skip-syntax-backward "w_"))
307 (let ((orig-point (point)) pos)
308 (when (or (looking-at "\\_<function\\_>")
309 (espresso--re-search-backward "\\_<function\\_>" (point-min) t))
310 (goto-char (match-beginning 0))
311 (let* ((func-loc (point))
312 (opening-brace-loc (progn (espresso--forward-function-decl)
315 (cond ((and (<= func-loc orig-point)
316 (<= orig-point opening-brace-loc))
317 (setq pos opening-brace-loc))
319 ((/= 0 (nth 0 (parse-partial-sexp
320 opening-brace-loc orig-point 0)))
321 (setq pos opening-brace-loc)))))
327 ((espresso--re-search-forward "\\_<function\\_>" (point-max) t)
328 (espresso--end-of-defun))
330 (t (goto-char (point-max))))))
332 (defun espresso--beginning-of-macro (&optional lim)
333 (let ((here (point)))
335 (if lim (narrow-to-region lim (point-max)))
337 (while (eq (char-before (1- (point))) ?\\)
339 (back-to-indentation)
340 (if (and (<= (point) here)
341 (looking-at espresso--opt-cpp-start))
346 (defun espresso--backward-syntactic-ws (&optional lim)
347 "Simple implementation of c-backward-syntactic-ws"
349 (when lim (narrow-to-region lim (point-max)))
351 (let ((in-macro (save-excursion (espresso--beginning-of-macro)))
354 (while (progn (unless in-macro (espresso--beginning-of-macro))
355 (forward-comment most-negative-fixnum)
359 (setq pos (point)))))))))
361 (defun espresso--forward-syntactic-ws (&optional lim)
362 "Simple implementation of c-forward-syntactic-ws"
364 (when lim (narrow-to-region (point-min) min))
367 (forward-comment most-positive-fixnum)
368 (when (eq (char-after) ?#)
373 (setq pos (point)))))))))
377 (defun espresso--inside-param-list-p ()
378 "Return non-nil iff point is inside a function parameter list."
382 (and (looking-at "(")
383 (progn (forward-symbol -1)
384 (or (looking-at "function")
385 (progn (forward-symbol -1) (looking-at "function"))))))
388 (defconst espresso--function-heading-1-re
390 "^\\s-*function\\s-+\\(" espresso--name-re "\\)")
391 "Regular expression matching the start of a function header. Match group 1
392 is the name of the function.")
394 (defconst espresso--function-heading-2-re
396 "^\\s-*\\(" espresso--name-re "\\)\\s-*:\\s-*function\\_>")
397 "Regular expression matching the start of a function entry in
398 an associative array. Match group 1 is the name of the function.")
400 (defconst espresso--macro-decl-re
401 (concat "^\\s-*#\\s-*define\\s-+\\(" espresso--cpp-name-re "\\)\\s-*(")
402 "Regular expression matching a CPP macro definition up to the opening
403 parenthesis. Match group 1 is the name of the function.")
405 (defconst espresso--keyword-re
406 (espresso--regexp-opt-symbol
407 '("abstract" "break" "case" "catch" "class" "const"
408 "continue" "debugger" "default" "delete" "do" "else"
409 "enum" "export" "extends" "final" "finally" "for"
410 "function" "goto" "if" "implements" "import" "in"
411 "instanceof" "interface" "native" "new" "package"
412 "private" "protected" "public" "return" "static"
413 "super" "switch" "synchronized" "throw"
414 "throws" "transient" "try" "typeof" "var" "void"
415 "volatile" "while" "with" "let"))
416 "Regular expression matching any JavaScript keyword.")
418 (defconst espresso--basic-type-re
419 (espresso--regexp-opt-symbol
420 '("boolean" "byte" "char" "double" "float" "int" "long"
422 "Regular expression matching any predefined type in JavaScript.")
424 (defconst espresso--constant-re
425 (espresso--regexp-opt-symbol '("false" "null" "undefined"
426 "true" "arguments" "this"))
427 "Regular expression matching any future reserved words in JavaScript.")
430 (defconst espresso--font-lock-keywords-1
433 (list espresso--function-heading-1-re 1 font-lock-function-name-face)
434 (list espresso--function-heading-2-re 1 font-lock-function-name-face))
435 "Level one font lock.")
437 (defconst espresso--font-lock-keywords-2
438 (append espresso--font-lock-keywords-1
439 (list (list espresso--keyword-re 1 font-lock-keyword-face)
440 (cons espresso--basic-type-re font-lock-type-face)
441 (cons espresso--constant-re font-lock-constant-face)))
442 "Level two font lock.")
445 ;; Limitations with variable declarations: There seems to be no
446 ;; sensible way to highlight variables occuring after an initialized
447 ;; variable in a variable list. For instance, in
449 ;; var x, y = f(a, b), z
451 ;; z will not be highlighted. Also, in variable declaration lists
452 ;; spanning several lines only variables on the first line will be
453 ;; highlighted. To get correct fontification, every line with variable
454 ;; declarations must contain a `var' keyword.
456 (defconst espresso--font-lock-keywords-3
458 ;; This goes before keywords-2 so it gets used preferentially
459 ;; instead of the keywords in keywords-2. Don't use override
460 ;; because that will override syntactic fontification too, which
461 ;; will fontify commented-out directives as if they weren't
463 ,@cpp-font-lock-keywords ; from font-lock.el
465 ,@espresso--font-lock-keywords-2
467 ;; variable declarations
469 (concat "\\_<\\(const\\|var\\)\\_>\\|" espresso--basic-type-re)
470 (list (concat "\\(" espresso--name-re "\\)"
471 "\\s-*\\([=;].*\\|\\_<in\\_>.*\\|,\\|/[/*]\\|$\\)")
474 '(1 font-lock-variable-name-face)))
476 ;; class instantiation
478 (concat "\\_<new\\_>\\s-+\\(" espresso--dotted-name-re "\\)")
479 (list 1 'font-lock-type-face))
483 (concat "\\_<instanceof\\_>\\s-+\\(" espresso--dotted-name-re "\\)")
484 (list 1 'font-lock-type-face))
489 "\\_<function\\_>\\(\\s-+" espresso--name-re "\\)?\\s-*(\\s-*"
490 espresso--name-start-re)
491 (list (concat "\\(" espresso--name-re "\\)\\(\\s-*).*\\)?")
494 '(1 font-lock-variable-name-face)))
496 ;; continued formal parameter list
499 "^\\s-*" espresso--name-re "\\s-*[,)]")
500 (list espresso--name-re
501 '(if (save-excursion (backward-char)
502 (espresso--inside-param-list-p))
506 '(0 font-lock-variable-name-face)))
508 ;; class declarations
509 ,@(mapcar #'(lambda (x)
511 (1 font-lock-type-face t t)
512 (2 font-lock-type-face t t)))
514 espresso--class-decls))
515 "Level three font lock.")
518 (defconst espresso--font-lock-keywords
519 '(espresso--font-lock-keywords-3 espresso--font-lock-keywords-1
520 espresso--font-lock-keywords-2
521 espresso--font-lock-keywords-3)
522 "See `font-lock-keywords'.")
524 ;; Note: Javascript cannot continue a regular expression literal
526 (defconst espresso--regexp-literal
527 "[=(,]\\(?:\\s-\\|\n\\)*\\(/\\)[^/*]\\(?:.*?[^\\]\\)?\\(/\\)"
528 "Match a regular expression literal. Match groups 1 and 2 are
529 the characters forming the beginning and end of the literal")
531 ;; we want to match regular expressions only at the beginning of
533 (defconst espresso--font-lock-syntactic-keywords
534 `((,espresso--regexp-literal (1 "|") (2 "|")))
535 "Highlighting of regular expressions. See also the variable
536 `font-lock-keywords'.")
540 (defconst espresso--possibly-braceless-keyword-re
541 (espresso--regexp-opt-symbol
542 '("catch" "do" "else" "finally" "for" "if" "try" "while" "with" "let"))
543 "Regular expression matching keywords that are optionally
544 followed by an opening brace.")
546 (defconst espresso--indent-operator-re
547 (concat "[-+*/%<>=&^|?:.]\\([^-+*/]\\|$\\)\\|"
548 (espresso--regexp-opt-symbol '("in" "instanceof")))
549 "Regular expression matching operators that affect indentation
550 of continued expressions.")
553 (defun espresso--looking-at-operator-p ()
554 "Return non-nil if text after point is an operator (that is not
557 (and (looking-at espresso--indent-operator-re)
558 (or (not (looking-at ":"))
560 (and (espresso--re-search-backward "[?:{]\\|\\_<case\\_>" nil t)
561 (looking-at "?")))))))
564 (defun espresso--continued-expression-p ()
565 "Returns non-nil if the current line continues an expression."
567 (back-to-indentation)
568 (or (espresso--looking-at-operator-p)
569 (and (espresso--re-search-backward "\n" nil t)
571 (skip-chars-backward " \t")
572 (or (bobp) (backward-char))
573 (and (> (point) (point-min))
574 (save-excursion (backward-char) (not (looking-at "[/*]/")))
575 (espresso--looking-at-operator-p)
576 (and (progn (backward-char)
577 (not (looking-at "++\\|--\\|/[/*]"))))))))))
580 (defun espresso--end-of-do-while-loop-p ()
581 "Returns non-nil if word after point is `while' of a do-while
582 statement, else returns nil. A braceless do-while statement
583 spanning several lines requires that the start of the loop is
584 indented to the same column as the current line."
588 (when (looking-at "\\s-*\\_<while\\_>")
590 (skip-chars-backward "[ \t\n]*}")
591 (looking-at "[ \t\n]*}"))
593 (backward-list) (forward-symbol -1) (looking-at "\\_<do\\_>"))
594 (espresso--re-search-backward "\\_<do\\_>" (point-at-bol) t)
595 (or (looking-at "\\_<do\\_>")
596 (let ((saved-indent (current-indentation)))
597 (while (and (espresso--re-search-backward "^\\s-*\\_<" nil t)
598 (/= (current-indentation) saved-indent)))
599 (and (looking-at "\\s-*\\_<do\\_>")
600 (not (espresso--re-search-forward
601 "\\_<while\\_>" (point-at-eol) t))
602 (= (current-indentation) saved-indent)))))))))
605 (defun espresso--ctrl-statement-indentation ()
606 "Returns the proper indentation of the current line if it
607 starts the body of a control statement without braces, else
610 (back-to-indentation)
611 (when (save-excursion
612 (and (not (looking-at "[{]"))
614 (espresso--re-search-backward "[[:graph:]]" nil t)
615 (or (eobp) (forward-char))
616 (when (= (char-before) ?\)) (backward-list))
617 (skip-syntax-backward " ")
618 (skip-syntax-backward "w_")
619 (looking-at espresso--possibly-braceless-keyword-re))
620 (not (espresso--end-of-do-while-loop-p))))
622 (goto-char (match-beginning 0))
623 (+ (current-indentation) espresso-indent-level)))))
626 (defun espresso--proper-indentation (parse-status)
627 "Return the proper indentation for the current line."
629 (back-to-indentation)
630 (let ((ctrl-stmt-indent (espresso--ctrl-statement-indentation))
631 (same-indent-p (looking-at "[]})]\\|\\_<case\\_>\\|\\_<default\\_>"))
632 (continued-expr-p (espresso--continued-expression-p)))
633 (cond (ctrl-stmt-indent)
634 ((eq (char-after) ?#) 0)
635 ((save-excursion (espresso--beginning-of-macro))
637 ((nth 1 parse-status)
638 (goto-char (nth 1 parse-status))
639 (if (looking-at "[({[]\\s-*\\(/[/*]\\|$\\)")
641 (skip-syntax-backward " ")
642 (when (= (char-before) ?\)) (backward-list))
643 (back-to-indentation)
647 (+ (current-column) (* 2 espresso-indent-level)
648 espresso-expr-indent-offset))
650 (+ (current-column) espresso-indent-level))))
651 (unless same-indent-p
653 (skip-chars-forward " \t"))
655 (continued-expr-p (+ espresso-indent-level
656 espresso-expr-indent-offset))
660 (defun espresso-indent-line ()
661 "Indent the current line as JavaScript source text."
666 (save-excursion (syntax-ppss (point-at-bol))))
667 (offset (- (current-column) (current-indentation))))
669 (if (nth 8 parse-status)
670 (indent-relative-maybe)
671 (indent-line-to (espresso--proper-indentation parse-status))
672 (when (> offset 0) (forward-char offset))))))
676 (defun espresso-c-fill-paragraph (&optional justify)
677 "Fill the paragraph with c-fill-paragraph"
680 ;; FIXME: filling a single-line C-style comment into multiple lines
681 ;; does something horrible to the undo list
683 (flet ((c-forward-sws
685 (espresso--forward-syntactic-ws limit))
689 (espresso--backward-syntactic-ws limit))
691 (c-beginning-of-macro
693 (espresso--beginning-of-macro limit)))
695 (let ((fill-paragraph-function 'c-fill-paragraph))
696 (c-fill-paragraph justify))))
700 (defun espresso--imenu-create-index ()
701 (let ((search-re (mapconcat (lambda (x)
702 (concat "\\(" x "\\)"))
703 (list espresso--function-heading-1-re
704 espresso--function-heading-2-re
708 espresso--class-decls "\\|")
710 espresso--macro-decl-re)
712 entries parent-entries ends tmp syntax)
716 (goto-char (point-min))
718 (while (re-search-forward search-re (point-max) t)
719 (goto-char (match-beginning 0))
720 (setq syntax (syntax-ppss))
721 (unless (or (nth 3 syntax) (nth 4 syntax))
722 (while (and ends (>= (point) (car ends)))
723 (setq tmp (nreverse entries)
724 entries (pop parent-entries))
728 (cons "[empty]" (set-marker (make-marker)
733 (setcdr (car entries) tmp))
735 (cond ((and (not parent-entries) ; regular function or macro
736 (or (looking-at espresso--function-heading-1-re)
737 (looking-at espresso--macro-decl-re)))
739 (push (cons (match-string-no-properties 1)
740 (set-marker (make-marker) (match-beginning 1)))
743 ;; does one of the espresso--class-decls regexps match?
744 ((let ((r espresso--class-decls))
745 (while (and r (not (looking-at (car r) )))
750 (match-string-no-properties 1)
753 (push entries parent-entries)
755 (goto-char (match-end 1))
763 (looking-at espresso--function-heading-2-re))
764 (push (cons (match-string-no-properties 1)
765 (set-marker (make-marker) (match-beginning 1)))
768 (goto-char (match-end 0)))
770 (while parent-entries
771 (setq tmp (nreverse entries)
772 entries (pop parent-entries))
773 (setcdr (car entries) tmp))))
777 (defun espresso--which-func-joiner (parts)
778 (mapconcat #'identity parts "."))
783 (defun espresso-mode ()
784 "Major mode for editing JavaScript source text.
788 \\{espresso-mode-map}"
790 (kill-all-local-variables)
792 (use-local-map espresso-mode-map)
793 (set-syntax-table espresso-mode-syntax-table)
794 (set (make-local-variable 'indent-line-function) 'espresso-indent-line)
795 (set (make-local-variable 'beginning-of-defun-function)
796 'espresso--beginning-of-defun)
797 (set (make-local-variable 'end-of-defun-function)
798 'espresso--end-of-defun)
800 (set (make-local-variable 'open-paren-in-column-0-is-defun-start) nil)
802 (set (make-local-variable 'font-lock-defaults)
803 (list espresso--font-lock-keywords
805 '(font-lock-syntactic-keywords
806 . espresso--font-lock-syntactic-keywords)))
808 (set (make-local-variable 'parse-sexp-ignore-comments) t)
809 (set (make-local-variable 'parse-sexp-lookup-properties) t)
810 (set (make-local-variable 'which-func-imenu-joiner-function)
811 #'espresso--which-func-joiner)
814 (setq comment-start "// ")
815 (setq comment-end "")
816 (set (make-local-variable 'fill-paragraph-function)
817 'espresso-c-fill-paragraph)
820 (setq imenu-case-fold-search nil)
821 (set (make-local-variable 'imenu-create-index-function)
822 #'espresso--imenu-create-index)
824 (setq major-mode 'espresso-mode)
825 (setq mode-name "Espresso")
827 ;; for filling, pretend we're cc-mode
828 (setq c-comment-prefix-regexp "//+\\|\\**"
829 c-paragraph-start "$"
830 c-paragraph-separate "$"
831 c-block-comment-prefix "* "
832 c-line-comment-starter "//"
833 c-comment-start-regexp "/[*/]\\|\\s!"
834 comment-start-skip "\\(//+\\|/\\*+\\)\\s *")
836 (let ((c-buffer-is-cc-mode t))
837 (c-setup-paragraph-variables))
839 ;; Important to fontify the whole buffer syntactically! If we don't,
840 ;; then we might have regular expression literals that aren't marked
841 ;; as strings, which will screw up parse-partial-sexp, scan-lists, etc.
842 ;; and and produce maddening "unbalanced parenthesis" errors. When we attempt
843 ;; to find the error and scroll to the portion of the buffer containing the problem,
844 ;; JIT-lock will apply the correct syntax to the regular expresion literal and
845 ;; the problem will mysteriously disappear.
846 (font-lock-set-defaults)
848 (let (font-lock-keywords) ; leaves syntactic keywords intact
849 (font-lock-fontify-buffer))
851 (run-mode-hooks 'espresso-mode-hook))
854 (eval-after-load "hideshow"
855 '(add-to-list 'hs-special-modes-alist
856 '(espresso-mode "{" "}" "/[*/]"
857 nil hs-c-like-adjust-block-beginning)))
859 (eval-after-load "folding"
860 (when (fboundp 'folding-add-to-marks-list)
861 (folding-add-to-marks-list 'espresso-mode "// {{{" "// }}}" )))
865 (provide 'espresso-mode)
867 ;; outline-regexp: ";;; "
869 ;; espresso.el ends here