summaryrefslogtreecommitdiff
path: root/elpa/typescript-mode-20220506.827/typescript-mode.el
diff options
context:
space:
mode:
Diffstat (limited to 'elpa/typescript-mode-20220506.827/typescript-mode.el')
-rw-r--r--elpa/typescript-mode-20220506.827/typescript-mode.el2988
1 files changed, 0 insertions, 2988 deletions
diff --git a/elpa/typescript-mode-20220506.827/typescript-mode.el b/elpa/typescript-mode-20220506.827/typescript-mode.el
deleted file mode 100644
index 220cf75..0000000
--- a/elpa/typescript-mode-20220506.827/typescript-mode.el
+++ /dev/null
@@ -1,2988 +0,0 @@
-;;; typescript-mode.el --- Major mode for editing typescript
-
-;; -----------------------------------------------------------------------------------
-;; TypeScript support for Emacs
-;; Unmodified original sourve available at http://www.karllandstrom.se/downloads/emacs/javascript.el
-;; Copyright (c) 2008 Free Software Foundation
-;; Portions Copyright (C) Microsoft Open Technologies, Inc. All rights reserved.
-;;
-;; This program 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 3 of the License, or
-;; (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with this program. If not, see <http://www.gnu.org/licenses/>.
-;; -------------------------------------------------------------------------------------------
-
-;; URL: http://github.com/ananthakumaran/typescript.el
-;; Version: 0.4
-;; Keywords: typescript languages
-;; Package-Requires: ((emacs "24.3"))
-
-;; This file is not part of GNU Emacs.
-
-;;; Commentary:
-
-;; This is based on Karl Landstrom's barebones typescript-mode. This
-;; is much more robust and works with cc-mode's comment filling
-;; (mostly).
-;; The modifications to the original javascript.el mode mainly consisted in
-;; replacing "javascript" with "typescript"
-;;
-;; The main features of this typescript mode are syntactic
-;; highlighting (enabled with `font-lock-mode' or
-;; `global-font-lock-mode'), automatic indentation and filling of
-;; comments.
-;;
-;;
-;; General Remarks:
-;;
-;; XXX: This mode assumes that block comments are not nested inside block
-;; XXX: comments
-;;
-;; Exported names start with "typescript-"; private names start with
-;; "typescript--".
-
-;;; Code:
-
-(eval-and-compile
- (require 'compile)
- (require 'cc-mode)
- (require 'font-lock)
- (require 'rx)
- (require 'newcomment))
-
-(eval-when-compile
- (require 'cl-lib))
-
-;;; Constants
-
-(defconst typescript--type-name-re "\\(?:[A-Z][A-Za-z0-9]+\\.\\)\\{0,\\}\\(?:[A-Z][A-Za-z0-9]+\\)"
- "Regexp matching a conventional TypeScript type-name. Must start with upper-case letter!")
-
-(defconst typescript--name-start-re "[a-zA-Z_$]"
- "Regexp matching the start of a typescript identifier, without grouping.")
-
-(defconst typescript--name-re (concat typescript--name-start-re
- "\\(?:\\s_\\|\\sw\\)*")
- "Regexp matching a typescript identifier, without grouping.")
-
-(defconst typescript--objfield-re (concat typescript--name-re ":")
- "Regexp matching the start of a typescript object field.")
-
-(defconst typescript--dotted-name-re
- (concat typescript--name-re "\\(?:\\." typescript--name-re "\\)*")
- "Regexp matching a dot-separated sequence of typescript names.")
-
-(defconst typescript--plain-method-re
- (concat "^\\s-*?\\(" typescript--dotted-name-re "\\)\\.prototype"
- "\\.\\(" typescript--name-re "\\)\\s-*?=\\s-*?\\(function\\)\\_>")
- "Regexp matching an explicit typescript prototype \"method\" declaration.
-Group 1 is a (possibly-dotted) class name, group 2 is a method name,
-and group 3 is the 'function' keyword.")
-
-(defconst typescript--plain-class-re
- (concat "^\\s-*\\(" typescript--dotted-name-re "\\)\\.prototype"
- "\\s-*=\\s-*{")
- "Regexp matching a typescript explicit prototype \"class\" declaration.
-An example of this is \"Class.prototype = { method1: ...}\".")
-
-(defconst typescript--module-declaration-re
- "^\\s-*\\(?:declare\\|\\(?:export\\(?:\\s-+default\\)?\\)\\)?"
- "Regexp matching ambient declaration modifier or export declaration.")
-
-;; var NewClass = BaseClass.extend(
-(defconst typescript--mp-class-decl-re
- (concat "^\\s-*var\\s-+"
- "\\(" typescript--name-re "\\)"
- "\\s-*=\\s-*"
- "\\(" typescript--dotted-name-re
- "\\)\\.extend\\(?:Final\\)?\\s-*(\\s-*{?\\s-*$"))
-
-;; var NewClass = Class.create()
-(defconst typescript--prototype-obsolete-class-decl-re
- (concat "^\\s-*\\(?:var\\s-+\\)?"
- "\\(" typescript--dotted-name-re "\\)"
- "\\s-*=\\s-*Class\\.create()"))
-
-(defconst typescript--prototype-objextend-class-decl-re-1
- (concat "^\\s-*Object\\.extend\\s-*("
- "\\(" typescript--dotted-name-re "\\)"
- "\\s-*,\\s-*{"))
-
-(defconst typescript--prototype-objextend-class-decl-re-2
- (concat "^\\s-*\\(?:var\\s-+\\)?"
- "\\(" typescript--dotted-name-re "\\)"
- "\\s-*=\\s-*Object\\.extend\\s-*\("))
-
-;; var NewClass = Class.create({
-(defconst typescript--prototype-class-decl-re
- (concat "^\\s-*\\(?:var\\s-+\\)?"
- "\\(" typescript--name-re "\\)"
- "\\s-*=\\s-*Class\\.create\\s-*(\\s-*"
- "\\(?:\\(" typescript--dotted-name-re "\\)\\s-*,\\s-*\\)?{?"))
-
-;; Parent class name(s) (yes, multiple inheritance in typescript) are
-;; matched with dedicated font-lock matchers
-(defconst typescript--dojo-class-decl-re
- (concat "^\\s-*dojo\\.declare\\s-*(\"\\(" typescript--dotted-name-re "\\)"))
-
-(defconst typescript--exttypescript-class-decl-re-1
- (concat "^\\s-*Ext\\.extend\\s-*("
- "\\s-*\\(" typescript--dotted-name-re "\\)"
- "\\s-*,\\s-*\\(" typescript--dotted-name-re "\\)")
- "Regexp matching an ExtTYPESCRIPT class declaration (style 1).")
-
-(defconst typescript--exttypescript-class-decl-re-2
- (concat "^\\s-*\\(?:var\\s-+\\)?"
- "\\(" typescript--name-re "\\)"
- "\\s-*=\\s-*Ext\\.extend\\s-*(\\s-*"
- "\\(" typescript--dotted-name-re "\\)")
- "Regexp matching an ExtTYPESCRIPT class declaration (style 2).")
-
-(defconst typescript--mochikit-class-re
- (concat "^\\s-*MochiKit\\.Base\\.update\\s-*(\\s-*"
- "\\(" typescript--dotted-name-re "\\)")
- "Regexp matching a MochiKit class declaration.")
-
-(defconst typescript--dummy-class-style
- '(:name "[Automatically Generated Class]"))
-
-(defconst typescript--class-styles
- `((:name "Plain"
- :class-decl ,typescript--plain-class-re
- :prototype t
- :contexts (toplevel)
- :framework typescript)
-
- (:name "MochiKit"
- :class-decl ,typescript--mochikit-class-re
- :prototype t
- :contexts (toplevel)
- :framework mochikit)
-
- (:name "Prototype (Obsolete)"
- :class-decl ,typescript--prototype-obsolete-class-decl-re
- :contexts (toplevel)
- :framework prototype)
-
- (:name "Prototype (Modern)"
- :class-decl ,typescript--prototype-class-decl-re
- :contexts (toplevel)
- :framework prototype)
-
- (:name "Prototype (Object.extend)"
- :class-decl ,typescript--prototype-objextend-class-decl-re-1
- :prototype t
- :contexts (toplevel)
- :framework prototype)
-
- (:name "Prototype (Object.extend) 2"
- :class-decl ,typescript--prototype-objextend-class-decl-re-2
- :prototype t
- :contexts (toplevel)
- :framework prototype)
-
- (:name "Dojo"
- :class-decl ,typescript--dojo-class-decl-re
- :contexts (toplevel)
- :framework dojo)
-
- (:name "ExtTYPESCRIPT (style 1)"
- :class-decl ,typescript--exttypescript-class-decl-re-1
- :prototype t
- :contexts (toplevel)
- :framework exttypescript)
-
- (:name "ExtTYPESCRIPT (style 2)"
- :class-decl ,typescript--exttypescript-class-decl-re-2
- :contexts (toplevel)
- :framework exttypescript)
-
- (:name "Merrill Press"
- :class-decl ,typescript--mp-class-decl-re
- :contexts (toplevel)
- :framework merrillpress))
-
- "List of typescript class definition styles.
-
-A class definition style is a plist with the following keys:
-
-:name is a human-readable name of the class type
-
-:class-decl is a regular expression giving the start of the
-class. Its first group must match the name of its class. If there
-is a parent class, the second group should match, and it should be
-the name of the class.
-
-If :prototype is present and non-nil, the parser will merge
-declarations for this constructs with others at the same lexical
-level that have the same name. Otherwise, multiple definitions
-will create multiple top-level entries. Don't use :prototype
-unnecessarily: it has an associated cost in performance.
-
-If :strip-prototype is present and non-nil, then if the class
-name as matched contains")
-
-(defconst typescript--available-frameworks
- (cl-loop with available-frameworks
- for style in typescript--class-styles
- for framework = (plist-get style :framework)
- unless (memq framework available-frameworks)
- collect framework into available-frameworks
- finally return available-frameworks)
- "List of available typescript frameworks symbols.")
-
-(defconst typescript--function-heading-1-re
- (concat
- typescript--module-declaration-re
- "\\s-*function\\s-+\\(" typescript--name-re "\\)")
- "Regexp matching the start of a typescript function header.
-Match group 1 is the name of the function.")
-
-(defconst typescript--function-heading-2-re
- (concat
- "^\\s-*\\(" typescript--name-re "\\)\\s-*:\\s-*function\\_>")
- "Regexp matching the start of a function entry in an associative array.
-Match group 1 is the name of the function.")
-
-(defconst typescript--function-heading-3-re
- (concat
- "^\\s-*\\(?:var\\s-+\\)?\\(" typescript--dotted-name-re "\\)"
- "\\s-*=\\s-*function\\_>")
- "Regexp matching a line in the typescript form \"var MUMBLE = function\".
-Match group 1 is MUMBLE.")
-
-(defun typescript--regexp-opt-symbol (list)
- "Like `regexp-opt', but surround the result with `\\\\_<' and `\\\\_>'."
- (concat "\\_<" (regexp-opt list t) "\\_>"))
-
-(defconst typescript--keyword-re
- (typescript--regexp-opt-symbol
- '("abstract" "any" "as" "async" "await" "boolean" "bigint" "break" "case" "catch" "class" "const"
- "constructor" "continue" "debugger" "declare" "default" "delete" "do" "else"
- "enum" "export" "extends" "extern" "false" "finally" "for"
- "function" "from" "get" "goto" "if" "implements" "import" "in" "instanceof"
- "interface" "keyof" "let" "module" "namespace" "never" "new" "null" "number" "object" "of"
- "override" "private" "protected" "public" "readonly" "return" "set" "static" "string"
- "super" "switch" "this" "throw" "true"
- "try" "type" "typeof" "unknown" "var" "void"
- "while")) ; yield is handled separately
- "Regexp matching any typescript keyword.")
-
-(defconst typescript--basic-type-re
- (typescript--regexp-opt-symbol
- '("any" "bool" "boolean" "bigint" "never" "number" "string" "unknown" "void"))
- "Regular expression matching any predefined type in typescript.")
-
-(defconst typescript--access-modifier-re
- (typescript--regexp-opt-symbol
- '("private" "protected" "public" "readonly" "static" "extends" "implements"))
- "Regular expression matching access modifiers.")
-
-(defconst typescript--decorator-re
- (concat "\\(@" typescript--name-re "\\)"))
-
-(defconst typescript--constant-re
- (typescript--regexp-opt-symbol '("false" "null" "undefined"
- "Infinity" "NaN"
- "true" "arguments" "this"))
- "Regular expression matching any future reserved words in typescript.")
-
-(defconst typescript--builtin-re
- (typescript--regexp-opt-symbol
- '("console"))
- "Regular expression matching builtins.")
-
-(defconst typescript--function-call-re "\\(\\(?:\\w\\|\\s_\\)+\\)\\(<.+>\\)?\s*("
- "Regular expression matching function calls.")
-
-(defconst typescript--font-lock-keywords-1
- (list
- "\\_<import\\_>"
- (list typescript--function-heading-1-re 1 font-lock-function-name-face)
- (list typescript--function-heading-2-re 1 font-lock-function-name-face))
- "Level one font lock keywords for `typescript-mode'.")
-
-(defconst typescript--font-lock-keywords-2
- (append typescript--font-lock-keywords-1
- (list (cons typescript--constant-re font-lock-constant-face)
- (cons typescript--basic-type-re font-lock-type-face)
- (list typescript--keyword-re 1 font-lock-keyword-face)
- (list "\\_<for\\_>"
- "\\s-+\\(each\\)\\_>" nil nil
- (list 1 'font-lock-keyword-face))
- (cons "\\_<yield\\(\\*\\|\\_>\\)" 'font-lock-keyword-face)))
- "Level two font lock keywords for `typescript-mode'.")
-
-;; typescript--pitem is the basic building block of the lexical
-;; database. When one refers to a real part of the buffer, the region
-;; of text to which it refers is split into a conceptual header and
-;; body. Consider the (very short) block described by a hypothetical
-;; typescript--pitem:
-;;
-;; function foo(a,b,c) { return 42; }
-;; ^ ^ ^
-;; | | |
-;; +- h-begin +- h-end +- b-end
-;;
-;; (Remember that these are buffer positions, and therefore point
-;; between characters, not at them. An arrow drawn to a character
-;; indicates the corresponding position is between that character and
-;; the one immediately preceding it.)
-;;
-;; The header is the region of text [h-begin, h-end], and is
-;; the text needed to unambiguously recognize the start of the
-;; construct. If the entire header is not present, the construct is
-;; not recognized at all. No other pitems may be nested inside the
-;; header.
-;;
-;; The body is the region [h-end, b-end]. It may contain nested
-;; typescript--pitem instances. The body of a pitem may be empty: in
-;; that case, b-end is equal to header-end.
-;;
-;; The three points obey the following relationship:
-;;
-;; h-begin < h-end <= b-end
-;;
-;; We put a text property in the buffer on the character *before*
-;; h-end, and if we see it, on the character *before* b-end.
-;;
-;; The text property for h-end, typescript--pstate, is actually a list
-;; of all typescript--pitem instances open after the marked character.
-;;
-;; The text property for b-end, typescript--pend, is simply the
-;; typescript--pitem that ends after the marked character. (Because
-;; pitems always end when the paren-depth drops below a critical
-;; value, and because we can only drop one level per character, only
-;; one pitem may end at a given character.)
-;;
-;; In the structure below, we only store h-begin and (sometimes)
-;; b-end. We can trivially and quickly find h-end by going to h-begin
-;; and searching for an typescript--pstate text property. Since no other
-;; typescript--pitem instances can be nested inside the header of a
-;; pitem, the location after the character with this text property
-;; must be h-end.
-;;
-;; typescript--pitem instances are never modified (with the exception
-;; of the b-end field). Instead, modified copies are added at subseqnce parse points.
-;; (The exception for b-end and its caveats is described below.)
-;;
-
-(cl-defstruct (typescript--pitem (:type list))
- ;; IMPORTANT: Do not alter the position of fields within the list.
- ;; Various bits of code depend on their positions, particularly
- ;; anything that manipulates the list of children.
-
- ;; List of children inside this pitem's body
- (children nil :read-only t)
-
- ;; When we reach this paren depth after h-end, the pitem ends
- (paren-depth nil :read-only t)
-
- ;; Symbol or class-style plist if this is a class
- (type nil :read-only t)
-
- ;; See above
- (h-begin nil :read-only t)
-
- ;; List of strings giving the parts of the name of this pitem (e.g.,
- ;; '("MyClass" "myMethod"), or t if this pitem is anonymous
- (name nil :read-only t)
-
- ;; THIS FIELD IS MUTATED, and its value is shared by all copies of
- ;; this pitem: when we copy-and-modify pitem instances, we share
- ;; their tail structures, so all the copies actually have the same
- ;; terminating cons cell. We modify that shared cons cell directly.
- ;;
- ;; The field value is either a number (buffer location) or nil if
- ;; unknown.
- ;;
- ;; If the field's value is greater than `typescript--cache-end', the
- ;; value is stale and must be treated as if it were nil. Conversely,
- ;; if this field is nil, it is guaranteed that this pitem is open up
- ;; to at least `typescript--cache-end'. (This property is handy when
- ;; computing whether we're inside a given pitem.)
- ;;
- (b-end nil))
-
-;; The pitem we start parsing with.
-(defconst typescript--initial-pitem
- (make-typescript--pitem
- :paren-depth most-negative-fixnum
- :type 'toplevel))
-
-;; When we say "jsdoc" here, we mean "jsdoc 3". There exist multiple dialects of
-;; "jsdoc documentation".
-
-;; Note that all typedoc/jsdoc regexp by themselves would match occurrences that appear outside
-;; documentation comments. The logic that uses these regexps must guard against it.
-(defconst typescript-typedoc-link-tag-regexp
- "\\[\\[.*?\\]\\]"
- "Matches a typedoc link.")
-
-(defconst typescript-typedoc-literal-markup-regexp
- "\\(`+\\).*?\\1"
- "Matches a typedoc keyword markup.")
-
-(defconst typescript-jsdoc-before-tag-regexp
- "\\(?:^\\s-*\\*+\\|/\\*\\*\\)\\s-*"
- "Matches everything we allow before the @ of a jsdoc tag.")
-
-;; This was taken from js2-mode.
-(defconst typescript-jsdoc-param-tag-regexp
- (concat typescript-jsdoc-before-tag-regexp
- "\\(@"
- (regexp-opt
- '("arg"
- "argument"
- "param"
- "prop"
- "property"
- "typedef"))
- "\\)"
- "\\s-*\\({[^}]+}\\)?" ; optional type
- "\\s-*\\[?\\([[:alnum:]_$\.]+\\)?\\]?" ; name
- "\\_>")
- "Matches jsdoc tags with optional type and optional param name.")
-
-;; This was taken from js2-mode.
-;; and extended with tags in http://usejsdoc.org/
-(defconst typescript-jsdoc-typed-tag-regexp
- (concat typescript-jsdoc-before-tag-regexp
- "\\(@"
- (regexp-opt
- '("enum"
- "extends"
- "field"
- "id"
- "implements"
- "lends"
- "mods"
- "requires"
- "return"
- "returns"
- "throw"
- "throws"
- "type"
- "yield"
- "yields"))
- "\\)\\s-*\\({[^}]+}\\)?")
- "Matches jsdoc tags with optional type.")
-
-;; This was taken from js2-mode.
-;; and extended with tags in http://usejsdoc.org/
-(defconst typescript-jsdoc-arg-tag-regexp
- (concat typescript-jsdoc-before-tag-regexp
- "\\(@"
- (regexp-opt
- '("access"
- "alias"
- "augments"
- "base"
- "borrows"
- "bug"
- "callback"
- "config"
- "default"
- "define"
- "emits"
- "exception"
- "extends"
- "external"
- "fires"
- "func"
- "function"
- "host"
- "kind"
- "listens"
- "member"
- "memberof"
- "method"
- "mixes"
- "module"
- "name"
- "namespace"
- "requires"
- "since"
- "suppress"
- "this"
- "throws"
- "var"
- "variation"
- "version"))
- "\\)\\s-+\\([^ \t]+\\)")
- "Matches jsdoc tags with a single argument.")
-
-;; This was taken from js2-mode
-;; and extended with tags in http://usejsdoc.org/
-(defconst typescript-jsdoc-empty-tag-regexp
- (concat typescript-jsdoc-before-tag-regexp
- "\\(@"
- (regexp-opt
- '("abstract"
- "addon"
- "async"
- "author"
- "class"
- "classdesc"
- "const"
- "constant"
- "constructor"
- "constructs"
- "copyright"
- "default"
- "defaultvalue"
- "deprecated"
- "desc"
- "description"
- "event"
- "example"
- "exec"
- "export"
- "exports"
- "file"
- "fileoverview"
- "final"
- "func"
- "function"
- "generator"
- "global"
- "hidden"
- "hideconstructor"
- "ignore"
- "implicitcast"
- "inheritdoc"
- "inner"
- "instance"
- "interface"
- "license"
- "method"
- "mixin"
- "noalias"
- "noshadow"
- "notypecheck"
- "override"
- "overview"
- "owner"
- "package"
- "preserve"
- "preservetry"
- "private"
- "protected"
- "public"
- "readonly"
- "static"
- "summary"
- "supported"
- "todo"
- "tutorial"
- "virtual"))
- "\\)\\s-*")
- "Matches empty jsdoc tags.")
-
-;; Note that this regexp by itself would match tslint flags that appear inside
-;; strings. The logic using this regexp must guard against it.
-(defconst typescript-tslint-flag-regexp
- "\\(?://\\|/\\*\\)\\s-*\\(tslint:.*?\\)\\(?:\\*/\\|$\\)"
- "Matches tslint flags.")
-
-;;; Faces
-
-(defface typescript-jsdoc-tag
- '((t :foreground "SlateGray"))
- "Face used to highlight @whatever tags in jsdoc comments."
- :group 'typescript)
-
-(defface typescript-jsdoc-type
- '((t :foreground "SteelBlue"))
- "Face used to highlight {FooBar} types in jsdoc comments."
- :group 'typescript)
-
-(defface typescript-jsdoc-value
- '((t :foreground "gold4"))
- "Face used to highlight tag values in jsdoc comments."
- :group 'typescript)
-
-(defface typescript-access-modifier-face
- '((t (:inherit font-lock-keyword-face)))
- "Face used to highlight access modifiers."
- :group 'typescript)
-
-(defface typescript-this-face
- '((t (:inherit font-lock-keyword-face)))
- "Face used to highlight 'this' keyword."
- :group 'typescript)
-
-(defface typescript-primitive-face
- '((t (:inherit font-lock-keyword-face)))
- "Face used to highlight builtin types."
- :group 'typescript)
-
-;;; User Customization
-
-(defgroup typescript nil
- "Customization variables for typescript mode."
- :tag "typescript"
- :group 'languages)
-
-(defcustom typescript-indent-level 4
- "Number of spaces for each indentation step in `typescript-mode'."
- :type 'integer
- :safe 'integerp
- :group 'typescript)
-;;;###autoload(put 'typescript-indent-level 'safe-local-variable #'integerp)
-
-(defcustom typescript-expr-indent-offset 0
- "Number of additional spaces used for indentation of continued expressions.
-The value must be no less than minus `typescript-indent-level'."
- :type 'integer
- :safe 'integerp
- :group 'typescript)
-
-(defcustom typescript-indent-switch-clauses t
- "Enable indenting of switch case and default clauses to
-replicate tsserver behaviour. Indent level is taken to be
-`typescript-indent-level'."
- :type 'boolean
- :group 'typescript)
-
-(defcustom typescript-indent-list-items t
- "Enable indenting of list items, useful for certain code styles."
- :type 'boolean
- :group 'typescript)
-
-(defcustom typescript-auto-indent-flag t
- "Whether to automatically indent when typing punctuation characters.
-If non-nil, the characters {}();,: also indent the current line
-in typescript mode."
- :type 'boolean
- :group 'typescript)
-
-(defcustom typescript-flat-functions nil
- "Treat nested functions as top-level functions in `typescript-mode'.
-This applies to function movement, marking, and so on."
- :type 'boolean
- :group 'typescript)
-
-(defcustom typescript-comment-lineup-func #'c-lineup-C-comments
- "Lineup function for `cc-mode-style', for C comments in `typescript-mode'."
- :type 'function
- :group 'typescript)
-
-(defcustom typescript-enabled-frameworks typescript--available-frameworks
- "Frameworks recognized by `typescript-mode'.
-To improve performance, you may turn off some frameworks you
-seldom use, either globally or on a per-buffer basis."
- :type (cons 'set (mapcar (lambda (x)
- (list 'const x))
- typescript--available-frameworks))
- :group 'typescript)
-
-(defcustom typescript-mode-hook nil
- "*Hook called by `typescript-mode'."
- :type 'hook
- :group 'typescript)
-
-(defcustom typescript-autoconvert-to-template-flag nil
- "Non-nil means automatically convert plain strings to templates.
-
-When the flag is non-nil the `typescript-autoconvert-to-template'
-is called whenever a plain string delimiter is typed in the buffer."
- :type 'boolean
- :group 'typescript)
-
-;;; Public utilities
-
-(defun typescript-convert-to-template ()
- "Convert the string at point to a template string."
- (interactive)
- (save-restriction
- (widen)
- (save-excursion
- (let* ((syntax (syntax-ppss))
- (str-terminator (nth 3 syntax))
- (string-start (or (and str-terminator (nth 8 syntax))
- ;; We have to consider the case that we're on the start delimiter of a string.
- ;; We tentatively take (point) as string-start. If it turns out we're
- ;; wrong, then typescript--move-to-end-of-plain-string will fail anway,
- ;; and we won't use the bogus value.
- (progn
- (forward-char)
- (point)))))
- (when (typescript--move-to-end-of-plain-string)
- (let ((end-start (or (nth 8 (syntax-ppss)) -1)))
- (undo-boundary)
- (when (= end-start string-start)
- (delete-char 1)
- (insert "`")))
- (goto-char string-start)
- (delete-char 1)
- (insert "`"))))))
-
-(defun typescript-autoconvert-to-template ()
- "Automatically convert a plain string to a teplate string, if needed.
-
-This function is meant to be automatically invoked when the user
-enters plain string delimiters. It checks whether the character
-before point is the end of a string. If it is, then it checks
-whether the string contains ${...}. If it does, then it converts
-the string from a plain string to a template."
- (interactive)
- (save-restriction
- (widen)
- (save-excursion
- (backward-char)
- (when (and (memq (char-after) '(?' ?\"))
- (not (eq (char-before) ?\\)))
- (let* ((string-start (nth 8 (syntax-ppss))))
- (when (and string-start
- (save-excursion
- (re-search-backward "\\${.*?}" string-start t)))
- (typescript-convert-to-template)))))))
-
-;;; KeyMap
-
-(defvar typescript-mode-map
- (let ((keymap (make-sparse-keymap)))
- (define-key keymap (kbd "C-c '") #'typescript-convert-to-template)
- keymap)
- "Keymap for `typescript-mode'.")
-
-(defun typescript--post-self-insert-function ()
- (when (and (derived-mode-p 'typescript-mode)
- typescript-autoconvert-to-template-flag
- (or (eq last-command-event ?\')
- (eq last-command-event ?\")))
- (typescript-autoconvert-to-template)))
-
-;;; Syntax table and parsing
-
-(defvar typescript-mode-syntax-table
- (let ((table (make-syntax-table)))
- (c-populate-syntax-table table)
- (modify-syntax-entry ?$ "_" table)
- (modify-syntax-entry ?` "\"" table)
- table)
- "Syntax table for `typescript-mode'.")
-
-(defvar typescript--quick-match-re nil
- "Autogenerated regexp used by `typescript-mode' to match buffer constructs.")
-
-(defvar typescript--quick-match-re-func nil
- "Autogenerated regexp used by `typescript-mode' to match constructs and functions.")
-
-(make-variable-buffer-local 'typescript--quick-match-re)
-(make-variable-buffer-local 'typescript--quick-match-re-func)
-
-(defvar typescript--cache-end 1
- "Last valid buffer position for the `typescript-mode' function cache.")
-(make-variable-buffer-local 'typescript--cache-end)
-
-(defvar typescript--last-parse-pos nil
- "Latest parse position reached by `typescript--ensure-cache'.")
-(make-variable-buffer-local 'typescript--last-parse-pos)
-
-(defvar typescript--state-at-last-parse-pos nil
- "Parse state at `typescript--last-parse-pos'.")
-(make-variable-buffer-local 'typescript--state-at-last-parse-pos)
-
-(defun typescript--flatten-list (list)
- (cl-loop for item in list
- nconc (cond ((consp item)
- (typescript--flatten-list item))
- (item (list item)))))
-
-(defun typescript--maybe-join (prefix separator suffix &rest list)
- "Helper function for `typescript--update-quick-match-re'.
-If LIST contains any element that is not nil, return its non-nil
-elements, separated by SEPARATOR, prefixed by PREFIX, and ended
-with SUFFIX as with `concat'. Otherwise, if LIST is empty, return
-nil. If any element in LIST is itself a list, flatten that
-element."
- (setq list (typescript--flatten-list list))
- (when list
- (concat prefix (mapconcat #'identity list separator) suffix)))
-
-(defun typescript--update-quick-match-re ()
- "Internal function used by `typescript-mode' for caching buffer constructs.
-This updates `typescript--quick-match-re', based on the current set of
-enabled frameworks."
- (setq typescript--quick-match-re
- (typescript--maybe-join
- "^[ \t]*\\(?:" "\\|" "\\)"
-
- ;; #define mumble
- "#define[ \t]+[a-zA-Z_]"
-
- (when (memq 'exttypescript typescript-enabled-frameworks)
- "Ext\\.extend")
-
- (when (memq 'prototype typescript-enabled-frameworks)
- "Object\\.extend")
-
- ;; var mumble = THING (
- (typescript--maybe-join
- "\\(?:var[ \t]+\\)?[a-zA-Z_$0-9.]+[ \t]*=[ \t]*\\(?:"
- "\\|"
- "\\)[ \t]*\("
-
- (when (memq 'prototype typescript-enabled-frameworks)
- "Class\\.create")
-
- (when (memq 'exttypescript typescript-enabled-frameworks)
- "Ext\\.extend")
-
- (when (memq 'merrillpress typescript-enabled-frameworks)
- "[a-zA-Z_$0-9]+\\.extend\\(?:Final\\)?"))
-
- (when (memq 'dojo typescript-enabled-frameworks)
- "dojo\\.declare[ \t]*\(")
-
- (when (memq 'mochikit typescript-enabled-frameworks)
- "MochiKit\\.Base\\.update[ \t]*\(")
-
- ;; mumble.prototypeTHING
- (typescript--maybe-join
- "[a-zA-Z_$0-9.]+\\.prototype\\(?:" "\\|" "\\)"
-
- (when (memq 'typescript typescript-enabled-frameworks)
- '( ;; foo.prototype.bar = function(
- "\\.[a-zA-Z_$0-9]+[ \t]*=[ \t]*function[ \t]*\("
-
- ;; mumble.prototype = {
- "[ \t]*=[ \t]*{")))))
-
- (setq typescript--quick-match-re-func
- (concat "function\\|" typescript--quick-match-re)))
-
-(defun typescript--forward-text-property (propname)
- "Move over the next value of PROPNAME in the buffer.
-If found, return that value and leave point after the character
-having that value; otherwise, return nil and leave point at EOB."
- (let ((next-value (get-text-property (point) propname)))
- (if next-value
- (forward-char)
-
- (goto-char (next-single-property-change
- (point) propname nil (point-max)))
- (unless (eobp)
- (setq next-value (get-text-property (point) propname))
- (forward-char)))
-
- next-value))
-
-(defun typescript--backward-text-property (propname)
- "Move over the previous value of PROPNAME in the buffer.
-If found, return that value and leave point just before the
-character that has that value, otherwise return nil and leave
-point at BOB."
- (unless (bobp)
- (let ((prev-value (get-text-property (1- (point)) propname)))
- (if prev-value
- (backward-char)
-
- (goto-char (previous-single-property-change
- (point) propname nil (point-min)))
-
- (unless (bobp)
- (backward-char)
- (setq prev-value (get-text-property (point) propname))))
-
- prev-value)))
-
-(defsubst typescript--forward-pstate ()
- (typescript--forward-text-property 'typescript--pstate))
-
-(defsubst typescript--backward-pstate ()
- (typescript--backward-text-property 'typescript--pstate))
-
-(defun typescript--pitem-goto-h-end (pitem)
- (goto-char (typescript--pitem-h-begin pitem))
- (typescript--forward-pstate))
-
-(defun typescript--re-search-forward-inner (regexp &optional bound count)
- "Helper function for `typescript--re-search-forward'."
- (let ((parse)
- str-terminator)
- (while (> count 0)
- (re-search-forward regexp bound)
- (setq parse (syntax-ppss))
- (cond ((setq str-terminator (nth 3 parse))
- (when (eq str-terminator t)
- (setq str-terminator ?/))
- (re-search-forward
- (concat "\\([^\\]\\|^\\)" (string str-terminator))
- (save-excursion (end-of-line) (point)) t))
- ((nth 7 parse)
- (forward-line))
- ((or (nth 4 parse)
- (and (eq (char-before) ?\/) (eq (char-after) ?\*)))
- (re-search-forward "\\*/"))
- (t
- (setq count (1- count))))))
- (point))
-
-
-(defun typescript--re-search-forward (regexp &optional bound noerror count)
- "Search forward, ignoring strings and comments.
-This function invokes `re-search-forward', but treats the buffer
-as if strings and comments have been removed."
- (let ((saved-point (point))
- (search-expr
- (cond ((null count)
- '(typescript--re-search-forward-inner regexp bound 1))
- ((< count 0)
- '(typescript--re-search-backward-inner regexp bound (- count)))
- ((> count 0)
- '(typescript--re-search-forward-inner regexp bound count)))))
- (condition-case err
- (eval search-expr)
- (search-failed
- (goto-char saved-point)
- (unless noerror
- (error (error-message-string err)))))))
-
-
-(defun typescript--re-search-backward-inner (regexp &optional bound count)
- "Auxiliary function for `typescript--re-search-backward'."
- (let ((parse))
- (while (> count 0)
- (re-search-backward regexp bound)
- (when (and (> (point) (point-min))
- (save-excursion (backward-char) (looking-at "/[/*]")))
- (forward-char))
- (setq parse (syntax-ppss))
- (cond
- ;; If we are in a comment or a string, jump back to the start
- ;; of the comment or string.
- ((nth 8 parse)
- (goto-char (nth 8 parse)))
- ((and (eq (char-before) ?/) (eq (char-after) ?*))
- (re-search-backward "/\\*"))
- (t
- (setq count (1- count))))))
- (point))
-
-
-(defun typescript--re-search-backward (regexp &optional bound noerror count)
- "Search backward, ignoring strings, and comments.
-
-This function invokes `re-search-backward' but treats the buffer
-as if strings and comments have been removed.
-
-IMPORTANT NOTE: searching for \"\\n\" with this function to find
-line breaks will generally not work, because the final newline of
-a one-line comment is considered to be part of the comment and
-will be skipped. Take the following code:
-
- let a = 1;
- let b = 2; // Foo
- let c = 3;
-
-If the point is in the last line, searching back for \"\\n\" will
-skip over the line with \"let b\". The newline found will be the
-one at the end of the line with \"let a\"."
- (let ((saved-point (point))
- (search-expr
- (cond ((null count)
- `(typescript--re-search-backward-inner ,regexp ,bound 1))
- ((< count 0)
- `(typescript--re-search-forward-inner ,regexp ,bound (- ,count)))
- ((> count 0)
- `(typescript--re-search-backward-inner ,regexp ,bound ,count)))))
- (condition-case err
- (eval search-expr)
- (search-failed
- (goto-char saved-point)
- (unless noerror
- (error (error-message-string err)))))))
-
-(defun typescript--forward-expression ()
- "Move forward over a whole typescript expression.
-This function doesn't move over expressions continued across
-lines."
- (cl-loop
- do (progn
- (forward-comment most-positive-fixnum)
- (cl-loop until (or (eolp)
- (progn
- (forward-comment most-positive-fixnum)
- (memq (char-after) '(?\, ?\; ?\] ?\) ?\}))))
- do (forward-sexp)))
- while (and (eq (char-after) ?\n)
- (save-excursion
- (forward-char)
- (typescript--continued-expression-p)))))
-
-(defun typescript--forward-function-decl ()
- "Move forward over a typescript function declaration.
-This puts point at the 'function' keyword.
-
-If this is a syntactically-correct non-expression function,
-return the name of the function, or t if the name could not be
-determined. Otherwise, return nil."
- (cl-assert (looking-at "\\_<function\\_>"))
- (let ((name t))
- (forward-word)
- (forward-comment most-positive-fixnum)
- (when (looking-at typescript--name-re)
- (setq name (match-string-no-properties 0))
- (goto-char (match-end 0)))
- (forward-comment most-positive-fixnum)
- (and (eq (char-after) ?\( )
- (ignore-errors (forward-list) t)
- (progn (forward-comment most-positive-fixnum)
- (and (eq (char-after) ?{)
- name)))))
-
-(defun typescript--function-prologue-beginning (&optional pos)
- "Return the start of the typescript function prologue containing POS.
-A function prologue is everything from start of the definition up
-to and including the opening brace. POS defaults to point.
-If POS is not in a function prologue, return nil."
- (let (prologue-begin)
- (save-excursion
- (if pos
- (goto-char pos)
- (setq pos (point)))
-
- (when (save-excursion
- (forward-line 0)
- (or (looking-at typescript--function-heading-2-re)
- (looking-at typescript--function-heading-3-re)))
-
- (setq prologue-begin (match-beginning 1))
- (when (<= prologue-begin pos)
- (goto-char (match-end 0))))
-
- (skip-syntax-backward "w_")
- (and (or (looking-at "\\_<function\\_>")
- (typescript--re-search-backward "\\_<function\\_>" nil t))
-
- (save-match-data (goto-char (match-beginning 0))
- (typescript--forward-function-decl))
-
- (<= pos (point))
- (or prologue-begin (match-beginning 0))))))
-
-(defun typescript--beginning-of-defun-raw ()
- "Helper function for `typescript-beginning-of-defun'.
-Go to previous defun-beginning and return the parse state for it,
-or nil if we went all the way back to bob and don't find
-anything."
- (typescript--ensure-cache)
- (let (pstate)
- (while (and (setq pstate (typescript--backward-pstate))
- (not (eq 'function (typescript--pitem-type (car pstate))))))
- (and (not (bobp)) pstate)))
-
-(defun typescript--pstate-is-toplevel-defun (pstate)
- "Helper function for `typescript--beginning-of-defun-nested'.
-If PSTATE represents a non-empty top-level defun, return the
-top-most pitem. Otherwise, return nil."
- (cl-loop for pitem in pstate
- with func-depth = 0
- with func-pitem
- if (eq 'function (typescript--pitem-type pitem))
- do (cl-incf func-depth)
- and do (setq func-pitem pitem)
- finally return (if (eq func-depth 1) func-pitem)))
-
-(defun typescript--beginning-of-defun-nested ()
- "Helper function for `typescript--beginning-of-defun'.
-Return the pitem of the function we went to the beginning of."
- (or
- ;; Look for the smallest function that encloses point...
- (cl-loop for pitem in (typescript--parse-state-at-point)
- if (and (eq 'function (typescript--pitem-type pitem))
- (typescript--inside-pitem-p pitem))
- do (goto-char (typescript--pitem-h-begin pitem))
- and return pitem)
-
- ;; ...and if that isn't found, look for the previous top-level
- ;; defun
- (cl-loop for pstate = (typescript--backward-pstate)
- while pstate
- if (typescript--pstate-is-toplevel-defun pstate)
- do (goto-char (typescript--pitem-h-begin it))
- and return it)))
-
-(defun typescript--beginning-of-defun-flat ()
- "Helper function for `typescript-beginning-of-defun'."
- (let ((pstate (typescript--beginning-of-defun-raw)))
- (when pstate
- (goto-char (typescript--pitem-h-begin (car pstate))))))
-
-(defun typescript-beginning-of-defun (&optional arg)
- "Value of `beginning-of-defun-function' for `typescript-mode'."
- (setq arg (or arg 1))
- (while (and (not (eobp)) (< arg 0))
- (cl-incf arg)
- (when (and (not typescript-flat-functions)
- (or (eq (typescript-syntactic-context) 'function)
- (typescript--function-prologue-beginning)))
- (typescript-end-of-defun))
-
- (if (typescript--re-search-forward
- "\\_<function\\_>" nil t)
- (goto-char (typescript--function-prologue-beginning))
- (goto-char (point-max))))
-
- (while (> arg 0)
- (cl-decf arg)
- ;; If we're just past the end of a function, the user probably wants
- ;; to go to the beginning of *that* function
- (when (eq (char-before) ?})
- (backward-char))
-
- (let ((prologue-begin (typescript--function-prologue-beginning)))
- (cond ((and prologue-begin (< prologue-begin (point)))
- (goto-char prologue-begin))
-
- (typescript-flat-functions
- (typescript--beginning-of-defun-flat))
- (t
- (typescript--beginning-of-defun-nested))))))
-
-(defun typescript--flush-caches (&optional beg ignored)
- "Flush the `typescript-mode' syntax cache after position BEG.
-BEG defaults to `point-min', meaning to flush the entire cache."
- (interactive)
- (setq beg (or beg (save-restriction (widen) (point-min))))
- (setq typescript--cache-end (min typescript--cache-end beg)))
-
-(defmacro typescript--debug (&rest arguments)
- ;; `(message ,@arguments)
- )
-
-(defun typescript--ensure-cache--pop-if-ended (open-items paren-depth)
- (let ((top-item (car open-items)))
- (when (<= paren-depth (typescript--pitem-paren-depth top-item))
- (cl-assert (not (get-text-property (1- (point)) 'typescript-pend)))
- (put-text-property (1- (point)) (point) 'typescript--pend top-item)
- (setf (typescript--pitem-b-end top-item) (point))
- (setq open-items
- ;; open-items must contain at least two items for this to
- ;; work, but because we push a dummy item to start with,
- ;; that assumption holds.
- (cons (typescript--pitem-add-child (cl-second open-items) top-item)
- (cddr open-items)))))
- open-items)
-
-(defmacro typescript--ensure-cache--update-parse ()
- "Helper function for `typescript--ensure-cache'.
-Update parsing information up to point, referring to parse,
-prev-parse-point, goal-point, and open-items bound lexically in
-the body of `typescript--ensure-cache'."
- `(progn
- (setq goal-point (point))
- (goto-char prev-parse-point)
- (while (progn
- (setq open-items (typescript--ensure-cache--pop-if-ended
- open-items (car parse)))
- ;; Make sure parse-partial-sexp doesn't stop because we *entered*
- ;; the given depth -- i.e., make sure we're deeper than the target
- ;; depth.
- (cl-assert (> (nth 0 parse)
- (typescript--pitem-paren-depth (car open-items))))
- (setq parse (parse-partial-sexp
- prev-parse-point goal-point
- (typescript--pitem-paren-depth (car open-items))
- nil parse))
-
-;; (let ((overlay (make-overlay prev-parse-point (point))))
-;; (overlay-put overlay 'face '(:background "red"))
-;; (unwind-protect
-;; (progn
-;; (typescript--debug "parsed: %S" parse)
-;; (sit-for 1))
-;; (delete-overlay overlay)))
-
- (setq prev-parse-point (point))
- (< (point) goal-point)))
-
- (setq open-items (typescript--ensure-cache--pop-if-ended
- open-items (car parse)))))
-
-(defun typescript--show-cache-at-point ()
- (interactive)
- (require 'pp)
- (let ((prop (get-text-property (point) 'typescript--pstate)))
- (with-output-to-temp-buffer "*Help*"
- (pp prop))))
-
-(defun typescript--split-name (string)
- "Split a typescript name into its dot-separated parts.
-This also removes any prototype parts from the split name
-\(unless the name is just \"prototype\" to start with)."
- (let ((name (save-match-data
- (split-string string "\\." t))))
- (unless (and (= (length name) 1)
- (equal (car name) "prototype"))
-
- (setq name (remove "prototype" name)))))
-
-(defvar typescript--guess-function-name-start nil)
-
-(defun typescript--guess-function-name (position)
- "Guess the name of the typescript function at POSITION.
-POSITION should be just after the end of the word \"function\".
-Return the name of the function, or nil if the name could not be
-guessed.
-
-This function clobbers match data. If we find the preamble
-begins earlier than expected while guessing the function name,
-set `typescript--guess-function-name-start' to that position; otherwise,
-set that variable to nil."
- (setq typescript--guess-function-name-start nil)
- (save-excursion
- (goto-char position)
- (forward-line 0)
- (cond
- ((looking-at typescript--function-heading-3-re)
- (and (eq (match-end 0) position)
- (setq typescript--guess-function-name-start (match-beginning 1))
- (match-string-no-properties 1)))
-
- ((looking-at typescript--function-heading-2-re)
- (and (eq (match-end 0) position)
- (setq typescript--guess-function-name-start (match-beginning 1))
- (match-string-no-properties 1))))))
-
-(defun typescript--clear-stale-cache ()
- ;; Clear any endings that occur after point
- (let (end-prop)
- (save-excursion
- (while (setq end-prop (typescript--forward-text-property
- 'typescript--pend))
- (setf (typescript--pitem-b-end end-prop) nil))))
-
- ;; Remove any cache properties after this point
- (remove-text-properties (point) (point-max)
- '(typescript--pstate t typescript--pend t)))
-
-(defun typescript--ensure-cache (&optional limit)
- "Ensures brace cache is valid up to the character before LIMIT.
-LIMIT defaults to point."
- (setq limit (or limit (point)))
- (when (< typescript--cache-end limit)
-
- (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)
-
- ;; Figure out which class styles we need to look for
- (setq filtered-class-styles
- (cl-loop for style in typescript--class-styles
- if (memq (plist-get style :framework)
- typescript-enabled-frameworks)
- collect style))
-
- (save-excursion
- (save-restriction
- (widen)
-
- ;; Find last known good position
- (goto-char typescript--cache-end)
- (unless (bobp)
- (setq open-items (get-text-property
- (1- (point)) 'typescript--pstate))
-
- (unless open-items
- (goto-char (previous-single-property-change
- (point) 'typescript--pstate nil (point-min)))
-
- (unless (bobp)
- (setq open-items (get-text-property (1- (point))
- 'typescript--pstate))
- (cl-assert open-items))))
-
- (unless open-items
- ;; Make a placeholder for the top-level definition
- (setq open-items (list typescript--initial-pitem)))
-
- (setq parse (syntax-ppss))
- (setq prev-parse-point (point))
-
- (typescript--clear-stale-cache)
-
- (narrow-to-region (point-min) limit)
-
- (cl-loop while (re-search-forward typescript--quick-match-re-func nil t)
- for orig-match-start = (goto-char (match-beginning 0))
- for orig-match-end = (match-end 0)
- do (typescript--ensure-cache--update-parse)
- for orig-depth = (nth 0 parse)
-
- ;; Each of these conditions should return non-nil if
- ;; we should add a new item and leave point at the end
- ;; of the new item's header (h-end in the
- ;; typescript--pitem diagram). This point is the one
- ;; after the last character we need to unambiguously
- ;; detect this construct. If one of these evaluates to
- ;; nil, the location of the point is ignored.
- if (cond
- ;; In comment or string
- ((nth 8 parse) nil)
-
- ;; Regular function declaration
- ((and (looking-at "\\_<function\\_>")
- (setq name (typescript--forward-function-decl)))
-
- (when (eq name t)
- (setq name (typescript--guess-function-name orig-match-end))
- (if name
- (when typescript--guess-function-name-start
- (setq orig-match-start
- typescript--guess-function-name-start))
-
- (setq name t)))
-
- (cl-assert (eq (char-after) ?{))
- (forward-char)
- (make-typescript--pitem
- :paren-depth orig-depth
- :h-begin orig-match-start
- :type 'function
- :name (if (eq name t)
- name
- (typescript--split-name name))))
-
- ;; "Prototype function" declaration
- ((looking-at typescript--plain-method-re)
- (goto-char (match-beginning 3))
- (when (save-match-data
- (typescript--forward-function-decl))
- (forward-char)
- (make-typescript--pitem
- :paren-depth orig-depth
- :h-begin orig-match-start
- :type 'function
- :name (nconc (typescript--split-name
- (match-string-no-properties 1))
- (list (match-string-no-properties 2))))))
-
- ;; Class definition
- ((cl-loop with syntactic-context =
- (typescript--syntactic-context-from-pstate open-items)
- for class-style in filtered-class-styles
- if (and (memq syntactic-context
- (plist-get class-style :contexts))
- (looking-at (plist-get class-style
- :class-decl)))
- do (goto-char (match-end 0))
- and return
- (make-typescript--pitem
- :paren-depth orig-depth
- :h-begin orig-match-start
- :type class-style
- :name (typescript--split-name
- (match-string-no-properties 1))))))
-
- do (typescript--ensure-cache--update-parse)
- and do (push it open-items)
- and do (put-text-property
- (1- (point)) (point) 'typescript--pstate open-items)
- else do (goto-char orig-match-end))
-
- (goto-char limit)
- (typescript--ensure-cache--update-parse)
- (setq typescript--cache-end limit)
- (setq typescript--last-parse-pos limit)
- (setq typescript--state-at-last-parse-pos open-items))))))
-
-(defun typescript--end-of-defun-flat ()
- "Helper function for `typescript-end-of-defun'."
- (cl-loop while (typescript--re-search-forward "}" nil t)
- do (typescript--ensure-cache)
- if (get-text-property (1- (point)) 'typescript--pend)
- if (eq 'function (typescript--pitem-type it))
- return t
- finally do (goto-char (point-max))))
-
-(defun typescript--end-of-defun-nested ()
- "Helper function for `typescript-end-of-defun'."
- (let* (pitem
- (this-end (save-excursion
- (and (setq pitem (typescript--beginning-of-defun-nested))
- (typescript--pitem-goto-h-end pitem)
- (progn (backward-char)
- (forward-list)
- (point)))))
- found)
-
- (if (and this-end (< (point) this-end))
- ;; We're already inside a function; just go to its end.
- (goto-char this-end)
-
- ;; Otherwise, go to the end of the next function...
- (while (and (typescript--re-search-forward "\\_<function\\_>" nil t)
- (not (setq found (progn
- (goto-char (match-beginning 0))
- (typescript--forward-function-decl))))))
-
- (if found (forward-list)
- ;; ... or eob.
- (goto-char (point-max))))))
-
-(defun typescript-end-of-defun (&optional arg)
- "Value of `end-of-defun-function' for `typescript-mode'."
- (setq arg (or arg 1))
- (while (and (not (bobp)) (< arg 0))
- (cl-incf arg)
- (typescript-beginning-of-defun)
- (typescript-beginning-of-defun)
- (unless (bobp)
- (typescript-end-of-defun)))
-
- (while (> arg 0)
- (cl-decf arg)
- ;; look for function backward. if we're inside it, go to that
- ;; function's end. otherwise, search for the next function's end and
- ;; go there
- (if typescript-flat-functions
- (typescript--end-of-defun-flat)
-
- ;; if we're doing nested functions, see whether we're in the
- ;; prologue. If we are, go to the end of the function; otherwise,
- ;; call typescript--end-of-defun-nested to do the real work
- (let ((prologue-begin (typescript--function-prologue-beginning)))
- (cond ((and prologue-begin (<= prologue-begin (point)))
- (goto-char prologue-begin)
- (re-search-forward "\\_<function")
- (goto-char (match-beginning 0))
- (typescript--forward-function-decl)
- (forward-list))
-
- (t (typescript--end-of-defun-nested)))))))
-
-(defun typescript--backward-syntactic-ws (&optional lim)
- "Simple implementation of `c-backward-syntactic-ws' for `typescript-mode'."
- (save-restriction
- (when lim (narrow-to-region lim (point-max)))
-
- (let ((pos (point)))
- (while (progn (forward-comment most-negative-fixnum)
- (/= (point)
- (prog1
- pos
- (setq pos (point)))))))))
-
-(defun typescript--forward-syntactic-ws (&optional lim)
- "Simple implementation of `c-forward-syntactic-ws' for `typescript-mode'."
- (save-restriction
- (when lim (narrow-to-region (point-min) lim))
- (let ((pos (point)))
- (while (progn
- (forward-comment most-positive-fixnum)
- (/= (point)
- (prog1
- pos
- (setq pos (point)))))))))
-
-;; Like (up-list -1), but only considers lists that end nearby"
-(defun typescript--up-nearby-list ()
- (save-restriction
- ;; Look at a very small region so our compuation time doesn't
- ;; explode in pathological cases.
- (narrow-to-region (max (point-min) (- (point) 500)) (point))
- (up-list -1)))
-
-(defun typescript--inside-param-list-p ()
- "Return non-nil iff point is in a function parameter list."
- (ignore-errors
- (save-excursion
- (typescript--up-nearby-list)
- (and (looking-at "(")
- (progn (forward-symbol -1)
- (or (looking-at "function")
- (progn (forward-symbol -1)
- (looking-at "function"))))))))
-
-(defun typescript--inside-dojo-class-list-p ()
- "Return non-nil iff point is in a Dojo multiple-inheritance class block."
- (ignore-errors
- (save-excursion
- (typescript--up-nearby-list)
- (let ((list-begin (point)))
- (forward-line 0)
- (and (looking-at typescript--dojo-class-decl-re)
- (goto-char (match-end 0))
- (looking-at "\"\\s-*,\\s-*\\[")
- (eq (match-end 0) (1+ list-begin)))))))
-
-(defun typescript--syntax-begin-function ()
- (when (< typescript--cache-end (point))
- (goto-char (max (point-min) typescript--cache-end)))
-
- (let ((pitem))
- (while (and (setq pitem (car (typescript--backward-pstate)))
- (not (eq 0 (typescript--pitem-paren-depth pitem)))))
-
- (when pitem
- (goto-char (typescript--pitem-h-begin pitem )))))
-
-(defun typescript--move-to-end-of-plain-string ()
- "If the point is in a plain string, move to the end of it.
-
-Otherwise, don't move. A plain string is a string which is not a
-template string. The point is considered to be \"in\" a string if
-it is on the delimiters of the string, or any point inside.
-
-Returns point if the end of the string was found, or nil if the
-end of the string was not found."
- (let ((end-position
- (save-excursion
- (let* ((syntax (syntax-ppss))
- (str-terminator (nth 3 syntax))
- ;; The 8th element will also be set if we are in a comment. So we
- ;; check str-terminator to protect against that.
- (string-start (and str-terminator
- (nth 8 syntax))))
- (if (and string-start
- (not (eq str-terminator ?`)))
- ;; We may already be at the end of the string.
- (if (and (eq (char-after) str-terminator)
- (not (eq (char-before) ?\\)))
- (point)
- ;; We just search forward and then check if the hit we get has a
- ;; string-start equal to ours.
- (cl-loop while (re-search-forward
- (concat "\\(?:[^\\]\\|^\\)\\(" (string str-terminator) "\\)")
- nil t)
- if (eq string-start
- (save-excursion (nth 8 (syntax-ppss (match-beginning 1)))))
- return (match-beginning 1)))
- ;; If we are on the start delimiter then the value of syntax-ppss will look
- ;; like we're not in a string at all, but this function considers the
- ;; start delimiter to be "in" the string. We take care of this here.
- (when (memq (char-after) '(?' ?\"))
- (forward-char)
- (typescript--move-to-end-of-plain-string)))))))
- (when end-position
- (goto-char end-position))))
-
-;;; Font Lock
-(defun typescript--make-framework-matcher (framework &rest regexps)
- "Helper function for building `typescript--font-lock-keywords'.
-Create a byte-compiled function for matching a concatenation of
-REGEXPS, but only if FRAMEWORK is in `typescript-enabled-frameworks'."
- (setq regexps (apply #'concat regexps))
- (byte-compile
- `(lambda (limit)
- (when (memq (quote ,framework) typescript-enabled-frameworks)
- (re-search-forward ,regexps limit t)))))
-
-(defvar typescript--tmp-location nil)
-(make-variable-buffer-local 'typescript--tmp-location)
-
-(defun typescript--forward-destructuring-spec (&optional func)
- "Move forward over a typescript destructuring spec.
-If FUNC is supplied, call it with no arguments before every
-variable name in the spec. Return true iff this was actually a
-spec. FUNC must preserve the match data."
- (cl-case (char-after)
- (?\[
- (forward-char)
- (while
- (progn
- (forward-comment most-positive-fixnum)
- (cond ((memq (char-after) '(?\[ ?\{))
- (typescript--forward-destructuring-spec func))
-
- ((eq (char-after) ?,)
- (forward-char)
- t)
-
- ((looking-at typescript--name-re)
- (and func (funcall func))
- (goto-char (match-end 0))
- t))))
- (when (eq (char-after) ?\])
- (forward-char)
- t))
-
- (?\{
- (forward-char)
- (forward-comment most-positive-fixnum)
- (while
- (when (looking-at typescript--objfield-re)
- (goto-char (match-end 0))
- (forward-comment most-positive-fixnum)
- (and (cond ((memq (char-after) '(?\[ ?\{))
- (typescript--forward-destructuring-spec func))
- ((looking-at typescript--name-re)
- (and func (funcall func))
- (goto-char (match-end 0))
- t))
- (progn (forward-comment most-positive-fixnum)
- (when (eq (char-after) ?\,)
- (forward-char)
- (forward-comment most-positive-fixnum)
- t)))))
- (when (eq (char-after) ?\})
- (forward-char)
- t))))
-
-(defun typescript--variable-decl-matcher (limit)
- "Font-lock matcher for variable names in a variable declaration.
-This is a cc-mode-style matcher that *always* fails, from the
-point of view of font-lock. It applies highlighting directly with
-`font-lock-apply-highlight'."
- (condition-case nil
- (save-restriction
- (narrow-to-region (point-min) limit)
-
- (let ((first t))
- (forward-comment most-positive-fixnum)
- (while
- (and (or first
- (when (eq (char-after) ?,)
- (forward-char)
- (forward-comment most-positive-fixnum)
- t))
- (cond ((looking-at typescript--name-re)
- (font-lock-apply-highlight
- '(0 font-lock-variable-name-face))
- (goto-char (match-end 0)))
-
- ((save-excursion
- (typescript--forward-destructuring-spec))
-
- (typescript--forward-destructuring-spec
- (lambda ()
- (font-lock-apply-highlight
- '(0 font-lock-variable-name-face)))))))
-
- (forward-comment most-positive-fixnum)
- (when (eq (char-after) ?=)
- (forward-char)
- (typescript--forward-expression)
- (forward-comment most-positive-fixnum))
-
- (setq first nil))))
-
- ;; Conditions to handle
- (scan-error nil)
- (end-of-buffer nil))
-
- ;; Matcher always "fails"
- nil)
-
-(defun typescript--in-documentation-comment-p ()
- "Reports whether point is inside a documentation comment."
- (let ((parse (syntax-ppss)))
- (and
- (nth 4 parse) ;; Inside a comment ...
- (save-match-data
- (save-excursion
- (goto-char (nth 8 parse))
- (looking-at "/\\*\\*")))))) ;; ... which starts with /**
-
-(defun typescript--documentation-font-lock-helper (re limit)
- "This is a helper macro that determines whether jsdoc highlighting is to be applied,
-and searches for the next token to be highlighted."
- (cl-loop while (re-search-forward re limit t)
- if (typescript--in-documentation-comment-p)
- return (point)))
-
-(defun typescript--jsdoc-param-matcher (limit)
- "Font-lock mode matcher that finds jsdoc parameter tags in documentation."
- (typescript--documentation-font-lock-helper typescript-jsdoc-param-tag-regexp limit))
-
-(defun typescript--jsdoc-typed-tag-matcher (limit)
- "Font-lock mode matcher that finds jsdoc typed tags in documentation."
- (typescript--documentation-font-lock-helper typescript-jsdoc-typed-tag-regexp limit))
-
-(defun typescript--jsdoc-arg-tag-matcher (limit)
- "Font-lock mode matcher that finds jsdoc tags that take one argument in documentation."
- (typescript--documentation-font-lock-helper typescript-jsdoc-arg-tag-regexp limit))
-
-(defun typescript--jsdoc-empty-tag-matcher (limit)
- "Font-lock mode matcher that finds jsdoc tags without argument in documentation."
- (typescript--documentation-font-lock-helper typescript-jsdoc-empty-tag-regexp limit))
-
-(defun typescript--typedoc-link-matcher (limit)
- "Font-lock mode matcher that finds typedoc links in documentation."
- (typescript--documentation-font-lock-helper typescript-typedoc-link-tag-regexp limit))
-
-(defun typescript--typedoc-literal-markup-matcher (limit)
- "Font-lock mode matcher that finds typedoc literal markup in documentation."
- (typescript--documentation-font-lock-helper typescript-typedoc-literal-markup-regexp limit))
-
-(defun typescript--tslint-flag-matcher (limit)
- "Font-lock mode matcher that finds tslint flags in comments."
- (cl-loop while (re-search-forward typescript-tslint-flag-regexp limit t)
- if (nth 4 (syntax-ppss (match-beginning 1)))
- return (point)))
-
-(defconst typescript--font-lock-keywords-3
- `(
- ,@typescript--font-lock-keywords-2
-
- (typescript--jsdoc-param-matcher (1 'typescript-jsdoc-tag t t)
- (2 'typescript-jsdoc-type t t)
- (3 'typescript-jsdoc-value t t))
-
- (typescript--jsdoc-typed-tag-matcher (1 'typescript-jsdoc-tag t t)
- (2 'typescript-jsdoc-type t t))
-
- (typescript--jsdoc-arg-tag-matcher (1 'typescript-jsdoc-tag t t)
- (2 'typescript-jsdoc-value t t))
-
- (typescript--jsdoc-empty-tag-matcher (1 'typescript-jsdoc-tag t t))
-
- (typescript--typedoc-link-matcher (0 'typescript-jsdoc-value t))
-
- (typescript--typedoc-literal-markup-matcher
- (0 'typescript-jsdoc-value t))
-
- (typescript--tslint-flag-matcher
- (1 font-lock-preprocessor-face t))
-
- ("\\.\\(prototype\\)\\_>"
- (1 font-lock-constant-face))
-
- (,(rx symbol-start "class" (+ space) (group (+ (or (syntax word) (syntax symbol)))))
- (1 font-lock-type-face))
-
- (,(rx symbol-start "extends" (+ space) (group (+ (or (syntax word) (syntax symbol)))))
- (1 font-lock-type-face))
-
- (,(rx symbol-start "implements" (+ space))
- (,(rx symbol-start (+ (syntax word))) nil nil (0 font-lock-type-face)))
-
- (,(rx symbol-start "interface" (+ space) (group (+ (or (syntax word) (syntax symbol)))))
- (1 font-lock-type-face))
-
- (,(rx symbol-start "type" (+ space) (group (+ (or (syntax word) (syntax symbol)))))
- (1 font-lock-type-face))
-
- (,(rx symbol-start "enum" (+ space) (group (+ (or (syntax word) (syntax symbol)))))
- (1 font-lock-type-face))
-
- ;; Highlights class being declared, in parts
- (typescript--class-decl-matcher
- ,(concat "\\(" typescript--name-re "\\)\\(?:\\.\\|.*$\\)")
- (goto-char (match-beginning 1))
- nil
- (1 font-lock-type-face))
-
- ;; Highlights parent class, in parts, if available
- (typescript--class-decl-matcher
- ,(concat "\\(" typescript--name-re "\\)\\(?:\\.\\|.*$\\)")
- (if (match-beginning 2)
- (progn
- (setq typescript--tmp-location (match-end 2))
- (goto-char typescript--tmp-location)
- (insert "=")
- (goto-char (match-beginning 2)))
- (setq typescript--tmp-location nil)
- (goto-char (point-at-eol)))
- (when typescript--tmp-location
- (save-excursion
- (goto-char typescript--tmp-location)
- (delete-char 1)))
- (1 font-lock-type-face))
-
- ;; Highlights parent class
- (typescript--class-decl-matcher
- (2 font-lock-type-face nil t))
-
- ;; Dojo needs its own matcher to override the string highlighting
- (,(typescript--make-framework-matcher
- 'dojo
- "^\\s-*dojo\\.declare\\s-*(\""
- "\\(" typescript--dotted-name-re "\\)"
- "\\(?:\"\\s-*,\\s-*\\(" typescript--dotted-name-re "\\)\\)?")
- (1 font-lock-type-face t)
- (2 font-lock-type-face nil t))
-
- ;; Match Dojo base classes. Of course Mojo has to be different
- ;; from everything else under the sun...
- (,(typescript--make-framework-matcher
- 'dojo
- "^\\s-*dojo\\.declare\\s-*(\""
- "\\(" typescript--dotted-name-re "\\)\"\\s-*,\\s-*\\[")
- ,(concat "[[,]\\s-*\\(" typescript--dotted-name-re "\\)\\s-*"
- "\\(?:\\].*$\\)?")
- (backward-char)
- (end-of-line)
- (1 font-lock-type-face))
-
- ;; continued Dojo base-class list
- (,(typescript--make-framework-matcher
- 'dojo
- "^\\s-*" typescript--dotted-name-re "\\s-*[],]")
- ,(concat "\\(" typescript--dotted-name-re "\\)"
- "\\s-*\\(?:\\].*$\\)?")
- (if (save-excursion (backward-char)
- (typescript--inside-dojo-class-list-p))
- (forward-symbol -1)
- (end-of-line))
- (end-of-line)
- (1 font-lock-type-face))
-
- ;; variable declarations
- ,(list
- (concat "\\_<\\(const\\|var\\|let\\)\\_>\\|" typescript--basic-type-re)
- (list #'typescript--variable-decl-matcher nil nil nil))
-
- ;; class instantiation
- ,(list
- (concat "\\_<new\\_>\\s-+\\(" typescript--dotted-name-re "\\)")
- (list 1 'font-lock-type-face))
-
- ;; instanceof
- ,(list
- (concat "\\_<instanceof\\_>\\s-+\\(" typescript--dotted-name-re "\\)")
- (list 1 'font-lock-type-face))
-
- ;; formal parameters
- ,(list
- (concat
- "\\_<function\\_>\\(\\s-+" typescript--name-re "\\)?\\s-*\\(<.*>\\)?\\s-*(\\s-*"
- typescript--name-start-re)
- (list (concat "\\(" typescript--name-re "\\)\\(\\s-*).*\\)?")
- '(backward-char)
- '(end-of-line)
- '(1 font-lock-variable-name-face)))
-
- ;; continued formal parameter list
- ,(list
- (concat
- "^\\s-*" typescript--name-re "\\s-*[,)]")
- (list typescript--name-re
- '(if (save-excursion (backward-char)
- (typescript--inside-param-list-p))
- (forward-symbol -1)
- (end-of-line))
- '(end-of-line)
- '(0 font-lock-variable-name-face))))
- "Level three font lock for `typescript-mode'.")
-
-(defun typescript--flyspell-mode-predicate ()
- "A custom predicate to help `flyspell-prog-mode' determine whether a word should be checked."
- ;; We depend on fontification for our results. font-lock-ensure is defined on
- ;; Emacs 25 and over. Earlier versions use font-lock-fontify-buffer.
- (if (fboundp 'font-lock-ensure)
- (font-lock-ensure)
- (font-lock-fontify-buffer))
- (and
- ;; Check with the default method that flyspell provides.
- (flyspell-generic-progmode-verify)
-
- ;;
- ;; And eliminate cases specific to our mode we don't want to have
- ;; spell-checked.
- ;;
-
- ;; Don't check the module names in import statements.
- (save-excursion
- (not (let* ((parse (syntax-ppss (1- (point))))
- (string-start-pos (and (nth 3 parse)
- (nth 8 parse))))
- (and string-start-pos
- (save-match-data
- ;; Move to back to the start of the string, then past any ws
- ;; and then past any non-ws to see if we have "from" or "import".
- (goto-char string-start-pos)
- (typescript--backward-syntactic-ws)
- (skip-syntax-backward "^-" (point-at-bol))
- (looking-at "from\\|import\\s-"))))))))
-
-(defun typescript--inside-pitem-p (pitem)
- "Return whether point is inside the given pitem's header or body."
- (typescript--ensure-cache)
- (cl-assert (typescript--pitem-h-begin pitem))
- (cl-assert (typescript--pitem-paren-depth pitem))
-
- (and (> (point) (typescript--pitem-h-begin pitem))
- (or (null (typescript--pitem-b-end pitem))
- (> (typescript--pitem-b-end pitem) (point)))))
-
-(defun typescript--parse-state-at-point ()
- "Parse the typescript program state at point.
-Return a list of `typescript--pitem' instances that apply to point, most
-specific first. In the worst case, the current toplevel instance
-will be returned."
- (save-excursion
- (save-restriction
- (widen)
- (typescript--ensure-cache)
- (let* ((bound (if (eobp) (point) (1+ (point))))
- (pstate (or (save-excursion
- (typescript--backward-pstate))
- (list typescript--initial-pitem))))
-
- ;; Loop until we either hit a pitem at BOB or pitem ends after
- ;; point (or at point if we're at eob)
- (cl-loop for pitem = (car pstate)
- until (or (eq (typescript--pitem-type pitem)
- 'toplevel)
- (typescript--inside-pitem-p pitem))
- do (pop pstate))
-
- pstate))))
-
-(defun typescript--syntactic-context-from-pstate (pstate)
- "Return the typescript syntactic context corresponding to PSTATE."
- (let ((type (typescript--pitem-type (car pstate))))
- (cond ((memq type '(function macro))
- type)
- ((consp type)
- 'class)
- (t 'toplevel))))
-
-(defun typescript-syntactic-context ()
- "Return the typescript syntactic context at point.
-When called interatively, also display a message with that
-context."
- (interactive)
- (let* ((syntactic-context (typescript--syntactic-context-from-pstate
- (typescript--parse-state-at-point))))
-
- (when (called-interactively-p 'interactive)
- (message "Syntactic context: %s" syntactic-context))
-
- syntactic-context))
-
-(defun typescript--class-decl-matcher (limit)
- "Font lock function used by `typescript-mode'.
-This performs fontification according to `typescript--class-styles'."
- (cl-loop initially (typescript--ensure-cache limit)
- while (re-search-forward typescript--quick-match-re limit t)
- for orig-end = (match-end 0)
- do (goto-char (match-beginning 0))
- if (cl-loop for style in typescript--class-styles
- for decl-re = (plist-get style :class-decl)
- if (and (memq (plist-get style :framework)
- typescript-enabled-frameworks)
- (memq (typescript-syntactic-context)
- (plist-get style :contexts))
- decl-re
- (looking-at decl-re))
- do (goto-char (match-end 0))
- and return t)
- return t
- else do (goto-char orig-end)))
-
-(defconst typescript--font-lock-keywords-4
- `(
- ;; highlights that override previous levels
- ;;
-
- ;; special highlight for `this' keyword
- ("\\(this\\)\\."
- (1 'typescript-this-face))
-
- (,typescript--access-modifier-re (1 'typescript-access-modifier-face))
- (,typescript--basic-type-re (1 'typescript-primitive-face))
-
- ;; generics support
- ,(list
- (concat typescript--name-re "\\s-*" "<\\s-*" typescript--name-start-re)
- (list (concat "\\(" typescript--name-re "\\)\\(\\s-*>[^<]*\\)?")
- '(backward-char)
- '(end-of-line)
- '(1 font-lock-type-face)))
-
- ;; type-highlighting in variable/parameter declarations
- ;; supports a small variety of common declarations:
- ;; - let a: SomeType;
- ;; - private b: SomeType;
- ;; - private someFunc(var: SomeType) {
- ;; - private array: SomeType[]
- ;; - private generic: SomeType<Foo>
- ;; - private genericArray: SomeType<Foo>[]
- ;; - function testFunc(): SomeType<> {
- ;; TODO: namespaced classes!
- ,(list
- (concat ":\\s-\\(" typescript--type-name-re "\\)\\(<" typescript--type-name-re ">\\)?\\(\[\]\\)?\\([,;]\\)?\\s-*{?")
- '(1 'font-lock-type-face))
-
- ;; type-casts
- ,(list
- (concat "<\\(" typescript--type-name-re "\\)>")
- '(1 'font-lock-type-face))
-
- ;; highlights that append to previous levels
- ;;
- ,@typescript--font-lock-keywords-3
-
- (,typescript--decorator-re (1 font-lock-function-name-face))
- (,typescript--function-call-re (1 font-lock-function-name-face))
- (,typescript--builtin-re (1 font-lock-type-face))
-
- ;; arrow function
- ("\\(=>\\)"
- (1 font-lock-keyword-face)))
- "Level four font lock for `typescript-mode'.")
-
-(defconst typescript--font-lock-keywords
- '(typescript--font-lock-keywords-4 typescript--font-lock-keywords-1
- typescript--font-lock-keywords-2
- typescript--font-lock-keywords-3
- typescript--font-lock-keywords-4)
- "Font lock keywords for `typescript-mode'. See `font-lock-keywords'.")
-
-;;; Propertize
-
-;;
-;; The propertize code was adapted from:
-;; https://github.com/emacs-mirror/emacs/blob/489d6466372f488adc53897435fff290394b62f7/lisp/progmodes/js.el
-;;
-
-(defconst typescript--syntax-propertize-regexp-regexp
- (rx
- ;; Start of regexp.
- "/"
- (0+ (or
- ;; Match characters outside of a character class.
- (not (any ?\[ ?/ ?\\))
- ;; Match backslash quoted characters.
- (and "\\" not-newline)
- ;; Match character class.
- (and
- "["
- (0+ (or
- (not (any ?\] ?\\))
- (and "\\" not-newline)))
- "]")))
- (group (zero-or-one "/")))
- "Regular expression matching a JavaScript regexp literal.")
-
-(defun typescript-syntax-propertize-regexp (end)
- (let ((ppss (syntax-ppss)))
- (when (eq (nth 3 ppss) ?/)
- ;; A /.../ regexp.
- (goto-char (nth 8 ppss))
- (when (looking-at typescript--syntax-propertize-regexp-regexp)
- ;; Don't touch text after END.
- (when (> end (match-end 1))
- (setq end (match-end 1)))
- (put-text-property (match-beginning 1) end
- 'syntax-table (string-to-syntax "\"/"))
- (goto-char end)))))
-
-(defun typescript-syntax-propertize (start end)
- ;; JavaScript allows immediate regular expression objects, written /.../.
- (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.
- ("\\(?:^\\|[=([{,:;|&!]\\|\\_<return\\_>\\)\\(?:[ \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 "\"/"))
- (typescript-syntax-propertize-regexp end)))))
- ;; Hash-bang at beginning of buffer.
- ("\\`\\(#\\)!" (1 "< b")))
- start end))
-
-;;; Indentation
-
-(defconst typescript--possibly-braceless-keyword-re
- (typescript--regexp-opt-symbol
- '("catch" "do" "else" "finally" "for" "if" "try" "while" "with"))
- "Regexp matching keywords optionally followed by an opening brace.")
-
-(defconst typescript--indent-keyword-re
- (typescript--regexp-opt-symbol '("in" "instanceof"))
- "Regexp matching keywords that affect indentation of continued expressions.")
-
-(defconst typescript--indent-operator-re
- (concat "[-+*/%<>=&^|?:.]\\([^-+*/]\\|$\\)\\|" typescript--indent-keyword-re)
- "Regexp matching operators that affect indentation of continued expressions.")
-
-;;
-;; We purposely do not allow the plus symbol as a prefix here, as this
-;; regex is used to check number literal in type annotations, and TS
-;; does not allow to use a plus symbol to prefix numbers there: you
-;; can use 1, but not +1 in a type annotation.
-;;
-;; This is meant to match NaN, floats, decimals, the two infinities
-;; and numbers recorded in binary, octal and hex.
-;;
-;; This regular expression was derived from:
-;; https://stackoverflow.com/a/30987109/
-;;
-(defconst typescript--number-literal-re
- "\\(?:NaN\\|-?\\(?:0[Bb][01]+\\|0[Oo][0-7]+\\|0[Xx][0-9a-fA-F]+\\|Infinity\\|\\(?:[[:digit:]]*\\.[[:digit:]]+\\|[[:digit:]]+\\)\\(?:[Ee][+-]?[[:digit:]]+\\)?\\)\\)"
- "Regexp that matches number literals.")
-
-(defconst typescript--reserved-start-keywords
- '("const" "export" "function" "let" "var")
- "These keywords cannot be variable or type names and start a new sentence.
-Note that the \"import\" keyword can be a type import since TS2.9, so it might
-not start a sentence!")
-
-(defconst typescript--reserved-start-keywords-re
- (typescript--regexp-opt-symbol '("const" "export" "function" "let" "var"))
- "A regular expression matching `typescript--reserved-start-keywords'.")
-
-(defconst typescript--type-vs-ternary-re
- (concat "[?]\\|" (typescript--regexp-opt-symbol
- (append typescript--reserved-start-keywords
- '("as" "class" "interface" "private" "public" "readonly"))))
- "Keywords/Symbols that help tell apart colon for types vs ternary operators.")
-
-(defun typescript--search-backward-matching-angle-bracket-inner (depth)
- "Auxiliary function for `typescript--search-backward-matching-angle-bracket'.
-DEPTH indicates how nested we think we are: it increases when we cross closing
-brackets, and decreases when we cross opening brackets."
- ;; We look backwards for a "<" that would correspond to the ">" we started
- ;; from. However, there is no guarantee that it exists, since our ">" could
- ;; be a greater-than operation. Some symbols will make it clear that we are
- ;; *not* in a type annotation, so we can return nil. Otherwise, we keep
- ;; looking for the matching one.
- (or (<= depth 0)
- (and
- ;; If we cross over a reserved start keyword, we abandon hope of finding
- ;; a matching angle bracket. This prevents extreme recursion depths.
- (typescript--re-search-backward (concat "[<>]\\|" typescript--reserved-start-keywords-re) nil t)
- (cl-case (char-after)
- (?< (typescript--search-backward-matching-angle-bracket-inner (- depth 1)))
- (?> (typescript--search-backward-matching-angle-bracket-inner (+ depth 1)))))))
-
-(defun typescript--search-backward-matching-angle-bracket ()
- "Search for matching \"<\" preceding a starting \">\".
-DEPTH indicates how nested we think we are. Assumes the starting position is
-right before the closing \">\". Returns nil when a match was not found,
-otherwise returns t and the current position is right before the matching
-\"<\"."
- (typescript--search-backward-matching-angle-bracket-inner 1))
-
-(defun typescript--re-search-backward-ignoring-angle-brackets ()
- "Search backwards, jumping over text within angle brackets.
-Searches specifically for any of \"=\", \"}\", and \"type\"."
- (and
- (typescript--re-search-backward "[>=}]\\|\\_<type\\_>" nil t)
- (or (not (looking-at ">"))
- (and
- (typescript--search-backward-matching-angle-bracket)
- (typescript--re-search-backward-ignoring-angle-brackets)))))
-
-(defun typescript--looking-at-operator-p ()
- "Return non-nil if point is on a typescript operator, other than a comma."
- (save-match-data
- (and (looking-at typescript--indent-operator-re)
- (or (not (looking-at ":"))
- (save-excursion
- (backward-sexp)
- (and
- (typescript--re-search-backward "[?:{]\\|\\_<case\\_>" nil t)
- (looking-at "?"))))
- ;; Do not identify forward slashes appearing in a "list" as
- ;; an operator. The lists are: arrays, or lists of
- ;; arguments. In this context, they must be part of regular
- ;; expressions, and not math operators.
- (not (and (looking-at "/")
- (save-excursion
- (typescript--backward-syntactic-ws)
- (memq (char-before) '(?, ?\[ ?\()))))
- ;; Do not identify methods, or fields, that are named "in" or
- ;; "instanceof" as being operator keywords.
- (not (and
- (looking-at typescript--indent-keyword-re)
- (save-excursion
- (typescript--backward-syntactic-ws)
- (memq (char-before) '(?, ?{ ?} ?\;)))))
- ;; Do not identify the symbol > if it is likely part of a type argument
- ;; T<A>, but identify it if it is likely a greater-than symbol. This is
- ;; a hard problem in the absence of semicolons, see:
- ;; https://github.com/ananthakumaran/typescript.el/issues/81
- (not (and
- (looking-at ">")
- (save-excursion
- (and
- (typescript--search-backward-matching-angle-bracket)
- ;; If we made it here, we found a candidate matching opening
- ;; angle bracket. We still need to guess whether it actually
- ;; is one, and not a spurious less-than operator!
-
- ;; Look backwards for the first of:
- ;; - one of the symbols: = :
- ;; - or a TypeScript keyword
- ;; Depending on what comes first, we can make an educated
- ;; guess on the nature of our ">" of interest.
- (typescript--re-search-backward (concat "[=:]\\|" typescript--keyword-re) nil t)
- (or
- ;; If the previous keyword is "as", definitely a type.
- (looking-at "\\_<as\\_>")
- ;; Same goes for type imports.
- (looking-at "\\_<import\\_>")
- ;; A colon could be either a type symbol, or a ternary
- ;; operator, try to guess which.
- (and (looking-at ":")
- (typescript--re-search-backward typescript--type-vs-ternary-re nil t)
- (not (looking-at "?")))
- ;; This final check lets us distinguish between a
- ;; 2-argument type "t < a , b > ..." and a use of the ","
- ;; operator between two comparisons "t < a , b > ...".
- ;; Looking back a little more lets us guess.
- (and (looking-at "=")
- (typescript--re-search-backward-ignoring-angle-brackets)
- (looking-at "\\_<type\\_>")))))))
- (not (and
- (looking-at "*")
- ;; Generator method (possibly using computed property).
- (looking-at (concat "\\* *\\(?:\\[\\|" typescript--name-re
- " *(\\)"))
- (save-excursion
- (typescript--backward-syntactic-ws)
- ;; We might misindent some expressions that would
- ;; return NaN anyway. Shouldn't be a problem.
- (memq (char-before) '(?, ?} ?{ ?\;))))))))
-
-
-(defun typescript--continued-expression-p ()
- "Return non-nil if the current line continues an expression."
- (save-excursion
- (back-to-indentation)
- (let ((list-start (nth 1 (syntax-ppss))))
- (and
- ;; This not clause is there to eliminate degenerate cases where we have
- ;; something that looks like a continued expression but we are in fact at
- ;; the beginning of the expression. Example: in `if (a) { .q(1)` when the
- ;; point is on the dot, the expression that follows looks like a member
- ;; expression but the object on which it is a member is missing. If we
- ;; naively treat this as a continued expression, we run into trouble
- ;; later. (An infinite loop.)
- (not (and list-start
- (save-excursion
- (typescript--backward-syntactic-ws)
- (backward-char)
- (eq (point) list-start))))
- ;; Don't identify the spread syntax or rest operator as a "continuation".
- (not (looking-at "\\.\\.\\."))
- (or (typescript--looking-at-operator-p)
- (and (progn
- (typescript--backward-syntactic-ws)
- (or (bobp) (backward-char))
- (and (> (point) (point-min))
- (save-excursion (backward-char) (not (looking-at "[/*]/")))
- (typescript--looking-at-operator-p)
- (and (progn (backward-char)
- (not (looking-at "++\\|--\\|/[/*]"))))))))))))
-
-(cl-defun typescript--compute-member-expression-indent ()
- "Determine the indent of a member expression.
-
-This function must be called with point located at the dot that
-starts the member expression.
-"
- ;; Find the line that has the object from which we are getting thismember.
- ;; And set an indent relative to that.
- (while (looking-at "\\.")
- (typescript--backward-syntactic-ws)
- (while (eq (char-before) ?\;)
- (backward-char))
- (when (memq (char-before) '(?\? ?\!))
- (backward-char))
- (while (memq (char-before) '(?\] ?} ?\) ?>))
- (if (not (eq (char-before) ?>))
- (backward-list)
- (backward-char)
- (typescript--backward-over-generic-parameter-list))
- (typescript--backward-syntactic-ws))
- (if (looking-back typescript--dotted-name-re nil)
- (back-to-indentation)
- (typescript--forward-syntactic-ws)))
- (+ (current-column) typescript-indent-level))
-
-(defun typescript--end-of-do-while-loop-p ()
- "Return non-nil if point is on the \"while\" of a do-while statement.
-Otherwise, return nil. A braceless do-while statement spanning
-several lines requires that the start of the loop is indented to
-the same column as the current line."
- (interactive)
- (save-excursion
- (save-match-data
- (when (looking-at "\\s-*\\_<while\\_>")
- (if (save-excursion
- (skip-chars-backward "[ \t\n]*}")
- (looking-at "[ \t\n]*}"))
- (save-excursion
- (backward-list) (forward-symbol -1) (looking-at "\\_<do\\_>"))
- (typescript--re-search-backward "\\_<do\\_>" (point-at-bol) t)
- (or (looking-at "\\_<do\\_>")
- (let ((saved-indent (current-indentation)))
- (while (and (typescript--re-search-backward "^\\s-*\\_<" nil t)
- (/= (current-indentation) saved-indent)))
- (and (looking-at "\\s-*\\_<do\\_>")
- (not (typescript--re-search-forward
- "\\_<while\\_>" (point-at-eol) t))
- (= (current-indentation) saved-indent)))))))))
-
-
-(defun typescript--ctrl-statement-indentation ()
- "Helper function for `typescript--proper-indentation'.
-Return the proper indentation of the current line if it starts
-the body of a control statement without braces; otherwise, return
-nil."
- (save-excursion
- (back-to-indentation)
- (when (save-excursion
- (and (not (eq (point-at-bol) (point-min)))
- (not (looking-at "[{]"))
- (progn
- (typescript--re-search-backward "[[:graph:]]" nil t)
- (or (eobp) (forward-char))
- (when (= (char-before) ?\)) (backward-list))
- (skip-syntax-backward " ")
- (skip-syntax-backward "w_")
- (and
- (looking-at typescript--possibly-braceless-keyword-re)
- ;; If preceded by period, it's a method call.
- (not (= (char-before) ?.))))
- (not (typescript--end-of-do-while-loop-p))))
- (save-excursion
- (goto-char (match-beginning 0))
- (+ (current-indentation) typescript-indent-level)))))
-
-(defun typescript--get-c-offset (symbol anchor)
- (let ((c-offsets-alist
- (list (cons 'c typescript-comment-lineup-func))))
- (c-get-syntactic-indentation (list (cons symbol anchor)))))
-
-(defun typescript--backward-over-generic-parameter-list ()
- "Search backward for the start of a generic's parameter list and move to it.
-
-This is a utility function for
-`typescript--backward-to-parameter-list'.
-
-This function must be called with the point placed on the final >
-of the generic's parameter list. It will scan backwards to find
-the start. If successful, it will move the point to the start of
-the list. If not, it does not move the point.
-
-Returns nil on failure, or the position to which the point was
-moved on success."
- (when (eq (char-after) ?>)
- (let ((depth 1))
- (cl-loop named search-loop
- while (> depth 0)
- do (progn
- (unless (re-search-backward "[<>]" nil t)
- (cl-return-from search-loop nil))
- (cond
- ((looking-at ">")
- (unless (eq (char-before) ?=)
- (setq depth (1+ depth))))
- ((looking-at "<") (setq depth (1- depth)))))
- finally return (point)))))
-
-(defun typescript--backward-to-parameter-list ()
- "Search backward for the end of a parameter list and move to it.
-
-This is a utility function for `typescript--proper-indentation'.
-
-This function must be called with the point placed before an
-opening curly brace. It will try to skip over the type
-annotation that would mark the return value of a function and
-move to the end of the parameter list. If it is unsuccessful, it
-does not move the point. \"Unsuccessful\" here also means that
-the position at which we started did not in fact mark the
-beginning of a function. The curly brace belonged to some other
-syntactic construct than a function.
-
-Returns nil on failure, or the position to which the point was
-moved on success."
- (let ((location
- (or
- ;; This handles the case of a function with return type annotation.
- (save-excursion
- (cl-loop named search-loop
- do
- (typescript--backward-syntactic-ws)
- ;; Check whether we are at "):".
- (when (and (eq (char-before) ?\:)
- (progn
- (backward-char)
- (skip-syntax-backward " ")
- (eq (char-before) ?\))))
- ;; Success! This the end of the parameter list.
- (cl-return-from search-loop (point)))
- ;; If we recognize a structure that belongs in a return type annotation,
- ;; skip back over it, or fail.
- (cond
- ;; Arrow of a function definition, or typeguard (eg. foo is SomeClass)
- ((looking-back "=>\\|is" (- (point) 2))
- (backward-char 2))
- ;; End of the parameters list of a generic.
- ((eq (char-before) ?>)
- (backward-char)
- (typescript--backward-over-generic-parameter-list))
- ;; Union of types, or a dot in a dotted name.
- ((memq (char-before) '(?| ?.))
- (backward-char))
- ((or
- ;; End-delimiter of a delimited construct, for constructs
- ;; not handled above.
- (memq (char-before) '(?\) ?} ?\" ?\]))
- ;; This is also dealing with dotted names. This may come
- ;; into play if a jump back moves over an entire dotted
- ;; name at once.
- ;;
- ;; The earlier test for dotted names comes into play if the
- ;; logic moves over one part of a dotted name at a time (which
- ;; is what `backward-sexp` normally does).
- (and (looking-back typescript--dotted-name-re nil)
- ;; We don't want the loop to walk over constructs like switch (...) or for (...), etc.
- (not (save-excursion
- (backward-word)
- (looking-at "\\_<\\(switch\\|if\\|while\\|until\\|for\\)\\_>\\(?:\\s-\\|\n\\)*(")))))
- (condition-case nil
- (backward-sexp)
- (scan-error (cl-return-from search-loop nil))))
- ((looking-back typescript--number-literal-re
- ;; We limit the search back to the previous space or end of line (if possible)
- ;; to prevent the search from going over the whole buffer.
- (save-excursion (re-search-backward "\\(?:\\s-\\|\n\\)" nil t)) t)
- (goto-char (match-beginning 0)))
- ;; Otherwise, we failed to find a location.
- (t
- (cl-return-from search-loop nil)))))
- ;; This handles the case of a function without return type annotation.
- (progn
- (typescript--backward-syntactic-ws)
- (when (eq (char-before) ?\))
- (point))))))
- (when location
- (goto-char location))))
-
-(defun typescript--proper-indentation (parse-status)
- "Return the proper indentation for the current line."
- (save-excursion
- (back-to-indentation)
- (let ((member-expr-p (looking-at "\\.")))
- (cond ((nth 4 parse-status) ;; Inside a comment.
- (typescript--get-c-offset 'c (nth 8 parse-status)))
- ((nth 8 parse-status) 0) ;; Inside a string.
- ((typescript--ctrl-statement-indentation)) ;; Control statements.
- ((eq (char-after) ?#) 0) ;; Looking at a pragma.
- ;; Inside a list of things. Note that in the TS contents, the curly braces
- ;; marking code blocks are "list of things".
- ((nth 1 parse-status)
- (let ((indent-start (point))
- (same-indent-p (looking-at "[]})]"))
- (switch-keyword-p (looking-at "\\_<default\\_>\\|\\_<case\\_>[^:]"))
- (continued-expr-p (typescript--continued-expression-p))
- (list-start (nth 1 parse-status)))
- (goto-char list-start)
- (if (looking-at "[({[]\\s-*\\(/[/*]\\|$\\)")
- (progn
- (skip-syntax-backward " ")
- (cond
- ((or (typescript--backward-to-parameter-list)
- (eq (char-before) ?\)))
- ;; Take the curly brace as marking off the body of a function.
- ;; In that case, we want the code that follows to see the indentation
- ;; that was in effect at the beginning of the function declaration, and thus
- ;; we want to move back over the list of function parameters.
- (condition-case nil
- (backward-list)
- (error nil)))
- ((looking-back "," nil)
- ;; If we get here, we have a comma, spaces and an opening curly brace. (And
- ;; (point) is just after the comma.) We don't want to move from the current position
- ;; so that object literals in parameter lists are properly indented.
- nil)
- (t
- ;; In all other cases, we don't want to move from the curly brace.
- (goto-char list-start)))
- (back-to-indentation)
- (let* ((in-switch-p (unless same-indent-p
- (looking-at "\\_<switch\\_>")))
- (same-indent-p (or same-indent-p
- (and switch-keyword-p
- in-switch-p)))
- (indent
- (cond (same-indent-p
- (current-column))
- (continued-expr-p
- (if (not member-expr-p)
- (+ (current-column) (* 2 typescript-indent-level)
- typescript-expr-indent-offset)
- (goto-char indent-start)
- (typescript--compute-member-expression-indent)))
- (t
- (+ (current-column) typescript-indent-level)))))
- (if (and in-switch-p typescript-indent-switch-clauses)
- (+ indent typescript-indent-level)
- indent)))
- (when (and (not same-indent-p)
- typescript-indent-list-items)
- (forward-char)
- (skip-chars-forward " \t"))
- (if continued-expr-p
- (if (not member-expr-p)
- (progn (back-to-indentation)
- (+ (current-column) typescript-indent-level
- typescript-expr-indent-offset))
- (goto-char indent-start)
- (typescript--compute-member-expression-indent))
- (current-column)))))
-
- ((typescript--continued-expression-p) ;; Inside a continued expression.
- (if member-expr-p
- (typescript--compute-member-expression-indent)
- (+ typescript-indent-level typescript-expr-indent-offset)))
- (t 0)))))
-
-(defun typescript-indent-line ()
- "Indent the current line as typescript."
- (interactive)
- (save-restriction
- (widen)
- (let* ((parse-status
- (save-excursion (syntax-ppss (point-at-bol))))
- (offset (- (current-column) (current-indentation))))
- (indent-line-to (typescript--proper-indentation parse-status))
- (when (> offset 0) (move-to-column (+ offset (current-indentation)))))))
-
-;;; Filling
-
-(defun typescript-c-fill-paragraph (&optional justify)
- "Fill the paragraph with `c-fill-paragraph'."
- (interactive "*P")
- ;; Dynamically replace functions using the lexically scoped cl-letf.
- ;; See below for more details:
- ;; http://endlessparentheses.com/understanding-letf-and-how-it-replaces-flet.html
- (cl-letf (((symbol-function 'c-forward-sws)
- (lambda (&optional limit)
- (typescript--forward-syntactic-ws limit)))
- ((symbol-function 'c-backward-sws)
- (lambda (&optional limit)
- (typescript--backward-syntactic-ws limit))))
- (let ((fill-paragraph-function 'c-fill-paragraph))
- (c-fill-paragraph justify))))
-
-;; We maintain a cache of semantic information, i.e., the classes and
-;; functions we've encountered so far. In order to avoid having to
-;; re-parse the buffer on every change, we cache the parse state at
-;; each interesting point in the buffer. Each parse state is a
-;; modified copy of the previous one, or in the case of the first
-;; parse state, the empty state.
-;;
-;; The parse state itself is just a stack of typescript--pitem
-;; instances. It starts off containing one element that is never
-;; closed, that is initially typescript--initial-pitem.
-;;
-
-
-(defun typescript--pitem-format (pitem)
- (let ((name (typescript--pitem-name pitem))
- (type (typescript--pitem-type pitem)))
-
- (format "name:%S type:%S"
- name
- (if (atom type)
- type
- (plist-get type :name)))))
-
-(defun typescript--make-merged-item (item child name-parts)
- "Helper function for `typescript--splice-into-items'.
-Return a new item that is the result of merging CHILD into
-ITEM. NAME-PARTS is a list of parts of the name of CHILD
-that we haven't consumed yet."
- (typescript--debug "typescript--make-merged-item: {%s} into {%s}"
- (typescript--pitem-format child)
- (typescript--pitem-format item))
-
- ;; If the item we're merging into isn't a class, make it into one
- (unless (consp (typescript--pitem-type item))
- (typescript--debug "typescript--make-merged-item: changing dest into class")
- (setq item (make-typescript--pitem
- :children (list item)
-
- ;; Use the child's class-style if it's available
- :type (if (atom (typescript--pitem-type child))
- typescript--dummy-class-style
- (typescript--pitem-type child))
-
- :name (typescript--pitem-strname item))))
-
- ;; Now we can merge either a function or a class into a class
- (cons (cond
- ((cdr name-parts)
- (typescript--debug "typescript--make-merged-item: recursing")
- ;; if we have more name-parts to go before we get to the
- ;; bottom of the class hierarchy, call the merger
- ;; recursively
- (typescript--splice-into-items (car item) child
- (cdr name-parts)))
-
- ((atom (typescript--pitem-type child))
- (typescript--debug "typescript--make-merged-item: straight merge")
- ;; Not merging a class, but something else, so just prepend
- ;; it
- (cons child (car item)))
-
- (t
- ;; Otherwise, merge the new child's items into those
- ;; of the new class
- (typescript--debug "typescript--make-merged-item: merging class contents")
- (append (car child) (car item))))
- (cdr item)))
-
-(defun typescript--pitem-strname (pitem)
- "Last part of the name of PITEM, as a string or symbol."
- (let ((name (typescript--pitem-name pitem)))
- (if (consp name)
- (car (last name))
- name)))
-
-(defun typescript--splice-into-items (items child name-parts)
- "Splice CHILD into the `typescript--pitem' ITEMS at NAME-PARTS.
-If a class doesn't exist in the tree, create it. Return
-the new items list. NAME-PARTS is a list of strings given
-the broken-down class name of the item to insert."
-
- (let ((top-name (car name-parts))
- (item-ptr items)
- new-items last-new-item new-cons item)
-
- (typescript--debug "typescript--splice-into-items: name-parts: %S items:%S"
- name-parts
- (mapcar #'typescript--pitem-name items))
-
- (cl-assert (stringp top-name))
- (cl-assert (> (length top-name) 0))
-
- ;; If top-name isn't found in items, then we build a copy of items
- ;; and throw it away. But that's okay, since most of the time, we
- ;; *will* find an instance.
-
- (while (and item-ptr
- (cond ((equal (typescript--pitem-strname (car item-ptr)) top-name)
- ;; Okay, we found an entry with the right name. Splice
- ;; the merged item into the list...
- (setq new-cons (cons (typescript--make-merged-item
- (car item-ptr) child
- name-parts)
- (cdr item-ptr)))
-
- (if last-new-item
- (setcdr last-new-item new-cons)
- (setq new-items new-cons))
-
- ;; ...and terminate the loop
- nil)
-
- (t
- ;; Otherwise, copy the current cons and move onto the
- ;; text. This is tricky; we keep track of the tail of
- ;; the list that begins with new-items in
- ;; last-new-item.
- (setq new-cons (cons (car item-ptr) nil))
- (if last-new-item
- (setcdr last-new-item new-cons)
- (setq new-items new-cons))
- (setq last-new-item new-cons)
-
- ;; Go to the next cell in items
- (setq item-ptr (cdr item-ptr))))))
-
- (if item-ptr
- ;; Yay! We stopped because we found something, not because
- ;; we ran out of items to search. Just return the new
- ;; list.
- (progn
- (typescript--debug "search succeeded: %S" name-parts)
- new-items)
-
- ;; We didn't find anything. If the child is a class and we don't
- ;; have any classes to drill down into, just push that class;
- ;; otherwise, make a fake class and carry on.
- (typescript--debug "search failed: %S" name-parts)
- (cons (if (cdr name-parts)
- ;; We have name-parts left to process. Make a fake
- ;; class for this particular part...
- (make-typescript--pitem
- ;; ...and recursively digest the rest of the name
- :children (typescript--splice-into-items
- nil child (cdr name-parts))
- :type typescript--dummy-class-style
- :name top-name)
-
- ;; Otherwise, this is the only name we have, so stick
- ;; the item on the front of the list
- child)
- items))))
-
-(defun typescript--pitem-add-child (pitem child)
- "Copy `typescript--pitem' PITEM, and push CHILD onto its list of children."
- (cl-assert (integerp (typescript--pitem-h-begin child)))
- (cl-assert (if (consp (typescript--pitem-name child))
- (cl-loop for part in (typescript--pitem-name child)
- always (stringp part))
- t))
-
- ;; This trick works because we know (based on our cl-defstructs) that
- ;; the child list is always the first element, and so the second
- ;; element and beyond can be shared when we make our "copy".
- (cons
-
- (let ((name (typescript--pitem-name child))
- (type (typescript--pitem-type child)))
-
- (cond ((cdr-safe name) ; true if a list of at least two elements
- ;; Use slow path because we need class lookup
- (typescript--splice-into-items (car pitem) child name))
-
- ((and (consp type)
- (plist-get type :prototype))
-
- ;; Use slow path because we need class merging. We know
- ;; name is a list here because down in
- ;; `typescript--ensure-cache', we made sure to only add
- ;; class entries with lists for :name
- (cl-assert (consp name))
- (typescript--splice-into-items (car pitem) child name))
-
- (t
- ;; Fast path
- (cons child (car pitem)))))
-
- (cdr pitem)))
-
-;;; compilation-mode support
-
-;; tsc supports formatting errors in two general ways: plain and
-;; pretty. ("Plain" is our term for "not pretty".) In tsc versions
-;; prior to 2.7, the plain and pretty formats both used the same
-;; format for references into files. `typescript-tsc-error-regexp`
-;; covers both plain and pretty for those versions.
-;;
-;; Version 2.7 changed the pretty format so as to format source code
-;; references differently. This required the introduction of
-;; `typescript-tsc-pretty-error-regexp`. The format of plain error
-;; messages did not change. So from that version onwards,
-;; `typescript-tsc-error-regexp` covers plain error messages and
-;; `typescript-tsc-pretty-error-regexp` covers pretty error messages.
-
-;; handle plain compiler-errors like the following when doing M-x compile<ret>tsc<ret>
-;;
-;; greeter.ts(24,9): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.
-;; greeter.ts(30,12): error TS2339: Property 'indexOf' does not exist on type 'number'.
-(defconst typescript-tsc-error-regexp
- (concat
- "^[[:blank:]]*"
- "\\([^(\r\n)]+\\)(\\([0-9]+\\),\\([0-9]+\\)):[[:blank:]]+"
- "error [[:alnum:]]+: [^\r\n]+$")
- "Regexp to match errors generated by tsc.")
-
-;; handle pretty compiler-errors like the following when doing M-x compile<ret>tsc<ret>
-;; test.ts:2:7 - error TS2322: Type '2' is not assignable to type 'string'.
-(defconst typescript-tsc-pretty-error-regexp
- (concat
- "^[[:blank:]]*"
- "\\([^(\r\n)]+\\):\\([0-9]+\\):\\([0-9]+\\) - [[:blank:]]*"
- "error [[:alnum:]]+: [^\r\n]+$")
- "Regexp to match errors generated by tsc.")
-
-;;
-;; Should handle output like:
-;; src/modules/authenticator.ts[1, 83]: ' should be "
-;; (quotemarks) src/modules/authenticator.ts[2, 26]: ' should be "
-;; ERROR: (quotemarks) src/modules/authenticator.ts[2, 26]: ' should be "
-;; WARNING: src/modules/authenticator.ts[2, 26]: ' should be "
-;;
-;; "(quotemarks)" it the rule name. It is produced when using the
-;; "verbose" formatter. The "verbose" formatter is identical to the
-;; default ("prose") formatter, except for the additional rule name.
-;;
-;; "ERROR:" and "WARNING:" are the severity. This was added in tslint
-;; 5.0. Prior versions have no notion of severity and simply omit this
-;; part.
-;;
-(defconst typescript-tslint-report-regexp
- (concat
- "^[[:blank:]]*"
- ;; severity ("type" in Emacs' parlance)
- "\\(?:\\(?:ERROR\\|\\(WARNING\\)\\):[[:blank:]]+\\)?"
- ;; rule name
- "\\((.*)[[:blank:]]+\\)?"
- ;; filename
- "\\([^(\r\n)]+\\)"
- "\\["
- ;; line
- "\\([[:digit:]]+\\)"
- ", "
- ;; column
- "\\([[:digit:]]+\\)"
- "\\]: "
- ;; message
- ".*$")
- "Regexp to match reports generated by tslint.")
-
-(defconst typescript-nglint-error-regexp
- (concat
- ;; severity ("type" in Emacs' parlance)
- "ERROR:[[:blank:]]+"
-
- ;; filename
- "\\([^(\r\n)]+\\)"
- ":"
- ;; line
- "\\([[:digit:]]+\\)"
- ":"
- ;; column
- "\\([[:digit:]]+\\)"
-
- " - "
- ;; message
- ".*$"))
-
-(defconst typescript-nglint-warning-regexp
- (concat
- ;; severity ("type" in Emacs' parlance)
- "WARNING:[[:blank:]]+"
-
- ;; filename
- "\\([^(\r\n)]+\\)"
- ":"
- ;; line
- "\\([[:digit:]]+\\)"
- ":"
- ;; column
- "\\([[:digit:]]+\\)"
-
- " - "
- ;; message
- ".*$"))
-
-(dolist
- (regexp
- `((typescript-tsc
- ,typescript-tsc-error-regexp
- 1 2 3 2)
-
- (typescript-tsc-pretty
- ,typescript-tsc-pretty-error-regexp
- 1 2 3 2)
-
- (typescript-tslint
- ,typescript-tslint-report-regexp
- 3 4 5 (1))
-
- (typescript-nglint-error
- ,typescript-nglint-error-regexp
- 1 2 3 2)
-
- (typescript-nglint-warning
- ,typescript-nglint-warning-regexp
- 1 2 3 1)))
- (add-to-list 'compilation-error-regexp-alist-alist regexp)
- (add-to-list 'compilation-error-regexp-alist (car regexp)))
-
-;;; Main Function
-
-;;;###autoload
-(define-derived-mode typescript-mode prog-mode "TypeScript"
- "Major mode for editing typescript.
-
-Key bindings:
-
-\\{typescript-mode-map}"
-
- :group 'typescript
- :syntax-table typescript-mode-syntax-table
-
- (setq-local indent-line-function 'typescript-indent-line)
- (setq-local beginning-of-defun-function 'typescript-beginning-of-defun)
- (setq-local end-of-defun-function 'typescript-end-of-defun)
- (setq-local open-paren-in-column-0-is-defun-start nil)
- (setq-local font-lock-defaults (list typescript--font-lock-keywords))
- (setq-local syntax-propertize-function #'typescript-syntax-propertize)
- (setq-local parse-sexp-ignore-comments t)
- (setq-local parse-sexp-lookup-properties t)
-
- ;; Comments
- (setq-local comment-start "// ")
- (setq-local comment-end "")
- (setq-local fill-paragraph-function 'typescript-c-fill-paragraph)
-
- ;; Parse cache
- (add-hook 'before-change-functions #'typescript--flush-caches t t)
-
- ;; Frameworks
- (typescript--update-quick-match-re)
-
- ;; for filling, pretend we're cc-mode
- (setq c-comment-prefix-regexp "//+\\|\\**"
- c-paragraph-start "$"
- c-paragraph-separate "$"
- c-block-comment-prefix "* "
- c-block-comment-ender-regexp "\\*/"
- c-line-comment-starter "//"
- c-comment-start-regexp "/[*/]\\|\\s!"
- comment-start-skip "\\(//+\\|/\\*+\\)\\s *")
-
- (setq-local electric-indent-chars
- (append "{}():;," electric-indent-chars))
- (setq-local 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)
- (make-local-variable 'paragraph-start)
- (make-local-variable 'paragraph-separate)
- (make-local-variable 'paragraph-ignore-fill-prefix)
- (make-local-variable 'adaptive-fill-mode)
- (make-local-variable 'adaptive-fill-regexp)
- (c-setup-paragraph-variables))
-
- (add-hook 'post-self-insert-hook
- #'typescript--post-self-insert-function)
-
- (setq-local syntax-begin-function #'typescript--syntax-begin-function))
-
-;; Set our custom predicate for flyspell prog mode
-(put 'typescript-mode 'flyspell-mode-predicate
- 'typescript--flyspell-mode-predicate)
-
-;;;###autoload
-(eval-after-load 'folding
- '(when (fboundp 'folding-add-to-marks-list)
- (folding-add-to-marks-list 'typescript-mode "// {{{" "// }}}" )))
-
-;;;###autoload
-(add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-mode))
-
-(provide 'typescript-mode)
-
-;;; typescript-mode.el ends here