dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

commit ac4479f2696bd01a85a6cfd91ff1bb0a23b8c732
parent 2a3a3de5275fede277a153f88710797976d408b2
Author: Lukas Henkel <lh@entf.net>
Date:   Sat, 17 Sep 2022 19:06:33 +0200

Add csharp-mode and web-mode

Diffstat:
Aelpa/csharp-mode-20220819.1351/csharp-compilation.el | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/csharp-mode-20220819.1351/csharp-mode-autoloads.el | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/csharp-mode-20220819.1351/csharp-mode-pkg.el | 12++++++++++++
Aelpa/csharp-mode-20220819.1351/csharp-mode.el | 599+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/csharp-mode-20220819.1351/csharp-tree-sitter.el | 425+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/lexic-20220501.1432/lexic-autoloads.el | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/lexic-20220501.1432/lexic-pkg.el | 2++
Aelpa/lexic-20220501.1432/lexic.el | 2034+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/web-mode-17.3.1.signed | 2++
Aelpa/web-mode-17.3.1/.github/CONTRIBUTING.md | 9+++++++++
Aelpa/web-mode-17.3.1/.github/FUNDING.yml | 2++
Aelpa/web-mode-17.3.1/README-elpa | 16++++++++++++++++
Aelpa/web-mode-17.3.1/README.md | 16++++++++++++++++
Aelpa/web-mode-17.3.1/web-mode-autoloads.el | 32++++++++++++++++++++++++++++++++
Aelpa/web-mode-17.3.1/web-mode-pkg.el | 2++
Aelpa/web-mode-17.3.1/web-mode.el | 14723+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minit.el | 2+-
17 files changed, 18132 insertions(+), 1 deletion(-)

diff --git a/elpa/csharp-mode-20220819.1351/csharp-compilation.el b/elpa/csharp-mode-20220819.1351/csharp-compilation.el @@ -0,0 +1,139 @@ +;;; csharp-compilation.el --- compilation support for C# -*- lexical-binding: t; -*- + +;; Copyright (C) 2020-2021 Free Software Foundation, Inc. + +;; Author : Theodor Thornhill <theo@thornhill.no> +;; Maintainer : Jostein Kjønigsen <jostein@gmail.com> +;; Theodor Thornhill <theo@thornhill.no> +;; Created : September 2020 +;; Modified : 2020 +;; Version : 1.1.1 +;; Keywords : c# languages oop mode +;; X-URL : https://github.com/emacs-csharp/csharp-mode + +;; 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/>. + + +(require 'compile) + +;; When invoked by MSBuild, csc’s errors look like this: +;; subfolder\file.cs(6,18): error CS1006: Name of constructor must +;; match name of class [c:\Users\user\project.csproj] + +(defun csharp--compilation-error-file-resolve () + "Resolve an msbuild error to a (filename . dirname) cons cell." + ;; http://stackoverflow.com/a/18049590/429091 + (cons (match-string 1) (file-name-directory (match-string 4)))) + +(defconst csharp-compilation-re-msbuild-error + (concat + "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?" + "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?): " + "error [[:alnum:]]+: [^\r\n]+\\[\\([^]\r\n]+\\)\\]$") + "Regexp to match compilation error from msbuild.") + +(defconst csharp-compilation-re-msbuild-warning + (concat + "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?" + "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?): " + "warning [[:alnum:]]+: [^\r\n]+\\[\\([^]\r\n]+\\)\\]$") + "Regexp to match compilation warning from msbuild.") + +;; Notes on xbuild and devenv commonalities +;; +;; These regexes were tailored for xbuild, but apart from the concurrent +;; build-marker ("1>") they share exactly the same match-markers. +;; +;; If we don't exclude the match-markers explicitly, these regexes +;; will also be used to match for devenv as well, including the build-marker +;; in the file-name, causing the lookup to fail. +;; +;; So if we don't want devenv to fail, we actually need to handle it in our +;; xbuild-regexes, but then we automatically get devenv-support for free. + +(defconst csharp-compilation-re-xbuild-error + (concat + "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?" + "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?" + ;; handle weird devenv output format with 4 numbers, not 2 by having optional + ;; extra capture-groups. + "\\(?:,\\([0-9]+\\)\\)*): " + "error [[:alnum:]]+: .+$") + "Regexp to match compilation error from xbuild.") + +(defconst csharp-compilation-re-xbuild-warning + (concat + "^[[:blank:]]*\\(?:[[:digit:]]+>\\)?" + "\\([^(\r\n)]+\\)(\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?" + ;; handle weird devenv output format with 4 numbers, not 2 by having optional + ;; extra capture-groups. + "\\(?:,\\([0-9]+\\)\\)?*): " + "warning [[:alnum:]]+: .+$") + "Regexp to match compilation warning from xbuild.") + +(defconst csharp-compilation-re-dotnet-error + "\\([^\r\n]+\\) : error [A-Z]+[0-9]+:") + +(defconst csharp-compilation-re-dotnet-warning + "\\([^\r\n]+\\) : warning [A-Z]+[0-9]+:") + +(defconst csharp-compilation-re-dotnet-testfail + (concat + "[[:blank:]]+Stack Trace:\n" + "[[:blank:]]+at [^\n]+ in \\([^\n]+\\):line \\([0-9]+\\)")) + + +(eval-after-load 'compile + (lambda () + (dolist + (regexp + `((dotnet-testfail + ,csharp-compilation-re-dotnet-testfail + 1 2) + (xbuild-error + ,csharp-compilation-re-xbuild-error + 1 2 3 2) + (xbuild-warning + ,csharp-compilation-re-xbuild-warning + 1 2 3 1) + (msbuild-error + ,csharp-compilation-re-msbuild-error + csharp--compilation-error-file-resolve + 2 + 3 + 2 + nil + (1 compilation-error-face) + (4 compilation-error-face)) + (msbuild-warning + ,csharp-compilation-re-msbuild-warning + csharp--compilation-error-file-resolve + 2 + 3 + 1 + nil + (1 compilation-warning-face) + (4 compilation-warning-face)) + (dotnet-error + ,csharp-compilation-re-dotnet-error + 1) + (dotnet-warning + ,csharp-compilation-re-dotnet-warning + 1 nil nil 1))) + (add-to-list 'compilation-error-regexp-alist-alist regexp) + (add-to-list 'compilation-error-regexp-alist (car regexp))))) + +(provide 'csharp-compilation) + +;;; csharp-compilation.el ends here diff --git a/elpa/csharp-mode-20220819.1351/csharp-mode-autoloads.el b/elpa/csharp-mode-20220819.1351/csharp-mode-autoloads.el @@ -0,0 +1,53 @@ +;;; csharp-mode-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*- +;; Generated by the `loaddefs-generate' function. + +;; This file is part of GNU Emacs. + +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + + +;;; Generated autoloads from csharp-compilation.el + +(register-definition-prefixes "csharp-compilation" '("csharp-")) + + +;;; Generated autoloads from csharp-mode.el + +(add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-mode)) +(autoload 'csharp-mode "csharp-mode" "\ +Major mode for editing Csharp code. + +Key bindings: +\\{csharp-mode-map} + +(fn)" t nil) +(register-definition-prefixes "csharp-mode" '("codedoc-font-lock-" "csharp-")) + + +;;; Generated autoloads from csharp-tree-sitter.el + +(autoload 'csharp-tree-sitter-mode "csharp-tree-sitter" "\ +Major mode for editing Csharp code. + +Key bindings: +\\{csharp-tree-sitter-mode-map} + +(fn)" t nil) +(register-definition-prefixes "csharp-tree-sitter" '("csharp-" "tree-sitter-indent-csharp-tree-sitter-scopes")) + +;;; End of scraped data + +(provide 'csharp-mode-autoloads) + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8-emacs-unix +;; End: + +;;; csharp-mode-autoloads.el ends here diff --git a/elpa/csharp-mode-20220819.1351/csharp-mode-pkg.el b/elpa/csharp-mode-20220819.1351/csharp-mode-pkg.el @@ -0,0 +1,12 @@ +(define-package "csharp-mode" "20220819.1351" "C# mode derived mode" + '((emacs "26.1")) + :commit "6e9d1f6b9900d3b8aa4106abf84a89311dfed85f" :authors + '(("Theodor Thornhill" . "theo@thornhill.no")) + :maintainer + '("Jostein Kjønigsen" . "jostein@gmail.com") + :keywords + '("c#" "languages" "oop" "mode") + :url "https://github.com/emacs-csharp/csharp-mode") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/elpa/csharp-mode-20220819.1351/csharp-mode.el b/elpa/csharp-mode-20220819.1351/csharp-mode.el @@ -0,0 +1,599 @@ +;;; csharp-mode.el --- C# mode derived mode -*- lexical-binding: t; -*- + +;; Copyright (C) 2020-2022 Free Software Foundation, Inc. + +;; Author : Theodor Thornhill <theo@thornhill.no> +;; Maintainer : Jostein Kjønigsen <jostein@gmail.com> +;; Theodor Thornhill <theo@thornhill.no> +;; Created : September 2020 +;; Modified : 2020 +;; Version : 1.1.1 +;; Keywords : c# languages oop mode +;; X-URL : https://github.com/emacs-csharp/csharp-mode +;; Package-Requires: ((emacs "26.1")) + +;; 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/>. + + +;;; Code: + + +(require 'cc-mode) +(require 'cc-langs) + +(eval-when-compile + (require 'cc-fonts)) + +(require 'csharp-compilation) + +(defgroup csharp nil + "Major mode for editing C# code." + :group 'prog-mode) + +(eval-and-compile + (defconst csharp--regex-identifier + "[A-Za-z][A-Za-z0-9_]*" + "Regex describing an dentifier in C#.") + + (defconst csharp--regex-identifier-matcher + (concat "\\(" csharp--regex-identifier "\\)") + "Regex matching an identifier in C#.") + + (defconst csharp--regex-type-name + "[A-Z][A-Za-z0-9_]*" + "Regex describing a type identifier in C#.") + + (defconst csharp--regex-type-name-matcher + (concat "\\(" csharp--regex-type-name "\\)") + "Regex matching a type identifier in C#.") + + (defconst csharp--regex-using-or-namespace + (concat "^using" "\\|" "namespace" + "\\s *" + csharp--regex-type-name-matcher) + "Regex matching identifiers after a using or namespace + declaration.")) + +(eval-and-compile + (c-add-language 'csharp-mode 'java-mode) + + (defun csharp--make-mode-syntax-table () + (let ((table (make-syntax-table))) + (c-populate-syntax-table table) + (modify-syntax-entry ?@ "_" table) + table)) + (defvar csharp--make-mode-syntax-table #'csharp--make-mode-syntax-table + "Workaround for Emacs bug#57065.")) + +(c-lang-defconst c-make-mode-syntax-table + csharp #'csharp--make-mode-syntax-table) + +(c-lang-defconst c-identifier-syntax-modifications + csharp (append '((?@ . "w")) + (c-lang-const c-identifier-syntax-modifications))) + +(c-lang-defconst c-symbol-start + csharp (concat "[" c-alpha "_@]")) + +(c-lang-defconst c-opt-type-suffix-key + csharp (concat "\\(\\[" (c-lang-const c-simple-ws) "*\\]\\|\\?\\)")) + +(c-lang-defconst c-identifier-ops + csharp '((left-assoc "."))) + +(c-lang-defconst c-overloadable-operators + csharp '("+" "-" "*" "/" "%" "&" "|" "^" "<<" ">>" "==" + "!=" ">" "<" ">=" "<=")) + +(c-lang-defconst c-multiline-string-start-char + csharp ?@) + +(c-lang-defconst c-ml-string-opener-re + ;; "\\(\\(?:@\\$?\\)\\(\"\\)\\)" + csharp + (rx + (group + (or "@" "@$") + (group "\"")))) + +(c-lang-defconst c-ml-string-max-opener-len + csharp 3) + +(c-lang-defconst c-ml-string-max-closer-len + csharp 2) + +(c-lang-defconst c-ml-string-any-closer-re + ;; "\\(?:\"\"\\)*\\(\\(\"\\)\\)\\(?:[^\"]\\|\\'\\)" + csharp + (rx + (seq + (zero-or-more "\"\"") + (group + (group "\"")) + (or (not (any "\"")) eos)))) + +(c-lang-defconst c-ml-string-back-closer-re + ;; "\\(?:\\`\\|[^\"]\\)\"*" + csharp + (rx + (seq + (or bos + (not (any "\""))) + (zero-or-more "\"")))) + +(c-lang-defconst c-type-prefix-kwds + csharp '("class" "interface" "struct")) + +(c-lang-defconst c-class-decl-kwds + csharp '("class" "interface" "struct")) + +;;; Keyword lists + +(c-lang-defconst c-primitive-type-kwds + csharp '("bool" "byte" "sbyte" "char" "decimal" "double" "float" "int" "uint" + "long" "ulong" "short" "ushort" "void" "object" "string" "var")) + +(c-lang-defconst c-other-decl-kwds + csharp nil) + +(c-lang-defconst c-type-list-kwds + csharp nil) + +(c-lang-defconst c-other-block-decl-kwds + csharp nil) + +(c-lang-defconst c-return-kwds + csharp '("return")) + +(c-lang-defconst c-typedef-kwds + csharp nil) + +(c-lang-defconst c-typeof-kwds + csharp '("typeof" "is" "as")) + +(c-lang-defconst c-type-modifier-prefix-kwds + csharp '("volatile")) + +(c-lang-defconst c-type-modifier-kwds + csharp '("readonly" "new")) + +(c-lang-defconst c-brace-list-decl-kwds + csharp '("enum" "new")) + +(c-lang-defconst c-recognize-post-brace-list-type-p + csharp t) + +(c-lang-defconst c-ref-list-kwds + csharp nil) + +(c-lang-defconst c-using-kwds + csharp '("using")) + +(c-lang-defconst c-equals-type-clause-kwds + csharp '("using")) + +(defun csharp-at-vsemi-p (&optional pos) + (if pos (goto-char pos)) + (save-excursion + (beginning-of-line) + (c-forward-syntactic-ws) + (looking-at "using\\s *("))) + +(c-lang-defconst c-at-vsemi-p-fn + csharp 'csharp-at-vsemi-p) + +(defun csharp-vsemi-status-unknown () t) + +(c-lang-defconst c-vsemi-status-unknown-p-fn + csharp 'csharp-vsemi-status-unknown-p) + + +(c-lang-defconst c-modifier-kwds + csharp '("abstract" "default" "final" "native" "private" "protected" + "public" "partial" "internal" "readonly" "static" "event" "transient" + "volatile" "sealed" "ref" "out" "virtual" "implicit" "explicit" + "fixed" "override" "params" "async" "await" "extern" "unsafe" + "get" "set" "this" "const" "delegate")) + +(c-lang-defconst c-other-kwds + csharp '("select" "from" "where" "join" "in" "on" "equals" "into" + "orderby" "ascending" "descending" "group" "when" + "let" "by" "namespace")) + +(c-lang-defconst c-colon-type-list-kwds + csharp '("class" "struct" "interface")) + +(c-lang-defconst c-block-stmt-1-kwds + csharp '("do" "else" "finally" "try")) + +(c-lang-defconst c-block-stmt-1-2-kwds + csharp '("try")) + +(c-lang-defconst c-block-stmt-2-kwds + csharp '("for" "if" "switch" "while" "catch" "foreach" "fixed" "checked" + "unchecked" "using" "lock")) + +(c-lang-defconst c-simple-stmt-kwds + csharp '("break" "continue" "goto" "throw" "return" "yield")) + +(c-lang-defconst c-constant-kwds + csharp '("true" "false" "null" "value")) + +(c-lang-defconst c-primary-expr-kwds + csharp '("this" "base" "operator")) + +(c-lang-defconst c-inexpr-class-kwds + csharp nil) + +(c-lang-defconst c-class-decl-kwds + csharp '("class" "struct" "interface")) + +(c-lang-defconst c-std-abbrev-keywords + csharp (append (c-lang-const c-std-abbrev-keywords) '("catch" "finally"))) + +(c-lang-defconst c-decl-prefix-re + csharp "\\([{}(;,<]+\\)") + +(c-lang-defconst c-recognize-typeless-decls + csharp t) + +(c-lang-defconst c-recognize-<>-arglists + csharp t) + +(c-lang-defconst c-opt-cpp-prefix + csharp "\\s *#\\s *") + +(c-lang-defconst c-opt-cpp-macro-define + csharp (if (c-lang-const c-opt-cpp-prefix) + "define")) + +(c-lang-defconst c-cpp-message-directives + csharp '("error" "warning" "region")) + +(c-lang-defconst c-cpp-expr-directives + csharp '("if" "elif")) + +(c-lang-defconst c-other-op-syntax-tokens + csharp (append '("#") + (c-lang-const c-other-op-syntax-tokens))) + +(c-lang-defconst c-line-comment-starter + csharp "//") + +(c-lang-defconst c-doc-comment-start-regexp + csharp "///") + +(c-add-style "csharp" + '("java" + (c-basic-offset . 4) + (c-comment-only-line-offset . (0 . 0)) + (c-offsets-alist . ((inline-open . 0) + (arglist-intro . +) + (arglist-close . 0) + (inexpr-class . 0) + (case-label . +) + (cpp-macro . c-lineup-dont-change) + (substatement-open . 0))))) + +(eval-and-compile + (unless (or (stringp c-default-style) + (assoc 'csharp-mode c-default-style)) + (setq c-default-style + (cons '(csharp-mode . "csharp") + c-default-style)))) + +(defun csharp--color-forwards (font-lock-face) + (let (id-beginning) + (goto-char (match-beginning 0)) + (forward-word) + (while (and (not (or (eq (char-after) ?\;) + (eq (char-after) ?\{))) + (progn + (forward-char) + (c-forward-syntactic-ws) + (setq id-beginning (point)) + (> (skip-chars-forward + (c-lang-const c-symbol-chars)) + 0)) + (not (get-text-property (point) 'face))) + (c-put-font-lock-face id-beginning (point) font-lock-face) + (c-forward-syntactic-ws)))) + +(c-lang-defconst c-basic-matchers-before + csharp `( + ;; Warning face on unclosed strings + ,@(if (version< emacs-version "27.0") + ;; Taken from 26.1 branch + `(,(c-make-font-lock-search-function + (concat ".\\(" c-string-limit-regexp "\\)") + '((c-font-lock-invalid-string)))) + `(("\\s|" 0 font-lock-warning-face t nil))) + + ;; Invalid single quotes + c-font-lock-invalid-single-quotes + + ;; Keyword constants + ,@(when (c-lang-const c-constant-kwds) + (let ((re (c-make-keywords-re nil (c-lang-const c-constant-kwds)))) + `((eval . (list ,(concat "\\<\\(" re "\\)\\>") + 1 c-constant-face-name))))) + + ;; Keywords except the primitive types. + ,`(,(concat "\\<" (c-lang-const c-regular-keywords-regexp)) + 1 font-lock-keyword-face) + + ;; Chained identifiers in using/namespace statements + ,`(,(c-make-font-lock-search-function + csharp--regex-using-or-namespace + `((csharp--color-forwards font-lock-variable-name-face) + nil + (goto-char (match-end 0))))) + + + ;; Negation character + (eval . (list "\\(!\\)[^=]" 1 c-negation-char-face-name)) + + ;; Types after 'new' + (eval . (list (concat "\\<new\\> *" csharp--regex-type-name-matcher) + 1 font-lock-type-face)) + + ;; Single identifier in attribute + (eval . (list (concat "\\[" csharp--regex-type-name-matcher "\\][^;]") + 1 font-lock-variable-name-face t)) + + ;; Function names + (eval . (list "\\([A-Za-z0-9_]+\\)\\(<[a-zA-Z0-9, ]+>\\)?(" + 1 font-lock-function-name-face)) + + ;; Nameof + (eval . (list (concat "\\(\\<nameof\\>\\) *(") + 1 font-lock-function-name-face)) + + (eval . (list (concat "\\<nameof\\> *( *" + csharp--regex-identifier-matcher + " *) *") + 1 font-lock-variable-name-face)) + + ;; Catch statements with type only + (eval . (list (concat "\\<catch\\> *( *" + csharp--regex-type-name-matcher + " *) *") + 1 font-lock-type-face)) + )) + +(c-lang-defconst c-basic-matchers-after + csharp (append + ;; Merge with cc-mode defaults - enables us to add more later + (c-lang-const c-basic-matchers-after))) + +(defcustom csharp-codedoc-tag-face 'c-doc-markup-face-name + "Face to be used on the codedoc docstring tags. + +Should be one of the font lock faces, such as +`font-lock-variable-name-face' and friends. + +Needs to be set before `csharp-mode' is loaded, because of +compilation and evaluation time conflicts." + :type 'symbol) + +(defcustom csharp-font-lock-extra-types + (list csharp--regex-type-name) + (c-make-font-lock-extra-types-blurb "C#" "csharp-mode" (concat)) + :type 'c-extra-types-widget + :group 'c) + +(defconst csharp-font-lock-keywords-1 (c-lang-const c-matchers-1 csharp) + "Minimal font locking for C# mode.") + +(defconst csharp-font-lock-keywords-2 (c-lang-const c-matchers-2 csharp) + "Fast normal font locking for C# mode.") + +(defconst csharp-font-lock-keywords-3 (c-lang-const c-matchers-3 csharp) + "Accurate normal font locking for C# mode.") + +(defvar csharp-font-lock-keywords csharp-font-lock-keywords-3 + "Default expressions to highlight in C# mode.") + +(defun csharp-font-lock-keywords-2 () + (c-compose-keywords-list csharp-font-lock-keywords-2)) +(defun csharp-font-lock-keywords-3 () + (c-compose-keywords-list csharp-font-lock-keywords-3)) +(defun csharp-font-lock-keywords () + (c-compose-keywords-list csharp-font-lock-keywords)) + +;;; Doc comments + +(defconst codedoc-font-lock-doc-comments + ;; Most of this is taken from the javadoc example, however, we don't use the + ;; '@foo' syntax, so I removed that. Supports the XML tags only + `((,(concat "</?\\sw" ; XML tags. + "\\(" + (concat "\\sw\\|\\s \\|[=\n\r*.:]\\|" + "\"[^\"]*\"\\|'[^']*'") + "\\)*/?>") + 0 ,csharp-codedoc-tag-face prepend nil) + ;; ("\\([a-zA-Z0-9_]+\\)=" 0 font-lock-variable-name-face prepend nil) + ;; ("\".*\"" 0 font-lock-string-face prepend nil) + ("&\\(\\sw\\|[.:]\\)+;" ; XML entities. + 0 ,csharp-codedoc-tag-face prepend nil))) + +(defconst codedoc-font-lock-keywords + `((,(lambda (limit) + (c-font-lock-doc-comments "///" limit + codedoc-font-lock-doc-comments))))) + +;;; End of doc comments + +;;; Adding syntax constructs + +(advice-add 'c-looking-at-inexpr-block + :around #'csharp-looking-at-inexpr-block) + +(defun csharp-looking-at-inexpr-block (orig-fun &rest args) + (let ((res (csharp-at-lambda-header))) + (if res + res + (apply orig-fun args)))) + +(defun csharp-at-lambda-header () + (save-excursion + (c-backward-syntactic-ws) + (unless (bobp) + (backward-char) + (c-safe (goto-char (scan-sexps (point) -1))) + (when (or (looking-at "([[:alnum:][:space:]_,]*)[ \t\n]*=>[ \t\n]*{") + (looking-at "[[:alnum:]_]+[ \t\n]*=>[ \t\n]*{")) + ;; If we are at a C# lambda header + (cons 'inexpr (point)))))) + +(advice-add 'c-guess-basic-syntax + :around #'csharp-guess-basic-syntax) + +(defun csharp-guess-basic-syntax (orig-fun &rest args) + (cond + (;; Attributes + (save-excursion + (goto-char (c-point 'iopl)) + (and + (eq (char-after) ?\[) + (save-excursion + (c-go-list-forward) + (and (eq (char-before) ?\]) + (not (eq (char-after) ?\;)))))) + `((annotation-top-cont ,(c-point 'iopl)))) + + ((and + ;; Heuristics to find object initializers + (save-excursion + ;; Next non-whitespace character should be '{' + (goto-char (c-point 'boi)) + (eq (char-after) ?{)) + (save-excursion + ;; 'new' should be part of the line + (goto-char (c-point 'iopl)) + (looking-at ".*\\s *new\\s *.*")) + ;; Line should not already be terminated + (save-excursion + (goto-char (c-point 'eopl)) + (or (not (eq (char-before) ?\;)) + (not (eq (char-before) ?\{))))) + (if (save-excursion + ;; if we have a hanging brace on line before + (goto-char (c-point 'eopl)) + (eq (char-before) ?\{)) + `((brace-list-intro ,(c-point 'iopl))) + `((block-open) (statement ,(c-point 'iopl))))) + (t + (apply orig-fun args)))) + +;;; End of new syntax constructs + + + +;;; Fix for strings on version 27.1 + +(when (version= emacs-version "27.1") + ;; See: + ;; https://github.com/emacs-csharp/csharp-mode/issues/175 + ;; https://github.com/emacs-csharp/csharp-mode/issues/151 + ;; for the full story. + (defun c-pps-to-string-delim (end) + (let* ((start (point)) + (no-st-s `(0 nil nil ?\" nil nil 0 nil ,start nil nil)) + (st-s `(0 nil nil t nil nil 0 nil ,start nil nil)) + no-st-pos st-pos + ) + (parse-partial-sexp start end nil nil no-st-s 'syntax-table) + (setq no-st-pos (point)) + (goto-char start) + (while (progn + (parse-partial-sexp (point) end nil nil st-s 'syntax-table) + (unless (bobp) + (c-clear-syn-tab (1- (point)))) + (setq st-pos (point)) + (and (< (point) end) + (not (eq (char-before) ?\"))))) + (goto-char (min no-st-pos st-pos)) + nil)) + + (defun c-multiline-string-check-final-quote () + (let (pos-ll pos-lt) + (save-excursion + (goto-char (point-max)) + (skip-chars-backward "^\"") + (while + (and + (not (bobp)) + (cond + ((progn + (setq pos-ll (c-literal-limits) + pos-lt (c-literal-type pos-ll)) + (memq pos-lt '(c c++))) + ;; In a comment. + (goto-char (car pos-ll))) + ((save-excursion + (backward-char) ; over " + (c-is-escaped (point))) + ;; At an escaped string. + (backward-char) + t) + (t + ;; At a significant " + (c-clear-syn-tab (1- (point))) + (setq pos-ll (c-literal-limits) + pos-lt (c-literal-type pos-ll)) + nil))) + (skip-chars-backward "^\"")) + (cond + ((bobp)) + ((eq pos-lt 'string) + (c-put-syn-tab (1- (point)) '(15))) + (t nil)))))) + +;;; End of fix for strings on version 27.1 + + + +(defvar csharp-mode-syntax-table + (funcall (c-lang-const c-make-mode-syntax-table csharp)) + "Syntax table used in `csharp-mode' buffers.") + +(defvar csharp-mode-map + (let ((map (c-make-inherited-keymap))) + map) + "Keymap used in `csharp-mode' buffers.") + +(easy-menu-define csharp-mode-menu csharp-mode-map "C# Mode Commands." + (cons "C#" (c-lang-const c-mode-menu csharp))) + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-mode)) + +;; Custom variables +;;;###autoload +(define-derived-mode csharp-mode prog-mode "C#" + "Major mode for editing Csharp code. + +Key bindings: +\\{csharp-mode-map}" + :after-hook (c-update-modeline) + (c-initialize-cc-mode t) + (c-init-language-vars csharp-mode) + (c-common-init 'csharp-mode) + (setq-local c-doc-comment-style '((csharp-mode . codedoc))) + (run-mode-hooks 'c-mode-common-hook)) + +(provide 'csharp-mode) + +;;; csharp-mode.el ends here diff --git a/elpa/csharp-mode-20220819.1351/csharp-tree-sitter.el b/elpa/csharp-mode-20220819.1351/csharp-tree-sitter.el @@ -0,0 +1,425 @@ +;;; csharp-tree-sitter.el --- tree sitter support for C# -*- lexical-binding: t; -*- + +;; Copyright (C) 2020-2021 Free Software Foundation, Inc. + +;; Author : Theodor Thornhill <theo@thornhill.no> +;; Maintainer : Jostein Kjønigsen <jostein@gmail.com> +;; Theodor Thornhill <theo@thornhill.no> +;; Created : September 2020 +;; Modified : 2020 +;; Version : 1.1.1 +;; Keywords : c# languages oop mode +;; X-URL : https://github.com/emacs-csharp/csharp-mode +;; Package-Requires: ((emacs "26.1") (tree-sitter "0.12.1") (tree-sitter-indent "0.1") (tree-sitter-langs "0.9.1")) + +;; 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/>. + + +;;; Code: +(require 'cl-lib) +(require 'cl-extra) +(require 'seq) + +(when t + ;; In order for the package to be usable and installable (and hence + ;; compilable) without tree-sitter, wrap the `require's within a dummy `when' + ;; so they're only executed when loading this file but not when compiling it. + (require 'tree-sitter) + (require 'tree-sitter-hl) + (require 'tree-sitter-indent) + (require 'tree-sitter-langs)) +;; Vars and functions defined by the above packages: +(defvar tree-sitter-major-mode-language-alist) ;From `tree-sitter-langs'. +(declare-function tree-sitter-indent-mode "ext:tree-sitter-indent") +(declare-function tree-sitter-indent-line "ext:tree-sitter-indent") +(declare-function tree-sitter-hl-mode "ext:tree-sitter-hl") +(declare-function tsc-node-end-position "ext:tree-sitter") +(declare-function tsc-node-start-position "ext:tree-sitter") +(declare-function tree-sitter-node-at-point "ext:tree-sitter") + +(require 'csharp-compilation) + +(defvar csharp-mode-syntax-table) +(defvar csharp-mode-map) + +;;; Tree-sitter + +(defconst csharp-mode-tree-sitter-patterns + [ ;; Various constructs + (comment) @comment + (modifier) @keyword + (this_expression) @keyword + (escape_sequence) @keyword + + ;; Literals + [(real_literal) (integer_literal)] @number + (null_literal) @constant + (boolean_literal) @constant + [(string_literal) + (verbatim_string_literal) + (interpolated_string_text) + (interpolated_verbatim_string_text) + (character_literal) + "\"" + "$\"" + "@$\"" + "$@\""] @string + + ;; Keywords + ["using" "namespace" "class" "if" "else" "throw" "new" "for" + "return" "await" "struct" "enum" "switch" "case" + "default" "typeof" "try" "catch" "finally" "break" + "foreach" "in" "yield" "get" "set" "when" "as" "out" + "is" "while" "continue" "this" "ref" "goto" "interface" + "from" "where" "select" "lock" "base" "record" "init" + "with" "let" "static" + ] @keyword + + ;; Linq + (from_clause (identifier) @variable) + (group_clause) + (order_by_clause) + (select_clause (identifier) @variable) + (query_continuation (identifier) @variable) @keyword + + ;; Enum + (enum_member_declaration (identifier) @variable) + (enum_declaration (identifier) @type) + + ;; Interface + (interface_declaration + name: (identifier) @type) + + ;; Struct + (struct_declaration (identifier) @type) + + ;; Record + (record_declaration (identifier) @type) + + (with_expression + (with_initializer_expression + (simple_assignment_expression + (identifier) @variable))) + + ;; Namespace + (namespace_declaration + name: (identifier) @type) + + ;; Class + (base_list (identifier) @type) + (property_declaration + (generic_name)) + (property_declaration + type: (nullable_type) @type + name: (identifier) @variable) + (property_declaration + type: (predefined_type) @type + name: (identifier) @variable) + (property_declaration + type: (identifier) @type + name: (identifier) @variable) + (class_declaration + name: (identifier) @type) + (constructor_declaration (identifier) @type) + + ;; Method + (method_declaration (identifier) @type (identifier) @function) + (method_declaration (predefined_type) @type (identifier) @function) + (method_declaration (nullable_type) @type (identifier) @function) + (method_declaration (void_keyword) @type (identifier) @function) + (method_declaration (generic_name) (identifier) @function) + (method_declaration (qualified_name (identifier) @type) (identifier) @function) + + ;; Function + (local_function_statement (identifier) @type (identifier) @function) + (local_function_statement (predefined_type) @type (identifier) @function) + (local_function_statement (nullable_type) @type (identifier) @function) + (local_function_statement (void_keyword) @type (identifier) @function) + (local_function_statement (generic_name) (identifier) @function) + + ;; Lambda + (lambda_expression + (identifier) @variable) + + ;; Parameter + (parameter + type: (qualified_name) @type) + (parameter + type: (identifier) @type + name: (identifier) @variable.parameter) + (parameter (identifier) @variable.parameter) + + ;; Array + (array_rank_specifier (identifier) @variable) + (array_type (identifier) @type) + (array_creation_expression) + + ;; Attribute + (attribute (identifier) @variable (attribute_argument_list)) + (attribute (identifier) @variable) + + ;; Object init + (anonymous_object_creation_expression) + (object_creation_expression (identifier) @type) + (initializer_expression (identifier) @variable) + + ;; Typeof + (type_of_expression (identifier) @variable) + + ;; Member access + (invocation_expression (member_access_expression (generic_name (identifier) @method.call))) + (invocation_expression (member_access_expression (identifier)\? @method.call .)) + (member_access_expression (identifier) @variable) + + ;; Variable + (variable_declaration (identifier) @type) + (variable_declarator (identifier) @variable) + + ;; Equals value + (equals_value_clause (identifier) @variable) + + ;; Return + (return_statement (identifier) @variable) + (yield_statement (identifier) @variable) + + ;; Type + (type_parameter + (identifier) @type) + (type_argument_list + (identifier) @type.argument) + (generic_name + (identifier) @type) + (implicit_type) @type + (predefined_type) @type + (nullable_type) @type + ["operator"] @type + + ;; Type constraints + (type_parameter_constraints_clause + (identifier) @type) + ;; (type_parameter_constraint + ;; (identifier) @type) ;; causes parsing error in tree-sitter + (type_constraint + (identifier) @type) + + ;; Exprs + (binary_expression (identifier) @variable (identifier) @variable) + (binary_expression (identifier)* @variable) + (conditional_expression (identifier) @variable) + ;; (prefix_unary_expression (identifier)* @variable) ;; crashes tree-sitter c-code with SIGABRT + (postfix_unary_expression (identifier)* @variable) + (assignment_expression (identifier) @variable) + (cast_expression (identifier) @type) + + ;; Preprocessor + (preprocessor_directive) @constant + (preprocessor_call (identifier) @string) + + ;; Loop + (for_each_statement (implicit_type) @type (identifier) @variable) + (for_each_statement (predefined_type) @type (identifier) @variable) + (for_each_statement (identifier) @type (identifier) @variable) + + ;; Exception + (catch_declaration (identifier) @type (identifier) @variable) + (catch_declaration (identifier) @type) + + ;; Switch + (switch_statement (identifier) @variable) + (switch_expression (identifier) @variable) + + ;; If + (if_statement (identifier) @variable) + + ;; Declaration expression + (declaration_expression (implicit_type) (identifier) @variable) + + ;; Arrow expression + (arrow_expression_clause (identifier) @variable) + + ;; Lock statement + (lock_statement (identifier) @variable) + + ;; Other + ;; (argument_list + ;; (identifier) @variable) ;; causes parsing error in tree-sitter + (label_name) @variable + (using_directive (identifier) @type.parameter) + (using_directive (qualified_name) @type.parameter) + (using_directive (name_equals (identifier) @type.parameter)) + ;; (await_expression (identifier)* @function) ;; crashes tree-sitter c-code with sigabrt! + (invocation_expression (identifier) @function) + (element_access_expression (identifier) @variable) + (conditional_access_expression (identifier) @variable) + (member_binding_expression (identifier) @variable) + (name_colon (identifier)* @variable.special) + (field_declaration) + (argument (identifier) @variable) + + ;; Catch-alls + (identifier) @variable + + ;; Interpolation + ;; (interpolated_string_expression) @string + ] + ) + +;;; Tree-sitter indentation + +(defgroup csharp-mode-indent nil "Indent lines using Tree-sitter as backend" + :group 'tree-sitter) + +(defcustom csharp-tree-sitter-indent-offset 4 + "Indent offset for csharp-tree-sitter-mode." + :type 'integer + :group 'csharp) + +(defvar tree-sitter-indent-csharp-tree-sitter-scopes + '((indent-all + ;; these nodes are always indented + . (accessor_declaration + break_statement + arrow_expression_clause + parameter_list + conditional_expression + constructor_initializer + argument_list + ".")) + (indent-rest + ;; if parent node is one of these and node is not first → indent + . (binary_expression + switch_section)) + (indent-body + ;; if parent node is one of these and current node is in middle → indent + . (enum_member_declaration_list + base_list + block + anonymous_object_creation_expression + initializer_expression + expression_statement + declaration_list + attribute_argument_list + switch_body + switch_expression)) + (paren-indent + ;; if parent node is one of these → indent to paren opener + . (parenthesized_expression)) + (align-char-to + ;; chaining char → node types we move parentwise to find the first chaining char + . ()) + (aligned-siblings + ;; siblings (nodes with same parent) should be aligned to the first child + . (parameter + argument)) + (multi-line-text + ;; if node is one of these, then don't modify the indent + ;; this is basically a peaceful way out by saying "this looks like something + ;; that cannot be indented using AST, so best I leave it as-is" + . (preprocessor_call + labeled_statement)) + (outdent + ;; these nodes always outdent (1 shift in opposite direction) + . (case_switch_label)) + (align-to-node-line + ;; this group has lists of alist (node type . (node types... )) + ;; we move parentwise, searching for one of the node + ;; types associated with the key node type. if found, + ;; align key node with line where the ancestor node + ;; was found. + . ((block . (lambda_expression))))) + "Scopes for indenting in C#.") + +;;; tree-sitter helper-functions. navigation, editing, etc. +;;; may be subject to future upstreaming-effort + +(defun csharp-beginning-of-defun () + "Replacement-function for `beginning-of-defun' for `csharp-tree-sitter-mode'." + (interactive) + (when-let ((declaration + (cl-some (lambda (decl) + (tree-sitter-node-at-point decl)) + '(method_declaration + constructor_declaration + class_declaration + namespace_declaration)))) + (goto-char (tsc-node-start-position declaration)))) + +(defun csharp-end-of-defun () + "Replacement-function for `end-of-defun' for `csharp-tree-sitter-mode'." + (interactive) + (when-let ((declaration + (cl-some (lambda (decl) + (tree-sitter-node-at-point decl)) + '(method_declaration + constructor_declaration + class_declaration + namespace_declaration)))) + (goto-char (tsc-node-end-position declaration)))) + +(defun csharp-delete-method-at-point () + "Deletes the method at point." + (interactive) + (when-let ((method (tree-sitter-node-at-point 'method_declaration))) + (delete-region (tsc-node-start-position method) + (tsc-node-end-position method)))) + +(defun csharp-change-string-at-point () + "Change string at point." + (interactive) + (when-let ((method (tree-sitter-node-at-point 'string_literal))) + (delete-region (1+ (tsc-node-start-position method)) + (1- (tsc-node-end-position method))))) + +;;; end tree-sitter helper-functions. + +(defvar csharp-tree-sitter-mode-map + (let ((map (make-sparse-keymap))) + map) + "Keymap used in csharp-mode buffers.") + +(defvar csharp-tree-sitter-mode-syntax-table + (let ((table (make-syntax-table))) + (modify-syntax-entry ?@ "_" table) + table)) + +;;;###autoload +(define-derived-mode csharp-tree-sitter-mode prog-mode "C#" + "Major mode for editing Csharp code. + +Key bindings: +\\{csharp-tree-sitter-mode-map}" + :group 'csharp + :syntax-table csharp-tree-sitter-mode-syntax-table + + (setq-local indent-line-function #'tree-sitter-indent-line) + (setq-local beginning-of-defun-function #'csharp-beginning-of-defun) + (setq-local end-of-defun-function #'csharp-end-of-defun) + + ;; https://github.com/ubolonton/emacs-tree-sitter/issues/84 + (unless font-lock-defaults + (setq font-lock-defaults '(nil))) + (setq-local tree-sitter-hl-default-patterns csharp-mode-tree-sitter-patterns) + ;; Comments + (setq-local comment-start "// ") + (setq-local comment-start-skip "\\(?://+\\|/\\*+\\)\\s *") + (setq-local comment-end "") + + (tree-sitter-hl-mode) + (tree-sitter-indent-mode)) + +(add-to-list 'tree-sitter-major-mode-language-alist '(csharp-tree-sitter-mode . c-sharp)) + +(provide 'csharp-tree-sitter) + +;;; csharp-tree-sitter.el ends here diff --git a/elpa/lexic-20220501.1432/lexic-autoloads.el b/elpa/lexic-20220501.1432/lexic-autoloads.el @@ -0,0 +1,65 @@ +;;; lexic-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*- +;; Generated by the `loaddefs-generate' function. + +;; This file is part of GNU Emacs. + +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + + +;;; Generated autoloads from lexic.el + +(autoload 'lexic-search "lexic" "\ +Search WORD through the command line tool lexic. +The result will be displayed in buffer named with +`lexic-buffer-name' with `lexic-mode' if called interactively. + +When provided with DICT-LIST-NAME, query `lexic-dictionary-alist' +to get the new dictionary list before search. +Alternatively, dictionary list can be specified directly +by DICT-LIST. Any non-list value of it means using all dictionaries. + +When called interactively, prompt for the word. +Prefix argument have the following meaning: +If `lexic-dictionary-alist' is defined, +use prefix argument to select a new DICT-LIST-NAME. +Otherwise, prefix argument means using all dictionaries. + +When INTERACTIVE-P is non-nil, a buffer displaying the result(s) is shown. +Otherwise, the result is returned as a string. + +When NO-HISTORY-P is non-nil, the search is not added to the session history. + +Word may contain some special characters: + * match zero or more characters + ? match zero or one character + / used at the beginning, for fuzzy search + | used at the beginning, for data search + escape the character right after + +TODO decouple the tool from the general method. + +(fn WORD &optional DICT-LIST-NAME DICT-LIST INTERACTIVE-P NO-HISTORY-P)" t nil) +(autoload 'lexic-search-word-at-point "lexic" "\ +Perform `lexic-search' on the word at or near point." t nil) +(autoload 'lexic-list-dictionary "lexic" "\ +Show available dictionaries." t nil) +(autoload 'lexic-dictionary-help "lexic" "\ +Show the Lexic help page." t nil) +(register-definition-prefixes "lexic" '("lexic-")) + +;;; End of scraped data + +(provide 'lexic-autoloads) + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8-emacs-unix +;; End: + +;;; lexic-autoloads.el ends here diff --git a/elpa/lexic-20220501.1432/lexic-pkg.el b/elpa/lexic-20220501.1432/lexic-pkg.el @@ -0,0 +1,2 @@ +;;; Generated package description from lexic.el -*- no-byte-compile: t -*- +(define-package "lexic" "20220501.1432" "A major mode to find out more about words" '((emacs "26.3")) :commit "f9b3de4d9c2dd1ce5022383e1a504b87bf7d1b09" :authors '(("pluskid" . "pluskid@gmail.com") ("gucong" . "gucong43216@gmail.com") ("TEC" . "tec@tecosaur.com")) :maintainer '("TEC" . "tec@tecosaur.com") :url "https://github.com/tecosaur/lexic") diff --git a/elpa/lexic-20220501.1432/lexic.el b/elpa/lexic-20220501.1432/lexic.el @@ -0,0 +1,2034 @@ +;;; lexic.el --- A major mode to find out more about words -*- lexical-binding: t; -*- + +;; Copyright 2006~2008 pluskid, +;; 2011~2012 gucong +;; 2020~2021 tecosaur + +;; Author: pluskid <pluskid@gmail.com>, +;; gucong <gucong43216@gmail.com>, +;; TEC <tec@tecosaur.com> +;; +;; Maintainer: TEC <tec@tecosaur.com> +;; Version: 0.0.1 +;; Package-Version: 20220501.1432 +;; Package-Commit: f9b3de4d9c2dd1ce5022383e1a504b87bf7d1b09 +;; Homepage: https://github.com/tecosaur/lexic +;; Package-Requires: ((emacs "26.3")) + +;;; License: + +;; 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 2, 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, write to the Free Software +;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +;;; Commentary: + +;; This provides a major mode to view the output of dictionary tools, +;; and utilities that perform searches and nicely format the results. +;; +;; Currently tied to sdcv, but this is intended to be changed in the future. + +;; Put this file into your load-path and the following into your +;; ~/.emacs: +;; (require 'lexic-mode) +;; (global-set-key (kbd "C-c d") 'lexic-search) + +;;; Changelog: + +;; 2020/07/28 +;; * New variable: `lexic-dictionary-specs', allows for +;; - Dictionary display names +;; - Custom dictionary entry formatters +;; - Dictionary sorting +;; * Update outline function calls to replace depreciated names.' +;; * Tweak lexic-mode +;; - Remove font-locking +;; - Change `outline-regexp' to ZERO WIDTH SPACE +;; - Add `outline-heading-end-regexp', a PUNCTUATION SPACE +;; - Expand the mode map, to bind +;; - Two modes of entry navigation +;; - History navigation +;; - TAB for toggling an entry +;; * Expand popup window +;; * Add linear history navigation +;; * Revise behaviour of `lexic-next-entry' and `lexic-previous-entry' +;; * New function: `lexic-get-outline-path' which gives the structural path +;; to the current position in buffer, e.g. dict → word v. t. → 1. (Chem.) +;; * Remove (now unused) custom face vars, could do with adding some +;; new face vars in the future +;; * Change the default of `lexic-program-path' to be an absolute path +;; * New functions: `lexic-format-result', `lexic-failed-p', +;; and `lexic-format-failure' to handle the upgraded entry processing +;; * New functions: `lexic-format-webster', `lexic-format-online-etym', +;; `lexic-format-element', and `lexic-format-soule' to format +;; the dictionaries recognised by default in `lexic-dictionary-specs'. +;; - with helper functions `lexic-format-webster-diacritics', and +;; `lexic-format-expand-abbreviations' for nicer content. + +;; 2012/01/02 +;; * New variable: `lexic-word-processor' +;; * Breaking change: +;; for `lexic-dictionary-alist', non-list (non-nil) value now means full dictionary list +;; * Rewrite `lexic-search' for both interactive and non-interactive use +;; * `lexic-dictionary-list' is left for customization use only +;; * Better highlighting. +;; +;; 2011/06/30 +;; * New feature: parse output for failed lookup +;; * Keymap modification +;; +;; 2008/06/11 +;; * lexic-mode v 0.1 init (with background process) + +;;; Code: + +(require 'outline) +(require 'visual-fill-column nil t) +(require 'cl-lib) +(require 'subr-x) + +(declare-function spell-fu-mode "spell-fu") + +;;;;################################################################## +;;;; User Options, Variables +;;;;################################################################## + +(defvar lexic-buffer-name "*lexic*" + "The name of the buffer of lexic.") +(defvar lexic-dictionary-list t + "A list of dictionaries to use. +Each entry is a string denoting the name of a dictionary, which +is then passed to lexic through the '-u' command line option. +Any non-list value means using all the dictionaries.") +(defvar lexic-dictionary-alist nil + "An alist of dictionaries, used to interactively form the dictionary list. +It has the form: + ((\"full\" . t) + (\"group1\" \"dict1\" \"dict2\" ...) + (\"group2\" \"dict2\" \"dict3\")) +Any cons cell here means using all dictionaries.") + +(defvar lexic-program-path (executable-find "sdcv") + "The path of lexic program.") + +(defvar lexic-dictionary-path nil + "The path to the dictionaries.") + +(defvar lexic-word-processor nil + "This is the function that take a word (stirng) +and return a word or a list of words for lookup by `lexic-search'. +All lookup result(s) will finally be concatenated together. + +nil value means do nothing with the original word. + +The following is an example. This function takes the original word and +compare whether simplified and traditional form of the word are the same. +If not, look up both of the words. + + (lambda (word) + (let ((sim (chinese-conv word \"simplified\")) + (tra (chinese-conv word \"traditional\"))) + (if (not (string= sim tra)) + (list sim tra) + word))) +") + + +(defvar lexic-current-dictionary-list nil + "A list of dictionaries to use in searches. +Either entries from `lexic-dictionary-alist', or any non-list value, +which will cause all avalible dictionaries to be used.") + +(defvar lexic-wait-timeout 2 + "The max time (in seconds) to wait for the lexic process to produce some output.") +(defvar lexic-wait-interval 0.1 + "The interval (in seconds) to sleep each time to wait for lexic's output.") + +(defconst lexic-process-name " %lexic-mode-process%") +(defconst lexic-process-buffer-name " *lexic-mode-process*") + +(defvar lexic-word-prompts '("Enter word or phrase: ") + "A list of prompts that lexic use to prompt for word.") + +(defvar lexic-choice-prompts '("Your choice[-1 to abort]: ") + "A list of prompts that lexic use to prompt for a choice of multiple candidates.") + +(defvar lexic-result-patterns '("^Found [0-9]+ items, similar to [*?/|]*\\(.+?\\)[*?]*\\.") + "A list of patterns to extract result word of lexic. +Special characters are stripped.") + +(defvar lexic--search-history nil) +(defvar lexic--search-history-position -1) + +(defvar lexic-expand-abbreviations t + "Whether or not to try to expand abbreviations, where they are expected.") + + +;;; ================================================================== +;;; Frontend, search word and display lexic buffer + +;;;###autoload +(defun lexic-search (word &optional dict-list-name dict-list interactive-p no-history-p) + "Search WORD through the command line tool lexic. +The result will be displayed in buffer named with +`lexic-buffer-name' with `lexic-mode' if called interactively. + +When provided with DICT-LIST-NAME, query `lexic-dictionary-alist' +to get the new dictionary list before search. +Alternatively, dictionary list can be specified directly +by DICT-LIST. Any non-list value of it means using all dictionaries. + +When called interactively, prompt for the word. +Prefix argument have the following meaning: +If `lexic-dictionary-alist' is defined, +use prefix argument to select a new DICT-LIST-NAME. +Otherwise, prefix argument means using all dictionaries. + +When INTERACTIVE-P is non-nil, a buffer displaying the result(s) is shown. +Otherwise, the result is returned as a string. + +When NO-HISTORY-P is non-nil, the search is not added to the session history. + +Word may contain some special characters: + * match zero or more characters + ? match zero or one character + / used at the beginning, for fuzzy search + | used at the beginning, for data search + \ escape the character right after + +TODO decouple the tool from the general method." + (interactive + (let* ((dict-list-name + (and current-prefix-arg lexic-dictionary-alist + (completing-read "Select dictionary list: " + lexic-dictionary-alist nil t))) + (dict-list + (and current-prefix-arg (not lexic-dictionary-alist))) + (guess (or (and transient-mark-mode mark-active + (buffer-substring-no-properties + (region-beginning) (region-end))) + (current-word nil t) + "lexical")) + (word (read-string (format "Search dict (default: %s): " guess) + nil nil guess))) + (list word dict-list-name dict-list t))) + ;; init current dictionary list + (unless lexic-current-dictionary-list + (setq lexic-current-dictionary-list lexic-dictionary-list)) + ;; dict-list-name to dict-list + (when (and (not dict-list) dict-list-name) + (if (not lexic-dictionary-alist) + (error "`lexic-dictionary-alist' not defined")) + (setq dict-list + (cdr (assoc dict-list-name lexic-dictionary-alist)))) + ;; prepare new dictionary list + (when (and dict-list (not (equal lexic-current-dictionary-list dict-list))) + (setq lexic-current-dictionary-list dict-list) + ;; kill lexic process + (and (get-process lexic-process-name) + (kill-process (get-process lexic-process-name))) + (while (get-process lexic-process-name) + (sleep-for 0.01))) + (let ((result + (mapconcat + (lambda (w) (lexic-do-lookup w)) + (if lexic-word-processor + (let ((processed (funcall lexic-word-processor word))) + (if (listp processed) processed (list processed))) + (list word)) + ""))) + (unless (or no-history-p (string= word + (nth lexic--search-history-position + lexic--search-history))) + (setq lexic--search-history + (append (cl-subseq lexic--search-history + 0 (1+ lexic--search-history-position)) + (list word)) + lexic--search-history-position (1- (length lexic--search-history)))) + (if (not interactive-p) + result + (with-current-buffer (get-buffer-create lexic-buffer-name) + (setq buffer-read-only nil) + (erase-buffer) + (insert result)) + (lexic-goto-lexic) + (lexic-mode) + (lexic-mode-reinit) + (let* ((window (get-buffer-window (lexic-get-buffer))) + (height (window-height window)) + (min-height (pcase (count-lines (point-min) (point-max)) + ((pred (> 50)) 12) + ((pred (> 100)) 16) + (_ 20)))) + (when (> min-height height) + (window-resize window (- 12 height))))))) + +;;;###autoload +(defun lexic-search-word-at-point () + "Perform `lexic-search' on the word at or near point." + (interactive) + (lexic-search + (downcase + (or (and transient-mark-mode mark-active + (buffer-substring-no-properties + (region-beginning) (region-end))) + (current-word nil t) + "lexical")) + nil nil t)) + +;;;###autoload +(defun lexic-list-dictionary () + "Show available dictionaries." + (interactive) + (let (resize-mini-windows) + (shell-command (concat lexic-program-path " -l") lexic-buffer-name))) + +(defun lexic-generate-dictionary-argument () + "Generate the appropriate stcv dictionary argument. +Using `lexic-current-dictionary-list' and `lexic-dictionary-path'." + (append + (and lexic-dictionary-path (list "--data-dir" (expand-file-name lexic-dictionary-path))) + (and (listp lexic-current-dictionary-list) + (mapcan (lambda (dict) + (list "-u" dict)) + lexic-current-dictionary-list)))) + +(defun lexic-search-history-backwards () + "Show the previous word searched." + (interactive) + (if (> lexic--search-history-position 0) + (lexic-search (nth (setq lexic--search-history-position + (1- lexic--search-history-position)) + lexic--search-history) + nil nil t t) + (message "At start of search history."))) + +(defun lexic-search-history-forwards () + "Show the next word searched." + (interactive) + (if (> (length lexic--search-history) lexic--search-history-position) + (lexic-search (nth (setq lexic--search-history-position + (1+ lexic--search-history-position)) + lexic--search-history) + nil nil t t) + (message "At end of search history."))) + +;;; ================================================================== +;;; utilities to switch from and to lexic buffer +(defvar lexic-previous-window-conf nil + "Window configuration before switching to lexic buffer.") +(defun lexic-goto-lexic () + "Switch to lexic buffer in other window." + (interactive) + (unless (eq (current-buffer) + (lexic-get-buffer)) + (setq lexic-previous-window-conf (current-window-configuration))) + (let* ((buffer (lexic-get-buffer)) + (window (get-buffer-window buffer))) + (if (null window) + (switch-to-buffer-other-window buffer) + (select-window window)))) + +(defun lexic-return-from-lexic () + "Bury lexic buffer and restore the previous window configuration." + (interactive) + (kill-process (get-process lexic-process-name)) + (if (window-configuration-p lexic-previous-window-conf) + (progn + (set-window-configuration lexic-previous-window-conf) + (setq lexic-previous-window-conf nil) + (bury-buffer (lexic-get-buffer))) + (bury-buffer))) + +(defun lexic-get-buffer () + "Get the lexic buffer. Create one if there's none." + (let ((buffer (get-buffer-create lexic-buffer-name))) + (with-current-buffer buffer + (unless (eq major-mode 'lexic-mode) + (lexic-mode))) + buffer)) + +;;; ================================================================== + +(defvar lexic-mode-map + (let ((map (copy-keymap special-mode-map))) + (define-key map "q" 'lexic-return-from-lexic) + (define-key map (kbd "RET") 'lexic-search-word-at-point) + (define-key map "a" 'outline-show-all) + (define-key map "h" 'outline-hide-body) + (define-key map "o" 'lexic-toggle-entry) + (define-key map (kbd "TAB") 'lexic-toggle-entry) + (define-key map "n" 'lexic-next-entry) + (define-key map "N" (lambda () (interactive) (lexic-next-entry t))) + (define-key map "p" 'lexic-previous-entry) + (define-key map "P" (lambda () (interactive) (lexic-previous-entry t))) + (define-key map "b" 'lexic-search-history-backwards) + (define-key map "f" 'lexic-search-history-forwards) + (set-keymap-parent map special-mode-map) + map) + "Keymap for `lexic-mode'.") + + +(define-derived-mode lexic-mode fundamental-mode "lexic" + "Major mode to look up word through lexic. +\\{lexic-mode-map} +Turning on lexic mode runs the normal hook `lexic-mode-hook'. + +This mode locally removes any `spell-fu-mode' or `flyspell-mode' entries in +`text-mode-hook', but won't catch any other spell-checking initialisation. +Consider resolving any edge cases with an addition to `lexic-mode-hook'." + (setq buffer-read-only t) + (add-hook 'kill-buffer-hook + (lambda () + (let ((proc (get-process lexic-process-name))) + (when (process-live-p proc) + (kill-process proc)))) + nil t) + (setq-local outline-regexp "\u200B+") + (setq-local outline-heading-end-regexp "\u2008") + (when (featurep 'visual-fill-column) + (setq-local visual-fill-column-center-text t) + (visual-fill-column-mode 1))) + +(defun lexic-mode-reinit () + "Re-initialize buffer. +Hide all entrys but the first one and goto +the beginning of the buffer." + (ignore-errors + (setq buffer-read-only nil) + (lexic-parse-failed) + (setq buffer-read-only t) + + (let* ((window (get-buffer-window (lexic-get-buffer))) + (win-height (window-height window)) + (content-height (count-lines (point-min) (point-max)))) + (when (> 0.5 (/ (float win-height) content-height)) + (outline-hide-sublevels 3))) + + (goto-char (point-min)) + (search-forward "\u200B\u200B") + (left-char 1))) + +(defun lexic-parse-failed () + "Determine if the search failed, and if so parse the failure." + (goto-char (point-min)) + (let (save-word) + (while (re-search-forward "^[0-9]+).*-->\\(.*\\)$" nil t) + (let ((cur-word (match-string-no-properties 1))) + (unless (string= save-word cur-word) + (setq save-word cur-word) + (re-search-backward "^\\(.\\)" nil t) + (insert (format "\n==>%s\n" save-word))))))) + +(defun lexic-expand-entry () + "Show the children of the current entry, or subtree if there are none." + (outline-show-children) + (when ; no children + (<= 0 (- (save-excursion (outline-next-heading) (point)) + (save-excursion (outline-end-of-subtree) (point)))) + (outline-show-subtree))) + +(defun lexic-next-entry (&optional linear) + "Move to the next entry, targeting the same level unless LINEAR is set." + (interactive) + (when (< 1 (lexic-outline-level)) + (outline-hide-subtree)) + (if linear + (outline-next-heading) + (condition-case nil + (outline-forward-same-level 1) + (error + (condition-case nil + (progn + (outline-up-heading 1 t) + (outline-forward-same-level 1)) + (error (progn (outline-next-heading) + (lexic-expand-entry))))))) + (lexic-expand-entry) + (recenter-top-bottom 1) + (message "%s" (lexic-get-outline-path))) + +(defun lexic-previous-entry (&optional linear) + "Move to the previous entry, targeting the same level unless LINEAR is set." + (interactive) + (outline-hide-subtree) + (if (= 2 (line-number-at-pos)) + (recenter-top-bottom -1) + (if linear + (outline-previous-heading) + (condition-case nil + (outline-backward-same-level 1) + (error + (condition-case nil + (outline-up-heading 1 t) + (error (outline-previous-heading)))))) + (lexic-expand-entry) + (recenter-top-bottom 2)) + (message "%s" (lexic-get-outline-path))) + +(defun lexic-toggle-entry () + "Toggle the folding of the lexic entry point currently lies in." + (interactive) + (save-excursion + (outline-back-to-heading) + (if (not (save-excursion + (outline-end-of-heading) + (outline-invisible-p (line-end-position)))) + (outline-hide-subtree) + (outline-show-subtree)))) + +;;; ================================================================== +;;; Support for lexic process in background +(defun lexic-do-lookup (word &optional raw-p) + "Send the WORD to the lexic process and return the result. +Optional argument RAW-P signals whether the result should be formatted or not." + (let ((process (lexic-get-process))) + (process-send-string process (concat word "\n")) + (with-current-buffer (process-buffer process) + (let ((i 0) result done) + (while (and (not done) + (< i lexic-wait-timeout)) + (when (lexic-match-tail lexic-word-prompts) + (setq result (buffer-substring-no-properties (point-min) + (point-max))) + (setq done t)) + (when (lexic-match-tail lexic-choice-prompts) + (process-send-string process "-1\n")) + (unless done + (sleep-for lexic-wait-interval) + (setq i (+ i lexic-wait-interval)))) + (unless (< i lexic-wait-timeout) + ;; timeout + (kill-process process) + (error "ERROR: timeout waiting for lexic")) + (erase-buffer) + (if raw-p result + (lexic-format-result result)))))) + +(defun lexic-oneshot-lookup (word &optional raw-p args) + "Use a oneshot stcv process just to look up WORD, with ARGS. +Optional argument RAW-P signals whether the result should be formatted or not." + (let ((result (with-temp-buffer + (apply #'call-process lexic-program-path nil t nil + (append '("-n") args (list word))) + (buffer-string)))) + (if raw-p result + (lexic-format-result result)))) + +(defun lexic-get-process () + "Get or create the lexic process." + (let ((process (get-process lexic-process-name))) + (unless process + (with-current-buffer (get-buffer-create + lexic-process-buffer-name) + (erase-buffer) + (setq process (apply #'start-process + lexic-process-name + lexic-process-buffer-name + lexic-program-path + (lexic-generate-dictionary-argument))) + (set-process-query-on-exit-flag process nil) + ;; kill the initial prompt + (let ((i 0)) + (message "starting lexic...") + (while (and (not (lexic-match-tail lexic-word-prompts)) + (< i lexic-wait-timeout)) + (sit-for lexic-wait-interval t) + (setq i (+ i lexic-wait-interval))) + (unless (< i lexic-wait-timeout) + ;; timeout + (kill-process process) + (error "ERROR: timeout waiting for lexic")) + (erase-buffer)) + (message ""))) + process)) + +(defun lexic-buffer-tail (length) + "Get a substring of length LENGTH at the end of current buffer." + (let ((beg (- (point-max) length)) + (end (point-max))) + (if (< beg (point-min)) + (setq beg (point-min))) + (buffer-substring-no-properties beg end))) + +(defun lexic-match-tail (prompts) + "Look for a sdcv prompt from PROMPTS in the tail of the current buffer. +Remove it and return t if found. Return nil otherwise." + (let ((done nil) + (prompt nil)) + (while (and (not done) + prompts) + (setq prompt (car prompts)) + (setq prompts (cdr prompts)) + (when (string-equal prompt + (lexic-buffer-tail (length prompt))) + (delete-region (- (point-max) (length prompt)) + (point-max)) + (setq done t))) + done)) + +;;;;################################################################## +;;;; Output Processing +;;;;################################################################## + +(defun lexic-format-result (result) + "For a RESULT from lexic, test for failure and format accordingly. +Entries are sorted by their :priority in `lexic-dictionary-specs' then formatted +by `lexic-format-result' in successful case, `cases-format-failure' otherwise." + (cond + ((string-match-p "^Nothing similar to" result) + (lexic-consider-no-results)) + ((lexic-failed-p result) + (lexic-format-failure result)) + (t + (let* ((entries + (sort (lexic-parse-results result) + (lambda (a b) + (< (or (lexic-dictionary-spec (plist-get a :dict) :priority) 1) + (or (lexic-dictionary-spec (plist-get b :dict) :priority) 1))))) + (word (save-match-data + (string-match "\\`Found.* similar to \\(\\w+\\)\\." result) + (downcase (match-string 1 result))))) + (concat + "\u200B" + (propertize (capitalize word) 'face 'outline-1) + "\u2008" + (apply #'concat + (mapcar (lambda (e) + (lexic-format-entry + e word)) + entries))))))) + +(defun lexic-consider-no-results () + "No results have been found. What should we tell the user?" + (let ((dicts? (not (string-match-p "\\`Dictionary's name +Word count[\n ]+\\'" + (shell-command-to-string (concat lexic-program-path " -l")))))) + (if dicts? + (user-error "Couldn't find anything similar to your search, sorry :(") + (user-error "No results found, but you don't seem to have any dictionaries installed! Try %s" + (propertize "M-x lexic-dictionary-help" 'face 'font-lock-keyword-face))))) + +(defun lexic-parse-results (result) + "Loop through every entry in RESULT and parse each one. +Returns a list of plists with keys :word, :dict, and :info." + (let (entries latest-match last-match dict word) + (with-temp-buffer + (insert result) + (goto-char (point-min)) + (while + (setq latest-match (re-search-forward + "-->\\([^\n]+\\)\n-->\\(.+\\)\n\n" nil t)) + (when last-match + (forward-line -3) + (setq entries + (append entries + `((:word ,word + :dict ,dict + :info ,(buffer-substring last-match (point)))))) + (forward-line 3)) + (setq last-match latest-match) + (setq dict (match-string 1)) + (setq word (match-string 2))) + (when last-match + (setq entries + (append entries + `((:word ,word + :dict ,dict + :info ,(buffer-substring last-match (point-max)))))))))) + +(defun lexic-failed-p (results) + "Whether the RESULTS match the hardcoded failure pattern." + (if (string-match-p "Found [0-9]+ items, similar to [^.]+\\.\n0)" results) t nil)) + +(defun lexic-format-failure (results) + "When lexic failed to match the word, format the suggestions in RESULTS." + (let (suggestions last-match) + (while (setq last-match + (string-match "^[0-9]+)\\(.*\\)-->\\([A-Za-z]+\\)" + results + (when last-match (1+ last-match)))) + (let ((dict (match-string 1 results)) + (word (match-string 2 results))) + (if (assoc dict suggestions) + (setcdr (assoc dict suggestions) + (list (append (cadr (assoc dict suggestions)) (list word)))) + (setq suggestions (append suggestions `((,dict . ((,word))))))))) + (concat + (propertize + (replace-regexp-in-string + "items" "entries" + (substring results 0 (string-match "\n" results))) + 'face 'warning) + "\n" + (mapconcat (lambda (dict-suggestions) + (format "\u200B\u200B%s\n\u200B\u200B\u200B%s" + (propertize (or + (lexic-dictionary-spec (car dict-suggestions) :short) + (car dict-suggestions)) + 'face 'outline-3) + (propertize + (mapconcat #'identity (cadr dict-suggestions) "\n\u200B\u200B\u200B") + 'face 'font-lock-keyword-face))) + (sort suggestions + (lambda (a b) + (< (or (lexic-dictionary-spec (car a) :priority) 1) + (or (lexic-dictionary-spec (car b) :priority) 1)))) + "\n")))) + +(defun lexic-format-entry (entry &optional expected-word) + "Format a given ENTRY, a plist with :word :dict and :info. +If the DICT has a :short value in `lexic-dictionary-specs' that is used as +the display name. Likewise if present, :formatter is used to generate the +entry. EXPECTED-WORD is the word expected in ENTRY." + (let ((dict (plist-get entry :dict))) + (concat + "\n\u200B\u200B" + (propertize (or (lexic-dictionary-spec dict :short) + dict) 'face 'outline-3) + "\n\u2008\n" + (if-let* ((formatter (lexic-dictionary-spec dict :formatter))) + (let ((case-fold-search nil)) + (string-trim (funcall formatter entry expected-word))) + (plist-get entry :info)) + "\n"))) + +(defun lexic-get-outline-path () + "Return a string giving the structural path to the current position." + (let ((outline-path "") + (last-pos 0) + outline-level-current substring level-regexp) + (save-excursion + (outline-back-to-heading) + (setq outline-level-current (lexic-outline-level)) + (while (/= (point) last-pos) + (setq outline-level-current (lexic-outline-level)) + (setq substring + (buffer-substring + (point) + (save-excursion (search-forward "\u2008") (point)))) + (setq level-regexp + (pcase outline-level-current + (1 "^\\([^\n]+\\)") + (2 "^\\([^ \n]+\\)") + (3 "^\u200B\u200B*\\([^,]+\\(?:, [ &.;a-z]+\\)?\\)") + (4 "\\([0-9]+\\.\\( ?([^)]+)\\)?\\( \\w+\\)\\{0,4\\}\\)") + (5 "\\(([a-z])\\( ?([^)]+)\\)?\\( \\w+\\)\\{0,4\\}\\)") + (_ "^\u200B\u200B*\\([^ ]+\\)"))) + (setq outline-path + (concat + (propertize " → " 'face 'bold) + (save-match-data + (string-match level-regexp substring) + (match-string 1 substring)) + outline-path)) + (setq last-pos (point)) + (ignore-errors + (outline-up-heading 1))) + (substring outline-path 2)))) + +(defun lexic-outline-level () + "It seems that while (outline-level) should work, it has issues." + (- (save-excursion (outline-back-to-heading) + (search-forward-regexp "\u200B+")) + (point))) + +(defvar lexic-dictionary-specs + '(("Webster's Revised Unabridged Dictionary (1913)" + :formatter lexic-format-webster + :priority 1) + ("Elements database" + :short "Element" + :formatter lexic-format-element + :priority 2) + ("Hitchcock's Bible Names Dictionary" + :short "Hitcchcock's Bible Names" + :priority 3) + ("Online Etymology Dictionary" + :short "Etymology" + :formatter lexic-format-online-etym + :priority 4) + ("Soule's Dictionary of English Synonyms" + :short "Synonyms" + :formatter lexic-format-soule + :priority 5)) + "List of dictionary specifications. +In each entry the car is the name according to lexic, and the cdr is +a plist whith the following options: + :short - a (usually) shorter display name for the dictionary + :formatter - a function with signature (ENTRY WORD) that returns a string + :priority - sort priority, defaults to 1") + +(defun lexic-dictionary-spec (dict spec) + "Helper function to get a :SPEC of a given DICT." + (plist-get (cdr (assoc dict lexic-dictionary-specs)) spec)) + +(defun lexic-format-webster (entry &optional _expected-word) + "Make a Webster's dictionary ENTRY for WORD look nice. +Designed for Webster's Revised Unabridged Dictionary (1913),as found at +http://download.huzheng.org/dict.org/stardict-dictd-web1913-2.4.2.tar.bz2. + +This should also work nicely with GCIDE." + (thread-last (plist-get entry :info) + (lexic-format-webster-diacritics) + (replace-regexp-in-string ; entry dividors + (format "\n\n\\(%s\\)" (plist-get entry :word)) + "\n ━━━━━━━━━ ■ ━━━━━━━━━\n\n\\1") + (replace-regexp-in-string ; entry headline + (rx line-start + (group-n 1 ; word + (any "A-Z") + (+ (any "a-z"))) + (optional " \\" ; word2 + (group-n 2 (+ (not (any "\\")))) + "\\") + (optional " (" ; pronounciation + (group-n 3 (+ (not (any ")")))) + ")") + ", " + (group-n 4 ; part of speech + (+ (any "A-Z" "a-z" ".;&" " "))) + (optional "[" ; etymology / alternative forms + (group-n 5 + (+ (or (+ (not (any "]["))) + (and "[" (+ (not (any "]["))) "]")))) + "]") + (optional ; definitely etymology + (+ (any "\n" " ")) "[" + (group-n 6 + (+ (or (+ (not (any "]["))) + (and "[" (+ (not (any "]["))) "]")))) + "]") + (optional " (" ; category + (group-n 7 (+ (not (any ")")))) + ")")) + (lambda (match) + (let* ((word2 (match-string 2 match)) + (pronounciation (match-string 3 match)) + (part-of-speech (lexic-format-expand-abbreviations + (replace-regexp-in-string " \\'" "" + (match-string 4 match)))) + (alternative-forms (when (match-string 6 match) + (lexic-format-expand-abbreviations (match-string 5 match)))) + (etymology (lexic-format-expand-abbreviations (match-string (if alternative-forms 6 5) match))) + (category (lexic-format-expand-abbreviations (match-string 7 match))) + (last-newline (lambda (text) (- (length text) + (or (save-match-data + (string-match "\n[^\n]*\\'" text)) 0))))) + (concat + "\u200B\u200B\u200B" + (propertize word2 + 'face 'bold) + (when pronounciation + (propertize (format " %s" pronounciation) + 'face 'font-lock-type-face)) + ", " + (propertize part-of-speech + 'face '(bold font-lock-keyword-face)) + (when alternative-forms + (setq alternative-forms + (lexic-format-reflow-text + (format " [%s]" alternative-forms) + 80 10 + (+ 3 (if pronounciation 1 0) + (funcall last-newline + (concat word2 pronounciation part-of-speech))) + " ")) + (propertize alternative-forms + 'face 'diff-context)) + (when etymology + (setq etymology + (lexic-format-reflow-text + (format " [%s]" etymology) + 80 10 + (+ 3 (if pronounciation 1 0) + (funcall last-newline + (concat word2 pronounciation part-of-speech alternative-forms))) + " ")) + (propertize etymology + 'face 'font-lock-comment-face)) + (when category + (propertize (format " (%s)" category) + 'face 'font-lock-constant-face)) + "\u2008")))) + (replace-regexp-in-string ; categorised terms + "{\\([^}]+?\\)}\\(.?\\) (\\([^)]+?\\))" + (lambda (match) + (let ((term (match-string 1 match)) + (punct (match-string 2 match)) + (category (match-string 3 match))) + (concat + (propertize term 'face 'font-lock-keyword-face) + punct + (propertize (format " (%s)" + (if lexic-expand-abbreviations + (lexic-format-expand-abbreviations category) + category)) + 'face 'font-lock-constant-face))))) + (replace-regexp-in-string ; other terms + "{\\([^}]+?\\)}" + (lambda (match) + (let ((term (match-string 1 match))) + (concat + (propertize term 'face 'font-lock-keyword-face))))) + (replace-regexp-in-string ; quotations + "^\n +\\(\\w[[:ascii:]]+?\\)\\(\n? *--[A-Za-z0-9. ]+\n? *[A-Za-z0-9. ]*\\)" + (lambda (match) + (let ((body (match-string 1 match)) + (author (match-string 2 match))) + (concat + "\n " + (propertize (format "❝%s❞" body) + 'face 'font-lock-doc-face) + author "\n")))) + (replace-regexp-in-string ; attributions + " --\\([A-Z][A-Za-z. ]+\n? *[A-Za-z0-9. ]*\\)" + (lambda (match) + (propertize (concat " ──" (match-string 1 match)) + 'face '(italic font-lock-type-face)))) + (replace-regexp-in-string ; inline quotations (1) + "``" "“") + (replace-regexp-in-string ; inline quotations (1) + "''" "”") + (replace-regexp-in-string ; em dash approximation + " -- " " ─── ") + (replace-regexp-in-string ; lists + " \\(?:\\([0-9]+\\.\\)\\|\\( ([a-z])\\)\\) \\(?: ?(\\([^)]+\\)) \\)?\\(.*\\)" + (lambda (match) + (let ((number (match-string 1 match)) + (letter (match-string 2 match)) + (category (match-string 3 match)) + (rest-of-line (match-string 4 match))) + (concat + (when letter "\u200B") + "\u200B\u200B\u200B\u200B " + (when number + (propertize number 'face '(bold font-lock-string-face))) + (when letter + (propertize letter 'face 'font-lock-string-face)) + (when category + (propertize (format " (%s)" + (if lexic-expand-abbreviations + (lexic-format-expand-abbreviations category) + category)) + 'face 'font-lock-constant-face)) + " " + rest-of-line + "\u2008")))) + (replace-regexp-in-string ; note + " Note: " + (concat " " + (propertize " " 'display '(space . (:width 0.55))) + (propertize "☞" 'face 'font-lock-function-name-face) + " ")) + (replace-regexp-in-string ; subheadings + " \\(\\w+\\): " + (lambda (match) + (propertize (concat " "(match-string 1 match) ": ") + 'face 'bold))))) + +(defun lexic-format-expand-abbreviations (content &optional force) + "Expand certain standard abbreviations in CONTENT when `lexic-expand-abbreviations' or FORCE are non-nil." + (when content + (when (or lexic-expand-abbreviations force) + (let ((abbreviations + '(; A + ("adj" "adjective") + ("a" "adjective") + ("abbrev" "abbreviated") + ("abl" "ablative") + ("Abp" "Archbishop") + ("acc" "Acoustics") + ("act" "active") + ("adv" "adverb") + ("Agric" "Agriculture") + ("Alban" "Albanian") + ("Alg" "Algebra") + ("Am" "America") + ("Amer" "American") + ("Am" "Amos") + ("Am\\. Cyc" "Appleton's American Cyclopedia") + ("Anal. Geom" "Analytical Geometry") + ("Anat" "Anatomy") + ("Anc" "Ancient") + ("Angl\\. Ch" "Anglican Church") + ("aor" "aorist") + ("Ar" "Arabic") + ("Arch" "Architecture") + ("Arch\\. Pub\\. Soc" "Architectural Pub. Society") + ("Arith" "Arithmetic") + ("Arm\\., Armor" "Armorican") + ("AS" "Anglo-Saxon") + ("Astrol" "Astrology") + ("Astron" "Astronomy") + ("aug" "augmentative") + ;; B + ("Bank" "Banking") + ("Beau\\. & Fl" "Beaumont & Fletcher") + ("B\\. & Fl" "Beaumont & Fletcher") + ("Bib\\. Sacra" "Bibliotheca Sacra") + ("Bib" "Biblical") + ("Bibliog" "Bibliography") + ("Biol" "Biology") + ("Bisc" "Biscayan") + ("B\\. Jon" "Ben Jonson") + ("Bk\\. of Com\\. Prayer " "Book of Common Prayer") + ("Blackw\\. Mag" "Blackwood's Magazine") + ("Bohem" "Bohemian") + ("Bot" "Botany") + ("Bp" "Bishop") + ("Brande & C" "Brande & Cox") + ("Braz" "Brazilian") + ("Brit\\. Critic" "British Critic") + ("Brit\\. Quar\\. Rev" "British Quarterly Review") + ("Burl" "Burlesque") + ;; C + ("C" "Centigrade") + ("Cant" "Canticles") + ("Carp" "Carpentry") + ("Catal" "Catalan") + ("Cath\\. Dict" "Catholic Dictionary") + ("Celt" "Celtic") + ("cf" "confer") + ("Cf" "Confer") + ("Ch" "Church") + ("Chald" "Chaldee") + ("Chem" "Chemistry") + ("Ch\\. Hist" "Church History") + ("Chron" "Chronology, Chronicles") + ("Civ" "Civil") + ("Class" "Classical") + ("Class\\. Myth" "Classical Mythology") + ("Col" "Colossians") + ("colloq\\., coll" "colloquial, colloquially") + ("Com" "Commerce, Common") + ("comp" "compound, compounded, composition") + ("compar" "comparative") + ("conj" "conjunction") + ("Con\\. Sect" "Conic Sections") + ("contr" "contracted, contraction") + ("Copt" "Coptic") + ("Corn" "Cornish") + ("corrupt" "corrupted, corruption") + ("Cotgr" "Cotgrave") + ("Cyc\\. Med" "Cyclopedia of Practical Medicine") + ("Crim\\. Law" "Criminal Law") + ("Crystallog" "Crystallography") + ("Cyc" "Cyclopedia") + ;; D + ("D" "Dutch (sometimes Daniel)") + ("Dan" "Danish") + ("dat" "dative") + ("def" "definitions") + ("Deut" "Deuteronomy") + ("Dial" "Dialectic") + ("dim" "diminutive") + ("Diosc" "dioscorides") + ("Disp" "Dispensatory") + ("Disus" "Disused") + ("Dom\\. Econ" "Domestic Economy") + ("Dublin Univ\\. Mag" "Dublin University Magazine") + ("Dyn" "Dynamics") + ;; E + ("E" "English") + ("Eccl" "Ecclesiastical, Ecclesiastes") + ("Eccl\\. Hist" "Ecclesiastical History") + ("Ecclus" "Ecclesiasticus") + ("Eclec\\. Rev" "Eclectic Review") + ("Ed\\. Rev" "Edinburgh Review") + ;; ("e\\. g" "exempli gratia (for example)") + ("Egypt" "Egyptian") + ("Elect" "Electricity") + ("Elec" "Electrical") + ("emph" "emphatic") + ("Encyc\\. Amer" "Encyclopedia Americana") + ("Encyc\\. Crit" "Encyclopedia Britannica") + ("Encyc\\. Dict" "Hunter's Encyclopedic Dictionary") + ("Encyc" "Encyclopedia") + ("Eng\\. Cyc" "English Cyclopedia") + ("Eng" "English") + ("Engin" "Engineering") + ("Eol" "Eolic") + ("Eph\\., Ephes" "Ephesians") + ("equiv" "equivalent") + ("Esd" "Esdras") + ("esp" "especially") + ("Etch\\. & Eng" "Etching & Engraving") + ("Ethnol" "Ethnology") + ("etym\\., etymol" "etymology") + ("Ex\\., Exod" "Exodus") + ("Ezek" "Ezekiel") + ;; F + ("F" "French") + ("f" "feminine") + ("fem" "feminine") + ("Fahr" "Fahrenheit") + ("Far" "Farriery") + ("Feud" "Feudal") + ("Fig" "Figurative, figuratively") + ("Fin" "Finnish") + ("For\\. Quart\\. Rev" "Foreign Quarterly Review") + ("Fort" "Fortification") + ("Fr" "French") + ("fr" "from") + ("freq" "frequentative") + ("Fries" "Friesic") + ("fut" "future") + ;; G + ("G" "German") + ("Gael" "Gaelic") + ("Gal" "Galen") + ("Gal" "Galatians") + ("Galv" "Galvanism") + ("gen" "generally, genitive") + ("Geneal" "Genealogy") + ("Gent\\. Mag" "Gentleman's Magazine") + ("Geog" "Geography") + ("Geol" "Geology") + ("Geom" "Geometry") + ("Ger" "Germanic or German") + ("Gk" "Greek") + ("Goth" "Gothic") + ("Gov\\. of Tongue" "Government of the Tongue") + ("Gr" "Greek") + ("Gram" "Grammar") + ("Gris" "Grisons") + ("Gun" "Gunnery") + ;; H + ("H" "High") + ("Hab" "Habakkuk") + ("Hag" "Haggai") + ("Ham\\. Nav\\. Encyc" "Hamersly's Naval Encyclopedia") + ("Heb" "Hebrew") + ("Her" "Heraldry") + ("Hind" "Hindostanee") + ("Hipp" "Hippocrates") + ("Hist" "History") + ("Horol" "Horology") + ("Hort" "Horticulture") + ("Hung" "Hungarian") + ("Hydraul" "Hydraulics") + ("Hydros" "Hydrostatics") + ("hypoth" "hypothetical") + ;; I + ("Icel" "Icelandic") + ;; ("i\\. e" "id est (that is)") + ("Illust" "Illustration, Illustrated") + ("imp" "imperfect") + ("Imp\\. Dict" "Imperial Dictionary") + ("incho" "inchoative") + ("ind" "indicative") + ("indef" "indefinite") + ("inf" "infinitive") + ("intens" "intensive") + ("interj" "interjection") + ("Internat\\. Cyc" "International Cyclopeia") + ("Ion" "Ionic") + ("i\\. q" "idem quod") + ("Ir" "Irish") + ("Is" "Isaiah") + ("Isa" "Isaiah") + ("It" "Italian") + ;; J + ("Jap" "Japanese") + ("Jas" "James") + ("Jav" "Javanese") + ("Jer" "Jeremiah") + ("Join" "Joinery") + ("Josh" "Joshua") + ("Judg" "Judges") + ;; K + ("K" "Kings") + ;; L + ("L" "Latin") + ("Lam" "Lamentations") + ("Lapp" "Lappish") + ("Lat" "Latin") + ("LD" "Low Dutch") + ("Lett" "Lettish") + ("Lev" "Leviticus") + ("LG" "Low German") + ("LGr" "Low Greek") + ("Linn" "Linnæus") + ("Lit" "Literally") + ("lit" "literally") + ("Lit" "Literature") + ("Lith" "Lithuanian") + ("LL" "Late Latin") + ;; M + ("M" "Middle") + ("m" "masculine") + ("masc" "masculine") + ("Maced" "Macedonian") + ("Mach" "Machinery") + ("Mad" "Madam") + ("Mag" "Magazine") + ("Mal" "Malachi") + ("Malay" "Malayan") + ("Man" "Manège") + ("Manuf" "Manufacturing") + ("Mar" "Maritime") + ("Math" "Mathematics") + ("Matt" "Matthew") + ("ME" "Middle English") + ("Mech" "Mechanic") + ("Med" "Medicine") + ("Metal" "Metallurgy") + ("Metaph" "Metaphysics") + ("Meteor" "Meteorolgy") + ("mgr" "milligrams") + ("MHG" "Middle High German") + ("Micros" "Microscopy") + ("Mil" "Military") + ("Min" "Mineralogy") + ("Mir\\. for Mag" "Mirror for Magistrates") + ("MLG" "Middle Low German") + ("Moham" "Mohammedan") + ("Mozley & W" "Mozley & Whiteley") + ("Mus" "Music") + ("Myst" "Mysteries") + ("Myth" "Mythology") + ;; N + ("Nat\\. Hist" "Natural History") + ("Nat\\. ord" "Natural order") + ("Naut" "Nautical") + ("Nav" "Navy") + ("Navig" "Navigation") + ("N\\. Brit\\. Rev" "North British Review") + ("Neh" "Nehemiah") + ("neut" "neuter") + ("New Am\\. Cyc" "New American Cyclopedia") + ("New Month\\. Mag" "New Monthly Magazine") + ("NF" "New French") + ("NGr" "Mew Greek") + ("NHeb" "New Hebrew") + ("NL" "New Latin") + ("nom" "nominative") + ("Norm\\. F" "Norman French") + ("North Am\\. Rev" "North American Review") + ("Norw" "Norwegian") + ("Num" "Numbers") + ("Numis" "Numismatics") + ("N" "New") + ;; O + ("O" "Old") + ("Ob" "Obadiah") + ("obs" "obsolete") + ("Obsoles" "Obsolescent") + ("OCelt" "Old Celtic") + ("OD" "Old Dutch") + ("ODan" "Old Danish") + ("OE" "Old English") + ("OF" "Old French") + ("OFelm" "Old Flemish") + ("OFris" "Old Frisian") + ("OFries" "Old Friesic") + ("OGael" "Old Gaelic") + ("OGr" "Old Greek") + ("OHG" "Old High German") + ("OIcel" "Old Icelandic") + ("OIt" "Old Italian") + ("OL" "Old Latin") + ("OIr" "Old Irish") + ("ON" "Old Norse") + ("OLG" "Old Low German") + ("OPer" "Old Persian") + ("OPg" "Old Portuguese") + ("OPol" "Old Polish") + ("Opt" "Optics") + ("orig" "original") + ("Ornith" "Ornithology") + ("OS" "Old Saxon") + ("OSlav" "Old Slavic") + ("OSp" "Old Spanish") + ("Oxf\\. Gloss" "Oxford Glossary of Architecture") + ;; P + ("p\\.[\n ]*a" "participial adjective") + ("Paint" "Painting") + ("Paleon" "Paleontology") + ("pass" "passive") + ("Pathol" "Pathology") + ("P\\. Cyc" "Penny Cyclopedia") + ("Per" "Persian") + ("perh" "perhaps") + ("pers" "person") + ("Persp" "Perspective") + ("Pert" "Pertaining") + ("Peruv" "Peruvian") + ("Pet" "Peter") + ("Pg" "Portuguese") + ("Pharm" "Pharmacy, Pharmacopœia") + ("Phil" "Phillipians") + ("Philem" "Philemon") + ("Philol" "Philology") + ("Philos" "Philosophy") + ("Phon" "Phonetics") + ("Photog" "Photography") + ("Photom" "Photometry") + ("Phren" "Phrenology") + ("Phys" "Physics") + ("Phys\\. Sci" "Physical Science") + ("Physiol" "Physiology") + ("pl" "plural") + ("Poet" "Poetry, Poetical") + ("Pol" "Polish") + ("Pol\\. Econ" "Political Economy") + ("Polit\\. Econ" "Political Economy") + ("Pop\\. Sci\\. Monthly" "Polular Science Monthly") + ("Poss" "Possessive") + ("pp" "pages") + ("P\\. Plowman" "Piers Plowman") + ("p\\.[\n ]*p" "past participle") + ("p\\.[\n ]*pr" "present participle") + ("p\\.[\n ]*ple" "present participle") + ("Pr" "Provençal") + ("Pref" "Preface") + ("pref" "prefix") + ("prep" "preposition") + ("pres" "present") + ("pret" "preterit") + ("prin" "principally") + ("Print" "Printing") + ("priv" "privative") + ("prob" "probably") + ("pron" "pronoun") + ("prop" "properly") + ("Pros" "Prosody") + ("prov" "provincial") + ("Prov" "Provincial") + ("Prov" "Proverbs") + ("Ps\\., Psa" "Psalms") + ("Pyro\\.-elect" "Pyro-electricity") + ("p" "participle") + ;; Q + ("Quart\\. Rev" "Quarterly Review") + ("q\\. v" "quod vide (which see)") + ;; R + ("R\\. C" "Roman Catholic") + ("R\\. C\\. Ch" "Roman Catholic Church") + ("Rep\\. Sec\\. of War" "Report of Secretary of War") + ("Rev" "Revelation") + ("Rev" "Review") + ("Rev\\. Ver" "Revised Version (of the Bible)") + ("Rhet" "Rhetoric") + ("R\\. of Brunne" "Robert of Brunne") + ("R\\. of Gl" "Robert of Gloucester") + ("Rom" "Roman, Romans") + ("Rom\\. Cath" "Roman Catholic") + ("Rom\\. of R" "Romaunt of the Rose") + ("Rpts" "reports") + ("Russ" "Russian") + ("R" "Rare") + ;; S + ("Sam" "Samaritan") + ("Sam" "Samuel") + ("Sat\\. Rev" "Saturday Review") + ("Sax" "Saxon") + ("sc" "scilicet (being understood)") + ("Scand" "Scandinavian") + ("Sci" "Science") + ("Sci\\. Am" "Scientific American") + ("Scot" "Scotland, Scottish") + ("Script" "Scripture, Scriptural") + ("Sculp" "Sculpture") + ("Serb" "Serbian") + ("Serv" "Servian") + ("Shak" "Shakespeare") + ("sing" "singular") + ("Skr" "Sanskrit") + ("Slav" "Slavonic") + ("Sp" "Spanish") + ("Specif" "Specifically") + ("Stat" "Statuary") + ("subj" "subjunctive") + ("superl" "superlative") + ("Surg" "Surgery") + ("Surv" "Surveying") + ("Sw" "Swedish") + ("Syd\\. Soc\\. Lex" "Sydenham Society Lexicon") + ("Syn" "Synonyms") + ("Synop" "Synopsis") + ("Syr" "Syriac") + ;; T + ("Tart" "Tartaric") + ("Teleg" "Telegraphy") + ("term" "termination") + ("Test" "Testament") + ("Theol" "Theology") + ("Thes" "Thessalonians") + ("Tim" "Timothy") + ("Todd & B" "Todd & Bowman") + ("Trans" "Translation") + ("Treas" "Treasury") + ("Trig" "Trigonometry") + ("Turk" "Turkish") + ("Typog" "Typography") + ;; U + ("Univ" "University") + ("Up" "Upper") + ("U\\. ?S" "United States") + ("U\\. ?S\\. Disp" "United States Dispensatory") + ("U\\. ?S\\. Pharm" "United States Pharmacopœia") + ("U\\. ?S\\. Int\\. Rev\\. Statutes" "United States Internal Revenue Statutes") + ("usu" "usually") + ;; V + ("v\\.[\n ]*i" "intransitive verb") + ("v\\.[\n ]*t" "transitive verb") + ("var" "variety") + ("vb\\.[\n ]*n" "verbal noun") + ("Veter" "Veterinary") + ("Vitr" "Vitruvius") + ;; W + ("W" "Welsh") + ("Wall" "Wallachian") + ("Westm\\. Cat" "Westminster Catechism") + ("Westm\\. Rev" "Westminster Review") + ;; Z + ("Zech" "Zechariah") + ("Zeph" "Zephaniah") + ("Zoöl" "Zoölogy") + ;; Reordered for correctness + ("n" "noun") + ("v" "verb")))) + (dolist (abbrev abbreviations) + (setq content + (replace-regexp-in-string + (concat "\\b" (car abbrev) "\\.") + (cadr abbrev) + content t))))) + content)) + +(defun lexic-format-webster-diacritics (pronunciation) + "Replace ascii pronounciation symbols in PRONUNCIATION with unicode equivalents." + (let ((diacritics + '(("[,C]" "Ç") + ("\"u" "ü") ; uum + ("'e" "é") ; eacute + ("\\^a" "â") ; acir + ("\"a" "ä") ; aum + ("`a" "à") ; agrave + ("\\*a" "å") ; aring + ("\\*u" "ů") ; uring + (",c" "ç") ; ccedil + ("cced" "ç") + ("\\^e" "ê") ; ecir + ("\"e" "ë") ; eum + ("`e" "è") ; egrave + ("\"i" "ï") ; ium + ("\\^i" "î") ; icir + ("`i" "ì") ; igrave + ("\"A" "Ä") ; Aum + ("\\*A" "Å") ; Aring + ("'E" "È") ; Eacute + ("ae" "æ") ; ae + ("AE" "Æ") ; AE + ("\\^o" "ô") ; ocir + ("\"o" "ö") ; oum + ("`o" "ò") ; ograve + ("'o" "ó") ; oacute + ("Oacute" "Ó") + ("\\^u" "û") ; ucir + ("`u" "ù") ; ugrave + ("'u" "ú") ; uacute + ("\"y" "ÿ") ; yum + ("\"O" "Ö") ; Oum + ("\"U" "Ü") + ("pound" "£") + ("'a" "á") ; aacute + ("'i" "í") ; iacute + ("frac23" "⅔") + ("frac13" "⅓") + ("frac12" "½") + ("frac14" "¼") + ("\\?" "�") ; Place-holder for unknown or illegible character. + ("hand" "☞") ; pointing hand (printer's u"fist") ; hand ; and + ("\\.\\.\\." "…") + ("\\*\\*\\*\\*\\*\\*\\*\\*" "✶") + ("sect" "§") ; sect + ("=a" "ā") ; amac + ("ng" "ṉ") ; u"n sub-macron" ; nsm + ("sharp" "♯") ; sharp + ("flat" "♭") ; flat + ("th" "th") ; th + ("=i" "ī") ; imac + ("imac" "ī") ; imac + ("=e" "ē") ; emac + ("\\.d" "ḍ") ; Sanskrit/Tamil d dot + ("\\.n" "ṇ") ; Sanskrit/Tamil n dot ; nsdot + ("\\.t" "ṭ") ; Sanskrit/Tamil t dot ; tsdot + ("a\\^" "ă") ; acr + ("e\\^" "ĕ") ; ecr + ("i\\^" "ĭ") ; icr + ("o\\^" "ŏ") ; ocr + ("!o" "ǒ") + ("OE" "Œ") ; OE + ("oe" "œ") ; oe + ("=O" "Ō") ; Omac + ("=o" "ō") ; omac + ("=u" "ū") ; umac + ("ocar" "ǒ") ; o hacek + ("=ae" "ǣ") ; aemac + ("u\\^" "ŭ") ; ucr + ("a\\^" "ă") + ("=y" "ȳ") ; ymac + ("asl" "a") ; FIXME: a u"semilong" (has a macron above with a short + ("-e" "e") ; FIXME: e u"semilong" ; esl + ("-i" "i") ; FIXME: i u"semilong" ; isl + ("-o" "o") ; FIXME: o u"semilong" ; osl + ("-u" "u") ; FIXME: u u"semilong" ; usl + ("-n" "ṉ") ; nsmac + ("\\.a" "ȧ") ; a with dot above ; adot + ("\\.c" "ċ") ; cdot + ("\\.h" "ḥ") ; hsdot + ("\\.m" "ṃ") ; msdot + ("\\.u" "ụ") ; usdot + ("\\.z" "ẓ") ; zsdot + ("Eth" "Ð") ; EDH + ("eth" "ð") ; edh + ("thorn" "þ") ; thorn + ("~a" "ã") ; atil + ("~e" "ẽ") ; etil + ("itil" "ĩ") + ("otil" "õ") + ("util" "ũ") + ("~n" "ñ") ; ntil + ("Atil" "Ã") + ("Etil" "Ẽ") + ("Itil" "Ĩ") + ("Otil" "Õ") + ("Util" "Ũ") + ("~N" "Ñ") ; Ntil + ("\\.n" "ṅ") ; ndot + ("\\.r" "ṛ") ; rsdot + ("yogh" "ȝ") ; yogh + ("deg" "°") + ("middot" "•") + ("root" "√") + ;; Greek letters + ("alpha" "α") + ("beta" "β") + ("gamma" "γ") + ("delta" "δ") + ("epsilon" "ε") + ("zeta" "ζ") + ("eta" "η") + ("theta" "θ") + ("iota" "ι") + ("approx" "κ") ; ap + ("lambda" "λ") + ("mu" "μ") + ("nu" "ν") + ("xi" "ξ") + ("omicron" "ο") + ("pi" "π") + ("rho" "ρ") + ("sigma" "σ") + ("sigmat" "ς") + ("tau" "τ") + ("upsilon" "υ") + ("phi" "φ") + ("chi" "χ") + ("psi" "ψ") + ("omega" "ω") + ("digamma" "ϝ") + ("ALPHA" "Α") + ("BETA" "Β") + ("Gamma" "Γ") ; GAMMA + ("Delta" "Δ") ; DELTA + ("EPSILON" "Ε") + ("ZETA" "Ζ") + ("ETA" "Η") + ("Theta" "Θ") ; THETA + ("IOTA" "Ι") + ("KAPPA" "Κ") + ("Lambda" "Λ") ; LAMBDA + ("MU" "Μ") + ("NU" "Ν") + ("XI" "Ξ") + ("Omicron" "Ο") ; OMICRON + ("Pi" "Π") ; PI + ("RHO" "Ρ") + ("Sigma" "Σ") ; SIGMA + ("Tau" "Τ") ; TAU + ("Upsilon" "Υ") ; UPSILON + ("PHI" "Φ") + ("Chi" "Χ") ; CHI + ("PSI" "Ψ") + ("Omega" "Ω") ; OMEGA + ;; FIXME: Vowels with a double dot below. There`s nothing suitable in the Unicode + ("add" "a") + ("udd" "u") + ("ADD" "A") + ("UDD" "U") + ;; Quotes + ("dagger" "†") + ("dag" "†") + ("u\\^" "§") ; par + ("and" "and") + ("or" "or") + ("sec" "˝") + ("[,C]" "Ç") + ("\"u" "ü") ; uum + ("'e" "é") ; eacute + ("\\^a" "â") ; acir + ("\"a" "ä") ; aum + ("`a" "à") ; agrave + ("\\*a" "å") ; aring + ("\\*u" "ů") ; uring + (",c" "ç") ; ccedil + ("cced" "ç") + ("\\^e" "ê") ; ecir + ("\"e" "ë") ; eum + ("`e" "è") ; egrave + ("\"i" "ï") ; ium + ("\\^i" "î") ; icir + ("`i" "ì") ; igrave + ("\"A" "Ä") ; Aum + ("\\*A" "Å") ; Aring + ("'E" "È") ; Eacute + ("ae" "æ") ; ae + ("AE" "Æ") ; AE + ("\\^o" "ô") ; ocir + ("\"o" "ö") ; oum + ("`o" "ò") ; ograve + ("'o" "ó") ; oacute + ("Oacute" "Ó") + ("\\^u" "û") ; ucir + ("`u" "ù") ; ugrave + ("'u" "ú") ; uacute + ("\"y" "ÿ") ; yum + ("\"O" "Ö") ; Oum + ("\"U" "Ü") + ("pound" "£") + ("'a" "á") ; aacute + ("'i" "í") ; iacute + ("frac23" "⅔") + ("frac13" "⅓") + ("frac12" "½") + ("frac14" "¼") + ;; ("\\?" "�") ; Place-holder for unknown or illegible character. + ("hand" "☞") ; pointing hand (printer's u"fist") ; hand ; and + ("sect" "§") ; sect + ("=a" "ā") ; amac + ("ng" "ṉ") ; u"n sub-macron" ; nsm + ("sharp" "♯") ; sharp + ("flat" "♭") ; flat + ("th" "th") ; th + ("=i" "ī") ; imac + ("=e" "ē") ; emac + ("\\.d" "ḍ") ; Sanskrit/Tamil d dot + ("\\.n" "ṇ") ; Sanskrit/Tamil n dot ; nsdot + ("\\.t" "ṭ") ; Sanskrit/Tamil t dot ; tsdot + ("a\\^" "ă") ; acr + ("e\\^" "ĕ") ; ecr + ("i\\^" "ĭ") ; icr + ("o\\^" "ŏ") ; ocr + ("!o" "ǒ") + ("OE" "Œ") ; OE + ("oe" "œ") ; oe + ("=O" "Ō") ; Omac + ("=o" "ō") ; omac + ("=u" "ū") ; umac + ("ocar" "ǒ") ; o hacek + ("=ae" "ǣ") ; aemac + ("u\\^" "ŭ") ; ucr + ("a\\^" "ă") + ("=y" "ȳ") ; ymac + ("asl" "a") ; FIXME: a u"semilong" (has a macron above with a short + ("-e" "e") ; FIXME: e u"semilong" ; esl + ("-i" "i") ; FIXME: i u"semilong" ; isl + ("-o" "o") ; FIXME: o u"semilong" ; osl + ("-u" "u") ; FIXME: u u"semilong" ; usl + ("-n" "ṉ") ; nsmac + ("\\.a" "ȧ") ; a with dot above ; adot + ("\\.c" "ċ") ; cdot + ("\\.h" "ḥ") ; hsdot + ("\\.m" "ṃ") ; msdot + ("\\.u" "ụ") ; usdot + ("\\.z" "ẓ") ; zsdot + ("Eth" "Ð") ; EDH + ("eth" "ð") ; edh + ("thorn" "þ") ; thorn + ("~a" "ã") ; atil + ("~e" "ẽ") ; etil + ("itil" "ĩ") + ("otil" "õ") + ("util" "ũ") + ("~n" "ñ") ; ntil + ("Atil" "Ã") + ("Etil" "Ẽ") + ("Itil" "Ĩ") + ("Otil" "Õ") + ("Util" "Ũ") + ("~N" "Ñ") ; Ntil + ("\\.n" "ṅ") ; ndot + ("\\.r" "ṛ") ; rsdot + ("yogh" "ȝ") ; yogh + ("deg" "°") + ("middot" "•") + ("root" "√") + ;; Greek letters + ("alpha" "α") + ("beta" "β") + ("gamma" "γ") + ("delta" "δ") + ("epsilon" "ε") + ("zeta" "ζ") + ("eta" "η") + ("theta" "θ") + ("iota" "ι") + ("approx" "κ") ; ap + ("lambda" "λ") + ("mu" "μ") + ("nu" "ν") + ("xi" "ξ") + ("omicron" "ο") + ("pi" "π") + ("rho" "ρ") + ("sigma" "σ") + ("sigmat" "ς") + ("tau" "τ") + ("upsilon" "υ") + ("phi" "φ") + ("chi" "χ") + ("psi" "ψ") + ("omega" "ω") + ("digamma" "ϝ") + ("ALPHA" "Α") + ("BETA" "Β") + ("Gamma" "Γ") ; GAMMA + ("Delta" "Δ") ; DELTA + ("EPSILON" "Ε") + ("ZETA" "Ζ") + ("ETA" "Η") + ("Theta" "Θ") ; THETA + ("IOTA" "Ι") + ("KAPPA" "Κ") + ("Lambda" "Λ") ; LAMBDA + ("MU" "Μ") + ("NU" "Ν") + ("XI" "Ξ") + ("Omicron" "Ο") ; OMICRON + ("Pi" "Π") ; PI + ("RHO" "Ρ") + ("Sigma" "Σ") ; SIGMA + ("Tau" "Τ") ; TAU + ("Upsilon" "Υ") ; UPSILON + ("PHI" "Φ") + ("Chi" "Χ") ; CHI + ("PSI" "Ψ") + ("Omega" "Ω") ; OMEGA + ;; FIXME: Vowels with a double dot below. There`s nothing suitable in the Unicode + ("add" "a") + ("udd" "u") + ("ADD" "A") + ("UDD" "U") + ;; Quotes + ("dagger" "†") + ("dag" "†") + ("u\\^" "§") ; par + ("and" "and") + ("or" "or") + ("times" "×") + ("sec" "˝")))) + (setq pronunciation + (replace-regexp-in-string + "\\.\\.\\." "…" + (replace-regexp-in-string + "\\*\\*\\*\\*\\*\\*\\*\\*" "✶" + pronunciation))) + (dolist (dcrt diacritics) + (setq pronunciation (replace-regexp-in-string + (concat "\\[" (car dcrt) "\\]") + (cadr dcrt) + pronunciation t))) + pronunciation)) + +(defun lexic-format-reflow-text (text max-width &optional min-width initial-colunm indent sepregex) + "Add newlines as required to ensure that TEXT never exceeds MAX-WIDTH columns. + +Can also set a MIN-WIDTH for new lines of text created by a line break, +an INITIAL-COLUNM that the text starts at, and an INDENT string to be inserted +after every line break. + +When regex SEPREGEX is provided, it is used to detect word separators. +It is \"[ ,.]\" by default." + (let* ((initial-col (or initial-colunm 0)) + (min-width (or min-width 1)) + (indent (or indent "")) + (sepregex (or sepregex "[ ,.]")) + (line-regex (format "\\(\\`.\\{%d,%d\\}\\(?:%s\\(?:.\\{1,%d\\}\\'\\)?\\|\\'\\)\\|.\\{%d\\}\\)\\(.*\\)" + min-width (- max-width (length indent)) + sepregex min-width (- max-width (length indent)))) + reflowed-text) + (setq text (replace-regexp-in-string "[[:space:]]+" " " text)) + (setq text + (if (> initial-col max-width) + (replace-regexp-in-string "\\` " "" text) + (replace-regexp-in-string + (format "\\`.\\{%d,%d\\}%s\\(?:.\\{1,%d\\}\\'\\)?\\|\\`" + (min min-width (- max-width initial-col)) (- max-width initial-col) + sepregex min-width) + (lambda (match) + (setq reflowed-text match) + "") + text))) + (while (not (string-empty-p text)) + (setq text + (if (<= (length text) max-width) + (progn (setq reflowed-text (concat reflowed-text + (unless (string-empty-p reflowed-text) + (concat "\n" indent)) + text)) "") + (replace-regexp-in-string + line-regex + (lambda (match) + (setq reflowed-text (concat reflowed-text "\n" indent (match-string 1 match))) + (match-string 2 match)) + text)))) + reflowed-text)) + +(defun lexic-format-online-etym (entry &optional _expected-word) + "Make an html ENTRY look nice. +Designed for an export of Douglas Harper's Online Etymology Dictionary, +collected using https://framagit.org/tuxor1337/dictmaster." + (thread-last + (string-join + (delq nil + (mapcar + (lambda (e) + (when (string= (plist-get e :dict) + (plist-get entry :dict)) + (plist-get e :info))) + (lexic-parse-results + (lexic-oneshot-lookup + (replace-regexp-in-string " ?(.*)" " (*)" (plist-get entry :word)) ; lexic accepts a glob + t (list "-0" "-u" (plist-get entry :dict))))))) + (replace-regexp-in-string + "\\(?:\\`\\|\n\n\\)<b>\\(.+?\\) (\\(.+?\\)\\([0-9]+\\)?)</b> ?" + (lambda (match) + (let ((word (match-string 1 match)) + (pos (lexic-format-expand-abbreviations (match-string 2 match))) + (index (match-string 3 match))) + (concat "\n\n\u200B\u200B\u200B" + (propertize word 'face 'bold) + " " + (propertize pos 'face '(bold font-lock-keyword-face)) + (when index + (propertize (concat " " index) 'face '(italic font-lock-doc-face))) + "\u2008\n\n")))) + (replace-regexp-in-string + "<i>\\(.*?\\)</i>" + (lambda (match) (propertize (match-string 1 match) 'face 'italic))) + (replace-regexp-in-string + "<b>\\(.*?\\)</b>" + (lambda (match) (propertize (match-string 1 match) 'face 'bold))) + (replace-regexp-in-string + "<strong>\\(.*?\\)</strong>" + (lambda (match) (propertize (match-string 1 match) 'face 'font-lock-constant-face))) + (replace-regexp-in-string + "<a href=\".*?\">\\(.*?\\)</a>" + (lambda (match) (propertize (match-string 1 match) 'face 'font-lock-keyword-face))) + (replace-regexp-in-string + "<span style=\".*?\">\\(.*?\\)</span>" + (lambda (match) (propertize (match-string 1 match) 'face 'font-lock-doc-face))) + (replace-regexp-in-string + "[0-9]\\{4\\}s?\\|[0-9]+c\\." + (lambda (match) (propertize match 'face 'font-lock-string-face))) + (replace-regexp-in-string + "<span>\\(.*?\\)</span>\\( (.+?)\\)?" + (lambda (match) + (let ((linked (match-string 1 match)) + (pos (lexic-format-expand-abbreviations (match-string 2 match)))) + (concat + (propertize linked 'face 'font-lock-keyword-face) + (when pos (propertize (replace-regexp-in-string "\\([0-9]+\\))" " \\1)" pos) + 'face '(bold diff-context))))))) + (replace-regexp-in-string + "<blockquote>\\(.+?\\) ?\\[\\(.+\\)\\]</blockquote>" + (lambda (match) + (concat "❝" + (propertize + (lexic-format-reflow-text + (match-string 1 match) 80 5 1 " ") + 'face 'diff-context) + "❞\n" + (propertize (concat " ──" + (lexic-format-reflow-text (match-string 2 match) + 75 5 3 " ")) + 'face '(italic font-lock-type-face))))) + (replace-regexp-in-string "<br/>\n?<br/>" "\n") + (replace-regexp-in-string + "<p>\\(.*?\\)</p>" + (lambda (match) + (concat + (lexic-format-reflow-text (match-string 1 match) + 80 5) + "\n"))) + (replace-regexp-in-string "</?p>" "") ; any straggling pars + (replace-regexp-in-string + "^.\\{86,\\}" + (lambda (match) + (lexic-format-reflow-text match 80 5))))) + +(defun lexic-format-element (entry &optional _expected-word) + "Make an ENTRY for an element Look nice. +Based on http://download.huzheng.org/dict.org/stardict-dictd_www.dict.org_elements-2.4.2.tar.bz2." + (replace-regexp-in-string + "^\\([a-z]+\\) +Symbol: \\([A-Za-z]+\\) +Atomic number: \\([0-9]+\\) +Atomic weight: \\((?[0-9.]+)?\\)" + (lambda (match) + (let ((element (match-string 1 match)) + (symbol (match-string 2 match)) + (number (match-string 3 match)) + (weight (match-string 4 match))) + (format + "┌────────────────┐ +│ %-3s %10s │ +│ %s %11s │ +└────────────────┘ +" + (propertize number 'face 'font-lock-function-name-face) + (propertize weight 'face 'font-lock-comment-face) + (propertize symbol 'face '(bold font-lock-keyword-face)) + (propertize element 'face 'font-lock-string-face)))) + (plist-get entry :info))) + +(defun lexic-format-soule (entry &optional _expected-word) + "Format an ENTRY for WORD in Soule's Dictionary of English Synonyms. +Designed using http://download.huzheng.org/bigdict/stardict-Soule_s_Dictionary_of_English_Synonyms-2.4.2.tar.bz2." + (thread-last (plist-get entry :info) + (replace-regexp-in-string ; categories + "^\\([IVX]+\\. \\)?\\([a-z.;& ]+\\)" + (lambda (match) + (concat + "\u200B\u200B\u200B" + (when case-fold-search + (propertize + 'face '(bold font-lock-constant-face))) + (propertize (lexic-format-expand-abbreviations (match-string 2 match)) + 'face '(bold font-lock-keyword-face)) + "\u2008"))) + (replace-regexp-in-string + "^\\([0-9]+\\.\\) \n\\([^,.]*,?\\)" + (lambda (match) + (concat + "\u200B\u200B\u200B\u200B" + (propertize (match-string 1 match) + 'face '(bold font-lock-string-face)) + " " + (match-string 2 match) + "\u2008"))) + (replace-regexp-in-string + "^\\(.\\{81\\}\\)" + (lambda (match) + (lexic-format-reflow-text match 80 1 0 " " "[, ]"))) + (replace-regexp-in-string + "," + (propertize "," 'face 'font-lock-type-face)))) + +;;;###autoload +(defun lexic-dictionary-help () + "Show the Lexic help page." + (interactive) + (let ((dict-help-buf (get-buffer-create "*lexic-dict-help*"))) + (with-current-buffer dict-help-buf + (setq buffer-read-only t) + (with-silent-modifications + (erase-buffer) + (insert "#+title: Lexic Dictionary Help +#+author: TEC + +* sdcv + +First you want to make sure you have the *stardict* CLI tool =sdcv=. +It should be available in [[https://repology.org/project/sdcv/versions][many package repositories]] under that name. + +Not that by itself =sdcv= does not come with any dictionaries, you'll need to install those yourself. + +* Downloading dictionaries + +You can find quite a few dictionaries on http://download.huzheng.org/dict.org/ +and http://download.huzheng.org/bigdict/. By default, Lexic will provide nice +formatting for some of these. Namely: + +| Dictionary | Recognised ~bookname~ | +|------------------------+------------------------------------------------| +| [[http://download.huzheng.org/dict.org/stardict-dictd-web1913-2.4.2.tar.bz2.][Webster 1913]] | =Webster's Revised Unabridged Dictionary (1913)= | +| [[http://download.huzheng.org/dict.org/stardict-dictd_www.dict.org_elements-2.4.2.tar.bz2][Elements]] | =Elements database= | +| Hitchcock's Bible Name | =Hitchcock's Bible Names Dictionary= | +| Online Etymology | =Online Etymology Dictionary= | +| [[http://download.huzheng.org/bigdict/stardict-Soule_s_Dictionary_of_English_Synonyms-2.4.2.tar.bz2][Soule's Synonyms]] | =Soule's Dictionary of English Synonyms= | + +The stardict form of the /Online Etymology Dictionary/ can be created by running +[[https://framagit.org/tuxor1337/dictmaster][dictmaster]]. Unfortunately I do not know of any nice hosted result of this. + +* Installing dictionaries + +By default =sdcv= will look for dictionaries in =$HOME/.stardict/dic=, (do take note +of the =dic= part of the path) but this can be changed by setting environment +variable =STARDICT_DATA_DIR=. + +I recommend creating a folder for each dictionary in =STARDICT_DATA_DIR=, for +example: + +#+begin_example +$STARDICT_DATA_DIR +├── elements +│   └── ... +├── etymology +│   └── ... +├── hitchcock +│   └── ... +├── synonyms +│   ├── SoulesSynonyms.dict.dz +│   ├── SoulesSynonyms.idx +│   └── SoulesSynonyms.ifo +└── webster +    └── ... +#+end_example + +A particular dictionary is composed of a few files: ++ =DICT.dict.dz= ++ =DICT.idx= ++ =DICT.ifo= + +For our purposes, we only care about the =.ifo= (info) file. It should look +something like this. +#+begin_example +StarDict's dict ifo file +version=2.4.2 +wordcount=160161 +idxfilesize=3024035 +bookname=Webster's Revised Unabridged Dictionary (1913) +description=Connoisseur's reference to American English +date=2007.8.28 +sametypesequence=m +#+end_example + +We are particularly interested in the ~bookname=~ line, as if you have one of the +[[Downloading dictionaries][recognised dictionaries]] in order to get the nice formatting you need to set the +~bookname~ to the recognised value. + +* Using Lexic + +Once you have =sdcv= and some dictionaries installed, just go ahead and try =M-x +lexic-search= 🙂.")) + (goto-char (point-min)) + (org-mode) + (set-transient-map special-mode-map t)) + (switch-to-buffer-other-window dict-help-buf))) + +(provide 'lexic) +;;; lexic.el ends here diff --git a/elpa/web-mode-17.3.1.signed b/elpa/web-mode-17.3.1.signed @@ -0,0 +1 @@ +Good signature from 066DAFCB81E42C40 GNU ELPA Signing Agent (2019) <elpasign@elpa.gnu.org> (trust undefined) created at 2022-08-19T23:05:05+0200 using RSA +\ No newline at end of file diff --git a/elpa/web-mode-17.3.1/.github/CONTRIBUTING.md b/elpa/web-mode-17.3.1/.github/CONTRIBUTING.md @@ -0,0 +1,9 @@ +# Contributing to Web-Mode + +Things that might be useful in your report + +* an accurate description of the issue +* an example on gist (a screenshot of the code is a bad idea because it can not be copy/paste) +* the output of ```M-x web-mode-debug``` +* lines in the * *Messages* * buffer related to the issue (if they exist) +* a screenshot (if needed) diff --git a/elpa/web-mode-17.3.1/.github/FUNDING.yml b/elpa/web-mode-17.3.1/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: fxbois +custom: ["https://www.paypal.me/fxbois"] diff --git a/elpa/web-mode-17.3.1/README-elpa b/elpa/web-mode-17.3.1/README-elpa @@ -0,0 +1,16 @@ +web-mode.el +========= + +web-mode.el is an emacs major mode for editing **web templates** aka HTML files embedding parts (CSS/JavaScript) and blocks (pre rendered by client/server side engines). + +web-mode.el is compatible with many template engines: PHP, JSP, ASP, Django, Twig, Jinja, Mustache, ERB, FreeMarker, Velocity, Cheetah, Smarty, CTemplate, Mustache, Blade, ErlyDTL, Go Template, Dust.js, Google Closure (soy), React/JSX, Angularjs, ejs, Nunjucks, etc. + +More infos on https://web-mode.org/ + +![ScreenShot](http://web-mode.org/web-mode.png?v=5) + +[![paypal.me](https://web-mode.org/images/PayPal.svg)](https://www.paypal.me/fxbois) + +[![MELPA](http://melpa.org/packages/web-mode-badge.svg)](http://melpa.org/#/web-mode) + +[![MELPA Stable](http://stable.melpa.org/packages/web-mode-badge.svg)](http://stable.melpa.org/#/web-mode) diff --git a/elpa/web-mode-17.3.1/README.md b/elpa/web-mode-17.3.1/README.md @@ -0,0 +1,16 @@ +web-mode.el +========= + +web-mode.el is an emacs major mode for editing **web templates** aka HTML files embedding parts (CSS/JavaScript) and blocks (pre rendered by client/server side engines). + +web-mode.el is compatible with many template engines: PHP, JSP, ASP, Django, Twig, Jinja, Mustache, ERB, FreeMarker, Velocity, Cheetah, Smarty, CTemplate, Mustache, Blade, ErlyDTL, Go Template, Dust.js, Google Closure (soy), React/JSX, Angularjs, ejs, Nunjucks, etc. + +More infos on https://web-mode.org/ + +![ScreenShot](http://web-mode.org/web-mode.png?v=5) + +[![paypal.me](https://web-mode.org/images/PayPal.svg)](https://www.paypal.me/fxbois) + +[![MELPA](http://melpa.org/packages/web-mode-badge.svg)](http://melpa.org/#/web-mode) + +[![MELPA Stable](http://stable.melpa.org/packages/web-mode-badge.svg)](http://stable.melpa.org/#/web-mode) diff --git a/elpa/web-mode-17.3.1/web-mode-autoloads.el b/elpa/web-mode-17.3.1/web-mode-autoloads.el @@ -0,0 +1,32 @@ +;;; web-mode-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*- +;; Generated by the `loaddefs-generate' function. + +;; This file is part of GNU Emacs. + +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + + +;;; Generated autoloads from web-mode.el + +(autoload 'web-mode "web-mode" "\ +Major mode for editing web templates. + +(fn)" t nil) +(register-definition-prefixes "web-mode" '("web-mode-")) + +;;; End of scraped data + +(provide 'web-mode-autoloads) + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8-emacs-unix +;; End: + +;;; web-mode-autoloads.el ends here diff --git a/elpa/web-mode-17.3.1/web-mode-pkg.el b/elpa/web-mode-17.3.1/web-mode-pkg.el @@ -0,0 +1,2 @@ +;; Generated package description from web-mode.el -*- no-byte-compile: t -*- +(define-package "web-mode" "17.3.1" "major mode for editing web templates" '((emacs "23.1")) :commit "38ed4c575939083487e8abe59240d0ce4f671c93" :authors '(("François-Xavier Bois")) :maintainer '("François-Xavier Bois" . "fxbois@gmail.com") :keywords '("languages") :url "https://web-mode.org") diff --git a/elpa/web-mode-17.3.1/web-mode.el b/elpa/web-mode-17.3.1/web-mode.el @@ -0,0 +1,14723 @@ +;;; web-mode.el --- major mode for editing web templates -*- coding: utf-8; lexical-binding: t; -*- + +;; Copyright 2011-2022 François-Xavier Bois + +;; Version: 17.3.1 +;; Author: François-Xavier Bois +;; Maintainer: François-Xavier Bois <fxbois@gmail.com> +;; Package-Requires: ((emacs "23.1")) +;; URL: https://web-mode.org +;; Repository: http://github.com/fxbois/web-mode +;; Created: July 2011 +;; Keywords: languages +;; License: GNU General Public License >= 3 +;; Distribution: This file is not part of Emacs + +;;; Commentary: + +;;============================================================================== +;; WEB-MODE is sponsored by ** Kernix ** Best Digital Agency & Data Lab (Paris) +;;============================================================================== + +;;; Code: + +;;---- CONSTS ------------------------------------------------------------------ + +(defconst web-mode-version "17.3.1" + "Web Mode version.") + +;;---- GROUPS ------------------------------------------------------------------ + +(defgroup web-mode nil + "Major mode for editing web templates" + :group 'languages + :prefix "web-" + :link '(url-link :tag "Site" "https://web-mode.org") + :link '(url-link :tag "Repository" "https://github.com/fxbois/web-mode")) + +(defgroup web-mode-faces nil + "Faces for syntax highlighting." + :group 'web-mode + :group 'faces) + +;;---- CUSTOMS ----------------------------------------------------------------- + +(defcustom web-mode-block-padding 0 + "Multi-line block (php, ruby, java, python, asp, etc.) left padding. + -1 to have to code aligned on the column 0." + :type '(choice (integer :tags "Number of spaces") + (const :tags "No indent" nil)) + :group 'web-mode) + +(defcustom web-mode-part-padding 1 + "Part elements (script, style) left padding." + :type '(choice (integer :tags "Number of spaces") + (const :tags "No indent" nil)) + :group 'web-mode) + +(defcustom web-mode-script-padding web-mode-part-padding + "Script element left padding." + :type '(choice (integer :tags "Number of spaces") + (const :tags "No indent" nil)) + :group 'web-mode) + +(defcustom web-mode-style-padding web-mode-part-padding + "Style element left padding." + :type '(choice (integer :tags "Number of spaces") + (const :tags "No indent" nil)) + :group 'web-mode) + +(defcustom web-mode-attr-indent-offset nil + "Html attribute indentation level." + :type '(choice (integer :tags "Number of spaces") + (const :tags "Default" nil)) + :safe #'(lambda (v) (or (integerp v) (booleanp v))) + :group 'web-mode) + +(defcustom web-mode-attr-value-indent-offset nil + "Html attribute value indentation level." + :type '(choice (integer :tags "Number of spaces") + (const :tags "Default" nil)) + :safe #'(lambda (v) (or (integerp v) (booleanp v))) + :group 'web-mode) + +(defcustom web-mode-markup-indent-offset + (if (and (boundp 'standard-indent) standard-indent) standard-indent 2) + "Html indentation level." + :type 'integer + :safe #'integerp + :group 'web-mode) + +(defcustom web-mode-css-indent-offset + (if (and (boundp 'standard-indent) standard-indent) standard-indent 2) + "CSS indentation level." + :type 'integer + :safe #'integerp + :group 'web-mode) + +(defcustom web-mode-code-indent-offset + (if (and (boundp 'standard-indent) standard-indent) standard-indent 2) + "Code (javascript, php, etc.) indentation level." + :type 'integer + :safe #'integerp + :group 'web-mode) + +(defcustom web-mode-sql-indent-offset 4 + "Sql (inside strings) indentation level." + :type 'integer + :safe #'integerp + :group 'web-mode) + +(defcustom web-mode-enable-css-colorization (display-graphic-p) + "In a CSS part, set background according to the color: #xxx, rgb(x,x,x)." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-comment-interpolation nil + "Enable highlight of keywords like FIXME, TODO, etc. in comments." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-comment-annotation nil + "Enable annotation in comments (jsdoc, phpdoc, etc.)." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-auto-indentation (display-graphic-p) + "Auto-indentation." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-auto-closing (display-graphic-p) + "Auto-closing." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-auto-pairing (display-graphic-p) + "Auto-pairing." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-auto-opening (display-graphic-p) + "Html element auto-opening." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-auto-quoting (display-graphic-p) + "Add double quotes after the character = in a tag." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-auto-expanding nil + "e.g. s/ expands to <span>|</span>." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-curly-brace-indentation nil + "Indent lines beginning with {." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-control-block-indentation t + "Control blocks increase indentation." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-current-element-highlight nil + "Enable current element highlight." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-current-column-highlight nil + "Show column for current element." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-whitespace-fontification nil + "Enable whitespaces." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-html-entities-fontification nil + "Enable html entities fontification." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-block-face nil + "Enable block face (useful for setting a background for example). +See web-mode-block-face." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-part-face nil + "Enable part face (useful for setting background of <style> or <script> + elements for example). See web-mode-part-face." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-inlays nil + "Enable inlays (e.g. LaTeX) highlighting." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-sexp-functions t + "Enable specific sexp functions." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-string-interpolation t + "Enable string interpolation fontification (php and erb)." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-literal-interpolation t + "Enable template literal fontification. e.g. css` `." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-sql-detection nil + "Enable fontification and indentation of sql queries in strings." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-heredoc-fontification t + "Enable heredoc fontification. The identifier should contain JS, JAVASCRIPT, CSS or HTML." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-element-content-fontification nil + "Enable element content fontification. The content of an element can have a face associated." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-element-tag-fontification nil + "Enable tag name fontification." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-front-matter-block nil + "Enable front matter block (data at the beginning the template between --- and ---)." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-engine-detection nil + "Detect such directive -*- engine: ENGINE -*- at the top of the file." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-enable-optional-tags nil + "Enable omission of certain closing tags (e.g. a li open tag followed by a li open tag is valid)." + :type 'boolean + :group 'web-mode) + +(defcustom web-mode-comment-style 1 + "Comment style : 1 = default, 2 = force server comments outside a block." + :group 'web-mode + :type '(choice (const :tag "Default" 1) + (const :tag "Force engine comments" 2))) + +(defcustom web-mode-indent-style 2 + "Indentation style." + :group 'web-mode + :type '(choice (const :tag "Default (all lines are indented)" 2) + (const :tag "Text at the beginning of line is not indented" 1))) + +(defcustom web-mode-auto-close-style 1 + "Auto-close style." + :group 'web-mode + :type '(choice (const :tag "Auto-close on </" 1) + (const :tag "Auto-close on > and </" 2) + (const :tag "Auto-close on < and >/>" 3))) + +(defcustom web-mode-auto-quote-style 1 + "Auto-quoting style." + :group 'web-mode + :type '(choice (const :tag "Auto-quotes with double quote" 1) + (const :tag "Auto-quotes with single quote" 2) + (const :tag "Auto-quotes with paren (for jsx)" 3))) + +(defcustom web-mode-extra-expanders '() + "A list of additional expanders." + :type '(alist :key-type string :value-type string) + :group 'web-mode) + +(defcustom web-mode-extra-auto-pairs '() + "A list of additional auto-pairs." + :type '(alist :key-type string :value-type string) + :group 'web-mode) + +(defcustom web-mode-extra-snippets '() + "A list of additional snippets." + :type '(alist :key-type string :value-type string) + :group 'web-mode) + +(defcustom web-mode-extra-builtins '() + "A list of additional builtins." + :type '(alist :key-type string :value-type string) + :group 'web-mode) + +(defcustom web-mode-extra-constants '() + "A list of additional constants." + :type '(alist :key-type string :value-type string) + :group 'web-mode) + +(defcustom web-mode-extra-keywords '() + "A list of additional keywords." + :type '(alist :key-type string :value-type string) + :group 'web-mode) + +(defcustom web-mode-extra-types '() + "A list of additional types." + :type '(alist :key-type string :value-type string) + :group 'web-mode) + +(defcustom web-mode-extra-control-blocks '() + "A list of additional control blocks." + :type '(alist :key-type string :value-type (repeat string)) + :group 'web-mode) + +(defcustom web-mode-tests-directory (concat default-directory "tests/") + "Directory containing all the unit tests." + :type 'directory + :group 'web-mode) + +(defcustom web-mode-jsx-depth-faces + nil + ;;'(web-mode-jsx-depth-1-face web-mode-jsx-depth-2-face web-mode-jsx-depth-3-face web-mode-jsx-depth-4-face web-mode-jsx-depth-5-face) + "Each jsx depth has is own face." + :type '(repeat face) + :group 'web-mode) + +(defcustom web-mode-commands-like-expand-region + '(web-mode-mark-and-expand er/expand-region mc/mark-next-like-this mc/mark-previous-like-this) + "Add commmand here if you have some wrapper function for er/expand-region" + :type '(repeat function) + :group 'web-mode) + +(defcustom web-mode-comment-formats + '(("java" . "/*") + ("javascript" . "/*") + ("typescript" . "//") + ("php" . "/*") + ("css" . "/*")) + "Default comment format for a language" + :type '(alist :key-type string :value-type string) + :group 'web-mode) + +(defcustom web-mode-script-template-types + '("text/x-handlebars" + "text/x-jquery-tmpl" + "text/x-jsrender" + "text/html" + "text/ng-template" + "text/x-template" + "text/mustache" + "text/x-dust-template") + "<script> block types that are interpreted as HTML." + :type '(repeat string) + :group 'web-mode) + +;; https://developer.mozilla.org/en-US/docs/Web/HTML/Element +(defcustom web-mode-tag-list + '("html" "base" "head" "link" "meta" "style" "title" "body" "address" + "article" "aside" "footer" "header" "h1" "h2" "h3" "h4" "h5" "h6" "main" + "nav" "section" "blockquote" "dd" "div" "dl" "dt" "figcaption" "figure" + "hr" "li" "menu" "ol" "p" "pre" "ula" "a" "abbr" "b" "bdi" "bdo" "br" + "cite" "code" "data" "dfn" "em" "i" "kbdmark" "q" "rp" "rt" "ruby" "s" + "samp" "small" "span" "strong" "sub" "sup" "time" "u" "var" "wbr" "area" + "audio" "img" "map" "track" "video" "embed" "iframe" "object" "picture" + "portal" "source" "svg" "math" "canvas" "noscript" "script" "del" "ins" + "caption" "col" "colgroup" "table" "tbody" "td" "tfoot" "th" "thead" "tr" + "button" "datalist" "fieldset" "form" "input" "label" "legend" "meter" + "optgroup" "option" "output" "progress" "select" "textarea" "details" + "dialog" "summary" "slot" "template") + "HTML tags used for completion." + :type '(repeat string) + :group 'web-mode) + + +;; https://www.w3schools.com/tags/ref_attributes.asp +;; Attributes marked as deprecated in HTML 5 are not added. +(defcustom web-mode-attribute-list + '("accept" "accesskey" "action" "alt" "async" "autocomplete" "autofocus" + "autoplay" "charset" "checked" "cite" "class" "cols" "colspan" "content" + "contenteditable" "controls" "coords" "data" "datetime" "default" "defer" + "dir" "dirname" "disabled" "download" "draggable" "enctype" "for" "form" + "formaction" "headers" "height" "hidden" "high" "href" "hreflang" "http" + "id" "ismap" "kind" "label" "lang" "list" "loop" "low" "max" "maxlength" + "media" "method" "min" "multiple" "muted" "name" "novalidate" "onabort" + "onafterprint" "onbeforeprint" "onbeforeunload" "onblur" "oncanplay" + "oncanplaythrough" "onchange" "onclick" "oncontextmenu" "oncopy" + "oncuechange" "oncut" "ondblclick" "ondrag" "ondragend" "ondragenter" + "ondragleave" "ondragover" "ondragstart" "ondrop" "ondurationchange" + "onemptied" "onended" "onerror" "onfocus" "onhashchange" "oninput" + "oninvalid" "onkeydown" "onkeypress" "onkeyup" "onload" "onloadeddata" + "onloadedmetadata" "onloadstart" "onmousedown" "onmousemove" "onmouseout" + "onmouseover" "onmouseup" "onmousewheel" "onoffline" "ononline" + "onpagehide" "onpageshow" "onpaste" "onpause" "onplay" "onplaying" + "onpopstate" "onprogress" "onratechange" "onreset" "onresize" "onscroll" + "onsearch" "onseeked" "onseeking" "onselect" "onstalled" "onstorage" + "onsubmit" "onsuspend" "ontimeupdate" "ontoggle" "onunload" + "onvolumechange" "onwaiting" "onwheel" "open" "optimum" "pattern" + "placeholder" "poster" "preload" "readonly" "rel" "required" "reversed" + "rows" "rowspan" "sandbox" "scope" "selected" "shape" "size" "sizes" + "span" "spellcheck" "src" "srcdoc" "srclang" "srcset" "start" "step" + "style" "tabindex" "target" "title" "translate" "type" "usemap" "value" + "width" "wrap") + "HTML attributes used for completion." + :type '(repeat string) + :group 'web-mode) + +;;---- FACES ------------------------------------------------------------------- + +(defface web-mode-error-face + '((t :background "red")) + "Face for warning." + :group 'web-mode-faces) + +(defface web-mode-warning-face + '((t :inherit font-lock-warning-face)) + "Face for warning." + :group 'web-mode-faces) + +(defface web-mode-preprocessor-face + '((t :inherit font-lock-preprocessor-face)) + "Face for preprocessor commands." + :group 'web-mode-faces) + +(defface web-mode-preprocessor-face + '((t :inherit font-lock-preprocessor-face)) + "Face for preprocessor." + :group 'web-mode-faces) + +(defface web-mode-block-delimiter-face + '((t :inherit font-lock-preprocessor-face)) + "Face for block delimiters." + :group 'web-mode-faces) + +(defface web-mode-block-control-face + '((t :inherit font-lock-preprocessor-face)) + "Face for preprocessor." + :group 'web-mode-faces) + +(defface web-mode-builtin-face + '((t :inherit font-lock-builtin-face)) + "Face for builtins." + :group 'web-mode-faces) + +(defface web-mode-symbol-face + '((t :foreground "goldenrod2")) + "Face for symbols." + :group 'web-mode-faces) + +(defface web-mode-doctype-face + '((t :foreground "Grey")) + "Face for html doctype." + :group 'web-mode-faces) + +(defface web-mode-html-tag-face + '((((class color) (min-colors 88) (background dark)) :foreground "Snow4") + (((class color) (min-colors 88) (background light)) :foreground "Snow4") + (((class color) (min-colors 16) (background dark)) :foreground "Snow4") + (((class color) (min-colors 16) (background light)) :foreground "Grey15") + (((class color) (min-colors 8)) :foreground "Snow4") + (((type tty) (class mono)) :inverse-video t) + (t :foreground "Snow4")) + "Face for html tags." + :group 'web-mode-faces) + +(defface web-mode-html-tag-custom-face + '((t :inherit web-mode-html-tag-face)) + "Face for html custom tags (e.g. <polymer-element>)." + :group 'web-mode-faces) + +(defface web-mode-html-tag-unclosed-face + '((t :inherit web-mode-html-tag-face :underline t)) + "Face for unclosed tags." + :group 'web-mode-faces) + +(defface web-mode-html-tag-namespaced-face + '((t :inherit web-mode-block-control-face)) + "Face for html namespaced tags (e.g. <c:forEach>)." + :group 'web-mode-faces) + +(defface web-mode-html-tag-bracket-face + '((((class color) (min-colors 88) (background dark)) :foreground "Snow3") + (((class color) (min-colors 88) (background light)) :foreground "Grey14") + (((class color) (min-colors 16) (background dark)) :foreground "Snow3") + (((class color) (min-colors 16) (background light)) :foreground "Grey14") + (((class color) (min-colors 8)) :foreground "Snow3") + (((type tty) (class mono)) :inverse-video t) + (t :foreground "Snow3")) + "Face for html tags angle brackets (<, > and />)." + :group 'web-mode-faces) + +(defface web-mode-html-attr-name-face + '((((class color) (min-colors 88) (background dark)) :foreground "Snow3") + (((class color) (min-colors 88) (background light)) :foreground "Snow4") + (((class color) (min-colors 16) (background dark)) :foreground "Snow3") + (((class color) (min-colors 16) (background light)) :foreground "Grey13") + (((class color) (min-colors 8)) :foreground "Snow3") + (((type tty) (class mono)) :inverse-video t) + (t :foreground "Snow4")) + "Face for html attribute names." + :group 'web-mode-faces) + +(defface web-mode-html-attr-custom-face + '((t :inherit web-mode-html-attr-name-face)) + "Face for custom attribute names (e.g. data-*)." + :group 'web-mode-faces) + +(defface web-mode-html-attr-engine-face + '((t :inherit web-mode-block-delimiter-face)) + "Face for custom engine attribute names (e.g. ng-*)." + :group 'web-mode-faces) + +(defface web-mode-html-attr-equal-face + '((t :inherit web-mode-html-attr-name-face)) + "Face for the = character between name and value." + :group 'web-mode-faces) + +(defface web-mode-html-attr-value-face + '((t :inherit font-lock-string-face)) + "Face for html attribute values." + :group 'web-mode-faces) + +(defface web-mode-block-attr-name-face + '((t :foreground "#8fbc8f")) + "Face for block attribute names." + :group 'web-mode-faces) + +(defface web-mode-block-attr-value-face + '((t :foreground "#5f9ea0")) + "Face for block attribute values." + :group 'web-mode-faces) + +(defface web-mode-variable-name-face + '((t :inherit font-lock-variable-name-face)) + "Face for variable names." + :group 'web-mode-faces) + +(defface web-mode-css-selector-face + '((t :inherit font-lock-keyword-face)) + "Face for CSS rules." + :group 'web-mode-faces) + +(defface web-mode-css-selector-class-face + '((t :inherit font-lock-keyword-face)) + "Face for CSS class rules." + :group 'web-mode-faces) + +(defface web-mode-css-selector-tag-face + '((t :inherit font-lock-keyword-face)) + "Face for CSS tag rules." + :group 'web-mode-faces) + +(defface web-mode-css-pseudo-class-face + '((t :inherit font-lock-builtin-face)) + "Face for CSS pseudo-classes." + :group 'web-mode-faces) + +(defface web-mode-css-at-rule-face + '((t :inherit font-lock-constant-face)) + "Face for CSS at-rules." + :group 'web-mode-faces) + +(defface web-mode-css-property-name-face + '((t :inherit font-lock-variable-name-face)) + "Face for CSS props." + :group 'web-mode-faces) + +(defface web-mode-css-color-face + '((t :inherit font-lock-builtin-face)) + "Face for CSS colors (#xxx)." + :group 'web-mode-faces) + +(defface web-mode-css-priority-face + '((t :inherit font-lock-builtin-face)) + "Face for CSS priority (!important)." + :group 'web-mode-faces) + +(defface web-mode-css-function-face + '((t :inherit font-lock-builtin-face)) + "Face for CSS functions." + :group 'web-mode-faces) + +(defface web-mode-css-variable-face + '((t :inherit web-mode-variable-name-face :slant italic)) + "Face for CSS vars." + :group 'web-mode-faces) + +(defface web-mode-function-name-face + '((t :inherit font-lock-function-name-face)) + "Face for function names." + :group 'web-mode-faces) + +(defface web-mode-filter-face + '((t :inherit font-lock-function-name-face)) + "Face for function names." + :group 'web-mode-faces) + +(defface web-mode-function-call-face + '((t :inherit font-lock-function-name-face)) + "Face for function calls." + :group 'web-mode-faces) + +(defface web-mode-string-face + '((t :inherit font-lock-string-face)) + "Face for strings." + :group 'web-mode-faces) + +(defface web-mode-block-string-face + '((t :inherit web-mode-string-face)) + "Face for block strings." + :group 'web-mode-faces) + +(defface web-mode-part-string-face + '((t :inherit web-mode-string-face)) + "Face for part strings." + :group 'web-mode-faces) + +(defface web-mode-javascript-string-face + '((t :inherit web-mode-string-face)) + "Face for javascript strings." + :group 'web-mode-faces) + +(defface web-mode-interpolate-color1-face + '((t :inherit web-mode-string-face)) + "Face for element interpolation strings." + :group 'web-mode-faces) + +(defface web-mode-interpolate-color2-face + '((t :inherit web-mode-string-face)) + "Face for element interpolation strings." + :group 'web-mode-faces) + +(defface web-mode-interpolate-color3-face + '((t :inherit web-mode-string-face)) + "Face for element interpolation strings." + :group 'web-mode-faces) + +(defface web-mode-css-string-face + '((t :inherit web-mode-string-face)) + "Face for css strings." + :group 'web-mode-faces) + +(defface web-mode-json-key-face + '((t :foreground "plum")) + "Face for json key strings." + :group 'web-mode-faces) + +(defface web-mode-json-context-face + '((t :foreground "orchid3")) + "Face for json context strings." + :group 'web-mode-faces) + +(defface web-mode-json-string-face + '((t :inherit web-mode-string-face)) + "Face for json strings." + :group 'web-mode-faces) + +(defface web-mode-comment-face + '((t :inherit font-lock-comment-face)) + "Face for comments." + :group 'web-mode-faces) + +(defface web-mode-block-comment-face + '((t :inherit web-mode-comment-face)) + "Face for server comments." + :group 'web-mode-faces) + +(defface web-mode-part-comment-face + '((t :inherit web-mode-comment-face)) + "Face for part comments." + :group 'web-mode-faces) + +(defface web-mode-json-comment-face + '((t :inherit web-mode-comment-face)) + "Face for json comments." + :group 'web-mode-faces) + +(defface web-mode-javascript-comment-face + '((t :inherit web-mode-comment-face)) + "Face for javascript comments." + :group 'web-mode-faces) + +(defface web-mode-css-comment-face + '((t :inherit web-mode-comment-face)) + "Face for css comments." + :group 'web-mode-faces) + +(defface web-mode-annotation-face + '((t :inherit web-mode-comment-face)) + "Face for code annotations." + :group 'web-mode-faces) + +(defface web-mode-annotation-tag-face + '((t :inherit web-mode-annotation-face :underline t)) + "Face for @tags in code annotations." + :group 'web-mode-faces) + +(defface web-mode-annotation-type-face + '((t :inherit web-mode-annotation-face :weight bold)) + "Face for types in code annotations." + :group 'web-mode-faces) + +(defface web-mode-annotation-value-face + '((t :inherit web-mode-annotation-face :slant italic)) + "Face for values in code annotations." + :group 'web-mode-faces) + +(defface web-mode-annotation-html-face + '((t :inherit web-mode-annotation-face :slant italic)) + "Face for HTML tags in code annotations." + :group 'web-mode-faces) + +(defface web-mode-constant-face + '((t :inherit font-lock-constant-face)) + "Face for language constants." + :group 'web-mode-faces) + +(defface web-mode-type-face + '((t :inherit font-lock-type-face)) + "Face for language types." + :group 'web-mode-faces) + +(defface web-mode-keyword-face + '((t :inherit font-lock-keyword-face)) + "Face for language keywords." + :group 'web-mode-faces) + +(defface web-mode-param-name-face + '((t :foreground "Snow3")) + "Face for server attribute names." + :group 'web-mode-faces) + +(defface web-mode-whitespace-face + '((t :background "DarkOrchid4")) + "Face for whitespaces." + :group 'web-mode-faces) + +(defface web-mode-inlay-face + '((((class color) (min-colors 88) (background dark)) :background "Black") + (((class color) (min-colors 88) (background light)) :background "LightYellow1") + (((class color) (min-colors 16) (background dark)) :background "Brey18") + (((class color) (min-colors 16) (background light)) :background "LightYellow1") + (((class color) (min-colors 8)) :background "Black") + (((type tty) (class mono)) :inverse-video t) + (t :background "Grey")) + "Face for inlays. Must be used in conjunction with web-mode-enable-inlays." + :group 'web-mode-faces) + +(defface web-mode-block-face + '((((class color) (min-colors 88) (background dark)) :background "Black") + (((class color) (min-colors 88) (background light)) :background "LightYellow1") + (((class color) (min-colors 16) (background dark)) :background "Grey18") + (((class color) (min-colors 16) (background light)) :background "LightYellow1") + (((class color) (min-colors 8)) :background "Black") + (((type tty) (class mono)) :inverse-video t) + (t :background "Grey")) + "Face for blocks (useful for setting a background for example). +Must be used in conjunction with web-mode-enable-block-face." + :group 'web-mode-faces) + +(defface web-mode-part-face + '((t :inherit web-mode-block-face)) + "Face for parts." + :group 'web-mode-faces) + +(defface web-mode-script-face + '((t :inherit web-mode-part-face)) + "Face for javascript inside a script element." + :group 'web-mode-faces) + +(defface web-mode-style-face + '((t :inherit web-mode-part-face)) + "Face for css inside a style element." + :group 'web-mode-faces) + +(defface web-mode-folded-face + '((t :underline t)) + "Overlay face for folded." + :group 'web-mode-faces) + +(defface web-mode-bold-face + '((t :weight bold)) + "bold face." + :group 'web-mode-faces) + +(defface web-mode-italic-face + '((t :slant italic)) + "bold face." + :group 'web-mode-faces) + +(defface web-mode-underline-face + '((t :underline t)) + "bold face." + :group 'web-mode-faces) + +(defface web-mode-current-element-highlight-face + '((t :background "#000000" :foreground "#ffffff")) + "Overlay face for element highlight." + :group 'web-mode-faces) + +(defface web-mode-current-column-highlight-face + '((t :background "#3e3c36")) + "Overlay face for current column." + :group 'web-mode-faces) + +(defface web-mode-comment-keyword-face + '((t :weight bold :box t)) + "Comment keywords." + :group 'web-mode-faces) + +(defface web-mode-sql-keyword-face + '((t :weight bold :slant italic)) + "Sql keywords." + :group 'web-mode-faces) + +(defface web-mode-html-entity-face + '((t :slant italic)) + "Face html entities (e.g. &#8211;, &eacute;)." + :group 'web-mode-faces) + +;; https://material.io/tools/color/#!/?view.left=0&view.right=0 +(defface web-mode-jsx-depth-1-face + '((t :background "#000053")) + "jsx depth 1" + :group 'web-mode-faces) + +(defface web-mode-jsx-depth-2-face + '((t :background "#001970")) + "jsx" + :group 'web-mode-faces) + +(defface web-mode-jsx-depth-3-face + '((t :background "#002984")) + "jsx" + :group 'web-mode-faces) + +(defface web-mode-jsx-depth-4-face + '((t :background "#49599a")) + "jsx" + :group 'web-mode-faces) + +(defface web-mode-jsx-depth-5-face + '((t :background "#9499b7")) + "jsx" + :group 'web-mode-faces) + +;;---- VARS -------------------------------------------------------------------- + +(defvar font-lock-beg) +(defvar font-lock-end) + +(defvar web-mode-auto-pairs nil) +(defvar web-mode-block-regexp nil) +(defvar web-mode-change-beg nil) +(defvar web-mode-change-end nil) +(defvar web-mode-chunk-length 64) +(defvar web-mode-column-overlays nil) +(defvar web-mode-comments-invisible nil) +(defvar web-mode-content-type "") +(defvar web-mode-engine nil) +;;(defvar web-mode-engine-attr-regexp nil) +(defvar web-mode-engine-font-lock-keywords nil) +(defvar web-mode-engine-token-regexp nil) +(defvar web-mode-expand-initial-pos nil) +(defvar web-mode-expand-initial-scroll nil) +(defvar web-mode-expand-previous-state "") +;;(defvar web-mode-font-lock-keywords '(web-mode-font-lock-highlight)) +(defvar web-mode-skip-fontification nil) +(defvar web-mode-inlay-regexp nil) +(defvar web-mode-is-scratch nil) +(defvar web-mode-jshint-errors 0) +(defvar web-mode-minor-engine nil) +(defvar web-mode-obarray nil) +(defvar web-mode-overlay-tag-start nil) +(defvar web-mode-overlay-tag-end nil) +(defvar web-mode-part-beg nil) +(defvar web-mode-scan-beg nil) +(defvar web-mode-scan-end nil) +(defvar web-mode-snippets nil) +(defvar web-mode-time nil) + +(defvar web-mode-offsetless-elements + '()) + +(defvar web-mode-indentless-elements + '("code" "pre" "textarea")) + +(defvar web-mode-indentless-attributes + '("onclick" "onmouseover" "onmouseout" "onsubmit")) + +(defvar web-mode-void-elements + '("area" "base" "br" "col" "command" "embed" "hr" "img" "input" "keygen" + "link" "meta" "param" "source" "track" "wbr" "tmpl_var")) + +(defvar web-mode-part-content-types + '("css" "javascript" "json" "jsx" "markdown" "pug" "ruby" + "sass" "sql" "stylus" "typescript")) + +(defvar web-mode-javascript-languages '("javascript" "jsx" "ejs")) + +;; NOTE: without 'syntax-table forward-word fails (#377) +(defvar web-mode-scan-properties + (list 'tag-beg 'tag-end 'tag-name 'tag-type + 'tag-attr 'tag-attr-beg 'tag-attr-end + 'part-side 'part-token + 'jsx-beg 'jsx-end 'jsx-depth + 'block-side 'block-token 'block-controls 'block-beg 'block-end + 'syntax-table) + "Text properties used for code regions/tokens and html nodes.") + +(defvar web-mode-start-tag-regexp "<\\([[:alpha:]][[:alnum:].:_-]*\\|>\\)" + "Regular expression for HTML/XML start tag.") + +(defvar web-mode-tag-regexp "</?\\([[:alpha:]][[:alnum:].:_-]*\\)" + "Regular expression for HTML/XML tag.") + +(defvar web-mode-dom-regexp "<\\(/?>\\|/?[[:alpha:]][[:alnum:].:_-]*\\|!--\\|!\\[CDATA\\[\\|!doctype\\|!DOCTYPE\\|\?xml\\)") + +(defvar web-mode-whitespaces-regexp + "^[ \t]\\{2,\\}$\\| \t\\|\t \\|[ \t]+$\\|^[ \n\t]+\\'\\|^[ \t]?[\n]\\{2,\\}" + "Regular expression for whitespaces.") + +(defvar web-mode-imenu-regexp-list + '(("<\\(h[1-9]\\)\\([^>]*\\)>\\([^<]*\\)" 1 3 ">") + ("^[ \t]*<\\([@a-z]+\\)[^>]*>? *$" 1 "id=\"\\([a-zA-Z0-9_]+\\)\"" "#" ">")) + "Regexps to match imenu items (see https://web-mode.org/doc/imenu.txt)") + +;; https://www.gnu.org/software/emacs/manual/html_node/ccmode/Syntactic-Symbols.html +(defvar web-mode-indentation-params + '(("lineup-args" . t) + ("lineup-calls" . t) + ("lineup-concats" . t) + ("lineup-quotes" . t) + ("lineup-ternary" . t) + ("case-extra-offset" . t) + )) + +(defvar web-mode-tag-history nil) +(defvar web-mode-attribute-history nil) +(defvar web-mode-attribute-value-history nil) + +(defvar web-mode-engines + '(("angular" . ("angularjs")) + ("anki" . ()) + ("archibus" . ()) + ("artanis" . ()) + ("asp" . ()) + ("aspx" . ()) + ("blade" . ("laravel")) + ("cl-emb" . ()) + ("clip" . ()) + ("closure" . ("soy")) + ("ctemplate" . ("mustache" "handlebars" "hapax" "ngtemplate" "ember" + "kite" "meteor" "blaze" "ractive" "velvet")) + ("django" . ("dtl" "twig" "swig" "jinja" "jinja2" "erlydtl" "liquid" + "clabango" "selmer" "nunjucks")) + ("dust" . ("dustjs")) + ("ejs" . ()) + ("elixir" . ("phoenix")) + ("erb" . ("eruby" "erubis" "crystal")) + ("expressionengine" . ("ee")) + ("freemarker" . ()) + ("go" . ("gtl" "hugo")) + ("hero" . ()) + ("json-t" . ()) + ("jsp" . ("grails")) + ("mako" . ()) + ("marko" . ()) + ("mason" . ("poet")) + ("lsp" . ("lisp")) + ("mojolicious" . ()) + ("php" . ()) + ("python" . ()) + ("razor" . ("play" "play2")) + ("riot" . ()) + ("smarty" . ()) + ("spip" . ()) + ("svelte" . ("svelte")) + ("template-toolkit" . ()) + ("thymeleaf" . ()) + ("perl" . ()) + ("underscore" . ("underscore.js")) + ("velocity" . ("vtl" "cheetah" "ssp")) + ("vue" . ("vuejs" "vue.js")) + ("web2py" . ()) + ("xoops" . ()) + ) + "Engine name aliases") + +(defvar web-mode-content-types + '(("css" . "\\.\\(s?css\\|css\\.erb\\)\\'") + ("javascript" . "\\.\\([mc]?js\\|js\\.erb\\)\\'") + ("typescript" . "\\.\\(ts\\|ts\\.erb\\)\\'") + ("json" . "\\.\\(api\\|json\\|jsonld\\)\\'") + ("jsx" . "\\.[jt]sx\\'") + ("xml" . "\\.xml\\'") + ("html" . ".")) + "content types") + +(defvar web-mode-engine-attr-regexps + '(("angular" . "ng-") + ("thymeleaf" . "th:") + ("vue" . "v-")) + "Engine custom attributes") + +(defvar web-mode-engine-attr-regexp + "^ng[-]\\|^th[:]\\|^v[-]\\|^[@:#(\[*]" + "Engine custom attributes") + +(defvar web-mode-last-enabled-feature nil) + +(defvar web-mode-features + '(("css-colorization" . web-mode-enable-css-colorization) + ("element-highlight" . web-mode-enable-current-element-highlight) + ("column-highlight" . web-mode-enable-current-column-highlight) + ("whitespace-fontification" . web-mode-enable-whitespace-fontification) + ("element-tag-fontification" . web-mode-enable-element-tag-fontification) + ("block-face" . web-mode-enable-block-face) + ("part-face" . web-mode-enable-part-face))) + +(defvar web-mode-comment-prefixing t) + +(defvar web-mode-engine-file-regexps + '(("angular" . "\\.component.html\\'") + ("anki" . "\\.anki\\'") + ("archibus" . "\\.axvw\\'") + ("artanis" . "\\.html\\.tpl\\'") + ("asp" . "\\.asp\\'") + ("aspx" . "\\.as[cp]x\\'") + ("blade" . "\\.blade\\.php\\'") + ("cl-emb" . "\\.clemb\\'") + ("clip" . "\\.ctml\\'") + ("closure" . "\\.soy\\'") + ("ctemplate" . "\\.\\(chtml\\|mustache\\)\\'") + ("django" . "\\.\\(djhtml\\|tmpl\\|dtl\\|liquid\\|j2\\|njk\\)\\'") + ("dust" . "\\.dust\\'") + ("elixir" . "\\.[hl]?eex\\'") + ("ejs" . "\\.ejs\\'") + ("erb" . "\\.\\(erb\\|rhtml\\|erb\\.html\\|ecr\\)\\'") + ("expressionengine" . "\\.ee\\'") + ("freemarker" . "\\.ftl\\'") + ("go" . "\\.go\\(html\\|tmpl\\)\\'") + ("handlebars" . "\\.\\(hb\\.html\\|hbs\\)\\'") + ("hero" . "\\.hero\\'") + ("jinja" . "\\.jinja\\'") + ("jsp" . "\\.[gj]sp\\'") + ("lsp" . "\\.lsp\\'") + ("mako" . "\\.mako?\\'") + ("marko" . "\\.marko\\'") + ("mason" . "\\.mas\\'") + ("mojolicious" . "\\.epl?\\'") + ("perl" . "\\.\\(ptmpl\\|perl\\.html\\)\\'") + ("php" . "\\.\\(p[hs]p\\|ctp\\|inc\\)\\'") + ("python" . "\\.pml\\'") + ("razor" . "\\.\\(cs\\|vb\\)html\\|\\.razor\\'") + ("riot" . "\\.tag\\'") + ("smarty" . "\\.tpl\\'") + ("svelte" . "\\.svelte\\'") + ("template-toolkit" . "\\.tt.?\\'") + ("thymeleaf" . "\\.thtml\\'") + ("velocity" . "\\.v\\(sl\\|tl\\|m\\)\\'") + ("vue" . "\\.vue\\'") + ("xoops" . "\\.xoops'") + ;; regexp on the path, not just the extension + ("django" . "[st]wig") + ("razor" . "scala") + ("spip" . "spip") + ) + "Engine file extensions.") + +(defvar web-mode-content-types-alist nil + "A list of filename patterns and corresponding web-mode content types. For example, +(setq web-mode-content-types-alist + '((\"json\" . \"/some/path/.*\\.api\\'\") + (\"jsx\" . \"/some/react/path/.*\\.js[x]?\\'\")))") + +(defvar web-mode-engines-alist nil + "A list of filename patterns and corresponding web-mode engine. For example, +(setq web-mode-engines-alist + '((\"php\" . \"\\\\.phtml\\\\'\") + (\"blade\" . \"\\\\.blade\\\\.\")))") + +(defvar web-mode-smart-quotes + '("«" . "»") + "Preferred smart quotes") + +(defvar web-mode-xml-chars + '((?\& . "&amp;") + (?\< . "&lt;") + (?\> . "&gt;")) + "XML chars") + +(defvar web-mode-html-entities + ;; #985 + ;; remove ("gt" . 62) ("lt" . 60) ("amp" . 38) + '(("AElig" . 198) ("Aacute" . 193) ("Acirc" . 194) ("Agrave" . 192) + ("Alpha" . 913) ("Aring" . 197) ("Atilde" . 195) ("Auml" . 196) + ("Beta" . 914) + ("Ccedil" . 199) ("Chi" . 935) + ("Dagger" . 8225) ("Delta" . 916) + ("ETH" . 208) ("Eacute" . 201) ("Ecirc" . 202) ("Egrave" . 200) + ("Epsilon" . 917) ("Eta" . 919) ("Euml" . 203) + ("Gamma" . 915) + ("Iacute" . 205) ("Icirc" . 206) ("Igrave" . 204) ("Iota" . 921) + ("Iuml" . 207) + ("Kappa" . 922) + ("Lambda" . 923) + ("Mu" . 924) + ("Ntilde" . 209) ("Nu" . 925) + ("OElig" . 338) ("Oacute" . 211) ("Ocirc" . 212) ("Ograve" . 210) + ("Omega" . 937) ("Omicron" . 927) ("Oslash" . 216) ("Otilde" . 213) + ("Ouml" . 214) + ("Phi" . 934) ("Pi" . 928) ("Prime" . 8243) ("Psi" . 936) + ("Rho" . 929) + ("Scaron" . 352) ("Sigma" . 931) + ("THORN" . 222) ("Tau" . 932) ("Theta" . 920) + ("UArr" . 8657) ("Uacute" . 218) ("Uacute" . 250) ("Ucirc" . 219) + ("Ugrave" . 217) ("Upsih" . 978) + ("Upsilon" . 933) ("Uuml" . 220) ("Uuml" . 252) + ("Xi" . 926) + ("Yacute" . 221) ("Yuml" . 376) + ("Zeta" . 918) + ("aacute" . 225) ("acirc" . 226) ("acute" . 180) ("aelig" . 230) + ("agrave" . 224) ("alefsym" . 8501) ("alpha" . 945) + ("ang" . 8736) ("apos" . 39) ("aring" . 229) ("asymp" . 8776) + ("atilde" . 227) ("auml" . 228) + ("bdquo" . 8222) ("beta" . 946) ("brvbar" . 166) ("bull" . 8226) + ("cap" . 8745) ("ccedil" . 231) ("cedil" . 184) ("cent" . 162) + ("chi" . 967) ("circ" . 710) ("clubs" . 9827) ("cong" . 8773) + ("copy" . 169) ("crarr" . 8629) ("cup" . 8746) ("curren" . 164) + ("dArr" . 8659) ("dagger" . 8224) ("darr" . 8595) ("deg" . 176) + ("delta" . 948) ("diams" . 9830) ("divide" . 247) + ("eacute" . 233) ("ecirc" . 234) ("egrave" . 232) ("empty" . 8709) + ("emsp" . 8195) ("ensp" . 8194) ("epsilon" . 949) ("equiv" . 8801) + ("eta" . 951) ("eth" . 240) ("euml" . 235) ("euro" . 8364) ("exist" . 8707) + ("fnof" . 402) ("forall" . 8704) ("frac12" . 189) ("frac14" . 188) + ("frac34" . 190) ("frasl" . 8260) + ("gamma" . 947) ("ge" . 8805) + ("hArr" . 8660) ("harr" . 8596) ("hearts" . 9829) ("hellip" . 8230) + ("iacute" . 237) ("icirc" . 238) ("iexcl" . 161) ("igrave" . 236) + ("image" . 8465) ("infin" . 8734) ("int" . 8747) ("iota" . 953) + ("iquest" . 191) ("isin" . 8712) ("iuml" . 239) + ("kappa" . 954) + ("lArr" . 8656) ("lambda" . 955) ("lang" . 9001) ("laquo" . 171) + ("larr" . 8592) ("lceil" . 8968) ("ldquo" . 8220) ("le" . 8804) + ("lfloor" . 8970) ("lowast" . 8727) ("loz" . 9674) ("lrm" . 8206) + ("lsaquo" . 8249) ("lsquo" . 8249) + ("macr" . 175) ("mdash" . 8212) ("micro" . 181) ("middot" . 183) + ("minus" . 8722) ("mu" . 956) + ("nabla" . 8711) ("nbsp" . 160) ("ndash" . 8211) ("ne" . 8800) + ("ni" . 8715) ("not" . 172) ("notin" . 8713) ("nsub" . 8836) + ("ntilde" . 241) ("nu" . 957) ("oacute" . 243) ("ocirc" . 244) + ("oelig" . 339) ("ograve" . 242) ("oline" . 8254) ("omega" . 969) + ("omicron" . 959) ("oplus" . 8853) ("or" . 8744) ("ordf" . 170) + ("ordm" . 186) ("oslash" . 248) ("otilde" . 245) ("otimes" . 8855) + ("ouml" . 246) + ("para" . 182) ("part" . 8706) ("permil" . 8240) ("perp" . 8869) + ("phi" . 966) ("pi" . 960) ("piv" . 982) ("plusmn" . 177) ("pound" . 163) + ("prime" . 8242) ("prod" . 8719) ("prop" . 8733) ("psi" . 968) + ("quot" . 34) + ("rArr" . 8658) ("radic" . 8730) ("rang" . 9002) ("raquo" . 187) + ("rarr" . 8594) ("rceil" . 8969) ("rdquo" . 8221) ("real" . 8476) + ("reg" . 174) ("rfloor" . 8971) ("rho" . 961) ("rlm" . 8207) + ("rsaquo" . 8250) ("rsquo" . 8250) ("sbquo" . 8218) + ("scaron" . 353) ("sdot" . 8901) ("sect" . 167) ("shy" . 173) + ("sigma" . 963) ("sigmaf" . 962) ("sim" . 8764) ("spades" . 9824) + ("sub" . 8834) ("sube" . 8838) ("sum" . 8721) ("sup" . 8835) + ("sup1" . 185) ("sup2" . 178) ("sup3" . 179) ("supe" . 8839) + ("szlig" . 223) + ("tau" . 964) ("there4" . 8756) ("theta" . 952) ("thetasym" . 977) + ("thinsp" . 8201) ("thorn" . 254) ("tilde" . 732) ("times" . 215) + ("trade" . 8482) + ("uarr" . 8593) ("ucirc" . 251) ("ugrave" . 249) ("uml" . 168) + ("upsilon" . 965) + ("weierp" . 8472) + ("xi" . 958) + ("yacute" . 253) ("yen" . 165) ("yuml" . 255) + ("zeta" . 950) ("zwj" . 8205) ("zwnj" . 8204))) + +;; http://webdesign.about.com/od/localization/l/blhtmlcodes-ascii.htm +(defvar web-mode-display-table + (let ((table (make-display-table))) + (aset table 9 (vector ?\xBB ?\t)) + (aset table 10 (vector ?\xB6 ?\n)) + (aset table 32 (vector ?\xB7)) + table) + "Display table used when switching to the whitespace visualization.") + +(defvar web-mode-expanders + '(("a/" . "<a href=\"|\"></a>") + ("b/" . "<table><tbody><tr><td>|</td><td></td></tr></tbody></table>") + ("c/" . "<div class=\"|\"></div>") + ("d/" . "<div>|</div>") + ("e/" . "<em>|</em>") + ("f/" . "<form>|</form>") + ("g/" . "<strong>|</strong>") + ("h/" . "<h1>|</h1>") + ("i/" . "<img src=\"|\" />") + ("j/" . "<script>|</script>") + ("l/" . "<li>|</li>") + ("m/" . "<main>|</main>") + ("n/" . "<input type=\"|\" />") + ("p/" . "<p>|</p>") + ("q/" . "<quote>|</quote>") + ("s/" . "<span>|</span>") + ("t/" . "<td>|</td>") + ("u/" . "<ul><li>|</li><li></li></ul>") + ("x/" . "<textarea>|</textarea>") + ("2/" . "<h2>|</h2>") + ("3/" . "<h3>|</h3>") + ("?/" . "<?php | ?>"))) + +(defvar web-mode-engines-auto-pairs + '(("angular" . (("{{ " . " }}"))) + ("anki" . (("{{ " . " }}"))) + ("artanis" . (("<% " . " %>") + ("<%=" . " | %>") + ("<@css" . " | %>") + ("<@icon" . " | %>") + ("<@include" . " | %>") + ("<@js" . " | %>"))) + ("asp" . (("<% " . " %>"))) + ("aspx" . (("<% " . " %>") + ("<%=" . "%>") + ("<%#" . "%>") + ("<%$" . "%>") + ("<%@" . "%>") + ("<%:" . "%>") + ("<%-" . "- | --%>"))) + ("blade" . (("{{{" . " | }}}") + ("{{ " . " }}") + ("{!!" . " | !!}") + ("@{{" . " | }}") + ("{{-" . "- | --}}"))) + ("cl-emb" . (("<% " . " %>") + ("<%=" . " | %>") + ("<%#" . " | %>"))) + ("ctemplate" . (("{{ " . "| }}") + ("{{~ " . "| }}") + ("{{{" . " | }}}") + ("{~{" . " | }}") + ("{{~{" . " | }}}") + ("{{!" . "-- | --}}") + ("{{^" . "}}") + ("{{/" . "}}") + ("{{#" . "}}"))) + ("django" . (("{{ " . " }}") + ("{% " . " %}") + ("{%-" . " | %}") + ("{# " . " #}"))) + ("elixir" . (("<% " . " %>") + ("<%=" . " | %>") + ("<%%" . " | %>") + ("<%#" . " | %>"))) + ("ejs" . (("<% " . " %>") + ("<%=" . "%>") + ("<%#" . "%>") + ("<%-" . "%>"))) + ("erb" . (("<% " . " %>") + ("<%=" . " %>") + ("<%#" . "%>") + ("<%-" . " %>"))) + ("freemarker" . (("<% " . " %>") + ("<#-" . "- | -->") + ("${ " . " }") + ("[% " . " %]") + ("[# " . " #]") + ("[#-" . "- | --]"))) + ("go" . (("{{ " . " }}") + ("{{-" . " | -}}"))) + ("hero" . (("<% " . " %>") + ("<%=" . " | %>") + ("<%!" . " | %>") + ("<%:" . " | %>") + ("<%#" . " | %>") + ("<%@" . " | %>") + ("<%~" . " | %>") + ("<%+" . " | %>"))) + ("jsp" . (("<% " . " %>") + ("<%-" . "- | --%>") + ("<%=" . "%>") + ("<%!" . "%>") + ("<%@" . "%>") + ("${ " . " }"))) + ("lsp" . (("<% " . " %>") + ("<%%" . " | %>") + ("<%#" . " | %>"))) + ("mako" . (("<% " . " %>") + ("<%!" . " | %>") + ("${ " . " }"))) + ("marko" . (("${ " . " }"))) + ("mason" . (("<% " . " %>") + ("<& " . " &>"))) + ("mojolicious" . (("<% " . " %>") + ("<%=" . " | %>") + ("<%%" . " | %>") + ("<%#" . " | %>"))) + ("php" . (("<?p" . "hp | ?>") + ("<? " . " ?>") + ("<?=" . "?>"))) + ("template-toolkit" . (("[% " . " %]") + ("[%-" . " | %]") + ("[%#" . " | %]"))) + ("riot" . (("={ " . " }"))) + ("underscore" . (("<% " . " %>"))) + ("vue" . (("{{ " . " }}"))) + ("web2py" . (("{{ " . " }}") + ("{{=" . "}}"))) + (nil . (("<!-" . "- | -->"))) + )) + +(defvar web-mode-engines-snippets + '(("artanis" . (("if" . "<% (if (|) %>\n\n<% ) %>") + ("when" . "<% (when (|) %>\n\n<% ) %>") + ("unless" . "<% (unless (|) %>\n\n<% ) %>") + ("cond" . "<% (cond %>\n<% [(|) %>\n\n<% ] %>\n<% [else %>\n\n<% ] %>\n<% ) %>") + ("let" . "<% (let ([|]) %>\n\n<% ) %>") + ("let*" . "<% (let* ([|]) %>\n\n<% ) %>") + ("do" . "<% (do ([|]) %>\n<% [()] %>\n\n<% ) %>") + ("for-each" . "<% (for-each %>\n|\n\n<% ) %>") + ("case" . "<% (case | %>\n<% [() %>\n\n<% ] %>\n<% [() %>\n\n<% ] %>\n<% ) %>"))) + ("ejs" . (("for" . "<% for (|) { %>\n\n<% } %>") + ("if" . "<% if (|) { %>\n\n<% } %>"))) + ("erb" . (("each" . "<% |.each do %>\n\n<% end %>") + ("if" . "<% if | %>\n\n<% end %>") + ("when" . "<% when | %>\n\n<% end %>") + ("unless" . "<% unless | %>\n\n<% end %>"))) + ("php" . (("if" . "<?php if (|): ?>\n\n<?php endif; ?>") + ("while" . "<?php while (|): ?>\n\n<?php endwhile; ?>") + ("for" . "<?php for (| ; ; ): ?>\n\n<?php endfor; ?>") + ("foreach" . "<?php foreach (| as ): ?>\n\n<?php endforeach; ?>") + ("each" . "<?php foreach (| as ): ?>\n\n<?php endforeach; ?>") + ("switch" . "<?php switch (|): ?>\n<?php case 1: ?>\n\n<?php break ;?>\n<?php case 2: ?>\n\n<?php break ;?>\n<?php endswitch;?>"))) + ("django" . (("block" . "{% block | %}\n\n{% endblock %}") + ("comment" . "{% comment | %}\n\n{% endcomment %}") + ("css" . "{% stylesheet %}\n\n{% endstylesheet %}") + ("cycle" . "{% cycle | as %}\n\n{% endcycle %}") + ("filter" . "{% filter | %}\n\n{% endfilter %}") + ("for" . "{% for | in %}\n\n{% endfor %}") + ("if" . "{% if | %}\n\n{% endif %}") + ("ifequal" . "{% ifequal | %}\n\n{% endifequal %}") + ("ifnotequal" . "{% ifnotequal | %}\n\n{% endifnotequal %}") + ("js" . "{% javascript | %}\n\n{% endjavascript %}") + ("schema" . "{% javascript | %}\n\n{% endschema %}") + ("safe" . "{% safe | %}\n\n{% endsafe %}"))) + ("mako" . (("if" . "% if |:\n% endif") + ("for" . "% for | in :\n% endfor") + ("doc" . "<%doc>\n|\n</%doc>") + ("inherit" . "<%inherit file=\"|\" />") + ("namespace" . "<%namespace name=\"|\" file=\"\" import=\"\"/>") + ("block" . "<%block name=\"|\">\n</%block>"))) + ("template-toolkit" . (("if" . "[% IF | %]\n\n[% END %]"))) + (nil . (("html5" . "<!doctype html>\n<html>\n<head>\n<title></title>\n<meta charset=\"utf-8\" />\n</head>\n<body>\n|\n</body>\n</html>") + ("table" . "<table><tbody>\n<tr>\n<td>|</td>\n<td></td>\n</tr>\n</tbody></table>") + ("ul" . "<ul>\n<li>|</li>\n<li></li>\n</ul>"))) + )) + +(defvar web-mode-engine-token-regexps + (list + '("artanis" . "\"\\|#|\\|;") + '("asp" . "//\\|/\\*\\|\"\\|''") + '("ejs" . "//\\|/\\*\\|\"\\|'") + '("erb" . "\"\\|'\\|#\\|<<[-]?['\"]?\\([[:alnum:]_]+\\)['\"]?") + '("lsp" . "\"\\|#|\\|;") + '("mako" . "\"\\|'\\|#") + '("mason" . "\"\\|'\\|#") + '("mojolicious" . "\"\\|'") + '("php" . "//\\|/\\*\\|#\\|\"\\|'\\|<<<['\"]?\\([[:alnum:]]+\\)['\"]?") + '("python" . "\"\\|'\\|#") + '("web2py" . "\"\\|'")) + "Engine regexps used to identify tokens (strings / comments) in blocks.") + +(defvar web-mode-engine-open-delimiter-regexps + (list + '("angular" . "{{") + '("anki" . "{{") + '("artanis" . "<%\\|<@\\(css\\|icon\\|include\\|js\\)") + '("asp" . "<%\\|</?[[:alpha:]]+:[[:alpha:]]+\\|</?[[:alpha:]]+Template") + '("aspx" . "<%.") + '("blade" . "{{.\\|{!!\\|@{{\\|@[[:alpha:]]") + '("cl-emb" . "<%") + '("closure" . "{.\\|/\\*\\| //") + '("clip" . "</?c:[[:alpha:]-]+") + '("ctemplate" . "[$]?{[{~].") + '("django" . "{[#{%]\\|^#") + '("dust" . "{.") + '("elixir" . "<%\\|</?[.:]") + '("ejs" . "<%") + '("erb" . "<%\\|^%.") + '("expressionengine" . "{.") + '("freemarker" . "<%\\|${\\|</?[[:alpha:]]+:[[:alpha:]]\\|</?[@#]\\|\\[/?[@#].") + '("go" . "{{.") + '("hero" . "<%") + '("jsp" . "<%\\|${") + '("lsp" . "<%") + '("mako" . "</?%\\|${\\|^[ \t]*%.\\|^[ \t]*##") + '("marko" . "${") + '("mason" . "</?[&%]\\|^%.") + '("mojolicious" . "<%\\|^[ \t]*%.") + '("perl" . "</?TMPL_[[:alpha:]]+") + '("php" . "<\\?") + '("python" . "<\\?") + '("razor" . "@.\\|^[ \t]*}") + '("riot" . "{.\\|/// begin script") + '("smarty" . "{[[:alpha:]#$/*\"]") + '("spip" . "\\[(#REM)\\|(\\|#[A-Z0-9_]\\|{\\|<:") + '("template-toolkit" . "\\[%\\(.\\|$\\)\\|%%#") + '("underscore" . "<%") + '("velocity" . "#[[:alpha:]#*]\\|$[[:alpha:]!{]") + '("vue" . "{{\\|[:@][-[:alpha:]]+=\"") + '("web2py" . "{{") + '("xoops" . "<{[[:alpha:]#$/*\"]") + '("svelte" . "{.") + ) + "Engine regexps used to identify blocks.") + +(defvar web-mode-normalization-rules + '(("tag-case" . "lower-case") + ("attr-case" . "lower-case") + ("special-chars" . "unicode") ;"unicode" "entities" + ("css-indentation" . t) + ("smart-apostrophes" . t) + ("smart-quotes" . t) + ("whitespaces" . t) + ("indentation" . t)) + "Normalization rules") + +(defvar web-mode-element-tag-faces + (list + '("h1" . web-mode-underline-face) + '("h2" . web-mode-underline-face) + '("h3" . web-mode-underline-face) + '("h4" . web-mode-underline-face) + '("title" . web-mode-underline-face) + '("em" . web-mode-italic-face) + '("strong" . web-mode-bold-face) + )) + +(defvar web-mode-element-content-faces + (list + '("h1" . web-mode-underline-face) + '("h2" . web-mode-underline-face) + '("h3" . web-mode-underline-face) + '("h4" . web-mode-underline-face) + '("title" . web-mode-underline-face) + '("em" . web-mode-italic-face) + '("strong" . web-mode-bold-face) + )) + +(defvar web-mode-comment-keywords + (regexp-opt + (append + (cdr (assoc "comment" web-mode-extra-keywords)) + '("FIXME" "TODO" "BUG" "KLUDGE" "WORKAROUND" "OPTIMIZE" "HACK" "REFACTOR" "REVIEW")))) + +(defvar web-mode-links + '(("\\.\\(png\\|jpe?g\\|gif\\|webp\\)$" "<img src=\"%s\" alt=\"\" />" nil 4) + ("\\.svg$" "<object data=\"%s\" type=\"image/svg+xml\"></object>" nil 0) + ("\\.js$" "<script type=\"text/javascript\" src=\"%s\"></script>" t 0) + ("\\.css$" "<link rel=\"stylesheet\" type=\"text/css\" href=\"%s\" />" t 0) + ("\\.html?$" "<a href=\"%s\"></a>" nil 4)) + "List of elements and extensions for `web-mode-file-link'. It +consists of a string that contains the regular expression that +matches the appropriate files, a format string with element that +contains the link (%s should be put where the path goes,) a bool +that tells if the element belongs in the <head> element, and +number of characters to move back if needed (or 0 if point +shouldn't be moved back.)") + +(defvar web-mode-sql-queries + (regexp-opt + '("SELECT" "INSERT" "UPDATE" "DELETE" "select" "insert" "update" "delete"))) + +(defvar web-mode-sql-keywords + (regexp-opt + (append + (cdr (assoc "sql" web-mode-extra-keywords)) + '("SELECT" "INSERT" "UPDATE" "DELETE" + "FROM" "WHERE" "GROUP BY" "LIKE" "LIMIT" "HAVING" "JOIN" "LEFT" "INNER" + "FULL" "OUTER" "VALUES" "ORDER BY" "SEPARATOR" "ASC" "DESC" + "AND" "OR" "ON" "WHEN" "ELSE" "END" "THEN")))) + +(defvar web-mode-python-constants + (regexp-opt + (append + (cdr (assoc "python" web-mode-extra-constants)) + '("True" "False" "None" "__debug__" "NotImplemented" "Ellipsis")))) + +(defvar web-mode-elixir-keywords + (regexp-opt + (append + (cdr (assoc "elixir" web-mode-extra-keywords)) + '("after" "and" "bc" "case" "catch" "cond" "defcallback" "defdelegate" "defexception" "defgaurdp" "defguard" "defimpl" "defmodule" "defoverridable" "defprotocol" "defrecord" "defrecordp" "defstruct" "do" "else" "end" "exit" "fn" "for" "form_for" "if" "in" "lc" "not" "or" "quote" "raise" "receive" "rescue" "super" "throw" "try" "unless" "unquote" "when" "with")))) + + +(defvar web-mode-elixir-constants + (regexp-opt + (append + (cdr (assoc "elixir" web-mode-extra-constants)) + '("nil" "true" "false")))) + +(defvar web-mode-erlang-constants + (regexp-opt + (append + (cdr (assoc "erlang" web-mode-extra-constants)) + '("true" "false")))) + +(defvar web-mode-erlang-keywords + (regexp-opt + (append + (cdr (assoc "erlang" web-mode-extra-keywords)) + '("else" "if" "do" "end")))) + +(defvar web-mode-cl-emb-constants + (regexp-opt + '("nil" "t" "raw" "escape"))) + +(defvar web-mode-cl-emb-keywords + (regexp-opt + '("if" "else" "endif" "unless" "endunless" "var" "repeat" + "endrepeat" "loop" "endloop" "include" "call" "with" + "endwith" "set" "genloop" "endgenloop" "insert"))) + +(defvar web-mode-artanis-constants + (regexp-opt + '("#f" "#t"))) + +(defvar web-mode-artanis-keywords + (regexp-opt + (append + (cdr (assoc "artanis" web-mode-extra-keywords)) + '("begin" "cut" "cute" "if" "when" "unless" "cond" "case" + "do" "quote" "syntax" "lambda" "lambda*" "and" "and-let*" + "or" "else" "delay" "receive" "use-modules" "match" + "match-lambda" "match-lambda*" "match-let" "match-let*" + "match-letrec" "let" "let*" "letrec" "letrec*" "and-let*" + "let-syntax" "letrec-syntax" "syntax-rules" "syntax-case" + "define" "define-syntax" "define-macro" + "define-condition-type" "define-immutable-record-type" + "define-record-type" "define-values" "parameterize" "for-each" + "require-extension" "set!" "test-approximate" "test-assert" + "test-begin" "test-end" "test-eq" "test-equal" "test-eqv" + "test-error" "test-group" "test-group-with-cleanup" "test-with-runner")))) + +(defvar web-mode-lsp-constants + (regexp-opt + '("nil" "t"))) + +(defvar web-mode-lsp-keywords + (regexp-opt + '("dolist" "let" "while" "cond" "when" "progn" "if" + "dotimes" "unless" "lambda" + "loop" "for" "and" "or" "in" "do" "defun"))) + +(defvar web-mode-php-constants + (regexp-opt + (append + (cdr (assoc "php" web-mode-extra-constants)) + '("TRUE" "FALSE" "NULL" "true" "false" "null" + "STR_PAD_LEFT" "STR_PAD_RIGHT" + "ENT_COMPAT" "ENT_QUOTES" "ENT_NOQUOTES" "ENT_IGNORE" + "ENT_SUBSTITUTE" "ENT_DISALLOWED" "ENT_HTML401" "ENT_XML1" + "ENT_XHTML" "ENT_HTML5" "JSON_PRETTY_PRINT" + "LIBXML_NOBLANKS")))) + +(defvar web-mode-php-keywords + (regexp-opt + (append + (cdr (assoc "php" web-mode-extra-keywords)) + '("abstract" "and" "array" "as" "break" "case" "catch" "class" "clone" + "const" "continue" "declare" "default" "die" "do" "echo" "else" "elseif" + "empty" "enddeclare" "endfor" "endforeach" "endif" "endswitch" "endwhile" + "eval" "exit" "extends" "final" "finally" "fn" "for" "foreach" "function" + "global" "goto" "if" "implements" "include" "include_once" "instanceof" + "insteadof" "interface" "isset" "list" "namespace" "new" "or" "parent" + "print" "private" "protected" "public" "require" "require_once" "return" + "self" "static" "switch" "trait" "try" "throw" "unset" "use" "var" + "while" "xor" "yield" "yield from")))) + +(defvar web-mode-php-types + (eval-when-compile + (regexp-opt + '("array" "bool" "boolean" "callable" "float" "int" "integer" + "iterable" "mixed" "object" "resource" "string" "void")))) + +(defvar web-mode-css-at-rules + (eval-when-compile + (regexp-opt + '("charset" "import" "media" "page" "font-face" + "namespace" "supports" "document" + "keyframes" "-moz-keyframes" "-webkit-keyframes" + "mixin" "viewport")))) + +(defvar web-mode-css-pseudo-classes + (eval-when-compile + (regexp-opt + '("active" "after" "before" "checked" "disabled" "empty" "enabled" + "first" "first-child" "first-letter" "first-line" "first-of-type" "focus" + "hover" "lang" "last-child" "last-of-type" "left" "link" + "not" "nth-child" "nth-last-child" "nth-last-of-type" "nth-of-type" + "only-child" "only-of-type" + "right" "root" "selection" "target" "visited")))) + +(defvar web-mode-python-keywords + (regexp-opt + (append + (cdr (assoc "python" web-mode-extra-keywords)) + '("and" "as" "assert" "break" "class" "continue" "def" "del" + "elif" "else" "except" "finally" "for" "from" "global" + "if" "import" "in" "is" "lambda" "nonlocal" "not" "or" "pass" + "raise" "return" "try" "while" "with" "yield")))) + +(defvar web-mode-jsp-keywords + (regexp-opt + (append + (cdr (assoc "jsp" web-mode-extra-keywords)) + '("case" "catch" "do" "else" "end" "false" "for" "function" + "if" "in" "include" + "new" "package" "page" "private" "protected" "public" + "return" "tag" "taglib" "throw" "throws" "true" "try" "void" "while")))) + +(defvar web-mode-erb-keywords + (regexp-opt + (append + (cdr (assoc "erb" web-mode-extra-keywords)) + '("alias" "and" "begin" "break" "case" "class" "def" "defined?" "do" + "elsif" "else" "end" "ensure" "fail" "for" "if" "in" + "module" "next" "not" "or" "redo" "rescue" "retry" "return" + "then" "super" "unless" "undef" "until" "when" "while" "yield" + "__ENCODING__" "__FILE__" "__LINE__")))) + +(defvar web-mode-mason-keywords + (regexp-opt + (append + (cdr (assoc "mason" web-mode-extra-keywords)) + '("and" "base" "close" "die" "each" "else" "elsif" "eval" "exists" + "foreach" "grep" "if" "length" "local" "my" "next" "open" "or" + "package" "pop" "ref" "return" "stat" "sub" "tie" + "undef" "unless" "use" "while")))) + +(defvar web-mode-erb-builtins + (regexp-opt + (append + (cdr (assoc "erb" web-mode-extra-builtins)) + + '("__callee__" "__dir__" "__method__" + "abort" "at_exit" "autoload" "autoload?" + "binding" "block_given?" "caller" "catch" + "eval" "exec" "exit" "exit!" "fail" "fork" "format" + "lambda" "load" "loop" "open" + "p" "print" "printf" "proc" "putc" "puts" + "raise" "rand" "readline" "readlines" "require" "require_relative" + "sleep" "spawn" "sprintf" "srand" "syscall" "system" + "throw" "trap" "warn" + "alias_method" "attr" "attr_accessor" "attr_reader" "attr_writer" + "define_method" "extend" "include" "module_function" + "prepend" "private" "protected" "public" + "refine" "using" + + "error_message_on" "error_messages_for" "form" "input" + "auto_discovery_link_tag" "image_tag" "javascript_include_tag" + "stylesheet_link_tag" "image_path" "path_to_image"" " + "javascript_path" "path_to_javascript" "register_javascript_expansion" + "register_javascript_include_default" "register_stylesheet_expansion" + "stylesheet_path" "path_to_stylesheet" "atom_feed" "entry" "updated" + "benchmark" "cache" "capture" "content_for" "distance_of_time_in_words" + "distance_of_time_in_words_to_now" "time_ago_in_words" "date_select" + "datetime_select" "time_select" "select_date" "select_datetime" + "select_day" "select_hour" "select_minute" "select_month" "select_second" + "select_time" "select_year" "debug" + "check_box" "fields_for" "file_field" "form_for" "hidden_field" + "label" "password_field" "radio_button" "text_area" "text_field" + "check_box_tag" "field_set_tag" "file_field_tag" "form_with" "form_tag" + "hidden_field_tag" "image_submit_tag" "label_tag" "password_field_tag" + "radio_button_tag" "select_tag" "submit_tag" "text_area_tag" + "text_field_tag" + "collection_select" "country_options_for_select" "country_select" + "option_groups_from_collection_for_select" "options_for_select" + "options_from_collection_for_select" "select" + "time_zone_options_for_select" + "time_zone_select" "button_to_function" "define_javascript_functions" + "escape_javascript" "javascript_tag" "link_to_function"" " + "number_to_currency" "number_to_human_size" "number_to_percentage" + "number_to_phone" "number_with_delimiter" "number_with_precision" + "evaluate_remote_response" "form_remote_for" "form_remote_tag" + "link_to_remote" "observe_field" "observe_field" + "periodically_call_remote" + "remote_form_for" "remote_function" "submit_to_remote" "update_page" + "update_page_tag" "dom_class" "dom_id" "partial_path" "sanitize" + "sanitize_css" "strip_links" "strip_tags" + "cdata_section" "content_tag" "escape_once" "tag" + "auto_link" "concat" "cycle" "excerpt" "highlight" "markdown" "pluralize" + "reset_cycle" "simple_format" "textilize" "textilize_without_paragraph" + "truncate" "word_wrap" "button_to" "current_page?" "link_to" "link_to_if" + "link_to_unless" "link_to_unless_current" "mail_to" "url_for" + "action_name" "atom_feed" "audio_path" "audio_tag" + "content_tag_for" "controller" "controller_name" "action_name" + "controller_path" "convert_to_model" "cookies" "csrf_meta_tag" + "csrf_meta_tags" "headers" + "current_cycle" "div_for" "email_field" "email_field_tag" + "favicon_link_tag" "flash" "l" "button_tag" + "grouped_collection_select" "grouped_options_for_select" + "image_alt" "j" "javascript_cdata_section" + "localize" "logger" "number_field" + "number_field_tag" "number_to_human" "params" "path_to_audio" + "path_to_video" "phone_field" "phone_field_tag" "provide" + "range_field" "range_field_tag" "raw" "render" "request" + "request_forgery_protection_token" "response" "safe_concat" + "safe_join" "search_field" "search_field_tag" + "session" "t" "telephone_field" "telephone_field_tag" + "time_tag" "translate" "url_field" "url_field_tag" + "url_options" "video_path" "video_tag" "simple_form_for" + "javascript_pack_tag" "stylesheet_pack_tag" "csp_meta_tag" + + )))) + +(defvar web-mode-asp-constants + (regexp-opt + (append + (cdr (assoc "asp" web-mode-extra-constants)) + '("adAsyncExecute" "adAsyncFetch" "adAsyncFetchNonBlocking" "adCmdFile" + "adCmdStoredProc" "adCmdTable" "adCmdTableDirect" "adCmdText" "adCmdUnknown" + "adCmdUnspecified" "adExecuteNoRecords" "adExecuteRecord" "adExecuteStream" + "adLockBatchOptimistic" "adLockOptimistic" "adLockPessimistic" + "adLockReadOnly" "adLockUnspecified" "adOpenDynamic" "adOpenForwardOnly" + "adOpenKeyset" "adOpenStatic" "adOpenUnspecified" "adOptionUnspecified" + "Empty" "Nothing" "Null" "True" "False" + "vbBack" "vbCr" "vbCrLf" "vbFormFeed" "vbLf" "vbNewLine" "vbNullChar" + "vbNullString" "vbObjectError" "vbScript" "vbTab" "vbVerticalTab")))) + +(defvar web-mode-asp-keywords + (regexp-opt + (append + (cdr (assoc "asp" web-mode-extra-keywords)) + '("Abs" "And" "Array" "Asc" "Atn" + "CBool" "CByte" "CCur" "CDate" "CDbl" "CInt" "CLng" "CSng" "CStr" + "Call" "Case" "Chr" "Class" "Const" "Cos" "CreateObject" + "Date" "DateAdd" "DateDiff" "DatePart" "DateSerial" "DateValue" + "Day" "Dim" "Do" + "Each" "Else" "ElseIf" "End" "Erase" "Err" "Eval" "Exit" "Exp" + "Explicit" + "Filter" "Fix" "For" "FormatCurrency" "FormatDateTime" + "FormatNumber" "FormatPercent" "Function" + "GetLocale" "GetObject" "GetRef" "Hex" "Hour" + "If" "In" "InStr" "InStrRev" "InputBox" "Int" "IsArray" "IsDate" + "IsEmpty" "IsNull" "IsNumeric" "IsObject" "Join" + "LBound" "LCase" "LTrim" "Language" "Left" "Len" "Let" + "LoadPicture" "Log" "Loop" + "Mid" "Minute" "Month" "MonthName" "MsgBox" + "New" "Next" "Not" "Now" + "Oct" "On" "Option" "Or" "Preserve" "Private" "Public" + "RGB" "RTrim" "Redim" "Rem" "Replace" "Right" "Rnd" "Round" + "ScriptEngine" "ScriptEngineBuildVersion" + "ScriptEngineMajorVersion" "ScriptEngineMinorVersion" + "Second" "Select" "Set" "SetLocale" "Sgn" "Sin" "Space" "Split" + "Sqr" "StrComp" "StrReverse" "String" "Sub" + "Tan" "Then" "Time" "TimeSerial" "TimeValue" "Timer" "To" "Trim" + "TypeName" + "UBound" "UCase" "Until" "VarType" + "Weekday" "WeekdayName" "Wend" "With" "While" "Year")))) + +(defvar web-mode-asp-types + (regexp-opt + (append + (cdr (assoc "asp" web-mode-extra-types)) + '("Application" "ASPError" "Request" "Response" "Server" "Session")))) + +(defvar web-mode-aspx-keywords + (regexp-opt + (append + (cdr (assoc "aspx" web-mode-extra-keywords)) + '("case" "catch" "do" "else" "end" "for" "foreach" "function" + "if" "in" "include" "new" "package" "page" "return" + "tag" "throw" "throws" "try" "while")))) + +(defvar web-mode-smarty-keywords + (regexp-opt '("as"))) + +(defvar web-mode-velocity-keywords + (eval-when-compile + (regexp-opt '("in" "true" "false")))) + +(defvar web-mode-freemarker-keywords + (eval-when-compile + (regexp-opt '("as" "list")))) + +(defvar web-mode-go-keywords + (eval-when-compile + (regexp-opt + '("const" "define" "else" "end" + "for" "func" "if" "import" + "pipeline" "range" "return" "struct" + "template" "type" "var" "with")))) + +(defvar web-mode-go-functions + (eval-when-compile + (regexp-opt + '("and" "call" "ge" "html" "index" "js" "len" "not" "or" + "print" "printf" "println" "urlquery" "where")))) + +(defvar web-mode-go-types + (regexp-opt + (append + (cdr (assoc "go" web-mode-extra-types)) + '("int" "string")))) + +(defvar web-mode-closure-keywords + (eval-when-compile + (regexp-opt '("in" "and" "not" "or")))) + +(defvar web-mode-svelte-keywords + (regexp-opt '("as"))) + +(defvar web-mode-django-control-blocks + (append + (cdr (assoc "django" web-mode-extra-control-blocks)) + '( + + "assets" "autoescape" + "block" "blocktrans" + "cache" "call" "capture" "comment" + "draw" + "embed" + "filter" "for" "foreach" "form" + "if" "ifchanged" "ifequal" "ifnotequal" + "macro" + "random" "raw" + "safe" "sandbox" "spaceless" + "tablerow" + "unless" + "verbatim" + "with" + + "endassets" "endautoescape" + "endblock" "endblocktrans" + "endcache" "endcall" "endcapture" "endcomment" + "draw" + "endembed" + "endfilter" "endfor" "endforeach" "endform" + "endif" "endifchanged" "endifequal" "endifnotequal" + "endmacro" + "endrandom" "endraw" + "endsafe" "endsandbox" "endspaceless" + "endtablerow" + "endunless" + "endverbatim" + "endwith" + + ;; "set" "endset" ;#504 + + "csrf_token" "cycle" "debug" + "elif" "else" "elseif" "elsif" "empty" "extends" + "firstof" "include" "load" "lorem" "now" "regroup" "ssi" + "trans" "templatetag" "url" "widthratio" + + ;; #805 + "graph" "endgraph" + "javascript" "endjavascript" + "schema" "endschema" + "stylesheet" "endstylesheet" + + ))) + +(defvar web-mode-django-control-blocks-regexp + (regexp-opt web-mode-django-control-blocks t)) + +(defvar web-mode-django-keywords + (eval-when-compile + (regexp-opt + '("and" "as" "assign" + "break" + "cache" "call" "case" "context" "continue" + "do" + "flush" "from" + "ignore" "import" "in" "is" + "layout" "load" + "missing" + "none" "not" + "or" + "pluralize" + "random" + "set" ;#504 + "unless" "use" + "var" + )))) + +(defvar web-mode-django-types + (eval-when-compile + (regexp-opt '("null" "false" "true")))) + +(defvar web-mode-blade-control-blocks + (append + (cdr (assoc "blade" web-mode-extra-control-blocks)) + '("component" "foreach" "forelse" "for" "if" "section" "slot" "switch" "unless" "while") + )) + +(defvar web-mode-blade-control-blocks-regexp + (regexp-opt web-mode-blade-control-blocks t)) + +(defvar web-mode-directives + (eval-when-compile + (regexp-opt + '("include" "page" "taglib" + "Assembly" "Control" "Implements" "Import" + "Master" "OutputCache" "Page" "Reference" "Register")))) + +(defvar web-mode-template-toolkit-keywords + (regexp-opt + '("block" "call" "case" "catch" "clear" "default" "do" + "else" "elsif" "end" "filter" "final" "for" + "foreach" "get" "if" "in" "include" "insert" "is" "last" + "macro" "meta" "or" "perl" "process" "rawperl" "return" + "set" "stop" "switch" "tags" "throw" "try" + "unless" "use" "while" "wrapper"))) + +(defvar web-mode-perl-keywords + (regexp-opt + '("__DATA__" "__END__" "__FILE__" "__LINE__" "__PACKAGE__" + "and" "cmp" "continue" "CORE" "do" "else" "elsif" "eq" "exp" + "for" "foreach" "ge" "gt" "if" "le" "lock" "lt" "m" "ne" "no" + "or" "package" "q" "qq" "qr" "qw" "qx" "s" "sub" + "tr" "unless" "until" "while" "xor" "y" + "my" "use" "print" "say"))) + +(defvar web-mode-javascript-keywords + (regexp-opt + (append + (cdr (assoc "javascript" web-mode-extra-keywords)) + '("as" "async" "await" "break" "case" "catch" "class" "const" "continue" + "debugger" "default" "delete" "do" "else" "enum" "eval" + "export" "extends" "finally" "for" "from" "function" "get" "if" + "implements" "import" "in" "instanceof" "interface" "let" + "new" "of" "package" "private" "protected" "public" + "return" "set" "static" "super" "switch" + "throw" "try" "type" "typeof" "var" "void" "while" "with" "yield")))) + +(defvar web-mode-javascript-constants + (regexp-opt + '("false" "null" "undefined" "Infinity" "NaN" "true" "arguments" "this"))) + +(defvar web-mode-razor-keywords + (regexp-opt + (append + (cdr (assoc "razor" web-mode-extra-keywords)) + '("false" "true" "foreach" "if" "else" "in" "var" "for" "display" + "match" "case" "to" + "Html")))) + +(defvar web-mode-selector-font-lock-keywords + (list + '("$[[:alnum:]-]+" 0 'web-mode-css-variable-face) + (cons (concat "@\\(" web-mode-css-at-rules "\\)\\_>") + '(0 'web-mode-css-at-rule-face)) + '("\\_<\\(all\|braille\\|embossed\\|handheld\\|print\\|projection\\|screen\\|speech\\|tty\\|tv\\|and\\|or\\)\\_>" + 1 'web-mode-keyword-face) + '("\\.[^ ,]+" 0 'web-mode-css-selector-class-face) + '("[^,]+" 0 'web-mode-css-selector-tag-face) + (cons (concat ":\\([ ]*[[:alpha:]][^,{]*\\)") '(0 'web-mode-css-pseudo-class-face t t)) + )) + +(defvar web-mode-declaration-font-lock-keywords + (list + '("--[[:alnum:]-]+" 0 'web-mode-css-variable-face) + '("$[[:alnum:]-]+" 0 'web-mode-css-variable-face) + (cons (concat "@\\(" web-mode-css-at-rules "\\)\\_>") '(1 'web-mode-css-at-rule-face)) + '("\\([[:alpha:]-]+\\)[ ]?:" 0 'web-mode-css-property-name-face) + '("\\([[:alpha:]-]+\\)[ ]?(" 1 'web-mode-css-function-face) + '("#[[:alnum:]]\\{1,6\\}" 0 'web-mode-css-color-face t t) + '("![ ]?important" 0 'web-mode-css-priority-face t t) + '("\\([^,]+\\)[ ]+{" 1 'web-mode-css-selector-face) + '("'[^']*'\\|\"[^\"]*\"" 0 'web-mode-string-face t t) + )) + +(defvar web-mode-html-font-lock-keywords + (list + '("</?[[:alnum:]]+[ >]\\|>" 0 'web-mode-html-tag-face t) + '(" \\([[:alnum:]-]+=\\)\\(\"[^\"]+\"\\)" + (1 'web-mode-html-attr-name-face) + (2 'web-mode-html-attr-value-face)) + )) + +;; voir https://www.gnu.org/software/emacs/manual/html_node/elisp/Search_002dbased-Fontification.html +(defvar web-mode-javascript-font-lock-keywords + (list + '("@\\([[:alnum:]_]+\\)\\_>" 0 'web-mode-keyword-face) + '("\\([[:alnum:]]+\\)[`]" 0 'web-mode-preprocessor-face) + (cons (concat "\\_<\\(function\\*\\)\\_>") '(1 'web-mode-keyword-face)) + (cons (concat "\\([ \t}{(]\\|^\\)\\(" web-mode-javascript-keywords "\\)\\_>") '(2 'web-mode-keyword-face)) + (cons (concat "\\_<\\(" web-mode-javascript-constants "\\)\\_>") '(0 'web-mode-constant-face)) + '("\\_<\\([$]\\)(" 1 'web-mode-type-face) + '("\\_<\\(new\\|instanceof\\|class\\|extends\\) \\([[:alnum:]_.]+\\)\\_>" 2 'web-mode-type-face) + '("\\_<\\([[:alnum:]_]+\\):[ ]*function[ ]*(" 1 'web-mode-function-name-face) + '("\\_<\\(function\\|get\\|set\\)[ ]+\\([[:alnum:]_]+\\)" + (1 'web-mode-keyword-face) + (2 'web-mode-function-name-face)) + '("\\([[:alnum:]_]+\\)[ ]*([^)]*)[ \n]*{" 1 'web-mode-function-name-face) + '("([ ]*\\([[:alnum:]_]+\\)[ ]*=>" 1 'web-mode-function-name-face) + '("[ ]*\\([[:alnum:]_]+\\)[ ]*=[ ]*([^)]*)[ ]*=>[ ]*{" 1 'web-mode-function-name-face) + '("\\_<\\(var\\|let\\|const\\)[ ]+\\([[:alnum:]_]+\\)" 2 'web-mode-variable-name-face) + '("({" "\\([[:alnum:]_]+\\)[, }]+" nil nil (1 'web-mode-variable-name-face)) ;#738 + '("\\([[:alnum:]_]+\\)[ ]*=> [{(]" 1 'web-mode-variable-name-face) + ;; #989 + ;; '("\\(function\\|[,=]\\|^\\)[ ]*(" + ;; ("\\([[:alnum:]_]+\\)\\([ ]*=[^,)]*\\)?[,)]" nil nil (1 'web-mode-variable-name-face))) + '("\\([[:alnum:]_]+\\):" 1 'web-mode-variable-name-face) + '("\\_<\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face) + '("[a-zA-Z]<\\([a-zA-Z]+\\)[,>]" 1 'web-mode-type-face) + )) + +(defvar web-mode-stylus-font-lock-keywords + (list + '("^[ \t]*\\([[:alnum:]().-]+\\)$" 1 'web-mode-css-selector-face) + '("^[ \t]*\\([[:alnum:]-]+[ ]*:\\)" 1 'web-mode-css-property-name-face) + )) + +(defvar web-mode-sass-font-lock-keywords + (list + '("^[ \t]*\\([[:alnum:]().-]+\\|&:\\(before\\|after\\)\\)$" 1 'web-mode-css-selector-face) + '("^[ \t]*\\([[:alnum:]-]+[ ]*:\\)" 1 'web-mode-css-property-name-face) + )) + +(defvar web-mode-pug-font-lock-keywords + (list + '("^[ \t]*\\(#?[[:alnum:].-]+\\)" 1 'web-mode-css-selector-face) + ;;'("^[ \t]*\\(#[[:alnum:]-]+\\)" 0 'web-mode-css-selector-face) + '(" \\([@:]?\\sw+[ ]?=\\)" 1 'web-mode-param-name-face) + )) + +(defvar web-mode-sql-font-lock-keywords + (list + (cons (concat "\\_<\\(" web-mode-sql-keywords "\\)\\_>") '(0 'web-mode-keyword-face)) + '("\\_<\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face) + )) + +(defvar web-mode-markdown-font-lock-keywords + (list + '("^[ ]*[*].*$" 0 'web-mode-variable-name-face) + '("^[ ]*#.*$" 0 'web-mode-comment-face) + )) + +(defvar web-mode-html-tag-font-lock-keywords + (list + '("\\(</?\\)\\([[:alnum:]]+\\)" + (1 'web-mode-html-tag-bracket-face) + (2 'web-mode-html-tag-face)) + '("\"[^\"]*\"" 0 'web-mode-html-attr-value-face) + '("\\([[:alnum:]]+\\)" 1 'web-mode-html-attr-name-face) + '("/?>" 0 'web-mode-html-tag-bracket-face) + )) + +(defvar web-mode-anki-font-lock-keywords + (list + '("{{[#/^]\\([[:alnum:]_.]+\\)" 1 'web-mode-block-control-face) + ;;'("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_.: ]*\\)" + ;; (1 'web-mode-block-attr-name-face) + ;; (2 'web-mode-block-attr-value-face)) + '("{{\\(.+\\)}}" 1 'web-mode-variable-name-face) + )) + +(defvar web-mode-dust-font-lock-keywords + (list + '("{[#:/?@><+^]\\([[:alpha:]_.]+\\)" 1 'web-mode-block-control-face) + '(":\\([[:alpha:]]+\\)" 1 'web-mode-keyword-face) + '("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_]*\\)" + (1 'web-mode-block-attr-name-face) + (2 'web-mode-block-attr-value-face)) + '("\\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face) + )) + +(defvar web-mode-expressionengine-font-lock-keywords + (list + '("{/?\\([[:alpha:]_]+:[[:alpha:]_:]+\\|if\\)" 1 'web-mode-block-control-face) + '(":\\([[:alpha:]_]+\\)" 1 'web-mode-keyword-face) + '(" {\\([[:alpha:]_]+\\)}" 1 'web-mode-keyword-face t) + '("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_]*\\)" + (1 'web-mode-block-attr-name-face) + (2 'web-mode-block-attr-value-face)) + '("\\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face) + )) + +(defvar web-mode-svelte-font-lock-keywords + (list + (cons (concat "[ ]\\(" web-mode-svelte-keywords "\\)[ ]") '(1 'web-mode-keyword-face)) + '("{[#:/@]\\([[:alpha:]_.]+\\)" 1 'web-mode-block-control-face) + '("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_]*\\)" + (1 'web-mode-block-attr-name-face) + (2 'web-mode-block-attr-value-face)) + '("\\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face) + '("\\_<\\([$]\\)\\([[:alnum:]_]+\\)" (1 'web-mode-constant-face) (2 'web-mode-variable-name-face)) + )) + +(defvar web-mode-template-toolkit-font-lock-keywords + (list + (cons (concat "\\_<\\(" web-mode-template-toolkit-keywords "\\)\\_>") '(1 'web-mode-keyword-face)) + '("\\\([[:alpha:]][[:alnum:]_]+\\)[ ]?(" 1 'web-mode-function-call-face) + '("\\\([[:alpha:]][[:alnum:]_]+\\)" 0 'web-mode-variable-name-face) + )) + +(defvar web-mode-smarty-font-lock-keywords + (list + (cons (concat "[ ]\\(" web-mode-smarty-keywords "\\)[ ]") '(1 'web-mode-keyword-face)) + '("{/?\\([[:alpha:]_]+\\)" 1 'web-mode-block-control-face) + '("\\([}{]\\)" 0 'web-mode-block-delimiter-face) + '("\\_<\\([$]\\)\\([[:alnum:]_]+\\)" (1 nil) (2 'web-mode-variable-name-face)) + '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face) + '(" \\(\\sw+[ ]?=\\)" 1 'web-mode-param-name-face) + '(" \\(\\sw+\\)[ }]" 1 'web-mode-param-name-face) + '("|\\([[:alnum:]_]+\\)" 1 'web-mode-function-call-face) + '("\\(->\\)\\(\\sw+\\)" (1 nil) (2 'web-mode-variable-name-face)) + '("[.]\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face) + '("[.]\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face) + '("#\\([[:alnum:]_]+\\)#" 1 'web-mode-variable-name-face) + )) + +(defvar web-mode-velocity-font-lock-keywords + (list + '("#{?\\([[:alpha:]_]+\\)\\_>" (1 'web-mode-block-control-face)) + (cons (concat "\\_<\\(" web-mode-velocity-keywords "\\)\\_>") '(1 'web-mode-keyword-face t t)) + '("#macro([ ]*\\([[:alpha:]]+\\)[ ]+" 1 'web-mode-function-name-face) + '("\\(def\\|define\\) \\([[:alnum:]_-]+\\)(" 2 'web-mode-function-name-face) + '("[.]\\([[:alnum:]_-]+\\)" 1 'web-mode-variable-name-face) + '("\\_<\\($[!]?[{]?\\)\\([[:alnum:]_-]+\\)[}]?" (1 nil) (2 'web-mode-variable-name-face)) + )) + +(defvar web-mode-mako-tag-font-lock-keywords + (list + '("</?%\\([[:alpha:]:]+\\)" 1 'web-mode-block-control-face) + '("\\_<\\([[:alpha:]]+=\\)\\(\"[^\"]*\"\\)" + (1 'web-mode-block-attr-name-face t t) + (2 'web-mode-block-attr-value-face t t)) + )) + +(defvar web-mode-mako-block-font-lock-keywords + (list + '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face) + (cons (concat "\\_<\\(" web-mode-python-constants "\\)\\_>") '(1 'web-mode-constant-face)) + (cons (concat "\\_<\\(" web-mode-python-keywords "\\)\\_>") '(1 'web-mode-keyword-face)) + (cons (concat "\\_<\\(endfor\\|endif\\|endwhile\\)\\_>") '(1 'web-mode-keyword-face)) + )) + +(defvar web-mode-web2py-font-lock-keywords + (list + '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face) + (cons (concat "\\_<\\(" web-mode-python-constants "\\)\\_>") '(1 'web-mode-constant-face)) + (cons (concat "\\_<\\(" web-mode-python-keywords "\\)\\_>") '(1 'web-mode-keyword-face)) + (cons (concat "\\_<\\(block\\|extend\\|super\\|end\\|include\\)\\_>") '(1 'web-mode-keyword-face)) + )) + +(defvar web-mode-django-expr-font-lock-keywords + (list + '("|[ ]?\\([[:alpha:]_]+\\)\\_>" 1 'web-mode-filter-face) + (cons (concat "\\_<\\(" web-mode-django-types "\\)\\_>") '(1 'web-mode-type-face)) + '("\\_<\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face) + '("[[:alnum:]_]+" 0 'web-mode-variable-name-face) + )) + +(defvar web-mode-django-code-font-lock-keywords + (list + '("{%[ ]*\\(set\\)[ ]+\\([[:alpha:]]+\\)[ ]*%}" + (1 'web-mode-block-control-face) + (2 'web-mode-variable-name-face)) + (cons (concat "\\({%\\|#\\)[ ]*\\(" web-mode-django-control-blocks-regexp "\\)[ %]") '(2 'web-mode-block-control-face)) + '("\\({%\\|#\\)[ ]*\\(end[[:alpha:]]+\\)\\_>" 2 'web-mode-block-control-face) ;#504 + (cons (concat "\\_<\\(" web-mode-django-keywords "\\)\\_>") '(1 'web-mode-keyword-face)) + (cons (concat "\\_<\\(" web-mode-django-types "\\)\\_>") '(1 'web-mode-type-face)) + '("|[ ]?\\([[:alpha:]_]+\\)\\_>" 1 'web-mode-function-call-face) + '("\\_<\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face) + '("[[:alnum:]_.]+" 0 'web-mode-variable-name-face) + '("[[:alnum:]_]+\\([.][[:alnum:]_]+\\)+" 0 'web-mode-variable-name-face t t) + )) + +(defvar web-mode-ctemplate-font-lock-keywords + (list + '("{[~]?{[#/>^]?[ ]*\\([[:alnum:]_.-]+\\)" 1 'web-mode-block-control-face) + '("[ \t]+\\([[:alnum:]_-]+\\)=" + (1 'web-mode-block-attr-name-face)) + '("\"[^\"]+\"" 0 'web-mode-block-string-face) + )) + +(defvar web-mode-razor-font-lock-keywords + (list + '("@\\([[:alnum:]_.]+\\)[ ]*[({]" 1 'web-mode-block-control-face) + (cons (concat "\\_<\\(" web-mode-razor-keywords "\\)\\_>") '(1 'web-mode-keyword-face)) + '("\\_<\\(String\\)\\_>" 1 'web-mode-type-face) + '("\\([[:alnum:]]+:\\)" 1 'web-mode-symbol-face) + '("\\(@[[:alnum:]_.]+\\)" 1 'web-mode-variable-name-face) + )) + +(defvar web-mode-riot-font-lock-keywords + (list + '("\\(parent\\|opts\\|tags\\|this\\)\\.\\([[:alnum:]_.]+\\)" + (1 'web-mode-constant-face) + (2 'web-mode-variable-name-face)) + '("\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face) + )) + +(defvar web-mode-closure-font-lock-keywords + (list + '("{\\([@/]?[[:alpha:]]+[?]?\\)" 1 'web-mode-block-control-face) + '("{[@]?param[?]?[ ]+\\([[:alnum:]]+[:]?\\)" 1 'web-mode-symbol-face) + '("\\_<\\(true\\|false\\|null\\)\\_>" 1 'web-mode-type-face) + '("\\\_<[[:alpha:]]+:[ ]+\\([[:alpha:]]+\\)" 1 'web-mode-type-face) + (cons (concat "\\_<\\(" web-mode-closure-keywords "\\)\\_>") '(1 'web-mode-keyword-face)) + '("{\\(alias\\|call\\|delcall\\|delpackage\\|deltemplate\\|namespace\\|template\\)[ ]+\\([[:alnum:].]+\\)" 2 'web-mode-constant-face) + '("\\(allowemptydefault\\|data\\|desc\\|meaning\\|autoescape\\|private\\|variant\\)=" 0 'web-mode-block-attr-name-face) + '("|\\([[:alpha:]]+\\)" 1 'web-mode-function-call-face) + '("\\_<\\([[:alnum:]]+\\)[ ]?(" 1 'web-mode-function-call-face) + '("$\\([[:alnum:]._]+\\)" 1 'web-mode-variable-name-face) + )) + +(defvar web-mode-go-font-lock-keywords + (list + '("{{[-]?[ ]*\\([[:alpha:]]+\\)" 1 'web-mode-block-control-face) + '("\\_<func \\([[:alnum:]]+\\)" 1 'web-mode-function-name-face) + '("\\_<type \\([[:alnum:]]+\\)" 1 'web-mode-type-face) + (cons (concat "\\_<\\(" web-mode-go-types "\\)\\_>") '(0 'web-mode-type-face)) + (cons (concat "\\_<\\(" web-mode-go-keywords "\\)\\_>") '(1 'web-mode-keyword-face)) + (cons (concat "\\_<\\(" web-mode-go-functions "\\)\\_>") '(1 'web-mode-function-call-face)) + '("[$.]\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face t t) + '("|[ ]?\\([[:alpha:]_]+\\)\\_>" 1 'web-mode-filter-face) + )) + +(defvar web-mode-expression-font-lock-keywords + (list + '("[[:alpha:]_]" 0 'web-mode-variable-name-face) + )) + +(defvar web-mode-angular-font-lock-keywords + (list + '("[[:alpha:]_]" 0 'web-mode-variable-name-face) + )) + +(defvar web-mode-underscore-font-lock-keywords + (list + (cons (concat "\\_<\\(" web-mode-javascript-keywords "\\)\\_>") '(0 'web-mode-keyword-face)) + '("\\_<\\(_\.[[:alpha:]]+\\)(" 1 'web-mode-function-call-face) + '("\\_<new \\([[:alnum:]_.]+\\)\\_>" 1 'web-mode-type-face) + '("\\_<\\([[:alnum:]_]+\\):[ ]*function[ ]*(" 1 'web-mode-function-name-face) + '("\\_<\\(var\\)\\_>[ ]+\\([[:alnum:]_]+\\)" + (1 'web-mode-keyword-face) + (2 'web-mode-variable-name-face)) + )) + +(defvar web-mode-vue-font-lock-keywords + (list + '("\\_<\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face) + '("[[:alpha:]_]" 0 'web-mode-variable-name-face) + )) + +(defvar web-mode-engine-tag-font-lock-keywords + (list + '("</?\\([[:alpha:]]+\\(?:Template\\|[:.][[:alpha:]-]+\\)\\|TMPL_[[:alpha:]]+\\)" 1 'web-mode-block-control-face) + '("\\_<\\([[:alpha:]-]+=\\)\\(\"[^\"]*\"\\)" + (1 'web-mode-block-attr-name-face t t) + (2 'web-mode-block-attr-value-face t t)) + '("\\_<\\([[:alpha:]-]+=\\)\\('[^']*\'\\)" + (1 'web-mode-block-attr-name-face t t) + (2 'web-mode-block-attr-value-face t t)) + )) + +(defvar web-mode-jsp-font-lock-keywords + (list + '("\\(throws\\|new\\|extends\\)[ ]+\\([[:alnum:].]+\\)" 2 'web-mode-type-face) + (cons (concat "\\_<\\(" web-mode-jsp-keywords "\\)\\_>") '(0 'web-mode-keyword-face)) + '("\\(public\\|private\\)[ ]+\\([[:alpha:]]+\\)[ ]+\\([[:alnum:]._]+\\)[ ]?(" + (2 'web-mode-type-face) + (3 'web-mode-function-name-face)) + '("\\_<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face) + '("@\\(\\sw*\\)" 1 'web-mode-variable-name-face) + '("\\_<\\([[:alnum:].]+\\)[ ]+[{[:alpha:]]+" 1 'web-mode-type-face) + )) + +(defvar web-mode-asp-font-lock-keywords + (list + (cons (concat "\\_<\\(" web-mode-asp-keywords "\\)\\_>") '(0 'web-mode-keyword-face)) + (cons (concat "\\_<\\(" web-mode-asp-types "\\)\\_>") '(0 'web-mode-type-face)) + (cons (concat "\\_<\\(" web-mode-asp-constants "\\)\\_>") '(0 'web-mode-constant-face)) + '("\\(Class\\|new\\) \\([[:alnum:]_]+\\)" 2 'web-mode-type-face) + '("Const \\([[:alnum:]_]+\\)" 1 'web-mode-constant-face) + '("\\_<dim\\_>" + (0 'web-mode-keyword-face) + ("[[:alnum:]_]+" nil nil (0 'web-mode-variable-name-face))) + '("\\_<\\(public\\|private\\|sub\\|function\\)\\_> \\([[:alnum:]_]+\\)[ ]*(" 2 'web-mode-function-name-face) + '("\\_<\\(public\\|private\\|dim\\)\\_> \\([[:alnum:]_]+\\)" 2 'web-mode-variable-name-face) + )) + +(defvar web-mode-aspx-font-lock-keywords + (list + (cons (concat "\\_<\\(" web-mode-aspx-keywords "\\)\\_>") '(0 'web-mode-keyword-face)) + '("\\_<\\([[:alnum:].]+\\)[ ]+[[:alpha:]]+" 1 'web-mode-type-face) + )) + +(defvar web-mode-uel-font-lock-keywords + (list + '("[$#{]{\\|}" 0 'web-mode-preprocessor-face) + '("\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face) + '("|[ ]*\\(trim\\|x\\|u\\)" 1 'web-mode-function-call-face) + '("[[:alpha:]_]" 0 'web-mode-variable-name-face) + )) + +(defvar web-mode-php-var-interpolation-font-lock-keywords + (list + '("[[:alpha:]_]" 0 'web-mode-variable-name-face) + '("\".+\"\\|'.*'" 0 'web-mode-string-face) + )) + +(defvar web-mode-marko-font-lock-keywords + (list + '("[[:alnum:]_]+" 0 'web-mode-variable-name-face) + )) + +(defvar web-mode-freemarker-square-font-lock-keywords + (list + '("\\[/?[#@]\\([[:alpha:]_.]*\\)" 1 'web-mode-block-control-face) + '("#\\(macro\\|function\\) \\([[:alpha:]]+\\)" 2 'web-mode-function-name-face) + (cons (concat "\\_<\\(" web-mode-freemarker-keywords "\\)\\_>") '(1 'web-mode-keyword-face)) + '("\\_<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face) + '("[[:alpha:]]\\([[:alnum:]_]+\\)?" 0 'web-mode-variable-name-face) + )) + +(defvar web-mode-freemarker-font-lock-keywords + (list + '("</?[#@]\\([[:alpha:]_.]*\\)" 1 'web-mode-block-control-face) + '("#\\(macro\\|function\\) \\([[:alpha:]]+\\)" 2 'web-mode-function-name-face) + (cons (concat "\\_<\\(" web-mode-freemarker-keywords "\\)\\_>") '(1 'web-mode-keyword-face)) + '("\\_<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face) + '("[[:alpha:]]\\([[:alnum:]_]+\\)?" 0 'web-mode-variable-name-face) + )) + +(defvar web-mode-directive-font-lock-keywords + (list + '("<%@[ ]*\\([[:alpha:]]+\\)[ ]+" 1 'web-mode-block-control-face) + '("\\_<\\([[:alpha:]]+=\\)\\(\"[^\"]*\"\\)" + (1 'web-mode-block-attr-name-face t t) + (2 'web-mode-block-attr-value-face t t)) + )) + +(defvar web-mode-erb-font-lock-keywords + (list + '("[^:]\\(:[[:alnum:]_]+\\)" 1 'web-mode-symbol-face) + '("\\([[:alnum:]_]+:\\)[ ]+" 1 'web-mode-symbol-face) + (cons (concat "\\_<\\(" web-mode-erb-builtins "\\)\\_>") '(0 'web-mode-builtin-face)) + (cons (concat "\\_<\\(" web-mode-erb-keywords "\\)\\_>") '(0 'web-mode-keyword-face)) + '("\\_<\\(self\\|true\\|false\\|nil\\)\\_>" 0 'web-mode-variable-name-face) + '("[@$]@?\\([[:alnum:]_]+\\)" 0 'web-mode-variable-name-face) + '("class[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-type-face) + '("def[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face) + '("\\(?:\\_<\\|::\\)\\([A-Z]+[[:alnum:]_]+\\)" 1 (unless (eq (char-after) ?\() 'web-mode-type-face)) + '("/[^/]+/" 0 'web-mode-string-face) + )) + +(defvar web-mode-ejs-font-lock-keywords + web-mode-javascript-font-lock-keywords) + +(defvar web-mode-python-font-lock-keywords + (list + (cons (concat "\\_<\\(" web-mode-python-keywords "\\)\\_>") '(0 'web-mode-keyword-face)) + )) + +(defvar web-mode-elixir-font-lock-keywords + (list + '("@\\([[:alnum:]_]+\\)" 0 'web-mode-variable-name-face) + '("[ ]\\(:[[:alnum:]-_]+\\)" 1 'web-mode-symbol-face) + '("def[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face) + (cons (concat "\\_<\\(" web-mode-elixir-keywords "\\)\\_>") '(0 'web-mode-builtin-face)) + (cons (concat "\\_<\\(" web-mode-elixir-constants "\\)\\_>") '(0 'web-mode-constant-face)) + )) + +(defvar web-mode-erlang-font-lock-keywords + (list + (cons (concat "\\_<\\(" web-mode-erlang-keywords "\\)\\_>") '(0 'web-mode-keyword-face)) + (cons (concat "\\_<\\(" web-mode-erlang-constants "\\)\\_>") '(0 'web-mode-constant-face)) + '("@\\([[:alnum:]_]+\\)" 0 'web-mode-variable-name-face) + '("[ ]\\(:[[:alnum:]-_]+\\)" 1 'web-mode-symbol-face) + )) + +(defvar web-mode-mason-code-font-lock-keywords + (list + (cons (concat "\\_<\\(" web-mode-mason-keywords "\\)\\_>") '(0 'web-mode-keyword-face)) + '("sub[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face) + '("\\_<\\([[:alnum:]_]+\\)[ ]?::" 1 'web-mode-type-face) + '("\\([@]\\)\\([[:alnum:]#_]*\\)" (1 nil) (2 'web-mode-variable-name-face)) + '("\\_<\\([$%]\\)\\([[:alnum:]@#_]*\\)" (1 nil) (2 'web-mode-variable-name-face)) + '("{\\([[:alnum:]_]+\\)}" 1 'web-mode-variable-name-face) + '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face) + '("[[:alnum:]_][ ]?::[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face) + '("->[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face) + '("\\(?:method\\|def\\) \\([[:alnum:]._]+\\)" 1 'web-mode-function-name-face) + '("|[ ]*\\([[:alnum:],]+\\)[ ]*%>" 1 'web-mode-filter-face) + )) + +(defvar web-mode-mason-block-font-lock-keywords + (list + '("<[/]?%\\([[:alpha:]]+\\)" 1 'web-mode-block-control-face) + '("[[:alpha:]]" 0 'web-mode-block-attr-value-face) + )) + +(defvar web-mode-mojolicious-font-lock-keywords + (list + (cons (concat "\\_<\\(" web-mode-perl-keywords "\\)\\_>") '(0 'web-mode-keyword-face)) + '("\\_<\\(begin\\|end\\)\\_>" 1 'web-mode-constant-face) + '("\\_<\\([$]\\)\\([[:alnum:]_]*\\)" (1 nil) (2 'web-mode-variable-name-face)) + )) + +(defvar web-mode-lsp-font-lock-keywords + (list + (cons (concat "\\_<\\(" web-mode-lsp-keywords "\\)\\_>") '(0 'web-mode-keyword-face)) + (cons (concat "\\_<\\(" web-mode-lsp-constants "\\)\\_>") '(1 'web-mode-constant-face)) + '("[ ]\\(:[[:alnum:]-_]+\\)" 1 'web-mode-symbol-face) + '("(defun \\([[:alnum:]-:]+\\)" 1 'web-mode-function-name-face) + '("(defvar \\([[:alnum:]-:]+\\)" 1 'web-mode-variable-name-face) + )) + +(defvar web-mode-cl-emb-font-lock-keywords + (list + (cons (concat "\\_<\\(" web-mode-cl-emb-keywords "\\)\\_>") '(0 'web-mode-keyword-face)) + (cons (concat "\\_<\\(" web-mode-cl-emb-constants "\\)\\_>") '(0 'web-mode-constant-face)) + '("\\(@\\)" 1 'web-mode-function-call-face) + (list (concat "\\(@" web-mode-cl-emb-keywords "\\)[ ]+\\([[:alnum:]_]+\\)") + '(1 'web-mode-keyword-face) + '(2 'web-mode-variable-name-face)) + )) + +(defvar web-mode-artanis-font-lock-keywords + (list + (cons (concat "\\_<\\(" web-mode-artanis-keywords "\\)\\_>") '(0 'web-mode-keyword-face)) + (cons (concat "\\_<\\(" web-mode-artanis-constants "\\)\\_>") '(0 'web-mode-constant-face)) + '("(define[*]? (\\([[:alnum:]-:_!#$%^&*=+/?<>.]+\\)" 1 'web-mode-function-name-face) + '("\\(#:[[:alnum:]-:_!#$%^&*=+/?<>.]+\\)" 1 'web-mode-builtin-face) + )) + +(defvar web-mode-php-font-lock-keywords + (list + (cons (concat "\\_<\\(" web-mode-php-keywords "\\)\\_>") '(0 'web-mode-keyword-face)) + (cons (concat "\\_<\\(" web-mode-php-types "\\)\\_>") '(1 'web-mode-type-face)) + (cons (concat "\\_<\\(" web-mode-php-constants "\\)\\_>") '(0 'web-mode-constant-face)) + '("function[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face) + '("\\_<\\([[:alnum:]_]+\\)[ ]?(" 1 'web-mode-function-call-face) + '("[[:alnum:]_][ ]?::[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-constant-face) + '("->[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face) + '("\\_<\\([[:alnum:]_]+\\)[ ]?::" 1 'web-mode-type-face) + '("\\_<\\(instanceof\\|class\\|extends\\|new\\)[ ]+\\([[:alnum:]_]+\\)" 2 'web-mode-type-face) + '("\\(\\_<\\|[+-]\\)\\([$]\\)\\([[:alnum:]_]*\\)" (2 nil) (3 'web-mode-variable-name-face)) + )) + +(defvar web-mode-spip-font-lock-keywords + (list + '("<:.+:>" 0 'web-mode-block-string-face) + '("#[A-Z0-9_]+" 0 'web-mode-variable-name-face) + '("|[a-z0-9_=!?<>]+" 0 'web-mode-function-call-face) + '("(\\([[:alnum:]_ ]+\\))" 1 'web-mode-constant-face) + )) + +(defvar web-mode-latex-font-lock-keywords + (list + '("[[:alnum:]_]+" 0 'web-mode-function-name-face t t) + )) + +(defvar web-mode-blade-font-lock-keywords + (append + (list + '("@\\([[:alpha:]_]+\\)" (1 'web-mode-block-control-face))) + web-mode-php-font-lock-keywords)) + +(defvar web-mode-engines-font-lock-keywords + '(("angular" . web-mode-angular-font-lock-keywords) + ("anki" . web-mode-anki-font-lock-keywords) + ("artanis" . web-mode-artanis-font-lock-keywords) + ("blade" . web-mode-blade-font-lock-keywords) + ("cl-emb" . web-mode-cl-emb-font-lock-keywords) + ("closure" . web-mode-closure-font-lock-keywords) + ("ctemplate" . web-mode-ctemplate-font-lock-keywords) + ("dust" . web-mode-dust-font-lock-keywords) + ("elixir" . web-mode-elixir-font-lock-keywords) + ("ejs" . web-mode-ejs-font-lock-keywords) + ("erb" . web-mode-erb-font-lock-keywords) + ("expressionengine" . web-mode-expressionengine-font-lock-keywords) + ("go" . web-mode-go-font-lock-keywords) + ("hero" . web-mode-go-font-lock-keywords) + ("lsp" . web-mode-lsp-font-lock-keywords) + ("marko" . web-mode-marko-font-lock-keywords) + ("mojolicious" . web-mode-mojolicious-font-lock-keywords) + ("php" . web-mode-php-font-lock-keywords) + ("python" . web-mode-python-font-lock-keywords) + ("razor" . web-mode-razor-font-lock-keywords) + ("riot" . web-mode-riot-font-lock-keywords) + ("smarty" . web-mode-smarty-font-lock-keywords) + ("spip" . web-mode-spip-font-lock-keywords) + ("template-toolkit" . web-mode-template-toolkit-font-lock-keywords) + ("underscore" . web-mode-underscore-font-lock-keywords) + ("web2py" . web-mode-web2py-font-lock-keywords) + ("velocity" . web-mode-velocity-font-lock-keywords) + ("vue" . web-mode-vue-font-lock-keywords) + ("xoops" . web-mode-smarty-font-lock-keywords) + ("svelte" . web-mode-svelte-font-lock-keywords) + ) + "Engines font-lock keywords") + +(defvar web-mode-prettify-symbols-alist + '(("=>" . 8658) + (">=" . 8805) + ("<=" . 8804))) + +(defvar web-mode-before-auto-complete-hooks nil + "List of functions to run before triggering the auto-complete library. + +Auto-complete sources will sometimes need some tweaking to work +nicely with web-mode. This hook gives users the chance to adjust +the environment as needed for ac-sources, right before they're used.") + +(defvar web-mode-ignore-ac-start-advice nil + "If not nil 'defadvice' for 'ac-start' will be ignored. + +Can be set inside a hook in 'web-mode-before-auto-complete-hooks' to +non nil to ignore the defadvice which sets ac-sources according to current +language. This is needed if the corresponding auto-completion triggers +another auto-completion with different ac-sources (e.g. ac-php)") + +(defvar web-mode-ac-sources-alist nil + "alist mapping language names to ac-sources for that language.") + +(defvar web-mode-trace nil + "Activate debug tracing.") + +(defvar web-mode-syntax-table + (let ((table (make-syntax-table))) + (modify-syntax-entry ?- "_" table) + (modify-syntax-entry ?_ "_" table) ;#563 + (modify-syntax-entry ?< "." table) + (modify-syntax-entry ?> "." table) + (modify-syntax-entry ?& "." table) + (modify-syntax-entry ?/ "." table) + (modify-syntax-entry ?= "." table) + (modify-syntax-entry ?% "." table) + table) + "Syntax table used to reveal whitespaces.") + +(defvar web-mode-map + (let ((map (make-sparse-keymap))) + + (define-key map [menu-bar wm] (cons "Web-Mode" (make-sparse-keymap))) + (define-key map [menu-bar wm dom] (cons "Dom" (make-sparse-keymap))) + (define-key map [menu-bar wm blk] (cons "Block" (make-sparse-keymap))) + (define-key map [menu-bar wm attr] (cons "Html Attr" (make-sparse-keymap))) + (define-key map [menu-bar wm tag] (cons "Html Tag" (make-sparse-keymap))) + (define-key map [menu-bar wm elt] (cons "Html Element" (make-sparse-keymap))) + + (define-key map [menu-bar wm sep-1] '(menu-item "--")) + + (define-key map [menu-bar wm dom dom-xpa] '(menu-item "XPath" web-mode-dom-xpath)) + (define-key map [menu-bar wm dom dom-tra] '(menu-item "Traverse" web-mode-dom-traverse)) + (define-key map [menu-bar wm dom dom-err] '(menu-item "Show error(s)" web-mode-dom-errors-show)) + (define-key map [menu-bar wm dom dom-ent] '(menu-item "Replace html entities" web-mode-dom-entities-replace)) + (define-key map [menu-bar wm dom dom-quo] '(menu-item "Replace dumb quotes" web-mode-dom-quotes-replace)) + (define-key map [menu-bar wm dom dom-apo] '(menu-item "Replace apostrophes" web-mode-dom-apostrophes-replace)) + (define-key map [menu-bar wm dom dom-nor] '(menu-item "Normalize" web-mode-dom-normalize)) + + (define-key map [menu-bar wm blk blk-sel] '(menu-item "Select" web-mode-block-select)) + (define-key map [menu-bar wm blk blk-pre] '(menu-item "Previous" web-mode-block-previous)) + (define-key map [menu-bar wm blk blk-nex] '(menu-item "Next" web-mode-block-next)) + (define-key map [menu-bar wm blk blk-kil] '(menu-item "Kill" web-mode-block-kill)) + (define-key map [menu-bar wm blk blk-end] '(menu-item "End" web-mode-block-end)) + (define-key map [menu-bar wm blk blk-clo] '(menu-item "Close" web-mode-block-close)) + (define-key map [menu-bar wm blk blk-beg] '(menu-item "Beginning" web-mode-block-beginning)) + + (define-key map [menu-bar wm attr attr-ins] '(menu-item "Insert" web-mode-attribute-insert)) + (define-key map [menu-bar wm attr attr-end] '(menu-item "End" web-mode-attribute-end)) + (define-key map [menu-bar wm attr attr-beg] '(menu-item "Beginning" web-mode-attribute-beginning)) + (define-key map [menu-bar wm attr attr-sel] '(menu-item "Select" web-mode-attribute-select)) + (define-key map [menu-bar wm attr attr-kil] '(menu-item "Kill" web-mode-attribute-kill)) + (define-key map [menu-bar wm attr attr-nex] '(menu-item "Next" web-mode-attribute-next)) + (define-key map [menu-bar wm attr attr-pre] '(menu-item "Previous" web-mode-attribute-previous)) + (define-key map [menu-bar wm attr attr-tra] '(menu-item "Transpose" web-mode-attribute-transpose)) + + (define-key map [menu-bar wm tag tag-beg] '(menu-item "Sort Attributes" web-mode-tag-attributes-sort)) + (define-key map [menu-bar wm tag tag-sel] '(menu-item "Select" web-mode-tag-select)) + (define-key map [menu-bar wm tag tag-pre] '(menu-item "Previous" web-mode-tag-previous)) + (define-key map [menu-bar wm tag tag-nex] '(menu-item "Next" web-mode-tag-next)) + (define-key map [menu-bar wm tag tag-end] '(menu-item "End" web-mode-tag-end)) + (define-key map [menu-bar wm tag tag-beg] '(menu-item "Beginning" web-mode-tag-beginning)) + + (define-key map [menu-bar wm elt elt-con] '(menu-item "Contract" web-mode-element-contract)) + (define-key map [menu-bar wm elt elt-ext] '(menu-item "Extract" web-mode-element-extract)) + (define-key map [menu-bar wm elt elt-van] '(menu-item "Vanish" web-mode-element-vanish)) + (define-key map [menu-bar wm elt elt-exc] '(menu-item "Transpose" web-mode-element-transpose)) + (define-key map [menu-bar wm elt elt-sel] '(menu-item "Select" web-mode-element-select)) + (define-key map [menu-bar wm elt elt-ren] '(menu-item "Rename" web-mode-element-rename)) + (define-key map [menu-bar wm elt elt-pre] '(menu-item "Previous" web-mode-element-previous)) + (define-key map [menu-bar wm elt elt-par] '(menu-item "Parent" web-mode-element-parent)) + (define-key map [menu-bar wm elt elt-nex] '(menu-item "Next" web-mode-element-next)) + (define-key map [menu-bar wm elt elt-mut] '(menu-item "Mute blanks" web-mode-element-mute-blanks)) + (define-key map [menu-bar wm elt elt-del] '(menu-item "Kill" web-mode-element-kill)) + (define-key map [menu-bar wm elt elt-end] '(menu-item "End" web-mode-element-end)) + (define-key map [menu-bar wm elt elt-inn] '(menu-item "Content (select)" web-mode-element-content-select)) + (define-key map [menu-bar wm elt elt-clo] '(menu-item "Close" web-mode-element-close)) + (define-key map [menu-bar wm elt elt-ins] '(menu-item "Insert" web-mode-element-insert)) + (define-key map [menu-bar wm elt elt-ins] '(menu-item "Word to tag" web-mode-element-insert-at-point)) + (define-key map [menu-bar wm elt elt-dup] '(menu-item "Clone" web-mode-element-clone)) + (define-key map [menu-bar wm elt elt-cfo] '(menu-item "Children fold" web-mode-element-children-fold-or-unfold)) + (define-key map [menu-bar wm elt elt-chi] '(menu-item "Child" web-mode-element-child)) + (define-key map [menu-bar wm elt elt-beg] '(menu-item "Beginning" web-mode-element-beginning)) + + (define-key map [menu-bar wm fol] '(menu-item "Fold/Unfold" web-mode-fold-or-unfold)) + (define-key map [menu-bar wm hig] '(menu-item "Fontify buffer" web-mode-buffer-fontify)) + (define-key map [menu-bar wm ind] '(menu-item "Indent buffer" web-mode-buffer-indent)) + (define-key map [menu-bar wm nav] '(menu-item "Tag/Block navigation" web-mode-navigate)) + (define-key map [menu-bar wm exp] '(menu-item "Mark and Expand" web-mode-mark-and-expand)) + (define-key map [menu-bar wm spa] '(menu-item "Toggle whitespaces" web-mode-whitespaces-show)) + (define-key map [menu-bar wm sni] '(menu-item "Insert snippet" web-mode-snippet-insert)) + + ;;-------------------------------------------------------------------------- + ;; "C-c <LETTER>" are reserved for users + + (define-key map (kbd "C-c C-a b") 'web-mode-attribute-beginning) + (define-key map (kbd "C-c C-a e") 'web-mode-attribute-end) + (define-key map (kbd "C-c C-a i") 'web-mode-attribute-insert) + (define-key map (kbd "C-c C-a n") 'web-mode-attribute-next) + (define-key map (kbd "C-c C-a s") 'web-mode-attribute-select) + (define-key map (kbd "C-c C-a k") 'web-mode-attribute-kill) + (define-key map (kbd "C-c C-a p") 'web-mode-attribute-previous) + (define-key map (kbd "C-c C-a t") 'web-mode-attribute-transpose) + + (define-key map (kbd "C-c C-b b") 'web-mode-block-beginning) + (define-key map (kbd "C-c C-b c") 'web-mode-block-close) + (define-key map (kbd "C-c C-b e") 'web-mode-block-end) + (define-key map (kbd "C-c C-b k") 'web-mode-block-kill) + (define-key map (kbd "C-c C-b n") 'web-mode-block-next) + (define-key map (kbd "C-c C-b p") 'web-mode-block-previous) + (define-key map (kbd "C-c C-b s") 'web-mode-block-select) + + (define-key map (kbd "C-c C-d a") 'web-mode-dom-apostrophes-replace) + (define-key map (kbd "C-c C-d d") 'web-mode-dom-errors-show) + (define-key map (kbd "C-c C-d e") 'web-mode-dom-entities-replace) + (define-key map (kbd "C-c C-d n") 'web-mode-dom-normalize) + (define-key map (kbd "C-c C-d q") 'web-mode-dom-quotes-replace) + (define-key map (kbd "C-c C-d t") 'web-mode-dom-traverse) + (define-key map (kbd "C-c C-d x") 'web-mode-dom-xpath) + + (define-key map (kbd "C-c C-e /") 'web-mode-element-close) + (define-key map (kbd "C-c C-e a") 'web-mode-element-content-select) + (define-key map (kbd "C-c C-e b") 'web-mode-element-beginning) + (define-key map (kbd "C-c C-e c") 'web-mode-element-clone) + (define-key map (kbd "C-c C-e d") 'web-mode-element-child) + (define-key map (kbd "C-c C-e e") 'web-mode-element-end) + (define-key map (kbd "C-c C-e f") 'web-mode-element-children-fold-or-unfold) + (define-key map (kbd "C-c C-e i") 'web-mode-element-insert) + (define-key map (kbd "C-c C-e I") 'web-mode-element-insert-at-point) + (define-key map (kbd "C-c C-e k") 'web-mode-element-kill) + (define-key map (kbd "C-c C-e m") 'web-mode-element-mute-blanks) + (define-key map (kbd "C-c C-e n") 'web-mode-element-next) + (define-key map (kbd "C-c C-e p") 'web-mode-element-previous) + (define-key map (kbd "C-c C-e r") 'web-mode-element-rename) + (define-key map (kbd "C-c C-e s") 'web-mode-element-select) + (define-key map (kbd "C-c C-e t") 'web-mode-element-transpose) + (define-key map (kbd "C-c C-e u") 'web-mode-element-parent) + (define-key map (kbd "C-c C-e v") 'web-mode-element-vanish) + (define-key map (kbd "C-c C-e w") 'web-mode-element-wrap) + (define-key map (kbd "C-c C-e +") 'web-mode-element-extract) + (define-key map (kbd "C-c C-e -") 'web-mode-element-contract) + + (define-key map (kbd "C-c C-t a") 'web-mode-tag-attributes-sort) + (define-key map (kbd "C-c C-t b") 'web-mode-tag-beginning) + (define-key map (kbd "C-c C-t e") 'web-mode-tag-end) + (define-key map (kbd "C-c C-t m") 'web-mode-tag-match) + (define-key map (kbd "C-c C-t n") 'web-mode-tag-next) + (define-key map (kbd "C-c C-t p") 'web-mode-tag-previous) + (define-key map (kbd "C-c C-t s") 'web-mode-tag-select) + + ;;-------------------------------------------------------------------------- + + ;;(define-key map (kbd "M-q") 'fill-paragraph) + (define-key map (kbd "M-;") 'web-mode-comment-or-uncomment) + + ;;C-c C-a : attribute + ;;C-c C-b : block + ;;C-c C-d : dom + ;;C-c C-e : element + (define-key map (kbd "C-c C-f") 'web-mode-fold-or-unfold) + (define-key map (kbd "C-c C-h") 'web-mode-buffer-fontify) + (define-key map (kbd "C-c C-i") 'web-mode-buffer-indent) + (define-key map (kbd "C-c C-j") 'web-mode-jshint) + (define-key map (kbd "C-c C-l") 'web-mode-file-link) + (define-key map (kbd "C-c C-m") 'web-mode-mark-and-expand) + (define-key map (kbd "C-c C-n") 'web-mode-navigate) + (define-key map (kbd "C-c C-r") 'web-mode-reload) + (define-key map (kbd "C-c C-s") 'web-mode-snippet-insert) + ;;C-c C-t : tag + (define-key map (kbd "C-c C-w") 'web-mode-whitespaces-show) + + map) + "Keymap for `web-mode'.") + +;;---- COMPATIBILITY ----------------------------------------------------------- + +(eval-and-compile + + ;; compatibility with emacs < 23 + (defun web-mode-string-match-p (regexp string &optional start) + "Same as `string-match' except it does not change the match data." + (let ((inhibit-changing-match-data t)) + (string-match regexp string start))) + + (unless (fboundp 'string-match-p) + (fset 'string-match-p (symbol-function 'web-mode-string-match-p))) + + ;; compatibility with emacs < 23.3 + (if (fboundp 'with-silent-modifications) + (defalias 'web-mode-with-silent-modifications 'with-silent-modifications) + (defmacro web-mode-with-silent-modifications (&rest body) + `(let ((old-modified-p (buffer-modified-p)) + (inhibit-modification-hooks t) + (buffer-undo-list t)) + (unwind-protect + ,@body + (restore-buffer-modified-p old-modified-p))))) + + ;; compatibility with emacs < 24.3 + (defun web-mode-buffer-narrowed-p () + (if (fboundp 'buffer-narrowed-p) + (buffer-narrowed-p) + (/= (- (point-max) (point-min)) (buffer-size)))) + + ;; compatibility with emacs < 24 + (defalias 'web-mode-prog-mode + (if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode)) + + ;; compatibility with emacs < 24.3 + (unless (fboundp 'setq-local) + (defmacro setq-local (var val) + `(set (make-local-variable ',var) ,val))) + + ;; compatability with emacs < 24.4 + (defun web-mode-string-suffix-p (suffix string) + "Return t if STRING ends with SUFFIX." + (and (string-match (rx-to-string `(: ,suffix eos) t) + string) + t)) + + (unless (fboundp 'string-suffix-p) + (fset 'string-suffix-p (symbol-function 'web-mode-string-suffix-p))) + + (unless (fboundp 'seq-some) + (defun seq-some (pred seq) + (unless (null seq) + (or (funcall pred (car seq)) + (seq-some pred (cdr seq)))))) + ) ;eval-and-compile + +;;---- MAJOR MODE -------------------------------------------------------------- + +;;;###autoload +(define-derived-mode web-mode web-mode-prog-mode "Web" + "Major mode for editing web templates." + + (make-local-variable 'web-mode-attr-indent-offset) + (make-local-variable 'web-mode-attr-value-indent-offset) + (make-local-variable 'web-mode-auto-pairs) + (make-local-variable 'web-mode-block-regexp) + (make-local-variable 'web-mode-change-beg) + (make-local-variable 'web-mode-change-end) + (make-local-variable 'web-mode-code-indent-offset) + (make-local-variable 'web-mode-column-overlays) + (make-local-variable 'web-mode-comment-formats) + (make-local-variable 'web-mode-comment-style) + (make-local-variable 'web-mode-content-type) + (make-local-variable 'web-mode-css-indent-offset) + (make-local-variable 'web-mode-display-table) + (make-local-variable 'web-mode-django-control-blocks) + (make-local-variable 'web-mode-django-control-blocks-regexp) + (make-local-variable 'web-mode-enable-block-face) + (make-local-variable 'web-mode-enable-inlays) + (make-local-variable 'web-mode-enable-part-face) + (make-local-variable 'web-mode-enable-sexp-functions) + (make-local-variable 'web-mode-engine) + (make-local-variable 'web-mode-engine-attr-regexp) + (make-local-variable 'web-mode-engine-file-regexps) + (make-local-variable 'web-mode-engine-open-delimiter-regexps) + (make-local-variable 'web-mode-engine-token-regexp) + (make-local-variable 'web-mode-expand-initial-pos) + (make-local-variable 'web-mode-expand-initial-scroll) + (make-local-variable 'web-mode-expand-previous-state) + (make-local-variable 'web-mode-indent-style) + (make-local-variable 'web-mode-indentless-attributes) + (make-local-variable 'web-mode-indentless-elements) + (make-local-variable 'web-mode-is-scratch) + (make-local-variable 'web-mode-skip-fontification) + (make-local-variable 'web-mode-jshint-errors) + (make-local-variable 'web-mode-last-enabled-feature) + (make-local-variable 'web-mode-markup-indent-offset) + (make-local-variable 'web-mode-minor-engine) + (make-local-variable 'web-mode-overlay-tag-end) + (make-local-variable 'web-mode-overlay-tag-start) + (make-local-variable 'web-mode-part-beg) + (make-local-variable 'web-mode-scan-beg) + (make-local-variable 'web-mode-scan-end) + (make-local-variable 'web-mode-sql-indent-offset) + (make-local-variable 'web-mode-time) + (make-local-variable 'web-mode-trace) + + (make-local-variable 'font-lock-beg) + (make-local-variable 'font-lock-end) + + (make-local-variable 'comment-end) + (make-local-variable 'comment-region-function) + (make-local-variable 'comment-start) + (make-local-variable 'fill-paragraph-function) + (make-local-variable 'font-lock-defaults) + (make-local-variable 'font-lock-extend-region-functions) + (make-local-variable 'font-lock-support-mode) + (make-local-variable 'font-lock-unfontify-region-function) + (make-local-variable 'imenu-case-fold-search) + (make-local-variable 'imenu-create-index-function) + (make-local-variable 'imenu-generic-expression) + (make-local-variable 'indent-line-function) + (make-local-variable 'parse-sexp-lookup-properties) + (make-local-variable 'uncomment-region-function) + (make-local-variable 'yank-excluded-properties) + + (setq web-mode-time (current-time)) + + (setq comment-end "-->" + comment-region-function 'web-mode-comment-or-uncomment-region + comment-start "<!--" + fill-paragraph-function 'web-mode-fill-paragraph + ;;font-lock-defaults '(web-mode-font-lock-keywords t) + font-lock-defaults '('(web-mode-fontify) t) + font-lock-extend-region-functions '(web-mode-extend-region) + font-lock-support-mode nil + font-lock-unfontify-region-function 'web-mode-unfontify-region + imenu-case-fold-search t + imenu-create-index-function 'web-mode-imenu-index + indent-line-function 'web-mode-indent-line + parse-sexp-lookup-properties t + yank-excluded-properties t + uncomment-region-function 'web-mode-comment-or-uncomment-region + prettify-symbols-alist web-mode-prettify-symbols-alist) + + (substitute-key-definition #'indent-new-comment-line + #'web-mode-comment-indent-new-line + web-mode-map global-map) + + (add-hook 'after-change-functions #'web-mode-on-after-change nil t) + (add-hook 'after-save-hook #'web-mode-on-after-save t t) + (add-hook 'change-major-mode-hook #'web-mode-on-exit nil t) + (add-hook 'post-command-hook #'web-mode-on-post-command nil t) + + (cond + ((boundp 'yas-after-exit-snippet-hook) + (add-hook 'yas-after-exit-snippet-hook + 'web-mode-yasnippet-exit-hook + t t)) + ((boundp 'yas/after-exit-snippet-hook) + (add-hook 'yas/after-exit-snippet-hook + 'web-mode-yasnippet-exit-hook + t t)) + ) + + (when web-mode-enable-whitespace-fontification + (web-mode-whitespaces-on)) + + (when web-mode-enable-sexp-functions + (setq-local forward-sexp-function #'web-mode-forward-sexp)) + + (web-mode-guess-engine-and-content-type) + (setq web-mode-change-beg (point-min) + web-mode-change-end (point-max)) + (when (> (point-max) 256000) + (web-mode-buffer-fontify)) + + (when (and (boundp 'hs-special-modes-alist) + (not (assoc major-mode hs-special-modes-alist))) + (add-to-list 'hs-special-modes-alist '(web-mode "{" "}" "/[*/]" web-mode-forward-sexp nil)) + ) ;when + + ;; compatibility with emacs < 24 + (if (fboundp 'prog-mode) + (put 'web-mode 'derived-mode-parent 'prog-mode)) + + (cond + ((not (buffer-file-name)) + ) + ((string-match-p "web-mode-benchmark.html" (buffer-file-name)) + (web-mode-measure "end")) + ) ;cond + + ) + +;;---- INVALIDATION ------------------------------------------------------------ + +;; 1/ after-change +;; 2/ extend-region +;; 3/ scan +;; 4/ fontify +;; 5/ post-command + +(defun web-mode-on-after-change (beg end len) + (when web-mode-trace + (message "after-change: pos(%d) beg(%d) end(%d) len(%d) this-command(%S)" + (point) beg end len this-command)) + (when (or (null web-mode-change-beg) (< beg web-mode-change-beg)) + (setq web-mode-change-beg beg)) + (when (or (null web-mode-change-end) (> end web-mode-change-end)) + (setq web-mode-change-end end))) + +(defun web-mode-extend-region () + (when web-mode-trace + (message "extend-region: font-lock-beg(%S) font-lock-end(%S) web-mode-change-beg(%S) web-mode-change-end(%S) web-mode-skip-fontification(%S)" + font-lock-beg font-lock-end web-mode-change-beg web-mode-change-end web-mode-skip-fontification)) + (when (and (string= web-mode-engine "php") + (and (>= font-lock-beg 6) (<= font-lock-beg 9)) + (or (message (buffer-substring-no-properties 1 6)) t) + (string= (buffer-substring-no-properties 1 6) "<?php")) + (setq font-lock-beg (point-min) + font-lock-end (point-max)) + ) + (when (or (null web-mode-change-beg) (< font-lock-beg web-mode-change-beg)) + (when web-mode-trace (message "extend-region: font-lock-beg(%S) < web-mode-change-beg(%S)" font-lock-beg web-mode-change-beg)) + (setq web-mode-change-beg font-lock-beg)) + (when (or (null web-mode-change-end) (> font-lock-end web-mode-change-end)) + (when web-mode-trace (message "extend-region: font-lock-end(%S) > web-mode-change-end(%S)" font-lock-end web-mode-change-end)) + (setq web-mode-change-end font-lock-end)) + (when font-lock-dont-widen + (setq web-mode-change-beg (max web-mode-change-beg (point-min)) + web-mode-change-end (min web-mode-change-end (point-max)))) + (let ((region (web-mode-scan web-mode-change-beg web-mode-change-end))) + (when region + ;;(message "region: %S" region) + (setq font-lock-beg (car region) + font-lock-end (cdr region)) + ) ;when + ) ;let + nil) + +(defun web-mode-scan (&optional beg end) + (when web-mode-trace + (message "scan: beg(%S) end(%S) web-mode-change-beg(%S) web-mode-change-end(%S)" + beg end web-mode-change-beg web-mode-change-end)) + (unless beg (setq beg web-mode-change-beg)) + (unless end (setq end web-mode-change-end)) + ;;(message "%S %S %S" web-mode-content-type (get-text-property beg 'part-side) (get-text-property end 'part-side)) + (when (and end (> end (point-max))) + (setq end (point-max))) + (setq web-mode-change-beg nil + web-mode-change-end nil) + (cond + ((or (null beg) (null end)) + nil) + ((and (member web-mode-engine '("php" "asp")) + (get-text-property beg 'block-side) + (get-text-property end 'block-side) + (> beg (point-min)) + (not (eq (get-text-property (1- beg) 'block-token) 'delimiter-beg)) + (not (eq (get-text-property end 'block-token) 'delimiter-end))) + ;;(message "invalidate block (%S > %S)" beg end) + (web-mode-invalidate-block-region beg end)) + ((and (or (member web-mode-content-type + '("css" "javascript" "json" "jsx" "sass" "stylus" "typescript")) + (and (get-text-property beg 'part-side) + (get-text-property end 'part-side) + (> beg (point-min)) + (get-text-property (1- beg) 'part-side)) + )) + ;;(message "invalidate part (%S > %S)" beg end) + (web-mode-invalidate-part-region beg end)) + (t + ;;(message "invalidate default (%S > %S)" beg end) + (web-mode-invalidate-region beg end)) + ) ;cond + ) + +(defun web-mode-invalidate-region (reg-beg reg-end) + (when web-mode-trace + (message "invalidate-region: point(%S) reg-beg(%S) reg-end(%S)" (point) reg-beg reg-end)) + (setq reg-beg (web-mode-invalidate-region-beginning-position reg-beg) + reg-end (web-mode-invalidate-region-end-position reg-end)) + ;;(message "invalidate-region: reg-beg(%S) reg-end(%S)" reg-beg reg-end) + (web-mode-scan-region reg-beg reg-end)) + +(defun web-mode--command-is-self-insert-p () + "Return non-nil if `this-command' is `self-insert-command'. +Also return non-nil if it is the command `self-insert-command' is remapped to." + (memq this-command (list 'self-insert-command + (key-binding [remap self-insert-command])))) + +(defun web-mode-on-post-command () + (when (and web-mode-trace + (not (member this-command + '(left-char right-char previous-line next-line save-buffer mwheel-scroll end-of-line beginning-of-line)))) + (message "post-command: this-command(%S) web-mode-change-beg(%S) web-mode-change-end(%S) previous-state(%S)" + this-command web-mode-change-beg web-mode-change-end web-mode-expand-previous-state)) + (let (ctx n char) + (when (and web-mode-expand-previous-state + (not (member this-command web-mode-commands-like-expand-region))) + (when (eq this-command 'keyboard-quit) + (goto-char web-mode-expand-initial-pos)) + (deactivate-mark) + (when web-mode-expand-initial-scroll + (set-window-start (selected-window) web-mode-expand-initial-scroll) + ) + (setq web-mode-expand-previous-state nil + web-mode-expand-initial-pos nil + web-mode-expand-initial-scroll nil)) + + (when (member this-command '(yank)) + ;;(setq web-mode-skip-fontification nil) + (when (and web-mode-scan-beg web-mode-scan-end global-font-lock-mode) + (save-excursion + (font-lock-fontify-region web-mode-scan-beg web-mode-scan-end)) + (when web-mode-enable-auto-indentation + (indent-region web-mode-scan-beg web-mode-scan-end)) + ) ;and + ) + + (when (and (< (point) 16) web-mode-change-beg web-mode-change-end) + (web-mode-detect-content-type)) + + (when (and web-mode-change-beg web-mode-change-end + web-mode-enable-engine-detection + (or (null web-mode-engine) (string= web-mode-engine "none")) + (< (point) web-mode-chunk-length) + (web-mode-detect-engine)) + (web-mode-on-engine-setted) + (web-mode-buffer-fontify)) + + (when (> (point) 1) + (setq char (char-before))) + + (cond + ((null char) + ) + ((and (>= (point) 3) + (web-mode--command-is-self-insert-p) + (not (member (get-text-property (point) 'part-token) '(comment string))) + (not (eq (get-text-property (point) 'tag-type) 'comment)) + ) + (setq ctx (web-mode-auto-complete))) + ((and web-mode-enable-auto-opening + (member this-command '(newline electric-newline-and-maybe-indent newline-and-indent)) + (or (and (not (eobp)) + (eq (char-after) ?\<) + (eq (get-text-property (point) 'tag-type) 'end) + (looking-back ">\n[ \t]*" (point-min)) + (setq n (length (match-string-no-properties 0))) + (eq (get-text-property (- (point) n) 'tag-type) 'start) + (string= (get-text-property (- (point) n) 'tag-name) + (get-text-property (point) 'tag-name)) + ) + (and (get-text-property (1- (point)) 'block-side) + (string= web-mode-engine "php") + (looking-back "<\\?php[ ]*\n" (point-min)) + (looking-at-p "[ ]*\\?>")))) + (newline-and-indent) + (forward-line -1) + (indent-according-to-mode) + ) + ) ;cond + + (cond + + ((not web-mode-enable-auto-opening) + ) + ((and (member this-command '(newline electric-newline-and-maybe-indent newline-and-indent)) + (get-text-property (point) 'part-side) + (eq (get-text-property (point) 'part-token) 'string)) + (indent-according-to-mode) + (when (and web-mode-change-end (> web-mode-change-end (point-max))) + (message "post-command: enlarge web-mode-change-end") + (setq web-mode-change-end (point-max)) + ) + ) + ((and (web-mode--command-is-self-insert-p) + (or (and ctx + (or (plist-get ctx :auto-closed) + (plist-get ctx :auto-expanded))) + (and (> (point) (point-min)) + (get-text-property (1- (point)) 'tag-end) + (get-text-property (line-beginning-position) 'tag-beg)))) + (indent-according-to-mode) + (when (and web-mode-change-end (> web-mode-change-end (point-max))) + (message "post-command: enlarge web-mode-change-end") + (setq web-mode-change-end (point-max)) + ) + ) + ((and (web-mode--command-is-self-insert-p) + (member (get-text-property (point) 'part-side) '(javascript jsx css)) + (looking-back "^[ \t]+[]})]" (point-min))) + (indent-according-to-mode) + (when (and web-mode-change-end (> web-mode-change-end (point-max))) + (message "post-command: enlarge web-mode-change-end") + (setq web-mode-change-end (point-max)) + ) + ) + ) ; cond web-mode-enable-auto-opening + + (when web-mode-enable-current-element-highlight + (web-mode-highlight-current-element)) + + (when (and web-mode-enable-current-column-highlight + (not (web-mode-buffer-narrowed-p))) + (web-mode-column-show)) + + (when (and web-mode-trace (not (member this-command + '(left-char right-char previous-line next-line save-buffer mwheel-scroll end-of-line beginning-of-line)))) + (when (or web-mode-change-beg web-mode-change-end) + (message "post-command: web-mode-change-beg(%S) web-mode-change-end(%S)" + web-mode-change-end web-mode-change-end)) + (message "-------------------------------------------------------------------") + ) + + )) + +;; NOTE: il est important d'identifier des caractères en fin de ligne +;; web-mode-block-tokenize travaille en effet sur les fins de lignes pour +;; les commentaires de type // +(defun web-mode-invalidate-block-region (pos-beg pos-end) + ;; (message "pos-beg(%S) pos-end(%S)" pos-beg pos-end) + (save-excursion + (let (beg end code-beg code-end) + ;;(message "invalidate-block-region: pos-beg(%S)=%S" pos-beg (get-text-property pos 'block-side)) + ;;(message "code-beg(%S) code-end(%S) pos-beg(%S) pos-end(%S)" code-beg code-end pos-beg pos-end) + (cond + ((not (and (setq code-beg (web-mode-block-code-beginning-position pos-beg)) + (setq code-end (web-mode-block-code-end-position pos-beg)) + (>= pos-beg code-beg) + (<= pos-end code-end) + (> code-end code-beg))) + (web-mode-invalidate-region pos-beg pos-end)) + ((member web-mode-engine '("asp")) + (goto-char pos-beg) + (forward-line -1) + (setq beg (line-beginning-position)) + (when (> code-beg beg) + (setq beg code-beg)) + (goto-char pos-beg) + (forward-line) + (setq end (line-end-position)) + (when (< code-end end) + (setq end code-end)) + ;; ?? pas de (web-mode-block-tokenize beg end) ? + (web-mode-block-tokenize beg end) + (cons beg end) + ) ;asp + (t + (goto-char pos-beg) + ;;(message "pos-beg=%S" pos-beg) + (when (string= web-mode-engine "php") + (cond + ((and (looking-back "\*" (point-min)) + (looking-at-p "/")) + (search-backward "/*" code-beg)) + ) ;cond + ) ;when + (if (web-mode-block-rsb "[;{}(][ ]*\n" code-beg) + (setq beg (match-end 0)) + (setq beg code-beg)) + (goto-char pos-end) + (if (web-mode-block-rsf "[;{})][ ]*\n" code-end) + (setq end (1- (match-end 0))) + (setq end code-end)) + (web-mode-block-tokenize beg end) + ;;(message "beg(%S) end(%S)" beg end) + (cons beg end) + ) + ) ;cond + ))) + +(defun web-mode-invalidate-part-region (pos-beg pos-end) + (save-excursion + (let (beg end part-beg part-end language) + (if (member web-mode-content-type web-mode-part-content-types) + (setq language web-mode-content-type) + (setq language (symbol-name (get-text-property pos-beg 'part-side)))) + (setq part-beg (web-mode-part-beginning-position pos-beg) + part-end (web-mode-part-end-position pos-beg)) + ;;(message "language(%S) pos-beg(%S) pos-end(%S) part-beg(%S) part-end(%S)" + ;; language pos-beg pos-end part-beg part-end) + (goto-char pos-beg) + (cond + ((not (and part-beg part-end + (>= pos-beg part-beg) + (<= pos-end part-end) + (> part-end part-beg))) + (web-mode-invalidate-region pos-beg pos-end)) + ((member language '("javascript" "json" "jsx" "typescript")) + (if (web-mode-javascript-rsb "[;{}(][ ]*\n" part-beg) + (setq beg (match-end 0)) + (setq beg part-beg)) + (goto-char pos-end) + (if (web-mode-javascript-rsf "[;{})][ ]*\n" part-end) + (setq end (match-end 0)) + (setq end part-end)) + (web-mode-scan-region beg end language)) + ((member language '("css" "sass")) + (let (rule1 rule2) + (setq rule1 (web-mode-css-rule-current pos-beg)) + (setq rule2 rule1) + (when (> pos-end (cdr rule1)) + (setq rule2 (web-mode-css-rule-current pos-end))) + (setq beg (car rule1) + end (cdr rule2)) + ) + (web-mode-scan-region beg end language)) + (t + (setq beg part-beg + end part-end) + (web-mode-scan-region beg end language)) + ) ;cond + ))) + +(defun web-mode-invalidate-region-beginning-position (pos) + (save-excursion + (goto-char pos) + + (cond + ((and (looking-at-p ">") ;#1151 + (looking-back "--" (point-min))) + (search-backward "<!--" nil t)) + ((and (bolp) (not (bobp))) + (backward-char)) + ) + + (beginning-of-line) + ;;(message "pos=%S point=%S %S" pos (point) (text-properties-at (point))) + (setq pos (point-min)) + (let ((continue (not (bobp)))) + (while continue + (cond + ((bobp) + (setq continue nil)) + ;; NOTE: Going back to the previous start tag is necessary + ;; when inserting a part endtag (e.g. </script>). + ;; Indeed, parts must be identified asap. + ((and (progn (back-to-indentation) t) + (get-text-property (point) 'tag-beg) + (eq (get-text-property (point) 'tag-type) 'start)) + (setq pos (point) + continue nil)) + (t + (forward-line -1)) + ) ;cond + ) ;while + ;;(message "pos=%S" pos) + pos))) + +(defun web-mode-invalidate-region-end-position (pos) + (save-excursion + (goto-char pos) + ;;(message "pos=%S %S" pos (get-text-property pos 'block-token)) + (when (string= web-mode-engine "jsp") + (cond + ((and (looking-back "<%" (point-min)) + (looking-at-p "--")) + (search-forward "--%>")) + ((and (looking-back "-- %" (point-min)) + (looking-at-p ">")) + (search-forward "--%>")) + ) ;cond + ) ;when + (setq pos (point-max)) + (let ((continue (not (eobp)))) + (while continue + (end-of-line) + ;;(message "%S %S" (point) (get-text-property (point) 'block-token)) + (cond + ((eobp) + (setq continue nil)) + ((and (not (get-text-property (point) 'tag-type)) + (not (get-text-property (point) 'part-side)) + (not (get-text-property (point) 'block-side))) + (setq pos (point) + continue nil)) + (t + (forward-line)) + ) ;cond + ) ;while + pos))) + +(defun web-mode-buffer-scan () + "Scan entine buffer." + (interactive) + (web-mode-scan-region (point-min) (point-max))) + +(defun web-mode-scan-region (beg end &optional content-type) + "Identify nodes/parts/blocks and syntactic symbols (strings/comments/etc.)." + ;;(message "scan-region: beg(%d) end(%d) content-type(%S)" beg end content-type) + (setq web-mode-scan-beg beg + web-mode-scan-end end) + (web-mode-with-silent-modifications + (save-excursion + (save-restriction + (save-match-data + (let ((inhibit-point-motion-hooks t) + (inhibit-quit t)) + (remove-list-of-text-properties beg end web-mode-scan-properties) + (cond + ((and content-type (string= content-type "php")) + ) + ((and content-type (member content-type web-mode-part-content-types)) + (put-text-property beg end 'part-side + (cond + ((string= content-type "javascript") 'javascript) + ((string= content-type "json") 'json) + ((string= content-type "jsx") 'jsx) + ((string= content-type "css") 'css) + ((string= content-type "sql") 'sql) + ((string= content-type "pug") 'pug) + ((string= content-type "sass") 'sass) + ((string= content-type "stylus") 'stylus) + ((string= content-type "markdown") 'markdown) + ((string= content-type "ruby") 'ruby) + ((string= content-type "typescript") 'typescript) + )) + (web-mode-scan-blocks beg end) + (web-mode-part-scan beg end content-type)) + ((member web-mode-content-type web-mode-part-content-types) + (web-mode-scan-blocks beg end) + (web-mode-part-scan beg end)) + ((string= web-mode-engine "riot") + (web-mode-scan-elements beg end) + (web-mode-scan-blocks beg end) + (web-mode-part-foreach beg end 'web-mode-part-scan)) + (t + (web-mode-scan-blocks beg end) + (web-mode-scan-elements beg end) + (web-mode-part-foreach beg end 'web-mode-part-scan)) + ) ;cond + (cons beg end) + )))))) + +;;---- LEXER BLOCKS ------------------------------------------------------------ + +(defun web-mode-scan-blocks (reg-beg reg-end) + "Identifies blocks (with block-side, block-beg, block-end text properties)." + (save-excursion + + (let ((i 0) open close closing-string sub1 sub2 pos tagopen tmp delim-open delim-close part-beg part-end tagclose) + + (goto-char reg-beg) + + ;;(message "%S: %Sx%S" (point) reg-beg reg-end) + ;;(message "regexp=%S" web-mode-block-regexp) + (while (and (< i 2000) + (> reg-end (point)) + web-mode-block-regexp + (re-search-forward web-mode-block-regexp reg-end t) + (not (eobp))) + + (setq i (1+ i) + closing-string nil + close nil + tagopen (match-string 0) + open (match-beginning 0) + delim-open nil + delim-close nil + pos nil) + + (let ((l (length tagopen))) + (when (member (string-to-char tagopen) '(?\s ?\t)) + (setq tagopen (replace-regexp-in-string "\\`[ \t]*" "" tagopen)) + (setq open (+ open (- l (length tagopen)))) + (setq l (length tagopen)) + ) + (setq sub1 (substring tagopen 0 1) + sub2 (substring tagopen 0 (if (>= l 2) 2 1))) + ) + ;;(message " found block #(%S) at pos=(%S), part-type=(%S)" i open (get-text-property open 'part-side)) + (cond + + ((string= web-mode-engine "php") + (unless (member (char-after) '(?x ?X)) + (setq closing-string '("<\\?". "\\?>"))) + (cond + ((looking-at-p "<?php") + (setq delim-open "<?php")) + ((eq (char-after) ?\=) + (setq delim-open "<?=")) + (t + (setq delim-open "<?")) + ) ;cond + (setq delim-close "?>") + ) ;php + + ((string= web-mode-engine "erb") + (cond + ((string= sub2 "<%") + (setq closing-string '("<%". "%>") + delim-open "<%\\(==\\|[=-]\\)?" + delim-close "[-]?%>")) + (t + (setq closing-string "EOL" + delim-open "%")) + ) + ) ;erb + + ((string= web-mode-engine "django") + (cond + ((string= sub2 "{{") + (setq closing-string "EODQ" + ;;(setq closing-string '("{{" . "}}") + delim-open "{{" + delim-close "}}")) + ((string= sub2 "{%") + (setq closing-string "%}" + delim-open "{%[+-]?" + delim-close "[-]?%}")) + ((string= sub2 "{#") + (setq closing-string "#}")) + (t + (setq closing-string "EOL" + delim-open "#[#]?")) + ) + ) ;django + + ((string= web-mode-engine "anki") + (setq closing-string "}}" + delim-open "{{[#/^]?" + delim-close "}}") + ) ;anki + + ((string= web-mode-engine "ejs") + (setq closing-string "%>" + delim-open "<%[=-]?" + delim-close "[-]?%>") + ) ;ejs + + ((string= web-mode-engine "lsp") + (setq closing-string "%>" + delim-open "<%[%#]?" + delim-close "%>") + ) ;lsp + + ((string= web-mode-engine "mako") + (cond + ((and (string= tagopen "<%") + (member (char-after) '(?\s ?\n ?\!))) + (setq closing-string "%>" + delim-open "<%[!]?" + delim-close "%>")) + ((member sub2 '("<%" "</")) + (setq closing-string ">" + delim-open "</?%" + delim-close "/?>")) + ((string= sub2 "${") + (setq closing-string "}" + delim-open "${" + delim-close "}")) + (t + (setq closing-string "EOL" + delim-open "%")) + ) + ) ;mako + + ((string= web-mode-engine "cl-emb") + (cond + ((string= tagopen "<%#") + (setq closing-string "#%>")) + ((string= sub2 "<%") + (setq closing-string "%>" + delim-open "<%[=%]?" + delim-close "%>")) + ) + ) ;cl-emb + + ((string= web-mode-engine "artanis") + (cond + ((string= tagopen "<%;") + (setq closing-string "%>")) + ((string= tagopen "<%#|") + (setq closing-string "|#%>")) + ((string= sub2 "<@") + (setq closing-string "%>" + delim-open "<@\\(css\\|icon\\|include\\|js\\)" + delim-close "%>")) + ((string= sub2 "<%") + (setq closing-string "%>" + delim-open "<%[=]?" + delim-close "%>")) + ) + ) ;artanis + + ((string= web-mode-engine "elixir") + (cond + ((member (char-after) '(?\#)) + (setq closing-string "%>")) + (t + (setq closing-string "%>" + delim-open "<%[=%]?" + delim-close "%>")) + ) + ) ;elixir + + ((string= web-mode-engine "mojolicious") + (cond + ((string= tagopen "<%#") + (setq closing-string "%>")) + ((string= sub2 "<%") + (setq closing-string "%>" + delim-open "<%\\(==\\|[=%]\\)?" + delim-close "%>")) + ((string= sub2 "%#") + (setq closing-string "EOL")) + (t + (setq closing-string "EOL" + delim-open "%\\(==\\|[=%]\\)?")) + ) + ) ;mojolicious + + ((string= web-mode-engine "ctemplate") + (cond + ((member tagopen '("{{{" "{{~")) + (setq closing-string "}~?}}" + delim-open "{{~?{" + delim-close "}~?}}") + ) + ((string= tagopen "{~{") + (setq closing-string "}~?}" + delim-open "{~{" + delim-close "}~?}") + ) + ((string= tagopen "{{!") + (setq closing-string (if (looking-at-p "--") "--}}" "}}")) + ) + ((string= sub2 "{{") + (setq closing-string "}~?}" + delim-open "{{[>#/%^&]?" + delim-close "}~?}")) + (t + (setq closing-string "}}" + delim-open "${{" + delim-close "}}")) + ) + ) ;ctemplate + + ((string= web-mode-engine "aspx") + (setq closing-string "%>" + delim-open "<%[:=#@$]?" + delim-close "%>") + ) ;aspx + + ((string= web-mode-engine "asp") + (cond + ((string= sub2 "<%") + (setq closing-string "%>" + delim-open "<%[:=#@$]?" + delim-close "%>")) + (t + (setq closing-string ">" + delim-open "</?" + delim-close "/?>")) + ) + ) ;asp + + ((string= web-mode-engine "jsp") + (cond + ((looking-at-p "--") + (setq closing-string "--%>")) + ((string= sub2 "<%") + (setq closing-string "%>" + delim-open "<%\\([!=@]\\|#=\\)?" + delim-close "[-]?%>")) + ((string= sub2 "${") + (setq closing-string "}" + delim-open "${" + delim-close "}")) + ) + ) ;jsp + + ((string= web-mode-engine "clip") + (setq closing-string ">" + delim-open "</?" + delim-close "/?>") + ) ;clip + + ((string= web-mode-engine "perl") + (setq closing-string ">" + delim-open "</?" + delim-close "/?>") + ) ;perl + + ((string= web-mode-engine "blade") + (cond + ((string= tagopen "{{-") + (setq closing-string "--}}")) + ((string= tagopen "{!!") + (setq closing-string "!!}" + delim-open "{!!" + delim-close "!!}")) + ((string= tagopen "@{{") + (setq closing-string nil)) + ((string= tagopen "{{{") + (setq closing-string "}}}" + delim-open "{{{" + delim-close "}}}")) + ((string= sub2 "{{") + (setq closing-string "}}" + delim-open "{{" + delim-close "}}")) + ((looking-at-p "[[:alnum:]]+\\.[[:alpha:]]+") + ) + ((looking-at-p "[[:alnum:]]+(") + (setq closing-string ")" + delim-open "@")) + ((string= sub1 "@") + (setq closing-string "EOB" + delim-open "@")) + ) + ) ;blade + + ((string= web-mode-engine "smarty") + (cond + ((string= tagopen "{*") + (setq closing-string "*}") + ) + ((string= tagopen "{#") + (setq closing-string "#}" + delim-open "{#" + delim-close "#}") + ) + (t + (setq closing-string (cons "{" "}") + delim-open "{/?" + delim-close "}") + ) ;t + ) ;cond + ) ;smarty + + ((string= web-mode-engine "hero") + (setq closing-string "%>" + delim-open "<%==?\\([biufsv]\\|bs\\)?\\|<%[:~@+!]?" + delim-close "%>") + ) ;hero + + ((string= web-mode-engine "xoops") + (cond + ((string= tagopen "<{*") + (setq closing-string "*}>") + ) + ((string= tagopen "<{#") + (setq closing-string "#}>" + delim-open "<{#" + delim-close "#}>") + ) + (t + (setq closing-string (cons "<{" "}>") + delim-open "<{/?" + delim-close "}>") + ) ;t + ) ;cond + ) ;xoops + + ((string= web-mode-engine "web2py") + (setq closing-string "}}" + delim-open "{{[=]?" + delim-close "}}") + ) ;web2py + + ((string= web-mode-engine "expressionengine") + (cond + ((string= sub2 "{!--") + (setq closing-string "--}")) + (t + (setq closing-string '("{". "}") + delim-open "{/?" + delim-close "}") + ) + ) + ) ;expressionengine + + ((string= web-mode-engine "dust") + (cond + ((string= sub2 "{!") + (setq closing-string "!}")) + (t + (setq closing-string '("{". "}") + delim-open "{[#/:?@><+^]?" + delim-close "/?}") + ) + ) + ) ;dust + + ((string= web-mode-engine "svelte") + (cond + ((string= sub2 "{!") + (setq closing-string "!}")) + ((string= sub2 "{}") + (setq closing-string nil + delim-open nil + delim-close nil)) + (t + (setq closing-string '("{". "}") + delim-open "{[#/:?@><+^]?" + delim-close "/?}") + ) + ) + ) ;svelte + + ((string= web-mode-engine "closure") + (cond + ((string= sub2 "//") + (setq closing-string "EOL") + ) + ((string= sub2 "/*") + (setq closing-string "*/") + ) + (t + (setq closing-string "}" + delim-open "{/?" + delim-close "/?}") + ) + ) + ) ;closure + + ((string= web-mode-engine "go") + (setq closing-string "}}" + delim-open "{{-?" + delim-close "-?}}") + ) ;go + + ((string= web-mode-engine "angular") + (setq closing-string "}}" + delim-open "{{" + delim-close "}}") + ) ;angular + + ((string= web-mode-engine "vue") + (cond + ((string-match-p "[:@][-[:alpha:]]+=\"" tagopen) + (setq closing-string "\"" + delim-open tagopen + delim-close "\"")) + ((string= tagopen "{{") + (setq closing-string "}}" + delim-open "{{" + delim-close "}}"))) + ) ;vue + + ((string= web-mode-engine "mason") + (cond + ((and (member sub2 '("<%" "</")) + (looking-at "[[:alpha:]]+")) + (if (member (match-string-no-properties 0) '("after" "around" "augment" "before" "def" "filter" "method" "override")) + (setq closing-string ">" + delim-open "<[/]?%" + delim-close ">") + (setq closing-string (concat "</%" (match-string-no-properties 0) ">") + delim-open "<[^>]+>" + delim-close "<[^>]+>") + ) ;if + ) + ((and (string= sub2 "<%") + (eq (char-after) ?\s)) + (setq closing-string "%>" + delim-open "<%" + delim-close "%>")) + ((string= tagopen "</&") + (setq closing-string ">" + delim-open "</&" + delim-close ">") + ) + ((string= sub2 "<&") + (setq closing-string "&>" + delim-open "<&[|]?" + delim-close "&>")) + (t + (setq closing-string "EOL" + delim-open "%")) + ) + ) ;mason + + ((string= web-mode-engine "underscore") + (setq closing-string "%>" + delim-open "<%" + delim-close "%>") + ) ;underscore + + ((string= web-mode-engine "template-toolkit") + (cond + ((string= tagopen "%%#") + (setq closing-string "EOL")) + ((string= tagopen "[%#") + (setq closing-string "%]")) + (t + (setq closing-string "%]" + delim-open "\\[%[-+]?" + delim-close "[-=+]?%\\]")) + ) + ) ;template-toolkit + + ((string= web-mode-engine "freemarker") + (cond + ((and (string= sub2 "<#") (eq (char-after) ?\-)) + (setq closing-string "-->")) + ((string= sub1 "<") + (setq closing-string ">" + delim-open "</?[#@]" + delim-close "/?>")) + ((string= sub1 "[") + (setq closing-string "]" + delim-open "\\[/?[#@]" + delim-close "/?\\]")) + (t + (setq closing-string "}" + delim-open "${" + delim-close "}")) + ) + ) ;freemarker + + ((string= web-mode-engine "velocity") + (cond + ((string= sub2 "##") + (setq closing-string "EOL")) + ((string= sub2 "#*") + (setq closing-string "*#")) + (t + (setq closing-string "EOV" + delim-open "#")) + ) + ) ;velocity + + ((string= web-mode-engine "razor") + (cond + ((string= sub2 "@@") + (forward-char 2) + (setq closing-string nil)) + ((string= sub2 "@*") + (setq closing-string "*@")) + ((string= sub1 "@") + (setq closing-string "EOR" + delim-open "@")) + ((and (string= sub1 "}") + (looking-at-p "[ ]*\n")) + ;;(setq closing-string "EOC") + (save-excursion + (let (paren-pos) + (setq paren-pos (web-mode-part-opening-paren-position (1- (point)))) + (if (and paren-pos (get-text-property paren-pos 'block-side)) + (setq closing-string "EOC") + (setq closing-string nil) + ) ;if + ) ;let + ) ;save-excursion + ;;(message "%s %S %S" sub2 (point) (get-text-property (point) 'part-side)) + ) + ((string= sub1 "}") + ;;(message "%s: %s" (point) sub1) + (save-excursion + (let (paren-pos) + (setq paren-pos (web-mode-part-opening-paren-position (1- (point)))) + (if (and paren-pos (get-text-property paren-pos 'block-side)) + (setq closing-string "EOR") + (setq closing-string nil) + ) ;if + ) ;let + ) ;save-excursion + ) ;case } + ) ;cond + ) ;razor + + ((and (string= web-mode-engine "riot") + (not (get-text-property open 'part-side))) + (setq closing-string (if (string= tagopen "{") "}" "/// end script") + delim-open "{" + delim-close "}") + ) ;riot + + ((string= web-mode-engine "spip") + (cond + ((and (string= sub1 "#") + (looking-at "[A-Z0-9_]+")) + (setq closing-string (match-string-no-properties 0))) + ((string= sub1 "(") + (setq closing-string '("(" . ")"))) + ((string= sub1 "{") + (setq closing-string '("{" . "}"))) + ((string= sub2 "<:") + (setq closing-string ":>")) + (t + (setq closing-string "]")) + )) + + ((string= web-mode-engine "marko") + (setq closing-string "}" + delim-open "${" + delim-close "}") + ) ;marko + + ) ;cond + + (when closing-string + (cond + + ((listp closing-string) + (cond + ((web-mode-rsf-balanced (car closing-string) (cdr closing-string) reg-end t) + (setq close (match-end 0) + pos (point)) + ) + ((and (string= web-mode-engine "php") + (string= "<?" sub2)) + + (if (or (text-property-not-all (1+ open) (point-max) 'tag-beg nil) + (text-property-not-all (1+ open) (point-max) 'block-beg nil) + (looking-at-p "[ \t\n]*<")) + (setq close nil + delim-close nil + pos (point)) + (setq close (point-max) + delim-close nil + pos (point-max)) + ) ;if + ) ;case + ) ;cond + ) ;case listp + + ((and (string= web-mode-engine "smarty") + (string= closing-string "}")) + (goto-char open) + (setq tmp (web-mode-closing-delimiter-position + "}" + (point) + (line-end-position))) + (if tmp + (setq tmp (1+ tmp)) + (setq tmp (line-end-position))) + (goto-char tmp) + (setq close (point) + pos (point)) + ) + + ((and (member web-mode-engine '("closure")) + (string= closing-string "}")) + (when (web-mode-closure-skip reg-beg reg-end) + (setq close (point) + pos (point)) + ;;(message "close=%S pos=%S" close pos) + ) ;when + ) + + ((string= closing-string "EOB") + (web-mode-blade-skip open) + (setq close (point) + pos (point))) + + ((string= closing-string "EOL") + (end-of-line) + (setq close (point) + pos (point))) + + ((string= closing-string "EOC") + (setq close (point) + pos (point))) + + ((string= closing-string "EODQ") + (when (web-mode-django-skip reg-beg reg-end) + (setq close (point) + pos (point)) + )) + + ((string= closing-string "EOR") + (web-mode-razor-skip open) + (setq close (if (> (point) reg-end) reg-end (point)) + pos (if (> (point) reg-end) reg-end (point))) + (goto-char pos)) + + ((string= closing-string "EOV") + (web-mode-velocity-skip open) + (setq close (point) + pos (point))) + + ((and (member web-mode-engine '("ctemplate")) + (re-search-forward closing-string reg-end t)) + (setq close (match-end 0) + pos (point))) + + ((search-forward closing-string reg-end t) + (setq close (match-end 0) + pos (point))) + ) ;cond + + (when (and close (>= reg-end pos)) + ;;(message "pos(%S) : open(%S) close(%S)" pos open close) + (put-text-property open (1+ open) 'block-beg 0) + (put-text-property open (1+ open) 'block-controls 0) + (put-text-property open close 'block-side t) + (put-text-property (1- close) close 'block-end t) + (when delim-open + (web-mode-block-delimiters-set open close delim-open delim-close)) + (web-mode-block-scan open close) + (cond + ((and (string= web-mode-engine "erb") + (looking-at-p "<%= javascript_tag do %>")) + (setq tagopen "<%= javascript_tag do %>")) + ((and (string= web-mode-engine "mojolicious") + (looking-at-p "%= javascript begin")) + (setq tagopen "%= javascript begin")) + ((and (string= web-mode-engine "mako") + (looking-at-p "<%block filter=\"collect_js\">")) + (setq tagopen "<%block filter=\"collect_js\">")) + ((and (string= web-mode-engine "mako") + (looking-at-p "<%block filter=\"collect_css\">")) + (setq tagopen "<%block filter=\"collect_css\">")) + ((and (string= web-mode-engine "django") + (looking-at-p "{% javascript %}")) + (setq tagopen "{% javascript %}")) + ((and (string= web-mode-engine "django") + (looking-at-p "{% schema %}")) + (setq tagopen "{% schema %}")) + ((and (string= web-mode-engine "django") + (looking-at-p "{% stylesheet %}")) + (setq tagopen "{% stylesheet %}")) + ) + ;;(message "%S %s" (point) tagopen) + (when (and (member tagopen '("<r:script" "<r:style" + "<c:js" "<c:css" + "<%= javascript_tag do %>" + "<%block filter=\"collect_js\">" + "<%block filter=\"collect_css\">" + "{% javascript %}" + "{% schema %}" + "{% stylesheet %}" + "%= javascript begin")) + (setq part-beg close) + (setq tagclose + (cond + ((string= tagopen "<r:script") "</r:script") + ((string= tagopen "<r:style") "</r:style") + ((string= tagopen "<c:js") "</c:js") + ((string= tagopen "<c:css") "</c:css") + ((string= tagopen "{% javascript %}") "{% endjavascript %}") + ((string= tagopen "{% schema %}") "{% endschema %}") + ((string= tagopen "{% stylesheet %}") "{% endstylesheet %}") + ((string= tagopen "%= javascript begin") "% end") + ((string= tagopen "<%= javascript_tag do %>") "<% end %>") + ((member tagopen '("<%block filter=\"collect_js\">" + "<%block filter=\"collect_css\">")) "</%block") + )) + (web-mode-sf tagclose) + (setq part-end (match-beginning 0)) + (> part-end part-beg)) + ;;(message "end=%S" (point)) + (put-text-property part-beg part-end + 'part-side + (cond + ((member tagopen '("<r:style" "<c:css" "<%block filter=\"collect_css\">" "{% stylesheet %}")) 'css) + (t 'javascript))) + (setq pos part-beg + part-beg nil + part-end nil) + ) ;when + ) ;when close + + (if pos (goto-char pos)) + + ) ;when closing-string + + ) ;while + + (cond + ((>= i 2000) + (message "scan-blocks ** warning (%S) **" i)) + ((string= web-mode-engine "razor") + (web-mode-block-foreach reg-beg reg-end 'web-mode-block-scan)) + ((string= web-mode-engine "django") + (web-mode-scan-engine-comments reg-beg reg-end + "{% comment %}" "{% endcomment %}")) + ((string= web-mode-engine "mako") + (web-mode-scan-engine-comments reg-beg reg-end + "<%doc>" "</%doc>")) + ((string= web-mode-engine "mason") + (web-mode-scan-engine-comments reg-beg reg-end + "<%doc>" "</%doc>")) + ) ;cond + + ))) + +(defun web-mode-scan-engine-comments (reg-beg reg-end tag-start tag-end) + "Scan engine comments (mako, django)." + (save-excursion + (let (beg end (continue t)) + (goto-char reg-beg) + (while (and continue + (< (point) reg-end) + (re-search-forward tag-start reg-end t)) + (goto-char (match-beginning 0)) + (setq beg (point)) + (if (not (re-search-forward tag-end reg-end t)) + (setq continue nil) + (setq end (point)) + (remove-list-of-text-properties beg end web-mode-scan-properties) + (add-text-properties beg end '(block-side t block-token comment)) + (put-text-property beg (1+ beg) 'block-beg 0) + (put-text-property (1- end) end 'block-end t) + ) ;if + ) ;while + ))) + +(defun web-mode-closure-skip (reg-beg reg-end) + (let (regexp char pos inc continue found) + (setq regexp "[\"'{}]" + inc 0) + (while (and (not found) (re-search-forward regexp reg-end t)) + (setq char (char-before)) + (cond + ((get-text-property (point) 'block-side) + (setq found t)) + ((eq char ?\{) + (setq inc (1+ inc))) + ((eq char ?\}) + (cond + ((and (not (eobp)) + (< inc 1)) + (setq found t + pos (point))) + ((> inc 0) + (setq inc (1- inc))) + ) + ) + ((eq char ?\') + (setq continue t) + (while (and continue (search-forward "'" reg-end t)) + (setq continue (web-mode-string-continue-p reg-beg)) + ) + ) + ((eq char ?\") + (setq continue t) + (while (and continue (search-forward "\"" reg-end t)) + (setq continue (web-mode-string-continue-p reg-beg)) + ) + ) + ) ;cond + ) ;while + pos)) + +(defun web-mode-django-skip (reg-beg reg-end) + (let (regexp char pos inc continue found) + (setq regexp "[\"'{}]" + inc 0) + (while (and (not found) (re-search-forward regexp reg-end t)) + (setq char (char-before)) + (cond + ((get-text-property (point) 'block-side) + (setq found t)) + ((eq char ?\{) + (setq inc (1+ inc))) + ((eq char ?\}) + (cond + ((and (not (eobp)) + (eq (char-after) ?\}) + (< inc 2)) + (forward-char) + (setq found t + pos (1+ (point)))) + ((> inc 0) + (setq inc (1- inc))) + ) + ) + ((eq char ?\') + (setq continue t) + (while (and continue (search-forward "'" reg-end t)) + (setq continue (web-mode-string-continue-p reg-beg)) + ) + ) + ((eq char ?\") + (setq continue t) + (while (and continue (search-forward "\"" reg-end t)) + (setq continue (web-mode-string-continue-p reg-beg)) + ) + ) + ) ;cond + ) ;while + pos)) + +(defun web-mode-blade-skip (pos) + (goto-char pos) + (forward-char) + (skip-chars-forward "a-zA-Z0-9_-")) + +(defun web-mode-velocity-skip (pos) + (goto-char pos) + (let ((continue t) (i 0)) + (when (eq ?\# (char-after)) + (forward-char)) + (when (member (char-after) '(?\$ ?\@)) + (forward-char)) + (when (member (char-after) '(?\!)) + (forward-char)) + (cond + ((member (char-after) '(?\{)) + (search-forward "}" nil t)) + ((looking-at-p "def \\|define ") + (search-forward ")" (line-end-position) t)) + (t + (setq continue t) + (while continue + (skip-chars-forward "a-zA-Z0-9_-") + (when (> (setq i (1+ i)) 500) + (message "velocity-skip ** warning (%S) **" pos) + (setq continue nil)) + (when (member (char-after) '(?\()) + (search-forward ")" nil t)) + (if (member (char-after) '(?\.)) + (forward-char) + (setq continue nil)) + ) ;while + ) ;t + ) ;cond + )) + +(defun web-mode-razor-skip (pos) + (goto-char pos) + (let ((continue t) (i 0)) + (while continue + (skip-chars-forward " =@a-zA-Z0-9_-") + (cond + ((> (setq i (1+ i)) 500) + (message "razor-skip ** warning **") + (setq continue nil)) + ((and (eq (char-after) ?\*) + (eq (char-before) ?@)) + (when (not (search-forward "*@" nil t)) + (setq continue nil)) + ) + ((looking-at-p "@[({]") + (forward-char) + (when (setq pos (web-mode-closing-paren-position (point))) + (goto-char pos)) + (forward-char) + ) + ((and (not (eobp)) (eq ?\( (char-after))) + (cond + ((looking-at-p "[ \n]*[<@]") + (setq continue nil)) + ((setq pos (web-mode-closing-paren-position)) + (goto-char pos) + (forward-char)) + (t + (forward-char)) + ) ;cond + ) + ((and (not (eobp)) (eq ?\< (char-after)) (looking-back "[a-z]" (point-min))) + (setq pos (point)) + (cond + ;; #988 + ((search-forward ">" (line-end-position) t) + (goto-char pos) + (setq continue nil) + ) + (t + (setq continue nil)) + ) ;cond + ) + ((and (not (eobp)) (eq ?\. (char-after))) + (forward-char)) + ((and (not (eobp)) (looking-at-p "[ \n]*else")) + (re-search-forward "[ \t]*else") + ) + ((looking-at-p "[ \n]*{") + (search-forward "{") + (search-forward "=>" (point-at-eol) 't) + (if (looking-at-p "[ \n]*[<@]") + (setq continue nil) + (backward-char) + (when (setq pos (web-mode-closing-paren-position)) + (goto-char pos)) + (forward-char) + ) ;if + ) + ((looking-at-p "}") + (forward-char)) + (t + (setq continue nil)) + ) ;cond + ) ;while + )) + +(defun web-mode-block-delimiters-set (reg-beg reg-end delim-open delim-close) + "Set text-property 'block-token to 'delimiter-(beg|end) on block delimiters (e.g. <?php and ?>)" + ;;(message "reg-beg(%S) reg-end(%S) delim-open(%S) delim-close(%S)" reg-beg reg-end delim-open delim-close) + (when (member web-mode-engine + '("artanis" "anki" "asp" "aspx" "cl-emb" "clip" "closure" "ctemplate" "django" "dust" + "elixir" "ejs" "erb" "expressionengine" "freemarker" "go" "hero" "jsp" "lsp" + "mako" "mason" "mojolicious" + "perl" + "smarty" "template-toolkit" "web2py" "xoops" "svelte")) + (save-excursion + (when delim-open + (goto-char reg-beg) + (looking-at delim-open) + (setq delim-open (match-string-no-properties 0))) + (when delim-close + (goto-char reg-end) + (looking-back delim-close reg-beg t) + (setq delim-close (match-string-no-properties 0))) + )) + (when delim-open + (put-text-property reg-beg (+ reg-beg (length delim-open)) + 'block-token 'delimiter-beg)) + (when delim-close + (put-text-property (- reg-end (length delim-close)) reg-end + 'block-token 'delimiter-end)) + ) + +(defun web-mode-block-foreach (reg-beg reg-end func) + (let ((i 0) (continue t) (block-beg reg-beg) (block-end nil)) + (while continue + (setq block-end nil) + (unless (get-text-property block-beg 'block-beg) + (setq block-beg (web-mode-block-next-position block-beg))) + (when (and block-beg (< block-beg reg-end)) + (setq block-end (web-mode-block-end-position block-beg))) + (cond + ((> (setq i (1+ i)) 2000) + (message "process-blocks ** warning (%S) **" (point)) + (setq continue nil)) + ((or (null block-end) (> block-end reg-end)) + (setq continue nil)) + (t + (setq block-end (1+ block-end)) + (funcall func block-beg block-end) + (setq block-beg block-end) + ) ;t + ) ;cond + ) ;while + )) + +(defun web-mode-block-scan (block-beg block-end) + (let (sub1 sub2 sub3 regexp token-type) + + ;;(message "block-beg=%S block-end=%S" block-beg block-end) + ;;(remove-text-properties block-beg block-end web-mode-scan-properties) + + (goto-char block-beg) + + (cond + ((>= (point-max) (+ block-beg 3)) + (setq sub3 (buffer-substring-no-properties block-beg (+ block-beg 3)) + sub2 (buffer-substring-no-properties block-beg (+ block-beg 2)) + sub1 (buffer-substring-no-properties block-beg (+ block-beg 1))) + ) + ((>= (point-max) (+ block-beg 2)) + (setq sub3 (buffer-substring-no-properties block-beg (+ block-beg 2)) + sub2 (buffer-substring-no-properties block-beg (+ block-beg 2)) + sub1 (buffer-substring-no-properties block-beg (+ block-beg 1))) + ) + (t + (setq sub1 (buffer-substring-no-properties block-beg (+ block-beg 1))) + (setq sub2 sub1 + sub3 sub1) + ) + ) + + (cond + + ((member web-mode-engine '("php" "lsp" "python" "web2py" "mason")) + (setq regexp web-mode-engine-token-regexp)) + + ((string= web-mode-engine "mako") + (cond + ((string= sub2 "##") + (setq token-type 'comment) + ) + (t + (setq regexp web-mode-engine-token-regexp)) + ) + ) ;mako + + ((string= web-mode-engine "django") + (cond + ((member sub2 '("{{" "{%")) + (setq regexp "\"\\|'")) + ((string= sub2 "{#") + (setq token-type 'comment)) + ) + ) ;django + + ((string= web-mode-engine "ctemplate") + (cond + ((string= sub3 "{{!") + (setq token-type 'comment)) + ((member sub2 '("{{")) + ) + ) + ) ;ctemplate + + ((string= web-mode-engine "go") + (cond + ((string= sub3 "{{/") + (setq token-type 'comment)) + ((string= sub2 "{{") + (setq regexp "\"\\|'")) + ) + ) ;go + + ((string= web-mode-engine "hero") + (cond + ((string= sub3 "<%#") + (setq token-type 'comment)) + (t + (setq regexp "\"\\|'")) + ) + ) ;hero + + ((string= web-mode-engine "razor") + (cond + ((string= sub2 "@*") + (setq token-type 'comment)) + (t + (setq regexp "//\\|@\\*\\|\"\\|'")) + ) + ) ;razor + + ((string= web-mode-engine "blade") + (cond + ((string= sub3 "{{-") + (setq token-type 'comment)) + (t + (setq regexp "\"\\|'")) + ) + ) ;blade + + ((string= web-mode-engine "cl-emb") + (cond + ((string= sub3 "<%#") + (setq token-type 'comment)) + (t + (setq regexp "\"\\|'")) + ) + ) ;cl-emb + + ((string= web-mode-engine "artanis") + (cond + ((string= sub3 "<%;") + (setq token-type 'comment)) + ((string= sub3 "<%#|") + (setq token-type 'comment)) + (t + (setq regexp "\"")) + ) + ) ;artanis + + ((string= web-mode-engine "elixir") + (cond + ((string= sub3 "<%#") + (setq token-type 'comment)) + (t + (setq regexp "\"\\|'")) + ) + ) ;elixir + + ((string= web-mode-engine "mojolicious") + (cond + ((or (string= sub2 "%#") (string= sub3 "<%#")) + (setq token-type 'comment)) + (t + (setq regexp "\"\\|'")) + ) + ) ;mojolicious + + ((string= web-mode-engine "velocity") + (cond + ((member sub2 '("##" "#*")) + (setq token-type 'comment)) + ((member sub1 '("$" "#")) + (setq regexp "\"\\|'")) + ) + ) ;velocity + + ((string= web-mode-engine "jsp") + (cond + ((string= sub3 "<%-") + (setq token-type 'comment)) + ((string= sub3 "<%@") + (setq regexp "/\\*")) + ((member sub2 '("${" "#{")) + (setq regexp "\"\\|'")) + ((string= sub2 "<%") + (setq regexp "//\\|/\\*\\|\"\\|'")) + ) + ) ;jsp + + ((string= web-mode-engine "clip") + (setq regexp nil) + ) ;clip + + ((string= web-mode-engine "perl") + (setq regexp nil) + ) ;perl + + ((and (string= web-mode-engine "asp") + (string= sub2 "<%")) + (setq regexp "//\\|/\\*\\|\"\\|''") + ) ;asp + + ((string= web-mode-engine "aspx") + (cond + ((string= sub3 "<%-") + (setq token-type 'comment)) + ((string= sub3 "<%@") + (setq regexp "/\\*")) + ((string= sub3 "<%$") + (setq regexp "\"\\|'")) + (t + (setq regexp "//\\|/\\*\\|\"\\|'")) + ) + ) ;aspx + + ((string= web-mode-engine "freemarker") + (cond + ((member sub3 '("<#-" "[#-")) + (setq token-type 'comment)) + ((member sub2 '("${" "#{")) + (setq regexp "\"\\|'")) + ((or (member sub2 '("<@" "[@" "<#" "[#")) + (member sub3 '("</@" "[/@" "</#" "[/#"))) + (setq regexp "\"\\|'")) + ) + ) ;freemarker + + ((member web-mode-engine '("ejs" "erb")) + (cond + ((string= sub3 "<%#") + (setq token-type 'comment)) + (t + (setq regexp web-mode-engine-token-regexp)) + ) + ) ;erb + + ((string= web-mode-engine "template-toolkit") + (cond + ((member sub3 '("[%#" "%%#")) + (setq token-type 'comment)) + (t + (setq regexp "#\\|\"\\|'")) + ) + ) ;template-toolkit + + ((string= web-mode-engine "underscore") + (setq regexp "/\\*\\|\"\\|'") + ) ;underscore + + ((string= web-mode-engine "angular") + (setq regexp "#\\|\"\\|'")) ;angular + + ((string= web-mode-engine "vue") + ) ;vue + + ((string= web-mode-engine "smarty") + (cond + ((string= sub2 "{*") + (setq token-type 'comment)) + (t + (setq regexp "\"\\|'"))) + ) ;smarty + + ((string= web-mode-engine "xoops") + (cond + ((string= sub3 "<{*") + (setq token-type 'comment)) + (t + (setq regexp "\"\\|'"))) + ) ;xoops + + ((string= web-mode-engine "spip") + (if (string= (buffer-substring-no-properties + block-beg (+ block-beg 7)) + "[(#REM)") + (setq token-type 'comment + regexp "\\]"))) + + ((string= web-mode-engine "dust") + (cond + ((string= sub2 "{!") + (setq token-type 'comment)) + (t + (setq regexp "\"\\|'")) + ) + ) ;dust + + ((string= web-mode-engine "expressionengine") + (cond + ((string= sub2 "{!") + (setq token-type 'comment)) + (t + (setq regexp "\"\\|'"))) + ) ;expressionengine + + ((string= web-mode-engine "closure") + (cond + ((member sub2 '("/*" "//")) + (setq token-type 'comment)) + (t + (setq regexp "\"\\|'")) + ) + ) ;closure + + ((string= web-mode-engine "svelte") + ) ;svelte + + ) ;cond + + (cond + (token-type + (put-text-property block-beg block-end 'block-token token-type)) + ((and regexp + (> (- block-end block-beg) 6)) + (web-mode-block-tokenize + (web-mode-block-code-beginning-position block-beg) + (web-mode-block-code-end-position block-beg) + regexp) + ) + ) ;cond + + )) + +(defun web-mode-block-tokenize (reg-beg reg-end &optional regexp) + (unless regexp (setq regexp web-mode-engine-token-regexp)) + ;;(message "tokenize: reg-beg(%S) reg-end(%S) regexp(%S)" reg-beg reg-end regexp) + ;;(message "tokenize: reg-beg(%S) reg-end(%S) command(%S)" reg-beg reg-end this-command) + ;;(message "%S>%S : %S" reg-beg reg-end (buffer-substring-no-properties reg-beg reg-end)) + (save-excursion + (let ((pos reg-beg) beg char match continue (flags 0) token-type token-end) + + (remove-list-of-text-properties reg-beg reg-end '(block-token)) + + ;; TODO : vérifier la cohérence + (put-text-property reg-beg reg-end 'block-side t) + + (goto-char reg-beg) + + (when (> (point) reg-end) + (message "block-tokenize ** reg-beg(%S) > reg-end(%S) **" reg-beg reg-end)) + + (while (and (< (point) reg-end) (re-search-forward regexp reg-end t)) + (setq beg (match-beginning 0) + match (match-string 0) + continue t + token-type 'comment + token-end (if (< reg-end (line-end-position)) reg-end (line-end-position)) + char (aref match 0)) + (cond + + ((and (string= web-mode-engine "asp") (string= match "''")) + (goto-char token-end)) + + ((and (string= web-mode-engine "razor") (eq char ?\')) + (cond + ((looking-at-p "\\(.\\|[\\][bfntr]\\|[\\]u....\\)'") + (search-forward "'" reg-end t) + (setq token-type 'string) + ) + (t + (re-search-forward "[[:alnum:]_-]+") + (setq token-type 'symbol) + ))) + + ((eq char ?\') + (setq token-type 'string) + (while (and continue (search-forward "'" reg-end t)) + (setq continue (web-mode-string-continue-p reg-beg)) + )) + + ((eq char ?\") + (setq token-type 'string) + (while (and continue (search-forward "\"" reg-end t)) + (setq continue (web-mode-string-continue-p reg-beg)) + )) + + ((string= match "//") + (goto-char token-end)) + + ((eq char ?\;) + (goto-char token-end)) + + ((string= match "#|") + (unless (search-forward "|#" reg-end t) + (goto-char token-end))) + + ((eq char ?\#) + (goto-char token-end)) + + ((string= match "/*") + (unless (search-forward "*/" reg-end t) + (goto-char token-end)) + ) + + ((string= match "@*") + (unless (search-forward "*@" reg-end t) + (goto-char token-end))) + + ((eq char ?\<) + (setq token-type 'string) + (re-search-forward (concat "^[ ]*" (match-string 1)) reg-end t)) + + (t + (message "block-tokenize ** token end (%S) **" beg) + (setq token-type nil)) + + ) ;cond + + (put-text-property beg (point) 'block-token token-type) + + (when (eq token-type 'comment) + (put-text-property beg (1+ beg) 'syntax-table (string-to-syntax "<")) + (if (or (< (point) (line-end-position)) (= (point) (point-max))) + (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax ">")) ;#445 #480 + (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax ">")) ;#377 + ) + ) + + ) ;while + + (web-mode-block-controls-unset pos) + + ))) + +(defun web-mode-set-php-controls (reg-beg reg-end) + (goto-char reg-beg) + (let (match controls + (continue t) + (regexp "endif\\|endforeach\\|endfor\\|endwhile\\|elseif\\|else\\|if\\|foreach\\|for\\|while")) + (while continue + (if (not (web-mode-block-rsf regexp reg-end)) + (setq continue nil) + (setq match (match-string-no-properties 0)) +;; (message "%S %S" match (point)) + (cond + ((and (member match '("else" "elseif")) + (looking-at-p "[ ]*[:(]")) + (setq controls (append controls (list (cons 'inside "if")))) + ) + ((and (>= (length match) 3) + (string= (substring match 0 3) "end")) + (setq controls (append controls (list (cons 'close (substring match 3))))) + ) + ((and (progn (skip-chars-forward "[ ]") t) + (eq (char-after) ?\() + (web-mode-closing-paren reg-end) + ;;(progn (message "ixi%S" (point))) + (looking-at-p ")[ ]*:")) + (setq controls (append controls (list (cons 'open match)))) + ) + ) ;cond + ) ;if + ) ;while + ;;(message "%S-%S %S" reg-beg reg-end controls) + (when (and controls (> (length controls) 1)) + (setq controls (web-mode-block-controls-reduce controls))) + controls)) + +(defun web-mode-block-controls-reduce (controls) + (when (and (eq (car (car controls)) 'open) + (member (cons 'close (cdr (car controls))) controls)) + (setq controls nil)) + controls) + +(defun web-mode-block-controls-unset (pos) + (cond + ((null (get-text-property pos 'block-side)) + (message "block-controls-unset ** invalid value (%S) **" pos)) + ((or (get-text-property pos 'block-beg) + (setq pos (web-mode-block-beginning-position pos))) + (put-text-property pos (1+ pos) 'block-controls 0)) + (t + (message "block-controls-unset ** failure (%S) **" (point))) + )) + +(defun web-mode-block-controls-get (pos) + (web-mode-with-silent-modifications + (let ((controls nil)) + (cond + ((null (get-text-property pos 'block-side)) + (message "block-controls-get ** invalid value (%S) **" pos)) + ((or (get-text-property pos 'block-beg) + (setq pos (web-mode-block-beginning-position pos))) + (setq controls (get-text-property pos 'block-controls)) + (when (integerp controls) + (web-mode-block-controls-set pos (web-mode-block-end-position pos)) + (setq controls (get-text-property pos 'block-controls)) + ) + ) + (t + (message "block-controls-get ** failure (%S) **" (point))) + ) ;cond + controls))) + +(defun web-mode-block-controls-set (reg-beg reg-end) + (save-excursion + (goto-char reg-beg) + (let (controls pos type control) + + (cond + + ((null web-mode-engine) + (message "block-controls-set ** unknown engine (%S) **" web-mode-engine) + ) + + ((string= web-mode-engine "php") + (setq controls (web-mode-set-php-controls reg-beg reg-end)) + (when (web-mode-block-starts-with "}" reg-beg) + (setq controls (append controls (list (cons 'close "{"))))) + (when (web-mode-block-ends-with (cons "{" "}") reg-beg) + (setq controls (append controls (list (cons 'open "{"))))) + ) ;php + + ((string= web-mode-engine "ejs") + (cond + ((web-mode-block-ends-with "}[ ]*else[ ]*{" reg-beg) + (setq controls (append controls (list (cons 'inside "{"))))) + ((web-mode-block-starts-with "}" reg-beg) + (setq controls (append controls (list (cons 'close "{"))))) + ((web-mode-block-ends-with "{" reg-beg) + (setq controls (append controls (list (cons 'open "{"))))) + ) + ) ;ejs + + ((string= web-mode-engine "erb") + (cond + ((web-mode-block-starts-with "else\\|elsif\\|when" reg-beg) + (setq controls (append controls (list (cons 'inside "ctrl"))))) + ((web-mode-block-starts-with "end" reg-beg) + (setq controls (append controls (list (cons 'close "ctrl"))))) + ((web-mode-block-ends-with " do\\( |.*|\\)?" reg-beg) + (setq controls (append controls (list (cons 'open "ctrl"))))) + ((and (web-mode-block-starts-with "\\(for\\|if\\|unless\\|case\\)\\_>" reg-beg) + (not (web-mode-block-ends-with "end" reg-end))) + (setq controls (append controls (list (cons 'open "ctrl"))))) + ) + ) ;erb + + ((string= web-mode-engine "django") + (cond + ((and (string= web-mode-minor-engine "jinja") ;#504 + (web-mode-block-starts-with "else\\_>" reg-beg)) + (let ((continue t) + (pos reg-beg) + (ctrl nil)) + (while continue + (cond + ((null (setq pos (web-mode-block-control-previous-position 'open pos))) + (setq continue nil)) + ((member (setq ctrl (cdr (car (get-text-property pos 'block-controls)))) '("if" "ifequal" "ifnotequal" "for")) + (setq continue nil) + ) + ) ;cond + ) + (setq controls (append controls (list (cons 'inside (or ctrl "if"))))) + ) + ) + ((web-mode-block-starts-with "form_start[ ]*(" reg-beg) + (setq controls (append controls (list (cons 'open "form_start"))))) + ((web-mode-block-starts-with "form_end[ ]*(" reg-beg) + (setq controls (append controls (list (cons 'close "form_start"))))) + ((not (eq (char-after (1+ reg-beg)) ?\%)) + ) + ((web-mode-block-starts-with "\\(else\\|els?if\\)" reg-beg) + (let ((continue t) + (pos reg-beg) + (ctrl nil)) + (while continue + (cond + ((null (setq pos (web-mode-block-control-previous-position 'open pos))) + (setq continue nil)) + ((member (setq ctrl (cdr (car (get-text-property pos 'block-controls)))) '("if" "ifequal" "ifnotequal")) + (setq continue nil) + ) + ) ;cond + ) ;while + (setq controls (append controls (list (cons 'inside (or ctrl "if"))))) + ) ;let + ) ;case else + ((web-mode-block-starts-with "\\(empty\\)" reg-beg) + (setq controls (append controls (list (cons 'inside "for"))))) + ((web-mode-block-starts-with "end\\([[:alpha:]]+\\)" reg-beg) + (setq controls (append controls (list (cons 'close (match-string-no-properties 1)))))) + ((web-mode-block-starts-with "set [[:alpha:]]+[ ]*%}" reg-beg) + (setq controls (append controls (list (cons 'open "set"))))) + ((web-mode-block-starts-with (concat web-mode-django-control-blocks-regexp "[ %]") reg-beg) + (let (control) + (setq control (match-string-no-properties 1)) + ;;(message "%S %S %S" control (concat "end" control) web-mode-django-control-blocks) + (when (member (concat "end" control) web-mode-django-control-blocks) + (setq controls (append controls (list (cons 'open control)))) + ) ;when + ) ;let + ) ;case + ) ;cond + ) ;django + + ((string= web-mode-engine "smarty") + (cond + ((and (eq (char-after (1+ reg-beg)) ?\/) + (web-mode-block-starts-with "\\([[:alpha:]]+\\)" reg-beg)) + (setq controls (append controls (list (cons 'close (match-string-no-properties 1)))))) + ((web-mode-block-starts-with "\\(else\\|elseif\\)" reg-beg) + (setq controls (append controls (list (cons 'inside "if"))))) + ((web-mode-block-starts-with "\\(block\\|foreach\\|for\\|if\\|section\\|while\\)") + (setq controls (append controls (list (cons 'open (match-string-no-properties 1)))))) + ) + ) ;smarty + + ((string= web-mode-engine "expressionengine") + (cond + ((and (eq (char-after (1+ reg-beg)) ?\/) + (web-mode-block-starts-with "\\(if\\)" reg-beg)) + (setq controls (append controls (list (cons 'close (match-string-no-properties 1)))))) + ((web-mode-block-starts-with "\\(if:else\\|if:ifelse\\)" reg-beg) + (setq controls (append controls (list (cons 'inside "if"))))) + ((web-mode-block-starts-with "\\(if\\)") + (setq controls (append controls (list (cons 'open (match-string-no-properties 1)))))) + ) + ) ;expressionengine + + ((string= web-mode-engine "xoops") + (cond + ((and (eq (char-after (+ reg-beg 2)) ?\/) + (web-mode-block-starts-with "\\([[:alpha:]]+\\)" reg-beg)) + (setq controls (append controls (list (cons 'close (match-string-no-properties 1)))))) + ((web-mode-block-starts-with "\\(else\\|elseif\\)" reg-beg) + (setq controls (append controls (list (cons 'inside "if"))))) + ((web-mode-block-starts-with "\\(block\\|foreach\\|for\\|if\\|section\\|while\\)") + (setq controls (append controls (list (cons 'open (match-string-no-properties 1)))))) + ) + ) ;xoops + + ((string= web-mode-engine "web2py") + (cond + ((web-mode-block-starts-with "def" reg-beg) + (setq controls (append controls (list (cons 'open "def"))))) + ((web-mode-block-starts-with "return" reg-beg) + (setq controls (append controls (list (cons 'close "def"))))) + ((web-mode-block-starts-with "block" reg-beg) + (setq controls (append controls (list (cons 'open "block"))))) + ((web-mode-block-starts-with "end" reg-beg) + (setq controls (append controls (list (cons 'close "block"))))) + ((web-mode-block-starts-with "pass" reg-beg) + (setq controls (append controls (list (cons 'close "ctrl"))))) + ((web-mode-block-starts-with "\\(except\\|finally\\|els\\)" reg-beg) + (setq controls (append controls (list (cons 'inside "ctrl"))))) + ((web-mode-block-starts-with "\\(if\\|for\\|try\\|while\\)") + (setq controls (append controls (list (cons 'open "ctrl"))))) + ) + ) ;web2py + + ((string= web-mode-engine "dust") + (cond + ((eq (char-after (1- reg-end)) ?\/) + ) + ((eq (char-after (1+ reg-beg)) ?\:) + (setq pos (web-mode-block-control-previous-position 'open reg-beg)) + (when pos + (setq controls (append controls + (list + (cons 'inside + (cdr (car (web-mode-block-controls-get pos)))))))) + ) + ((looking-at "{/\\([[:alpha:].]+\\)") + (setq controls (append controls (list (cons 'close (match-string-no-properties 1)))))) + ((looking-at "{[#?@><+^]\\([[:alpha:].]+\\)") + (setq controls (append controls (list (cons 'open (match-string-no-properties 1)))))) + ) + ) ;dust + + ((string= web-mode-engine "anki") + (cond + ((looking-at "{{[#^]\\([[:alpha:].]+\\)") + (setq controls (append controls (list (cons 'open (match-string-no-properties 1)))))) + ((looking-at "{{/\\([[:alpha:].]+\\)") + (setq controls (append controls (list (cons 'close (match-string-no-properties 1)))))) + ) + ) ;anki + + ((member web-mode-engine '("mojolicious")) + (cond + ((web-mode-block-ends-with "begin" reg-beg) + (setq controls (append controls (list (cons 'open "begin"))))) + ((web-mode-block-starts-with "end" reg-beg) + (setq controls (append controls (list (cons 'close "begin"))))) + ((web-mode-block-starts-with "}[ ]*else[ ]*{" reg-beg) + (setq controls (append controls (list (cons 'inside "{"))))) + ((web-mode-block-starts-with "}" reg-beg) + (setq controls (append controls (list (cons 'close "{"))))) + ((web-mode-block-ends-with "{" reg-beg) + (setq controls (append controls (list (cons 'open "{"))))) + ) + ) ;mojolicious + + ((member web-mode-engine '("aspx" "underscore")) + (cond + ((and (web-mode-block-starts-with "}" reg-beg) + (web-mode-block-ends-with "{" reg-beg)) + (setq controls (append controls (list (cons 'inside "{"))))) + ((web-mode-block-starts-with "}" reg-beg) + (setq controls (append controls (list (cons 'close "{"))))) + ((web-mode-block-ends-with "{" reg-beg) + (setq controls (append controls (list (cons 'open "{"))))) + ) + ) ;aspx underscore + + ((member web-mode-engine '("jsp" "asp" "clip" "perl")) + (cond + ((eq (char-after (1- reg-end)) ?\/) + ) + ((looking-at "<TMPL_ELSE") + (setq controls (append controls (list (cons 'inside "TMPL_IF"))))) + ((looking-at "</?\\([[:alpha:]]+\\(?:[:.][[:alpha:]]+\\)\\|[[:alpha:]]+Template\\|TMPL_[[:alpha:]]+\\)") + (setq control (match-string-no-properties 1) + type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open)) + (when (not (member control '("h:inputtext" "jsp:usebean" "jsp:forward" "struts:property"))) + (setq controls (append controls (list (cons type control))))) + ) + (t + (when (web-mode-block-starts-with "}" reg-beg) + (setq controls (append controls (list (cons 'close "{"))))) + (when (web-mode-block-ends-with "{" reg-beg) + (setq controls (append controls (list (cons 'open "{"))))) + ) + ) + ) ;jsp asp + + ((string= web-mode-engine "mako") + (cond + ((looking-at "</?%\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)") + (cond + ((eq (char-after (- (web-mode-block-end-position reg-beg) 1)) ?\/) + ) + (t + (setq control (match-string-no-properties 1) + type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open)) + (setq controls (append controls (list (cons type control))))) + ) + ) + ((web-mode-block-starts-with "\\(else\\|elif\\)" reg-beg) + (setq controls (append controls (list (cons 'inside "if"))))) + ((web-mode-block-starts-with "end\\(if\\|for\\)" reg-beg) + (setq controls (append controls (list (cons 'close (match-string-no-properties 1)))))) + ((and (web-mode-block-starts-with "if\\|for" reg-beg) + (web-mode-block-ends-with ":" reg-beg)) + (setq controls (append controls (list (cons 'open (match-string-no-properties 0)))))) + ) + ) ;mako + + ((string= web-mode-engine "mason") + (cond + ((looking-at "</?%\\(after\\|around\\|augment\\|before\\|def\\|filter\\|method\\|override\\)") + (setq control (match-string-no-properties 1) + type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open)) + (setq controls (append controls (list (cons type control)))) + ) + ) + ) ;mason + + ((string= web-mode-engine "ctemplate") + (cond + ((looking-at-p "{{else") ;#721 + (let ((continue t) + (pos reg-beg) + (ctrl nil)) + (while continue + (cond + ((null (setq pos (web-mode-block-control-previous-position 'open pos))) + (setq continue nil)) + ((member (setq ctrl (cdr (car (get-text-property pos 'block-controls)))) '("if" "each")) + (setq continue nil) + ) + ) ;cond + ) ;while + (setq controls (append controls (list (cons 'inside (or ctrl "if"))))) + ) + ) + + ((looking-at "{{[#^/][ ]*\\([[:alpha:]_.-]+\\)") + (setq control (match-string-no-properties 1) + type (if (eq (aref (match-string-no-properties 0) 2) ?\/) 'close 'open)) + (setq controls (append controls (list (cons type control)))) + ) + ) + ) ;ctemplate + + ((string= web-mode-engine "blade") + (cond + ((not (eq (char-after) ?\@)) + ) + ((web-mode-block-starts-with + "section\(\s*\\(['\"]\\).*\\1\s*,\s*\\(['\"]\\).*\\2\s*\)" reg-beg) + ) + ((web-mode-block-starts-with "case\\|break" reg-beg) + (setq type (if (eq (aref (match-string-no-properties 0) 0) ?b) 'close 'open)) + (setq controls (append controls (list (cons type "case")))) + ) + ((web-mode-block-starts-with + (concat "\\(?:end\\)?\\(" web-mode-blade-control-blocks-regexp "\\)") + reg-beg) + (setq control (match-string-no-properties 1) + type (if (eq (aref (match-string-no-properties 0) 0) ?e) 'close 'open)) + (setq controls (append controls (list (cons type control)))) + ) + ((web-mode-block-starts-with "stop\\|show\\|overwrite" reg-beg) + (setq controls (append controls (list (cons 'close "section"))))) + ((web-mode-block-starts-with "else\\|elseif" reg-beg) + (setq controls (append controls (list (cons 'inside "if"))))) + ((web-mode-block-starts-with "empty" reg-beg) + (setq controls (append controls (list (cons 'inside "forelse"))))) + ) + ) ;blade + + ((string= web-mode-engine "closure") + (cond + ((eq (char-after (1- reg-end)) ?\/) + ) + ((looking-at "alias\\|namespace") + ) + ((web-mode-block-starts-with "ifempty" reg-beg) + (setq controls (append controls (list (cons 'inside "foreach"))))) + ((web-mode-block-starts-with "else\\|elseif" reg-beg) + (setq controls (append controls (list (cons 'inside "if"))))) + ((web-mode-block-starts-with "case\\|default" reg-beg) + (setq controls (append controls (list (cons 'inside "switch"))))) + ((looking-at + "{/?\\(call\\|deltemplate\\|for\\|foreach\\|if\\|let\\|literal\\|msg\\|param\\|switch\\|template\\)") + (setq control (match-string-no-properties 1) + type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open)) + (setq controls (append controls (list (cons type control)))) + ) + ) + ) ;closure + + ((string= web-mode-engine "go") + (cond + ((web-mode-block-starts-with "end\\_>" reg-beg) + (setq controls (append controls (list (cons 'close "ctrl"))))) + ((web-mode-block-starts-with "else\\_>" reg-beg) + (setq controls (append controls (list (cons 'inside "ctrl"))))) + ((web-mode-block-starts-with "\\(range\\|with\\|if\\|define\\|block\\)\\_>" reg-beg) + (setq controls (append controls (list (cons 'open "ctrl"))))) + ) + ) ;go + + ((string= web-mode-engine "template-toolkit") + (cond + ((web-mode-block-starts-with "end" reg-beg) + (setq controls (append controls (list (cons 'close "ctrl"))))) + ((web-mode-block-starts-with "els\\|catch\\|final" reg-beg) + (setq controls (append controls (list (cons 'inside "ctrl"))))) + ((web-mode-block-starts-with "filter\\|foreach\\|if\\|last\\|next\\|perl\\|rawperl\\|try\\|unless\\|while" reg-beg) + (setq controls (append controls (list (cons 'open "ctrl"))))) + ) + ) ;template-toolkit + + ((string= web-mode-engine "cl-emb") + (cond + ((web-mode-block-starts-with "@else" reg-beg) + (setq controls (append controls (list (cons 'inside "if"))))) + ((web-mode-block-starts-with "@\\(?:end\\)?\\(if\\|unless\\|repeat\\|loop\\|with\\|genloop\\)" reg-beg) + (setq control (match-string-no-properties 1) + type (if (eq (aref (match-string-no-properties 0) 1) ?e) 'close 'open)) + (setq controls (append controls (list (cons type control))))) + ) + ) ;cl-emb + + ((string= web-mode-engine "elixir") + (cond + ((web-mode-block-starts-with "end" reg-beg) + (setq controls (append controls (list (cons 'close "ctrl"))))) + ((web-mode-block-starts-with "else" reg-beg) + (setq controls (append controls (list (cons 'inside "ctrl"))))) + ((web-mode-block-ends-with " do" reg-beg) + (setq controls (append controls (list (cons 'open "ctrl"))))) + ((web-mode-block-ends-with " ->" reg-beg) + (setq controls (append controls (list (cons 'open "ctrl"))))) + ) + ) ;elixir + + ((string= web-mode-engine "velocity") + (cond + ((web-mode-block-starts-with "{?end" reg-beg) + (setq controls (append controls (list (cons 'close "ctrl"))))) + ((web-mode-block-starts-with "{?els" reg-beg) + (setq controls (append controls (list (cons 'inside "ctrl"))))) + ((web-mode-block-starts-with "{?\\(def\\|if\\|for\\|foreach\\|macro\\)" reg-beg) + ;;((web-mode-block-starts-with "{?\\(define\\|\\|if\\|for\\|foreach\\|macro\\)" reg-beg) + (setq controls (append controls (list (cons 'open "ctrl"))))) + ) + ) ;velocity + + ((string= web-mode-engine "freemarker") + (cond + ((looking-at "[<[]#\\(import\\|include\\|assign\\|return\\|local\\)") + ) + ((eq (char-after (1- reg-end)) ?\/) + ) + ((looking-at "[<[]#\\(break\\|case\\|default\\)") + (setq controls (append controls (list (cons 'inside "switch")))) + ) + ((looking-at "[<[]#els") + (setq controls (append controls (list (cons 'inside "if")))) + ) + ((looking-at "</?\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)") + (setq control (match-string-no-properties 1) + type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open)) + (setq controls (append controls (list (cons type control)))) + ) + ((looking-at "[<[]/?\\(@\\)") + (setq control (match-string-no-properties 1) + type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open)) + (setq controls (append controls (list (cons type control)))) + ) + ((looking-at "[<[]/?#\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)") + (setq control (match-string-no-properties 1) + type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open)) + (setq controls (append controls (list (cons type control)))) + ) + (t + (when (web-mode-block-starts-with "}" reg-beg) + (setq controls (append controls (list (cons 'close "{"))))) + (when (web-mode-block-ends-with "{" reg-beg) + (setq controls (append controls (list (cons 'open "{"))))) + ) + ) + ) ;freemarker + + ((string= web-mode-engine "razor") + (when (web-mode-block-starts-with "}" reg-beg) + (setq controls (append controls (list (cons 'close "{"))))) + (when (web-mode-block-ends-with "{" reg-beg) + (setq controls (append controls (list (cons 'open "{"))))) + ) ;razor + + ((string= web-mode-engine "lsp") + (when (web-mode-block-starts-with ")" reg-beg) + (setq controls (append controls (list (cons 'close "("))))) + (when (web-mode-block-is-opened-sexp reg-beg reg-end) + (setq controls (append controls (list (cons 'open "("))))) + ) ;lsp + + ((string= web-mode-engine "hero") + (cond + ((web-mode-block-ends-with "}[ ]*else[ ]*{" reg-beg) + (setq controls (append controls (list (cons 'inside "{"))))) + ((web-mode-block-starts-with "}" reg-beg) + (setq controls (append controls (list (cons 'close "{"))))) + ((web-mode-block-ends-with "{" reg-beg) + (setq controls (append controls (list (cons 'open "{"))))) + ) + ) ;hero + + ((string= web-mode-engine "svelte") + (cond + ((eq (char-after (1- reg-end)) ?\/) + ) + ((eq (char-after (1+ reg-beg)) ?\:) + (setq pos (web-mode-block-control-previous-position 'open reg-beg)) + (when pos + (setq controls (append controls + (list + (cons 'inside + (cdr (car (web-mode-block-controls-get pos)))))))) + ) + ((looking-at "{/\\([[:alpha:].]+\\)") + (setq controls (append controls (list (cons 'close (match-string-no-properties 1)))))) + ((looking-at "{[#?><+^]\\([[:alpha:].]+\\)") + (setq controls (append controls (list (cons 'open (match-string-no-properties 1)))))) + ) + ) ;svelte + + ) ;cond engine + + (put-text-property reg-beg (1+ reg-beg) 'block-controls controls) + ;;(message "(%S) controls=%S" reg-beg controls) + + ))) + +(defun web-mode-block-is-opened-sexp (reg-beg reg-end) + (let ((n 0)) + (save-excursion + (goto-char reg-beg) + (while (web-mode-block-rsf "[()]" reg-end) + (if (eq (char-before) ?\() (setq n (1+ n)) (setq n (1- n))))) + (> n 0))) + +;;---- LEXER PARTS ------------------------------------------------------------- + +(defun web-mode-scan-elements (reg-beg reg-end) + (save-excursion + (let (part-beg part-end flags limit close-expr props tname tbeg tend element-content-type (regexp web-mode-dom-regexp) part-close-tag char) + ;;(message "scan-elements: reg-beg(%S) reg-end(%S)" reg-beg reg-end) + (goto-char reg-beg) + + (while (web-mode-dom-rsf regexp reg-end) + + ;;(message "%S: %S (%S %S)" (point) (match-string-no-properties 0) reg-beg reg-end) + + (setq flags 0 + tname (downcase (match-string-no-properties 1)) + char (aref tname 0) + tbeg (match-beginning 0) + tend nil + element-content-type nil + limit reg-end + part-beg nil + part-end nil + props nil + close-expr nil + part-close-tag nil) + + ;;(message "tname[%S] tbeg(%S) point(%S)" tname tbeg (point)) + + (cond + + ((member tname '("/>" ">")) ;;jsx fragment #952 + (setq tname "_fragment_" + tend (point)) + (if (eq char ?\/) + (setq props (list 'tag-name tname 'tag-type 'end) + flags (logior flags 20)) ;; 16 + 4 + (setq props (list 'tag-name tname 'tag-type 'start) + flags (logior flags 16)) + ) ;if + ) + + ((not (member char '(?\! ?\?))) + (cond + ((string-match-p "-" tname) + (setq flags (logior flags 2))) + ((string-match-p ":" tname) + (setq flags (logior flags 32))) + ) + (cond + ((eq char ?\/) + (setq props (list 'tag-name (substring tname 1) 'tag-type 'end) + flags (logior flags 4) + limit (if (> reg-end (line-end-position)) (line-end-position) reg-end)) + ) + ((web-mode-element-is-void tname) + ;;(message "void: tag=%S" tname) + (setq props (list 'tag-name tname 'tag-type 'void))) + (t + (setq props (list 'tag-name tname 'tag-type 'start))) + ) ;cond + ) ; not <! <? + ((and (eq char ?\!) (eq (aref tname 1) ?\-)) + (setq close-expr "-->" + props '(tag-type comment))) + ((string= tname "?xml") + (setq ;;regexp web-mode-tag-regexp2 + close-expr "?>" + props '(tag-type declaration))) + ((string= tname "![cdata[") + (setq close-expr "]]>" + props '(tag-type cdata))) + ((string= tname "!doctype") + (setq ;;regexp web-mode-tag-regexp2 + props '(tag-type doctype))) + ) ;cond - special tags + + (cond + + (tend + ) + + ((and (null close-expr) (eq (char-after) ?\>)) + (setq flags (logior flags 16) + tend (1+ (point))) + ;;(message "end=%S" tend) + ) + + ((and (null close-expr) + (looking-at "[ ]\\(class\\|id\\|href\\|style\\)=\"[[:alnum:]_=:/?;#. -]*\">")) + (let ((beg (1+ (point))) + (end (+ (point) (length (match-string-no-properties 0))))) + (setq flags (logior flags 17) + tend end) + (put-text-property beg (1+ beg) 'tag-attr-beg 0) + (put-text-property beg (1- end) 'tag-attr t) + (put-text-property (- end 2) (1- end) 'tag-attr-end (length (match-string-no-properties 1))) + ) ;let + ) + + ((null close-expr) + (setq flags (logior flags (web-mode-attr-skip reg-end))) + (when (> (logand flags 8) 0) + (setq props (plist-put props 'tag-type 'void))) + (setq tend (point))) + + ((web-mode-dom-sf close-expr limit t) + (setq tend (point))) + + (t + (setq tend (line-end-position))) + + ) ;cond + + (cond + ((string= tname "style") + (let (style) + (setq style (buffer-substring-no-properties tbeg tend) + part-close-tag "</style>") + (cond + ((string-match-p " lang[ ]*=[ ]*[\"']stylus" style) + (setq element-content-type "stylus")) + ((string-match-p " lang[ ]*=[ ]*[\"']sass" style) + (setq element-content-type "sass")) + (t + (setq element-content-type "css")) + ) ;cond + ) ;let + ) ;style + ((string= tname "script") + (let (script) + (setq script (buffer-substring-no-properties tbeg tend) + part-close-tag "</script>") + (cond + ((string-match-p " type[ ]*=[ ]*[\"']text/\\(jsx\\|babel\\)" script) + (setq element-content-type "jsx")) + ((string-match-p " type[ ]*=[ ]*[\"']text/\\(markdown\\|template\\)" script) + (setq element-content-type "markdown")) + ((string-match-p " type[ ]*=[ ]*[\"']text/ruby" script) + (setq element-content-type "ruby")) + ((seq-some (lambda (x) + (string-match-p (concat "type[ ]*=[ ]*[\"']" x) script)) + web-mode-script-template-types) + (setq element-content-type "html" + part-close-tag nil)) + ((string-match-p " type[ ]*=[ ]*[\"']application/\\(ld\\+json\\|json\\)" script) + (setq element-content-type "json")) + ((string-match-p " lang[ ]*=[ ]*[\"']\\(typescript\\|ts\\)" script) + (setq element-content-type "typescript")) + (t + (setq element-content-type "javascript")) + ) ;cond + ) ;let + ) ;script + ((and (string= tname "template") (string-match-p " lang" (buffer-substring-no-properties tbeg tend))) + (let (template) + (setq template (buffer-substring-no-properties tbeg tend) + part-close-tag "</template>") + (cond + ((string-match-p " lang[ ]*=[ ]*[\"']pug" template) + (setq element-content-type "pug")) + (t + (setq element-content-type "html")) + ) ;cond + ) ;let + ) ;style + ((and (string= web-mode-engine "archibus") + (string= tname "sql")) + (setq element-content-type "sql" + part-close-tag "</sql>")) + ) + + (add-text-properties tbeg tend props) + (put-text-property tbeg (1+ tbeg) 'tag-beg flags) + (put-text-property (1- tend) tend 'tag-end t) + + (when (and part-close-tag + (web-mode-dom-sf part-close-tag reg-end t) + (setq part-beg tend) + (setq part-end (match-beginning 0)) + (> part-end part-beg)) + (put-text-property part-beg part-end 'part-side + (intern element-content-type web-mode-obarray)) + (setq tend part-end) + ) ;when + + (goto-char tend) + + ) ;while + + ))) + +;; FLAGS: tag +;; (1)attrs (2)custom (4)slash-beg (8)slash-end (16)bracket-end (32)namespaced + +;; FLAGS: attr +;; (1)custom-attr (2)engine-attr (4)spread-attr[jsx] (8)code-value +;; SPECS: https://www.w3.org/TR/2012/WD-html-markup-20120329/syntax.html#attr-value-unquoted + +;; STATES: attr +;; (0)nil (1)space (2)name (3)space-before (4)equal (5)space-after +;; (6)value-uq (7)value-sq (8)value-dq (9)value-bq : jsx attr={} + +(defun web-mode-attr-skip (limit) + + (let ((tag-flags 0) (attr-flags 0) (continue t) (attrs 0) (counter 0) (brace-depth 0) + (pos-ori (point)) (state 0) (equal-offset 0) (go-back nil) + (is-jsx (or (string= web-mode-content-type "jsx") (eq (get-text-property (point) 'part-type) 'jsx))) + attr name-beg name-end val-beg char pos escaped spaced quoted) + + (while continue + + (setq pos (point) + char (char-after) + ;;spaced (eq char ?\s) + spaced (member char '(?\s ?\n)) + ) + + (when quoted (setq quoted (1+ quoted))) + + (cond + + ((>= pos limit) + (setq continue nil) + (setq go-back t) + (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags))) + ) + + ((or (and (= state 8) (not (member char '(?\" ?\\)))) + (and (= state 7) (not (member char '(?\' ?\\)))) + (and (= state 9) (not (member char '(?} ?\\)))) + ) + (when (and (= state 9) (eq char ?\{)) + (setq brace-depth (1+ brace-depth))) + ) + + ((and (= state 9) (eq char ?\}) (> brace-depth 1)) + (setq brace-depth (1- brace-depth))) + + ((get-text-property pos 'block-side) + (when (= state 2) + (setq name-end pos)) + ) + + ((and (= state 2) is-jsx (eq char ?\}) (eq attr-flags 4)) + (setq name-end pos) + (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags))) + (setq state 0 + attr-flags 0 + equal-offset 0 + name-beg nil + name-end nil + val-beg nil) + ) + + ((or (and (= state 8) (eq ?\" char) (not escaped)) + (and (= state 7) (eq ?\' char) (not escaped)) + (and (= state 9) (eq ?\} char) (= brace-depth 1)) + ) + + ;;(message "%S %S" (point) attr-flags) + (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags))) + (setq state 0 + attr-flags 0 + equal-offset 0 + name-beg nil + name-end nil + val-beg nil) + ) + + ((and (member state '(4 5)) (member char '(?\' ?\" ?\{))) + (setq val-beg pos) + (setq quoted 1) + (setq state (cond ((eq ?\' char) 7) + ((eq ?\" char) 8) + (t 9))) + (when (= state 9) + (setq brace-depth 1)) + ) + + ((and (eq ?\= char) (member state '(2 3))) + (setq equal-offset (- pos name-beg) + name-end (1- pos)) + (setq state 4) + (setq attr (buffer-substring-no-properties name-beg (1+ name-end))) + (when (and web-mode-indentless-attributes (member (downcase attr) web-mode-indentless-attributes)) + ;;(message "onclick") + (setq attr-flags (logior attr-flags 8))) + ) + + ((and spaced (= state 0)) + (setq state 1) + ) + + ((and (eq char ?\<) (not (member state '(7 8 9)))) + (setq continue nil) + (setq go-back t) + (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags))) + ) + + ((and (eq char ?\>) (not (member state '(7 8 9)))) + (setq tag-flags (logior tag-flags 16)) + (when (eq (char-before) ?\/) + (setq tag-flags (logior tag-flags 8)) + ) + (setq continue nil) + (when name-beg + (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))) + ) + + ((and spaced (member state '(1 3 5))) + ) + + ((and spaced (= state 2)) + (setq state 3) + ) + + ((and (eq char ?\/) (member state '(4 5))) + (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags))) + (setq state 1 + attr-flags 0 + equal-offset 0 + name-beg nil + name-end nil + val-beg nil) + ) + + ((and (eq char ?\/) (member state '(0 1))) + ) + + ((and spaced (= state 4)) + (setq state 5) + ) + + ((and (= state 3) + (or (and (>= char 97) (<= char 122)) ;a - z + (and (>= char 65) (<= char 90)) ;A - Z + (eq char ?\-))) + (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags))) + (setq state 2 + attr-flags 0 + equal-offset 0 + name-beg pos + name-end pos + val-beg nil) + ) + + ((and (eq char ?\n) (not (member state '(7 8 9)))) + (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags))) + (setq state 1 + attr-flags 0 + equal-offset 0 + name-beg nil + name-end nil + val-beg nil) + ) + + ((and (= state 6) (member char '(?\s ?\n))) ;#1150 + (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags))) + (setq state 1 + attr-flags 0 + equal-offset 0 + name-beg nil + name-end nil + val-beg nil) + ) + + ((and quoted (= quoted 2) (member char '(?\s ?\n ?\>))) + (when (eq char ?\>) + (setq tag-flags (logior tag-flags 16)) + (setq continue nil)) + (setq state 6) + (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags))) + (setq state 1 + attr-flags 0 + equal-offset 0 + name-beg nil + name-end nil + val-beg nil) + ) + + ((and (not spaced) (= state 1)) + (when (and is-jsx (eq char ?\{)) + (setq attr-flags 4)) + (setq state 2) + (setq name-beg pos + name-end pos) + ) + + ((member state '(4 5)) + (setq val-beg pos) + (setq state 6) + ) + + ((= state 1) + (setq state 2) + ) + + ((= state 2) + (setq name-end pos) + (when (and nil (= attr-flags 0) (member char '(?\- ?\:))) + (let (attr) + (setq attr (buffer-substring-no-properties name-beg (1+ name-end))) + (cond + ((member attr '("http-equiv")) + (setq attr-flags (1- attr-flags)) + ) + ;;((and web-mode-engine-attr-regexp + ;; (string-match-p web-mode-engine-attr-regexp attr)) + ;; (setq attr-flags (logior attr-flags 2)) + ;; ) + ((and (eq char ?\-) (not (string= attr "http-"))) + (setq attr-flags (logior attr-flags 1))) + ) ;cond + ) ;let + ) ;when attr-flags = 1 + ) ;state=2 + + ) ;cond + + ;;(message "point(%S) end(%S) state(%S) c(%S) name-beg(%S) name-end(%S) val-beg(%S) attr-flags(%S) equal-offset(%S)" pos end state char name-beg name-end val-beg attr-flags equal-offset tag-flags) + + (when (and quoted (>= quoted 2)) + (setq quoted nil)) + + (setq escaped (eq ?\\ char)) + (when (null go-back) + (forward-char)) + + ) ;while + + (when (> attrs 0) (setq tag-flags (logior tag-flags 1))) + + tag-flags)) + +(defun web-mode-attr-scan (pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags) + ;;(message "point(%S) state(%S) c(%c) name-beg(%S) name-end(%S) val-beg(%S) attr-flags(%S) equal-offset(%S) tag-flags(%S)" + ;; pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags) + (when (null attr-flags) (setq attr-flags 0)) + (when (and name-beg name-end web-mode-engine-attr-regexp) + (let (name) + (setq name (buffer-substring-no-properties name-beg (1+ name-end))) + ;;(message "%S" name) + (cond + ((string-match-p "^data[-]" name) + (setq attr-flags (logior attr-flags 1)) + ) + ((string-match-p web-mode-engine-attr-regexp name) + (setq attr-flags (logior attr-flags 2)) + ) + ) + ) ;name + ) + ;;(message "%S" name) + (cond + ((null name-beg) + 0) + ((or (and (= state 8) (not (eq ?\" char))) + (and (= state 7) (not (eq ?\' char)))) + (put-text-property name-beg (1+ name-beg) 'tag-attr-beg attr-flags) + (put-text-property name-beg val-beg 'tag-attr t) + (put-text-property (1- val-beg) val-beg 'tag-attr-end equal-offset) + 1) + ((and (member state '(4 5)) (null val-beg)) + (put-text-property name-beg (1+ name-beg) 'tag-attr-beg attr-flags) + (put-text-property name-beg (+ name-beg equal-offset 1) 'tag-attr t) + (put-text-property (+ name-beg equal-offset) (+ name-beg equal-offset 1) 'tag-attr-end equal-offset) + 1) + (t + (let (val-end) + (if (null val-beg) + (setq val-end name-end) + (setq val-end pos) + (cond + ((null char) + (setq val-end (1- val-end))) + ((member char '(?\s ?\n ?\/)) + (setq val-end (1- val-end))) + ((eq char ?\>) + (if (= (logand tag-flags 8) 8) + (progn + ;;(message "tag-flags=%S %S" tag-flags (logand tag-flags 8)) + (setq val-end (- val-end 2))) + (setq val-end (- val-end 1))) + ;; (message "val-end=%S" val-end) + ) + ) + ) + (put-text-property name-beg (1+ name-beg) 'tag-attr-beg attr-flags) + (put-text-property name-beg (1+ val-end) 'tag-attr t) + (put-text-property val-end (1+ val-end) 'tag-attr-end equal-offset) + ) ;let + 1) ;t + ) ;cond + ) + +(defun web-mode-part-foreach (reg-beg reg-end func) + (let ((i 0) (continue t) (part-beg reg-beg) (part-end nil)) + (while continue + (setq part-end nil) + (unless (get-text-property part-beg 'part-side) + (setq part-beg (web-mode-part-next-position part-beg))) + (when (and part-beg (< part-beg reg-end)) + (setq part-end (web-mode-part-end-position part-beg))) + (cond + ((> (setq i (1+ i)) 100) + (message "process-parts ** warning (%S) **" (point)) + (setq continue nil)) + ((or (null part-end) (> part-end reg-end)) + (setq continue nil)) + (t + (setq part-end (1+ part-end)) + (funcall func part-beg part-end) + (setq part-beg part-end)) + ) ;cond + ) ;while + )) + +(defun web-mode-part-scan (reg-beg reg-end &optional content-type depth) + (save-excursion + (let (token-re ch-before ch-at ch-next token-type beg continue) + ;;(message "%S %S" reg-beg reg-end) + (cond + (content-type + ) + ((member web-mode-content-type web-mode-part-content-types) + (setq content-type web-mode-content-type)) + (t + (setq content-type (symbol-name (get-text-property reg-beg 'part-side)))) + ) ;cond + + (goto-char reg-beg) + + (cond + ((member content-type '("javascript" "json")) + (setq token-re "/\\|\"\\|'\\|`")) + ((member content-type '("typescript")) + (setq token-re "\"\\|'\\|`\\|//\\|/\\*")) + ((member content-type '("jsx")) + (setq token-re "/\\|\"\\|'\\|`\\|</?[[:alpha:]>]")) + ((string= web-mode-content-type "css") + (setq token-re "\"\\|'\\|/\\*\\|//")) + ((string= content-type "css") + (setq token-re "\"\\|'\\|/\\*")) + (t + (setq token-re "/\\*\\|\"\\|'")) + ) + + (while (and token-re (< (point) reg-end) (web-mode-dom-rsf token-re reg-end t)) + + (setq beg (match-beginning 0) + token-type nil + continue t + ch-at (char-after beg) + ch-next (or (char-after (1+ beg)) ?\d) + ch-before (or (char-before beg) ?\d)) + + ;;(message "[%S>%S|%S] %S %c %c %c" reg-beg reg-end depth beg ch-before ch-at ch-next) + + (cond + + ((eq ?\' ch-at) + (while (and continue (search-forward "'" reg-end t)) + (cond + ((get-text-property (1- (point)) 'block-side) + (setq continue t)) + (t + (setq continue (web-mode-string-continue-p reg-beg))) + ) + ) ;while + (setq token-type 'string)) + + ((eq ?\` ch-at) + (while (and continue (search-forward "`" reg-end t)) + (cond + ((get-text-property (1- (point)) 'block-side) + (setq continue t)) + (t + (setq continue (web-mode-string-continue-p reg-beg))) + ) + ) ;while + (setq token-type 'string)) + + ((eq ?\" ch-at) + (while (and continue (search-forward "\"" reg-end t)) + (cond + ((get-text-property (1- (point)) 'block-side) + (setq continue t)) + (t + (setq continue (web-mode-string-continue-p reg-beg))) + ) ;cond + ) ;while + (cond + ((string= content-type "json") + (if (looking-at-p "[ ]*:") + (cond + ((eq ?\@ (char-after (1+ beg))) + (setq token-type 'context)) + (t + (setq token-type 'key)) + ) + (setq token-type 'string)) + ) ;json + (t + (setq token-type 'string)) + ) ;cond + ) + + ((and (eq ?\< ch-at) + (not (or (and (>= ch-before 97) (<= ch-before 122)) + (and (>= ch-before 65) (<= ch-before 90))))) + ;;(message "before [%S>%S|%S] pt=%S" reg-beg reg-end depth (point)) + (search-backward "<") + (if (web-mode-jsx-skip reg-end) + (web-mode-jsx-scan-element beg (point) depth) + (forward-char)) + ;;(message "after [%S>%S|%S] pt=%S" reg-beg reg-end depth (point)) + ) + + ((and (eq ?\/ ch-at) (member content-type '("javascript" "jsx"))) + (cond + ((eq ?\\ ch-before) + ) + ((eq ?\* ch-next) + ;;(message "--> %S %S" (point) reg-end) + (when (search-forward "*/" reg-end t) + (setq token-type 'comment)) + ) + ((eq ?\/ ch-next) + (setq token-type 'comment) + (goto-char (if (< reg-end (line-end-position)) reg-end (line-end-position))) + ) + ((and (looking-at-p ".*/") + (looking-back "\\(^\\|case\\|[[(,=:!&|?{};]\\)[ ]*/" (point-min))) + ;;(re-search-forward "/[gimyu]*" reg-end t)) + (let ((eol (line-end-position))) + (while (and continue (search-forward "/" eol t)) + (cond + ((get-text-property (1- (point)) 'block-side) + (setq continue t)) + ((looking-back "\\\\+/" reg-beg t) + (setq continue (= (mod (- (point) (match-beginning 0)) 2) 0))) + (t + (re-search-forward "[gimyu]*" eol t) + (setq token-type 'string) + (setq continue nil)) + ) + ) ;while + ) ;let + ) + ) ;cond + ) + + ((eq ?\/ ch-next) + ;;(message "%S" (point)) + (cond + ((and (string= content-type "css") + (eq ?/ ch-at) + (eq ?: ch-before)) + ) + (t + (unless (eq ?\\ ch-before) + (setq token-type 'comment) + (goto-char (if (< reg-end (line-end-position)) reg-end (line-end-position))) + ) + ) + ) + + ) + + ((eq ?\* ch-next) + (cond + ((search-forward "*/" reg-end t) + (setq token-type 'comment)) + ((not (eobp)) + (forward-char)) + ) ;cond + ) + + ) ;cond + + (when (and beg (>= reg-end (point)) token-type) + (put-text-property beg (point) 'part-token token-type) + (cond + ((eq token-type 'comment) + (put-text-property beg (1+ beg) 'syntax-table (string-to-syntax "<")) + (when (< (point) (point-max)) + (if (< (point) (line-end-position)) + (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax ">")) ;#445 + (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax ">")) ;#377 + ) + ) ;when + ) ;comment + ((eq token-type 'string) + (put-text-property beg (1+ beg) 'syntax-table (string-to-syntax "|")) + (when (< (point) (point-max)) + (if (< (point) (line-end-position)) + (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax "|")) + (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax "|")) + ) + ) ;when + ) ;string + ) ;cond + ) ;when + + (when (> (point) reg-end) + (message "reg-beg(%S) reg-end(%S) token-type(%S) point(%S)" reg-beg reg-end token-type (point))) + + ;;(message "#[%S>%S|%S] %S %c %c %c | (%S)" reg-beg reg-end depth beg ch-before ch-at ch-next (point)) + + ) ;while + + ))) + +(defun web-mode-string-continue-p (reg-beg) + "Is `point' preceeded by an odd number of backslashes?" + (let ((p (1- (point)))) + (while (and (< reg-beg p) (eq ?\\ (char-before p))) + (setq p (1- p))) + (= (mod (- (point) p) 2) 0))) + +;; css rule = selector(s) + declaration (properties) +(defun web-mode-css-rule-next (limit) + (let (at-rule var-rule sel-beg sel-end dec-beg dec-end chunk) + (skip-chars-forward "\n\t ") + (setq sel-beg (point)) + (when (and (< (point) limit) + (web-mode-part-rsf "[{;]" limit)) + (setq sel-end (1- (point))) + (cond + ((eq (char-before) ?\{) + (setq dec-beg (point)) + (setq dec-end (web-mode-closing-paren-position (1- dec-beg) limit)) + (if dec-end + (progn + (goto-char dec-end) + (forward-char)) + (setq dec-end limit) + (goto-char limit)) + ) + (t + ) + ) ;cond + (setq chunk (buffer-substring-no-properties sel-beg sel-end)) + (cond + ((string-match "@\\([[:alpha:]-]+\\)" chunk) + (setq at-rule (match-string-no-properties 1 chunk))) + ((string-match "\\$\\([[:alpha:]-]+\\)" chunk) + (setq var-rule (match-string-no-properties 1 chunk))) + ) ;cond + ) ;when + (if (not sel-end) + (progn (goto-char limit) nil) + (list :at-rule at-rule + :var-rule var-rule + :sel-beg sel-beg + :sel-end sel-end + :dec-beg dec-beg + :dec-end dec-end) + ) ;if + )) + +(defun web-mode-css-rule-current (&optional pos part-beg part-end) + "Current CSS rule boundaries." + (unless pos (setq pos (point))) + (unless part-beg (setq part-beg (web-mode-part-beginning-position pos))) + (unless part-end (setq part-end (web-mode-part-end-position pos))) + (save-excursion + (let (beg end) + (goto-char pos) + (if (not (web-mode-part-sb "{" part-beg)) + (progn + (setq beg part-beg) + (if (web-mode-part-sf ";" part-end) + (setq end (1+ (point))) + (setq end part-end)) + ) ;progn + (setq beg (point)) + (setq end (web-mode-closing-paren-position beg part-end)) + (if end + (setq end (1+ end)) + (setq end (line-end-position))) +;; (message "%S >>beg%S >>end%S" pos beg end) + (if (> pos end) + + ;;selectors + (progn + (goto-char pos) + (if (web-mode-part-rsb "[};]" part-beg) + (setq beg (1+ (point))) + (setq beg part-beg) + ) ;if + (goto-char pos) + (if (web-mode-part-rsf "[{;]" part-end) + (cond + ((eq (char-before) ?\;) + (setq end (point)) + ) + (t + (setq end (web-mode-closing-paren-position (1- (point)) part-end)) + (if end + (setq end (1+ end)) + (setq end part-end)) + ) + ) ;cond + (setq end part-end) + ) + ) ;progn selectors + + ;; declaration + (goto-char beg) + (if (web-mode-part-rsb "[}{;]" part-beg) + (setq beg (1+ (point))) + (setq beg part-beg) + ) ;if + ) ;if > pos end + ) +;; (message "beg(%S) end(%S)" beg end) + (when (eq (char-after beg) ?\n) + (setq beg (1+ beg))) + (cons beg end) + ))) + +(defun web-mode-jsx-skip (reg-end) + (let ((continue t) (pos nil) (i 0) tag) + (looking-at "<\\([[:alpha:]][[:alnum:]:-]*\\)") + (setq tag (match-string-no-properties 1)) + ;;(message "point=%S tag=%S" (point) tag) + (save-excursion + (while continue + (cond + ((> (setq i (1+ i)) 1000) + (message "jsx-skip ** warning **") + (setq continue nil)) + ((looking-at "<[[:alpha:]][[:alnum:]:-]*[ ]*/>") + (goto-char (match-end 0)) + (setq pos (point)) + (setq continue nil)) + ((not (web-mode-dom-rsf ">\\([ \t\n]*[\];,)':}|&]\\)\\|{" reg-end)) + (setq continue nil) + ) + ((eq (char-before) ?\{) + (backward-char) + (web-mode-closing-paren reg-end) + (forward-char) + ) + (t + (setq continue nil) + (setq pos (match-beginning 1)) + ) ;t + ) ;cond + ) ;while + ) ;save-excursion + (when pos (goto-char pos)) + ;;(message "jsx-skip: %S" pos) + pos)) + +;; (defun web-mode-jsx-skip2 (reg-end) +;; (let ((continue t) (pos nil) (i 0) (tag nil) (regexp nil) (counter 1)) +;; (looking-at "<\\([[:alpha:]][[:alnum:]:-]*\\)") +;; (setq tag (match-string-no-properties 1)) +;; (setq regexp (concat "</?" tag)) +;; ;;(message "point=%S tag=%S" (point) tag) +;; (save-excursion +;; (while continue +;; (cond +;; ((> (setq i (1+ i)) 100) +;; (message "jsx-skip ** warning **") +;; (setq continue nil)) +;; ((looking-at "<[[:alpha:]][[:alnum:]:-]*[ ]*/>") +;; (goto-char (match-end 0)) +;; (setq pos (point)) +;; (setq continue nil)) +;; ((not (web-mode-dom-rsf ">\\([ \t\n]*[\];,)':}]\\)\\|{" reg-end)) +;; (setq continue nil) +;; ) +;; ((eq (char-before) ?\{) +;; (backward-char) +;; (web-mode-closing-paren reg-end) +;; (forward-char) +;; ) +;; (t +;; (setq continue nil) +;; (setq pos (match-beginning 1)) +;; ) ;t +;; ) ;cond +;; ) ;while +;; ) ;save-excursion +;; (when pos (goto-char pos)) +;; ;;(message "jsx-skip: %S" pos) +;; pos)) + +;; http://facebook.github.io/jsx/ +;; https://github.com/facebook/jsx/blob/master/AST.md +(defun web-mode-jsx-scan-element (reg-beg reg-end depth) + (unless depth (setq depth 1)) + (save-excursion + (let (token-beg token-end regexp) + (goto-char reg-beg) + (put-text-property reg-beg (1+ reg-beg) 'jsx-beg depth) + (put-text-property (1- reg-end) reg-end 'jsx-end depth) + (put-text-property reg-beg reg-end 'jsx-depth depth) + (goto-char reg-beg) + (web-mode-scan-elements reg-beg reg-end) + (web-mode-jsx-scan-expression reg-beg reg-end (1+ depth)) + ))) + +(defun web-mode-jsx-scan-expression (reg-beg reg-end depth) + (let ((continue t) beg end) + (save-excursion + (goto-char reg-beg) + ;;(message "reg-beg=%S reg-end=%S" reg-beg reg-end) + (while (and continue (search-forward "{" reg-end t)) + (backward-char) + (setq beg (point) + end (web-mode-closing-paren reg-end)) + (cond + ((eq (get-text-property beg 'part-token) 'comment) + (forward-char)) + ((not end) + (setq continue nil)) + (t + (setq end (1+ end)) + (put-text-property beg end 'jsx-depth depth) + (put-text-property beg (1+ beg) 'jsx-beg depth) + (put-text-property (1- end) end 'jsx-end depth) + (web-mode-part-scan beg end "jsx" (1+ depth)) + ) ;t + ) ;cond + ) ;while + ) ;save-excursion + )) + +(defun web-mode-jsx-is-html (&optional pos) + (interactive) + (unless pos (setq pos (point))) + (let (ret (depth (get-text-property pos 'jsx-depth))) + (cond + ((or (null depth) (<= pos 2)) + (setq pos nil)) + ((and (= depth 1) (get-text-property pos 'jsx-beg)) + (setq pos nil)) + ((get-text-property pos 'tag-end) + (setq pos nil)) + ((get-text-property pos 'tag-attr-beg) + (setq pos nil)) + ((get-text-property pos 'jsx-beg) + (setq pos (null (get-text-property pos 'tag-beg)))) + ((setq pos (web-mode-jsx-depth-beginning-position pos)) + (setq pos (not (null (get-text-property pos 'tag-beg))))) + (t + (setq pos nil)) + ) ;cond + ;;(message "is-html: %S (depth=%S)" pos depth) + pos)) + +(defun web-mode-jsx-is-expr (&optional pos) + (cond + ((and (get-text-property pos 'jsx-beg) + (not (get-text-property pos 'tag-beg))) + nil) + (t + (setq pos (web-mode-jsx-depth-beginning-position pos)) + (null (get-text-property pos 'tag-beg))) + ) ;cond + ) + +(defun web-mode-jsx-depth-beginning-position (&optional pos target-depth) + (interactive) + (unless pos (setq pos (point))) + (unless target-depth (setq target-depth (get-text-property pos 'jsx-depth))) + (cond + ((or (null target-depth) (bobp)) + (setq pos nil)) + ((and (get-text-property pos 'jsx-beg) (= target-depth (get-text-property pos 'jsx-depth))) + ) + (t + (let ((continue t) depth) + (while continue + (setq pos (previous-single-property-change pos 'jsx-depth)) + (cond + ((or (null pos) + (null (setq depth (get-text-property pos 'jsx-depth)))) + (setq continue nil + pos nil)) + ((and (get-text-property pos 'jsx-beg) (= target-depth depth)) + (setq continue nil)) + ) ;cond + ) ;while + ) ;let + ) ;t + ) ;cond + ;;(message "beg: %S" pos) + pos) + +(defun web-mode-jsx-element-next (reg-end) + (let (continue beg end) + (setq beg (point)) + (unless (get-text-property beg 'jsx-depth) + (setq beg (next-single-property-change beg 'jsx-beg))) + (setq continue (and beg (< beg reg-end)) + end beg) + (while continue + (setq end (next-single-property-change end 'jsx-end)) + (cond + ((or (null end) (> end reg-end)) + (setq continue nil + end nil)) + ((eq (get-text-property end 'jsx-depth) 1) + (setq continue nil)) + (t + (setq end (1+ end))) + ) ;cond + ) ;while + ;;(message "beg=%S end=%S" beg end) + (if (and beg end (< beg end)) (cons beg end) nil))) + +(defun web-mode-jsx-expression-next (reg-end) + (let (beg end depth continue pos) + (setq beg (point)) + ;;(message "pt=%S" beg) + (unless (and (get-text-property beg 'jsx-beg) (null (get-text-property beg 'tag-beg))) + ;;(setq beg (next-single-property-change beg 'jsx-beg)) + (setq continue t + pos (1+ beg)) + (while continue + (setq pos (next-single-property-change pos 'jsx-beg)) + (cond + ((null pos) + (setq continue nil + beg nil)) + ((> pos reg-end) + (setq continue nil + beg nil)) + ((null (get-text-property pos 'jsx-beg)) + ) + ((null (get-text-property pos 'tag-beg)) + (setq continue nil + beg pos)) + ;;(t + ;; (setq pos (1+ pos))) + ) ;cond + ) ;while + ) ;unless + ;;(message "beg=%S" beg) + (when (and beg (< beg reg-end)) + (setq depth (get-text-property beg 'jsx-beg) + continue (not (null depth)) + pos beg) + ;;(message "beg=%S" beg) + (while continue + (setq pos (next-single-property-change pos 'jsx-end)) + ;;(message "pos=%S" pos) + (cond + ((null pos) + (setq continue nil)) + ((> pos reg-end) + (setq continue nil)) + ((eq depth (get-text-property pos 'jsx-end)) + (setq continue nil + end pos)) + (t + ;;(setq pos (1+ pos)) + ) + ) ;cond + ) ;while + ) ;when + ;;(message "%S > %S" beg end) + (if (and beg end) (cons beg end) nil))) + +(defun web-mode-jsx-depth-next (reg-end) + (let (beg end depth continue pos) + (setq beg (point)) + ;;(message "pt=%S" beg) + (unless (get-text-property beg 'jsx-beg) + ;;(setq beg (next-single-property-change beg 'jsx-beg)) + ;;(setq pos (1+ beg)) + (setq pos (next-single-property-change (1+ beg) 'jsx-beg)) + (cond + ((null pos) + (setq beg nil)) + ((>= pos reg-end) + (setq beg nil)) + (t + (setq beg pos)) + ) ;cond + ) ;unless + ;;(message "beg=%S" beg) + (when beg + (setq depth (get-text-property beg 'jsx-beg) + continue (not (null depth)) + pos beg) + ;;(message "beg=%S" beg) + (while continue + (setq pos (next-single-property-change pos 'jsx-end)) + ;;(message "pos=%S" pos) + (cond + ((null pos) + (setq continue nil)) + ((> pos reg-end) + (setq continue nil)) + ((eq depth (get-text-property pos 'jsx-end)) + (setq continue nil + end pos)) + (t + ;;(setq pos (1+ pos)) + ) + ) ;cond + ) ;while + ) ;when + ;;(message "%S > %S" beg end) + (if (and beg end) (cons beg end) nil))) + +(defun web-mode-jsx-beginning () + (interactive) + (let (depth (continue t) (reg-beg (point-min)) (pos (point))) + (setq depth (get-text-property pos 'jsx-depth)) + (cond + ((not depth) + ) + ((get-text-property (1- pos) 'jsx-beg) + (goto-char (1- pos))) + (t + (while continue + (setq pos (previous-single-property-change pos 'jsx-beg)) + ;;(message "pos=%S" pos) + (cond + ((null pos) + (setq continue nil)) + ((<= pos reg-beg) + (setq continue nil)) + ((eq depth (get-text-property pos 'jsx-beg)) + (setq continue nil)) + ) ;cond + ) ;while + (web-mode-go pos) + ) ;t + ) ;cond + )) + +(defun web-mode-jsx-end () + (interactive) + (let (depth (continue t) (reg-end (point-max)) (pos (point))) + (setq depth (get-text-property pos 'jsx-depth)) + (cond + ((not depth) + ) + ((get-text-property pos 'jsx-end) + (goto-char (+ pos 1))) + (t + (while continue + (setq pos (next-single-property-change pos 'jsx-end)) + ;;(message "pos=%S" pos) + (cond + ((null pos) + (setq continue nil)) + ((> pos reg-end) + (setq continue nil)) + ((eq depth (get-text-property pos 'jsx-end)) + (setq continue nil)) + ) ;cond + ) ;while + (web-mode-go pos 1) + ) ;t + ) ;cond + )) + +;;---- FONTIFICATION ----------------------------------------------------------- + +(defun web-mode-fontify (limit) + (when web-mode-trace + (message "fontify: point(%S) limit(%S)" (point) limit)) + (cond + ;;(web-mode-skip-fontification + ;; nil) + (t + (web-mode-with-silent-modifications + (save-excursion + (save-restriction + (save-match-data + (let ((beg (point)) + (buffer-undo-list t) + (end limit) + (inhibit-point-motion-hooks t) + (inhibit-quit t)) + (remove-list-of-text-properties beg end '(font-lock-face face)) + (cond + ((and (get-text-property beg 'block-side) + (not (get-text-property beg 'block-beg))) + (web-mode-fontify-block beg end)) + ((or (member web-mode-content-type web-mode-part-content-types) + (get-text-property beg 'part-side)) + (web-mode-fontify-part beg end) + (web-mode-block-foreach beg end 'web-mode-fontify-block)) + ((string= web-mode-engine "none") + (web-mode-fontify-tags beg end) + (web-mode-part-foreach beg end 'web-mode-fontify-part)) + (t + (web-mode-fontify-tags beg end) + (web-mode-part-foreach beg end 'web-mode-fontify-part) + (web-mode-block-foreach beg end 'web-mode-fontify-block)) + ) ;cond + (when web-mode-enable-element-content-fontification + (web-mode-fontify-elements beg end)) + (when web-mode-enable-whitespace-fontification + (web-mode-fontify-whitespaces beg end)) + ) ;let + )))) + nil) ;t + )) + +(defun web-mode-buffer-fontify () + (interactive) + (cond + ((and (fboundp 'font-lock-flush) global-font-lock-mode) + (font-lock-flush) + (font-lock-ensure)) + (t ;emacs 24 + ;;(font-lock-fontify-buffer) + (and global-font-lock-mode + (font-lock-fontify-region (point-min) (point-max)))) + )) + +(defun web-mode-unfontify-region (beg end) + ;;(message "unfontify: %S %S" beg end) + ) + +(defun web-mode-fontify-region (beg end keywords) +;; (message "beg=%S end=%S keywords=%S" beg end (symbol-name keywords)) + (save-excursion + (let ((font-lock-keywords keywords) + (font-lock-multiline nil) + (font-lock-keywords-case-fold-search + (member web-mode-engine '("archibus" "asp" "template-toolkit"))) + (font-lock-keywords-only t) + (font-lock-extend-region-functions nil)) + (when (and (listp font-lock-keywords) global-font-lock-mode) + (font-lock-fontify-region beg end) + ) + ))) + +(defun web-mode-fontify-tags (reg-beg reg-end &optional depth) + (let ((continue t)) + (goto-char reg-beg) + (when (and (not (get-text-property (point) 'tag-beg)) + (not (web-mode-tag-next))) + (setq continue nil)) + (when (and continue (>= (point) reg-end)) + (setq continue nil)) + (while continue + (cond + (depth + (when (eq depth (get-text-property (point) 'jsx-depth)) + (web-mode-fontify-tag)) + ) + (t + (web-mode-fontify-tag)) + ) ;cond + (when (or (not (web-mode-tag-next)) + (>= (point) reg-end)) + (setq continue nil)) + ) ;while + (when web-mode-enable-inlays + (when (null web-mode-inlay-regexp) + (setq web-mode-inlay-regexp (regexp-opt '("\\[" "\\(" "\\begin{align}")))) + (let (beg end expr) + (goto-char reg-beg) + (while (web-mode-dom-rsf web-mode-inlay-regexp reg-end) + (setq beg (match-beginning 0) + end nil + expr (substring (match-string-no-properties 0) 0 2)) + (setq expr (cond + ((string= expr "\\[") "\\]") + ((string= expr "\\(") "\\)") + (t "\\end{align}"))) + (when (and (web-mode-dom-sf expr reg-end) + (setq end (match-end 0)) + (not (text-property-any beg end 'tag-end t))) + (font-lock-append-text-property beg end 'font-lock-face 'web-mode-inlay-face) + ) ;when + ) ;while + ) ;let + ) ;when + (when web-mode-enable-html-entities-fontification + (let (beg end) + (goto-char reg-beg) + (while (web-mode-dom-rsf "&\\([#]?[[:alnum:]]\\{2,8\\}\\);" reg-end) + (setq beg (match-beginning 0) + end (match-end 0)) + (when (not (text-property-any beg end 'tag-end t)) + (font-lock-append-text-property beg end 'font-lock-face 'web-mode-html-entity-face) + ) ;when + ) ;while + ) ;let + ) ;when + )) + +(defun web-mode-fontify-tag (&optional beg end) + (unless beg (setq beg (point))) + (unless end (setq end (1+ (web-mode-tag-end-position beg)))) + (let (name type face flags slash-beg slash-end bracket-end) + (setq flags (get-text-property beg 'tag-beg) + type (get-text-property beg 'tag-type) + name (get-text-property beg 'tag-name)) + (setq bracket-end (> (logand flags 16) 0)) + (cond + ((eq type 'comment) + (put-text-property beg end 'font-lock-face 'web-mode-comment-face) + (when (and web-mode-enable-comment-interpolation (> (- end beg) 5)) + (web-mode-interpolate-comment beg end nil))) + ((eq type 'cdata) + (put-text-property beg end 'font-lock-face 'web-mode-doctype-face)) + ((eq type 'doctype) + (put-text-property beg end 'font-lock-face 'web-mode-doctype-face)) + ((eq type 'declaration) + (put-text-property beg end 'font-lock-face 'web-mode-doctype-face)) + (name + (setq slash-beg (> (logand flags 4) 0) + slash-end (> (logand flags 8) 0) + bracket-end (> (logand flags 16) 0)) + (setq face (cond + ((not bracket-end) 'web-mode-html-tag-unclosed-face) + ((and web-mode-enable-element-tag-fontification + (setq face (cdr (assoc name web-mode-element-tag-faces)))) + face) + ((> (logand flags 32) 0) 'web-mode-html-tag-namespaced-face) + ((> (logand flags 2) 0) 'web-mode-html-tag-custom-face) + (t 'web-mode-html-tag-face))) + (put-text-property beg (+ beg (if slash-beg 2 1)) + 'font-lock-face 'web-mode-html-tag-bracket-face) + (unless (string= name "_fragment_") + (put-text-property (+ beg (if slash-beg 2 1)) + (+ beg (if slash-beg 2 1) (length name)) + 'font-lock-face face)) + (when (or slash-end bracket-end) + (put-text-property (- end (if slash-end 2 1)) end 'font-lock-face 'web-mode-html-tag-bracket-face) + ) ;when + (when (> (logand flags 1) 0) + ;;(message "%S>%S" beg end) + (web-mode-fontify-attrs beg end)) + ) ;case name + ) ;cond + )) + +(defun web-mode-fontify-attrs (reg-beg reg-end) + (let ((continue t) (pos reg-beg) beg end flags offset face) + ;;(message "fontify-attrs %S>%S" reg-beg reg-end) + (while continue + (setq beg (web-mode-attribute-next-position pos reg-end)) + (cond + ((or (null beg) (>= beg reg-end)) + (setq continue nil)) + (t + (setq flags (or (get-text-property beg 'tag-attr-beg) 0)) + (setq face (cond + ((= (logand flags 1) 1) 'web-mode-html-attr-custom-face) + ((= (logand flags 2) 2) 'web-mode-html-attr-engine-face) + ((= (logand flags 4) 4) nil) + (t 'web-mode-html-attr-name-face))) + ;;(setq end (if (get-text-property beg 'tag-attr-end) beg (web-mode-attribute-end-position beg))) + (setq end (web-mode-attribute-end-position beg)) + ;;(message "beg=%S end=%S" beg end) + (cond + ((or (null end) (>= end reg-end)) + (setq continue nil)) + (t + (setq offset (get-text-property end 'tag-attr-end)) + (if (= offset 0) + (put-text-property beg (1+ end) 'font-lock-face face) + (put-text-property beg (+ beg offset) 'font-lock-face face) + (put-text-property (+ beg offset) (+ beg offset 1) + 'font-lock-face + 'web-mode-html-attr-equal-face) + (when (not (get-text-property (+ beg offset 1) 'jsx-beg)) + (put-text-property (+ beg offset 1) (1+ end) + 'font-lock-face + 'web-mode-html-attr-value-face) + ) + ) ;if offset + (setq pos (1+ end)) + ) ;t + ) ;cond + ) ;t + );cond + ) ;while + )) + +(defun web-mode-fontify-block (reg-beg reg-end) + (when web-mode-trace + (message "fontify-block: reg-beg(%S) reg-end(%S) engine(%S) keywords(%S)" + reg-beg reg-end web-mode-engine (not (null web-mode-engine-font-lock-keywords)))) + + (let (sub1 sub2 sub3 continue char keywords token-type face beg end (buffer (current-buffer))) + + ;; NOTE: required for blocks inside tag attrs + (remove-list-of-text-properties reg-beg reg-end '(font-lock-face)) + + (goto-char reg-beg) + + (when (null web-mode-engine-font-lock-keywords) + (setq sub1 (buffer-substring-no-properties + reg-beg (+ reg-beg 1)) + sub2 (buffer-substring-no-properties + reg-beg (+ reg-beg 2)) + sub3 (buffer-substring-no-properties + reg-beg (+ reg-beg (if (>= (point-max) (+ reg-beg 3)) 3 2)))) + ) + + (cond + + ((and (get-text-property reg-beg 'block-beg) + (eq (get-text-property reg-beg 'block-token) 'comment)) + (put-text-property reg-beg reg-end 'font-lock-face 'web-mode-comment-face) + ) ;comment block + + (web-mode-engine-font-lock-keywords + (setq keywords web-mode-engine-font-lock-keywords)) + + ((string= web-mode-engine "django") + (cond + ((string= sub2 "{{") + (setq keywords web-mode-django-expr-font-lock-keywords)) + ((string= sub2 "{%") + (setq keywords web-mode-django-code-font-lock-keywords)) + ((string= sub1 "#") + (setq keywords web-mode-django-code-font-lock-keywords)) + )) ;django + + ((string= web-mode-engine "mako") + (cond + ((member sub3 '("<% " "<%\n" "<%!")) + (setq keywords web-mode-mako-block-font-lock-keywords)) + ((eq (aref sub2 0) ?\%) + (setq keywords web-mode-mako-block-font-lock-keywords)) + ((member sub2 '("<%" "</")) + (setq keywords web-mode-mako-tag-font-lock-keywords)) + ((member sub2 '("${")) + (setq keywords web-mode-uel-font-lock-keywords)) + )) ;mako + + ((string= web-mode-engine "mason") + ;;(message "%S %S" sub2 sub3) + (cond + ((member sub3 '("<% " "<%\n" "<&|")) + (setq keywords web-mode-mason-code-font-lock-keywords)) + ((eq (aref sub2 0) ?\%) + (setq keywords web-mode-mason-code-font-lock-keywords)) + ((and (or (string= sub2 "<%") (string= sub3 "</%")) + (not (member sub3 '("<%c" "<%i" "<%p")))) + (setq keywords web-mode-mason-block-font-lock-keywords)) + (t + (setq keywords web-mode-mason-code-font-lock-keywords)) + )) ;mason + + ((string= web-mode-engine "jsp") + (cond + ((string= sub3 "<%@") + (setq keywords web-mode-directive-font-lock-keywords)) + ((member sub2 '("${" "#{")) + (setq keywords web-mode-uel-font-lock-keywords)) + ((string= sub2 "<%") + (setq keywords web-mode-jsp-font-lock-keywords)) + )) ;jsp + + ((string= web-mode-engine "asp") + (cond + ((or (string= sub2 "<%") + (not (string= sub1 "<"))) + (setq keywords web-mode-asp-font-lock-keywords)) + (t + (setq keywords web-mode-engine-tag-font-lock-keywords)) + )) ;asp + + ((string= web-mode-engine "clip") + (setq keywords web-mode-engine-tag-font-lock-keywords) + ) ;clip + + ((string= web-mode-engine "perl") + (setq keywords web-mode-engine-tag-font-lock-keywords) + ) ;perl + + ((string= web-mode-engine "aspx") + (cond + ((string= sub3 "<%@") + (setq keywords web-mode-directive-font-lock-keywords)) + ((string= sub3 "<%$") + (setq keywords web-mode-expression-font-lock-keywords)) + (t + (setq keywords web-mode-aspx-font-lock-keywords)) + )) ;aspx + + ((string= web-mode-engine "freemarker") + (cond + ((member sub2 '("${" "#{")) + (setq keywords web-mode-uel-font-lock-keywords)) + ((or (member sub2 '("<@" "[@" "<#" "[#")) + (member sub3 '("</@" "[/@" "</#" "[/#"))) + (setq keywords (if (eq ?\[ (aref sub2 0)) + web-mode-freemarker-square-font-lock-keywords + web-mode-freemarker-font-lock-keywords))) + (t + (setq keywords web-mode-engine-tag-font-lock-keywords)) + )) ;freemarker + + ) ;cond + + (when keywords + (web-mode-fontify-region reg-beg reg-end keywords) + (setq continue t) + (setq end reg-beg) + (while continue + (if (get-text-property end 'block-token) + (setq beg end) + (setq beg (next-single-property-change end 'block-token buffer reg-end))) + (setq end nil) + (when beg (setq char (char-after beg))) + (if (and beg (< beg reg-end)) + (progn + (setq token-type (get-text-property beg 'block-token)) + (setq face (cond + ((eq token-type 'string) 'web-mode-block-string-face) + ((eq token-type 'comment) 'web-mode-block-comment-face) + ((eq token-type 'symbol) 'web-mode-symbol-face) + (t 'web-mode-block-delimiter-face))) + (setq end (next-single-property-change beg 'block-token buffer reg-end)) +;; (message "end=%S" end) + (if (and end (<= end reg-end)) + (progn + ;;(message "%S > %S face(%S)" beg end face) + (remove-list-of-text-properties beg end '(face)) + (put-text-property beg end 'font-lock-face face) + ) + (setq continue nil + end nil) + ) ;if end + ) ;progn beg + (setq continue nil + end nil) + ) ;if beg + (when (and beg end) + (save-match-data + (when (and web-mode-enable-heredoc-fontification + (eq char ?\<) + (> (- end beg) 8) + (string-match-p "JS\\|JAVASCRIPT\\|HTM\\|CSS" (buffer-substring-no-properties beg end))) + (setq keywords + (cond + ((string-match-p "H" (buffer-substring-no-properties beg (+ beg 8))) + web-mode-html-font-lock-keywords) + (t + web-mode-javascript-font-lock-keywords) + )) + (web-mode-fontify-region beg end keywords) + ) + ) ;save-match-data + (when (and web-mode-enable-string-interpolation + (member char '(?\" ?\<)) + (member web-mode-engine '("php" "erb")) + (> (- end beg) 4)) + (web-mode-interpolate-block-string beg end) + ) ;when + (when (and web-mode-enable-comment-interpolation + (eq token-type 'comment) + (> (- end beg) 3)) + (web-mode-interpolate-comment beg end t) + ) ;when + (when (and web-mode-enable-comment-annotation + (eq token-type 'comment) + (> (- end beg) 3)) + (web-mode-annotate-comment beg end) + ) ;when + (when (and web-mode-enable-sql-detection + (eq token-type 'string) + (> (- end beg) 6) + (web-mode-looking-at-p (concat "\\(.\\|<<<[[:alnum:]]+\\)[ \n]*" web-mode-sql-queries) beg) + ) + (web-mode-interpolate-sql-string beg end) + ) ;when + ) ;when beg end + ) ;while continue + ) ;when keywords + + (when (and (member web-mode-engine '("mako")) + (> (- reg-end reg-beg) 12) + (eq ?\< (char-after reg-beg))) + (web-mode-interpolate-block-tag reg-beg reg-end)) + + (when web-mode-enable-block-face + (font-lock-append-text-property reg-beg reg-end 'face 'web-mode-block-face)) + + )) + +(defun web-mode-fontify-part (reg-beg reg-end &optional depth) + (save-excursion + (let (start continue token-type face pos beg end string-face comment-face content-type) + ;;(message "fontify-part: reg-beg(%S) reg-end(%S)" reg-beg reg-end) + (if (member web-mode-content-type web-mode-part-content-types) + (setq content-type web-mode-content-type) + (setq content-type (symbol-name (get-text-property reg-beg 'part-side)))) + ;;(message "content-type=%S" content-type) + (unless depth + (when (string= content-type "jsx") (setq depth 0)) + ) + (setq string-face 'web-mode-part-string-face + comment-face 'web-mode-part-comment-face) + (cond + ((member content-type '("javascript" "jsx")) + (setq string-face 'web-mode-javascript-string-face + comment-face 'web-mode-javascript-comment-face) + (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords)) + ((string= content-type "json") + (setq string-face 'web-mode-json-string-face + comment-face 'web-mode-json-comment-face) + (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords)) + ((string= content-type "css") + (setq string-face 'web-mode-css-string-face + comment-face 'web-mode-css-comment-face) + (web-mode-fontify-css-rules reg-beg reg-end)) + ((string= content-type "sql") + (web-mode-fontify-region reg-beg reg-end web-mode-sql-font-lock-keywords)) + ((string= content-type "stylus") + (web-mode-fontify-region reg-beg reg-end web-mode-stylus-font-lock-keywords)) + ((string= content-type "sass") + (web-mode-fontify-region reg-beg reg-end web-mode-sass-font-lock-keywords)) + ((string= content-type "pug") + (web-mode-fontify-region reg-beg reg-end web-mode-pug-font-lock-keywords)) + ((string= content-type "markdown") + (web-mode-fontify-region reg-beg reg-end web-mode-markdown-font-lock-keywords)) + ((string= content-type "ruby") + (web-mode-fontify-region reg-beg reg-end web-mode-erb-font-lock-keywords)) + ((string= content-type "typescript") + (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords)) + ) ;cond + + (goto-char reg-beg) + + ;;(when (string= content-type "jsx") (web-mode-fontify-tags reg-beg reg-end)) + ;;(setq continue (and pos (< pos reg-end))) + (setq continue t + pos reg-beg) + (while continue + (if (get-text-property pos 'part-token) + (setq beg pos) + (setq beg (next-single-property-change pos 'part-token))) + (cond + ((or (null beg) (>= beg reg-end)) + (setq continue nil + end nil)) + ((and (eq depth 0) (get-text-property beg 'jsx-depth)) + (setq pos (or (next-single-property-change beg 'jsx-depth) (point-max)))) + (t + ;;(message "%c" (char-after beg)) + (setq token-type (get-text-property beg 'part-token)) + (setq face (cond + ((eq token-type 'string) string-face) + ((eq token-type 'comment) comment-face) + ((eq token-type 'context) 'web-mode-json-context-face) + ((eq token-type 'key) 'web-mode-json-key-face) + (t nil))) + (setq end (or (next-single-property-change beg 'part-token) (point-max)) + pos end) + (cond + ((or (null end) (> end reg-end)) + (setq continue nil + end nil)) + (t + (when face + (remove-list-of-text-properties beg end '(face)) + (put-text-property beg end 'font-lock-face face)) + (cond + ((< (- end beg) 6) + ) + ((eq token-type 'string) + (cond + ((and (eq (char-after beg) ?\`) + web-mode-enable-literal-interpolation + (member content-type '("javascript" "jsx" "typescript"))) + (web-mode-interpolate-javascript-literal beg end) + ) + ((and (eq (char-after beg) ?\") + web-mode-enable-string-interpolation + (member content-type '("javascript" "jsx" "typescript"))) + (web-mode-interpolate-javascript-string beg end)) + ) ;cond + ) ;case string + ((eq token-type 'comment) + (when web-mode-enable-comment-interpolation + (web-mode-interpolate-comment beg end t)) + (when web-mode-enable-comment-annotation + (web-mode-annotate-comment beg end)) + ) + ) ;cond + ) ;t + ) ;cond + ) ;t + ) ;cond + ) ;while + + (when (and (string= web-mode-content-type "html") web-mode-enable-part-face) + (font-lock-append-text-property reg-beg reg-end 'face + (cond + ((string= content-type "javascript") + 'web-mode-script-face) + ((string= content-type "css") + 'web-mode-style-face) + (t + 'web-mode-part-face))) + ) + + (when (and web-mode-enable-css-colorization (string= content-type "stylus")) + (goto-char reg-beg) + (while (and (re-search-forward "#[0-9a-fA-F]\\{6\\}\\|#[0-9a-fA-F]\\{3\\}\\|rgba?([ ]*\\([[:digit:]]\\{1,3\\}\\)[ ]*,[ ]*\\([[:digit:]]\\{1,3\\}\\)[ ]*,[ ]*\\([[:digit:]]\\{1,3\\}\\)\\(.*?\\))" end t) + (<= (point) reg-end)) + (web-mode-colorize (match-beginning 0) (match-end 0)) + ) + ) + + (when (and (eq depth 0) (string= content-type "jsx")) + (let (pair elt-beg elt-end exp-beg exp-end exp-depth) + (goto-char reg-beg) + (while (setq pair (web-mode-jsx-element-next reg-end)) + ;;(message "elt-pair=%S" pair) + (setq elt-beg (car pair) + elt-end (cdr pair)) + (remove-list-of-text-properties elt-beg (1+ elt-end) '(face)) + (web-mode-fontify-tags elt-beg elt-end 1) + (goto-char elt-beg) + (while (setq pair (web-mode-jsx-expression-next elt-end)) + ;;(message "exp-pair=%S elt-end=%S" pair elt-end) + (setq exp-beg (car pair) + exp-end (cdr pair)) + (when (eq (char-after exp-beg) ?\{) + ;;(message "%S : %c %c" exp-beg (char-after (+ exp-beg 1)) (char-after (+ exp-beg 2))) + (cond + ;;((and (eq (char-after (+ exp-beg 1)) ?\/) (eq (char-after (+ exp-beg 2)) ?\*)) + ;; (put-text-property exp-beg (1+ exp-end) 'font-lock-face 'web-mode-part-comment-face) + ;; ) + (t + (setq exp-depth (get-text-property exp-beg 'jsx-depth)) + (remove-list-of-text-properties exp-beg exp-end '(font-lock-face)) + (put-text-property exp-beg (1+ exp-beg) 'font-lock-face 'web-mode-block-delimiter-face) + (when (and (eq (get-text-property exp-beg 'tag-attr-beg) 4) (web-mode-looking-at-p "\.\.\." (1+ exp-beg))) + (put-text-property exp-beg (+ exp-beg 4) 'font-lock-face 'web-mode-block-delimiter-face)) + (put-text-property exp-end (1+ exp-end) 'font-lock-face 'web-mode-block-delimiter-face) + (web-mode-fontify-tags (1+ exp-beg) exp-end (1+ exp-depth)) + (web-mode-fontify-part (1+ exp-beg) exp-end exp-depth) + (web-mode-fontify-region (1+ exp-beg) exp-end web-mode-javascript-font-lock-keywords) + ) ;t + ) ;cond + ) ;when + (goto-char (1+ exp-beg)) + ) ;while exp + + (when (and elt-beg web-mode-jsx-depth-faces) + (let (depth-beg depth-end jsx-face) + (goto-char elt-beg) + (while (setq pair (web-mode-jsx-depth-next reg-end)) + ;;(message "depth-pair=%S" pair) + (setq depth-beg (car pair) + depth-end (cdr pair) + depth (get-text-property depth-beg 'jsx-depth) + jsx-face (elt web-mode-jsx-depth-faces (1- depth))) + ;;(message "%S" jsx-face) + (font-lock-prepend-text-property depth-beg (1+ depth-end) 'face jsx-face) + (goto-char (+ depth-beg 2)) + ) + ) ;let + ) + + (goto-char (1+ elt-end)) + ) ;while elt + ) ;let + ) ;when + + ) ;let + ) ;save-excursion + ) + +(defun web-mode-fontify-css-rules (part-beg part-end) + (save-excursion + (goto-char part-beg) + (let (rule (continue t) (i 0) (at-rule nil) (var-rule nil)) + (while continue + (setq rule (web-mode-css-rule-next part-end)) + ;;(message "rule=%S" rule) + (cond + ((> (setq i (1+ i)) 1000) + (message "fontify-css-rules ** too much rules **") + (setq continue nil)) + ((null rule) + (setq continue nil)) + ((and (setq at-rule (plist-get rule :at-rule)) + (not (member at-rule '("charset" "font-face" "import" "viewport"))) + (plist-get rule :dec-end)) + (web-mode-fontify-css-rule (plist-get rule :sel-beg) + (plist-get rule :sel-end) + nil nil) + (web-mode-fontify-css-rules (plist-get rule :dec-beg) + (plist-get rule :dec-end))) + (t + (web-mode-fontify-css-rule (plist-get rule :sel-beg) + (plist-get rule :sel-end) + (plist-get rule :dec-beg) + (plist-get rule :dec-end))) + ) ;cond + ) ;while + ) ;let + )) + +(defun web-mode-fontify-css-rule (sel-beg sel-end dec-beg dec-end) + (save-excursion + ;;(let ((end sel-end)) + ;;(message "sel-beg=%S sel-end=%S dec-beg=%S dec-end=%S" sel-beg sel-end dec-beg dec-end) + (web-mode-fontify-region sel-beg sel-end web-mode-selector-font-lock-keywords) + (when (and dec-beg dec-end) + ;;(setq end dec-end) + (web-mode-fontify-region dec-beg dec-end web-mode-declaration-font-lock-keywords) + ) ;when + (when (and dec-beg dec-end) + (goto-char dec-beg) + (while (and web-mode-enable-css-colorization + (re-search-forward "\\(?1:#[0-9a-fA-F]\\{6\\}\\)\\|\\(?1:#[0-9a-fA-F]\\{3\\}\\)\\|\\(?1:rgba?([ ]*\\(?2:[[:digit:]]\\{1,3\\}\\)[ ]*,[ ]*\\(?3:[[:digit:]]\\{1,3\\}\\)[ ]*,[ ]*\\(?4:[[:digit:]]\\{1,3\\}\\)\\(.*?\\))\\)\\|[: ]\\(?1:black\\|silver\\|gray\\|white\\|maroon\\|red\\|purple\\|fuchsia\\|green\\|lime\\|olive\\|yellow\\|navy\\|blue\\|teal\\|aqua\\|orange\\|aliceblue\\|antiquewhite\\|aquamarine\\|azure\\|beige\\|bisque\\|blanchedalmond\\|blueviolet\\|brown\\|burlywood\\|cadetblue\\|chartreuse\\|chocolate\\|coral\\|cornflowerblue\\|cornsilk\\|crimson\\|cyan\\|darkblue\\|darkcyan\\|darkgoldenrod\\|darkgray\\|darkgreen\\|darkgrey\\|darkkhaki\\|darkmagenta\\|darkolivegreen\\|darkorange\\|darkorchid\\|darkred\\|darksalmon\\|darkseagreen\\|darkslateblue\\|darkslategray\\|darkslategrey\\|darkturquoise\\|darkviolet\\|deeppink\\|deepskyblue\\|dimgray\\|dimgrey\\|dodgerblue\\|firebrick\\|floralwhite\\|forestgreen\\|gainsboro\\|ghostwhite\\|gold\\|goldenrod\\|greenyellow\\|grey\\|honeydew\\|hotpink\\|indianred\\|indigo\\|ivory\\|khaki\\|lavender\\|lavenderblush\\|lawngreen\\|lemonchiffon\\|lightblue\\|lightcoral\\|lightcyan\\|lightgoldenrodyellow\\|lightgray\\|lightgreen\\|lightgrey\\|lightpink\\|lightsalmon\\|lightseagreen\\|lightskyblue\\|lightslategray\\|lightslategrey\\|lightsteelblue\\|lightyellow\\|limegreen\\|linen\\|magenta\\|mediumaquamarine\\|mediumblue\\|mediumorchid\\|mediumpurple\\|mediumseagreen\\|mediumslateblue\\|mediumspringgreen\\|mediumturquoise\\|mediumvioletred\\|midnightblue\\|mintcream\\|mistyrose\\|moccasin\\|navajowhite\\|oldlace\\|olivedrab\\|orangered\\|orchid\\|palegoldenrod\\|palegreen\\|paleturquoise\\|palevioletred\\|papayawhip\\|peachpuff\\|peru\\|pink\\|plum\\|powderblue\\|rosybrown\\|royalblue\\|saddlebrown\\|salmon\\|sandybrown\\|seagreen\\|seashell\\|sienna\\|skyblue\\|slateblue\\|slategray\\|slategrey\\|snow\\|springgreen\\|steelblue\\|tan\\|thistle\\|tomato\\|turquoise\\|violet\\|wheat\\|whitesmoke\\|yellowgreen\\)[ ;]" dec-end t) + ;;(progn (message "%S %S" end (point)) t) + (<= (point) dec-end)) + ;;(message "web-mode-colorize beg=%S end=%S match=%S" (match-beginning 0) (match-end 0) (buffer-substring-no-properties (match-beginning 0) (match-end 0))) + (web-mode-colorize (match-beginning 1) (match-end 1)) + ) ;while + ) ;when + ;;) ;let + )) + +(defun web-mode-colorize-foreground (color) + (let* ((values (x-color-values color)) + (r (car values)) + (g (cadr values)) + (b (car (cdr (cdr values))))) + (if (> 128.0 (floor (+ (* .3 r) (* .59 g) (* .11 b)) 256)) + "white" "black"))) + +(defun web-mode-colorize (beg end) + (let (str str1 plist) + (setq str (buffer-substring-no-properties beg end)) + ;;(setq str1 (match-string-no-properties 1)) + ;;(message "str=%S" str str1) + (cond + ;;(t + ;; (message "%S %S %S %S %S" (match-string-no-properties 0) (match-string-no-properties 1) (match-string-no-properties 2) (match-string-no-properties 3) (match-string-no-properties 4)) + ;; ) + ((string= (substring str 0 1) "#") + (setq plist (list :background str + :foreground (web-mode-colorize-foreground str)))) + ((and (>= (length str) 3) (string= (substring str 0 3) "rgb")) + (setq str (format "#%02X%02X%02X" + (string-to-number (match-string-no-properties 2)) + (string-to-number (match-string-no-properties 3)) + (string-to-number (match-string-no-properties 4)))) + (setq plist (list :background str + :foreground (web-mode-colorize-foreground str)))) + ((string= str "black") (setq plist (list :background "#000000" :foreground (web-mode-colorize-foreground "#000000")))) + ((string= str "silver") (setq plist (list :background "#c0c0c0" :foreground (web-mode-colorize-foreground "#c0c0c0")))) + ((string= str "gray") (setq plist (list :background "#808080" :foreground (web-mode-colorize-foreground "#808080")))) + ((string= str "white") (setq plist (list :background "#ffffff" :foreground (web-mode-colorize-foreground "#ffffff")))) + ((string= str "maroon") (setq plist (list :background "#800000" :foreground (web-mode-colorize-foreground "#800000")))) + ((string= str "red") (setq plist (list :background "#ff0000" :foreground (web-mode-colorize-foreground "#ff0000")))) + ((string= str "purple") (setq plist (list :background "#800080" :foreground (web-mode-colorize-foreground "#800080")))) + ((string= str "fuchsia") (setq plist (list :background "#ff00ff" :foreground (web-mode-colorize-foreground "#ff00ff")))) + ((string= str "green") (setq plist (list :background "#008000" :foreground (web-mode-colorize-foreground "#008000")))) + ((string= str "lime") (setq plist (list :background "#00ff00" :foreground (web-mode-colorize-foreground "#00ff00")))) + ((string= str "olive") (setq plist (list :background "#808000" :foreground (web-mode-colorize-foreground "#808000")))) + ((string= str "yellow") (setq plist (list :background "#ffff00" :foreground (web-mode-colorize-foreground "#ffff00")))) + ((string= str "navy") (setq plist (list :background "#000080" :foreground (web-mode-colorize-foreground "#000080")))) + ((string= str "blue") (setq plist (list :background "#0000ff" :foreground (web-mode-colorize-foreground "#0000ff")))) + ((string= str "teal") (setq plist (list :background "#008080" :foreground (web-mode-colorize-foreground "#008080")))) + ((string= str "aqua") (setq plist (list :background "#00ffff" :foreground (web-mode-colorize-foreground "#00ffff")))) + ((string= str "orange") (setq plist (list :background "#ffa500" :foreground (web-mode-colorize-foreground "#ffa500")))) + ((string= str "aliceblue") (setq plist (list :background "#f0f8ff" :foreground (web-mode-colorize-foreground "#f0f8ff")))) + ((string= str "antiquewhite") (setq plist (list :background "#faebd7" :foreground (web-mode-colorize-foreground "#faebd7")))) + ((string= str "aquamarine") (setq plist (list :background "#7fffd4" :foreground (web-mode-colorize-foreground "#7fffd4")))) + ((string= str "azure") (setq plist (list :background "#f0ffff" :foreground (web-mode-colorize-foreground "#f0ffff")))) + ((string= str "beige") (setq plist (list :background "#f5f5dc" :foreground (web-mode-colorize-foreground "#f5f5dc")))) + ((string= str "bisque") (setq plist (list :background "#ffe4c4" :foreground (web-mode-colorize-foreground "#ffe4c4")))) + ((string= str "blanchedalmond") (setq plist (list :background "#ffebcd" :foreground (web-mode-colorize-foreground "#ffebcd")))) + ((string= str "blueviolet") (setq plist (list :background "#8a2be2" :foreground (web-mode-colorize-foreground "#8a2be2")))) + ((string= str "brown") (setq plist (list :background "#a52a2a" :foreground (web-mode-colorize-foreground "#a52a2a")))) + ((string= str "burlywood") (setq plist (list :background "#deb887" :foreground (web-mode-colorize-foreground "#deb887")))) + ((string= str "cadetblue") (setq plist (list :background "#5f9ea0" :foreground (web-mode-colorize-foreground "#5f9ea0")))) + ((string= str "chartreuse") (setq plist (list :background "#7fff00" :foreground (web-mode-colorize-foreground "#7fff00")))) + ((string= str "chocolate") (setq plist (list :background "#d2691e" :foreground (web-mode-colorize-foreground "#d2691e")))) + ((string= str "coral") (setq plist (list :background "#ff7f50" :foreground (web-mode-colorize-foreground "#ff7f50")))) + ((string= str "cornflowerblue") (setq plist (list :background "#6495ed" :foreground (web-mode-colorize-foreground "#6495ed")))) + ((string= str "cornsilk") (setq plist (list :background "#fff8dc" :foreground (web-mode-colorize-foreground "#fff8dc")))) + ((string= str "crimson") (setq plist (list :background "#dc143c" :foreground (web-mode-colorize-foreground "#dc143c")))) + ((string= str "cyan") (setq plist (list :background "#00ffff" :foreground (web-mode-colorize-foreground "#00ffff")))) + ((string= str "darkblue") (setq plist (list :background "#00008b" :foreground (web-mode-colorize-foreground "#00008b")))) + ((string= str "darkcyan") (setq plist (list :background "#008b8b" :foreground (web-mode-colorize-foreground "#008b8b")))) + ((string= str "darkgoldenrod") (setq plist (list :background "#b8860b" :foreground (web-mode-colorize-foreground "#b8860b")))) + ((string= str "darkgray") (setq plist (list :background "#a9a9a9" :foreground (web-mode-colorize-foreground "#a9a9a9")))) + ((string= str "darkgreen") (setq plist (list :background "#006400" :foreground (web-mode-colorize-foreground "#006400")))) + ((string= str "darkgrey") (setq plist (list :background "#a9a9a9" :foreground (web-mode-colorize-foreground "#a9a9a9")))) + ((string= str "darkkhaki") (setq plist (list :background "#bdb76b" :foreground (web-mode-colorize-foreground "#bdb76b")))) + ((string= str "darkmagenta") (setq plist (list :background "#8b008b" :foreground (web-mode-colorize-foreground "#8b008b")))) + ((string= str "darkolivegreen") (setq plist (list :background "#556b2f" :foreground (web-mode-colorize-foreground "#556b2f")))) + ((string= str "darkorange") (setq plist (list :background "#ff8c00" :foreground (web-mode-colorize-foreground "#ff8c00")))) + ((string= str "darkorchid") (setq plist (list :background "#9932cc" :foreground (web-mode-colorize-foreground "#9932cc")))) + ((string= str "darkred") (setq plist (list :background "#8b0000" :foreground (web-mode-colorize-foreground "#8b0000")))) + ((string= str "darksalmon") (setq plist (list :background "#e9967a" :foreground (web-mode-colorize-foreground "#e9967a")))) + ((string= str "darkseagreen") (setq plist (list :background "#8fbc8f" :foreground (web-mode-colorize-foreground "#8fbc8f")))) + ((string= str "darkslateblue") (setq plist (list :background "#483d8b" :foreground (web-mode-colorize-foreground "#483d8b")))) + ((string= str "darkslategray") (setq plist (list :background "#2f4f4f" :foreground (web-mode-colorize-foreground "#2f4f4f")))) + ((string= str "darkslategrey") (setq plist (list :background "#2f4f4f" :foreground (web-mode-colorize-foreground "#2f4f4f")))) + ((string= str "darkturquoise") (setq plist (list :background "#00ced1" :foreground (web-mode-colorize-foreground "#00ced1")))) + ((string= str "darkviolet") (setq plist (list :background "#9400d3" :foreground (web-mode-colorize-foreground "#9400d3")))) + ((string= str "deeppink") (setq plist (list :background "#ff1493" :foreground (web-mode-colorize-foreground "#ff1493")))) + ((string= str "deepskyblue") (setq plist (list :background "#00bfff" :foreground (web-mode-colorize-foreground "#00bfff")))) + ((string= str "dimgray") (setq plist (list :background "#696969" :foreground (web-mode-colorize-foreground "#696969")))) + ((string= str "dimgrey") (setq plist (list :background "#696969" :foreground (web-mode-colorize-foreground "#696969")))) + ((string= str "dodgerblue") (setq plist (list :background "#1e90ff" :foreground (web-mode-colorize-foreground "#1e90ff")))) + ((string= str "firebrick") (setq plist (list :background "#b22222" :foreground (web-mode-colorize-foreground "#b22222")))) + ((string= str "floralwhite") (setq plist (list :background "#fffaf0" :foreground (web-mode-colorize-foreground "#fffaf0")))) + ((string= str "forestgreen") (setq plist (list :background "#228b22" :foreground (web-mode-colorize-foreground "#228b22")))) + ((string= str "gainsboro") (setq plist (list :background "#dcdcdc" :foreground (web-mode-colorize-foreground "#dcdcdc")))) + ((string= str "ghostwhite") (setq plist (list :background "#f8f8ff" :foreground (web-mode-colorize-foreground "#f8f8ff")))) + ((string= str "gold") (setq plist (list :background "#ffd700" :foreground (web-mode-colorize-foreground "#ffd700")))) + ((string= str "goldenrod") (setq plist (list :background "#daa520" :foreground (web-mode-colorize-foreground "#daa520")))) + ((string= str "greenyellow") (setq plist (list :background "#adff2f" :foreground (web-mode-colorize-foreground "#adff2f")))) + ((string= str "grey") (setq plist (list :background "#808080" :foreground (web-mode-colorize-foreground "#808080")))) + ((string= str "honeydew") (setq plist (list :background "#f0fff0" :foreground (web-mode-colorize-foreground "#f0fff0")))) + ((string= str "hotpink") (setq plist (list :background "#ff69b4" :foreground (web-mode-colorize-foreground "#ff69b4")))) + ((string= str "indianred") (setq plist (list :background "#cd5c5c" :foreground (web-mode-colorize-foreground "#cd5c5c")))) + ((string= str "indigo") (setq plist (list :background "#4b0082" :foreground (web-mode-colorize-foreground "#4b0082")))) + ((string= str "ivory") (setq plist (list :background "#fffff0" :foreground (web-mode-colorize-foreground "#fffff0")))) + ((string= str "khaki") (setq plist (list :background "#f0e68c" :foreground (web-mode-colorize-foreground "#f0e68c")))) + ((string= str "lavender") (setq plist (list :background "#e6e6fa" :foreground (web-mode-colorize-foreground "#e6e6fa")))) + ((string= str "lavenderblush") (setq plist (list :background "#fff0f5" :foreground (web-mode-colorize-foreground "#fff0f5")))) + ((string= str "lawngreen") (setq plist (list :background "#7cfc00" :foreground (web-mode-colorize-foreground "#7cfc00")))) + ((string= str "lemonchiffon") (setq plist (list :background "#fffacd" :foreground (web-mode-colorize-foreground "#fffacd")))) + ((string= str "lightblue") (setq plist (list :background "#add8e6" :foreground (web-mode-colorize-foreground "#add8e6")))) + ((string= str "lightcoral") (setq plist (list :background "#f08080" :foreground (web-mode-colorize-foreground "#f08080")))) + ((string= str "lightcyan") (setq plist (list :background "#e0ffff" :foreground (web-mode-colorize-foreground "#e0ffff")))) + ((string= str "lightgoldenrodyellow") (setq plist (list :background "#fafad2" :foreground (web-mode-colorize-foreground "#fafad2")))) + ((string= str "lightgray") (setq plist (list :background "#d3d3d3" :foreground (web-mode-colorize-foreground "#d3d3d3")))) + ((string= str "lightgreen") (setq plist (list :background "#90ee90" :foreground (web-mode-colorize-foreground "#90ee90")))) + ((string= str "lightgrey") (setq plist (list :background "#d3d3d3" :foreground (web-mode-colorize-foreground "#d3d3d3")))) + ((string= str "lightpink") (setq plist (list :background "#ffb6c1" :foreground (web-mode-colorize-foreground "#ffb6c1")))) + ((string= str "lightsalmon") (setq plist (list :background "#ffa07a" :foreground (web-mode-colorize-foreground "#ffa07a")))) + ((string= str "lightseagreen") (setq plist (list :background "#20b2aa" :foreground (web-mode-colorize-foreground "#20b2aa")))) + ((string= str "lightskyblue") (setq plist (list :background "#87cefa" :foreground (web-mode-colorize-foreground "#87cefa")))) + ((string= str "lightslategray") (setq plist (list :background "#778899" :foreground (web-mode-colorize-foreground "#778899")))) + ((string= str "lightslategrey") (setq plist (list :background "#778899" :foreground (web-mode-colorize-foreground "#778899")))) + ((string= str "lightsteelblue") (setq plist (list :background "#b0c4de" :foreground (web-mode-colorize-foreground "#b0c4de")))) + ((string= str "lightyellow") (setq plist (list :background "#ffffe0" :foreground (web-mode-colorize-foreground "#ffffe0")))) + ((string= str "limegreen") (setq plist (list :background "#32cd32" :foreground (web-mode-colorize-foreground "#32cd32")))) + ((string= str "linen") (setq plist (list :background "#faf0e6" :foreground (web-mode-colorize-foreground "#faf0e6")))) + ((string= str "magenta") (setq plist (list :background "#ff00ff" :foreground (web-mode-colorize-foreground "#ff00ff")))) + ((string= str "mediumaquamarine") (setq plist (list :background "#66cdaa" :foreground (web-mode-colorize-foreground "#66cdaa")))) + ((string= str "mediumblue") (setq plist (list :background "#0000cd" :foreground (web-mode-colorize-foreground "#0000cd")))) + ((string= str "mediumorchid") (setq plist (list :background "#ba55d3" :foreground (web-mode-colorize-foreground "#ba55d3")))) + ((string= str "mediumpurple") (setq plist (list :background "#9370db" :foreground (web-mode-colorize-foreground "#9370db")))) + ((string= str "mediumseagreen") (setq plist (list :background "#3cb371" :foreground (web-mode-colorize-foreground "#3cb371")))) + ((string= str "mediumslateblue") (setq plist (list :background "#7b68ee" :foreground (web-mode-colorize-foreground "#7b68ee")))) + ((string= str "mediumspringgreen") (setq plist (list :background "#00fa9a" :foreground (web-mode-colorize-foreground "#00fa9a")))) + ((string= str "mediumturquoise") (setq plist (list :background "#48d1cc" :foreground (web-mode-colorize-foreground "#48d1cc")))) + ((string= str "mediumvioletred") (setq plist (list :background "#c71585" :foreground (web-mode-colorize-foreground "#c71585")))) + ((string= str "midnightblue") (setq plist (list :background "#191970" :foreground (web-mode-colorize-foreground "#191970")))) + ((string= str "mintcream") (setq plist (list :background "#f5fffa" :foreground (web-mode-colorize-foreground "#f5fffa")))) + ((string= str "mistyrose") (setq plist (list :background "#ffe4e1" :foreground (web-mode-colorize-foreground "#ffe4e1")))) + ((string= str "moccasin") (setq plist (list :background "#ffe4b5" :foreground (web-mode-colorize-foreground "#ffe4b5")))) + ((string= str "navajowhite") (setq plist (list :background "#ffdead" :foreground (web-mode-colorize-foreground "#ffdead")))) + ((string= str "oldlace") (setq plist (list :background "#fdf5e6" :foreground (web-mode-colorize-foreground "#fdf5e6")))) + ((string= str "olivedrab") (setq plist (list :background "#6b8e23" :foreground (web-mode-colorize-foreground "#6b8e23")))) + ((string= str "orangered") (setq plist (list :background "#ff4500" :foreground (web-mode-colorize-foreground "#ff4500")))) + ((string= str "orchid") (setq plist (list :background "#da70d6" :foreground (web-mode-colorize-foreground "#da70d6")))) + ((string= str "palegoldenrod") (setq plist (list :background "#eee8aa" :foreground (web-mode-colorize-foreground "#eee8aa")))) + ((string= str "palegreen") (setq plist (list :background "#98fb98" :foreground (web-mode-colorize-foreground "#98fb98")))) + ((string= str "paleturquoise") (setq plist (list :background "#afeeee" :foreground (web-mode-colorize-foreground "#afeeee")))) + ((string= str "palevioletred") (setq plist (list :background "#db7093" :foreground (web-mode-colorize-foreground "#db7093")))) + ((string= str "papayawhip") (setq plist (list :background "#ffefd5" :foreground (web-mode-colorize-foreground "#ffefd5")))) + ((string= str "peachpuff") (setq plist (list :background "#ffdab9" :foreground (web-mode-colorize-foreground "#ffdab9")))) + ((string= str "peru") (setq plist (list :background "#cd853f" :foreground (web-mode-colorize-foreground "#cd853f")))) + ((string= str "pink") (setq plist (list :background "#ffc0cb" :foreground (web-mode-colorize-foreground "#ffc0cb")))) + ((string= str "plum") (setq plist (list :background "#dda0dd" :foreground (web-mode-colorize-foreground "#dda0dd")))) + ((string= str "powderblue") (setq plist (list :background "#b0e0e6" :foreground (web-mode-colorize-foreground "#b0e0e6")))) + ((string= str "rosybrown") (setq plist (list :background "#bc8f8f" :foreground (web-mode-colorize-foreground "#bc8f8f")))) + ((string= str "royalblue") (setq plist (list :background "#4169e1" :foreground (web-mode-colorize-foreground "#4169e1")))) + ((string= str "saddlebrown") (setq plist (list :background "#8b4513" :foreground (web-mode-colorize-foreground "#8b4513")))) + ((string= str "salmon") (setq plist (list :background "#fa8072" :foreground (web-mode-colorize-foreground "#fa8072")))) + ((string= str "sandybrown") (setq plist (list :background "#f4a460" :foreground (web-mode-colorize-foreground "#f4a460")))) + ((string= str "seagreen") (setq plist (list :background "#2e8b57" :foreground (web-mode-colorize-foreground "#2e8b57")))) + ((string= str "seashell") (setq plist (list :background "#fff5ee" :foreground (web-mode-colorize-foreground "#fff5ee")))) + ((string= str "sienna") (setq plist (list :background "#a0522d" :foreground (web-mode-colorize-foreground "#a0522d")))) + ((string= str "skyblue") (setq plist (list :background "#87ceeb" :foreground (web-mode-colorize-foreground "#87ceeb")))) + ((string= str "slateblue") (setq plist (list :background "#6a5acd" :foreground (web-mode-colorize-foreground "#6a5acd")))) + ((string= str "slategray") (setq plist (list :background "#708090" :foreground (web-mode-colorize-foreground "#708090")))) + ((string= str "slategrey") (setq plist (list :background "#708090" :foreground (web-mode-colorize-foreground "#708090")))) + ((string= str "snow") (setq plist (list :background "#fffafa" :foreground (web-mode-colorize-foreground "#fffafa")))) + ((string= str "springgreen") (setq plist (list :background "#00ff7f" :foreground (web-mode-colorize-foreground "#00ff7f")))) + ((string= str "steelblue") (setq plist (list :background "#4682b4" :foreground (web-mode-colorize-foreground "#4682b4")))) + ((string= str "tan") (setq plist (list :background "#d2b48c" :foreground (web-mode-colorize-foreground "#d2b48c")))) + ((string= str "thistle") (setq plist (list :background "#d8bfd8" :foreground (web-mode-colorize-foreground "#d8bfd8")))) + ((string= str "tomato") (setq plist (list :background "#ff6347" :foreground (web-mode-colorize-foreground "#ff6347")))) + ((string= str "turquoise") (setq plist (list :background "#40e0d0" :foreground (web-mode-colorize-foreground "#40e0d0")))) + ((string= str "violet") (setq plist (list :background "#ee82ee" :foreground (web-mode-colorize-foreground "#ee82ee")))) + ((string= str "wheat") (setq plist (list :background "#f5deb3" :foreground (web-mode-colorize-foreground "#f5deb3")))) + ((string= str "whitesmoke") (setq plist (list :background "#f5f5f5" :foreground (web-mode-colorize-foreground "#f5f5f5")))) + ((string= str "yellowgreen") (setq plist (list :background "#9acd32" :foreground (web-mode-colorize-foreground "#9acd32")))) + ) ;cond + (put-text-property beg end 'face plist) + )) + +(defun web-mode-interpolate-block-tag (beg end) + (save-excursion + (goto-char (+ 4 beg)) + (setq end (1- end)) + (while (re-search-forward "${.*?}" end t) + (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(face)) + (web-mode-fontify-region (match-beginning 0) (match-end 0) + web-mode-uel-font-lock-keywords)) + )) + +(defun web-mode-interpolate-javascript-string (beg end) + (save-excursion + (goto-char (1+ beg)) + (setq end (1- end)) + (while (re-search-forward "${.*?}" end t) + (put-text-property (match-beginning 0) (match-end 0) + 'font-lock-face + 'web-mode-variable-name-face) + ) + )) + +(defun web-mode-interpolate-javascript-literal (beg end) + (save-excursion + (goto-char (1+ beg)) + (setq end (1- end)) + (while (re-search-forward "${.*?}" end t) + (put-text-property (match-beginning 0) (match-end 0) + 'font-lock-face + 'web-mode-variable-name-face) + ) + (cond + ((web-mode-looking-back "\\(css\\|styled[[:alnum:].]+\\)" beg) + (goto-char (1+ beg)) + (while (re-search-forward ".*?:" end t) + (put-text-property (match-beginning 0) (match-end 0) + 'font-lock-face + 'web-mode-interpolate-color1-face) + ) + ) ;case css + ((web-mode-looking-back "\\(template\\|html\\)" beg) + (goto-char (1+ beg)) + (while (re-search-forward web-mode-tag-regexp end t) + (put-text-property (match-beginning 1) (match-end 1) + 'font-lock-face + 'web-mode-interpolate-color1-face) + ) + (goto-char (1+ beg)) + (while (re-search-forward "</?\\|/?>\\| [.@?]?[[:alnum:]]+=" end t) + (cond + ((member (char-after (match-beginning 0)) '(?\< ?\/ ?\>)) + (put-text-property (match-beginning 0) (match-end 0) + 'font-lock-face + 'web-mode-interpolate-color2-face) + ) + (t + (put-text-property (1+ (match-beginning 0)) (1- (match-end 0)) + 'font-lock-face + 'web-mode-interpolate-color3-face) + ) ;t + ) ;cond + ) ;while + ) ;case html + ) ;cond type of literal + )) + +;; todo : parsing plus compliqué: {$obj->values[3]->name} +(defun web-mode-interpolate-block-string (beg end) + (save-excursion + (goto-char (1+ beg)) + (setq end (1- end)) + (cond + ((string= web-mode-engine "php") + (while (re-search-forward "$[[:alnum:]_]+\\(->[[:alnum:]_]+\\)*\\|{[ ]*$.+?}" end t) +;; (message "%S > %S" (match-beginning 0) (match-end 0)) + (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(font-lock-face)) + (web-mode-fontify-region (match-beginning 0) (match-end 0) + web-mode-php-var-interpolation-font-lock-keywords) + )) + ((string= web-mode-engine "erb") + (while (re-search-forward "#{.*?}" end t) + (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(font-lock-face)) + (put-text-property (match-beginning 0) (match-end 0) + 'font-lock-face 'web-mode-variable-name-face) + )) + ) ;cond + )) + +(defun web-mode-interpolate-comment (beg end block-side) + (save-excursion + (let ((regexp (concat "\\_<\\(" web-mode-comment-keywords "\\)\\_>"))) + (goto-char beg) + (while (re-search-forward regexp end t) + (font-lock-prepend-text-property (match-beginning 1) (match-end 1) + 'font-lock-face + 'web-mode-comment-keyword-face) + ) ;while + ))) + +(defun web-mode-annotate-comment (beg end) + (save-excursion + ;;(message "beg=%S end=%S" beg end) + (goto-char beg) + (when (looking-at-p "/\\*\\*") + (while (re-search-forward "\\(.+\\)" end t) + (font-lock-prepend-text-property (match-beginning 1) (match-end 1) + 'font-lock-face + 'web-mode-annotation-face)) + (goto-char beg) + (while (re-search-forward "[ ]+\\({[^}]+}\\)" end t) + (font-lock-prepend-text-property (match-beginning 1) (match-end 1) + 'font-lock-face + 'web-mode-annotation-type-face)) + (goto-char beg) + (while (re-search-forward "\\(@[[:alnum:]]+\\)" end t) + (font-lock-prepend-text-property (match-beginning 1) (match-end 1) + 'font-lock-face + 'web-mode-annotation-tag-face)) + (goto-char beg) + (while (re-search-forward "}[[:blank:]]+\\([[:graph:]]+\\)" end t) + (font-lock-prepend-text-property (match-beginning 1) (match-end 1) + 'font-lock-face + 'web-mode-annotation-value-face)) + (goto-char beg) + (while (re-search-forward "@see[[:blank:]]+\\([[:graph:]]+\\)" end t) + (font-lock-prepend-text-property (match-beginning 1) (match-end 1) + 'font-lock-face + 'web-mode-annotation-value-face)) + (goto-char beg) + (while (re-search-forward "{\\(@\\(?:link\\|code\\)\\)\\s-+\\([^}\n]+\\)\\(#.+\\)?}" end t) + (font-lock-prepend-text-property (match-beginning 2) (match-end 2) + 'font-lock-face + 'web-mode-annotation-value-face)) + (goto-char beg) + (while (re-search-forward "\\(</?\\)\\([[:alnum:]]+\\)\\s-*\\(/?>\\)" end t) + (font-lock-prepend-text-property (match-beginning 1) (match-end 1) + 'font-lock-face + 'web-mode-annotation-html-face) + (font-lock-prepend-text-property (match-beginning 2) (match-end 2) + 'font-lock-face + 'web-mode-annotation-html-face) + (font-lock-prepend-text-property (match-beginning 3) (match-end 3) + 'font-lock-face + 'web-mode-annotation-html-face)) + ) ;when + )) + +(defun web-mode-interpolate-sql-string (beg end) + (save-excursion + (let ((case-fold-search t) + (regexp (concat "\\_<\\(" web-mode-sql-keywords "\\)\\_>"))) + (goto-char beg) + (while (re-search-forward regexp end t) + (font-lock-prepend-text-property (match-beginning 1) (match-end 1) + 'font-lock-face + 'web-mode-sql-keyword-face) + ) ;while + ))) + +;;---- EFFECTS ----------------------------------------------------------------- + +(defun web-mode-fill-paragraph (&optional justify) + (save-excursion + (let ((pos (point)) fill-coll + prop pair beg end delim-beg delim-end chunk fill-col) + (cond + ((or (eq (get-text-property pos 'part-token) 'comment) + (eq (get-text-property pos 'block-token) 'comment)) + (setq prop + (if (get-text-property pos 'part-token) 'part-token 'block-token)) + (setq pair (web-mode-property-boundaries prop pos)) + (when (and pair (> (- (cdr pair) (car pair)) 6)) + (setq fill-coll (if (< fill-column 10) 70 fill-column)) + (setq beg (car pair) + end (cdr pair)) + (goto-char beg) + (setq chunk (buffer-substring-no-properties beg (+ beg 2))) + (cond + ((string= chunk "//") + (setq delim-beg "//" + delim-end "EOL")) + ((string= chunk "/*") + (setq delim-beg "/*" + delim-end "*/")) + ((string= chunk "{#") + (setq delim-beg "{#" + delim-end "#}")) + ((string= chunk "<!") + (setq delim-beg "<!--" + delim-end "-->")) + ) + ) + ) ;comment - case + ((web-mode-is-content) + (setq pair (web-mode-content-boundaries pos)) + (setq beg (car pair) + end (cdr pair)) + ) + ) ;cond + ;;(message "beg(%S) end(%S)" beg end) + (when (and beg end) + (fill-region beg end)) + t))) + +(defun web-mode-engine-syntax-check () + (interactive) + (let ((proc nil) (errors nil) + (file (concat temporary-file-directory "emacs-web-mode-tmp"))) + (write-region (point-min) (point-max) file) + (cond + ;; ((null (buffer-file-name)) + ;; ) + ((string= web-mode-engine "php") + (setq proc (start-process "php-proc" nil "php" "-l" file)) + (set-process-filter + proc + (lambda (proc output) + (cond + ((string-match-p "No syntax errors" output) + (message "No syntax errors") + ) + (t + ;; (setq output (replace-regexp-in-string temporary-file-directory "" output)) + ;; (message output) + (message "Syntax error") + (setq errors t)) + ) ;cond + ;; (delete-file file) + ) ;lambda + ) + ) ;php + (t + (message "no syntax checker found") + ) ;t + ) ;cond + errors)) + +(defun web-mode-jshint () + "Run JSHint on all the JavaScript parts." + (interactive) + (let (proc lines) + (when (buffer-file-name) + (setq proc (start-process + "jshint-proc" + nil + (or (executable-find "jshint") "/usr/local/bin/jshint") + "--extract=auto" + (buffer-file-name))) + (setq web-mode-jshint-errors 0) + (set-process-filter proc + (lambda (proc output) + (let ((offset 0) overlay pos (old 0) msg) + (remove-overlays (point-min) (point-max) 'font-lock-face 'web-mode-error-face) + (while (string-match + "line \\([[:digit:]]+\\), col \\([[:digit:]]+\\), \\(.+\\)\\.$" + output offset) + (setq web-mode-jshint-errors (1+ web-mode-jshint-errors)) + (setq offset (match-end 0)) + (setq pos (web-mode-coord-position + (match-string-no-properties 1 output) + (match-string-no-properties 2 output))) + (when (get-text-property pos 'tag-beg) + (setq pos (1- pos))) + (when (not (= pos old)) + (setq old pos) + (setq overlay (make-overlay pos (1+ pos))) + (overlay-put overlay 'font-lock-face 'web-mode-error-face) + ) + (setq msg (or (overlay-get overlay 'help-echo) + (concat "line=" + (match-string-no-properties 1 output) + " column=" + (match-string-no-properties 2 output) + ))) + (overlay-put overlay 'help-echo + (concat msg " ## " (match-string-no-properties 3 output))) + ) ;while + )) + ) + ) ;when + )) + +(defun web-mode-dom-errors-show () + "Show unclosed tags." + (interactive) + (let (beg end tag pos l n tags i cont cell overlay overlays first + (ori (point)) + (errors 0) + (continue t) + ) + (setq overlays (overlays-in (point-min) (point-max))) + (when overlays + (dolist (overlay overlays) + (when (eq (overlay-get overlay 'face) 'web-mode-warning-face) + (delete-overlay overlay) + ) + ) + ) + (goto-char (point-min)) + (when (not (or (get-text-property (point) 'tag-beg) + (web-mode-tag-next))) + (setq continue nil)) + (while continue + (setq pos (point)) + (setq tag (get-text-property pos 'tag-name)) + (cond + ((eq (get-text-property (point) 'tag-type) 'start) + (setq tags (push (list tag pos) tags)) +;; (message "(%S) opening %S" pos tag) + ) + ((eq (get-text-property (point) 'tag-type) 'end) + (setq i 0 + l (length tags) + cont t) + (while (and (< i l) cont) + (setq cell (nth i tags)) +;; (message "cell=%S" cell) + (setq i (1+ i)) + (cond + ((string= tag (nth 0 cell)) + (setq cont nil) + ) + (t + (setq errors (1+ errors)) + (setq beg (nth 1 cell)) + (setq end (web-mode-tag-end-position beg)) + (unless first + (setq first beg)) + (setq overlay (make-overlay beg (1+ end))) + (overlay-put overlay 'font-lock-face 'web-mode-warning-face) +;; (message "invalid <%S> at %S" (nth 0 cell) (nth 1 cell)) + ) + ) ;cond + ) ;while + + (dotimes (i i) + (setq tags (cdr tags))) + + ) + ) ;cond + (when (not (web-mode-tag-next)) + (setq continue nil)) + ) ;while + (message "%S error(s) detected" errors) + (if (< errors 1) + (goto-char ori) + (goto-char first) + (recenter)) + ;; (message "%S" tags) + )) + +(defun web-mode-fontify-elements (beg end) + (save-excursion + (goto-char beg) + (let ((continue (or (get-text-property (point) 'tag-beg) (web-mode-tag-next))) + (i 0) (ctx nil) (face nil)) + (while continue + (cond + ((> (setq i (1+ i)) 1000) + (message "fontify-elements ** too much tags **") + (setq continue nil)) + ((> (point) end) + (setq continue nil)) + ((not (get-text-property (point) 'tag-beg)) + (setq continue nil)) + ((eq (get-text-property (point) 'tag-type) 'start) + (when (and (setq ctx (web-mode-element-boundaries (point))) + (<= (car (cdr ctx)) end) + (setq face (cdr (assoc (get-text-property (point) 'tag-name) web-mode-element-content-faces)))) + (font-lock-prepend-text-property (1+ (cdr (car ctx))) (car (cdr ctx)) + 'font-lock-face face)) + ) + ) ;cond + (when (not (web-mode-tag-next)) + (setq continue nil)) + ) ;while + ))) + +(defun web-mode-enable (feature) + "Enable one feature." + (interactive + (list (completing-read + "Feature: " + (let (features) + (dolist (elt web-mode-features) + (setq features (append features (list (car elt))))) + features)))) + (when (and (or (not feature) (< (length feature) 1)) web-mode-last-enabled-feature) + (setq feature web-mode-last-enabled-feature)) + (when feature + (setq web-mode-last-enabled-feature feature) + (setq feature (cdr (assoc feature web-mode-features))) + (cond + ((eq feature 'web-mode-enable-current-column-highlight) + (web-mode-column-show)) + ((eq feature 'web-mode-enable-current-element-highlight) + (when (not web-mode-enable-current-element-highlight) + (web-mode-toggle-current-element-highlight)) + ) + ((eq feature 'web-mode-enable-whitespace-fontification) + (web-mode-whitespaces-on)) + (t + (set feature t) + (web-mode-buffer-fontify)) + ) + ) ;when + ) + +(defun web-mode-disable (feature) + "Disable one feature." + (interactive + (list (completing-read + "Feature: " + (let (features) + (dolist (elt web-mode-features) + (setq features (append features (list (car elt))))) + features)))) + (when (and (or (not feature) (< (length feature) 1)) web-mode-last-enabled-feature) + (setq feature web-mode-last-enabled-feature)) + (when feature + (setq feature (cdr (assoc feature web-mode-features))) + (cond + ((eq feature 'web-mode-enable-current-column-highlight) + (web-mode-column-hide)) + ((eq feature 'web-mode-enable-current-element-highlight) + (when web-mode-enable-current-element-highlight + (web-mode-toggle-current-element-highlight)) + ) + ((eq feature 'web-mode-enable-whitespace-fontification) + (web-mode-whitespaces-off)) + (t + (set feature nil) + (web-mode-buffer-fontify)) + ) + ) ;when + ) + +(defun web-mode-toggle-current-element-highlight () + "Toggle highlighting of the current html element." + (interactive) + (if web-mode-enable-current-element-highlight + (progn + (web-mode-delete-tag-overlays) + (setq web-mode-enable-current-element-highlight nil)) + (setq web-mode-enable-current-element-highlight t) + )) + +(defun web-mode-make-tag-overlays () + (unless web-mode-overlay-tag-start + (setq web-mode-overlay-tag-start (make-overlay 1 1) + web-mode-overlay-tag-end (make-overlay 1 1)) + (overlay-put web-mode-overlay-tag-start + 'font-lock-face + 'web-mode-current-element-highlight-face) + (overlay-put web-mode-overlay-tag-end + 'font-lock-face + 'web-mode-current-element-highlight-face))) + +(defun web-mode-delete-tag-overlays () + (when web-mode-overlay-tag-start + (delete-overlay web-mode-overlay-tag-start) + (delete-overlay web-mode-overlay-tag-end))) + +(defun web-mode-column-overlay-factory (index) + (let (overlay) + (when (null web-mode-column-overlays) + (dotimes (i 100) + (setq overlay (make-overlay 1 1)) + (overlay-put overlay 'font-lock-face 'web-mode-current-column-highlight-face) + (setq web-mode-column-overlays (append web-mode-column-overlays (list overlay))) + ) + ) ;when + (setq overlay (nth index web-mode-column-overlays)) + (when (null overlay) + (setq overlay (make-overlay 1 1)) + (overlay-put overlay 'font-lock-face 'web-mode-current-column-highlight-face) + (setq web-mode-column-overlays (append web-mode-column-overlays (list overlay))) + ) ;when + overlay)) + +(defun web-mode-column-hide () + (setq web-mode-enable-current-column-highlight nil) + (remove-overlays (point-min) (point-max) + 'font-lock-face + 'web-mode-current-column-highlight-face)) + +(defun web-mode-column-show () + (let ((index 0) overlay diff column line-to line-from) + (web-mode-column-hide) + (setq web-mode-enable-current-column-highlight t) + (save-excursion + (back-to-indentation) + (setq column (current-column) + line-to (web-mode-line-number)) + (when (and (get-text-property (point) 'tag-beg) + (member (get-text-property (point) 'tag-type) '(start end)) + (web-mode-tag-match) + (setq line-from (web-mode-line-number)) + (not (= line-from line-to))) + (when (> line-from line-to) + (let (tmp) + (setq tmp line-from) + (setq line-from line-to) + (setq line-to tmp)) + ) ;when + ;;(message "column(%S) line-from(%S) line-to(%S)" column line-from line-to) + (goto-char (point-min)) + (when (> line-from 1) + (forward-line (1- line-from))) + (while (<= line-from line-to) + (setq overlay (web-mode-column-overlay-factory index)) + (setq diff (- (line-end-position) (point))) + (cond + ((or (and (= column 0) (= diff 0)) + (> column diff)) + (end-of-line) + (move-overlay overlay (point) (point)) + (overlay-put overlay + 'after-string + (concat + (if (> column diff) (make-string (- column diff) ?\s) "") + (propertize " " + 'font-lock-face + 'web-mode-current-column-highlight-face) + ) ;concat + ) + ) + (t + (move-to-column column) + (overlay-put overlay 'after-string nil) + (move-overlay overlay (point) (1+ (point))) + ) + ) ;cond + (setq line-from (1+ line-from)) + (forward-line) + (setq index (1+ index)) + ) ;while + ) ;when + ) ;save-excursion + ) ;let + ) + +(defun web-mode-highlight-current-element () + (let ((ctx (web-mode-element-boundaries)) len) + (cond + ((null ctx) + (web-mode-delete-tag-overlays)) + ((eq (get-text-property (caar ctx) 'tag-type) 'void) ;; #1046 + (web-mode-make-tag-overlays) + (setq len (length (get-text-property (caar ctx) 'tag-name))) + (move-overlay web-mode-overlay-tag-start (+ (caar ctx) 1) (+ (caar ctx) 1 len)) + ) + (t + (web-mode-make-tag-overlays) + (setq len (length (get-text-property (caar ctx) 'tag-name))) + (move-overlay web-mode-overlay-tag-start (+ (caar ctx) 1) (+ (caar ctx) 1 len)) + (move-overlay web-mode-overlay-tag-end (+ (cadr ctx) 2) (+ (cadr ctx) 2 len)) + ) ;t + ) ;cond + )) + +(defun web-mode-fontify-whitespaces (beg end) + (save-excursion + (goto-char beg) + (while (re-search-forward web-mode-whitespaces-regexp end t) + (add-text-properties (match-beginning 0) (match-end 0) + '(face web-mode-whitespace-face)) + ) ;while + )) + +(defun web-mode-whitespaces-show () + "Toggle whitespaces." + (interactive) + (if web-mode-enable-whitespace-fontification + (web-mode-whitespaces-off) + (web-mode-whitespaces-on))) + +(defun web-mode-whitespaces-on () + "Show whitespaces." + (interactive) + (when web-mode-display-table + (setq buffer-display-table web-mode-display-table)) + (setq web-mode-enable-whitespace-fontification t)) + +(defun web-mode-whitespaces-off () + (setq buffer-display-table nil) + (setq web-mode-enable-whitespace-fontification nil)) + +(defun web-mode-use-tabs () + "Tweaks vars to be compatible with TAB indentation." + (let (offset) + (setq web-mode-block-padding 0) + (setq web-mode-script-padding 0) + (setq web-mode-style-padding 0) + (setq offset + (cond + ((and (boundp 'tab-width) tab-width) tab-width) + ((and (boundp 'standard-indent) standard-indent) standard-indent) + (t 4))) + ;; (message "offset(%S)" offset) + (setq web-mode-attr-indent-offset offset) + (setq web-mode-code-indent-offset offset) + (setq web-mode-css-indent-offset offset) + (setq web-mode-markup-indent-offset offset) + (setq web-mode-sql-indent-offset offset) + (add-to-list 'web-mode-indentation-params '("lineup-args" . nil)) + (add-to-list 'web-mode-indentation-params '("lineup-calls" . nil)) + (add-to-list 'web-mode-indentation-params '("lineup-concats" . nil)) + (add-to-list 'web-mode-indentation-params '("lineup-ternary" . nil)) + )) + +(defun web-mode-element-children-fold-or-unfold (&optional pos) + "Fold/Unfold all the children of the current html element." + (interactive) + (unless pos (setq pos (point))) + (save-excursion + (dolist (child (reverse (web-mode-element-children pos))) + (goto-char child) + (web-mode-fold-or-unfold)) + )) + +(defun web-mode-fold-or-unfold (&optional pos) + "Toggle folding on an html element or a control block." + (interactive) + (web-mode-scan) + (web-mode-with-silent-modifications + (save-excursion + (if pos (goto-char pos)) + (let (beg-inside beg-outside end-inside end-outside overlay overlays regexp) + (when (looking-back "^[\t ]*" (point-min)) + (back-to-indentation)) + (setq overlays (overlays-at (point))) + (dolist (elt overlays) + (when (and (not overlay) + (eq (overlay-get elt 'font-lock-face) 'web-mode-folded-face)) + (setq overlay elt))) + (cond + ;; *** unfolding + (overlay + (setq beg-inside (overlay-start overlay) + end-inside (overlay-end overlay)) + (remove-overlays beg-inside end-inside) + (put-text-property beg-inside end-inside 'invisible nil) + ) + ;; *** block folding + ((and (get-text-property (point) 'block-side) + (cdr (web-mode-block-is-control (point)))) + (setq beg-outside (web-mode-block-beginning-position (point))) + (setq beg-inside (1+ (web-mode-block-end-position (point)))) + (when (web-mode-block-match) + (setq end-inside (point)) + (setq end-outside (1+ (web-mode-block-end-position (point))))) + ) + ;; *** html comment folding + ((eq (get-text-property (point) 'tag-type) 'comment) + (setq beg-outside (web-mode-tag-beginning-position)) + (setq beg-inside (+ beg-outside 4)) + (setq end-outside (web-mode-tag-end-position)) + (setq end-inside (- end-outside 3)) + ) + ;; *** tag folding + ((or (member (get-text-property (point) 'tag-type) '(start end)) + (web-mode-element-parent)) + (when (not (web-mode-element-is-collapsed (point))) + (web-mode-tag-beginning) + (when (eq (get-text-property (point) 'tag-type) 'end) + (web-mode-tag-match)) + (setq beg-outside (point)) + (web-mode-tag-end) + (setq beg-inside (point)) + (goto-char beg-outside) + (when (web-mode-tag-match) + (setq end-inside (point)) + (web-mode-tag-end) + (setq end-outside (point))) + ) + ) + ) ;cond + (when (and beg-inside beg-outside end-inside end-outside) + (setq overlay (make-overlay beg-outside end-outside)) + (overlay-put overlay 'font-lock-face 'web-mode-folded-face) + (put-text-property beg-inside end-inside 'invisible t)) + )))) + +;;---- TRANSFORMATION ---------------------------------------------------------- + +(defun web-mode-buffer-change-tag-case (&optional type) + "Change html tag case." + (interactive) + (save-excursion + (goto-char (point-min)) + (let ((continue t) f) + (setq f (if (member type '("upper" "uppercase" "upper-case")) 'uppercase 'downcase)) + (when (and (not (get-text-property (point) 'tag-beg)) + (not (web-mode-tag-next))) + (setq continue nil)) + (while continue + (skip-chars-forward "<!/") + (if (looking-at "\\([[:alnum:]:-]+\\)") + (replace-match (funcall f (match-string 0)) t)) +;; (message "tag: %S (%S)" +;; (get-text-property (point) 'tag-name) +;; (point)) + (unless (web-mode-tag-next) + (setq continue nil)) + ) ;while + ))) + +(defun web-mode-buffer-change-attr-case (&optional type) + "Change case of html attribute names." + (interactive) + (unless type (setq type "downcase")) + (save-excursion + (goto-char (point-min)) + (let ((continue t) + (fun (if (eq (aref (downcase type) 0) ?u) 'uppercase 'downcase))) + (while continue + (cond + ((not (web-mode-attribute-next)) + (setq continue nil)) + ((looking-at "\\([[:alnum:]-]+\\)") + (replace-match (funcall fun (match-string 0)) t) + ) + ) ;cond + ) ;while + ))) + +;; tag-case=lower|upper-case , attr-case=lower|upper-case +;; special-chars=unicode|html-entities +;; smart-apostrophes=bool , smart-quotes=bool , indentation=bool +(defun web-mode-dom-normalize () + "Normalize buffer" + (interactive) + (save-excursion + (let ((rules web-mode-normalization-rules) elt) + (when (setq elt (cdr (assoc "tag-case" rules))) + (web-mode-buffer-change-tag-case elt)) + (when (setq elt (cdr (assoc "attr-case" rules))) + (web-mode-buffer-change-attr-case elt)) + (when (setq elt (cdr (assoc "css-indentation" rules))) + (web-mode-css-indent)) + (when (setq elt (cdr (assoc "smart-apostrophes" rules))) + (web-mode-dom-apostrophes-replace)) + (when (setq elt (cdr (assoc "smart-quotes" rules))) + (web-mode-dom-quotes-replace)) + (when (setq elt (cdr (assoc "special-chars" rules))) + (if (string= elt "entities") + (web-mode-dom-entities-encode) + (web-mode-dom-entities-replace))) + (when (setq elt (cdr (assoc "whitespaces" rules))) + (goto-char (point-min)) + (while (not (eobp)) + (forward-line) + (delete-blank-lines)) + (delete-trailing-whitespace) + (untabify (point-min) (point-max))) + (when (setq elt (cdr (assoc "indentation" rules))) + (web-mode-buffer-indent)) + ))) + +(defun web-mode-dom-apostrophes-replace () + "Replace char(') with char(’) in the innerText of html elements." + (interactive) + (save-excursion + (let ((min (point-min)) (max (point-max))) + (when mark-active + (setq min (region-beginning) + max (region-end)) + (deactivate-mark)) + (goto-char min) + (while (web-mode-content-rsf "\\([[:alpha:]]\\)'\\([[:alpha:]]\\)" max) + (replace-match "\\1’\\2")) + ))) + +(defun web-mode-dom-entities-encode () + (save-excursion + (let (regexp ms elt (min (point-min)) (max (point-max))) + (when mark-active + (setq min (region-beginning) + max (region-end)) + (deactivate-mark)) + (goto-char min) + (setq regexp "[") + (dolist (pair web-mode-html-entities) + (setq regexp (concat regexp (char-to-string (cdr pair)))) + ) + (setq regexp (concat regexp "]")) + (while (web-mode-content-rsf regexp max) + (setq elt (match-string-no-properties 0)) + (setq elt (aref elt 0)) + (setq elt (car (rassoc elt web-mode-html-entities))) + (replace-match (concat "&" elt ";")) + (setq max (+ max (length elt) 1)) + ) ;while + ))) + +(defun web-mode-dom-entities-replace () + "Replace html entities (e.g. &eacute; &#233; or &#x00E9; become é)" + (interactive) + (save-excursion + (let (ms pair elt (min (point-min)) (max (point-max))) + (when mark-active + (setq min (region-beginning) + max (region-end)) + (deactivate-mark)) + (goto-char min) + (while (web-mode-content-rsf "&\\([#]?[[:alnum:]]\\{2,8\\}\\);" max) + (setq elt nil) + (setq ms (match-string-no-properties 1)) + (cond + ((not (eq (aref ms 0) ?\#)) + (and (setq pair (assoc ms web-mode-html-entities)) + (setq elt (cdr pair)) + (setq elt (char-to-string elt)))) + ((eq (aref ms 1) ?x) + (setq elt (substring ms 2)) + (setq elt (downcase elt)) + (setq elt (string-to-number elt 16)) + (setq elt (char-to-string elt))) + (t + (setq elt (substring ms 1)) + (setq elt (char-to-string (string-to-number elt)))) + ) ;cond + (when elt (replace-match elt)) + ) ;while + ))) + +(defun web-mode-dom-xml-replace () + "Replace &, > and < in html content." + (interactive) + (save-excursion + (let (expr (min (point-min)) (max (point-max))) + (when mark-active + (setq min (region-beginning) + max (region-end)) + (deactivate-mark)) + (goto-char min) + (while (web-mode-content-rsf "[&<>]" max) + (replace-match (cdr (assq (char-before) web-mode-xml-chars)) t t)) + ))) + +(defun web-mode-dom-quotes-replace () + "Replace dumb quotes." + (interactive) + (save-excursion + (let (expr (min (point-min)) (max (point-max))) + (when mark-active + (setq min (region-beginning) + max (region-end)) + (deactivate-mark)) + (goto-char min) + (setq expr (concat (car web-mode-smart-quotes) "\\2" (cdr web-mode-smart-quotes))) + (while (web-mode-content-rsf "\\(\"\\)\\(.\\{1,200\\}\\)\\(\"\\)" max) + (replace-match expr) + ) ;while + ))) + +;;---- INDENTATION ------------------------------------------------------------- + +;; todo : passer de règle en règle et mettre un \n à la fin +(defun web-mode-css-indent () + (save-excursion + (goto-char (point-min)) + (let ((continue t) rule part-end) + (while continue + (cond + ((not (web-mode-part-next)) + (setq continue nil)) + ((eq (get-text-property (point) 'part-side) 'css) + (setq part-end (web-mode-part-end-position)) + (while (setq rule (web-mode-css-rule-next part-end)) + (when (not (looking-at-p "[[:space:]]*\\($\\|<\\)")) + (newline) + (indent-according-to-mode) + (setq part-end (web-mode-part-end-position))) + ) + ) + ) ;cond + ) + ))) + +(defun web-mode-buffer-indent () + "Indent all buffer." + (interactive) + (let ((debug t) (ts (current-time)) (sub nil)) + (indent-region (point-min) (point-max)) + (when debug + (setq sub (time-subtract (current-time) ts)) + (message "buffer-indent: time elapsed = %Ss %9Sµs" (nth 1 sub) (nth 2 sub))) + (delete-trailing-whitespace))) + +(defun web-mode-point-context (pos) + "POS should be at the beginning of the indentation." + (save-excursion + (let (curr-char curr-indentation curr-line + language + options + reg-beg reg-col + prev-char prev-indentation prev-line prev-pos + token + part-language + depth) + + (setq reg-beg (point-min) + reg-col 0 + token "live" + options "" + language "" + prev-line "" + prev-char 0 + prev-pos nil) + + (when (get-text-property pos 'part-side) + (setq part-language (symbol-name (get-text-property pos 'part-side)))) + + ;;(message "part-language=%S" part-language) + + (cond + + ((and (bobp) (member web-mode-content-type '("html" "xml"))) + (setq language web-mode-content-type) + ) + + ((string= web-mode-content-type "css") + (setq language "css" + curr-indentation web-mode-css-indent-offset)) + + ((member web-mode-content-type '("javascript" "json" "typescript")) + (setq language web-mode-content-type + curr-indentation web-mode-code-indent-offset)) + + ((or (string= web-mode-content-type "jsx") + (and part-language (string= part-language "jsx"))) + (setq language "jsx" + curr-indentation web-mode-code-indent-offset) + (cond + ((web-mode-jsx-is-html pos) + (setq curr-indentation web-mode-markup-indent-offset + options "is-html")) + ((and (setq depth (get-text-property pos 'jsx-depth)) (> depth 1)) + (when (get-text-property pos 'jsx-beg) + (setq depth (1- depth))) + (setq reg-beg (web-mode-jsx-depth-beginning-position pos depth)) + (setq reg-beg (1+ reg-beg)) + ;;(message "%S" (point)) + (save-excursion + (goto-char reg-beg) + ;;(message "pt=%S" reg-beg) + (cond + ((and (not (looking-at-p "[ ]*$")) + (looking-back "^[[:space:]]*{" (point-min))) + (setq reg-col (+ (current-indentation) ;; #1027 + (cond + ((looking-at "[ ]+") (1+ (length (match-string-no-properties 0)))) + (t 0)) + )) + ) + ((looking-at-p "[ ]*\\[[ ]*$") ;; #0659 + (setq reg-col (current-indentation)) + ) + ((and (looking-back "=[ ]*{" (point-min)) ;; #0739 #1022 + (not (looking-at-p "[[:space:]]*<"))) + (setq reg-col (current-indentation)) + ) + ;;((and (looking-back "=[ ]*{" (point-min)) ;; #0739 + ;; (looking-at-p "{[ ]*")) + ;; (setq reg-col (current-indentation)) + ;; ) + ((get-text-property (1- (point)) 'tag-beg) + ;;(message "point=%S" (point)) + (setq reg-col (current-indentation)) + ) + (t + (message "%S : %S %S" (point) (current-indentation) web-mode-code-indent-offset) + ;;(setq reg-col (+ (current-indentation) web-mode-code-indent-offset web-mode-jsx-expression-padding))) + (setq reg-col (+ (current-indentation) web-mode-code-indent-offset))) + ) + + ;;(message "%S %S %S" (point) (current-indentation) reg-col) + ) ;save-excursion + ) + ((string= web-mode-content-type "jsx") + (setq reg-beg (point-min))) + (t + (setq reg-beg (or (web-mode-part-beginning-position pos) (point-min))) + (save-excursion + (goto-char reg-beg) + (search-backward "<" nil t) + (setq reg-col (current-column)) + ) ;save-excursion + ) + ) ;cond + ;;(message "jsx reg-beg=%S" reg-beg) + ) ;jsx + + ((string= web-mode-content-type "php") + (setq language "php" + curr-indentation web-mode-code-indent-offset)) + + ((or (string= web-mode-content-type "xml")) + (setq language "xml" + curr-indentation web-mode-markup-indent-offset)) + + ;; TODO: est ce util ? + ((and (get-text-property pos 'tag-beg) + (get-text-property pos 'tag-name) + ;;(not (get-text-property pos 'part-side)) + ) + (setq language "html" + curr-indentation web-mode-markup-indent-offset)) + + ((and (get-text-property pos 'block-side) + (not (get-text-property pos 'block-beg))) + + (setq reg-beg (or (web-mode-block-beginning-position pos) (point-min))) + (goto-char reg-beg) + (setq reg-col (current-column)) + ;;(message "%S %S" reg-beg reg-col) + (setq language web-mode-engine) + (setq curr-indentation web-mode-code-indent-offset) + + (cond + ((string= web-mode-engine "blade") + (save-excursion + (when (web-mode-rsf "{[{!]+[ ]*") + (setq reg-col (current-column)))) + (setq reg-beg (+ reg-beg 2)) + ) + ((string= web-mode-engine "razor") + ;;(setq reg-beg (+ reg-beg 2)) + ;;(setq reg-col (current-column)) + ) + ;; tests/demo.chtml + ((string= web-mode-engine "ctemplate") + (save-excursion + (when (web-mode-rsf "{{#?") + (setq reg-col (current-column)))) + ) + ((string= web-mode-engine "dust") + (save-excursion + (when (web-mode-rsf "{@") + (setq reg-col (current-column)))) + ) + ((string= web-mode-engine "svelte") + (save-excursion + (when (web-mode-rsf "{@") + (setq reg-col (current-column)))) + ) + ((string= web-mode-engine "template-toolkit") + (setq reg-beg (+ reg-beg 3) + reg-col (+ reg-col 3)) + ) + ((and (string= web-mode-engine "jsp") + (web-mode-looking-at "<%@" reg-beg)) + (save-excursion + (goto-char reg-beg) + (looking-at "<%@[ ]*[[:alpha:]]+[ ]+\\|</?[[:alpha:]]+[:.][[:alpha:]]+[ ]+") + (goto-char (match-end 0)) + (setq reg-col (current-column)) + ) + ) + ((and (string= web-mode-engine "freemarker") + (web-mode-looking-at "<@\\|<%@\\|<[[:alpha:]]" reg-beg)) + (save-excursion + (goto-char reg-beg) + (looking-at "<@[[:alpha:].]+[ ]+\\|<%@[ ]*[[:alpha:]]+[ ]+\\|<[[:alpha:]]+:[[:alpha:]]+[ ]+") + (goto-char (match-end 0)) + (setq reg-col (current-column)) + ) + ) + ) ;cond + ) ;block-side + + ((and part-language (member part-language + '("css" "javascript" "json" "sql" "markdown" + "pug" "ruby" "sass" "stylus" "typescript"))) + (setq reg-beg (or (web-mode-part-beginning-position pos) (point-min))) + (goto-char reg-beg) + (if (and (string= web-mode-engine "mojolicious") + (looking-back "javascript begin" (point-min))) + (search-backward "%" nil t) + (search-backward "<" nil t)) + (setq reg-col (current-column)) + (setq language part-language) + (cond + ((string= language "css") + (setq curr-indentation web-mode-css-indent-offset)) + ((string= language "sql") + (setq curr-indentation web-mode-sql-indent-offset)) + ((string= language "markdown") + (setq curr-indentation web-mode-code-indent-offset)) + ((string= language "pug") + (setq curr-indentation web-mode-code-indent-offset)) + ((string= language "sass") + (setq curr-indentation web-mode-code-indent-offset)) + ((string= language "stylus") + (setq curr-indentation web-mode-code-indent-offset)) + ((string= language "ruby") + (setq curr-indentation web-mode-code-indent-offset)) + ((string= language "typescript") + (setq curr-indentation web-mode-code-indent-offset)) + (t + (setq language "javascript" + curr-indentation web-mode-code-indent-offset)) + ) + ) ;part-side + + (t + (setq language "html" + curr-indentation web-mode-markup-indent-offset) + ) + + ) ;cond + + (cond + ((or (and (> pos (point-min)) + (eq (get-text-property pos 'part-token) 'comment) + (eq (get-text-property (1- pos) 'part-token) 'comment) + (progn + (setq reg-beg (previous-single-property-change pos 'part-token)) + t)) + (and (> pos (point-min)) + (eq (get-text-property pos 'block-token) 'comment) + (eq (get-text-property (1- pos) 'block-token) 'comment) + (progn + (setq reg-beg (previous-single-property-change pos 'block-token)) + t)) + (and (> pos (point-min)) + (eq (get-text-property pos 'tag-type) 'comment) + (not (get-text-property pos 'tag-beg)) + (progn + (setq reg-beg (web-mode-tag-beginning-position pos)) + t)) + ) + (setq token "comment")) + ((or (and (> pos (point-min)) + (member (get-text-property pos 'part-token) + '(string context key)) + (member (get-text-property (1- pos) 'part-token) + '(string context key))) + (and (eq (get-text-property pos 'block-token) 'string) + (eq (get-text-property (1- pos) 'block-token) 'string))) + (setq token "string")) + ) + + (goto-char pos) + (setq curr-line (web-mode-trim + (buffer-substring-no-properties + (line-beginning-position) + (line-end-position)))) + (setq curr-char (if (string= curr-line "") 0 (aref curr-line 0))) + + (when (or (member language '("php" "blade" "javascript" "typescript" "jsx" "razor" "css")) + (and (member language '("html" "xml")) + (not (eq ?\< curr-char)))) + (let (prev) + (cond + ((member language '("html" "xml" "javascript" "jsx" "css")) + (when (setq prev (web-mode-part-previous-live-line reg-beg)) + (setq prev-line (nth 0 prev) + prev-indentation (nth 1 prev) + prev-pos (nth 2 prev)) + ) + ) + ((setq prev (web-mode-block-previous-live-line)) + (setq prev-line (car prev) + prev-indentation (cdr prev)) + (setq prev-line (web-mode-clean-block-line prev-line))) + ) ;cond + ) ;let + (when (>= (length prev-line) 1) + (setq prev-char (aref prev-line (1- (length prev-line)))) + (setq prev-line (substring-no-properties prev-line)) + ) + ) + + (cond + ((not (member web-mode-content-type '("html" "xml"))) + ) + ((member language '("javascript" "typescript" "jsx" "ruby")) + (setq reg-col (if web-mode-script-padding (+ reg-col web-mode-script-padding) 0))) + ((member language '("css" "sql" "markdown" "pug" "sass" "stylus")) + (setq reg-col (if web-mode-style-padding (+ reg-col web-mode-style-padding) 0))) + ((not (member language '("html" "xml"))) + (setq reg-col + (cond + ((not web-mode-block-padding) reg-col) + ((eq web-mode-block-padding -1) 0) + (t (+ reg-col web-mode-block-padding)) + ) ;cond + ) ;setq + ) + ) + + (list :curr-char curr-char + :curr-indentation curr-indentation + :curr-line curr-line + :language language + :options options + :prev-char prev-char + :prev-indentation prev-indentation + :prev-line prev-line + :prev-pos prev-pos + :reg-beg reg-beg + :reg-col reg-col + :token token) + ))) + +(defun web-mode-indent-line () + + (web-mode-scan) + + (let ((offset nil) + (char nil) + (debug nil) + (inhibit-modification-hooks nil) + (adjust t)) + + (save-excursion + (back-to-indentation) + (setq char (char-after)) + (let* ((pos (point)) + (ctx (web-mode-point-context pos)) + (curr-char (plist-get ctx :curr-char)) + (curr-indentation (plist-get ctx :curr-indentation)) + (curr-line (plist-get ctx :curr-line)) + (language (plist-get ctx :language)) + (prev-char (plist-get ctx :prev-char)) + (prev-indentation (plist-get ctx :prev-indentation)) + (prev-line (plist-get ctx :prev-line)) + (prev-pos (plist-get ctx :prev-pos)) + (reg-beg (plist-get ctx :reg-beg)) + (reg-col (plist-get ctx :reg-col)) + (token (plist-get ctx :token)) + (options (plist-get ctx :options)) + (chars (list curr-char prev-char)) + (tmp nil) + (is-js (member language '("javascript" "jsx" "ejs" "typescript")))) + + (when (member language '("json" "typescript")) + (setq language "javascript")) + + ;;(message "%S %S" (plist-get ctx :language) language) + ;;(message "curr-char=[%c] prev-char=[%c]\n%S" curr-char prev-char ctx) + ;;(message "options=%S" ctx) + + (cond + + ((or (bobp) (= (line-number-at-pos pos) 1)) + (when debug (message "I100(%S) first line" pos)) + (setq offset 0)) + + ;; #123 #1145 + ((and web-mode-enable-front-matter-block + (eq (char-after (point-min)) ?\-) + (or (looking-at-p "---") + (search-forward "---" (point-max) t))) + (when debug (message "I108(%S) front-matter-block" pos)) + (setq offset nil)) + + ;; #1073 + ((get-text-property pos 'invisible) + (when debug (message "I110(%S) invible" pos)) + (setq offset nil)) + + ((string= token "string") + (when debug (message "I120(%S) string" pos)) + (cond + ((web-mode-is-token-end pos) + (if (get-text-property pos 'block-side) + (web-mode-block-token-beginning) + (web-mode-part-token-beginning)) + (setq offset (current-indentation)) + ) + ((and web-mode-enable-sql-detection + (web-mode-block-token-starts-with (concat "[ \n]*" web-mode-sql-queries))) + (save-excursion + (let (col) + (web-mode-block-string-beginning) + (skip-chars-forward "[ \"'\n]") + (setq col (current-column)) + (goto-char pos) + (if (looking-at-p "\\(SELECT\\|INSERT\\|DELETE\\|UPDATE\\|FROM\\|LEFT\\|JOIN\\|WHERE\\|GROUP BY\\|LIMIT\\|HAVING\\|\)\\)") + (setq offset col) + (setq offset (+ col web-mode-sql-indent-offset))) + ) + ) ;save-excursion + ) + ((and is-js + (web-mode-is-ql-string pos "Relay\.QL")) + (setq offset (web-mode-relayql-indentation pos)) + ) + ((and is-js + (web-mode-is-ql-string pos "gql")) + (setq offset (web-mode-relayql-indentation pos "gql")) + ) + ((and is-js + (web-mode-is-ql-string pos "graphql")) + (setq offset (web-mode-relayql-indentation pos "graphql")) + ) + ((and is-js + (web-mode-is-css-string pos)) + (when debug (message "I127(%S) css string" pos)) + (setq offset (web-mode-token-css-indentation pos)) + ) + ((and is-js + (web-mode-is-html-string pos)) + (when debug (message "I128(%S) html string" pos)) + (setq offset (web-mode-token-html-indentation pos)) + ) + (t + (setq offset nil)) + ) ;cond + ) ;case string + + ((string= token "comment") + (when debug (message "I130(%S) comment" pos)) + (if (eq (get-text-property pos 'tag-type) 'comment) + (web-mode-tag-beginning) + (goto-char (car + (web-mode-property-boundaries + (if (eq (get-text-property pos 'part-token) 'comment) + 'part-token + 'block-token) + pos)))) + (setq offset (current-column)) + (cond + ((string= web-mode-engine "freemarker") + (setq offset (+ (current-indentation) 2))) + ((member (buffer-substring-no-properties (point) (+ (point) 2)) '("/*" "{*" "@*")) + (cond + ((eq ?\* curr-char) + (setq offset (+ offset 1))) + (t + (setq offset (+ offset 3))) + ) ;cond + ) + ((string= (buffer-substring-no-properties (point) (+ (point) 4)) "<!--") + (cond + ((string-match-p "^<!\\[endif" curr-line) + ) + ((looking-at-p "<!--\\[if") + (setq offset (+ offset web-mode-markup-indent-offset))) + ((string-match-p "^-->" curr-line) + (setq offset offset)) + ((string-match-p "^-" curr-line) + (setq offset (+ offset 3))) + (t + (setq offset (+ offset 5))) + ) ;cond + ) + ((and (string= web-mode-engine "django") (looking-back "{% comment %}" (point-min))) + (setq offset (- offset 12))) + ((and (string= web-mode-engine "mako") (looking-back "<%doc%>" (point-min))) + (setq offset (- offset 6))) + ((and (string= web-mode-engine "mason") (looking-back "<%doc%>" (point-min))) + (setq offset (- offset 6))) + ) ;cond + ) ;case comment + + ((and (string= web-mode-engine "mason") + (string-match-p "^%" curr-line)) + (when debug (message "I140(%S) mason" pos)) + (setq offset 0)) + + ((and (string= web-mode-engine "django") + (string-match-p "^#" curr-line)) + (when debug (message "I144(%S) django line statements" pos)) + (setq offset 0)) + + ((and (get-text-property pos 'block-beg) + (or (web-mode-block-is-close pos) + (web-mode-block-is-inside pos))) + (when debug (message "I150(%S) block-match" pos)) + (cond + ((not (web-mode-block-match)) + ) + ((and (string= web-mode-engine "closure") + (string-match-p "{\\(case\\|default\\)" curr-line)) + (setq offset (+ (current-indentation) web-mode-markup-indent-offset))) + (t + (setq offset (current-indentation)) + (if (and (string= web-mode-engine "blade") + (string-match-p "@break" curr-line)) + (setq offset (+ (current-indentation) offset))) + ) + ) ;cond + ) + + ((eq (get-text-property pos 'block-token) 'delimiter-end) + (when debug (message "I160(%S) block-beginning" pos)) + (when (web-mode-block-beginning) + (setq reg-col (current-indentation)) + (setq offset (current-column)))) + + ((or (and (get-text-property pos 'tag-beg) + (eq (get-text-property pos 'tag-type) 'end)) + (and (eq (get-text-property pos 'tag-type) 'comment) + (string-match-p "<!--#\\(else\\|elif\\|endif\\)" curr-line))) + (when debug (message "I170(%S) tag-match" pos)) + (when (web-mode-tag-match) + (setq offset (current-indentation)))) + + ((and (member language '("jsx")) + (eq curr-char ?\}) + (get-text-property pos 'jsx-end)) + (when debug (message "I180(%S) jsx-expr-end" pos)) + (web-mode-go (1- reg-beg)) + (setq reg-col nil) + ;;(setq offset (current-column))) + (setq offset (current-indentation))) + + ((and (member language '("html" "xml" "javascript" "jsx")) + (get-text-property pos 'tag-type) + (not (get-text-property pos 'tag-beg)) + ;;(or (not (string= language "jsx")) + ;; (string= options "is-html")) + (not (and (string= language "jsx") + (or (string= options "is-html") + (web-mode-jsx-is-expr pos)))) + ) + (when debug (message "I190(%S) attr-indent" pos)) + (cond + ((and (not (get-text-property pos 'tag-attr-beg)) + (get-text-property pos 'tag-attr) + (get-text-property (1- pos) 'tag-attr) + (web-mode-attribute-beginning) + (not (string-match-p "^/?>" curr-line)) + ;;(progn (message "pos=%S point=%S" pos (point)) t) + ) + + (cond + ((eq (logand (get-text-property (point) 'tag-attr-beg) 8) 8) + (setq offset nil)) + ((not (web-mode-tag-beginning)) + (message "** tag-beginning ** failure") + (setq offset nil)) + (web-mode-attr-value-indent-offset + (setq offset (+ (current-column) web-mode-attr-value-indent-offset))) + ((web-mode-dom-rsf "=[ ]*[\"']?" pos) + ;;(message "%S" (point)) + (setq offset (current-column))) + (t + (setq offset (+ (current-column) web-mode-markup-indent-offset))) + ) ;cond + ) ;and + ((not (web-mode-tag-beginning)) + (message "** error ** unable to jump to tag beg")) + ((string-match-p "^/?>" curr-line) + (setq offset (web-mode-column-at-pos (web-mode-tag-beginning-position pos))) + ) + (web-mode-attr-indent-offset + (setq offset (+ (current-column) web-mode-attr-indent-offset))) + ((looking-at-p (concat web-mode-start-tag-regexp "[ ]*\n")) + ;;(message "%S: %S" (point) (web-mode-inside-block-control pos)) + (setq offset (+ (current-column) (or web-mode-attr-indent-offset web-mode-code-indent-offset))) + ;; #1109 + (setq tmp (web-mode-inside-block-control pos)) + (when (and tmp (> tmp (point))) + (setq offset (+ offset (or web-mode-attr-indent-offset web-mode-code-indent-offset)))) + ) + ((web-mode-attribute-next) + (setq offset (current-column))) + ) ;cond + ) ;attr-indent + + ((or (member language '("html" "xml")) + (and (member language '("jsx")) + (string= options "is-html"))) + (when debug (message "I200(%S) web-mode-markup-indentation" pos)) + ;; https://www.w3.org/TR/html5/syntax.html#optional-tags + (when web-mode-enable-optional-tags + (save-excursion + (let (tag-name parent-tag-name parent-tag-pos) + (when (and (setq tag-name (get-text-property pos 'tag-name)) + (setq parent-tag-pos (web-mode-element-parent-position pos)) + (setq parent-tag-name (get-text-property parent-tag-pos 'tag-name)) + (or (and (string= parent-tag-name "p") (member tag-name '("p" "address", "article", "aside", "blockquote", "div", "dl", "fieldset", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "header", "hgroup", "hr", "main", "nav", "ol", "pre", "section", "table", "ul"))) + (and (string= parent-tag-name "li") (member tag-name '("li"))) + (and (string= parent-tag-name "dt") (member tag-name '("dt" "dd"))) + (and (string= parent-tag-name "td") (member tag-name '("td" "th"))) + (and (string= parent-tag-name "th") (member tag-name '("td" "th"))) + )) + (when debug (message "I205(%S) %S(%S) auto-closing" pos parent-tag-name parent-tag-pos)) + (setq offset (web-mode-indentation-at-pos parent-tag-pos)) + )))) ; when let save-excursion when + + (when (string= web-mode-engine "closure") + (save-excursion + (when (and (re-search-backward "{/?switch" nil t) + (string= (match-string-no-properties 0) "{switch")) + (setq offset (+ (current-indentation) (* 2 web-mode-markup-indent-offset))) + ) + )) + (cond + ((not (null offset)) + ) + ((get-text-property pos 'tag-beg) + (setq offset (web-mode-markup-indentation pos)) + ) + ((and web-mode-indentless-elements + (not (string= language "jsx")) + (null (get-text-property pos 'block-side)) + (null (get-text-property pos 'part-side)) + (and (null (get-text-property pos 'tag-beg)) + (save-excursion + (and (web-mode-element-parent) + (member (get-text-property (point) 'tag-name) web-mode-indentless-elements)))) + ) + (setq offset nil)) + ((or (eq (length curr-line) 0) + (= web-mode-indent-style 2) + (get-text-property pos 'tag-beg) + (get-text-property pos 'reg-beg)) + (setq offset (web-mode-markup-indentation pos)) + ) + ) + ) + + ((string= language "ctemplate") + (when debug (message "I210(%S) ctemplate" pos)) + (setq offset reg-col)) + + ((string= language "expressionengine") + (when debug (message "I212(%S) expressionengine" pos)) + (setq offset (+ reg-col (or web-mode-attr-indent-offset web-mode-code-indent-offset)))) + + ((string= language "asp") + (when debug (message "I230(%S) asp" pos)) + (setq offset (web-mode-asp-indentation pos + curr-line + reg-col + curr-indentation + reg-beg))) + + ((member language '("lsp" "cl-emb" "artanis")) + (when debug (message "I240(%S) lsp" pos)) + (setq offset (web-mode-lisp-indentation pos ctx))) + + ((and (member curr-char '(?\})) + (string= language "razor") + (get-text-property pos 'block-end)) + (when debug (message "I245(%S) razor closing" pos)) + (goto-char reg-beg) + ;;(message "%S %S" (point) (current-column)) + (setq offset (current-column) + reg-col nil) + ) + + ((member curr-char '(?\} ?\) ?\])) + (when debug (message "I250(%S) closing-paren" pos)) + (let (ori pos2) + (setq pos2 pos) + ;; #1096 + (when (looking-at-p ".[\]})]+") + (skip-chars-forward "[\]})]") + (backward-char) + (setq pos2 (point)) + ) ;when + (if (get-text-property pos 'block-side) + (setq ori (web-mode-block-opening-paren-position pos2 reg-beg)) + (setq ori (web-mode-part-opening-paren-position pos2 reg-beg))) + ;;(message "ori=%S" ori) + (cond + ((null ori) + (setq offset reg-col)) + ((and (goto-char ori) + (looking-back ")[ ]*" (point-min)) ;; peut-on se passer du looking-back ? + (re-search-backward ")[ ]*" nil t) + (web-mode-block-opening-paren reg-beg)) + (back-to-indentation) + (setq offset (current-indentation)) + ) + (t + (goto-char ori) + (back-to-indentation) + (setq offset (current-indentation)) + ;;(message "ori=%S offset=%S" ori offset) + (when (get-text-property pos 'jsx-depth) + ;;(when (get-text-property pos 'jsx-end) + (setq adjust nil)) + ) ;t + ) ;cond + ) ;let + ) + + ((member language '("mako" "web2py")) + (when debug (message "I254(%S) python (mako/web2py)" pos)) + (setq offset (web-mode-python-indentation pos + curr-line + reg-col + curr-indentation + reg-beg))) + + ((member language '("erb" "ruby")) + (when debug (message "I260(%S) erb" pos)) + (setq offset (web-mode-ruby-indentation pos + curr-line + reg-col + curr-indentation + reg-beg))) + + ((string= language "css") + (when debug (message "I270(%S) css-indentation" pos)) + ;;(message "prev=%c" prev-char) + (cond + ((eq prev-char ?:) + (setq offset (+ prev-indentation web-mode-css-indent-offset))) + ((eq prev-char ?,) + (setq offset prev-indentation)) + (t + (setq offset (car (web-mode-css-indentation pos + reg-col + curr-indentation + language + reg-beg)))))) + + ((string= language "sql") + (when debug (message "I280(%S) sql" pos)) + (setq offset (car (web-mode-sql-indentation pos + reg-col + curr-indentation + language + reg-beg)))) + + ((string= language "markdown") + (when debug (message "I290(%S) markdown" pos)) + (setq offset (car (web-mode-markdown-indentation pos + reg-col + curr-indentation + language + reg-beg)))) + + ((string= language "stylus") + (when debug (message "I294(%S) stylus" pos)) + (setq offset (car (web-mode-stylus-indentation pos + reg-col + curr-indentation + language + reg-beg)))) + ((string= language "sass") + (when debug (message "I296(%S) sass" pos)) + (setq offset (car (web-mode-stylus-indentation pos + reg-col + curr-indentation + language + reg-beg)))) + + ((string= language "pug") + (when debug (message "I298(%S) pug" pos)) + (setq offset (car (web-mode-pug-indentation pos + reg-col + curr-indentation + language + reg-beg)))) + + ((and (string= language "razor") + (string-match-p "^\\." curr-line) + (string-match-p "^\\." prev-line)) + (when debug (message "I300(%S) razor" pos)) + (setq offset prev-indentation)) + + ((and (string= language "razor") + (string-match-p "^case " curr-line) + (string-match-p "^case " prev-line)) + (when debug (message "I310(%S) razor case" pos)) + (search-backward "case ") + (setq offset (current-column))) + + ((and is-js + (member ?\. chars) + (not (string-match-p "^\\.\\.\\." curr-line))) + (when debug (message "I320(%S) javascript-calls" pos)) + (let (pair) + (setq pair (web-mode-javascript-calls-beginning-position pos reg-beg)) + ;;(message "%S" pair) + (when pair + (goto-char (car pair)) + ;;(message "%S %S" (point) pair) + (cond + ((cdr (assoc "lineup-calls" web-mode-indentation-params)) + ;;(message "ici") + ;;(search-forward ".") + (if (cdr pair) + (progn + (goto-char (cdr pair)) + (setq offset (current-column)) + (looking-at "\\.\\([ \t\n]*\\)") + (setq offset (- offset (length (match-string-no-properties 1)))) + (unless (eq curr-char ?\.) (setq offset (1+ offset))) + ) ;progn + ;; TODO: cela devrait etre fait dans web-mode-javascript-calls-beginning-position + (skip-chars-forward " \t\n") + (setq offset (+ (current-indentation) web-mode-code-indent-offset)) + ) ;if + ) + (t + (setq offset (+ (current-indentation) web-mode-code-indent-offset)) + ) ;t + ) ;cond + ) ;when + ) ;let + ) + + ((and is-js + (member ?\+ chars)) + (when debug (message "I330(%S) javascript-string" pos)) + ;;(message "js-concat") + (cond + ((not (web-mode-javascript-string-beginning pos reg-beg)) + ) + ((null (cdr (assoc "lineup-concats" web-mode-indentation-params))) + (setq offset (+ (current-indentation) web-mode-code-indent-offset))) + ((not (eq curr-char ?\+)) + (setq offset (current-column))) + (t + (setq offset (current-column)) + (when (not (looking-back "\\(^[ \t]+\\|if[ ]*[(]?\\)" (point-min))) + (goto-char pos) + (looking-at "\\+[ \t\n]*") + (setq offset (- offset (length (match-string-no-properties 0))))) + ) + ) + ) + + ;; #579 , #742 + ((and (member language '("javascript" "jsx" "ejs" "php")) + (string-match-p "=[>]?$" prev-line)) + (when debug (message "I340(%S)" pos)) + (setq offset (+ prev-indentation web-mode-code-indent-offset)) + ;;(message "ici%S" offset) + ) + + ;; #1016 + ((and (member language '("javascript" "jsx" "ejs")) + (string-match-p "^[ \t]*|}" curr-line)) + (when debug (message "I346(%S) flow-exact-object-type-end" pos)) + (when (re-search-backward "{|" reg-beg t) + (setq offset (current-indentation)) + ) + ) + + ;; #446, #638, #800, #978, #998 + ((and (member language '("javascript" "jsx" "ejs" "php")) + (or (string-match-p "[&|?:+-]$" prev-line) + (string-match-p "^[&|?:+-]" curr-line)) + (not (and (string= language "php") + (string-match-p "^->" curr-line))) + (not (and (string= language "php") + (string-match-p "^?[a-zA-z]*" curr-line))) + (not (and (string= language "php") + (string-match-p "\\(else[ ]?:\\|if[ ]?([^)]*)[ ]?:\\)" prev-line))) + (not (string-match-p "^\\(++\\|--\\)" curr-line)) + (not (and is-js + (string-match-p "]:\\|{|$" prev-line))) + (not (and (eq prev-char ?\:) + (string-match-p "^\\(case\\|default\\)" prev-line))) + ) + ;;(message "prev=%S" prev-line) + (when debug (message "I350(%S) multiline statement" pos)) + (let (is-ternary) + (setq is-ternary (or (string-match-p "[?:]$" prev-line) + (string-match-p "^[?:]" curr-line))) + (cond + ((not (funcall (if is-js + 'web-mode-javascript-statement-beginning + 'web-mode-block-statement-beginning) + pos reg-beg is-ternary)) + ) + ((null (cdr (assoc "lineup-ternary" web-mode-indentation-params))) + (setq offset (+ (current-indentation) web-mode-code-indent-offset))) + (t + (setq offset (current-column)) + (when (and (member curr-char '(?\+ ?\- ?\& ?\| ?\? ?\:)) + (not (looking-back "\\(^[ \t]+\\|if[ ]*[(]?\\)" (point-min)))) ; #743 + (goto-char pos) + (looking-at "\\(||\\|&&\\|[&|?:+-]\\)[ \t\n]*") + (setq offset (- offset (length (match-string-no-properties 0))))) + ) + ) ;cond + ) ;let + ) + + ((and is-js + (eq prev-char ?\() + (string-match-p "=>[ ]*([ ]*$" prev-line)) + (when debug (message "I355(%S) => (" pos)) + (setq offset (+ prev-indentation web-mode-code-indent-offset)) + ) + + ((and is-js + (or (member ?\, chars) + (member prev-char '(?\( ?\[)))) + (when debug (message "I360(%S) javascript-args" pos)) + (cond + ((not (web-mode-javascript-args-beginning pos reg-beg)) + (message "no js args beg") + ) + ((or (not (cdr (assoc "lineup-args" web-mode-indentation-params))) + (looking-at-p "|?\n") ;; #1016 + ;;(eq (char-after) ?\n) + ) + (if (and reg-col (> reg-col (current-indentation))) + (setq offset (+ reg-col web-mode-code-indent-offset)) + (setq offset (+ (current-indentation) web-mode-code-indent-offset))) + ) + ((not (eq curr-char ?\,)) + (setq offset (current-column))) + (t + (setq offset (current-column)) + (goto-char pos) + (looking-at ",[ \t\n]*") + (setq offset (- offset (length (match-string-no-properties 0))))) + ) ;cond + ) + + ((and is-js + (or (eq prev-char ?\)) + (string-match-p "\\(^\\|[}[:space:]]+\\)else$" prev-line))) + (when debug (message "I370(%S)" pos)) + (cond + ((and (string-match-p "else$" prev-line) + (not (string-match-p "^{" curr-line))) + (setq offset (+ prev-indentation web-mode-code-indent-offset)) + ) + ((and (string-match-p "else$" prev-line) + (string-match-p "^{" curr-line) + web-mode-enable-curly-brace-indentation) + (setq offset (+ prev-indentation web-mode-code-indent-offset)) + ) + ((setq tmp (web-mode-part-is-opener prev-pos reg-beg)) + ;;(message "is-opener") + (if (or (not (looking-at-p "{")) ;; #1020, #1053, #1160 + web-mode-enable-curly-brace-indentation) + (setq offset (+ tmp web-mode-code-indent-offset)) + (setq offset tmp)) + ) + (t + (setq offset + (car (web-mode-javascript-indentation pos + reg-col + curr-indentation + language + reg-beg))) + ) ;t + ) ;cond + + ) + + ;; TODO : a retoucher completement car le code js a ete place ci-dessus + ;;((and (member language '("javascript" "jsx" "ejs" "php")) + ((and (member language '("php")) + (or (and (eq prev-char ?\)) + (string-match-p "^\\(for\\|foreach\\|if\\|else[ ]*if\\|while\\)[ ]*(" prev-line)) + (and is-js + (web-mode-part-is-opener prev-pos reg-beg)) + (string-match-p "^else$" prev-line)) + (not (string-match-p "^\\([{.]\\|->\\)" curr-line))) + (when debug (message "I380(%S)" pos)) + (cond + ((and (eq prev-char ?\)) + (string-match-p "^\\(for\\|if\\|while\\)[ ]*(" prev-line)) + (setq offset (+ prev-indentation web-mode-code-indent-offset)) + ) + ((member language '("javascript" "jsx")) + (setq offset + (+ (car (web-mode-javascript-indentation pos + reg-col + curr-indentation + language + reg-beg)) + web-mode-code-indent-offset)) + ) + (t + (setq offset (+ prev-indentation web-mode-code-indent-offset)) + ) + ) + ) + + ((and (member language '("php" "blade")) (string-match-p "^->" curr-line)) + (when debug (message "I390(%S) block-calls" pos)) + (cond + ((not (web-mode-block-calls-beginning pos reg-beg)) + ) + ((cdr (assoc "lineup-calls" web-mode-indentation-params)) + ;;(message "point=%S" (point)) + (if (looking-back "::[ ]*" (point-min)) + (progn + (re-search-backward "::[ ]*") + (setq offset (current-column)) + ;;(message "ici%S offset=%S" (point) offset) + ) + (search-forward "->") + (setq offset (- (current-column) 2))) + ) + (t + (setq offset (+ (current-indentation) web-mode-code-indent-offset))) + )) + + ((and is-js (member ?\, chars)) + (when debug (message "I400(%S) part-args" pos)) + (cond + ((not (web-mode-part-args-beginning pos reg-beg)) + ;;(message "ici") + ) + ((cdr (assoc "lineup-args" web-mode-indentation-params)) + (setq offset (current-column)) + ;;(message "offset=%S" offset) + (when (eq curr-char ?\,) + (goto-char pos) + (looking-at ",[ \t\n]*") + (setq offset (- offset (length (match-string-no-properties 0))))) + ) + (t + (setq offset (+ (current-indentation) web-mode-code-indent-offset))) + )) + + ((member ?\, chars) + (when debug (message "I401(%S) block-args" pos)) + (cond + ((not (web-mode-block-args-beginning pos reg-beg)) + ;;(message "ici") + ) + ((cdr (assoc "lineup-args" web-mode-indentation-params)) + (setq offset (current-column)) + ;;(message "offset=%S" offset) + (when (eq curr-char ?\,) + (goto-char pos) + (looking-at ",[ \t\n]*") + (setq offset (- offset (length (match-string-no-properties 0))))) + ) + (t + (setq offset (+ (current-indentation) web-mode-code-indent-offset))) + )) + + + ((and (string= language "php") (member ?\. chars)) + (when debug (message "I410(%S) block-string" pos)) + (cond + ((not (web-mode-block-string-beginning pos reg-beg)) + ) + ((null (cdr (assoc "lineup-concats" web-mode-indentation-params))) + (setq offset (+ (current-indentation) web-mode-code-indent-offset))) + ((not (eq curr-char ?\.)) + (setq offset (current-column))) + (t + (setq offset (current-column)) + (goto-char pos) + (when (cdr (assoc "lineup-quotes" web-mode-indentation-params)) + (looking-at "\\.[ \t\n]*") + (setq offset (- offset (length (match-string-no-properties 0))))) + ))) + + ((member language '("javascript" "jsx" "ejs" "underscore")) + (when debug (message "I420(%S) javascript-indentation" pos)) + (setq offset (car (web-mode-javascript-indentation pos + reg-col + curr-indentation + language + reg-beg)))) + + (t + (when debug (message "I430(%S) bracket-indentation" pos)) + (setq offset (car (web-mode-bracket-indentation pos + reg-col + curr-indentation + language + reg-beg)))) + + ) ;cond + + (when (and offset reg-col adjust (< offset reg-col)) (setq offset reg-col)) + + ) ;let + ) ;save-excursion + + (when offset + ;;(message "offset=%S" offset) + (let ((diff (- (current-column) (current-indentation)))) + (when (not (= offset (current-indentation))) + (setq web-mode-change-beg (line-beginning-position) + web-mode-change-end (+ web-mode-change-beg offset))) + (setq offset (max 0 offset)) + (indent-line-to offset) + (if (> diff 0) (move-to-column (+ (current-column) diff))) + (when (and (string= web-mode-engine "mason") + (= offset 0) + (eq char ?\%)) + (save-excursion + (font-lock-fontify-region (line-beginning-position) (line-end-position))) + ) ;when + ) ;let + ) ;when + + )) + +(defun web-mode-bracket-level (pos limit) + (save-excursion + (let ((continue t) + (regexp "[\]\[}{)(]") + (char nil) + (map nil) + (key nil) + (value 0) + (open '(?\( ?\{ ?\[))) + (goto-char pos) + (while (and continue (re-search-backward regexp limit t)) + (setq char (aref (match-string-no-properties 0) 0)) + (setq key (cond ((eq char ?\)) ?\() + ((eq char ?\}) ?\{) + ((eq char ?\]) ?\[) + (t char))) + (setq value (or (plist-get map key) 0)) + (setq value (if (member char open) (1+ value) (1- value))) + (setq map (plist-put map key value)) + (setq continue (< value 1)) + ;;(message "pos=%S char=%c key=%c value=%S" (point) char key value) + ) ;while + (if (>= value 1) (current-indentation) nil) + ))) + +(defun web-mode-token-html-indentation (pos) + (save-excursion + (let (beg (continue t) end level map offset regexp tag val void (css-beg 0)) + (goto-char pos) + ;;(message "pos=%S" pos) + (setq beg (web-mode-part-token-beginning-position pos)) + (save-excursion + (when (and (> (- pos beg) 5) + (re-search-backward "</?[a-zA-Z0-9]+" beg t) + (string= "<style" (downcase (match-string-no-properties 0)))) + (setq css-beg (point)) + ) + ) + ;;(message "beg=%S" beg) + (cond + ((eq (char-after pos) ?\`) + (setq offset (web-mode-indentation-at-pos beg))) + ((web-mode-looking-back "`[ \n\t]*" pos) + (setq offset (+ (web-mode-indentation-at-pos beg) web-mode-markup-indent-offset))) + ((looking-at "</\\([a-zA-Z0-9]+\\)") + (setq tag (match-string-no-properties 1) + regexp (concat "</?" tag) + level -1) + (while (and continue (re-search-backward regexp beg t)) + (cond + ((eq (aref (match-string-no-properties 0) 1) ?\/) + (setq level (1- level))) + (t + (setq level (1+ level))) + ) ;cond + (when (= level 0) + (setq continue nil + offset (current-indentation))) + ) ;while + ) + ((> css-beg 0) + ;;(message "CSS") + (cond + ((member (char-after) '(?\) ?\} ?\])) + (web-mode-go (web-mode-token-opening-paren-position pos (+ css-beg 8) "")) + (setq offset (current-indentation)) + ) + ((setq level (web-mode-bracket-level pos (+ css-beg 8))) + (setq offset (+ level web-mode-css-indent-offset)) + ) + (t + (setq offset (+ (web-mode-indentation-at-pos css-beg) web-mode-style-padding)) + ) ;t + ) + ) + ((looking-at "[a-zA-Z-]+[ ]?=") + (re-search-backward "<[a-zA-Z]+[ ]*" beg t) + (setq offset (+ (current-column) (length (match-string-no-properties 0)))) + ) + ((looking-at-p "/>") + (search-backward "<" beg t) + (setq offset (current-column)) + ) + (t + (setq regexp "</?\\([a-zA-Z0-9]+\\)") + ;;(message "point=%S" (point)) + (while (and continue (re-search-backward regexp beg t)) + (setq tag (downcase (match-string-no-properties 1)) + end nil + void nil) + (cond + ((eq (aref (match-string-no-properties 0) 1) ?/) + (setq end t)) + ((web-mode-element-is-void tag) + (setq void t)) + (t + (save-excursion + (when (and (search-forward ">" pos t) (eq (char-before (1- (point))) ?\/)) + (setq void t)) + ) ;save-excursion + ) ;t + ) ;cond + (unless void + (setq val (or (lax-plist-get map tag) 0)) + (setq val (if end (1- val) (1+ val))) + (setq map (lax-plist-put map tag val)) + ;;(message "val=%S tag=%S end=%S | %S" val tag end (plist-get map tag)) + (setq continue (not (> val 0))) + ) ;unless + ;(message "pos=%S tag=%S val=%S end=%S void=%S" (point) tag val end void) + ) ;while + (cond + ((> val 0) + ;;(message "point=%S" (point)) + ;;(goto-char (1+ beg)) + ;;(forward-char) + ;;(re-search-forward "[[:space:]]*") + (setq offset (+ (current-indentation) web-mode-markup-indent-offset))) + (t + (setq offset (current-indentation))) + ) + ) ;t + ) ;cond + offset))) + +(defun web-mode-token-css-indentation (pos) + (save-excursion + (let (offset) + (goto-char pos) + (web-mode-part-token-beginning) + (setq offset (+ web-mode-css-indent-offset (current-indentation))) + ) ;let + )) + +(defun web-mode-relayql-indentation (pos &optional prefix) + (unless prefix (setq prefix "relayql")) + (let (beg offset level char) + (setq char (char-after)) + (setq beg (web-mode-part-token-beginning-position pos)) + (goto-char beg) + (cond + ((member char '(?\`)) + (setq offset (current-indentation)) + ) + ((member char '(?\) ?\} ?\])) + (web-mode-go (web-mode-token-opening-paren-position pos beg prefix)) + (setq offset (current-indentation)) + ) + ((setq level (web-mode-bracket-level pos beg)) + (setq offset (+ level web-mode-code-indent-offset)) + ) + (t + (setq offset (+ (current-indentation) web-mode-code-indent-offset)) + ) + ) + offset)) + +(defun web-mode-markup-indentation (pos) + (let (offset beg ret jsx-depth) + (when (and (setq jsx-depth (get-text-property pos 'jsx-depth)) + (get-text-property pos 'jsx-beg) + (not (get-text-property pos 'tag-beg))) + (setq jsx-depth (1- jsx-depth))) + ;;(when (setq beg (web-mode-markup-indentation-origin pos jsx-depth)) + (cond + ((not (setq beg (web-mode-markup-indentation-origin pos jsx-depth))) + (setq offset 0)) + ((null (setq ret (web-mode-element-is-opened beg pos))) + (setq offset (web-mode-indentation-at-pos beg))) + ((eq ret t) + (setq offset (+ (web-mode-indentation-at-pos beg) + web-mode-markup-indent-offset))) + (t + (setq offset ret)) + ) ;cond + ;;(message "markup-indentation-origin=%S (jsx-depth=%S)" beg jsx-depth) + ;;) ;when beg + offset)) + +(defun web-mode-css-indentation (pos initial-column language-offset language &optional limit) + (let ((open-ctx (web-mode-bracket-up pos language limit)) offset) + (cond + ((or (null open-ctx) (null (plist-get open-ctx :pos))) + (setq offset initial-column)) + (t + (setq offset (+ (plist-get open-ctx :indentation) language-offset))) + ) ;cond + (cons (if (< offset initial-column) initial-column offset) open-ctx) + )) + +(defun web-mode-sql-indentation (pos initial-column language-offset language &optional limit) + (let ((open-ctx (web-mode-bracket-up pos language limit)) offset) + ;;(message "%S %S %S %S %S" pos (point) initial-column language-offset open-ctx) + (cond + ((and (not (null open-ctx)) (not (null (plist-get open-ctx :pos)))) + (setq offset (+ (plist-get open-ctx :column) 1))) + ((looking-at-p "\\(SELECT\\|INSERT\\|DELETE\\|UPDATE\\|FROM\\|LEFT\\|JOIN\\|WHERE\\|GROUP BY\\|LIMIT\\|HAVING\\|ON\\|select\\|insert\\|delete\\|update\\|from\\|left\\|join\\|where\\|group by\\|limit\\|having\\|on\\|AND\\|and\\|OR\\|or\\)") + (setq offset initial-column)) + (t + (setq offset (+ initial-column language-offset))) + ) ;cond + (cons (if (< offset initial-column) initial-column offset) open-ctx) + )) + +(defun web-mode-markdown-indentation (pos initial-column language-offset language &optional limit) + (let (offset) + (save-excursion + (goto-char pos) + (setq offset (current-column)) + ) ;save-excursion + ;;(message "%S %S %S %S" pos (point) initial-column language-offset) + (cons (if (<= offset initial-column) initial-column offset) nil))) + +(defun web-mode-stylus-indentation (pos initial-column language-offset language &optional limit) + (let (offset) + (save-excursion + (goto-char pos) + (setq offset (current-column)) + (if (looking-at-p "[[:alnum:]-]+:") + (setq offset (+ initial-column language-offset)) + (setq offset initial-column)) + ) ;save-excursion + ;;(message "%S %S %S %S" pos (point) initial-column language-offset) + (cons (if (<= offset initial-column) initial-column offset) nil))) + +(defun web-mode-sass-indentation (pos initial-column language-offset language &optional limit) + (let (offset) + (save-excursion + (goto-char pos) + (setq offset (current-column)) + (if (looking-at-p "[[:alnum:]-]+:") + (setq offset (+ initial-column language-offset)) + (setq offset initial-column)) + ) ;save-excursion + ;;(message "%S %S %S %S" pos (point) initial-column language-offset) + (cons (if (<= offset initial-column) initial-column offset) nil))) + +(defun web-mode-pug-indentation (pos initial-column language-offset language &optional limit) + nil + ) + +(defun web-mode-javascript-indentation (pos initial-column language-offset language &optional limit) + (let (open-ctx indentation offset sub) + (setq open-ctx (web-mode-bracket-up pos language limit)) + ;;(message "pos(%S) initial-column(%S) language-offset(%S) language(%S) limit(%S)" pos initial-column language-offset language limit) + ;;(message "javascript-indentation: %S\nchar=%c" open-ctx (plist-get open-ctx :char)) + (setq indentation (plist-get open-ctx :indentation)) + (when (and initial-column (> initial-column indentation)) + (setq indentation initial-column) + ) + (setq case-fold-search nil) ; #1006 + (cond + ((or (null open-ctx) (null (plist-get open-ctx :pos))) + (setq offset initial-column)) + ((and (member language '("javascript" "jsx" "ejs")) + (eq (plist-get open-ctx :char) ?\{) + (web-mode-looking-back "switch[ ]*" (plist-get open-ctx :pos))) + (setq sub (if (cdr (assoc "case-extra-offset" web-mode-indentation-params)) 0 1)) + (cond + ((looking-at-p "case\\|default") + (setq offset (+ indentation (* language-offset (- 1 sub))))) + (t + (setq offset (+ indentation (* language-offset (- 2 sub))))) + ) ;cond switch + ) + (t + (setq offset (+ indentation language-offset))) + ) ;cond + (setq case-fold-search t) + (cons (if (< offset initial-column) initial-column offset) open-ctx) + )) + +(defun web-mode-bracket-indentation (pos initial-column language-offset language &optional limit) + (save-excursion + (let* ((ctx (web-mode-bracket-up pos language limit)) + (char (plist-get ctx :char)) + (pos (plist-get ctx :pos)) + (indentation (plist-get ctx :indentation))) + ;;(message "pos(%S) initial-column(%S) language-offset(%S) language(%S) limit(%S)" pos initial-column language-offset language limit) + ;;(message "bracket-up: %S, %c" ctx char) + (cond + ((null pos) + (setq indentation initial-column)) + ((and (member language '("php")) + (eq char ?\{) + (web-mode-looking-back "switch[ ]*" pos) + (not (looking-at-p "case\\|default"))) + (setq indentation (+ indentation (* language-offset 2))) + ) + ((and (member language '("php")) + (eq char ?\{) + (goto-char pos) + (web-mode-looking-back "[)][ ]*" pos) + (search-backward ")") + (web-mode-block-opening-paren limit)) + (setq indentation (+ (current-indentation) language-offset)) + ) + (t + (setq indentation (+ indentation language-offset)) + ) + ) ;cond + (cons (if (< indentation initial-column) initial-column indentation) ctx) + ))) + +(defun web-mode-ruby-indentation (pos line initial-column language-offset limit) + (unless limit (setq limit nil)) + (let (h offset prev-line prev-indentation open-ctx) + (setq open-ctx (web-mode-bracket-up pos "ruby" limit)) + ;;(message "%S" open-ctx) + (if (plist-get open-ctx :pos) + (cond + ((web-mode-looking-at-p ".[ \t\n]+" (plist-get open-ctx :pos)) + (setq offset (+ (plist-get open-ctx :indentation) language-offset))) + (t + (setq offset (1+ (plist-get open-ctx :column)))) + ) + (setq h (web-mode-previous-line pos limit)) + (setq offset initial-column) + (when h + (setq prev-line (car h)) + (setq prev-indentation (cdr h)) + (cond + ((string-match-p ",$" prev-line) + (save-excursion + (goto-char limit) + (looking-at "<%=? [a-z]+ ") + (setq offset (+ initial-column (length (match-string-no-properties 0)))) + ) ;save-excursion + ) + ((string-match-p "^[ ]*\\(end\\|else\\|elsif\\|when\\)" line) + (setq offset (- prev-indentation language-offset)) + ) + ((string-match-p "[ ]+\\(do\\)" prev-line) + (setq offset (+ prev-indentation language-offset)) + ) + ((string-match-p "^[ ]*\\(when\\|if\\|else\\|elsif\\|unless\\|for\\|while\\|def\\|class\\)" prev-line) + (setq offset (+ prev-indentation language-offset)) + ) + (t + (setq offset prev-indentation) + ) + ) + ) ;when + ) ;if + offset)) + +(defun web-mode-python-indentation (pos line initial-column language-offset limit) + (unless limit (setq limit nil)) + (let (h offset prev-line prev-indentation ctx) + (setq ctx (web-mode-bracket-up pos "python" limit)) + ;;(message "point-ctx=%S" ctx) + (if (plist-get ctx :pos) + (cond + ((web-mode-looking-at-p ".[ \t\n]+" (plist-get ctx :pos)) + (setq offset (+ (plist-get ctx :indentation) language-offset))) + (t + (setq offset (1+ (plist-get ctx :column)))) + ) + ;; else + (setq h (web-mode-previous-line pos limit)) + (setq offset initial-column) + (when h + (setq prev-line (car h)) + (setq prev-indentation (cdr h)) + (cond + ((string-match-p "^\\(pass\\|else\\|elif\\|when\\|except\\)" line) + (setq offset (- prev-indentation language-offset)) + ) + ((string-match-p "\\(if\\|else\\|elif\\|for\\|while\\|try\\|except\\)" prev-line) + (setq offset (+ prev-indentation language-offset)) + ) + (t + (setq offset prev-indentation) + ) + ) ;cond + ) ;when + ) ;if + ;;offset + (if (< offset initial-column) initial-column offset) + )) + +(defun web-mode-lisp-indentation (pos point-ctx) + (let (offset open-ctx) + (setq open-ctx (web-mode-bracket-up pos "lsp" (plist-get point-ctx :reg-beg))) + ;;(message "point-ctx=%S" point-ctx) + ;;(message "open-ctx=%S" open-ctx) + (cond + ((null (plist-get open-ctx :pos)) + (setq offset (plist-get point-ctx :reg-col))) + ((member (plist-get point-ctx :curr-char) '(?\( ?\))) + (if (web-mode-looking-at-p "((" (plist-get open-ctx :pos)) + (setq offset (+ (plist-get open-ctx :column) 1)) + (setq offset (+ (plist-get open-ctx :column) web-mode-code-indent-offset))) + ) + (t + (goto-char (plist-get open-ctx :pos)) + (forward-char) + (web-mode-rsf "[[:alnum:]-:]+ ") + (setq offset (current-column)) + ) + ) ;cond + offset)) + +(defun web-mode-asp-indentation (pos line initial-column language-offset limit) + (unless limit (setq limit nil)) + (let (h out prev-line prev-indentation) + (setq h (web-mode-previous-line pos limit)) + (setq out initial-column) + (when h + (setq prev-line (car h)) + (setq prev-indentation (cdr h)) + ;;(message "line=%S" line) + (cond + ((string-match-p "''" line) + (setq out prev-indentation)) + ;; ---------------------------------------------------------------------- + ;; unindent + ((string-match-p "\\_<\\(\\(end \\(if\\|function\\|class\\|sub\\|with\\)\\)\\|else\\|elseif\\|next\\|loop\\)\\_>" line) + (setq out (- prev-indentation language-offset))) + ;; ---------------------------------------------------------------------- + ;; select case statement + ((string-match-p "\\_<\\(select case\\)\\_>" line) + (setq out (- prev-indentation 0))) + ((string-match-p "\\_<\\(end select\\)" line) + (setq out (- prev-indentation (* 2 language-offset)))) + ((and (string-match-p "\\_<\\(case\\)\\_>" line) (not (string-match-p "\\_<\\(select case\\)\\_>" prev-line))) + (setq out (- prev-indentation language-offset))) + ;; ---------------------------------------------------------------------- + ;; do nothing + ((string-match-p "\\_<\\(\\(end \\(if\\|function\\|class\\|sub\\|select\\|with\\)\\)\\|loop\\( until\\| while\\)?\\)\\_>" prev-line) + (setq out (+ prev-indentation 0))) + ;; indent + ((string-match-p "\\_<\\(\\(select \\)?case\\|else\\|elseif\\|unless\\|for\\|class\\|with\\|do\\( until\\| while\\)?\\|while\\|\\(public \\|private \\)?\\(function\\|sub\\|class\\)\\)\\_>" prev-line) + (setq out (+ prev-indentation language-offset))) + ;; single line if statement + ((string-match-p "\\_<if\\_>.*\\_<then\\_>[ \t]*[[:alpha:]]+" prev-line) + (setq out (+ prev-indentation 0))) + ;; normal if statement + ((string-match-p "\\_<\\if\\_>" prev-line) + (setq out (+ prev-indentation language-offset))) + (t + (setq out prev-indentation)) + ) + ) ;when + out)) + +(defun web-mode-block-previous-live-line () + (save-excursion + (let ((continue t) (line "") (pos (point))) + (beginning-of-line) + (while (and continue (not (bobp)) (forward-line -1)) + (when (not (web-mode-block-is-token-line)) + (setq line (web-mode-trim (buffer-substring (point) (line-end-position))))) + (when (not (string= line "")) + (setq continue nil)) + ) ;while + (if (string= line "") + (progn (goto-char pos) nil) + (cons line (current-indentation))) + ))) + +(defun web-mode-part-is-opener (pos reg-beg) + (save-excursion + (save-match-data + (if (and pos + (web-mode-go (web-mode-part-opening-paren-position pos)) + (>= (point) reg-beg) + (looking-back "\\(^\\|[ \t]\\)\\(if\\|for\\|while\\)[ ]*" (point-min))) + (current-indentation) + nil) + ))) + +(defun web-mode-part-previous-live-line (reg-beg) + (unless reg-beg (setq reg-beg (point-min))) + ;;(message "reg-beg=%S" reg-beg) + (save-excursion + (let ((continue (> (point) reg-beg)) + (line "") + bol-pos + eol-pos + pos) + (beginning-of-line) + (while (and continue (> (point) reg-beg) (forward-line -1)) + (setq bol-pos (point) + eol-pos (line-end-position)) + (when (> reg-beg bol-pos) + (setq bol-pos reg-beg)) + (when (not (web-mode-part-is-token-line bol-pos)) + (setq line (web-mode-trim (buffer-substring bol-pos eol-pos))) + (when (not (string= line "")) (setq continue nil)) + ) ;when + ) ;while + (cond + ((string= line "") + nil) + (t + (setq continue t) + (setq pos (1- eol-pos)) + (while (and (>= pos bol-pos) continue) + (cond + ((eq (char-after pos) ?\s) + (setq pos (1- pos))) + ((get-text-property pos 'part-token) + (setq pos (1- pos))) + (t + (setq continue nil)) + ) ;cond + ) ;while + ;;(message "%S %S : %S" bol-pos eol-pos pos) + (setq line (web-mode-clean-part-line line)) + (list line (current-indentation) pos)) + ) ;cond + ))) + +(defun web-mode-in-code-block (open close &optional prop) + (save-excursion + (let ((pos (point)) pos-open pos-close start end ret) + (when prop + (setq start pos + end pos) + (when (eq (get-text-property pos prop) (get-text-property (1- pos) prop)) + (setq start (or (previous-single-property-change pos prop) (point-min)))) + (when (eq (get-text-property pos prop) (get-text-property (1+ pos) prop)) + (setq end (next-single-property-change pos prop))) + ;; (message "start(%S) end(%S)" start end) + ) + (setq ret (and (web-mode-sb open start t) + (setq pos-open (point)) + (web-mode-sf close end t) + (setq pos-close (point)) + (>= pos-close pos))) + (if ret + (cons pos-open pos-close) + ret) + ))) + +(defun web-mode-clean-part-line (input) + (let ((out "") + (beg 0) + (keep t) + (n (length input))) + (dotimes (i n) + (if (or (get-text-property i 'block-side input) + (eq (get-text-property i 'part-token input) 'comment) + (eq (get-text-property i 'tag-type input) 'comment)) + (when keep + (setq out (concat out (substring input beg i)) + beg 0 + keep nil)) + (when (null keep) + (setq beg i + keep t)) + ) ;if + ) ;dotimes + (if (> beg 0) (setq out (concat out (substring input beg n)))) + (setq out (if (= (length out) 0) input out)) + (web-mode-trim out) + )) + +(defun web-mode-clean-block-line (input) + (let ((out "") + (beg 0) + (keep t) + (n (length input))) + (dotimes (i n) + (if (or (not (get-text-property i 'block-side input)) + (member (get-text-property i 'block-token input) + '(comment delimiter-beg delimiter-end))) + (when keep + (setq out (concat out (substring input beg i)) + beg 0 + keep nil)) + (when (null keep) + (setq beg i + keep t)) + ) ;if + ) ;dotimes + (if (> beg 0) (setq out (concat out (substring input beg n)))) + (setq out (if (= (length out) 0) input out)) + (web-mode-trim out) + ;; (message "%S [%s] > [%s]" beg input out) + )) + +(defun web-mode-language-at-pos (&optional pos) + (unless pos (setq pos (point))) + (cond + ((get-text-property pos 'block-side) + web-mode-engine) + ((get-text-property pos 'part-side) + (symbol-name (get-text-property pos 'part-side))) + (t + web-mode-content-type) + ) ;cond + ) + +(defun web-mode-coord-position (line column) + (save-excursion + (when (stringp line) (setq line (string-to-number line))) + (when (stringp column) (setq column (string-to-number column))) + (goto-char (point-min)) + (forward-line (1- line)) + (move-to-column (1- column)) + (point))) + +(defun web-mode-is-single-line-block (pos) + (= (web-mode-line-number (web-mode-block-beginning-position pos)) + (web-mode-line-number (web-mode-block-end-position pos)))) + +(defun web-mode-line-number (&optional pos) + (setq pos (or pos (point))) + (+ (count-lines 1 pos) (if (= (web-mode-column-at-pos pos) 0) 1 0))) + +(defun web-mode-block-is-control (pos) + (save-excursion + (let (control state controls pair) + (goto-char pos) + (setq controls (web-mode-block-controls-get pos)) + (setq pair (car controls)) + (cond + ((eq (car pair) 'inside) + ) + ((eq (car pair) 'open) + (setq state t + control (cdr pair))) + ((eq (car pair) 'close) + (setq state nil + control (cdr pair))) + ) ;cond + ;; (message "engine=%S control=%S state=%S" web-mode-engine control state) + (if control (cons control state) nil) + ))) + +(defun web-mode-block-is-opening-control (pos) + (save-excursion + (let (controls pair) + (goto-char pos) + (if (and (setq controls (web-mode-block-controls-get pos)) + (= (length controls) 1) + (setq pair (car controls)) + (eq (car pair) 'open)) + (cdr pair) + nil) + ))) + +(defun web-mode-markup-indentation-origin (pos jsx-depth) + (save-excursion + (let* ((found (bobp)) + (jsx-beg nil) + (types '(start end void)) + (type nil)) + (when jsx-depth + (setq jsx-beg (web-mode-jsx-depth-beginning-position pos jsx-depth))) + (while (not found) + (forward-line -1) + (if (bobp) + (setq pos (point) + found t) + (back-to-indentation) + (when (and jsx-beg (< (point) jsx-beg)) + (goto-char jsx-beg)) + (setq pos (point)) + (setq type (get-text-property pos 'tag-type)) + (setq found (or (and (null jsx-depth) + (null (get-text-property pos 'part-side)) + (get-text-property pos 'tag-beg) + (member type types) + (null (get-text-property (1- pos) 'invisible))) + (and (null jsx-depth) + (null (get-text-property pos 'part-side)) + (eq (get-text-property pos 'tag-type) 'comment) + (web-mode-looking-at-p "<!--#\\(endif\\|if\\)" pos) + (null (get-text-property (1- pos) 'invisible))) + (and jsx-depth + (get-text-property pos 'tag-beg) + (member type types) + (null (get-text-property (1- pos) 'invisible)) + (eq (get-text-property pos 'jsx-depth) jsx-depth)) + (and (get-text-property pos 'block-beg) + (not type) + (web-mode-block-is-control pos) + (not (looking-at-p "{% commen\\|@break"))))) + ) ;if + ) ;while + ;;(message "indent-origin=%S" pos) + pos))) + +;;TODO : prendre en compte part-token +;; state=t <=> start tag +(defun web-mode-element-is-opened (pos limit) + (let (tag + last-end-tag + tag-pos block-pos + state + n + ret + (continue t) + controls + control + (buffer (current-buffer)) + (h (make-hash-table :test 'equal)) + (h2 (make-hash-table :test 'equal))) + +;; (message "pos-ori=%S limit=%S" pos limit) + + (while continue + (setq control nil + controls nil + last-end-tag nil + tag nil) + + (cond + ((and (eq (get-text-property pos 'tag-type) 'comment) + (web-mode-looking-at "<!--#\\(endif\\|if\\)" pos)) + ;;(message "pos=%S" pos) + (setq tag "#if") + (setq n (gethash tag h 0)) + (if (string= (match-string-no-properties 1) "if") + (puthash tag (1+ n) h) + (puthash tag (1- n) h)) + ;;(setq tag-pos pos) + ) + ((get-text-property pos 'tag-beg) + (when (member (get-text-property pos 'tag-type) '(start end)) + (setq tag (get-text-property pos 'tag-name) + state (eq (get-text-property pos 'tag-type) 'start)) + (if (null state) (setq last-end-tag (cons tag pos))) + (setq n (gethash tag h 0)) + (cond + ((null state) + (when (> n 0) (puthash tag (1- n) h)) + (puthash tag (1- n) h2)) + ((member tag web-mode-offsetless-elements) + ) + (t + (puthash tag (1+ n) h) + (puthash tag (1+ n) h2)) + ) ;cond + ) ;when + (when (setq pos (web-mode-tag-end-position pos)) + (setq tag-pos nil) + (when (and block-pos (> pos block-pos)) + (setq block-pos nil)) + ) ;when + ) + ((and web-mode-enable-control-block-indentation + (get-text-property pos 'block-beg)) + (when (setq controls (web-mode-block-controls-get pos)) + (dolist (control controls) + (setq tag (cdr control)) + (setq n (gethash tag h 0)) + (cond + ((eq (car control) 'inside) + ) + ((eq (car control) 'open) + (puthash tag (1+ n) h)) + ((> n 0) + (puthash tag (1- n) h)) + ) ;cond + ) ;dolist + ) + (when (setq pos (web-mode-block-end-position pos)) + (setq block-pos nil) + (when (and tag-pos (> pos tag-pos)) + (setq tag-pos nil)) + ) + ) + ) ;cond + +;; (message "tag=%S end-pos=%S" tag pos) + + (when (and pos (< pos limit)) + (when (or (null tag-pos) (>= pos tag-pos)) + (setq tag-pos (web-mode-tag-next-position pos limit)) +;; (message "from=%S tag-next-pos=%S" pos tag-pos) + ) + (when (or (null block-pos) (>= pos block-pos)) + (setq block-pos (web-mode-block-next-position pos limit)) +;; (message "from=%S block-next-pos=%S" pos block-pos) + ) + ) + + (cond + ((null pos) + ) + ((and (null tag-pos) + (null block-pos)) + (setq pos nil)) + ((and tag-pos block-pos) + (if (< tag-pos block-pos) + (progn + (setq pos tag-pos) + (setq tag-pos nil)) + (setq pos block-pos) + (setq block-pos nil)) + ) + ((null tag-pos) + (setq pos block-pos) + (setq block-pos nil)) + (t + (setq pos tag-pos) + (setq tag-pos nil)) + ) + + (when (or (null pos) + (>= pos limit)) + (setq continue nil)) + ) ;while + + ;;(message "hashtable=%S" h) + (maphash (lambda (k v) (if (> v 0) (setq ret t))) h) + + (when (and (null ret) + last-end-tag + (> (hash-table-count h2) 1) + (< (gethash (car last-end-tag) h2) 0)) +;; (message "last-end-tag=%S" last-end-tag) + (save-excursion + (goto-char (cdr last-end-tag)) + (web-mode-tag-match) + (when (not (= (point) (cdr last-end-tag))) + (setq n (point)) + (back-to-indentation) + (if (= n (point)) (setq ret (current-indentation)))) + )) + + ret)) + +(defun web-mode-previous-line (pos limit) + (save-excursion + (let (beg end line (continue t)) + (goto-char pos) + (while continue + (forward-line -1) + (setq end (line-end-position)) + (setq line (buffer-substring-no-properties (point) end)) + (when (or (not (string-match-p "^[ \t]*$" line)) + (bobp) + (<= (point) limit)) + (setq continue nil)) + ) + (if (<= (point) limit) + ;;todo : affiner (le + 3 n est pas générique cf. <?php <% <%- etc.) + (setq beg (if (< (+ limit 3) end) (+ limit 3) end)) + (setq beg (line-beginning-position)) + ) ;if + (setq line (buffer-substring-no-properties beg end)) + (cons line (current-indentation)) + ))) + +(defun web-mode-bracket-up (pos language &optional limit) + (unless limit (setq limit nil)) + ;;(message "pos(%S) language(%S) limit(%S)" pos language limit) + (save-excursion + (goto-char pos) + (let ((continue t) + (regexp "[\]\[}{)(]") + (char nil) + (column nil) + (indentation nil) + (map nil) + (key nil) + (value 0) + (open '(?\( ?\{ ?\[)) + (searcher nil) + (opener nil)) + (cond + ((get-text-property pos 'block-side) + (setq searcher 'web-mode-block-rsb + opener 'web-mode-block-opening-paren-position)) + (t + (setq searcher 'web-mode-part-rsb + opener 'web-mode-part-opening-paren-position)) + ) + (while (and continue (funcall searcher regexp limit)) + (setq char (aref (match-string-no-properties 0) 0)) + (setq key (cond ((eq char ?\)) ?\() + ((eq char ?\}) ?\{) + ((eq char ?\]) ?\[) + (t char))) + (setq value (or (plist-get map key) 0)) + (setq value (if (member char open) (1+ value) (1- value))) + (setq map (plist-put map key value)) + (setq continue (< value 1)) + ;;(message "pos=%S char=%c key=%c value=%S map=%S" (point) char key value map) + ) ;while + (setq column (current-column) + indentation (current-indentation)) + (when (and (> value 0) + (eq char ?\{) + (looking-back ")[ ]*" (point-min))) + (search-backward ")") + (when (setq pos (funcall opener (point) limit)) + (goto-char pos) + ;;(message "pos=%S" pos) + (setq indentation (current-indentation))) + ) ;when + (list :pos (if (> value 0) (point) nil) + :char char + :column column + :indentation indentation) + ) ;let + )) + +(defun web-mode-count-char-in-string (char string) + (let ((n 0)) + (dotimes (i (length string)) + (if (eq (elt string i) char) + (setq n (1+ n)))) + n)) + +(defun web-mode-mark-and-expand () + "Mark and expand." + (interactive) + (web-mode-mark (point))) + +(defun web-mode-mark (pos) + (let ((beg pos) (end pos) prop reg-beg boundaries) + + (if mark-active + (setq reg-beg (region-beginning)) + (setq web-mode-expand-initial-pos (point) + web-mode-expand-initial-scroll (window-start)) + ) + + ;; (message "regs=%S %S %S %S" (region-beginning) (region-end) (point-min) (point-max)) + ;; (message "before=%S" web-mode-expand-previous-state) + + (cond + + ((and mark-active + (= (region-beginning) (point-min)) + (or (= (region-end) (point-max)) + (= (1+ (region-end)) (point-max)))) + (deactivate-mark) + (goto-char (or web-mode-expand-initial-pos (point-min))) + (setq web-mode-expand-previous-state nil) + (when web-mode-expand-initial-scroll + (set-window-start (selected-window) web-mode-expand-initial-scroll)) + ) + + ((string= web-mode-expand-previous-state "elt-content") + (web-mode-element-parent) + ;;(message "pos=%S" (point)) + (web-mode-element-select) + (setq web-mode-expand-previous-state "html-parent")) + + ((and (member (get-text-property pos 'block-token) '(comment string)) + (not (member web-mode-expand-previous-state '("block-token" "block-body" "block-side")))) + (when (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)) + (setq beg (or (previous-single-property-change pos 'block-token) (point-min)))) + (when (eq (get-text-property pos 'block-token) (get-text-property (1+ pos) 'block-token)) + (setq end (next-single-property-change pos 'block-token))) + (set-mark beg) + (goto-char end) + (exchange-point-and-mark) + (setq web-mode-expand-previous-state "block-token")) + + ((and (get-text-property pos 'block-side) + (not (member web-mode-expand-previous-state '("block-body" "block-side"))) + (not (member web-mode-engine '(django go))) + (setq boundaries (web-mode-in-code-block "{" "}" 'block-side))) + (set-mark (car boundaries)) + (goto-char (cdr boundaries)) + (exchange-point-and-mark) + (setq web-mode-expand-previous-state "block-body")) + + ((and (get-text-property pos 'block-side) + (not (member web-mode-expand-previous-state '("block-side")))) + (set-mark (web-mode-block-beginning-position pos)) + (goto-char (1+ (web-mode-block-end-position pos))) + (exchange-point-and-mark) + (setq web-mode-expand-previous-state "block-side")) + + ((and (get-text-property pos 'part-token) + (not (string= web-mode-expand-previous-state "part-token"))) + (when (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)) + (setq beg (previous-single-property-change pos 'part-token))) + (when (eq (get-text-property pos 'part-token) (get-text-property (1+ pos) 'part-token)) + (setq end (next-single-property-change pos 'part-token))) + (set-mark beg) + (goto-char end) + (exchange-point-and-mark) + (setq web-mode-expand-previous-state "part-token")) + + ((and (get-text-property pos 'part-side) + (not (string= web-mode-expand-previous-state "client-part")) + (setq boundaries (web-mode-in-code-block "{" "}" 'part-side))) + (set-mark (car boundaries)) + (goto-char (cdr boundaries)) + (exchange-point-and-mark) + (setq web-mode-expand-previous-state "client-part")) + + ((and (get-text-property pos 'part-side) + (not (string= web-mode-expand-previous-state "part-side"))) + (when (eq (get-text-property pos 'part-side) (get-text-property (1- pos) 'part-side)) + (setq beg (previous-single-property-change pos 'part-side))) + (when (eq (get-text-property pos 'part-side) (get-text-property (1+ pos) 'part-side)) + (setq end (next-single-property-change pos 'part-side))) + (when (eq (char-after beg) ?\n) + (setq beg (1+ beg))) + (set-mark beg) + (goto-char end) + (when (looking-back "^[ \t]+" (point-min)) + (beginning-of-line)) + (exchange-point-and-mark) + (setq web-mode-expand-previous-state "part-side")) + + ((and (get-text-property pos 'tag-attr) + (not (member web-mode-expand-previous-state '("html-attr" "html-tag")))) + (web-mode-attribute-select pos) + (setq web-mode-expand-previous-state "html-attr")) + + ((and (eq (get-text-property pos 'tag-type) 'comment) + (not (member web-mode-expand-previous-state '("html-tag" "html-comment" "html-elt" "html-parent")))) + (web-mode-tag-select) + (setq web-mode-expand-previous-state "html-comment")) + + ((and (get-text-property pos 'tag-name) + (not (member web-mode-expand-previous-state '("html-tag" "html-elt" "html-parent")))) + (web-mode-tag-select) + (setq web-mode-expand-previous-state "html-tag")) + + ((and (get-text-property pos 'tag-beg) + (string= web-mode-expand-previous-state "html-tag")) + (web-mode-element-select) + (setq web-mode-expand-previous-state "html-elt")) + + (t + (cond + ((not (web-mode-element-parent)) + (push-mark (point)) + (push-mark (point-max) nil t) + (goto-char (point-min)) + (setq web-mode-expand-previous-state "mark-whole")) + ((not (= (web-mode-tag-end-position (point)) (1- beg))) + (web-mode-element-content-select) + (setq web-mode-expand-previous-state "elt-content")) + (t + (web-mode-element-select) + (setq web-mode-expand-previous-state "html-parent")) + ) + ) ;t + + ) ;cond + + ;;(message "w=%S" (window-end)) + ;;(message "after=%S" web-mode-expand-previous-state) + + )) + +(defun web-mode-block-kill () + "Kill the current block." + (interactive) + (web-mode-block-select) + (when mark-active + (kill-region (region-beginning) (region-end)))) + +(defun web-mode-block-select () + "Select the current block." + (interactive) + (let (beg) + (when (setq beg (web-mode-block-beginning-position (point))) + (goto-char beg) + (set-mark (point)) + (web-mode-block-end) + (exchange-point-and-mark)) + beg)) + +(defun web-mode-tag-select () + "Select the current html tag." + (interactive) + (let (beg) + (when (setq beg (web-mode-tag-beginning-position (point))) + (goto-char beg) + (set-mark (point)) + (web-mode-tag-end) + (exchange-point-and-mark)) + beg)) + +(defun web-mode-element-content-select () + "Select the content of a html element." + (interactive) + (let (pos beg end) + (web-mode-element-select) + (when mark-active + (setq pos (point)) + (deactivate-mark) + (web-mode-tag-match) + (setq end (point)) + (goto-char pos) + (web-mode-tag-end) + (set-mark (point)) + (goto-char end) + (exchange-point-and-mark) + ))) + +(defun web-mode-element-select () + "Select the current html element (including opening and closing tags)." + (interactive) + (let* ((pos (point)) + (type (get-text-property pos 'tag-type))) + (cond + ((not type) + (web-mode-element-parent) + (unless (= (point) pos) (web-mode-element-select))) + ((member type '(start void)) + (web-mode-tag-beginning) + (set-mark (point)) + (web-mode-tag-match) + (web-mode-tag-end) + (exchange-point-and-mark)) + (t + (web-mode-tag-match) + (set-mark (point)) + (web-mode-tag-match) + (web-mode-tag-end) + (exchange-point-and-mark)) + ))) + +(defun web-mode-element-is-collapsed (&optional pos) + (unless pos (setq pos (point))) + (let (boundaries) + (and (setq boundaries (web-mode-element-boundaries pos)) + (or (= (car (car boundaries)) (car (cdr boundaries))) + (= (cdr (car boundaries)) (1- (car (cdr boundaries))))) + ))) + +(defun web-mode-element-contract () + "Flatten elements." + (interactive) + (let (beg end (continue t) replacement boundaries) + (cond + ((or (not (get-text-property (point) 'tag-type)) + (not (member (get-text-property (point) 'tag-type) '(start end)))) + (web-mode-element-parent)) + ((eq (get-text-property (point) 'tag-type) 'end) + (web-mode-tag-match)) + ) ;cond + (setq boundaries (web-mode-element-boundaries (point))) + (setq beg (car (car boundaries)) + end (cdr (cdr boundaries))) + (goto-char beg) + ;;(message "beg(%S) end(%S)" beg end) + (while continue + (if (or (not (re-search-forward ">[ \t\r\n]+\\|[ \t\r\n]+<")) + (>= (point) end)) + (setq continue nil) + (setq end (+ (- end (length (match-string-no-properties 0))) 1)) + (setq replacement (if (eq (char-before) ?\<) "<" ">")) + (replace-match replacement nil nil) + ;;(message "end(%S)" end)) + ) + ) ;while + (goto-char beg) + )) + +(defun web-mode-element-extract () + "Flatten element." + (interactive) + (let (beg end (continue t) save boundaries) + (cond + ((or (not (get-text-property (point) 'tag-type)) + (not (member (get-text-property (point) 'tag-type) '(start end)))) + (web-mode-element-parent)) + ((eq (get-text-property (point) 'tag-type) 'end) + (web-mode-tag-match)) + ) ;cond + (setq boundaries (web-mode-element-boundaries (point))) + (setq beg (car (car boundaries)) + end (cdr (cdr boundaries))) + (goto-char beg) + (while continue + (if (or (not (and (or (get-text-property (point) 'tag-type) (web-mode-tag-next)) + (web-mode-tag-end))) + (>= (point) end)) + (setq continue nil) + (setq save (point)) + ;;(message "point(%S)" (point)) + (skip-chars-forward "\n\t ") + (when (get-text-property (point) 'tag-type) + (newline) + (indent-according-to-mode) + (setq end (+ end (- (point) save)))) + ) ;if + ) ;while + (goto-char beg) + )) + +(defun web-mode-element-transpose () + "Transpose two html elements." + (interactive) + (let (pos start1 end1 start2 end2) + (save-excursion + (setq pos (point)) + (cond + ((get-text-property pos 'tag-type) + (setq start1 (web-mode-element-beginning-position pos) + end1 (1+ (web-mode-element-end-position pos))) + ) + ((setq start1 (web-mode-element-parent-position pos)) + (setq end1 (1+ (web-mode-element-end-position pos))) + ) + ) ;cond + (when (and start1 end1 (> end1 0)) + (goto-char end1) + (unless (get-text-property (point) 'tag-beg) + (skip-chars-forward "\n\t ")) + (when (get-text-property (point) 'tag-beg) + (setq start2 (web-mode-element-beginning-position (point)) + end2 (1+ (web-mode-element-end-position (point)))) + ) + ) + (transpose-regions start1 end1 start2 end2) + ) ;save-excursion + start2)) + +(defun web-mode-element-children-comment (&optional pos) + "Comment all the children of the current html element." + (interactive) + (unless pos (setq pos (point))) + (save-excursion + (dolist (child (reverse (web-mode-element-children pos))) + (goto-char child) + (web-mode-comment (point))) + )) + +(defun web-mode-element-mute-blanks () + "Mute blanks." + (interactive) + (let (pos parent beg end children elt) + (setq pos (point)) + (save-excursion + (when (and (setq parent (web-mode-element-boundaries pos)) + (web-mode-element-child-position (point))) + (setq children (reverse (web-mode-element-children))) + (goto-char (car (cdr parent))) + (dolist (child children) + (setq elt (web-mode-element-boundaries child)) + (when (> (point) (1+ (cddr elt))) + (when (and (not (eq (get-text-property (point) 'part-token) 'comment)) + (not (eq (get-text-property (1+ (cddr elt)) 'part-token) 'comment))) + (web-mode-insert-text-at-pos "-->" (point)) + (web-mode-insert-text-at-pos "<!--" (1+ (cddr elt)))) + ) + (goto-char child) + ) + (when (and (> (point) (1+ (cdr (car parent)))) + (not (eq (get-text-property (point) 'part-token) 'comment)) + (not (eq (get-text-property (1+ (cdr (car parent))) 'part-token) 'comment))) + (web-mode-insert-text-at-pos "-->" (point)) + (web-mode-insert-text-at-pos "<!--" (1+ (cdr (car parent))))) + ) ;when + ))) + +(defun web-mode-element-children (&optional pos) + (unless pos (setq pos (point))) + (let ((continue t) (i 0) child children) + (save-excursion + (when (and (member (get-text-property pos 'tag-type) '(start end)) + (setq child (web-mode-element-child-position pos))) + (while continue + (cond + ((> (setq i (1+ i)) 100) + (setq continue nil) + (message "element-children ** warning **")) + ((= i 1) + (goto-char child)) + ((web-mode-element-sibling-next) + ) + (t + (setq continue nil)) + ) ;cond + (when continue + (setq children (append children (list (point))))) + ) ;while + ) ;when + ) ;save-excursion + ;;(message "%S" children) + children)) + +(defun web-mode-property-boundaries (prop &optional pos) + "property boundaries (cdr is 1+)" + (unless pos (setq pos (point))) + (let (beg end val) + (setq val (get-text-property pos prop)) + (if (null val) + val + (if (or (bobp) + (not (eq (get-text-property (1- pos) prop) val))) + (setq beg pos) + (setq beg (previous-single-property-change pos prop)) + (when (null beg) (setq beg (point-min)))) + (if (or (eobp) + (not (eq (get-text-property (1+ pos) prop) val))) + (setq end pos) + (setq end (next-single-property-change pos prop)) + (when (null end) (setq end (point-min)))) + (cons beg end)))) + +(defun web-mode-content-boundaries (&optional pos) + (unless pos (setq pos (point))) + (let (beg end) + (setq beg (or (previous-property-change pos (current-buffer)) + (point-max))) + (setq end (or (next-property-change pos (current-buffer)) + (point-min))) + (while (and (< beg end) (member (char-after beg) '(?\s ?\n))) + (setq beg (1+ beg))) + (while (and (> end beg) (member (char-after (1- end)) '(?\s ?\n))) + (setq end (1- end))) +;; (message "beg(%S) end(%S)" beg end) + (cons beg end) + )) + +(defun web-mode-element-boundaries (&optional pos) + "Return ((start-tag-beg . start-tag-end) . (end-tag-beg . end-tag-end)) +First level car and cdr are the same with void elements. +Pos should be in a tag." + (unless pos (setq pos (point))) + (let (start-tag-beg start-tag-end end-tag-beg end-tag-end) + (cond + ((eq (get-text-property pos 'tag-type) 'start) + (setq start-tag-beg (web-mode-tag-beginning-position pos) + start-tag-end (web-mode-tag-end-position pos)) + (when (setq pos (web-mode-tag-match-position pos)) + (setq end-tag-beg pos + end-tag-end (web-mode-tag-end-position pos))) + ) + ((eq (get-text-property pos 'tag-type) 'end) + (setq end-tag-beg (web-mode-tag-beginning-position pos) + end-tag-end (web-mode-tag-end-position pos)) + (when (setq pos (web-mode-tag-match-position pos)) + (setq start-tag-beg pos + start-tag-end (web-mode-tag-end-position pos))) + ) + ((eq (get-text-property pos 'tag-type) 'void) + (setq start-tag-beg (web-mode-tag-beginning-position pos) + start-tag-end (web-mode-tag-end-position pos)) + (setq end-tag-beg start-tag-beg + end-tag-end start-tag-end) + ) + ) ;cond + (if (and start-tag-beg start-tag-end end-tag-beg end-tag-end) + (cons (cons start-tag-beg start-tag-end) (cons end-tag-beg end-tag-end)) + nil) + )) + +(defun web-mode-surround () + "Surround each line of the current REGION with a start/end tag." + (interactive) + (when mark-active + (let (beg end line-beg line-end pos tag tag-start tag-end) + (save-excursion + (combine-after-change-calls + (setq tag (web-mode-element-complete) + tag-start (concat "<" tag ">") + tag-end (concat "</" tag ">") + pos (point) + beg (region-beginning) + end (region-end) + line-beg (web-mode-line-number beg) + line-end (web-mode-line-number end)) + (goto-char end) + (unless (bolp) + (insert tag-end) + (back-to-indentation) + (when (> beg (point)) + (goto-char beg)) + (insert tag-start)) + (while (> line-end line-beg) + (forward-line -1) + (setq line-end (1- line-end)) + (unless (looking-at-p "[[:space:]]*$") + (end-of-line) + (insert tag-end) + (back-to-indentation) + (when (> beg (point)) + (goto-char beg)) + (insert tag-start)) + ) ;while + (deactivate-mark) + ) ;combine-after-change-calls + ) ;save-excursion + ))) + +(defun web-mode-lify-region () + "Transform current REGION in an html list (<li>line1</li>...)" + (interactive) + (let (beg end lines) + (save-excursion + (combine-after-change-calls + (when mark-active + (setq beg (region-beginning) + end (region-end)) + (setq lines (buffer-substring beg end)) + (kill-region beg end) + (setq lines (replace-regexp-in-string "^[ \t]*" "<li>" lines)) + (setq lines (replace-regexp-in-string "$" "</li>" lines)) + (web-mode-insert-and-indent lines) + ) ;when + ) ;combine-after-change-calls + ) ;save-excursion + ) ;let + ) + +(defun web-mode-element-complete (&optional prompt) + "Completes for an element tag." + (completing-read + (or prompt "Tag name: ") + (append + web-mode-tag-list + web-mode-tag-history) + nil nil nil 'web-mode-tag-history)) + +(defun web-mode-element-wrap (&optional tag-name) + "Wrap current REGION with start and end tags. +Prompt user if TAG-NAME isn't provided." + (interactive) + (let (beg end pos tag sep) + (save-excursion + (setq tag (or tag-name (web-mode-element-complete))) + (setq pos (point)) + (cond + (mark-active + (setq beg (region-beginning) + end (region-end))) + ((get-text-property pos 'tag-type) + (setq beg (web-mode-element-beginning-position pos) + end (1+ (web-mode-element-end-position pos)))) + ((setq beg (web-mode-element-parent-position pos)) + (setq end (1+ (web-mode-element-end-position pos)))) + ) + ;; (message "beg(%S) end(%S)" beg end) + (when (and beg end (> end 0)) + (setq sep (if (get-text-property beg 'tag-beg) "\n" "")) + (web-mode-insert-text-at-pos (concat sep "</" tag ">") end) + (web-mode-insert-text-at-pos (concat "<" tag ">" sep) beg) + (when (string= sep "\n") (indent-region beg (+ end (* (+ 3 (length tag)) 2)))) + ) + ) ;save-excursion + (web-mode-go beg))) + +(defun web-mode-element-vanish (&optional arg) + "Vanish the current html element. The content of the element is kept." + (interactive "p") + (let (type (pos (point)) start-b start-e end-b end-e) + (while (>= arg 1) + (setq type (get-text-property pos 'tag-type)) + (when type + (cond + ((member type '(void)) + (web-mode-element-kill) + (set-mark (point)) + (web-mode-tag-match) + (web-mode-tag-end) + (exchange-point-and-mark)) + ((member type '(start)) + (setq start-b (web-mode-tag-beginning-position) + start-e (web-mode-tag-end-position)) + (when (web-mode-tag-match) + (setq end-b (web-mode-tag-beginning-position) + end-e (web-mode-tag-end-position))) + ) + (t + (setq end-b (web-mode-tag-beginning-position) + end-e (web-mode-tag-end-position)) + (when (web-mode-tag-match) + (setq start-b (web-mode-tag-beginning-position) + start-e (web-mode-tag-end-position))) + ) ;t + ) ;cond + (when (and start-b end-b) + (goto-char end-b) + (delete-region end-b (1+ end-e)) + (delete-blank-lines) + (goto-char start-b) + (delete-region start-b (1+ start-e)) + (delete-blank-lines) + (web-mode-buffer-indent) + ) + ;; (message "start %S %S - end %S %S" start-b start-e end-b end-e)) + ) ;when + (skip-chars-forward "[:space:]\n") + (setq arg (1- arg)) + ) ;while + ) ;let + ) + +(defun web-mode-element-kill (&optional arg) + "Kill the current html element." + (interactive "p") + (while (>= arg 1) + (setq arg (1- arg)) + (web-mode-element-select) + (when mark-active + (kill-region (region-beginning) (region-end))) + ) ;while + ) + +(defun web-mode-element-clone (&optional arg) + "Clone the current html element." + (interactive "p") + (let (col pos) + (while (>= arg 1) + (setq arg (1- arg) + col 0) + (web-mode-element-select) + (when mark-active + (save-excursion + (goto-char (region-beginning)) + (setq col (current-column))) + (kill-region (region-beginning) (region-end)) + (yank) + (newline) + (indent-line-to col) + (setq pos (point)) + (yank) + (goto-char pos)) + ) + ) ;let + ) + +(defun web-mode-element-insert () + "Insert an html element." + (interactive) + (let (tag-name) + (cond + ((and (get-text-property (point) 'tag-type) + (not (get-text-property (point) 'tag-beg))) + (message "element-insert ** invalid context **")) + ((not (and (setq tag-name (web-mode-element-complete)) + (> (length tag-name) 0))) + (message "element-insert ** failure **")) + ((web-mode-element-is-void tag-name) + (insert (concat "<" (replace-regexp-in-string "/" "" tag-name) "/>")) + ) + (mark-active + (let ((beg (region-beginning)) (end (region-end))) + (deactivate-mark) + (goto-char end) + (insert "</" tag-name ">") + (goto-char beg) + (insert "<" tag-name ">") + ) + ) + (t + (insert (concat "<" tag-name ">" "</" tag-name ">")) + (web-mode-sb "</") + ) + ) ;cond + )) + +(defun web-mode-element-insert-at-point () + "Replace the word at point with a html tag of it." + (interactive) + (let ((tag-name (thing-at-point 'word))) + (cond + ((web-mode-element-is-void tag-name) + (backward-kill-word 1) + (insert (concat "<" (replace-regexp-in-string "/" "" tag-name) "/>")) + ) + (mark-active + (setq tag-name (buffer-substring (region-beginning) (region-end))) + (delete-region (region-beginning) (region-end)) + (insert (concat "<" tag-name ">" "</" tag-name ">")) + (web-mode-sb "</") + ) + (tag-name ; do nothing is there isn's word at point + (backward-kill-word 1) + (insert (concat "<" tag-name ">" "</" tag-name ">")) + (web-mode-sb "</") + ) + ) ;cond + )) + +(defun web-mode-element-rename (&optional tag-name) + "Rename the current html element." + (interactive) + (save-excursion + (let (pos) + (unless tag-name (setq tag-name (web-mode-element-complete "New tag name: "))) + (when (and (> (length tag-name) 0) + (web-mode-element-beginning) + (looking-at "<\\([[:alnum:]]+\\(:?[[:alpha:]_-]+\\)?\\)")) + (setq pos (point)) + (unless (web-mode-element-is-void) + (save-match-data + (web-mode-tag-match) + (if (looking-at "</[ ]*\\([[:alnum:]]+\\(:?[[:alpha:]_-]+\\)?\\)") + (replace-match (concat "</" tag-name)) + ))) + (goto-char pos) + (replace-match (concat "<" tag-name)) + )))) + +(defun web-mode-current-trimmed-line () + (web-mode-trim (buffer-substring-no-properties + (line-beginning-position) + (line-end-position)))) + +(defun web-mode-trim (string) + (replace-regexp-in-string "\\`[ \t\n]*" "" (replace-regexp-in-string "[ \t\n]*\\'" "" string))) + +(defun web-mode-is-token-end (pos) + (let (block-token part-token) + (setq block-token (get-text-property pos 'block-token)) + (setq part-token (get-text-property pos 'part-token)) + (cond + ((not (or block-token part-token)) + nil) + ((>= (1+ pos) (point-max)) + t) + ((and block-token + (not (string= (get-text-property (1+ pos) 'block-token) block-token))) + t) + ((and part-token + (not (string= (get-text-property (1+ pos) 'part-token) part-token))) + t) + (t + nil) + ) ;cond + )) + +(defun web-mode-block-is-token-line () + (save-excursion + (let ((continue t) (counter 0)) + (beginning-of-line) + (back-to-indentation) + (while (and continue (not (eolp))) + (cond + ((get-text-property (point) 'block-token) + (setq counter (1+ counter))) + ((not (member (following-char) '(?\s ?\t))) + (setq continue nil + counter 0)) + ) ;cond + (forward-char) + ) ;while + (> counter 0) + ))) + +(defun web-mode-part-is-token-line (pos) + (save-excursion + (let ((continue t) + (counter 0)) + (goto-char pos) + (setq continue (not (eolp))) + (while continue + (forward-char) + (cond + ((eolp) + (setq continue nil)) + ((or (get-text-property (point) 'block-side) + (member (get-text-property (point) 'part-token) '(comment string))) + (setq counter (1+ counter))) + ((not (member (following-char) '(?\s ?\t))) + (setq continue nil + counter 0)) + ) + ) ;while + (> counter 0)))) + +(defun web-mode-is-content (&optional pos) + (unless pos (setq pos (point))) + (not (or (get-text-property pos 'part-side) + (get-text-property pos 'tag-type) + (get-text-property pos 'block-side) + ))) + +(defun web-mode-is-comment-or-string (&optional pos) + (unless pos (setq pos (point))) + (not (null (or (eq (get-text-property pos 'tag-type) 'comment) + (member (get-text-property pos 'block-token) '(comment string)) + (member (get-text-property pos 'part-token) '(comment string)))))) + +;; NOTE: we look at the firt one +(defun web-mode-block-is-open (&optional pos) + (unless pos (setq pos (point)))) + +;; NOTE: we look at the last one +(defun web-mode-block-is-close (&optional pos) + (unless pos (setq pos (point))) + (and (get-text-property pos 'block-side) + (eq (caar (web-mode-block-controls-get pos)) 'close))) + +;; NOTE: we look at the first one +(defun web-mode-block-is-inside (&optional pos) + (unless pos (setq pos (point))) + (and (get-text-property pos 'block-side) + (eq (caar (web-mode-block-controls-get pos)) 'inside))) + +(defun web-mode-element-is-void (&optional tag) + (cond + ((and (not tag) (eq (get-text-property (point) 'tag-type) 'void)) + t) + ((and tag (member tag '("div" "li" "a" "p" "h1" "h2" "h3" "ul" "span" "article" "section" "td" "tr"))) + nil) + ((and tag (string-suffix-p "/" tag)) + t) + ((and tag (string= web-mode-content-type "jsx")) + (member (downcase tag) '("img" "br" "hr"))) + (tag + (car (member (downcase tag) web-mode-void-elements))) + (t + nil) + )) + +;;---- COMMENT ------------------------------------------------------------------ + +(defun web-mode-toggle-comments () + "Toggle comments visbility." + (interactive) + (web-mode-with-silent-modifications + (save-excursion + (if web-mode-comments-invisible + (remove-overlays)) + (setq web-mode-comments-invisible (null web-mode-comments-invisible)) + (let ((continue t) + (pos (point-min)) + (visibility web-mode-comments-invisible) + overlay end) + (while continue + (setq pos (next-single-property-change pos 'font-lock-face)) + (if (null pos) + (setq continue nil) + (when (eq (get-text-property pos 'font-lock-face) 'web-mode-comment-face) + (setq end (next-single-property-change pos 'font-lock-face)) + (put-text-property pos end 'invisible visibility) + (when visibility + (setq overlay (make-overlay pos end))) + (goto-char pos) + ) + ) + ) + ) ;let + ))) + +(defun web-mode-comment-or-uncomment-region (beg end &optional arg) + (interactive) + (save-excursion + (push-mark end) + (goto-char beg) + (setq mark-active t) + (web-mode-comment-or-uncomment) + (pop-mark))) + +(defun web-mode-comment-or-uncomment () + "Comment or uncomment line(s), block or region at POS." + (interactive) + ;; TODO : if mark is at eol, mark-- + (if (and (not mark-active) (looking-at-p "[[:space:]]*$")) + (web-mode-comment-insert) + (when (and (use-region-p) (eq (point) (region-end))) + (if (bolp) (backward-char)) + (exchange-point-and-mark)) + (if (eq (get-text-property (point) 'block-token) 'delimiter-beg) + (web-mode-block-skip-blank-forward (point) '(delimiter-beg)) + (skip-chars-forward "[:space:]" (line-end-position))) + (cond + ;; #1147 + ((and (get-text-property (point) 'jsx-beg) + (eq (get-text-property (1+ (point)) 'part-token) 'comment)) + (web-mode-uncomment (1+ (point)))) + ((or (eq (get-text-property (point) 'tag-type) 'comment) + (eq (get-text-property (point) 'block-token) 'comment) + (eq (get-text-property (point) 'part-token) 'comment)) + (web-mode-uncomment (point))) + (t + (web-mode-comment (point))) + ) + ) ;if + ) + +(defun web-mode-comment-indent-new-line (&optional soft) + (interactive) + (let (ctx) + (setq ctx (web-mode-comment-context)) + (cond + ((null ctx) + (newline 1)) + (t + (newline 1) + (indent-line-to (plist-get ctx :col)) + (let ((prefix (plist-get ctx :prefix))) + (insert + (concat prefix + ;; Check if the comment ends with a space, and if not, insert one. + (if + (string-equal (substring prefix -1 (length prefix)) " ") + "" + " "))))) + ) ;cond + )) + +(defun web-mode-comment-context (&optional pos) + (cond + (pos + ) + ((and (eolp) (not (bobp))) + (setq pos (1- (point)))) + (t + (setq pos (point))) + ) ;cond + (let (beg col prefix type format) + (cond + ((eq (get-text-property pos 'block-token) 'comment) + (setq type "block")) + ((eq (get-text-property pos 'tag-type) 'comment) + (setq type "tag")) + ((eq (get-text-property pos 'part-token) 'comment) + (setq type "part")) + ) + (if (null type) nil + (save-excursion + (goto-char pos) + (web-mode-comment-beginning) + (setq beg (point) + col (current-column)) + (cond + ((looking-at-p "/\\*") + (setq format "/*" + prefix " * ")) + ((looking-at-p "//") + (setq format "//" + prefix "//")) + ((looking-at-p "#") + (setq format "#" + prefix "#")) + ((looking-at-p ";") + (setq format ";" + prefix ";")) + ((looking-at-p "''") + (setq format "''" + prefix "''")) + ) ;cond + (list :beg beg :col col :prefix prefix :type type :format format))))) + +(defun web-mode-comment-insert () + (let ((alt nil) (language nil) (pos (point))) + (setq language (web-mode-language-at-pos pos)) + (setq alt (cdr (assoc language web-mode-comment-formats))) + ;;(message "language=%S" language) + (cond + ((get-text-property pos 'block-side) + (cond + ((and alt (string= alt "//")) + (insert "// ")) + (t + (insert "/* */") + (search-backward " */")) + ) ;cond + ) ;case block-side + ((get-text-property pos 'part-side) + (cond + ((and alt (string= alt "//")) + (insert "// ")) + (t + (insert "/* */") + (search-backward " */")) + ) ;cond + ) ;case part-side + (t + (insert "<!-- -->") + (search-backward " -->") + ) ;case html + ) ;cond + )) + +(defun web-mode-comment (pos) + (let (ctx language col sel beg end tmp block-side single-line-block pos-after content) + + (setq pos-after pos) + + (setq block-side (get-text-property pos 'block-side)) + (setq single-line-block (web-mode-is-single-line-block pos)) + + (cond + + ((and block-side (string= web-mode-engine "erb")) + (web-mode-comment-erb-block pos) + ) + + ((and block-side (string= web-mode-engine "artanis")) + (web-mode-comment-artanis-block pos) + ) + + ((and single-line-block block-side + (intern-soft (concat "web-mode-comment-" web-mode-engine "-block"))) + (funcall (intern (concat "web-mode-comment-" web-mode-engine "-block")) pos) + ) + + (t + (setq ctx (web-mode-point-context + (if mark-active (region-beginning) (line-beginning-position)))) + ;;(message "%S" ctx) + (setq language (plist-get ctx :language)) + (setq col (current-column)) + (cond + (mark-active + ;;(message "%S %S" (point) col) + ) + ((and (member language '("html" "xml")) + (get-text-property (progn (back-to-indentation) (point)) 'tag-beg)) + (web-mode-element-select)) + (t + (end-of-line) + (set-mark (line-beginning-position))) + ) ;cond + + (setq beg (region-beginning) + end (region-end)) + + (when (> (point) (mark)) + (exchange-point-and-mark)) + + (if (and (eq (char-before end) ?\n) + (not (eq (char-after end) ?\n))) + (setq end (1- end))) + + (setq sel (buffer-substring-no-properties beg end)) + + (cond + + ((member language '("html" "xml")) + (cond + ((and (= web-mode-comment-style 2) (string= web-mode-engine "django")) + (setq content (concat "{# " sel " #}"))) + ((and (= web-mode-comment-style 2) (member web-mode-engine '("ejs" "erb"))) + (setq content (concat "<%# " sel " %>"))) + ((and (= web-mode-comment-style 2) (string= web-mode-engine "artanis")) + (setq content (concat "<%; " sel " %>"))) + ((and (= web-mode-comment-style 2) (string= web-mode-engine "aspx")) + (setq content (concat "<%-- " sel " --%>"))) + ((and (= web-mode-comment-style 2) (string= web-mode-engine "smarty")) + (setq content (concat "{* " sel " *}"))) + ((and (= web-mode-comment-style 2) (string= web-mode-engine "expressionengine")) + (setq content (concat "{!-- " sel " --}"))) + ((and (= web-mode-comment-style 2) (string= web-mode-engine "xoops")) + (setq content (concat "<{* " sel " *}>"))) + ((and (= web-mode-comment-style 2) (string= web-mode-engine "hero")) + (setq content (concat "<%# " sel " %>"))) + ((and (= web-mode-comment-style 2) (string= web-mode-engine "blade")) + (setq content (concat "{{-- " sel " --}}"))) + ((and (= web-mode-comment-style 2) (string= web-mode-engine "ctemplate")) + (setq content (concat "{{!-- " sel " --}}"))) + ((and (= web-mode-comment-style 2) (string= web-mode-engine "razor")) + (setq content (concat "@* " sel " *@"))) + (t + (setq content (concat "<!-- " sel " -->")) + (when (< (length sel) 1) + (search-backward " -->") + (setq pos-after nil)) + )) + ) ;case html + + ((member language '("php" "javascript" "typescript" "java" "jsx")) + (let (alt) + (setq alt (cdr (assoc language web-mode-comment-formats))) + ;;(message "language=%S alt=%S sel=%S col=%S" language alt sel col) + (cond + ((and alt (string= alt "//")) + (setq content (replace-regexp-in-string (concat "\n[ ]\\{" (number-to-string col) "\\}") "\n" sel)) + (setq content (replace-regexp-in-string (concat "\n") "\n// " content)) + (setq content (concat "// " content))) + ((get-text-property pos 'jsx-depth) + (setq content (concat "{/* " sel " */}"))) + (web-mode-comment-prefixing + (setq content (replace-regexp-in-string (concat "\n[ ]\\{" (number-to-string col) "\\}") "\n* " sel)) + (setq content (concat "/* " content " */"))) + (t + (setq content (concat "/* " sel " */"))) + ) ;cond + ) ;let + ) + + ((member language '("erb")) + (setq content (replace-regexp-in-string "^[ ]*" "#" sel))) + + ((member language '("asp")) + (setq content (replace-regexp-in-string "^[ ]*" "''" sel))) + + (t + (setq content (concat "/* " sel " */"))) + + ) ;cond + + (when content + (delete-region beg end) + (deactivate-mark) + (let (beg end) + (setq beg (point-at-bol)) + (insert content) + (setq end (point-at-eol)) + (indent-region beg end) + ) + ) ;when + + ) ;t + ) ;cond + + (when pos-after (goto-char pos-after)) + + )) + +(defun web-mode-comment-ejs-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (web-mode-insert-text-at-pos "//" (+ beg 2)))) + +(defun web-mode-comment-erb-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (web-mode-insert-text-at-pos "#" (+ beg 2)))) + +(defun web-mode-comment-artanis-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (web-mode-insert-text-at-pos ";" (+ beg 2)))) + +(defun web-mode-comment-django-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (web-mode-insert-text-at-pos "#" end) + (web-mode-insert-text-at-pos "#" (1+ beg)))) + +(defun web-mode-comment-dust-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (web-mode-insert-text-at-pos "!" end) + (web-mode-insert-text-at-pos "!" (1+ beg)))) + +(defun web-mode-comment-aspx-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (web-mode-insert-text-at-pos "#" end) + (web-mode-insert-text-at-pos "#" (1+ beg)))) + +(defun web-mode-comment-jsp-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (web-mode-insert-text-at-pos "--" (+ beg 2)))) + +(defun web-mode-comment-go-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (web-mode-insert-text-at-pos "*/" (1- end)) + (web-mode-insert-text-at-pos "/*" (+ beg (if (web-mode-looking-at "{{" beg) 2 0))))) + +(defun web-mode-comment-php-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (web-mode-insert-text-at-pos "*/" (- end 2)) + (web-mode-insert-text-at-pos "/*" (+ beg 1 (if (web-mode-looking-at "<\\?php" beg) 5 3))))) + +(defun web-mode-comment-svelte-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (web-mode-insert-text-at-pos "!" end) + (web-mode-insert-text-at-pos "!" (1+ beg)))) + +(defun web-mode-comment-boundaries (&optional pos) + (interactive) + (unless pos (setq pos (point))) + (let ((beg pos) (end pos) prop) + (save-excursion + (goto-char pos) + (setq prop + (cond + ((eq (get-text-property pos 'block-token) 'comment) 'block-token) + ((eq (get-text-property pos 'tag-type) 'comment) 'tag-type) + ((eq (get-text-property pos 'part-token) 'comment) 'part-token) + (t nil) + )) + (if (null prop) + (setq beg nil + end nil) + (when (and (not (bobp)) + (eq (get-text-property pos prop) (get-text-property (1- pos) prop))) + (setq beg (or (previous-single-property-change pos prop) (point-min)))) + (when (and (not (eobp)) + (eq (get-text-property pos prop) (get-text-property (1+ pos) prop))) + (setq end (or (next-single-property-change pos prop) (point-max))))) + (message "beg(%S) end(%S) point-max(%S)" beg end (point-max)) + (when (and beg (string= (buffer-substring-no-properties beg (+ beg 2)) "//")) + (goto-char end) + (while (and (looking-at-p "\n[ ]*//") + (not (eobp))) + (search-forward "//") + (backward-char 2) + ;;(message "%S" (point)) + (setq end (next-single-property-change (point) prop)) + (goto-char end) + ;;(message "%S" (point)) + ) ;while + ) ;when + ;;(when end (setq end (1- end))) ;; #1021 + ) ;save-excursion + ;;(message "beg=%S end=%S" beg end) + (if (and beg end) (cons beg end) nil) + )) + +(defun web-mode-uncomment (pos) + (let ((beg pos) (end pos) (sub2 "") comment boundaries) + (save-excursion + (cond + ((and (get-text-property pos 'block-side) + (intern-soft (concat "web-mode-uncomment-" web-mode-engine "-block"))) + (funcall (intern (concat "web-mode-uncomment-" web-mode-engine "-block")) pos)) + ((and (setq boundaries (web-mode-comment-boundaries pos)) + (setq beg (car boundaries)) + (setq end (1+ (cdr boundaries))) + (> (- end beg) 4)) + (when (and (eq (get-text-property beg 'part-token) 'comment) + (> beg 1) ;#1158 + (get-text-property (1- beg) 'jsx-beg)) + (setq beg (1- beg) + end (1+ end))) + (setq comment (buffer-substring-no-properties beg end)) + (setq sub2 (substring comment 0 2)) + (cond + ((member sub2 '("<!" "<%")) + (setq comment (replace-regexp-in-string "\\(^<[!%]--[ ]?\\|[ ]?--[%]?>$\\)" "" comment))) + ((string= sub2 "{#") + (setq comment (replace-regexp-in-string "\\(^{#[ ]?\\|[ ]?#}$\\)" "" comment))) + ((string= sub2 "{/") ;jsx comments + (setq comment (replace-regexp-in-string "\\(^{/\\*[ ]?\\|[ ]?\\*/}$\\)" "" comment))) + ((string= sub2 "/*") + ;;(message "%S" comment) + ;;(setq comment (replace-regexp-in-string "\\(\\*/\\|^/\\*[ ]?\\|^[ \t]*\\*\\)" "" comment)) + (setq comment (replace-regexp-in-string "\\([ ]?\\*/$\\|^/\\*[ ]?\\)" "" comment)) + (setq comment (replace-regexp-in-string "\\(^[ \t]*\\*\\)" "" comment)) + ;;(message "%S" comment) + ) + ((string= sub2 "''") + (setq comment (replace-regexp-in-string "''" "" comment))) + ((string= sub2 "//") + (setq comment (replace-regexp-in-string "^ *//" "" comment))) + ) ;cond + (delete-region beg end) + (web-mode-insert-and-indent comment) + (goto-char beg) + ) + ) ;cond + (indent-according-to-mode) + ))) + +(defun web-mode-uncomment-erb-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (cond + ((string= (buffer-substring-no-properties beg (+ beg 4)) "<%#=") + (web-mode-remove-text-at-pos 1 (+ beg 2))) + ((string-match-p "<[%[:alpha:]]" (buffer-substring-no-properties (+ beg 2) (- end 2))) + (web-mode-remove-text-at-pos 2 (1- end)) + (web-mode-remove-text-at-pos 3 beg)) + (t + (web-mode-remove-text-at-pos 1 (+ beg 2))) + ) ;cond + ) + ) + +(defun web-mode-uncomment-artanis-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (cond + ((string= (buffer-substring-no-properties beg (+ beg 4)) "<%;=") + (web-mode-remove-text-at-pos 1 (+ beg 2))) + ((string-match-p "<[%[:alpha:]]" (buffer-substring-no-properties (+ beg 2) (- end 2))) + (web-mode-remove-text-at-pos 2 (1- end)) + (web-mode-remove-text-at-pos 3 beg)) + (t + (web-mode-remove-text-at-pos 1 (+ beg 2))) + ) ;cond + ) + ) + +(defun web-mode-uncomment-ejs-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (web-mode-remove-text-at-pos 1 (+ beg 2)))) + +(defun web-mode-uncomment-django-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (cond + ((web-mode-looking-at-p "{#[{%]" beg) + (web-mode-remove-text-at-pos 1 (1- end)) + (web-mode-remove-text-at-pos 1 (1+ beg)) + ) + (t + (web-mode-remove-text-at-pos 2 (1- end)) + (web-mode-remove-text-at-pos 2 beg)) + ) ;cond + )) + +(defun web-mode-uncomment-ctemplate-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (web-mode-remove-text-at-pos 5 (- end 4)) + (web-mode-remove-text-at-pos 5 beg))) + +(defun web-mode-uncomment-dust-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (web-mode-remove-text-at-pos 1 (1- end)) + (web-mode-remove-text-at-pos 1 (1+ beg)))) + +(defun web-mode-uncomment-aspx-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (web-mode-remove-text-at-pos 1 (1- end)) + (web-mode-remove-text-at-pos 1 (1+ beg)))) + +(defun web-mode-uncomment-jsp-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (web-mode-remove-text-at-pos 2 (+ beg 2)))) + +(defun web-mode-uncomment-go-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (web-mode-remove-text-at-pos 2 (+ beg 2)) + (web-mode-remove-text-at-pos 2 (- end 5)))) + +(defun web-mode-uncomment-svelte-block (pos) + (let (beg end) + (setq beg (web-mode-block-beginning-position pos) + end (web-mode-block-end-position pos)) + (web-mode-remove-text-at-pos 1 (1- end)) + (web-mode-remove-text-at-pos 1 (1+ beg)))) + +(defun web-mode-snippet-names () + (mapcar #'car web-mode-snippets)) + +(defun web-mode-snippet-insert (code) + "Insert a snippet." + (interactive + (list (completing-read "Snippet: " (web-mode-snippet-names)))) + (let (beg + (continue t) + (counter 0) + end + sel + snippet + (l (length web-mode-snippets)) + pos) + (when mark-active + (setq sel (web-mode-trim (buffer-substring-no-properties + (region-beginning) (region-end)))) + (delete-region (region-beginning) (region-end))) + (while (and continue (< counter l)) + (setq snippet (nth counter web-mode-snippets)) + (when (string= (car snippet) code) + (setq continue nil)) + (setq counter (1+ counter))) + (when snippet + (setq snippet (cdr snippet)) + (setq beg (point-at-bol)) + (insert snippet) + (setq pos (point) + end (point)) + (cond + ((string-match-p "¦" snippet) + (search-backward "¦") + (delete-char 1) + (setq pos (point) + end (1- end))) + ((string-match-p "|" snippet) + (search-backward "|") + (delete-char 1) + (setq pos (point) + end (1- end))) + ) ;cond + (when sel + (insert sel) + (setq pos (point) + end (+ end (length sel)))) + (goto-char end) + (setq end (point-at-eol)) + (unless sel (goto-char pos)) + (indent-region beg end)) + )) + +(defun web-mode-looking-at (regexp pos) + (save-excursion + (goto-char pos) + (looking-at regexp))) + +(defun web-mode-looking-at-p (regexp pos) + (save-excursion + (goto-char pos) + (looking-at-p regexp))) + +(defun web-mode-looking-back (regexp pos &optional limit greedy) + (save-excursion + (goto-char pos) + (if limit + (looking-back regexp limit greedy) + (looking-back regexp (point-min))))) + +(defun web-mode-insert-text-at-pos (text pos) + (let ((mem web-mode-enable-auto-pairing)) + (setq web-mode-enable-auto-pairing nil) + (save-excursion + (goto-char pos) + (insert text) + (setq web-mode-enable-auto-pairing mem) + ))) + +(defun web-mode-remove-text-at-pos (n &optional pos) + (unless pos (setq pos (point))) + (delete-region pos (+ pos n))) + +(defun web-mode-insert-and-indent (text) + (let (beg end) + (setq beg (point-at-bol)) + (insert text) + (setq end (point-at-eol)) + (indent-region beg end) + )) + +(defun web-mode-column-at-pos (pos) + (save-excursion + (goto-char pos) + (current-column))) + +(defun web-mode-indentation-at-pos (pos) + (save-excursion + (goto-char pos) + (current-indentation))) + +(defun web-mode-navigate (&optional pos) + "Move point to the matching opening/closing tag/block." + (interactive) + (unless pos (setq pos (point))) + (let (init) + (goto-char pos) + (setq init (point)) + (when (> (current-indentation) (current-column)) + (back-to-indentation)) + (setq pos (point)) + (cond + ((and (get-text-property pos 'block-side) + (web-mode-block-beginning) + (web-mode-block-controls-get (point))) + (web-mode-block-match)) + ((member (get-text-property pos 'tag-type) '(start end)) + (web-mode-tag-beginning) + (web-mode-tag-match)) + (t + (goto-char init)) + ) + )) + +(defun web-mode-block-match (&optional pos) + (unless pos (setq pos (point))) + (let (pos-ori controls control (counter 1) type (continue t) pair) + (setq pos-ori pos) + (goto-char pos) + (setq controls (web-mode-block-controls-get pos)) + ;;(message "controls=%S" controls) + (cond + (controls + (setq pair (car controls)) + (setq control (cdr pair)) + (setq type (car pair)) + (when (eq type 'inside) (setq type 'close)) + (while continue + (cond + ((and (> pos-ori 1) (bobp)) + (setq continue nil)) + ((or (and (eq type 'open) (not (web-mode-block-next))) + (and (eq type 'close) (not (web-mode-block-previous)))) + (setq continue nil) + ) + ((null (setq controls (web-mode-block-controls-get (point)))) + ) + (t + ;;TODO : est il nécessaire de faire un reverse sur controls si on doit matcher backward + (dolist (pair controls) + (cond + ((not (string= (cdr pair) control)) + ) + ((eq (car pair) 'inside) + ) + ((eq (car pair) type) + (setq counter (1+ counter))) + (t + (setq counter (1- counter))) + ) + ) ;dolist + (when (= counter 0) + (setq continue nil)) + ) ;t + ) ;cond + ) ;while + (if (= counter 0) (point) nil) + ) ;controls + (t + (goto-char pos-ori) + nil + ) ;controls = nul + ) ;conf + )) + +(defun web-mode-tag-match (&optional pos) + "Move point to the matching opening/closing tag." + (interactive) + (unless pos (setq pos (point))) + (let (regexp name) + (cond + ((eq (get-text-property pos 'tag-type) 'void) + (web-mode-tag-beginning)) + ((and (eq (get-text-property pos 'tag-type) 'comment) + (web-mode-looking-at-p "<!--#\\(elif\\|else\\|endif\\|if\\)" pos)) + (setq regexp "<!--#\\(end\\)?if") + (if (web-mode-looking-at-p "<!--#if" pos) + (web-mode-tag-fetch-closing regexp pos) + (web-mode-tag-fetch-opening regexp pos)) + ) + (t + (setq name (get-text-property pos 'tag-name)) + (when (string= name "_fragment_") (setq name ">")) + (setq regexp (concat "</?" name)) + (when (member (get-text-property pos 'tag-type) '(start end)) + (web-mode-tag-beginning) + (setq pos (point))) + (if (eq (get-text-property pos 'tag-type) 'end) + (web-mode-tag-fetch-opening regexp pos) + (web-mode-tag-fetch-closing regexp pos)) + ) ;t + ) ;cond + t)) + +(defun web-mode-tag-fetch-opening (regexp pos) + (let ((counter 1) (n 0) (is-comment nil) (types '(start end))) + (when (eq (aref regexp 1) ?\!) + (setq types '(comment) + is-comment t)) + (goto-char pos) + (while (and (> counter 0) (re-search-backward regexp nil t)) + (when (and (get-text-property (point) 'tag-beg) + (member (get-text-property (point) 'tag-type) types)) + (setq n (1+ n)) + (cond + ((and is-comment + (eq (aref (match-string-no-properties 0) 5) ?e)) + (setq counter (1+ counter))) + (is-comment + (setq counter (1- counter))) + ((eq (get-text-property (point) 'tag-type) 'end) + (setq counter (1+ counter))) + (t + (setq counter (1- counter)) + ) + ) + ) + ) + (if (= n 0) (goto-char pos)) + )) + +(defun web-mode-tag-fetch-closing (regexp pos) + (let ((counter 1) (is-comment nil) (n 0)) + (when (eq (aref regexp 1) ?\!) + (setq is-comment t)) + (goto-char pos) + (web-mode-tag-end) + (while (and (> counter 0) (re-search-forward regexp nil t)) + (when (get-text-property (match-beginning 0) 'tag-beg) + (setq n (1+ n)) + (cond + ((and is-comment + (eq (aref (match-string-no-properties 0) 5) ?e)) + (setq counter (1- counter))) + (is-comment + (setq counter (1+ counter))) + ((eq (get-text-property (point) 'tag-type) 'end) + (setq counter (1- counter))) + (t + (setq counter (1+ counter))) + ) + ) ;when + ) ;while + (if (> n 0) + (web-mode-tag-beginning) + (goto-char pos)) + )) + +(defun web-mode-element-tag-name (&optional pos) + (unless pos (setq pos (point))) + (save-excursion + (goto-char pos) + (if (and (web-mode-tag-beginning) + (looking-at web-mode-tag-regexp)) + (match-string-no-properties 1) + nil))) + +(defun web-mode-element-close () + "Close html element." + (interactive) + (let (jmp epp ins tag) + + (if (and (eq (char-before) ?\>) + (web-mode-element-is-void (get-text-property (1- (point)) 'tag-name))) + (unless (eq (char-before (1- (point))) ?\/) + (backward-char) + (insert "/") + (forward-char)) + (setq epp (web-mode-element-parent-position))) + + ;;(message "epp=%S" epp) + (when epp + (setq tag (get-text-property epp 'tag-name)) + (setq tag (web-mode-element-tag-name epp)) + ;;(message "tag=%S %c" tag (char-before)) + (cond + ((or (null tag) (web-mode-element-is-void tag)) + (setq epp nil)) + ((looking-back "</" (point-min)) + (setq ins tag)) + ((looking-back "<" (point-min)) + (setq ins (concat "/" tag))) + (t + ;;auto-close-style = 2 + ;;(message "%S %c" (point) (char-after)) + (when (and (looking-at-p "[[:alpha:]]") (> (length tag) 4)) + (dolist (elt '("div" "span" "strong" "pre" "li")) + (when (and (string-match-p (concat "^" elt) tag) (not (string= tag elt))) + (setq tag elt) + (put-text-property epp (point) 'tag-name tag)) + ) + ) ;when + (if (web-mode-element-is-void (get-text-property (point) 'tag-name)) + (setq ins nil + epp nil) + (setq ins (concat "</" tag))) + ) + ) ;cond + (when ins + (unless (looking-at-p "[ ]*>") + (setq ins (concat ins ">"))) + (insert ins) + (setq tag (downcase tag)) + (save-excursion + (search-backward "<") + (setq jmp (and (eq (char-before) ?\>) + (string= (get-text-property (1- (point)) 'tag-name) tag))) + (if jmp (setq jmp (point))) + ) ;save-excursion + (if jmp (goto-char jmp)) + ) ;when not ins + ) ;when epp + epp)) + +(defun web-mode-detect-content-type () + (cond + ((and (string= web-mode-engine "none") + (< (point) 16) + (eq (char-after 1) ?\#) + (string-match-p "php" (buffer-substring-no-properties + (line-beginning-position) + (line-end-position)))) + (web-mode-set-engine "php")) + ((and (string= web-mode-content-type "javascript") + (< (point) web-mode-chunk-length) + (eq (char-after (point-min)) ?\/) + (string-match-p "@jsx" (buffer-substring-no-properties + (line-beginning-position) + (line-end-position)))) + (web-mode-set-content-type "jsx")) + )) + +(defun web-mode-auto-complete () + "Autocomple at point." + (interactive) + (let ((pos (point)) + (char (char-before)) + (chunk (buffer-substring-no-properties (- (point) 2) (point))) + (expanders nil) (tag nil) + (auto-closed nil) + (auto-expanded nil) + (auto-paired nil) + (auto-quoted nil)) + + ;;-- auto-closing + (when web-mode-enable-auto-closing + + (cond + + ((and (= web-mode-auto-close-style 3) + (eq char ?\<)) + (insert "/>") + (backward-char 2) + (setq auto-closed t)) + + ((and (= web-mode-auto-close-style 3) + (eq char ?\>) + (looking-at-p "/>")) + (save-excursion + (re-search-backward web-mode-start-tag-regexp) + (setq tag (match-string-no-properties 1))) + (insert "<") + (forward-char) + (insert tag) + (setq auto-closed t)) + + ((and (>= pos 4) + (or (string= "</" chunk) + ;;(progn (message "%c" char) nil) + (and (= web-mode-auto-close-style 2) + (or (string= web-mode-content-type "jsx") + (not (get-text-property pos 'part-side))) + (string-match-p "[[:alnum:]'\"]>" chunk))) + (not (get-text-property (- pos 2) 'block-side)) + (web-mode-element-close)) + (setq auto-closed t)) + + ) ;cond + ) ;when + + ;;-- auto-pairing + (when (and web-mode-enable-auto-pairing + (>= pos 4) + (not auto-closed)) + (let ((i 0) expr after pos-end (l (length web-mode-auto-pairs))) + (setq pos-end (if (> (+ pos 32) (line-end-position)) + (line-end-position) + (+ pos 10))) + (setq chunk (buffer-substring-no-properties (- pos 3) pos) + after (buffer-substring-no-properties pos pos-end)) + (while (and (< i l) (not auto-paired)) + (setq expr (elt web-mode-auto-pairs i) + i (1+ i)) + ;;(message "chunk=%S expr=%S after=%S" chunk expr after) + (when (and (string= (car expr) chunk) + (not (string-match-p (regexp-quote (cdr expr)) after))) + (setq auto-paired t) + (insert (cdr expr)) + (if (string-match-p "|" (cdr expr)) + (progn + (search-backward "|") + (delete-char 1)) + (goto-char pos)) + ) ;when + ) ;while + ) ;let + ) + + ;;-- auto-expanding + (when (and web-mode-enable-auto-expanding + (not auto-closed) + (not auto-paired) + (eq char ?\/) + (looking-back "\\(^\\|[[:punct:][:space:]>]\\)./" (point-min)) + (or (web-mode-jsx-is-html (1- pos)) + (and (not (get-text-property (1- pos) 'tag-type)) + (not (get-text-property (1- pos) 'part-side)))) + (not (get-text-property (1- pos) 'block-side)) + ) + (setq expanders (append web-mode-extra-expanders web-mode-expanders)) + (let ((i 0) pair (l (length expanders))) + (setq chunk (buffer-substring-no-properties (- pos 2) pos)) + ;;(message "%S" chunk) + (while (and (< i l) (not auto-expanded)) + (setq pair (elt expanders i) + i (1+ i)) + (when (string= (car pair) chunk) + (setq auto-expanded t) + (delete-char -2) + (insert (cdr pair)) + (when (string-match-p "|" (cdr pair)) + (search-backward "|") + (delete-char 1)) + ) ;when + ) ;while + ) ;let + ) + + ;;-- auto-quoting + (when (and web-mode-enable-auto-quoting + (>= pos 4) + (not (get-text-property pos 'block-side)) + (not auto-closed) + (not auto-paired) + (not auto-expanded) + (get-text-property (- pos 2) 'tag-attr)) + (cond + ((and (eq char ?\=) + (not (looking-at-p "[ ]*[\"']"))) + (cond ((= web-mode-auto-quote-style 2) + (insert "''")) + ((= web-mode-auto-quote-style 3) + (insert "{}")) + (t + (insert "\"\""))) + (if (looking-at-p "[ \n>]") + (backward-char) + (insert " ") + (backward-char 2) + ) + (setq auto-quoted t)) + ((and (eq char ?\") + (looking-back "=[ ]*\"" (point-min)) + (not (looking-at-p "[ ]*[\"]"))) + (insert-and-inherit "\"") + (backward-char) + (setq auto-quoted t)) + ((and (eq char ?\') + (looking-back "=[ ]*'" (point-min)) + (not (looking-at-p "[ ]*[']"))) + (insert-and-inherit "'") + (backward-char) + (setq auto-quoted t)) + ((and (eq char ?\{) + (eq (get-text-property pos 'part-side) 'jsx) + (looking-back "=[ ]*{" (point-min)) + (not (looking-at-p "[ ]*[}]"))) + (insert-and-inherit "}") + (backward-char) + (setq auto-quoted t)) + ((and (eq char ?\") + (eq (char-after) ?\")) + (delete-char 1) + (cond + ((looking-back "=\"\"" (point-min)) + (backward-char)) + ((eq (char-after) ?\s) + (forward-char)) + (t + (insert " ")) + ) ;cond + ) + ) ;cond + ) ;when + + ;;-- + (cond + ((or auto-closed auto-paired auto-expanded auto-quoted) + (when (and web-mode-change-end (>= (line-end-position) web-mode-change-end)) + (setq web-mode-change-end (line-end-position))) + (list :auto-closed auto-closed + :auto-paired auto-paired + :auto-expanded auto-expanded + :auto-quoted auto-quoted)) + (t + nil) + ) + + )) + +(defun web-mode-dom-xpath (&optional pos) + "Display html path." + (interactive) + (unless pos (setq pos (point))) + (save-excursion + (goto-char pos) + (let (path tag) + (while (web-mode-element-parent) + (looking-at web-mode-tag-regexp) + (setq tag (match-string-no-properties 1)) + (setq path (cons tag path)) + ) + (message "/%s" (mapconcat 'identity path "/")) + ))) + +(defun web-mode-block-ends-with (regexp &optional pos) + (unless pos (setq pos (point))) + (save-excursion + (goto-char pos) + (save-match-data + (if (stringp regexp) + (and (web-mode-block-end) + (progn (backward-char) t) + (web-mode-block-skip-blank-backward) + (progn (forward-char) t) + (looking-back regexp (point-min))) + (let ((pair regexp) + (block-beg (web-mode-block-beginning-position pos)) + (block-end (web-mode-block-end-position pos))) + (and (web-mode-block-end) + (web-mode-block-sb (car pair) block-beg) + (not (web-mode-sf (cdr pair) block-end))) + ) ;let + ) ;if + ))) + +(defun web-mode-block-token-starts-with (regexp &optional pos) + (unless pos (setq pos (point))) + (save-excursion + (and (goto-char pos) + (web-mode-block-token-beginning) + (skip-chars-forward "[\"']") + (looking-at regexp)) + )) + +(defun web-mode-block-starts-with (regexp &optional pos) + (unless pos (setq pos (point))) + (save-excursion + (and (web-mode-block-beginning) + (web-mode-block-skip-blank-forward) + (looking-at regexp)) + )) + +(defun web-mode-block-skip-blank-backward (&optional pos) + (unless pos (setq pos (point))) + (let ((continue t)) + (goto-char pos) + (while continue + (if (and (get-text-property (point) 'block-side) + (not (bobp)) + (or (member (char-after) '(?\s ?\n)) + (member (get-text-property (point) 'block-token) + '(delimiter-beg delimiter-end comment)))) + (backward-char) + (setq continue nil)) + ) ;while + (point))) + +(defun web-mode-block-skip-blank-forward (&optional pos props) + (unless pos (setq pos (point))) + (unless props (setq props '(delimiter-beg delimiter-end comment))) + (let ((continue t)) + (goto-char pos) + (while continue + (if (and (get-text-property (point) 'block-side) + (or (member (char-after) '(?\s ?\n ?\t)) + (member (get-text-property (point) 'block-token) props))) + (forward-char) + (setq continue nil)) + ) ;while + (point))) + +(defun web-mode-tag-attributes-sort (&optional pos) + "Sort the attributes inside the current html tag." + (interactive) + (unless pos (setq pos (point))) + (save-excursion + (let (attrs (continue t) min max tag-beg tag-end attr attr-name attr-beg attr-end indent indentation sorter ins) + (if (not (member (get-text-property pos 'tag-type) '(start void))) + nil + (setq tag-beg (web-mode-tag-beginning-position pos) + tag-end (web-mode-tag-end-position)) +;; (message "%S %S" tag-beg tag-end) + (goto-char tag-beg) + (while continue + (if (or (not (web-mode-attribute-next)) + (>= (point) tag-end)) + (setq continue nil) + ;;(message "attr=%S" (point)) + (setq attr-beg (web-mode-attribute-beginning-position) + attr-end (1+ (web-mode-attribute-end-position))) + (when (null min) + (setq min attr-beg)) + (setq max attr-end) + (goto-char attr-beg) + (setq attr (buffer-substring-no-properties attr-beg attr-end)) + (if (string-match "^\\([[:alnum:]-]+\\)=" attr) + (setq attr-name (match-string-no-properties 1 attr)) + (setq attr-name attr)) + (setq indent (looking-back "^[ \t]*" (point-min))) + (setq attrs (append attrs (list (list attr-beg attr-end attr-name attr indent)))) + ) ;if + ) ;while + ) ;if in tag + (when attrs + (setq sorter (function + (lambda (elt1 elt2) + (string< (nth 2 elt1) (nth 2 elt2)) + ))) + (setq attrs (sort attrs sorter)) + (delete-region (1- min) max) + (setq ins "") + (dolist (elt attrs) + (if (and (nth 4 elt) (> (length ins) 1)) + (setq ins (concat ins "\n")) + (setq ins (concat ins " "))) + (setq ins (concat ins (nth 3 elt))) + ) + (goto-char (1- min)) + (insert ins) + (web-mode-tag-beginning) + (setq min (line-beginning-position)) + (web-mode-tag-end) + (setq max (line-end-position)) + (indent-region min max) + ) + ;;(message "attrs=%S" attrs) + ))) + +(defun web-mode-attribute-insert (&optional attr-name attr-value) + "Insert an attribute inside current tag." + (interactive) + (let (attr attr-name attr-value) + (cond + ((not (member (get-text-property (point) 'tag-type) '(start void))) + (message "attribute-insert ** invalid context **")) + ((not (and (setq attr-name (or attr-name (completing-read + "Attribute name: " + (append + web-mode-attribute-list + web-mode-attribute-history) + nil nil nil 'web-mode-attribute-history))) + (> (length attr-name) 0))) + (message "attribute-insert ** failure **")) + (t + (setq attr (concat " " attr-name)) + (when (setq attr-value (or attr-value (completing-read + "Attribute value: " + web-mode-attribute-value-history + nil nil nil 'web-mode-attribute-value-history))) + (setq attr (concat attr "=\"" attr-value "\""))) + (web-mode-tag-end) + (if (looking-back "/>" (point-min)) + (backward-char 2) + (backward-char)) + (insert attr) + ) ;t + ) ;cond + )) + +(defun web-mode-attribute-transpose (&optional pos) + "Transpose the current html attribute." + (interactive) + (unless pos (setq pos (point))) + (let (ret attr-beg attr-end next-beg next-end tag-end) + (when (and (get-text-property pos 'tag-attr) + (setq next-beg (web-mode-attribute-next-position pos)) + (setq next-end (web-mode-attribute-end-position next-beg)) + (setq tag-end (web-mode-tag-end-position pos)) + (> tag-end next-end)) + (setq attr-beg (web-mode-attribute-beginning-position pos) + attr-end (web-mode-attribute-end-position pos)) + ;; (message "%S %S - %S %S" attr-beg attr-end next-beg next-end) + (transpose-regions attr-beg (1+ attr-end) next-beg (1+ next-end)) + ))) + +(defun web-mode-attribute-select (&optional pos) + "Select the current html attribute." + (interactive) + (unless pos (setq pos (point))) + (if (null (get-text-property pos 'tag-attr)) + nil + (goto-char pos) + (web-mode-attribute-beginning) + (set-mark (point)) + (web-mode-attribute-end) + (exchange-point-and-mark) + (point) + )) + +(defun web-mode-attribute-kill (&optional arg) + "Kill the current html attribute." + (interactive "p") + (unless arg (setq arg 1)) + (while (>= arg 1) + (setq arg (1- arg)) + (web-mode-attribute-select) + (when mark-active + (let ((beg (region-beginning)) (end (region-end))) + (save-excursion + (goto-char end) + (when (looking-at "[ \n\t]*") + (setq end (+ end (length (match-string-no-properties 0))))) + ) ;save-excursion + (kill-region beg end) + ) ;let + ) ;when + ) ;while + ;; Delete a potential space before the closing ">". + (when (and (looking-at ">") + (looking-back " " (point-min))) + (delete-char -1)) + ) + +(defun web-mode-block-close (&optional pos) + "Close the first unclosed control block." + (interactive) + (unless pos (setq pos (point))) + (let ((continue t) + (h (make-hash-table :test 'equal)) ctx ctrl n closing-block) + (save-excursion + (while (and continue (web-mode-block-previous)) + (when (setq ctx (web-mode-block-is-control (point))) + (setq ctrl (car ctx)) + (setq n (gethash ctrl h 0)) + (if (cdr ctx) + (puthash ctrl (1+ n) h) + (puthash ctrl (1- n) h)) + (when (> (gethash ctrl h) 0) + (setq continue nil)) + ) + ) ;while + ) ;save-excursion + (when (and (null continue) + (setq closing-block (web-mode-closing-block ctrl))) + (insert closing-block) + (indent-according-to-mode)) + )) + +(defun web-mode-closing-block (type) + (cond + ((string= web-mode-engine "php") (concat "<?php end" type "; ?>")) + ((string= web-mode-engine "django") (concat "{% end" type " %}")) + ((string= web-mode-engine "ctemplate") (concat "{{/" type "}}")) + ((string= web-mode-engine "blade") + (if (string= type "section") (concat "@show") (concat "@end" type))) + ((string= web-mode-engine "dust") (concat "{/" type "}")) + ((string= web-mode-engine "mako") (concat "% end" type)) + ((string= web-mode-engine "closure") (concat "{/" type "}")) + ((string= web-mode-engine "smarty") (concat "{/" type "}")) + ((string= web-mode-engine "expressionengine") (concat "{/" type "}")) + ((string= web-mode-engine "xoops") (concat "<{/" type "}>")) + ((string= web-mode-engine "svelte") (concat "{/" type "}")) + ((string= web-mode-engine "underscore") "<% } %>") + ((string= web-mode-engine "lsp") "<% ) %>") + ((string= web-mode-engine "erb") "<% } %>") + ((string= web-mode-engine "erb") "<% end %>") + ((string= web-mode-engine "artanis") "<% ) %>") + ((string= web-mode-engine "hero") "<% } %>") + ((string= web-mode-engine "go") "{{end}}") + ((string= web-mode-engine "velocity") "#end") + ((string= web-mode-engine "velocity") "#{end}") + ((string= web-mode-engine "template-toolkit") "[% end %]") + ((member web-mode-engine '("asp" "jsp")) + (if (string-match-p "[:.]" type) (concat "</" type ">") "<% } %>")) + (t nil) + ) ;cond + ) + +;;---- POSITION ---------------------------------------------------------------- + +(defun web-mode-comment-beginning-position (&optional pos) + (unless pos (setq pos (point))) + (car (web-mode-comment-boundaries pos))) + +(defun web-mode-comment-end-position (&optional pos) + (unless pos (setq pos (point))) + (cdr (web-mode-comment-boundaries pos))) + +(defun web-mode-part-opening-paren-position (pos &optional limit) + (save-restriction + (unless limit (setq limit nil)) + (goto-char pos) + (let* ((n -1) + (paren (char-after)) + (pairs '((?\) . "[)(]") + (?\] . "[\]\[]") + (?\} . "[}{]") + (?\> . "[><]"))) + (regexp (cdr (assoc paren pairs))) + (continue (not (null regexp))) + (counter 0)) + (while (and continue (re-search-backward regexp limit t)) + (cond + ((> (setq counter (1+ counter)) 500) + (message "part-opening-paren-position ** warning **") + (setq continue nil)) + ((or (web-mode-is-comment-or-string) + (get-text-property (point) 'block-side)) + ) + ((eq (char-after) paren) + (setq n (1- n))) + (t + (setq n (1+ n)) + (setq continue (not (= n 0)))) + ) + ) ;while + (if (= n 0) (point) nil) + ))) + +(defun web-mode-token-opening-paren-position (pos limit context) + (save-restriction + (unless limit (setq limit nil)) + (goto-char pos) + (let* ((n -1) + (paren (char-after)) + (pairs '((?\) . "[)(]") + (?\] . "[\]\[]") + (?\} . "[}{]") + (?\> . "[><]"))) + (regexp (cdr (assoc paren pairs))) + (continue (not (null regexp))) + (counter 0)) + (while (and continue (re-search-backward regexp limit t)) + (cond + ((> (setq counter (1+ counter)) 200) + (message "token-opening-paren-position ** warning **") + (setq continue nil)) + ((get-text-property (point) 'block-side) + ) + ((eq (char-after) paren) + (setq n (1- n))) + (t + (setq n (1+ n)) + (setq continue (not (= n 0)))) + ) + ) ;while + (if (= n 0) (point) nil) + ))) + +(defun web-mode-closing-paren-position (&optional pos limit) + (save-excursion + (unless pos (setq pos (point))) + (unless limit (setq limit nil)) + (goto-char pos) + (let* ((n 0) + (block-side (and (get-text-property pos 'block-side) + (not (string= web-mode-engine "razor")))) + (paren (char-after)) + (pairs '((?\( . "[)(]") + (?\[ . "[\]\[]") + (?\{ . "[}{]") + (?\< . "[><]"))) + (regexp (cdr (assoc paren pairs))) + (continue (not (null regexp)))) + (while (and continue (re-search-forward regexp limit t)) + (cond + ((or (web-mode-is-comment-or-string (1- (point))) + (and block-side (not (get-text-property (point) 'block-side)))) + ;;(message "pt=%S" (point)) + ) + ((eq (char-before) paren) + (setq n (1+ n))) + (t + (setq n (1- n)) + (setq continue (not (= n 0))) + ) + ) ;cond + ) ;while + (if (= n 0) (1- (point)) nil) + ))) + +(defun web-mode-closing-delimiter-position (delimiter &optional pos limit) + (unless pos (setq pos (point))) + (unless limit (setq limit nil)) + (save-excursion + (goto-char pos) + (setq pos nil) + (let ((continue t)) + (while (and continue (re-search-forward delimiter limit t)) + (setq continue nil + pos (1- (point))) + ) ;while + pos))) + +(defun web-mode-tag-match-position (&optional pos) + (unless pos (setq pos (point))) + (save-excursion + (web-mode-tag-match pos) + (if (= pos (point)) nil (point)))) + +(defun web-mode-tag-beginning-position (&optional pos) + (unless pos (setq pos (point))) + (let (beg end depth) + (setq depth (get-text-property pos 'jsx-depth)) + (when (and depth (get-text-property pos 'tag-attr-beg)) + (setq depth (get-text-property (1- pos) 'jsx-depth))) + (cond + ((null pos) + (setq end nil)) + ((get-text-property pos 'tag-beg) + (setq beg pos)) + ((and (> pos 1) (get-text-property (1- pos) 'tag-beg)) + (setq beg (1- pos))) + ((get-text-property pos 'tag-type) + (setq beg (previous-single-property-change pos 'tag-beg)) + (when beg (setq beg (1- beg))) + (cond + ((not (get-text-property beg 'tag-beg)) + (setq beg nil)) + ((and depth (not (eq depth (get-text-property beg 'jsx-depth)))) + (let ((continue (> beg (point-min)))) + (while continue + (setq beg (previous-single-property-change beg 'tag-beg)) + (when beg (setq beg (1- beg))) + (cond + ((null beg) + (setq continue nil)) + ((not (get-text-property beg 'tag-beg)) + (setq continue nil + beg nil)) + ((eq depth (get-text-property beg 'jsx-depth)) + (setq continue nil)) + ) ;cond + ) ;while + ) ;let + ) + ) ;cond + ) + (t + (setq beg nil)) + ) ;cond + beg)) + +(defun web-mode-tag-end-position (&optional pos) + (unless pos (setq pos (point))) + (let (end depth) + (setq depth (get-text-property pos 'jsx-depth)) + (when (and depth (get-text-property pos 'tag-attr-beg)) + (setq depth (get-text-property (1- pos) 'jsx-depth))) + (cond + ((null pos) + (setq end nil)) + ((get-text-property pos 'tag-end) + (setq end pos)) + ((get-text-property pos 'tag-type) + (setq end (next-single-property-change pos 'tag-end)) + (cond + ((not (get-text-property end 'tag-end)) + (setq end nil)) + ((and depth (not (eq depth (get-text-property end 'jsx-depth)))) + (let ((continue (< end (point-max)))) + (while continue + (setq end (1+ end)) + (setq end (next-single-property-change end 'tag-end)) + (cond + ((null end) + (setq continue nil)) + ((not (get-text-property end 'tag-end)) + (setq continue nil + end nil)) + ((eq depth (get-text-property end 'jsx-depth)) + (setq continue nil)) + ) ;cond + ) ;while + ) ;let + ) + ) ;cond + ) + (t + (setq end nil)) + ) ;cond + end)) + +;; TODO: prendre en compte jsx-depth +(defun web-mode-tag-next-position (&optional pos limit) + (unless pos (setq pos (point))) + (unless limit (setq limit (point-max))) + (cond + ((or (>= pos (point-max)) (>= pos limit)) nil) + (t + (when (get-text-property pos 'tag-beg) (setq pos (1+ pos))) + (setq pos (next-single-property-change pos 'tag-beg)) + (if (and pos (<= pos limit)) pos nil)) + )) + +;; TODO: prendre en compte jsx-depth +(defun web-mode-tag-previous-position (&optional pos limit) + (unless pos (setq pos (point))) + (unless limit (setq limit (point-min))) + (cond + ((or (<= pos (point-min)) (<= pos limit)) nil) + (t + (when (get-text-property pos 'tag-beg) (setq pos (1- pos))) + (web-mode-go (previous-single-property-change pos 'tag-beg) -1)) + )) + +;; TODO: prendre en compte jsx-depth +(defun web-mode-attribute-beginning-position (&optional pos) + (unless pos (setq pos (point))) + (cond + ((null (get-text-property pos 'tag-attr)) + nil) + ((get-text-property pos 'tag-attr-beg) + pos) + ((and (> pos (point-min)) (get-text-property (1- pos) 'tag-attr-beg)) + (1- pos)) + (t + (setq pos (previous-single-property-change pos 'tag-attr-beg)) + (setq pos (1- pos))) + )) + +;; TODO: retoucher en incluant un param limit et en s'inspirant de +;; web-mode-attribute-next-position +(defun web-mode-attribute-end-position (&optional pos) + (unless pos (setq pos (point))) + (let (beg end depth flags) + ;;(message "pos=%S" pos) + (setq depth (get-text-property pos 'jsx-depth)) + (cond + ((null pos) + (setq end nil)) + ((get-text-property pos 'tag-attr-end) + (setq end pos)) + ((get-text-property pos 'tag-attr) + (setq end (next-single-property-change pos 'tag-attr-end)) + (when (and depth + end + (setq beg (web-mode-attribute-beginning-position end)) + (setq flags (get-text-property pos 'tag-attr-beg)) + (eq (logand flags 4) 4)) + (setq depth (1- (get-text-property beg 'jsx-depth))) + ;;(message "%S %S" beg end) + ) + (cond + ((not (get-text-property end 'tag-attr-end)) + (setq end nil)) + ((and depth + (eq depth (get-text-property end 'jsx-depth)) + (not (eq depth (get-text-property end 'jsx-end)))) + ) + ((and depth (eq (1+ depth) (get-text-property end 'jsx-depth))) + ) + ((and depth (not (eq (1+ depth) (get-text-property end 'jsx-depth)))) + (let ((continue (< end (point-max)))) + (while continue + (setq end (1+ end)) + (setq end (next-single-property-change end 'tag-attr-end)) + (cond + ((null end) + (setq continue nil)) + ((not (get-text-property end 'tag-attr-end)) + (setq continue nil + end nil)) + ((eq (1+ depth) (get-text-property end 'jsx-depth)) + (setq continue nil)) + ) ;cond + ) ;while + ) ;let + ) + ) ;cond + ) + (t + (setq end nil)) + ) ;cond + end)) + +;; attention si pos est au debut d'un spread attributes, cela +;; risque de poser pb +(defun web-mode-attribute-next-position (&optional pos limit) + (unless pos (setq pos (point))) + (unless limit (setq limit (point-max))) + (let (continue depth) + (when (get-text-property pos 'tag-attr-beg) + (setq pos (1+ pos))) + (if (< pos limit) + (setq continue t + depth (get-text-property pos 'jsx-depth)) + (setq continue nil + pos nil)) + (while continue + (setq pos (next-single-property-change pos 'tag-attr-beg)) + (cond + ((null pos) + (setq continue nil)) + ((>= pos limit) + (setq continue nil + pos nil)) + ((null depth) + (setq continue nil)) + ((and (eq (get-text-property pos 'tag-attr-beg) 4) + (eq (1+ depth) (get-text-property pos 'jsx-depth))) + (setq continue nil)) + ((eq depth (get-text-property pos 'jsx-depth)) + (setq continue nil)) + (t + (setq pos (1+ pos) + continue (< pos limit))) + ) + ) ;while + pos)) + +(defun web-mode-attribute-previous-position (&optional pos limit) + (unless pos (setq pos (point))) + (unless limit (setq limit (point-min))) + (let (continue depth) + (cond + ((and (> pos (point-min)) (get-text-property (1- pos) 'tag-attr-beg)) + (setq pos (1- pos) + continue nil)) + (t + (when (get-text-property pos 'tag-attr-beg) + (setq pos (1- pos))) + (if (> pos limit) + (setq continue t + depth (get-text-property pos 'jsx-depth)) + (setq continue nil + pos nil)) + ) ;t + ) ;cond + (while continue + (setq pos (previous-single-property-change pos 'tag-attr-beg)) + (cond + ((null pos) + (setq continue nil)) + ((< pos limit) + (setq continue nil + pos nil)) + ;;((null depth) + ;; (setq continue nil)) + ((and depth (eq depth (get-text-property pos 'jsx-depth))) + (setq pos (1- pos) + continue nil)) + (depth + (setq pos nil + continue (> pos limit))) + (t + (setq pos (1- pos) + continue nil)) + ) ;cond + ) ;while + pos)) + +;; TODO: prendre en compte jsx-depth +(defun web-mode-element-beginning-position (&optional pos) + (unless pos (setq pos (point))) + (cond + ((null (get-text-property pos 'tag-type)) + (setq pos (web-mode-element-parent-position))) + ((eq (get-text-property pos 'tag-type) 'end) + (setq pos (web-mode-tag-match-position pos)) + (setq pos (if (get-text-property pos 'tag-beg) pos nil))) + ((member (get-text-property pos 'tag-type) '(start void)) + (setq pos (web-mode-tag-beginning-position pos))) + (t + (setq pos nil)) + ) ;cond + pos) + +;; TODO: prendre en compte jsx-depth +(defun web-mode-element-end-position (&optional pos) + (unless pos (setq pos (point))) + (cond + ((null (get-text-property pos 'tag-type)) + (setq pos (web-mode-element-parent-position pos)) + (when pos + (setq pos (web-mode-tag-match-position pos)) + (when pos (setq pos (web-mode-tag-end-position pos))) + ) + ) + ((member (get-text-property pos 'tag-type) '(end void comment)) + (setq pos (web-mode-tag-end-position pos)) + ) + ((member (get-text-property pos 'tag-type) '(start)) + (setq pos (web-mode-tag-match-position pos)) + (when pos (setq pos (web-mode-tag-end-position pos)))) + (t + (setq pos nil)) + ) ;cond + pos) + +(defun web-mode-element-child-position (&optional pos) + (save-excursion + (let (child close) + (unless pos (setq pos (point))) + (goto-char pos) + (cond + ((eq (get-text-property pos 'tag-type) 'start) + (web-mode-tag-match) + (setq close (point)) + (goto-char pos) + ) + ((eq (get-text-property pos 'tag-type) 'void) + ) + ((eq (get-text-property pos 'tag-type) 'end) + (web-mode-tag-beginning) + (setq close (point)) + (web-mode-tag-match) + ) + ((web-mode-element-parent-position pos) + (setq pos (point)) + (web-mode-tag-match) + (setq close (point)) + (goto-char pos) + ) + ) ;cond + (when (and close + (web-mode-element-next) + (< (point) close)) + (setq child (point)) + ) + child))) + +(defun web-mode-element-parent-position (&optional pos) + (let (n tag-type tag-name (continue t) (tags (make-hash-table :test 'equal))) + (save-excursion + (if pos (goto-char pos)) + (while (and continue (web-mode-tag-previous)) + (setq pos (point) + tag-type (get-text-property pos 'tag-type) + tag-name (get-text-property pos 'tag-name) + n (gethash tag-name tags 0)) + (when (member tag-type '(end start)) + (if (eq tag-type 'end) + (puthash tag-name (1- n) tags) + (puthash tag-name (1+ n) tags) + (when (= n 0) (setq continue nil)) + ) ;if + ) ;when + ) ;while + ) ;save-excursion + (if (null continue) pos nil))) + +(defun web-mode-element-previous-position (&optional pos limit) + (unless pos (setq pos (point))) + (unless limit (setq limit (point-min))) + (save-excursion + (goto-char pos) + (let ((continue (not (bobp))) + (props '(start void comment))) + (while continue + (setq pos (web-mode-tag-previous)) + (cond + ((or (null pos) (< (point) limit)) + (setq continue nil + pos nil)) + ((member (get-text-property (point) 'tag-type) props) + (setq continue nil)) + ) + ) ;while + pos))) + +(defun web-mode-element-next-position (&optional pos limit) + (unless pos (setq pos (point))) + (unless limit (setq limit (point-max))) + (save-excursion + (goto-char pos) + (let ((continue (not (eobp))) + (props '(start void comment))) + (while continue + (setq pos (web-mode-tag-next)) + (cond + ((or (null pos) (> (point) limit)) + (setq continue nil + pos nil)) + ((member (get-text-property (point) 'tag-type) props) + (setq continue nil)) + ) + ) ;while +;; (message "pos=%S" pos) + pos))) + +(defun web-mode-part-end-position (&optional pos) + (unless pos (setq pos (point))) + (cond + ((member web-mode-content-type web-mode-part-content-types) + (setq pos (point-max))) + ((not (get-text-property pos 'part-side)) + (setq pos nil)) + ((= pos (point-max)) + (setq pos nil)) + ((not (get-text-property (1+ pos) 'part-side)) + pos) + (t + (setq pos (next-single-property-change pos 'part-side))) + ) ;cond + pos) + +(defun web-mode-part-beginning-position (&optional pos) + (unless pos (setq pos (point))) + (cond + (web-mode-part-beg + (setq pos web-mode-part-beg)) + ((member web-mode-content-type web-mode-part-content-types) + (setq pos (point-min) + web-mode-part-beg (point-min))) + ((not (get-text-property pos 'part-side)) + (setq pos nil)) + ((= pos (point-min)) + (setq pos nil)) + ((not (get-text-property (1- pos) 'part-side)) + pos) + (t + (setq pos (previous-single-property-change pos 'part-side))) + ) ;cond + pos) + +(defun web-mode-part-next-position (&optional pos) + (unless pos (setq pos (point))) + (cond + ((and (= pos (point-min)) (get-text-property pos 'part-side)) + ) + ((not (get-text-property pos 'part-side)) + (setq pos (next-single-property-change pos 'part-side))) + ((and (setq pos (web-mode-part-end-position pos)) (>= pos (point-max))) + (setq pos nil)) + ((and (setq pos (1+ pos)) (not (get-text-property pos 'part-side))) + (setq pos (next-single-property-change pos 'part-side))) + ) ;cond + pos) + +(defun web-mode-block-match-position (&optional pos) + (unless pos (setq pos (point))) + (save-excursion + (web-mode-block-match pos) + (if (= pos (point)) nil (point)))) + +;; type may be nil +(defun web-mode-block-control-previous-position (type &optional pos) + (unless pos (setq pos (point))) + (let ((continue t) controls) + (while continue + (setq pos (web-mode-block-previous-position pos)) + (cond + ((null pos) + (setq continue nil + pos nil)) + ((null type) + (setq continue nil)) + ((and (setq controls (web-mode-block-controls-get pos)) + (eq (car (car controls)) type)) + (setq continue nil)) + ) ;cond + ) ;while + pos)) + +(defun web-mode-inside-block-control (&optional pos) + (unless pos (setq pos (point))) + (setq pos (web-mode-block-control-previous-position nil pos)) + (if (and pos (member (car (car (web-mode-block-controls-get pos))) '(open inside))) + pos + nil)) + +(defun web-mode-block-opening-paren-position (pos limit) + (save-excursion + (when (> limit pos) + (message "block-opening-paren-position: limit(%S) > pos(%S)" limit pos)) + (goto-char pos) + (let (c + n + pt + (continue (> pos limit)) + (pairs '((?\) . ?\() + (?\] . ?\[) + (?\} . ?\{))) + (h (make-hash-table :test 'equal)) + (regexp "[\]\[)(}{]")) + (while (and continue (re-search-backward regexp limit t)) + (cond + ((web-mode-is-comment-or-string) + ) + (t + (setq c (char-after)) + (cond + ((member c '(?\( ?\{ ?\[)) + (setq n (gethash c h 0)) + (if (= n 0) + (setq continue nil + pt (point)) + (puthash c (1+ n) h) + )) + (t + (setq c (cdr (assoc c pairs))) + (setq n (gethash c h 0)) + (puthash c (1- n) h)) + ) ;cond + ) ;t + ) ;cond + ) ;while + pt))) + +(defun web-mode-block-code-beginning-position (&optional pos) + (unless pos (setq pos (point))) + (when (and (setq pos (web-mode-block-beginning-position pos)) + (eq (get-text-property pos 'block-token) 'delimiter-beg)) + (setq pos (next-single-property-change pos 'block-token))) + pos) + +(defun web-mode-block-beginning-position (&optional pos) + (unless pos (setq pos (point))) + (cond + ((or (and (get-text-property pos 'block-side) (= pos (point-min))) + (get-text-property pos 'block-beg)) + ) + ((and (> pos (point-min)) (get-text-property (1- pos) 'block-beg)) + (setq pos (1- pos))) + ((get-text-property pos 'block-side) + (setq pos (previous-single-property-change pos 'block-beg)) + (setq pos (if (and pos (> pos (point-min))) (1- pos) (point-min)))) + (t + (setq pos nil)) + ) ;cond + pos) + +(defun web-mode-block-string-beginning-position (pos &optional block-beg) + (unless pos (setq pos (point))) + (unless block-beg (setq block-beg (web-mode-block-beginning-position pos))) + (let (char (ori pos) (continue (not (null pos)))) + (while continue + (setq char (char-after pos)) + (cond + ((< pos block-beg) + (setq continue nil + pos block-beg)) + ((and (member (get-text-property pos 'block-token) '(string comment)) + (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token))) + (setq pos (web-mode-block-token-beginning-position pos)) + ) + ((member char '(?\) ?\])) + (setq pos (web-mode-block-opening-paren-position pos block-beg)) + (setq pos (1- pos)) + ) + ((and (> ori pos) (member char '(?\( ?\= ?\[ ?\? ?\: ?\; ?\, ?\`))) + (if (and (eq char ?\:) ; #1024 + (web-mode-looking-at ":" pos)) + (setq pos (1- pos)) + (web-mode-looking-at ".[ \t\n]*" pos) + (setq pos (+ pos (length (match-string-no-properties 0))) + continue nil) + ) + ) + ((web-mode-looking-at "\\(return\\|echo\\|include\\|print\\)[ \n]" pos) + (setq pos (+ pos (length (match-string-no-properties 0))) + continue nil)) + (t + (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?;,`:]\\|\\(return\\|echo\\|include\\|print\\)" block-beg)) + (when (not pos) + (message "block-string-beginning-position ** search failure **") + (setq continue nil + pos block-beg))) + ) ;cond + ) ;while + ;;(message "pos=%S" pos) + pos)) + +(defun web-mode-block-statement-beginning-position (pos block-beg is-ternary) + (unless pos (setq pos (point))) + (setq pos (1- pos)) + (unless block-beg (setq block-beg (web-mode-block-beginning-position pos))) + (let (char (continue (not (null pos)))) + (while continue + (setq char (char-after pos)) + (cond + ((< pos block-beg) + (setq continue nil + pos block-beg)) + ((and (member (get-text-property pos 'block-token) '(string comment)) + (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token))) + (setq pos (web-mode-block-token-beginning-position pos))) + ((member char '(?\) ?\] ?\})) + (setq pos (web-mode-block-opening-paren-position pos block-beg)) + (setq pos (1- pos))) + ((and (eq char ?\=) + (web-mode-looking-back "[<>!=]+" pos block-beg t)) + (setq pos (- pos 1 (length (match-string-no-properties 0)))) + ;;(setq pos (1- pos)) + ;;(message "%S pos=%S" (match-string-no-properties 0) pos) + ) + ((member char '(?\( ?\[ ?\{ ?\=)) + (setq continue nil) + (web-mode-looking-at ".[ \t\n]*" pos) + (setq pos (+ pos (length (match-string-no-properties 0))))) + ((web-mode-looking-at "\\(return\\|echo\\|include\\|print\\)[ \n]" pos) + (setq pos (+ pos (length (match-string-no-properties 0))) + continue nil)) + (t + (setq pos (web-mode-rsb-position pos "[\]\[}{)(=]\\|\\(return\\|echo\\|include\\|print\\)" block-beg)) + (when (not pos) + (message "block-statement-beginning-position ** search failure **") + (setq continue nil + pos block-beg))) + ) ;cond + ) ;while + pos)) + +(defun web-mode-block-args-beginning-position (pos &optional block-beg) + (unless pos (setq pos (point))) + (setq pos (1- pos)) ;#512 + (unless block-beg (setq block-beg (web-mode-block-beginning-position pos))) + (let (char (continue (not (null pos)))) + (while continue + (setq char (char-after pos)) + (cond + ((< pos block-beg) + (message "block-args-beginning-position ** failure **") + (setq continue nil + pos block-beg)) + ((and (member (get-text-property pos 'block-token) '(string comment)) + (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token))) + (setq pos (web-mode-block-token-beginning-position pos))) + ((member char '(?\) ?\] ?\})) + (setq pos (web-mode-block-opening-paren-position pos block-beg)) + (setq pos (1- pos))) + ((member char '(?\( ?\[ ?\{)) + (setq continue nil) + (web-mode-looking-at ".[ \t\n]*" pos) + (setq pos (+ pos (length (match-string-no-properties 0))))) + ((and (string= web-mode-engine "php") + (web-mode-looking-at "\\(extends\\|implements\\)[ \n]" pos)) + (setq pos (+ pos (length (match-string-no-properties 0))) + continue nil)) + (t + (setq pos (web-mode-rsb-position pos "[\]\[}{)(]\\|\\(extends\\|implements\\)" block-beg)) + (when (not pos) + (message "block-args-beginning-position ** search failure **") + (setq pos block-beg + continue nil)) + ) ;t + ) ;cond + ) ;while + pos)) + +(defun web-mode-block-calls-beginning-position (pos &optional block-beg) + (unless pos (setq pos (point))) + (unless block-beg (setq block-beg (web-mode-block-beginning-position pos))) + (let (char (continue (not (null pos)))) + (while continue + (setq char (char-after pos)) + (cond + ((< pos block-beg) + (message "block-calls-beginning-position ** failure **") + (setq continue nil + pos block-beg)) + ((and (member (get-text-property pos 'block-token) '(string comment)) + (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token))) + (setq pos (web-mode-block-token-beginning-position pos))) + ((member char '(?\) ?\])) + (setq pos (web-mode-block-opening-paren-position pos block-beg)) + (setq pos (1- pos))) + ((member char '(?\( ?\[ ?\{ ?\} ?\= ?\? ?\: ?\; ?\,)) + (web-mode-looking-at ".[ \t\n]*" pos) + (setq pos (+ pos (length (match-string-no-properties 0))) + continue nil)) + ((web-mode-looking-at "\\(return\\|else\\)[ \n]" pos) + (setq pos (+ pos (length (match-string-no-properties 0))) + continue nil)) + (t + (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,]\\|\\(return\\|else\\)" block-beg)) + (when (not pos) + (message "block-calls-beginning-position ** search failure **") + (setq pos block-beg + continue nil)) + ) ;t + ) ;cond + ) ;while + pos)) + +(defun web-mode-javascript-string-beginning-position (pos &optional reg-beg) + (unless pos (setq pos (point))) + (let ((char nil) + (blockside (get-text-property pos 'block-side)) + (i 0) + (continue (not (null pos)))) + (unless reg-beg + (if blockside + (setq reg-beg (web-mode-block-beginning-position pos)) + (setq reg-beg (web-mode-part-beginning-position pos))) + ) + (while continue + (setq char (char-after pos)) + (cond + ((> (setq i (1+ i)) 20000) + (message "javascript-string-beginning-position ** warning (%S) **" pos) + (setq continue nil + pos nil)) + ((null pos) + (message "javascript-string-beginning-position ** invalid pos **") + (setq continue nil)) + ((< pos reg-beg) + (message "javascript-string-beginning-position ** failure **") + (setq continue nil + pos reg-beg)) + ((and blockside + (member (get-text-property pos 'block-token) '(string comment)) + (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token))) + (setq pos (web-mode-block-token-beginning-position pos))) + ((and (not blockside) + (member (get-text-property pos 'part-token) '(string comment)) + (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token))) + (setq pos (web-mode-part-token-beginning-position pos))) + ((and (not blockside) + (get-text-property pos 'block-side)) + (when (setq pos (web-mode-block-beginning-position pos)) + (setq pos (1- pos)))) + ((member char '(?\) ?\] ?\})) + (setq pos (web-mode-part-opening-paren-position pos reg-beg)) + (setq pos (1- pos))) + ((member char '(?\( ?\{ ?\[ ?\= ?\? ?\: ?\; ?\, ?\& ?\|)) + (setq continue nil) + (web-mode-looking-at ".[ \t\n]*" pos) + (setq pos (+ pos (length (match-string-no-properties 0))))) + ((web-mode-looking-at "\\(return\\)[ \n]" pos) + (setq pos (+ pos (length (match-string-no-properties 0))) + continue nil)) + (t + (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,&|]\\|\\(return\\)" reg-beg)) + (when (not pos) + (message "javascript-string-beginning-position ** search failure **") + (setq continue nil + pos reg-beg))) + ) ;cond + ) ;while + ;;(message "js-statement-beg:%S" pos) + pos)) + +;; TODO: reg-beg : jsx-beg +;; TODO: skipper les expr dont la depth est superieure + +;; NOTE: blockside is useful for ejs +(defun web-mode-javascript-statement-beginning-position (pos reg-beg is-ternary) + (unless pos (setq pos (point))) + (setq pos (1- pos)) + (let ((char nil) + (blockside (get-text-property pos 'block-side)) + (i 0) + (is-jsx (string= web-mode-content-type "jsx")) + (depth-o nil) (depth-l nil) + (continue (not (null pos))) + (regexp "[\]\[}{)(=:]\\|\\(return\\)")) + (when is-ternary + (setq regexp (concat regexp "\\|[><]"))) + (setq depth-o (get-text-property pos 'jsx-depth)) + (unless reg-beg + (cond + (blockside + (setq reg-beg (web-mode-block-beginning-position pos))) + (is-jsx + (setq reg-beg (web-mode-jsx-depth-beginning-position pos))) + (t + (setq reg-beg (web-mode-part-beginning-position pos))) + ) ;cond + ) ;unless + (while continue + (setq char (char-after pos)) + (cond + ((> (setq i (1+ i)) 20000) + (message "javascript-statement-beginning-position ** warning (%S) **" pos) + (setq continue nil + pos nil)) + ((null pos) + (message "javascript-statement-beginning-position ** invalid pos **") + (setq continue nil)) + ((< pos reg-beg) + (when (not is-jsx) + (message "javascript-statement-beginning-position ** failure **")) + (setq continue nil + pos reg-beg)) + ((and is-jsx + (progn (setq depth-l (get-text-property pos 'jsx-depth)) t) + (not (eq depth-l depth-o))) + ;;(message "%S > depth-o(%S) depth-l(%S)" pos depth-o depth-l) + (setq pos (previous-single-property-change pos 'jsx-depth)) + (setq pos (1- pos)) + ;;(message "--> %S %S" pos (get-text-property pos 'jsx-depth)) + ) + ((and blockside + (member (get-text-property pos 'block-token) '(string comment)) + (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token))) + (setq pos (web-mode-block-token-beginning-position pos))) + ((and (not blockside) + (member (get-text-property pos 'part-token) '(string comment)) + (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token))) + (setq pos (web-mode-part-token-beginning-position pos))) + ((and (not blockside) + (get-text-property pos 'block-side)) + (when (setq pos (web-mode-block-beginning-position pos)) + (setq pos (1- pos)))) + ((member char '(?\) ?\] ?\})) + (setq pos (web-mode-part-opening-paren-position pos reg-beg)) + (setq pos (1- pos))) + ((and (eq char ?\=) + (web-mode-looking-back "[<>!=]+" pos reg-beg t)) + (setq pos (- pos 1 (length (match-string-no-properties 0))))) + ((member char '(?\( ?\{ ?\[ ?\= ?\< ?\>)) + (web-mode-looking-at ".[ \t\n]*" pos) + (setq continue nil + pos (+ pos (length (match-string-no-properties 0))))) + + ((web-mode-looking-at "\\(return\\)[ \n]" pos) + (setq continue nil + pos (+ pos (length (match-string-no-properties 0))))) + ((and (eq char ?\:) + (web-mode-looking-back "[{,][ \t\n]*[[:alnum:]_]+[ ]*" pos)) + (web-mode-looking-at ".[ \t\n]*" pos) + (setq continue nil + pos (+ pos (length (match-string-no-properties 0))))) + (t + (setq pos (web-mode-rsb-position pos regexp reg-beg)) + (when (not pos) + (cond + (is-jsx + (when (web-mode-looking-at "[ \n]*" reg-beg) + (setq pos (+ reg-beg (length (match-string-no-properties 0))))) + (setq continue nil)) + (t + (message "javascript-statement-beginning-position ** search failure **") + (setq continue nil + pos reg-beg)) + ) ;cond + ) + ) ;t + ) ;cond + ) ;while + ;;(message "%S -------" pos) + pos)) + +(defun web-mode-javascript-args-beginning-position (pos &optional reg-beg) + (unless pos (setq pos (point))) + (setq pos (1- pos)) + (let ((char nil) + (blockside (get-text-property pos 'block-side)) + (i 0) + (continue (not (null pos)))) + (unless reg-beg + (if blockside + (setq reg-beg (web-mode-block-beginning-position pos)) + (setq reg-beg (web-mode-part-beginning-position pos))) + ) + (while continue + (setq char (char-after pos)) + ;;(message "pos(%S) char(%c)" pos char) + (cond + ((> (setq i (1+ i)) 20000) + (message "javascript-args-beginning-position ** warning (%S) **" pos) + (setq continue nil + pos nil)) + ((null pos) + (message "javascript-args-beginning-position ** invalid pos **") + (setq continue nil)) + ((< pos reg-beg) + (message "javascript-args-beginning-position ** failure(position) **") + (setq continue nil + pos reg-beg)) + ((and blockside + (member (get-text-property pos 'block-token) '(string comment)) + (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token))) + (setq pos (web-mode-block-token-beginning-position pos))) + ((and (not blockside) + (member (get-text-property pos 'part-token) '(string comment)) + (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token))) + (setq pos (web-mode-part-token-beginning-position pos))) + ((and (not blockside) + (get-text-property pos 'block-side)) + (when (setq pos (web-mode-block-beginning-position pos)) + (setq pos (1- pos))) + ) + ((member char '(?\) ?\] ?\})) + (when (setq pos (web-mode-part-opening-paren-position pos reg-beg)) + (setq pos (1- pos)))) + ((member char '(?\( ?\[ ?\{)) + (web-mode-looking-at ".[ ]*" pos) + (setq pos (+ pos (length (match-string-no-properties 0))) + continue nil) + ) + ((web-mode-looking-at "\\(var\\|let\\|return\\|const\\)[ \n]" pos) + (setq pos (+ pos (length (match-string-no-properties 0))) + continue nil)) + (t + (setq pos (web-mode-rsb-position pos "[\]\[}{)(]\\|\\(var\\|let\\|return\\|const\\)" reg-beg)) + (when (not pos) + (message "javascript-args-beginning-position ** search failure **") + (setq continue nil + pos reg-beg))) + ) ;cond + ) ;while + ;;(message "=%S" pos) + pos)) + +(defun web-mode-javascript-calls-beginning-position (pos &optional reg-beg) + (unless pos (setq pos (point))) + ;;(message "pos=%S" pos) + (let ((char nil) + (dot-pos nil) + (blockside (get-text-property pos 'block-side)) + (i 0) + (continue (not (null pos)))) + (unless reg-beg + (setq reg-beg (if blockside + (web-mode-block-beginning-position pos) + (web-mode-part-beginning-position pos)))) + (while continue + (setq char (char-after pos)) + ;;(message "%S| %S=%c" reg-beg pos char) + (cond + ((> (setq i (1+ i)) 20000) + (message "javascript-calls-beginning-position ** warning (%S) **" pos) + (setq continue nil + pos nil)) + ((null pos) + (message "javascript-calls-beginning-position ** invalid pos **") + (setq continue nil)) + ((< pos reg-beg) + (setq continue nil + pos reg-beg)) + ((and blockside + (member (get-text-property pos 'block-token) '(string comment)) + (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token))) + (setq pos (web-mode-block-token-beginning-position pos))) + ((and (not blockside) + (member (get-text-property pos 'part-token) '(string comment)) + (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token))) + (setq pos (web-mode-part-token-beginning-position pos))) + ((and (not blockside) + (get-text-property pos 'block-side)) + (when (setq pos (web-mode-block-beginning-position pos)) + (setq pos (1- pos)))) + ((and (member char '(?\.)) (> i 1)) + (setq dot-pos pos + pos (1- pos))) + ((member char '(?\) ?\])) + (when (setq pos (web-mode-part-opening-paren-position pos reg-beg)) + (setq pos (1- pos))) + ) + ((member char '(?\( ?\{ ?\} ?\[ ?\= ?\? ?\: ?\; ?\, ?\& ?\| ?\>)) + (web-mode-looking-at ".[ \t\n]*" pos) + (setq pos (+ pos (length (match-string-no-properties 0))) + continue nil)) + ((web-mode-looking-at "\\(return\\|else\\|const\\)[ \n]" pos) + (setq pos (+ pos (length (match-string-no-properties 0))) + continue nil)) + (t + (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,&|>.]\\|\\(return\\|else\\|const\\)" reg-beg)) + (when (not pos) + (message "javascript-calls-beginning-position ** search failure **") + (setq pos reg-beg + continue nil)) + ) ;t + ) ;cond + ) ;while + ;;(message "pos=%S dot-pos=%S" pos dot-pos) + (if (null pos) pos (cons pos dot-pos)) + )) + +(defun web-mode-part-token-beginning-position (&optional pos) + (unless pos (setq pos (point))) + (cond + ((not (get-text-property pos 'part-token)) + nil) + ((or (= pos (point-min)) + (and (> pos (point-min)) + (not (get-text-property (1- pos) 'part-token)))) + pos) + (t + (setq pos (previous-single-property-change pos 'part-token)) + (if (and pos (> pos (point-min))) pos (point-min))) + )) + +(defun web-mode-part-token-end-position (&optional pos) + (unless pos (setq pos (point))) + (cond + ((not (get-text-property pos 'part-token)) + nil) + ((or (= pos (point-max)) + (not (get-text-property (1+ pos) 'part-token))) + pos) + (t + (1- (next-single-property-change pos 'part-token))) + )) + +(defun web-mode-block-token-beginning-position (&optional pos) + (unless pos (setq pos (point))) + (cond + ((not (get-text-property pos 'block-token)) + nil) + ((or (= pos (point-min)) + (and (> pos (point-min)) + (not (get-text-property (1- pos) 'block-token)))) + pos) + (t + (setq pos (previous-single-property-change pos 'block-token)) + (if (and pos (> pos (point-min))) pos (point-min))) + )) + +(defun web-mode-block-token-end-position (&optional pos) + (unless pos (setq pos (point))) + (cond + ((not (get-text-property pos 'block-token)) + nil) + ((or (= pos (point-max)) + (not (get-text-property (1+ pos) 'block-token))) + pos) + (t + (1- (next-single-property-change pos 'block-token))) + )) + +(defun web-mode-block-code-end-position (&optional pos) + (unless pos (setq pos (point))) + (setq pos (web-mode-block-end-position pos)) + (cond + ((not pos) + nil) + ((and (eq (get-text-property pos 'block-token) 'delimiter-end) + (eq (get-text-property (1- pos) 'block-token) 'delimiter-end)) + (previous-single-property-change pos 'block-token)) + ((= pos (1- (point-max))) ;; TODO: comparer plutot avec line-end-position + (point-max)) + (t + pos) + )) + +(defun web-mode-block-end-position (&optional pos) + (unless pos (setq pos (point))) + (cond + ((get-text-property pos 'block-end) + pos) + ((get-text-property pos 'block-side) + (or (next-single-property-change pos 'block-end) + (point-max))) + (t + nil) + )) + +(defun web-mode-block-previous-position (&optional pos) + (unless pos (setq pos (point))) + (cond + ((= pos (point-min)) + (setq pos nil)) + ((get-text-property pos 'block-side) + (setq pos (web-mode-block-beginning-position pos)) + (cond + ((or (null pos) (= pos (point-min))) + (setq pos nil) + ) + ((and (setq pos (previous-single-property-change pos 'block-beg)) + (> pos (point-min))) + (setq pos (1- pos)) + ) + ) + ) ;block-side + ((get-text-property (1- pos) 'block-side) + (setq pos (web-mode-block-beginning-position (1- pos))) + ) + (t + (setq pos (previous-single-property-change pos 'block-side)) + (cond + ((and (null pos) (get-text-property (point-min) 'block-beg)) + (setq pos (point-min))) + ((and pos (> pos (point-min))) + (setq pos (web-mode-block-beginning-position (1- pos)))) + ) + ) + ) ;conf + pos) + +(defun web-mode-block-next-position (&optional pos limit) + (unless pos (setq pos (point))) + (unless limit (setq limit (point-max))) + (cond + ((and (get-text-property pos 'block-side) + (setq pos (web-mode-block-end-position pos)) + (< pos (point-max)) + (setq pos (1+ pos))) + (unless (get-text-property pos 'block-beg) + (setq pos (next-single-property-change pos 'block-side))) + ) + (t + (setq pos (next-single-property-change pos 'block-side))) + ) ;cond + (if (and pos (<= pos limit)) pos nil)) + +(defun web-mode-is-css-string (pos) + (let (beg) + (cond + ((and (setq beg (web-mode-part-token-beginning-position pos)) + (web-mode-looking-at-p "`" beg) + (web-mode-looking-back "\\(styled[[:alnum:].]+\\|css\\)" beg)) + beg) + (t + nil) + ) ;cond + )) + +;; Relay.QL , gql, graphql +(defun web-mode-is-ql-string (pos prefix-regexp) + (let (beg) + (cond + ((and (setq beg (web-mode-part-token-beginning-position pos)) + (web-mode-looking-back prefix-regexp beg)) + beg) + (t + nil) + ) ;cond + )) + +(defun web-mode-is-html-string (pos) + (let (beg) + (cond + ((and (setq beg (web-mode-part-token-beginning-position pos)) + (web-mode-looking-at-p "`[ \t\n]*<[a-zA-Z]" beg) + (web-mode-looking-back "\\(template\\|html\\)\\([ ]*[=:][ ]*\\)?" beg)) + beg) + (t + nil) + ) ;cond + )) + +;;---- EXCURSION --------------------------------------------------------------- + +(defun web-mode-backward-sexp (n) + (interactive "p") + (if (< n 0) (web-mode-forward-sexp (- n)) + (let (pos) + (dotimes (_ n) + (skip-chars-backward "[:space:]") + (setq pos (point)) + (cond + ((bobp) nil) + ((get-text-property (1- pos) 'block-end) + (backward-char 1) + (web-mode-block-beginning)) + ((get-text-property (1- pos) 'block-token) + (backward-char 1) + (web-mode-block-token-beginning)) + ((get-text-property (1- pos) 'part-token) + (backward-char 1) + (web-mode-part-token-beginning)) + ((get-text-property (1- pos) 'tag-end) + (backward-char 1) + (web-mode-element-beginning)) + ((get-text-property (1- pos) 'tag-attr) + (backward-char 1) + (web-mode-attribute-beginning)) + ((get-text-property (1- pos) 'tag-type) + (backward-char 1) + (web-mode-tag-beginning)) + ((get-text-property (1- pos) 'jsx-end) + (backward-char 1) + (web-mode-jsx-beginning)) + (t + (let ((forward-sexp-function nil)) + (backward-sexp)) + ) ;case t + ) ;cond + ) ;dotimes + ))) ;let if defun + +(defun web-mode-forward-sexp (n) + (interactive "p") + (if (< n 0) (web-mode-backward-sexp (- n)) + (let (pos) + (dotimes (_ n) + (skip-chars-forward "[:space:]") + (setq pos (point)) + (cond + ((eobp) nil) + ((get-text-property pos 'block-beg) + (web-mode-block-end)) + ((get-text-property pos 'block-token) + (web-mode-block-token-end)) + ((get-text-property pos 'part-token) + (web-mode-part-token-end)) + ((get-text-property pos 'tag-beg) + (web-mode-element-end)) + ((get-text-property pos 'tag-attr) + (web-mode-attribute-end)) + ((get-text-property pos 'tag-type) + (web-mode-tag-end)) + ((get-text-property pos 'jsx-beg) + (web-mode-jsx-end)) + (t + (let ((forward-sexp-function nil)) + (forward-sexp)) + ) ;case t + ) ;cond + ) ;dotimes + ))) ;let if defun + +(defun web-mode-comment-beginning () + "Fetch current comment beg." + (interactive) + (web-mode-go (web-mode-comment-beginning-position (point)))) + +(defun web-mode-comment-end () + "Fetch current comment end." + (interactive) + (web-mode-go (web-mode-comment-end-position (point)) 1)) + +(defun web-mode-tag-beginning () + "Fetch current html tag beg." + (interactive) + (web-mode-go (web-mode-tag-beginning-position (point)))) + +(defun web-mode-tag-end () + "Fetch current html tag end." + (interactive) + (web-mode-go (web-mode-tag-end-position (point)) 1)) + +(defun web-mode-tag-previous () + "Fetch previous tag." + (interactive) + (web-mode-go (web-mode-tag-previous-position (point)))) + +(defun web-mode-tag-next () + "Fetch next tag. Might be html comment or server tag (e.g. jsp)." + (interactive) + (web-mode-go (web-mode-tag-next-position (point)))) + +(defun web-mode-attribute-beginning () + "Fetch html attribute beginning." + (interactive) + (web-mode-go (web-mode-attribute-beginning-position (point)))) + +(defun web-mode-attribute-end () + "Fetch html attribute end." + (interactive) + (web-mode-go (web-mode-attribute-end-position (point)) 1)) + +(defun web-mode-attribute-next (&optional arg) + "Fetch next attribute." + (interactive "p") + (unless arg (setq arg 1)) + (cond + ((= arg 1) (web-mode-go (web-mode-attribute-next-position (point)))) + ((< arg 1) (web-mode-element-previous (* arg -1))) + (t + (while (>= arg 1) + (setq arg (1- arg)) + (web-mode-go (web-mode-attribute-next-position (point))) + ) + ) + ) + ) + +(defun web-mode-attribute-previous (&optional arg) + "Fetch previous attribute." + (interactive "p") + (unless arg (setq arg 1)) + (unless arg (setq arg 1)) + (cond + ((= arg 1) (web-mode-go (web-mode-attribute-previous-position (point)))) + ((< arg 1) (web-mode-element-next (* arg -1))) + (t + (while (>= arg 1) + (setq arg (1- arg)) + (web-mode-go (web-mode-attribute-previous-position (point))) + ) + ) + ) + ) + +(defun web-mode-element-previous (&optional arg) + "Fetch previous element." + (interactive "p") + (unless arg (setq arg 1)) + (cond + ((= arg 1) (web-mode-go (web-mode-element-previous-position (point)))) + ((< arg 1) (web-mode-element-next (* arg -1))) + (t + (while (>= arg 1) + (setq arg (1- arg)) + (web-mode-go (web-mode-element-previous-position (point))) + ) ;while + ) ;t + ) ;cond + ) + +(defun web-mode-element-next (&optional arg) + "Fetch next element." + (interactive "p") + (unless arg (setq arg 1)) + (cond + ((= arg 1) (web-mode-go (web-mode-element-next-position (point)))) + ((< arg 1) (web-mode-element-previous (* arg -1))) + (t + (while (>= arg 1) + (setq arg (1- arg)) + (web-mode-go (web-mode-element-next-position (point))) + ) ;while + ) ;t + ) ;cond + ) + +(defun web-mode-element-sibling-next () + "Fetch next sibling element." + (interactive) + (let ((pos (point))) + (save-excursion + (cond + ((not (get-text-property pos 'tag-type)) + (if (and (web-mode-element-parent) + (web-mode-tag-match) + (web-mode-tag-next) + (member (get-text-property (point) 'tag-type) '(start void comment))) + (setq pos (point)) + (setq pos nil)) + ) + ((member (get-text-property pos 'tag-type) '(start void)) + (if (and (web-mode-tag-match) + (web-mode-tag-next) + (member (get-text-property (point) 'tag-type) '(start void comment))) + (setq pos (point)) + (setq pos nil)) + ) + ((and (web-mode-tag-next) + (member (get-text-property (point) 'tag-type) '(start void comment))) + (setq pos (point))) + (t + (setq pos nil)) + ) ;cond + ) ;save-excursion + (web-mode-go pos))) + +(defun web-mode-element-sibling-previous () + "Fetch previous sibling element." + (interactive) + (let ((pos (point))) + (save-excursion + (cond + ((not (get-text-property pos 'tag-type)) + (if (and (web-mode-element-parent) + (web-mode-tag-previous) + (web-mode-element-beginning)) + (setq pos (point)) + (setq pos nil)) + ) + ((eq (get-text-property pos 'tag-type) 'start) + (if (and (web-mode-tag-beginning) + (web-mode-tag-previous) + (web-mode-element-beginning)) + (setq pos (point)) + (setq pos nil)) + ) + ((and (web-mode-element-beginning) + (web-mode-tag-previous) + (web-mode-element-beginning)) + (setq pos (point))) + (t + (setq pos nil)) + ) ;cond + ) ;save-excursion + (web-mode-go pos))) + +(defun web-mode-element-beginning () + "Move to beginning of element." + (interactive) + (web-mode-go (web-mode-element-beginning-position (point)))) + +(defun web-mode-element-end () + "Move to end of element." + (interactive) + (web-mode-go (web-mode-element-end-position (point)) 1)) + +(defun web-mode-element-parent () + "Fetch parent element." + (interactive) + (web-mode-go (web-mode-element-parent-position (point)))) + +(defun web-mode-element-child () + "Fetch child element." + (interactive) + (web-mode-go (web-mode-element-child-position (point)))) + +(defun web-mode-dom-traverse () + "Traverse html dom tree." + (interactive) + (cond + ((web-mode-element-child) + ) + ((web-mode-element-sibling-next) + ) + ((and (web-mode-element-parent) + (not (web-mode-element-sibling-next))) + (goto-char (point-min))) + (t + (goto-char (point-min))) + ) ;cond + ) + +(defun web-mode-closing-paren (limit) + (let ((pos (web-mode-closing-paren-position (point) limit))) + (if (or (null pos) (> pos limit)) + nil + (goto-char pos) + pos) + )) + +(defun web-mode-part-next () + "Move point to the beginning of the next part." + (interactive) + (web-mode-go (web-mode-part-next-position (point)))) + +(defun web-mode-part-beginning () + "Move point to the beginning of the current part." + (interactive) + (web-mode-go (web-mode-part-beginning-position (point)))) + +(defun web-mode-part-end () + "Move point to the end of the current part." + (interactive) + (web-mode-go (web-mode-part-end-position (point)) 1)) + +(defun web-mode-block-previous () + "Move point to the beginning of the previous block." + (interactive) + (web-mode-go (web-mode-block-previous-position (point)))) + +(defun web-mode-block-next () + "Move point to the beginning of the next block." + (interactive) + (web-mode-go (web-mode-block-next-position (point)))) + +(defun web-mode-block-beginning () + "Move point to the beginning of the current block." + (interactive) + (web-mode-go (web-mode-block-beginning-position (point)))) + +(defun web-mode-block-end () + "Move point to the end of the current block." + (interactive) + (web-mode-go (web-mode-block-end-position (point)) 1)) + +(defun web-mode-block-token-beginning () + (web-mode-go (web-mode-block-token-beginning-position (point)))) + +(defun web-mode-block-token-end () + (web-mode-go (web-mode-block-token-end-position (point)) 1)) + +(defun web-mode-part-token-beginning () + (web-mode-go (web-mode-part-token-beginning-position (point)))) + +(defun web-mode-part-token-end () + (web-mode-go (web-mode-part-token-end-position (point)) 1)) + +(defun web-mode-block-opening-paren (limit) + (web-mode-go (web-mode-block-opening-paren-position (point) limit))) + +(defun web-mode-block-string-beginning (&optional pos block-beg) + (unless pos (setq pos (point))) + (unless block-beg (setq block-beg (web-mode-block-beginning-position pos))) + (web-mode-go (web-mode-block-string-beginning-position pos block-beg))) + +(defun web-mode-block-statement-beginning (pos block-beg is-ternary) + (unless pos (setq pos (point))) + (unless block-beg (setq block-beg (web-mode-block-beginning-position pos))) + (web-mode-go (web-mode-block-statement-beginning-position pos block-beg is-ternary))) + +(defun web-mode-block-args-beginning (&optional pos block-beg) + (unless pos (setq pos (point))) + (unless block-beg (setq block-beg (web-mode-block-beginning-position pos))) + (web-mode-go (web-mode-block-args-beginning-position pos block-beg))) + +(defun web-mode-block-calls-beginning (&optional pos block-beg) + (unless pos (setq pos (point))) + (unless block-beg (setq block-beg (web-mode-block-beginning-position pos))) + (web-mode-go (web-mode-block-calls-beginning-position pos block-beg))) + +(defun web-mode-javascript-string-beginning (&optional pos reg-beg) + (unless pos (setq pos (point))) + (unless reg-beg + (if (get-text-property pos 'block-side) + (setq reg-beg (web-mode-block-beginning-position pos)) + (setq reg-beg (web-mode-part-beginning-position pos)))) + (web-mode-go (web-mode-javascript-string-beginning-position pos reg-beg))) + +(defun web-mode-javascript-statement-beginning (pos reg-beg is-ternary) + (unless pos (setq pos (point))) + (unless reg-beg + (if (get-text-property pos 'block-side) + (setq reg-beg (web-mode-block-beginning-position pos)) + (setq reg-beg (web-mode-part-beginning-position pos)))) + (web-mode-go (web-mode-javascript-statement-beginning-position pos reg-beg is-ternary))) + +(defun web-mode-javascript-args-beginning (&optional pos reg-beg) + (unless pos (setq pos (point))) + (unless reg-beg + (setq reg-beg (if (get-text-property pos 'block-side) + (web-mode-block-beginning-position pos) + (web-mode-part-beginning-position pos)))) + ;;(message "reg-beg%S" reg-beg) + (web-mode-go (web-mode-javascript-args-beginning-position pos reg-beg))) + +(defun web-mode-javascript-calls-beginning (&optional pos reg-beg) + (unless pos (setq pos (point))) + (unless reg-beg + (if (get-text-property pos 'block-side) + (setq reg-beg (web-mode-block-beginning-position pos)) + (setq reg-beg (web-mode-part-beginning-position pos)))) + (let (pair) + (setq pair (web-mode-javascript-calls-beginning-position pos reg-beg)) + (when pair (web-mode-go (car pair))) + )) + +(defun web-mode-go (pos &optional offset) + (unless offset (setq offset 0)) + (when pos + (cond + ((and (> offset 0) (<= (+ pos offset) (point-max))) + (setq pos (+ pos offset))) + ((and (< offset 0) (>= (+ pos offset) (point-min))) + (setq pos (+ pos offset))) + ) ;cond + (goto-char pos)) + pos) + +;;---- SEARCH ------------------------------------------------------------------ + +(defun web-mode-rsf-balanced (regexp-open regexp-close &optional limit noerror) + (unless noerror (setq noerror t)) + (let ((continue t) + (level 1) + (pos (point)) + ret + (regexp (concat regexp-open "\\|" regexp-close))) + (while continue + (setq ret (re-search-forward regexp limit noerror)) + (cond + ((null ret) + (setq continue nil) + ) + (t + (if (string-match-p regexp-open (match-string-no-properties 0)) + (setq level (1+ level)) + (setq level (1- level))) + (when (< level 1) + (setq continue nil) + ) + ) ;t + ) ;cond + ) ;while + (when (not (= level 0)) (goto-char pos)) + ret)) + +(defun web-mode-block-sb (expr &optional limit noerror) + (unless limit (setq limit (web-mode-block-beginning-position (point)))) + (unless noerror (setq noerror t)) + (let ((continue t) ret) + (while continue + (setq ret (search-backward expr limit noerror)) + (when (or (null ret) + (not (get-text-property (point) 'block-token))) + (setq continue nil) + ) ;when + ) ;while + ret)) + +(defun web-mode-block-sf (expr &optional limit noerror) + (unless limit (setq limit (web-mode-block-end-position (point)))) + (unless noerror (setq noerror t)) + (let ((continue t) ret) + (while continue + (setq ret (search-forward expr limit noerror)) + (when (or (null ret) + (not (get-text-property (point) 'block-token))) + (setq continue nil) + ) ;when + ) ;while + ret)) + +(defun web-mode-block-rsb (regexp &optional limit noerror) + (unless limit (setq limit (web-mode-block-beginning-position (point)))) + (unless noerror (setq noerror t)) + (let ((continue t) ret) + (while continue + (setq ret (re-search-backward regexp limit noerror)) + (when (or (null ret) + (not (get-text-property (point) 'block-token))) + (setq continue nil) + ) ;when + ) ;while + ret)) + +(defun web-mode-block-rsf (regexp &optional limit noerror) + (unless limit (setq limit (web-mode-block-end-position (point)))) + (unless noerror (setq noerror t)) + (let ((continue t) ret) + (while continue + (setq ret (re-search-forward regexp limit noerror)) + (when (or (null ret) + (not (get-text-property (point) 'block-token))) + (setq continue nil) + ) ;when + ) ;while + ret)) + +(defun web-mode-part-sb (expr &optional limit noerror) + (unless limit (setq limit (web-mode-part-beginning-position (point)))) + (unless noerror (setq noerror t)) + (let ((continue t) ret) + (while continue + (setq ret (search-backward expr limit noerror)) + (when (or (null ret) + (and (not (get-text-property (point) 'part-token)) + (not (get-text-property (point) 'block-side))) + ) + (setq continue nil) + ) ;when + ) ;while + ret)) + +(defun web-mode-part-sf (expr &optional limit noerror) + (unless limit (setq limit (web-mode-part-end-position (point)))) + (unless noerror (setq noerror t)) + (let ((continue t) ret) + (while continue + (setq ret (search-forward expr limit noerror)) + (when (or (null ret) + (and (not (get-text-property (point) 'part-token)) + (not (get-text-property (point) 'block-side))) + ) + (setq continue nil) + ) ;when + ) ;while + ret)) + +(defun web-mode-part-rsb (regexp &optional limit noerror) + (unless limit (setq limit (web-mode-part-beginning-position (point)))) + (unless noerror (setq noerror t)) + (let ((continue t) ret) + (while continue + (setq ret (re-search-backward regexp limit noerror)) + (when (or (null ret) + (and (not (get-text-property (point) 'part-token)) + (not (get-text-property (point) 'block-side))) + ) + (setq continue nil) + ) ;when + ) ;while + ret)) + +(defun web-mode-part-rsf (regexp &optional limit noerror) + (unless limit (setq limit (web-mode-part-end-position (point)))) + (unless noerror (setq noerror t)) + (let ((continue t) ret) + (while continue + (setq ret (re-search-forward regexp limit t)) + (when (or (null ret) + (and (not (get-text-property (point) 'part-token)) + (not (get-text-property (point) 'block-side))) + ) + (setq continue nil) + ) ;when + ) ;while + ret)) + +(defun web-mode-javascript-rsb (regexp &optional limit noerror) + (unless limit (setq limit (web-mode-part-beginning-position (point)))) + (unless noerror (setq noerror t)) + (let ((continue t) ret) + (while continue + (setq ret (re-search-backward regexp limit noerror)) + (when (or (null ret) + (and (not (get-text-property (point) 'part-token)) + (not (get-text-property (point) 'block-side)) + (not (get-text-property (point) 'jsx-depth))) + ) + (setq continue nil) + ) ;when + ) ;while + ret)) + +(defun web-mode-javascript-rsf (regexp &optional limit noerror) + (unless limit (setq limit (web-mode-part-end-position (point)))) + (unless noerror (setq noerror t)) + (let ((continue t) ret) + (while continue + (setq ret (re-search-forward regexp limit t)) + (when (or (null ret) + (and (not (get-text-property (point) 'part-token)) + (not (get-text-property (point) 'block-side)) + (not (get-text-property (point) 'jsx-depth))) + ) + (setq continue nil) + ) ;when + ) ;while + ret)) + +(defun web-mode-dom-sf (expr &optional limit noerror) + (unless noerror (setq noerror t)) + (let ((continue t) ret) + (while continue + (setq ret (search-forward expr limit noerror)) + (if (or (null ret) + (not (get-text-property (- (point) (length expr)) 'block-side))) + (setq continue nil)) + ) + ret)) + +(defun web-mode-dom-rsf (regexp &optional limit noerror) + (unless noerror (setq noerror t)) + (let ((continue t) (ret nil)) + (while continue + (setq ret (re-search-forward regexp limit noerror)) + ;; (message "ret=%S point=%S limit=%S i=%S" ret (point) limit 0) + (cond + ((null ret) + (setq continue nil)) + ((or (get-text-property (match-beginning 0) 'block-side) + (get-text-property (match-beginning 0) 'part-token)) + ) + (t + (setq continue nil)) + ) ;cond + ) ;while + ret)) + +(defun web-mode-rsb-position (pos regexp &optional limit noerror) + (unless noerror (setq noerror t)) + (save-excursion + (goto-char pos) + (if (re-search-backward regexp limit noerror) (point) nil) + )) + +(defun web-mode-rsb (regexp &optional limit noerror) + (unless noerror (setq noerror t)) + (let ((continue t) ret) + (while continue + (setq ret (re-search-backward regexp limit noerror)) + (if (or (null ret) + (not (web-mode-is-comment-or-string))) + (setq continue nil))) + ret)) + +(defun web-mode-rsf (regexp &optional limit noerror) + (unless noerror (setq noerror t)) + (let ((continue t) ret) + (while continue + (setq ret (re-search-forward regexp limit noerror)) + (if (or (null ret) + (not (web-mode-is-comment-or-string))) + (setq continue nil)) + ) + ret)) + +(defun web-mode-sb (expr &optional limit noerror) + (unless noerror (setq noerror t)) + (let ((continue t) ret) + (while continue + (setq ret (search-backward expr limit noerror)) + (if (or (null ret) + (not (web-mode-is-comment-or-string))) + (setq continue nil))) + ret)) + +(defun web-mode-sf (expr &optional limit noerror) + (unless noerror (setq noerror t)) + (let ((continue t) ret) + (while continue + (setq ret (search-forward expr limit noerror)) + (if (or (null ret) + (not (web-mode-is-comment-or-string))) + (setq continue nil))) + ret)) + +(defun web-mode-content-rsf (regexp &optional limit noerror) + (unless noerror (setq noerror t)) + (let ((continue t) ret beg end) + (while continue + (setq ret (re-search-forward regexp limit noerror) + beg (if (null ret) (point) (match-beginning 0)) + end (if (null ret) (point) (1- (match-end 0)))) + (if (or (null ret) + (and (web-mode-is-content beg) + (web-mode-is-content end))) + (setq continue nil))) + ret)) + +;;---- ADVICES ----------------------------------------------------------------- + +(defadvice ac-start (before web-mode-set-up-ac-sources activate) + "Set `ac-sources' based on current language before running auto-complete." + (when (equal major-mode 'web-mode) + ;; set ignore each time to nil. User has to implement a hook to change it + ;; for each completion + (setq web-mode-ignore-ac-start-advice nil) + (run-hooks 'web-mode-before-auto-complete-hooks) + (unless web-mode-ignore-ac-start-advice + (when web-mode-ac-sources-alist + (let ((new-web-mode-ac-sources + (assoc (web-mode-language-at-pos) + web-mode-ac-sources-alist))) + (setq ac-sources (cdr new-web-mode-ac-sources))))))) + +;;---- MINOR MODE ADDONS ------------------------------------------------------- + +(defun web-mode-yasnippet-exit-hook () + "Yasnippet exit hook" + (when (and (boundp 'yas-snippet-beg) (boundp 'yas-snippet-end)) + (indent-region yas-snippet-beg yas-snippet-end))) + +(defun web-mode-imenu-index () + (interactive) + "Returns imenu items." + (let (toc-index + line) + (save-excursion + (goto-char (point-min)) + (while (not (eobp)) + (setq line (buffer-substring-no-properties + (line-beginning-position) + (line-end-position))) + (let (found + (i 0) + item + regexp + type + type-idx + content + content-idx + content-regexp + close-tag-regexp + concat-str + jumpto + str) + (while (and (not found ) (< i (length web-mode-imenu-regexp-list))) + (setq item (nth i web-mode-imenu-regexp-list)) + (setq regexp (nth 0 item)) + (setq type-idx (nth 1 item)) + (setq content-idx (nth 2 item)) + (setq concat-str (nth 3 item)) + (when (not (numberp content-idx)) + (setq content-regexp (nth 2 item) + close-tag-regexp (nth 4 item) + content-idx nil)) + + (when (string-match regexp line) + + (cond + (content-idx + (setq type (match-string type-idx line)) + (setq content (match-string content-idx line)) + (setq str (concat type concat-str content)) + (setq jumpto (line-beginning-position))) + (t + (let (limit) + (setq type (match-string type-idx line)) + (goto-char (line-beginning-position)) + (save-excursion + (setq limit (re-search-forward close-tag-regexp (point-max) t))) + + (when limit + (when (re-search-forward content-regexp limit t) + (setq content (match-string 1)) + (setq str (concat type concat-str content)) + (setq jumpto (line-beginning-position)) + ) + ))) + ) + (when str (setq toc-index + (cons (cons str jumpto) + toc-index) + ) + (setq found t)) + ) + (setq i (1+ i)))) + (forward-line) + (goto-char (line-end-position)) ;; make sure we are at eobp + )) + (nreverse toc-index))) + +;;---- UNIT TESTING ------------------------------------------------------------ + +(defun web-mode-test () + "Executes web-mode unit tests. See `web-mode-tests-directory'." + (interactive) + (let (files ret regexp) + (setq regexp "^[[:alnum:]][[:alnum:]._]+\\'") + (setq files (directory-files web-mode-tests-directory t regexp)) + (dolist (file files) + (cond + ((eq (string-to-char (file-name-nondirectory file)) ?\_) + (delete-file file)) + (t + (setq ret (web-mode-test-process file))) + ) ;cond + ) ;dolist + )) + +(defun web-mode-test-process (file) + (with-temp-buffer + (let (out sig1 sig2 success err) + (setq-default indent-tabs-mode nil) + (if (string-match-p "sql" file) + (setq web-mode-enable-sql-detection t) + (setq web-mode-enable-sql-detection nil)) + (insert-file-contents file) + (set-visited-file-name file) + (web-mode) + (setq sig1 (md5 (current-buffer))) + (delete-horizontal-space) + (while (not (eobp)) + (forward-line) + (delete-horizontal-space) + (end-of-line)) + (web-mode-buffer-indent) + (setq sig2 (md5 (current-buffer))) + (setq success (string= sig1 sig2)) + (setq out (concat (if success "ok" "ko") " : " (file-name-nondirectory file) "\n")) + (princ out) + (setq err (concat (file-name-directory file) "_err." (file-name-nondirectory file))) + (if success + (when (file-readable-p err) + (delete-file err)) + (write-file err) + (message "[%s]" (buffer-string)) + ) ;if + out))) + +;;---- MISC -------------------------------------------------------------------- + +(defun web-mode-set-engine (engine) + "Set the engine for the current buffer." + (interactive + (list (completing-read + "Engine: " + (let (engines) + (dolist (elt web-mode-engines) + (setq engines (append engines (list (car elt))))) + engines)))) + (setq web-mode-content-type "html" + web-mode-engine (web-mode-engine-canonical-name engine) + web-mode-minor-engine engine) + (web-mode-on-engine-setted) + (web-mode-buffer-fontify)) + +(defun web-mode-set-content-type (content-type) + "Set the content-type for the current buffer" + (interactive (list (completing-read "Content-type: " web-mode-part-content-types))) + (setq web-mode-content-type content-type) + (when (called-interactively-p 'any) + ) + (web-mode-buffer-fontify)) + +(defun web-mode-on-engine-setted () + (let (elt elts) + + (when (string= web-mode-engine "razor") (setq web-mode-enable-block-face t)) + ;;(setq web-mode-engine-attr-regexp (cdr (assoc web-mode-engine web-mode-engine-attr-regexps))) + (setq web-mode-engine-token-regexp (cdr (assoc web-mode-engine web-mode-engine-token-regexps))) + + ;;(message "%S %S %S" web-mode-engine web-mode-engine-attr-regexp web-mode-engine-token-regexp) + + (when (null web-mode-minor-engine) + (setq web-mode-minor-engine "none")) + + (setq elt (assoc web-mode-engine web-mode-engine-open-delimiter-regexps)) + (cond + (elt + (setq web-mode-block-regexp (cdr elt))) + ((string= web-mode-engine "archibus") + (setq web-mode-block-regexp nil)) + (t + (setq web-mode-engine "none")) + ) + + (unless (boundp 'web-mode-extra-auto-pairs) + (setq web-mode-extra-auto-pairs nil)) + + (setq web-mode-auto-pairs + (append + (cdr (assoc web-mode-engine web-mode-engines-auto-pairs)) + (cdr (assoc nil web-mode-engines-auto-pairs)) + (cdr (assoc web-mode-engine web-mode-extra-auto-pairs)) + (cdr (assoc nil web-mode-extra-auto-pairs)))) + + (unless (boundp 'web-mode-extra-snippets) + (setq web-mode-extra-snippets nil)) + + (setq elts + (append + (cdr (assoc web-mode-engine web-mode-extra-snippets)) + (cdr (assoc nil web-mode-extra-snippets)) + (cdr (assoc web-mode-engine web-mode-engines-snippets)) + (cdr (assoc nil web-mode-engines-snippets)))) + + ;;(message "%S" elts) + + (dolist (elt elts) + (unless (assoc (car elt) web-mode-snippets) + (setq web-mode-snippets (cons elt web-mode-snippets))) + ) + + (setq web-mode-engine-font-lock-keywords + (symbol-value (cdr (assoc web-mode-engine web-mode-engines-font-lock-keywords)))) + + (when (and (string= web-mode-minor-engine "jinja") + (not (member "endtrans" web-mode-django-control-blocks))) + (add-to-list 'web-mode-django-control-blocks "endtrans") + (setq web-mode-django-control-blocks-regexp + (regexp-opt web-mode-django-control-blocks t)) + ) + + (when (string= web-mode-engine "spip") + (modify-syntax-entry ?# "w" (syntax-table))) + +;; (message "%S" (symbol-value (cdr (assoc web-mode-engine web-mode-engines-font-lock-keywords)))) + + )) + +(defun web-mode-detect-engine () + (save-excursion + (goto-char (point-min)) + (when (re-search-forward "-\\*- engine:[ ]*\\([[:alnum:]-]+\\)[ ]*-\\*-" web-mode-chunk-length t) + (setq web-mode-minor-engine (match-string-no-properties 1)) + (setq web-mode-engine (web-mode-engine-canonical-name web-mode-minor-engine))) + web-mode-minor-engine)) + +(defun web-mode-guess-engine-and-content-type () + (let (buff-name found) + + (setq buff-name (buffer-file-name)) + (unless buff-name (setq buff-name (buffer-name))) + (setq web-mode-is-scratch (string= buff-name "*scratch*")) + (setq web-mode-content-type nil) + + (when (boundp 'web-mode-content-types-alist) + (setq found nil) + (dolist (elt web-mode-content-types-alist) + (when (and (not found) (string-match-p (cdr elt) buff-name)) + (setq web-mode-content-type (car elt) + found t)) + ) ;dolist + ) ;when + + (unless web-mode-content-type + (setq found nil) + (dolist (elt web-mode-content-types) + (when (and (not found) (string-match-p (cdr elt) buff-name)) + (setq web-mode-content-type (car elt) + found t) + ;;(message "%S" web-mode-content-type) + ) ;when + ) ;dolist + ) ;unless + + (when (boundp 'web-mode-engines-alist) + (setq found nil) + (dolist (elt web-mode-engines-alist) + (cond + ((stringp (cdr elt)) + (when (string-match-p (cdr elt) buff-name) + (setq web-mode-engine (car elt)))) + ((functionp (cdr elt)) + (when (funcall (cdr elt)) + (setq web-mode-engine (car elt)))) + ) ;cond + ) ;dolist + ) ;when + + (unless web-mode-engine + (setq found nil) + (dolist (elt web-mode-engine-file-regexps) + ;;(message "%S %S" (cdr elt) buff-name) + (when (and (not found) (string-match-p (cdr elt) buff-name)) + (setq web-mode-engine (car elt) + found t)) + ) + ) + + (when (and (or (null web-mode-engine) (string= web-mode-engine "none")) + (string-match-p "php" (buffer-substring-no-properties + (line-beginning-position) + (line-end-position)))) + (setq web-mode-engine "php")) + + (when (and (string= web-mode-content-type "javascript") + (string-match-p "@jsx" + (buffer-substring-no-properties + (point-min) + (if (< (point-max) web-mode-chunk-length) + (point-max) + web-mode-chunk-length) + ))) + (setq web-mode-content-type "jsx")) + + (when web-mode-engine + (setq web-mode-minor-engine web-mode-engine + web-mode-engine (web-mode-engine-canonical-name web-mode-engine)) + ) + + (when (and (or (null web-mode-engine) + (string= web-mode-engine "none")) + web-mode-enable-engine-detection) + (web-mode-detect-engine)) + + (web-mode-on-engine-setted) + + )) + +(defun web-mode-engine-canonical-name (name) + (let (engine) + (cond + ((null name) + nil) + ((assoc name web-mode-engines) + name) + (t + (dolist (elt web-mode-engines) + (when (and (null engine) (member name (cdr elt))) + (setq engine (car elt))) + ) ;dolist + engine) + ))) + +(defun web-mode-on-after-save () + (when web-mode-is-scratch + (web-mode-guess-engine-and-content-type) + (web-mode-buffer-fontify)) + nil) + +(defun web-mode-on-exit () + (web-mode-with-silent-modifications + (put-text-property (point-min) (point-max) 'invisible nil) + (remove-overlays) + (remove-hook 'change-major-mode-hook 'web-mode-on-exit t) + )) + +(defun web-mode-file-link (file) + "Insert a link to a file in html document. This function can be +extended to support more filetypes by customizing +`web-mode-links'." + (interactive + (list (file-relative-name (read-file-name "Link file: ")))) + (let ((matched nil) + (point-line (line-number-at-pos)) + (point-column (current-column))) + (dolist (type web-mode-links) + (when (string-match (car type) file) + (setq matched t) + (when (nth 2 type) + (goto-char (point-min)) + (search-forward "</head>") + (backward-char 7) + (open-line 1)) + (insert (format (cadr type) file)) + (indent-for-tab-command) + (when (nth 2 type) + ;; return point where it was and fix indentation + (forward-line) + (indent-for-tab-command) + (if (> point-line (- (line-number-at-pos) 2)) + (forward-line (+ (- point-line (line-number-at-pos)) 1)) + (forward-line (- point-line (line-number-at-pos)))) + (move-to-column point-column)) + ;; move point back if needed + (backward-char (nth 3 type)))) + (when (not matched) + (user-error "Unknown file type")))) + +(defun web-mode-reload () + "Reload web-mode." + (interactive) + (web-mode-with-silent-modifications + (put-text-property (point-min) (point-max) 'invisible nil) + (remove-overlays) + (setq font-lock-unfontify-region-function 'font-lock-default-unfontify-region) + (load "web-mode.el") + (setq web-mode-change-beg nil + web-mode-change-end nil) + (web-mode) + )) + +(defun web-mode-measure (msg) + (let (sub) + (when (null web-mode-time) (setq web-mode-time (current-time))) + (setq sub (time-subtract (current-time) web-mode-time)) + (when nil + (save-excursion + (let ((n 0)) + (goto-char (point-min)) + (while (web-mode-tag-next) + (setq n (1+ n)) + ) + (message "%S tags found" n) + ))) + (message "%18s: time elapsed = %Ss %9Sµs" msg (nth 1 sub) (nth 2 sub)) + )) + +(defun web-mode-reveal () + "Display text properties at point." + (interactive) + (let (symbols out) + (setq out (format + "[point=%S engine=%S minor=%S content-type=%S language-at-pos=%S]\n" + (point) + web-mode-engine + web-mode-minor-engine + web-mode-content-type + (web-mode-language-at-pos (point)))) + (setq symbols (append web-mode-scan-properties '(font-lock-face face))) + (dolist (symbol symbols) + (when symbol + (setq out (concat out (format "%s(%S) " (symbol-name symbol) (get-text-property (point) symbol))))) + ) + (message "%s\n" out) + ;;(message "syntax-class=%S" (syntax-class (syntax-after (point)))) + (message nil))) + +(defun web-mode-toggle-tracing () + "Toggle tracing." + (interactive) + (if web-mode-trace + (setq web-mode-trace nil) + (message "** tracing on ** point(%S) web-mode-change-beg(%S) web-mode-change-end(%S) web-mode-skip-fontification(%S)" + (point) web-mode-change-beg web-mode-change-end web-mode-skip-fontification) + (setq web-mode-trace t))) + +(defun web-mode-debug () + "Display informations useful for debugging." + (interactive) + (let ((modes nil) + (customs '(web-mode-enable-current-column-highlight web-mode-enable-current-element-highlight indent-tabs-mode)) + (ignore '(abbrev-mode auto-composition-mode auto-compression-mode auto-encryption-mode auto-insert-mode blink-cursor-mode column-number-mode delete-selection-mode display-time-mode electric-indent-mode file-name-shadow-mode font-lock-mode global-font-lock-mode global-hl-line-mode line-number-mode menu-bar-mode mouse-wheel-mode recentf-mode show-point-mode tool-bar-mode tooltip-mode transient-mark-mode))) + (message "\n") + (message "--- WEB-MODE DEBUG BEG ---") + (message "versions: emacs(%S.%S) web-mode(%S)" + emacs-major-version emacs-minor-version web-mode-version) + (message "vars: engine(%S) minor(%S) content-type(%S) file(%S)" + web-mode-engine + web-mode-minor-engine + web-mode-content-type + (or (buffer-file-name) (buffer-name))) + (message "system: window(%S) config(%S)" window-system system-configuration) + (message "colors: fg(%S) bg(%S) " + (cdr (assoc 'foreground-color default-frame-alist)) + (cdr (assoc 'background-color default-frame-alist))) + (mapc (lambda (mode) + (condition-case nil + (if (and (symbolp mode) (symbol-value mode) (not (member mode ignore))) + (push mode modes)) + (error nil)) + ) ;lambda + minor-mode-list) + (message "minor modes: %S" modes) + (message "vars:") + (dolist (custom customs) + (message (format "%s=%S " (symbol-name custom) (symbol-value custom)))) + (message "--- WEB-MODE DEBUG END ---") + (switch-to-buffer "*Messages*") + (goto-char (point-max)) + (recenter) + )) + +(provide 'web-mode) + +;;; web-mode.el ends here + +;; Local Variables: +;; coding: utf-8 +;; indent-tabs-mode: nil +;; End: diff --git a/init.el b/init.el @@ -303,7 +303,7 @@ ("melpa-stable" . "https://stable.melpa.org/packages/") ("melpa" . "https://melpa.org/packages/"))) '(package-selected-packages - '(csharp-mode editorconfig forge elfeed-tube-mpv elfeed-tube cider restclient-jq graphviz-dot-mode consult-eglot jq-mode multiple-cursors ob-restclient restclient vterm deadgrep helpful pdf-tools paredit-menu paredit corfu sly eglot aggressive-indent project nov nhexl-mode elfeed magit yaml-mode json-mode lua-mode go-mode geiser-guile geiser org-roam org-contrib org ace-window expand-region consult marginalia uuidgen request diminish which-key)) + '(web-mode lexic csharp-mode editorconfig forge elfeed-tube-mpv elfeed-tube cider restclient-jq graphviz-dot-mode consult-eglot jq-mode multiple-cursors ob-restclient restclient vterm deadgrep helpful pdf-tools paredit-menu paredit corfu sly eglot aggressive-indent project nov nhexl-mode elfeed magit yaml-mode json-mode lua-mode go-mode geiser-guile geiser org-roam org-contrib org ace-window expand-region consult marginalia uuidgen request diminish which-key)) '(pcomplete-ignore-case t t) '(pixel-scroll-precision-mode t) '(read-buffer-completion-ignore-case t)