config

Personal configuration.
git clone git://code.dwrz.net/config
Log | Files | Refs

web-mode.el (586563B)


      1 ;;; web-mode.el --- major mode for editing web templates -*- coding: utf-8; lexical-binding: t; -*-
      2 
      3 ;; Copyright 2011-2024 François-Xavier Bois
      4 
      5 ;; Version: 17.3.20
      6 ;; Author: François-Xavier Bois
      7 ;; Maintainer: François-Xavier Bois <fxbois@gmail.com>
      8 ;; Package-Requires: ((emacs "23.1"))
      9 ;; URL: https://web-mode.org
     10 ;; Repository: http://github.com/fxbois/web-mode
     11 ;; Created: July 2011
     12 ;; Keywords: languages
     13 ;; License: GNU General Public License >= 3
     14 ;; Distribution: This file is not part of Emacs
     15 
     16 ;;; Commentary:
     17 
     18 ;;==============================================================================
     19 ;; WEB-MODE is sponsored by ** Kernix ** Best Digital Agency & Data Lab (Paris)
     20 ;;==============================================================================
     21 
     22 ;;; Code:
     23 
     24 ;;---- CONSTS ------------------------------------------------------------------
     25 
     26 (defconst web-mode-version "17.3.20"
     27   "Web Mode version.")
     28 
     29 ;;---- GROUPS ------------------------------------------------------------------
     30 
     31 (defgroup web-mode nil
     32   "Major mode for editing web templates"
     33   :group 'languages
     34   :prefix "web-"
     35   :link '(url-link :tag "Site" "https://web-mode.org")
     36   :link '(url-link :tag "Repository" "https://github.com/fxbois/web-mode"))
     37 
     38 (defgroup web-mode-faces nil
     39   "Faces for syntax highlighting."
     40   :group 'web-mode
     41   :group 'faces)
     42 
     43 ;;---- CUSTOMS -----------------------------------------------------------------
     44 
     45 (defcustom web-mode-block-padding 0
     46   "Multi-line block (php, ruby, java, python, asp, etc.) left padding.
     47    -1 to have to code aligned on the column 0."
     48   :type '(choice (integer :tags "Number of spaces")
     49           (const :tags "No indent" nil))
     50   :group 'web-mode)
     51 
     52 (defcustom web-mode-part-padding 1
     53   "Part elements (script, style) left padding."
     54   :type '(choice (integer :tags "Number of spaces")
     55           (const :tags "No indent" nil))
     56   :group 'web-mode)
     57 
     58 (defcustom web-mode-script-padding web-mode-part-padding
     59   "Script element left padding."
     60   :type '(choice (integer :tags "Number of spaces")
     61           (const :tags "No indent" nil))
     62   :group 'web-mode)
     63 
     64 (defcustom web-mode-style-padding web-mode-part-padding
     65   "Style element left padding."
     66   :type '(choice (integer :tags "Number of spaces")
     67           (const :tags "No indent" nil))
     68   :group 'web-mode)
     69 
     70 (defcustom web-mode-attr-indent-offset nil
     71   "Html attribute indentation level."
     72   :type '(choice (integer :tags "Number of spaces")
     73           (const :tags "Default" nil))
     74   :group 'web-mode)
     75 ;;;###autoload
     76 (put 'web-mode-attr-indent-offset
     77      'safe-local-variable #'(lambda (v) (or (integerp v) (booleanp v))))
     78 
     79 (defcustom web-mode-attr-value-indent-offset nil
     80   "Html attribute value indentation level."
     81   :type '(choice (integer :tags "Number of spaces")
     82           (const :tags "Default" nil))
     83   :group 'web-mode)
     84 ;;;###autoload
     85 (put 'web-mode-attr-value-indent-offset
     86      'safe-local-variable #'(lambda (v) (or (integerp v) (booleanp v))))
     87 
     88 (defcustom web-mode-markup-indent-offset
     89   (if (and (boundp 'standard-indent) standard-indent) standard-indent 2)
     90   "Html indentation level."
     91   :type 'integer
     92   :group 'web-mode)
     93 ;;;###autoload
     94 (put 'web-mode-markup-indent-offset 'safe-local-variable #'integerp)
     95 
     96 (defcustom web-mode-markup-comment-indent-offset
     97   5
     98   "Html comment indentation level."
     99   :type 'integer
    100   :group 'web-mode)
    101 ;;;###autoload
    102 (put 'web-mode-markup-comment-indent-offset 'safe-local-variable #'integerp)
    103 
    104 (defcustom web-mode-css-indent-offset
    105   (if (and (boundp 'standard-indent) standard-indent) standard-indent 2)
    106   "CSS indentation level."
    107   :type 'integer
    108   :group 'web-mode)
    109 ;;;###autoload
    110 (put 'web-mode-css-indent-offset 'safe-local-variable #'integerp)
    111 
    112 (defcustom web-mode-code-indent-offset
    113   (if (and (boundp 'standard-indent) standard-indent) standard-indent 2)
    114   "Code (javascript, php, etc.) indentation level."
    115   :type 'integer
    116   :group 'web-mode)
    117 ;;;###autoload
    118 (put 'web-mode-code-indent-offset 'safe-local-variable #'integerp)
    119 
    120 (defcustom web-mode-sql-indent-offset 4
    121   "Sql (inside strings) indentation level."
    122   :type 'integer
    123   :group 'web-mode)
    124 ;;;###autoload
    125 (put 'web-mode-sql-indent-offset 'safe-local-variable #'integerp)
    126 
    127 (defcustom web-mode-enable-css-colorization (display-graphic-p)
    128   "In a CSS part, set background according to the color: #xxx, rgb(x,x,x)."
    129   :type 'boolean
    130   :group 'web-mode)
    131 
    132 (defcustom web-mode-enable-comment-interpolation nil
    133   "Enable highlight of keywords like FIXME, TODO, etc. in comments."
    134   :type 'boolean
    135   :group 'web-mode)
    136 
    137 (defcustom web-mode-enable-comment-annotation nil
    138   "Enable annotation in comments (jsdoc, phpdoc, etc.)."
    139   :type 'boolean
    140   :group 'web-mode)
    141 
    142 (defcustom web-mode-enable-auto-indentation (display-graphic-p)
    143   "Auto-indentation."
    144   :type 'boolean
    145   :group 'web-mode)
    146 
    147 (defcustom web-mode-enable-auto-closing (display-graphic-p)
    148   "Auto-closing."
    149   :type 'boolean
    150   :group 'web-mode)
    151 
    152 (defcustom web-mode-enable-auto-pairing (display-graphic-p)
    153   "Auto-pairing."
    154   :type 'boolean
    155   :group 'web-mode)
    156 
    157 (defcustom web-mode-enable-auto-opening (display-graphic-p)
    158   "Html element auto-opening."
    159   :type 'boolean
    160   :group 'web-mode)
    161 
    162 (defcustom web-mode-enable-auto-quoting (display-graphic-p)
    163   "Add double quotes after the character = in a tag."
    164   :type 'boolean
    165   :group 'web-mode)
    166 
    167 (defcustom web-mode-enable-auto-expanding nil
    168   "e.g. s/ expands to <span>|</span>."
    169   :type 'boolean
    170   :group 'web-mode)
    171 
    172 (defcustom web-mode-enable-curly-brace-indentation nil
    173   "Indent lines beginning with {."
    174   :type 'boolean
    175   :group 'web-mode)
    176 
    177 (defcustom web-mode-enable-control-block-indentation t
    178   "Control blocks increase indentation."
    179   :type 'boolean
    180   :group 'web-mode)
    181 
    182 (defcustom web-mode-enable-current-element-highlight nil
    183   "Enable current element highlight."
    184   :type 'boolean
    185   :group 'web-mode)
    186 
    187 (defcustom web-mode-enable-current-column-highlight nil
    188   "Show column for current element."
    189   :type 'boolean
    190   :group 'web-mode)
    191 
    192 (defcustom web-mode-enable-whitespace-fontification nil
    193   "Enable whitespaces."
    194   :type 'boolean
    195   :group 'web-mode)
    196 
    197 (defcustom web-mode-enable-html-entities-fontification nil
    198   "Enable html entities fontification."
    199   :type 'boolean
    200   :group 'web-mode)
    201 
    202 (defcustom web-mode-enable-block-face nil
    203   "Enable block face (useful for setting a background for example).
    204 See web-mode-block-face."
    205   :type 'boolean
    206   :group 'web-mode)
    207 
    208 (defcustom web-mode-enable-part-face nil
    209   "Enable part face (useful for setting background of <style> or <script>
    210  elements for example). See web-mode-part-face."
    211   :type 'boolean
    212   :group 'web-mode)
    213 
    214 (defcustom web-mode-enable-inlays nil
    215   "Enable inlays (e.g. LaTeX) highlighting."
    216   :type 'boolean
    217   :group 'web-mode)
    218 
    219 (defcustom web-mode-enable-sexp-functions t
    220   "Enable specific sexp functions."
    221   :type 'boolean
    222   :group 'web-mode)
    223 
    224 (defcustom web-mode-enable-string-interpolation t
    225   "Enable string interpolation fontification (php and erb)."
    226   :type 'boolean
    227   :group 'web-mode)
    228 
    229 (defcustom web-mode-enable-literal-interpolation t
    230   "Enable template literal fontification. e.g. css` `."
    231   :type 'boolean
    232   :group 'web-mode)
    233 
    234 (defcustom web-mode-enable-sql-detection nil
    235   "Enable fontification and indentation of sql queries in strings."
    236   :type 'boolean
    237   :group 'web-mode)
    238 
    239 (defcustom web-mode-enable-heredoc-fontification t
    240   "Enable heredoc fontification. The identifier should contain JS, JAVASCRIPT,
    241  CSS or HTML."
    242   :type 'boolean
    243   :group 'web-mode)
    244 
    245 (defcustom web-mode-enable-element-content-fontification nil
    246   "Enable element content fontification. The content of an element can have a
    247 face associated."
    248   :type 'boolean
    249   :group 'web-mode)
    250 
    251 (defcustom web-mode-enable-element-tag-fontification nil
    252   "Enable tag name fontification."
    253   :type 'boolean
    254   :group 'web-mode)
    255 
    256 (defcustom web-mode-enable-front-matter-block nil
    257   "Enable front matter block (data at the beginning the template
    258 between --- and ---)."
    259   :type 'boolean
    260   :group 'web-mode)
    261 
    262 (defcustom web-mode-enable-engine-detection nil
    263   "Detect such directive -*- engine: ENGINE -*- at the top of the file."
    264   :type 'boolean
    265   :group 'web-mode)
    266 
    267 (defcustom web-mode-enable-optional-tags nil
    268   "Enable omission of certain closing tags (e.g. a li open tag followed
    269 by a li open tag is valid)."
    270   :type 'boolean
    271   :group 'web-mode)
    272 
    273 (defcustom web-mode-comment-style 1
    274   "Comment style : 1 = default, 2 = force server comments outside a block."
    275   :group 'web-mode
    276   :type '(choice (const :tag "Default" 1)
    277           (const :tag "Force engine comments" 2)))
    278 
    279 (defcustom web-mode-indent-style 2
    280   "Indentation style."
    281   :group 'web-mode
    282   :type '(choice (const :tag "Default (all lines are indented)" 2)
    283           (const :tag "Text at the beginning of line is not indented" 1)))
    284 
    285 (defcustom web-mode-auto-close-style 1
    286   "Auto-close style."
    287   :group 'web-mode
    288   :type '(choice (const :tag "Auto-close on </" 1)
    289           (const :tag "Auto-close on > and </" 2)
    290           (const :tag "Auto-close on < and >/>" 3)))
    291 
    292 (defcustom web-mode-auto-quote-style 1
    293   "Auto-quoting style."
    294   :group 'web-mode
    295   :type '(choice (const :tag "Auto-quotes with double quote" 1)
    296           (const :tag "Auto-quotes with single quote" 2)
    297           (const :tag "Auto-quotes with paren (for jsx)" 3)))
    298 
    299 (defcustom web-mode-extra-expanders '()
    300   "A list of additional expanders."
    301   :type '(alist :key-type string :value-type string)
    302   :group 'web-mode)
    303 
    304 (defcustom web-mode-extra-auto-pairs '()
    305   "A list of additional auto-pairs."
    306   :type '(alist :key-type string :value-type string)
    307   :group 'web-mode)
    308 
    309 (defcustom web-mode-extra-snippets '()
    310   "A list of additional snippets."
    311   :type '(alist :key-type string :value-type string)
    312   :group 'web-mode)
    313 
    314 (defcustom web-mode-extra-builtins '()
    315   "A list of additional builtins."
    316   :type '(alist :key-type string :value-type string)
    317   :group 'web-mode)
    318 
    319 (defcustom web-mode-extra-constants '()
    320   "A list of additional constants."
    321   :type '(alist :key-type string :value-type string)
    322   :group 'web-mode)
    323 
    324 (defcustom web-mode-extra-keywords '()
    325   "A list of additional keywords."
    326   :type '(alist :key-type string :value-type string)
    327   :group 'web-mode)
    328 
    329 (defcustom web-mode-extra-types '()
    330   "A list of additional types."
    331   :type '(alist :key-type string :value-type string)
    332   :group 'web-mode)
    333 
    334 (defcustom web-mode-extra-control-blocks '()
    335   "A list of additional control blocks."
    336   :type '(alist :key-type string :value-type (repeat string))
    337   :group 'web-mode)
    338 
    339 (defcustom web-mode-tests-directory (concat default-directory "tests/")
    340   "Directory containing all the unit tests."
    341   :type 'directory
    342   :group 'web-mode)
    343 
    344 (defcustom web-mode-jsx-depth-faces
    345   nil
    346   ;;'(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)
    347   "Each jsx depth has is own face."
    348   :type '(repeat face)
    349   :group 'web-mode)
    350 
    351 (defcustom web-mode-commands-like-expand-region
    352   '(web-mode-mark-and-expand er/expand-region mc/mark-next-like-this mc/mark-previous-like-this)
    353   "Add commmand here if you have some wrapper function for er/expand-region"
    354   :type '(repeat function)
    355   :group 'web-mode)
    356 
    357 (defcustom web-mode-comment-formats
    358   '(("java"       . "/*")
    359     ("javascript" . "/*")
    360     ("typescript" . "//")
    361     ("php"        . "/*")
    362     ("css"        . "/*"))
    363   "Default comment format for a language"
    364   :type '(alist :key-type string :value-type string)
    365   :group 'web-mode)
    366 
    367 (defcustom web-mode-script-template-types
    368   '("text/x-handlebars"
    369     "text/x-jquery-tmpl"
    370     "text/x-jsrender"
    371     "text/html"
    372     "text/ng-template"
    373     "text/x-template"
    374     "text/mustache"
    375     "text/x-dust-template")
    376   "<script> block types that are interpreted as HTML."
    377   :type '(repeat string)
    378   :group 'web-mode)
    379 
    380 ;; https://developer.mozilla.org/en-US/docs/Web/HTML/Element
    381 (defcustom web-mode-tag-list
    382   '("a" "abbr" "address" "area" "article" "aside" "audio" "b"
    383     "base" "bdi" "bdo" "blockquote" "body" "br" "button" "canvas"
    384     "caption" "cite" "code" "col" "colgroup" "data" "datalist"
    385     "dd" "del" "details" "dfn" "dialog" "div" "dl" "dt" "em"
    386     "embed" "fieldset" "figcaption" "figure" "footer" "form" "h1"
    387     "h2" "h3" "h4" "h5" "h6" "head" "header" "hgroup" "hr" "html"
    388     "i" "iframe" "img" "input" "ins" "kbd" "label" "legend" "li"
    389     "link" "main" "map" "mark" "math" "menu" "meta" "meter" "nav"
    390     "noscript" "object" "ol" "optgroup" "option" "output" "p"
    391     "picture" "pre" "progress" "q" "rp" "rt" "ruby" "s" "samp"
    392     "script" "search" "section" "select" "slot" "small" "source"
    393     "span" "strong" "style" "sub" "summary" "sup" "svg" "table"
    394     "tbody" "td" "template" "textarea" "tfoot" "th" "thead" "time"
    395     "title" "tr" "track" "u" "ul" "var" "video" "wbr")
    396   "HTML tags used for completion."
    397   :type '(repeat string)
    398   :group 'web-mode)
    399 
    400 
    401 ;; https://www.w3schools.com/tags/ref_attributes.asp
    402 ;; Attributes marked as deprecated in HTML 5 are not added.
    403 (defcustom web-mode-attribute-list
    404   '("accept" "accesskey" "action" "alt" "async" "autocomplete" "autofocus"
    405     "autoplay" "charset" "checked" "cite" "class" "cols" "colspan" "content"
    406     "contenteditable" "controls" "coords" "data" "datetime" "default" "defer"
    407     "dir" "dirname" "disabled" "download" "draggable" "enctype" "for" "form"
    408     "formaction" "headers" "height" "hidden" "high" "href" "hreflang" "http"
    409     "id" "ismap" "kind" "label" "lang" "list" "loop" "low" "max" "maxlength"
    410     "media" "method" "min" "multiple" "muted" "name" "novalidate" "onabort"
    411     "onafterprint" "onbeforeprint" "onbeforeunload" "onblur" "oncanplay"
    412     "oncanplaythrough" "onchange" "onclick" "oncontextmenu" "oncopy"
    413     "oncuechange" "oncut" "ondblclick" "ondrag" "ondragend" "ondragenter"
    414     "ondragleave" "ondragover" "ondragstart" "ondrop" "ondurationchange"
    415     "onemptied" "onended" "onerror" "onfocus" "onhashchange" "oninput"
    416     "oninvalid" "onkeydown" "onkeypress" "onkeyup" "onload" "onloadeddata"
    417     "onloadedmetadata" "onloadstart" "onmousedown" "onmousemove" "onmouseout"
    418     "onmouseover" "onmouseup" "onmousewheel" "onoffline" "ononline"
    419     "onpagehide" "onpageshow" "onpaste" "onpause" "onplay" "onplaying"
    420     "onpopstate" "onprogress" "onratechange" "onreset" "onresize" "onscroll"
    421     "onsearch" "onseeked" "onseeking" "onselect" "onstalled" "onstorage"
    422     "onsubmit" "onsuspend" "ontimeupdate" "ontoggle" "onunload"
    423     "onvolumechange" "onwaiting" "onwheel" "open" "optimum" "pattern"
    424     "placeholder" "poster" "preload" "readonly" "rel" "required" "reversed"
    425     "rows" "rowspan" "sandbox" "scope" "selected" "shape" "size" "sizes"
    426     "span" "spellcheck" "src" "srcdoc" "srclang" "srcset" "start" "step"
    427     "style" "tabindex" "target" "title" "translate" "type" "usemap" "value"
    428     "width" "wrap")
    429   "HTML attributes used for completion."
    430   :type '(repeat string)
    431   :group 'web-mode)
    432 
    433 (defcustom web-mode-engines-alist nil
    434   "A list of filename patterns and corresponding `web-mode' engine.
    435 For example,
    436 \(setq web-mode-engines-alist
    437        \\='((\"php\"    . \"\\\\.phtml\\\\\\='\")
    438          (\"blade\"  . \"\\\\.blade\\\\.\")))"
    439   :type '(alist :key-type string :value-type string)
    440   :group 'web-mode)
    441 
    442 ;;---- FACES -------------------------------------------------------------------
    443 
    444 (defface web-mode-error-face
    445     '((t :background "red"))
    446   "Face for warning."
    447   :group 'web-mode-faces)
    448 
    449 (defface web-mode-warning-face
    450     '((t :inherit font-lock-warning-face))
    451   "Face for warning."
    452   :group 'web-mode-faces)
    453 
    454 (defface web-mode-preprocessor-face
    455     '((t :inherit font-lock-preprocessor-face))
    456   "Face for preprocessor commands."
    457   :group 'web-mode-faces)
    458 
    459 (defface web-mode-preprocessor-face
    460     '((t :inherit font-lock-preprocessor-face))
    461   "Face for preprocessor."
    462   :group 'web-mode-faces)
    463 
    464 (defface web-mode-block-delimiter-face
    465     '((t :inherit font-lock-preprocessor-face))
    466   "Face for block delimiters."
    467   :group 'web-mode-faces)
    468 
    469 (defface web-mode-block-control-face
    470     '((t :inherit font-lock-preprocessor-face))
    471   "Face for preprocessor."
    472   :group 'web-mode-faces)
    473 
    474 (defface web-mode-builtin-face
    475     '((t :inherit font-lock-builtin-face))
    476   "Face for builtins."
    477   :group 'web-mode-faces)
    478 
    479 (defface web-mode-symbol-face
    480     '((t :foreground "goldenrod2"))
    481   "Face for symbols."
    482   :group 'web-mode-faces)
    483 
    484 (defface web-mode-doctype-face
    485     '((t :foreground "Grey"))
    486   "Face for html doctype."
    487   :group 'web-mode-faces)
    488 
    489 (defface web-mode-html-tag-face
    490     '((((class color) (min-colors 88) (background dark))  :foreground "Snow4")
    491       (((class color) (min-colors 88) (background light)) :foreground "Snow4")
    492       (((class color) (min-colors 16) (background dark))  :foreground "Snow4")
    493       (((class color) (min-colors 16) (background light)) :foreground "Grey15")
    494       (((class color) (min-colors 8))                     :foreground "Snow4")
    495       (((type tty) (class mono))                          :inverse-video t)
    496       (t                                                  :foreground "Snow4"))
    497   "Face for html tags."
    498   :group 'web-mode-faces)
    499 
    500 (defface web-mode-html-tag-custom-face
    501     '((t :inherit web-mode-html-tag-face))
    502   "Face for html custom tags (e.g. <polymer-element>)."
    503   :group 'web-mode-faces)
    504 
    505 (defface web-mode-html-tag-unclosed-face
    506     '((t :inherit web-mode-html-tag-face :underline t))
    507   "Face for unclosed tags."
    508   :group 'web-mode-faces)
    509 
    510 (defface web-mode-html-tag-namespaced-face
    511     '((t :inherit web-mode-block-control-face))
    512   "Face for html namespaced tags (e.g. <c:forEach>)."
    513   :group 'web-mode-faces)
    514 
    515 (defface web-mode-html-tag-bracket-face
    516     '((((class color) (min-colors 88) (background dark))  :foreground "Snow3")
    517       (((class color) (min-colors 88) (background light)) :foreground "Grey14")
    518       (((class color) (min-colors 16) (background dark))  :foreground "Snow3")
    519       (((class color) (min-colors 16) (background light)) :foreground "Grey14")
    520       (((class color) (min-colors 8))                     :foreground "Snow3")
    521       (((type tty) (class mono))                          :inverse-video t)
    522       (t                                                  :foreground "Snow3"))
    523   "Face for html tags angle brackets (<, > and />)."
    524   :group 'web-mode-faces)
    525 
    526 (defface web-mode-html-attr-name-face
    527     '((((class color) (min-colors 88) (background dark))  :foreground "Snow3")
    528       (((class color) (min-colors 88) (background light)) :foreground "Snow4")
    529       (((class color) (min-colors 16) (background dark))  :foreground "Snow3")
    530       (((class color) (min-colors 16) (background light)) :foreground "Grey13")
    531       (((class color) (min-colors 8))                     :foreground "Snow3")
    532       (((type tty) (class mono))                          :inverse-video t)
    533       (t                                                  :foreground "Snow4"))
    534   "Face for html attribute names."
    535   :group 'web-mode-faces)
    536 
    537 (defface web-mode-html-attr-custom-face
    538     '((t :inherit web-mode-html-attr-name-face))
    539   "Face for custom attribute names (e.g. data-*)."
    540   :group 'web-mode-faces)
    541 
    542 (defface web-mode-html-attr-engine-face
    543     '((t :inherit web-mode-block-delimiter-face))
    544   "Face for custom engine attribute names (e.g. ng-*)."
    545   :group 'web-mode-faces)
    546 
    547 (defface web-mode-html-attr-equal-face
    548     '((t :inherit web-mode-html-attr-name-face))
    549   "Face for the = character between name and value."
    550   :group 'web-mode-faces)
    551 
    552 (defface web-mode-html-attr-value-face
    553     '((t :inherit font-lock-string-face))
    554   "Face for html attribute values."
    555   :group 'web-mode-faces)
    556 
    557 (defface web-mode-block-attr-name-face
    558     '((t :foreground "#8fbc8f"))
    559   "Face for block attribute names."
    560   :group 'web-mode-faces)
    561 
    562 (defface web-mode-block-attr-value-face
    563     '((t :foreground "#5f9ea0"))
    564   "Face for block attribute values."
    565   :group 'web-mode-faces)
    566 
    567 (defface web-mode-variable-name-face
    568     '((t :inherit font-lock-variable-name-face))
    569   "Face for variable names."
    570   :group 'web-mode-faces)
    571 
    572 (defface web-mode-css-selector-face
    573     '((t :inherit font-lock-keyword-face))
    574   "Face for CSS rules."
    575   :group 'web-mode-faces)
    576 
    577 (defface web-mode-css-selector-class-face
    578     '((t :inherit font-lock-keyword-face))
    579   "Face for CSS class rules."
    580   :group 'web-mode-faces)
    581 
    582 (defface web-mode-css-selector-tag-face
    583     '((t :inherit font-lock-keyword-face))
    584   "Face for CSS tag rules."
    585   :group 'web-mode-faces)
    586 
    587 (defface web-mode-css-pseudo-class-face
    588     '((t :inherit font-lock-builtin-face))
    589   "Face for CSS pseudo-classes."
    590   :group 'web-mode-faces)
    591 
    592 (defface web-mode-css-at-rule-face
    593     '((t :inherit font-lock-constant-face))
    594   "Face for CSS at-rules."
    595   :group 'web-mode-faces)
    596 
    597 (defface web-mode-css-property-name-face
    598     '((t :inherit font-lock-variable-name-face))
    599   "Face for CSS props."
    600   :group 'web-mode-faces)
    601 
    602 (defface web-mode-css-color-face
    603     '((t :inherit font-lock-builtin-face))
    604   "Face for CSS colors (#xxx)."
    605   :group 'web-mode-faces)
    606 
    607 (defface web-mode-css-priority-face
    608     '((t :inherit font-lock-builtin-face))
    609   "Face for CSS priority (!important)."
    610   :group 'web-mode-faces)
    611 
    612 (defface web-mode-css-function-face
    613     '((t :inherit font-lock-builtin-face))
    614   "Face for CSS functions."
    615   :group 'web-mode-faces)
    616 
    617 (defface web-mode-css-variable-face
    618     '((t :inherit web-mode-variable-name-face :slant italic))
    619   "Face for CSS vars."
    620   :group 'web-mode-faces)
    621 
    622 (defface web-mode-function-name-face
    623     '((t :inherit font-lock-function-name-face))
    624   "Face for function names."
    625   :group 'web-mode-faces)
    626 
    627 (defface web-mode-filter-face
    628     '((t :inherit font-lock-function-name-face))
    629   "Face for function names."
    630   :group 'web-mode-faces)
    631 
    632 (defface web-mode-function-call-face
    633     '((t :inherit font-lock-function-name-face))
    634   "Face for function calls."
    635   :group 'web-mode-faces)
    636 
    637 (defface web-mode-string-face
    638     '((t :inherit font-lock-string-face))
    639   "Face for strings."
    640   :group 'web-mode-faces)
    641 
    642 (defface web-mode-block-string-face
    643     '((t :inherit web-mode-string-face))
    644   "Face for block strings."
    645   :group 'web-mode-faces)
    646 
    647 (defface web-mode-part-string-face
    648     '((t :inherit web-mode-string-face))
    649   "Face for part strings."
    650   :group 'web-mode-faces)
    651 
    652 (defface web-mode-javascript-string-face
    653     '((t :inherit web-mode-string-face))
    654   "Face for javascript strings."
    655   :group 'web-mode-faces)
    656 
    657 (defface web-mode-interpolate-color1-face
    658     '((t :inherit web-mode-string-face))
    659   "Face for element interpolation strings."
    660   :group 'web-mode-faces)
    661 
    662 (defface web-mode-interpolate-color2-face
    663     '((t :inherit web-mode-string-face))
    664   "Face for element interpolation strings."
    665   :group 'web-mode-faces)
    666 
    667 (defface web-mode-interpolate-color3-face
    668     '((t :inherit web-mode-string-face))
    669   "Face for element interpolation strings."
    670   :group 'web-mode-faces)
    671 
    672 (defface web-mode-interpolate-color4-face
    673     '((t :inherit web-mode-string-face))
    674   "Face for element interpolation strings."
    675   :group 'web-mode-faces)
    676 
    677 (defface web-mode-css-string-face
    678     '((t :inherit web-mode-string-face))
    679   "Face for css strings."
    680   :group 'web-mode-faces)
    681 
    682 (defface web-mode-json-key-face
    683     '((t :foreground "plum"))
    684   "Face for json key strings."
    685   :group 'web-mode-faces)
    686 
    687 (defface web-mode-json-context-face
    688     '((t :foreground "orchid3"))
    689   "Face for json context strings."
    690   :group 'web-mode-faces)
    691 
    692 (defface web-mode-json-string-face
    693     '((t :inherit web-mode-string-face))
    694   "Face for json strings."
    695   :group 'web-mode-faces)
    696 
    697 (defface web-mode-comment-face
    698     '((t :inherit font-lock-comment-face))
    699   "Face for comments."
    700   :group 'web-mode-faces)
    701 
    702 (defface web-mode-block-comment-face
    703     '((t :inherit web-mode-comment-face))
    704   "Face for server comments."
    705   :group 'web-mode-faces)
    706 
    707 (defface web-mode-part-comment-face
    708     '((t :inherit web-mode-comment-face))
    709   "Face for part comments."
    710   :group 'web-mode-faces)
    711 
    712 (defface web-mode-json-comment-face
    713     '((t :inherit web-mode-comment-face))
    714   "Face for json comments."
    715   :group 'web-mode-faces)
    716 
    717 (defface web-mode-javascript-comment-face
    718     '((t :inherit web-mode-comment-face))
    719   "Face for javascript comments."
    720   :group 'web-mode-faces)
    721 
    722 (defface web-mode-css-comment-face
    723     '((t :inherit web-mode-comment-face))
    724   "Face for css comments."
    725   :group 'web-mode-faces)
    726 
    727 (defface web-mode-annotation-face
    728     '((t :inherit web-mode-comment-face))
    729   "Face for code annotations."
    730   :group 'web-mode-faces)
    731 
    732 (defface web-mode-annotation-tag-face
    733     '((t :inherit web-mode-annotation-face :underline t))
    734   "Face for @tags in code annotations."
    735   :group 'web-mode-faces)
    736 
    737 (defface web-mode-annotation-type-face
    738     '((t :inherit web-mode-annotation-face :weight bold))
    739   "Face for types in code annotations."
    740   :group 'web-mode-faces)
    741 
    742 (defface web-mode-annotation-value-face
    743     '((t :inherit web-mode-annotation-face :slant italic))
    744   "Face for values in code annotations."
    745   :group 'web-mode-faces)
    746 
    747 (defface web-mode-annotation-html-face
    748     '((t :inherit web-mode-annotation-face :slant italic))
    749   "Face for HTML tags in code annotations."
    750   :group 'web-mode-faces)
    751 
    752 (defface web-mode-constant-face
    753     '((t :inherit font-lock-constant-face))
    754   "Face for language constants."
    755   :group 'web-mode-faces)
    756 
    757 (defface web-mode-type-face
    758     '((t :inherit font-lock-type-face))
    759   "Face for language types."
    760   :group 'web-mode-faces)
    761 
    762 (defface web-mode-keyword-face
    763     '((t :inherit font-lock-keyword-face))
    764   "Face for language keywords."
    765   :group 'web-mode-faces)
    766 
    767 (defface web-mode-param-name-face
    768     '((t :foreground "Snow3"))
    769   "Face for server attribute names."
    770   :group 'web-mode-faces)
    771 
    772 (defface web-mode-whitespace-face
    773     '((t :background "DarkOrchid4"))
    774   "Face for whitespaces."
    775   :group 'web-mode-faces)
    776 
    777 (defface web-mode-inlay-face
    778     '((((class color) (min-colors 88) (background dark))  :background "Black")
    779       (((class color) (min-colors 88) (background light)) :background "LightYellow1")
    780       (((class color) (min-colors 16) (background dark))  :background "Brey18")
    781       (((class color) (min-colors 16) (background light)) :background "LightYellow1")
    782       (((class color) (min-colors 8))                     :background "Black")
    783       (((type tty) (class mono))                          :inverse-video t)
    784       (t                                                  :background "Grey"))
    785   "Face for inlays. Must be used in conjunction with web-mode-enable-inlays."
    786   :group 'web-mode-faces)
    787 
    788 (defface web-mode-block-face
    789     '((((class color) (min-colors 88) (background dark))  :background "Black")
    790       (((class color) (min-colors 88) (background light)) :background "LightYellow1")
    791       (((class color) (min-colors 16) (background dark))  :background "Grey18")
    792       (((class color) (min-colors 16) (background light)) :background "LightYellow1")
    793       (((class color) (min-colors 8))                     :background "Black")
    794       (((type tty) (class mono))                          :inverse-video t)
    795       (t                                                  :background "Grey"))
    796   "Face for blocks (useful for setting a background for example).
    797 Must be used in conjunction with web-mode-enable-block-face."
    798   :group 'web-mode-faces)
    799 
    800 (defface web-mode-part-face
    801     '((t :inherit web-mode-block-face))
    802   "Face for parts."
    803   :group 'web-mode-faces)
    804 
    805 (defface web-mode-script-face
    806     '((t :inherit web-mode-part-face))
    807   "Face for javascript inside a script element."
    808   :group 'web-mode-faces)
    809 
    810 (defface web-mode-style-face
    811     '((t :inherit web-mode-part-face))
    812   "Face for css inside a style element."
    813   :group 'web-mode-faces)
    814 
    815 (defface web-mode-folded-face
    816     '((t :underline t))
    817   "Overlay face for folded."
    818   :group 'web-mode-faces)
    819 
    820 (defface web-mode-bold-face
    821     '((t :weight bold))
    822   "bold face."
    823   :group 'web-mode-faces)
    824 
    825 (defface web-mode-italic-face
    826     '((t :slant italic))
    827   "bold face."
    828   :group 'web-mode-faces)
    829 
    830 (defface web-mode-underline-face
    831     '((t :underline t))
    832   "bold face."
    833   :group 'web-mode-faces)
    834 
    835 (defface web-mode-current-element-highlight-face
    836     '((t :background "#000000" :foreground "#ffffff"))
    837   "Overlay face for element highlight."
    838   :group 'web-mode-faces)
    839 
    840 (defface web-mode-current-column-highlight-face
    841     '((t :background "#3e3c36"))
    842   "Overlay face for current column."
    843   :group 'web-mode-faces)
    844 
    845 (defface web-mode-comment-keyword-face
    846     '((t :weight bold :box t))
    847   "Comment keywords."
    848   :group 'web-mode-faces)
    849 
    850 (defface web-mode-sql-keyword-face
    851     '((t :weight bold :slant italic))
    852   "Sql keywords."
    853   :group 'web-mode-faces)
    854 
    855 (defface web-mode-html-entity-face
    856     '((t :slant italic))
    857   "Face html entities (e.g. &#8211;, &eacute;)."
    858   :group 'web-mode-faces)
    859 
    860 ;; https://material.io/tools/color/#!/?view.left=0&view.right=0
    861 (defface web-mode-jsx-depth-1-face
    862     '((t :background "#000053"))
    863   "jsx depth 1"
    864   :group 'web-mode-faces)
    865 
    866 (defface web-mode-jsx-depth-2-face
    867     '((t :background "#001970"))
    868   "jsx"
    869   :group 'web-mode-faces)
    870 
    871 (defface web-mode-jsx-depth-3-face
    872     '((t :background "#002984"))
    873   "jsx"
    874   :group 'web-mode-faces)
    875 
    876 (defface web-mode-jsx-depth-4-face
    877     '((t :background "#49599a"))
    878   "jsx"
    879   :group 'web-mode-faces)
    880 
    881 (defface web-mode-jsx-depth-5-face
    882     '((t :background "#9499b7"))
    883   "jsx"
    884   :group 'web-mode-faces)
    885 
    886 ;;---- VARS --------------------------------------------------------------------
    887 
    888 (defvar font-lock-beg)
    889 (defvar font-lock-end)
    890 
    891 (defvar web-mode-auto-pairs nil)
    892 (defvar web-mode-block-regexp nil)
    893 (defvar web-mode-change-beg nil)
    894 (defvar web-mode-change-end nil)
    895 (defvar web-mode-chunk-length 64)
    896 (defvar web-mode-column-overlays nil)
    897 (defvar web-mode-comments-invisible nil)
    898 (defvar web-mode-content-type "")
    899 (defvar web-mode-engine nil)
    900 ;;(defvar web-mode-engine-attr-regexp nil)
    901 (defvar web-mode-engine-font-lock-keywords nil)
    902 (defvar web-mode-engine-token-regexp nil)
    903 (defvar web-mode-expand-initial-pos nil)
    904 (defvar web-mode-expand-initial-scroll nil)
    905 (defvar web-mode-expand-previous-state "")
    906 ;;(defvar web-mode-font-lock-keywords '(web-mode-font-lock-highlight))
    907 (defvar web-mode-skip-fontification nil)
    908 (defvar web-mode-inlay-regexp nil)
    909 (defvar web-mode-is-scratch nil)
    910 (defvar web-mode-jshint-errors 0)
    911 (defvar web-mode-minor-engine nil)
    912 (defvar web-mode-obarray nil)
    913 (defvar web-mode-overlay-tag-start nil)
    914 (defvar web-mode-overlay-tag-end nil)
    915 (defvar web-mode-part-beg nil)
    916 (defvar web-mode-scan-beg nil)
    917 (defvar web-mode-scan-end nil)
    918 (defvar web-mode-snippets nil)
    919 (defvar web-mode-time nil)
    920 
    921 (defvar web-mode-offsetless-elements
    922   '())
    923 
    924 (defvar web-mode-indentless-elements
    925   '("code" "pre" "textarea"))
    926 
    927 (defvar web-mode-indentless-attributes
    928   '("onclick" "onmouseover" "onmouseout" "onsubmit"))
    929 
    930 (defvar web-mode-void-elements
    931   '("area" "base" "br" "col" "command" "embed" "hr" "img" "input" "keygen"
    932     "link" "meta" "param" "source" "track" "wbr" "tmpl_var"))
    933 
    934 (defvar web-mode-part-content-types
    935   '("css" "javascript" "json" "jsx" "markdown" "pug" "ruby"
    936     "sass" "sql" "stylus" "typescript"))
    937 
    938 (defvar web-mode-javascript-languages '("javascript" "jsx" "ejs"))
    939 
    940 ;; NOTE: without 'syntax-table forward-word fails (#377)
    941 (defvar web-mode-scan-properties
    942   (list 'tag-beg 'tag-end 'tag-name 'tag-type
    943         'tag-attr 'tag-attr-beg 'tag-attr-end
    944         'part-side 'part-token
    945         'jsx-beg 'jsx-end 'jsx-depth
    946         'block-side 'block-token 'block-controls 'block-beg 'block-end
    947         'syntax-table)
    948   "Text properties used for code regions/tokens and html nodes.")
    949 
    950 (defvar web-mode-start-tag-regexp "<\\([[:alnum:].:_-]+\\|>\\)"
    951   "Regular expression for HTML/XML start tag.")
    952 
    953 (defvar web-mode-tag-regexp "</?\\([[:alnum:].:_-]+\\)"
    954   "Regular expression for HTML/XML tag.")
    955 
    956 (defvar web-mode-dom-regexp "<\\(/?>\\|/?[[:alnum:].:_-]+\\|!--\\|!\\[CDATA\\[\\|!doctype\\|!DOCTYPE\\|\?xml\\)")
    957 
    958 (defvar web-mode-whitespaces-regexp
    959   "^[ \t]\\{2,\\}$\\| \t\\|\t \\|[ \t]+$\\|^[ \n\t]+\\'\\|^[ \t]?[\n]\\{2,\\}"
    960   "Regular expression for whitespaces.")
    961 
    962 (defvar web-mode-imenu-regexp-list
    963   '(("<\\(h[1-9]\\)\\([^>]*\\)>\\([^<]*\\)" 1 3 ">")
    964     ("^[ \t]*<\\([@a-z]+\\)[^>]*>? *$" 1 "id=\"\\([a-zA-Z0-9_]+\\)\"" "#" ">"))
    965   "Regexps to match imenu items (see https://web-mode.org/doc/imenu.txt)")
    966 
    967 ;; https://www.gnu.org/software/emacs/manual/html_node/ccmode/Syntactic-Symbols.html
    968 (defvar web-mode-indentation-params
    969   '(("lineup-args"       . t)
    970     ("lineup-calls"      . t)
    971     ("lineup-concats"    . t)
    972     ("lineup-quotes"     . t)
    973     ("lineup-ternary"    . t)
    974     ("case-extra-offset" . t)
    975     ))
    976 
    977 (defvar web-mode-tag-history nil)
    978 (defvar web-mode-attribute-history nil)
    979 (defvar web-mode-attribute-value-history nil)
    980 
    981 (defvar web-mode-engines
    982   '(("angular"          . ("angularjs"))
    983     ("anki"             . ())
    984     ("antlers"          . ())
    985     ("archibus"         . ())
    986     ("artanis"          . ())
    987     ("asp"              . ())
    988     ("aspx"             . ())
    989     ("astro"            . ())
    990     ("blade"            . ("laravel"))
    991     ("cl-emb"           . ())
    992     ("clip"             . ())
    993     ("closure"          . ("soy"))
    994     ("ctemplate"        . ("mustache" "handlebars" "hapax" "ngtemplate" "ember"
    995                            "kite" "meteor" "blaze" "ractive" "velvet"))
    996     ("django"           . ("dtl" "twig" "swig" "jinja" "jinja2" "erlydtl" "liquid"
    997                            "clabango" "selmer" "nunjucks"))
    998     ("dust"             . ("dustjs"))
    999     ("ejs"              . ())
   1000     ("elixir"           . ("phoenix"))
   1001     ("erb"              . ("eruby" "erubis" "crystal"))
   1002     ("expressionengine" . ("ee"))
   1003     ("freemarker"       . ())
   1004     ("go"               . ("gtl" "hugo"))
   1005     ("hero"             . ())
   1006     ("json-t"           . ())
   1007     ("jsp"              . ("grails"))
   1008     ("mako"             . ())
   1009     ("marko"            . ("pandoc"))
   1010     ("mason"            . ("poet"))
   1011     ("lsp"              . ("lisp"))
   1012     ("mojolicious"      . ())
   1013     ("php"              . ())
   1014     ("python"           . ())
   1015     ("razor"            . ("play" "play2"))
   1016     ("riot"             . ())
   1017     ("smarty"           . ())
   1018     ("spip"             . ())
   1019     ("svelte"           . ("svelte"))
   1020     ("template-toolkit" . ())
   1021     ("thymeleaf"        . ())
   1022     ("perl"             . ())
   1023     ("underscore"       . ("underscore.js"))
   1024     ("velocity"         . ("vtl" "cheetah" "ssp"))
   1025     ("vue"              . ("vuejs" "vue.js"))
   1026     ("web2py"           . ())
   1027     ("xoops"            . ())
   1028     )
   1029   "Engine name aliases")
   1030 
   1031 (defvar web-mode-content-types
   1032   '(("css"        . "\\.\\(s?css\\|css\\.erb\\)\\'")
   1033     ("javascript" . "\\.\\([mc]?js\\|js\\.erb\\)\\'")
   1034     ("typescript" . "\\.\\([mc]?ts\\|ts\\.erb\\)\\'")
   1035     ("json"       . "\\.\\(api\\|json\\|jsonld\\)\\'")
   1036     ("jsx"        . "\\.[jt]sx\\'")
   1037     ("xml"        . "\\.xml\\'")
   1038     ("html"       . "."))
   1039   "content types")
   1040 
   1041 (defvar web-mode-engine-attr-regexps
   1042   '(("angular"   . "ng-")
   1043     ("thymeleaf" . "th:")
   1044     ("vue"       . "v-"))
   1045   "Engine custom attributes")
   1046 
   1047 (defvar web-mode-engine-attr-regexp
   1048   "^ng[-]\\|^th[:]\\|^v[-]\\|^[@:#(\[*]"
   1049   "Engine custom attributes")
   1050 
   1051 (defvar web-mode-last-enabled-feature nil)
   1052 
   1053 (defvar web-mode-features
   1054   '(("css-colorization"          . web-mode-enable-css-colorization)
   1055     ("element-highlight"         . web-mode-enable-current-element-highlight)
   1056     ("column-highlight"          . web-mode-enable-current-column-highlight)
   1057     ("whitespace-fontification"  . web-mode-enable-whitespace-fontification)
   1058     ("element-tag-fontification" . web-mode-enable-element-tag-fontification)
   1059     ("block-face"                . web-mode-enable-block-face)
   1060     ("part-face"                 . web-mode-enable-part-face)))
   1061 
   1062 (defvar web-mode-comment-prefixing t)
   1063 
   1064 (defvar web-mode-engine-file-regexps
   1065   '(("angular"          . "\\.component\\.html\\'")
   1066     ("anki"             . "\\.anki\\'")
   1067     ("antlers"          . "\\.antlers\\.html\\'")
   1068     ("archibus"         . "\\.axvw\\'")
   1069     ("artanis"          . "\\.html\\.tpl\\'")
   1070     ("asp"              . "\\.asp\\'")
   1071     ("aspx"             . "\\.as[cp]x\\'")
   1072     ("astro"            . "\\.astro\\'")
   1073     ("blade"            . "\\.blade\\.php\\'")
   1074     ("cl-emb"           . "\\.clemb\\'")
   1075     ("clip"             . "\\.ctml\\'")
   1076     ("closure"          . "\\.soy\\'")
   1077     ("ctemplate"        . "\\.\\(chtml\\|mustache\\)\\'")
   1078     ("django"           . "\\.\\(djhtml\\|tmpl\\|dtl\\|liquid\\|j2\\|njk\\)\\'")
   1079     ("dust"             . "\\.dust\\'")
   1080     ("elixir"           . "\\.[hl]?eex\\'")
   1081     ("ejs"              . "\\.ejs\\'")
   1082     ("erb"              . "\\.\\(erb\\|rhtml\\|erb\\.html\\|ecr\\)\\'")
   1083     ("expressionengine" . "\\.ee\\'")
   1084     ("freemarker"       . "\\.ftl\\'")
   1085     ("go"               . "\\.go\\(html\\|tmpl\\)\\'")
   1086     ("handlebars"       . "\\.\\(hb\\.html\\|hbs\\)\\'")
   1087     ("hero"             . "\\.hero\\'")
   1088     ("jinja"            . "\\.\\(jinja\\|nwt\\)\\'")
   1089     ("jsp"              . "\\.[gj]sp\\'")
   1090     ("lsp"              . "\\.lsp\\'")
   1091     ("mako"             . "\\.mako?\\'")
   1092     ("marko"            . "\\.marko\\'")
   1093     ("mason"            . "\\.mas\\'")
   1094     ("mojolicious"      . "\\.epl?\\'")
   1095     ("perl"             . "\\.\\(ptmpl\\|perl\\.html\\)\\'")
   1096     ("php"              . "\\.\\(p[hs]p\\|ctp\\|inc\\)\\'")
   1097     ("python"           . "\\.pml\\'")
   1098     ("razor"            . "\\.\\(cs\\|vb\\)html\\|\\.razor\\'")
   1099     ("riot"             . "\\.tag\\'")
   1100     ("smarty"           . "\\.tpl\\'")
   1101     ("svelte"           . "\\.svelte\\'")
   1102     ("template-toolkit" . "\\.tt.?\\'")
   1103     ("thymeleaf"        . "\\.thtml\\'")
   1104     ("velocity"         . "\\.v\\(sl\\|tl\\|m\\)\\'")
   1105     ("vue"              . "\\.vue\\'")
   1106     ("xoops"            . "\\.xoops'")
   1107     ;; regexp on the path, not just the extension
   1108     ("django"           . "[st]wig")
   1109     ("razor"            . "scala")
   1110     ("spip"             . "spip")
   1111     )
   1112   "Engine file extensions.")
   1113 
   1114 (defvar web-mode-content-types-alist nil
   1115   "A list of filename patterns and corresponding web-mode content types.
   1116 For example,
   1117 (setq web-mode-content-types-alist
   1118   \\='((\"json\" . \"/some/path/.*\\.api\\\\='\")
   1119     (\"jsx\"  . \"/some/react/path/.*\\.js[x]?\\\\='\")))")
   1120 
   1121 (defvar web-mode-smart-quotes
   1122   '("«" . "»")
   1123   "Preferred smart quotes")
   1124 
   1125 (defvar web-mode-xml-chars
   1126   '((?\& . "&amp;")
   1127     (?\< . "&lt;")
   1128     (?\> . "&gt;"))
   1129   "XML chars")
   1130 
   1131 ;; #1254 : https://html.spec.whatwg.org/entities.json
   1132 (defvar web-mode-html-entities
   1133   ;; #985
   1134   ;; remove ("gt" . 62) ("lt" . 60) ("amp" . 38)
   1135   '(("AElig" . 198) ("Aacute" . 193) ("Acirc" . 194) ("Agrave" . 192)
   1136     ("Alpha" . 913) ("Aring" . 197) ("Atilde" . 195) ("Auml" . 196)
   1137     ("Beta" . 914)
   1138     ("Ccedil" . 199) ("Chi" . 935)
   1139     ("Dagger" . 8225) ("Delta" . 916)
   1140     ("ETH" . 208) ("Eacute" . 201) ("Ecirc" . 202) ("Egrave" . 200)
   1141     ("Epsilon" . 917) ("Eta" . 919) ("Euml" . 203)
   1142     ("Gamma" . 915)
   1143     ("Iacute" . 205) ("Icirc" . 206) ("Igrave" . 204) ("Iota" . 921)
   1144     ("Iuml" . 207)
   1145     ("Kappa" . 922)
   1146     ("Lambda" . 923)
   1147     ("Mu" . 924)
   1148     ("Ntilde" . 209) ("Nu" . 925)
   1149     ("OElig" . 338) ("Oacute" . 211) ("Ocirc" . 212) ("Ograve" . 210)
   1150     ("Omega" . 937) ("Omicron" . 927) ("Oslash" . 216) ("Otilde" . 213)
   1151     ("Ouml" . 214)
   1152     ("Phi" . 934) ("Pi" . 928) ("Prime" . 8243) ("Psi" . 936)
   1153     ("Rho" . 929)
   1154     ("Scaron" . 352) ("Sigma" . 931)
   1155     ("THORN" . 222) ("Tau" . 932) ("Theta" . 920)
   1156     ("UArr" . 8657) ("Uacute" . 218) ("Uacute" . 250) ("Ucirc" . 219)
   1157     ("Ugrave" . 217)  ("Upsih" . 978)
   1158     ("Upsilon" . 933) ("Uuml" . 220) ("Uuml" . 252)
   1159     ("Xi" . 926)
   1160     ("Yacute" . 221) ("Yuml" . 376)
   1161     ("Zeta" . 918)
   1162     ("aacute" . 225) ("acirc" . 226) ("acute" . 180) ("aelig" . 230)
   1163     ("agrave" . 224) ("alefsym" . 8501) ("alpha" . 945)
   1164     ("ang" . 8736) ("apos" . 39) ("aring" . 229) ("asymp" . 8776)
   1165     ("atilde" . 227) ("auml" . 228)
   1166     ("bdquo" . 8222) ("beta" . 946) ("brvbar" . 166) ("bull" . 8226)
   1167     ("cap" . 8745) ("ccedil" . 231) ("cedil" . 184) ("cent" . 162)
   1168     ("chi" . 967) ("circ" . 710) ("clubs" . 9827) ("cong" . 8773)
   1169     ("copy" . 169) ("crarr"  . 8629) ("cup" . 8746) ("curren" . 164)
   1170     ("dArr" . 8659) ("dagger" . 8224) ("darr" . 8595) ("deg" . 176)
   1171     ("delta" . 948) ("diams" . 9830) ("divide" . 247)
   1172     ("eacute" . 233) ("ecirc"  . 234) ("egrave" . 232) ("empty" . 8709)
   1173     ("emsp" . 8195) ("ensp" . 8194) ("epsilon" . 949) ("equiv" . 8801)
   1174     ("eta" . 951) ("eth" . 240) ("euml" . 235) ("euro" . 8364) ("exist" . 8707)
   1175     ("fnof" . 402) ("forall" . 8704) ("frac12" . 189) ("frac14" . 188)
   1176     ("frac34" . 190) ("frasl" . 8260)
   1177     ("gamma" . 947) ("ge" . 8805)
   1178     ("hArr" . 8660) ("harr" . 8596) ("hearts" . 9829) ("hellip" . 8230)
   1179     ("iacute" . 237) ("icirc" . 238) ("iexcl" . 161) ("igrave" . 236)
   1180     ("image" . 8465) ("infin" . 8734) ("int" . 8747) ("iota" . 953)
   1181     ("iquest" . 191) ("isin" . 8712) ("iuml" . 239)
   1182     ("kappa" . 954)
   1183     ("lArr" . 8656) ("lambda" . 955) ("lang" . 9001) ("laquo" . 171)
   1184     ("larr" . 8592) ("lceil" . 8968) ("ldquo" . 8220) ("le" . 8804)
   1185     ("lfloor" . 8970) ("lowast" . 8727) ("loz" . 9674) ("lrm" . 8206)
   1186     ("lsaquo" . 8249) ("lsquo" . 8249)
   1187     ("macr" . 175) ("mdash" . 8212) ("micro" . 181) ("middot" . 183)
   1188     ("minus" . 8722) ("mu" . 956)
   1189     ("nabla" . 8711) ("nbsp" . 160) ("ndash" . 8211) ("ne" . 8800)
   1190     ("ni" . 8715) ("not" . 172) ("notin" . 8713) ("nsub" . 8836)
   1191     ("ntilde" . 241) ("nu" . 957) ("oacute" . 243) ("ocirc" . 244)
   1192     ("oelig" . 339) ("ograve" . 242) ("oline" . 8254) ("omega" . 969)
   1193     ("omicron" . 959) ("oplus" . 8853) ("or" . 8744) ("ordf" . 170)
   1194     ("ordm" . 186) ("oslash" . 248) ("otilde" . 245) ("otimes" . 8855)
   1195     ("ouml" . 246)
   1196     ("para" . 182) ("part" . 8706) ("permil" . 8240) ("perp" . 8869)
   1197     ("phi" . 966) ("pi" . 960) ("piv" . 982) ("plusmn" . 177) ("pound" . 163)
   1198     ("prime" . 8242) ("prod" . 8719) ("prop" . 8733) ("psi" . 968)
   1199     ("quot" . 34)
   1200     ("rArr" . 8658) ("radic" . 8730) ("rang" . 9002) ("raquo" . 187)
   1201     ("rarr" . 8594) ("rceil" . 8969) ("rdquo" . 8221) ("real" . 8476)
   1202     ("reg" . 174) ("rfloor" . 8971) ("rho" . 961) ("rlm" . 8207)
   1203     ("rsaquo" . 8250) ("rsquo" . 8250) ("sbquo" . 8218)
   1204     ("scaron" . 353) ("sdot" . 8901) ("sect" . 167) ("shy" . 173)
   1205     ("sigma" . 963) ("sigmaf" . 962) ("sim" . 8764) ("spades" . 9824)
   1206     ("sub" . 8834) ("sube" . 8838) ("sum" . 8721) ("sup" . 8835)
   1207     ("sup1" . 185) ("sup2" . 178) ("sup3" . 179) ("supe" . 8839)
   1208     ("szlig" . 223)
   1209     ("tau" . 964) ("there4" . 8756) ("theta" . 952) ("thetasym" . 977)
   1210     ("thinsp" . 8201) ("thorn" . 254) ("tilde" . 732) ("times" . 215)
   1211     ("trade" . 8482)
   1212     ("uarr" . 8593) ("ucirc" . 251) ("ugrave" . 249) ("uml" . 168)
   1213     ("upsilon" . 965)
   1214     ("weierp" . 8472)
   1215     ("xi" . 958)
   1216     ("yacute" . 253) ("yen" . 165) ("yuml" . 255)
   1217     ("zeta" . 950) ("zwj" . 8205) ("zwnj" . 8204)))
   1218 
   1219 ;; http://webdesign.about.com/od/localization/l/blhtmlcodes-ascii.htm
   1220 (defvar web-mode-display-table
   1221   (let ((table (make-display-table)))
   1222     (aset table 9  (vector ?\xBB ?\t))
   1223     (aset table 10 (vector ?\xB6 ?\n))
   1224     (aset table 32 (vector ?\xB7))
   1225     table)
   1226   "Display table used when switching to the whitespace visualization.")
   1227 
   1228 (defvar web-mode-expanders
   1229   '(("a/" . "<a href=\"|\"></a>")
   1230     ("b/" . "<table><tbody><tr><td>|</td><td></td></tr></tbody></table>")
   1231     ("c/" . "<div class=\"|\"></div>")
   1232     ("d/" . "<div>|</div>")
   1233     ("e/" . "<em>|</em>")
   1234     ("f/" . "<form>|</form>")
   1235     ("g/" . "<strong>|</strong>")
   1236     ("h/" . "<h1>|</h1>")
   1237     ("i/" . "<img src=\"|\" />")
   1238     ("j/" . "<script>|</script>")
   1239     ("l/" . "<li>|</li>")
   1240     ("m/" . "<main>|</main>")
   1241     ("n/" . "<input type=\"|\" />")
   1242     ("p/" . "<p>|</p>")
   1243     ("q/" . "<quote>|</quote>")
   1244     ("s/" . "<span>|</span>")
   1245     ("t/" . "<td>|</td>")
   1246     ("u/" . "<ul><li>|</li><li></li></ul>")
   1247     ("x/" . "<textarea>|</textarea>")
   1248     ("2/" . "<h2>|</h2>")
   1249     ("3/" . "<h3>|</h3>")
   1250     ("?/" . "<?php | ?>")))
   1251 
   1252 (defvar web-mode-engines-auto-pairs
   1253   '(("angular"          . (("{{ " . " }}")))
   1254     ("anki"             . (("{{ " . " }}")))
   1255     ("antlers"          . (("{{ "  . " }}")
   1256                            ("{{$ " . "| $}}")
   1257                            ("{{? " . "| ?}}")
   1258                            ("{{# " . "| #}}")))
   1259     ("artanis"          . (("<% "       . " %>")
   1260                            ("<%="       . " | %>")
   1261                            ("<@css"     . " | %>")
   1262                            ("<@icon"    . " | %>")
   1263                            ("<@include" . " | %>")
   1264                            ("<@js"      . " | %>")))
   1265     ("asp"              . (("<% " . " %>")))
   1266     ("aspx"             . (("<% " . " %>")
   1267                            ("<%=" . "%>")
   1268                            ("<%#" . "%>")
   1269                            ("<%$" . "%>")
   1270                            ("<%@" . "%>")
   1271                            ("<%:" . "%>")
   1272                            ("<%-" . "- | --%>")))
   1273     ("astro"            . (("{ " . " }")))
   1274     ("blade"            . (("{{{" . " | }}}")
   1275                            ("{{ " . " }}")
   1276                            ("{!!" . " | !!}")
   1277                            ("@{{" . " | }}")
   1278                            ("{{-" . "- | --}}")))
   1279     ("cl-emb"           . (("<% " . " %>")
   1280                            ("<%=" . " | %>")
   1281                            ("<%#" . " | %>")))
   1282     ("ctemplate"        . (("{{ " . "| }}")
   1283                            ("{{~ " . "| }}")
   1284                            ("{{{" . " | }}}")
   1285                            ("{~{" . " | }}")
   1286                            ("{{~{" . " | }}}")
   1287                            ("{{!" . "-- | --}}")
   1288                            ("{{^" . "}}")
   1289                            ("{{/" . "}}")
   1290                            ("{{#" . "}}")))
   1291     ("django"           . (("{{ " . " }}")
   1292                            ("{% " . " %}")
   1293                            ("{%-" . " | %}")
   1294                            ("{# " . " #}")))
   1295     ("elixir"           . (("<% " . " %>")
   1296                            ("<%=" . " | %>")
   1297                            ("<%%" . " | %>")
   1298                            ("<%#" . " | %>")))
   1299     ("ejs"              . (("<% " . " %>")
   1300                            ("<%=" . "%>")
   1301                            ("<%#" . "%>")
   1302                            ("<%-" . "%>")))
   1303     ("erb"              . (("<% " . " %>")
   1304                            ("<%=" . " %>")
   1305                            ("<%#" . "%>")
   1306                            ("<%-" . " %>")))
   1307     ("freemarker"       . (("<% " . " %>")
   1308                            ("<#-" . "- | -->")
   1309                            ("${ " . " }")
   1310                            ("[% " . " %]")
   1311                            ("[# " . " #]")
   1312                            ("[#-" . "- | --]")))
   1313     ("go"               . (("{{ " . " }}")
   1314                            ("{{-" . " | -}}")))
   1315     ("hero"             . (("<% " . " %>")
   1316                            ("<%=" . " | %>")
   1317                            ("<%!" . " | %>")
   1318                            ("<%:" . " | %>")
   1319                            ("<%#" . " | %>")
   1320                            ("<%@" . " | %>")
   1321                            ("<%~" . " | %>")
   1322                            ("<%+" . " | %>")))
   1323     ("jsp"              . (("<% " . " %>")
   1324                            ("<%-" . "- | --%>")
   1325                            ("<%=" . "%>")
   1326                            ("<%!" . "%>")
   1327                            ("<%@" . "%>")
   1328                            ("${ " . " }")))
   1329     ("lsp"              . (("<% " . " %>")
   1330                            ("<%%" . " | %>")
   1331                            ("<%#" . " | %>")))
   1332     ("mako"             . (("<% " . " %>")
   1333                            ("<%!" . " | %>")
   1334                            ("${ " . " }")))
   1335     ("marko"            . (("${ " . " }")))
   1336     ("mason"            . (("<% " . " %>")
   1337                            ("<& " . " &>")))
   1338     ("mojolicious"      . (("<% " . " %>")
   1339                            ("<%=" . " | %>")
   1340                            ("<%%" . " | %>")
   1341                            ("<%#" . " | %>")))
   1342     ("php"              . (("<?p" . "hp | ?>")
   1343                            ("<? " . " ?>")
   1344                            ("<?=" . "?>")))
   1345     ("template-toolkit" . (("[% " . " %]")
   1346                            ("[%-" . " | %]")
   1347                            ("[%#" . " | %]")))
   1348     ("riot"             . (("={ " . " }")))
   1349     ("underscore"       . (("<% " . " %>")))
   1350     ("vue"              . (("{{ " . " }}")))
   1351     ("web2py"           . (("{{ " . " }}")
   1352                            ("{{=" . "}}")))
   1353     (nil                . (("<!-" . "- | -->")))
   1354     ))
   1355 
   1356 (defvar web-mode-engines-snippets
   1357   '(("artanis" . (("if"       . "<% (if (|) %>\n\n<% ) %>")
   1358                   ("when"     . "<% (when (|) %>\n\n<% ) %>")
   1359                   ("unless"   . "<% (unless (|) %>\n\n<% ) %>")
   1360                   ("cond"     . "<% (cond %>\n<%  [(|) %>\n\n<%  ] %>\n<%  [else %>\n\n<%  ] %>\n<% ) %>")
   1361                   ("let"      . "<% (let ([|]) %>\n\n<% ) %>")
   1362                   ("let*"     . "<% (let* ([|]) %>\n\n<% ) %>")
   1363                   ("do"       . "<% (do ([|]) %>\n<%     [()] %>\n\n<% ) %>")
   1364                   ("for-each" . "<% (for-each %>\n|\n\n<% ) %>")
   1365                   ("case"     . "<% (case | %>\n<%   [() %>\n\n<%   ] %>\n<%   [() %>\n\n<%   ] %>\n<% ) %>")))
   1366     ("ejs" . (("for"     . "<% for (|) { %>\n\n<% } %>")
   1367               ("if"      . "<% if (|) { %>\n\n<% } %>")))
   1368     ("erb" . (("each"    . "<% |.each do  %>\n\n<% end %>")
   1369               ("if"      . "<% if | %>\n\n<% end %>")
   1370               ("when"    . "<% when | %>\n\n<% end %>")
   1371               ("unless"  . "<% unless | %>\n\n<% end %>")))
   1372     ("php" . (("if"      . "<?php if (|): ?>\n\n<?php endif; ?>")
   1373               ("while"   . "<?php while (|): ?>\n\n<?php endwhile; ?>")
   1374               ("for"     . "<?php for (| ; ; ): ?>\n\n<?php endfor; ?>")
   1375               ("foreach" . "<?php foreach (| as ): ?>\n\n<?php endforeach; ?>")
   1376               ("each"    . "<?php foreach (| as ): ?>\n\n<?php endforeach; ?>")
   1377               ("switch"  . "<?php switch (|): ?>\n<?php case 1: ?>\n\n<?php break ;?>\n<?php case 2: ?>\n\n<?php break ;?>\n<?php endswitch;?>")))
   1378     ("django" . (("block"      . "{% block | %}\n\n{% endblock %}")
   1379                  ("comment"    . "{% comment | %}\n\n{% endcomment %}")
   1380                  ("css"        . "{% stylesheet  %}\n\n{% endstylesheet  %}")
   1381                  ("cycle"      . "{% cycle | as  %}\n\n{% endcycle  %}")
   1382                  ("filter"     . "{% filter | %}\n\n{% endfilter %}")
   1383                  ("for"        . "{% for | in  %}\n\n{% endfor %}")
   1384                  ("if"         . "{% if | %}\n\n{% endif %}")
   1385                  ("ifequal"    . "{% ifequal | %}\n\n{% endifequal %}")
   1386                  ("ifnotequal" . "{% ifnotequal | %}\n\n{% endifnotequal %}")
   1387                  ("js"         . "{% javascript | %}\n\n{% endjavascript %}")
   1388                  ("schema"     . "{% schema | %}\n\n{% endschema %}")
   1389                  ("safe"       . "{% safe | %}\n\n{% endsafe %}")))
   1390     ("mako" . (("if"        . "% if |:\n% endif")
   1391                ("for"       . "% for | in :\n% endfor")
   1392                ("doc"       . "<%doc>\n|\n</%doc>")
   1393                ("inherit"   . "<%inherit file=\"|\" />")
   1394                ("namespace" . "<%namespace name=\"|\" file=\"\" import=\"\"/>")
   1395                ("block"     . "<%block name=\"|\">\n</%block>")))
   1396     ("template-toolkit" . (("if"      . "[% IF | %]\n\n[% END %]")))
   1397     (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>")
   1398             ("table" . "<table><tbody>\n<tr>\n<td>|</td>\n<td></td>\n</tr>\n</tbody></table>")
   1399             ("ul"    . "<ul>\n<li>|</li>\n<li></li>\n</ul>")))
   1400     ))
   1401 
   1402 (defvar web-mode-engine-token-regexps
   1403   (list
   1404    '("antlers"     . "\"\\|'")
   1405    '("artanis"     . "\"\\|#|\\|;")
   1406    '("asp"         . "//\\|/\\*\\|\"\\|'")
   1407    '("ejs"         . "//\\|/\\*\\|\"\\|'")
   1408    '("erb"         . "\"\\|'\\|#\\|<<[-]?['\"]?\\([[:alnum:]_]+\\)['\"]?")
   1409    '("lsp"         . "\"\\|#|\\|;")
   1410    '("mako"        . "\"\\|'\\|#")
   1411    '("mason"       . "\"\\|'\\|#")
   1412    '("mojolicious" . "\"\\|'")
   1413    '("php"         . "//\\|/\\*\\|#\\|\"\\|'\\|<<<['\"]?\\([[:alnum:]]+\\)['\"]?")
   1414    '("python"      . "\"\\|'\\|#")
   1415    '("web2py"      . "\"\\|'"))
   1416   "Engine regexps used to identify tokens (strings / comments) in blocks.")
   1417 
   1418 (defvar web-mode-engine-open-delimiter-regexps
   1419   (list
   1420    '("angular"          . "{{")
   1421    '("anki"             . "{{")
   1422    '("antlers"          . "{{[@#$]?")
   1423    '("artanis"          . "<%\\|<@\\(css\\|icon\\|include\\|js\\)")
   1424    '("asp"              . "<%\\|</?[[:alpha:]]+:[[:alpha:]]+\\|</?[[:alpha:]]+Template")
   1425    '("aspx"             . "<%.")
   1426    '("astro"            . "---")
   1427    '("blade"            . "{{.\\|{!!\\|@{{\\|@[[:alpha:]]")
   1428    '("cl-emb"           . "<%")
   1429    '("closure"          . "{.\\|/\\*\\| //")
   1430    '("clip"             . "</?c:[[:alpha:]-]+")
   1431    '("ctemplate"        . "[$]?{[{~].")
   1432    '("django"           . "{[#{%]\\|^#")
   1433    '("dust"             . "{.")
   1434    '("elixir"           . "<%\\|</?[.:]")
   1435    '("ejs"              . "<%")
   1436    '("erb"              . "<%\\|^%.")
   1437    '("expressionengine" . "{.")
   1438    '("freemarker"       . "<%\\|${\\|</?[[:alpha:]]+:[[:alpha:]]\\|</?[@#]\\|\\[/?[@#].")
   1439    '("go"               . "{{.")
   1440    '("hero"             . "<%")
   1441    '("jsp"              . "<%\\|${")
   1442    '("lsp"              . "<%")
   1443    '("mako"             . "</?%\\|${\\|^[ \t]*%.\\|^[ \t]*##")
   1444    '("marko"            . "${")
   1445    '("mason"            . "</?[&%]\\|^%.")
   1446    '("mojolicious"      . "<%\\|^[ \t]*%.")
   1447    '("perl"             . "</?TMPL_[[:alpha:]]+")
   1448    '("php"              . "<\\?")
   1449    '("python"           . "<\\?")
   1450    '("razor"            . "@.\\|^[ \t]*}")
   1451    '("riot"             . "{.\\|/// begin script")
   1452    '("smarty"           . "{[[:alpha:]#$/*\"]")
   1453    '("spip"             . "\\[(#REM)\\|(\\|#[A-Z0-9_]\\|{\\|<:")
   1454    '("template-toolkit" . "\\[%\\(.\\|$\\)\\|%%#")
   1455    '("underscore"       . "<%")
   1456    '("velocity"         . "#[[:alpha:]#*]\\|$[[:alpha:]!{]")
   1457    '("vue"              . "{{\\|[:@][-[:alpha:]]+=\"")
   1458    '("web2py"           . "{{")
   1459    '("xoops"            . "<{[[:alpha:]#$/*\"]")
   1460    '("svelte"           . "{.")
   1461    )
   1462   "Engine regexps used to identify blocks.")
   1463 
   1464 (defvar web-mode-normalization-rules
   1465   '(("tag-case"          . "lower-case")
   1466     ("attr-case"         . "lower-case")
   1467     ("special-chars"     . "unicode") ;"unicode" "entities"
   1468     ("css-indentation"   . t)
   1469     ("smart-apostrophes" . t)
   1470     ("smart-quotes"      . t)
   1471     ("whitespaces"       . t)
   1472     ("indentation"       . t))
   1473   "Normalization rules")
   1474 
   1475 (defvar web-mode-element-tag-faces
   1476   (list
   1477    '("h1"     . web-mode-underline-face)
   1478    '("h2"     . web-mode-underline-face)
   1479    '("h3"     . web-mode-underline-face)
   1480    '("h4"     . web-mode-underline-face)
   1481    '("title"  . web-mode-underline-face)
   1482    '("em"     . web-mode-italic-face)
   1483    '("strong" . web-mode-bold-face)
   1484    ))
   1485 
   1486 (defvar web-mode-element-content-faces
   1487   (list
   1488    '("h1"     . web-mode-underline-face)
   1489    '("h2"     . web-mode-underline-face)
   1490    '("h3"     . web-mode-underline-face)
   1491    '("h4"     . web-mode-underline-face)
   1492    '("title"  . web-mode-underline-face)
   1493    '("em"     . web-mode-italic-face)
   1494    '("strong" . web-mode-bold-face)
   1495    ))
   1496 
   1497 (defvar web-mode-comment-keywords
   1498   (regexp-opt
   1499    (append
   1500     (cdr (assoc "comment" web-mode-extra-keywords))
   1501     '("FIXME" "TODO" "BUG" "KLUDGE" "WORKAROUND" "OPTIMIZE" "HACK" "REFACTOR" "REVIEW"))))
   1502 
   1503 (defvar web-mode-links
   1504   '(("\\.\\(png\\|jpe?g\\|gif\\|webp\\)$" "<img src=\"%s\" alt=\"\" />" nil 4)
   1505     ("\\.svg$" "<object data=\"%s\" type=\"image/svg+xml\"></object>" nil 0)
   1506     ("\\.js$" "<script type=\"text/javascript\" src=\"%s\"></script>" t 0)
   1507     ("\\.css$" "<link rel=\"stylesheet\" type=\"text/css\" href=\"%s\" />" t 0)
   1508     ("\\.html?$" "<a href=\"%s\"></a>" nil 4))
   1509   "List of elements and extensions for `web-mode-file-link'. It
   1510 consists of a string that contains the regular expression that
   1511 matches the appropriate files, a format string with element that
   1512 contains the link (%s should be put where the path goes,) a bool
   1513 that tells if the element belongs in the <head> element, and
   1514 number of characters to move back if needed (or 0 if point
   1515 shouldn't be moved back.)")
   1516 
   1517 (defvar web-mode-sql-queries
   1518   (regexp-opt
   1519    '("SELECT" "INSERT" "UPDATE" "DELETE" "select" "insert" "update" "delete")))
   1520 
   1521 (defvar web-mode-sql-keywords
   1522   (regexp-opt
   1523    (append
   1524     (cdr (assoc "sql" web-mode-extra-keywords))
   1525     '("SELECT" "INSERT" "UPDATE" "DELETE"
   1526       "FROM" "WHERE" "GROUP BY" "LIKE" "LIMIT" "HAVING" "JOIN" "LEFT" "INNER"
   1527       "FULL" "OUTER" "VALUES" "ORDER BY" "SEPARATOR" "ASC" "DESC"
   1528       "AND" "OR" "ON" "WHEN" "ELSE" "END" "THEN"))))
   1529 
   1530 (defvar web-mode-python-constants
   1531   (regexp-opt
   1532    (append
   1533     (cdr (assoc "python" web-mode-extra-constants))
   1534     '("True" "False" "None" "__debug__" "NotImplemented" "Ellipsis"))))
   1535 
   1536 (defvar web-mode-elixir-keywords
   1537   (regexp-opt
   1538    (append
   1539     (cdr (assoc "elixir" web-mode-extra-keywords))
   1540     '("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"))))
   1541 
   1542 
   1543 (defvar web-mode-elixir-constants
   1544   (regexp-opt
   1545    (append
   1546     (cdr (assoc "elixir" web-mode-extra-constants))
   1547     '("nil" "true" "false"))))
   1548 
   1549 (defvar web-mode-erlang-constants
   1550   (regexp-opt
   1551    (append
   1552     (cdr (assoc "erlang" web-mode-extra-constants))
   1553     '("true" "false"))))
   1554 
   1555 (defvar web-mode-erlang-keywords
   1556   (regexp-opt
   1557    (append
   1558     (cdr (assoc "erlang" web-mode-extra-keywords))
   1559     '("else" "if" "do" "end"))))
   1560 
   1561 (defvar web-mode-cl-emb-constants
   1562   (regexp-opt
   1563    '("nil" "t" "raw" "escape")))
   1564 
   1565 (defvar web-mode-cl-emb-keywords
   1566   (regexp-opt
   1567    '("if" "else" "endif" "unless" "endunless" "var" "repeat"
   1568      "endrepeat" "loop" "endloop" "include" "call" "with"
   1569      "endwith" "set" "genloop" "endgenloop" "insert")))
   1570 
   1571 (defvar web-mode-artanis-constants
   1572   (regexp-opt
   1573    '("#f" "#t")))
   1574 
   1575 (defvar web-mode-artanis-keywords
   1576   (regexp-opt
   1577    (append
   1578     (cdr (assoc "artanis" web-mode-extra-keywords))
   1579     '("begin" "cut" "cute" "if" "when" "unless" "cond" "case"
   1580       "do" "quote" "syntax" "lambda" "lambda*" "and" "and-let*"
   1581       "or" "else" "delay" "receive" "use-modules" "match"
   1582       "match-lambda" "match-lambda*" "match-let" "match-let*"
   1583       "match-letrec" "let" "let*" "letrec" "letrec*" "and-let*"
   1584       "let-syntax" "letrec-syntax" "syntax-rules" "syntax-case"
   1585       "define" "define-syntax" "define-macro"
   1586       "define-condition-type" "define-immutable-record-type"
   1587       "define-record-type" "define-values" "parameterize" "for-each"
   1588       "require-extension" "set!" "test-approximate" "test-assert"
   1589       "test-begin" "test-end" "test-eq" "test-equal" "test-eqv"
   1590       "test-error" "test-group" "test-group-with-cleanup" "test-with-runner"))))
   1591 
   1592 (defvar web-mode-lsp-constants
   1593   (regexp-opt
   1594    '("nil" "t")))
   1595 
   1596 (defvar web-mode-lsp-keywords
   1597   (regexp-opt
   1598    '("dolist" "let" "while" "cond" "when" "progn" "if"
   1599      "dotimes" "unless" "lambda"
   1600      "loop" "for" "and" "or" "in" "do" "defun")))
   1601 
   1602 (defvar web-mode-php-constants
   1603   (regexp-opt
   1604    (append
   1605     (cdr (assoc "php" web-mode-extra-constants))
   1606     '("TRUE" "FALSE" "NULL" "true" "false" "null"
   1607       "STR_PAD_LEFT" "STR_PAD_RIGHT"
   1608       "ENT_COMPAT" "ENT_QUOTES" "ENT_NOQUOTES" "ENT_IGNORE"
   1609       "ENT_SUBSTITUTE" "ENT_DISALLOWED" "ENT_HTML401" "ENT_XML1"
   1610       "ENT_XHTML" "ENT_HTML5" "JSON_PRETTY_PRINT" "JSON_UNESCAPED_SLASHES"
   1611       "LIBXML_NOBLANKS"))))
   1612 
   1613 (defvar web-mode-php-keywords
   1614   (regexp-opt
   1615    (append
   1616     (cdr (assoc "php" web-mode-extra-keywords))
   1617     '("abstract" "and" "array" "as" "break" "case" "catch" "class" "clone"
   1618       "const" "continue" "declare" "default" "die" "do" "echo" "else" "elseif"
   1619       "empty" "enddeclare" "endfor" "endforeach" "endif" "endswitch" "endwhile"
   1620       "eval" "exit" "extends" "final" "finally" "fn" "for" "foreach" "function"
   1621       "global" "goto" "if" "implements" "include" "include_once" "instanceof"
   1622       "insteadof" "interface" "isset" "list" "namespace" "new" "or" "parent"
   1623       "print" "private" "protected" "public" "require" "require_once" "return"
   1624       "self" "static" "switch" "trait" "try" "throw" "unset" "use" "var"
   1625       "while" "xor" "yield" "yield from"))))
   1626 
   1627 (defvar web-mode-php-types
   1628   (eval-when-compile
   1629     (regexp-opt
   1630      '("array" "bool" "boolean" "callable" "float" "int" "integer"
   1631        "iterable" "mixed" "object" "resource" "string" "void"))))
   1632 
   1633 (defvar web-mode-css-at-rules
   1634   (eval-when-compile
   1635     (regexp-opt
   1636      '("charset" "import" "media" "page" "font-face"
   1637        "namespace" "supports" "document"
   1638        "keyframes" "-moz-keyframes" "-webkit-keyframes"
   1639        "mixin" "viewport"))))
   1640 
   1641 (defvar web-mode-css-pseudo-classes
   1642   (eval-when-compile
   1643     (regexp-opt
   1644      '("active" "after" "before" "checked" "disabled" "empty" "enabled"
   1645        "first" "first-child" "first-letter" "first-line" "first-of-type" "focus"
   1646        "hover" "lang" "last-child" "last-of-type" "left" "link"
   1647        "not" "nth-child" "nth-last-child" "nth-last-of-type" "nth-of-type"
   1648        "only-child" "only-of-type"
   1649        "right" "root" "selection" "target" "visited"))))
   1650 
   1651 (defvar web-mode-python-keywords
   1652   (regexp-opt
   1653    (append
   1654     (cdr (assoc "python" web-mode-extra-keywords))
   1655     '("and" "as" "assert" "break" "class" "continue" "def" "del"
   1656       "elif" "else" "except" "finally" "for" "from" "global"
   1657       "if" "import" "in" "is" "lambda" "nonlocal" "not" "or" "pass"
   1658       "raise" "return" "try" "while" "with" "yield"))))
   1659 
   1660 (defvar web-mode-jsp-keywords
   1661   (regexp-opt
   1662    (append
   1663     (cdr (assoc "jsp" web-mode-extra-keywords))
   1664     '("case" "catch" "do" "else" "end" "false" "for" "function"
   1665       "if" "in" "include"
   1666       "new" "package" "page" "private" "protected" "public"
   1667       "return" "tag" "taglib" "throw" "throws" "true" "try" "void" "while"))))
   1668 
   1669 (defvar web-mode-erb-keywords
   1670   (regexp-opt
   1671    (append
   1672     (cdr (assoc "erb" web-mode-extra-keywords))
   1673     '("alias" "and" "begin" "break" "case" "class" "def" "defined?" "do"
   1674       "elsif" "else" "end" "ensure" "fail" "for" "if" "in"
   1675       "module" "next" "not" "or" "redo" "rescue" "retry" "return"
   1676       "then" "super" "unless" "undef" "until" "when" "while" "yield"
   1677       "__ENCODING__" "__FILE__" "__LINE__"))))
   1678 
   1679 (defvar web-mode-mason-keywords
   1680   (regexp-opt
   1681    (append
   1682     (cdr (assoc "mason" web-mode-extra-keywords))
   1683     '("and" "base" "close" "die" "each" "else" "elsif" "eval" "exists"
   1684       "foreach" "grep" "if" "length" "local" "my" "next" "open" "or"
   1685       "package" "pop" "ref" "return" "stat" "sub" "tie"
   1686       "undef" "unless" "use" "while"))))
   1687 
   1688 (defvar web-mode-erb-builtins
   1689   (regexp-opt
   1690    (append
   1691     (cdr (assoc "erb" web-mode-extra-builtins))
   1692 
   1693     '("__callee__" "__dir__" "__method__"
   1694       "abort" "at_exit" "autoload" "autoload?"
   1695       "binding" "block_given?" "caller" "catch"
   1696       "eval" "exec" "exit" "exit!" "fail" "fork" "format"
   1697       "lambda" "load" "loop" "open"
   1698       "p" "print" "printf" "proc" "putc" "puts"
   1699       "raise" "rand" "readline" "readlines" "require" "require_relative"
   1700       "sleep" "spawn" "sprintf" "srand" "syscall" "system"
   1701       "throw" "trap" "warn"
   1702       "alias_method" "attr" "attr_accessor" "attr_reader" "attr_writer"
   1703       "define_method" "extend" "include" "module_function"
   1704       "prepend" "private" "protected" "public"
   1705       "refine" "using"
   1706 
   1707       "error_message_on" "error_messages_for" "form" "input"
   1708       "auto_discovery_link_tag" "image_tag" "javascript_include_tag"
   1709       "stylesheet_link_tag" "image_path" "path_to_image"" "
   1710       "javascript_path" "path_to_javascript" "register_javascript_expansion"
   1711       "register_javascript_include_default" "register_stylesheet_expansion"
   1712       "stylesheet_path" "path_to_stylesheet" "atom_feed" "entry" "updated"
   1713       "benchmark" "cache" "capture" "content_for" "distance_of_time_in_words"
   1714       "distance_of_time_in_words_to_now" "time_ago_in_words" "date_select"
   1715       "datetime_select" "time_select" "select_date" "select_datetime"
   1716       "select_day" "select_hour" "select_minute" "select_month" "select_second"
   1717       "select_time" "select_year" "debug"
   1718       "check_box" "fields_for" "file_field" "form_for" "hidden_field"
   1719       "label" "password_field" "radio_button" "text_area" "text_field"
   1720       "check_box_tag" "field_set_tag" "file_field_tag" "form_with" "form_tag"
   1721       "hidden_field_tag" "image_submit_tag" "label_tag" "password_field_tag"
   1722       "radio_button_tag" "select_tag" "submit_tag" "text_area_tag"
   1723       "text_field_tag"
   1724       "collection_select" "country_options_for_select" "country_select"
   1725       "option_groups_from_collection_for_select" "options_for_select"
   1726       "options_from_collection_for_select" "select"
   1727       "time_zone_options_for_select"
   1728       "time_zone_select" "button_to_function" "define_javascript_functions"
   1729       "escape_javascript" "javascript_tag" "link_to_function"" "
   1730       "number_to_currency" "number_to_human_size" "number_to_percentage"
   1731       "number_to_phone" "number_with_delimiter" "number_with_precision"
   1732       "evaluate_remote_response" "form_remote_for" "form_remote_tag"
   1733       "link_to_remote" "observe_field" "observe_field"
   1734       "periodically_call_remote"
   1735       "remote_form_for" "remote_function" "submit_to_remote" "update_page"
   1736       "update_page_tag" "dom_class" "dom_id" "partial_path" "sanitize"
   1737       "sanitize_css" "strip_links" "strip_tags"
   1738       "cdata_section" "content_tag" "escape_once" "tag"
   1739       "auto_link" "concat" "cycle" "excerpt" "highlight" "markdown" "pluralize"
   1740       "reset_cycle" "simple_format" "textilize" "textilize_without_paragraph"
   1741       "truncate" "word_wrap" "button_to" "current_page?" "link_to" "link_to_if"
   1742       "link_to_unless" "link_to_unless_current" "mail_to" "url_for"
   1743       "action_name" "atom_feed" "audio_path" "audio_tag"
   1744       "content_tag_for" "controller" "controller_name" "action_name"
   1745       "controller_path" "convert_to_model" "cookies" "csrf_meta_tag"
   1746       "csrf_meta_tags" "headers"
   1747       "current_cycle" "div_for" "email_field" "email_field_tag"
   1748       "favicon_link_tag" "flash" "l" "button_tag"
   1749       "grouped_collection_select" "grouped_options_for_select"
   1750       "image_alt" "j" "javascript_cdata_section"
   1751       "localize" "logger" "number_field"
   1752       "number_field_tag" "number_to_human" "params" "path_to_audio"
   1753       "path_to_video" "phone_field" "phone_field_tag" "provide"
   1754       "range_field" "range_field_tag" "raw" "render" "render_to_string" "request"
   1755       "request_forgery_protection_token" "response" "safe_concat"
   1756       "safe_join" "search_field" "search_field_tag"
   1757       "session" "t" "telephone_field" "telephone_field_tag"
   1758       "time_tag" "translate" "url_field" "url_field_tag"
   1759       "url_options" "video_path" "video_tag" "simple_form_for"
   1760       "javascript_pack_tag" "stylesheet_pack_tag" "csp_meta_tag"
   1761 
   1762       ))))
   1763 
   1764 (defvar web-mode-asp-constants
   1765   (regexp-opt
   1766    (append
   1767     (cdr (assoc "asp" web-mode-extra-constants))
   1768     '("adAsyncExecute" "adAsyncFetch" "adAsyncFetchNonBlocking" "adCmdFile"
   1769       "adCmdStoredProc" "adCmdTable" "adCmdTableDirect" "adCmdText" "adCmdUnknown"
   1770       "adCmdUnspecified" "adExecuteNoRecords" "adExecuteRecord" "adExecuteStream"
   1771       "adLockBatchOptimistic" "adLockOptimistic" "adLockPessimistic"
   1772       "adLockReadOnly" "adLockUnspecified" "adOpenDynamic" "adOpenForwardOnly"
   1773       "adOpenKeyset" "adOpenStatic" "adOpenUnspecified" "adOptionUnspecified"
   1774       "Empty" "Nothing" "Null" "True" "False"
   1775       "vbBack" "vbCr" "vbCrLf" "vbFormFeed" "vbLf" "vbNewLine" "vbNullChar"
   1776       "vbNullString" "vbObjectError" "vbScript" "vbTab" "vbVerticalTab"))))
   1777 
   1778 (defvar web-mode-asp-keywords
   1779   (regexp-opt
   1780    (append
   1781     (cdr (assoc "asp" web-mode-extra-keywords))
   1782     '("Abs" "And" "Array" "Asc" "Atn"
   1783       "CBool" "CByte" "CCur" "CDate" "CDbl" "CInt" "CLng" "CSng" "CStr"
   1784       "Call" "Case" "Chr" "Class" "Const" "Cos" "CreateObject"
   1785       "Date" "DateAdd" "DateDiff" "DatePart" "DateSerial" "DateValue"
   1786       "Day" "Dim" "Do"
   1787       "Each" "Else" "ElseIf" "End" "Erase" "Err" "Eval" "Exit" "Exp"
   1788       "Explicit"
   1789       "Filter" "Fix" "For" "FormatCurrency" "FormatDateTime"
   1790       "FormatNumber" "FormatPercent" "Function"
   1791       "GetLocale" "GetObject" "GetRef" "Hex" "Hour"
   1792       "If" "In" "InStr" "InStrRev" "InputBox" "Int" "IsArray" "IsDate"
   1793       "IsEmpty" "IsNull" "IsNumeric" "IsObject" "Join"
   1794       "LBound" "LCase" "LTrim" "Language" "Left" "Len" "Let"
   1795       "LoadPicture" "Log" "Loop"
   1796       "Mid" "Minute" "Month" "MonthName" "MsgBox"
   1797       "New" "Next" "Not" "Now"
   1798       "Oct" "On" "Option" "Or" "Preserve" "Private" "Public"
   1799       "RGB" "RTrim" "Redim" "Rem" "Replace" "Right" "Rnd" "Round"
   1800       "ScriptEngine" "ScriptEngineBuildVersion"
   1801       "ScriptEngineMajorVersion" "ScriptEngineMinorVersion"
   1802       "Second" "Select" "Set" "SetLocale" "Sgn" "Sin" "Space" "Split"
   1803       "Sqr" "StrComp" "StrReverse" "String" "Sub"
   1804       "Tan" "Then" "Time" "TimeSerial" "TimeValue" "Timer" "To" "Trim"
   1805       "TypeName"
   1806       "UBound" "UCase" "Until" "VarType"
   1807       "Weekday" "WeekdayName" "Wend" "With" "While" "Year"))))
   1808 
   1809 (defvar web-mode-asp-types
   1810   (regexp-opt
   1811    (append
   1812     (cdr (assoc "asp" web-mode-extra-types))
   1813     '("Application" "ASPError" "Request" "Response" "Server" "Session"))))
   1814 
   1815 (defvar web-mode-aspx-keywords
   1816   (regexp-opt
   1817    (append
   1818     (cdr (assoc "aspx" web-mode-extra-keywords))
   1819     '("case" "catch" "do" "else" "end" "for" "foreach" "function"
   1820       "if" "in" "include" "new" "package" "page" "return"
   1821       "tag" "throw" "throws" "try" "while"))))
   1822 
   1823 (defvar web-mode-smarty-keywords
   1824   (regexp-opt '("as")))
   1825 
   1826 (defvar web-mode-velocity-keywords
   1827   (eval-when-compile
   1828     (regexp-opt '("in" "true" "false"))))
   1829 
   1830 (defvar web-mode-freemarker-keywords
   1831   (eval-when-compile
   1832     (regexp-opt '("as" "list"))))
   1833 
   1834 (defvar web-mode-go-keywords
   1835   (eval-when-compile
   1836     (regexp-opt
   1837      '("const" "define" "else" "end"
   1838        "for" "func" "if" "import"
   1839        "pipeline" "range" "return" "struct"
   1840        "template" "type" "var" "with"))))
   1841 
   1842 (defvar web-mode-go-functions
   1843   (eval-when-compile
   1844     (regexp-opt
   1845      '("and" "call" "ge" "html" "index" "js" "len" "not" "or"
   1846        "print" "printf" "println" "urlquery" "where"))))
   1847 
   1848 (defvar web-mode-go-types
   1849   (regexp-opt
   1850    (append
   1851     (cdr (assoc "go" web-mode-extra-types))
   1852     '("int" "string"))))
   1853 
   1854 (defvar web-mode-closure-keywords
   1855   (eval-when-compile
   1856     (regexp-opt '("in" "and" "not" "or"))))
   1857 
   1858 (defvar web-mode-svelte-keywords
   1859   (regexp-opt '("as")))
   1860 
   1861 (defvar web-mode-django-control-blocks
   1862   (append
   1863    (cdr (assoc "django" web-mode-extra-control-blocks))
   1864    '(
   1865 
   1866      "assets" "autoescape"
   1867      "block" "blocktrans" "blocktranslate"
   1868      "cache" "call" "capture" "comment"
   1869      "draw"
   1870      "embed"
   1871      "filter" "for" "foreach" "form"
   1872      "if" "ifchanged" "ifequal" "ifnotequal"
   1873      "macro"
   1874      "random" "raw"
   1875      "safe" "sandbox" "spaceless"
   1876      "tablerow"
   1877      "unless"
   1878      "verbatim"
   1879      "with"
   1880 
   1881      "endassets" "endautoescape"
   1882      "endblock" "endblocktrans" "endblocktranslate"
   1883      "endcache" "endcall" "endcapture" "endcomment"
   1884      "draw"
   1885      "endembed"
   1886      "endfilter" "endfor" "endforeach" "endform"
   1887      "endif" "endifchanged" "endifequal" "endifnotequal"
   1888      "endmacro"
   1889      "endrandom" "endraw"
   1890      "endsafe" "endsandbox" "endspaceless"
   1891      "endtablerow"
   1892      "endunless"
   1893      "endverbatim"
   1894      "endwith"
   1895 
   1896      ;; "set" "endset" ;#504
   1897 
   1898      "csrf_token" "cycle" "debug"
   1899      "elif" "else" "elseif" "elsif" "empty" "extends"
   1900      "firstof" "include" "load" "lorem" "now" "regroup" "ssi"
   1901      "trans" "templatetag" "url" "widthratio"
   1902 
   1903      ;; #805
   1904      "graph" "endgraph"
   1905      "javascript" "endjavascript"
   1906      "schema" "endschema"
   1907      "stylesheet" "endstylesheet"
   1908 
   1909      )))
   1910 
   1911 (defvar web-mode-django-control-blocks-regexp
   1912   (regexp-opt web-mode-django-control-blocks t))
   1913 
   1914 (defvar web-mode-django-keywords
   1915   (eval-when-compile
   1916     (regexp-opt
   1917      '("and" "as" "assign"
   1918        "break"
   1919        "cache" "call" "case" "context" "continue"
   1920        "do"
   1921        "flush" "from"
   1922        "ignore" "import" "in" "is"
   1923        "layout" "load"
   1924        "missing"
   1925        "none" "not"
   1926        "or"
   1927        "pluralize"
   1928        "random"
   1929        "set" ;#504
   1930        "unless" "use"
   1931        "var"
   1932        ))))
   1933 
   1934 (defvar web-mode-django-types
   1935   (eval-when-compile
   1936     (regexp-opt '("null" "false" "true"))))
   1937 
   1938 (defvar web-mode-blade-control-blocks
   1939   (append
   1940    (cdr (assoc "blade" web-mode-extra-control-blocks))
   1941    '("component" "foreach" "forelse" "for" "if" "section" "slot" "switch" "unless" "while")
   1942    ))
   1943 
   1944 (defvar web-mode-blade-control-blocks-regexp
   1945   (regexp-opt web-mode-blade-control-blocks t))
   1946 
   1947 (defvar web-mode-directives
   1948   (eval-when-compile
   1949     (regexp-opt
   1950      '("include" "page" "taglib"
   1951        "Assembly" "Control" "Implements" "Import"
   1952        "Master" "OutputCache" "Page" "Reference" "Register"))))
   1953 
   1954 (defvar web-mode-template-toolkit-keywords
   1955   (regexp-opt
   1956    '("block" "call" "case" "catch" "clear" "default" "do"
   1957      "else" "elsif" "end" "filter" "final" "for"
   1958      "foreach" "get" "if" "in" "include" "insert" "is" "last"
   1959      "macro" "meta" "or" "perl" "process" "rawperl" "return"
   1960      "set" "stop" "switch" "tags" "throw" "try"
   1961      "unless" "use" "while" "wrapper")))
   1962 
   1963 (defvar web-mode-perl-keywords
   1964   (regexp-opt
   1965    '("__DATA__" "__END__" "__FILE__" "__LINE__" "__PACKAGE__"
   1966      "and" "cmp" "continue" "CORE" "do" "else" "elsif" "eq" "exp"
   1967      "for" "foreach" "ge" "gt" "if" "le" "lock" "lt" "m" "ne" "no"
   1968      "or" "package" "q" "qq" "qr" "qw" "qx" "s" "sub"
   1969      "tr" "unless" "until" "while" "xor" "y"
   1970      "my" "use" "print" "say")))
   1971 
   1972 (defvar web-mode-javascript-keywords
   1973   (regexp-opt
   1974    (append
   1975     (cdr (assoc "javascript" web-mode-extra-keywords))
   1976     '("as" "async" "await" "break" "case" "catch" "class" "const" "continue"
   1977       "debugger" "default" "delete" "do" "else" "enum" "eval"
   1978       "export" "extends" "finally" "for" "from" "function" "get" "if"
   1979       "implements" "import" "in" "instanceof" "interface" "let"
   1980       "new" "of" "package" "private" "protected" "public"
   1981       "return" "set" "static" "super" "switch"
   1982       "throw" "try" "type" "typeof" "var" "void" "while" "with" "yield"))))
   1983 
   1984 (defvar web-mode-javascript-constants
   1985   (regexp-opt
   1986    '("false" "null" "undefined" "Infinity" "NaN" "true" "arguments" "this")))
   1987 
   1988 (defvar web-mode-razor-keywords
   1989   (regexp-opt
   1990    (append
   1991     (cdr (assoc "razor" web-mode-extra-keywords))
   1992     '("false" "true" "foreach" "if" "else" "in" "var" "for" "display"
   1993       "match" "case" "to"
   1994       "Html"))))
   1995 
   1996 (defvar web-mode-selector-font-lock-keywords
   1997   (list
   1998    '("$[[:alnum:]-]+" 0 'web-mode-css-variable-face)
   1999    (cons (concat "@\\(" web-mode-css-at-rules "\\)\\_>")
   2000          '(0 'web-mode-css-at-rule-face))
   2001    '("\\_<\\(all\|braille\\|embossed\\|handheld\\|print\\|projection\\|screen\\|speech\\|tty\\|tv\\|and\\|or\\)\\_>"
   2002      1 'web-mode-keyword-face)
   2003    '("\\.[^ ,]+" 0 'web-mode-css-selector-class-face)
   2004    '("[^,]+" 0 'web-mode-css-selector-tag-face)
   2005    (cons (concat ":\\([ ]*[[:alpha:]][^,{]*\\)") '(0 'web-mode-css-pseudo-class-face t t))
   2006    ))
   2007 
   2008 (defvar web-mode-declaration-font-lock-keywords
   2009   (list
   2010    '("--[[:alnum:]-]+" 0 'web-mode-css-variable-face)
   2011    '("$[[:alnum:]-]+" 0 'web-mode-css-variable-face)
   2012    (cons (concat "@\\(" web-mode-css-at-rules "\\)\\_>") '(1 'web-mode-css-at-rule-face))
   2013    '("\\([[:alpha:]-]+\\)[ ]?:" 0 'web-mode-css-property-name-face)
   2014    '("\\([[:alpha:]-]+\\)[ ]?(" 1 'web-mode-css-function-face)
   2015    '("#[[:alnum:]]\\{1,6\\}" 0 'web-mode-css-color-face t t)
   2016    '("![ ]?important" 0 'web-mode-css-priority-face t t)
   2017    '("\\([^,]+\\)[ ]+{" 1 'web-mode-css-selector-face)
   2018    '("'[^']*'\\|\"[^\"]*\"" 0 'web-mode-string-face t t)
   2019    ))
   2020 
   2021 (defvar web-mode-html-font-lock-keywords
   2022   (list
   2023    '("</?[[:alnum:]]+[ >]\\|>" 0 'web-mode-html-tag-face t)
   2024    '(" \\([[:alnum:]-]+=\\)\\(\"[^\"]+\"\\)"
   2025      (1 'web-mode-html-attr-name-face)
   2026      (2 'web-mode-html-attr-value-face))
   2027    ))
   2028 
   2029 ;; voir https://www.gnu.org/software/emacs/manual/html_node/elisp/Search_002dbased-Fontification.html
   2030 (defvar web-mode-javascript-font-lock-keywords
   2031   (list
   2032    '("@\\([[:alnum:]_]+\\)\\_>" 0 'web-mode-keyword-face)
   2033    '("\\([[:alnum:]]+\\)[`]" 0 'web-mode-preprocessor-face)
   2034    (cons (concat "\\_<\\(function\\*\\)\\_>") '(1 'web-mode-keyword-face))
   2035    (cons (concat "\\([ \t}{(]\\|^\\)\\(" web-mode-javascript-keywords "\\)\\_>") '(2 'web-mode-keyword-face))
   2036    (cons (concat "\\_<\\(" web-mode-javascript-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2037    '("\\_<\\([$]\\)(" 1 'web-mode-type-face)
   2038    '("\\_<\\(new\\|instanceof\\|class\\|extends\\|import\\) \\([[:alnum:]_.]+\\)\\_>" 2 'web-mode-type-face)
   2039    '("\\_<\\([[:alnum:]_]+\\):[ ]*function[ ]*(" 1 'web-mode-function-name-face)
   2040    '("\\_<\\(function\\|get\\|set\\)[ ]+\\([[:alnum:]_]+\\)"
   2041      (1 'web-mode-keyword-face)
   2042      (2 'web-mode-function-name-face))
   2043    '("\\([[:alnum:]_]+\\)[ ]*([^)]*)[ \n]*{" 1 'web-mode-function-name-face)
   2044    '("([ ]*\\([[:alnum:]_]+\\)[ ]*=>" 1 'web-mode-function-name-face)
   2045    '("[ ]*\\([[:alnum:]_]+\\)[ ]*=[ ]*([^)]*)[ ]*=>[ ]*{" 1 'web-mode-function-name-face)
   2046    '("\\_<\\(var\\|let\\|const\\)[ ]+\\([[:alnum:]_]+\\)" 2 'web-mode-variable-name-face)
   2047    '("({" "\\([[:alnum:]_]+\\)[, }]+" nil nil (1 'web-mode-variable-name-face)) ;#738
   2048    '("\\([[:alnum:]_]+\\)[ ]*=> [{(]" 1 'web-mode-variable-name-face)
   2049    ;; #989
   2050    ;; '("\\(function\\|[,=]\\|^\\)[ ]*("
   2051    ;;   ("\\([[:alnum:]_]+\\)\\([ ]*=[^,)]*\\)?[,)]" nil nil (1 'web-mode-variable-name-face)))
   2052    '("\\([[:alnum:]_]+\\):" 1 'web-mode-variable-name-face)
   2053    '("\\_<\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2054    '("[a-zA-Z]<\\([a-zA-Z]+\\)[,>]" 1 'web-mode-type-face)
   2055    ))
   2056 
   2057 (defvar web-mode-stylus-font-lock-keywords
   2058   (list
   2059    '("^[ \t]*\\([[:alnum:]().-]+\\)$" 1 'web-mode-css-selector-face)
   2060    '("^[ \t]*\\([[:alnum:]-]+[ ]*:\\)" 1 'web-mode-css-property-name-face)
   2061    ))
   2062 
   2063 (defvar web-mode-sass-font-lock-keywords
   2064   (list
   2065    '("^[ \t]*\\([[:alnum:]().-]+\\|&:\\(before\\|after\\)\\)$" 1 'web-mode-css-selector-face)
   2066    '("^[ \t]*\\([[:alnum:]-]+[ ]*:\\)" 1 'web-mode-css-property-name-face)
   2067    ))
   2068 
   2069 (defvar web-mode-pug-font-lock-keywords
   2070   (list
   2071    '("^[ \t]*\\(#?[[:alnum:].-]+\\)" 1 'web-mode-css-selector-face)
   2072    ;;'("^[ \t]*\\(#[[:alnum:]-]+\\)" 0 'web-mode-css-selector-face)
   2073    '(" \\([@:]?\\sw+[ ]?=\\)" 1 'web-mode-param-name-face)
   2074    ))
   2075 
   2076 (defvar web-mode-sql-font-lock-keywords
   2077   (list
   2078    (cons (concat "\\_<\\(" web-mode-sql-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2079    '("\\_<\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2080    ))
   2081 
   2082 (defvar web-mode-markdown-font-lock-keywords
   2083   (list
   2084    '("^[ ]*[*].*$" 0 'web-mode-variable-name-face)
   2085    '("^[ ]*#.*$" 0 'web-mode-comment-face)
   2086    ))
   2087 
   2088 (defvar web-mode-html-tag-font-lock-keywords
   2089   (list
   2090    '("\\(</?\\)\\([[:alnum:]]+\\)"
   2091      (1 'web-mode-html-tag-bracket-face)
   2092      (2 'web-mode-html-tag-face))
   2093    '("\"[^\"]*\"" 0 'web-mode-html-attr-value-face)
   2094    '("\\([[:alnum:]]+\\)" 1 'web-mode-html-attr-name-face)
   2095    '("/?>" 0 'web-mode-html-tag-bracket-face)
   2096    ))
   2097 
   2098 (defvar web-mode-anki-font-lock-keywords
   2099   (list
   2100    '("{{[#/^]\\([[:alnum:]_.]+\\)" 1 'web-mode-block-control-face)
   2101    ;;'("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_.: ]*\\)"
   2102    ;;  (1 'web-mode-block-attr-name-face)
   2103    ;;  (2 'web-mode-block-attr-value-face))
   2104    '("{{\\(.+\\)}}" 1 'web-mode-variable-name-face)
   2105    ))
   2106 
   2107 (defvar web-mode-dust-font-lock-keywords
   2108   (list
   2109    '("{[#:/?@><+^]\\([[:alpha:]_.]+\\)" 1 'web-mode-block-control-face)
   2110    '(":\\([[:alpha:]]+\\)" 1 'web-mode-keyword-face)
   2111    '("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_]*\\)"
   2112      (1 'web-mode-block-attr-name-face)
   2113      (2 'web-mode-block-attr-value-face))
   2114    '("\\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face)
   2115    ))
   2116 
   2117 (defvar web-mode-expressionengine-font-lock-keywords
   2118   (list
   2119    '("{/?\\([[:alpha:]_]+:[[:alpha:]_:]+\\|if\\)" 1 'web-mode-block-control-face)
   2120    '(":\\([[:alpha:]_]+\\)" 1 'web-mode-keyword-face)
   2121    '(" {\\([[:alpha:]_]+\\)}" 1 'web-mode-keyword-face t)
   2122    '("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_]*\\)"
   2123      (1 'web-mode-block-attr-name-face)
   2124      (2 'web-mode-block-attr-value-face))
   2125    '("\\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face)
   2126    ))
   2127 
   2128 (defvar web-mode-svelte-font-lock-keywords
   2129   (list
   2130    (cons (concat "[ ]\\(" web-mode-svelte-keywords "\\)[ ]") '(1 'web-mode-keyword-face))
   2131    '("{[#:/@]\\([[:alpha:]_.]+\\)" 1 'web-mode-block-control-face)
   2132    '("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_]*\\)"
   2133      (1 'web-mode-block-attr-name-face)
   2134      (2 'web-mode-block-attr-value-face))
   2135    '("\\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face)
   2136    '("\\_<\\([$]\\)\\([[:alnum:]_]+\\)" (1 'web-mode-constant-face) (2 'web-mode-variable-name-face))
   2137    ))
   2138 
   2139 (defvar web-mode-template-toolkit-font-lock-keywords
   2140   (list
   2141    (cons (concat "\\_<\\(" web-mode-template-toolkit-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2142    '("\\\([[:alpha:]][[:alnum:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2143    '("\\\([[:alpha:]][[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2144    ))
   2145 
   2146 (defvar web-mode-smarty-font-lock-keywords
   2147   (list
   2148    (cons (concat "[ ]\\(" web-mode-smarty-keywords "\\)[ ]") '(1 'web-mode-keyword-face))
   2149    '("{/?\\([[:alpha:]_]+\\)" 1 'web-mode-block-control-face)
   2150    '("\\([}{]\\)" 0 'web-mode-block-delimiter-face)
   2151    '("\\_<\\([$]\\)\\([[:alnum:]_]+\\)" (1 nil) (2 'web-mode-variable-name-face))
   2152    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2153    '(" \\(\\sw+[ ]?=\\)" 1 'web-mode-param-name-face)
   2154    '(" \\(\\sw+\\)[ }]" 1 'web-mode-param-name-face)
   2155    '("|\\([[:alnum:]_]+\\)" 1 'web-mode-function-call-face)
   2156    '("\\(->\\)\\(\\sw+\\)" (1 nil) (2 'web-mode-variable-name-face))
   2157    '("[.]\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2158    '("[.]\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2159    '("#\\([[:alnum:]_]+\\)#" 1 'web-mode-variable-name-face)
   2160    ))
   2161 
   2162 (defvar web-mode-velocity-font-lock-keywords
   2163   (list
   2164    '("#{?\\([[:alpha:]_]+\\)\\_>" (1 'web-mode-block-control-face))
   2165    (cons (concat "\\_<\\(" web-mode-velocity-keywords "\\)\\_>") '(1 'web-mode-keyword-face t t))
   2166    '("#macro([ ]*\\([[:alpha:]]+\\)[ ]+" 1 'web-mode-function-name-face)
   2167    '("\\(def\\|define\\) \\([[:alnum:]_-]+\\)(" 2 'web-mode-function-name-face)
   2168    '("[.]\\([[:alnum:]_-]+\\)" 1 'web-mode-variable-name-face)
   2169    '("\\_<\\($[!]?[{]?\\)\\([[:alnum:]_-]+\\)[}]?" (1 nil) (2 'web-mode-variable-name-face))
   2170    ))
   2171 
   2172 (defvar web-mode-mako-tag-font-lock-keywords
   2173   (list
   2174    '("</?%\\([[:alpha:]:]+\\)" 1 'web-mode-block-control-face)
   2175    '("\\_<\\([[:alpha:]]+=\\)\\(\"[^\"]*\"\\)"
   2176      (1 'web-mode-block-attr-name-face t t)
   2177      (2 'web-mode-block-attr-value-face t t))
   2178    ))
   2179 
   2180 (defvar web-mode-mako-block-font-lock-keywords
   2181   (list
   2182    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2183    (cons (concat "\\_<\\(" web-mode-python-constants "\\)\\_>") '(1 'web-mode-constant-face))
   2184    (cons (concat "\\_<\\(" web-mode-python-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2185    (cons (concat "\\_<\\(endfor\\|endif\\|endwhile\\)\\_>") '(1 'web-mode-keyword-face))
   2186    ))
   2187 
   2188 (defvar web-mode-web2py-font-lock-keywords
   2189   (list
   2190    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2191    (cons (concat "\\_<\\(" web-mode-python-constants "\\)\\_>") '(1 'web-mode-constant-face))
   2192    (cons (concat "\\_<\\(" web-mode-python-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2193    (cons (concat "\\_<\\(block\\|extend\\|super\\|end\\|include\\)\\_>") '(1 'web-mode-keyword-face))
   2194    ))
   2195 
   2196 (defvar web-mode-django-expr-font-lock-keywords
   2197   (list
   2198    '("|[ ]?\\([[:alpha:]_]+\\)\\_>" 1 'web-mode-filter-face)
   2199    (cons (concat "\\_<\\(" web-mode-django-types "\\)\\_>") '(1 'web-mode-type-face))
   2200    '("\\_<\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2201    '("[[:alnum:]_]+" 0 'web-mode-variable-name-face)
   2202    ))
   2203 
   2204 (defvar web-mode-django-code-font-lock-keywords
   2205   (list
   2206    '("{%[ ]*\\(set\\)[ ]+\\([[:alpha:]]+\\)[ ]*%}"
   2207      (1 'web-mode-block-control-face)
   2208      (2 'web-mode-variable-name-face))
   2209    (cons (concat "\\({%\\|#\\)[ ]*\\(" web-mode-django-control-blocks-regexp "\\)[ %]") '(2 'web-mode-block-control-face))
   2210    '("\\({%\\|#\\)[ ]*\\(end[[:alpha:]]+\\)\\_>" 2 'web-mode-block-control-face) ;#504
   2211    (cons (concat "\\_<\\(" web-mode-django-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2212    (cons (concat "\\_<\\(" web-mode-django-types "\\)\\_>") '(1 'web-mode-type-face))
   2213    '("|[ ]?\\([[:alpha:]_]+\\)\\_>" 1 'web-mode-function-call-face)
   2214    '("\\_<\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2215    '("[[:alnum:]_.]+" 0 'web-mode-variable-name-face)
   2216    '("[[:alnum:]_]+\\([.][[:alnum:]_]+\\)+" 0 'web-mode-variable-name-face t t)
   2217    ))
   2218 
   2219 (defvar web-mode-ctemplate-font-lock-keywords
   2220   (list
   2221    '("{[~]?{[#/>^]?[ ]*\\([[:alnum:]_.-]+\\)" 1 'web-mode-block-control-face)
   2222    '("[ \t]+\\([[:alnum:]_-]+\\)="
   2223      (1 'web-mode-block-attr-name-face))
   2224    '("\"[^\"]+\"" 0 'web-mode-block-string-face)
   2225    ))
   2226 
   2227 (defvar web-mode-astro-font-lock-keywords
   2228   (append
   2229    (list
   2230     '("\\({\\)\\([[:alpha:]]+\\)\\(}\\)"
   2231       (1 'web-mode-block-control-face)
   2232       (2 'web-mode-variable-name-face)
   2233       (3 'web-mode-block-control-face)))
   2234     web-mode-javascript-font-lock-keywords
   2235     ))
   2236 
   2237 (defvar web-mode-antlers-font-lock-keywords
   2238   (list
   2239    '("{{[ ]*\\(/?\\(if\\|elseif\\|else\\|unless\\|switch\\)\\)" 1 'web-mode-block-control-face)
   2240    '("[ \t]+\\(:?[[:alnum:]_-]+\\)=" (1 'web-mode-block-attr-name-face))
   2241    '("[[:alnum:]_.]+" 0 'web-mode-variable-name-face)
   2242    '("\"[^\"]+\"" 0 'web-mode-block-string-face)
   2243    '("'[^']+'" 0 'web-mode-block-string-face)
   2244    ))
   2245 
   2246 (defvar web-mode-razor-font-lock-keywords
   2247   (list
   2248    '("@\\([[:alnum:]_.]+\\)[ ]*[({]" 1 'web-mode-block-control-face)
   2249    (cons (concat "\\_<\\(" web-mode-razor-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2250    '("\\_<\\(String\\)\\_>" 1 'web-mode-type-face)
   2251    '("\\([[:alnum:]]+:\\)" 1 'web-mode-symbol-face)
   2252    '("\\(@[[:alnum:]_.]+\\)" 1 'web-mode-variable-name-face)
   2253    ))
   2254 
   2255 (defvar web-mode-riot-font-lock-keywords
   2256   (list
   2257    '("\\(parent\\|opts\\|tags\\|this\\)\\.\\([[:alnum:]_.]+\\)"
   2258      (1 'web-mode-constant-face)
   2259      (2 'web-mode-variable-name-face))
   2260    '("\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face)
   2261    ))
   2262 
   2263 (defvar web-mode-closure-font-lock-keywords
   2264   (list
   2265    '("{\\([@/]?[[:alpha:]]+[?]?\\)" 1 'web-mode-block-control-face)
   2266    '("{[@]?param[?]?[ ]+\\([[:alnum:]]+[:]?\\)" 1 'web-mode-symbol-face)
   2267    '("\\_<\\(true\\|false\\|null\\)\\_>" 1 'web-mode-type-face)
   2268    '("\\\_<[[:alpha:]]+:[ ]+\\([[:alpha:]]+\\)" 1 'web-mode-type-face)
   2269    (cons (concat "\\_<\\(" web-mode-closure-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2270    '("{\\(alias\\|call\\|delcall\\|delpackage\\|deltemplate\\|namespace\\|template\\)[ ]+\\([[:alnum:].]+\\)" 2 'web-mode-constant-face)
   2271    '("\\(allowemptydefault\\|data\\|desc\\|meaning\\|autoescape\\|private\\|variant\\)=" 0 'web-mode-block-attr-name-face)
   2272    '("|\\([[:alpha:]]+\\)" 1 'web-mode-function-call-face)
   2273    '("\\_<\\([[:alnum:]]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2274    '("$\\([[:alnum:]._]+\\)" 1 'web-mode-variable-name-face)
   2275    ))
   2276 
   2277 (defvar web-mode-go-font-lock-keywords
   2278   (list
   2279    '("{{[-]?[ ]*\\([[:alpha:]]+\\)" 1 'web-mode-block-control-face)
   2280    '("\\_<func \\([[:alnum:]]+\\)" 1 'web-mode-function-name-face)
   2281    '("\\_<type \\([[:alnum:]]+\\)" 1 'web-mode-type-face)
   2282    (cons (concat "\\_<\\(" web-mode-go-types "\\)\\_>") '(0 'web-mode-type-face))
   2283    (cons (concat "\\_<\\(" web-mode-go-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2284    (cons (concat "\\_<\\(" web-mode-go-functions "\\)\\_>") '(1 'web-mode-function-call-face))
   2285    '("[$.]\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face t t)
   2286    '("|[ ]?\\([[:alpha:]_]+\\)\\_>" 1 'web-mode-filter-face)
   2287    ))
   2288 
   2289 (defvar web-mode-expression-font-lock-keywords
   2290   (list
   2291    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2292    ))
   2293 
   2294 (defvar web-mode-angular-font-lock-keywords
   2295   (list
   2296    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2297    ))
   2298 
   2299 (defvar web-mode-underscore-font-lock-keywords
   2300   (list
   2301    (cons (concat "\\_<\\(" web-mode-javascript-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2302    '("\\_<\\(_\.[[:alpha:]]+\\)(" 1 'web-mode-function-call-face)
   2303    '("\\_<new \\([[:alnum:]_.]+\\)\\_>" 1 'web-mode-type-face)
   2304    '("\\_<\\([[:alnum:]_]+\\):[ ]*function[ ]*(" 1 'web-mode-function-name-face)
   2305    '("\\_<\\(var\\)\\_>[ ]+\\([[:alnum:]_]+\\)"
   2306      (1 'web-mode-keyword-face)
   2307      (2 'web-mode-variable-name-face))
   2308    ))
   2309 
   2310 (defvar web-mode-vue-font-lock-keywords
   2311   (list
   2312    '("\\_<\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2313    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2314    ))
   2315 
   2316 (defvar web-mode-engine-tag-font-lock-keywords
   2317   (list
   2318    '("</?\\([[:alpha:]]+\\(?:Template\\|[:.][[:alpha:]-]+\\)\\|TMPL_[[:alpha:]]+\\)" 1 'web-mode-block-control-face)
   2319    '("\\_<\\([[:alpha:]-]+=\\)\\(\"[^\"]*\"\\)"
   2320      (1 'web-mode-block-attr-name-face t t)
   2321      (2 'web-mode-block-attr-value-face t t))
   2322    '("\\_<\\([[:alpha:]-]+=\\)\\('[^']*\'\\)"
   2323      (1 'web-mode-block-attr-name-face t t)
   2324      (2 'web-mode-block-attr-value-face t t))
   2325    ))
   2326 
   2327 (defvar web-mode-jsp-font-lock-keywords
   2328   (list
   2329    '("\\(throws\\|new\\|extends\\)[ ]+\\([[:alnum:].]+\\)" 2 'web-mode-type-face)
   2330    (cons (concat "\\_<\\(" web-mode-jsp-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2331    '("\\(public\\|private\\)[ ]+\\([[:alpha:]]+\\)[ ]+\\([[:alnum:]._]+\\)[ ]?("
   2332      (2 'web-mode-type-face)
   2333      (3 'web-mode-function-name-face))
   2334    '("\\_<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2335    '("@\\(\\sw*\\)" 1 'web-mode-variable-name-face)
   2336    '("\\_<\\([[:alnum:].]+\\)[ ]+[{[:alpha:]]+" 1 'web-mode-type-face)
   2337    ))
   2338 
   2339 (defvar web-mode-asp-font-lock-keywords
   2340   (list
   2341    (cons (concat "\\_<\\(" web-mode-asp-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2342    (cons (concat "\\_<\\(" web-mode-asp-types "\\)\\_>") '(0 'web-mode-type-face))
   2343    (cons (concat "\\_<\\(" web-mode-asp-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2344    '("\\(Class\\|new\\) \\([[:alnum:]_]+\\)" 2 'web-mode-type-face)
   2345    '("Const \\([[:alnum:]_]+\\)" 1 'web-mode-constant-face)
   2346    '("\\_<dim\\_>"
   2347      (0 'web-mode-keyword-face)
   2348      ("[[:alnum:]_]+" nil nil (0 'web-mode-variable-name-face)))
   2349    '("\\_<\\(public\\|private\\|sub\\|function\\)\\_> \\([[:alnum:]_]+\\)[ ]*(" 2 'web-mode-function-name-face)
   2350    '("\\_<\\(public\\|private\\|dim\\)\\_> \\([[:alnum:]_]+\\)" 2 'web-mode-variable-name-face)
   2351    ))
   2352 
   2353 (defvar web-mode-aspx-font-lock-keywords
   2354   (list
   2355    (cons (concat "\\_<\\(" web-mode-aspx-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2356    '("\\_<\\([[:alnum:].]+\\)[ ]+[[:alpha:]]+" 1 'web-mode-type-face)
   2357    ))
   2358 
   2359 (defvar web-mode-uel-font-lock-keywords
   2360   (list
   2361    '("[$#{]{\\|}" 0 'web-mode-preprocessor-face)
   2362    '("\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2363    '("|[ ]*\\(trim\\|x\\|u\\)" 1 'web-mode-function-call-face)
   2364    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2365    ))
   2366 
   2367 (defvar web-mode-php-var-interpolation-font-lock-keywords
   2368   (list
   2369    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2370    '("\".+\"\\|'.*'" 0 'web-mode-string-face)
   2371    ))
   2372 
   2373 (defvar web-mode-marko-font-lock-keywords
   2374   (list
   2375    '("[[:alnum:]_]+" 0 'web-mode-variable-name-face)
   2376    ))
   2377 
   2378 (defvar web-mode-freemarker-square-font-lock-keywords
   2379   (list
   2380    '("\\[/?[#@]\\([[:alpha:]_.]*\\)" 1 'web-mode-block-control-face)
   2381    '("#\\(macro\\|function\\) \\([[:alpha:]]+\\)" 2 'web-mode-function-name-face)
   2382    (cons (concat "\\_<\\(" web-mode-freemarker-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2383    '("\\_<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2384    '("[[:alpha:]]\\([[:alnum:]_]+\\)?" 0 'web-mode-variable-name-face)
   2385    ))
   2386 
   2387 (defvar web-mode-freemarker-font-lock-keywords
   2388   (list
   2389    '("</?[#@]\\([[:alpha:]_.]*\\)" 1 'web-mode-block-control-face)
   2390    '("#\\(macro\\|function\\) \\([[:alpha:]]+\\)" 2 'web-mode-function-name-face)
   2391    (cons (concat "\\_<\\(" web-mode-freemarker-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2392    '("\\_<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2393    '("[[:alpha:]]\\([[:alnum:]_]+\\)?" 0 'web-mode-variable-name-face)
   2394    ))
   2395 
   2396 (defvar web-mode-directive-font-lock-keywords
   2397   (list
   2398    '("<%@[ ]*\\([[:alpha:]]+\\)[ ]+" 1 'web-mode-block-control-face)
   2399    '("\\_<\\([[:alpha:]]+=\\)\\(\"[^\"]*\"\\)"
   2400      (1 'web-mode-block-attr-name-face t t)
   2401      (2 'web-mode-block-attr-value-face t t))
   2402    ))
   2403 
   2404 (defvar web-mode-erb-font-lock-keywords
   2405   (list
   2406    '("[^:]\\(:[[:alnum:]_]+\\)" 1 'web-mode-symbol-face)
   2407    '("\\([[:alnum:]_]+:\\)[ ]+" 1 'web-mode-symbol-face)
   2408    (cons (concat "\\_<\\(" web-mode-erb-builtins "\\)\\_>") '(0 'web-mode-builtin-face))
   2409    (cons (concat "\\_<\\(" web-mode-erb-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2410    '("\\_<\\(self\\|true\\|false\\|nil\\)\\_>" 0 'web-mode-variable-name-face)
   2411    '("[@$]@?\\([[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2412    '("class[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-type-face)
   2413    '("def[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2414    '("\\(?:\\_<\\|::\\)\\([A-Z]+[[:alnum:]_]+\\)" 1 (unless (eq (char-after) ?\() 'web-mode-type-face))
   2415    '("/[^/]+/" 0 'web-mode-string-face)
   2416    ))
   2417 
   2418 (defvar web-mode-ejs-font-lock-keywords
   2419   web-mode-javascript-font-lock-keywords)
   2420 
   2421 (defvar web-mode-python-font-lock-keywords
   2422   (list
   2423    (cons (concat "\\_<\\(" web-mode-python-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2424    ))
   2425 
   2426 (defvar web-mode-elixir-font-lock-keywords
   2427   (list
   2428    '("@\\([[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2429    '("[ ]\\(:[[:alnum:]-_]+\\)" 1 'web-mode-symbol-face)
   2430    '("def[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2431    (cons (concat "\\_<\\(" web-mode-elixir-keywords "\\)\\_>") '(0 'web-mode-builtin-face))
   2432    (cons (concat "\\_<\\(" web-mode-elixir-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2433    ))
   2434 
   2435 (defvar web-mode-erlang-font-lock-keywords
   2436   (list
   2437    (cons (concat "\\_<\\(" web-mode-erlang-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2438    (cons (concat "\\_<\\(" web-mode-erlang-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2439    '("@\\([[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2440    '("[ ]\\(:[[:alnum:]-_]+\\)" 1 'web-mode-symbol-face)
   2441    ))
   2442 
   2443 (defvar web-mode-mason-code-font-lock-keywords
   2444   (list
   2445    (cons (concat "\\_<\\(" web-mode-mason-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2446    '("sub[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2447    '("\\_<\\([[:alnum:]_]+\\)[ ]?::" 1 'web-mode-type-face)
   2448    '("\\([@]\\)\\([[:alnum:]#_]*\\)" (1 nil) (2 'web-mode-variable-name-face))
   2449    '("\\_<\\([$%]\\)\\([[:alnum:]@#_]*\\)" (1 nil) (2 'web-mode-variable-name-face))
   2450    '("{\\([[:alnum:]_]+\\)}" 1 'web-mode-variable-name-face)
   2451    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2452    '("[[:alnum:]_][ ]?::[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2453    '("->[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2454    '("\\(?:method\\|def\\) \\([[:alnum:]._]+\\)" 1 'web-mode-function-name-face)
   2455    '("|[ ]*\\([[:alnum:],]+\\)[ ]*%>" 1 'web-mode-filter-face)
   2456    ))
   2457 
   2458 (defvar web-mode-mason-block-font-lock-keywords
   2459   (list
   2460    '("<[/]?%\\([[:alpha:]]+\\)" 1 'web-mode-block-control-face)
   2461    '("[[:alpha:]]" 0 'web-mode-block-attr-value-face)
   2462    ))
   2463 
   2464 (defvar web-mode-mojolicious-font-lock-keywords
   2465   (list
   2466    (cons (concat "\\_<\\(" web-mode-perl-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2467    '("\\_<\\(begin\\|end\\)\\_>" 1 'web-mode-constant-face)
   2468    '("\\_<\\([$]\\)\\([[:alnum:]_]*\\)" (1 nil) (2 'web-mode-variable-name-face))
   2469    ))
   2470 
   2471 (defvar web-mode-lsp-font-lock-keywords
   2472   (list
   2473    (cons (concat "\\_<\\(" web-mode-lsp-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2474    (cons (concat "\\_<\\(" web-mode-lsp-constants "\\)\\_>") '(1 'web-mode-constant-face))
   2475    '("[ ]\\(:[[:alnum:]-_]+\\)" 1 'web-mode-symbol-face)
   2476    '("(defun \\([[:alnum:]-:]+\\)" 1 'web-mode-function-name-face)
   2477    '("(defvar \\([[:alnum:]-:]+\\)" 1 'web-mode-variable-name-face)
   2478    ))
   2479 
   2480 (defvar web-mode-cl-emb-font-lock-keywords
   2481   (list
   2482    (cons (concat "\\_<\\(" web-mode-cl-emb-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2483    (cons (concat "\\_<\\(" web-mode-cl-emb-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2484    '("\\(@\\)" 1 'web-mode-function-call-face)
   2485    (list (concat "\\(@" web-mode-cl-emb-keywords "\\)[ ]+\\([[:alnum:]_]+\\)")
   2486          '(1 'web-mode-keyword-face)
   2487          '(2 'web-mode-variable-name-face))
   2488    ))
   2489 
   2490 (defvar web-mode-artanis-font-lock-keywords
   2491   (list
   2492    (cons (concat "\\_<\\(" web-mode-artanis-keywords  "\\)\\_>") '(0 'web-mode-keyword-face))
   2493    (cons (concat "\\_<\\(" web-mode-artanis-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2494    '("(define[*]? (\\([[:alnum:]-:_!#$%^&*=+/?<>.]+\\)" 1 'web-mode-function-name-face)
   2495    '("\\(#:[[:alnum:]-:_!#$%^&*=+/?<>.]+\\)"            1 'web-mode-builtin-face)
   2496    ))
   2497 
   2498 (defvar web-mode-php-font-lock-keywords
   2499   (list
   2500    (cons (concat "\\_<\\(" web-mode-php-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2501    (cons (concat "\\_<\\(" web-mode-php-types "\\)\\_>") '(1 'web-mode-type-face))
   2502    (cons (concat "\\(" web-mode-php-constants "\\)") '(0 'web-mode-constant-face))
   2503    '("function[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2504    '("\\_<\\([[:alnum:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2505    '("[[:alnum:]_][ ]?::[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-constant-face)
   2506    '("->[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2507    '("\\_<\\([[:alnum:]_]+\\)[ ]?::" 1 'web-mode-type-face)
   2508    '("\\_<\\(instanceof\\|class\\|extends\\|new\\)[ ]+\\([[:alnum:]_]+\\)" 2 'web-mode-type-face)
   2509    '("\\(\\_<\\|[+-]\\)\\([$]\\)\\([[:alnum:]_]*\\)" (2 nil) (3 'web-mode-variable-name-face))
   2510    ))
   2511 
   2512 (defvar web-mode-spip-font-lock-keywords
   2513   (list
   2514    '("<:.+:>" 0 'web-mode-block-string-face)
   2515    '("#[A-Z0-9_]+" 0 'web-mode-variable-name-face)
   2516    '("|[a-z0-9_=!?<>]+" 0 'web-mode-function-call-face)
   2517    '("(\\([[:alnum:]_ ]+\\))" 1 'web-mode-constant-face)
   2518    ))
   2519 
   2520 (defvar web-mode-latex-font-lock-keywords
   2521   (list
   2522    '("[[:alnum:]_]+" 0 'web-mode-function-name-face t t)
   2523    ))
   2524 
   2525 (defvar web-mode-blade-font-lock-keywords
   2526   (append
   2527    (list
   2528     '("@\\([[:alpha:]_]+\\)" (1 'web-mode-block-control-face)))
   2529    web-mode-php-font-lock-keywords))
   2530 
   2531 (defvar web-mode-engines-font-lock-keywords
   2532   '(("angular"          . web-mode-angular-font-lock-keywords)
   2533     ("anki"             . web-mode-anki-font-lock-keywords)
   2534     ("antlers"          . web-mode-antlers-font-lock-keywords)
   2535     ("artanis"          . web-mode-artanis-font-lock-keywords)
   2536     ("astro"            . web-mode-astro-font-lock-keywords)
   2537     ("blade"            . web-mode-blade-font-lock-keywords)
   2538     ("cl-emb"           . web-mode-cl-emb-font-lock-keywords)
   2539     ("closure"          . web-mode-closure-font-lock-keywords)
   2540     ("ctemplate"        . web-mode-ctemplate-font-lock-keywords)
   2541     ("dust"             . web-mode-dust-font-lock-keywords)
   2542     ("elixir"           . web-mode-elixir-font-lock-keywords)
   2543     ("ejs"              . web-mode-ejs-font-lock-keywords)
   2544     ("erb"              . web-mode-erb-font-lock-keywords)
   2545     ("expressionengine" . web-mode-expressionengine-font-lock-keywords)
   2546     ("go"               . web-mode-go-font-lock-keywords)
   2547     ("hero"             . web-mode-go-font-lock-keywords)
   2548     ("lsp"              . web-mode-lsp-font-lock-keywords)
   2549     ("marko"            . web-mode-marko-font-lock-keywords)
   2550     ("mojolicious"      . web-mode-mojolicious-font-lock-keywords)
   2551     ("php"              . web-mode-php-font-lock-keywords)
   2552     ("python"           . web-mode-python-font-lock-keywords)
   2553     ("razor"            . web-mode-razor-font-lock-keywords)
   2554     ("riot"             . web-mode-riot-font-lock-keywords)
   2555     ("smarty"           . web-mode-smarty-font-lock-keywords)
   2556     ("spip"             . web-mode-spip-font-lock-keywords)
   2557     ("template-toolkit" . web-mode-template-toolkit-font-lock-keywords)
   2558     ("underscore"       . web-mode-underscore-font-lock-keywords)
   2559     ("web2py"           . web-mode-web2py-font-lock-keywords)
   2560     ("velocity"         . web-mode-velocity-font-lock-keywords)
   2561     ("vue"              . web-mode-vue-font-lock-keywords)
   2562     ("xoops"            . web-mode-smarty-font-lock-keywords)
   2563     ("svelte"           . web-mode-svelte-font-lock-keywords)
   2564     )
   2565   "Engines font-lock keywords")
   2566 
   2567 (defvar web-mode-prettify-symbols-alist
   2568   '(("=>" . 8658)
   2569     (">=" . 8805)
   2570     ("<=" . 8804)))
   2571 
   2572 (defvar web-mode-before-auto-complete-hooks nil
   2573   "List of functions to run before triggering the auto-complete library.
   2574 
   2575 Auto-complete sources will sometimes need some tweaking to work
   2576 nicely with web-mode. This hook gives users the chance to adjust
   2577 the environment as needed for ac-sources, right before they're used.")
   2578 
   2579 (defvar web-mode-ignore-ac-start-advice nil
   2580   "If not nil `defadvice' for `ac-start' will be ignored.
   2581 
   2582 Can be set inside a hook in `web-mode-before-auto-complete-hooks' to
   2583 non nil to ignore the defadvice which sets ac-sources according to current
   2584 language. This is needed if the corresponding auto-completion triggers
   2585 another auto-completion with different ac-sources (e.g. ac-php)")
   2586 
   2587 (defvar web-mode-ac-sources-alist nil
   2588   "alist mapping language names to ac-sources for that language.")
   2589 
   2590 (defvar web-mode-trace nil
   2591   "Activate debug tracing.")
   2592 
   2593 (defvar web-mode-syntax-table
   2594   (let ((table (make-syntax-table)))
   2595     (modify-syntax-entry ?- "_" table)
   2596     (modify-syntax-entry ?_ "_" table) ;#563
   2597     (modify-syntax-entry ?< "." table)
   2598     (modify-syntax-entry ?> "." table)
   2599     (modify-syntax-entry ?& "." table)
   2600     (modify-syntax-entry ?/ "." table)
   2601     (modify-syntax-entry ?= "." table)
   2602     (modify-syntax-entry ?% "." table)
   2603     table)
   2604   "Syntax table used to reveal whitespaces.")
   2605 
   2606 (defvar web-mode-map
   2607   (let ((map (make-sparse-keymap)))
   2608 
   2609     (define-key map [menu-bar wm]             (cons "Web-Mode" (make-sparse-keymap)))
   2610     (define-key map [menu-bar wm dom]         (cons "Dom" (make-sparse-keymap)))
   2611     (define-key map [menu-bar wm blk]         (cons "Block" (make-sparse-keymap)))
   2612     (define-key map [menu-bar wm attr]        (cons "Html Attr" (make-sparse-keymap)))
   2613     (define-key map [menu-bar wm tag]         (cons "Html Tag" (make-sparse-keymap)))
   2614     (define-key map [menu-bar wm elt]         (cons "Html Element" (make-sparse-keymap)))
   2615 
   2616     (define-key map [menu-bar wm sep-1]       '(menu-item "--"))
   2617 
   2618     (define-key map [menu-bar wm dom dom-xpa] '(menu-item "XPath" web-mode-dom-xpath))
   2619     (define-key map [menu-bar wm dom dom-tra] '(menu-item "Traverse" web-mode-dom-traverse))
   2620     (define-key map [menu-bar wm dom dom-err] '(menu-item "Show error(s)" web-mode-dom-errors-show))
   2621     (define-key map [menu-bar wm dom dom-ent] '(menu-item "Replace html entities" web-mode-dom-entities-replace))
   2622     (define-key map [menu-bar wm dom dom-quo] '(menu-item "Replace dumb quotes" web-mode-dom-quotes-replace))
   2623     (define-key map [menu-bar wm dom dom-apo] '(menu-item "Replace apostrophes" web-mode-dom-apostrophes-replace))
   2624     (define-key map [menu-bar wm dom dom-nor] '(menu-item "Normalize" web-mode-dom-normalize))
   2625 
   2626     (define-key map [menu-bar wm blk blk-sel] '(menu-item "Select" web-mode-block-select))
   2627     (define-key map [menu-bar wm blk blk-pre] '(menu-item "Previous" web-mode-block-previous))
   2628     (define-key map [menu-bar wm blk blk-nex] '(menu-item "Next" web-mode-block-next))
   2629     (define-key map [menu-bar wm blk blk-kil] '(menu-item "Kill" web-mode-block-kill))
   2630     (define-key map [menu-bar wm blk blk-end] '(menu-item "End" web-mode-block-end))
   2631     (define-key map [menu-bar wm blk blk-clo] '(menu-item "Close" web-mode-block-close))
   2632     (define-key map [menu-bar wm blk blk-beg] '(menu-item "Beginning" web-mode-block-beginning))
   2633 
   2634     (define-key map [menu-bar wm attr attr-ins] '(menu-item "Insert" web-mode-attribute-insert))
   2635     (define-key map [menu-bar wm attr attr-end] '(menu-item "End" web-mode-attribute-end))
   2636     (define-key map [menu-bar wm attr attr-beg] '(menu-item "Beginning" web-mode-attribute-beginning))
   2637     (define-key map [menu-bar wm attr attr-sel] '(menu-item "Select" web-mode-attribute-select))
   2638     (define-key map [menu-bar wm attr attr-kil] '(menu-item "Kill" web-mode-attribute-kill))
   2639     (define-key map [menu-bar wm attr attr-nex] '(menu-item "Next" web-mode-attribute-next))
   2640     (define-key map [menu-bar wm attr attr-pre] '(menu-item "Previous" web-mode-attribute-previous))
   2641     (define-key map [menu-bar wm attr attr-tra] '(menu-item "Transpose" web-mode-attribute-transpose))
   2642 
   2643     (define-key map [menu-bar wm tag tag-beg] '(menu-item "Sort Attributes" web-mode-tag-attributes-sort))
   2644     (define-key map [menu-bar wm tag tag-sel] '(menu-item "Select" web-mode-tag-select))
   2645     (define-key map [menu-bar wm tag tag-pre] '(menu-item "Previous" web-mode-tag-previous))
   2646     (define-key map [menu-bar wm tag tag-nex] '(menu-item "Next" web-mode-tag-next))
   2647     (define-key map [menu-bar wm tag tag-end] '(menu-item "End" web-mode-tag-end))
   2648     (define-key map [menu-bar wm tag tag-beg] '(menu-item "Beginning" web-mode-tag-beginning))
   2649 
   2650     (define-key map [menu-bar wm elt elt-con] '(menu-item "Contract" web-mode-element-contract))
   2651     (define-key map [menu-bar wm elt elt-ext] '(menu-item "Extract" web-mode-element-extract))
   2652     (define-key map [menu-bar wm elt elt-van] '(menu-item "Vanish" web-mode-element-vanish))
   2653     (define-key map [menu-bar wm elt elt-exc] '(menu-item "Transpose" web-mode-element-transpose))
   2654     (define-key map [menu-bar wm elt elt-sel] '(menu-item "Select" web-mode-element-select))
   2655     (define-key map [menu-bar wm elt elt-ren] '(menu-item "Rename" web-mode-element-rename))
   2656     (define-key map [menu-bar wm elt elt-pre] '(menu-item "Previous" web-mode-element-previous))
   2657     (define-key map [menu-bar wm elt elt-par] '(menu-item "Parent" web-mode-element-parent))
   2658     (define-key map [menu-bar wm elt elt-nex] '(menu-item "Next" web-mode-element-next))
   2659     (define-key map [menu-bar wm elt elt-mut] '(menu-item "Mute blanks" web-mode-element-mute-blanks))
   2660     (define-key map [menu-bar wm elt elt-del] '(menu-item "Kill" web-mode-element-kill))
   2661     (define-key map [menu-bar wm elt elt-end] '(menu-item "End" web-mode-element-end))
   2662     (define-key map [menu-bar wm elt elt-inn] '(menu-item "Content (select)" web-mode-element-content-select))
   2663     (define-key map [menu-bar wm elt elt-clo] '(menu-item "Close" web-mode-element-close))
   2664     (define-key map [menu-bar wm elt elt-ins] '(menu-item "Insert" web-mode-element-insert))
   2665     (define-key map [menu-bar wm elt elt-ins] '(menu-item "Word to tag" web-mode-element-insert-at-point))
   2666     (define-key map [menu-bar wm elt elt-dup] '(menu-item "Clone" web-mode-element-clone))
   2667     (define-key map [menu-bar wm elt elt-cfo] '(menu-item "Children fold" web-mode-element-children-fold-or-unfold))
   2668     (define-key map [menu-bar wm elt elt-chi] '(menu-item "Child" web-mode-element-child))
   2669     (define-key map [menu-bar wm elt elt-beg] '(menu-item "Beginning" web-mode-element-beginning))
   2670 
   2671     (define-key map [menu-bar wm fol]         '(menu-item "Fold/Unfold" web-mode-fold-or-unfold))
   2672     (define-key map [menu-bar wm hig]         '(menu-item "Fontify buffer" web-mode-buffer-fontify))
   2673     (define-key map [menu-bar wm ind]         '(menu-item "Indent buffer" web-mode-buffer-indent))
   2674     (define-key map [menu-bar wm nav]         '(menu-item "Tag/Block navigation" web-mode-navigate))
   2675     (define-key map [menu-bar wm exp]         '(menu-item "Mark and Expand" web-mode-mark-and-expand))
   2676     (define-key map [menu-bar wm spa]         '(menu-item "Toggle whitespaces" web-mode-whitespaces-show))
   2677     (define-key map [menu-bar wm sni]         '(menu-item "Insert snippet" web-mode-snippet-insert))
   2678 
   2679     ;;--------------------------------------------------------------------------
   2680     ;; "C-c <LETTER>" are reserved for users
   2681 
   2682     (define-key map (kbd "C-c C-a b") 'web-mode-attribute-beginning)
   2683     (define-key map (kbd "C-c C-a e") 'web-mode-attribute-end)
   2684     (define-key map (kbd "C-c C-a i") 'web-mode-attribute-insert)
   2685     (define-key map (kbd "C-c C-a n") 'web-mode-attribute-next)
   2686     (define-key map (kbd "C-c C-a s") 'web-mode-attribute-select)
   2687     (define-key map (kbd "C-c C-a k") 'web-mode-attribute-kill)
   2688     (define-key map (kbd "C-c C-a p") 'web-mode-attribute-previous)
   2689     (define-key map (kbd "C-c C-a t") 'web-mode-attribute-transpose)
   2690 
   2691     (define-key map (kbd "C-c C-b b") 'web-mode-block-beginning)
   2692     (define-key map (kbd "C-c C-b c") 'web-mode-block-close)
   2693     (define-key map (kbd "C-c C-b e") 'web-mode-block-end)
   2694     (define-key map (kbd "C-c C-b k") 'web-mode-block-kill)
   2695     (define-key map (kbd "C-c C-b n") 'web-mode-block-next)
   2696     (define-key map (kbd "C-c C-b p") 'web-mode-block-previous)
   2697     (define-key map (kbd "C-c C-b s") 'web-mode-block-select)
   2698 
   2699     (define-key map (kbd "C-c C-d a") 'web-mode-dom-apostrophes-replace)
   2700     (define-key map (kbd "C-c C-d d") 'web-mode-dom-errors-show)
   2701     (define-key map (kbd "C-c C-d e") 'web-mode-dom-entities-replace)
   2702     (define-key map (kbd "C-c C-d n") 'web-mode-dom-normalize)
   2703     (define-key map (kbd "C-c C-d q") 'web-mode-dom-quotes-replace)
   2704     (define-key map (kbd "C-c C-d t") 'web-mode-dom-traverse)
   2705     (define-key map (kbd "C-c C-d x") 'web-mode-dom-xpath)
   2706 
   2707     (define-key map (kbd "C-c C-e /") 'web-mode-element-close)
   2708     (define-key map (kbd "C-c C-e a") 'web-mode-element-content-select)
   2709     (define-key map (kbd "C-c C-e b") 'web-mode-element-beginning)
   2710     (define-key map (kbd "C-c C-e c") 'web-mode-element-clone)
   2711     (define-key map (kbd "C-c C-e d") 'web-mode-element-child)
   2712     (define-key map (kbd "C-c C-e e") 'web-mode-element-end)
   2713     (define-key map (kbd "C-c C-e f") 'web-mode-element-children-fold-or-unfold)
   2714     (define-key map (kbd "C-c C-e i") 'web-mode-element-insert)
   2715     (define-key map (kbd "C-c C-e I") 'web-mode-element-insert-at-point)
   2716     (define-key map (kbd "C-c C-e k") 'web-mode-element-kill)
   2717     (define-key map (kbd "C-c C-e m") 'web-mode-element-mute-blanks)
   2718     (define-key map (kbd "C-c C-e n") 'web-mode-element-next)
   2719     (define-key map (kbd "C-c C-e p") 'web-mode-element-previous)
   2720     (define-key map (kbd "C-c C-e r") 'web-mode-element-rename)
   2721     (define-key map (kbd "C-c C-e s") 'web-mode-element-select)
   2722     (define-key map (kbd "C-c C-e t") 'web-mode-element-transpose)
   2723     (define-key map (kbd "C-c C-e u") 'web-mode-element-parent)
   2724     (define-key map (kbd "C-c C-e v") 'web-mode-element-vanish)
   2725     (define-key map (kbd "C-c C-e w") 'web-mode-element-wrap)
   2726     (define-key map (kbd "C-c C-e +") 'web-mode-element-extract)
   2727     (define-key map (kbd "C-c C-e -") 'web-mode-element-contract)
   2728 
   2729     (define-key map (kbd "C-c C-t a") 'web-mode-tag-attributes-sort)
   2730     (define-key map (kbd "C-c C-t b") 'web-mode-tag-beginning)
   2731     (define-key map (kbd "C-c C-t e") 'web-mode-tag-end)
   2732     (define-key map (kbd "C-c C-t m") 'web-mode-tag-match)
   2733     (define-key map (kbd "C-c C-t n") 'web-mode-tag-next)
   2734     (define-key map (kbd "C-c C-t p") 'web-mode-tag-previous)
   2735     (define-key map (kbd "C-c C-t s") 'web-mode-tag-select)
   2736 
   2737     ;;--------------------------------------------------------------------------
   2738 
   2739     ;;(define-key map (kbd "M-q")       'fill-paragraph)
   2740     (define-key map (kbd "M-;")       'web-mode-comment-or-uncomment)
   2741 
   2742     ;;C-c C-a : attribute
   2743     ;;C-c C-b : block
   2744     ;;C-c C-d : dom
   2745     ;;C-c C-e : element
   2746     (define-key map (kbd "C-c C-f")   'web-mode-fold-or-unfold)
   2747     (define-key map (kbd "C-c C-h")   'web-mode-buffer-fontify)
   2748     (define-key map (kbd "C-c C-i")   'web-mode-buffer-indent)
   2749     (define-key map (kbd "C-c C-j")   'web-mode-jshint)
   2750     (define-key map (kbd "C-c C-l")   'web-mode-file-link)
   2751     (define-key map (kbd "C-c C-m")   'web-mode-mark-and-expand)
   2752     (define-key map (kbd "C-c C-n")   'web-mode-navigate)
   2753     (define-key map (kbd "C-c C-r")   'web-mode-reload)
   2754     (define-key map (kbd "C-c C-s")   'web-mode-snippet-insert)
   2755     ;;C-c C-t : tag
   2756     (define-key map (kbd "C-c C-w")   'web-mode-whitespaces-show)
   2757 
   2758     map)
   2759   "Keymap for `web-mode'.")
   2760 
   2761 ;;---- COMPATIBILITY -----------------------------------------------------------
   2762 
   2763 (eval-and-compile
   2764 
   2765   ;; compatibility with emacs < 23
   2766   (defun web-mode-string-match-p (regexp string &optional start)
   2767     "Same as `string-match' except it does not change the match data."
   2768     (save-match-data
   2769       (string-match regexp string start)))
   2770 
   2771   (unless (fboundp 'string-match-p)
   2772     (fset 'string-match-p (symbol-function 'web-mode-string-match-p)))
   2773 
   2774   ;; compatibility with emacs < 23.3
   2775   (if (fboundp 'with-silent-modifications)
   2776       (defalias 'web-mode-with-silent-modifications 'with-silent-modifications)
   2777       (defmacro web-mode-with-silent-modifications (&rest body)
   2778         `(let ((old-modified-p (buffer-modified-p))
   2779                (inhibit-modification-hooks t)
   2780                (buffer-undo-list t))
   2781            (unwind-protect
   2782                 ,@body
   2783              (restore-buffer-modified-p old-modified-p)))))
   2784 
   2785   ;; compatibility with emacs < 24.3
   2786   (defun web-mode-buffer-narrowed-p ()
   2787     (if (fboundp 'buffer-narrowed-p)
   2788         (buffer-narrowed-p)
   2789         (/= (- (point-max) (point-min)) (buffer-size))))
   2790 
   2791   ;; compatibility with emacs < 24
   2792   (defalias 'web-mode-prog-mode
   2793       (if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode))
   2794 
   2795   ;; compatibility with emacs < 24.3
   2796   (unless (fboundp 'setq-local)
   2797     (defmacro setq-local (var val)
   2798       `(set (make-local-variable ',var) ,val)))
   2799 
   2800   ;; compatability with emacs < 24.4
   2801   (defun web-mode-string-suffix-p (suffix string)
   2802     "Return t if STRING ends with SUFFIX."
   2803     (and (string-match (rx-to-string `(: ,suffix eos) t)
   2804                        string)
   2805          t))
   2806 
   2807   (unless (fboundp 'string-suffix-p)
   2808     (fset 'string-suffix-p (symbol-function 'web-mode-string-suffix-p)))
   2809 
   2810   (unless (fboundp 'seq-some)
   2811     (defun seq-some (pred seq)
   2812       (unless (null seq)
   2813         (or (funcall pred (car seq))
   2814             (seq-some pred (cdr seq))))))
   2815   ) ;eval-and-compile
   2816 
   2817 ;;---- MAJOR MODE --------------------------------------------------------------
   2818 
   2819 ;;;###autoload
   2820 (define-derived-mode
   2821     web-mode web-mode-prog-mode "Web"
   2822     "Major mode for editing web templates."
   2823 
   2824     (make-local-variable 'web-mode-attr-indent-offset)
   2825     (make-local-variable 'web-mode-attr-value-indent-offset)
   2826     (make-local-variable 'web-mode-auto-pairs)
   2827     (make-local-variable 'web-mode-block-regexp)
   2828     (make-local-variable 'web-mode-change-beg)
   2829     (make-local-variable 'web-mode-change-end)
   2830     (make-local-variable 'web-mode-code-indent-offset)
   2831     (make-local-variable 'web-mode-column-overlays)
   2832     (make-local-variable 'web-mode-comment-formats)
   2833     (make-local-variable 'web-mode-comment-style)
   2834     (make-local-variable 'web-mode-content-type)
   2835     (make-local-variable 'web-mode-css-indent-offset)
   2836     (make-local-variable 'web-mode-display-table)
   2837     (make-local-variable 'web-mode-django-control-blocks)
   2838     (make-local-variable 'web-mode-django-control-blocks-regexp)
   2839     (make-local-variable 'web-mode-enable-block-face)
   2840     (make-local-variable 'web-mode-enable-inlays)
   2841     (make-local-variable 'web-mode-enable-part-face)
   2842     (make-local-variable 'web-mode-enable-sexp-functions)
   2843     (make-local-variable 'web-mode-engine)
   2844     (make-local-variable 'web-mode-engine-attr-regexp)
   2845     (make-local-variable 'web-mode-engine-file-regexps)
   2846     (make-local-variable 'web-mode-engine-open-delimiter-regexps)
   2847     (make-local-variable 'web-mode-engine-token-regexp)
   2848     (make-local-variable 'web-mode-expand-initial-pos)
   2849     (make-local-variable 'web-mode-expand-initial-scroll)
   2850     (make-local-variable 'web-mode-expand-previous-state)
   2851     (make-local-variable 'web-mode-indent-style)
   2852     (make-local-variable 'web-mode-indentless-attributes)
   2853     (make-local-variable 'web-mode-indentless-elements)
   2854     (make-local-variable 'web-mode-is-scratch)
   2855     (make-local-variable 'web-mode-skip-fontification)
   2856     (make-local-variable 'web-mode-jshint-errors)
   2857     (make-local-variable 'web-mode-last-enabled-feature)
   2858     (make-local-variable 'web-mode-markup-indent-offset)
   2859     (make-local-variable 'web-mode-minor-engine)
   2860     (make-local-variable 'web-mode-overlay-tag-end)
   2861     (make-local-variable 'web-mode-overlay-tag-start)
   2862     (make-local-variable 'web-mode-part-beg)
   2863     (make-local-variable 'web-mode-scan-beg)
   2864     (make-local-variable 'web-mode-scan-end)
   2865     (make-local-variable 'web-mode-sql-indent-offset)
   2866     (make-local-variable 'web-mode-time)
   2867     (make-local-variable 'web-mode-trace)
   2868 
   2869     (make-local-variable 'font-lock-beg)
   2870     (make-local-variable 'font-lock-end)
   2871 
   2872     (make-local-variable 'comment-end)
   2873     (make-local-variable 'comment-region-function)
   2874     (make-local-variable 'comment-start)
   2875     (make-local-variable 'fill-paragraph-function)
   2876     (make-local-variable 'font-lock-defaults)
   2877     (make-local-variable 'font-lock-extend-region-functions)
   2878     (make-local-variable 'font-lock-support-mode)
   2879     (make-local-variable 'font-lock-unfontify-region-function)
   2880     (make-local-variable 'imenu-case-fold-search)
   2881     (make-local-variable 'imenu-create-index-function)
   2882     (make-local-variable 'imenu-generic-expression)
   2883     (make-local-variable 'indent-line-function)
   2884     (make-local-variable 'parse-sexp-lookup-properties)
   2885     (make-local-variable 'uncomment-region-function)
   2886     (make-local-variable 'yank-excluded-properties)
   2887 
   2888     (setq web-mode-time (current-time))
   2889 
   2890     (setq comment-end "-->"
   2891           comment-region-function 'web-mode-comment-or-uncomment-region
   2892           comment-start "<!--"
   2893           fill-paragraph-function 'web-mode-fill-paragraph
   2894           ;;font-lock-defaults '(web-mode-font-lock-keywords t)
   2895           font-lock-defaults '('(web-mode-fontify) t)
   2896           font-lock-extend-region-functions '(web-mode-extend-region)
   2897           font-lock-support-mode nil
   2898           font-lock-unfontify-region-function 'web-mode-unfontify-region
   2899           imenu-case-fold-search t
   2900           imenu-create-index-function 'web-mode-imenu-index
   2901           indent-line-function 'web-mode-indent-line
   2902           parse-sexp-lookup-properties t
   2903           yank-excluded-properties t
   2904           uncomment-region-function 'web-mode-comment-or-uncomment-region
   2905           prettify-symbols-alist web-mode-prettify-symbols-alist)
   2906 
   2907     (substitute-key-definition #'indent-new-comment-line
   2908                                #'web-mode-comment-indent-new-line
   2909                                web-mode-map global-map)
   2910 
   2911     (add-hook 'after-change-functions #'web-mode-on-after-change nil t)
   2912     (add-hook 'after-save-hook        #'web-mode-on-after-save t t)
   2913     (add-hook 'change-major-mode-hook #'web-mode-on-exit nil t)
   2914     (add-hook 'post-command-hook      #'web-mode-on-post-command nil t)
   2915     (add-hook 'hack-local-variables-hook #'web-mode-guess-engine-and-content-type t t)
   2916 
   2917     (cond
   2918       ((boundp 'yas-after-exit-snippet-hook)
   2919        (add-hook 'yas-after-exit-snippet-hook
   2920                  'web-mode-yasnippet-exit-hook
   2921                  t t))
   2922       ((boundp 'yas/after-exit-snippet-hook)
   2923        (add-hook 'yas/after-exit-snippet-hook
   2924                  'web-mode-yasnippet-exit-hook
   2925                  t t))
   2926       )
   2927 
   2928     (when web-mode-enable-whitespace-fontification
   2929       (web-mode-whitespaces-on))
   2930 
   2931     (when web-mode-enable-sexp-functions
   2932       (setq-local forward-sexp-function #'web-mode-forward-sexp))
   2933 
   2934     (setq web-mode-change-beg (point-min)
   2935           web-mode-change-end (point-max))
   2936     (when (> (point-max) 256000)
   2937       (web-mode-buffer-fontify))
   2938 
   2939     (when (and (boundp 'hs-special-modes-alist)
   2940                (not (assoc major-mode hs-special-modes-alist)))
   2941       (add-to-list 'hs-special-modes-alist '(web-mode "{" "}" "/[*/]" web-mode-forward-sexp nil))
   2942       ) ;when
   2943 
   2944     ;; compatibility with emacs < 24
   2945     (if (fboundp 'prog-mode)
   2946         (put 'web-mode 'derived-mode-parent 'prog-mode))
   2947 
   2948     (cond
   2949       ((not (buffer-file-name))
   2950        )
   2951       ((string-match-p "web-mode-benchmark.html" (buffer-file-name))
   2952        (web-mode-measure "end"))
   2953       ) ;cond
   2954 
   2955     )
   2956 
   2957 ;;---- INVALIDATION ------------------------------------------------------------
   2958 
   2959 ;; 1/ after-change
   2960 ;; 2/ extend-region
   2961 ;; 3/ scan
   2962 ;; 4/ fontify
   2963 ;; 5/ post-command
   2964 
   2965 (defun web-mode-on-after-change (beg end len)
   2966   (when web-mode-trace
   2967     (message "after-change: pos(%d) beg(%d) end(%d) len(%d) this-command(%S)"
   2968              (point) beg end len this-command))
   2969   (when (or (null web-mode-change-beg) (< beg web-mode-change-beg))
   2970     (setq web-mode-change-beg beg))
   2971   (when (or (null web-mode-change-end) (> end web-mode-change-end))
   2972     (setq web-mode-change-end end)))
   2973 
   2974 (defun web-mode-extend-region ()
   2975   (when web-mode-trace
   2976     (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)"
   2977              font-lock-beg font-lock-end web-mode-change-beg web-mode-change-end web-mode-skip-fontification))
   2978   (when (and (string= web-mode-engine "php")
   2979              (and (>= font-lock-beg 6) (<= font-lock-beg 9))
   2980              (or (message (buffer-substring-no-properties 1 6)) t)
   2981              (string= (buffer-substring-no-properties 1 6) "<?php"))
   2982     (setq font-lock-beg (point-min)
   2983           font-lock-end (point-max))
   2984     )
   2985   (when (or (null web-mode-change-beg) (< font-lock-beg web-mode-change-beg))
   2986     (when web-mode-trace (message "extend-region: font-lock-beg(%S) < web-mode-change-beg(%S)" font-lock-beg web-mode-change-beg))
   2987     (setq web-mode-change-beg font-lock-beg))
   2988   (when (or (null web-mode-change-end) (> font-lock-end web-mode-change-end))
   2989     (when web-mode-trace (message "extend-region: font-lock-end(%S) > web-mode-change-end(%S)" font-lock-end web-mode-change-end))
   2990     (setq web-mode-change-end font-lock-end))
   2991   (when font-lock-dont-widen
   2992     (setq web-mode-change-beg (max web-mode-change-beg (point-min))
   2993           web-mode-change-end (min web-mode-change-end (point-max))))
   2994   (let ((region (web-mode-scan web-mode-change-beg web-mode-change-end)))
   2995     (when region
   2996       ;;(message "region: %S" region)
   2997       (setq font-lock-beg (car region)
   2998             font-lock-end (cdr region))
   2999       ) ;when
   3000     ) ;let
   3001   nil)
   3002 
   3003 (defun web-mode-scan (&optional beg end)
   3004   (when web-mode-trace
   3005     (message "scan: beg(%S) end(%S) web-mode-change-beg(%S) web-mode-change-end(%S)"
   3006              beg end web-mode-change-beg web-mode-change-end))
   3007   (unless beg (setq beg web-mode-change-beg))
   3008   (unless end (setq end web-mode-change-end))
   3009   ;;(message "%S %S %S" web-mode-content-type (get-text-property beg 'part-side) (get-text-property end 'part-side))
   3010   (when (and end (> end (point-max)))
   3011     (setq end (point-max)))
   3012   (setq web-mode-change-beg nil
   3013         web-mode-change-end nil)
   3014   (cond
   3015     ((or (null beg) (null end))
   3016      nil)
   3017     ((and (member web-mode-engine '("php" "asp"))
   3018           (get-text-property beg 'block-side)
   3019           (get-text-property end 'block-side)
   3020           (> beg (point-min))
   3021           (not (eq (get-text-property (1- beg) 'block-token) 'delimiter-beg))
   3022           (not (eq (get-text-property end 'block-token) 'delimiter-end)))
   3023      ;;(message "invalidate block (%S > %S)" beg end)
   3024      (web-mode-invalidate-block-region beg end))
   3025     ((and (or (member web-mode-content-type
   3026                       '("css" "javascript" "json" "jsx" "sass" "stylus" "typescript"))
   3027               (and (get-text-property beg 'part-side)
   3028                    (get-text-property end 'part-side)
   3029                    (> beg (point-min))
   3030                    (get-text-property (1- beg) 'part-side))
   3031               ))
   3032      ;;(message "invalidate part (%S > %S)" beg end)
   3033      (web-mode-invalidate-part-region beg end))
   3034     (t
   3035      ;;(message "invalidate default (%S > %S)" beg end)
   3036      (web-mode-invalidate-region beg end))
   3037     ) ;cond
   3038   )
   3039 
   3040 (defun web-mode-invalidate-region (reg-beg reg-end)
   3041   (when web-mode-trace
   3042     (message "invalidate-region: point(%S) reg-beg(%S) reg-end(%S)" (point) reg-beg reg-end))
   3043   (setq reg-beg (web-mode-invalidate-region-beginning-position reg-beg)
   3044         reg-end (web-mode-invalidate-region-end-position reg-end))
   3045   ;;(message "invalidate-region: reg-beg(%S) reg-end(%S)" reg-beg reg-end)
   3046   (web-mode-scan-region reg-beg reg-end))
   3047 
   3048 (defun web-mode--command-is-self-insert-p ()
   3049   "Return non-nil if `this-command' is `self-insert-command'.
   3050 Also return non-nil if it is the command `self-insert-command' is remapped to."
   3051   (memq this-command (list 'self-insert-command
   3052                            (key-binding [remap self-insert-command]))))
   3053 
   3054 (defun web-mode-on-post-command ()
   3055   (when (and web-mode-trace
   3056              (not (member this-command
   3057                           '(left-char right-char previous-line next-line save-buffer mwheel-scroll end-of-line beginning-of-line))))
   3058     (message "post-command: this-command(%S) web-mode-change-beg(%S) web-mode-change-end(%S) previous-state(%S)"
   3059              this-command web-mode-change-beg web-mode-change-end web-mode-expand-previous-state))
   3060   (let (ctx n char)
   3061     (when (and web-mode-expand-previous-state
   3062                (not (member this-command web-mode-commands-like-expand-region)))
   3063       (when (eq this-command 'keyboard-quit)
   3064         (goto-char web-mode-expand-initial-pos))
   3065       (deactivate-mark)
   3066       (when web-mode-expand-initial-scroll
   3067         (set-window-start (selected-window) web-mode-expand-initial-scroll)
   3068         )
   3069       (setq web-mode-expand-previous-state nil
   3070             web-mode-expand-initial-pos nil
   3071             web-mode-expand-initial-scroll nil))
   3072 
   3073     (when (member this-command '(yank))
   3074       ;;(setq web-mode-skip-fontification nil)
   3075       (when (and web-mode-scan-beg web-mode-scan-end global-font-lock-mode)
   3076         (save-excursion
   3077           (font-lock-fontify-region web-mode-scan-beg web-mode-scan-end))
   3078         (when web-mode-enable-auto-indentation
   3079           (indent-region web-mode-scan-beg web-mode-scan-end))
   3080         ) ;and
   3081       )
   3082 
   3083     (when (and (< (point) 16) web-mode-change-beg web-mode-change-end)
   3084       (web-mode-detect-content-type))
   3085 
   3086     (when (and web-mode-change-beg web-mode-change-end
   3087                web-mode-enable-engine-detection
   3088                (or (null web-mode-engine) (string= web-mode-engine "none"))
   3089                (< (point) web-mode-chunk-length)
   3090                (web-mode-detect-engine))
   3091       (web-mode-on-engine-setted)
   3092       (web-mode-buffer-fontify))
   3093 
   3094     (when (> (point) 1)
   3095       (setq char (char-before)))
   3096 
   3097     (cond
   3098       ((null char)
   3099        )
   3100       ((and (>= (point) 3)
   3101             (web-mode--command-is-self-insert-p)
   3102             (not (member (get-text-property (point) 'part-token) '(comment string)))
   3103             (not (eq (get-text-property (point) 'tag-type) 'comment))
   3104             )
   3105        (setq ctx (web-mode-auto-complete)))
   3106       ((and web-mode-enable-auto-opening
   3107             (member this-command '(newline electric-newline-and-maybe-indent newline-and-indent))
   3108             (or (and (not (eobp))
   3109                      (eq (char-after) ?\<)
   3110                      (eq (get-text-property (point) 'tag-type) 'end)
   3111                      (looking-back ">\n[ \t]*" (point-min))
   3112                      (setq n (length (match-string-no-properties 0)))
   3113                      (eq (get-text-property (- (point) n) 'tag-type) 'start)
   3114                      (string= (get-text-property (- (point) n) 'tag-name)
   3115                               (get-text-property (point) 'tag-name))
   3116                      )
   3117                 (and (get-text-property (1- (point)) 'block-side)
   3118                      (string= web-mode-engine "php")
   3119                      (looking-back "<\\?php[ ]*\n" (point-min))
   3120                      (looking-at-p "[ ]*\\?>"))))
   3121        (newline-and-indent)
   3122        (forward-line -1)
   3123        (indent-according-to-mode)
   3124        )
   3125       ) ;cond
   3126 
   3127     (cond
   3128 
   3129       ((not web-mode-enable-auto-opening)
   3130        )
   3131       ((and (member this-command '(newline electric-newline-and-maybe-indent newline-and-indent))
   3132             (get-text-property (point) 'part-side)
   3133             (eq (get-text-property (point) 'part-token) 'string))
   3134        (indent-according-to-mode)
   3135        (when (and web-mode-change-end (> web-mode-change-end (point-max)))
   3136          (message "post-command: enlarge web-mode-change-end")
   3137          (setq web-mode-change-end (point-max))
   3138          )
   3139        )
   3140       ((and (web-mode--command-is-self-insert-p)
   3141             (or (and ctx
   3142                      (or (plist-get ctx :auto-closed)
   3143                          (plist-get ctx :auto-expanded)))
   3144                 (and (> (point) (point-min))
   3145                      (get-text-property (1- (point)) 'tag-end)
   3146                      (get-text-property (line-beginning-position) 'tag-beg))))
   3147        (indent-according-to-mode)
   3148        (when (and web-mode-change-end (> web-mode-change-end (point-max)))
   3149          (message "post-command: enlarge web-mode-change-end")
   3150          (setq web-mode-change-end (point-max))
   3151          )
   3152        )
   3153       ((and (web-mode--command-is-self-insert-p)
   3154             (member (get-text-property (point) 'part-side) '(javascript jsx css))
   3155             (looking-back "^[ \t]+[]})]" (point-min)))
   3156        (indent-according-to-mode)
   3157        (when (and web-mode-change-end (> web-mode-change-end (point-max)))
   3158          (message "post-command: enlarge web-mode-change-end")
   3159          (setq web-mode-change-end (point-max))
   3160          )
   3161        )
   3162       ) ; cond web-mode-enable-auto-opening
   3163 
   3164     (when web-mode-enable-current-element-highlight
   3165       (web-mode-highlight-current-element))
   3166 
   3167     (when (and web-mode-enable-current-column-highlight
   3168                (not (web-mode-buffer-narrowed-p)))
   3169       (web-mode-column-show))
   3170 
   3171     (when (and web-mode-trace (not (member this-command
   3172                                            '(left-char right-char previous-line next-line save-buffer mwheel-scroll end-of-line beginning-of-line))))
   3173       (when (or web-mode-change-beg web-mode-change-end)
   3174         (message "post-command: web-mode-change-beg(%S) web-mode-change-end(%S)"
   3175                  web-mode-change-end web-mode-change-end))
   3176       (message "-------------------------------------------------------------------")
   3177       )
   3178 
   3179     ))
   3180 
   3181 ;; NOTE: il est important d'identifier des caractères en fin de ligne
   3182 ;; web-mode-block-tokenize travaille en effet sur les fins de lignes pour
   3183 ;; les commentaires de type //
   3184 (defun web-mode-invalidate-block-region (pos-beg pos-end)
   3185   ;;  (message "pos-beg(%S) pos-end(%S)" pos-beg pos-end)
   3186   (save-excursion
   3187     (let (beg end code-beg code-end)
   3188       ;;(message "invalidate-block-region: pos-beg(%S)=%S" pos-beg (get-text-property pos 'block-side))
   3189       ;;(message "code-beg(%S) code-end(%S) pos-beg(%S) pos-end(%S)" code-beg code-end pos-beg pos-end)
   3190       (cond
   3191         ((not (and (setq code-beg (web-mode-block-code-beginning-position pos-beg))
   3192                    (setq code-end (web-mode-block-code-end-position pos-beg))
   3193                    (>= pos-beg code-beg)
   3194                    (<= pos-end code-end)
   3195                    (> code-end code-beg)))
   3196          (web-mode-invalidate-region pos-beg pos-end))
   3197         ((member web-mode-engine '("asp"))
   3198          (goto-char pos-beg)
   3199          (forward-line -1)
   3200          (setq beg (line-beginning-position))
   3201          (when (> code-beg beg)
   3202            (setq beg code-beg))
   3203          (goto-char pos-beg)
   3204          (forward-line)
   3205          (setq end (line-end-position))
   3206          (when (< code-end end)
   3207            (setq end code-end))
   3208          ;; ?? pas de (web-mode-block-tokenize beg end) ?
   3209          (web-mode-block-tokenize beg end)
   3210          (cons beg end)
   3211          ) ;asp
   3212         (t
   3213          (goto-char pos-beg)
   3214          ;;(message "pos-beg=%S" pos-beg)
   3215          (when (string= web-mode-engine "php")
   3216            (cond
   3217              ((and (looking-back "\*" (point-min))
   3218                    (looking-at-p "/"))
   3219               (search-backward "/*" code-beg))
   3220              ) ;cond
   3221            ) ;when
   3222          (if (web-mode-block-rsb "[;{}(][ ]*\n" code-beg)
   3223              (setq beg (match-end 0))
   3224              (setq beg code-beg))
   3225          (goto-char pos-end)
   3226          (if (web-mode-block-rsf "[;{})][ ]*\n" code-end)
   3227              (setq end (1- (match-end 0)))
   3228              (setq end code-end))
   3229          (web-mode-block-tokenize beg end)
   3230          ;;(message "beg(%S) end(%S)" beg end)
   3231          (cons beg end)
   3232          )
   3233         ) ;cond
   3234       )))
   3235 
   3236 (defun web-mode-invalidate-part-region (pos-beg pos-end)
   3237   (save-excursion
   3238     (let (beg end part-beg part-end language)
   3239       (if (member web-mode-content-type web-mode-part-content-types)
   3240           (setq language web-mode-content-type)
   3241           (setq language (symbol-name (get-text-property pos-beg 'part-side))))
   3242       (setq part-beg (web-mode-part-beginning-position pos-beg)
   3243             part-end (web-mode-part-end-position pos-beg))
   3244       ;;(message "language(%S) pos-beg(%S) pos-end(%S) part-beg(%S) part-end(%S)"
   3245       ;;         language pos-beg pos-end part-beg part-end)
   3246       (goto-char pos-beg)
   3247       (cond
   3248         ((not (and part-beg part-end
   3249                    (>= pos-beg part-beg)
   3250                    (<= pos-end part-end)
   3251                    (> part-end part-beg)))
   3252          (web-mode-invalidate-region pos-beg pos-end))
   3253         ((member language '("javascript" "json" "jsx" "typescript"))
   3254          (if (web-mode-javascript-rsb "[;{}(][ ]*\n" part-beg)
   3255              (setq beg (match-end 0))
   3256              (setq beg part-beg))
   3257          (goto-char pos-end)
   3258          (if (web-mode-javascript-rsf "[;{})][ ]*\n" part-end)
   3259              (setq end (match-end 0))
   3260              (setq end part-end))
   3261          (web-mode-scan-region beg end language))
   3262         ((member language '("css" "sass"))
   3263          (let (rule1 rule2)
   3264            (setq rule1 (web-mode-css-rule-current pos-beg))
   3265            (setq rule2 rule1)
   3266            (when (> pos-end (cdr rule1))
   3267              (setq rule2 (web-mode-css-rule-current pos-end)))
   3268            (setq beg (car rule1)
   3269                  end (cdr rule2))
   3270            )
   3271          (web-mode-scan-region beg end language))
   3272         (t
   3273          (setq beg part-beg
   3274                end part-end)
   3275          (web-mode-scan-region beg end language))
   3276         ) ;cond
   3277       )))
   3278 
   3279 (defun web-mode-invalidate-region-beginning-position (pos)
   3280   (save-excursion
   3281     (goto-char pos)
   3282 
   3283     (cond
   3284       ((and (looking-at-p ">") ;#1151
   3285             (looking-back "--" (point-min)))
   3286        (search-backward "<!--" nil t))
   3287       ((and (bolp) (not (bobp)))
   3288        (backward-char))
   3289       )
   3290 
   3291     (beginning-of-line)
   3292     ;;(message "pos=%S point=%S %S" pos (point) (text-properties-at (point)))
   3293     (setq pos (point-min))
   3294     (let ((continue (not (bobp))))
   3295       (while continue
   3296         (cond
   3297           ((bobp)
   3298            (setq continue nil))
   3299           ;; NOTE: Going back to the previous start tag is necessary
   3300           ;; when inserting a part endtag (e.g. </script>).
   3301           ;; Indeed, parts must be identified asap.
   3302           ((and (progn (back-to-indentation) t)
   3303                 (get-text-property (point) 'tag-beg)
   3304                 (eq (get-text-property (point) 'tag-type) 'start))
   3305            (setq pos (point)
   3306                  continue nil))
   3307           (t
   3308            (forward-line -1))
   3309           ) ;cond
   3310         ) ;while
   3311       ;;(message "pos=%S" pos)
   3312       pos)))
   3313 
   3314 (defun web-mode-invalidate-region-end-position (pos)
   3315   (save-excursion
   3316     (goto-char pos)
   3317     ;;(message "pos=%S %S" pos (get-text-property pos 'block-token))
   3318     (when (string= web-mode-engine "jsp")
   3319       (cond
   3320         ((and (looking-back "<%" (point-min))
   3321               (looking-at-p "--"))
   3322          (search-forward "--%>"))
   3323         ((and (looking-back "-- %" (point-min))
   3324               (looking-at-p ">"))
   3325          (search-forward "--%>"))
   3326         ) ;cond
   3327       ) ;when
   3328     (setq pos (point-max))
   3329     (let ((continue (not (eobp))))
   3330       (while continue
   3331         (end-of-line)
   3332         ;;(message "%S %S" (point) (get-text-property (point) 'block-token))
   3333         (cond
   3334           ((eobp)
   3335            (setq continue nil))
   3336           ((and (not (get-text-property (point) 'tag-type))
   3337                 (not (get-text-property (point) 'part-side))
   3338                 (not (get-text-property (point) 'block-side)))
   3339            (setq pos (point)
   3340                  continue nil))
   3341           (t
   3342            (forward-line))
   3343           ) ;cond
   3344         ) ;while
   3345       pos)))
   3346 
   3347 (defun web-mode-buffer-scan ()
   3348   "Scan entine buffer."
   3349   (interactive)
   3350   (web-mode-scan-region (point-min) (point-max)))
   3351 
   3352 (defun web-mode-scan-region (beg end &optional content-type)
   3353   "Identify nodes/parts/blocks and syntactic symbols (strings/comments/etc.)."
   3354   ;;(message "scan-region: beg(%d) end(%d) content-type(%S)" beg end content-type)
   3355   (setq web-mode-scan-beg beg
   3356         web-mode-scan-end end)
   3357   (web-mode-with-silent-modifications
   3358    (save-excursion
   3359      (save-restriction
   3360        (save-match-data
   3361          (let ((inhibit-point-motion-hooks t)
   3362                (inhibit-quit t))
   3363            (remove-list-of-text-properties beg end web-mode-scan-properties)
   3364            (cond
   3365              ((and content-type (string= content-type "php"))
   3366               )
   3367              ((and content-type (member content-type web-mode-part-content-types))
   3368               (put-text-property beg end 'part-side
   3369                                  (cond
   3370                                    ((string= content-type "javascript") 'javascript)
   3371                                    ((string= content-type "json") 'json)
   3372                                    ((string= content-type "jsx") 'jsx)
   3373                                    ((string= content-type "css") 'css)
   3374                                    ((string= content-type "sql") 'sql)
   3375                                    ((string= content-type "pug") 'pug)
   3376                                    ((string= content-type "sass") 'sass)
   3377                                    ((string= content-type "stylus") 'stylus)
   3378                                    ((string= content-type "markdown") 'markdown)
   3379                                    ((string= content-type "ruby") 'ruby)
   3380                                    ((string= content-type "typescript") 'typescript)
   3381                                    ))
   3382               (web-mode-scan-blocks beg end)
   3383               (web-mode-part-scan beg end content-type))
   3384              ((member web-mode-content-type web-mode-part-content-types)
   3385               (web-mode-scan-blocks beg end)
   3386               (web-mode-part-scan beg end))
   3387              ((string= web-mode-engine "riot")
   3388               (web-mode-scan-elements beg end)
   3389               (web-mode-scan-blocks beg end)
   3390               (web-mode-part-foreach beg end 'web-mode-part-scan))
   3391              (t
   3392               (web-mode-scan-blocks beg end)
   3393               (web-mode-scan-elements beg end)
   3394               (web-mode-part-foreach beg end 'web-mode-part-scan))
   3395              ) ;cond
   3396            (cons beg end)
   3397            ))))))
   3398 
   3399 ;;---- LEXER BLOCKS ------------------------------------------------------------
   3400 
   3401 (defun web-mode-scan-blocks (reg-beg reg-end)
   3402   "Identifies blocks (with block-side, block-beg, block-end text properties)."
   3403   (save-excursion
   3404 
   3405     (let ((i 0) open close closing-string sub1 sub2 pos tagopen tmp delim-open delim-close part-beg part-end tagclose)
   3406 
   3407       (goto-char reg-beg)
   3408 
   3409       ;;(message "%S: %Sx%S" (point) reg-beg reg-end)
   3410       ;;(message "regexp=%S" web-mode-block-regexp)
   3411       (while (and (< i 2000)
   3412                   (> reg-end (point))
   3413                   web-mode-block-regexp
   3414                   (re-search-forward web-mode-block-regexp reg-end t)
   3415                   (not (eobp)))
   3416 
   3417         (setq i (1+ i)
   3418               closing-string nil
   3419               close nil
   3420               tagopen (match-string 0)
   3421               open (match-beginning 0)
   3422               delim-open nil
   3423               delim-close nil
   3424               pos nil)
   3425 
   3426         (let ((l (length tagopen)))
   3427           (when (member (string-to-char tagopen) '(?\s ?\t))
   3428             (setq tagopen (replace-regexp-in-string "\\`[ \t]*" "" tagopen))
   3429             (setq open (+ open (- l (length tagopen))))
   3430             (setq l (length tagopen))
   3431             )
   3432           (setq sub1 (substring tagopen 0 1)
   3433                 sub2 (substring tagopen 0 (if (>= l 2) 2 1)))
   3434           )
   3435         ;;(message " found block #(%S) at pos=(%S), part-type=(%S)" i open (get-text-property open 'part-side))
   3436         (cond
   3437 
   3438           ((string= web-mode-engine "php")
   3439            (unless (member (char-after) '(?x ?X))
   3440              (setq closing-string '("<\\?". "\\?>")))
   3441            (cond
   3442              ((looking-at-p "<?php")
   3443               (setq delim-open "<?php")
   3444               (setq delim-close "?>"))
   3445              ((eq (char-after) ?\=)
   3446               (setq delim-open "<?=")
   3447               (setq delim-close "?>"))
   3448              (t
   3449               (setq delim-open "<?")
   3450               (setq delim-close "?>"))
   3451              ) ;cond
   3452            ) ;php
   3453 
   3454           ((string= web-mode-engine "erb")
   3455            (cond
   3456              ((string= sub2 "<%")
   3457               (setq closing-string '("<%". "%>")
   3458                     delim-open "<%\\(==\\|[=-]\\)?"
   3459                     delim-close "[-]?%>"))
   3460              (t
   3461               (setq closing-string "EOL"
   3462                     delim-open "%"))
   3463              )
   3464            ) ;erb
   3465 
   3466           ((string= web-mode-engine "django")
   3467            (cond
   3468              ((string= sub2 "{{")
   3469               (setq closing-string "EODQ"
   3470                     ;;(setq closing-string '("{{" . "}}")
   3471                     delim-open "{{"
   3472                     delim-close "}}"))
   3473              ((string= sub2 "{%")
   3474               (setq closing-string "%}"
   3475                     delim-open "{%[+-]?"
   3476                     delim-close "[-]?%}"))
   3477              ((string= sub2 "{#")
   3478               (setq closing-string "#}"))
   3479              (t
   3480               (setq closing-string "EOL"
   3481                     delim-open "#[#]?"))
   3482              )
   3483            ) ;django
   3484 
   3485           ((string= web-mode-engine "anki")
   3486            (setq closing-string "}}"
   3487                  delim-open "{{[#/^]?"
   3488                  delim-close "}}")
   3489            ) ;anki
   3490 
   3491           ((string= web-mode-engine "ejs")
   3492            (setq closing-string "%>"
   3493                  delim-open "<%[=-]?"
   3494                  delim-close "[-]?%>")
   3495            ) ;ejs
   3496 
   3497           ((string= web-mode-engine "lsp")
   3498            (setq closing-string "%>"
   3499                  delim-open "<%[%#]?"
   3500                  delim-close "%>")
   3501            ) ;lsp
   3502 
   3503           ((string= web-mode-engine "mako")
   3504            (cond
   3505              ((and (string= tagopen "<%")
   3506                    (member (char-after) '(?\s ?\n ?\!)))
   3507               (setq closing-string "%>"
   3508                     delim-open "<%[!]?"
   3509                     delim-close "%>"))
   3510              ((member sub2 '("<%" "</"))
   3511               (setq closing-string ">"
   3512                     delim-open "</?%"
   3513                     delim-close "/?>"))
   3514              ((string= sub2 "${")
   3515               (setq closing-string "}"
   3516                     delim-open "${"
   3517                     delim-close "}"))
   3518              (t
   3519               (setq closing-string "EOL"
   3520                     delim-open "%"))
   3521              )
   3522            ) ;mako
   3523 
   3524           ((string= web-mode-engine "cl-emb")
   3525            (cond
   3526              ((string= tagopen "<%#")
   3527               (setq closing-string "#%>"))
   3528              ((string= sub2 "<%")
   3529               (setq closing-string "%>"
   3530                     delim-open "<%[=%]?"
   3531                     delim-close "%>"))
   3532              )
   3533            ) ;cl-emb
   3534 
   3535           ((string= web-mode-engine "artanis")
   3536            (cond
   3537              ((string= tagopen "<%;")
   3538               (setq closing-string "%>"))
   3539              ((string= tagopen "<%#|")
   3540               (setq closing-string "|#%>"))
   3541              ((string= sub2 "<@")
   3542               (setq closing-string "%>"
   3543                     delim-open "<@\\(css\\|icon\\|include\\|js\\)"
   3544                     delim-close "%>"))
   3545              ((string= sub2 "<%")
   3546               (setq closing-string "%>"
   3547                     delim-open "<%[=]?"
   3548                     delim-close "%>"))
   3549              )
   3550            ) ;artanis
   3551 
   3552           ((string= web-mode-engine "elixir")
   3553            (cond
   3554              ((member (char-after) '(?\#))
   3555               (setq closing-string "%>"))
   3556              (t
   3557               (setq closing-string "%>"
   3558                     delim-open "<%[=%]?"
   3559                     delim-close "%>"))
   3560              )
   3561            ) ;elixir
   3562 
   3563           ((string= web-mode-engine "mojolicious")
   3564            (cond
   3565              ((string= tagopen "<%#")
   3566               (setq closing-string "%>"))
   3567              ((string= sub2 "<%")
   3568               (setq closing-string "%>"
   3569                     delim-open "<%\\(==\\|[=%]\\)?"
   3570                     delim-close "%>"))
   3571              ((string= sub2 "%#")
   3572               (setq closing-string "EOL"))
   3573              (t
   3574               (setq closing-string "EOL"
   3575                     delim-open "%\\(==\\|[=%]\\)?"))
   3576              )
   3577            ) ;mojolicious
   3578 
   3579           ((string= web-mode-engine "ctemplate")
   3580            (cond
   3581              ((member tagopen '("{{{" "{{~"))
   3582               (setq closing-string "}~?}}"
   3583                     delim-open "{{~?{"
   3584                     delim-close "}~?}}")
   3585               )
   3586              ((string= tagopen "{~{")
   3587               (setq closing-string "}~?}"
   3588                     delim-open "{~{"
   3589                     delim-close "}~?}")
   3590               )
   3591              ((string= tagopen "{{!")
   3592               (setq closing-string (if (looking-at-p "--") "--}}" "}}"))
   3593               )
   3594              ((string= sub2 "{{")
   3595               (setq closing-string "}~?}"
   3596                     delim-open "{{[>#/%^&]?"
   3597                     delim-close "}~?}"))
   3598              (t
   3599               (setq closing-string "}}"
   3600                     delim-open "${{"
   3601                     delim-close "}}"))
   3602              )
   3603            ) ;ctemplate
   3604 
   3605           ((string= web-mode-engine "antlers")
   3606            (cond
   3607              ((string= tagopen "{{$")
   3608               (setq closing-string "$}}"
   3609                     delim-open "{{$"
   3610                     delim-close "$}}")
   3611               )
   3612              ((string= tagopen "{{?")
   3613               (setq closing-string "?}}"
   3614                     delim-open "{{?"
   3615                     delim-close "?}}")
   3616               )
   3617              ((string= tagopen "{{$")
   3618               (setq closing-string "$}}"
   3619                     delim-open "{{$"
   3620                     delim-close "$}}")
   3621               )
   3622              ((string= sub2 "{{")
   3623               (setq closing-string "}}"
   3624                     delim-open "{{"
   3625                     delim-close "}}"))
   3626              )
   3627            ) ;antlers
   3628 
   3629           ((string= web-mode-engine "astro")
   3630            (cond
   3631              ((string= tagopen "---")
   3632               (setq closing-string "---"
   3633                     delim-open "---"
   3634                     delim-close "---")
   3635               )
   3636              )
   3637            ) ;astro
   3638 
   3639           ((string= web-mode-engine "aspx")
   3640            (setq closing-string "%>"
   3641                  delim-open "<%[:=#@$]?"
   3642                  delim-close "%>")
   3643            ) ;aspx
   3644 
   3645           ((string= web-mode-engine "asp")
   3646            (cond
   3647              ((string= sub2 "<%")
   3648               (setq closing-string "%>"
   3649                     delim-open "<%[:=#@$]?"
   3650                     delim-close "%>"))
   3651              (t
   3652               (setq closing-string ">"
   3653                     delim-open "</?"
   3654                     delim-close "/?>"))
   3655              )
   3656            ) ;asp
   3657 
   3658           ((string= web-mode-engine "jsp")
   3659            (cond
   3660              ((looking-at-p "--")
   3661               (setq closing-string "--%>"))
   3662              ((string= sub2 "<%")
   3663               (setq closing-string "%>"
   3664                     delim-open "<%\\([!=@]\\|#=\\)?"
   3665                     delim-close "[-]?%>"))
   3666              ((string= sub2 "${")
   3667               (setq closing-string "}"
   3668                     delim-open "${"
   3669                     delim-close "}"))
   3670              )
   3671            ) ;jsp
   3672 
   3673           ((string= web-mode-engine "clip")
   3674            (setq closing-string ">"
   3675                  delim-open "</?"
   3676                  delim-close "/?>")
   3677            ) ;clip
   3678 
   3679           ((string= web-mode-engine "perl")
   3680            (setq closing-string ">"
   3681                  delim-open "</?"
   3682                  delim-close "/?>")
   3683            ) ;perl
   3684 
   3685           ((string= web-mode-engine "blade")
   3686            (cond
   3687              ((string= tagopen "{{-")
   3688               (setq closing-string "--}}"))
   3689              ((string= tagopen "{!!")
   3690               (setq closing-string "!!}"
   3691                     delim-open "{!!"
   3692                     delim-close "!!}"))
   3693              ((string= tagopen "@{{")
   3694               (setq closing-string nil))
   3695              ((string= tagopen "{{{")
   3696               (setq closing-string "}}}"
   3697                     delim-open "{{{"
   3698                     delim-close "}}}"))
   3699              ((string= sub2 "{{")
   3700               (setq closing-string "}}"
   3701                     delim-open "{{"
   3702                     delim-close "}}"))
   3703              ((looking-at-p "[[:alnum:]]+\\.[[:alpha:]]+")
   3704               )
   3705              ((string= sub1 "@")
   3706               (setq closing-string "EOB"
   3707                     delim-open "@"))
   3708              ((looking-at-p "[[:alnum:]]+(")
   3709               (setq closing-string ")"
   3710                     delim-open "@"))
   3711              )
   3712            ;;(message "closing-string=%S delim-open=%S delim-close=%S" closing-string delim-open delim-close)
   3713            ) ;blade
   3714 
   3715           ((string= web-mode-engine "smarty")
   3716            (cond
   3717              ((string= tagopen "{*")
   3718               (setq closing-string "*}")
   3719               )
   3720              ((string= tagopen "{#")
   3721               (setq closing-string "#}"
   3722                     delim-open "{#"
   3723                     delim-close "#}")
   3724               )
   3725              (t
   3726               (setq closing-string (cons "{" "}")
   3727                     delim-open "{/?"
   3728                     delim-close "}")
   3729               ) ;t
   3730              ) ;cond
   3731            ) ;smarty
   3732 
   3733           ((string= web-mode-engine "hero")
   3734            (setq closing-string "%>"
   3735                  delim-open "<%==?\\([biufsv]\\|bs\\)?\\|<%[:~@+!]?"
   3736                  delim-close "%>")
   3737            ) ;hero
   3738 
   3739           ((string= web-mode-engine "xoops")
   3740            (cond
   3741              ((string= tagopen "<{*")
   3742               (setq closing-string "*}>")
   3743               )
   3744              ((string= tagopen "<{#")
   3745               (setq closing-string "#}>"
   3746                     delim-open "<{#"
   3747                     delim-close "#}>")
   3748               )
   3749              (t
   3750               (setq closing-string (cons "<{" "}>")
   3751                     delim-open "<{/?"
   3752                     delim-close "}>")
   3753               ) ;t
   3754              ) ;cond
   3755            ) ;xoops
   3756 
   3757           ((string= web-mode-engine "web2py")
   3758            (setq closing-string "}}"
   3759                  delim-open "{{[=]?"
   3760                  delim-close "}}")
   3761            ) ;web2py
   3762 
   3763           ((string= web-mode-engine "expressionengine")
   3764            (cond
   3765              ((string= sub2 "{!--")
   3766               (setq closing-string "--}"))
   3767              (t
   3768               (setq closing-string '("{". "}")
   3769                     delim-open "{/?"
   3770                     delim-close "}")
   3771               )
   3772              )
   3773            ) ;expressionengine
   3774 
   3775           ((string= web-mode-engine "dust")
   3776            (cond
   3777              ((string= sub2 "{!")
   3778               (setq closing-string "!}"))
   3779              (t
   3780               (setq closing-string '("{". "}")
   3781                     delim-open "{[#/:?@><+^]?"
   3782                     delim-close "/?}")
   3783               )
   3784              )
   3785            ) ;dust
   3786 
   3787           ((string= web-mode-engine "svelte")
   3788            (cond
   3789              ((string= sub2 "{!")
   3790               (setq closing-string "!}"))
   3791              ((string= sub2 "{}")
   3792               (setq closing-string nil
   3793                     delim-open nil
   3794                     delim-close nil))
   3795              (t
   3796               (setq closing-string '("{". "}")
   3797                     delim-open "{[#/:?@><+^]?"
   3798                     delim-close "/?}")
   3799               )
   3800              )
   3801            ) ;svelte
   3802 
   3803           ((string= web-mode-engine "closure")
   3804            (cond
   3805              ((string= sub2 "//")
   3806               (setq closing-string "EOL")
   3807               )
   3808              ((string= sub2 "/*")
   3809               (setq closing-string "*/")
   3810               )
   3811              (t
   3812               (setq closing-string "}"
   3813                     delim-open "{/?"
   3814                     delim-close "/?}")
   3815               )
   3816              )
   3817            ) ;closure
   3818 
   3819           ((string= web-mode-engine "go")
   3820            (setq closing-string "}}"
   3821                  delim-open "{{-?"
   3822                  delim-close "-?}}")
   3823            ) ;go
   3824 
   3825           ((string= web-mode-engine "angular")
   3826            (setq closing-string "}}"
   3827                  delim-open "{{"
   3828                  delim-close "}}")
   3829            ) ;angular
   3830 
   3831           ((string= web-mode-engine "vue")
   3832            (cond
   3833              ((string-match-p "[:@][-[:alpha:]]+=\"" tagopen)
   3834               (setq closing-string "\""
   3835                     delim-open tagopen
   3836                     delim-close "\""))
   3837              ((string= tagopen "{{")
   3838               (setq closing-string "}}"
   3839                     delim-open "{{"
   3840                     delim-close "}}")))
   3841            ) ;vue
   3842 
   3843           ((string= web-mode-engine "mason")
   3844            (cond
   3845              ((and (member sub2 '("<%" "</"))
   3846                    (looking-at "[[:alpha:]]+"))
   3847               (if (member (match-string-no-properties 0) '("after" "around" "augment" "before" "def" "filter" "method" "override"))
   3848                   (setq closing-string ">"
   3849                         delim-open "<[/]?%"
   3850                         delim-close ">")
   3851                   (setq closing-string (concat "</%" (match-string-no-properties 0) ">")
   3852                         delim-open "<[^>]+>"
   3853                         delim-close "<[^>]+>")
   3854                   ) ;if
   3855               )
   3856              ((and (string= sub2 "<%")
   3857                    (eq (char-after) ?\s))
   3858               (setq closing-string "%>"
   3859                     delim-open "<%"
   3860                     delim-close "%>"))
   3861              ((string= tagopen "</&")
   3862               (setq closing-string ">"
   3863                     delim-open "</&"
   3864                     delim-close ">")
   3865               )
   3866              ((string= sub2 "<&")
   3867               (setq closing-string "&>"
   3868                     delim-open "<&[|]?"
   3869                     delim-close "&>"))
   3870              (t
   3871               (setq closing-string "EOL"
   3872                     delim-open "%"))
   3873              )
   3874            ) ;mason
   3875 
   3876           ((string= web-mode-engine "underscore")
   3877            (setq closing-string "%>"
   3878                  delim-open "<%"
   3879                  delim-close "%>")
   3880            ) ;underscore
   3881 
   3882           ((string= web-mode-engine "template-toolkit")
   3883            (cond
   3884              ((string= tagopen "%%#")
   3885               (setq closing-string "EOL"))
   3886              ((string= tagopen "[%#")
   3887               (setq closing-string "%]"))
   3888              (t
   3889               (setq closing-string "%]"
   3890                     delim-open "\\[%[-+]?"
   3891                     delim-close "[-=+]?%\\]"))
   3892              )
   3893            ) ;template-toolkit
   3894 
   3895           ((string= web-mode-engine "freemarker")
   3896            (cond
   3897              ((and (string= sub2 "<#") (eq (char-after) ?\-))
   3898               (setq closing-string "-->"))
   3899              ((string= sub1 "<")
   3900               (setq closing-string ">"
   3901                     delim-open "</?[#@]"
   3902                     delim-close "/?>"))
   3903              ((string= sub1 "[")
   3904               (setq closing-string "]"
   3905                     delim-open "\\[/?[#@]"
   3906                     delim-close "/?\\]"))
   3907              (t
   3908               (setq closing-string "}"
   3909                     delim-open "${"
   3910                     delim-close "}"))
   3911              )
   3912            ) ;freemarker
   3913 
   3914           ((string= web-mode-engine "velocity")
   3915            (cond
   3916              ((string= sub2 "##")
   3917               (setq closing-string "EOL"))
   3918              ((string= sub2 "#*")
   3919               (setq closing-string "*#"))
   3920              (t
   3921               (setq closing-string "EOV"
   3922                     delim-open "#"))
   3923              )
   3924            ) ;velocity
   3925 
   3926           ((string= web-mode-engine "razor")
   3927            (cond
   3928              ((string= sub2 "@@")
   3929               (forward-char 2)
   3930               (setq closing-string nil))
   3931              ((string= sub2 "@*")
   3932               (setq closing-string "*@"))
   3933              ((string= sub1 "@")
   3934               (setq closing-string "EOR"
   3935                     delim-open "@"))
   3936              ((and (string= sub1 "}")
   3937                    (looking-at-p "[ ]*\n"))
   3938               ;;(setq closing-string "EOC")
   3939               (save-excursion
   3940                 (let (paren-pos)
   3941                   (setq paren-pos (web-mode-part-opening-paren-position (1- (point))))
   3942                   (if (and paren-pos (get-text-property paren-pos 'block-side))
   3943                       (setq closing-string "EOC")
   3944                       (setq closing-string nil)
   3945                       ) ;if
   3946                   ) ;let
   3947                 ) ;save-excursion
   3948               ;;(message "%s %S %S" sub2 (point) (get-text-property (point) 'part-side))
   3949               )
   3950              ((string= sub1 "}")
   3951               ;;(message "%s: %s" (point) sub1)
   3952               (save-excursion
   3953                 (let (paren-pos)
   3954                   (setq paren-pos (web-mode-part-opening-paren-position (1- (point))))
   3955                   (if (and paren-pos (get-text-property paren-pos 'block-side))
   3956                       (setq closing-string "EOR")
   3957                       (setq closing-string nil)
   3958                       ) ;if
   3959                   ) ;let
   3960                 ) ;save-excursion
   3961               ) ;case }
   3962              ) ;cond
   3963            ) ;razor
   3964 
   3965           ((and (string= web-mode-engine "riot")
   3966                 (not (get-text-property open 'part-side)))
   3967            (setq closing-string (if (string= tagopen "{") "}" "/// end script")
   3968                  delim-open "{"
   3969                  delim-close "}")
   3970            ) ;riot
   3971 
   3972           ((string= web-mode-engine "spip")
   3973            (cond
   3974              ((and (string= sub1 "#")
   3975                    (looking-at "[A-Z0-9_]+"))
   3976               (setq closing-string (match-string-no-properties 0)))
   3977              ((string= sub1 "(")
   3978               (setq closing-string '("(" . ")")))
   3979              ((string= sub1 "{")
   3980               (setq closing-string '("{" . "}")))
   3981              ((string= sub2 "<:")
   3982               (setq closing-string ":>"))
   3983              (t
   3984               (setq closing-string "]"))
   3985              ))
   3986 
   3987           ((string= web-mode-engine "marko")
   3988            (setq closing-string "}"
   3989                  delim-open "${"
   3990                  delim-close "}")
   3991            ) ;marko
   3992 
   3993           ) ;cond
   3994 
   3995         (when closing-string
   3996           (cond
   3997 
   3998             ((listp closing-string)
   3999              (cond
   4000                ((web-mode-rsf-balanced (car closing-string) (cdr closing-string) reg-end t)
   4001                 (setq close (match-end 0)
   4002                       pos (point))
   4003                 )
   4004                ((and (string= web-mode-engine "php")
   4005                      (string= "<?" sub2))
   4006 
   4007                 (if (or (text-property-not-all (1+ open) (point-max) 'tag-beg nil)
   4008                         (text-property-not-all (1+ open) (point-max) 'block-beg nil)
   4009                         (looking-at-p "[ \t\n]*<"))
   4010                     (setq close nil
   4011                           delim-close nil
   4012                           pos (point))
   4013                     (setq close (point-max)
   4014                           delim-close nil
   4015                           pos (point-max))
   4016                     ) ;if
   4017                 ) ;case
   4018                ) ;cond
   4019              ) ;case listp
   4020 
   4021             ((and (string= web-mode-engine "smarty")
   4022                   (string= closing-string "}"))
   4023              (goto-char open)
   4024              (setq tmp (web-mode-closing-delimiter-position
   4025                         "}"
   4026                         (point)
   4027                         (line-end-position)))
   4028              (if tmp
   4029                  (setq tmp (1+ tmp))
   4030                  (setq tmp (line-end-position)))
   4031              (goto-char tmp)
   4032              (setq close (point)
   4033                    pos (point))
   4034              )
   4035 
   4036             ((and (member web-mode-engine '("closure"))
   4037                   (string= closing-string "}"))
   4038              (when (web-mode-closure-skip reg-beg reg-end)
   4039                (setq close (point)
   4040                      pos (point))
   4041                ;;(message "close=%S pos=%S" close pos)
   4042                ) ;when
   4043              )
   4044 
   4045             ((string= closing-string "EOB")
   4046              (web-mode-blade-skip open)
   4047              (setq close (point)
   4048                    pos (point)))
   4049 
   4050             ((string= closing-string "EOL")
   4051              (end-of-line)
   4052              (setq close (point)
   4053                    pos (point)))
   4054 
   4055             ((string= closing-string "EOC")
   4056              (setq close (point)
   4057                    pos (point)))
   4058 
   4059             ((string= closing-string "EODQ")
   4060              (when (web-mode-django-skip reg-beg reg-end)
   4061                (setq close (point)
   4062                      pos (point))
   4063                ))
   4064 
   4065             ((string= closing-string "EOR")
   4066              (web-mode-razor-skip open)
   4067              (setq close (if (> (point) reg-end) reg-end (point))
   4068                    pos (if (> (point) reg-end) reg-end (point)))
   4069              (goto-char pos))
   4070 
   4071             ((string= closing-string "EOV")
   4072              (web-mode-velocity-skip open)
   4073              (setq close (point)
   4074                    pos (point)))
   4075 
   4076             ((and (member web-mode-engine '("ctemplate"))
   4077                   (re-search-forward closing-string reg-end t))
   4078              (setq close (match-end 0)
   4079                    pos (point)))
   4080 
   4081             ((and (member web-mode-engine '("antlers"))
   4082                   (re-search-forward closing-string reg-end t))
   4083              (setq close (match-end 0)
   4084                    pos (point)))
   4085 
   4086             ((and (member web-mode-engine '("astro"))
   4087                   (re-search-forward closing-string reg-end t))
   4088              (setq close (match-end 0)
   4089                    pos (point)))
   4090 
   4091             ((search-forward closing-string reg-end t)
   4092              (setq close (match-end 0)
   4093                    pos (point)))
   4094             ) ;cond
   4095 
   4096           (when (and close (>= reg-end pos))
   4097             ;;(message "pos(%S) : open(%S) close(%S)" pos open close)
   4098             (put-text-property open (1+ open) 'block-beg 0)
   4099             (put-text-property open (1+ open) 'block-controls 0)
   4100             (put-text-property open close 'block-side t)
   4101             (put-text-property (1- close) close 'block-end t)
   4102             (when delim-open
   4103               (web-mode-block-delimiters-set open close delim-open delim-close))
   4104             (web-mode-block-scan open close)
   4105             (cond
   4106               ((and (string= web-mode-engine "erb")
   4107                     (looking-at-p "<%= javascript_tag do %>"))
   4108                (setq tagopen "<%= javascript_tag do %>"))
   4109               ((and (string= web-mode-engine "mojolicious")
   4110                     (looking-at-p "%= javascript begin"))
   4111                (setq tagopen "%= javascript begin"))
   4112               ((and (string= web-mode-engine "mako")
   4113                     (looking-at-p "<%block filter=\"collect_js\">"))
   4114                (setq tagopen "<%block filter=\"collect_js\">"))
   4115               ((and (string= web-mode-engine "mako")
   4116                     (looking-at-p "<%block filter=\"collect_css\">"))
   4117                (setq tagopen "<%block filter=\"collect_css\">"))
   4118               ((and (string= web-mode-engine "django")
   4119                     (looking-at-p "{% javascript %}"))
   4120                (setq tagopen "{% javascript %}"))
   4121               ((and (string= web-mode-engine "django")
   4122                     (looking-at-p "{% schema %}"))
   4123                (setq tagopen "{% schema %}"))
   4124               ((and (string= web-mode-engine "django")
   4125                     (looking-at-p "{% stylesheet %}"))
   4126                (setq tagopen "{% stylesheet %}"))
   4127               )
   4128             ;;(message "%S %s" (point) tagopen)
   4129             (when (and (member tagopen '("<r:script" "<r:style"
   4130                                          "<c:js" "<c:css"
   4131                                          "<%= javascript_tag do %>"
   4132                                          "<%block filter=\"collect_js\">"
   4133                                          "<%block filter=\"collect_css\">"
   4134                                          "{% javascript %}"
   4135                                          "{% schema %}"
   4136                                          "{% stylesheet %}"
   4137                                          "%= javascript begin"
   4138                                          "---"))
   4139                        (setq part-beg close)
   4140                        (setq tagclose
   4141                              (cond
   4142                                ((string= tagopen "<r:script") "</r:script")
   4143                                ((string= tagopen "<r:style") "</r:style")
   4144                                ((string= tagopen "<c:js") "</c:js")
   4145                                ((string= tagopen "<c:css") "</c:css")
   4146                                ((string= tagopen "{% javascript %}") "{% endjavascript %}")
   4147                                ((string= tagopen "{% schema %}") "{% endschema %}")
   4148                                ((string= tagopen "{% stylesheet %}") "{% endstylesheet %}")
   4149                                ((string= tagopen "%= javascript begin") "% end")
   4150                                ((string= tagopen "---") "---")
   4151                                ((string= tagopen "<%= javascript_tag do %>") "<% end %>")
   4152                                ((member tagopen '("<%block filter=\"collect_js\">"
   4153                                                   "<%block filter=\"collect_css\">")) "</%block")
   4154                                ))
   4155                        (web-mode-sf tagclose)
   4156                        (setq part-end (match-beginning 0))
   4157                        (> part-end part-beg))
   4158               ;;(message "tagopen=%S tagclose=%S end=%S" tagopen tagclose (point))
   4159               (put-text-property part-beg part-end
   4160                                  'part-side
   4161                                  (cond
   4162                                    ((member tagopen '("<r:style" "<c:css" "<%block filter=\"collect_css\">" "{% stylesheet %}")) 'css)
   4163                                    (t 'javascript)))
   4164               (setq pos part-beg
   4165                     part-beg nil
   4166                     part-end nil)
   4167               ) ;when
   4168             ) ;when close
   4169 
   4170           (if pos (goto-char pos))
   4171 
   4172           ) ;when closing-string
   4173 
   4174         ) ;while
   4175 
   4176       (cond
   4177         ((>= i 2000)
   4178          (message "scan-blocks ** warning (%S) **" i))
   4179         ((string= web-mode-engine "razor")
   4180          (web-mode-block-foreach reg-beg reg-end 'web-mode-block-scan))
   4181         ((string= web-mode-engine "django")
   4182          (web-mode-scan-engine-comments reg-beg reg-end
   4183                                         "{% comment %}" "{% endcomment %}"))
   4184         ((string= web-mode-engine "mako")
   4185          (web-mode-scan-engine-comments reg-beg reg-end
   4186                                         "<%doc>" "</%doc>"))
   4187         ((string= web-mode-engine "mason")
   4188          (web-mode-scan-engine-comments reg-beg reg-end
   4189                                         "<%doc>" "</%doc>"))
   4190         ) ;cond
   4191 
   4192       )))
   4193 
   4194 (defun web-mode-scan-engine-comments (reg-beg reg-end tag-start tag-end)
   4195   "Scan engine comments (mako, django)."
   4196   (save-excursion
   4197     (let (beg end (continue t))
   4198       (goto-char reg-beg)
   4199       (while (and continue
   4200                   (< (point) reg-end)
   4201                   (re-search-forward tag-start reg-end t))
   4202         (goto-char (match-beginning 0))
   4203         (setq beg (point))
   4204         (if (not (re-search-forward tag-end reg-end t))
   4205             (setq continue nil)
   4206             (setq end (point))
   4207             (remove-list-of-text-properties beg end web-mode-scan-properties)
   4208             (add-text-properties beg end '(block-side t block-token comment))
   4209             (put-text-property beg (1+ beg) 'block-beg 0)
   4210             (put-text-property (1- end) end 'block-end t)
   4211             ) ;if
   4212         ) ;while
   4213       )))
   4214 
   4215 (defun web-mode-closure-skip (reg-beg reg-end)
   4216   (let (regexp char pos inc continue found)
   4217     (setq regexp "[\"'{}]"
   4218           inc 0)
   4219     (while (and (not found) (re-search-forward regexp reg-end t))
   4220       (setq char (char-before))
   4221       (cond
   4222         ((get-text-property (point) 'block-side)
   4223          (setq found t))
   4224         ((eq char ?\{)
   4225          (setq inc (1+ inc)))
   4226         ((eq char ?\})
   4227          (cond
   4228            ((and (not (eobp))
   4229                  (< inc 1))
   4230             (setq found t
   4231                   pos (point)))
   4232            ((> inc 0)
   4233             (setq inc (1- inc)))
   4234            )
   4235          )
   4236         ((eq char ?\')
   4237          (setq continue t)
   4238          (while (and continue (search-forward "'" reg-end t))
   4239            (setq continue (web-mode-string-continue-p reg-beg))
   4240            )
   4241          )
   4242         ((eq char ?\")
   4243          (setq continue t)
   4244          (while (and continue (search-forward "\"" reg-end t))
   4245            (setq continue (web-mode-string-continue-p reg-beg))
   4246            )
   4247          )
   4248         ) ;cond
   4249       ) ;while
   4250     pos))
   4251 
   4252 (defun web-mode-django-skip (reg-beg reg-end)
   4253   (let (regexp char pos inc continue found)
   4254     (setq regexp "[\"'{}]"
   4255           inc 0)
   4256     (while (and (not found) (re-search-forward regexp reg-end t))
   4257       (setq char (char-before))
   4258       (cond
   4259         ((get-text-property (point) 'block-side)
   4260          (setq found t))
   4261         ((eq char ?\{)
   4262          (setq inc (1+ inc)))
   4263         ((eq char ?\})
   4264          (cond
   4265            ((and (not (eobp))
   4266                  (eq (char-after) ?\})
   4267                  (< inc 2))
   4268             (forward-char)
   4269             (setq found t
   4270                   pos (1+ (point))))
   4271            ((> inc 0)
   4272             (setq inc (1- inc)))
   4273            )
   4274          )
   4275         ((eq char ?\')
   4276          (setq continue t)
   4277          (while (and continue (search-forward "'" reg-end t))
   4278            (setq continue (web-mode-string-continue-p reg-beg))
   4279            )
   4280          )
   4281         ((eq char ?\")
   4282          (setq continue t)
   4283          (while (and continue (search-forward "\"" reg-end t))
   4284            (setq continue (web-mode-string-continue-p reg-beg))
   4285            )
   4286          )
   4287         ) ;cond
   4288       ) ;while
   4289     pos))
   4290 
   4291 (defun web-mode-blade-skip (pos)
   4292   (let (regexp char inc continue found (reg-beg pos) (reg-end (point-max)))
   4293     ;;(message "pos=%S" pos)
   4294     (goto-char pos)
   4295     (forward-char)
   4296     (skip-chars-forward "a-zA-Z0-9_-")
   4297     (skip-chars-forward " ")
   4298     (when (eq (char-after) ?\()
   4299       (setq regexp "[\"'()]"
   4300             inc 0)
   4301       (while (and (not found) (re-search-forward regexp reg-end t))
   4302         (setq char (char-before))
   4303         ;;(message "point=%S char=%c inc=%S" (point) char inc)
   4304         (cond
   4305          ((eq char ?\()
   4306           (setq inc (1+ inc)))
   4307          ((eq char ?\))
   4308           (cond
   4309            ((and (not (eobp))
   4310                  (< inc 2))
   4311             (forward-char)
   4312             (setq inc (1- inc))
   4313             (setq found t)
   4314             )
   4315            ((> inc 0)
   4316             (setq inc (1- inc)))
   4317            )
   4318           )
   4319          ((eq char ?\')
   4320           (setq continue t)
   4321           (while (and continue (search-forward "'" reg-end t))
   4322             (setq continue (web-mode-string-continue-p reg-beg))
   4323             )
   4324           )
   4325          ((eq char ?\")
   4326           (setq continue t)
   4327           (while (and continue (search-forward "\"" reg-end t))
   4328             (setq continue (web-mode-string-continue-p reg-beg))
   4329             )
   4330           )
   4331          ) ;cond
   4332         ;;(message "inc=%S found=%S" inc found)
   4333         ) ;while
   4334       ) ; when
   4335     ;;(message "point=%S inc=%S" (point) inc)
   4336     (when found (backward-char))
   4337   ))
   4338 
   4339 (defun web-mode-velocity-skip (pos)
   4340   (goto-char pos)
   4341   (let ((continue t) (i 0))
   4342     (when (eq ?\# (char-after))
   4343       (forward-char))
   4344     (when (member (char-after) '(?\$ ?\@))
   4345       (forward-char))
   4346     (when (member (char-after) '(?\!))
   4347       (forward-char))
   4348     (cond
   4349       ((member (char-after) '(?\{))
   4350        (search-forward "}" nil t))
   4351       ((looking-at-p "def \\|define ")
   4352        (search-forward ")" (line-end-position) t))
   4353       (t
   4354        (setq continue t)
   4355        (while continue
   4356          (skip-chars-forward "a-zA-Z0-9_-")
   4357          (when (> (setq i (1+ i)) 500)
   4358            (message "velocity-skip ** warning (%S) **" pos)
   4359            (setq continue nil))
   4360          (when (member (char-after) '(?\())
   4361            (search-forward ")" nil t))
   4362          (if (member (char-after) '(?\.))
   4363              (forward-char)
   4364              (setq continue nil))
   4365          ) ;while
   4366        ) ;t
   4367       ) ;cond
   4368     ))
   4369 
   4370 (defun web-mode-razor-skip (pos)
   4371   (goto-char pos)
   4372   (let ((continue t) (i 0))
   4373     (while continue
   4374       (skip-chars-forward " =@a-zA-Z0-9_-")
   4375       (cond
   4376         ((> (setq i (1+ i)) 500)
   4377          (message "razor-skip ** warning **")
   4378          (setq continue nil))
   4379         ((and (eq (char-after) ?\*)
   4380               (eq (char-before) ?@))
   4381          (when (not (search-forward "*@" nil t))
   4382            (setq continue nil))
   4383          )
   4384         ((looking-at-p "@[({]")
   4385          (forward-char)
   4386          (when (setq pos (web-mode-closing-paren-position (point)))
   4387            (goto-char pos))
   4388          (forward-char)
   4389          )
   4390         ((and (not (eobp)) (eq ?\( (char-after)))
   4391          (cond
   4392            ((looking-at-p "[ \n]*[<@]")
   4393             (setq continue nil))
   4394            ((setq pos (web-mode-closing-paren-position))
   4395             (goto-char pos)
   4396             (forward-char))
   4397            (t
   4398             (forward-char))
   4399            ) ;cond
   4400          )
   4401         ((and (not (eobp)) (eq ?\< (char-after)) (looking-back "[a-z]" (point-min)))
   4402          (setq pos (point))
   4403          (cond
   4404            ;; #988
   4405            ((search-forward ">" (line-end-position) t)
   4406             (goto-char pos)
   4407             (setq continue nil)
   4408             )
   4409            (t
   4410             (setq continue nil))
   4411            ) ;cond
   4412          )
   4413         ((and (not (eobp)) (eq ?\. (char-after)))
   4414          (forward-char))
   4415         ((and (not (eobp)) (looking-at-p "[ \n]*else"))
   4416          (re-search-forward "[ \t]*else")
   4417          )
   4418         ((looking-at-p "[ \n]*{")
   4419          (search-forward "{")
   4420          (search-forward "=>" (line-end-position) 't)
   4421          (if (looking-at-p "[ \n]*[<@]")
   4422              (setq continue nil)
   4423              (backward-char)
   4424              (when (setq pos (web-mode-closing-paren-position))
   4425                (goto-char pos))
   4426              (forward-char)
   4427              ) ;if
   4428          )
   4429         ((looking-at-p "}")
   4430          (forward-char))
   4431         (t
   4432          (setq continue nil))
   4433         ) ;cond
   4434       ) ;while
   4435     ))
   4436 
   4437 (defun web-mode-block-delimiters-set (reg-beg reg-end delim-open delim-close)
   4438   "Set text-property `block-token' to `delimiter-(beg|end)' on block delimiters
   4439 (e.g. <?php and ?>)"
   4440   ;;(message "reg-beg(%S) reg-end(%S) delim-open(%S) delim-close(%S)" reg-beg reg-end delim-open delim-close)
   4441   (when (member web-mode-engine
   4442                 '("artanis" "anki" "antlers" "asp" "aspx"
   4443                   "cl-emb" "clip" "closure" "ctemplate" "django" "dust"
   4444                   "elixir" "ejs" "erb" "expressionengine" "freemarker" "go" "hero" "jsp" "lsp"
   4445                   "mako" "mason" "mojolicious"
   4446                   "perl"
   4447                   "smarty" "template-toolkit" "web2py" "xoops" "svelte"))
   4448     (save-excursion
   4449       (when delim-open
   4450         (goto-char reg-beg)
   4451         (looking-at delim-open)
   4452         (setq delim-open (match-string-no-properties 0)))
   4453       (when delim-close
   4454         (goto-char reg-end)
   4455         (looking-back delim-close reg-beg t)
   4456         (setq delim-close (match-string-no-properties 0)))
   4457       ))
   4458   (when delim-open
   4459     (put-text-property reg-beg (+ reg-beg (length delim-open))
   4460                        'block-token 'delimiter-beg))
   4461   (when delim-close
   4462     (put-text-property (- reg-end (length delim-close)) reg-end
   4463                        'block-token 'delimiter-end))
   4464   )
   4465 
   4466 (defun web-mode-block-foreach (reg-beg reg-end func)
   4467   (let ((i 0) (continue t) (block-beg reg-beg) (block-end nil))
   4468     (while continue
   4469       (setq block-end nil)
   4470       (unless (get-text-property block-beg 'block-beg)
   4471         (setq block-beg (web-mode-block-next-position block-beg)))
   4472       (when (and block-beg (< block-beg reg-end))
   4473         (setq block-end (web-mode-block-end-position block-beg)))
   4474       (cond
   4475         ((> (setq i (1+ i)) 2000)
   4476          (message "process-blocks ** warning (%S) **" (point))
   4477          (setq continue nil))
   4478         ((or (null block-end) (> block-end reg-end))
   4479          (setq continue nil))
   4480         (t
   4481          (setq block-end (1+ block-end))
   4482          (funcall func block-beg block-end)
   4483          (setq block-beg block-end)
   4484          ) ;t
   4485         ) ;cond
   4486       ) ;while
   4487     ))
   4488 
   4489 (defun web-mode-block-scan (block-beg block-end)
   4490   (let (sub1 sub2 sub3 regexp token-type)
   4491 
   4492     ;;(message "block-beg=%S block-end=%S" block-beg block-end)
   4493     ;;(remove-text-properties block-beg block-end web-mode-scan-properties)
   4494 
   4495     (goto-char block-beg)
   4496 
   4497     (cond
   4498       ((>= (point-max) (+ block-beg 3))
   4499        (setq sub3 (buffer-substring-no-properties block-beg (+ block-beg 3))
   4500              sub2 (buffer-substring-no-properties block-beg (+ block-beg 2))
   4501              sub1 (buffer-substring-no-properties block-beg (+ block-beg 1)))
   4502        )
   4503       ((>= (point-max) (+ block-beg 2))
   4504        (setq sub3 (buffer-substring-no-properties block-beg (+ block-beg 2))
   4505              sub2 (buffer-substring-no-properties block-beg (+ block-beg 2))
   4506              sub1 (buffer-substring-no-properties block-beg (+ block-beg 1)))
   4507        )
   4508       (t
   4509        (setq sub1 (buffer-substring-no-properties block-beg (+ block-beg 1)))
   4510        (setq sub2 sub1
   4511              sub3 sub1)
   4512        )
   4513       )
   4514 
   4515     (cond
   4516 
   4517       ((member web-mode-engine '("php" "lsp" "python" "web2py" "mason"))
   4518        (setq regexp web-mode-engine-token-regexp))
   4519 
   4520       ((string= web-mode-engine "mako")
   4521        (cond
   4522          ((string= sub2 "##")
   4523           (setq token-type 'comment)
   4524           )
   4525          (t
   4526           (setq regexp web-mode-engine-token-regexp))
   4527          )
   4528        ) ;mako
   4529 
   4530       ((string= web-mode-engine "django")
   4531        (cond
   4532          ((member sub2 '("{{" "{%"))
   4533           (setq regexp "\"\\|'"))
   4534          ((string= sub2 "{#")
   4535           (setq token-type 'comment))
   4536          )
   4537        ) ;django
   4538 
   4539       ((string= web-mode-engine "ctemplate")
   4540        (cond
   4541          ((string= sub3 "{{!")
   4542           (setq token-type 'comment))
   4543          ((member sub2 '("{{"))
   4544           )
   4545          )
   4546        ) ;ctemplate
   4547 
   4548       ((string= web-mode-engine "antlers")
   4549        (cond
   4550          ((string= sub3 "{{#")
   4551           (setq token-type 'comment))
   4552          ((member sub2 '("{{"))
   4553           )
   4554          )
   4555        ) ;antlers
   4556 
   4557       ((string= web-mode-engine "astro")
   4558        (setq regexp "\"\\|'")
   4559        ) ;astro
   4560 
   4561       ((string= web-mode-engine "go")
   4562        (cond
   4563          ((string= sub3 "{{/")
   4564           (setq token-type 'comment))
   4565          ((string= sub2 "{{")
   4566           (setq regexp "\"\\|'"))
   4567          )
   4568        ) ;go
   4569 
   4570       ((string= web-mode-engine "hero")
   4571        (cond
   4572          ((string= sub3 "<%#")
   4573           (setq token-type 'comment))
   4574          (t
   4575           (setq regexp "\"\\|'"))
   4576          )
   4577        ) ;hero
   4578 
   4579       ((string= web-mode-engine "razor")
   4580        (cond
   4581          ((string= sub2 "@*")
   4582           (setq token-type 'comment))
   4583          (t
   4584           (setq regexp "//\\|@\\*\\|\"\\|'"))
   4585          )
   4586        ) ;razor
   4587 
   4588       ((string= web-mode-engine "blade")
   4589        (cond
   4590          ((string= sub3 "{{-")
   4591           (setq token-type 'comment))
   4592          (t
   4593           (setq regexp "\"\\|'"))
   4594          )
   4595        ) ;blade
   4596 
   4597       ((string= web-mode-engine "cl-emb")
   4598        (cond
   4599          ((string= sub3 "<%#")
   4600           (setq token-type 'comment))
   4601          (t
   4602           (setq regexp "\"\\|'"))
   4603          )
   4604        ) ;cl-emb
   4605 
   4606       ((string= web-mode-engine "artanis")
   4607        (cond
   4608          ((string= sub3 "<%;")
   4609           (setq token-type 'comment))
   4610          ((string= sub3 "<%#|")
   4611           (setq token-type 'comment))
   4612          (t
   4613           (setq regexp "\""))
   4614          )
   4615        ) ;artanis
   4616 
   4617       ((string= web-mode-engine "elixir")
   4618        (cond
   4619          ((string= sub3 "<%#")
   4620           (setq token-type 'comment))
   4621          (t
   4622           (setq regexp "\"\\|'"))
   4623          )
   4624        ) ;elixir
   4625 
   4626       ((string= web-mode-engine "mojolicious")
   4627        (cond
   4628          ((or (string= sub2 "%#") (string= sub3 "<%#"))
   4629           (setq token-type 'comment))
   4630          (t
   4631           (setq regexp "\"\\|'"))
   4632          )
   4633        ) ;mojolicious
   4634 
   4635       ((string= web-mode-engine "velocity")
   4636        (cond
   4637          ((member sub2 '("##" "#*"))
   4638           (setq token-type 'comment))
   4639          ((member sub1 '("$" "#"))
   4640           (setq regexp "\"\\|'"))
   4641          )
   4642        ) ;velocity
   4643 
   4644       ((string= web-mode-engine "jsp")
   4645        (cond
   4646          ((string= sub3 "<%-")
   4647           (setq token-type 'comment))
   4648          ((string= sub3 "<%@")
   4649           (setq regexp "/\\*"))
   4650          ((member sub2 '("${" "#{"))
   4651           (setq regexp "\"\\|'"))
   4652          ((string= sub2 "<%")
   4653           (setq regexp "//\\|/\\*\\|\"\\|'"))
   4654          )
   4655        ) ;jsp
   4656 
   4657       ((string= web-mode-engine "clip")
   4658        (setq regexp nil)
   4659        ) ;clip
   4660 
   4661       ((string= web-mode-engine "perl")
   4662        (setq regexp nil)
   4663        ) ;perl
   4664 
   4665       ((and (string= web-mode-engine "asp")
   4666             (string= sub2 "<%"))
   4667        (setq regexp "//\\|/\\*\\|\"\\|'")
   4668        ) ;asp
   4669 
   4670       ((string= web-mode-engine "aspx")
   4671        (cond
   4672          ((string= sub3 "<%-")
   4673           (setq token-type 'comment))
   4674          ((string= sub3 "<%@")
   4675           (setq regexp "/\\*"))
   4676          ((string= sub3 "<%$")
   4677           (setq regexp "\"\\|'"))
   4678          (t
   4679           (setq regexp "//\\|/\\*\\|\"\\|'"))
   4680          )
   4681        ) ;aspx
   4682 
   4683       ((string= web-mode-engine "freemarker")
   4684        (cond
   4685          ((member sub3 '("<#-" "[#-"))
   4686           (setq token-type 'comment))
   4687          ((member sub2 '("${" "#{"))
   4688           (setq regexp "\"\\|'"))
   4689          ((or (member sub2 '("<@" "[@" "<#" "[#"))
   4690               (member sub3 '("</@" "[/@" "</#" "[/#")))
   4691           (setq regexp "\"\\|'"))
   4692          )
   4693        ) ;freemarker
   4694 
   4695       ((member web-mode-engine '("ejs" "erb"))
   4696        (cond
   4697          ((string= sub3 "<%#")
   4698           (setq token-type 'comment))
   4699          (t
   4700           (setq regexp web-mode-engine-token-regexp))
   4701          )
   4702        ) ;erb
   4703 
   4704       ((string= web-mode-engine "template-toolkit")
   4705        (cond
   4706          ((member sub3 '("[%#" "%%#"))
   4707           (setq token-type 'comment))
   4708          (t
   4709           (setq regexp "#\\|\"\\|'"))
   4710          )
   4711        ) ;template-toolkit
   4712 
   4713       ((string= web-mode-engine "underscore")
   4714        (setq regexp "/\\*\\|\"\\|'")
   4715        ) ;underscore
   4716 
   4717       ((string= web-mode-engine "angular")
   4718        (setq regexp "#\\|\"\\|'")) ;angular
   4719 
   4720       ((string= web-mode-engine "vue")
   4721        ) ;vue
   4722 
   4723       ((string= web-mode-engine "smarty")
   4724        (cond
   4725          ((string= sub2 "{*")
   4726           (setq token-type 'comment))
   4727          (t
   4728           (setq regexp "\"\\|'")))
   4729        ) ;smarty
   4730 
   4731       ((string= web-mode-engine "xoops")
   4732        (cond
   4733          ((string= sub3 "<{*")
   4734           (setq token-type 'comment))
   4735          (t
   4736           (setq regexp "\"\\|'")))
   4737        ) ;xoops
   4738 
   4739       ((string= web-mode-engine "spip")
   4740        (if (string= (buffer-substring-no-properties
   4741                      block-beg (+ block-beg 7))
   4742                     "[(#REM)")
   4743            (setq token-type 'comment
   4744                  regexp "\\]")))
   4745 
   4746       ((string= web-mode-engine "dust")
   4747        (cond
   4748          ((string= sub2 "{!")
   4749           (setq token-type 'comment))
   4750          (t
   4751           (setq regexp "\"\\|'"))
   4752          )
   4753        ) ;dust
   4754 
   4755       ((string= web-mode-engine "expressionengine")
   4756        (cond
   4757          ((string= sub2 "{!")
   4758           (setq token-type 'comment))
   4759          (t
   4760           (setq regexp "\"\\|'")))
   4761        ) ;expressionengine
   4762 
   4763       ((string= web-mode-engine "closure")
   4764        (cond
   4765          ((member sub2 '("/*" "//"))
   4766           (setq token-type 'comment))
   4767          (t
   4768           (setq regexp "\"\\|'"))
   4769          )
   4770        ) ;closure
   4771 
   4772       ((string= web-mode-engine "svelte")
   4773        ) ;svelte
   4774 
   4775       ) ;cond
   4776 
   4777     (cond
   4778       (token-type
   4779        (put-text-property block-beg block-end 'block-token token-type))
   4780       ((and regexp
   4781             (> (- block-end block-beg) 6))
   4782        (web-mode-block-tokenize
   4783         (web-mode-block-code-beginning-position block-beg)
   4784         (web-mode-block-code-end-position block-beg)
   4785         regexp)
   4786        )
   4787       ) ;cond
   4788 
   4789     ))
   4790 
   4791 (defun web-mode-block-tokenize (reg-beg reg-end &optional regexp)
   4792   (unless regexp (setq regexp web-mode-engine-token-regexp))
   4793   ;;(message "tokenize: reg-beg(%S) reg-end(%S) regexp(%S)" reg-beg reg-end regexp)
   4794   ;;(message "tokenize: reg-beg(%S) reg-end(%S) command(%S)" reg-beg reg-end this-command)
   4795   ;;(message "%S>%S : %S" reg-beg reg-end (buffer-substring-no-properties reg-beg reg-end))
   4796   (save-excursion
   4797     (let ((pos reg-beg) beg char match continue token-type token-end)
   4798 
   4799       (remove-list-of-text-properties reg-beg reg-end '(block-token))
   4800 
   4801       ;; TODO : vérifier la cohérence
   4802       (put-text-property reg-beg reg-end 'block-side t)
   4803 
   4804       (goto-char reg-beg)
   4805 
   4806       (when (> (point) reg-end)
   4807         (message "block-tokenize ** reg-beg(%S) > reg-end(%S) **" reg-beg reg-end))
   4808 
   4809       (while (and (< (point) reg-end) (re-search-forward regexp reg-end t))
   4810         (setq beg (match-beginning 0)
   4811               match (match-string 0)
   4812               continue t
   4813               token-type 'comment
   4814               token-end (if (< reg-end (line-end-position)) reg-end (line-end-position))
   4815               char (aref match 0))
   4816         (cond
   4817 
   4818           ((and (string= web-mode-engine "asp") (string= match "'"))
   4819            (goto-char token-end))
   4820 
   4821           ((and (string= web-mode-engine "razor") (eq char ?\'))
   4822            (cond
   4823              ((looking-at-p "\\(.\\|[\\][bfntr]\\|[\\]u....\\)'")
   4824               (search-forward "'" reg-end t)
   4825               (setq token-type 'string)
   4826               )
   4827              (t
   4828               (re-search-forward "[[:alnum:]_-]+")
   4829               (setq token-type 'symbol)
   4830               )))
   4831 
   4832           ((eq char ?\')
   4833            (setq token-type 'string)
   4834            (while (and continue (search-forward "'" reg-end t))
   4835              (setq continue (web-mode-string-continue-p reg-beg))
   4836              ))
   4837 
   4838           ((eq char ?\")
   4839            (setq token-type 'string)
   4840            (while (and continue (search-forward "\"" reg-end t))
   4841              (setq continue (web-mode-string-continue-p reg-beg))
   4842              ))
   4843 
   4844           ((string= match "//")
   4845            (goto-char token-end))
   4846 
   4847           ((eq char ?\;)
   4848            (goto-char token-end))
   4849 
   4850           ((string= match "#|")
   4851            (unless (search-forward "|#" reg-end t)
   4852              (goto-char token-end)))
   4853 
   4854           ((eq char ?\#)
   4855            (goto-char token-end))
   4856 
   4857           ((string= match "/*")
   4858            (unless (search-forward "*/" reg-end t)
   4859              (goto-char token-end))
   4860            )
   4861 
   4862           ((string= match "@*")
   4863            (unless (search-forward "*@" reg-end t)
   4864              (goto-char token-end)))
   4865 
   4866           ((eq char ?\<)
   4867            (setq token-type 'string)
   4868            (re-search-forward (concat "^[ ]*" (match-string 1)) reg-end t))
   4869 
   4870           (t
   4871            (message "block-tokenize ** token end (%S) **" beg)
   4872            (setq token-type nil))
   4873 
   4874           ) ;cond
   4875 
   4876         (put-text-property beg (point) 'block-token token-type)
   4877 
   4878         (when (eq token-type 'comment)
   4879           (put-text-property beg (1+ beg) 'syntax-table (string-to-syntax "<"))
   4880           (if (or (< (point) (line-end-position)) (= (point) (point-max)))
   4881               (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax ">")) ;#445 #480
   4882               (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax ">")) ;#377
   4883               )
   4884           )
   4885 
   4886         ) ;while
   4887 
   4888       (web-mode-block-controls-unset pos)
   4889 
   4890       )))
   4891 
   4892 (defun web-mode-set-php-controls (reg-beg reg-end)
   4893   (goto-char reg-beg)
   4894   (let (match controls
   4895               (continue t)
   4896               (regexp "endif\\|endforeach\\|endfor\\|endwhile\\|elseif\\|else\\|if\\|foreach\\|for\\|while"))
   4897     (while continue
   4898       (if (not (web-mode-block-rsf regexp reg-end))
   4899           (setq continue nil)
   4900           (setq match (match-string-no-properties 0))
   4901           ;;        (message "%S %S" match (point))
   4902           (cond
   4903             ((and (member match '("else" "elseif"))
   4904                   (looking-at-p "[ ]*[:(]"))
   4905              (setq controls (append controls (list (cons 'inside "if"))))
   4906              )
   4907             ((and (>= (length match) 3)
   4908                   (string= (substring match 0 3) "end"))
   4909              (setq controls (append controls (list (cons 'close (substring match 3)))))
   4910              )
   4911             ((and (progn (skip-chars-forward "[ ]") t)
   4912                   (eq (char-after) ?\()
   4913                   (web-mode-closing-paren reg-end)
   4914                   ;;(progn (message "ixi%S" (point)))
   4915                   (looking-at-p ")[ ]*:"))
   4916              (setq controls (append controls (list (cons 'open match))))
   4917              )
   4918             ) ;cond
   4919           ) ;if
   4920       ) ;while
   4921     ;;(message "%S-%S %S" reg-beg reg-end controls)
   4922     (when (and controls (> (length controls) 1))
   4923       (setq controls (web-mode-block-controls-reduce controls)))
   4924     controls))
   4925 
   4926 (defun web-mode-block-controls-reduce (controls)
   4927   (when (and (eq (car (car controls)) 'open)
   4928              (member (cons 'close (cdr (car controls))) controls))
   4929     (setq controls nil))
   4930   controls)
   4931 
   4932 (defun web-mode-block-controls-unset (pos)
   4933   (cond
   4934     ((null (get-text-property pos 'block-side))
   4935      (message "block-controls-unset ** invalid value (%S) **" pos))
   4936     ((or (get-text-property pos 'block-beg)
   4937          (setq pos (web-mode-block-beginning-position pos)))
   4938      (put-text-property pos (1+ pos) 'block-controls 0))
   4939     (t
   4940      (message "block-controls-unset ** failure (%S) **" (point)))
   4941     ))
   4942 
   4943 (defun web-mode-block-controls-get (pos)
   4944   (web-mode-with-silent-modifications
   4945    (let ((controls nil))
   4946      (cond
   4947        ((null (get-text-property pos 'block-side))
   4948         (message "block-controls-get ** invalid value (%S) **" pos))
   4949        ((or (get-text-property pos 'block-beg)
   4950             (setq pos (web-mode-block-beginning-position pos)))
   4951         (setq controls (get-text-property pos 'block-controls))
   4952         (when (integerp controls)
   4953           (web-mode-block-controls-set pos (web-mode-block-end-position pos))
   4954           (setq controls (get-text-property pos 'block-controls))
   4955           )
   4956         )
   4957        (t
   4958         (message "block-controls-get ** failure (%S) **" (point)))
   4959        ) ;cond
   4960      controls)))
   4961 
   4962 (defun web-mode-block-controls-set (reg-beg reg-end)
   4963   (save-excursion
   4964     (goto-char reg-beg)
   4965     (let (controls pos type control)
   4966 
   4967       (cond
   4968 
   4969         ((null web-mode-engine)
   4970          (message "block-controls-set ** unknown engine (%S) **" web-mode-engine)
   4971          )
   4972 
   4973         ((string= web-mode-engine "php")
   4974          (setq controls (web-mode-set-php-controls reg-beg reg-end))
   4975          (when (web-mode-block-starts-with "}" reg-beg)
   4976            (setq controls (append controls (list (cons 'close "{")))))
   4977          (when (web-mode-block-ends-with (cons "{" "}") reg-beg)
   4978            (setq controls (append controls (list (cons 'open "{")))))
   4979          ) ;php
   4980 
   4981         ((string= web-mode-engine "ejs")
   4982          (cond
   4983            ((web-mode-block-ends-with "}[ ]*else[ ]*{" reg-beg)
   4984             (setq controls (append controls (list (cons 'inside "{")))))
   4985            ((web-mode-block-starts-with "}" reg-beg)
   4986             (setq controls (append controls (list (cons 'close "{")))))
   4987            ((web-mode-block-ends-with "{" reg-beg)
   4988             (setq controls (append controls (list (cons 'open "{")))))
   4989            )
   4990          ) ;ejs
   4991 
   4992         ((string= web-mode-engine "erb")
   4993          (cond
   4994            ((web-mode-block-starts-with "else\\|elsif\\|when" reg-beg)
   4995             (setq controls (append controls (list (cons 'inside "ctrl")))))
   4996            ((web-mode-block-starts-with "end" reg-beg)
   4997             (setq controls (append controls (list (cons 'close "ctrl")))))
   4998            ((web-mode-block-ends-with " do\\( |.*|\\)?" reg-beg)
   4999             (setq controls (append controls (list (cons 'open "ctrl")))))
   5000            ((and (web-mode-block-starts-with "\\(for\\|if\\|unless\\|case\\)\\_>" reg-beg)
   5001                  (not (web-mode-block-ends-with "end" reg-end)))
   5002             (setq controls (append controls (list (cons 'open "ctrl")))))
   5003            )
   5004          ) ;erb
   5005 
   5006         ((string= web-mode-engine "django")
   5007          (cond
   5008            ((and (string= web-mode-minor-engine "jinja") ;#504
   5009                  (web-mode-block-starts-with "else\\_>" reg-beg))
   5010             (let ((continue t)
   5011                   (pos reg-beg)
   5012                   (ctrl nil))
   5013               (while continue
   5014                 (cond
   5015                   ((null (setq pos (web-mode-block-control-previous-position 'open pos)))
   5016                    (setq continue nil))
   5017                   ((member (setq ctrl (cdr (car (get-text-property pos 'block-controls)))) '("if" "ifequal" "ifnotequal" "for"))
   5018                    (setq continue nil)
   5019                    )
   5020                   ) ;cond
   5021                 )
   5022               (setq controls (append controls (list (cons 'inside (or ctrl "if")))))
   5023               )
   5024             )
   5025            ((web-mode-block-starts-with "form_start[ ]*(" reg-beg)
   5026             (setq controls (append controls (list (cons 'open "form_start")))))
   5027            ((web-mode-block-starts-with "form_end[ ]*(" reg-beg)
   5028             (setq controls (append controls (list (cons 'close "form_start")))))
   5029            ((not (eq (char-after (1+ reg-beg)) ?\%))
   5030             )
   5031            ((web-mode-block-starts-with "\\(else\\|els?if\\)" reg-beg)
   5032             (let ((continue t)
   5033                   (pos reg-beg)
   5034                   (ctrl nil))
   5035               (while continue
   5036                 (cond
   5037                   ((null (setq pos (web-mode-block-control-previous-position 'open pos)))
   5038                    (setq continue nil))
   5039                   ((member (setq ctrl (cdr (car (get-text-property pos 'block-controls)))) '("if" "ifequal" "ifnotequal"))
   5040                    (setq continue nil)
   5041                    )
   5042                   ) ;cond
   5043                 ) ;while
   5044               (setq controls (append controls (list (cons 'inside (or ctrl "if")))))
   5045               ) ;let
   5046             ) ;case else
   5047            ((web-mode-block-starts-with "\\(empty\\)" reg-beg)
   5048             (setq controls (append controls (list (cons 'inside "for")))))
   5049            ((web-mode-block-starts-with "end\\([[:alpha:]]+\\)" reg-beg)
   5050             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5051            ((web-mode-block-starts-with "set [[:alpha:]]+[ ]*%}" reg-beg)
   5052             (setq controls (append controls (list (cons 'open "set")))))
   5053            ((web-mode-block-starts-with (concat web-mode-django-control-blocks-regexp "[ %]") reg-beg)
   5054             (let (control)
   5055               (setq control (match-string-no-properties 1))
   5056               ;;(message "%S %S %S" control (concat "end" control) web-mode-django-control-blocks)
   5057               (when (member (concat "end" control) web-mode-django-control-blocks)
   5058                 (setq controls (append controls (list (cons 'open control))))
   5059                 ) ;when
   5060               ) ;let
   5061             ) ;case
   5062            ) ;cond
   5063          ) ;django
   5064 
   5065         ((string= web-mode-engine "smarty")
   5066          (cond
   5067            ((and (eq (char-after (1+ reg-beg)) ?\/)
   5068                  (web-mode-block-starts-with "\\([[:alpha:]]+\\)" reg-beg))
   5069             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5070            ((web-mode-block-starts-with "\\(else\\|elseif\\)" reg-beg)
   5071             (setq controls (append controls (list (cons 'inside "if")))))
   5072            ((web-mode-block-starts-with "\\(block\\|foreach\\|for\\|if\\|section\\|while\\)")
   5073             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5074            )
   5075          ) ;smarty
   5076 
   5077         ((string= web-mode-engine "expressionengine")
   5078          (cond
   5079            ((and (eq (char-after (1+ reg-beg)) ?\/)
   5080                  (web-mode-block-starts-with "\\(if\\)" reg-beg))
   5081             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5082            ((web-mode-block-starts-with "\\(if:else\\|if:ifelse\\)" reg-beg)
   5083             (setq controls (append controls (list (cons 'inside "if")))))
   5084            ((web-mode-block-starts-with "\\(if\\)")
   5085             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5086            )
   5087          ) ;expressionengine
   5088 
   5089         ((string= web-mode-engine "xoops")
   5090          (cond
   5091            ((and (eq (char-after (+ reg-beg 2)) ?\/)
   5092                  (web-mode-block-starts-with "\\([[:alpha:]]+\\)" reg-beg))
   5093             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5094            ((web-mode-block-starts-with "\\(else\\|elseif\\)" reg-beg)
   5095             (setq controls (append controls (list (cons 'inside "if")))))
   5096            ((web-mode-block-starts-with "\\(block\\|foreach\\|for\\|if\\|section\\|while\\)")
   5097             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5098            )
   5099          ) ;xoops
   5100 
   5101         ((string= web-mode-engine "web2py")
   5102          (cond
   5103            ((web-mode-block-starts-with "def" reg-beg)
   5104             (setq controls (append controls (list (cons 'open "def")))))
   5105            ((web-mode-block-starts-with "return" reg-beg)
   5106             (setq controls (append controls (list (cons 'close "def")))))
   5107            ((web-mode-block-starts-with "block" reg-beg)
   5108             (setq controls (append controls (list (cons 'open "block")))))
   5109            ((web-mode-block-starts-with "end" reg-beg)
   5110             (setq controls (append controls (list (cons 'close "block")))))
   5111            ((web-mode-block-starts-with "pass" reg-beg)
   5112             (setq controls (append controls (list (cons 'close "ctrl")))))
   5113            ((web-mode-block-starts-with "\\(except\\|finally\\|els\\)" reg-beg)
   5114             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5115            ((web-mode-block-starts-with "\\(if\\|for\\|try\\|while\\)")
   5116             (setq controls (append controls (list (cons 'open "ctrl")))))
   5117            )
   5118          ) ;web2py
   5119 
   5120         ((string= web-mode-engine "dust")
   5121          (cond
   5122            ((eq (char-after (1- reg-end)) ?\/)
   5123             )
   5124            ((eq (char-after (1+ reg-beg)) ?\:)
   5125             (setq pos (web-mode-block-control-previous-position 'open reg-beg))
   5126             (when pos
   5127               (setq controls (append controls
   5128                                      (list
   5129                                       (cons 'inside
   5130                                             (cdr (car (web-mode-block-controls-get pos))))))))
   5131             )
   5132            ((looking-at "{/\\([[:alpha:].]+\\)")
   5133             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5134            ((looking-at "{[#?@><+^]\\([[:alpha:].]+\\)")
   5135             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5136            )
   5137          ) ;dust
   5138 
   5139         ((string= web-mode-engine "anki")
   5140          (cond
   5141            ((looking-at "{{[#^]\\([[:alpha:].]+\\)")
   5142             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5143            ((looking-at "{{/\\([[:alpha:].]+\\)")
   5144             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5145            )
   5146          ) ;anki
   5147 
   5148         ((member web-mode-engine '("mojolicious"))
   5149          (cond
   5150            ((web-mode-block-ends-with "begin" reg-beg)
   5151             (setq controls (append controls (list (cons 'open "begin")))))
   5152            ((web-mode-block-starts-with "end" reg-beg)
   5153             (setq controls (append controls (list (cons 'close "begin")))))
   5154            ((web-mode-block-starts-with "}[ ]*else[ ]*{" reg-beg)
   5155             (setq controls (append controls (list (cons 'inside "{")))))
   5156            ((web-mode-block-starts-with "}" reg-beg)
   5157             (setq controls (append controls (list (cons 'close "{")))))
   5158            ((web-mode-block-ends-with "{" reg-beg)
   5159             (setq controls (append controls (list (cons 'open "{")))))
   5160            )
   5161          ) ;mojolicious
   5162 
   5163         ((member web-mode-engine '("aspx" "underscore"))
   5164          (cond
   5165            ((and (web-mode-block-starts-with "}" reg-beg)
   5166                  (web-mode-block-ends-with "{" reg-beg))
   5167             (setq controls (append controls (list (cons 'inside "{")))))
   5168            ((web-mode-block-starts-with "}" reg-beg)
   5169             (setq controls (append controls (list (cons 'close "{")))))
   5170            ((web-mode-block-ends-with "{" reg-beg)
   5171             (setq controls (append controls (list (cons 'open "{")))))
   5172            )
   5173          ) ;aspx underscore
   5174 
   5175         ((member web-mode-engine '("jsp" "asp" "clip" "perl"))
   5176          (cond
   5177            ((eq (char-after (1- reg-end)) ?\/)
   5178             )
   5179            ((looking-at "<TMPL_ELSE")
   5180             (setq controls (append controls (list (cons 'inside "TMPL_IF")))))
   5181            ((looking-at "</?\\([[:alpha:]]+\\(?:[:.][[:alpha:]]+\\)\\|[[:alpha:]]+Template\\|TMPL_[[:alpha:]]+\\)")
   5182             (setq control (match-string-no-properties 1)
   5183                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5184             (when (not (member control '("h:inputtext" "jsp:usebean" "jsp:forward" "struts:property")))
   5185               (setq controls (append controls (list (cons type control)))))
   5186             )
   5187            (t
   5188             (when (web-mode-block-starts-with "}" reg-beg)
   5189               (setq controls (append controls (list (cons 'close "{")))))
   5190             (when (web-mode-block-ends-with "{" reg-beg)
   5191               (setq controls (append controls (list (cons 'open "{")))))
   5192             )
   5193            )
   5194          ) ;jsp asp
   5195 
   5196         ((string= web-mode-engine "mako")
   5197          (cond
   5198            ((looking-at "</?%\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)")
   5199             (cond
   5200               ((eq (char-after (- (web-mode-block-end-position reg-beg) 1)) ?\/)
   5201                )
   5202               (t
   5203                (setq control (match-string-no-properties 1)
   5204                      type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5205                (setq controls (append controls (list (cons type control)))))
   5206               )
   5207             )
   5208            ((web-mode-block-starts-with "\\(else\\|elif\\)" reg-beg)
   5209             (setq controls (append controls (list (cons 'inside "if")))))
   5210            ((web-mode-block-starts-with "end\\(if\\|for\\)" reg-beg)
   5211             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5212            ((and (web-mode-block-starts-with "if\\|for" reg-beg)
   5213                  (web-mode-block-ends-with ":" reg-beg))
   5214             (setq controls (append controls (list (cons 'open (match-string-no-properties 0))))))
   5215            )
   5216          ) ;mako
   5217 
   5218         ((string= web-mode-engine "mason")
   5219          (cond
   5220            ((looking-at "</?%\\(after\\|around\\|augment\\|before\\|def\\|filter\\|method\\|override\\)")
   5221             (setq control (match-string-no-properties 1)
   5222                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5223             (setq controls (append controls (list (cons type control))))
   5224             )
   5225            )
   5226          ) ;mason
   5227 
   5228         ((string= web-mode-engine "ctemplate")
   5229          (cond
   5230            ((looking-at-p "{{else") ;#721
   5231             (let ((continue t)
   5232                   (pos reg-beg)
   5233                   (ctrl nil))
   5234               (while continue
   5235                 (cond
   5236                   ((null (setq pos (web-mode-block-control-previous-position 'open pos)))
   5237                    (setq continue nil))
   5238                   ((member (setq ctrl (cdr (car (get-text-property pos 'block-controls)))) '("if" "each"))
   5239                    (setq continue nil)
   5240                    )
   5241                   ) ;cond
   5242                 ) ;while
   5243               (setq controls (append controls (list (cons 'inside (or ctrl "if")))))
   5244               )
   5245             )
   5246 
   5247            ((looking-at "{{[#^/][ ]*\\([[:alpha:]_.-]+\\)")
   5248             (setq control (match-string-no-properties 1)
   5249                   type (if (eq (aref (match-string-no-properties 0) 2) ?\/) 'close 'open))
   5250             (setq controls (append controls (list (cons type control))))
   5251             )
   5252            )
   5253          ) ;ctemplate
   5254 
   5255         ((string= web-mode-engine "antlers")
   5256          (cond
   5257            ((web-mode-block-starts-with "\\(else\\|elseif\\)" reg-beg)
   5258             (setq controls (append controls (list (cons 'inside "if")))))
   5259            ((looking-at  "{{[ ]*/?\\(if\\|unless\\)")
   5260             (setq control (match-string-no-properties 1)
   5261                   type (if (eq (aref (match-string-no-properties 0) 3) ?\/) 'close 'open))
   5262             (setq controls (append controls (list (cons type control))))
   5263             )
   5264            )
   5265          ) ;antlers
   5266 
   5267         ((string= web-mode-engine "blade")
   5268          (cond
   5269            ((not (eq (char-after) ?\@))
   5270             )
   5271            ((web-mode-block-starts-with
   5272              "section\(\s*\\(['\"]\\).*\\1\s*,\s*\\(['\"]\\).*\\2\s*\)" reg-beg)
   5273             )
   5274            ((web-mode-block-starts-with "case\\|break" reg-beg)
   5275             (setq type (if (eq (aref (match-string-no-properties 0) 0) ?b) 'close 'open))
   5276             (setq controls (append controls (list (cons type "case"))))
   5277             )
   5278            ((web-mode-block-starts-with
   5279              (concat "\\(?:end\\)?\\(" web-mode-blade-control-blocks-regexp "\\)")
   5280              reg-beg)
   5281             (setq control (match-string-no-properties 1)
   5282                   type (if (eq (aref (match-string-no-properties 0) 0) ?e) 'close 'open))
   5283             (setq controls (append controls (list (cons type control))))
   5284             )
   5285            ((web-mode-block-starts-with "stop\\|show\\|overwrite" reg-beg)
   5286             (setq controls (append controls (list (cons 'close "section")))))
   5287            ((web-mode-block-starts-with "else\\|elseif" reg-beg)
   5288             (setq controls (append controls (list (cons 'inside "if")))))
   5289            ((web-mode-block-starts-with "empty" reg-beg)
   5290             (setq controls (append controls (list (cons 'inside "forelse")))))
   5291            )
   5292          ) ;blade
   5293 
   5294         ((string= web-mode-engine "closure")
   5295          (cond
   5296            ((eq (char-after (1- reg-end)) ?\/)
   5297             )
   5298            ((looking-at "alias\\|namespace")
   5299             )
   5300            ((web-mode-block-starts-with "ifempty" reg-beg)
   5301             (setq controls (append controls (list (cons 'inside "foreach")))))
   5302            ((web-mode-block-starts-with "else\\|elseif" reg-beg)
   5303             (setq controls (append controls (list (cons 'inside "if")))))
   5304            ((web-mode-block-starts-with "case\\|default" reg-beg)
   5305             (setq controls (append controls (list (cons 'inside "switch")))))
   5306            ((looking-at
   5307              "{/?\\(call\\|deltemplate\\|for\\|foreach\\|if\\|let\\|literal\\|msg\\|param\\|switch\\|template\\)")
   5308             (setq control (match-string-no-properties 1)
   5309                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5310             (setq controls (append controls (list (cons type control))))
   5311             )
   5312            )
   5313          ) ;closure
   5314 
   5315         ((string= web-mode-engine "go")
   5316          (cond
   5317            ((web-mode-block-starts-with "end\\_>" reg-beg)
   5318             (setq controls (append controls (list (cons 'close "ctrl")))))
   5319            ((web-mode-block-starts-with "else\\_>" reg-beg)
   5320             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5321            ((web-mode-block-starts-with "\\(range\\|with\\|if\\|define\\|block\\)\\_>" reg-beg)
   5322             (setq controls (append controls (list (cons 'open "ctrl")))))
   5323            )
   5324          ) ;go
   5325 
   5326         ((string= web-mode-engine "template-toolkit")
   5327          (cond
   5328            ((web-mode-block-starts-with "end" reg-beg)
   5329             (setq controls (append controls (list (cons 'close "ctrl")))))
   5330            ((web-mode-block-starts-with "els\\|catch\\|final" reg-beg)
   5331             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5332            ((web-mode-block-starts-with "filter\\|foreach\\|if\\|last\\|next\\|perl\\|rawperl\\|try\\|unless\\|while" reg-beg)
   5333             (setq controls (append controls (list (cons 'open "ctrl")))))
   5334            )
   5335          ) ;template-toolkit
   5336 
   5337         ((string= web-mode-engine "cl-emb")
   5338          (cond
   5339            ((web-mode-block-starts-with "@else" reg-beg)
   5340             (setq controls (append controls (list (cons 'inside "if")))))
   5341            ((web-mode-block-starts-with "@\\(?:end\\)?\\(if\\|unless\\|repeat\\|loop\\|with\\|genloop\\)" reg-beg)
   5342             (setq control (match-string-no-properties 1)
   5343                   type (if (eq (aref (match-string-no-properties 0) 1) ?e) 'close 'open))
   5344             (setq controls (append controls (list (cons type control)))))
   5345            )
   5346          ) ;cl-emb
   5347 
   5348         ((string= web-mode-engine "elixir")
   5349          (cond
   5350            ((web-mode-block-starts-with "end" reg-beg)
   5351             (setq controls (append controls (list (cons 'close "ctrl")))))
   5352            ((web-mode-block-starts-with "else" reg-beg)
   5353             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5354            ((web-mode-block-ends-with " do" reg-beg)
   5355             (setq controls (append controls (list (cons 'open "ctrl")))))
   5356            ((web-mode-block-ends-with " ->" reg-beg)
   5357             (setq controls (append controls (list (cons 'open "ctrl")))))
   5358            )
   5359          ) ;elixir
   5360 
   5361         ((string= web-mode-engine "velocity")
   5362          (cond
   5363            ((web-mode-block-starts-with "{?end" reg-beg)
   5364             (setq controls (append controls (list (cons 'close "ctrl")))))
   5365            ((web-mode-block-starts-with "{?els" reg-beg)
   5366             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5367            ((web-mode-block-starts-with "{?\\(def\\|if\\|for\\|foreach\\|macro\\)" reg-beg)
   5368             ;;((web-mode-block-starts-with "{?\\(define\\|\\|if\\|for\\|foreach\\|macro\\)" reg-beg)
   5369             (setq controls (append controls (list (cons 'open "ctrl")))))
   5370            )
   5371          ) ;velocity
   5372 
   5373         ((string= web-mode-engine "freemarker")
   5374          (cond
   5375            ((looking-at "[<[]#\\(import\\|include\\|assign\\|return\\|local\\)")
   5376             )
   5377            ((eq (char-after (1- reg-end)) ?\/)
   5378             )
   5379            ((looking-at "[<[]#\\(break\\|case\\|default\\)")
   5380             (setq controls (append controls (list (cons 'inside "switch"))))
   5381             )
   5382            ((looking-at "[<[]#els")
   5383             (setq controls (append controls (list (cons 'inside "if"))))
   5384             )
   5385            ((looking-at "</?\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)")
   5386             (setq control (match-string-no-properties 1)
   5387                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5388             (setq controls (append controls (list (cons type control))))
   5389             )
   5390            ((looking-at "[<[]/?\\(@\\)")
   5391             (setq control (match-string-no-properties 1)
   5392                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5393             (setq controls (append controls (list (cons type control))))
   5394             )
   5395            ((looking-at "[<[]/?#\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)")
   5396             (setq control (match-string-no-properties 1)
   5397                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5398             (setq controls (append controls (list (cons type control))))
   5399             )
   5400            (t
   5401             (when (web-mode-block-starts-with "}" reg-beg)
   5402               (setq controls (append controls (list (cons 'close "{")))))
   5403             (when (web-mode-block-ends-with "{" reg-beg)
   5404               (setq controls (append controls (list (cons 'open "{")))))
   5405             )
   5406            )
   5407          ) ;freemarker
   5408 
   5409         ((string= web-mode-engine "razor")
   5410          (when (web-mode-block-starts-with "}" reg-beg)
   5411            (setq controls (append controls (list (cons 'close "{")))))
   5412          (when (web-mode-block-ends-with "{" reg-beg)
   5413            (setq controls (append controls (list (cons 'open "{")))))
   5414          ) ;razor
   5415 
   5416         ((string= web-mode-engine "lsp")
   5417          (when (web-mode-block-starts-with ")" reg-beg)
   5418            (setq controls (append controls (list (cons 'close "(")))))
   5419          (when (web-mode-block-is-opened-sexp reg-beg reg-end)
   5420            (setq controls (append controls (list (cons 'open "(")))))
   5421          ) ;lsp
   5422 
   5423         ((string= web-mode-engine "hero")
   5424          (cond
   5425            ((web-mode-block-ends-with "}[ ]*else[ ]*{" reg-beg)
   5426             (setq controls (append controls (list (cons 'inside "{")))))
   5427            ((web-mode-block-starts-with "}" reg-beg)
   5428             (setq controls (append controls (list (cons 'close "{")))))
   5429            ((web-mode-block-ends-with "{" reg-beg)
   5430             (setq controls (append controls (list (cons 'open "{")))))
   5431            )
   5432          ) ;hero
   5433 
   5434         ((string= web-mode-engine "svelte")
   5435          (cond
   5436            ((eq (char-after (1- reg-end)) ?\/)
   5437             )
   5438            ((eq (char-after (1+ reg-beg)) ?\:)
   5439             (setq pos (web-mode-block-control-previous-position 'open reg-beg))
   5440             (when pos
   5441               (setq controls (append controls
   5442                                      (list
   5443                                       (cons 'inside
   5444                                             (cdr (car (web-mode-block-controls-get pos))))))))
   5445             )
   5446            ((looking-at "{/\\([[:alpha:].]+\\)")
   5447             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5448            ((looking-at "{[#?><+^]\\([[:alpha:].]+\\)")
   5449             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5450            )
   5451          ) ;svelte
   5452 
   5453         ) ;cond engine
   5454 
   5455       (put-text-property reg-beg (1+ reg-beg) 'block-controls controls)
   5456       ;;(message "(%S) controls=%S" reg-beg controls)
   5457 
   5458       )))
   5459 
   5460 (defun web-mode-block-is-opened-sexp (reg-beg reg-end)
   5461   (let ((n 0))
   5462     (save-excursion
   5463       (goto-char reg-beg)
   5464       (while (web-mode-block-rsf "[()]" reg-end)
   5465         (if (eq (char-before) ?\() (setq n (1+ n)) (setq n (1- n)))))
   5466     (> n 0)))
   5467 
   5468 ;;---- LEXER PARTS -------------------------------------------------------------
   5469 
   5470 (defun web-mode-scan-elements (reg-beg reg-end)
   5471   (save-excursion
   5472     (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)
   5473       ;;(message "scan-elements: reg-beg(%S) reg-end(%S)" reg-beg reg-end)
   5474       (goto-char reg-beg)
   5475 
   5476       (while (web-mode-dom-rsf regexp reg-end)
   5477 
   5478         ;;(message "%S: %S (%S %S)" (point) (match-string-no-properties 0) reg-beg reg-end)
   5479 
   5480         (setq flags 0
   5481               tname (downcase (match-string-no-properties 1))
   5482               char (aref tname 0)
   5483               tbeg (match-beginning 0)
   5484               tend nil
   5485               element-content-type nil
   5486               limit reg-end
   5487               part-beg nil
   5488               part-end nil
   5489               props nil
   5490               close-expr nil
   5491               part-close-tag nil)
   5492 
   5493         ;;(message "tname[%S] tbeg(%S) point(%S)" tname tbeg (point))
   5494 
   5495         (cond
   5496 
   5497           ((member tname '("/>" ">")) ;;jsx fragment #952
   5498            (setq tname "_fragment_"
   5499                  tend (point))
   5500            (if (eq char ?\/)
   5501                (setq props (list 'tag-name tname 'tag-type 'end)
   5502                      flags (logior flags 20)) ;; 16 + 4
   5503                (setq props (list 'tag-name tname 'tag-type 'start)
   5504                      flags (logior flags 16))
   5505                ) ;if
   5506            )
   5507 
   5508           ((not (member char '(?\! ?\?)))
   5509            (cond
   5510              ((string-match-p "-" tname)
   5511               (setq flags (logior flags 2)))
   5512              ;;((string-match-p ":" tname)
   5513              ;; (setq flags (logior flags 32)))
   5514              ((string-match-p "[._:]" tname)
   5515               (setq flags (logior flags 32)))
   5516              )
   5517            (cond
   5518              ((eq char ?\/)
   5519               (setq props (list 'tag-name (substring tname 1) 'tag-type 'end)
   5520                     flags (logior flags 4)
   5521                     limit (if (> reg-end (line-end-position)) (line-end-position) reg-end))
   5522               )
   5523              ((web-mode-element-is-void tname)
   5524               ;;(message "void: tag=%S" tname)
   5525               (setq props (list 'tag-name tname 'tag-type 'void)))
   5526              (t
   5527               (setq props (list 'tag-name tname 'tag-type 'start)))
   5528              ) ;cond
   5529            ) ; not <! <?
   5530           ((and (eq char ?\!) (eq (aref tname 1) ?\-))
   5531            (setq close-expr "-->"
   5532                  props '(tag-type comment)))
   5533           ((string= tname "?xml")
   5534            (setq ;;regexp web-mode-tag-regexp2
   5535             close-expr "?>"
   5536             props '(tag-type declaration)))
   5537           ((string= tname "![cdata[")
   5538            (setq close-expr "]]>"
   5539                  props '(tag-type cdata)))
   5540           ((string= tname "!doctype")
   5541            (setq ;;regexp web-mode-tag-regexp2
   5542             props '(tag-type doctype)))
   5543           ) ;cond - special tags
   5544 
   5545         (cond
   5546 
   5547           (tend
   5548            )
   5549 
   5550           ((and (null close-expr) (eq (char-after) ?\>))
   5551            (setq flags (logior flags 16)
   5552                  tend (1+ (point)))
   5553            ;;(message "end=%S" tend)
   5554            )
   5555 
   5556           ((and (null close-expr)
   5557                 (looking-at "[ ]\\(class\\|id\\|href\\|style\\)=\"[[:alnum:]_=:/?;#. -]*\">"))
   5558            (let ((beg (1+ (point)))
   5559                  (end (+ (point) (length (match-string-no-properties 0)))))
   5560              (setq flags (logior flags 17)
   5561                    tend end)
   5562              (put-text-property beg (1+ beg) 'tag-attr-beg 0)
   5563              (put-text-property beg (1- end) 'tag-attr t)
   5564              (put-text-property (- end 2) (1- end) 'tag-attr-end (length (match-string-no-properties 1)))
   5565              ) ;let
   5566            )
   5567 
   5568           ((null close-expr)
   5569            (setq flags (logior flags (web-mode-attr-skip reg-end)))
   5570            (when (> (logand flags 8) 0)
   5571              (setq props (plist-put props 'tag-type 'void)))
   5572            (setq tend (point)))
   5573 
   5574           ((web-mode-dom-sf close-expr limit t)
   5575            (setq tend (point)))
   5576 
   5577           (t
   5578            (setq tend (line-end-position)))
   5579 
   5580           ) ;cond
   5581 
   5582         (cond
   5583           ((string= tname "style")
   5584            (let (style)
   5585              (setq style (buffer-substring-no-properties tbeg tend)
   5586                    part-close-tag "</style>")
   5587              (cond
   5588                ((string-match-p " lang[ ]*=[ ]*[\"']stylus" style)
   5589                 (setq element-content-type "stylus"))
   5590                ((string-match-p " lang[ ]*=[ ]*[\"']sass" style)
   5591                 (setq element-content-type "sass"))
   5592                (t
   5593                 (setq element-content-type "css"))
   5594                ) ;cond
   5595              ) ;let
   5596            ) ;style
   5597           ((string= tname "script")
   5598            (let (script)
   5599              (setq script (buffer-substring-no-properties tbeg tend)
   5600                    part-close-tag "</script>")
   5601              (cond
   5602                ((string-match-p " type[ ]*=[ ]*[\"']text/\\(jsx\\|babel\\)" script)
   5603                 (setq element-content-type "jsx"))
   5604                ((string-match-p " type[ ]*=[ ]*[\"']text/\\(markdown\\|template\\)" script)
   5605                 (setq element-content-type "markdown"))
   5606                ((string-match-p " type[ ]*=[ ]*[\"']text/ruby" script)
   5607                 (setq element-content-type "ruby"))
   5608                ((seq-some (lambda (x)
   5609                             (string-match-p (concat "type[ ]*=[ ]*[\"']" x) script))
   5610                           web-mode-script-template-types)
   5611                 (setq element-content-type "html"
   5612                       part-close-tag nil))
   5613                ((string-match-p " type[ ]*=[ ]*[\"']application/\\(ld\\+json\\|json\\)" script)
   5614                 (setq element-content-type "json"))
   5615                ((string-match-p " lang[ ]*=[ ]*[\"']\\(typescript\\|ts\\)" script)
   5616                 (setq element-content-type "typescript"))
   5617                (t
   5618                 (setq element-content-type "javascript"))
   5619                ) ;cond
   5620              ) ;let
   5621            ) ;script
   5622           ((string= tname "i18n")
   5623            (setq element-content-type "javascript"
   5624                  part-close-tag "</i18n>"))
   5625           ((and (string= tname "template") (string-match-p " lang" (buffer-substring-no-properties tbeg tend)))
   5626            (let (template)
   5627              (setq template (buffer-substring-no-properties tbeg tend)
   5628                    part-close-tag "</template>")
   5629              (cond
   5630                ((string-match-p " lang[ ]*=[ ]*[\"']pug" template)
   5631                 (setq element-content-type "pug"))
   5632                (t
   5633                 (setq element-content-type "html"))
   5634                ) ;cond
   5635              ) ;let
   5636            ) ;style
   5637           ((and (string= web-mode-engine "archibus")
   5638                 (string= tname "sql"))
   5639            (setq element-content-type "sql"
   5640                  part-close-tag "</sql>"))
   5641           )
   5642 
   5643         (add-text-properties tbeg tend props)
   5644         (put-text-property tbeg (1+ tbeg) 'tag-beg flags)
   5645         (put-text-property (1- tend) tend 'tag-end t)
   5646 
   5647         (when (and part-close-tag
   5648                    (web-mode-dom-sf part-close-tag reg-end t)
   5649                    (setq part-beg tend)
   5650                    (setq part-end (match-beginning 0))
   5651                    (> part-end part-beg))
   5652           (put-text-property part-beg part-end 'part-side
   5653                              (intern element-content-type web-mode-obarray))
   5654           (setq tend part-end)
   5655           ) ;when
   5656 
   5657         (goto-char tend)
   5658 
   5659         ) ;while
   5660 
   5661       )))
   5662 
   5663 ;; FLAGS: tag
   5664 ;; (1)attrs (2)custom (4)slash-beg (8)slash-end (16)bracket-end (32)namespaced
   5665 
   5666 ;; FLAGS: attr
   5667 ;; (1)custom-attr (2)engine-attr (4)spread-attr[jsx] (8)code-value
   5668 ;; https://www.w3.org/TR/2012/WD-html-markup-20120329/syntax.html#attr-value-unquoted
   5669 
   5670 ;; STATES: attr
   5671 ;; (0)nil (1)space (2)name (3)space-before (4)equal (5)space-after
   5672 ;; (6)value-uq (7)value-sq (8)value-dq (9)value-bq : jsx attr={}
   5673 ;; (10)value-block
   5674 
   5675 (defun web-mode-attr-skip (limit)
   5676 
   5677   (let ((tag-flags 0) (attr-flags 0) (continue t) (attrs 0) (brace-depth 0)
   5678         (state 0) (equal-offset 0) (go-back nil)
   5679         (is-jsx (or (string= web-mode-content-type "jsx") (eq (get-text-property (point) 'part-type) 'jsx)))
   5680         attr name-beg name-end val-beg char pos mem step escaped spaced quoted)
   5681 
   5682     (while continue
   5683 
   5684       (setq pos (point)
   5685             char (char-after)
   5686             mem state
   5687             ;;spaced (eq char ?\s)
   5688             spaced (member char '(?\s ?\n))
   5689             step nil)
   5690 
   5691       (ignore mem step) ;; Only used in debug print
   5692       (when quoted (setq quoted (1+ quoted)))
   5693 
   5694       (cond
   5695 
   5696         ((>= pos limit)
   5697          (setq continue nil)
   5698          (setq go-back t)
   5699          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5700          )
   5701 
   5702         ((and (or (= state 0) (= state 1)) (get-text-property pos 'block-side))
   5703          )
   5704 
   5705         ((or (and (= state 8) (not (member char '(?\" ?\\))))
   5706              (and (= state 7) (not (member char '(?\' ?\\))))
   5707              (and (= state 9) (not (member char '(?} ?\\))))
   5708              )
   5709          (when (and (= state 9) (eq char ?\{))
   5710            (setq brace-depth (1+ brace-depth)))
   5711          )
   5712 
   5713         ((and (= state 9) (eq char ?\}) (> brace-depth 1))
   5714          (setq brace-depth (1- brace-depth)))
   5715 
   5716         ;; #1233
   5717         ;;((get-text-property pos 'block-side)
   5718         ;; (when (= state 2)
   5719         ;;   (setq name-end pos))
   5720         ;; )
   5721 
   5722         ((and (= state 2) is-jsx (eq char ?\}) (eq attr-flags 4))
   5723          (setq name-end pos)
   5724          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5725          (setq state 0
   5726                attr-flags 0
   5727                equal-offset 0
   5728                name-beg nil
   5729                name-end nil
   5730                val-beg nil)
   5731          )
   5732 
   5733         ((or (and (= state 8) (eq ?\" char) (not escaped))
   5734              (and (= state 7) (eq ?\' char) (not escaped))
   5735              (and (= state 9) (eq ?\} char) (= brace-depth 1))
   5736              (and (= state 10) (get-text-property pos 'block-end))
   5737              )
   5738          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5739          (setq state 0
   5740                attr-flags 0
   5741                equal-offset 0
   5742                name-beg nil
   5743                name-end nil
   5744                val-beg nil)
   5745          )
   5746 
   5747         ((and (member state '(4 5)) (get-text-property pos 'block-beg))
   5748          (setq val-beg pos)
   5749          (setq state 10))
   5750 
   5751         ((and (member state '(4 5)) (member char '(?\' ?\" ?\{)))
   5752          (setq val-beg pos)
   5753          (setq quoted 1)
   5754          (setq state (cond ((eq ?\' char) 7)
   5755                            ((eq ?\" char) 8)
   5756                            (t             9)))
   5757          (setq step 100)
   5758          (when (= state 9) (setq brace-depth 1))
   5759          )
   5760 
   5761         ((and (eq ?\= char) (member state '(2 3)))
   5762          (setq equal-offset (- pos name-beg)
   5763                name-end (1- pos))
   5764          (setq state 4)
   5765          (setq attr (buffer-substring-no-properties name-beg (1+ name-end)))
   5766          (when (and web-mode-indentless-attributes (member (downcase attr) web-mode-indentless-attributes))
   5767            (setq attr-flags (logior attr-flags 8)))
   5768          )
   5769 
   5770         ((and spaced (= state 0))
   5771          (setq state 1)
   5772          )
   5773 
   5774         ((and (eq char ?\<) (not (member state '(7 8 9))))
   5775          (setq continue nil)
   5776          (setq go-back t)
   5777          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5778          )
   5779 
   5780         ((and (eq char ?\>) (not (member state '(7 8 9))))
   5781          (setq tag-flags (logior tag-flags 16))
   5782          (when (eq (char-before) ?\/)
   5783            (setq tag-flags (logior tag-flags 8))
   5784            )
   5785          (setq continue nil)
   5786          (when name-beg
   5787            (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags))))
   5788          )
   5789 
   5790         ((and spaced (member state '(1 3 5)))
   5791          )
   5792 
   5793         ((and spaced (= state 2))
   5794          (setq state 3)
   5795          )
   5796 
   5797         ((and (eq char ?\/) (member state '(4 5)))
   5798          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5799          (setq state 1
   5800                attr-flags 0
   5801                equal-offset 0
   5802                name-beg nil
   5803                name-end nil
   5804                val-beg nil)
   5805          )
   5806 
   5807         ((and (eq char ?\/) (member state '(0 1)))
   5808          )
   5809 
   5810         ((and spaced (= state 4))
   5811          (setq state 5)
   5812          )
   5813 
   5814         ((and (= state 3)
   5815               (or (and (>= char 97) (<= char 122)) ;a - z
   5816                   (and (>= char 65) (<= char 90)) ;A - Z
   5817                   (eq char ?\-)))
   5818          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5819          (setq state 2
   5820                attr-flags 0
   5821                equal-offset 0
   5822                name-beg pos
   5823                name-end pos
   5824                val-beg nil)
   5825          )
   5826 
   5827         ((and (eq char ?\n) (not (member state '(7 8 9))))
   5828          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5829          (setq state 1
   5830                attr-flags 0
   5831                equal-offset 0
   5832                name-beg nil
   5833                name-end nil
   5834                val-beg nil)
   5835          )
   5836 
   5837         ((and (= state 6) (member char '(?\s ?\n))) ;#1150
   5838          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5839          (setq state 1
   5840                attr-flags 0
   5841                equal-offset 0
   5842                name-beg nil
   5843                name-end nil
   5844                val-beg nil)
   5845          )
   5846 
   5847         ((and quoted (= quoted 2) (member char '(?\s ?\n ?\>)))
   5848          (when (eq char ?\>)
   5849            (setq tag-flags (logior tag-flags 16))
   5850            (setq continue nil))
   5851          (setq state 6)
   5852          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5853          (setq state 1
   5854                attr-flags 0
   5855                equal-offset 0
   5856                name-beg nil
   5857                name-end nil
   5858                val-beg nil)
   5859          )
   5860 
   5861         ((and (not spaced) (= state 1))
   5862          (when (and is-jsx (eq char ?\{))
   5863            (setq attr-flags 4))
   5864          (setq state 2)
   5865          (setq name-beg pos
   5866                name-end pos)
   5867          )
   5868 
   5869         ((member state '(4 5))
   5870          (setq val-beg pos)
   5871          (setq state 6)
   5872          )
   5873 
   5874         ((= state 1)
   5875          (setq state 2)
   5876          )
   5877 
   5878         ((= state 2)
   5879          (setq name-end pos)
   5880          (when (and nil (= attr-flags 0) (member char '(?\- ?\:)))
   5881            (let (attr)
   5882              (setq attr (buffer-substring-no-properties name-beg (1+ name-end)))
   5883              (cond
   5884                ((member attr '("http-equiv"))
   5885                 (setq attr-flags (1- attr-flags))
   5886                 )
   5887                ((and (eq char ?\-) (not (string= attr "http-")))
   5888                 (setq attr-flags (logior attr-flags 1)))
   5889                ) ;cond
   5890              ) ;let
   5891            ) ;when attr-flags = 1
   5892          ) ;state=2
   5893 
   5894         ) ;cond
   5895 
   5896       ;;(message "point(%S) state(%S) c(%S) name-beg(%S) name-end(%S) val-beg(%S) attr-flags(%S) equal-offset(%S)" pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)
   5897 
   5898       (when (and quoted (>= quoted 2))
   5899         (setq quoted nil))
   5900 
   5901       (setq escaped (eq ?\\ char))
   5902       (when (null go-back)
   5903         (forward-char))
   5904 
   5905       ;;(when (not (= mem state)) (message "pos=%S before=%S after=%S step=%S" pos mem state step))
   5906 
   5907       ) ;while
   5908 
   5909     (when (> attrs 0) (setq tag-flags (logior tag-flags 1)))
   5910 
   5911     tag-flags))
   5912 
   5913 (defun web-mode-attr-scan (pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)
   5914   ;;(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)
   5915   (when (null attr-flags) (setq attr-flags 0))
   5916   (when (and name-beg name-end web-mode-engine-attr-regexp)
   5917     (let (name)
   5918       (setq name (buffer-substring-no-properties name-beg (1+ name-end)))
   5919       (cond
   5920         ((string-match-p "^data[-]" name)
   5921          (setq attr-flags (logior attr-flags 1))
   5922          )
   5923         ((string-match-p web-mode-engine-attr-regexp name)
   5924          (setq attr-flags (logior attr-flags 2))
   5925          )
   5926         )
   5927       ) ;name
   5928     )
   5929   ;;(message "%S" name)
   5930   (cond
   5931     ((null name-beg)
   5932      0)
   5933     ((or (and (= state 8) (not (eq ?\" char)))
   5934          (and (= state 7) (not (eq ?\' char))))
   5935      (put-text-property name-beg (1+ name-beg) 'tag-attr-beg attr-flags)
   5936      (put-text-property name-beg val-beg 'tag-attr t)
   5937      (put-text-property (1- val-beg) val-beg 'tag-attr-end equal-offset)
   5938      1)
   5939     ((and (member state '(4 5)) (null val-beg))
   5940      (put-text-property name-beg (1+ name-beg) 'tag-attr-beg attr-flags)
   5941      (put-text-property name-beg (+ name-beg equal-offset 1) 'tag-attr t)
   5942      (put-text-property (+ name-beg equal-offset) (+ name-beg equal-offset 1) 'tag-attr-end equal-offset)
   5943      1)
   5944     (t
   5945      (let (val-end)
   5946        (if (null val-beg)
   5947            (setq val-end name-end)
   5948            (setq val-end pos)
   5949            (cond
   5950              ((null char)
   5951               (setq val-end (1- val-end)))
   5952              ((member char '(?\s ?\n ?\/))
   5953               (setq val-end (1- val-end)))
   5954              ((eq char ?\>)
   5955               (if (= (logand tag-flags 8) 8)
   5956                   (progn
   5957                     ;;(message "tag-flags=%S %S" tag-flags (logand tag-flags 8))
   5958                     (setq val-end (- val-end 2)))
   5959                   (setq val-end (- val-end 1)))
   5960               ;; (message "val-end=%S" val-end)
   5961               )
   5962              )
   5963            )
   5964        (put-text-property name-beg (1+ name-beg) 'tag-attr-beg attr-flags)
   5965        (put-text-property name-beg (1+ val-end) 'tag-attr t)
   5966        (put-text-property val-end (1+ val-end) 'tag-attr-end equal-offset)
   5967        ) ;let
   5968      1) ;t
   5969     ) ;cond
   5970   )
   5971 
   5972 (defun web-mode-part-foreach (reg-beg reg-end func)
   5973   (let ((i 0) (continue t) (part-beg reg-beg) (part-end nil))
   5974     (while continue
   5975       (setq part-end nil)
   5976       (unless (get-text-property part-beg 'part-side)
   5977         (setq part-beg (web-mode-part-next-position part-beg)))
   5978       (when (and part-beg (< part-beg reg-end))
   5979         (setq part-end (web-mode-part-end-position part-beg)))
   5980       (cond
   5981         ((> (setq i (1+ i)) 100)
   5982          (message "process-parts ** warning (%S) **" (point))
   5983          (setq continue nil))
   5984         ((or (null part-end) (> part-end reg-end))
   5985          (setq continue nil))
   5986         (t
   5987          (setq part-end (1+ part-end))
   5988          (funcall func part-beg part-end)
   5989          (setq part-beg part-end))
   5990         ) ;cond
   5991       ) ;while
   5992     ))
   5993 
   5994 (defun web-mode-part-scan (reg-beg reg-end &optional content-type depth)
   5995   (save-excursion
   5996     (let (token-re ch-before ch-at ch-next token-type beg continue)
   5997       ;;(message "%S %S" reg-beg reg-end)
   5998       (cond
   5999         (content-type
   6000          )
   6001         ((member web-mode-content-type web-mode-part-content-types)
   6002          (setq content-type web-mode-content-type))
   6003         (t
   6004          (setq content-type (symbol-name (get-text-property reg-beg 'part-side))))
   6005         ) ;cond
   6006 
   6007       (goto-char reg-beg)
   6008 
   6009       (cond
   6010         ((member content-type '("javascript" "json"))
   6011          (setq token-re "/\\|\"\\|'\\|`"))
   6012         ((member content-type '("typescript"))
   6013          (setq token-re "/\\|\"\\|'\\|`\\|//\\|/\\*"))
   6014         ((member content-type '("jsx"))
   6015          (setq token-re "/\\|\"\\|'\\|`\\|</?[[:alpha:]>]"))
   6016         ((string= web-mode-content-type "css")
   6017          (setq token-re "\"\\|'\\|/\\*\\|//"))
   6018         ((string= content-type "css")
   6019          (setq token-re "\"\\|'\\|/\\*"))
   6020         (t
   6021          (setq token-re "/\\*\\|\"\\|'"))
   6022         )
   6023 
   6024       (while (and token-re (< (point) reg-end) (web-mode-dom-rsf token-re reg-end t))
   6025 
   6026         (setq beg (match-beginning 0)
   6027               token-type nil
   6028               continue t
   6029               ch-at (char-after beg)
   6030               ch-next (or (char-after (1+ beg)) ?\d)
   6031               ch-before (or (char-before beg) ?\d))
   6032 
   6033         ;;(message "[%S>%S|%S] %S %c %c %c" reg-beg reg-end depth beg ch-before ch-at ch-next)
   6034 
   6035         (cond
   6036 
   6037           ((eq ?\' ch-at)
   6038            (while (and continue (search-forward "'" reg-end t))
   6039              (cond
   6040                ((get-text-property (1- (point)) 'block-side)
   6041                 (setq continue t))
   6042                (t
   6043                 (setq continue (web-mode-string-continue-p reg-beg)))
   6044                )
   6045              ) ;while
   6046            (setq token-type 'string))
   6047 
   6048           ((eq ?\` ch-at)
   6049            (while (and continue (search-forward "`" reg-end t))
   6050              (cond
   6051                ((get-text-property (1- (point)) 'block-side)
   6052                 (setq continue t))
   6053                (t
   6054                 (setq continue (web-mode-string-continue-p reg-beg)))
   6055                )
   6056              ) ;while
   6057            (setq token-type 'string))
   6058 
   6059           ((eq ?\" ch-at)
   6060            (while (and continue (search-forward "\"" reg-end t))
   6061              (cond
   6062                ((get-text-property (1- (point)) 'block-side)
   6063                 (setq continue t))
   6064                (t
   6065                 (setq continue (web-mode-string-continue-p reg-beg)))
   6066                ) ;cond
   6067              ) ;while
   6068            (cond
   6069              ((string= content-type "json")
   6070               (if (looking-at-p "[ ]*:")
   6071                   (cond
   6072                     ((eq ?\@ (char-after (1+ beg)))
   6073                      (setq token-type 'context))
   6074                     (t
   6075                      (setq token-type 'key))
   6076                     )
   6077                   (setq token-type 'string))
   6078               ) ;json
   6079              (t
   6080               (setq token-type 'string))
   6081              ) ;cond
   6082            )
   6083 
   6084           ((and (eq ?\< ch-at)
   6085                 (not (or (and (>= ch-before 97) (<= ch-before 122)) ;; a-z
   6086                          (and (>= ch-before 65) (<= ch-before 90))))) ;; A-Z
   6087            ;;(message "before [%S>%S|%S] pt=%S" reg-beg reg-end depth (point))
   6088            (search-backward "<")
   6089            (if (web-mode-jsx-skip reg-end)
   6090                (web-mode-jsx-scan-element beg (point) depth)
   6091                (forward-char))
   6092            ;;(message "after [%S>%S|%S] pt=%S" reg-beg reg-end depth (point))
   6093            )
   6094 
   6095           ((and (eq ?\/ ch-at) (member content-type '("javascript" "jsx" "typescript")))
   6096            (cond
   6097              ((eq ?\\ ch-before)
   6098               )
   6099              ((eq ?\* ch-next)
   6100               ;;(message "--> %S %S" (point) reg-end)
   6101               (when (search-forward "*/" reg-end t)
   6102                 (setq token-type 'comment))
   6103               )
   6104              ((eq ?\/ ch-next)
   6105               (setq token-type 'comment)
   6106               (goto-char (if (< reg-end (line-end-position)) reg-end (line-end-position)))
   6107               )
   6108              ((and (looking-at-p ".*/")
   6109                    (looking-back "\\(^\\|case\\|[[(,=:!&|?{};]\\)[ ]*/" (point-min)))
   6110               ;;(re-search-forward "/[gimyu]*" reg-end t))
   6111               (let ((eol (line-end-position)))
   6112                 (while (and continue (search-forward "/" eol t))
   6113                   (cond
   6114                     ((get-text-property (1- (point)) 'block-side)
   6115                      (setq continue t))
   6116                     ((looking-back "\\\\+/" reg-beg t)
   6117                      (setq continue (= (mod (- (point) (match-beginning 0)) 2) 0)))
   6118                     (t
   6119                      (re-search-forward "[gimyu]*" eol t)
   6120                      (setq token-type 'string)
   6121                      (setq continue nil))
   6122                     )
   6123                   ) ;while
   6124                 ) ;let
   6125               )
   6126              ) ;cond
   6127            )
   6128 
   6129           ((eq ?\/ ch-next)
   6130            ;;(message "%S" (point))
   6131            (cond
   6132              ((and (string= content-type "css")
   6133                    (eq ?/ ch-at)
   6134                    (eq ?: ch-before))
   6135               )
   6136              (t
   6137               (unless (eq ?\\ ch-before)
   6138                 (setq token-type 'comment)
   6139                 (goto-char (if (< reg-end (line-end-position)) reg-end (line-end-position)))
   6140                 )
   6141               )
   6142              )
   6143 
   6144            )
   6145 
   6146           ((eq ?\* ch-next)
   6147            (cond
   6148              ((search-forward "*/" reg-end t)
   6149               (setq token-type 'comment))
   6150              ((not (eobp))
   6151               (forward-char))
   6152              ) ;cond
   6153            )
   6154 
   6155           ) ;cond
   6156 
   6157         (when (and beg (>= reg-end (point)) token-type)
   6158           (put-text-property beg (point) 'part-token token-type)
   6159           (cond
   6160             ((eq token-type 'comment)
   6161              (put-text-property beg (1+ beg) 'syntax-table (string-to-syntax "<"))
   6162              (when (< (point) (point-max))
   6163                (if (< (point) (line-end-position))
   6164                    (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax ">")) ;#445
   6165                    (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax ">")) ;#377
   6166                    )
   6167                ) ;when
   6168              ) ;comment
   6169             ((eq token-type 'string)
   6170              (put-text-property beg (1+ beg) 'syntax-table (string-to-syntax "|"))
   6171              (when (< (point) (point-max))
   6172                (if (< (point) (line-end-position))
   6173                    (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax "|"))
   6174                    (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax "|"))
   6175                    )
   6176                ) ;when
   6177              ) ;string
   6178             ) ;cond
   6179           ) ;when
   6180 
   6181         (when (> (point) reg-end)
   6182           (message "reg-beg(%S) reg-end(%S) token-type(%S) point(%S)" reg-beg reg-end token-type (point)))
   6183 
   6184         ;;(message "#[%S>%S|%S] %S %c %c %c | (%S)" reg-beg reg-end depth beg ch-before ch-at ch-next (point))
   6185 
   6186         ) ;while
   6187 
   6188       )))
   6189 
   6190 (defun web-mode-string-continue-p (reg-beg)
   6191   "Is `point' preceeded by an odd number of backslashes?"
   6192   (let ((p (1- (point))))
   6193     (while (and (< reg-beg p) (eq ?\\ (char-before p)))
   6194       (setq p (1- p)))
   6195     (= (mod (- (point) p) 2) 0)))
   6196 
   6197 ;; css rule = selector(s) + declaration (properties)
   6198 (defun web-mode-css-rule-next (limit)
   6199   (let (at-rule var-rule sel-beg sel-end dec-beg dec-end chunk)
   6200     (skip-chars-forward "\n\t ")
   6201     (setq sel-beg (point))
   6202     (when (and (< (point) limit)
   6203                (web-mode-part-rsf "[{;]" limit))
   6204       (setq sel-end (1- (point)))
   6205       (cond
   6206         ((eq (char-before) ?\{)
   6207          (setq dec-beg (point))
   6208          (setq dec-end (web-mode-closing-paren-position (1- dec-beg) limit))
   6209          (if dec-end
   6210              (progn
   6211                (goto-char dec-end)
   6212                (forward-char))
   6213              (setq dec-end limit)
   6214              (goto-char limit))
   6215          )
   6216         (t
   6217          )
   6218         ) ;cond
   6219       (setq chunk (buffer-substring-no-properties sel-beg sel-end))
   6220       (cond
   6221         ((string-match "@\\([[:alpha:]-]+\\)" chunk)
   6222          (setq at-rule (match-string-no-properties 1 chunk)))
   6223         ((string-match "\\$\\([[:alpha:]-]+\\)" chunk)
   6224          (setq var-rule (match-string-no-properties 1 chunk)))
   6225         ) ;cond
   6226       ) ;when
   6227     (if (not sel-end)
   6228         (progn (goto-char limit) nil)
   6229         (list :at-rule at-rule
   6230               :var-rule var-rule
   6231               :sel-beg sel-beg
   6232               :sel-end sel-end
   6233               :dec-beg dec-beg
   6234               :dec-end dec-end)
   6235         ) ;if
   6236     ))
   6237 
   6238 (defun web-mode-css-rule-current (&optional pos part-beg part-end)
   6239   "Current CSS rule boundaries."
   6240   (unless pos (setq pos (point)))
   6241   (unless part-beg (setq part-beg (web-mode-part-beginning-position pos)))
   6242   (unless part-end (setq part-end (web-mode-part-end-position pos)))
   6243   (save-excursion
   6244     (let (beg end)
   6245       (goto-char pos)
   6246       (if (not (web-mode-part-sb "{" part-beg))
   6247           (progn
   6248             (setq beg part-beg)
   6249             (if (web-mode-part-sf ";" part-end)
   6250                 (setq end (1+ (point)))
   6251                 (setq end part-end))
   6252             ) ;progn
   6253           (setq beg (point))
   6254           (setq end (web-mode-closing-paren-position beg part-end))
   6255           (if end
   6256               (setq end (1+ end))
   6257               (setq end (line-end-position)))
   6258           ;;        (message "%S >>beg%S >>end%S" pos beg end)
   6259           (if (> pos end)
   6260 
   6261               ;;selectors
   6262               (progn
   6263                 (goto-char pos)
   6264                 (if (web-mode-part-rsb "[};]" part-beg)
   6265                     (setq beg (1+ (point)))
   6266                     (setq beg part-beg)
   6267                     ) ;if
   6268                 (goto-char pos)
   6269                 (if (web-mode-part-rsf "[{;]" part-end)
   6270                     (cond
   6271                       ((eq (char-before) ?\;)
   6272                        (setq end (point))
   6273                        )
   6274                       (t
   6275                        (setq end (web-mode-closing-paren-position (1- (point)) part-end))
   6276                        (if end
   6277                            (setq end (1+ end))
   6278                            (setq end part-end))
   6279                        )
   6280                       ) ;cond
   6281                     (setq end part-end)
   6282                     )
   6283                 ) ;progn selectors
   6284 
   6285               ;; declaration
   6286               (goto-char beg)
   6287               (if (web-mode-part-rsb "[}{;]" part-beg)
   6288                   (setq beg (1+ (point)))
   6289                   (setq beg part-beg)
   6290                   ) ;if
   6291               ) ;if > pos end
   6292           )
   6293       ;;      (message "beg(%S) end(%S)" beg end)
   6294       (when (eq (char-after beg) ?\n)
   6295         (setq beg (1+ beg)))
   6296       (cons beg end)
   6297       )))
   6298 
   6299 (defun web-mode-jsx-skip2 (reg-end)
   6300   (let ((continue t) (pos nil) (i 0))
   6301     (looking-at "<\\([[:alpha:]][[:alnum:]:-]*\\)")
   6302     ;; (let ((tag (match-string-no-properties 1)))
   6303     ;;   (message "point=%S tag=%S" (point) tag))
   6304     (save-excursion
   6305       (while continue
   6306         (cond
   6307           ((> (setq i (1+ i)) 1000)
   6308            (message "jsx-skip ** warning **")
   6309            (setq continue nil))
   6310           ((looking-at "<[[:alpha:]][[:alnum:]:-]*[ ]*/>")
   6311            (goto-char (match-end 0))
   6312            (setq pos (point))
   6313            (setq continue nil))
   6314           ((not (web-mode-dom-rsf ">\\([ \t\n]*[\];,)':}|&]\\)\\|{" reg-end))
   6315            (setq continue nil)
   6316            )
   6317           ((eq (char-before) ?\{)
   6318            (backward-char)
   6319            (web-mode-closing-paren reg-end)
   6320            (forward-char)
   6321            )
   6322           (t
   6323            (setq continue nil)
   6324            (setq pos (match-beginning 1))
   6325            ) ;t
   6326           ) ;cond
   6327         ) ;while
   6328       ) ;save-excursion
   6329     (when pos (goto-char pos))
   6330     ;;(message "jsx-skip: %S" pos)
   6331     pos))
   6332 
   6333  (defun web-mode-jsx-skip (reg-end) ;; #1299
   6334    (let ((continue t) (pos nil) (i 0) (tag nil) (regexp nil) (counter 0) (ret nil) (match nil) (inside t))
   6335      (looking-at "<\\([[:alpha:]][[:alnum:]:-]*\\)")
   6336      (setq tag (match-string-no-properties 1))
   6337      (setq regexp (concat "<" tag "[[:space:]/>]"))
   6338      ;;(message "-----\npoint=%S tag=%S reg-end=%S" (point) tag reg-end)
   6339      (save-excursion
   6340        (while continue
   6341          (setq ret (web-mode-dom-rsf regexp reg-end))
   6342          (if ret
   6343              (progn
   6344                (setq match (match-string-no-properties 0))
   6345                (when (and (eq (aref match 0) ?\<)
   6346                           (eq (char-before) ?\>))
   6347                  (backward-char)
   6348                  (when (eq (char-before) ?\/) (backward-char)))
   6349                )
   6350            (setq match nil)
   6351            ) ;if
   6352          ;;(message "point=%S regexp=%S match=%S" (point) regexp match)
   6353          (cond
   6354           ((> (setq i (1+ i)) 100)
   6355            (message "jsx-skip ** warning **")
   6356            (setq continue nil))
   6357           ((not ret)
   6358            (setq continue nil)
   6359            )
   6360           ((eq (aref match 0) ?\{)
   6361            (backward-char)
   6362            (web-mode-closing-paren reg-end)
   6363            (forward-char)
   6364            (if inside
   6365                (setq regexp (concat "[{]\\|/?>"))
   6366              (setq regexp (concat "[{]\\|</?" tag "[[:space:]/>]"))
   6367              )
   6368            )
   6369           ((and (eq (char-before) ?\>) (eq (char-before (1- (point))) ?\/)) ;; />
   6370            (setq inside nil)
   6371            (if (eq counter 1)
   6372                (progn
   6373                  (setq counter 0)
   6374                  (setq continue nil)
   6375                  (setq pos (point)))
   6376              (setq regexp (concat "[{]\\|<" tag "[[:space:]/>]"))
   6377              )
   6378            )
   6379           ((eq (char-before) ?\>) ;; >
   6380            (setq inside nil)
   6381            (if (= counter 0)
   6382                (progn
   6383                  (setq continue nil)
   6384                  (setq pos (point)))
   6385              (setq regexp (concat "[{]\\|</?" tag "[[:space:]/>]"))
   6386              )
   6387            )
   6388           ((and (> (length match) 1) (string= (substring match 0 2) "</"))
   6389            (setq inside t)
   6390            (setq counter (1- counter))
   6391            (setq regexp (concat "[{]\\|>"))
   6392            )
   6393           (t ;; <tag
   6394            (setq inside t)
   6395            (setq counter (1+ counter))
   6396            (setq regexp (concat "[{]\\|>"))
   6397            ) ;t
   6398           ) ;cond
   6399          ;;(message "point=%S counter=%S inside=%S" (point) counter inside)
   6400          ) ;while
   6401        ) ;save-excursion
   6402      (when pos (goto-char pos))
   6403      ;;(message "jsx-skip: %S" pos)
   6404      pos))
   6405 
   6406 ;; http://facebook.github.io/jsx/
   6407 ;; https://github.com/facebook/jsx/blob/master/AST.md
   6408 (defun web-mode-jsx-scan-element (reg-beg reg-end depth)
   6409   (unless depth (setq depth 1))
   6410   (save-excursion
   6411     (goto-char reg-beg)
   6412     (put-text-property reg-beg (1+ reg-beg) 'jsx-beg depth)
   6413     (put-text-property (1- reg-end) reg-end 'jsx-end depth)
   6414     (put-text-property reg-beg reg-end 'jsx-depth depth)
   6415     (goto-char reg-beg)
   6416     (web-mode-scan-elements reg-beg reg-end)
   6417     (web-mode-jsx-scan-expression reg-beg reg-end (1+ depth))
   6418     ))
   6419 
   6420 (defun web-mode-jsx-scan-expression (reg-beg reg-end depth)
   6421   (let ((continue t) beg end)
   6422     (save-excursion
   6423       (goto-char reg-beg)
   6424       ;;(message "reg-beg=%S reg-end=%S" reg-beg reg-end)
   6425       (while (and continue (search-forward "{" reg-end t))
   6426         (backward-char)
   6427         (setq beg (point)
   6428               end (web-mode-closing-paren reg-end))
   6429         (cond
   6430           ((eq (get-text-property beg 'part-token) 'comment)
   6431            (forward-char))
   6432           ((not end)
   6433            (setq continue nil))
   6434           (t
   6435            (setq end (1+ end))
   6436            (put-text-property beg end 'jsx-depth depth)
   6437            (put-text-property beg (1+ beg) 'jsx-beg depth)
   6438            (put-text-property (1- end) end 'jsx-end depth)
   6439            (web-mode-part-scan beg end "jsx" (1+ depth))
   6440            ) ;t
   6441           ) ;cond
   6442         ) ;while
   6443       ) ;save-excursion
   6444     ))
   6445 
   6446 (defun web-mode-jsx-is-html (&optional pos)
   6447   (interactive)
   6448   (unless pos (setq pos (point)))
   6449   (let ((depth (get-text-property pos 'jsx-depth)))
   6450     (cond
   6451       ((or (null depth) (<= pos 2))
   6452        (setq pos nil))
   6453       ((and (= depth 1) (get-text-property pos 'jsx-beg))
   6454        (setq pos nil))
   6455       ((get-text-property pos 'tag-end)
   6456        (setq pos nil))
   6457       ((get-text-property pos 'tag-attr-beg)
   6458        (setq pos nil))
   6459       ((get-text-property pos 'jsx-beg)
   6460        (setq pos (null (get-text-property pos 'tag-beg))))
   6461       ((setq pos (web-mode-jsx-depth-beginning-position pos))
   6462        (setq pos (not (null (get-text-property pos 'tag-beg)))))
   6463       (t
   6464        (setq pos nil))
   6465       ) ;cond
   6466     ;;(message "is-html: %S (depth=%S)" pos depth)
   6467     pos))
   6468 
   6469 (defun web-mode-jsx-is-expr (&optional pos)
   6470   (cond
   6471     ((and (get-text-property pos 'jsx-beg)
   6472           (not (get-text-property pos 'tag-beg)))
   6473      nil)
   6474     (t
   6475      (setq pos (web-mode-jsx-depth-beginning-position pos))
   6476      (null (get-text-property pos 'tag-beg)))
   6477     ) ;cond
   6478   )
   6479 
   6480 (defun web-mode-jsx-depth-beginning-position (&optional pos target-depth)
   6481   (interactive)
   6482   (unless pos (setq pos (point)))
   6483   (unless target-depth (setq target-depth (get-text-property pos 'jsx-depth)))
   6484   (cond
   6485     ((or (null target-depth) (bobp))
   6486      (setq pos nil))
   6487     ((and (get-text-property pos 'jsx-beg) (= target-depth (get-text-property pos 'jsx-depth)))
   6488      )
   6489     (t
   6490      (let ((continue t) depth)
   6491        (while continue
   6492          (setq pos (previous-single-property-change pos 'jsx-depth))
   6493          (cond
   6494            ((or (null pos)
   6495                 (null (setq depth (get-text-property pos 'jsx-depth))))
   6496             (setq continue nil
   6497                   pos nil))
   6498            ((and (get-text-property pos 'jsx-beg) (= target-depth depth))
   6499             (setq continue nil))
   6500            ) ;cond
   6501          ) ;while
   6502        ) ;let
   6503      ) ;t
   6504     ) ;cond
   6505   ;;(message "beg: %S" pos)
   6506   pos)
   6507 
   6508 (defun web-mode-jsx-element-next (reg-end)
   6509   (let (continue beg end)
   6510     (setq beg (point))
   6511     (unless (get-text-property beg 'jsx-depth)
   6512       (setq beg (next-single-property-change beg 'jsx-beg)))
   6513     (setq continue (and beg (< beg reg-end))
   6514           end beg)
   6515     (while continue
   6516       (setq end (next-single-property-change end 'jsx-end))
   6517       (cond
   6518         ((or (null end) (> end reg-end))
   6519          (setq continue nil
   6520                end nil))
   6521         ((eq (get-text-property end 'jsx-depth) 1)
   6522          (setq continue nil))
   6523         (t
   6524          (setq end (1+ end)))
   6525         ) ;cond
   6526       ) ;while
   6527     ;;(message "beg=%S end=%S" beg end)
   6528     (if (and beg end (< beg end)) (cons beg end) nil)))
   6529 
   6530 (defun web-mode-jsx-expression-next (reg-end)
   6531   (let (beg end depth continue pos)
   6532     (setq beg (point))
   6533     ;;(message "pt=%S" beg)
   6534     (unless (and (get-text-property beg 'jsx-beg) (null (get-text-property beg 'tag-beg)))
   6535       ;;(setq beg (next-single-property-change beg 'jsx-beg))
   6536       (setq continue t
   6537             pos (1+ beg))
   6538       (while continue
   6539         (setq pos (next-single-property-change pos 'jsx-beg))
   6540         (cond
   6541           ((null pos)
   6542            (setq continue nil
   6543                  beg nil))
   6544           ((> pos reg-end)
   6545            (setq continue nil
   6546                  beg nil))
   6547           ((null (get-text-property pos 'jsx-beg))
   6548            )
   6549           ((null (get-text-property pos 'tag-beg))
   6550            (setq continue nil
   6551                  beg pos))
   6552           ;;(t
   6553           ;; (setq pos (1+ pos)))
   6554           ) ;cond
   6555         ) ;while
   6556       ) ;unless
   6557     ;;(message "beg=%S" beg)
   6558     (when (and beg (< beg reg-end))
   6559       (setq depth (get-text-property beg 'jsx-beg)
   6560             continue (not (null depth))
   6561             pos beg)
   6562       ;;(message "beg=%S" beg)
   6563       (while continue
   6564         (setq pos (next-single-property-change pos 'jsx-end))
   6565         ;;(message "pos=%S" pos)
   6566         (cond
   6567           ((null pos)
   6568            (setq continue nil))
   6569           ((> pos reg-end)
   6570            (setq continue nil))
   6571           ((eq depth (get-text-property pos 'jsx-end))
   6572            (setq continue nil
   6573                  end pos))
   6574           (t
   6575            ;;(setq pos (1+ pos))
   6576            )
   6577           ) ;cond
   6578         ) ;while
   6579       ) ;when
   6580     ;;(message "%S > %S" beg end)
   6581     (if (and beg end) (cons beg end) nil)))
   6582 
   6583 (defun web-mode-jsx-depth-next (reg-end)
   6584   (let (beg end depth continue pos)
   6585     (setq beg (point))
   6586     ;;(message "pt=%S" beg)
   6587     (unless (get-text-property beg 'jsx-beg)
   6588       ;;(setq beg (next-single-property-change beg 'jsx-beg))
   6589       ;;(setq pos (1+ beg))
   6590       (setq pos (next-single-property-change (1+ beg) 'jsx-beg))
   6591       (cond
   6592         ((null pos)
   6593          (setq beg nil))
   6594         ((>= pos reg-end)
   6595          (setq beg nil))
   6596         (t
   6597          (setq beg pos))
   6598         ) ;cond
   6599       ) ;unless
   6600     ;;(message "beg=%S" beg)
   6601     (when beg
   6602       (setq depth (get-text-property beg 'jsx-beg)
   6603             continue (not (null depth))
   6604             pos beg)
   6605       ;;(message "beg=%S" beg)
   6606       (while continue
   6607         (setq pos (next-single-property-change pos 'jsx-end))
   6608         ;;(message "pos=%S" pos)
   6609         (cond
   6610           ((null pos)
   6611            (setq continue nil))
   6612           ((> pos reg-end)
   6613            (setq continue nil))
   6614           ((eq depth (get-text-property pos 'jsx-end))
   6615            (setq continue nil
   6616                  end pos))
   6617           (t
   6618            ;;(setq pos (1+ pos))
   6619            )
   6620           ) ;cond
   6621         ) ;while
   6622       ) ;when
   6623     ;;(message "%S > %S" beg end)
   6624     (if (and beg end) (cons beg end) nil)))
   6625 
   6626 (defun web-mode-jsx-beginning ()
   6627   (interactive)
   6628   (let (depth (continue t) (reg-beg (point-min)) (pos (point)))
   6629     (setq depth (get-text-property pos 'jsx-depth))
   6630     (cond
   6631       ((not depth)
   6632        )
   6633       ((get-text-property (1- pos) 'jsx-beg)
   6634        (goto-char (1- pos)))
   6635       (t
   6636        (while continue
   6637          (setq pos (previous-single-property-change pos 'jsx-beg))
   6638          ;;(message "pos=%S" pos)
   6639          (cond
   6640            ((null pos)
   6641             (setq continue nil))
   6642            ((<= pos reg-beg)
   6643             (setq continue nil))
   6644            ((eq depth (get-text-property pos 'jsx-beg))
   6645             (setq continue nil))
   6646            ) ;cond
   6647          ) ;while
   6648        (web-mode-go pos)
   6649        ) ;t
   6650       ) ;cond
   6651     ))
   6652 
   6653 (defun web-mode-jsx-end ()
   6654   (interactive)
   6655   (let (depth (continue t) (reg-end (point-max)) (pos (point)))
   6656     (setq depth (get-text-property pos 'jsx-depth))
   6657     (cond
   6658       ((not depth)
   6659        )
   6660       ((get-text-property pos 'jsx-end)
   6661        (goto-char (+ pos 1)))
   6662       (t
   6663        (while continue
   6664          (setq pos (next-single-property-change pos 'jsx-end))
   6665          ;;(message "pos=%S" pos)
   6666          (cond
   6667            ((null pos)
   6668             (setq continue nil))
   6669            ((> pos reg-end)
   6670             (setq continue nil))
   6671            ((eq depth (get-text-property pos 'jsx-end))
   6672             (setq continue nil))
   6673            ) ;cond
   6674          ) ;while
   6675        (web-mode-go pos 1)
   6676        ) ;t
   6677       ) ;cond
   6678     ))
   6679 
   6680 ;;---- FONTIFICATION -----------------------------------------------------------
   6681 
   6682 (defun web-mode-fontify (limit)
   6683   (when web-mode-trace
   6684     (message "fontify: point(%S) limit(%S)" (point) limit))
   6685   (cond
   6686     ;;(web-mode-skip-fontification
   6687     ;; nil)
   6688     (t
   6689      (web-mode-with-silent-modifications
   6690       (save-excursion
   6691         (save-restriction
   6692           (save-match-data
   6693             (let ((beg (point))
   6694                   (buffer-undo-list t)
   6695                   (end limit)
   6696                   (inhibit-point-motion-hooks t)
   6697                   (inhibit-quit t))
   6698               (remove-list-of-text-properties beg end '(font-lock-face face))
   6699               (cond
   6700                 ((and (get-text-property beg 'block-side)
   6701                       (not (get-text-property beg 'block-beg)))
   6702                  (web-mode-fontify-block beg end))
   6703                 ((or (member web-mode-content-type web-mode-part-content-types)
   6704                      (get-text-property beg 'part-side))
   6705                  (web-mode-fontify-part beg end)
   6706                  (web-mode-block-foreach beg end 'web-mode-fontify-block))
   6707                 ((string= web-mode-engine "none")
   6708                  (web-mode-fontify-tags beg end)
   6709                  (web-mode-part-foreach beg end 'web-mode-fontify-part))
   6710                 (t
   6711                  (web-mode-fontify-tags beg end)
   6712                  (web-mode-part-foreach beg end 'web-mode-fontify-part)
   6713                  (web-mode-block-foreach beg end 'web-mode-fontify-block))
   6714                 ) ;cond
   6715               (when web-mode-enable-element-content-fontification
   6716                 (web-mode-fontify-elements beg end))
   6717               (when web-mode-enable-whitespace-fontification
   6718                 (web-mode-fontify-whitespaces beg end))
   6719               ) ;let
   6720             ))))
   6721      nil) ;t
   6722     ))
   6723 
   6724 (defun web-mode-buffer-fontify ()
   6725   (interactive)
   6726   (cond
   6727     ((and (fboundp 'font-lock-flush) global-font-lock-mode)
   6728      (font-lock-flush)
   6729      (font-lock-ensure))
   6730     (t  ;emacs 24
   6731      ;;(font-lock-fontify-buffer)
   6732      (and global-font-lock-mode
   6733           (font-lock-fontify-region (point-min) (point-max))))
   6734     ))
   6735 
   6736 (defun web-mode-unfontify-region (beg end)
   6737   (ignore beg end)
   6738   ;;(message "unfontify: %S %S" beg end)
   6739   )
   6740 
   6741 (defun web-mode-fontify-region (beg end keywords)
   6742   ;;  (message "beg=%S end=%S keywords=%S" beg end (symbol-name keywords))
   6743   (save-excursion
   6744     (let ((font-lock-keywords keywords)
   6745           (font-lock-multiline nil)
   6746           (font-lock-keywords-case-fold-search
   6747            (member web-mode-engine '("archibus" "asp" "template-toolkit")))
   6748           (font-lock-keywords-only t)
   6749           (font-lock-extend-region-functions nil))
   6750       (when (and (listp font-lock-keywords) global-font-lock-mode)
   6751         (font-lock-fontify-region beg end)
   6752         )
   6753       )))
   6754 
   6755 (defun web-mode-fontify-tags (reg-beg reg-end &optional depth)
   6756   (let ((continue t))
   6757     (goto-char reg-beg)
   6758     (when (and (not (get-text-property (point) 'tag-beg))
   6759                (not (web-mode-tag-next)))
   6760       (setq continue nil))
   6761     (when (and continue (>= (point) reg-end))
   6762       (setq continue nil))
   6763     (while continue
   6764       (cond
   6765         (depth
   6766          (when (eq depth (get-text-property (point) 'jsx-depth))
   6767            (web-mode-fontify-tag))
   6768          )
   6769         (t
   6770          (web-mode-fontify-tag))
   6771         ) ;cond
   6772       (when (or (not (web-mode-tag-next))
   6773                 (>= (point) reg-end))
   6774         (setq continue nil))
   6775       ) ;while
   6776     (when web-mode-enable-inlays
   6777       (when (null web-mode-inlay-regexp)
   6778         (setq web-mode-inlay-regexp (regexp-opt '("\\[" "\\(" "\\begin{align}"))))
   6779       (let (beg end expr)
   6780         (goto-char reg-beg)
   6781         (while (web-mode-dom-rsf web-mode-inlay-regexp reg-end)
   6782           (setq beg (match-beginning 0)
   6783                 end nil
   6784                 expr (substring (match-string-no-properties 0) 0 2))
   6785           (setq expr (cond
   6786                        ((string= expr "\\[") "\\]")
   6787                        ((string= expr "\\(") "\\)")
   6788                        (t "\\end{align}")))
   6789           (when (and (web-mode-dom-sf expr reg-end)
   6790                      (setq end (match-end 0))
   6791                      (not (text-property-any beg end 'tag-end t)))
   6792             (font-lock-append-text-property beg end 'font-lock-face 'web-mode-inlay-face)
   6793             ) ;when
   6794           ) ;while
   6795         ) ;let
   6796       ) ;when
   6797     (when web-mode-enable-html-entities-fontification
   6798       (let (beg end)
   6799         (goto-char reg-beg)
   6800         (while (web-mode-dom-rsf "&\\([#]?[[:alnum:]]\\{2,8\\}\\);" reg-end)
   6801           (setq beg (match-beginning 0)
   6802                 end (match-end 0))
   6803           (when (not (text-property-any beg end 'tag-end t))
   6804             (font-lock-append-text-property beg end 'font-lock-face 'web-mode-html-entity-face)
   6805             ) ;when
   6806           ) ;while
   6807         ) ;let
   6808       ) ;when
   6809     ))
   6810 
   6811 (defun web-mode-fontify-tag (&optional beg end)
   6812   (unless beg (setq beg (point)))
   6813   (unless end (setq end (1+ (web-mode-tag-end-position beg))))
   6814   (let (name type face flags slash-beg slash-end bracket-end)
   6815     (setq flags (get-text-property beg 'tag-beg)
   6816           type (get-text-property beg 'tag-type)
   6817           name (get-text-property beg 'tag-name))
   6818     (setq bracket-end (> (logand flags 16) 0))
   6819     (cond
   6820       ((eq type 'comment)
   6821        (put-text-property beg end 'font-lock-face 'web-mode-comment-face)
   6822        (when (and web-mode-enable-comment-interpolation (> (- end beg) 5))
   6823          (web-mode-interpolate-comment beg end nil)))
   6824       ((eq type 'cdata)
   6825        (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
   6826       ((eq type 'doctype)
   6827        (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
   6828       ((eq type 'declaration)
   6829        (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
   6830       (name
   6831        (setq slash-beg (> (logand flags 4) 0)
   6832              slash-end (> (logand flags 8) 0)
   6833              bracket-end (> (logand flags 16) 0))
   6834        (setq face (cond
   6835                     ((not bracket-end)       'web-mode-html-tag-unclosed-face)
   6836                     ((and web-mode-enable-element-tag-fontification
   6837                           (setq face (cdr (assoc name web-mode-element-tag-faces))))
   6838                      face)
   6839                     ((> (logand flags 32) 0) 'web-mode-html-tag-namespaced-face)
   6840                     ((> (logand flags 2) 0)  'web-mode-html-tag-custom-face)
   6841                     (t                       'web-mode-html-tag-face)))
   6842        (put-text-property beg (+ beg (if slash-beg 2 1))
   6843                           'font-lock-face 'web-mode-html-tag-bracket-face)
   6844        (unless (string= name "_fragment_")
   6845          (put-text-property (+ beg (if slash-beg 2 1))
   6846                             (+ beg (if slash-beg 2 1) (length name))
   6847                             'font-lock-face face))
   6848        (when (or slash-end bracket-end)
   6849          (put-text-property (- end (if slash-end 2 1)) end 'font-lock-face 'web-mode-html-tag-bracket-face)
   6850          ) ;when
   6851        (when (> (logand flags 1) 0)
   6852          ;;(message "%S>%S" beg end)
   6853          (web-mode-fontify-attrs beg end))
   6854        ) ;case name
   6855       ) ;cond
   6856     ))
   6857 
   6858 (defun web-mode-fontify-attrs (reg-beg reg-end)
   6859   (let ((continue t) (pos reg-beg) beg end flags offset face)
   6860     ;;(message "fontify-attrs %S>%S" reg-beg reg-end)
   6861     (while continue
   6862       (setq beg (web-mode-attribute-next-position pos reg-end))
   6863       (cond
   6864         ((or (null beg) (>= beg reg-end))
   6865          (setq continue nil))
   6866         (t
   6867          (setq flags (or (get-text-property beg 'tag-attr-beg) 0))
   6868          (setq face (cond
   6869                       ((= (logand flags 1) 1) 'web-mode-html-attr-custom-face)
   6870                       ((= (logand flags 2) 2) 'web-mode-html-attr-engine-face)
   6871                       ((= (logand flags 4) 4) nil)
   6872                       (t                      'web-mode-html-attr-name-face)))
   6873          ;;(setq end (if (get-text-property beg 'tag-attr-end) beg (web-mode-attribute-end-position beg)))
   6874          (setq end (web-mode-attribute-end-position beg))
   6875          ;;(message "beg=%S end=%S" beg end)
   6876          (cond
   6877            ((or (null end) (>= end reg-end))
   6878             (setq continue nil))
   6879            (t
   6880             (setq offset (get-text-property end 'tag-attr-end))
   6881             (if (= offset 0)
   6882                 (put-text-property beg (1+ end) 'font-lock-face face)
   6883                 (put-text-property beg (+ beg offset) 'font-lock-face face)
   6884                 (put-text-property (+ beg offset) (+ beg offset 1)
   6885                                    'font-lock-face
   6886                                    'web-mode-html-attr-equal-face)
   6887                 (when (not (get-text-property (+ beg offset 1) 'jsx-beg))
   6888                   (put-text-property (+ beg offset 1) (1+ end)
   6889                                      'font-lock-face
   6890                                      'web-mode-html-attr-value-face)
   6891                   )
   6892                 ) ;if offset
   6893             (setq pos (1+ end))
   6894             ) ;t
   6895            ) ;cond
   6896          ) ;t
   6897         );cond
   6898       ) ;while
   6899     ))
   6900 
   6901 (defun web-mode-fontify-block (reg-beg reg-end)
   6902   (when web-mode-trace
   6903     (message "fontify-block: reg-beg(%S) reg-end(%S) engine(%S) keywords(%S)"
   6904              reg-beg reg-end web-mode-engine (not (null web-mode-engine-font-lock-keywords))))
   6905 
   6906   (let (sub1 sub2 sub3 continue char keywords token-type face beg end (buffer (current-buffer)))
   6907 
   6908     ;; NOTE: required for blocks inside tag attrs
   6909     ;; NOTE: ajout de face dans la liste pour sucharger la couleur définie par
   6910     ;;       un prealable web-mode-fontity-part (2022-12-25 #1230)
   6911     (remove-list-of-text-properties reg-beg reg-end '(font-lock-face face))
   6912     ;;(message "reg-beg=%S reg-end=%S" reg-beg reg-end)
   6913 
   6914     (goto-char reg-beg)
   6915 
   6916     (when (null web-mode-engine-font-lock-keywords)
   6917       (setq sub1 (buffer-substring-no-properties
   6918                   reg-beg (+ reg-beg 1))
   6919             sub2 (buffer-substring-no-properties
   6920                   reg-beg (+ reg-beg 2))
   6921             sub3 (buffer-substring-no-properties
   6922                   reg-beg (+ reg-beg (if (>= (point-max) (+ reg-beg 3)) 3 2))))
   6923       )
   6924 
   6925     (cond
   6926 
   6927       ((and (get-text-property reg-beg 'block-beg)
   6928             (eq (get-text-property reg-beg 'block-token) 'comment))
   6929        (put-text-property reg-beg reg-end 'font-lock-face 'web-mode-comment-face)
   6930        ) ;comment block
   6931 
   6932       (web-mode-engine-font-lock-keywords
   6933        (setq keywords web-mode-engine-font-lock-keywords))
   6934 
   6935       ((string= web-mode-engine "django")
   6936        (cond
   6937          ((string= sub2 "{{")
   6938           (setq keywords web-mode-django-expr-font-lock-keywords))
   6939          ((string= sub2 "{%")
   6940           (setq keywords web-mode-django-code-font-lock-keywords))
   6941          ((string= sub1 "#")
   6942           (setq keywords web-mode-django-code-font-lock-keywords))
   6943          )) ;django
   6944 
   6945       ((string= web-mode-engine "mako")
   6946        (cond
   6947          ((member sub3 '("<% " "<%\n" "<%!"))
   6948           (setq keywords web-mode-mako-block-font-lock-keywords))
   6949          ((eq (aref sub2 0) ?\%)
   6950           (setq keywords web-mode-mako-block-font-lock-keywords))
   6951          ((member sub2 '("<%" "</"))
   6952           (setq keywords web-mode-mako-tag-font-lock-keywords))
   6953          ((member sub2 '("${"))
   6954           (setq keywords web-mode-uel-font-lock-keywords))
   6955          )) ;mako
   6956 
   6957       ((string= web-mode-engine "mason")
   6958        ;;(message "%S %S" sub2 sub3)
   6959        (cond
   6960          ((member sub3 '("<% " "<%\n" "<&|"))
   6961           (setq keywords web-mode-mason-code-font-lock-keywords))
   6962          ((eq (aref sub2 0) ?\%)
   6963           (setq keywords web-mode-mason-code-font-lock-keywords))
   6964          ((and (or (string= sub2 "<%") (string= sub3 "</%"))
   6965                (not (member sub3 '("<%c" "<%i" "<%p"))))
   6966           (setq keywords web-mode-mason-block-font-lock-keywords))
   6967          (t
   6968           (setq keywords web-mode-mason-code-font-lock-keywords))
   6969          )) ;mason
   6970 
   6971       ((string= web-mode-engine "jsp")
   6972        (cond
   6973          ((string= sub3 "<%@")
   6974           (setq keywords web-mode-directive-font-lock-keywords))
   6975          ((member sub2 '("${" "#{"))
   6976           (setq keywords web-mode-uel-font-lock-keywords))
   6977          ((string= sub2 "<%")
   6978           (setq keywords web-mode-jsp-font-lock-keywords))
   6979          )) ;jsp
   6980 
   6981       ((string= web-mode-engine "asp")
   6982        (cond
   6983          ((or (string= sub2 "<%")
   6984               (not (string= sub1 "<")))
   6985           (setq keywords web-mode-asp-font-lock-keywords))
   6986          (t
   6987           (setq keywords web-mode-engine-tag-font-lock-keywords))
   6988          )) ;asp
   6989 
   6990       ((string= web-mode-engine "clip")
   6991        (setq keywords web-mode-engine-tag-font-lock-keywords)
   6992        ) ;clip
   6993 
   6994       ((string= web-mode-engine "perl")
   6995        (setq keywords web-mode-engine-tag-font-lock-keywords)
   6996        ) ;perl
   6997 
   6998       ((string= web-mode-engine "aspx")
   6999        (cond
   7000          ((string= sub3 "<%@")
   7001           (setq keywords web-mode-directive-font-lock-keywords))
   7002          ((string= sub3 "<%$")
   7003           (setq keywords web-mode-expression-font-lock-keywords))
   7004          (t
   7005           (setq keywords web-mode-aspx-font-lock-keywords))
   7006          )) ;aspx
   7007 
   7008       ((string= web-mode-engine "freemarker")
   7009        (cond
   7010          ((member sub2 '("${" "#{"))
   7011           (setq keywords web-mode-uel-font-lock-keywords))
   7012          ((or (member sub2 '("<@" "[@" "<#" "[#"))
   7013               (member sub3 '("</@" "[/@" "</#" "[/#")))
   7014           (setq keywords (if (eq ?\[ (aref sub2 0))
   7015                              web-mode-freemarker-square-font-lock-keywords
   7016                              web-mode-freemarker-font-lock-keywords)))
   7017          (t
   7018           (setq keywords web-mode-engine-tag-font-lock-keywords))
   7019          )) ;freemarker
   7020 
   7021       ) ;cond
   7022 
   7023     (when keywords
   7024       (web-mode-fontify-region reg-beg reg-end keywords)
   7025       (setq continue t)
   7026       (setq end reg-beg)
   7027       (while continue
   7028         (if (get-text-property end 'block-token)
   7029             (setq beg end)
   7030             (setq beg (next-single-property-change end 'block-token buffer reg-end)))
   7031         (setq end nil)
   7032         (when beg (setq char (char-after beg)))
   7033         (if (and beg (< beg reg-end))
   7034             (progn
   7035               (setq token-type (get-text-property beg 'block-token))
   7036               (setq face (cond
   7037                            ((eq token-type 'string)  'web-mode-block-string-face)
   7038                            ((eq token-type 'comment) 'web-mode-block-comment-face)
   7039                            ((eq token-type 'symbol)  'web-mode-symbol-face)
   7040                            (t                        'web-mode-block-delimiter-face)))
   7041               (setq end (next-single-property-change beg 'block-token buffer reg-end))
   7042               ;;              (message "end=%S" end)
   7043               (if (and end (<= end reg-end))
   7044                   (progn
   7045                     ;;(message "%S > %S face(%S)" beg end face)
   7046                     (remove-list-of-text-properties beg end '(face))
   7047                     (put-text-property beg end 'font-lock-face face)
   7048                     )
   7049                   (setq continue nil
   7050                         end nil)
   7051                   ) ;if end
   7052               ) ;progn beg
   7053             (setq continue nil
   7054                   end nil)
   7055             ) ;if beg
   7056         (when (and beg end)
   7057           (save-match-data
   7058             (when (and web-mode-enable-heredoc-fontification
   7059                        (eq char ?\<)
   7060                        (> (- end beg) 8)
   7061                        (string-match-p "JS\\|JAVASCRIPT\\|HTM\\|CSS" (buffer-substring-no-properties beg end)))
   7062               (setq keywords
   7063                     (cond
   7064                       ((string-match-p "H" (buffer-substring-no-properties beg (+ beg 8)))
   7065                        web-mode-html-font-lock-keywords)
   7066                       (t
   7067                        web-mode-javascript-font-lock-keywords)
   7068                       ))
   7069               (web-mode-fontify-region beg end keywords)
   7070               )
   7071             ) ;save-match-data
   7072           (when (and web-mode-enable-string-interpolation
   7073                      (member char '(?\" ?\<))
   7074                      (member web-mode-engine '("php" "erb"))
   7075                      (> (- end beg) 4))
   7076             (web-mode-interpolate-block-string beg end)
   7077             ) ;when
   7078           (when (and web-mode-enable-comment-interpolation
   7079                      (eq token-type 'comment)
   7080                      (> (- end beg) 3))
   7081             (web-mode-interpolate-comment beg end t)
   7082             ) ;when
   7083           (when (and web-mode-enable-comment-annotation
   7084                      (eq token-type 'comment)
   7085                      (> (- end beg) 3))
   7086             (web-mode-annotate-comment beg end)
   7087             ) ;when
   7088           (when (and web-mode-enable-sql-detection
   7089                      (eq token-type 'string)
   7090                      (> (- end beg) 6)
   7091                      (web-mode-looking-at-p (concat "\\(.\\|<<<[[:alnum:]]+\\)[ \n]*" web-mode-sql-queries) beg)
   7092                      )
   7093             (web-mode-interpolate-sql-string beg end)
   7094             ) ;when
   7095           ) ;when beg end
   7096         ) ;while continue
   7097       ) ;when keywords
   7098 
   7099     (when (and (member web-mode-engine '("mako"))
   7100                (> (- reg-end reg-beg) 12)
   7101                (eq ?\< (char-after reg-beg)))
   7102       (web-mode-interpolate-block-tag reg-beg reg-end))
   7103 
   7104     (when web-mode-enable-block-face
   7105       (font-lock-append-text-property reg-beg reg-end 'face 'web-mode-block-face))
   7106 
   7107     ))
   7108 
   7109 (defun web-mode-fontify-part (reg-beg reg-end &optional depth)
   7110   (save-excursion
   7111     (let (continue token-type face pos beg end string-face comment-face content-type)
   7112       ;;(message "fontify-part: reg-beg(%S) reg-end(%S)" reg-beg reg-end)
   7113       (if (member web-mode-content-type web-mode-part-content-types)
   7114           (setq content-type web-mode-content-type)
   7115           (setq content-type (symbol-name (get-text-property reg-beg 'part-side))))
   7116       ;;(message "content-type=%S" content-type)
   7117       (unless depth
   7118         (when (string= content-type "jsx") (setq depth 0))
   7119         )
   7120       (setq string-face 'web-mode-part-string-face
   7121             comment-face 'web-mode-part-comment-face)
   7122       (cond
   7123         ((member content-type '("javascript" "jsx"))
   7124          (setq string-face 'web-mode-javascript-string-face
   7125                comment-face 'web-mode-javascript-comment-face)
   7126          (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
   7127         ((string= content-type "json")
   7128          (setq string-face 'web-mode-json-string-face
   7129                comment-face 'web-mode-json-comment-face)
   7130          (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
   7131         ((string= content-type "css")
   7132          (setq string-face 'web-mode-css-string-face
   7133                comment-face 'web-mode-css-comment-face)
   7134          (web-mode-fontify-css-rules reg-beg reg-end))
   7135         ((string= content-type "sql")
   7136          (web-mode-fontify-region reg-beg reg-end web-mode-sql-font-lock-keywords))
   7137         ((string= content-type "stylus")
   7138          (web-mode-fontify-region reg-beg reg-end web-mode-stylus-font-lock-keywords))
   7139         ((string= content-type "sass")
   7140          (web-mode-fontify-region reg-beg reg-end web-mode-sass-font-lock-keywords))
   7141         ((string= content-type "pug")
   7142          (web-mode-fontify-region reg-beg reg-end web-mode-pug-font-lock-keywords))
   7143         ((string= content-type "markdown")
   7144          (web-mode-fontify-region reg-beg reg-end web-mode-markdown-font-lock-keywords))
   7145         ((string= content-type "ruby")
   7146          (web-mode-fontify-region reg-beg reg-end web-mode-erb-font-lock-keywords))
   7147         ((string= content-type "typescript")
   7148          (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
   7149         ) ;cond
   7150 
   7151       (goto-char reg-beg)
   7152 
   7153       ;;(when (string= content-type "jsx") (web-mode-fontify-tags reg-beg reg-end))
   7154       ;;(setq continue (and pos (< pos reg-end)))
   7155       (setq continue t
   7156             pos reg-beg)
   7157       (while continue
   7158         (if (get-text-property pos 'part-token)
   7159             (setq beg pos)
   7160             (setq beg (next-single-property-change pos 'part-token)))
   7161         (cond
   7162           ((or (null beg) (>= beg reg-end))
   7163            (setq continue nil
   7164                  end nil))
   7165           ((and (eq depth 0) (get-text-property beg 'jsx-depth))
   7166            (setq pos (or (next-single-property-change beg 'jsx-depth) (point-max))))
   7167           (t
   7168            ;;(message "%c" (char-after beg))
   7169            (setq token-type (get-text-property beg 'part-token))
   7170            (setq face (cond
   7171                         ((eq token-type 'string)  string-face)
   7172                         ((eq token-type 'comment) comment-face)
   7173                         ((eq token-type 'context) 'web-mode-json-context-face)
   7174                         ((eq token-type 'key)     'web-mode-json-key-face)
   7175                         (t                        nil)))
   7176            (setq end (or (next-single-property-change beg 'part-token) (point-max))
   7177                  pos end)
   7178            (cond
   7179              ((or (null end) (> end reg-end))
   7180               (setq continue nil
   7181                     end nil))
   7182              (t
   7183               (when face
   7184                 (remove-list-of-text-properties beg end '(face))
   7185                 (put-text-property beg end 'font-lock-face face))
   7186               (cond
   7187                 ((< (- end beg) 6)
   7188                  )
   7189                 ((eq token-type 'string)
   7190                  (cond
   7191                    ((and (eq (char-after beg) ?\`)
   7192                          web-mode-enable-literal-interpolation
   7193                          (member content-type '("javascript" "jsx" "typescript")))
   7194                     (web-mode-interpolate-javascript-literal beg end)
   7195                     )
   7196                    ((and (eq (char-after beg) ?\")
   7197                          web-mode-enable-string-interpolation
   7198                          (member content-type '("javascript" "jsx" "typescript")))
   7199                     (web-mode-interpolate-javascript-string beg end))
   7200                    ) ;cond
   7201                  ) ;case string
   7202                 ((eq token-type 'comment)
   7203                  (when web-mode-enable-comment-interpolation
   7204                    (web-mode-interpolate-comment beg end t))
   7205                  (when web-mode-enable-comment-annotation
   7206                    (web-mode-annotate-comment beg end))
   7207                  )
   7208                 ) ;cond
   7209               ) ;t
   7210              ) ;cond
   7211            ) ;t
   7212           ) ;cond
   7213         ) ;while
   7214 
   7215       (when (and (string= web-mode-content-type "html") web-mode-enable-part-face)
   7216         (font-lock-append-text-property reg-beg reg-end 'face
   7217                                         (cond
   7218                                           ((string= content-type "javascript")
   7219                                            'web-mode-script-face)
   7220                                           ((string= content-type "css")
   7221                                            'web-mode-style-face)
   7222                                           (t
   7223                                            'web-mode-part-face)))
   7224         )
   7225 
   7226       (when (and web-mode-enable-css-colorization (string= content-type "stylus"))
   7227         (goto-char reg-beg)
   7228         (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)
   7229                     (<= (point) reg-end))
   7230           (web-mode-colorize (match-beginning 0) (match-end 0))
   7231           )
   7232         )
   7233 
   7234       (when (and (eq depth 0) (string= content-type "jsx"))
   7235         (let (pair elt-beg elt-end exp-beg exp-end exp-depth)
   7236           (goto-char reg-beg)
   7237           (while (setq pair (web-mode-jsx-element-next reg-end))
   7238             ;;(message "elt-pair=%S" pair)
   7239             (setq elt-beg (car pair)
   7240                   elt-end (cdr pair))
   7241             (remove-list-of-text-properties elt-beg (1+ elt-end) '(face))
   7242             (web-mode-fontify-tags elt-beg elt-end 1)
   7243             (goto-char elt-beg)
   7244             (while (setq pair (web-mode-jsx-expression-next elt-end))
   7245               ;;(message "exp-pair=%S elt-end=%S" pair elt-end)
   7246               (setq exp-beg (car pair)
   7247                     exp-end (cdr pair))
   7248               (when (eq (char-after exp-beg) ?\{)
   7249                 ;;(message "%S : %c %c" exp-beg (char-after (+ exp-beg 1)) (char-after (+ exp-beg 2)))
   7250                 (cond
   7251                   ;;((and (eq (char-after (+ exp-beg 1)) ?\/) (eq (char-after (+ exp-beg 2)) ?\*))
   7252                   ;; (put-text-property exp-beg (1+ exp-end) 'font-lock-face 'web-mode-part-comment-face)
   7253                   ;; )
   7254                   (t
   7255                    (setq exp-depth (get-text-property exp-beg 'jsx-depth))
   7256                    (remove-list-of-text-properties exp-beg exp-end '(font-lock-face))
   7257                    (put-text-property exp-beg (1+ exp-beg) 'font-lock-face 'web-mode-block-delimiter-face)
   7258                    (when (and (eq (get-text-property exp-beg 'tag-attr-beg) 4) (web-mode-looking-at-p "\.\.\." (1+ exp-beg)))
   7259                      (put-text-property exp-beg (+ exp-beg 4) 'font-lock-face 'web-mode-block-delimiter-face))
   7260                    (put-text-property exp-end (1+ exp-end) 'font-lock-face 'web-mode-block-delimiter-face)
   7261                    (web-mode-fontify-tags (1+ exp-beg) exp-end (1+ exp-depth))
   7262                    (web-mode-fontify-part (1+ exp-beg) exp-end exp-depth)
   7263                    (web-mode-fontify-region (1+ exp-beg) exp-end web-mode-javascript-font-lock-keywords)
   7264                    ) ;t
   7265                   ) ;cond
   7266                 ) ;when
   7267               (goto-char (1+ exp-beg))
   7268               ) ;while exp
   7269 
   7270             (when (and elt-beg web-mode-jsx-depth-faces)
   7271               (let (depth-beg depth-end jsx-face)
   7272                 (goto-char elt-beg)
   7273                 (while (setq pair (web-mode-jsx-depth-next reg-end))
   7274                   ;;(message "depth-pair=%S" pair)
   7275                   (setq depth-beg (car pair)
   7276                         depth-end (cdr pair)
   7277                         depth (get-text-property depth-beg 'jsx-depth)
   7278                         jsx-face (elt web-mode-jsx-depth-faces (1- depth)))
   7279                   ;;(message "%S" jsx-face)
   7280                   (font-lock-prepend-text-property depth-beg (1+ depth-end) 'face jsx-face)
   7281                   (goto-char (+ depth-beg 2))
   7282                   )
   7283                 ) ;let
   7284               )
   7285 
   7286             (goto-char (1+ elt-end))
   7287             ) ;while elt
   7288           ) ;let
   7289         ) ;when
   7290 
   7291       ) ;let
   7292     ) ;save-excursion
   7293   )
   7294 
   7295 (defun web-mode-fontify-css-rules (part-beg part-end)
   7296   (save-excursion
   7297     (goto-char part-beg)
   7298     (let (rule (continue t) (i 0) (at-rule nil))
   7299       (while continue
   7300         (setq rule (web-mode-css-rule-next part-end))
   7301         ;;(message "rule=%S" rule)
   7302         (cond
   7303           ((> (setq i (1+ i)) 1000)
   7304            (message "fontify-css-rules ** too much rules **")
   7305            (setq continue nil))
   7306           ((null rule)
   7307            (setq continue nil))
   7308           ((and (setq at-rule (plist-get rule :at-rule))
   7309                 (not (member at-rule '("charset" "font-face" "import" "viewport")))
   7310                 (plist-get rule :dec-end))
   7311            (web-mode-fontify-css-rule (plist-get rule :sel-beg)
   7312                                       (plist-get rule :sel-end)
   7313                                       nil nil)
   7314            (web-mode-fontify-css-rules (plist-get rule :dec-beg)
   7315                                        (plist-get rule :dec-end)))
   7316           (t
   7317            (web-mode-fontify-css-rule (plist-get rule :sel-beg)
   7318                                       (plist-get rule :sel-end)
   7319                                       (plist-get rule :dec-beg)
   7320                                       (plist-get rule :dec-end)))
   7321           ) ;cond
   7322         ) ;while
   7323       ) ;let
   7324     ))
   7325 
   7326 (defun web-mode-fontify-css-rule (sel-beg sel-end dec-beg dec-end)
   7327   (save-excursion
   7328     ;;(let ((end sel-end))
   7329     ;;(message "sel-beg=%S sel-end=%S dec-beg=%S dec-end=%S" sel-beg sel-end dec-beg dec-end)
   7330     (web-mode-fontify-region sel-beg sel-end web-mode-selector-font-lock-keywords)
   7331     (when (and dec-beg dec-end)
   7332       ;;(setq end dec-end)
   7333       (web-mode-fontify-region dec-beg dec-end web-mode-declaration-font-lock-keywords)
   7334       ) ;when
   7335     (when (and dec-beg dec-end)
   7336       (goto-char dec-beg)
   7337       (while (and web-mode-enable-css-colorization
   7338                   (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)
   7339                   ;;(progn (message "%S %S" end (point)) t)
   7340                   (<= (point) dec-end))
   7341         ;;(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)))
   7342         (web-mode-colorize (match-beginning 1) (match-end 1))
   7343         ) ;while
   7344       ) ;when
   7345     ;;) ;let
   7346     ))
   7347 
   7348 (defun web-mode-colorize-foreground (color)
   7349   (let* ((values (x-color-values color))
   7350          (r (car values))
   7351          (g (cadr values))
   7352          (b (car (cdr (cdr values)))))
   7353     (if (> 128.0 (floor (+ (* .3 r) (* .59 g) (* .11 b)) 256))
   7354         "white" "black")))
   7355 
   7356 (defun web-mode-colorize (beg end)
   7357   (let (str plist)
   7358     (setq str (buffer-substring-no-properties beg end))
   7359     ;;(setq str1 (match-string-no-properties 1))
   7360     ;;(message "str=%S" str str1)
   7361     (cond
   7362       ;;(t
   7363       ;; (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))
   7364       ;; )
   7365       ((string= (substring str 0 1) "#")
   7366        (setq plist (list :background str
   7367                          :foreground (web-mode-colorize-foreground str))))
   7368       ((and (>= (length str) 3) (string= (substring str 0 3) "rgb"))
   7369        (setq str (format "#%02X%02X%02X"
   7370                          (string-to-number (match-string-no-properties 2))
   7371                          (string-to-number (match-string-no-properties 3))
   7372                          (string-to-number (match-string-no-properties 4))))
   7373        (setq plist (list :background str
   7374                          :foreground (web-mode-colorize-foreground str))))
   7375       ((string= str "black") (setq plist (list :background "#000000" :foreground (web-mode-colorize-foreground "#000000"))))
   7376       ((string= str "silver") (setq plist (list :background "#c0c0c0" :foreground (web-mode-colorize-foreground "#c0c0c0"))))
   7377       ((string= str "gray") (setq plist (list :background "#808080" :foreground (web-mode-colorize-foreground "#808080"))))
   7378       ((string= str "white") (setq plist (list :background "#ffffff" :foreground (web-mode-colorize-foreground "#ffffff"))))
   7379       ((string= str "maroon") (setq plist (list :background "#800000" :foreground (web-mode-colorize-foreground "#800000"))))
   7380       ((string= str "red") (setq plist (list :background "#ff0000" :foreground (web-mode-colorize-foreground "#ff0000"))))
   7381       ((string= str "purple") (setq plist (list :background "#800080" :foreground (web-mode-colorize-foreground "#800080"))))
   7382       ((string= str "fuchsia") (setq plist (list :background "#ff00ff" :foreground (web-mode-colorize-foreground "#ff00ff"))))
   7383       ((string= str "green") (setq plist (list :background "#008000" :foreground (web-mode-colorize-foreground "#008000"))))
   7384       ((string= str "lime") (setq plist (list :background "#00ff00" :foreground (web-mode-colorize-foreground "#00ff00"))))
   7385       ((string= str "olive") (setq plist (list :background "#808000" :foreground (web-mode-colorize-foreground "#808000"))))
   7386       ((string= str "yellow") (setq plist (list :background "#ffff00" :foreground (web-mode-colorize-foreground "#ffff00"))))
   7387       ((string= str "navy") (setq plist (list :background "#000080" :foreground (web-mode-colorize-foreground "#000080"))))
   7388       ((string= str "blue") (setq plist (list :background "#0000ff" :foreground (web-mode-colorize-foreground "#0000ff"))))
   7389       ((string= str "teal") (setq plist (list :background "#008080" :foreground (web-mode-colorize-foreground "#008080"))))
   7390       ((string= str "aqua") (setq plist (list :background "#00ffff" :foreground (web-mode-colorize-foreground "#00ffff"))))
   7391       ((string= str "orange") (setq plist (list :background "#ffa500" :foreground (web-mode-colorize-foreground "#ffa500"))))
   7392       ((string= str "aliceblue") (setq plist (list :background "#f0f8ff" :foreground (web-mode-colorize-foreground "#f0f8ff"))))
   7393       ((string= str "antiquewhite") (setq plist (list :background "#faebd7" :foreground (web-mode-colorize-foreground "#faebd7"))))
   7394       ((string= str "aquamarine") (setq plist (list :background "#7fffd4" :foreground (web-mode-colorize-foreground "#7fffd4"))))
   7395       ((string= str "azure") (setq plist (list :background "#f0ffff" :foreground (web-mode-colorize-foreground "#f0ffff"))))
   7396       ((string= str "beige") (setq plist (list :background "#f5f5dc" :foreground (web-mode-colorize-foreground "#f5f5dc"))))
   7397       ((string= str "bisque") (setq plist (list :background "#ffe4c4" :foreground (web-mode-colorize-foreground "#ffe4c4"))))
   7398       ((string= str "blanchedalmond") (setq plist (list :background "#ffebcd" :foreground (web-mode-colorize-foreground "#ffebcd"))))
   7399       ((string= str "blueviolet") (setq plist (list :background "#8a2be2" :foreground (web-mode-colorize-foreground "#8a2be2"))))
   7400       ((string= str "brown") (setq plist (list :background "#a52a2a" :foreground (web-mode-colorize-foreground "#a52a2a"))))
   7401       ((string= str "burlywood") (setq plist (list :background "#deb887" :foreground (web-mode-colorize-foreground "#deb887"))))
   7402       ((string= str "cadetblue") (setq plist (list :background "#5f9ea0" :foreground (web-mode-colorize-foreground "#5f9ea0"))))
   7403       ((string= str "chartreuse") (setq plist (list :background "#7fff00" :foreground (web-mode-colorize-foreground "#7fff00"))))
   7404       ((string= str "chocolate") (setq plist (list :background "#d2691e" :foreground (web-mode-colorize-foreground "#d2691e"))))
   7405       ((string= str "coral") (setq plist (list :background "#ff7f50" :foreground (web-mode-colorize-foreground "#ff7f50"))))
   7406       ((string= str "cornflowerblue") (setq plist (list :background "#6495ed" :foreground (web-mode-colorize-foreground "#6495ed"))))
   7407       ((string= str "cornsilk") (setq plist (list :background "#fff8dc" :foreground (web-mode-colorize-foreground "#fff8dc"))))
   7408       ((string= str "crimson") (setq plist (list :background "#dc143c" :foreground (web-mode-colorize-foreground "#dc143c"))))
   7409       ((string= str "cyan") (setq plist (list :background "#00ffff" :foreground (web-mode-colorize-foreground "#00ffff"))))
   7410       ((string= str "darkblue") (setq plist (list :background "#00008b" :foreground (web-mode-colorize-foreground "#00008b"))))
   7411       ((string= str "darkcyan") (setq plist (list :background "#008b8b" :foreground (web-mode-colorize-foreground "#008b8b"))))
   7412       ((string= str "darkgoldenrod") (setq plist (list :background "#b8860b" :foreground (web-mode-colorize-foreground "#b8860b"))))
   7413       ((string= str "darkgray") (setq plist (list :background "#a9a9a9" :foreground (web-mode-colorize-foreground "#a9a9a9"))))
   7414       ((string= str "darkgreen") (setq plist (list :background "#006400" :foreground (web-mode-colorize-foreground "#006400"))))
   7415       ((string= str "darkgrey") (setq plist (list :background "#a9a9a9" :foreground (web-mode-colorize-foreground "#a9a9a9"))))
   7416       ((string= str "darkkhaki") (setq plist (list :background "#bdb76b" :foreground (web-mode-colorize-foreground "#bdb76b"))))
   7417       ((string= str "darkmagenta") (setq plist (list :background "#8b008b" :foreground (web-mode-colorize-foreground "#8b008b"))))
   7418       ((string= str "darkolivegreen") (setq plist (list :background "#556b2f" :foreground (web-mode-colorize-foreground "#556b2f"))))
   7419       ((string= str "darkorange") (setq plist (list :background "#ff8c00" :foreground (web-mode-colorize-foreground "#ff8c00"))))
   7420       ((string= str "darkorchid") (setq plist (list :background "#9932cc" :foreground (web-mode-colorize-foreground "#9932cc"))))
   7421       ((string= str "darkred") (setq plist (list :background "#8b0000" :foreground (web-mode-colorize-foreground "#8b0000"))))
   7422       ((string= str "darksalmon") (setq plist (list :background "#e9967a" :foreground (web-mode-colorize-foreground "#e9967a"))))
   7423       ((string= str "darkseagreen") (setq plist (list :background "#8fbc8f" :foreground (web-mode-colorize-foreground "#8fbc8f"))))
   7424       ((string= str "darkslateblue") (setq plist (list :background "#483d8b" :foreground (web-mode-colorize-foreground "#483d8b"))))
   7425       ((string= str "darkslategray") (setq plist (list :background "#2f4f4f" :foreground (web-mode-colorize-foreground "#2f4f4f"))))
   7426       ((string= str "darkslategrey") (setq plist (list :background "#2f4f4f" :foreground (web-mode-colorize-foreground "#2f4f4f"))))
   7427       ((string= str "darkturquoise") (setq plist (list :background "#00ced1" :foreground (web-mode-colorize-foreground "#00ced1"))))
   7428       ((string= str "darkviolet") (setq plist (list :background "#9400d3" :foreground (web-mode-colorize-foreground "#9400d3"))))
   7429       ((string= str "deeppink") (setq plist (list :background "#ff1493" :foreground (web-mode-colorize-foreground "#ff1493"))))
   7430       ((string= str "deepskyblue") (setq plist (list :background "#00bfff" :foreground (web-mode-colorize-foreground "#00bfff"))))
   7431       ((string= str "dimgray") (setq plist (list :background "#696969" :foreground (web-mode-colorize-foreground "#696969"))))
   7432       ((string= str "dimgrey") (setq plist (list :background "#696969" :foreground (web-mode-colorize-foreground "#696969"))))
   7433       ((string= str "dodgerblue") (setq plist (list :background "#1e90ff" :foreground (web-mode-colorize-foreground "#1e90ff"))))
   7434       ((string= str "firebrick") (setq plist (list :background "#b22222" :foreground (web-mode-colorize-foreground "#b22222"))))
   7435       ((string= str "floralwhite") (setq plist (list :background "#fffaf0" :foreground (web-mode-colorize-foreground "#fffaf0"))))
   7436       ((string= str "forestgreen") (setq plist (list :background "#228b22" :foreground (web-mode-colorize-foreground "#228b22"))))
   7437       ((string= str "gainsboro") (setq plist (list :background "#dcdcdc" :foreground (web-mode-colorize-foreground "#dcdcdc"))))
   7438       ((string= str "ghostwhite") (setq plist (list :background "#f8f8ff" :foreground (web-mode-colorize-foreground "#f8f8ff"))))
   7439       ((string= str "gold") (setq plist (list :background "#ffd700" :foreground (web-mode-colorize-foreground "#ffd700"))))
   7440       ((string= str "goldenrod") (setq plist (list :background "#daa520" :foreground (web-mode-colorize-foreground "#daa520"))))
   7441       ((string= str "greenyellow") (setq plist (list :background "#adff2f" :foreground (web-mode-colorize-foreground "#adff2f"))))
   7442       ((string= str "grey") (setq plist (list :background "#808080" :foreground (web-mode-colorize-foreground "#808080"))))
   7443       ((string= str "honeydew") (setq plist (list :background "#f0fff0" :foreground (web-mode-colorize-foreground "#f0fff0"))))
   7444       ((string= str "hotpink") (setq plist (list :background "#ff69b4" :foreground (web-mode-colorize-foreground "#ff69b4"))))
   7445       ((string= str "indianred") (setq plist (list :background "#cd5c5c" :foreground (web-mode-colorize-foreground "#cd5c5c"))))
   7446       ((string= str "indigo") (setq plist (list :background "#4b0082" :foreground (web-mode-colorize-foreground "#4b0082"))))
   7447       ((string= str "ivory") (setq plist (list :background "#fffff0" :foreground (web-mode-colorize-foreground "#fffff0"))))
   7448       ((string= str "khaki") (setq plist (list :background "#f0e68c" :foreground (web-mode-colorize-foreground "#f0e68c"))))
   7449       ((string= str "lavender") (setq plist (list :background "#e6e6fa" :foreground (web-mode-colorize-foreground "#e6e6fa"))))
   7450       ((string= str "lavenderblush") (setq plist (list :background "#fff0f5" :foreground (web-mode-colorize-foreground "#fff0f5"))))
   7451       ((string= str "lawngreen") (setq plist (list :background "#7cfc00" :foreground (web-mode-colorize-foreground "#7cfc00"))))
   7452       ((string= str "lemonchiffon") (setq plist (list :background "#fffacd" :foreground (web-mode-colorize-foreground "#fffacd"))))
   7453       ((string= str "lightblue") (setq plist (list :background "#add8e6" :foreground (web-mode-colorize-foreground "#add8e6"))))
   7454       ((string= str "lightcoral") (setq plist (list :background "#f08080" :foreground (web-mode-colorize-foreground "#f08080"))))
   7455       ((string= str "lightcyan") (setq plist (list :background "#e0ffff" :foreground (web-mode-colorize-foreground "#e0ffff"))))
   7456       ((string= str "lightgoldenrodyellow") (setq plist (list :background "#fafad2" :foreground (web-mode-colorize-foreground "#fafad2"))))
   7457       ((string= str "lightgray") (setq plist (list :background "#d3d3d3" :foreground (web-mode-colorize-foreground "#d3d3d3"))))
   7458       ((string= str "lightgreen") (setq plist (list :background "#90ee90" :foreground (web-mode-colorize-foreground "#90ee90"))))
   7459       ((string= str "lightgrey") (setq plist (list :background "#d3d3d3" :foreground (web-mode-colorize-foreground "#d3d3d3"))))
   7460       ((string= str "lightpink") (setq plist (list :background "#ffb6c1" :foreground (web-mode-colorize-foreground "#ffb6c1"))))
   7461       ((string= str "lightsalmon") (setq plist (list :background "#ffa07a" :foreground (web-mode-colorize-foreground "#ffa07a"))))
   7462       ((string= str "lightseagreen") (setq plist (list :background "#20b2aa" :foreground (web-mode-colorize-foreground "#20b2aa"))))
   7463       ((string= str "lightskyblue") (setq plist (list :background "#87cefa" :foreground (web-mode-colorize-foreground "#87cefa"))))
   7464       ((string= str "lightslategray") (setq plist (list :background "#778899" :foreground (web-mode-colorize-foreground "#778899"))))
   7465       ((string= str "lightslategrey") (setq plist (list :background "#778899" :foreground (web-mode-colorize-foreground "#778899"))))
   7466       ((string= str "lightsteelblue") (setq plist (list :background "#b0c4de" :foreground (web-mode-colorize-foreground "#b0c4de"))))
   7467       ((string= str "lightyellow") (setq plist (list :background "#ffffe0" :foreground (web-mode-colorize-foreground "#ffffe0"))))
   7468       ((string= str "limegreen") (setq plist (list :background "#32cd32" :foreground (web-mode-colorize-foreground "#32cd32"))))
   7469       ((string= str "linen") (setq plist (list :background "#faf0e6" :foreground (web-mode-colorize-foreground "#faf0e6"))))
   7470       ((string= str "magenta") (setq plist (list :background "#ff00ff" :foreground (web-mode-colorize-foreground "#ff00ff"))))
   7471       ((string= str "mediumaquamarine") (setq plist (list :background "#66cdaa" :foreground (web-mode-colorize-foreground "#66cdaa"))))
   7472       ((string= str "mediumblue") (setq plist (list :background "#0000cd" :foreground (web-mode-colorize-foreground "#0000cd"))))
   7473       ((string= str "mediumorchid") (setq plist (list :background "#ba55d3" :foreground (web-mode-colorize-foreground "#ba55d3"))))
   7474       ((string= str "mediumpurple") (setq plist (list :background "#9370db" :foreground (web-mode-colorize-foreground "#9370db"))))
   7475       ((string= str "mediumseagreen") (setq plist (list :background "#3cb371" :foreground (web-mode-colorize-foreground "#3cb371"))))
   7476       ((string= str "mediumslateblue") (setq plist (list :background "#7b68ee" :foreground (web-mode-colorize-foreground "#7b68ee"))))
   7477       ((string= str "mediumspringgreen") (setq plist (list :background "#00fa9a" :foreground (web-mode-colorize-foreground "#00fa9a"))))
   7478       ((string= str "mediumturquoise") (setq plist (list :background "#48d1cc" :foreground (web-mode-colorize-foreground "#48d1cc"))))
   7479       ((string= str "mediumvioletred") (setq plist (list :background "#c71585" :foreground (web-mode-colorize-foreground "#c71585"))))
   7480       ((string= str "midnightblue") (setq plist (list :background "#191970" :foreground (web-mode-colorize-foreground "#191970"))))
   7481       ((string= str "mintcream") (setq plist (list :background "#f5fffa" :foreground (web-mode-colorize-foreground "#f5fffa"))))
   7482       ((string= str "mistyrose") (setq plist (list :background "#ffe4e1" :foreground (web-mode-colorize-foreground "#ffe4e1"))))
   7483       ((string= str "moccasin") (setq plist (list :background "#ffe4b5" :foreground (web-mode-colorize-foreground "#ffe4b5"))))
   7484       ((string= str "navajowhite") (setq plist (list :background "#ffdead" :foreground (web-mode-colorize-foreground "#ffdead"))))
   7485       ((string= str "oldlace") (setq plist (list :background "#fdf5e6" :foreground (web-mode-colorize-foreground "#fdf5e6"))))
   7486       ((string= str "olivedrab") (setq plist (list :background "#6b8e23" :foreground (web-mode-colorize-foreground "#6b8e23"))))
   7487       ((string= str "orangered") (setq plist (list :background "#ff4500" :foreground (web-mode-colorize-foreground "#ff4500"))))
   7488       ((string= str "orchid") (setq plist (list :background "#da70d6" :foreground (web-mode-colorize-foreground "#da70d6"))))
   7489       ((string= str "palegoldenrod") (setq plist (list :background "#eee8aa" :foreground (web-mode-colorize-foreground "#eee8aa"))))
   7490       ((string= str "palegreen") (setq plist (list :background "#98fb98" :foreground (web-mode-colorize-foreground "#98fb98"))))
   7491       ((string= str "paleturquoise") (setq plist (list :background "#afeeee" :foreground (web-mode-colorize-foreground "#afeeee"))))
   7492       ((string= str "palevioletred") (setq plist (list :background "#db7093" :foreground (web-mode-colorize-foreground "#db7093"))))
   7493       ((string= str "papayawhip") (setq plist (list :background "#ffefd5" :foreground (web-mode-colorize-foreground "#ffefd5"))))
   7494       ((string= str "peachpuff") (setq plist (list :background "#ffdab9" :foreground (web-mode-colorize-foreground "#ffdab9"))))
   7495       ((string= str "peru") (setq plist (list :background "#cd853f" :foreground (web-mode-colorize-foreground "#cd853f"))))
   7496       ((string= str "pink") (setq plist (list :background "#ffc0cb" :foreground (web-mode-colorize-foreground "#ffc0cb"))))
   7497       ((string= str "plum") (setq plist (list :background "#dda0dd" :foreground (web-mode-colorize-foreground "#dda0dd"))))
   7498       ((string= str "powderblue") (setq plist (list :background "#b0e0e6" :foreground (web-mode-colorize-foreground "#b0e0e6"))))
   7499       ((string= str "rosybrown") (setq plist (list :background "#bc8f8f" :foreground (web-mode-colorize-foreground "#bc8f8f"))))
   7500       ((string= str "royalblue") (setq plist (list :background "#4169e1" :foreground (web-mode-colorize-foreground "#4169e1"))))
   7501       ((string= str "saddlebrown") (setq plist (list :background "#8b4513" :foreground (web-mode-colorize-foreground "#8b4513"))))
   7502       ((string= str "salmon") (setq plist (list :background "#fa8072" :foreground (web-mode-colorize-foreground "#fa8072"))))
   7503       ((string= str "sandybrown") (setq plist (list :background "#f4a460" :foreground (web-mode-colorize-foreground "#f4a460"))))
   7504       ((string= str "seagreen") (setq plist (list :background "#2e8b57" :foreground (web-mode-colorize-foreground "#2e8b57"))))
   7505       ((string= str "seashell") (setq plist (list :background "#fff5ee" :foreground (web-mode-colorize-foreground "#fff5ee"))))
   7506       ((string= str "sienna") (setq plist (list :background "#a0522d" :foreground (web-mode-colorize-foreground "#a0522d"))))
   7507       ((string= str "skyblue") (setq plist (list :background "#87ceeb" :foreground (web-mode-colorize-foreground "#87ceeb"))))
   7508       ((string= str "slateblue") (setq plist (list :background "#6a5acd" :foreground (web-mode-colorize-foreground "#6a5acd"))))
   7509       ((string= str "slategray") (setq plist (list :background "#708090" :foreground (web-mode-colorize-foreground "#708090"))))
   7510       ((string= str "slategrey") (setq plist (list :background "#708090" :foreground (web-mode-colorize-foreground "#708090"))))
   7511       ((string= str "snow") (setq plist (list :background "#fffafa" :foreground (web-mode-colorize-foreground "#fffafa"))))
   7512       ((string= str "springgreen") (setq plist (list :background "#00ff7f" :foreground (web-mode-colorize-foreground "#00ff7f"))))
   7513       ((string= str "steelblue") (setq plist (list :background "#4682b4" :foreground (web-mode-colorize-foreground "#4682b4"))))
   7514       ((string= str "tan") (setq plist (list :background "#d2b48c" :foreground (web-mode-colorize-foreground "#d2b48c"))))
   7515       ((string= str "thistle") (setq plist (list :background "#d8bfd8" :foreground (web-mode-colorize-foreground "#d8bfd8"))))
   7516       ((string= str "tomato") (setq plist (list :background "#ff6347" :foreground (web-mode-colorize-foreground "#ff6347"))))
   7517       ((string= str "turquoise") (setq plist (list :background "#40e0d0" :foreground (web-mode-colorize-foreground "#40e0d0"))))
   7518       ((string= str "violet") (setq plist (list :background "#ee82ee" :foreground (web-mode-colorize-foreground "#ee82ee"))))
   7519       ((string= str "wheat") (setq plist (list :background "#f5deb3" :foreground (web-mode-colorize-foreground "#f5deb3"))))
   7520       ((string= str "whitesmoke") (setq plist (list :background "#f5f5f5" :foreground (web-mode-colorize-foreground "#f5f5f5"))))
   7521       ((string= str "yellowgreen") (setq plist (list :background "#9acd32" :foreground (web-mode-colorize-foreground "#9acd32"))))
   7522       ) ;cond
   7523     (put-text-property beg end 'face plist)
   7524     ))
   7525 
   7526 (defun web-mode-interpolate-block-tag (beg end)
   7527   (save-excursion
   7528     (goto-char (+ 4 beg))
   7529     (setq end (1- end))
   7530     (while (re-search-forward "${.*?}" end t)
   7531       (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(face))
   7532       (web-mode-fontify-region (match-beginning 0) (match-end 0)
   7533                                web-mode-uel-font-lock-keywords))
   7534     ))
   7535 
   7536 (defun web-mode-interpolate-javascript-string (beg end)
   7537   (save-excursion
   7538     (goto-char (1+ beg))
   7539     (setq end (1- end))
   7540     (while (re-search-forward "${.*?}" end t)
   7541       (put-text-property (match-beginning 0) (match-end 0)
   7542                          'font-lock-face
   7543                          'web-mode-variable-name-face)
   7544       )
   7545     ))
   7546 
   7547 (defun web-mode-interpolate-javascript-literal (beg end)
   7548   (save-excursion
   7549     (setq end (1- end))
   7550     (goto-char (1+ beg))
   7551     (cond
   7552       ((web-mode-looking-back "\\(css\\|styled[[:alnum:].]+\\|css = \\)" beg)
   7553        (goto-char (1+ beg))
   7554        (while (re-search-forward ".*?:" end t)
   7555          (put-text-property (match-beginning 0) (match-end 0)
   7556                             'font-lock-face
   7557                             'web-mode-interpolate-color1-face)
   7558          )
   7559        ) ;case css
   7560       ((web-mode-looking-back "\\(template\\|html\\|html = \\)" beg)
   7561        (goto-char (1+ beg))
   7562        (while (re-search-forward web-mode-tag-regexp end t)
   7563          (put-text-property (match-beginning 1) (match-end 1)
   7564                             'font-lock-face
   7565                             'web-mode-interpolate-color1-face)
   7566          )
   7567        (goto-char (1+ beg))
   7568        (while (re-search-forward "</?\\|/?>\\| [.@?]?[[:alnum:]]+=" end t)
   7569          (cond
   7570            ((member (char-after (match-beginning 0)) '(?\< ?\/ ?\>))
   7571             (put-text-property (match-beginning 0) (match-end 0)
   7572                                'font-lock-face
   7573                                'web-mode-interpolate-color2-face)
   7574             )
   7575            (t
   7576             (put-text-property (1+ (match-beginning 0)) (1- (match-end 0))
   7577                                'font-lock-face
   7578                                'web-mode-interpolate-color3-face)
   7579             ) ;t
   7580            ) ;cond
   7581          ) ;while
   7582        (goto-char (1+ beg))
   7583        (while (re-search-forward "<\\(script\\|style\\)>\\(.*\\)</\\(script\\|style\\)>" end t)
   7584          (put-text-property (match-beginning 2) (match-end 2)
   7585                             'font-lock-face
   7586                             'web-mode-interpolate-color4-face)
   7587          )
   7588        ) ;case html
   7589       ) ;cond type of literal
   7590     (goto-char (1+ beg))
   7591     (while (re-search-forward "${.*?}" end t)
   7592       (put-text-property (match-beginning 0) (match-end 0)
   7593                          'font-lock-face
   7594                          'web-mode-variable-name-face)
   7595       ) ;while
   7596     ))
   7597 
   7598 ;; todo : parsing plus compliqué: {$obj->values[3]->name}
   7599 (defun web-mode-interpolate-block-string (beg end)
   7600   (save-excursion
   7601     (goto-char (1+ beg))
   7602     (setq end (1- end))
   7603     (cond
   7604       ((string= web-mode-engine "php")
   7605        (while (re-search-forward "$[[:alnum:]_]+\\(->[[:alnum:]_]+\\)*\\|{[ ]*$.+?}" end t)
   7606          ;;        (message "%S > %S" (match-beginning 0) (match-end 0))
   7607          (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(font-lock-face))
   7608          (web-mode-fontify-region (match-beginning 0) (match-end 0)
   7609                                   web-mode-php-var-interpolation-font-lock-keywords)
   7610          ))
   7611       ((string= web-mode-engine "erb")
   7612        (while (re-search-forward "#{.*?}" end t)
   7613          (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(font-lock-face))
   7614          (put-text-property (match-beginning 0) (match-end 0)
   7615                             'font-lock-face 'web-mode-variable-name-face)
   7616          ))
   7617       ) ;cond
   7618     ))
   7619 
   7620 (defun web-mode-interpolate-comment (beg end _block-side)
   7621   (save-excursion
   7622     (let ((regexp (concat "\\_<\\(" web-mode-comment-keywords "\\)\\_>")))
   7623       (goto-char beg)
   7624       (while (re-search-forward regexp end t)
   7625         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7626                                          'font-lock-face
   7627                                          'web-mode-comment-keyword-face)
   7628         ) ;while
   7629       )))
   7630 
   7631 (defun web-mode-annotate-comment (beg end)
   7632   (save-excursion
   7633     ;;(message "beg=%S end=%S" beg end)
   7634     (goto-char beg)
   7635     (when (looking-at-p "/\\*\\*")
   7636       (while (re-search-forward "\\(.+\\)" end t)
   7637         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7638                                          'font-lock-face
   7639                                          'web-mode-annotation-face))
   7640       (goto-char beg)
   7641       (while (re-search-forward "[ ]+\\({[^}]+}\\)" end t)
   7642         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7643                                          'font-lock-face
   7644                                          'web-mode-annotation-type-face))
   7645       (goto-char beg)
   7646       (while (re-search-forward "\\(@[[:alnum:]]+\\)" end t)
   7647         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7648                                          'font-lock-face
   7649                                          'web-mode-annotation-tag-face))
   7650       (goto-char beg)
   7651       (while (re-search-forward "}[[:blank:]]+\\([[:graph:]]+\\)" end t)
   7652         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7653                                          'font-lock-face
   7654                                          'web-mode-annotation-value-face))
   7655       (goto-char beg)
   7656       (while (re-search-forward "@see[[:blank:]]+\\([[:graph:]]+\\)" end t)
   7657         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7658                                          'font-lock-face
   7659                                          'web-mode-annotation-value-face))
   7660       (goto-char beg)
   7661       (while (re-search-forward "{\\(@\\(?:link\\|code\\)\\)\\s-+\\([^}\n]+\\)\\(#.+\\)?}" end t)
   7662         (font-lock-prepend-text-property (match-beginning 2) (match-end 2)
   7663                                          'font-lock-face
   7664                                          'web-mode-annotation-value-face))
   7665       (goto-char beg)
   7666       (while (re-search-forward "\\(</?\\)\\([[:alnum:]]+\\)\\s-*\\(/?>\\)" end t)
   7667         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7668                                          'font-lock-face
   7669                                          'web-mode-annotation-html-face)
   7670         (font-lock-prepend-text-property (match-beginning 2) (match-end 2)
   7671                                          'font-lock-face
   7672                                          'web-mode-annotation-html-face)
   7673         (font-lock-prepend-text-property (match-beginning 3) (match-end 3)
   7674                                          'font-lock-face
   7675                                          'web-mode-annotation-html-face))
   7676       ) ;when
   7677     ))
   7678 
   7679 (defun web-mode-interpolate-sql-string (beg end)
   7680   (save-excursion
   7681     (let ((case-fold-search t)
   7682           (regexp (concat "\\_<\\(" web-mode-sql-keywords "\\)\\_>")))
   7683       (goto-char beg)
   7684       (while (re-search-forward regexp end t)
   7685         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7686                                          'font-lock-face
   7687                                          'web-mode-sql-keyword-face)
   7688         ) ;while
   7689       )))
   7690 
   7691 ;;---- EFFECTS -----------------------------------------------------------------
   7692 
   7693 (defun web-mode-fill-paragraph (&optional _justify)
   7694   (save-excursion
   7695     (let ((pos (point))
   7696           prop pair beg end delim-beg delim-end chunk fill-coll)
   7697       (ignore delim-beg delim-end fill-coll)
   7698       (cond
   7699         ((or (eq (get-text-property pos 'part-token) 'comment)
   7700              (eq (get-text-property pos 'block-token) 'comment))
   7701          (setq prop
   7702                (if (get-text-property pos 'part-token) 'part-token 'block-token))
   7703          (setq pair (web-mode-property-boundaries prop pos))
   7704          (when (and pair (> (- (cdr pair) (car pair)) 6))
   7705            (setq fill-coll (if (< fill-column 10) 70 fill-column))
   7706            (setq beg (car pair)
   7707                  end (cdr pair))
   7708            (goto-char beg)
   7709            (setq chunk (buffer-substring-no-properties beg (+ beg 2)))
   7710            (cond
   7711              ((string= chunk "//")
   7712               (setq delim-beg "//"
   7713                     delim-end "EOL"))
   7714              ((string= chunk "/*")
   7715               (setq delim-beg "/*"
   7716                     delim-end "*/"))
   7717              ((string= chunk "{#")
   7718               (setq delim-beg "{#"
   7719                     delim-end "#}"))
   7720              ((string= chunk "<!")
   7721               (setq delim-beg "<!--"
   7722                     delim-end "-->"))
   7723              )
   7724            )
   7725          ) ;comment - case
   7726         ((web-mode-is-content)
   7727          (setq pair (web-mode-content-boundaries pos))
   7728          (setq beg (car pair)
   7729                end (cdr pair))
   7730          )
   7731         ) ;cond
   7732       ;;(message "beg(%S) end(%S)" beg end)
   7733       (when (and beg end)
   7734         (fill-region beg end))
   7735       t)))
   7736 
   7737 (defun web-mode-engine-syntax-check ()
   7738   (interactive)
   7739   (let ((proc nil) (errors nil)
   7740         (file (concat temporary-file-directory "emacs-web-mode-tmp")))
   7741     (write-region (point-min) (point-max) file)
   7742     (cond
   7743       ;; ((null (buffer-file-name))
   7744       ;; )
   7745       ((string= web-mode-engine "php")
   7746        (setq proc (start-process "php-proc" nil "php" "-l" file))
   7747        (set-process-filter
   7748         proc
   7749         (lambda (_proc output)
   7750           (cond
   7751             ((string-match-p "No syntax errors" output)
   7752              (message "No syntax errors")
   7753              )
   7754             (t
   7755              ;; (setq output (replace-regexp-in-string temporary-file-directory "" output))
   7756              ;; (message output)
   7757              (message "Syntax error")
   7758              (setq errors t))
   7759             ) ;cond
   7760           ;; (delete-file file)
   7761           ) ;lambda
   7762         )
   7763        ) ;php
   7764       (t
   7765        (message "no syntax checker found")
   7766        ) ;t
   7767       ) ;cond
   7768     errors))
   7769 
   7770 (defun web-mode-jshint ()
   7771   "Run JSHint on all the JavaScript parts."
   7772   (interactive)
   7773   (let (proc)
   7774     (when (buffer-file-name)
   7775       (setq proc (start-process
   7776                   "jshint-proc"
   7777                   nil
   7778                   (or (executable-find "jshint") "/usr/local/bin/jshint")
   7779                   "--extract=auto"
   7780                   (buffer-file-name)))
   7781       (setq web-mode-jshint-errors 0)
   7782       (set-process-filter proc
   7783                           (lambda (_proc output)
   7784                             (let ((offset 0) overlay pos (old 0) msg)
   7785                               (remove-overlays (point-min) (point-max) 'font-lock-face 'web-mode-error-face)
   7786                               (while (string-match
   7787                                       "line \\([[:digit:]]+\\), col \\([[:digit:]]+\\), \\(.+\\)\\.$"
   7788                                       output offset)
   7789                                 (setq web-mode-jshint-errors (1+ web-mode-jshint-errors))
   7790                                 (setq offset (match-end 0))
   7791                                 (setq pos (web-mode-coord-position
   7792                                            (match-string-no-properties 1 output)
   7793                                            (match-string-no-properties 2 output)))
   7794                                 (when (get-text-property pos 'tag-beg)
   7795                                   (setq pos (1- pos)))
   7796                                 (when (not (= pos old))
   7797                                   (setq old pos)
   7798                                   (setq overlay (make-overlay pos (1+ pos)))
   7799                                   (overlay-put overlay 'font-lock-face 'web-mode-error-face)
   7800                                   )
   7801                                 (setq msg (or (overlay-get overlay 'help-echo)
   7802                                               (concat "line="
   7803                                                       (match-string-no-properties 1 output)
   7804                                                       " column="
   7805                                                       (match-string-no-properties 2 output)
   7806                                                       )))
   7807                                 (overlay-put overlay 'help-echo
   7808                                              (concat msg " ## " (match-string-no-properties 3 output)))
   7809                                 ) ;while
   7810                               ))
   7811                           )
   7812       ) ;when
   7813     ))
   7814 
   7815 (defun web-mode-dom-errors-show ()
   7816   "Show unclosed tags."
   7817   (interactive)
   7818   (let (beg end tag pos l tags i cont cell overlay overlays first
   7819             (ori (point))
   7820             (errors 0)
   7821             (continue t)
   7822             )
   7823     (setq overlays (overlays-in (point-min) (point-max)))
   7824     (when overlays
   7825       (dolist (overlay overlays)
   7826         (when (eq (overlay-get overlay 'face) 'web-mode-warning-face)
   7827           (delete-overlay overlay)
   7828           )
   7829         )
   7830       )
   7831     (goto-char (point-min))
   7832     (when (not (or (get-text-property (point) 'tag-beg)
   7833                    (web-mode-tag-next)))
   7834       (setq continue nil))
   7835     (while continue
   7836       (setq pos (point))
   7837       (setq tag (get-text-property pos 'tag-name))
   7838       (cond
   7839         ((eq (get-text-property (point) 'tag-type) 'start)
   7840          (setq tags (push (list tag pos) tags))
   7841          ;;        (message "(%S) opening %S" pos tag)
   7842          )
   7843         ((eq (get-text-property (point) 'tag-type) 'end)
   7844          (setq i 0
   7845                l (length tags)
   7846                cont t)
   7847          (while (and (< i l) cont)
   7848            (setq cell (nth i tags))
   7849            ;;          (message "cell=%S" cell)
   7850            (setq i (1+ i))
   7851            (cond
   7852              ((string= tag (nth 0 cell))
   7853               (setq cont nil)
   7854               )
   7855              (t
   7856               (setq errors (1+ errors))
   7857               (setq beg (nth 1 cell))
   7858               (setq end (web-mode-tag-end-position beg))
   7859               (unless first
   7860                 (setq first beg))
   7861               (setq overlay (make-overlay beg (1+ end)))
   7862               (overlay-put overlay 'font-lock-face 'web-mode-warning-face)
   7863               ;;            (message "invalid <%S> at %S" (nth 0 cell) (nth 1 cell))
   7864               )
   7865              ) ;cond
   7866            ) ;while
   7867 
   7868          (dotimes (_i i)
   7869            (setq tags (cdr tags)))
   7870 
   7871          )
   7872         ) ;cond
   7873       (when (not (web-mode-tag-next))
   7874         (setq continue nil))
   7875       ) ;while
   7876     (message "%S error(s) detected" errors)
   7877     (if (< errors 1)
   7878         (goto-char ori)
   7879         (goto-char first)
   7880         (recenter))
   7881     ;;    (message "%S" tags)
   7882     ))
   7883 
   7884 (defun web-mode-fontify-elements (beg end)
   7885   (save-excursion
   7886     (goto-char beg)
   7887     (let ((continue (or (get-text-property (point) 'tag-beg) (web-mode-tag-next)))
   7888           (i 0) (ctx nil) (face nil))
   7889       (while continue
   7890         (cond
   7891           ((> (setq i (1+ i)) 1000)
   7892            (message "fontify-elements ** too much tags **")
   7893            (setq continue nil))
   7894           ((> (point) end)
   7895            (setq continue nil))
   7896           ((not (get-text-property (point) 'tag-beg))
   7897            (setq continue nil))
   7898           ((eq (get-text-property (point) 'tag-type) 'start)
   7899            (when (and (setq ctx (web-mode-element-boundaries (point)))
   7900                       (<= (car (cdr ctx)) end)
   7901                       (setq face (cdr (assoc (get-text-property (point) 'tag-name) web-mode-element-content-faces))))
   7902              (font-lock-prepend-text-property (1+ (cdr (car ctx))) (car (cdr ctx))
   7903                                               'font-lock-face face))
   7904            )
   7905           ) ;cond
   7906         (when (not (web-mode-tag-next))
   7907           (setq continue nil))
   7908         ) ;while
   7909       )))
   7910 
   7911 (defun web-mode-enable (feature)
   7912   "Enable one feature."
   7913   (interactive
   7914    (list (completing-read
   7915           "Feature: "
   7916           (let (features)
   7917             (dolist (elt web-mode-features)
   7918               (setq features (append features (list (car elt)))))
   7919             features))))
   7920   (when (and (or (not feature) (< (length feature) 1)) web-mode-last-enabled-feature)
   7921     (setq feature web-mode-last-enabled-feature))
   7922   (when feature
   7923     (setq web-mode-last-enabled-feature feature)
   7924     (setq feature (cdr (assoc feature web-mode-features)))
   7925     (cond
   7926       ((eq feature 'web-mode-enable-current-column-highlight)
   7927        (web-mode-column-show))
   7928       ((eq feature 'web-mode-enable-current-element-highlight)
   7929        (when (not web-mode-enable-current-element-highlight)
   7930          (web-mode-toggle-current-element-highlight))
   7931        )
   7932       ((eq feature 'web-mode-enable-whitespace-fontification)
   7933        (web-mode-whitespaces-on))
   7934       (t
   7935        (set feature t)
   7936        (web-mode-buffer-fontify))
   7937       )
   7938     ) ;when
   7939   )
   7940 
   7941 (defun web-mode-disable (feature)
   7942   "Disable one feature."
   7943   (interactive
   7944    (list (completing-read
   7945           "Feature: "
   7946           (let (features)
   7947             (dolist (elt web-mode-features)
   7948               (setq features (append features (list (car elt)))))
   7949             features))))
   7950   (when (and (or (not feature) (< (length feature) 1)) web-mode-last-enabled-feature)
   7951     (setq feature web-mode-last-enabled-feature))
   7952   (when feature
   7953     (setq feature (cdr (assoc feature web-mode-features)))
   7954     (cond
   7955       ((eq feature 'web-mode-enable-current-column-highlight)
   7956        (web-mode-column-hide))
   7957       ((eq feature 'web-mode-enable-current-element-highlight)
   7958        (when web-mode-enable-current-element-highlight
   7959          (web-mode-toggle-current-element-highlight))
   7960        )
   7961       ((eq feature 'web-mode-enable-whitespace-fontification)
   7962        (web-mode-whitespaces-off))
   7963       (t
   7964        (set feature nil)
   7965        (web-mode-buffer-fontify))
   7966       )
   7967     ) ;when
   7968   )
   7969 
   7970 (defun web-mode-toggle-current-element-highlight ()
   7971   "Toggle highlighting of the current html element."
   7972   (interactive)
   7973   (if web-mode-enable-current-element-highlight
   7974       (progn
   7975         (web-mode-delete-tag-overlays)
   7976         (setq web-mode-enable-current-element-highlight nil))
   7977       (setq web-mode-enable-current-element-highlight t)
   7978       ))
   7979 
   7980 (defun web-mode-make-tag-overlays ()
   7981   (unless web-mode-overlay-tag-start
   7982     (setq web-mode-overlay-tag-start (make-overlay 1 1)
   7983           web-mode-overlay-tag-end (make-overlay 1 1))
   7984     (overlay-put web-mode-overlay-tag-start
   7985                  'font-lock-face
   7986                  'web-mode-current-element-highlight-face)
   7987     (overlay-put web-mode-overlay-tag-end
   7988                  'font-lock-face
   7989                  'web-mode-current-element-highlight-face)))
   7990 
   7991 (defun web-mode-delete-tag-overlays ()
   7992   (when web-mode-overlay-tag-start
   7993     (delete-overlay web-mode-overlay-tag-start)
   7994     (delete-overlay web-mode-overlay-tag-end)))
   7995 
   7996 (defun web-mode-column-overlay-factory (index)
   7997   (let (overlay)
   7998     (when (null web-mode-column-overlays)
   7999       (dotimes (_i 100)
   8000         (setq overlay (make-overlay 1 1))
   8001         (overlay-put overlay 'font-lock-face 'web-mode-current-column-highlight-face)
   8002         (setq web-mode-column-overlays (append web-mode-column-overlays (list overlay)))
   8003         )
   8004       ) ;when
   8005     (setq overlay (nth index web-mode-column-overlays))
   8006     (when (null overlay)
   8007       (setq overlay (make-overlay 1 1))
   8008       (overlay-put overlay 'font-lock-face 'web-mode-current-column-highlight-face)
   8009       (setq web-mode-column-overlays (append web-mode-column-overlays (list overlay)))
   8010       ) ;when
   8011     overlay))
   8012 
   8013 (defun web-mode-column-hide ()
   8014   (setq web-mode-enable-current-column-highlight nil)
   8015   (remove-overlays (point-min) (point-max)
   8016                    'font-lock-face
   8017                    'web-mode-current-column-highlight-face))
   8018 
   8019 (defun web-mode-count-invisible-character-ranges (min max)
   8020   (interactive "r")
   8021   (let ((count 0) (current-pos min))
   8022     (save-excursion
   8023       (while (<= current-pos max)
   8024         (goto-char current-pos)
   8025         (if (get-text-property current-pos 'invisible)
   8026             (progn
   8027               (setq count (1+ count))
   8028               (setq current-pos (1+ current-pos))
   8029               (while (and (<= current-pos max)
   8030                           (get-text-property current-pos 'invisible))
   8031                 (setq current-pos (1+ current-pos))))
   8032           (setq current-pos (1+ current-pos)))))
   8033     count))
   8034 
   8035 (defun web-mode-column-show ()
   8036   (let ((index 0) overlay diff column line-to line-from line-delta regions (overlay-skip nil) last-line-no)
   8037     (web-mode-column-hide)
   8038     (setq web-mode-enable-current-column-highlight t)
   8039     (save-excursion ;;save-mark-and-excursion
   8040       (back-to-indentation)
   8041       (setq column (current-column)
   8042             line-to (web-mode-line-number))
   8043       (when (and (get-text-property (point) 'tag-beg)
   8044                  (member (get-text-property (point) 'tag-type) '(start end))
   8045                  (web-mode-tag-match)
   8046                  (setq line-from (web-mode-line-number))
   8047                  (not (= line-from line-to)))
   8048         (when (> line-from line-to)
   8049           (let (tmp)
   8050             (setq tmp line-from)
   8051             (setq line-from line-to)
   8052             (setq line-to tmp))
   8053           ) ;when
   8054         ;;(message "column(%S) line-from(%S) line-to(%S)" column line-from line-to)
   8055         (goto-char (point-min))
   8056         (when (> line-from 1)
   8057           (forward-line (1- line-from)))
   8058         ;; Added by JMA
   8059         (save-excursion ;;save-mark-and-excursion
   8060           (let (start-point end-point)
   8061             (goto-line line-from)
   8062             (move-to-column column)
   8063             (setq start-point (point))
   8064             (goto-line line-to)
   8065             (move-to-column column)
   8066             (setq end-point (point))
   8067             (setq line-delta (count-lines start-point end-point t))
   8068             (setq line-delta (+ line-delta (web-mode-count-invisible-character-ranges start-point end-point))))
   8069           (setq line-to (+ line-from (1- line-delta))))
   8070         ;(message (format "Currently at line: %d" (line-number-at-pos)))
   8071         (setq last-line-no (line-number-at-pos))
   8072         ;; end JMA add
   8073         (while (<= line-from line-to)
   8074           (setq overlay (web-mode-column-overlay-factory index))
   8075           (setq diff (- (line-end-position) (point)))
   8076           (cond
   8077             ((or (and (= column 0) (= diff 0))
   8078                  (> column diff))
   8079              (end-of-line)
   8080              (move-overlay overlay (point) (point))
   8081              (overlay-put overlay
   8082                           'after-string
   8083                           (concat
   8084                            (if (> column diff) (make-string (- column diff) ?\s) "")
   8085                            (propertize " "
   8086                                        'font-lock-face
   8087                                        'web-mode-current-column-highlight-face)
   8088                            ) ;concat
   8089                           )
   8090              )
   8091             (t
   8092              (move-to-column column)
   8093              (overlay-put overlay 'after-string nil)
   8094              (move-overlay overlay (point) (1+ (point)))
   8095              )
   8096             ) ;cond
   8097           (setq line-from (1+ line-from))
   8098           (forward-line)
   8099           ;; JMA ADD
   8100           ;(message (format "Currently at line: %d" (line-number-at-pos)))
   8101           (if (not (= (1+ last-line-no) (line-number-at-pos)))
   8102               (delete-overlay overlay))
   8103           (setq last-line-no (line-number-at-pos))
   8104           ;; END JMA ADD
   8105           (setq index (1+ index))
   8106           ) ;while
   8107         ) ;when
   8108       ) ;save-excursion
   8109     ) ;let
   8110   )
   8111 
   8112 (defun web-mode-column-show2 ()
   8113   (let ((index 0) overlay diff column line-to line-from
   8114         line-delta regions (overlay-skip nil) last-line-no)
   8115     (web-mode-column-hide)
   8116     (setq web-mode-enable-current-column-highlight t)
   8117     (save-excursion
   8118       (back-to-indentation)
   8119       (setq column (current-column)
   8120             line-to (web-mode-line-number))
   8121       (when (and (get-text-property (point) 'tag-beg)
   8122                  (member (get-text-property (point) 'tag-type) '(start end))
   8123                  (web-mode-tag-match)
   8124                  (setq line-from (web-mode-line-number))
   8125                  (not (= line-from line-to)))
   8126         (when (> line-from line-to)
   8127           (let (tmp)
   8128             (setq tmp line-from)
   8129             (setq line-from line-to)
   8130             (setq line-to tmp))
   8131           ) ;when
   8132         ;;(message "column(%S) line-from(%S) line-to(%S)" column line-from line-to)
   8133         (goto-char (point-min))
   8134         (when (> line-from 1)
   8135           (forward-line (1- line-from)))
   8136         (while (<= line-from line-to)
   8137           (setq overlay (web-mode-column-overlay-factory index))
   8138           (setq diff (- (line-end-position) (point)))
   8139           (cond
   8140             ((or (and (= column 0) (= diff 0))
   8141                  (> column diff))
   8142              (end-of-line)
   8143              (move-overlay overlay (point) (point))
   8144              (overlay-put overlay
   8145                           'after-string
   8146                           (concat
   8147                            (if (> column diff) (make-string (- column diff) ?\s) "")
   8148                            (propertize " "
   8149                                        'font-lock-face
   8150                                        'web-mode-current-column-highlight-face)
   8151                            ) ;concat
   8152                           )
   8153              )
   8154             (t
   8155              (move-to-column column)
   8156              (overlay-put overlay 'after-string nil)
   8157              (move-overlay overlay (point) (1+ (point)))
   8158              )
   8159             ) ;cond
   8160           (setq line-from (1+ line-from))
   8161           (forward-line)
   8162           (setq index (1+ index))
   8163           ) ;while
   8164         ) ;when
   8165       ) ;save-excursion
   8166     ) ;let
   8167   )
   8168 
   8169 (defun web-mode-highlight-current-element ()
   8170   (let ((ctx (web-mode-element-boundaries)) len)
   8171     (cond
   8172       ((null ctx)
   8173        (web-mode-delete-tag-overlays))
   8174       ((eq (get-text-property (caar ctx) 'tag-type) 'void) ;; #1046
   8175        (web-mode-make-tag-overlays)
   8176        (setq len (length (get-text-property (caar ctx) 'tag-name)))
   8177        (move-overlay web-mode-overlay-tag-start (+ (caar ctx) 1) (+ (caar ctx) 1 len))
   8178        (move-overlay web-mode-overlay-tag-end (+ (cadr ctx) 1) (+ (cadr ctx) 1 len)) ;; #1257
   8179        )
   8180       (t
   8181        (web-mode-make-tag-overlays)
   8182        (setq len (length (get-text-property (caar ctx) 'tag-name)))
   8183        (move-overlay web-mode-overlay-tag-start (+ (caar ctx) 1) (+ (caar ctx) 1 len))
   8184        (move-overlay web-mode-overlay-tag-end (+ (cadr ctx) 2) (+ (cadr ctx) 2 len))
   8185        ) ;t
   8186       ) ;cond
   8187     ))
   8188 
   8189 (defun web-mode-fontify-whitespaces (beg end)
   8190   (save-excursion
   8191     (goto-char beg)
   8192     (while (re-search-forward web-mode-whitespaces-regexp end t)
   8193       (add-text-properties (match-beginning 0) (match-end 0)
   8194                            '(face web-mode-whitespace-face))
   8195       ) ;while
   8196     ))
   8197 
   8198 (defun web-mode-whitespaces-show ()
   8199   "Toggle whitespaces."
   8200   (interactive)
   8201   (if web-mode-enable-whitespace-fontification
   8202       (web-mode-whitespaces-off)
   8203       (web-mode-whitespaces-on)))
   8204 
   8205 (defun web-mode-whitespaces-on ()
   8206   "Show whitespaces."
   8207   (interactive)
   8208   (when web-mode-display-table
   8209     (setq buffer-display-table web-mode-display-table))
   8210   (setq web-mode-enable-whitespace-fontification t))
   8211 
   8212 (defun web-mode-whitespaces-off ()
   8213   (setq buffer-display-table nil)
   8214   (setq web-mode-enable-whitespace-fontification nil))
   8215 
   8216 (defun web-mode-use-tabs ()
   8217   "Tweaks vars to be compatible with TAB indentation."
   8218   (let (offset)
   8219     (setq web-mode-block-padding 0)
   8220     (setq web-mode-script-padding 0)
   8221     (setq web-mode-style-padding 0)
   8222     (setq offset
   8223           (cond
   8224             ((and (boundp 'tab-width) tab-width) tab-width)
   8225             ((and (boundp 'standard-indent) standard-indent) standard-indent)
   8226             (t 4)))
   8227     ;;    (message "offset(%S)" offset)
   8228     (setq web-mode-attr-indent-offset offset)
   8229     (setq web-mode-code-indent-offset offset)
   8230     (setq web-mode-css-indent-offset offset)
   8231     (setq web-mode-markup-indent-offset offset)
   8232     (setq web-mode-sql-indent-offset offset)
   8233     (add-to-list 'web-mode-indentation-params '("lineup-args" . nil))
   8234     (add-to-list 'web-mode-indentation-params '("lineup-calls" . nil))
   8235     (add-to-list 'web-mode-indentation-params '("lineup-concats" . nil))
   8236     (add-to-list 'web-mode-indentation-params '("lineup-ternary" . nil))
   8237     ))
   8238 
   8239 (defun web-mode-element-children-fold-or-unfold (&optional pos)
   8240   "Fold/Unfold all the children of the current html element."
   8241   (interactive)
   8242   (unless pos (setq pos (point)))
   8243   (save-excursion
   8244     (dolist (child (reverse (web-mode-element-children pos)))
   8245       (goto-char child)
   8246       (web-mode-fold-or-unfold))
   8247     ))
   8248 
   8249 (defun web-mode-fold-or-unfold (&optional pos)
   8250   "Toggle folding on an html element or a control block."
   8251   (interactive)
   8252   (web-mode-scan)
   8253   (web-mode-with-silent-modifications
   8254    (save-excursion
   8255      (if pos (goto-char pos))
   8256      (let (beg-inside beg-outside end-inside end-outside overlay overlays)
   8257        (when (looking-back "^[\t ]*" (point-min))
   8258          (back-to-indentation))
   8259        (setq overlays (overlays-at (point)))
   8260        (dolist (elt overlays)
   8261          (when (and (not overlay)
   8262                     (eq (overlay-get elt 'font-lock-face) 'web-mode-folded-face))
   8263            (setq overlay elt)))
   8264        (cond
   8265          ;; *** unfolding
   8266          (overlay
   8267           (setq beg-inside (overlay-start overlay)
   8268                 end-inside (overlay-end overlay))
   8269           (remove-overlays beg-inside end-inside)
   8270           (put-text-property beg-inside end-inside 'invisible nil)
   8271           )
   8272          ;; *** block folding
   8273          ((and (get-text-property (point) 'block-side)
   8274                (cdr (web-mode-block-is-control (point))))
   8275           (setq beg-outside (web-mode-block-beginning-position (point)))
   8276           (setq beg-inside (1+ (web-mode-block-end-position (point))))
   8277           (when (web-mode-block-match)
   8278             (setq end-inside (point))
   8279             (setq end-outside (1+ (web-mode-block-end-position (point)))))
   8280           )
   8281          ;; *** html comment folding
   8282          ((eq (get-text-property (point) 'tag-type) 'comment)
   8283           (setq beg-outside (web-mode-tag-beginning-position))
   8284           (setq beg-inside (+ beg-outside 4))
   8285           (setq end-outside (web-mode-tag-end-position))
   8286           (setq end-inside (- end-outside 3))
   8287           )
   8288          ;; *** tag folding
   8289          ((or (member (get-text-property (point) 'tag-type) '(start end))
   8290               (web-mode-element-parent))
   8291           (when (not (web-mode-element-is-collapsed (point)))
   8292             (web-mode-tag-beginning)
   8293             (when (eq (get-text-property (point) 'tag-type) 'end)
   8294               (web-mode-tag-match))
   8295             (setq beg-outside (point))
   8296             (web-mode-tag-end)
   8297             (setq beg-inside (point))
   8298             (goto-char beg-outside)
   8299             (when (web-mode-tag-match)
   8300               (setq end-inside (point))
   8301               (web-mode-tag-end)
   8302               (setq end-outside (point)))
   8303             )
   8304           )
   8305          ) ;cond
   8306        (when (and beg-inside beg-outside end-inside end-outside)
   8307          (setq overlay (make-overlay beg-outside end-outside))
   8308          (overlay-put overlay 'font-lock-face 'web-mode-folded-face)
   8309          (put-text-property beg-inside end-inside 'invisible t))
   8310        ))))
   8311 
   8312 ;;---- TRANSFORMATION ----------------------------------------------------------
   8313 
   8314 (defun web-mode-buffer-change-tag-case (&optional type)
   8315   "Change html tag case."
   8316   (interactive)
   8317   (save-excursion
   8318     (goto-char (point-min))
   8319     (let ((continue t) f)
   8320       (setq f (if (member type '("upper" "uppercase" "upper-case")) 'uppercase 'downcase))
   8321       (when (and (not (get-text-property (point) 'tag-beg))
   8322                  (not (web-mode-tag-next)))
   8323         (setq continue nil))
   8324       (while continue
   8325         (skip-chars-forward "<!/")
   8326         (if (looking-at "\\([[:alnum:]:-]+\\)")
   8327             (replace-match (funcall f (match-string 0)) t))
   8328         ;;        (message "tag: %S (%S)"
   8329         ;;                 (get-text-property (point) 'tag-name)
   8330         ;;                 (point))
   8331         (unless (web-mode-tag-next)
   8332           (setq continue nil))
   8333         ) ;while
   8334       )))
   8335 
   8336 (defun web-mode-buffer-change-attr-case (&optional type)
   8337   "Change case of html attribute names."
   8338   (interactive)
   8339   (unless type (setq type "downcase"))
   8340   (save-excursion
   8341     (goto-char (point-min))
   8342     (let ((continue t)
   8343           (fun (if (eq (aref (downcase type) 0) ?u) 'uppercase 'downcase)))
   8344       (while continue
   8345         (cond
   8346           ((not (web-mode-attribute-next))
   8347            (setq continue nil))
   8348           ((looking-at "\\([[:alnum:]-]+\\)")
   8349            (replace-match (funcall fun (match-string 0)) t)
   8350            )
   8351           ) ;cond
   8352         ) ;while
   8353       )))
   8354 
   8355 ;; tag-case=lower|upper-case , attr-case=lower|upper-case
   8356 ;; special-chars=unicode|html-entities
   8357 ;; smart-apostrophes=bool , smart-quotes=bool , indentation=bool
   8358 (defun web-mode-dom-normalize ()
   8359   "Normalize buffer"
   8360   (interactive)
   8361   (save-excursion
   8362     (let ((rules web-mode-normalization-rules) elt)
   8363       (when (setq elt (cdr (assoc "tag-case" rules)))
   8364         (web-mode-buffer-change-tag-case elt))
   8365       (when (setq elt (cdr (assoc "attr-case" rules)))
   8366         (web-mode-buffer-change-attr-case elt))
   8367       (when (setq elt (cdr (assoc "css-indentation" rules)))
   8368         (web-mode-css-indent))
   8369       (when (setq elt (cdr (assoc "smart-apostrophes" rules)))
   8370         (web-mode-dom-apostrophes-replace))
   8371       (when (setq elt (cdr (assoc "smart-quotes" rules)))
   8372         (web-mode-dom-quotes-replace))
   8373       (when (setq elt (cdr (assoc "special-chars" rules)))
   8374         (if (string= elt "entities")
   8375             (web-mode-dom-entities-encode)
   8376             (web-mode-dom-entities-replace)))
   8377       (when (setq elt (cdr (assoc "whitespaces" rules)))
   8378         (goto-char (point-min))
   8379         (while (not (eobp))
   8380           (forward-line)
   8381           (delete-blank-lines))
   8382         (delete-trailing-whitespace)
   8383         (untabify (point-min) (point-max)))
   8384       (when (setq elt (cdr (assoc "indentation" rules)))
   8385         (web-mode-buffer-indent))
   8386       )))
   8387 
   8388 (defun web-mode-dom-apostrophes-replace ()
   8389   "Replace char(') with char(’) in the innerText of html elements."
   8390   (interactive)
   8391   (save-excursion
   8392     (let ((min (point-min)) (max (point-max)))
   8393       (when mark-active
   8394         (setq min (region-beginning)
   8395               max (region-end))
   8396         (deactivate-mark))
   8397       (goto-char min)
   8398       (while (web-mode-content-rsf "\\([[:alpha:]]\\)'\\([[:alpha:]]\\)" max)
   8399         (replace-match "\\1’\\2"))
   8400       )))
   8401 
   8402 (defun web-mode-dom-entities-encode ()
   8403   (save-excursion
   8404     (let (regexp elt (min (point-min)) (max (point-max)))
   8405       (when mark-active
   8406         (setq min (region-beginning)
   8407               max (region-end))
   8408         (deactivate-mark))
   8409       (goto-char min)
   8410       (setq regexp "[")
   8411       (dolist (pair web-mode-html-entities)
   8412         (setq regexp (concat regexp (char-to-string (cdr pair))))
   8413         )
   8414       (setq regexp (concat regexp "]"))
   8415       (while (web-mode-content-rsf regexp max)
   8416         (setq elt (match-string-no-properties 0))
   8417         (setq elt (aref elt 0))
   8418         (setq elt (car (rassoc elt web-mode-html-entities)))
   8419         (replace-match (concat "&" elt ";"))
   8420         (setq max (+ max (length elt) 1))
   8421         ) ;while
   8422       )))
   8423 
   8424 (defun web-mode-dom-entities-replace ()
   8425   "Replace html entities (e.g. &eacute; &#233; or &#x00E9; become é)"
   8426   (interactive)
   8427   (save-excursion
   8428     (let (ms pair elt (min (point-min)) (max (point-max)))
   8429       (when mark-active
   8430         (setq min (region-beginning)
   8431               max (region-end))
   8432         (deactivate-mark))
   8433       (goto-char min)
   8434       (while (web-mode-content-rsf "&\\([#]?[[:alnum:]]\\{2,8\\}\\);" max)
   8435         (setq elt nil)
   8436         (setq ms (match-string-no-properties 1))
   8437         (cond
   8438           ((not (eq (aref ms 0) ?\#))
   8439            (and (setq pair (assoc ms web-mode-html-entities))
   8440                 (setq elt (cdr pair))
   8441                 (setq elt (char-to-string elt))))
   8442           ((eq (aref ms 1) ?x)
   8443            (setq elt (substring ms 2))
   8444            (setq elt (downcase elt))
   8445            (setq elt (string-to-number elt 16))
   8446            (setq elt (char-to-string elt)))
   8447           (t
   8448            (setq elt (substring ms 1))
   8449            (setq elt (char-to-string (string-to-number elt))))
   8450           ) ;cond
   8451         (when elt (replace-match elt))
   8452         ) ;while
   8453       )))
   8454 
   8455 (defun web-mode-dom-xml-replace ()
   8456   "Replace &, > and < in html content."
   8457   (interactive)
   8458   (save-excursion
   8459     (let ((min (point-min)) (max (point-max)))
   8460       (when mark-active
   8461         (setq min (region-beginning)
   8462               max (region-end))
   8463         (deactivate-mark))
   8464       (goto-char min)
   8465       (while (web-mode-content-rsf "[&<>]" max)
   8466         (replace-match (cdr (assq (char-before) web-mode-xml-chars)) t t))
   8467       )))
   8468 
   8469 (defun web-mode-dom-quotes-replace ()
   8470   "Replace dumb quotes."
   8471   (interactive)
   8472   (save-excursion
   8473     (let (expr (min (point-min)) (max (point-max)))
   8474       (when mark-active
   8475         (setq min (region-beginning)
   8476               max (region-end))
   8477         (deactivate-mark))
   8478       (goto-char min)
   8479       (setq expr (concat (car web-mode-smart-quotes) "\\2" (cdr web-mode-smart-quotes)))
   8480       (while (web-mode-content-rsf "\\(\"\\)\\(.\\{1,200\\}\\)\\(\"\\)" max)
   8481         (replace-match expr)
   8482         ) ;while
   8483       )))
   8484 
   8485 ;;---- INDENTATION -------------------------------------------------------------
   8486 
   8487 ;; todo : passer de règle en règle et mettre un \n à la fin
   8488 (defun web-mode-css-indent ()
   8489   (save-excursion
   8490     (goto-char (point-min))
   8491     (let ((continue t) part-end)
   8492       (while continue
   8493         (cond
   8494           ((not (web-mode-part-next))
   8495            (setq continue nil))
   8496           ((eq (get-text-property (point) 'part-side) 'css)
   8497            (setq part-end (web-mode-part-end-position))
   8498            (while (web-mode-css-rule-next part-end)
   8499              (when (not (looking-at-p "[[:space:]]*\\($\\|<\\)"))
   8500                (newline)
   8501                (indent-according-to-mode)
   8502                (setq part-end (web-mode-part-end-position)))
   8503              )
   8504            )
   8505           ) ;cond
   8506         )
   8507       )))
   8508 
   8509 (defun web-mode-buffer-indent ()
   8510   "Indent all buffer."
   8511   (interactive)
   8512   (let ((debug t) (ts (current-time)) (sub nil))
   8513     (indent-region (point-min) (point-max))
   8514     (when debug
   8515       (setq sub (time-subtract (current-time) ts))
   8516       (message "buffer-indent: time elapsed = %Ss %9Sµs" (nth 1 sub) (nth 2 sub)))
   8517     (delete-trailing-whitespace)))
   8518 
   8519 (defun web-mode-point-context (pos)
   8520   "POS should be at the beginning of the indentation."
   8521   (save-excursion
   8522     (let (curr-char curr-indentation curr-line
   8523                     language
   8524                     options
   8525                     reg-beg reg-col
   8526                     prev-char prev-indentation prev-line prev-pos
   8527                     token
   8528                     part-language
   8529                     depth)
   8530 
   8531       (setq reg-beg (point-min)
   8532             reg-col 0
   8533             token "live"
   8534             options ""
   8535             language ""
   8536             prev-line ""
   8537             prev-char 0
   8538             prev-pos nil
   8539             prev-line-end nil)
   8540 
   8541       (when (get-text-property pos 'part-side)
   8542         (setq part-language (symbol-name (get-text-property pos 'part-side))))
   8543 
   8544       ;;(message "part-language=%S" part-language)
   8545 
   8546       (cond
   8547 
   8548         ((and (bobp) (member web-mode-content-type '("html" "xml")))
   8549          (setq language web-mode-content-type)
   8550          )
   8551 
   8552         ((string= web-mode-content-type "css")
   8553          (setq language "css"
   8554                curr-indentation web-mode-css-indent-offset))
   8555 
   8556         ((member web-mode-content-type '("javascript" "json" "typescript"))
   8557          (setq language web-mode-content-type
   8558                curr-indentation web-mode-code-indent-offset))
   8559 
   8560         ((or (string= web-mode-content-type "jsx")
   8561              (and part-language (string= part-language "jsx")))
   8562          (setq language "jsx"
   8563                curr-indentation web-mode-code-indent-offset)
   8564          (cond
   8565            ((web-mode-jsx-is-html pos)
   8566             (setq curr-indentation web-mode-markup-indent-offset
   8567                   options "is-html"))
   8568            ((and (setq depth (get-text-property pos 'jsx-depth)) (> depth 1))
   8569             (when (get-text-property pos 'jsx-beg)
   8570               (setq depth (1- depth)))
   8571             (setq reg-beg (web-mode-jsx-depth-beginning-position pos depth))
   8572             (setq reg-beg (1+ reg-beg))
   8573             ;;(message "%S" (point))
   8574             (save-excursion
   8575               (goto-char reg-beg)
   8576               ;;(message "pt=%S" reg-beg)
   8577               (cond
   8578                 ((and (not (looking-at-p "[ ]*$"))
   8579                       (looking-back "^[[:space:]]*{" (point-min)))
   8580                  (setq reg-col (+ (current-indentation) ;; #1027
   8581                                   (cond
   8582                                     ((looking-at "[ ]+") (1+ (length (match-string-no-properties 0))))
   8583                                     (t 0))
   8584                                   ))
   8585                  )
   8586                 ((looking-at-p "[ ]*\\[[ ]*$") ;; #0659
   8587                  (setq reg-col (current-indentation))
   8588                  )
   8589                 ((and (looking-back "=[ ]*{" (point-min)) ;; #0739 #1022
   8590                       (not (looking-at-p "[[:space:]]*<")))
   8591                  (setq reg-col (current-indentation))
   8592                  )
   8593                 ;;((and (looking-back "=[ ]*{" (point-min)) ;; #0739
   8594                 ;;      (looking-at-p "{[ ]*"))
   8595                 ;; (setq reg-col (current-indentation))
   8596                 ;; )
   8597                 ((get-text-property (1- (point)) 'tag-beg)
   8598                  ;;(message "point=%S" (point))
   8599                  (setq reg-col (current-indentation))
   8600                  )
   8601                 (t
   8602                  (message "%S : %S %S" (point) (current-indentation) web-mode-code-indent-offset)
   8603                  ;;(setq reg-col (+ (current-indentation) web-mode-code-indent-offset web-mode-jsx-expression-padding)))
   8604                  (setq reg-col (+ (current-indentation) web-mode-code-indent-offset)))
   8605                 )
   8606 
   8607               ;;(message "%S %S %S" (point) (current-indentation) reg-col)
   8608               ) ;save-excursion
   8609             )
   8610            ((string= web-mode-content-type "jsx")
   8611             (setq reg-beg (point-min)))
   8612            (t
   8613             (setq reg-beg (or (web-mode-part-beginning-position pos) (point-min)))
   8614             (save-excursion
   8615               (goto-char reg-beg)
   8616               (search-backward "<" nil t)
   8617               (setq reg-col (current-column))
   8618               ) ;save-excursion
   8619             )
   8620            ) ;cond
   8621          ;;(message "jsx reg-beg=%S" reg-beg)
   8622          ) ;jsx
   8623 
   8624         ((string= web-mode-content-type "php")
   8625          (setq language "php"
   8626                curr-indentation web-mode-code-indent-offset))
   8627 
   8628         ((or (string= web-mode-content-type "xml"))
   8629          (setq language "xml"
   8630                curr-indentation web-mode-markup-indent-offset))
   8631 
   8632         ;; TODO: est ce util ?
   8633         ((and (get-text-property pos 'tag-beg)
   8634               (get-text-property pos 'tag-name)
   8635               ;;(not (get-text-property pos 'part-side))
   8636               )
   8637          (setq language "html"
   8638                curr-indentation web-mode-markup-indent-offset))
   8639 
   8640         ((and (get-text-property pos 'block-side)
   8641               (not (get-text-property pos 'block-beg)))
   8642 
   8643          (setq reg-beg (or (web-mode-block-beginning-position pos) (point-min)))
   8644          (goto-char reg-beg)
   8645          (setq reg-col (current-column))
   8646          ;;(message "%S %S" reg-beg reg-col)
   8647          (setq language web-mode-engine)
   8648          (setq curr-indentation web-mode-code-indent-offset)
   8649 
   8650          (cond
   8651            ((string= web-mode-engine "blade")
   8652             (save-excursion
   8653               (when (web-mode-rsf "{[{!]+[ ]*")
   8654                 (setq reg-col (current-column))))
   8655             (setq reg-beg (+ reg-beg 2))
   8656             )
   8657            ((string= web-mode-engine "razor")
   8658             ;;(setq reg-beg (+ reg-beg 2))
   8659             ;;(setq reg-col (current-column))
   8660             )
   8661            ;; tests/demo.chtml
   8662            ((string= web-mode-engine "ctemplate")
   8663             (save-excursion
   8664               (when (web-mode-rsf "{{#?")
   8665                 (setq reg-col (current-column))))
   8666             )
   8667            ((string= web-mode-engine "dust")
   8668             (save-excursion
   8669               (when (web-mode-rsf "{@")
   8670                 (setq reg-col (current-column))))
   8671             )
   8672            ((string= web-mode-engine "svelte")
   8673             (save-excursion
   8674               (when (web-mode-rsf "{@")
   8675                 (setq reg-col (current-column))))
   8676             )
   8677            ((string= web-mode-engine "template-toolkit")
   8678             (setq reg-beg (+ reg-beg 3)
   8679                   reg-col (+ reg-col 3))
   8680             )
   8681            ((and (string= web-mode-engine "jsp")
   8682                  (web-mode-looking-at "<%@" reg-beg))
   8683             (save-excursion
   8684               (goto-char reg-beg)
   8685               (looking-at "<%@[ ]*[[:alpha:]]+[ ]+\\|</?[[:alpha:]]+[:.][[:alpha:]]+[ ]+")
   8686               (goto-char (match-end 0))
   8687               (setq reg-col (current-column))
   8688               )
   8689             )
   8690            ((and (string= web-mode-engine "freemarker")
   8691                  (web-mode-looking-at "<@\\|<%@\\|<[[:alpha:]]" reg-beg))
   8692             (save-excursion
   8693               (goto-char reg-beg)
   8694               (looking-at "<@[[:alpha:].]+[ ]+\\|<%@[ ]*[[:alpha:]]+[ ]+\\|<[[:alpha:]]+:[[:alpha:]]+[ ]+")
   8695               (goto-char (match-end 0))
   8696               (setq reg-col (current-column))
   8697               )
   8698             )
   8699            ) ;cond
   8700          ) ;block-side
   8701 
   8702         ((and part-language (member part-language
   8703                                     '("css" "javascript" "json" "sql" "markdown"
   8704                                       "pug" "ruby" "sass" "stylus" "typescript")))
   8705          (setq reg-beg (or (web-mode-part-beginning-position pos) (point-min)))
   8706          (goto-char reg-beg)
   8707          (if (and (string= web-mode-engine "mojolicious")
   8708                   (looking-back "javascript begin" (point-min)))
   8709              (search-backward "%" nil t)
   8710              (search-backward "<" nil t))
   8711          (setq reg-col (current-column))
   8712          (setq language part-language)
   8713          (cond
   8714            ((string= language "css")
   8715             (setq curr-indentation web-mode-css-indent-offset))
   8716            ((string= language "sql")
   8717             (setq curr-indentation web-mode-sql-indent-offset))
   8718            ((string= language "markdown")
   8719             (setq curr-indentation web-mode-code-indent-offset))
   8720            ((string= language "pug")
   8721             (setq curr-indentation web-mode-code-indent-offset))
   8722            ((string= language "sass")
   8723             (setq curr-indentation web-mode-code-indent-offset))
   8724            ((string= language "stylus")
   8725             (setq curr-indentation web-mode-code-indent-offset))
   8726            ((string= language "ruby")
   8727             (setq curr-indentation web-mode-code-indent-offset))
   8728            ((string= language "typescript")
   8729             (setq curr-indentation web-mode-code-indent-offset))
   8730            (t
   8731             (setq language "javascript"
   8732                   curr-indentation web-mode-code-indent-offset))
   8733            )
   8734          ) ;part-side
   8735 
   8736         (t
   8737          (setq language "html"
   8738                curr-indentation web-mode-markup-indent-offset)
   8739          )
   8740 
   8741         ) ;cond
   8742 
   8743       (cond
   8744         ((or (and (> pos (point-min))
   8745                   (eq (get-text-property pos 'part-token) 'comment)
   8746                   (eq (get-text-property (1- pos) 'part-token) 'comment)
   8747                   (progn
   8748                     (setq reg-beg (previous-single-property-change pos 'part-token))
   8749                     t))
   8750              (and (> pos (point-min))
   8751                   (eq (get-text-property pos 'block-token) 'comment)
   8752                   (eq (get-text-property (1- pos) 'block-token) 'comment)
   8753                   (progn
   8754                     (setq reg-beg (previous-single-property-change pos 'block-token))
   8755                     t))
   8756              (and (> pos (point-min))
   8757                   (eq (get-text-property pos 'tag-type) 'comment)
   8758                   (not (get-text-property pos 'tag-beg))
   8759                   (progn
   8760                     (setq reg-beg (web-mode-tag-beginning-position pos))
   8761                     t))
   8762              )
   8763          (setq token "comment"))
   8764         ((or (and (> pos (point-min))
   8765                   (member (get-text-property pos 'part-token)
   8766                           '(string context key))
   8767                   (member (get-text-property (1- pos) 'part-token)
   8768                           '(string context key)))
   8769              (and (eq (get-text-property pos 'block-token) 'string)
   8770                   (eq (get-text-property (1- pos) 'block-token) 'string)))
   8771          (setq token "string"))
   8772         )
   8773 
   8774       (goto-char pos)
   8775       (setq curr-line (web-mode-trim
   8776                        (buffer-substring-no-properties
   8777                         (line-beginning-position)
   8778                         (line-end-position))))
   8779       (setq curr-char (if (string= curr-line "") 0 (aref curr-line 0)))
   8780 
   8781       (when (or (member language '("php" "blade" "javascript" "typescript" "jsx" "razor" "css"))
   8782                 (and (member language '("html" "xml"))
   8783                      (not (eq ?\< curr-char))))
   8784         (let (prev)
   8785           (cond
   8786             ((member language '("html" "xml" "javascript" "typescript" "jsx" "css"))
   8787              (when (setq prev (web-mode-part-previous-live-line reg-beg))
   8788                (setq prev-line (nth 0 prev)
   8789                      prev-indentation (nth 1 prev)
   8790                      prev-pos (nth 2 prev)
   8791                      prev-line-end (nth 3 prev))
   8792                )
   8793              )
   8794             ((setq prev (web-mode-block-previous-live-line))
   8795              (setq prev-line (nth 0 prev)
   8796                    prev-indentation (nth 1 prev)
   8797                    prev-pos (nth 2 prev)
   8798                    prev-line-end (nth 3 prev))
   8799              (setq prev-line (web-mode-clean-block-line prev-line)))
   8800             ) ;cond
   8801           ) ;let
   8802         (when (>= (length prev-line) 1)
   8803           (setq prev-char (aref prev-line (1- (length prev-line))))
   8804           (setq prev-line (substring-no-properties prev-line))
   8805           )
   8806         )
   8807 
   8808       (cond
   8809         ((not (member web-mode-content-type '("html" "xml")))
   8810          )
   8811         ((member language '("javascript" "typescript" "jsx" "ruby"))
   8812          (setq reg-col (if web-mode-script-padding (+ reg-col web-mode-script-padding) 0)))
   8813         ((member language '("css" "sql" "markdown" "pug" "sass" "stylus"))
   8814          (setq reg-col (if web-mode-style-padding (+ reg-col web-mode-style-padding) 0)))
   8815         ((not (member language '("html" "xml")))
   8816          (setq reg-col
   8817                (cond
   8818                  ((not web-mode-block-padding) reg-col)
   8819                  ((eq web-mode-block-padding -1) 0)
   8820                  (t (+ reg-col web-mode-block-padding))
   8821                  ) ;cond
   8822                ) ;setq
   8823          )
   8824         )
   8825 
   8826       (list :curr-char curr-char
   8827             :curr-indentation curr-indentation
   8828             :curr-line curr-line
   8829             :language language
   8830             :options options
   8831             :prev-char prev-char
   8832             :prev-indentation prev-indentation
   8833             :prev-line prev-line
   8834             :prev-line-end prev-line-end
   8835             :prev-pos prev-pos
   8836             :reg-beg reg-beg
   8837             :reg-col reg-col
   8838             :token token)
   8839       )))
   8840 
   8841 (defun web-mode-indent-line ()
   8842 
   8843   (web-mode-scan)
   8844 
   8845   (let ((offset nil)
   8846         (char nil)
   8847         (debug nil)
   8848         (inhibit-modification-hooks nil)
   8849         (adjust t))
   8850 
   8851     (save-excursion
   8852       (back-to-indentation)
   8853       (setq char (char-after))
   8854       (let* ((pos (point))
   8855              (ctx (web-mode-point-context pos))
   8856              (curr-char (plist-get ctx :curr-char))
   8857              (curr-indentation (plist-get ctx :curr-indentation))
   8858              (curr-line (plist-get ctx :curr-line))
   8859              (language (plist-get ctx :language))
   8860              (prev-char (plist-get ctx :prev-char))
   8861              (prev-indentation (plist-get ctx :prev-indentation))
   8862              (prev-line (plist-get ctx :prev-line))
   8863              (prev-line-end (plist-get ctx :prev-line-end))
   8864              (prev-pos (plist-get ctx :prev-pos))
   8865              (reg-beg (plist-get ctx :reg-beg))
   8866              (reg-col (plist-get ctx :reg-col))
   8867              (token (plist-get ctx :token))
   8868              (options (plist-get ctx :options))
   8869              (chars (list curr-char prev-char))
   8870              (tmp nil)
   8871              (is-js (member language '("javascript" "jsx" "ejs" "typescript"))))
   8872 
   8873         (when (member language '("json" "typescript"))
   8874           (setq language "javascript"))
   8875 
   8876         ;;(message "%S %S" (plist-get ctx :language) language)
   8877         ;;(message "curr-char=[%c] prev-char=[%c]\n%S" curr-char prev-char ctx)
   8878         ;;(message "options=%S" ctx)
   8879 
   8880         (cond
   8881 
   8882           ((or (bobp) (= (line-number-at-pos pos) 1))
   8883            (when debug (message "I100(%S) first line" pos))
   8884            (setq offset 0))
   8885 
   8886           ;; #123 #1145
   8887           ((and web-mode-enable-front-matter-block
   8888                 (eq (char-after (point-min)) ?\-)
   8889                 (or (looking-at-p "---")
   8890                     (search-forward "---" (point-max) t)))
   8891            (when debug (message "I108(%S) front-matter-block" pos))
   8892            (setq offset nil))
   8893 
   8894           ;; #1073
   8895           ((get-text-property pos 'invisible)
   8896            (when debug (message "I110(%S) invible" pos))
   8897            (setq offset nil))
   8898 
   8899           ((string= token "string")
   8900            (when debug (message "I120(%S) string" pos))
   8901            (cond
   8902              ((web-mode-is-token-end pos)
   8903               (if (get-text-property pos 'block-side)
   8904                   (web-mode-block-token-beginning)
   8905                   (web-mode-part-token-beginning))
   8906               (setq offset (current-indentation))
   8907               )
   8908              ((and web-mode-enable-sql-detection
   8909                    (web-mode-block-token-starts-with (concat "[ \n]*" web-mode-sql-queries)))
   8910               (save-excursion
   8911                 (let (col)
   8912                   (web-mode-block-string-beginning)
   8913                   (skip-chars-forward "[ \"'\n]")
   8914                   (setq col (current-column))
   8915                   (goto-char pos)
   8916                   (if (looking-at-p "\\(SELECT\\|INSERT\\|DELETE\\|UPDATE\\|FROM\\|LEFT\\|JOIN\\|WHERE\\|GROUP BY\\|LIMIT\\|HAVING\\|\)\\)")
   8917                       (setq offset col)
   8918                       (setq offset (+ col web-mode-sql-indent-offset)))
   8919                   )
   8920                 ) ;save-excursion
   8921               )
   8922              ((and is-js
   8923                    (web-mode-is-ql-string pos "Relay\.QL"))
   8924               (setq offset (web-mode-relayql-indentation pos))
   8925               )
   8926              ((and is-js
   8927                    (web-mode-is-ql-string pos "gql"))
   8928               (setq offset (web-mode-relayql-indentation pos "gql"))
   8929               )
   8930              ((and is-js
   8931                    (web-mode-is-ql-string pos "graphql"))
   8932               (setq offset (web-mode-relayql-indentation pos "graphql"))
   8933               )
   8934              ((and is-js
   8935                    (web-mode-is-css-string pos))
   8936               (when debug (message "I127(%S) css string" pos))
   8937               (setq offset (web-mode-token-css-indentation pos))
   8938               )
   8939              ((and is-js
   8940                    (web-mode-is-html-string pos))
   8941               (when debug (message "I128(%S) html string" pos))
   8942               (setq offset (web-mode-token-html-indentation pos))
   8943               )
   8944              (t
   8945               (setq offset nil))
   8946              ) ;cond
   8947            ) ;case string
   8948 
   8949           ((string= token "comment")
   8950            (when debug (message "I130(%S) comment" pos))
   8951            (if (eq (get-text-property pos 'tag-type) 'comment)
   8952                (web-mode-tag-beginning)
   8953                (goto-char (car
   8954                            (web-mode-property-boundaries
   8955                             (if (eq (get-text-property pos 'part-token) 'comment)
   8956                                 'part-token
   8957                                 'block-token)
   8958                             pos))))
   8959            (setq offset (current-column))
   8960            (cond
   8961              ((string= web-mode-engine "freemarker")
   8962               (setq offset (+ (current-indentation) 2)))
   8963              ((member (buffer-substring-no-properties (point) (+ (point) 2)) '("/*" "{*" "@*"))
   8964               (cond
   8965                 ((eq ?\* curr-char)
   8966                  (setq offset (+ offset 1)))
   8967                 (t
   8968                  (setq offset (+ offset 3)))
   8969                 ) ;cond
   8970               )
   8971              ((string= (buffer-substring-no-properties (point) (+ (point) 4)) "<!--")
   8972               (cond
   8973                 ((string-match-p "^<!\\[endif" curr-line)
   8974                  )
   8975                 ((looking-at-p "<!--\\[if")
   8976                  (setq offset (+ offset web-mode-markup-indent-offset)))
   8977                 ((string-match-p "^-->" curr-line)
   8978                  (setq offset offset))
   8979                 ((string-match-p "^-" curr-line)
   8980                  (setq offset (+ offset 3)))
   8981                 (t
   8982                  (setq offset (+ offset web-mode-markup-comment-indent-offset)))
   8983                 ) ;cond
   8984               )
   8985              ((and (string= web-mode-engine "django") (looking-back "{% comment %}" (point-min)))
   8986               (setq offset (- offset 12)))
   8987              ((and (string= web-mode-engine "mako") (looking-back "<%doc%>" (point-min)))
   8988               (setq offset (- offset 6)))
   8989              ((and (string= web-mode-engine "mason") (looking-back "<%doc%>" (point-min)))
   8990               (setq offset (- offset 6)))
   8991              ) ;cond
   8992            ) ;case comment
   8993 
   8994           ((and (string= web-mode-engine "mason")
   8995                 (string-match-p "^%" curr-line))
   8996            (when debug (message "I140(%S) mason" pos))
   8997            (setq offset 0))
   8998 
   8999           ((and (string= web-mode-engine "razor")
   9000                 (string-match-p "^\\([{}]\\|else\\)" curr-line))
   9001            (when debug (message "I142(%S) razor" pos))
   9002            (save-excursion
   9003              (web-mode-block-previous)
   9004              (setq offset (current-indentation))
   9005              ))
   9006 
   9007           ((and (string= web-mode-engine "django")
   9008                 (string-match-p "^#" curr-line))
   9009            (when debug (message "I144(%S) django line statements" pos))
   9010            (setq offset 0))
   9011 
   9012           ((and (get-text-property pos 'block-beg)
   9013                 (or (web-mode-block-is-close pos)
   9014                     (web-mode-block-is-inside pos)))
   9015            (when debug (message "I150(%S) block-match" pos))
   9016            (cond
   9017              ((not (web-mode-block-match))
   9018               )
   9019              ((and (string= web-mode-engine "closure")
   9020                    (string-match-p "{\\(case\\|default\\)" curr-line))
   9021               (setq offset (+ (current-indentation) web-mode-markup-indent-offset)))
   9022              (t
   9023               (setq offset (current-indentation))
   9024               (if (and (string= web-mode-engine "blade")
   9025                        (string-match-p "@break" curr-line))
   9026                   (setq offset (+ (current-indentation) offset)))
   9027               )
   9028              ) ;cond
   9029            )
   9030 
   9031           ((eq (get-text-property pos 'block-token) 'delimiter-end)
   9032            (when debug (message "I160(%S) block-beginning" pos))
   9033            (when (web-mode-block-beginning)
   9034              (setq reg-col (current-indentation))
   9035              (setq offset (current-column))))
   9036 
   9037           ((or (and (get-text-property pos 'tag-beg)
   9038                     (eq (get-text-property pos 'tag-type) 'end))
   9039                (and (eq (get-text-property pos 'tag-type) 'comment)
   9040                     (string-match-p "<!--#\\(else\\|elif\\|endif\\)" curr-line)))
   9041            (when debug (message "I170(%S) tag-match" pos))
   9042            (when (web-mode-tag-match)
   9043              (setq offset (current-indentation))))
   9044 
   9045           ((and (member language '("jsx"))
   9046                 (eq curr-char ?\})
   9047                 (get-text-property pos 'jsx-end))
   9048            (when debug (message "I180(%S) jsx-expr-end" pos))
   9049            (web-mode-go (1- reg-beg))
   9050            (setq reg-col nil)
   9051            ;;(setq offset (current-column)))
   9052            (setq offset (current-indentation)))
   9053 
   9054           ((and (member language '("html" "xml" "javascript" "jsx"))
   9055                 (get-text-property pos 'tag-type)
   9056                 (not (get-text-property pos 'tag-beg))
   9057                 ;;(or (not (string= language "jsx"))
   9058                 ;;    (string= options "is-html"))
   9059                 (not (and (string= language "jsx")
   9060                           (web-mode-jsx-is-expr pos)))
   9061                 )
   9062            (when debug (message "I190(%S) attr-indent" pos))
   9063            (cond
   9064              ((and (not (get-text-property pos 'tag-attr-beg))
   9065                    (get-text-property pos 'tag-attr)
   9066                    (get-text-property (1- pos) 'tag-attr)
   9067                    (web-mode-attribute-beginning)
   9068                    (not (string-match-p "^/?>" curr-line))
   9069                    ;;(progn (message "pos=%S point=%S" pos (point)) t)
   9070                    )
   9071 
   9072               (cond
   9073                 ((eq (logand (get-text-property (point) 'tag-attr-beg) 8) 8)
   9074                  (setq offset nil))
   9075                 ((not (web-mode-tag-beginning))
   9076                  (message "** tag-beginning ** failure")
   9077                  (setq offset nil))
   9078                 (web-mode-attr-value-indent-offset
   9079                  (setq offset (+ (current-column) web-mode-attr-value-indent-offset)))
   9080                 ((web-mode-dom-rsf "=[ ]*[\"']?" pos)
   9081                  ;;(message "%S" (point))
   9082                  (setq offset (current-column)))
   9083                 (t
   9084                  (setq offset (+ (current-column) web-mode-markup-indent-offset)))
   9085                 ) ;cond
   9086               ) ;and
   9087              ((not (web-mode-tag-beginning))
   9088               (message "** error ** unable to jump to tag beg"))
   9089              ((string-match-p "^/?>" curr-line)
   9090               (setq offset (web-mode-column-at-pos (web-mode-tag-beginning-position pos)))
   9091               )
   9092              (web-mode-attr-indent-offset
   9093               (setq offset (+ (current-column) web-mode-attr-indent-offset)))
   9094              ((looking-at-p (concat web-mode-start-tag-regexp "[ ]*\n"))
   9095               ;;(message "%S: %S" (point) (web-mode-inside-block-control pos))
   9096               (setq offset (+ (current-column) (or web-mode-attr-indent-offset web-mode-code-indent-offset)))
   9097               ;; #1109
   9098               (setq tmp (web-mode-inside-block-control pos))
   9099               (when (and tmp (> tmp (point)))
   9100                 (setq offset (+ offset (or web-mode-attr-indent-offset web-mode-code-indent-offset))))
   9101               )
   9102              ((web-mode-attribute-next)
   9103               (setq offset (current-column)))
   9104              ) ;cond
   9105            ) ;attr-indent
   9106 
   9107           ((or (member language '("html" "xml"))
   9108                (and (member language '("jsx"))
   9109                     (string= options "is-html")))
   9110            (when debug (message "I200(%S) web-mode-markup-indentation" pos))
   9111            ;; https://www.w3.org/TR/html5/syntax.html#optional-tags
   9112            (when web-mode-enable-optional-tags
   9113              (save-excursion
   9114                (let (tag-name parent-tag-name parent-tag-pos)
   9115                  (when (and (setq tag-name (get-text-property pos 'tag-name))
   9116                             (setq parent-tag-pos (web-mode-element-parent-position pos))
   9117                             (setq parent-tag-name (get-text-property parent-tag-pos 'tag-name))
   9118                             (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")))
   9119                                 (and (string= parent-tag-name "li") (member tag-name '("li")))
   9120                                 (and (string= parent-tag-name "dt") (member tag-name '("dt" "dd")))
   9121                                 (and (string= parent-tag-name "td") (member tag-name '("td" "th")))
   9122                                 (and (string= parent-tag-name "th") (member tag-name '("td" "th")))
   9123                                 ))
   9124                    (when debug (message "I205(%S) %S(%S) auto-closing" pos parent-tag-name parent-tag-pos))
   9125                    (setq offset (web-mode-indentation-at-pos parent-tag-pos))
   9126                    )))) ; when let save-excursion when
   9127 
   9128            (when (string= web-mode-engine "closure")
   9129              (save-excursion
   9130                (when (and (re-search-backward "{/?switch" nil t)
   9131                           (string= (match-string-no-properties 0) "{switch"))
   9132                  (setq offset (+ (current-indentation) (* 2 web-mode-markup-indent-offset)))
   9133                  )
   9134                ))
   9135            (cond
   9136              ((not (null offset))
   9137               )
   9138              ((get-text-property pos 'tag-beg)
   9139               (setq offset (web-mode-markup-indentation pos))
   9140               )
   9141              ((and web-mode-indentless-elements
   9142                    (not (string= language "jsx"))
   9143                    (null (get-text-property pos 'block-side))
   9144                    (null (get-text-property pos 'part-side))
   9145                    (and (null (get-text-property pos 'tag-beg))
   9146                         (save-excursion
   9147                           (and (web-mode-element-parent)
   9148                                (member (get-text-property (point) 'tag-name) web-mode-indentless-elements))))
   9149                    )
   9150               (setq offset nil))
   9151              ((or (eq (length curr-line) 0)
   9152                   (= web-mode-indent-style 2)
   9153                   (get-text-property pos 'tag-beg)
   9154                   (get-text-property pos 'reg-beg))
   9155               (setq offset (web-mode-markup-indentation pos))
   9156               )
   9157              )
   9158            )
   9159 
   9160           ((string= language "ctemplate")
   9161            (when debug (message "I210(%S) ctemplate" pos))
   9162            (setq offset reg-col))
   9163 
   9164           ((string= language "antlers")
   9165            (when debug (message "I214(%S) antlers" pos))
   9166            (setq offset reg-col))
   9167 
   9168           ((string= language "expressionengine")
   9169            (when debug (message "I220(%S) expressionengine" pos))
   9170            (setq offset (+ reg-col (or web-mode-attr-indent-offset web-mode-code-indent-offset))))
   9171 
   9172           ((string= language "asp")
   9173            (when debug (message "I230(%S) asp" pos))
   9174            (setq offset (web-mode-asp-indentation pos
   9175                                                   curr-line
   9176                                                   reg-col
   9177                                                   curr-indentation
   9178                                                   reg-beg)))
   9179 
   9180           ((member language '("lsp" "cl-emb" "artanis"))
   9181            (when debug (message "I240(%S) lsp" pos))
   9182            (setq offset (web-mode-lisp-indentation pos ctx)))
   9183 
   9184           ((and (member curr-char '(?\}))
   9185                 (string= language "razor")
   9186                 (get-text-property pos 'block-end))
   9187            (when debug (message "I245(%S) razor closing" pos))
   9188            (goto-char reg-beg)
   9189            ;;(message "%S %S" (point) (current-column))
   9190            (setq offset (current-column)
   9191                  reg-col nil)
   9192            )
   9193 
   9194           ((member curr-char '(?\} ?\) ?\]))
   9195            (when debug (message "I250(%S) closing-paren" pos))
   9196            (let (ori pos2)
   9197              (setq pos2 pos)
   9198              ;; #1096
   9199              (when (looking-at-p ".[\]})]+")
   9200                (skip-chars-forward "[\]})]")
   9201                (backward-char)
   9202                (setq pos2 (point))
   9203                ) ;when
   9204              (if (get-text-property pos 'block-side)
   9205                  (setq ori (web-mode-block-opening-paren-position pos2 reg-beg))
   9206                  (setq ori (web-mode-part-opening-paren-position pos2 reg-beg)))
   9207              ;;(message "ori=%S" ori)
   9208              (cond
   9209                ((null ori)
   9210                 (setq offset reg-col))
   9211                ((and (goto-char ori)
   9212                      (looking-back ")[ ]*" (point-min)) ;; peut-on se passer du looking-back ?
   9213                      (re-search-backward ")[ ]*" nil t)
   9214                      (web-mode-block-opening-paren reg-beg))
   9215                 (back-to-indentation)
   9216                 (setq offset (current-indentation))
   9217                 )
   9218                (t
   9219                 (goto-char ori)
   9220                 (back-to-indentation)
   9221                 (setq offset (current-indentation))
   9222                 ;;(message "ori=%S offset=%S" ori offset)
   9223                 (when (get-text-property pos 'jsx-depth)
   9224                   ;;(when (get-text-property pos 'jsx-end)
   9225                   (setq adjust nil))
   9226                 ) ;t
   9227                ) ;cond
   9228              ) ;let
   9229            )
   9230 
   9231           ((member language '("mako" "web2py"))
   9232            (when debug (message "I254(%S) python (mako/web2py)" pos))
   9233            (setq offset (web-mode-python-indentation pos
   9234                                                      curr-line
   9235                                                      reg-col
   9236                                                      curr-indentation
   9237                                                      reg-beg)))
   9238 
   9239           ((member language '("erb" "ruby"))
   9240            (when debug (message "I260(%S) erb" pos))
   9241            (setq offset (web-mode-ruby-indentation pos
   9242                                                    curr-line
   9243                                                    reg-col
   9244                                                    curr-indentation
   9245                                                    reg-beg)))
   9246 
   9247           ((string= language "css")
   9248            (when debug (message "I270(%S) css-indentation" pos))
   9249            ;;(message "prev=%c" prev-char)
   9250            (cond
   9251              ((eq prev-char ?:)
   9252               (setq offset (+ prev-indentation web-mode-css-indent-offset)))
   9253              ((eq prev-char ?,)
   9254               (setq offset prev-indentation))
   9255              (t
   9256               (setq offset (car (web-mode-css-indentation pos
   9257                                                           reg-col
   9258                                                           curr-indentation
   9259                                                           language
   9260                                                           reg-beg))))))
   9261 
   9262           ((string= language "sql")
   9263            (when debug (message "I280(%S) sql" pos))
   9264            (setq offset (car (web-mode-sql-indentation pos
   9265                                                        reg-col
   9266                                                        curr-indentation
   9267                                                        language
   9268                                                        reg-beg))))
   9269 
   9270           ((string= language "markdown")
   9271            (when debug (message "I290(%S) markdown" pos))
   9272            (setq offset (car (web-mode-markdown-indentation pos
   9273                                                             reg-col
   9274                                                             curr-indentation
   9275                                                             language
   9276                                                             reg-beg))))
   9277 
   9278           ((string= language "stylus")
   9279            (when debug (message "I294(%S) stylus" pos))
   9280            (setq offset (car (web-mode-stylus-indentation pos
   9281                                                           reg-col
   9282                                                           curr-indentation
   9283                                                           language
   9284                                                           reg-beg))))
   9285           ((string= language "sass")
   9286            (when debug (message "I296(%S) sass" pos))
   9287            (setq offset (car (web-mode-stylus-indentation pos
   9288                                                           reg-col
   9289                                                           curr-indentation
   9290                                                           language
   9291                                                           reg-beg))))
   9292 
   9293           ((string= language "pug")
   9294            (when debug (message "I298(%S) pug" pos))
   9295            (setq offset (car (web-mode-pug-indentation pos
   9296                                                        reg-col
   9297                                                        curr-indentation
   9298                                                        language
   9299                                                        reg-beg))))
   9300 
   9301           ((and (string= language "razor")
   9302                 (string-match-p "^\\." curr-line)
   9303                 (string-match-p "^\\." prev-line))
   9304            (when debug (message "I300(%S) razor" pos))
   9305            (setq offset prev-indentation))
   9306 
   9307           ((and (string= language "razor")
   9308                 (string-match-p "^case " curr-line)
   9309                 (string-match-p "^case " prev-line))
   9310            (when debug (message "I310(%S) razor case" pos))
   9311            (search-backward "case ")
   9312            (setq offset (current-column)))
   9313 
   9314           ((and is-js
   9315                 (member ?\. chars)
   9316                 (not (string-match-p "^\\.\\.\\." curr-line)))
   9317            (when debug (message "I320(%S) javascript-calls" pos))
   9318            (let (pair)
   9319              (setq pair (web-mode-javascript-calls-beginning-position pos reg-beg))
   9320              ;;(message "%S" pair)
   9321              (when pair
   9322                (goto-char (car pair))
   9323                ;;(message "%S %S" (point) pair)
   9324                (cond
   9325                  ((cdr (assoc "lineup-calls" web-mode-indentation-params))
   9326                   ;;(message "ici")
   9327                   ;;(search-forward ".")
   9328                   (if (cdr pair)
   9329                       (progn
   9330                         (goto-char (cdr pair))
   9331                         (setq offset (current-column))
   9332                         (looking-at "\\.\\([ \t\n]*\\)")
   9333                         (setq offset (- offset (length (match-string-no-properties 1))))
   9334                         (unless (eq curr-char ?\.) (setq offset (1+ offset)))
   9335                         ) ;progn
   9336                       ;; TODO: cela devrait etre fait dans web-mode-javascript-calls-beginning-position
   9337                       (skip-chars-forward " \t\n")
   9338                       (setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9339                       ) ;if
   9340                   )
   9341                  (t
   9342                   (setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9343                   ) ;t
   9344                  ) ;cond
   9345                ) ;when
   9346              ) ;let
   9347            )
   9348 
   9349           ((and is-js
   9350                 (member ?\+ chars))
   9351            (when debug (message "I330(%S) javascript-string" pos))
   9352            ;;(message "js-concat")
   9353            (cond
   9354              ((not (web-mode-javascript-string-beginning pos reg-beg))
   9355               )
   9356              ((null (cdr (assoc "lineup-concats" web-mode-indentation-params)))
   9357               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9358              ((not (eq curr-char ?\+))
   9359               (setq offset (current-column)))
   9360              (t
   9361               (setq offset (current-column))
   9362               (when (not (looking-back "\\(^[ \t]+\\|if[ ]*[(]?\\)" (point-min)))
   9363                 (goto-char pos)
   9364                 (looking-at "\\+[ \t\n]*")
   9365                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9366               )
   9367              )
   9368            )
   9369 
   9370           ;; #579 , #742
   9371           ((and (member language '("javascript" "jsx" "ejs" "php"))
   9372                 (string-match-p "=[>]?$" prev-line))
   9373            (when debug (message "I340(%S)" pos))
   9374            (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9375            ;;(message "ici%S" offset)
   9376            )
   9377 
   9378           ;; #1016
   9379           ((and (member language '("javascript" "jsx" "ejs"))
   9380                 (string-match-p "^[ \t]*|}" curr-line))
   9381            (when debug (message "I346(%S) flow-exact-object-type-end" pos))
   9382            (when (re-search-backward "{|" reg-beg t)
   9383              (setq offset (current-indentation))
   9384              )
   9385            )
   9386 
   9387           ;; #446, #638, #800, #978, #998
   9388           ((and (member language '("javascript" "jsx" "ejs" "php"))
   9389                 (or (string-match-p "[&|?:+-]$" prev-line)
   9390                     (string-match-p "^[&|?:+-]" curr-line))
   9391                 (not (and (string= language "php")
   9392                           (string-match-p "^->" curr-line)))
   9393                 (not (and (string= language "php")
   9394                           (string-match-p "^?[a-zA-z]*" curr-line)))
   9395                 (not (and (string= language "php")
   9396                           (string-match-p "\\(else[ ]?:\\|if[ ]?([^)]*)[ ]?:\\)" prev-line)))
   9397                 (not (string-match-p "^\\(++\\|--\\)" curr-line))
   9398                 (not (and is-js
   9399                           (string-match-p "]:\\|{|$" prev-line)))
   9400                 (not (and (eq prev-char ?\:)
   9401                           (string-match-p "^\\(case\\|default\\)" prev-line)))
   9402                 )
   9403            ;;(message "prev=%S" prev-line)
   9404            (when debug (message "I350(%S) multiline statement" pos))
   9405            (let (is-ternary)
   9406              (setq is-ternary (or (string-match-p "[?:]$" prev-line)
   9407                                   (string-match-p "^[?:]" curr-line)))
   9408              (cond
   9409                ((not (funcall (if is-js
   9410                                   'web-mode-javascript-statement-beginning
   9411                                   'web-mode-block-statement-beginning)
   9412                               pos reg-beg is-ternary))
   9413                 )
   9414                ((null (cdr (assoc "lineup-ternary" web-mode-indentation-params)))
   9415                 (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9416                (t
   9417                 (setq offset (current-column))
   9418                 (when (and (member curr-char '(?\+ ?\- ?\& ?\| ?\? ?\:))
   9419                            (not (looking-back "\\(^[ \t]+\\|if[ ]*[(]?\\)" (point-min)))) ; #743
   9420                   (goto-char pos)
   9421                   (looking-at "\\(||\\|&&\\|[&|?:+-]\\)[ \t\n]*")
   9422                   (setq offset (- offset (length (match-string-no-properties 0)))))
   9423                 )
   9424                ) ;cond
   9425              ) ;let
   9426            )
   9427 
   9428           ((and is-js
   9429                 (eq prev-char ?\()
   9430                 (string-match-p "=>[ ]*([ ]*$" prev-line))
   9431            (when debug (message "I355(%S) => (" pos))
   9432            (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9433            )
   9434 
   9435           ((and is-js
   9436                 (or (member ?\, chars)
   9437                     (member prev-char '(?\( ?\[))))
   9438            (when debug (message "I360(%S) javascript-args(%S)" pos (web-mode-jsx-is-html prev-line-end)))
   9439            (cond
   9440              ((not (web-mode-javascript-args-beginning pos reg-beg))
   9441               (message "no js args beg")
   9442               )
   9443              ((or (not (cdr (assoc "lineup-args" web-mode-indentation-params)))
   9444                   (looking-at-p "|?\n") ;; #1016
   9445                   ;;(eq (char-after) ?\n)
   9446                   )
   9447               (if (and reg-col (> reg-col (current-indentation)))
   9448                   (setq offset (+ reg-col web-mode-code-indent-offset))
   9449                   (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9450               )
   9451              ((not (eq curr-char ?\,))
   9452               (setq offset (current-column)))
   9453              (t
   9454               (setq offset (current-column))
   9455               (goto-char pos)
   9456               (looking-at ",[ \t\n]*")
   9457               (setq offset (- offset (length (match-string-no-properties 0)))))
   9458              ) ;cond
   9459            )
   9460 
   9461           ((and is-js
   9462                 (or (eq prev-char ?\))
   9463                     (string-match-p "\\(^\\|[}[:space:]]+\\)else$" prev-line)))
   9464            (when debug (message "I370(%S)" pos))
   9465            (cond
   9466              ((and (string-match-p "else$" prev-line)
   9467                    (not (string-match-p "^{" curr-line)))
   9468               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9469               )
   9470              ((and (string-match-p "else$" prev-line)
   9471                    (string-match-p "^{" curr-line)
   9472                    web-mode-enable-curly-brace-indentation)
   9473               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9474               )
   9475              ((setq tmp (web-mode-part-is-opener prev-pos reg-beg))
   9476               ;;(message "is-opener")
   9477               (if (or (not (looking-at-p "{")) ;; #1020, #1053, #1160
   9478                       web-mode-enable-curly-brace-indentation)
   9479                   (setq offset (+ tmp web-mode-code-indent-offset))
   9480                   (setq offset tmp))
   9481               )
   9482              (t
   9483               (setq offset
   9484                     (car (web-mode-javascript-indentation pos
   9485                                                           reg-col
   9486                                                           curr-indentation
   9487                                                           language
   9488                                                           reg-beg)))
   9489               ) ;t
   9490              ) ;cond
   9491 
   9492            )
   9493 
   9494           ;; TODO : a retoucher completement car le code js a ete place ci-dessus
   9495           ;;((and (member language '("javascript" "jsx" "ejs" "php"))
   9496           ((and (member language '("php"))
   9497                 (or (and (eq prev-char ?\))
   9498                          (string-match-p "^\\(for\\|foreach\\|if\\|else[ ]*if\\|while\\)[ ]*(" prev-line))
   9499                     (and is-js
   9500                          (web-mode-part-is-opener prev-pos reg-beg))
   9501                     (string-match-p "^else$" prev-line))
   9502                 (not (string-match-p "^\\([{.]\\|->\\)" curr-line)))
   9503            (when debug (message "I380(%S)" pos))
   9504            (cond
   9505              ((and (eq prev-char ?\))
   9506                    (string-match-p "^\\(for\\|if\\|while\\)[ ]*(" prev-line))
   9507               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9508               )
   9509              ((member language '("javascript" "jsx"))
   9510               (setq offset
   9511                     (+ (car (web-mode-javascript-indentation pos
   9512                                                              reg-col
   9513                                                              curr-indentation
   9514                                                              language
   9515                                                              reg-beg))
   9516                        web-mode-code-indent-offset))
   9517               )
   9518              (t
   9519               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9520               )
   9521              )
   9522            )
   9523 
   9524           ((and (member language '("php" "blade")) (string-match-p "^->" curr-line))
   9525            (when debug (message "I390(%S) block-calls" pos))
   9526            (cond
   9527              ((not (web-mode-block-calls-beginning pos reg-beg))
   9528               )
   9529              ((cdr (assoc "lineup-calls" web-mode-indentation-params))
   9530               ;;(message "point=%S" (point))
   9531               (if (looking-back "::[ ]*" (point-min))
   9532                   (progn
   9533                     (re-search-backward "::[ ]*")
   9534                     (setq offset (current-column))
   9535                     ;;(message "ici%S offset=%S" (point) offset)
   9536                     )
   9537                   (search-forward "->")
   9538                   (setq offset (- (current-column) 2)))
   9539               )
   9540              (t
   9541               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9542              ))
   9543 
   9544           ((and is-js (member ?\, chars))
   9545            (when debug (message "I400(%S) part-args" pos))
   9546            (cond
   9547              ((not (web-mode-part-args-beginning pos reg-beg))
   9548               ;;(message "ici")
   9549               )
   9550              ((cdr (assoc "lineup-args" web-mode-indentation-params))
   9551               (setq offset (current-column))
   9552               ;;(message "offset=%S" offset)
   9553               (when (eq curr-char ?\,)
   9554                 (goto-char pos)
   9555                 (looking-at ",[ \t\n]*")
   9556                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9557               )
   9558              (t
   9559               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9560              ))
   9561 
   9562           ((member ?\, chars)
   9563            (when debug (message "I401(%S) block-args" pos))
   9564            (cond
   9565              ((not (web-mode-block-args-beginning pos reg-beg))
   9566               ;;(message "ici")
   9567               )
   9568              ((cdr (assoc "lineup-args" web-mode-indentation-params))
   9569               (setq offset (current-column))
   9570               ;;(message "offset=%S" offset)
   9571               (when (eq curr-char ?\,)
   9572                 (goto-char pos)
   9573                 (looking-at ",[ \t\n]*")
   9574                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9575               )
   9576              (t
   9577               (setq offset (current-column))
   9578               ;;(message "point=%S offset=%S" (point) offset)
   9579               (if (looking-back "[ ]+" (point-min))
   9580                   (progn
   9581                     (setq offset (current-indentation)))
   9582                 (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9583               ;;(when (eq curr-char ?\,)
   9584               ;;  (goto-char pos)
   9585               ;;  (looking-at ",[ \t\n]*")
   9586               ;;  (setq offset (- offset (length (match-string-no-properties 0)))))
   9587               ;;(setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9588               ) ;t
   9589              ))
   9590 
   9591 
   9592           ((and (string= language "php") (member ?\. chars))
   9593            (when debug (message "I410(%S) block-string" pos))
   9594            (cond
   9595              ((not (web-mode-block-string-beginning pos reg-beg))
   9596               )
   9597              ((null (cdr (assoc "lineup-concats" web-mode-indentation-params)))
   9598               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9599              ((not (eq curr-char ?\.))
   9600               (setq offset (current-column)))
   9601              (t
   9602               (setq offset (current-column))
   9603               (goto-char pos)
   9604               (when (cdr (assoc "lineup-quotes" web-mode-indentation-params))
   9605                 (looking-at "\\.[ \t\n]*")
   9606                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9607               )))
   9608 
   9609           ((member language '("javascript" "jsx" "ejs" "underscore"))
   9610            (when debug (message "I420(%S) javascript-indentation" pos))
   9611            (setq offset (car (web-mode-javascript-indentation pos
   9612                                                               reg-col
   9613                                                               curr-indentation
   9614                                                               language
   9615                                                               reg-beg))))
   9616 
   9617           (t
   9618            (when debug (message "I430(%S) bracket-indentation" pos))
   9619            (setq offset (car (web-mode-bracket-indentation pos
   9620                                                            reg-col
   9621                                                            curr-indentation
   9622                                                            language
   9623                                                            reg-beg))))
   9624 
   9625           ) ;cond
   9626 
   9627         (when (and offset reg-col adjust (< offset reg-col)) (setq offset reg-col))
   9628 
   9629         ) ;let
   9630       ) ;save-excursion
   9631 
   9632     (when offset
   9633       ;;(message "offset=%S" offset)
   9634       (let ((diff (- (current-column) (current-indentation))))
   9635         (when (not (= offset (current-indentation)))
   9636           (setq web-mode-change-beg (line-beginning-position)
   9637                 web-mode-change-end (+ web-mode-change-beg offset)))
   9638         (setq offset (max 0 offset))
   9639         (indent-line-to offset)
   9640         (if (> diff 0) (move-to-column (+ (current-column) diff)))
   9641         (when (and (string= web-mode-engine "mason")
   9642                    (= offset 0)
   9643                    (eq char ?\%))
   9644           (save-excursion
   9645             (font-lock-fontify-region (line-beginning-position) (line-end-position)))
   9646           ) ;when
   9647         ) ;let
   9648       ) ;when
   9649 
   9650     ))
   9651 
   9652 (defun web-mode-bracket-level (pos limit)
   9653   (save-excursion
   9654     (let ((continue t)
   9655           (regexp "[\]\[}{)(]")
   9656           (char nil)
   9657           (map nil)
   9658           (key nil)
   9659           (value 0)
   9660           (open '(?\( ?\{ ?\[)))
   9661       (goto-char pos)
   9662       (while (and continue (re-search-backward regexp limit t))
   9663         (setq char (aref (match-string-no-properties 0) 0))
   9664         (setq key (cond ((eq char ?\)) ?\()
   9665                         ((eq char ?\}) ?\{)
   9666                         ((eq char ?\]) ?\[)
   9667                         (t             char)))
   9668         (setq value (or (plist-get map key) 0))
   9669         (setq value (if (member char open) (1+ value) (1- value)))
   9670         (setq map (plist-put map key value))
   9671         (setq continue (< value 1))
   9672         ;;(message "pos=%S char=%c key=%c value=%S" (point) char key value)
   9673         ) ;while
   9674       (if (>= value 1) (current-indentation) nil)
   9675       )))
   9676 
   9677 (defun web-mode-token-html-indentation (pos)
   9678   (save-excursion
   9679     (let (beg (continue t) end level map offset regexp tag val void (css-beg 0))
   9680       (goto-char pos)
   9681       ;;(message "pos=%S" pos)
   9682       (setq beg (web-mode-part-token-beginning-position pos))
   9683       (save-excursion
   9684         (when (and (> (- pos beg) 5)
   9685                    (re-search-backward "</?[a-zA-Z0-9]+" beg t)
   9686                    (string= "<style" (downcase (match-string-no-properties 0))))
   9687           (setq css-beg (point))
   9688           )
   9689         )
   9690       ;;(message "beg=%S" beg)
   9691       (cond
   9692         ((eq (char-after pos) ?\`)
   9693          (setq offset (web-mode-indentation-at-pos beg)))
   9694         ((web-mode-looking-back "`[ \n\t]*" pos)
   9695          (setq offset (+ (web-mode-indentation-at-pos beg) web-mode-markup-indent-offset)))
   9696         ((looking-at "</\\([a-zA-Z0-9]+\\)")
   9697          (setq tag (match-string-no-properties 1)
   9698                regexp (concat "</?" tag)
   9699                level -1)
   9700          (while (and continue (re-search-backward regexp beg t))
   9701            (cond
   9702              ((eq (aref (match-string-no-properties 0) 1) ?\/)
   9703               (setq level (1- level)))
   9704              (t
   9705               (setq level (1+ level)))
   9706              ) ;cond
   9707            (when (= level 0)
   9708              (setq continue nil
   9709                    offset (current-indentation)))
   9710            ) ;while
   9711          )
   9712         ((> css-beg 0)
   9713          ;;(message "CSS")
   9714          (cond
   9715            ((member (char-after) '(?\) ?\} ?\]))
   9716             (web-mode-go (web-mode-token-opening-paren-position pos (+ css-beg 8) ""))
   9717             (setq offset (current-indentation))
   9718             )
   9719            ((setq level (web-mode-bracket-level pos (+ css-beg 8)))
   9720             (setq offset (+ level web-mode-css-indent-offset))
   9721             )
   9722            (t
   9723             (setq offset (+ (web-mode-indentation-at-pos css-beg) web-mode-style-padding))
   9724             ) ;t
   9725            )
   9726          )
   9727         ((looking-at "[a-zA-Z-]+[ ]?=")
   9728          (re-search-backward "<[a-zA-Z]+[ ]*" beg t)
   9729          (setq offset (+ (current-column) (length (match-string-no-properties 0))))
   9730          )
   9731         ((looking-at-p "/>")
   9732          (search-backward "<" beg t)
   9733          (setq offset (current-column))
   9734          )
   9735         (t
   9736          (setq regexp "</?\\([a-zA-Z0-9]+\\)")
   9737          ;;(message "point=%S" (point))
   9738          (while (and continue (re-search-backward regexp beg t))
   9739            (setq tag (downcase (match-string-no-properties 1))
   9740                  end nil
   9741                  void nil)
   9742            (cond
   9743              ((eq (aref (match-string-no-properties 0) 1) ?/)
   9744               (setq end t))
   9745              ((web-mode-element-is-void tag)
   9746               (setq void t))
   9747              (t
   9748               (save-excursion
   9749                 (when (and (search-forward ">" pos t) (eq (char-before (1- (point))) ?\/))
   9750                   (setq void t))
   9751                 ) ;save-excursion
   9752               ) ;t
   9753              ) ;cond
   9754            (unless void
   9755              (setq val (or (lax-plist-get map tag) 0))
   9756              (setq val (if end (1- val) (1+ val)))
   9757              (setq map (lax-plist-put map tag val))
   9758              ;;(message "val=%S tag=%S end=%S | %S" val tag end (plist-get map tag))
   9759              (setq continue (not (> val 0)))
   9760              ) ;unless
   9761                                         ;(message "pos=%S tag=%S val=%S end=%S void=%S" (point) tag val end void)
   9762            ) ;while
   9763          (cond
   9764            ((> val 0)
   9765             ;;(message "point=%S" (point))
   9766             ;;(goto-char (1+ beg))
   9767             ;;(forward-char)
   9768             ;;(re-search-forward "[[:space:]]*")
   9769             (setq offset (+ (current-indentation) web-mode-markup-indent-offset)))
   9770            (t
   9771             (setq offset (current-indentation)))
   9772            )
   9773          ) ;t
   9774         ) ;cond
   9775       offset)))
   9776 
   9777 (defun web-mode-token-css-indentation (pos)
   9778   (save-excursion
   9779     (goto-char pos)
   9780     (web-mode-part-token-beginning)
   9781     (+ web-mode-css-indent-offset (current-indentation))
   9782     ))
   9783 
   9784 (defun web-mode-relayql-indentation (pos &optional prefix)
   9785   (unless prefix (setq prefix "relayql"))
   9786   (let (beg offset level char)
   9787     (setq char (char-after))
   9788     (setq beg (web-mode-part-token-beginning-position pos))
   9789     (goto-char beg)
   9790     (cond
   9791       ((member char '(?\`))
   9792        (setq offset (current-indentation))
   9793        )
   9794       ((member char '(?\) ?\} ?\]))
   9795        (web-mode-go (web-mode-token-opening-paren-position pos beg prefix))
   9796        (setq offset (current-indentation))
   9797        )
   9798       ((setq level (web-mode-bracket-level pos beg))
   9799        (setq offset (+ level web-mode-code-indent-offset))
   9800        )
   9801       (t
   9802        (setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9803        )
   9804       )
   9805     offset))
   9806 
   9807 (defun web-mode-markup-indentation (pos)
   9808   (let (offset beg ret jsx-depth)
   9809     (when (and (setq jsx-depth (get-text-property pos 'jsx-depth))
   9810                (get-text-property pos 'jsx-beg)
   9811                (not (get-text-property pos 'tag-beg)))
   9812       (setq jsx-depth (1- jsx-depth)))
   9813     ;;(when (setq beg (web-mode-markup-indentation-origin pos jsx-depth))
   9814     (cond
   9815       ((not (setq beg (web-mode-markup-indentation-origin pos jsx-depth)))
   9816        (setq offset 0))
   9817       ((null (setq ret (web-mode-element-is-opened beg pos)))
   9818        (setq offset (web-mode-indentation-at-pos beg)))
   9819       ((eq ret t)
   9820        (setq offset (+ (web-mode-indentation-at-pos beg)
   9821                        web-mode-markup-indent-offset)))
   9822       (t
   9823        (setq offset ret))
   9824       ) ;cond
   9825     ;;(message "markup-indentation-origin=%S (jsx-depth=%S)" beg jsx-depth)
   9826     ;;) ;when beg
   9827     offset))
   9828 
   9829 (defun web-mode-css-indentation (pos initial-column language-offset language &optional limit)
   9830   (let ((open-ctx (web-mode-bracket-up pos language limit)) offset)
   9831     (cond
   9832       ((or (null open-ctx) (null (plist-get open-ctx :pos)))
   9833        (setq offset initial-column))
   9834       (t
   9835        (setq offset (+ (plist-get open-ctx :indentation) language-offset)))
   9836       ) ;cond
   9837     (cons (if (< offset initial-column) initial-column offset) open-ctx)
   9838     ))
   9839 
   9840 (defun web-mode-sql-indentation (pos initial-column language-offset language &optional limit)
   9841   (let ((open-ctx (web-mode-bracket-up pos language limit)) offset)
   9842     ;;(message "%S %S %S %S %S" pos (point) initial-column language-offset open-ctx)
   9843     (cond
   9844       ((and (not (null open-ctx)) (not (null (plist-get open-ctx :pos))))
   9845        (setq offset (+ (plist-get open-ctx :column) 1)))
   9846       ((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\\)")
   9847        (setq offset initial-column))
   9848       (t
   9849        (setq offset (+ initial-column language-offset)))
   9850       ) ;cond
   9851     (cons (if (< offset initial-column) initial-column offset) open-ctx)
   9852     ))
   9853 
   9854 (defun web-mode-markdown-indentation (pos initial-column _language-offset _language &optional _limit)
   9855   (let (offset)
   9856     (save-excursion
   9857       (goto-char pos)
   9858       (setq offset (current-column))
   9859       ) ;save-excursion
   9860     ;;(message "%S %S %S %S" pos (point) initial-column language-offset)
   9861     (cons (if (<= offset initial-column) initial-column offset) nil)))
   9862 
   9863 (defun web-mode-stylus-indentation (pos initial-column language-offset _language &optional _limit)
   9864   (let (offset)
   9865     (save-excursion
   9866       (goto-char pos)
   9867       (setq offset (current-column))
   9868       (if (looking-at-p "[[:alnum:]-]+:")
   9869           (setq offset (+ initial-column language-offset))
   9870           (setq offset initial-column))
   9871       ) ;save-excursion
   9872     ;;(message "%S %S %S %S" pos (point) initial-column language-offset)
   9873     (cons (if (<= offset initial-column) initial-column offset) nil)))
   9874 
   9875 (defun web-mode-sass-indentation (pos initial-column language-offset _language &optional _limit)
   9876   (let (offset)
   9877     (save-excursion
   9878       (goto-char pos)
   9879       (setq offset (current-column))
   9880       (if (looking-at-p "[[:alnum:]-]+:")
   9881           (setq offset (+ initial-column language-offset))
   9882           (setq offset initial-column))
   9883       ) ;save-excursion
   9884     ;;(message "%S %S %S %S" pos (point) initial-column language-offset)
   9885     (cons (if (<= offset initial-column) initial-column offset) nil)))
   9886 
   9887 (defun web-mode-pug-indentation (_pos _initial-column _language-offset _language &optional _limit)
   9888   nil
   9889   )
   9890 
   9891 (defun web-mode-javascript-indentation (pos initial-column language-offset language &optional limit)
   9892   (let (open-ctx open-pos indentation offset sub block-pos)
   9893     (setq open-ctx (web-mode-bracket-up pos language limit))
   9894     ;;(message "%S" open-ctx)
   9895     ;;(message "pos(%S) initial-column(%S) language-offset(%S) language(%S) limit(%S)" pos initial-column language-offset language limit)
   9896     ;;(message "javascript-indentation: %S\nchar=%c" open-ctx (plist-get open-ctx :char))
   9897     (setq indentation (plist-get open-ctx :indentation))
   9898     (when (and initial-column (> initial-column indentation))
   9899       (setq indentation initial-column))
   9900     (setq case-fold-search nil) ;#1006
   9901     (when open-ctx
   9902       (setq open-pos (plist-get open-ctx :pos)))
   9903     (setq block-pos (web-mode-inside-block-control pos))
   9904     (when (and block-pos (> limit block-pos)) ;#1275
   9905       (setq block-pos nil))
   9906     ;;(message "bracket-pos=%S block-pos=%S" open-pos block-pos)
   9907     (cond
   9908       ((and block-pos (or (null open-pos) (> block-pos open-pos))) ;#1230
   9909        (setq offset (+ indentation language-offset)))
   9910       ((null open-pos)
   9911        (setq offset initial-column))
   9912       ((and (member language '("javascript" "jsx" "ejs"))
   9913             (eq (plist-get open-ctx :char) ?\{)
   9914             (web-mode-looking-back "switch[ ]*" (plist-get open-ctx :pos)))
   9915        (setq sub (if (cdr (assoc "case-extra-offset" web-mode-indentation-params)) 0 1))
   9916        (cond
   9917          ((looking-at-p "case\\|default")
   9918           (setq offset (+ indentation (* language-offset (- 1 sub)))))
   9919          (t
   9920           (setq offset (+ indentation (* language-offset (- 2 sub)))))
   9921          ) ;cond switch
   9922        )
   9923       (t
   9924        (setq offset (+ indentation language-offset)))
   9925       ) ;cond
   9926     (setq case-fold-search t)
   9927     (cons (if (< offset initial-column) initial-column offset) open-ctx)
   9928     ))
   9929 
   9930 (defun web-mode-bracket-indentation (pos initial-column language-offset language &optional limit)
   9931   (save-excursion
   9932     (let* ((ctx (web-mode-bracket-up pos language limit))
   9933            (char (plist-get ctx :char))
   9934            (pos (plist-get ctx :pos))
   9935            (indentation (plist-get ctx :indentation)))
   9936       ;;(message "pos(%S) initial-column(%S) language-offset(%S) language(%S) limit(%S)" pos initial-column language-offset language limit)
   9937       ;;(message "bracket-up: %S, %c" ctx char)
   9938       (cond
   9939         ((null pos)
   9940          (setq indentation initial-column))
   9941         ((and (member language '("php"))
   9942               (eq char ?\{)
   9943               (web-mode-looking-back "switch[ ]*" pos)
   9944               (not (looking-at-p "case\\|default")))
   9945          (setq indentation (+ indentation (* language-offset 2)))
   9946          )
   9947         ((and (member language '("php"))
   9948               (eq char ?\{)
   9949               (goto-char pos)
   9950               (web-mode-looking-back "[)][ ]*" pos)
   9951               (search-backward ")")
   9952               (web-mode-block-opening-paren limit))
   9953          (setq indentation (+ (current-indentation) language-offset))
   9954          )
   9955         (t
   9956          (setq indentation (+ indentation language-offset))
   9957          )
   9958         ) ;cond
   9959       (cons (if (< indentation initial-column) initial-column indentation) ctx)
   9960       )))
   9961 
   9962 (defun web-mode-ruby-indentation (pos line initial-column language-offset limit)
   9963   (unless limit (setq limit nil))
   9964   (let (h offset prev-line prev-indentation open-ctx)
   9965     (setq open-ctx (web-mode-bracket-up pos "ruby" limit))
   9966     ;;(message "%S" open-ctx)
   9967     (if (plist-get open-ctx :pos)
   9968         (cond
   9969           ((web-mode-looking-at-p ".[ \t\n]+" (plist-get open-ctx :pos))
   9970            (setq offset (+ (plist-get open-ctx :indentation) language-offset)))
   9971           (t
   9972            (setq offset (1+ (plist-get open-ctx :column))))
   9973           )
   9974         (setq h (web-mode-previous-line pos limit))
   9975         (setq offset initial-column)
   9976         (when h
   9977           (setq prev-line (car h))
   9978           (setq prev-indentation (cdr h))
   9979           (cond
   9980             ((string-match-p ",$" prev-line)
   9981              (save-excursion
   9982                (goto-char limit)
   9983                (looking-at "<%=? [a-z_]+ ")
   9984                (setq offset (+ initial-column (length (match-string-no-properties 0))))
   9985                ) ;save-excursion
   9986              )
   9987             ((string-match-p "^[ ]*\\(end\\|else\\|elsif\\|when\\)" line)
   9988              (setq offset (- prev-indentation language-offset))
   9989              )
   9990             ((string-match-p "[ ]+\\(do\\)" prev-line)
   9991              (setq offset (+ prev-indentation language-offset))
   9992              )
   9993             ((string-match-p "^[ ]*\\(when\\|if\\|else\\|elsif\\|unless\\|for\\|while\\|def\\|class\\)" prev-line)
   9994              (setq offset (+ prev-indentation language-offset))
   9995              )
   9996             (t
   9997              (setq offset prev-indentation)
   9998              )
   9999             )
  10000           ) ;when
  10001         ) ;if
  10002     offset))
  10003 
  10004 (defun web-mode-python-indentation (pos line initial-column language-offset limit)
  10005   (unless limit (setq limit nil))
  10006   (let (h offset prev-line prev-indentation ctx)
  10007     (setq ctx (web-mode-bracket-up pos "python" limit))
  10008     ;;(message "point-ctx=%S" ctx)
  10009     (if (plist-get ctx :pos)
  10010         (cond
  10011           ((web-mode-looking-at-p ".[ \t\n]+" (plist-get ctx :pos))
  10012            (setq offset (+ (plist-get ctx :indentation) language-offset)))
  10013           (t
  10014            (setq offset (1+ (plist-get ctx :column))))
  10015           )
  10016         ;; else
  10017         (setq h (web-mode-previous-line pos limit))
  10018         (setq offset initial-column)
  10019         (when h
  10020           (setq prev-line (car h))
  10021           (setq prev-indentation (cdr h))
  10022           (cond
  10023             ((string-match-p "^\\(pass\\|else\\|elif\\|when\\|except\\)" line)
  10024              (setq offset (- prev-indentation language-offset))
  10025              )
  10026             ((string-match-p "\\(if\\|else\\|elif\\|for\\|while\\|try\\|except\\)" prev-line)
  10027              (setq offset (+ prev-indentation language-offset))
  10028              )
  10029             (t
  10030              (setq offset prev-indentation)
  10031              )
  10032             ) ;cond
  10033           ) ;when
  10034         ) ;if
  10035     ;;offset
  10036     (if (< offset initial-column) initial-column offset)
  10037     ))
  10038 
  10039 (defun web-mode-lisp-indentation (pos point-ctx)
  10040   (let (offset open-ctx)
  10041     (setq open-ctx (web-mode-bracket-up pos "lsp" (plist-get point-ctx :reg-beg)))
  10042     ;;(message "point-ctx=%S" point-ctx)
  10043     ;;(message "open-ctx=%S" open-ctx)
  10044     (cond
  10045       ((null (plist-get open-ctx :pos))
  10046        (setq offset (plist-get point-ctx :reg-col)))
  10047       ((member (plist-get point-ctx :curr-char) '(?\( ?\)))
  10048        (if (web-mode-looking-at-p "((" (plist-get open-ctx :pos))
  10049            (setq offset (+ (plist-get open-ctx :column) 1))
  10050            (setq offset (+ (plist-get open-ctx :column) web-mode-code-indent-offset)))
  10051        )
  10052       (t
  10053        (goto-char (plist-get open-ctx :pos))
  10054        (forward-char)
  10055        (web-mode-rsf "[[:alnum:]-:]+ ")
  10056        (setq offset (current-column))
  10057        )
  10058       ) ;cond
  10059     offset))
  10060 
  10061 (defun web-mode-asp-indentation (pos line initial-column language-offset limit)
  10062   (unless limit (setq limit nil))
  10063   (let (h out prev-line prev-indentation)
  10064     (setq h (web-mode-previous-line pos limit))
  10065     (setq out initial-column)
  10066     (when h
  10067       (setq prev-line (car h))
  10068       (setq prev-indentation (cdr h))
  10069       ;;(message "line=%S" line)
  10070       (cond
  10071         ((string-match-p "'" line)
  10072          (setq out prev-indentation))
  10073         ;; ----------------------------------------------------------------------
  10074         ;; unindent
  10075         ((string-match-p "\\_<\\(\\(end \\(if\\|function\\|class\\|sub\\|with\\)\\)\\|else\\|elseif\\|next\\|loop\\)\\_>" line)
  10076          (setq out (- prev-indentation language-offset)))
  10077         ;; ----------------------------------------------------------------------
  10078         ;; select case statement
  10079         ((string-match-p "\\_<\\(select case\\)\\_>" line)
  10080          (setq out (- prev-indentation 0)))
  10081         ((string-match-p "\\_<\\(end select\\)" line)
  10082          (setq out (- prev-indentation (* 2 language-offset))))
  10083         ((and (string-match-p "\\_<\\(case\\)\\_>" line) (not (string-match-p "\\_<\\(select case\\)\\_>" prev-line)))
  10084          (setq out (- prev-indentation language-offset)))
  10085         ;; ----------------------------------------------------------------------
  10086         ;; do nothing
  10087         ((string-match-p "\\_<\\(\\(end \\(if\\|function\\|class\\|sub\\|select\\|with\\)\\)\\|loop\\( until\\| while\\)?\\)\\_>" prev-line)
  10088          (setq out (+ prev-indentation 0)))
  10089         ;; indent
  10090         ((string-match-p "\\_<\\(\\(select \\)?case\\|else\\|elseif\\|unless\\|for\\|class\\|with\\|do\\( until\\| while\\)?\\|while\\|\\(public \\|private \\)?\\(function\\|sub\\|class\\)\\)\\_>" prev-line)
  10091          (setq out (+ prev-indentation language-offset)))
  10092         ;; single line if statement
  10093         ((string-match-p "\\_<if\\_>.*\\_<then\\_>[ \t]*[[:alpha:]]+" prev-line)
  10094          (setq out (+ prev-indentation 0)))
  10095         ;; normal if statement
  10096         ((string-match-p "\\_<\\if\\_>" prev-line)
  10097          (setq out (+ prev-indentation language-offset)))
  10098         (t
  10099          (setq out prev-indentation))
  10100         )
  10101       ) ;when
  10102     out))
  10103 
  10104 (defun web-mode-block-previous-live-line ()
  10105   (save-excursion
  10106     (let ((continue t) (line "") (pos (point)))
  10107       (beginning-of-line)
  10108       (while (and continue (not (bobp)) (forward-line -1))
  10109         (when (not (web-mode-block-is-token-line))
  10110           (setq line (web-mode-trim (buffer-substring (point) (line-end-position)))))
  10111         (when (not (string= line ""))
  10112           (setq continue nil))
  10113         ) ;while
  10114       (if (string= line "")
  10115           (progn (goto-char pos) nil)
  10116           (list line (current-indentation) pos (line-end-position)))
  10117       )))
  10118 
  10119 (defun web-mode-part-is-opener (pos reg-beg)
  10120   (save-excursion
  10121     (save-match-data
  10122       (if (and pos
  10123                (web-mode-go (web-mode-part-opening-paren-position pos))
  10124                (>= (point) reg-beg)
  10125                (looking-back "\\(^\\|[ \t]\\)\\(if\\|for\\|while\\)[ ]*" (point-min)))
  10126           (current-indentation)
  10127           nil)
  10128       )))
  10129 
  10130 (defun web-mode-part-previous-live-line (reg-beg)
  10131   (unless reg-beg (setq reg-beg (point-min)))
  10132   ;;(message "reg-beg=%S" reg-beg)
  10133   (save-excursion
  10134     (let ((continue (> (point) reg-beg))
  10135           (line "")
  10136           bol-pos
  10137           eol-pos
  10138           pos)
  10139       (beginning-of-line)
  10140       (while (and continue (> (point) reg-beg) (forward-line -1))
  10141         (setq bol-pos (point)
  10142               eol-pos (line-end-position))
  10143         (when (> reg-beg bol-pos)
  10144           (setq bol-pos reg-beg))
  10145         (when (not (web-mode-part-is-token-line bol-pos))
  10146           (setq line (web-mode-trim (buffer-substring bol-pos eol-pos)))
  10147           (when (not (string= line "")) (setq continue nil))
  10148           ) ;when
  10149         ) ;while
  10150       (cond
  10151         ((string= line "")
  10152          nil)
  10153         (t
  10154          (setq continue t)
  10155          (setq pos (1- eol-pos))
  10156          (while (and (>= pos bol-pos) continue)
  10157            (cond
  10158              ((eq (char-after pos) ?\s)
  10159               (setq pos (1- pos)))
  10160              ((get-text-property pos 'part-token)
  10161               (setq pos (1- pos)))
  10162              (t
  10163               (setq continue nil))
  10164              ) ;cond
  10165            ) ;while
  10166          ;;(message "%S %S : %S" bol-pos eol-pos pos)
  10167          (setq line (web-mode-clean-part-line line))
  10168          (list line (current-indentation) pos (line-end-position)))
  10169         ) ;cond
  10170       )))
  10171 
  10172 (defun web-mode-in-code-block (open close &optional prop)
  10173   (save-excursion
  10174     (let ((pos (point)) pos-open pos-close start end ret)
  10175       (when prop
  10176         (setq start pos
  10177               end pos)
  10178         (when (eq (get-text-property pos prop) (get-text-property (1- pos) prop))
  10179           (setq start (or (previous-single-property-change pos prop) (point-min))))
  10180         (when (eq (get-text-property pos prop) (get-text-property (1+ pos) prop))
  10181           (setq end (next-single-property-change pos prop)))
  10182         ;;        (message "start(%S) end(%S)" start end)
  10183         )
  10184       (setq ret (and (web-mode-sb open start t)
  10185                      (setq pos-open (point))
  10186                      (web-mode-sf close end t)
  10187                      (setq pos-close (point))
  10188                      (>= pos-close pos)))
  10189       (if ret
  10190           (cons pos-open pos-close)
  10191           ret)
  10192       )))
  10193 
  10194 (defun web-mode-clean-part-line (input)
  10195   (let ((out "")
  10196         (beg 0)
  10197         (keep t)
  10198         (n (length input)))
  10199     (dotimes (i n)
  10200       (if (or (get-text-property i 'block-side input)
  10201               (eq (get-text-property i 'part-token input) 'comment)
  10202               (eq (get-text-property i 'tag-type input) 'comment))
  10203           (when keep
  10204             (setq out (concat out (substring input beg i))
  10205                   beg 0
  10206                   keep nil))
  10207           (when (null keep)
  10208             (setq beg i
  10209                   keep t))
  10210           ) ;if
  10211       ) ;dotimes
  10212     (if (> beg 0) (setq out (concat out (substring input beg n))))
  10213     (setq out (if (= (length out) 0) input out))
  10214     (web-mode-trim out)
  10215     ))
  10216 
  10217 (defun web-mode-clean-block-line (input)
  10218   (let ((out "")
  10219         (beg 0)
  10220         (keep t)
  10221         (n (length input)))
  10222     (dotimes (i n)
  10223       (if (or (not (get-text-property i 'block-side input))
  10224               (member (get-text-property i 'block-token input)
  10225                       '(comment delimiter-beg delimiter-end)))
  10226           (when keep
  10227             (setq out (concat out (substring input beg i))
  10228                   beg 0
  10229                   keep nil))
  10230           (when (null keep)
  10231             (setq beg i
  10232                   keep t))
  10233           ) ;if
  10234       ) ;dotimes
  10235     (if (> beg 0) (setq out (concat out (substring input beg n))))
  10236     (setq out (if (= (length out) 0) input out))
  10237     (web-mode-trim out)
  10238     ;;    (message "%S [%s] > [%s]" beg input out)
  10239     ))
  10240 
  10241 (defun web-mode-language-at-pos (&optional pos)
  10242   (unless pos (setq pos (point)))
  10243   (cond
  10244     ((get-text-property pos 'block-side)
  10245      web-mode-engine)
  10246     ((get-text-property pos 'part-side)
  10247      (symbol-name (get-text-property pos 'part-side)))
  10248     (t
  10249      web-mode-content-type)
  10250     ) ;cond
  10251   )
  10252 
  10253 (defun web-mode-coord-position (line column)
  10254   (save-excursion
  10255     (when (stringp line) (setq line (string-to-number line)))
  10256     (when (stringp column) (setq column (string-to-number column)))
  10257     (goto-char (point-min))
  10258     (forward-line (1- line))
  10259     (move-to-column (1- column))
  10260     (point)))
  10261 
  10262 (defun web-mode-is-single-line-block (pos)
  10263   (= (web-mode-line-number (web-mode-block-beginning-position pos))
  10264      (web-mode-line-number (web-mode-block-end-position pos))))
  10265 
  10266 (defun web-mode-line-number (&optional pos)
  10267   (setq pos (or pos (point)))
  10268   (+ (count-lines 1 pos) (if (= (web-mode-column-at-pos pos) 0) 1 0)))
  10269 
  10270 (defun web-mode-block-is-control (pos)
  10271   (save-excursion
  10272     (let (control state controls pair)
  10273       (goto-char pos)
  10274       (setq controls (web-mode-block-controls-get pos))
  10275       (setq pair (car controls))
  10276       (cond
  10277         ((eq (car pair) 'inside)
  10278          )
  10279         ((eq (car pair) 'open)
  10280          (setq state t
  10281                control (cdr pair)))
  10282         ((eq (car pair) 'close)
  10283          (setq state nil
  10284                control (cdr pair)))
  10285         ) ;cond
  10286       ;;      (message "engine=%S control=%S state=%S" web-mode-engine control state)
  10287       (if control (cons control state) nil)
  10288       )))
  10289 
  10290 (defun web-mode-block-is-opening-control (pos)
  10291   (save-excursion
  10292     (let (controls pair)
  10293       (goto-char pos)
  10294       (if (and (setq controls (web-mode-block-controls-get pos))
  10295                (= (length controls) 1)
  10296                (setq pair (car controls))
  10297                (eq (car pair) 'open))
  10298           (cdr pair)
  10299           nil)
  10300       )))
  10301 
  10302 (defun web-mode-markup-indentation-origin (pos jsx-depth)
  10303   (save-excursion
  10304     (let* ((found (bobp))
  10305            (jsx-beg nil)
  10306            (types '(start end void))
  10307            (type nil))
  10308       (when jsx-depth
  10309         (setq jsx-beg (web-mode-jsx-depth-beginning-position pos jsx-depth)))
  10310       (while (not found)
  10311         (forward-line -1)
  10312         (if (bobp)
  10313             (setq pos (point)
  10314                   found t)
  10315             (back-to-indentation)
  10316             (when (and jsx-beg (< (point) jsx-beg))
  10317               (goto-char jsx-beg))
  10318             (setq pos (point))
  10319             (setq type (get-text-property pos 'tag-type))
  10320             (setq found (or (and (null jsx-depth)
  10321                                  (null (get-text-property pos 'part-side))
  10322                                  (get-text-property pos 'tag-beg)
  10323                                  (member type types)
  10324                                  (null (get-text-property (1- pos) 'invisible)))
  10325                             (and (null jsx-depth)
  10326                                  (null (get-text-property pos 'part-side))
  10327                                  (eq (get-text-property pos 'tag-type) 'comment)
  10328                                  (web-mode-looking-at-p "<!--#\\(endif\\|if\\)" pos)
  10329                                  (null (get-text-property (1- pos) 'invisible)))
  10330                             (and jsx-depth
  10331                                  (get-text-property pos 'tag-beg)
  10332                                  (member type types)
  10333                                  (null (get-text-property (1- pos) 'invisible))
  10334                                  (eq (get-text-property pos 'jsx-depth) jsx-depth))
  10335                             (and (get-text-property pos 'block-beg)
  10336                                  (not type)
  10337                                  (web-mode-block-is-control pos)
  10338                                  (not (looking-at-p "{% commen\\|@break")))))
  10339             ) ;if
  10340         ) ;while
  10341       ;;(message "indent-origin=%S" pos)
  10342       pos)))
  10343 
  10344 ;;TODO : prendre en compte part-token
  10345 ;; state=t <=> start tag
  10346 (defun web-mode-element-is-opened (pos limit)
  10347   (let (tag
  10348         last-end-tag
  10349         tag-pos block-pos
  10350         state
  10351         n
  10352         ret
  10353         (continue t)
  10354         controls
  10355         (h (make-hash-table :test 'equal))
  10356         (h2 (make-hash-table :test 'equal)))
  10357 
  10358     ;;    (message "pos-ori=%S limit=%S" pos limit)
  10359 
  10360     (while continue
  10361       (setq controls nil
  10362             last-end-tag nil
  10363             tag nil)
  10364 
  10365       (cond
  10366         ((and (eq (get-text-property pos 'tag-type) 'comment)
  10367               (web-mode-looking-at "<!--#\\(endif\\|if\\)" pos))
  10368          ;;(message "pos=%S" pos)
  10369          (setq tag "#if")
  10370          (setq n (gethash tag h 0))
  10371          (if (string= (match-string-no-properties 1) "if")
  10372              (puthash tag (1+ n) h)
  10373              (puthash tag (1- n) h))
  10374          ;;(setq tag-pos pos)
  10375          )
  10376         ((get-text-property pos 'tag-beg)
  10377          (when (member (get-text-property pos 'tag-type) '(start end))
  10378            (setq tag (get-text-property pos 'tag-name)
  10379                  state (eq (get-text-property pos 'tag-type) 'start))
  10380            (if (null state) (setq last-end-tag (cons tag pos)))
  10381            (setq n (gethash tag h 0))
  10382            (cond
  10383              ((null state)
  10384               (when (> n 0) (puthash tag (1- n) h))
  10385               (puthash tag (1- n) h2))
  10386              ((member tag web-mode-offsetless-elements)
  10387               )
  10388              (t
  10389               (puthash tag (1+ n) h)
  10390               (puthash tag (1+ n) h2))
  10391              ) ;cond
  10392            ) ;when
  10393          (when (setq pos (web-mode-tag-end-position pos))
  10394            (setq tag-pos nil)
  10395            (when (and block-pos (> pos block-pos))
  10396              (setq block-pos nil))
  10397            ) ;when
  10398          )
  10399         ((and web-mode-enable-control-block-indentation
  10400               (get-text-property pos 'block-beg))
  10401          (when (setq controls (web-mode-block-controls-get pos))
  10402            (dolist (control controls)
  10403              (setq tag (cdr control))
  10404              (setq n (gethash tag h 0))
  10405              (cond
  10406                ((eq (car control) 'inside)
  10407                 )
  10408                ((eq (car control) 'open)
  10409                 (puthash tag (1+ n) h))
  10410                ((> n 0)
  10411                 (puthash tag (1- n) h))
  10412                ) ;cond
  10413              ) ;dolist
  10414            )
  10415          (when (setq pos (web-mode-block-end-position pos))
  10416            (setq block-pos nil)
  10417            (when (and tag-pos (> pos tag-pos))
  10418              (setq tag-pos nil))
  10419            )
  10420          )
  10421         ) ;cond
  10422 
  10423       ;;      (message "tag=%S end-pos=%S" tag pos)
  10424 
  10425       (when (and pos (< pos limit))
  10426         (when (or (null tag-pos) (>= pos tag-pos))
  10427           (setq tag-pos (web-mode-tag-next-position pos limit))
  10428           ;;          (message "from=%S tag-next-pos=%S" pos tag-pos)
  10429           )
  10430         (when (or (null block-pos) (>= pos block-pos))
  10431           (setq block-pos (web-mode-block-next-position pos limit))
  10432           ;;          (message "from=%S block-next-pos=%S" pos block-pos)
  10433           )
  10434         )
  10435 
  10436       (cond
  10437         ((null pos)
  10438          )
  10439         ((and (null tag-pos)
  10440               (null block-pos))
  10441          (setq pos nil))
  10442         ((and tag-pos block-pos)
  10443          (if (< tag-pos block-pos)
  10444              (progn
  10445                (setq pos tag-pos)
  10446                (setq tag-pos nil))
  10447              (setq pos block-pos)
  10448              (setq block-pos nil))
  10449          )
  10450         ((null tag-pos)
  10451          (setq pos block-pos)
  10452          (setq block-pos nil))
  10453         (t
  10454          (setq pos tag-pos)
  10455          (setq tag-pos nil))
  10456         )
  10457 
  10458       (when (or (null pos)
  10459                 (>= pos limit))
  10460         (setq continue nil))
  10461       ) ;while
  10462 
  10463     ;;(message "hashtable=%S" h)
  10464     (maphash (lambda (_k v) (if (> v 0) (setq ret t))) h)
  10465 
  10466     (when (and (null ret)
  10467                last-end-tag
  10468                (> (hash-table-count h2) 1)
  10469                (< (gethash (car last-end-tag) h2) 0))
  10470       ;;      (message "last-end-tag=%S" last-end-tag)
  10471       (save-excursion
  10472         (goto-char (cdr last-end-tag))
  10473         (web-mode-tag-match)
  10474         (when (not (= (point) (cdr last-end-tag)))
  10475           (setq n (point))
  10476           (back-to-indentation)
  10477           (if (= n (point)) (setq ret (current-indentation))))
  10478         ))
  10479 
  10480     ret))
  10481 
  10482 (defun web-mode-previous-line (pos limit)
  10483   (save-excursion
  10484     (let (beg end line (continue t))
  10485       (goto-char pos)
  10486       (while continue
  10487         (forward-line -1)
  10488         (setq end (line-end-position))
  10489         (setq line (buffer-substring-no-properties (point) end))
  10490         (when (or (not (string-match-p "^[ \t]*$" line))
  10491                   (bobp)
  10492                   (<= (point) limit))
  10493           (setq continue nil))
  10494         )
  10495       (if (<= (point) limit)
  10496           ;;todo : affiner (le + 3 n est pas générique cf. <?php <% <%- etc.)
  10497           (setq beg (if (< (+ limit 3) end) (+ limit 3) end))
  10498           (setq beg (line-beginning-position))
  10499           ) ;if
  10500       (setq line (buffer-substring-no-properties beg end))
  10501       (cons line (current-indentation))
  10502       )))
  10503 
  10504 (defun web-mode-bracket-up (pos _language &optional limit)
  10505   (unless limit (setq limit nil))
  10506   ;;(message "pos(%S) language(%S) limit(%S)" pos language limit)
  10507   (save-excursion
  10508     (goto-char pos)
  10509     (let ((continue t)
  10510           (regexp "[\]\[}{)(]")
  10511           (char nil)
  10512           (column nil)
  10513           (indentation nil)
  10514           (map nil)
  10515           (key nil)
  10516           (value 0)
  10517           (open '(?\( ?\{ ?\[))
  10518           (searcher nil)
  10519           (opener nil))
  10520       (cond
  10521         ((get-text-property pos 'block-side)
  10522          (setq searcher 'web-mode-block-rsb
  10523                opener 'web-mode-block-opening-paren-position))
  10524         (t
  10525          (setq searcher 'web-mode-part-rsb
  10526                opener 'web-mode-part-opening-paren-position))
  10527         )
  10528       (while (and continue (funcall searcher regexp limit))
  10529         (setq char (aref (match-string-no-properties 0) 0))
  10530         (setq key (cond ((eq char ?\)) ?\()
  10531                         ((eq char ?\}) ?\{)
  10532                         ((eq char ?\]) ?\[)
  10533                         (t             char)))
  10534         (setq value (or (plist-get map key) 0))
  10535         (setq value (if (member char open) (1+ value) (1- value)))
  10536         (setq map (plist-put map key value))
  10537         (setq continue (< value 1))
  10538         ;;(message "pos=%S char=%c key=%c value=%S map=%S" (point) char key value map)
  10539         ) ;while
  10540       (setq column (current-column)
  10541             indentation (current-indentation))
  10542       (when (and (> value 0)
  10543                  (eq char ?\{)
  10544                  (looking-back ")[ ]*" (point-min)))
  10545         (search-backward ")")
  10546         (when (setq pos (funcall opener (point) limit))
  10547           (goto-char pos)
  10548           ;;(message "pos=%S" pos)
  10549           (setq indentation (current-indentation)))
  10550         ) ;when
  10551       (list :pos (if (> value 0) (point) nil)
  10552             :char char
  10553             :column column
  10554             :indentation indentation)
  10555       ) ;let
  10556     ))
  10557 
  10558 (defun web-mode-count-char-in-string (char string)
  10559   (let ((n 0))
  10560     (dotimes (i (length string))
  10561       (if (eq (elt string i) char)
  10562           (setq n (1+ n))))
  10563     n))
  10564 
  10565 (defun web-mode-mark-and-expand ()
  10566   "Mark and expand."
  10567   (interactive)
  10568   (web-mode-mark (point)))
  10569 
  10570 (defun web-mode-mark (pos)
  10571   (let ((beg pos) (end pos) boundaries)
  10572 
  10573     (if mark-active
  10574         (setq web-mode-expand-initial-pos (point)
  10575               web-mode-expand-initial-scroll (window-start))
  10576         )
  10577 
  10578     ;; (message "regs=%S %S %S %S" (region-beginning) (region-end) (point-min) (point-max))
  10579     ;; (message "before=%S" web-mode-expand-previous-state)
  10580 
  10581     (cond
  10582 
  10583       ((and mark-active
  10584             (= (region-beginning) (point-min))
  10585             (or (= (region-end) (point-max))
  10586                 (= (1+ (region-end)) (point-max))))
  10587        (deactivate-mark)
  10588        (goto-char (or web-mode-expand-initial-pos (point-min)))
  10589        (setq web-mode-expand-previous-state nil)
  10590        (when web-mode-expand-initial-scroll
  10591          (set-window-start (selected-window) web-mode-expand-initial-scroll))
  10592        )
  10593 
  10594       ((string= web-mode-expand-previous-state "elt-content")
  10595        (web-mode-element-parent)
  10596        ;;(message "pos=%S" (point))
  10597        (web-mode-element-select)
  10598        (setq web-mode-expand-previous-state "html-parent"))
  10599 
  10600       ((and (member (get-text-property pos 'block-token) '(comment string))
  10601             (not (member web-mode-expand-previous-state '("block-token" "block-body" "block-side"))))
  10602        (when (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token))
  10603          (setq beg (or (previous-single-property-change pos 'block-token) (point-min))))
  10604        (when (eq (get-text-property pos 'block-token) (get-text-property (1+ pos) 'block-token))
  10605          (setq end (next-single-property-change pos 'block-token)))
  10606        (set-mark beg)
  10607        (goto-char end)
  10608        (exchange-point-and-mark)
  10609        (setq web-mode-expand-previous-state "block-token"))
  10610 
  10611       ((and (get-text-property pos 'block-side)
  10612             (not (member web-mode-expand-previous-state '("block-body" "block-side")))
  10613             (not (member web-mode-engine '(django go)))
  10614             (setq boundaries (web-mode-in-code-block "{" "}" 'block-side)))
  10615        (set-mark (car boundaries))
  10616        (goto-char (cdr boundaries))
  10617        (exchange-point-and-mark)
  10618        (setq web-mode-expand-previous-state "block-body"))
  10619 
  10620       ((and (get-text-property pos 'block-side)
  10621             (not (member web-mode-expand-previous-state '("block-side"))))
  10622        (set-mark (web-mode-block-beginning-position pos))
  10623        (goto-char (1+ (web-mode-block-end-position pos)))
  10624        (exchange-point-and-mark)
  10625        (setq web-mode-expand-previous-state "block-side"))
  10626 
  10627       ((and (get-text-property pos 'part-token)
  10628             (not (string= web-mode-expand-previous-state "part-token")))
  10629        (when (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token))
  10630          (setq beg (previous-single-property-change pos 'part-token)))
  10631        (when (eq (get-text-property pos 'part-token) (get-text-property (1+ pos) 'part-token))
  10632          (setq end (next-single-property-change pos 'part-token)))
  10633        (set-mark beg)
  10634        (goto-char end)
  10635        (exchange-point-and-mark)
  10636        (setq web-mode-expand-previous-state "part-token"))
  10637 
  10638       ((and (get-text-property pos 'part-side)
  10639             (not (string= web-mode-expand-previous-state "client-part"))
  10640             (setq boundaries (web-mode-in-code-block "{" "}" 'part-side)))
  10641        (set-mark (car boundaries))
  10642        (goto-char (cdr boundaries))
  10643        (exchange-point-and-mark)
  10644        (setq web-mode-expand-previous-state "client-part"))
  10645 
  10646       ((and (get-text-property pos 'part-side)
  10647             (not (string= web-mode-expand-previous-state "part-side")))
  10648        (when (eq (get-text-property pos 'part-side) (get-text-property (1- pos) 'part-side))
  10649          (setq beg (previous-single-property-change pos 'part-side)))
  10650        (when (eq (get-text-property pos 'part-side) (get-text-property (1+ pos) 'part-side))
  10651          (setq end (next-single-property-change pos 'part-side)))
  10652        (when (eq (char-after beg) ?\n)
  10653          (setq beg (1+ beg)))
  10654        (set-mark beg)
  10655        (goto-char end)
  10656        (when (looking-back "^[ \t]+" (point-min))
  10657          (beginning-of-line))
  10658        (exchange-point-and-mark)
  10659        (setq web-mode-expand-previous-state "part-side"))
  10660 
  10661       ((and (get-text-property pos 'tag-attr)
  10662             (not (member web-mode-expand-previous-state '("html-attr" "html-tag"))))
  10663        (web-mode-attribute-select pos)
  10664        (setq web-mode-expand-previous-state "html-attr"))
  10665 
  10666       ((and (eq (get-text-property pos 'tag-type) 'comment)
  10667             (not (member web-mode-expand-previous-state '("html-tag" "html-comment" "html-elt" "html-parent"))))
  10668        (web-mode-tag-select)
  10669        (setq web-mode-expand-previous-state "html-comment"))
  10670 
  10671       ((and (get-text-property pos 'tag-name)
  10672             (not (member web-mode-expand-previous-state '("html-tag" "html-elt" "html-parent"))))
  10673        (web-mode-tag-select)
  10674        (setq web-mode-expand-previous-state "html-tag"))
  10675 
  10676       ((and (get-text-property pos 'tag-beg)
  10677             (string= web-mode-expand-previous-state "html-tag"))
  10678        (web-mode-element-select)
  10679        (setq web-mode-expand-previous-state "html-elt"))
  10680 
  10681       (t
  10682        (cond
  10683          ((not (web-mode-element-parent))
  10684           (push-mark (point))
  10685           (push-mark (point-max) nil t)
  10686           (goto-char (point-min))
  10687           (setq web-mode-expand-previous-state "mark-whole"))
  10688          ((not (= (web-mode-tag-end-position (point)) (1- beg)))
  10689           (web-mode-element-content-select)
  10690           (setq web-mode-expand-previous-state "elt-content"))
  10691          (t
  10692           (web-mode-element-select)
  10693           (setq web-mode-expand-previous-state "html-parent"))
  10694          )
  10695        ) ;t
  10696 
  10697       ) ;cond
  10698 
  10699     ;;(message "w=%S" (window-end))
  10700     ;;(message "after=%S" web-mode-expand-previous-state)
  10701 
  10702     ))
  10703 
  10704 (defun web-mode-block-kill ()
  10705   "Kill the current block."
  10706   (interactive)
  10707   (web-mode-block-select)
  10708   (when mark-active
  10709     (kill-region (region-beginning) (region-end))))
  10710 
  10711 (defun web-mode-block-select ()
  10712   "Select the current block."
  10713   (interactive)
  10714   (let (beg)
  10715     (when (setq beg (web-mode-block-beginning-position (point)))
  10716       (goto-char beg)
  10717       (set-mark (point))
  10718       (web-mode-block-end)
  10719       (exchange-point-and-mark))
  10720     beg))
  10721 
  10722 (defun web-mode-tag-select ()
  10723   "Select the current html tag."
  10724   (interactive)
  10725   (let (beg)
  10726     (when (setq beg (web-mode-tag-beginning-position (point)))
  10727       (goto-char beg)
  10728       (set-mark (point))
  10729       (web-mode-tag-end)
  10730       (exchange-point-and-mark))
  10731     beg))
  10732 
  10733 (defun web-mode-element-content-select ()
  10734   "Select the content of a html element."
  10735   (interactive)
  10736   (let (pos end)
  10737     (web-mode-element-select)
  10738     (when mark-active
  10739       (setq pos (point))
  10740       (deactivate-mark)
  10741       (web-mode-tag-match)
  10742       (setq end (point))
  10743       (goto-char pos)
  10744       (web-mode-tag-end)
  10745       (set-mark (point))
  10746       (goto-char end)
  10747       (exchange-point-and-mark)
  10748       )))
  10749 
  10750 (defun web-mode-element-select ()
  10751   "Select the current html element (including opening and closing tags)."
  10752   (interactive)
  10753   (let* ((pos (point))
  10754          (type (get-text-property pos 'tag-type)))
  10755     (cond
  10756       ((not type)
  10757        (web-mode-element-parent)
  10758        (unless (= (point) pos) (web-mode-element-select)))
  10759       ((member type '(start void))
  10760        (web-mode-tag-beginning)
  10761        (set-mark (point))
  10762        (web-mode-tag-match)
  10763        (web-mode-tag-end)
  10764        (exchange-point-and-mark))
  10765       (t
  10766        (web-mode-tag-match)
  10767        (set-mark (point))
  10768        (web-mode-tag-match)
  10769        (web-mode-tag-end)
  10770        (exchange-point-and-mark))
  10771       )))
  10772 
  10773 (defun web-mode-element-is-collapsed (&optional pos)
  10774   (unless pos (setq pos (point)))
  10775   (let (boundaries)
  10776     (and (setq boundaries (web-mode-element-boundaries pos))
  10777          (or (= (car (car boundaries)) (car (cdr boundaries)))
  10778              (= (cdr (car boundaries)) (1- (car (cdr boundaries)))))
  10779          )))
  10780 
  10781 (defun web-mode-element-contract ()
  10782   "Flatten elements."
  10783   (interactive)
  10784   (let (beg end (continue t) replacement boundaries)
  10785     (cond
  10786       ((or (not (get-text-property (point) 'tag-type))
  10787            (not (member (get-text-property (point) 'tag-type) '(start end))))
  10788        (web-mode-element-parent))
  10789       ((eq (get-text-property (point) 'tag-type) 'end)
  10790        (web-mode-tag-match))
  10791       ) ;cond
  10792     (setq boundaries (web-mode-element-boundaries (point)))
  10793     (setq beg (car (car boundaries))
  10794           end (cdr (cdr boundaries)))
  10795     (goto-char beg)
  10796     ;;(message "beg(%S) end(%S)" beg end)
  10797     (while continue
  10798       (if (or (not (re-search-forward ">[ \t\r\n]+\\|[ \t\r\n]+<"))
  10799               (>= (point) end))
  10800           (setq continue nil)
  10801           (setq end (+ (- end (length (match-string-no-properties 0))) 1))
  10802           (setq replacement (if (eq (char-before) ?\<) "<" ">"))
  10803           (replace-match replacement nil nil)
  10804           ;;(message "end(%S)" end))
  10805           )
  10806       ) ;while
  10807     (goto-char beg)
  10808     ))
  10809 
  10810 (defun web-mode-element-extract ()
  10811   "Flatten element."
  10812   (interactive)
  10813   (let (beg end (continue t) save boundaries)
  10814     (cond
  10815       ((or (not (get-text-property (point) 'tag-type))
  10816            (not (member (get-text-property (point) 'tag-type) '(start end))))
  10817        (web-mode-element-parent))
  10818       ((eq (get-text-property (point) 'tag-type) 'end)
  10819        (web-mode-tag-match))
  10820       ) ;cond
  10821     (setq boundaries (web-mode-element-boundaries (point)))
  10822     (setq beg (car (car boundaries))
  10823           end (cdr (cdr boundaries)))
  10824     (goto-char beg)
  10825     (while continue
  10826       (if (or (not (and (or (get-text-property (point) 'tag-type) (web-mode-tag-next))
  10827                         (web-mode-tag-end)))
  10828               (>= (point) end))
  10829           (setq continue nil)
  10830           (setq save (point))
  10831           ;;(message "point(%S)" (point))
  10832           (skip-chars-forward "\n\t ")
  10833           (when (get-text-property (point) 'tag-type)
  10834             (newline)
  10835             (indent-according-to-mode)
  10836             (setq end (+ end (- (point) save))))
  10837           ) ;if
  10838       ) ;while
  10839     (goto-char beg)
  10840     ))
  10841 
  10842 (defun web-mode-element-transpose ()
  10843   "Transpose two html elements."
  10844   (interactive)
  10845   (let (pos start1 end1 start2 end2)
  10846     (save-excursion
  10847       (setq pos (point))
  10848       (cond
  10849         ((get-text-property pos 'tag-type)
  10850          (setq start1 (web-mode-element-beginning-position pos)
  10851                end1 (1+ (web-mode-element-end-position pos)))
  10852          )
  10853         ((setq start1 (web-mode-element-parent-position pos))
  10854          (setq end1 (1+ (web-mode-element-end-position pos)))
  10855          )
  10856         ) ;cond
  10857       (when (and start1 end1 (> end1 0))
  10858         (goto-char end1)
  10859         (unless (get-text-property (point) 'tag-beg)
  10860           (skip-chars-forward "\n\t "))
  10861         (when (get-text-property (point) 'tag-beg)
  10862           (setq start2 (web-mode-element-beginning-position (point))
  10863                 end2 (1+ (web-mode-element-end-position (point))))
  10864           )
  10865         )
  10866       (transpose-regions start1 end1 start2 end2)
  10867       ) ;save-excursion
  10868     start2))
  10869 
  10870 (defun web-mode-element-children-comment (&optional pos)
  10871   "Comment all the children of the current html element."
  10872   (interactive)
  10873   (unless pos (setq pos (point)))
  10874   (save-excursion
  10875     (dolist (child (reverse (web-mode-element-children pos)))
  10876       (goto-char child)
  10877       (web-mode-comment (point)))
  10878     ))
  10879 
  10880 (defun web-mode-element-mute-blanks ()
  10881   "Mute blanks."
  10882   (interactive)
  10883   (let (pos parent children elt)
  10884     (setq pos (point))
  10885     (save-excursion
  10886       (when (and (setq parent (web-mode-element-boundaries pos))
  10887                  (web-mode-element-child-position (point)))
  10888         (setq children (reverse (web-mode-element-children)))
  10889         (goto-char (car (cdr parent)))
  10890         (dolist (child children)
  10891           (setq elt (web-mode-element-boundaries child))
  10892           (when (> (point) (1+ (cddr elt)))
  10893             (when (and (not (eq (get-text-property (point) 'part-token) 'comment))
  10894                        (not (eq (get-text-property (1+ (cddr elt)) 'part-token) 'comment)))
  10895               (web-mode-insert-text-at-pos "-->" (point))
  10896               (web-mode-insert-text-at-pos "<!--" (1+ (cddr elt))))
  10897             )
  10898           (goto-char child)
  10899           )
  10900         (when (and (> (point) (1+ (cdr (car parent))))
  10901                    (not (eq (get-text-property (point) 'part-token) 'comment))
  10902                    (not (eq (get-text-property (1+ (cdr (car parent))) 'part-token) 'comment)))
  10903           (web-mode-insert-text-at-pos "-->" (point))
  10904           (web-mode-insert-text-at-pos "<!--" (1+ (cdr (car parent)))))
  10905         ) ;when
  10906       )))
  10907 
  10908 (defun web-mode-element-children (&optional pos)
  10909   (unless pos (setq pos (point)))
  10910   (let ((continue t) (i 0) child children)
  10911     (save-excursion
  10912       (when (and (member (get-text-property pos 'tag-type) '(start end))
  10913                  (setq child (web-mode-element-child-position pos)))
  10914         (while continue
  10915           (cond
  10916             ((> (setq i (1+ i)) 100)
  10917              (setq continue nil)
  10918              (message "element-children ** warning **"))
  10919             ((= i 1)
  10920              (goto-char child))
  10921             ((web-mode-element-sibling-next)
  10922              )
  10923             (t
  10924              (setq continue nil))
  10925             ) ;cond
  10926           (when continue
  10927             (setq children (append children (list (point)))))
  10928           ) ;while
  10929         ) ;when
  10930       ) ;save-excursion
  10931     ;;(message "%S" children)
  10932     children))
  10933 
  10934 (defun web-mode-property-boundaries (prop &optional pos)
  10935   "property boundaries (cdr is 1+)"
  10936   (unless pos (setq pos (point)))
  10937   (let (beg end val)
  10938     (setq val (get-text-property pos prop))
  10939     (if (null val)
  10940         val
  10941         (if (or (bobp)
  10942                 (not (eq (get-text-property (1- pos) prop) val)))
  10943             (setq beg pos)
  10944             (setq beg (previous-single-property-change pos prop))
  10945             (when (null beg) (setq beg (point-min))))
  10946         (if (or (eobp)
  10947                 (not (eq (get-text-property (1+ pos) prop) val)))
  10948             (setq end pos)
  10949             (setq end (next-single-property-change pos prop))
  10950             (when (null end) (setq end (point-min))))
  10951         (cons beg end))))
  10952 
  10953 (defun web-mode-content-boundaries (&optional pos)
  10954   (unless pos (setq pos (point)))
  10955   (let (beg end)
  10956     (setq beg (or (previous-property-change pos (current-buffer))
  10957                   (point-max)))
  10958     (setq end (or (next-property-change pos (current-buffer))
  10959                   (point-min)))
  10960     (while (and (< beg end) (member (char-after beg) '(?\s ?\n)))
  10961       (setq beg (1+ beg)))
  10962     (while (and (> end beg) (member (char-after (1- end)) '(?\s ?\n)))
  10963       (setq end (1- end)))
  10964     ;;    (message "beg(%S) end(%S)" beg end)
  10965     (cons beg end)
  10966     ))
  10967 
  10968 (defun web-mode-element-boundaries (&optional pos)
  10969   "Return ((start-tag-beg . start-tag-end) . (end-tag-beg . end-tag-end))
  10970 First level car and cdr are the same with void elements.
  10971 Pos should be in a tag."
  10972   (unless pos (setq pos (point)))
  10973   (let (start-tag-beg start-tag-end end-tag-beg end-tag-end)
  10974     (cond
  10975       ((eq (get-text-property pos 'tag-type) 'start)
  10976        (setq start-tag-beg (web-mode-tag-beginning-position pos)
  10977              start-tag-end (web-mode-tag-end-position pos))
  10978        (when (setq pos (web-mode-tag-match-position pos))
  10979          (setq end-tag-beg pos
  10980                end-tag-end (web-mode-tag-end-position pos)))
  10981        )
  10982       ((eq (get-text-property pos 'tag-type) 'end)
  10983        (setq end-tag-beg (web-mode-tag-beginning-position pos)
  10984              end-tag-end (web-mode-tag-end-position pos))
  10985        (when (setq pos (web-mode-tag-match-position pos))
  10986          (setq start-tag-beg pos
  10987                start-tag-end (web-mode-tag-end-position pos)))
  10988        )
  10989       ((eq (get-text-property pos 'tag-type) 'void)
  10990        (setq start-tag-beg (web-mode-tag-beginning-position pos)
  10991              start-tag-end (web-mode-tag-end-position pos))
  10992        (setq end-tag-beg start-tag-beg
  10993              end-tag-end start-tag-end)
  10994        )
  10995       ) ;cond
  10996     (if (and start-tag-beg start-tag-end end-tag-beg end-tag-end)
  10997         (cons (cons start-tag-beg start-tag-end) (cons end-tag-beg end-tag-end))
  10998         nil)
  10999     ))
  11000 
  11001 (defun web-mode-surround ()
  11002   "Surround each line of the current REGION with a start/end tag."
  11003   (interactive)
  11004   (when mark-active
  11005     (let (beg end line-beg line-end tag tag-start tag-end)
  11006       (save-excursion
  11007         (combine-after-change-calls
  11008           (setq tag (web-mode-element-complete)
  11009                 tag-start (concat "<" tag ">")
  11010                 tag-end (concat "</" tag ">")
  11011                 beg (region-beginning)
  11012                 end (region-end)
  11013                 line-beg (web-mode-line-number beg)
  11014                 line-end (web-mode-line-number end))
  11015           (goto-char end)
  11016           (unless (bolp)
  11017             (insert tag-end)
  11018             (back-to-indentation)
  11019             (when (> beg (point))
  11020               (goto-char beg))
  11021             (insert tag-start))
  11022           (while (> line-end line-beg)
  11023             (forward-line -1)
  11024             (setq line-end (1- line-end))
  11025             (unless (looking-at-p "[[:space:]]*$")
  11026               (end-of-line)
  11027               (insert tag-end)
  11028               (back-to-indentation)
  11029               (when (> beg (point))
  11030                 (goto-char beg))
  11031               (insert tag-start))
  11032             ) ;while
  11033           (deactivate-mark)
  11034           ) ;combine-after-change-calls
  11035         ) ;save-excursion
  11036       )))
  11037 
  11038 (defun web-mode-lify-region ()
  11039   "Transform current REGION in an html list (<li>line1</li>...)"
  11040   (interactive)
  11041   (let (beg end lines)
  11042     (save-excursion
  11043       (combine-after-change-calls
  11044         (when  mark-active
  11045           (setq beg (region-beginning)
  11046                 end (region-end))
  11047           (setq lines (buffer-substring beg end))
  11048           (kill-region beg end)
  11049           (setq lines (replace-regexp-in-string "^[ \t]*" "<li>" lines))
  11050           (setq lines (replace-regexp-in-string "$" "</li>" lines))
  11051           (web-mode-insert-and-indent lines)
  11052           ) ;when
  11053         ) ;combine-after-change-calls
  11054       ) ;save-excursion
  11055     ) ;let
  11056   )
  11057 
  11058 (defun web-mode-element-complete (&optional prompt)
  11059   "Completes for an element tag."
  11060   (completing-read
  11061    (or prompt "Tag name: ")
  11062    (append
  11063     web-mode-tag-list
  11064     web-mode-tag-history)
  11065    nil nil nil 'web-mode-tag-history))
  11066 
  11067 (defun web-mode-element-wrap (&optional tag-name)
  11068   "Wrap current REGION with start and end tags.
  11069 Prompt user if TAG-NAME isn't provided."
  11070   (interactive)
  11071   (let (beg end pos tag sep)
  11072     (save-excursion
  11073       (setq tag (or tag-name (web-mode-element-complete)))
  11074       (setq pos (point))
  11075       (cond
  11076         (mark-active
  11077          (setq beg (region-beginning)
  11078                end (region-end)))
  11079         ((get-text-property pos 'tag-type)
  11080          (setq beg (web-mode-element-beginning-position pos)
  11081                end (1+ (web-mode-element-end-position pos))))
  11082         ((setq beg (web-mode-element-parent-position pos))
  11083          (setq end (1+ (web-mode-element-end-position pos))))
  11084         )
  11085       ;;      (message "beg(%S) end(%S)" beg end)
  11086       (when (and beg end (> end 0))
  11087         (setq sep (if (get-text-property beg 'tag-beg) "\n" ""))
  11088         (web-mode-insert-text-at-pos (concat sep "</" tag ">") end)
  11089         (web-mode-insert-text-at-pos (concat "<" tag ">" sep) beg)
  11090         (when (string= sep "\n") (indent-region beg (+ end (* (+ 3 (length tag)) 2))))
  11091         )
  11092       ) ;save-excursion
  11093     (web-mode-go beg)))
  11094 
  11095 (defun web-mode-element-vanish (&optional arg)
  11096   "Vanish the current html element. The content of the element is kept."
  11097   (interactive "p")
  11098   (let (type (pos (point)) start-b start-e end-b end-e)
  11099     (while (>= arg 1)
  11100       (setq type (get-text-property pos 'tag-type))
  11101       (when type
  11102         (cond
  11103           ((member type '(void))
  11104            (web-mode-element-kill)
  11105            (set-mark (point))
  11106            (web-mode-tag-match)
  11107            (web-mode-tag-end)
  11108            (exchange-point-and-mark))
  11109           ((member type '(start))
  11110            (setq start-b (web-mode-tag-beginning-position)
  11111                  start-e (web-mode-tag-end-position))
  11112            (when (web-mode-tag-match)
  11113              (setq end-b (web-mode-tag-beginning-position)
  11114                    end-e (web-mode-tag-end-position)))
  11115            )
  11116           (t
  11117            (setq end-b (web-mode-tag-beginning-position)
  11118                  end-e (web-mode-tag-end-position))
  11119            (when (web-mode-tag-match)
  11120              (setq start-b (web-mode-tag-beginning-position)
  11121                    start-e (web-mode-tag-end-position)))
  11122            ) ;t
  11123           ) ;cond
  11124         (when (and start-b end-b)
  11125           (goto-char end-b)
  11126           (delete-region end-b (1+ end-e))
  11127           (delete-blank-lines)
  11128           (goto-char start-b)
  11129           (delete-region start-b (1+ start-e))
  11130           (delete-blank-lines)
  11131           (web-mode-buffer-indent)
  11132           )
  11133         ;;        (message "start %S %S - end %S %S" start-b start-e end-b end-e))
  11134         ) ;when
  11135       (skip-chars-forward "[:space:]\n")
  11136       (setq arg (1- arg))
  11137       ) ;while
  11138     ) ;let
  11139   )
  11140 
  11141 (defun web-mode-element-kill (&optional arg)
  11142   "Kill the current html element."
  11143   (interactive "p")
  11144   (while (>= arg 1)
  11145     (setq arg (1- arg))
  11146     (web-mode-element-select)
  11147     (when mark-active
  11148       (kill-region (region-beginning) (region-end)))
  11149     ) ;while
  11150   )
  11151 
  11152 (defun web-mode-element-clone (&optional arg)
  11153   "Clone the current html element."
  11154   (interactive "p")
  11155   (let (col pos)
  11156     (while (>= arg 1)
  11157       (setq arg (1- arg)
  11158             col 0)
  11159       (web-mode-element-select)
  11160       (when mark-active
  11161         (save-excursion
  11162           (goto-char (region-beginning))
  11163           (setq col (current-column)))
  11164         (kill-region (region-beginning) (region-end))
  11165         (yank)
  11166         (newline)
  11167         (indent-line-to col)
  11168         (setq pos (point))
  11169         (yank)
  11170         (goto-char pos))
  11171       )
  11172     ) ;let
  11173   )
  11174 
  11175 (defun web-mode-element-insert ()
  11176   "Insert an html element."
  11177   (interactive)
  11178   (let (tag-name)
  11179     (cond
  11180       ((and (get-text-property (point) 'tag-type)
  11181             (not (get-text-property (point) 'tag-beg)))
  11182        (message "element-insert ** invalid context **"))
  11183       ((not (and (setq tag-name (web-mode-element-complete))
  11184                  (> (length tag-name) 0)))
  11185        (message "element-insert ** failure **"))
  11186       ((web-mode-element-is-void tag-name)
  11187        (insert (concat "<" (replace-regexp-in-string "/" "" tag-name) "/>"))
  11188        )
  11189       (mark-active
  11190        (let ((beg (region-beginning)) (end (region-end)))
  11191          (deactivate-mark)
  11192          (goto-char end)
  11193          (insert "</" tag-name ">")
  11194          (goto-char beg)
  11195          (insert "<" tag-name ">")
  11196          )
  11197        )
  11198       (t
  11199        (insert (concat "<" tag-name ">" "</" tag-name ">"))
  11200        (web-mode-sb "</")
  11201        )
  11202       ) ;cond
  11203     ))
  11204 
  11205 (defun web-mode-element-insert-at-point ()
  11206   "Replace the word at point with a html tag of it."
  11207   (interactive)
  11208   (let ((tag-name (thing-at-point 'word)))
  11209     (cond
  11210       ((web-mode-element-is-void tag-name)
  11211        (backward-kill-word 1)
  11212        (insert (concat "<" (replace-regexp-in-string "/" "" tag-name) "/>"))
  11213        )
  11214       (mark-active
  11215        (setq tag-name (buffer-substring (region-beginning) (region-end)))
  11216        (delete-region (region-beginning) (region-end))
  11217        (insert (concat "<" tag-name ">" "</" tag-name ">"))
  11218        (web-mode-sb "</")
  11219        )
  11220       (tag-name ; do nothing is there isn's word at point
  11221        (backward-kill-word 1)
  11222        (insert (concat "<" tag-name ">" "</" tag-name ">"))
  11223        (web-mode-sb "</")
  11224        )
  11225       ) ;cond
  11226     ))
  11227 
  11228 (defun web-mode-element-rename (&optional tag-name)
  11229   "Rename the current html element."
  11230   (interactive)
  11231   (save-excursion
  11232     (let (pos)
  11233       (unless tag-name (setq tag-name (web-mode-element-complete "New tag name: ")))
  11234       (when (and (> (length tag-name) 0)
  11235                  (web-mode-element-beginning)
  11236                  (looking-at "<\\([[:alnum:]]+\\(:?[[:alpha:]_-]+\\)?\\)"))
  11237         (setq pos (point))
  11238         (unless (web-mode-element-is-void)
  11239           (save-match-data
  11240             (web-mode-tag-match)
  11241             (if (looking-at "</[ ]*\\([[:alnum:]]+\\(:?[[:alpha:]_-]+\\)?\\)")
  11242                 (replace-match (concat "</" tag-name))
  11243                 )))
  11244         (goto-char pos)
  11245         (replace-match (concat "<" tag-name))
  11246         ))))
  11247 
  11248 (defun web-mode-current-trimmed-line ()
  11249   (web-mode-trim (buffer-substring-no-properties
  11250                   (line-beginning-position)
  11251                   (line-end-position))))
  11252 
  11253 (defun web-mode-trim (string)
  11254   (replace-regexp-in-string "\\`[ \t\n]*" "" (replace-regexp-in-string "[ \t\n]*\\'" "" string)))
  11255 
  11256 (defun web-mode-is-token-end (pos)
  11257   (let (block-token part-token)
  11258     (setq block-token (get-text-property pos 'block-token))
  11259     (setq part-token (get-text-property pos 'part-token))
  11260     (cond
  11261       ((not (or block-token part-token))
  11262        nil)
  11263       ((>= (1+ pos) (point-max))
  11264        t)
  11265       ((and block-token
  11266             (not (string= (get-text-property (1+ pos) 'block-token) block-token)))
  11267        t)
  11268       ((and part-token
  11269             (not (string= (get-text-property (1+ pos) 'part-token) part-token)))
  11270        t)
  11271       (t
  11272        nil)
  11273       ) ;cond
  11274     ))
  11275 
  11276 (defun web-mode-block-is-token-line ()
  11277   (save-excursion
  11278     (let ((continue t) (counter 0))
  11279       (beginning-of-line)
  11280       (back-to-indentation)
  11281       (while (and continue (not (eolp)))
  11282         (cond
  11283           ((get-text-property (point) 'block-token)
  11284            (setq counter (1+ counter)))
  11285           ((not (member (following-char) '(?\s ?\t)))
  11286            (setq continue nil
  11287                  counter 0))
  11288           ) ;cond
  11289         (forward-char)
  11290         ) ;while
  11291       (> counter 0)
  11292       )))
  11293 
  11294 (defun web-mode-part-is-token-line (pos)
  11295   (save-excursion
  11296     (let ((continue t)
  11297           (counter 0))
  11298       (goto-char pos)
  11299       (setq continue (not (eolp)))
  11300       (while continue
  11301         (forward-char)
  11302         (cond
  11303           ((eolp)
  11304            (setq continue nil))
  11305           ((or (get-text-property (point) 'block-side)
  11306                (member (get-text-property (point) 'part-token) '(comment string)))
  11307            (setq counter (1+ counter)))
  11308           ((not (member (following-char) '(?\s ?\t)))
  11309            (setq continue nil
  11310                  counter 0))
  11311           )
  11312         ) ;while
  11313       (> counter 0))))
  11314 
  11315 (defun web-mode-is-content (&optional pos)
  11316   (unless pos (setq pos (point)))
  11317   (not (or (get-text-property pos 'part-side)
  11318            (get-text-property pos 'tag-type)
  11319            (get-text-property pos 'block-side)
  11320            )))
  11321 
  11322 (defun web-mode-is-comment-or-string (&optional pos)
  11323   (unless pos (setq pos (point)))
  11324   (not (null (or (eq (get-text-property pos 'tag-type) 'comment)
  11325                  (member (get-text-property pos 'block-token) '(comment string))
  11326                  (member (get-text-property pos 'part-token) '(comment string))))))
  11327 
  11328 ;; NOTE: we look at the firt one
  11329 (defun web-mode-block-is-open (&optional pos)
  11330   (unless pos (setq pos (point))))
  11331 
  11332 ;; NOTE: we look at the last one
  11333 (defun web-mode-block-is-close (&optional pos)
  11334   (unless pos (setq pos (point)))
  11335   (and (get-text-property pos 'block-side)
  11336        (eq (caar (web-mode-block-controls-get pos)) 'close)))
  11337 
  11338 ;; NOTE: we look at the first one
  11339 (defun web-mode-block-is-inside (&optional pos)
  11340   (unless pos (setq pos (point)))
  11341   (and (get-text-property pos 'block-side)
  11342        (eq (caar (web-mode-block-controls-get pos)) 'inside)))
  11343 
  11344 (defun web-mode-element-is-void (&optional tag)
  11345   (cond
  11346     ((and (not tag) (eq (get-text-property (point) 'tag-type) 'void))
  11347      t)
  11348     ((and tag (member tag '("div" "li" "a" "p" "h1" "h2" "h3" "ul" "span" "article" "section" "td" "tr")))
  11349      nil)
  11350     ((and tag (string-suffix-p "/" tag))
  11351      t)
  11352     ((and tag (string= web-mode-content-type "jsx"))
  11353      (member (downcase tag) '("img" "br" "hr")))
  11354     (tag
  11355      (car (member (downcase tag) web-mode-void-elements)))
  11356     (t
  11357      nil)
  11358     ))
  11359 
  11360 ;;---- COMMENT ------------------------------------------------------------------
  11361 
  11362 (defun web-mode-toggle-comments ()
  11363   "Toggle comments visbility."
  11364   (interactive)
  11365   (web-mode-with-silent-modifications
  11366    (save-excursion
  11367      (if web-mode-comments-invisible
  11368          (remove-overlays))
  11369      (setq web-mode-comments-invisible (null web-mode-comments-invisible))
  11370      (let ((continue t)
  11371            (pos (point-min))
  11372            (visibility web-mode-comments-invisible)
  11373            end)
  11374        (while continue
  11375          (setq pos (next-single-property-change pos 'font-lock-face))
  11376          (if (null pos)
  11377              (setq continue nil)
  11378              (when (eq (get-text-property pos 'font-lock-face) 'web-mode-comment-face)
  11379                (setq end (next-single-property-change pos 'font-lock-face))
  11380                (put-text-property pos end 'invisible visibility)
  11381                (when visibility
  11382                  (make-overlay pos end))
  11383                (goto-char pos)
  11384                )
  11385              )
  11386          )
  11387        ) ;let
  11388      )))
  11389 
  11390 (defun web-mode-comment-or-uncomment-region (beg end &optional _arg)
  11391   (interactive)
  11392   (save-excursion
  11393     (push-mark end)
  11394     (goto-char beg)
  11395     (setq mark-active t)
  11396     (web-mode-comment-or-uncomment)
  11397     (pop-mark)))
  11398 
  11399 (defun web-mode-comment-or-uncomment ()
  11400   "Comment or uncomment line(s), block or region at POS."
  11401   (interactive)
  11402   ;; TODO : if mark is at eol, mark--
  11403   (if (and (not mark-active) (looking-at-p "[[:space:]]*$"))
  11404       (web-mode-comment-insert)
  11405       (when (and (use-region-p) (eq (point) (region-end)))
  11406         (if (bolp) (backward-char))
  11407         (exchange-point-and-mark))
  11408       (if (eq (get-text-property (point) 'block-token) 'delimiter-beg)
  11409           (web-mode-block-skip-blank-forward (point) '(delimiter-beg))
  11410           (skip-chars-forward "[:space:]" (line-end-position)))
  11411       (cond
  11412         ;; #1147
  11413         ((and (get-text-property (point) 'jsx-beg)
  11414               (eq (get-text-property (1+ (point)) 'part-token) 'comment))
  11415          (web-mode-uncomment (1+ (point))))
  11416         ((or (eq (get-text-property (point) 'tag-type) 'comment)
  11417              (eq (get-text-property (point) 'block-token) 'comment)
  11418              (eq (get-text-property (point) 'part-token) 'comment))
  11419          (web-mode-uncomment (point)))
  11420         (t
  11421          (web-mode-comment (point)))
  11422         )
  11423       ) ;if
  11424   )
  11425 
  11426 (defun web-mode-comment-indent-new-line (&optional _soft)
  11427   (interactive)
  11428   (let (ctx)
  11429     (setq ctx (web-mode-comment-context))
  11430     (cond
  11431       ((null ctx)
  11432        (newline 1))
  11433       (t
  11434        (newline 1)
  11435        (indent-line-to (plist-get ctx :col))
  11436        (let ((prefix (plist-get ctx :prefix)))
  11437          (insert
  11438           (concat prefix
  11439                   ;; Check if the comment ends with a space, and if not, insert one.
  11440                   (if
  11441                    (string-equal (substring prefix -1 (length prefix)) " ")
  11442                    ""
  11443                    " ")))))
  11444       ) ;cond
  11445     ))
  11446 
  11447 (defun web-mode-comment-context (&optional pos)
  11448   (cond
  11449     (pos
  11450      )
  11451     ((and (eolp) (not (bobp)))
  11452      (setq pos (1- (point))))
  11453     (t
  11454      (setq pos (point)))
  11455     ) ;cond
  11456   (let (beg col prefix type format)
  11457     (cond
  11458       ((eq (get-text-property pos 'block-token) 'comment)
  11459        (setq type "block"))
  11460       ((eq (get-text-property pos 'tag-type) 'comment)
  11461        (setq type "tag"))
  11462       ((eq (get-text-property pos 'part-token) 'comment)
  11463        (setq type "part"))
  11464       )
  11465     (if (null type) nil
  11466         (save-excursion
  11467           (goto-char pos)
  11468           (web-mode-comment-beginning)
  11469           (setq beg (point)
  11470                 col (current-column))
  11471           (cond
  11472             ((looking-at-p "/\\*")
  11473              (setq format "/*"
  11474                    prefix " * "))
  11475             ((looking-at-p "//")
  11476              (setq format "//"
  11477                    prefix "//"))
  11478             ((looking-at-p "#")
  11479              (setq format "#"
  11480                    prefix "#"))
  11481             ((looking-at-p ";")
  11482              (setq format ";"
  11483                    prefix ";"))
  11484             ((looking-at-p "''")
  11485              (setq format "''"
  11486                    prefix "''"))
  11487             ) ;cond
  11488           (list :beg beg :col col :prefix prefix :type type :format format)))))
  11489 
  11490 (defun web-mode-comment-insert ()
  11491   (let ((alt nil) (language nil) (pos (point)))
  11492     (setq language (web-mode-language-at-pos pos))
  11493     (setq alt (cdr (assoc language web-mode-comment-formats)))
  11494     ;;(message "language=%S" language)
  11495     (cond
  11496       ((get-text-property pos 'block-side)
  11497        (cond
  11498          ((and alt (string= alt "//"))
  11499           (insert "// "))
  11500          (t
  11501           (insert "/*  */")
  11502           (search-backward " */"))
  11503          ) ;cond
  11504        ) ;case block-side
  11505       ((get-text-property pos 'part-side)
  11506        (cond
  11507          ((and alt (string= alt "//"))
  11508           (insert "// "))
  11509          (t
  11510           (insert "/*  */")
  11511           (search-backward " */"))
  11512          ) ;cond
  11513        ) ;case part-side
  11514       (t
  11515        (insert "<!--  -->")
  11516        (search-backward " -->")
  11517        ) ;case html
  11518       ) ;cond
  11519     ))
  11520 
  11521 (defun web-mode-comment (pos)
  11522   (let (ctx language col sel beg end block-side single-line-block pos-after content)
  11523 
  11524     (setq pos-after pos)
  11525 
  11526     (setq block-side (get-text-property pos 'block-side))
  11527     (setq single-line-block (web-mode-is-single-line-block pos))
  11528 
  11529     (cond
  11530 
  11531       ((and block-side (string= web-mode-engine "erb"))
  11532        (web-mode-comment-erb-block pos)
  11533        )
  11534 
  11535       ((and block-side (string= web-mode-engine "artanis"))
  11536        (web-mode-comment-artanis-block pos)
  11537        )
  11538 
  11539       ((and single-line-block block-side
  11540             (intern-soft (concat "web-mode-comment-" web-mode-engine "-block")))
  11541        (funcall (intern (concat "web-mode-comment-" web-mode-engine "-block")) pos)
  11542        )
  11543 
  11544       (t
  11545        (setq ctx (web-mode-point-context
  11546                   (if mark-active (region-beginning) (line-beginning-position))))
  11547        ;;(message "%S" ctx)
  11548        (setq language (plist-get ctx :language))
  11549        (setq col (current-column))
  11550        (cond
  11551          (mark-active
  11552           ;;(message "%S %S" (point) col)
  11553           )
  11554          ((and (member language '("html" "xml"))
  11555                (get-text-property (progn (back-to-indentation) (point)) 'tag-beg))
  11556           (web-mode-element-select))
  11557          (t
  11558           (end-of-line)
  11559           (set-mark (line-beginning-position)))
  11560          ) ;cond
  11561 
  11562        (setq beg (region-beginning)
  11563              end (region-end))
  11564 
  11565        (when (> (point) (mark))
  11566          (exchange-point-and-mark))
  11567 
  11568        (if (and (eq (char-before end) ?\n)
  11569                 (not (eq (char-after end) ?\n)))
  11570            (setq end (1- end)))
  11571 
  11572        (setq sel (buffer-substring-no-properties beg end))
  11573 
  11574        (cond
  11575 
  11576          ((member language '("html" "xml"))
  11577           (cond
  11578             ((and (= web-mode-comment-style 2) (string= web-mode-engine "django"))
  11579              (setq content (concat "{# " sel " #}")))
  11580             ((and (= web-mode-comment-style 2) (member web-mode-engine '("ejs" "erb")))
  11581              (setq content (concat "<%# " sel " %>")))
  11582             ((and (= web-mode-comment-style 2) (string= web-mode-engine "artanis"))
  11583              (setq content (concat "<%; " sel " %>")))
  11584             ((and (= web-mode-comment-style 2) (string= web-mode-engine "aspx"))
  11585              (setq content (concat "<%-- " sel " --%>")))
  11586             ((and (= web-mode-comment-style 2) (string= web-mode-engine "smarty"))
  11587              (setq content (concat "{* " sel " *}")))
  11588             ((and (= web-mode-comment-style 2) (string= web-mode-engine "expressionengine"))
  11589              (setq content (concat "{!-- " sel " --}")))
  11590             ((and (= web-mode-comment-style 2) (string= web-mode-engine "xoops"))
  11591              (setq content (concat "<{* " sel " *}>")))
  11592             ((and (= web-mode-comment-style 2) (string= web-mode-engine "hero"))
  11593              (setq content (concat "<%# " sel " %>")))
  11594             ((and (= web-mode-comment-style 2) (string= web-mode-engine "blade"))
  11595              (setq content (concat "{{-- " sel " --}}")))
  11596             ((and (= web-mode-comment-style 2) (string= web-mode-engine "ctemplate"))
  11597              (setq content (concat "{{!-- " sel " --}}")))
  11598             ((and (= web-mode-comment-style 2) (string= web-mode-engine "antlers"))
  11599              (setq content (concat "{{# " sel " #}}")))
  11600             ((and (= web-mode-comment-style 2) (string= web-mode-engine "razor"))
  11601              (setq content (concat "@* " sel " *@")))
  11602             (t
  11603              (setq content (concat "<!-- " sel " -->"))
  11604              (when (< (length sel) 1)
  11605                (search-backward " -->")
  11606                (setq pos-after nil))
  11607              ))
  11608           ) ;case html
  11609 
  11610          ((member language '("php" "javascript" "typescript" "java" "jsx"))
  11611           (let (alt)
  11612             (setq alt (cdr (assoc language web-mode-comment-formats)))
  11613             ;;(message "language=%S alt=%S sel=%S col=%S" language alt sel col)
  11614             (cond
  11615               ((and alt (string= alt "//"))
  11616                (setq content (replace-regexp-in-string (concat "\n[ ]\\{" (number-to-string col) "\\}") "\n" sel))
  11617                (setq content (replace-regexp-in-string (concat "\n") "\n// " content))
  11618                (setq content (concat "// " content)))
  11619               ((get-text-property pos 'jsx-depth)
  11620                (setq content (concat "{/* " sel " */}")))
  11621               (web-mode-comment-prefixing
  11622                (setq content (replace-regexp-in-string (concat "\n[ ]\\{" (number-to-string col) "\\}") "\n* " sel))
  11623                (setq content (concat "/* " content " */")))
  11624               (t
  11625                (setq content (concat "/* " sel " */")))
  11626               ) ;cond
  11627             ) ;let
  11628           )
  11629 
  11630          ((member language '("erb"))
  11631           (setq content (replace-regexp-in-string "^[ ]*" "#" sel)))
  11632 
  11633          ((member language '("asp"))
  11634           (setq content (replace-regexp-in-string "^[ ]*" "'" sel)))
  11635 
  11636          (t
  11637           (setq content (concat "/* " sel " */")))
  11638 
  11639          ) ;cond
  11640 
  11641        (when content
  11642          (delete-region beg end)
  11643          (deactivate-mark)
  11644          (let (beg end)
  11645            (setq beg (line-beginning-position))
  11646            (insert content)
  11647            (setq end (line-end-position))
  11648            (indent-region beg end)
  11649            )
  11650          ) ;when
  11651 
  11652        ) ;t
  11653       ) ;cond
  11654 
  11655     (when pos-after (goto-char pos-after))
  11656 
  11657     ))
  11658 
  11659 (defun web-mode-comment-ejs-block (pos)
  11660   (let (beg end)
  11661     (setq beg (web-mode-block-beginning-position pos)
  11662           end (web-mode-block-end-position pos))
  11663     (web-mode-insert-text-at-pos "//" (+ beg 2))))
  11664 
  11665 (defun web-mode-comment-erb-block (pos)
  11666   (let (beg end)
  11667     (setq beg (web-mode-block-beginning-position pos)
  11668           end (web-mode-block-end-position pos))
  11669     (web-mode-insert-text-at-pos "#" (+ beg 2))))
  11670 
  11671 (defun web-mode-comment-artanis-block (pos)
  11672   (let (beg end)
  11673     (setq beg (web-mode-block-beginning-position pos)
  11674           end (web-mode-block-end-position pos))
  11675     (web-mode-insert-text-at-pos ";" (+ beg 2))))
  11676 
  11677 (defun web-mode-comment-django-block (pos)
  11678   (let (beg end)
  11679     (setq beg (web-mode-block-beginning-position pos)
  11680           end (web-mode-block-end-position pos))
  11681     (web-mode-insert-text-at-pos "#" end)
  11682     (web-mode-insert-text-at-pos "#" (1+ beg))))
  11683 
  11684 (defun web-mode-comment-dust-block (pos)
  11685   (let (beg end)
  11686     (setq beg (web-mode-block-beginning-position pos)
  11687           end (web-mode-block-end-position pos))
  11688     (web-mode-insert-text-at-pos "!" end)
  11689     (web-mode-insert-text-at-pos "!" (1+ beg))))
  11690 
  11691 (defun web-mode-comment-aspx-block (pos)
  11692   (let (beg end)
  11693     (setq beg (web-mode-block-beginning-position pos)
  11694           end (web-mode-block-end-position pos))
  11695     (web-mode-insert-text-at-pos "#" end)
  11696     (web-mode-insert-text-at-pos "#" (1+ beg))))
  11697 
  11698 (defun web-mode-comment-jsp-block (pos)
  11699   (let (beg end)
  11700     (setq beg (web-mode-block-beginning-position pos)
  11701           end (web-mode-block-end-position pos))
  11702     (web-mode-insert-text-at-pos "--" (+ beg 2))))
  11703 
  11704 (defun web-mode-comment-go-block (pos)
  11705   (let (beg end)
  11706     (setq beg (web-mode-block-beginning-position pos)
  11707           end (web-mode-block-end-position pos))
  11708     (web-mode-insert-text-at-pos "*/" (1- end))
  11709     (web-mode-insert-text-at-pos "/*" (+ beg (if (web-mode-looking-at "{{" beg) 2 0)))))
  11710 
  11711 (defun web-mode-comment-php-block (pos)
  11712   (let (beg end)
  11713     (setq beg (web-mode-block-beginning-position pos)
  11714           end (web-mode-block-end-position pos))
  11715     (web-mode-insert-text-at-pos "*/" (- end 2))
  11716     (web-mode-insert-text-at-pos "/*" (+ beg 1 (if (web-mode-looking-at "<\\?php" beg) 5 3)))))
  11717 
  11718 (defun web-mode-comment-svelte-block (pos)
  11719   (let (beg end)
  11720     (setq beg (web-mode-block-beginning-position pos)
  11721           end (web-mode-block-end-position pos))
  11722     (web-mode-insert-text-at-pos "!" end)
  11723     (web-mode-insert-text-at-pos "!" (1+ beg))))
  11724 
  11725 (defun web-mode-comment-boundaries (&optional pos)
  11726   (interactive)
  11727   (unless pos (setq pos (point)))
  11728   (let ((beg pos) (end pos) prop)
  11729     (save-excursion
  11730       (goto-char pos)
  11731       (setq prop
  11732             (cond
  11733               ((eq (get-text-property pos 'block-token) 'comment) 'block-token)
  11734               ((eq (get-text-property pos 'tag-type) 'comment) 'tag-type)
  11735               ((eq (get-text-property pos 'part-token) 'comment) 'part-token)
  11736               (t nil)
  11737               ))
  11738       (if (null prop)
  11739           (setq beg nil
  11740                 end nil)
  11741           (when (and (not (bobp))
  11742                      (eq (get-text-property pos prop) (get-text-property (1- pos) prop)))
  11743             (setq beg (or (previous-single-property-change pos prop) (point-min))))
  11744           (when (and (not (eobp))
  11745                      (eq (get-text-property pos prop) (get-text-property (1+ pos) prop)))
  11746             (setq end (or (next-single-property-change pos prop) (point-max)))))
  11747       (message "beg(%S) end(%S) point-max(%S)" beg end (point-max))
  11748       (when (and beg (string= (buffer-substring-no-properties beg (+ beg 2)) "//"))
  11749         (goto-char end)
  11750         (while (and (looking-at-p "\n[ ]*//")
  11751                     (not (eobp)))
  11752           (search-forward "//")
  11753           (backward-char 2)
  11754           ;;(message "%S" (point))
  11755           (setq end (next-single-property-change (point) prop))
  11756           (goto-char end)
  11757           ;;(message "%S" (point))
  11758           ) ;while
  11759         ) ;when
  11760       ;;(when end (setq end (1- end))) ;; #1021
  11761       ) ;save-excursion
  11762     ;;(message "beg=%S end=%S" beg end)
  11763     (if (and beg end) (cons beg end) nil)
  11764     ))
  11765 
  11766 (defun web-mode-uncomment (pos)
  11767   (let ((beg pos) (end pos) (sub2 "") comment boundaries)
  11768     (save-excursion
  11769       (cond
  11770         ((and (get-text-property pos 'block-side)
  11771               (intern-soft (concat "web-mode-uncomment-" web-mode-engine "-block")))
  11772          (funcall (intern (concat "web-mode-uncomment-" web-mode-engine "-block")) pos))
  11773         ((and (setq boundaries (web-mode-comment-boundaries pos))
  11774               (setq beg (car boundaries))
  11775               (setq end (1+ (cdr boundaries)))
  11776               (> (- end beg) 4))
  11777          (when (and (eq (get-text-property beg 'part-token) 'comment)
  11778                     (> beg 1) ;#1158
  11779                     (get-text-property (1- beg) 'jsx-beg))
  11780            (setq beg (1- beg)
  11781                  end (1+ end)))
  11782          (setq comment (buffer-substring-no-properties beg end))
  11783          (setq sub2 (substring comment 0 2))
  11784          (cond
  11785            ((member sub2 '("<!" "<%"))
  11786             (setq comment (replace-regexp-in-string "\\(^<[!%]--[ ]?\\|[ ]?--[%]?>$\\)" "" comment)))
  11787            ((string= sub2 "{#")
  11788             (setq comment (replace-regexp-in-string "\\(^{#[ ]?\\|[ ]?#}$\\)" "" comment)))
  11789            ((string= sub2 "{/") ;jsx comments
  11790             (setq comment (replace-regexp-in-string "\\(^{/\\*[ ]?\\|[ ]?\\*/}$\\)" "" comment)))
  11791            ((string= sub2 "/*")
  11792             ;;(message "%S" comment)
  11793             ;;(setq comment (replace-regexp-in-string "\\(\\*/\\|^/\\*[ ]?\\|^[ \t]*\\*\\)" "" comment))
  11794             (setq comment (replace-regexp-in-string "\\([ ]?\\*/$\\|^/\\*[ ]?\\)" "" comment))
  11795             (setq comment (replace-regexp-in-string "\\(^[ \t]*\\*\\)" "" comment))
  11796             ;;(message "%S" comment)
  11797             )
  11798            ((string= sub2 "''")
  11799             (setq comment (replace-regexp-in-string "''" "" comment)))
  11800            ((string= sub2 "//")
  11801             (setq comment (replace-regexp-in-string "^ *//" "" comment)))
  11802            ) ;cond
  11803          (delete-region beg end)
  11804          (web-mode-insert-and-indent comment)
  11805          (goto-char beg)
  11806          )
  11807         ) ;cond
  11808       (indent-according-to-mode)
  11809       )))
  11810 
  11811 (defun web-mode-uncomment-erb-block (pos)
  11812   (let (beg end)
  11813     (setq beg (web-mode-block-beginning-position pos)
  11814           end (web-mode-block-end-position pos))
  11815     (cond
  11816       ((string= (buffer-substring-no-properties beg (+ beg 4)) "<%#=")
  11817        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11818       ((string-match-p "<[%[:alpha:]]" (buffer-substring-no-properties (+ beg 2) (- end 2)))
  11819        (web-mode-remove-text-at-pos 2 (1- end))
  11820        (web-mode-remove-text-at-pos 3 beg))
  11821       (t
  11822        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11823       ) ;cond
  11824     )
  11825   )
  11826 
  11827 (defun web-mode-uncomment-artanis-block (pos)
  11828   (let (beg end)
  11829     (setq beg (web-mode-block-beginning-position pos)
  11830           end (web-mode-block-end-position pos))
  11831     (cond
  11832       ((string= (buffer-substring-no-properties beg (+ beg 4)) "<%;=")
  11833        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11834       ((string-match-p "<[%[:alpha:]]" (buffer-substring-no-properties (+ beg 2) (- end 2)))
  11835        (web-mode-remove-text-at-pos 2 (1- end))
  11836        (web-mode-remove-text-at-pos 3 beg))
  11837       (t
  11838        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11839       ) ;cond
  11840     )
  11841   )
  11842 
  11843 (defun web-mode-uncomment-ejs-block (pos)
  11844   (let (beg end)
  11845     (setq beg (web-mode-block-beginning-position pos)
  11846           end (web-mode-block-end-position pos))
  11847     (web-mode-remove-text-at-pos 1 (+ beg 2))))
  11848 
  11849 (defun web-mode-uncomment-django-block (pos)
  11850   (let (beg end)
  11851     (setq beg (web-mode-block-beginning-position pos)
  11852           end (web-mode-block-end-position pos))
  11853     (cond
  11854       ((web-mode-looking-at-p "{#[{%]" beg)
  11855        (web-mode-remove-text-at-pos 1 (1- end))
  11856        (web-mode-remove-text-at-pos 1 (1+ beg))
  11857        )
  11858       (t
  11859        (web-mode-remove-text-at-pos 2 (1- end))
  11860        (web-mode-remove-text-at-pos 2 beg))
  11861       ) ;cond
  11862     ))
  11863 
  11864 (defun web-mode-uncomment-ctemplate-block (pos)
  11865   (let (beg end)
  11866     (setq beg (web-mode-block-beginning-position pos)
  11867           end (web-mode-block-end-position pos))
  11868     (web-mode-remove-text-at-pos 5 (- end 4))
  11869     (web-mode-remove-text-at-pos 5 beg)))
  11870 
  11871 (defun web-mode-uncomment-antlers-block (pos)
  11872   (let (beg end)
  11873     (setq beg (web-mode-block-beginning-position pos)
  11874           end (web-mode-block-end-position pos))
  11875     (web-mode-remove-text-at-pos 3 (- end 2))
  11876     (web-mode-remove-text-at-pos 3 beg)))
  11877 
  11878 (defun web-mode-uncomment-dust-block (pos)
  11879   (let (beg end)
  11880     (setq beg (web-mode-block-beginning-position pos)
  11881           end (web-mode-block-end-position pos))
  11882     (web-mode-remove-text-at-pos 1 (1- end))
  11883     (web-mode-remove-text-at-pos 1 (1+ beg))))
  11884 
  11885 (defun web-mode-uncomment-aspx-block (pos)
  11886   (let (beg end)
  11887     (setq beg (web-mode-block-beginning-position pos)
  11888           end (web-mode-block-end-position pos))
  11889     (web-mode-remove-text-at-pos 1 (1- end))
  11890     (web-mode-remove-text-at-pos 1 (1+ beg))))
  11891 
  11892 (defun web-mode-uncomment-jsp-block (pos)
  11893   (let (beg end)
  11894     (setq beg (web-mode-block-beginning-position pos)
  11895           end (web-mode-block-end-position pos))
  11896     (web-mode-remove-text-at-pos 2 (+ beg 2))))
  11897 
  11898 (defun web-mode-uncomment-go-block (pos)
  11899   (let (beg end)
  11900     (setq beg (web-mode-block-beginning-position pos)
  11901           end (web-mode-block-end-position pos))
  11902     (web-mode-remove-text-at-pos 2 (+ beg 2))
  11903     (web-mode-remove-text-at-pos 2 (- end 5))))
  11904 
  11905 (defun web-mode-uncomment-svelte-block (pos)
  11906   (let (beg end)
  11907     (setq beg (web-mode-block-beginning-position pos)
  11908           end (web-mode-block-end-position pos))
  11909     (web-mode-remove-text-at-pos 1 (1- end))
  11910     (web-mode-remove-text-at-pos 1 (1+ beg))))
  11911 
  11912 (defun web-mode-snippet-names ()
  11913   (mapcar #'car web-mode-snippets))
  11914 
  11915 (defun web-mode-snippet-insert (code)
  11916   "Insert a snippet."
  11917   (interactive
  11918    (list (completing-read "Snippet: " (web-mode-snippet-names))))
  11919   (let (beg
  11920         (continue t)
  11921         (counter 0)
  11922         end
  11923         sel
  11924         snippet
  11925         (l (length web-mode-snippets))
  11926         pos)
  11927     (when mark-active
  11928       (setq sel (web-mode-trim (buffer-substring-no-properties
  11929                                 (region-beginning) (region-end))))
  11930       (delete-region (region-beginning) (region-end)))
  11931     (while (and continue (< counter l))
  11932       (setq snippet (nth counter web-mode-snippets))
  11933       (when (string= (car snippet) code)
  11934         (setq continue nil))
  11935       (setq counter (1+ counter)))
  11936     (when snippet
  11937       (setq snippet (cdr snippet))
  11938       (setq beg (line-beginning-position))
  11939       (insert snippet)
  11940       (setq pos (point)
  11941             end (point))
  11942       (cond
  11943         ((string-match-p "¦" snippet)
  11944          (search-backward "¦")
  11945          (delete-char 1)
  11946          (setq pos (point)
  11947                end (1- end)))
  11948         ((string-match-p "|" snippet)
  11949          (search-backward "|")
  11950          (delete-char 1)
  11951          (setq pos (point)
  11952                end (1- end)))
  11953         ) ;cond
  11954       (when sel
  11955         (insert sel)
  11956         (setq pos (point)
  11957               end (+ end (length sel))))
  11958       (goto-char end)
  11959       (setq end (line-end-position))
  11960       (unless sel (goto-char pos))
  11961       (indent-region beg end))
  11962     ))
  11963 
  11964 (defun web-mode-looking-at (regexp pos)
  11965   (save-excursion
  11966     (goto-char pos)
  11967     (looking-at regexp)))
  11968 
  11969 (defun web-mode-looking-at-p (regexp pos)
  11970   (save-excursion
  11971     (goto-char pos)
  11972     (looking-at-p regexp)))
  11973 
  11974 (defun web-mode-looking-back (regexp pos &optional limit greedy)
  11975   (save-excursion
  11976     (goto-char pos)
  11977     (if limit
  11978         (looking-back regexp limit greedy)
  11979         (looking-back regexp (point-min)))))
  11980 
  11981 (defun web-mode-insert-text-at-pos (text pos)
  11982   (let ((mem web-mode-enable-auto-pairing))
  11983     (setq web-mode-enable-auto-pairing nil)
  11984     (save-excursion
  11985       (goto-char pos)
  11986       (insert text)
  11987       (setq web-mode-enable-auto-pairing mem)
  11988       )))
  11989 
  11990 (defun web-mode-remove-text-at-pos (n &optional pos)
  11991   (unless pos (setq pos (point)))
  11992   (delete-region pos (+ pos n)))
  11993 
  11994 (defun web-mode-insert-and-indent (text)
  11995   (let (beg end)
  11996     (setq beg (line-beginning-position))
  11997     (insert text)
  11998     (setq end (line-end-position))
  11999     (indent-region beg end)
  12000     ))
  12001 
  12002 (defun web-mode-column-at-pos (pos)
  12003   (save-excursion
  12004     (goto-char pos)
  12005     (current-column)))
  12006 
  12007 (defun web-mode-indentation-at-pos (pos)
  12008   (save-excursion
  12009     (goto-char pos)
  12010     (current-indentation)))
  12011 
  12012 (defun web-mode-navigate (&optional pos)
  12013   "Move point to the matching opening/closing tag/block."
  12014   (interactive)
  12015   (unless pos (setq pos (point)))
  12016   (let (init)
  12017     (goto-char pos)
  12018     (setq init (point))
  12019     (when (> (current-indentation) (current-column))
  12020       (back-to-indentation))
  12021     (setq pos (point))
  12022     (cond
  12023       ((and (get-text-property pos 'block-side)
  12024             (web-mode-block-beginning)
  12025             (web-mode-block-controls-get (point)))
  12026        (web-mode-block-match))
  12027       ((member (get-text-property pos 'tag-type) '(start end))
  12028        (web-mode-tag-beginning)
  12029        (web-mode-tag-match))
  12030       (t
  12031        (goto-char init))
  12032       )
  12033     ))
  12034 
  12035 (defun web-mode-block-match (&optional pos)
  12036   (unless pos (setq pos (point)))
  12037   (let (pos-ori controls control (counter 1) type (continue t) pair)
  12038     (setq pos-ori pos)
  12039     (goto-char pos)
  12040     (setq controls (web-mode-block-controls-get pos))
  12041     ;;(message "controls=%S" controls)
  12042     (cond
  12043       (controls
  12044        (setq pair (car controls))
  12045        (setq control (cdr pair))
  12046        (setq type (car pair))
  12047        (when (eq type 'inside) (setq type 'close))
  12048        (while continue
  12049          (cond
  12050            ((and (> pos-ori 1) (bobp))
  12051             (setq continue nil))
  12052            ((or (and (eq type 'open) (not (web-mode-block-next)))
  12053                 (and (eq type 'close) (not (web-mode-block-previous))))
  12054             (setq continue nil)
  12055             )
  12056            ((null (setq controls (web-mode-block-controls-get (point))))
  12057             )
  12058            (t
  12059             ;;TODO : est il nécessaire de faire un reverse sur controls si on doit matcher backward
  12060             (dolist (pair controls)
  12061               (cond
  12062                 ((not (string= (cdr pair) control))
  12063                  )
  12064                 ((eq (car pair) 'inside)
  12065                  )
  12066                 ((eq (car pair) type)
  12067                  (setq counter (1+ counter)))
  12068                 (t
  12069                  (setq counter (1- counter)))
  12070                 )
  12071               ) ;dolist
  12072             (when (= counter 0)
  12073               (setq continue nil))
  12074             ) ;t
  12075            ) ;cond
  12076          ) ;while
  12077        (if (= counter 0) (point) nil)
  12078        ) ;controls
  12079       (t
  12080        (goto-char pos-ori)
  12081        nil
  12082        ) ;controls = nul
  12083       ) ;conf
  12084     ))
  12085 
  12086 (defun web-mode-tag-match (&optional pos)
  12087   "Move point to the matching opening/closing tag."
  12088   (interactive)
  12089   (unless pos (setq pos (point)))
  12090   (let (regexp name)
  12091     (cond
  12092       ((eq (get-text-property pos 'tag-type) 'void)
  12093        (web-mode-tag-beginning))
  12094       ((and (eq (get-text-property pos 'tag-type) 'comment)
  12095             (web-mode-looking-at-p "<!--#\\(elif\\|else\\|endif\\|if\\)" pos))
  12096        (setq regexp "<!--#\\(end\\)?if")
  12097        (if (web-mode-looking-at-p "<!--#if" pos)
  12098            (web-mode-tag-fetch-closing regexp pos)
  12099            (web-mode-tag-fetch-opening regexp pos))
  12100        )
  12101       (t
  12102        (setq name (get-text-property pos 'tag-name))
  12103        (when (string= name "_fragment_") (setq name ">"))
  12104        (setq regexp (concat "</?" name))
  12105        (when (member (get-text-property pos 'tag-type) '(start end))
  12106          (web-mode-tag-beginning)
  12107          (setq pos (point)))
  12108        (if (eq (get-text-property pos 'tag-type) 'end)
  12109            (web-mode-tag-fetch-opening regexp pos)
  12110            (web-mode-tag-fetch-closing regexp pos))
  12111        ) ;t
  12112       ) ;cond
  12113     t))
  12114 
  12115 (defun web-mode-tag-fetch-opening (regexp pos)
  12116   (let ((counter 1) (n 0) (is-comment nil) (types '(start end)))
  12117     (when (eq (aref regexp 1) ?\!)
  12118       (setq types '(comment)
  12119             is-comment t))
  12120     (goto-char pos)
  12121     (while (and (> counter 0) (re-search-backward regexp nil t))
  12122       (when (and (get-text-property (point) 'tag-beg)
  12123                  (member (get-text-property (point) 'tag-type) types))
  12124         (setq n (1+ n))
  12125         (cond
  12126           ((and is-comment
  12127                 (eq (aref (match-string-no-properties 0) 5) ?e))
  12128            (setq counter (1+ counter)))
  12129           (is-comment
  12130            (setq counter (1- counter)))
  12131           ((eq (get-text-property (point) 'tag-type) 'end)
  12132            (setq counter (1+ counter)))
  12133           (t
  12134            (setq counter (1- counter))
  12135            )
  12136           )
  12137         )
  12138       )
  12139     (if (= n 0) (goto-char pos))
  12140     ))
  12141 
  12142 (defun web-mode-tag-fetch-closing (regexp pos)
  12143   (let ((counter 1) (is-comment nil) (n 0))
  12144     (when (eq (aref regexp 1) ?\!)
  12145       (setq is-comment t))
  12146     (goto-char pos)
  12147     (web-mode-tag-end)
  12148     (while (and (> counter 0) (re-search-forward regexp nil t))
  12149       (when (get-text-property (match-beginning 0) 'tag-beg)
  12150         (setq n (1+ n))
  12151         (cond
  12152           ((and is-comment
  12153                 (eq (aref (match-string-no-properties 0) 5) ?e))
  12154            (setq counter (1- counter)))
  12155           (is-comment
  12156            (setq counter (1+ counter)))
  12157           ((eq (get-text-property (point) 'tag-type) 'end)
  12158            (setq counter (1- counter)))
  12159           (t
  12160            (setq counter (1+ counter)))
  12161           )
  12162         ) ;when
  12163       ) ;while
  12164     (if (> n 0)
  12165         (web-mode-tag-beginning)
  12166         (goto-char pos))
  12167     ))
  12168 
  12169 (defun web-mode-element-tag-name (&optional pos)
  12170   (unless pos (setq pos (point)))
  12171   (save-excursion
  12172     (goto-char pos)
  12173     (if (and (web-mode-tag-beginning)
  12174              (looking-at web-mode-tag-regexp))
  12175         (match-string-no-properties 1)
  12176         nil)))
  12177 
  12178 (defun web-mode-element-close ()
  12179   "Close html element."
  12180   (interactive)
  12181   (let (jmp epp ins tag)
  12182 
  12183     (if (and (eq (char-before) ?\>)
  12184              (web-mode-element-is-void (get-text-property (1- (point)) 'tag-name)))
  12185         (unless (eq (char-before (1- (point))) ?\/)
  12186           (backward-char)
  12187           (insert "/")
  12188           (forward-char))
  12189         (setq epp (web-mode-element-parent-position)))
  12190 
  12191     ;;(message "epp=%S" epp)
  12192     (when epp
  12193       (setq tag (get-text-property epp 'tag-name))
  12194       (setq tag (web-mode-element-tag-name epp))
  12195       ;;(message "tag=%S %c" tag (char-before))
  12196       (cond
  12197         ((or (null tag) (web-mode-element-is-void tag))
  12198          (setq epp nil))
  12199         ((looking-back "</" (point-min))
  12200          (setq ins tag))
  12201         ((looking-back "<" (point-min))
  12202          (setq ins (concat "/" tag)))
  12203         (t
  12204          ;;auto-close-style = 2
  12205          ;;(message "%S %c" (point) (char-after))
  12206          (when (and (looking-at-p "[[:alpha:]]") (> (length tag) 4))
  12207            (dolist (elt '("div" "span" "strong" "pre" "li"))
  12208              (when (and (string-match-p (concat "^" elt) tag) (not (string= tag elt)))
  12209                (setq tag elt)
  12210                (put-text-property epp (point) 'tag-name tag))
  12211              )
  12212            ) ;when
  12213          (if (web-mode-element-is-void (get-text-property (point) 'tag-name))
  12214              (setq ins nil
  12215                    epp nil)
  12216              (setq ins (concat "</" tag)))
  12217          )
  12218         ) ;cond
  12219       (when ins
  12220         (unless (looking-at-p "[ ]*>")
  12221           (setq ins (concat ins ">")))
  12222         (insert ins)
  12223         (setq tag (downcase tag))
  12224         (save-excursion
  12225           (search-backward "<")
  12226           (setq jmp (and (eq (char-before) ?\>)
  12227                          (string= (get-text-property (1- (point)) 'tag-name) tag)))
  12228           (if jmp (setq jmp (point)))
  12229           ) ;save-excursion
  12230         (if jmp (goto-char jmp))
  12231         ) ;when not ins
  12232       ) ;when epp
  12233     epp))
  12234 
  12235 (defun web-mode-detect-content-type ()
  12236   (cond
  12237     ((and (string= web-mode-engine "none")
  12238           (< (point) 16)
  12239           (eq (char-after 1) ?\#)
  12240           (string-match-p "php" (buffer-substring-no-properties
  12241                                  (line-beginning-position)
  12242                                  (line-end-position))))
  12243      (web-mode-set-engine "php"))
  12244     ((and (string= web-mode-content-type "javascript")
  12245           (< (point) web-mode-chunk-length)
  12246           (eq (char-after (point-min)) ?\/)
  12247           (string-match-p "@jsx" (buffer-substring-no-properties
  12248                                   (line-beginning-position)
  12249                                   (line-end-position))))
  12250      (web-mode-set-content-type "jsx"))
  12251     ))
  12252 
  12253 (defun web-mode-auto-complete ()
  12254   "Autocomple at point."
  12255   (interactive)
  12256   (let ((pos (point))
  12257         (char (char-before))
  12258         (chunk (buffer-substring-no-properties (- (point) 2) (point)))
  12259         (expanders nil) (tag nil)
  12260         (auto-closed   nil)
  12261         (auto-expanded nil)
  12262         (auto-paired   nil)
  12263         (auto-quoted   nil))
  12264 
  12265     ;;-- auto-closing
  12266     (when web-mode-enable-auto-closing
  12267 
  12268       (cond
  12269 
  12270         ((and (= web-mode-auto-close-style 3)
  12271               (eq char ?\<))
  12272          (insert "/>")
  12273          (backward-char 2)
  12274          (setq auto-closed t))
  12275 
  12276         ((and (= web-mode-auto-close-style 3)
  12277               (eq char ?\>)
  12278               (looking-at-p "/>"))
  12279          (save-excursion
  12280            (re-search-backward web-mode-start-tag-regexp)
  12281            (setq tag (match-string-no-properties 1)))
  12282          (insert "<")
  12283          (forward-char)
  12284          (insert tag)
  12285          (setq auto-closed t))
  12286 
  12287         ((and (>= pos 4)
  12288               (or (string= "</" chunk)
  12289                   ;;(progn (message "%c" char) nil)
  12290                   (and (= web-mode-auto-close-style 2)
  12291                        (or (string= web-mode-content-type "jsx")
  12292                            (not (get-text-property pos 'part-side)))
  12293                        (string-match-p "[[:alnum:]'\"]>" chunk)))
  12294               (not (get-text-property (- pos 2) 'block-side))
  12295               (web-mode-element-close))
  12296          (setq auto-closed t))
  12297 
  12298         ) ;cond
  12299       ) ;when
  12300 
  12301     ;;-- auto-pairing
  12302     (when (and web-mode-enable-auto-pairing
  12303                (>= pos 4)
  12304                (not auto-closed))
  12305       (let ((i 0) expr after pos-end (l (length web-mode-auto-pairs)))
  12306         (setq pos-end (if (> (+ pos 32) (line-end-position))
  12307                           (line-end-position)
  12308                           (+ pos 10)))
  12309         (setq chunk (buffer-substring-no-properties (- pos 3) pos)
  12310               after (buffer-substring-no-properties pos pos-end))
  12311         (while (and (< i l) (not auto-paired))
  12312           (setq expr (elt web-mode-auto-pairs i)
  12313                 i (1+ i))
  12314           ;;(message "chunk=%S expr=%S after=%S" chunk expr after)
  12315           (when (and (string= (car expr) chunk)
  12316                      (not (string-match-p (regexp-quote (cdr expr)) after)))
  12317             (setq auto-paired t)
  12318             (insert (cdr expr))
  12319             (if (string-match-p "|" (cdr expr))
  12320                 (progn
  12321                   (search-backward "|")
  12322                   (delete-char 1))
  12323                 (goto-char pos))
  12324             ) ;when
  12325           ) ;while
  12326         ) ;let
  12327       )
  12328 
  12329     ;;-- auto-expanding
  12330     (when (and web-mode-enable-auto-expanding
  12331                (not auto-closed)
  12332                (not auto-paired)
  12333                (eq char ?\/)
  12334                (looking-back "\\(^\\|[[:punct:][:space:]>]\\)./" (point-min))
  12335                (or (web-mode-jsx-is-html (1- pos))
  12336                    (and (not (get-text-property (1- pos) 'tag-type))
  12337                         (not (get-text-property (1- pos) 'part-side))))
  12338                (not (get-text-property (1- pos) 'block-side))
  12339                )
  12340       (setq expanders (append web-mode-extra-expanders web-mode-expanders))
  12341       (let ((i 0) pair (l (length expanders)))
  12342         (setq chunk (buffer-substring-no-properties (- pos 2) pos))
  12343         ;;(message "%S" chunk)
  12344         (while (and (< i l) (not auto-expanded))
  12345           (setq pair (elt expanders i)
  12346                 i (1+ i))
  12347           (when (string= (car pair) chunk)
  12348             (setq auto-expanded t)
  12349             (delete-char -2)
  12350             (insert (cdr pair))
  12351             (when (string-match-p "|" (cdr pair))
  12352               (search-backward "|")
  12353               (delete-char 1))
  12354             ) ;when
  12355           ) ;while
  12356         ) ;let
  12357       )
  12358 
  12359     ;;-- auto-quoting
  12360     (when (and web-mode-enable-auto-quoting
  12361                (>= pos 4)
  12362                (not (get-text-property pos 'block-side))
  12363                (not auto-closed)
  12364                (not auto-paired)
  12365                (not auto-expanded)
  12366                (get-text-property (- pos 2) 'tag-attr))
  12367       (cond
  12368         ((and (eq char ?\=)
  12369               (not (looking-at-p "[ ]*[\"']")))
  12370          (cond ((= web-mode-auto-quote-style 2)
  12371                 (insert "''"))
  12372                ((= web-mode-auto-quote-style 3)
  12373                 (insert "{}"))
  12374                (t
  12375                 (insert "\"\"")))
  12376          (if (looking-at-p "[ \n>]")
  12377              (backward-char)
  12378              (insert " ")
  12379              (backward-char 2)
  12380              )
  12381          (setq auto-quoted t))
  12382         ((and (eq char ?\")
  12383               (looking-back "=[ ]*\"" (point-min))
  12384               (not (looking-at-p "[ ]*[\"]")))
  12385          (insert-and-inherit "\"")
  12386          (backward-char)
  12387          (setq auto-quoted t))
  12388         ((and (eq char ?\')
  12389               (looking-back "=[ ]*'" (point-min))
  12390               (not (looking-at-p "[ ]*[']")))
  12391          (insert-and-inherit "'")
  12392          (backward-char)
  12393          (setq auto-quoted t))
  12394         ((and (eq char ?\{)
  12395               (eq (get-text-property pos 'part-side) 'jsx)
  12396               (looking-back "=[ ]*{" (point-min))
  12397               (not (looking-at-p "[ ]*[}]")))
  12398          (insert-and-inherit "}")
  12399          (backward-char)
  12400          (setq auto-quoted t))
  12401         ((and (eq char ?\")
  12402               (eq (char-after) ?\"))
  12403          (delete-char 1)
  12404          (cond
  12405            ((looking-back "=\"\"" (point-min))
  12406             (backward-char))
  12407            ((eq (char-after) ?\s)
  12408             (forward-char))
  12409            (t
  12410             (insert " "))
  12411            ) ;cond
  12412          )
  12413         ) ;cond
  12414       ) ;when
  12415 
  12416     ;;--
  12417     (cond
  12418       ((or auto-closed auto-paired auto-expanded auto-quoted)
  12419        (when (and web-mode-change-end (>= (line-end-position) web-mode-change-end))
  12420          (setq web-mode-change-end (line-end-position)))
  12421        (list :auto-closed auto-closed
  12422              :auto-paired auto-paired
  12423              :auto-expanded auto-expanded
  12424              :auto-quoted auto-quoted))
  12425       (t
  12426        nil)
  12427       )
  12428 
  12429     ))
  12430 
  12431 (defun web-mode-dom-xpath (&optional pos)
  12432   "Display html path."
  12433   (interactive)
  12434   (unless pos (setq pos (point)))
  12435   (save-excursion
  12436     (goto-char pos)
  12437     (let (path tag)
  12438       (while (web-mode-element-parent)
  12439         (looking-at web-mode-tag-regexp)
  12440         (setq tag (match-string-no-properties 1))
  12441         (setq path (cons tag path))
  12442         )
  12443       (message "/%s" (mapconcat 'identity path "/"))
  12444       )))
  12445 
  12446 (defun web-mode-block-ends-with (regexp &optional pos)
  12447   (unless pos (setq pos (point)))
  12448   (save-excursion
  12449     (goto-char pos)
  12450     (save-match-data
  12451       (if (stringp regexp)
  12452           (and (web-mode-block-end)
  12453                (progn (backward-char) t)
  12454                (web-mode-block-skip-blank-backward)
  12455                (progn (forward-char) t)
  12456                (looking-back regexp (point-min)))
  12457           (let ((pair regexp)
  12458                 (block-beg (web-mode-block-beginning-position pos))
  12459                 (block-end (web-mode-block-end-position pos)))
  12460             (and (web-mode-block-end)
  12461                  (web-mode-block-sb (car pair) block-beg)
  12462                  (not (web-mode-sf (cdr pair) block-end)))
  12463             ) ;let
  12464           ) ;if
  12465       )))
  12466 
  12467 (defun web-mode-block-token-starts-with (regexp &optional pos)
  12468   (unless pos (setq pos (point)))
  12469   (save-excursion
  12470     (and (goto-char pos)
  12471          (web-mode-block-token-beginning)
  12472          (skip-chars-forward "[\"']")
  12473          (looking-at regexp))
  12474     ))
  12475 
  12476 (defun web-mode-block-starts-with (regexp &optional pos)
  12477   (unless pos (setq pos (point)))
  12478   (save-excursion
  12479     (and (web-mode-block-beginning)
  12480          (web-mode-block-skip-blank-forward)
  12481          (looking-at regexp))
  12482     ))
  12483 
  12484 (defun web-mode-block-skip-blank-backward (&optional pos)
  12485   (unless pos (setq pos (point)))
  12486   (let ((continue t))
  12487     (goto-char pos)
  12488     (while continue
  12489       (if (and (get-text-property (point) 'block-side)
  12490                (not (bobp))
  12491                (or (member (char-after) '(?\s ?\n))
  12492                    (member (get-text-property (point) 'block-token)
  12493                            '(delimiter-beg delimiter-end comment))))
  12494           (backward-char)
  12495           (setq continue nil))
  12496       ) ;while
  12497     (point)))
  12498 
  12499 (defun web-mode-block-skip-blank-forward (&optional pos props)
  12500   (unless pos (setq pos (point)))
  12501   (unless props (setq props '(delimiter-beg delimiter-end comment)))
  12502   (let ((continue t))
  12503     (goto-char pos)
  12504     (while continue
  12505       (if (and (get-text-property (point) 'block-side)
  12506                (or (member (char-after) '(?\s ?\n ?\t))
  12507                    (member (get-text-property (point) 'block-token) props)))
  12508           (forward-char)
  12509           (setq continue nil))
  12510       ) ;while
  12511     (point)))
  12512 
  12513 (defun web-mode-tag-attributes-sort (&optional pos)
  12514   "Sort the attributes inside the current html tag."
  12515   (interactive)
  12516   (unless pos (setq pos (point)))
  12517   (save-excursion
  12518     (let (attrs (continue t) min max tag-beg tag-end attr attr-name attr-beg attr-end indent sorter ins)
  12519       (if (not (member (get-text-property pos 'tag-type) '(start void)))
  12520           nil
  12521           (setq tag-beg (web-mode-tag-beginning-position pos)
  12522                 tag-end (web-mode-tag-end-position))
  12523           ;;        (message "%S %S" tag-beg tag-end)
  12524           (goto-char tag-beg)
  12525           (while continue
  12526             (if (or (not (web-mode-attribute-next))
  12527                     (>= (point) tag-end))
  12528                 (setq continue nil)
  12529                 ;;(message "attr=%S" (point))
  12530                 (setq attr-beg (web-mode-attribute-beginning-position)
  12531                       attr-end (1+ (web-mode-attribute-end-position)))
  12532                 (when (null min)
  12533                   (setq min attr-beg))
  12534                 (setq max attr-end)
  12535                 (goto-char attr-beg)
  12536                 (setq attr (buffer-substring-no-properties attr-beg attr-end))
  12537                 (if (string-match "^\\([[:alnum:]-]+\\)=" attr)
  12538                     (setq attr-name (match-string-no-properties 1 attr))
  12539                     (setq attr-name attr))
  12540                 (setq indent (looking-back "^[ \t]*" (point-min)))
  12541                 (setq attrs (append attrs (list (list attr-beg attr-end attr-name attr indent))))
  12542                 ) ;if
  12543             ) ;while
  12544           ) ;if in tag
  12545       (when attrs
  12546         (setq sorter (function
  12547                       (lambda (elt1 elt2)
  12548                        (string< (nth 2 elt1) (nth 2 elt2))
  12549                        )))
  12550         (setq attrs (sort attrs sorter))
  12551         (delete-region (1- min) max)
  12552         (setq ins "")
  12553         (dolist (elt attrs)
  12554           (if (and (nth 4 elt) (> (length ins) 1))
  12555               (setq ins (concat ins "\n"))
  12556               (setq ins (concat ins " ")))
  12557           (setq ins (concat ins (nth 3 elt)))
  12558           )
  12559         (goto-char (1- min))
  12560         (insert ins)
  12561         (web-mode-tag-beginning)
  12562         (setq min (line-beginning-position))
  12563         (web-mode-tag-end)
  12564         (setq max (line-end-position))
  12565         (indent-region min max)
  12566         )
  12567       ;;(message "attrs=%S" attrs)
  12568       )))
  12569 
  12570 (defun web-mode-attribute-insert (&optional _attr-name _attr-value)
  12571   "Insert an attribute inside current tag."
  12572   (interactive)
  12573   (let (attr attr-name attr-value)
  12574     (cond
  12575       ((not (member (get-text-property (point) 'tag-type) '(start void)))
  12576        (message "attribute-insert ** invalid context **"))
  12577       ((not (and (setq attr-name (or attr-name (completing-read
  12578                                                 "Attribute name: "
  12579                                                 (append
  12580                                                  web-mode-attribute-list
  12581                                                  web-mode-attribute-history)
  12582                                                 nil nil nil 'web-mode-attribute-history)))
  12583                  (> (length attr-name) 0)))
  12584        (message "attribute-insert ** failure **"))
  12585       (t
  12586        (setq attr (concat " " attr-name))
  12587        (when (setq attr-value (or attr-value (completing-read
  12588                                               "Attribute value: "
  12589                                               web-mode-attribute-value-history
  12590                                               nil nil nil 'web-mode-attribute-value-history)))
  12591          (setq attr (concat attr "=\"" attr-value "\"")))
  12592        (web-mode-tag-end)
  12593        (if (looking-back "/>" (point-min))
  12594            (backward-char 2)
  12595            (backward-char))
  12596        (insert attr)
  12597        ) ;t
  12598       ) ;cond
  12599     ))
  12600 
  12601 (defun web-mode-attribute-transpose (&optional pos)
  12602   "Transpose the current html attribute."
  12603   (interactive)
  12604   (unless pos (setq pos (point)))
  12605   (let (attr-beg attr-end next-beg next-end tag-end)
  12606     (when (and (get-text-property pos 'tag-attr)
  12607                (setq next-beg (web-mode-attribute-next-position pos))
  12608                (setq next-end (web-mode-attribute-end-position next-beg))
  12609                (setq tag-end (web-mode-tag-end-position pos))
  12610                (> tag-end next-end))
  12611       (setq attr-beg (web-mode-attribute-beginning-position pos)
  12612             attr-end (web-mode-attribute-end-position pos))
  12613       ;;      (message "%S %S - %S %S" attr-beg attr-end next-beg next-end)
  12614       (transpose-regions attr-beg (1+ attr-end) next-beg (1+ next-end))
  12615       )))
  12616 
  12617 (defun web-mode-attribute-select (&optional pos)
  12618   "Select the current html attribute."
  12619   (interactive)
  12620   (unless pos (setq pos (point)))
  12621   (if (null (get-text-property pos 'tag-attr))
  12622       nil
  12623       (goto-char pos)
  12624       (web-mode-attribute-beginning)
  12625       (set-mark (point))
  12626       (web-mode-attribute-end)
  12627       (exchange-point-and-mark)
  12628       (point)
  12629       ))
  12630 
  12631 (defun web-mode-attribute-kill (&optional arg)
  12632   "Kill the current html attribute."
  12633   (interactive "p")
  12634   (unless arg (setq arg 1))
  12635   (while (>= arg 1)
  12636     (setq arg (1- arg))
  12637     (web-mode-attribute-select)
  12638     (when mark-active
  12639       (let ((beg (region-beginning)) (end (region-end)))
  12640         (save-excursion
  12641           (goto-char end)
  12642           (when (looking-at "[ \n\t]*")
  12643             (setq end (+ end (length (match-string-no-properties 0)))))
  12644           ) ;save-excursion
  12645         (kill-region beg end)
  12646         ) ;let
  12647       ) ;when
  12648     ) ;while
  12649   ;; Delete a potential space before the closing ">".
  12650   (when (and (looking-at ">")
  12651              (looking-back " " (point-min)))
  12652     (delete-char -1))
  12653   )
  12654 
  12655 (defun web-mode-block-close (&optional pos)
  12656   "Close the first unclosed control block."
  12657   (interactive)
  12658   (unless pos (setq pos (point)))
  12659   (let ((continue t)
  12660         (h (make-hash-table :test 'equal)) ctx ctrl n closing-block)
  12661     (save-excursion
  12662       (while (and continue (web-mode-block-previous))
  12663         (when (setq ctx (web-mode-block-is-control (point)))
  12664           (setq ctrl (car ctx))
  12665           (setq n (gethash ctrl h 0))
  12666           (if (cdr ctx)
  12667               (puthash ctrl (1+ n) h)
  12668               (puthash ctrl (1- n) h))
  12669           (when (> (gethash ctrl h) 0)
  12670             (setq continue nil))
  12671           )
  12672         ) ;while
  12673       ) ;save-excursion
  12674     (when (and (null continue)
  12675                (setq closing-block (web-mode-closing-block ctrl)))
  12676       (insert closing-block)
  12677       (indent-according-to-mode))
  12678     ))
  12679 
  12680 (defun web-mode-closing-block (type)
  12681   (cond
  12682     ((string= web-mode-engine "php")              (concat "<?php end" type "; ?>"))
  12683     ((string= web-mode-engine "django")           (concat "{% end" type " %}"))
  12684     ((string= web-mode-engine "antlers")          (concat "{{/" type "}}"))
  12685     ((string= web-mode-engine "ctemplate")        (concat "{{/" type "}}"))
  12686     ((string= web-mode-engine "blade")
  12687      (if (string= type "section") (concat "@show") (concat "@end" type)))
  12688     ((string= web-mode-engine "dust")             (concat "{/" type "}"))
  12689     ((string= web-mode-engine "mako")             (concat "% end" type))
  12690     ((string= web-mode-engine "closure")          (concat "{/" type "}"))
  12691     ((string= web-mode-engine "smarty")           (concat "{/" type "}"))
  12692     ((string= web-mode-engine "expressionengine") (concat "{/" type "}"))
  12693     ((string= web-mode-engine "xoops")            (concat "<{/" type "}>"))
  12694     ((string= web-mode-engine "svelte")           (concat "{/" type "}"))
  12695     ((string= web-mode-engine "underscore")        "<% } %>")
  12696     ((string= web-mode-engine "lsp")               "<% ) %>")
  12697     ((string= web-mode-engine "erb")               "<% } %>")
  12698     ((string= web-mode-engine "erb")               "<% end %>")
  12699     ((string= web-mode-engine "artanis")           "<% ) %>")
  12700     ((string= web-mode-engine "hero")              "<% } %>")
  12701     ((string= web-mode-engine "go")                "{{end}}")
  12702     ((string= web-mode-engine "velocity")          "#end")
  12703     ((string= web-mode-engine "velocity")          "#{end}")
  12704     ((string= web-mode-engine "template-toolkit")  "[% end %]")
  12705     ((member web-mode-engine '("asp" "jsp"))
  12706      (if (string-match-p "[:.]" type) (concat "</" type ">") "<% } %>"))
  12707     (t nil)
  12708     ) ;cond
  12709   )
  12710 
  12711 ;;---- POSITION ----------------------------------------------------------------
  12712 
  12713 (defun web-mode-comment-beginning-position (&optional pos)
  12714   (unless pos (setq pos (point)))
  12715   (car (web-mode-comment-boundaries pos)))
  12716 
  12717 (defun web-mode-comment-end-position (&optional pos)
  12718   (unless pos (setq pos (point)))
  12719   (cdr (web-mode-comment-boundaries pos)))
  12720 
  12721 (defun web-mode-part-opening-paren-position (pos &optional limit)
  12722   (save-restriction
  12723     (unless limit (setq limit nil))
  12724     (goto-char pos)
  12725     (let* ((n -1)
  12726            (paren (char-after))
  12727            (pairs '((?\) . "[)(]")
  12728                     (?\] . "[\]\[]")
  12729                     (?\} . "[}{]")
  12730                     (?\> . "[><]")))
  12731            (regexp (cdr (assoc paren pairs)))
  12732            (continue (not (null regexp)))
  12733            (counter 0))
  12734       (while (and continue (re-search-backward regexp limit t))
  12735         (cond
  12736           ((> (setq counter (1+ counter)) 500)
  12737            (message "part-opening-paren-position ** warning **")
  12738            (setq continue nil))
  12739           ((or (web-mode-is-comment-or-string)
  12740                (get-text-property (point) 'block-side))
  12741            )
  12742           ((eq (char-after) paren)
  12743            (setq n (1- n)))
  12744           (t
  12745            (setq n (1+ n))
  12746            (setq continue (not (= n 0))))
  12747           )
  12748         ) ;while
  12749       (if (= n 0) (point) nil)
  12750       )))
  12751 
  12752 (defun web-mode-token-opening-paren-position (pos limit _context)
  12753   (save-restriction
  12754     (unless limit (setq limit nil))
  12755     (goto-char pos)
  12756     (let* ((n -1)
  12757            (paren (char-after))
  12758            (pairs '((?\) . "[)(]")
  12759                     (?\] . "[\]\[]")
  12760                     (?\} . "[}{]")
  12761                     (?\> . "[><]")))
  12762            (regexp (cdr (assoc paren pairs)))
  12763            (continue (not (null regexp)))
  12764            (counter 0))
  12765       (while (and continue (re-search-backward regexp limit t))
  12766         (cond
  12767           ((> (setq counter (1+ counter)) 200)
  12768            (message "token-opening-paren-position ** warning **")
  12769            (setq continue nil))
  12770           ((get-text-property (point) 'block-side)
  12771            )
  12772           ((eq (char-after) paren)
  12773            (setq n (1- n)))
  12774           (t
  12775            (setq n (1+ n))
  12776            (setq continue (not (= n 0))))
  12777           )
  12778         ) ;while
  12779       (if (= n 0) (point) nil)
  12780       )))
  12781 
  12782 (defun web-mode-closing-paren-position (&optional pos limit)
  12783   (save-excursion
  12784     (unless pos (setq pos (point)))
  12785     (unless limit (setq limit nil))
  12786     (goto-char pos)
  12787     (let* ((n 0)
  12788            (block-side (and (get-text-property pos 'block-side)
  12789                             (not (string= web-mode-engine "razor"))))
  12790            (paren (char-after))
  12791            (pairs '((?\( . "[)(]")
  12792                     (?\[ . "[\]\[]")
  12793                     (?\{ . "[}{]")
  12794                     (?\< . "[><]")))
  12795            (regexp (cdr (assoc paren pairs)))
  12796            (continue (not (null regexp))))
  12797       (while (and continue (re-search-forward regexp limit t))
  12798         (cond
  12799           ((or (web-mode-is-comment-or-string (1- (point)))
  12800                (and block-side (not (get-text-property (point) 'block-side))))
  12801            ;;(message "pt=%S" (point))
  12802            )
  12803           ((eq (char-before) paren)
  12804            (setq n (1+ n)))
  12805           (t
  12806            (setq n (1- n))
  12807            (setq continue (not (= n 0)))
  12808            )
  12809           ) ;cond
  12810         ) ;while
  12811       (if (= n 0) (1- (point)) nil)
  12812       )))
  12813 
  12814 (defun web-mode-closing-delimiter-position (delimiter &optional pos limit)
  12815   (unless pos (setq pos (point)))
  12816   (unless limit (setq limit nil))
  12817   (save-excursion
  12818     (goto-char pos)
  12819     (setq pos nil)
  12820     (let ((continue t))
  12821       (while (and continue (re-search-forward delimiter limit t))
  12822         (setq continue nil
  12823               pos (1- (point)))
  12824         ) ;while
  12825       pos)))
  12826 
  12827 (defun web-mode-tag-match-position (&optional pos)
  12828   (unless pos (setq pos (point)))
  12829   (save-excursion
  12830     (web-mode-tag-match pos)
  12831     (if (= pos (point)) nil (point))))
  12832 
  12833 (defun web-mode-tag-beginning-position (&optional pos)
  12834   (unless pos (setq pos (point)))
  12835   (let (beg depth)
  12836     (setq depth (get-text-property pos 'jsx-depth))
  12837     (when (and depth (get-text-property pos 'tag-attr-beg))
  12838       (setq depth (get-text-property (1- pos) 'jsx-depth)))
  12839     (cond
  12840       ((null pos))
  12841       ((get-text-property pos 'tag-beg)
  12842        (setq beg pos))
  12843       ((and (> pos 1) (get-text-property (1- pos) 'tag-beg))
  12844        (setq beg (1- pos)))
  12845       ((get-text-property pos 'tag-type)
  12846        (setq beg (previous-single-property-change pos 'tag-beg))
  12847        (when beg (setq beg (1- beg)))
  12848        (cond
  12849          ((not (get-text-property beg 'tag-beg))
  12850           (setq beg nil))
  12851          ((and depth (not (eq depth (get-text-property beg 'jsx-depth))))
  12852           (let ((continue (> beg (point-min))))
  12853             (while continue
  12854               (setq beg (previous-single-property-change beg 'tag-beg))
  12855               (when beg (setq beg (1- beg)))
  12856               (cond
  12857                 ((null beg)
  12858                  (setq continue nil))
  12859                 ((not (get-text-property beg 'tag-beg))
  12860                  (setq continue nil
  12861                        beg nil))
  12862                 ((eq depth (get-text-property beg 'jsx-depth))
  12863                  (setq continue nil))
  12864                 ) ;cond
  12865               ) ;while
  12866             ) ;let
  12867           )
  12868          ) ;cond
  12869        )
  12870       (t
  12871        (setq beg nil))
  12872       ) ;cond
  12873     beg))
  12874 
  12875 (defun web-mode-tag-end-position (&optional pos)
  12876   (unless pos (setq pos (point)))
  12877   (let (end depth)
  12878     (setq depth (get-text-property pos 'jsx-depth))
  12879     (when (and depth (get-text-property pos 'tag-attr-beg))
  12880       (setq depth (get-text-property (1- pos) 'jsx-depth)))
  12881     (cond
  12882       ((null pos)
  12883        (setq end nil))
  12884       ((get-text-property pos 'tag-end)
  12885        (setq end pos))
  12886       ((get-text-property pos 'tag-type)
  12887        (setq end (next-single-property-change pos 'tag-end))
  12888        (cond
  12889          ((not (get-text-property end 'tag-end))
  12890           (setq end nil))
  12891          ((and depth (not (eq depth (get-text-property end 'jsx-depth))))
  12892           (let ((continue (< end (point-max))))
  12893             (while continue
  12894               (setq end (1+ end))
  12895               (setq end (next-single-property-change end 'tag-end))
  12896               (cond
  12897                 ((null end)
  12898                  (setq continue nil))
  12899                 ((not (get-text-property end 'tag-end))
  12900                  (setq continue nil
  12901                        end nil))
  12902                 ((eq depth (get-text-property end 'jsx-depth))
  12903                  (setq continue nil))
  12904                 ) ;cond
  12905               ) ;while
  12906             ) ;let
  12907           )
  12908          ) ;cond
  12909        )
  12910       (t
  12911        (setq end nil))
  12912       ) ;cond
  12913     end))
  12914 
  12915 ;; TODO: prendre en compte jsx-depth
  12916 (defun web-mode-tag-next-position (&optional pos limit)
  12917   (unless pos (setq pos (point)))
  12918   (unless limit (setq limit (point-max)))
  12919   (cond
  12920     ((or (>= pos (point-max)) (>= pos limit)) nil)
  12921     (t
  12922      (when (get-text-property pos 'tag-beg) (setq pos (1+ pos)))
  12923      (setq pos (next-single-property-change pos 'tag-beg))
  12924      (if (and pos (<= pos limit)) pos nil))
  12925     ))
  12926 
  12927 ;; TODO: prendre en compte jsx-depth
  12928 (defun web-mode-tag-previous-position (&optional pos limit)
  12929   (unless pos (setq pos (point)))
  12930   (unless limit (setq limit (point-min)))
  12931   (cond
  12932     ((or (<= pos (point-min)) (<= pos limit)) nil)
  12933     (t
  12934      (when (get-text-property pos 'tag-beg) (setq pos (1- pos)))
  12935      (web-mode-go (previous-single-property-change pos 'tag-beg) -1))
  12936     ))
  12937 
  12938 ;; TODO: prendre en compte jsx-depth
  12939 (defun web-mode-attribute-beginning-position (&optional pos)
  12940   (unless pos (setq pos (point)))
  12941   (cond
  12942     ((null (get-text-property pos 'tag-attr))
  12943      nil)
  12944     ((get-text-property pos 'tag-attr-beg)
  12945      pos)
  12946     ((and (> pos (point-min)) (get-text-property (1- pos) 'tag-attr-beg))
  12947      (1- pos))
  12948     (t
  12949      (setq pos (previous-single-property-change pos 'tag-attr-beg))
  12950      (setq pos (1- pos)))
  12951     ))
  12952 
  12953 ;; TODO: retoucher en incluant un param limit et en s'inspirant de
  12954 ;;       web-mode-attribute-next-position
  12955 (defun web-mode-attribute-end-position (&optional pos)
  12956   (unless pos (setq pos (point)))
  12957   (let (beg end depth flags)
  12958     ;;(message "pos=%S" pos)
  12959     (setq depth (get-text-property pos 'jsx-depth))
  12960     (cond
  12961       ((null pos)
  12962        (setq end nil))
  12963       ((get-text-property pos 'tag-attr-end)
  12964        (setq end pos))
  12965       ((get-text-property pos 'tag-attr)
  12966        (setq end (next-single-property-change pos 'tag-attr-end))
  12967        (when (and depth
  12968                   end
  12969                   (setq beg (web-mode-attribute-beginning-position end))
  12970                   (setq flags (get-text-property pos 'tag-attr-beg))
  12971                   (eq (logand flags 4) 4))
  12972          (setq depth (1- (get-text-property beg 'jsx-depth)))
  12973          ;;(message "%S %S" beg end)
  12974          )
  12975        (cond
  12976          ((not (get-text-property end 'tag-attr-end))
  12977           (setq end nil))
  12978          ((and depth
  12979                (eq depth (get-text-property end 'jsx-depth))
  12980                (not (eq depth (get-text-property end 'jsx-end))))
  12981           )
  12982          ((and depth (eq (1+ depth) (get-text-property end 'jsx-depth)))
  12983           )
  12984          ((and depth (not (eq (1+ depth) (get-text-property end 'jsx-depth))))
  12985           (let ((continue (< end (point-max))))
  12986             (while continue
  12987               (setq end (1+ end))
  12988               (setq end (next-single-property-change end 'tag-attr-end))
  12989               (cond
  12990                 ((null end)
  12991                  (setq continue nil))
  12992                 ((not (get-text-property end 'tag-attr-end))
  12993                  (setq continue nil
  12994                        end nil))
  12995                 ((eq (1+ depth) (get-text-property end 'jsx-depth))
  12996                  (setq continue nil))
  12997                 ) ;cond
  12998               ) ;while
  12999             ) ;let
  13000           )
  13001          ) ;cond
  13002        )
  13003       (t
  13004        (setq end nil))
  13005       ) ;cond
  13006     end))
  13007 
  13008 ;; attention si pos est au debut d'un spread attributes, cela
  13009 ;; risque de poser pb
  13010 (defun web-mode-attribute-next-position (&optional pos limit)
  13011   (unless pos (setq pos (point)))
  13012   (unless limit (setq limit (point-max)))
  13013   (let (continue depth)
  13014     (when (get-text-property pos 'tag-attr-beg)
  13015       (setq pos (1+ pos)))
  13016     (if (< pos limit)
  13017         (setq continue t
  13018               depth (get-text-property pos 'jsx-depth))
  13019         (setq continue nil
  13020               pos nil))
  13021     (while continue
  13022       (setq pos (next-single-property-change pos 'tag-attr-beg))
  13023       (cond
  13024         ((null pos)
  13025          (setq continue nil))
  13026         ((>= pos limit)
  13027          (setq continue nil
  13028                pos nil))
  13029         ((null depth)
  13030          (setq continue nil))
  13031         ((and (eq (get-text-property pos 'tag-attr-beg) 4)
  13032               (eq (1+ depth) (get-text-property pos 'jsx-depth)))
  13033          (setq continue nil))
  13034         ((eq depth (get-text-property pos 'jsx-depth))
  13035          (setq continue nil))
  13036         (t
  13037          (setq pos (1+ pos)
  13038                continue (< pos limit)))
  13039         )
  13040       ) ;while
  13041     pos))
  13042 
  13043 (defun web-mode-attribute-previous-position (&optional pos limit)
  13044   (unless pos (setq pos (point)))
  13045   (unless limit (setq limit (point-min)))
  13046   (let (continue depth)
  13047     (cond
  13048       ((and (> pos (point-min)) (get-text-property (1- pos) 'tag-attr-beg))
  13049        (setq pos (1- pos)
  13050              continue nil))
  13051       (t
  13052        (when (get-text-property pos 'tag-attr-beg)
  13053          (setq pos (1- pos)))
  13054        (if (> pos limit)
  13055            (setq continue t
  13056                  depth (get-text-property pos 'jsx-depth))
  13057            (setq continue nil
  13058                  pos nil))
  13059        ) ;t
  13060       ) ;cond
  13061     (while continue
  13062       (setq pos (previous-single-property-change pos 'tag-attr-beg))
  13063       (cond
  13064         ((null pos)
  13065          (setq continue nil))
  13066         ((< pos limit)
  13067          (setq continue nil
  13068                pos nil))
  13069         ;;((null depth)
  13070         ;; (setq continue nil))
  13071         ((and depth (eq depth (get-text-property pos 'jsx-depth)))
  13072          (setq  pos (1- pos)
  13073                 continue nil))
  13074         (depth
  13075          (setq pos nil
  13076                continue (> pos limit)))
  13077         (t
  13078          (setq pos (1- pos)
  13079                continue nil))
  13080         ) ;cond
  13081       ) ;while
  13082     pos))
  13083 
  13084 ;; TODO: prendre en compte jsx-depth
  13085 (defun web-mode-element-beginning-position (&optional pos)
  13086   (unless pos (setq pos (point)))
  13087   (cond
  13088     ((null (get-text-property pos 'tag-type))
  13089      (setq pos (web-mode-element-parent-position)))
  13090     ((eq (get-text-property pos 'tag-type) 'end)
  13091      (setq pos (web-mode-tag-match-position pos))
  13092      (setq pos (if (get-text-property pos 'tag-beg) pos nil)))
  13093     ((member (get-text-property pos 'tag-type) '(start void))
  13094      (setq pos (web-mode-tag-beginning-position pos)))
  13095     (t
  13096      (setq pos nil))
  13097     ) ;cond
  13098   pos)
  13099 
  13100 ;; TODO: prendre en compte jsx-depth
  13101 (defun web-mode-element-end-position (&optional pos)
  13102   (unless pos (setq pos (point)))
  13103   (cond
  13104     ((null (get-text-property pos 'tag-type))
  13105      (setq pos (web-mode-element-parent-position pos))
  13106      (when pos
  13107        (setq pos (web-mode-tag-match-position pos))
  13108        (when pos (setq pos (web-mode-tag-end-position pos)))
  13109        )
  13110      )
  13111     ((member (get-text-property pos 'tag-type) '(end void comment))
  13112      (setq pos (web-mode-tag-end-position pos))
  13113      )
  13114     ((member (get-text-property pos 'tag-type) '(start))
  13115      (setq pos (web-mode-tag-match-position pos))
  13116      (when pos (setq pos (web-mode-tag-end-position pos))))
  13117     (t
  13118      (setq pos nil))
  13119     ) ;cond
  13120   pos)
  13121 
  13122 (defun web-mode-element-child-position (&optional pos)
  13123   (save-excursion
  13124     (let (child close)
  13125       (unless pos (setq pos (point)))
  13126       (goto-char pos)
  13127       (cond
  13128         ((eq (get-text-property pos 'tag-type) 'start)
  13129          (web-mode-tag-match)
  13130          (setq close (point))
  13131          (goto-char pos)
  13132          )
  13133         ((eq (get-text-property pos 'tag-type) 'void)
  13134          )
  13135         ((eq (get-text-property pos 'tag-type) 'end)
  13136          (web-mode-tag-beginning)
  13137          (setq close (point))
  13138          (web-mode-tag-match)
  13139          )
  13140         ((web-mode-element-parent-position pos)
  13141          (setq pos (point))
  13142          (web-mode-tag-match)
  13143          (setq close (point))
  13144          (goto-char pos)
  13145          )
  13146         ) ;cond
  13147       (when (and close
  13148                  (web-mode-element-next)
  13149                  (< (point) close))
  13150         (setq child (point))
  13151         )
  13152       child)))
  13153 
  13154 (defun web-mode-element-parent-position (&optional pos)
  13155   (let (n tag-type tag-name (continue t) (tags (make-hash-table :test 'equal)))
  13156     (save-excursion
  13157       (if pos (goto-char pos))
  13158       (while (and continue (web-mode-tag-previous))
  13159         (setq pos (point)
  13160               tag-type (get-text-property pos 'tag-type)
  13161               tag-name (get-text-property pos 'tag-name)
  13162               n (gethash tag-name tags 0))
  13163         (when (member tag-type '(end start))
  13164           (if (eq tag-type 'end)
  13165               (puthash tag-name (1- n) tags)
  13166               (puthash tag-name (1+ n) tags)
  13167               (when (= n 0) (setq continue nil))
  13168               ) ;if
  13169           ) ;when
  13170         ) ;while
  13171       ) ;save-excursion
  13172     (if (null continue) pos nil)))
  13173 
  13174 (defun web-mode-element-previous-position (&optional pos limit)
  13175   (unless pos (setq pos (point)))
  13176   (unless limit (setq limit (point-min)))
  13177   (save-excursion
  13178     (goto-char pos)
  13179     (let ((continue (not (bobp)))
  13180           (props '(start void comment)))
  13181       (while continue
  13182         (setq pos (web-mode-tag-previous))
  13183         (cond
  13184           ((or (null pos) (< (point) limit))
  13185            (setq continue nil
  13186                  pos nil))
  13187           ((member (get-text-property (point) 'tag-type) props)
  13188            (setq continue nil))
  13189           )
  13190         ) ;while
  13191       pos)))
  13192 
  13193 (defun web-mode-element-next-position (&optional pos limit)
  13194   (unless pos (setq pos (point)))
  13195   (unless limit (setq limit (point-max)))
  13196   (save-excursion
  13197     (goto-char pos)
  13198     (let ((continue (not (eobp)))
  13199           (props '(start void comment)))
  13200       (while continue
  13201         (setq pos (web-mode-tag-next))
  13202         (cond
  13203           ((or (null pos) (> (point) limit))
  13204            (setq continue nil
  13205                  pos nil))
  13206           ((member (get-text-property (point) 'tag-type) props)
  13207            (setq continue nil))
  13208           )
  13209         ) ;while
  13210       ;;      (message "pos=%S" pos)
  13211       pos)))
  13212 
  13213 (defun web-mode-part-end-position (&optional pos)
  13214   (unless pos (setq pos (point)))
  13215   (cond
  13216     ((member web-mode-content-type web-mode-part-content-types)
  13217      (setq pos (point-max)))
  13218     ((not (get-text-property pos 'part-side))
  13219      (setq pos nil))
  13220     ((= pos (point-max))
  13221      (setq pos nil))
  13222     ((not (get-text-property (1+ pos) 'part-side))
  13223      pos)
  13224     (t
  13225      (setq pos (next-single-property-change pos 'part-side)))
  13226     ) ;cond
  13227   pos)
  13228 
  13229 (defun web-mode-part-beginning-position (&optional pos)
  13230   (unless pos (setq pos (point)))
  13231   (cond
  13232     (web-mode-part-beg
  13233      (setq pos web-mode-part-beg))
  13234     ((member web-mode-content-type web-mode-part-content-types)
  13235      (setq pos (point-min)
  13236            web-mode-part-beg (point-min)))
  13237     ((not (get-text-property pos 'part-side))
  13238      (setq pos nil))
  13239     ((= pos (point-min))
  13240      (setq pos nil))
  13241     ((not (get-text-property (1- pos) 'part-side))
  13242      pos)
  13243     (t
  13244      (setq pos (previous-single-property-change pos 'part-side)))
  13245     ) ;cond
  13246   pos)
  13247 
  13248 (defun web-mode-part-next-position (&optional pos)
  13249   (unless pos (setq pos (point)))
  13250   (cond
  13251     ((and (= pos (point-min)) (get-text-property pos 'part-side))
  13252      )
  13253     ((not (get-text-property pos 'part-side))
  13254      (setq pos (next-single-property-change pos 'part-side)))
  13255     ((and (setq pos (web-mode-part-end-position pos)) (>= pos (point-max)))
  13256      (setq pos nil))
  13257     ((and (setq pos (1+ pos)) (not (get-text-property pos 'part-side)))
  13258      (setq pos (next-single-property-change pos 'part-side)))
  13259     ) ;cond
  13260   pos)
  13261 
  13262 (defun web-mode-block-match-position (&optional pos)
  13263   (unless pos (setq pos (point)))
  13264   (save-excursion
  13265     (web-mode-block-match pos)
  13266     (if (= pos (point)) nil (point))))
  13267 
  13268 ;; type may be nil
  13269 (defun web-mode-block-control-previous-position (type &optional pos)
  13270   (unless pos (setq pos (point)))
  13271   (let ((continue t) controls)
  13272     (while continue
  13273       (setq pos (web-mode-block-previous-position pos))
  13274       (cond
  13275         ((null pos)
  13276          (setq continue nil
  13277                pos nil))
  13278         ((null type)
  13279          (setq continue nil))
  13280         ((and (setq controls (web-mode-block-controls-get pos))
  13281               (eq (car (car controls)) type))
  13282          (setq continue nil))
  13283         ) ;cond
  13284       ) ;while
  13285     pos))
  13286 
  13287 (defun web-mode-inside-block-control (&optional pos)
  13288   (unless pos (setq pos (point)))
  13289   (setq pos (web-mode-block-control-previous-position nil pos))
  13290   (if (and pos (member (car (car (web-mode-block-controls-get pos))) '(open inside)))
  13291       pos
  13292       nil))
  13293 
  13294 (defun web-mode-block-opening-paren-position (pos limit)
  13295   (save-excursion
  13296     (when (> limit pos)
  13297       (message "block-opening-paren-position: limit(%S) > pos(%S)" limit pos))
  13298     (goto-char pos)
  13299     (let (c
  13300           n
  13301           pt
  13302           (continue (> pos limit))
  13303           (pairs '((?\) . ?\()
  13304                    (?\] . ?\[)
  13305                    (?\} . ?\{)))
  13306           (h (make-hash-table :test 'equal))
  13307           (regexp "[\]\[)(}{]"))
  13308       (while (and continue (re-search-backward regexp limit t))
  13309         (cond
  13310           ((web-mode-is-comment-or-string)
  13311            )
  13312           (t
  13313            (setq c (char-after))
  13314            (cond
  13315              ((member c '(?\( ?\{ ?\[))
  13316               (setq n (gethash c h 0))
  13317               (if (= n 0)
  13318                   (setq continue nil
  13319                         pt (point))
  13320                   (puthash c (1+ n) h)
  13321                   ))
  13322              (t
  13323               (setq c (cdr (assoc c pairs)))
  13324               (setq n (gethash c h 0))
  13325               (puthash c (1- n) h))
  13326              ) ;cond
  13327            ) ;t
  13328           ) ;cond
  13329         ) ;while
  13330       pt)))
  13331 
  13332 (defun web-mode-block-code-beginning-position (&optional pos)
  13333   (unless pos (setq pos (point)))
  13334   (when (and (setq pos (web-mode-block-beginning-position pos))
  13335              (eq (get-text-property pos 'block-token) 'delimiter-beg))
  13336     (setq pos (next-single-property-change pos 'block-token)))
  13337   pos)
  13338 
  13339 (defun web-mode-block-beginning-position (&optional pos)
  13340   (unless pos (setq pos (point)))
  13341   (cond
  13342     ((or (and (get-text-property pos 'block-side) (= pos (point-min)))
  13343          (get-text-property pos 'block-beg))
  13344      )
  13345     ((and (> pos (point-min)) (get-text-property (1- pos) 'block-beg))
  13346      (setq pos (1- pos)))
  13347     ((get-text-property pos 'block-side)
  13348      (setq pos (previous-single-property-change pos 'block-beg))
  13349      (setq pos (if (and pos (> pos (point-min))) (1- pos) (point-min))))
  13350     (t
  13351      (setq pos nil))
  13352     ) ;cond
  13353   pos)
  13354 
  13355 (defun web-mode-block-string-beginning-position (pos &optional block-beg)
  13356   (unless pos (setq pos (point)))
  13357   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13358   (let (char (ori pos) (continue (not (null pos))))
  13359     (while continue
  13360       (setq char (char-after pos))
  13361       (cond
  13362         ((< pos block-beg)
  13363          (setq continue nil
  13364                pos block-beg))
  13365         ((and (member (get-text-property pos 'block-token) '(string comment))
  13366               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13367          (setq pos (web-mode-block-token-beginning-position pos))
  13368          )
  13369         ((member char '(?\) ?\]))
  13370          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13371          (setq pos (1- pos))
  13372          )
  13373         ((and (> ori pos) (member char '(?\( ?\= ?\[ ?\? ?\: ?\; ?\, ?\`)))
  13374          (if (and (eq char ?\:) ; #1024
  13375                   (web-mode-looking-at ":" pos))
  13376              (setq pos (1- pos))
  13377              (web-mode-looking-at ".[ \t\n]*" pos)
  13378              (setq pos (+ pos (length (match-string-no-properties 0)))
  13379                    continue nil)
  13380              )
  13381          )
  13382         ((web-mode-looking-at "\\(return\\|echo\\|include\\|print\\)[ \n]" pos)
  13383          (setq pos (+ pos (length (match-string-no-properties 0)))
  13384                continue nil))
  13385         (t
  13386          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?;,`:]\\|\\(return\\|echo\\|include\\|print\\)" block-beg))
  13387          (when (not pos)
  13388            (message "block-string-beginning-position ** search failure **")
  13389            (setq continue nil
  13390                  pos block-beg)))
  13391         ) ;cond
  13392       ) ;while
  13393     ;;(message "pos=%S" pos)
  13394     pos))
  13395 
  13396 (defun web-mode-block-statement-beginning-position (pos block-beg _is-ternary)
  13397   (unless pos (setq pos (point)))
  13398   (setq pos (1- pos))
  13399   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13400   (let (char (continue (not (null pos))))
  13401     (while continue
  13402       (setq char (char-after pos))
  13403       (cond
  13404         ((< pos block-beg)
  13405          (setq continue nil
  13406                pos block-beg))
  13407         ((and (member (get-text-property pos 'block-token) '(string comment))
  13408               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13409          (setq pos (web-mode-block-token-beginning-position pos)))
  13410         ((member char '(?\) ?\] ?\}))
  13411          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13412          (setq pos (1- pos)))
  13413         ((and (eq char ?\=)
  13414               (web-mode-looking-back "[<>!=]+" pos block-beg t))
  13415          (setq pos (- pos 1 (length (match-string-no-properties 0))))
  13416          ;;(setq pos (1- pos))
  13417          ;;(message "%S pos=%S" (match-string-no-properties 0) pos)
  13418          )
  13419         ((member char '(?\( ?\[ ?\{ ?\=))
  13420          (setq continue nil)
  13421          (web-mode-looking-at ".[ \t\n]*" pos)
  13422          (setq pos (+ pos (length (match-string-no-properties 0)))))
  13423         ((web-mode-looking-at "\\(return\\|echo\\|include\\|print\\)[ \n]" pos)
  13424          (setq pos (+ pos (length (match-string-no-properties 0)))
  13425                continue nil))
  13426         (t
  13427          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=]\\|\\(return\\|echo\\|include\\|print\\)" block-beg))
  13428          (when (not pos)
  13429            (message "block-statement-beginning-position ** search failure **")
  13430            (setq continue nil
  13431                  pos block-beg)))
  13432         ) ;cond
  13433       ) ;while
  13434     pos))
  13435 
  13436 (defun web-mode-block-args-beginning-position (pos &optional block-beg)
  13437   (unless pos (setq pos (point)))
  13438   (setq pos (1- pos)) ;#512
  13439   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13440   (let (char (continue (not (null pos))))
  13441     (while continue
  13442       (setq char (char-after pos))
  13443       (cond
  13444         ((< pos block-beg)
  13445          (message "block-args-beginning-position ** failure **")
  13446          (setq continue nil
  13447                pos block-beg))
  13448         ((and (member (get-text-property pos 'block-token) '(string comment))
  13449               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13450          (setq pos (web-mode-block-token-beginning-position pos)))
  13451         ((member char '(?\) ?\] ?\}))
  13452          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13453          (setq pos (1- pos)))
  13454         ((member char '(?\( ?\[ ?\{))
  13455          (setq continue nil)
  13456          (web-mode-looking-at ".[ \t\n]*" pos)
  13457          (setq pos (+ pos (length (match-string-no-properties 0)))))
  13458         ((and (string= web-mode-engine "php")
  13459               (web-mode-looking-at "\\(extends\\|implements\\)[ \n]" pos))
  13460          (setq pos (+ pos (length (match-string-no-properties 0)))
  13461                continue nil))
  13462         (t
  13463          (setq pos (web-mode-rsb-position pos "[\]\[}{)(]\\|\\(extends\\|implements\\)" block-beg))
  13464          (when (not pos)
  13465            (message "block-args-beginning-position ** search failure **")
  13466            (setq pos block-beg
  13467                  continue nil))
  13468          ) ;t
  13469         ) ;cond
  13470       ) ;while
  13471     pos))
  13472 
  13473 (defun web-mode-block-calls-beginning-position (pos &optional block-beg)
  13474   (unless pos (setq pos (point)))
  13475   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13476   (let (char (continue (not (null pos))))
  13477     (while continue
  13478       (setq char (char-after pos))
  13479       (cond
  13480         ((< pos block-beg)
  13481          (message "block-calls-beginning-position ** failure **")
  13482          (setq continue nil
  13483                pos block-beg))
  13484         ((and (member (get-text-property pos 'block-token) '(string comment))
  13485               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13486          (setq pos (web-mode-block-token-beginning-position pos)))
  13487         ((member char '(?\) ?\]))
  13488          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13489          (setq pos (1- pos)))
  13490         ((member char '(?\( ?\[ ?\{ ?\} ?\= ?\? ?\: ?\; ?\,))
  13491          (web-mode-looking-at ".[ \t\n]*" pos)
  13492          (setq pos (+ pos (length (match-string-no-properties 0)))
  13493                continue nil))
  13494         ((web-mode-looking-at "\\(return\\|else\\)[ \n]" pos)
  13495          (setq pos (+ pos (length (match-string-no-properties 0)))
  13496                continue nil))
  13497         (t
  13498          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,]\\|\\(return\\|else\\)" block-beg))
  13499          (when (not pos)
  13500            (message "block-calls-beginning-position ** search failure **")
  13501            (setq pos block-beg
  13502                  continue nil))
  13503          ) ;t
  13504         ) ;cond
  13505       ) ;while
  13506     pos))
  13507 
  13508 (defun web-mode-javascript-string-beginning-position (pos &optional reg-beg)
  13509   (unless pos (setq pos (point)))
  13510   (let ((char nil)
  13511         (blockside (get-text-property pos 'block-side))
  13512         (i 0)
  13513         (continue (not (null pos))))
  13514     (unless reg-beg
  13515       (if blockside
  13516           (setq reg-beg (web-mode-block-beginning-position pos))
  13517           (setq reg-beg (web-mode-part-beginning-position pos)))
  13518       )
  13519     (while continue
  13520       (setq char (char-after pos))
  13521       (cond
  13522         ((> (setq i (1+ i)) 20000)
  13523          (message "javascript-string-beginning-position ** warning (%S) **" pos)
  13524          (setq continue nil
  13525                pos nil))
  13526         ((null pos)
  13527          (message "javascript-string-beginning-position ** invalid pos **")
  13528          (setq continue nil))
  13529         ((< pos reg-beg)
  13530          (message "javascript-string-beginning-position ** failure **")
  13531          (setq continue nil
  13532                pos reg-beg))
  13533         ((and blockside
  13534               (member (get-text-property pos 'block-token) '(string comment))
  13535               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13536          (setq pos (web-mode-block-token-beginning-position pos)))
  13537         ((and (not blockside)
  13538               (member (get-text-property pos 'part-token) '(string comment))
  13539               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13540          (setq pos (web-mode-part-token-beginning-position pos)))
  13541         ((and (not blockside)
  13542               (get-text-property pos 'block-side))
  13543          (when (setq pos (web-mode-block-beginning-position pos))
  13544            (setq pos (1- pos))))
  13545         ((member char '(?\) ?\] ?\}))
  13546          (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13547          (setq pos (1- pos)))
  13548         ((member char '(?\( ?\{ ?\[ ?\= ?\? ?\: ?\; ?\, ?\& ?\|))
  13549          (setq continue nil)
  13550          (web-mode-looking-at ".[ \t\n]*" pos)
  13551          (setq pos (+ pos (length (match-string-no-properties 0)))))
  13552         ((web-mode-looking-at "\\(return\\)[ \n]" pos)
  13553          (setq pos (+ pos (length (match-string-no-properties 0)))
  13554                continue nil))
  13555         (t
  13556          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,&|]\\|\\(return\\)" reg-beg))
  13557          (when (not pos)
  13558            (message "javascript-string-beginning-position ** search failure **")
  13559            (setq continue nil
  13560                  pos reg-beg)))
  13561         ) ;cond
  13562       ) ;while
  13563     ;;(message "js-statement-beg:%S" pos)
  13564     pos))
  13565 
  13566 ;; TODO: reg-beg : jsx-beg
  13567 ;; TODO: skipper les expr dont la depth est superieure
  13568 
  13569 ;; NOTE: blockside is useful for ejs
  13570 (defun web-mode-javascript-statement-beginning-position (pos reg-beg is-ternary)
  13571   (unless pos (setq pos (point)))
  13572   (setq pos (1- pos))
  13573   (let ((char nil)
  13574         (blockside (get-text-property pos 'block-side))
  13575         (i 0)
  13576         (is-jsx (string= web-mode-content-type "jsx"))
  13577         (depth-o nil) (depth-l nil)
  13578         (continue (not (null pos)))
  13579         (regexp "[\]\[}{)(=:]\\|\\(return\\)"))
  13580     (when is-ternary
  13581       (setq regexp (concat regexp "\\|[><]")))
  13582     (setq depth-o (get-text-property pos 'jsx-depth))
  13583     (unless reg-beg
  13584       (cond
  13585         (blockside
  13586          (setq reg-beg (web-mode-block-beginning-position pos)))
  13587         (is-jsx
  13588          (setq reg-beg (web-mode-jsx-depth-beginning-position pos)))
  13589         (t
  13590          (setq reg-beg (web-mode-part-beginning-position pos)))
  13591         ) ;cond
  13592       ) ;unless
  13593     (while continue
  13594       (setq char (char-after pos))
  13595       (cond
  13596         ((> (setq i (1+ i)) 20000)
  13597          (message "javascript-statement-beginning-position ** warning (%S) **" pos)
  13598          (setq continue nil
  13599                pos nil))
  13600         ((null pos)
  13601          (message "javascript-statement-beginning-position ** invalid pos **")
  13602          (setq continue nil))
  13603         ((< pos reg-beg)
  13604          (when (not is-jsx)
  13605            (message "javascript-statement-beginning-position ** failure **"))
  13606          (setq continue nil
  13607                pos reg-beg))
  13608         ((and is-jsx
  13609               (progn (setq depth-l (get-text-property pos 'jsx-depth)) t)
  13610               (not (eq depth-l depth-o)))
  13611          ;;(message "%S > depth-o(%S) depth-l(%S)" pos depth-o depth-l)
  13612          (setq pos (previous-single-property-change pos 'jsx-depth))
  13613          (setq pos (1- pos))
  13614          ;;(message "--> %S %S" pos (get-text-property pos 'jsx-depth))
  13615          )
  13616         ((and blockside
  13617               (member (get-text-property pos 'block-token) '(string comment))
  13618               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13619          (setq pos (web-mode-block-token-beginning-position pos)))
  13620         ((and (not blockside)
  13621               (member (get-text-property pos 'part-token) '(string comment))
  13622               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13623          (setq pos (web-mode-part-token-beginning-position pos)))
  13624         ((and (not blockside)
  13625               (get-text-property pos 'block-side))
  13626          (when (setq pos (web-mode-block-beginning-position pos))
  13627            (setq pos (1- pos))))
  13628         ((member char '(?\) ?\] ?\}))
  13629          (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13630          (setq pos (1- pos)))
  13631         ((and (eq char ?\=)
  13632               (web-mode-looking-back "[<>!=]+" pos reg-beg t))
  13633          (setq pos (- pos 1 (length (match-string-no-properties 0)))))
  13634         ((member char '(?\( ?\{ ?\[ ?\= ?\< ?\>))
  13635          (web-mode-looking-at ".[ \t\n]*" pos)
  13636          (setq continue nil
  13637                pos (+ pos (length (match-string-no-properties 0)))))
  13638 
  13639         ((web-mode-looking-at "\\(return\\)[ \n]" pos)
  13640          (setq continue nil
  13641                pos (+ pos (length (match-string-no-properties 0)))))
  13642         ((and (eq char ?\:)
  13643               (web-mode-looking-back "[{,][ \t\n]*[[:alnum:]_]+[ ]*" pos))
  13644          (web-mode-looking-at ".[ \t\n]*" pos)
  13645          (setq continue nil
  13646                pos (+ pos (length (match-string-no-properties 0)))))
  13647         (t
  13648          (setq pos (web-mode-rsb-position pos regexp reg-beg))
  13649          (when (not pos)
  13650            (cond
  13651              (is-jsx
  13652               (when (web-mode-looking-at "[ \n]*" reg-beg)
  13653                 (setq pos (+ reg-beg (length (match-string-no-properties 0)))))
  13654               (setq continue nil))
  13655              (t
  13656               (message "javascript-statement-beginning-position ** search failure **")
  13657               (setq continue nil
  13658                     pos reg-beg))
  13659              ) ;cond
  13660            )
  13661          ) ;t
  13662         ) ;cond
  13663       ) ;while
  13664     ;;(message "%S -------" pos)
  13665     pos))
  13666 
  13667 (defun web-mode-javascript-args-beginning-position (pos &optional reg-beg)
  13668   (unless pos (setq pos (point)))
  13669   (setq pos (1- pos))
  13670   (let ((char nil)
  13671         (blockside (get-text-property pos 'block-side))
  13672         (i 0)
  13673         (continue (not (null pos))))
  13674     (unless reg-beg
  13675       (if blockside
  13676           (setq reg-beg (web-mode-block-beginning-position pos))
  13677           (setq reg-beg (web-mode-part-beginning-position pos)))
  13678       )
  13679     (while continue
  13680       (setq char (char-after pos))
  13681       ;;(message "pos(%S) char(%c)" pos char)
  13682       (cond
  13683         ((> (setq i (1+ i)) 20000)
  13684          (message "javascript-args-beginning-position ** warning (%S) **" pos)
  13685          (setq continue nil
  13686                pos nil))
  13687         ((null pos)
  13688          (message "javascript-args-beginning-position ** invalid pos **")
  13689          (setq continue nil))
  13690         ((< pos reg-beg)
  13691          (message "javascript-args-beginning-position ** failure(position) **")
  13692          (setq continue nil
  13693                pos reg-beg))
  13694         ((and blockside
  13695               (member (get-text-property pos 'block-token) '(string comment))
  13696               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13697          (setq pos (web-mode-block-token-beginning-position pos)))
  13698         ((and (not blockside)
  13699               (member (get-text-property pos 'part-token) '(string comment))
  13700               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13701          (setq pos (web-mode-part-token-beginning-position pos)))
  13702         ((and (not blockside)
  13703               (get-text-property pos 'block-side))
  13704          (when (setq pos (web-mode-block-beginning-position pos))
  13705            (setq pos (1- pos)))
  13706          )
  13707         ((member char '(?\) ?\] ?\}))
  13708          (when (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13709            (setq pos (1- pos))))
  13710         ((member char '(?\( ?\[ ?\{))
  13711          (web-mode-looking-at ".[ ]*" pos)
  13712          (setq pos (+ pos (length (match-string-no-properties 0)))
  13713                continue nil)
  13714          )
  13715         ((web-mode-looking-at "\\(var\\|let\\|return\\|const\\)[ \n]" pos)
  13716          (setq pos (+ pos (length (match-string-no-properties 0)))
  13717                continue nil))
  13718         (t
  13719          (setq pos (web-mode-rsb-position pos "[\]\[}{)(]\\|\\(var\\|let\\|return\\|const\\)" reg-beg))
  13720          (when (not pos)
  13721            (message "javascript-args-beginning-position ** search failure **")
  13722            (setq continue nil
  13723                  pos reg-beg)))
  13724         ) ;cond
  13725       ) ;while
  13726     ;;(message "=%S" pos)
  13727     pos))
  13728 
  13729 (defun web-mode-javascript-calls-beginning-position (pos &optional reg-beg)
  13730   (unless pos (setq pos (point)))
  13731   ;;(message "pos=%S" pos)
  13732   (let ((char nil)
  13733         (dot-pos nil)
  13734         (blockside (get-text-property pos 'block-side))
  13735         (i 0)
  13736         (continue (not (null pos))))
  13737     (unless reg-beg
  13738       (setq reg-beg (if blockside
  13739                         (web-mode-block-beginning-position pos)
  13740                         (web-mode-part-beginning-position pos))))
  13741     (while continue
  13742       (setq char (char-after pos))
  13743       ;;(message "%S| %S=%c" reg-beg pos char)
  13744       (cond
  13745         ((> (setq i (1+ i)) 20000)
  13746          (message "javascript-calls-beginning-position ** warning (%S) **" pos)
  13747          (setq continue nil
  13748                pos nil))
  13749         ((null pos)
  13750          (message "javascript-calls-beginning-position ** invalid pos **")
  13751          (setq continue nil))
  13752         ((< pos reg-beg)
  13753          (setq continue nil
  13754                pos reg-beg))
  13755         ((and blockside
  13756               (member (get-text-property pos 'block-token) '(string comment))
  13757               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13758          (setq pos (web-mode-block-token-beginning-position pos)))
  13759         ((and (not blockside)
  13760               (member (get-text-property pos 'part-token) '(string comment))
  13761               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13762          (setq pos (web-mode-part-token-beginning-position pos)))
  13763         ((and (not blockside)
  13764               (get-text-property pos 'block-side))
  13765          (when (setq pos (web-mode-block-beginning-position pos))
  13766            (setq pos (1- pos))))
  13767         ((and (member char '(?\.)) (> i 1))
  13768          (setq dot-pos pos
  13769                pos (1- pos)))
  13770         ((member char '(?\) ?\]))
  13771          (when (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13772            (setq pos (1- pos)))
  13773          )
  13774         ((member char '(?\( ?\{ ?\} ?\[ ?\= ?\? ?\: ?\; ?\, ?\& ?\| ?\>))
  13775          (web-mode-looking-at ".[ \t\n]*" pos)
  13776          (setq pos (+ pos (length (match-string-no-properties 0)))
  13777                continue nil))
  13778         ((web-mode-looking-at "\\(return\\|else\\|const\\)[ \n]" pos)
  13779          (setq pos (+ pos (length (match-string-no-properties 0)))
  13780                continue nil))
  13781         (t
  13782          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,&|>.]\\|\\(return\\|else\\|const\\)" reg-beg))
  13783          (when (not pos)
  13784            (message "javascript-calls-beginning-position ** search failure **")
  13785            (setq pos reg-beg
  13786                  continue nil))
  13787          ) ;t
  13788         ) ;cond
  13789       ) ;while
  13790     ;;(message "pos=%S dot-pos=%S" pos dot-pos)
  13791     (if (null pos) pos (cons pos dot-pos))
  13792     ))
  13793 
  13794 (defun web-mode-part-token-beginning-position (&optional pos)
  13795   (unless pos (setq pos (point)))
  13796   (cond
  13797     ((not (get-text-property pos 'part-token))
  13798      nil)
  13799     ((or (= pos (point-min))
  13800          (and (> pos (point-min))
  13801               (not (get-text-property (1- pos) 'part-token))))
  13802      pos)
  13803     (t
  13804      (setq pos (previous-single-property-change pos 'part-token))
  13805      (if (and pos (> pos (point-min))) pos (point-min)))
  13806     ))
  13807 
  13808 (defun web-mode-part-token-end-position (&optional pos)
  13809   (unless pos (setq pos (point)))
  13810   (cond
  13811     ((not (get-text-property pos 'part-token))
  13812      nil)
  13813     ((or (= pos (point-max))
  13814          (not (get-text-property (1+ pos) 'part-token)))
  13815      pos)
  13816     (t
  13817      (1- (next-single-property-change pos 'part-token)))
  13818     ))
  13819 
  13820 (defun web-mode-block-token-beginning-position (&optional pos)
  13821   (unless pos (setq pos (point)))
  13822   (cond
  13823     ((not (get-text-property pos 'block-token))
  13824      nil)
  13825     ((or (= pos (point-min))
  13826          (and (> pos (point-min))
  13827               (not (get-text-property (1- pos) 'block-token))))
  13828      pos)
  13829     (t
  13830      (setq pos (previous-single-property-change pos 'block-token))
  13831      (if (and pos (> pos (point-min))) pos (point-min)))
  13832     ))
  13833 
  13834 (defun web-mode-block-token-end-position (&optional pos)
  13835   (unless pos (setq pos (point)))
  13836   (cond
  13837     ((not (get-text-property pos 'block-token))
  13838      nil)
  13839     ((or (= pos (point-max))
  13840          (not (get-text-property (1+ pos) 'block-token)))
  13841      pos)
  13842     (t
  13843      (1- (next-single-property-change pos 'block-token)))
  13844     ))
  13845 
  13846 (defun web-mode-block-code-end-position (&optional pos)
  13847   (unless pos (setq pos (point)))
  13848   (setq pos (web-mode-block-end-position pos))
  13849   (cond
  13850     ((not pos)
  13851      nil)
  13852     ((and (eq (get-text-property pos 'block-token) 'delimiter-end)
  13853           (eq (get-text-property (1- pos) 'block-token) 'delimiter-end))
  13854      (previous-single-property-change pos 'block-token))
  13855     ((= pos (1- (point-max))) ;; TODO: comparer plutot avec line-end-position
  13856      (point-max))
  13857     (t
  13858      pos)
  13859     ))
  13860 
  13861 (defun web-mode-block-end-position (&optional pos)
  13862   (unless pos (setq pos (point)))
  13863   (cond
  13864     ((get-text-property pos 'block-end)
  13865      pos)
  13866     ((get-text-property pos 'block-side)
  13867      (or (next-single-property-change pos 'block-end)
  13868          (point-max)))
  13869     (t
  13870      nil)
  13871     ))
  13872 
  13873 (defun web-mode-block-previous-position (&optional pos)
  13874   (unless pos (setq pos (point)))
  13875   (cond
  13876     ((= pos (point-min))
  13877      (setq pos nil))
  13878     ((get-text-property pos 'block-side)
  13879      (setq pos (web-mode-block-beginning-position pos))
  13880      (cond
  13881        ((or (null pos) (= pos (point-min)))
  13882         (setq pos nil)
  13883         )
  13884        ((and (setq pos (previous-single-property-change pos 'block-beg))
  13885              (> pos (point-min)))
  13886         (setq pos (1- pos))
  13887         )
  13888        )
  13889      ) ;block-side
  13890     ((get-text-property (1- pos) 'block-side)
  13891      (setq pos (web-mode-block-beginning-position (1- pos)))
  13892      )
  13893     (t
  13894      (setq pos (previous-single-property-change pos 'block-side))
  13895      (cond
  13896        ((and (null pos) (get-text-property (point-min) 'block-beg))
  13897         (setq pos (point-min)))
  13898        ((and pos (> pos (point-min)))
  13899         (setq pos (web-mode-block-beginning-position (1- pos))))
  13900        )
  13901      )
  13902     ) ;conf
  13903   pos)
  13904 
  13905 (defun web-mode-block-next-position (&optional pos limit)
  13906   (unless pos (setq pos (point)))
  13907   (unless limit (setq limit (point-max)))
  13908   (cond
  13909     ((and (get-text-property pos 'block-side)
  13910           (setq pos (web-mode-block-end-position pos))
  13911           (< pos (point-max))
  13912           (setq pos (1+ pos)))
  13913      (unless (get-text-property pos 'block-beg)
  13914        (setq pos (next-single-property-change pos 'block-side)))
  13915      )
  13916     (t
  13917      (setq pos (next-single-property-change pos 'block-side)))
  13918     ) ;cond
  13919   (if (and pos (<= pos limit)) pos nil))
  13920 
  13921 (defun web-mode-is-css-string (pos)
  13922   (let (beg)
  13923     (cond
  13924       ((and (setq beg (web-mode-part-token-beginning-position pos))
  13925             (web-mode-looking-at-p "`" beg)
  13926             (web-mode-looking-back "\\(styled[[:alnum:].]+\\|css\\)" beg))
  13927        beg)
  13928       (t
  13929        nil)
  13930       ) ;cond
  13931     ))
  13932 
  13933 ;; Relay.QL , gql, graphql
  13934 (defun web-mode-is-ql-string (pos prefix-regexp)
  13935   (let (beg)
  13936     (cond
  13937       ((and (setq beg (web-mode-part-token-beginning-position pos))
  13938             (web-mode-looking-back prefix-regexp beg))
  13939        beg)
  13940       (t
  13941        nil)
  13942       ) ;cond
  13943     ))
  13944 
  13945 (defun web-mode-is-html-string (pos)
  13946   (let (beg)
  13947     (cond
  13948       ((and (setq beg (web-mode-part-token-beginning-position pos))
  13949             (web-mode-looking-at-p "`[ \t\n]*<[a-zA-Z]" beg)
  13950             (web-mode-looking-back "\\(template\\|html\\)\\([ ]*[=:][ ]*\\)?" beg))
  13951        beg)
  13952       (t
  13953        nil)
  13954       ) ;cond
  13955     ))
  13956 
  13957 ;;---- EXCURSION ---------------------------------------------------------------
  13958 
  13959 (defun web-mode-backward-sexp (n)
  13960   (interactive "p")
  13961   (if (< n 0) (web-mode-forward-sexp (- n))
  13962       (let (pos)
  13963         (dotimes (_ n)
  13964           (skip-chars-backward "[:space:]")
  13965           (setq pos (point))
  13966           (cond
  13967             ((bobp) nil)
  13968             ((get-text-property (1- pos) 'block-end)
  13969              (backward-char 1)
  13970              (web-mode-block-beginning))
  13971             ((get-text-property (1- pos) 'block-token)
  13972              (backward-char 1)
  13973              (web-mode-block-token-beginning))
  13974             ((get-text-property (1- pos) 'part-token)
  13975              (backward-char 1)
  13976              (web-mode-part-token-beginning))
  13977             ((get-text-property (1- pos) 'tag-end)
  13978              (backward-char 1)
  13979              (web-mode-element-beginning))
  13980             ((get-text-property (1- pos) 'tag-attr)
  13981              (backward-char 1)
  13982              (web-mode-attribute-beginning))
  13983             ((get-text-property (1- pos) 'tag-type)
  13984              (backward-char 1)
  13985              (web-mode-tag-beginning))
  13986             ((get-text-property (1- pos) 'jsx-end)
  13987              (backward-char 1)
  13988              (web-mode-jsx-beginning))
  13989             (t
  13990              (let ((forward-sexp-function nil))
  13991                (backward-sexp))
  13992              ) ;case t
  13993             ) ;cond
  13994           ) ;dotimes
  13995         ))) ;let if defun
  13996 
  13997 (defun web-mode-forward-sexp (n)
  13998   (interactive "p")
  13999   (if (< n 0) (web-mode-backward-sexp (- n))
  14000       (let (pos)
  14001         (dotimes (_ n)
  14002           (skip-chars-forward "[:space:]")
  14003           (setq pos (point))
  14004           (cond
  14005             ((eobp) nil)
  14006             ((get-text-property pos 'block-beg)
  14007              (web-mode-block-end))
  14008             ((get-text-property pos 'block-token)
  14009              (web-mode-block-token-end))
  14010             ((get-text-property pos 'part-token)
  14011              (web-mode-part-token-end))
  14012             ((get-text-property pos 'tag-beg)
  14013              (web-mode-element-end))
  14014             ((get-text-property pos 'tag-attr)
  14015              (web-mode-attribute-end))
  14016             ((get-text-property pos 'tag-type)
  14017              (web-mode-tag-end))
  14018             ((get-text-property pos 'jsx-beg)
  14019              (web-mode-jsx-end))
  14020             (t
  14021              (let ((forward-sexp-function nil))
  14022                (forward-sexp))
  14023              ) ;case t
  14024             ) ;cond
  14025           ) ;dotimes
  14026         ))) ;let if defun
  14027 
  14028 (defun web-mode-comment-beginning ()
  14029   "Fetch current comment beg."
  14030   (interactive)
  14031   (web-mode-go (web-mode-comment-beginning-position (point))))
  14032 
  14033 (defun web-mode-comment-end ()
  14034   "Fetch current comment end."
  14035   (interactive)
  14036   (web-mode-go (web-mode-comment-end-position (point)) 1))
  14037 
  14038 (defun web-mode-tag-beginning ()
  14039   "Fetch current html tag beg."
  14040   (interactive)
  14041   (web-mode-go (web-mode-tag-beginning-position (point))))
  14042 
  14043 (defun web-mode-tag-end ()
  14044   "Fetch current html tag end."
  14045   (interactive)
  14046   (web-mode-go (web-mode-tag-end-position (point)) 1))
  14047 
  14048 (defun web-mode-tag-previous ()
  14049   "Fetch previous tag."
  14050   (interactive)
  14051   (web-mode-go (web-mode-tag-previous-position (point))))
  14052 
  14053 (defun web-mode-tag-next ()
  14054   "Fetch next tag. Might be html comment or server tag (e.g. jsp)."
  14055   (interactive)
  14056   (web-mode-go (web-mode-tag-next-position (point))))
  14057 
  14058 (defun web-mode-attribute-beginning ()
  14059   "Fetch html attribute beginning."
  14060   (interactive)
  14061   (web-mode-go (web-mode-attribute-beginning-position (point))))
  14062 
  14063 (defun web-mode-attribute-end ()
  14064   "Fetch html attribute end."
  14065   (interactive)
  14066   (web-mode-go (web-mode-attribute-end-position (point)) 1))
  14067 
  14068 (defun web-mode-attribute-next (&optional arg)
  14069   "Fetch next attribute."
  14070   (interactive "p")
  14071   (unless arg (setq arg 1))
  14072   (cond
  14073     ((= arg 1) (web-mode-go (web-mode-attribute-next-position (point))))
  14074     ((< arg 1) (web-mode-element-previous (* arg -1)))
  14075     (t
  14076      (while (>= arg 1)
  14077        (setq arg (1- arg))
  14078        (web-mode-go (web-mode-attribute-next-position (point)))
  14079        )
  14080      )
  14081     )
  14082   )
  14083 
  14084 (defun web-mode-attribute-previous (&optional arg)
  14085   "Fetch previous attribute."
  14086   (interactive "p")
  14087   (unless arg (setq arg 1))
  14088   (unless arg (setq arg 1))
  14089   (cond
  14090     ((= arg 1) (web-mode-go (web-mode-attribute-previous-position (point))))
  14091     ((< arg 1) (web-mode-element-next (* arg -1)))
  14092     (t
  14093      (while (>= arg 1)
  14094        (setq arg (1- arg))
  14095        (web-mode-go (web-mode-attribute-previous-position (point)))
  14096        )
  14097      )
  14098     )
  14099   )
  14100 
  14101 (defun web-mode-element-previous (&optional arg)
  14102   "Fetch previous element."
  14103   (interactive "p")
  14104   (unless arg (setq arg 1))
  14105   (cond
  14106     ((= arg 1) (web-mode-go (web-mode-element-previous-position (point))))
  14107     ((< arg 1) (web-mode-element-next (* arg -1)))
  14108     (t
  14109      (while (>= arg 1)
  14110        (setq arg (1- arg))
  14111        (web-mode-go (web-mode-element-previous-position (point)))
  14112        ) ;while
  14113      ) ;t
  14114     ) ;cond
  14115   )
  14116 
  14117 (defun web-mode-element-next (&optional arg)
  14118   "Fetch next element."
  14119   (interactive "p")
  14120   (unless arg (setq arg 1))
  14121   (cond
  14122     ((= arg 1) (web-mode-go (web-mode-element-next-position (point))))
  14123     ((< arg 1) (web-mode-element-previous (* arg -1)))
  14124     (t
  14125      (while (>= arg 1)
  14126        (setq arg (1- arg))
  14127        (web-mode-go (web-mode-element-next-position (point)))
  14128        ) ;while
  14129      ) ;t
  14130     ) ;cond
  14131   )
  14132 
  14133 (defun web-mode-element-sibling-next ()
  14134   "Fetch next sibling element."
  14135   (interactive)
  14136   (let ((pos (point)))
  14137     (save-excursion
  14138       (cond
  14139         ((not (get-text-property pos 'tag-type))
  14140          (if (and (web-mode-element-parent)
  14141                   (web-mode-tag-match)
  14142                   (web-mode-tag-next)
  14143                   (member (get-text-property (point) 'tag-type) '(start void comment)))
  14144              (setq pos (point))
  14145              (setq pos nil))
  14146          )
  14147         ((member (get-text-property pos 'tag-type) '(start void))
  14148          (if (and (web-mode-tag-match)
  14149                   (web-mode-tag-next)
  14150                   (member (get-text-property (point) 'tag-type) '(start void comment)))
  14151              (setq pos (point))
  14152              (setq pos nil))
  14153          )
  14154         ((and (web-mode-tag-next)
  14155               (member (get-text-property (point) 'tag-type) '(start void comment)))
  14156          (setq pos (point)))
  14157         (t
  14158          (setq pos nil))
  14159         ) ;cond
  14160       ) ;save-excursion
  14161     (web-mode-go pos)))
  14162 
  14163 (defun web-mode-element-sibling-previous ()
  14164   "Fetch previous sibling element."
  14165   (interactive)
  14166   (let ((pos (point)))
  14167     (save-excursion
  14168       (cond
  14169         ((not (get-text-property pos 'tag-type))
  14170          (if (and (web-mode-element-parent)
  14171                   (web-mode-tag-previous)
  14172                   (web-mode-element-beginning))
  14173              (setq pos (point))
  14174              (setq pos nil))
  14175          )
  14176         ((eq (get-text-property pos 'tag-type) 'start)
  14177          (if (and (web-mode-tag-beginning)
  14178                   (web-mode-tag-previous)
  14179                   (web-mode-element-beginning))
  14180              (setq pos (point))
  14181              (setq pos nil))
  14182          )
  14183         ((and (web-mode-element-beginning)
  14184               (web-mode-tag-previous)
  14185               (web-mode-element-beginning))
  14186          (setq pos (point)))
  14187         (t
  14188          (setq pos nil))
  14189         ) ;cond
  14190       ) ;save-excursion
  14191     (web-mode-go pos)))
  14192 
  14193 (defun web-mode-element-beginning ()
  14194   "Move to beginning of element."
  14195   (interactive)
  14196   (web-mode-go (web-mode-element-beginning-position (point))))
  14197 
  14198 (defun web-mode-element-end ()
  14199   "Move to end of element."
  14200   (interactive)
  14201   (web-mode-go (web-mode-element-end-position (point)) 1))
  14202 
  14203 (defun web-mode-element-parent ()
  14204   "Fetch parent element."
  14205   (interactive)
  14206   (web-mode-go (web-mode-element-parent-position (point))))
  14207 
  14208 (defun web-mode-element-child ()
  14209   "Fetch child element."
  14210   (interactive)
  14211   (web-mode-go (web-mode-element-child-position (point))))
  14212 
  14213 (defun web-mode-dom-traverse ()
  14214   "Traverse html dom tree."
  14215   (interactive)
  14216   (cond
  14217     ((web-mode-element-child)
  14218      )
  14219     ((web-mode-element-sibling-next)
  14220      )
  14221     ((and (web-mode-element-parent)
  14222           (not (web-mode-element-sibling-next)))
  14223      (goto-char (point-min)))
  14224     (t
  14225      (goto-char (point-min)))
  14226     ) ;cond
  14227   )
  14228 
  14229 (defun web-mode-closing-paren (limit)
  14230   (let ((pos (web-mode-closing-paren-position (point) limit)))
  14231     (if (or (null pos) (> pos limit))
  14232         nil
  14233         (goto-char pos)
  14234         pos)
  14235     ))
  14236 
  14237 (defun web-mode-part-next ()
  14238   "Move point to the beginning of the next part."
  14239   (interactive)
  14240   (web-mode-go (web-mode-part-next-position (point))))
  14241 
  14242 (defun web-mode-part-beginning ()
  14243   "Move point to the beginning of the current part."
  14244   (interactive)
  14245   (web-mode-go (web-mode-part-beginning-position (point))))
  14246 
  14247 (defun web-mode-part-end ()
  14248   "Move point to the end of the current part."
  14249   (interactive)
  14250   (web-mode-go (web-mode-part-end-position (point)) 1))
  14251 
  14252 (defun web-mode-block-previous ()
  14253   "Move point to the beginning of the previous block."
  14254   (interactive)
  14255   (web-mode-go (web-mode-block-previous-position (point))))
  14256 
  14257 (defun web-mode-block-next ()
  14258   "Move point to the beginning of the next block."
  14259   (interactive)
  14260   (web-mode-go (web-mode-block-next-position (point))))
  14261 
  14262 (defun web-mode-block-beginning ()
  14263   "Move point to the beginning of the current block."
  14264   (interactive)
  14265   (web-mode-go (web-mode-block-beginning-position (point))))
  14266 
  14267 (defun web-mode-block-end ()
  14268   "Move point to the end of the current block."
  14269   (interactive)
  14270   (web-mode-go (web-mode-block-end-position (point)) 1))
  14271 
  14272 (defun web-mode-block-token-beginning ()
  14273   (web-mode-go (web-mode-block-token-beginning-position (point))))
  14274 
  14275 (defun web-mode-block-token-end ()
  14276   (web-mode-go (web-mode-block-token-end-position (point)) 1))
  14277 
  14278 (defun web-mode-part-token-beginning ()
  14279   (web-mode-go (web-mode-part-token-beginning-position (point))))
  14280 
  14281 (defun web-mode-part-token-end ()
  14282   (web-mode-go (web-mode-part-token-end-position (point)) 1))
  14283 
  14284 (defun web-mode-block-opening-paren (limit)
  14285   (web-mode-go (web-mode-block-opening-paren-position (point) limit)))
  14286 
  14287 (defun web-mode-block-string-beginning (&optional pos block-beg)
  14288   (unless pos (setq pos (point)))
  14289   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14290   (web-mode-go (web-mode-block-string-beginning-position pos block-beg)))
  14291 
  14292 (defun web-mode-block-statement-beginning (pos block-beg is-ternary)
  14293   (unless pos (setq pos (point)))
  14294   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14295   (web-mode-go (web-mode-block-statement-beginning-position pos block-beg is-ternary)))
  14296 
  14297 (defun web-mode-block-args-beginning (&optional pos block-beg)
  14298   (unless pos (setq pos (point)))
  14299   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14300   (web-mode-go (web-mode-block-args-beginning-position pos block-beg)))
  14301 
  14302 (defun web-mode-block-calls-beginning (&optional pos block-beg)
  14303   (unless pos (setq pos (point)))
  14304   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14305   (web-mode-go (web-mode-block-calls-beginning-position pos block-beg)))
  14306 
  14307 (defun web-mode-javascript-string-beginning (&optional pos reg-beg)
  14308   (unless pos (setq pos (point)))
  14309   (unless reg-beg
  14310     (if (get-text-property pos 'block-side)
  14311         (setq reg-beg (web-mode-block-beginning-position pos))
  14312         (setq reg-beg (web-mode-part-beginning-position pos))))
  14313   (web-mode-go (web-mode-javascript-string-beginning-position pos reg-beg)))
  14314 
  14315 (defun web-mode-javascript-statement-beginning (pos reg-beg is-ternary)
  14316   (unless pos (setq pos (point)))
  14317   (unless reg-beg
  14318     (if (get-text-property pos 'block-side)
  14319         (setq reg-beg (web-mode-block-beginning-position pos))
  14320         (setq reg-beg (web-mode-part-beginning-position pos))))
  14321   (web-mode-go (web-mode-javascript-statement-beginning-position pos reg-beg is-ternary)))
  14322 
  14323 (defun web-mode-javascript-args-beginning (&optional pos reg-beg)
  14324   (unless pos (setq pos (point)))
  14325   (unless reg-beg
  14326     (setq reg-beg (if (get-text-property pos 'block-side)
  14327                       (web-mode-block-beginning-position pos)
  14328                       (web-mode-part-beginning-position pos))))
  14329   ;;(message "reg-beg%S" reg-beg)
  14330   (web-mode-go (web-mode-javascript-args-beginning-position pos reg-beg)))
  14331 
  14332 (defun web-mode-javascript-calls-beginning (&optional pos reg-beg)
  14333   (unless pos (setq pos (point)))
  14334   (unless reg-beg
  14335     (if (get-text-property pos 'block-side)
  14336         (setq reg-beg (web-mode-block-beginning-position pos))
  14337         (setq reg-beg (web-mode-part-beginning-position pos))))
  14338   (let (pair)
  14339     (setq pair (web-mode-javascript-calls-beginning-position pos reg-beg))
  14340     (when pair (web-mode-go (car pair)))
  14341     ))
  14342 
  14343 (defun web-mode-go (pos &optional offset)
  14344   (unless offset (setq offset 0))
  14345   (when pos
  14346     (cond
  14347       ((and (> offset 0) (<= (+ pos offset) (point-max)))
  14348        (setq pos (+ pos offset)))
  14349       ((and (< offset 0) (>= (+ pos offset) (point-min)))
  14350        (setq pos (+ pos offset)))
  14351       ) ;cond
  14352     (goto-char pos))
  14353   pos)
  14354 
  14355 ;;---- SEARCH ------------------------------------------------------------------
  14356 
  14357 (defun web-mode-rsf-balanced (regexp-open regexp-close &optional limit noerror)
  14358   (unless noerror (setq noerror t))
  14359   (let ((continue t)
  14360         (level 1)
  14361         (pos (point))
  14362         ret
  14363         (regexp (concat regexp-open "\\|" regexp-close)))
  14364     (while continue
  14365       (setq ret (re-search-forward regexp limit noerror))
  14366       (cond
  14367         ((null ret)
  14368          (setq continue nil)
  14369          )
  14370         (t
  14371          (if (string-match-p regexp-open (match-string-no-properties 0))
  14372              (setq level (1+ level))
  14373              (setq level (1- level)))
  14374          (when (< level 1)
  14375            (setq continue nil)
  14376            )
  14377          ) ;t
  14378         ) ;cond
  14379       ) ;while
  14380     (when (not (= level 0)) (goto-char pos))
  14381     ret))
  14382 
  14383 (defun web-mode-block-sb (expr &optional limit noerror)
  14384   (unless limit (setq limit (web-mode-block-beginning-position (point))))
  14385   (unless noerror (setq noerror t))
  14386   (let ((continue t) ret)
  14387     (while continue
  14388       (setq ret (search-backward expr limit noerror))
  14389       (when (or (null ret)
  14390                 (not (get-text-property (point) 'block-token)))
  14391         (setq continue nil)
  14392         ) ;when
  14393       ) ;while
  14394     ret))
  14395 
  14396 (defun web-mode-block-sf (expr &optional limit noerror)
  14397   (unless limit (setq limit (web-mode-block-end-position (point))))
  14398   (unless noerror (setq noerror t))
  14399   (let ((continue t) ret)
  14400     (while continue
  14401       (setq ret (search-forward expr limit noerror))
  14402       (when (or (null ret)
  14403                 (not (get-text-property (point) 'block-token)))
  14404         (setq continue nil)
  14405         ) ;when
  14406       ) ;while
  14407     ret))
  14408 
  14409 (defun web-mode-block-rsb (regexp &optional limit noerror)
  14410   (unless limit (setq limit (web-mode-block-beginning-position (point))))
  14411   (unless noerror (setq noerror t))
  14412   (let ((continue t) ret)
  14413     (while continue
  14414       (setq ret (re-search-backward regexp limit noerror))
  14415       (when (or (null ret)
  14416                 (not (get-text-property (point) 'block-token)))
  14417         (setq continue nil)
  14418         ) ;when
  14419       ) ;while
  14420     ret))
  14421 
  14422 (defun web-mode-block-rsf (regexp &optional limit noerror)
  14423   (unless limit (setq limit (web-mode-block-end-position (point))))
  14424   (unless noerror (setq noerror t))
  14425   (let ((continue t) ret)
  14426     (while continue
  14427       (setq ret (re-search-forward regexp limit noerror))
  14428       (when (or (null ret)
  14429                 (not (get-text-property (point) 'block-token)))
  14430         (setq continue nil)
  14431         ) ;when
  14432       ) ;while
  14433     ret))
  14434 
  14435 (defun web-mode-part-sb (expr &optional limit noerror)
  14436   (unless limit (setq limit (web-mode-part-beginning-position (point))))
  14437   (unless noerror (setq noerror t))
  14438   (let ((continue t) ret)
  14439     (while continue
  14440       (setq ret (search-backward expr limit noerror))
  14441       (when (or (null ret)
  14442                 (and (not (get-text-property (point) 'part-token))
  14443                      (not (get-text-property (point) 'block-side)))
  14444                 )
  14445         (setq continue nil)
  14446         ) ;when
  14447       ) ;while
  14448     ret))
  14449 
  14450 (defun web-mode-part-sf (expr &optional limit noerror)
  14451   (unless limit (setq limit (web-mode-part-end-position (point))))
  14452   (unless noerror (setq noerror t))
  14453   (let ((continue t) ret)
  14454     (while continue
  14455       (setq ret (search-forward expr limit noerror))
  14456       (when (or (null ret)
  14457                 (and (not (get-text-property (point) 'part-token))
  14458                      (not (get-text-property (point) 'block-side)))
  14459                 )
  14460         (setq continue nil)
  14461         ) ;when
  14462       ) ;while
  14463     ret))
  14464 
  14465 (defun web-mode-part-rsb (regexp &optional limit noerror)
  14466   (unless limit (setq limit (web-mode-part-beginning-position (point))))
  14467   (unless noerror (setq noerror t))
  14468   (let ((continue t) ret)
  14469     (while continue
  14470       (setq ret (re-search-backward regexp limit noerror))
  14471       (when (or (null ret)
  14472                 (and (not (get-text-property (point) 'part-token))
  14473                      (not (get-text-property (point) 'block-side)))
  14474                 )
  14475         (setq continue nil)
  14476         ) ;when
  14477       ) ;while
  14478     ret))
  14479 
  14480 (defun web-mode-part-rsf (regexp &optional limit noerror)
  14481   (unless limit (setq limit (web-mode-part-end-position (point))))
  14482   (unless noerror (setq noerror t))
  14483   (let ((continue t) ret)
  14484     (while continue
  14485       (setq ret (re-search-forward regexp limit t))
  14486       (when (or (null ret)
  14487                 (and (not (get-text-property (point) 'part-token))
  14488                      (not (get-text-property (point) 'block-side)))
  14489                 )
  14490         (setq continue nil)
  14491         ) ;when
  14492       ) ;while
  14493     ret))
  14494 
  14495 (defun web-mode-javascript-rsb (regexp &optional limit noerror)
  14496   (unless limit (setq limit (web-mode-part-beginning-position (point))))
  14497   (unless noerror (setq noerror t))
  14498   (let ((continue t) ret)
  14499     (while continue
  14500       (setq ret (re-search-backward regexp limit noerror))
  14501       (when (or (null ret)
  14502                 (and (not (get-text-property (point) 'part-token))
  14503                      (not (get-text-property (point) 'block-side))
  14504                      (not (get-text-property (point) 'jsx-depth)))
  14505                 )
  14506         (setq continue nil)
  14507         ) ;when
  14508       ) ;while
  14509     ret))
  14510 
  14511 (defun web-mode-javascript-rsf (regexp &optional limit noerror)
  14512   (unless limit (setq limit (web-mode-part-end-position (point))))
  14513   (unless noerror (setq noerror t))
  14514   (let ((continue t) ret)
  14515     (while continue
  14516       (setq ret (re-search-forward regexp limit t))
  14517       (when (or (null ret)
  14518                 (and (not (get-text-property (point) 'part-token))
  14519                      (not (get-text-property (point) 'block-side))
  14520                      (not (get-text-property (point) 'jsx-depth)))
  14521                 )
  14522         (setq continue nil)
  14523         ) ;when
  14524       ) ;while
  14525     ret))
  14526 
  14527 (defun web-mode-dom-sf (expr &optional limit noerror)
  14528   (unless noerror (setq noerror t))
  14529   (let ((continue t) ret)
  14530     (while continue
  14531       (setq ret (search-forward expr limit noerror))
  14532       (if (or (null ret)
  14533               (not (get-text-property (- (point) (length expr)) 'block-side)))
  14534           (setq continue nil))
  14535       )
  14536     ret))
  14537 
  14538 (defun web-mode-dom-rsf (regexp &optional limit noerror)
  14539   (unless noerror (setq noerror t))
  14540   (let ((continue t) (ret nil))
  14541     (while continue
  14542       (setq ret (re-search-forward regexp limit noerror))
  14543       ;;      (message "ret=%S point=%S limit=%S i=%S" ret (point) limit 0)
  14544       (cond
  14545         ((null ret)
  14546          (setq continue nil))
  14547         ((or (get-text-property (match-beginning 0) 'block-side)
  14548              (get-text-property (match-beginning 0) 'part-token))
  14549          )
  14550         (t
  14551          (setq continue nil))
  14552         ) ;cond
  14553       ) ;while
  14554     ret))
  14555 
  14556 (defun web-mode-rsb-position (pos regexp &optional limit noerror)
  14557   (unless noerror (setq noerror t))
  14558   (save-excursion
  14559     (goto-char pos)
  14560     (if (re-search-backward regexp limit noerror) (point) nil)
  14561     ))
  14562 
  14563 (defun web-mode-rsb (regexp &optional limit noerror)
  14564   (unless noerror (setq noerror t))
  14565   (let ((continue t) ret)
  14566     (while continue
  14567       (setq ret (re-search-backward regexp limit noerror))
  14568       (if (or (null ret)
  14569               (not (web-mode-is-comment-or-string)))
  14570           (setq continue nil)))
  14571     ret))
  14572 
  14573 (defun web-mode-rsf (regexp &optional limit noerror)
  14574   (unless noerror (setq noerror t))
  14575   (let ((continue t) ret)
  14576     (while continue
  14577       (setq ret (re-search-forward regexp limit noerror))
  14578       (if (or (null ret)
  14579               (not (web-mode-is-comment-or-string)))
  14580           (setq continue nil))
  14581       )
  14582     ret))
  14583 
  14584 (defun web-mode-sb (expr &optional limit noerror)
  14585   (unless noerror (setq noerror t))
  14586   (let ((continue t) ret)
  14587     (while continue
  14588       (setq ret (search-backward expr limit noerror))
  14589       (if (or (null ret)
  14590               (not (web-mode-is-comment-or-string)))
  14591           (setq continue nil)))
  14592     ret))
  14593 
  14594 (defun web-mode-sf (expr &optional limit noerror)
  14595   (unless noerror (setq noerror t))
  14596   (let ((continue t) ret)
  14597     (while continue
  14598       (setq ret (search-forward expr limit noerror))
  14599       (if (or (null ret)
  14600               (not (web-mode-is-comment-or-string)))
  14601           (setq continue nil)))
  14602     ret))
  14603 
  14604 (defun web-mode-content-rsf (regexp &optional limit noerror)
  14605   (unless noerror (setq noerror t))
  14606   (let ((continue t) ret beg end)
  14607     (while continue
  14608       (setq ret (re-search-forward regexp limit noerror)
  14609             beg (if (null ret) (point) (match-beginning 0))
  14610             end (if (null ret) (point) (1- (match-end 0))))
  14611       (if (or (null ret)
  14612               (and (web-mode-is-content beg)
  14613                    (web-mode-is-content end)))
  14614           (setq continue nil)))
  14615     ret))
  14616 
  14617 ;;---- ADVICES -----------------------------------------------------------------
  14618 
  14619 (defadvice ac-start (before web-mode-set-up-ac-sources activate)
  14620   "Set `ac-sources' based on current language before running auto-complete."
  14621   (when (equal major-mode 'web-mode)
  14622     ;; set ignore each time to nil. User has to implement a hook to change it
  14623     ;; for each completion
  14624     (setq web-mode-ignore-ac-start-advice nil)
  14625     (run-hooks 'web-mode-before-auto-complete-hooks)
  14626     (unless web-mode-ignore-ac-start-advice
  14627       (when web-mode-ac-sources-alist
  14628         (let ((new-web-mode-ac-sources
  14629                (assoc (web-mode-language-at-pos)
  14630                       web-mode-ac-sources-alist)))
  14631           (setq ac-sources (cdr new-web-mode-ac-sources)))))))
  14632 
  14633 ;;---- MINOR MODE ADDONS -------------------------------------------------------
  14634 
  14635 (defun web-mode-yasnippet-exit-hook ()
  14636   "Yasnippet exit hook"
  14637   (when (and (boundp 'yas-snippet-beg) (boundp 'yas-snippet-end))
  14638     (indent-region yas-snippet-beg yas-snippet-end)))
  14639 
  14640 (defun web-mode-imenu-index ()
  14641   "Returns imenu items."
  14642   (interactive)
  14643   (let (toc-index
  14644         line)
  14645     (save-excursion
  14646       (goto-char (point-min))
  14647       (while (not (eobp))
  14648         (setq line (buffer-substring-no-properties
  14649                     (line-beginning-position)
  14650                     (line-end-position)))
  14651         (let (found
  14652               (i 0)
  14653               item
  14654               regexp
  14655               type
  14656               type-idx
  14657               content
  14658               content-idx
  14659               content-regexp
  14660               close-tag-regexp
  14661               concat-str
  14662               jumpto
  14663               str)
  14664           (while (and (not found ) (< i (length web-mode-imenu-regexp-list)))
  14665             (setq item (nth i web-mode-imenu-regexp-list))
  14666             (setq regexp (nth 0 item))
  14667             (setq type-idx (nth 1 item))
  14668             (setq content-idx (nth 2 item))
  14669             (setq concat-str (nth 3 item))
  14670             (when (not (numberp content-idx))
  14671               (setq content-regexp (nth 2 item)
  14672                     close-tag-regexp (nth 4 item)
  14673                     content-idx nil))
  14674 
  14675             (when (string-match regexp line)
  14676 
  14677               (cond
  14678                 (content-idx
  14679                  (setq type (match-string type-idx line))
  14680                  (setq content (match-string content-idx line))
  14681                  (setq str (concat type concat-str content))
  14682                  (setq jumpto (line-beginning-position)))
  14683                 (t
  14684                  (let (limit)
  14685                    (setq type (match-string type-idx line))
  14686                    (goto-char (line-beginning-position))
  14687                    (save-excursion
  14688                      (setq limit (re-search-forward close-tag-regexp (point-max) t)))
  14689 
  14690                    (when limit
  14691                      (when (re-search-forward content-regexp limit t)
  14692                        (setq content (match-string 1))
  14693                        (setq str (concat type concat-str content))
  14694                        (setq jumpto (line-beginning-position))
  14695                        )
  14696                      )))
  14697                 )
  14698               (when str (setq toc-index
  14699                               (cons (cons str jumpto)
  14700                                     toc-index)
  14701                               )
  14702                     (setq found t))
  14703               )
  14704             (setq i (1+ i))))
  14705         (forward-line)
  14706         (goto-char (line-end-position)) ;; make sure we are at eobp
  14707         ))
  14708     (nreverse toc-index)))
  14709 
  14710 ;;---- UNIT TESTING ------------------------------------------------------------
  14711 
  14712 (defun web-mode-test ()
  14713   "Executes web-mode unit tests. See `web-mode-tests-directory'."
  14714   (interactive)
  14715   (let (files regexp)
  14716     (setq regexp "^[[:alnum:]][[:alnum:]._]+\\'")
  14717     (setq files (directory-files web-mode-tests-directory t regexp))
  14718     (dolist (file files)
  14719       (cond
  14720         ((eq (string-to-char (file-name-nondirectory file)) ?\_)
  14721          (delete-file file))
  14722         (t
  14723          (web-mode-test-process file))
  14724         ) ;cond
  14725       ) ;dolist
  14726     ))
  14727 
  14728 (defun web-mode-test-process (file)
  14729   (with-temp-buffer
  14730     (let (out sig1 sig2 success err)
  14731       (setq-default indent-tabs-mode nil)
  14732       (if (string-match-p "sql" file)
  14733           (setq web-mode-enable-sql-detection t)
  14734           (setq web-mode-enable-sql-detection nil))
  14735       (insert-file-contents file)
  14736       (set-visited-file-name file)
  14737       (web-mode)
  14738       (setq sig1 (md5 (current-buffer)))
  14739       (delete-horizontal-space)
  14740       (while (not (eobp))
  14741         (forward-line)
  14742         (delete-horizontal-space)
  14743         (end-of-line))
  14744       (web-mode-buffer-indent)
  14745       (setq sig2 (md5 (current-buffer)))
  14746       (setq success (string= sig1 sig2))
  14747       (setq out (concat (if success "ok" "ko") " : " (file-name-nondirectory file) "\n"))
  14748       (princ out)
  14749       (setq err (concat (file-name-directory file) "_err." (file-name-nondirectory file)))
  14750       (if success
  14751           (when (file-readable-p err)
  14752             (delete-file err))
  14753           (write-file err)
  14754           (message "[%s]" (buffer-string))
  14755           ) ;if
  14756       out)))
  14757 
  14758 ;;---- MISC --------------------------------------------------------------------
  14759 
  14760 (defun web-mode-set-engine (engine)
  14761   "Set the engine for the current buffer."
  14762   (interactive
  14763    (list (completing-read
  14764           "Engine: "
  14765           (let (engines)
  14766             (dolist (elt web-mode-engines)
  14767               (setq engines (append engines (list (car elt)))))
  14768             engines))))
  14769   (setq web-mode-content-type "html"
  14770         web-mode-engine (web-mode-engine-canonical-name engine)
  14771         web-mode-minor-engine engine)
  14772   (web-mode-on-engine-setted)
  14773   (web-mode-buffer-fontify))
  14774 
  14775 (defun web-mode-set-content-type (content-type)
  14776   "Set the content-type for the current buffer"
  14777   (interactive (list (completing-read "Content-type: " web-mode-part-content-types)))
  14778   (setq web-mode-content-type content-type)
  14779   (when (called-interactively-p 'any)
  14780     )
  14781   (web-mode-buffer-fontify))
  14782 
  14783 (defun web-mode-on-engine-setted ()
  14784   (let (elt elts)
  14785 
  14786     (when (string= web-mode-engine "razor") (setq web-mode-enable-block-face t))
  14787     ;;(setq web-mode-engine-attr-regexp (cdr (assoc web-mode-engine web-mode-engine-attr-regexps)))
  14788     (setq web-mode-engine-token-regexp (cdr (assoc web-mode-engine web-mode-engine-token-regexps)))
  14789 
  14790     ;;(message "%S %S %S" web-mode-engine web-mode-engine-attr-regexp web-mode-engine-token-regexp)
  14791 
  14792     (when (null web-mode-minor-engine)
  14793       (setq web-mode-minor-engine "none"))
  14794 
  14795     (setq elt (assoc web-mode-engine web-mode-engine-open-delimiter-regexps))
  14796     (cond
  14797       (elt
  14798        (setq web-mode-block-regexp (cdr elt)))
  14799       ((string= web-mode-engine "archibus")
  14800        (setq web-mode-block-regexp nil))
  14801       (t
  14802        (setq web-mode-engine "none"))
  14803       )
  14804 
  14805     (unless (boundp 'web-mode-extra-auto-pairs)
  14806       (setq web-mode-extra-auto-pairs nil))
  14807 
  14808     (setq web-mode-auto-pairs
  14809           (append
  14810            (cdr (assoc web-mode-engine web-mode-engines-auto-pairs))
  14811            (cdr (assoc nil web-mode-engines-auto-pairs))
  14812            (cdr (assoc web-mode-engine web-mode-extra-auto-pairs))
  14813            (cdr (assoc nil web-mode-extra-auto-pairs))))
  14814 
  14815     (unless (boundp 'web-mode-extra-snippets)
  14816       (setq web-mode-extra-snippets nil))
  14817 
  14818     (setq elts
  14819           (append
  14820            (cdr (assoc web-mode-engine web-mode-extra-snippets))
  14821            (cdr (assoc nil             web-mode-extra-snippets))
  14822            (cdr (assoc web-mode-engine web-mode-engines-snippets))
  14823            (cdr (assoc nil             web-mode-engines-snippets))))
  14824 
  14825     ;;(message "%S" elts)
  14826 
  14827     (dolist (elt elts)
  14828       (unless (assoc (car elt) web-mode-snippets)
  14829         (setq web-mode-snippets (cons elt web-mode-snippets)))
  14830       )
  14831 
  14832     (setq web-mode-engine-font-lock-keywords
  14833           (symbol-value (cdr (assoc web-mode-engine web-mode-engines-font-lock-keywords))))
  14834 
  14835     (when (and (string= web-mode-minor-engine "jinja")
  14836                (not (member "endtrans" web-mode-django-control-blocks)))
  14837       (add-to-list 'web-mode-django-control-blocks "endtrans")
  14838       (setq web-mode-django-control-blocks-regexp
  14839             (regexp-opt web-mode-django-control-blocks t))
  14840       )
  14841 
  14842     (when (string= web-mode-engine "spip")
  14843       (modify-syntax-entry ?# "w" (syntax-table)))
  14844 
  14845     ;;(message "%S" (symbol-value (cdr (assoc web-mode-engine web-mode-engines-font-lock-keywords))))
  14846 
  14847     ))
  14848 
  14849 (defun web-mode-detect-engine ()
  14850   (save-excursion
  14851     (goto-char (point-min))
  14852     (when (re-search-forward "-\\*- engine:[ ]*\\([[:alnum:]-]+\\)[ ]*-\\*-" web-mode-chunk-length t)
  14853       (setq web-mode-minor-engine (match-string-no-properties 1))
  14854       (setq web-mode-engine (web-mode-engine-canonical-name web-mode-minor-engine)))
  14855     web-mode-minor-engine))
  14856 
  14857 (defun web-mode-guess-engine-and-content-type ()
  14858   (let (buff-name found)
  14859 
  14860     (setq buff-name (buffer-file-name))
  14861     (unless buff-name (setq buff-name (buffer-name)))
  14862     (setq web-mode-is-scratch (string= buff-name "*scratch*"))
  14863     (setq web-mode-content-type nil)
  14864 
  14865     (when (boundp 'web-mode-content-types-alist)
  14866       (setq found nil)
  14867       (dolist (elt web-mode-content-types-alist)
  14868         (when (and (not found) (string-match-p (cdr elt) buff-name))
  14869           (setq web-mode-content-type (car elt)
  14870                 found t))
  14871         ) ;dolist
  14872       ) ;when
  14873 
  14874     (unless web-mode-content-type
  14875       (setq found nil)
  14876       (dolist (elt web-mode-content-types)
  14877         (when (and (not found) (string-match-p (cdr elt) buff-name))
  14878           (setq web-mode-content-type (car elt)
  14879                 found t)
  14880           ;;(message "%S" web-mode-content-type)
  14881           ) ;when
  14882         ) ;dolist
  14883       ) ;unless
  14884 
  14885     (when (boundp 'web-mode-engines-alist)
  14886       (setq found nil)
  14887       (dolist (elt web-mode-engines-alist)
  14888         (cond
  14889           ((stringp (cdr elt))
  14890            (when (string-match-p (cdr elt) buff-name)
  14891              (setq web-mode-engine (car elt))))
  14892           ((functionp (cdr elt))
  14893            (when (funcall (cdr elt))
  14894              (setq web-mode-engine (car elt))))
  14895           ) ;cond
  14896         ) ;dolist
  14897       ) ;when
  14898 
  14899     (unless web-mode-engine
  14900       (setq found nil)
  14901       (dolist (elt web-mode-engine-file-regexps)
  14902         ;;(message "%S %S %S" (cdr elt) (car elt) buff-name)
  14903         (when (and (not found) (string-match-p (cdr elt) buff-name))
  14904           ;;(message "%S %S %S" (cdr elt) (car elt) buff-name)
  14905           (setq web-mode-engine (car elt)
  14906                 found t)
  14907           ;;(when (and web-mode-engine (string= web-mode-engine "astro"))
  14908           ;;  (setq web-mode-enable-front-matter-block t)
  14909           ;;) ;when
  14910           ) ;when
  14911         )
  14912       )
  14913 
  14914     (when (and (or (null web-mode-engine) (string= web-mode-engine "none"))
  14915                (string-match-p "php" (buffer-substring-no-properties
  14916                                       (line-beginning-position)
  14917                                       (line-end-position))))
  14918       (setq web-mode-engine "php"))
  14919 
  14920     (when (and (string= web-mode-content-type "javascript")
  14921                (string-match-p "@jsx"
  14922                                (buffer-substring-no-properties
  14923                                 (point-min)
  14924                                 (if (< (point-max) web-mode-chunk-length)
  14925                                     (point-max)
  14926                                     web-mode-chunk-length)
  14927                                 )))
  14928       (setq web-mode-content-type "jsx"))
  14929 
  14930     (when web-mode-engine
  14931       (setq web-mode-minor-engine web-mode-engine
  14932             web-mode-engine (web-mode-engine-canonical-name web-mode-engine))
  14933       )
  14934 
  14935     ;;(message "%S %S" web-mode-engine web-mode-enable-engine-detection)
  14936 
  14937     (when (and (or (null web-mode-engine)
  14938                    (string= web-mode-engine "none"))
  14939                web-mode-enable-engine-detection)
  14940       (web-mode-detect-engine))
  14941 
  14942     (web-mode-on-engine-setted)
  14943 
  14944     ))
  14945 
  14946 (defun web-mode-engine-canonical-name (name)
  14947   (let (engine)
  14948     (cond
  14949       ((null name)
  14950        nil)
  14951       ((assoc name web-mode-engines)
  14952        name)
  14953       (t
  14954        (dolist (elt web-mode-engines)
  14955          (when (and (null engine) (member name (cdr elt)))
  14956            (setq engine (car elt)))
  14957          ) ;dolist
  14958        engine)
  14959       )))
  14960 
  14961 (defun web-mode-on-after-save ()
  14962   (when web-mode-is-scratch
  14963     (web-mode-guess-engine-and-content-type)
  14964     (web-mode-buffer-fontify))
  14965   nil)
  14966 
  14967 (defun web-mode-on-exit ()
  14968   (web-mode-with-silent-modifications
  14969    (put-text-property (point-min) (point-max) 'invisible nil)
  14970    (remove-overlays)
  14971    (remove-hook 'change-major-mode-hook 'web-mode-on-exit t)
  14972    ))
  14973 
  14974 (defun web-mode-file-link (file)
  14975   "Insert a link to a file in html document. This function can be
  14976 extended to support more filetypes by customizing
  14977 `web-mode-links'."
  14978   (interactive
  14979    (list (file-relative-name (read-file-name "Link file: "))))
  14980   (let ((matched nil)
  14981         (point-line (line-number-at-pos))
  14982         (point-column (current-column)))
  14983     (dolist (type web-mode-links)
  14984       (when (string-match (car type) file)
  14985         (setq matched t)
  14986         (when (nth 2 type)
  14987           (goto-char (point-min))
  14988           (search-forward "</head>")
  14989           (backward-char 7)
  14990           (open-line 1))
  14991         (insert (format (cadr type) file))
  14992         (indent-for-tab-command)
  14993         (when (nth 2 type)
  14994           ;; return point where it was and fix indentation
  14995           (forward-line)
  14996           (indent-for-tab-command)
  14997           (if (> point-line (- (line-number-at-pos) 2))
  14998               (forward-line (+ (- point-line (line-number-at-pos)) 1))
  14999               (forward-line (- point-line (line-number-at-pos))))
  15000           (move-to-column point-column))
  15001         ;; move point back if needed
  15002         (backward-char (nth 3 type))))
  15003     (when (not matched)
  15004       (user-error "Unknown file type"))))
  15005 
  15006 (defun web-mode-reload ()
  15007   "Reload web-mode."
  15008   (interactive)
  15009   (web-mode-with-silent-modifications
  15010    (put-text-property (point-min) (point-max) 'invisible nil)
  15011    (remove-overlays)
  15012    (setq font-lock-unfontify-region-function 'font-lock-default-unfontify-region)
  15013    (load "web-mode.el")
  15014    (setq web-mode-change-beg nil
  15015          web-mode-change-end nil)
  15016    (web-mode)
  15017    ))
  15018 
  15019 (defun web-mode-measure (msg)
  15020   (let (sub)
  15021     (when (null web-mode-time) (setq web-mode-time (current-time)))
  15022     (setq sub (time-subtract (current-time) web-mode-time))
  15023     (when nil
  15024       (save-excursion
  15025         (let ((n 0))
  15026           (goto-char (point-min))
  15027           (while (web-mode-tag-next)
  15028             (setq n (1+ n))
  15029             )
  15030           (message "%S tags found" n)
  15031           )))
  15032     (message "%18s: time elapsed = %Ss %9Sµs" msg (nth 1 sub) (nth 2 sub))
  15033     ))
  15034 
  15035 (defun web-mode-reveal ()
  15036   "Display text properties at point."
  15037   (interactive)
  15038   (let (symbols out)
  15039     (setq out (format
  15040                "[point=%S engine=%S minor=%S content-type=%S language-at-pos=%S]\n"
  15041                (point)
  15042                web-mode-engine
  15043                web-mode-minor-engine
  15044                web-mode-content-type
  15045                (web-mode-language-at-pos (point))))
  15046     (setq symbols (append web-mode-scan-properties '(font-lock-face face)))
  15047     (dolist (symbol symbols)
  15048       (when symbol
  15049         (setq out (concat out (format "%s(%S) " (symbol-name symbol) (get-text-property (point) symbol)))))
  15050       )
  15051     (message "%s\n" out)
  15052     ;;(message "syntax-class=%S" (syntax-class (syntax-after (point))))
  15053     (message nil)))
  15054 
  15055 (defun web-mode-toggle-tracing ()
  15056   "Toggle tracing."
  15057   (interactive)
  15058   (if web-mode-trace
  15059       (setq web-mode-trace nil)
  15060       (message "** tracing on ** point(%S) web-mode-change-beg(%S) web-mode-change-end(%S) web-mode-skip-fontification(%S)"
  15061                (point) web-mode-change-beg web-mode-change-end web-mode-skip-fontification)
  15062       (setq web-mode-trace t)))
  15063 
  15064 (defun web-mode-debug ()
  15065   "Display informations useful for debugging."
  15066   (interactive)
  15067   (let ((modes nil)
  15068         (customs '(web-mode-enable-current-column-highlight web-mode-enable-current-element-highlight indent-tabs-mode))
  15069         (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)))
  15070     (message "\n")
  15071     (message "--- WEB-MODE DEBUG BEG ---")
  15072     (message "versions: emacs(%S.%S) web-mode(%S)"
  15073              emacs-major-version emacs-minor-version web-mode-version)
  15074     (message "vars: engine(%S) minor(%S) content-type(%S) file(%S)"
  15075              web-mode-engine
  15076              web-mode-minor-engine
  15077              web-mode-content-type
  15078              (or (buffer-file-name) (buffer-name)))
  15079     (message "system: window(%S) config(%S)" window-system system-configuration)
  15080     (message "colors: fg(%S) bg(%S) "
  15081              (cdr (assoc 'foreground-color default-frame-alist))
  15082              (cdr (assoc 'background-color default-frame-alist)))
  15083     (mapc (lambda (mode)
  15084             (condition-case nil
  15085                 (if (and (symbolp mode) (symbol-value mode) (not (member mode ignore)))
  15086                     (push mode modes))
  15087               (error nil))
  15088             ) ;lambda
  15089           minor-mode-list)
  15090     (message "minor modes: %S" modes)
  15091     (message "vars:")
  15092     (dolist (custom customs)
  15093       (message (format "%s=%S " (symbol-name custom) (symbol-value custom))))
  15094     (message "--- WEB-MODE DEBUG END ---")
  15095     (switch-to-buffer "*Messages*")
  15096     (goto-char (point-max))
  15097     (recenter)
  15098     ))
  15099 
  15100 (provide 'web-mode)
  15101 
  15102 ;;; web-mode.el ends here
  15103 
  15104 ;; Local Variables:
  15105 ;; coding: utf-8
  15106 ;; indent-tabs-mode: nil
  15107 ;; sentence-end-double-space: nil
  15108 ;; End: