dotemacs

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

web-mode.el (576937B)


      1 ;;; web-mode.el --- major mode for editing web templates -*- coding: utf-8; lexical-binding: t; -*-
      2 
      3 ;; Copyright 2011-2023 François-Xavier Bois
      4 
      5 ;; Version: 17.3.8
      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.8"
     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   :safe #'(lambda (v) (or (integerp v) (booleanp v)))
     75   :group 'web-mode)
     76 
     77 (defcustom web-mode-attr-value-indent-offset nil
     78   "Html attribute value indentation level."
     79   :type '(choice (integer :tags "Number of spaces")
     80           (const :tags "Default" nil))
     81   :safe #'(lambda (v) (or (integerp v) (booleanp v)))
     82   :group 'web-mode)
     83 
     84 (defcustom web-mode-markup-indent-offset
     85   (if (and (boundp 'standard-indent) standard-indent) standard-indent 2)
     86   "Html indentation level."
     87   :type 'integer
     88   :safe #'integerp
     89   :group 'web-mode)
     90 
     91 (defcustom web-mode-css-indent-offset
     92   (if (and (boundp 'standard-indent) standard-indent) standard-indent 2)
     93   "CSS indentation level."
     94   :type 'integer
     95   :safe #'integerp
     96   :group 'web-mode)
     97 
     98 (defcustom web-mode-code-indent-offset
     99   (if (and (boundp 'standard-indent) standard-indent) standard-indent 2)
    100   "Code (javascript, php, etc.) indentation level."
    101   :type 'integer
    102   :safe #'integerp
    103   :group 'web-mode)
    104 
    105 (defcustom web-mode-sql-indent-offset 4
    106   "Sql (inside strings) indentation level."
    107   :type 'integer
    108   :safe #'integerp
    109   :group 'web-mode)
    110 
    111 (defcustom web-mode-enable-css-colorization (display-graphic-p)
    112   "In a CSS part, set background according to the color: #xxx, rgb(x,x,x)."
    113   :type 'boolean
    114   :group 'web-mode)
    115 
    116 (defcustom web-mode-enable-comment-interpolation nil
    117   "Enable highlight of keywords like FIXME, TODO, etc. in comments."
    118   :type 'boolean
    119   :group 'web-mode)
    120 
    121 (defcustom web-mode-enable-comment-annotation nil
    122   "Enable annotation in comments (jsdoc, phpdoc, etc.)."
    123   :type 'boolean
    124   :group 'web-mode)
    125 
    126 (defcustom web-mode-enable-auto-indentation (display-graphic-p)
    127   "Auto-indentation."
    128   :type 'boolean
    129   :group 'web-mode)
    130 
    131 (defcustom web-mode-enable-auto-closing (display-graphic-p)
    132   "Auto-closing."
    133   :type 'boolean
    134   :group 'web-mode)
    135 
    136 (defcustom web-mode-enable-auto-pairing (display-graphic-p)
    137   "Auto-pairing."
    138   :type 'boolean
    139   :group 'web-mode)
    140 
    141 (defcustom web-mode-enable-auto-opening (display-graphic-p)
    142   "Html element auto-opening."
    143   :type 'boolean
    144   :group 'web-mode)
    145 
    146 (defcustom web-mode-enable-auto-quoting (display-graphic-p)
    147   "Add double quotes after the character = in a tag."
    148   :type 'boolean
    149   :group 'web-mode)
    150 
    151 (defcustom web-mode-enable-auto-expanding nil
    152   "e.g. s/ expands to <span>|</span>."
    153   :type 'boolean
    154   :group 'web-mode)
    155 
    156 (defcustom web-mode-enable-curly-brace-indentation nil
    157   "Indent lines beginning with {."
    158   :type 'boolean
    159   :group 'web-mode)
    160 
    161 (defcustom web-mode-enable-control-block-indentation t
    162   "Control blocks increase indentation."
    163   :type 'boolean
    164   :group 'web-mode)
    165 
    166 (defcustom web-mode-enable-current-element-highlight nil
    167   "Enable current element highlight."
    168   :type 'boolean
    169   :group 'web-mode)
    170 
    171 (defcustom web-mode-enable-current-column-highlight nil
    172   "Show column for current element."
    173   :type 'boolean
    174   :group 'web-mode)
    175 
    176 (defcustom web-mode-enable-whitespace-fontification nil
    177   "Enable whitespaces."
    178   :type 'boolean
    179   :group 'web-mode)
    180 
    181 (defcustom web-mode-enable-html-entities-fontification nil
    182   "Enable html entities fontification."
    183   :type 'boolean
    184   :group 'web-mode)
    185 
    186 (defcustom web-mode-enable-block-face nil
    187   "Enable block face (useful for setting a background for example).
    188 See web-mode-block-face."
    189   :type 'boolean
    190   :group 'web-mode)
    191 
    192 (defcustom web-mode-enable-part-face nil
    193   "Enable part face (useful for setting background of <style> or <script>
    194  elements for example). See web-mode-part-face."
    195   :type 'boolean
    196   :group 'web-mode)
    197 
    198 (defcustom web-mode-enable-inlays nil
    199   "Enable inlays (e.g. LaTeX) highlighting."
    200   :type 'boolean
    201   :group 'web-mode)
    202 
    203 (defcustom web-mode-enable-sexp-functions t
    204   "Enable specific sexp functions."
    205   :type 'boolean
    206   :group 'web-mode)
    207 
    208 (defcustom web-mode-enable-string-interpolation t
    209   "Enable string interpolation fontification (php and erb)."
    210   :type 'boolean
    211   :group 'web-mode)
    212 
    213 (defcustom web-mode-enable-literal-interpolation t
    214   "Enable template literal fontification. e.g. css` `."
    215   :type 'boolean
    216   :group 'web-mode)
    217 
    218 (defcustom web-mode-enable-sql-detection nil
    219   "Enable fontification and indentation of sql queries in strings."
    220   :type 'boolean
    221   :group 'web-mode)
    222 
    223 (defcustom web-mode-enable-heredoc-fontification t
    224   "Enable heredoc fontification. The identifier should contain JS, JAVASCRIPT,
    225  CSS or HTML."
    226   :type 'boolean
    227   :group 'web-mode)
    228 
    229 (defcustom web-mode-enable-element-content-fontification nil
    230   "Enable element content fontification. The content of an element can have a
    231 face associated."
    232   :type 'boolean
    233   :group 'web-mode)
    234 
    235 (defcustom web-mode-enable-element-tag-fontification nil
    236   "Enable tag name fontification."
    237   :type 'boolean
    238   :group 'web-mode)
    239 
    240 (defcustom web-mode-enable-front-matter-block nil
    241   "Enable front matter block (data at the beginning the template
    242 between --- and ---)."
    243   :type 'boolean
    244   :group 'web-mode)
    245 
    246 (defcustom web-mode-enable-engine-detection nil
    247   "Detect such directive -*- engine: ENGINE -*- at the top of the file."
    248   :type 'boolean
    249   :group 'web-mode)
    250 
    251 (defcustom web-mode-enable-optional-tags nil
    252   "Enable omission of certain closing tags (e.g. a li open tag followed
    253 by a li open tag is valid)."
    254   :type 'boolean
    255   :group 'web-mode)
    256 
    257 (defcustom web-mode-comment-style 1
    258   "Comment style : 1 = default, 2 = force server comments outside a block."
    259   :group 'web-mode
    260   :type '(choice (const :tag "Default" 1)
    261           (const :tag "Force engine comments" 2)))
    262 
    263 (defcustom web-mode-indent-style 2
    264   "Indentation style."
    265   :group 'web-mode
    266   :type '(choice (const :tag "Default (all lines are indented)" 2)
    267           (const :tag "Text at the beginning of line is not indented" 1)))
    268 
    269 (defcustom web-mode-auto-close-style 1
    270   "Auto-close style."
    271   :group 'web-mode
    272   :type '(choice (const :tag "Auto-close on </" 1)
    273           (const :tag "Auto-close on > and </" 2)
    274           (const :tag "Auto-close on < and >/>" 3)))
    275 
    276 (defcustom web-mode-auto-quote-style 1
    277   "Auto-quoting style."
    278   :group 'web-mode
    279   :type '(choice (const :tag "Auto-quotes with double quote" 1)
    280           (const :tag "Auto-quotes with single quote" 2)
    281           (const :tag "Auto-quotes with paren (for jsx)" 3)))
    282 
    283 (defcustom web-mode-extra-expanders '()
    284   "A list of additional expanders."
    285   :type '(alist :key-type string :value-type string)
    286   :group 'web-mode)
    287 
    288 (defcustom web-mode-extra-auto-pairs '()
    289   "A list of additional auto-pairs."
    290   :type '(alist :key-type string :value-type string)
    291   :group 'web-mode)
    292 
    293 (defcustom web-mode-extra-snippets '()
    294   "A list of additional snippets."
    295   :type '(alist :key-type string :value-type string)
    296   :group 'web-mode)
    297 
    298 (defcustom web-mode-extra-builtins '()
    299   "A list of additional builtins."
    300   :type '(alist :key-type string :value-type string)
    301   :group 'web-mode)
    302 
    303 (defcustom web-mode-extra-constants '()
    304   "A list of additional constants."
    305   :type '(alist :key-type string :value-type string)
    306   :group 'web-mode)
    307 
    308 (defcustom web-mode-extra-keywords '()
    309   "A list of additional keywords."
    310   :type '(alist :key-type string :value-type string)
    311   :group 'web-mode)
    312 
    313 (defcustom web-mode-extra-types '()
    314   "A list of additional types."
    315   :type '(alist :key-type string :value-type string)
    316   :group 'web-mode)
    317 
    318 (defcustom web-mode-extra-control-blocks '()
    319   "A list of additional control blocks."
    320   :type '(alist :key-type string :value-type (repeat string))
    321   :group 'web-mode)
    322 
    323 (defcustom web-mode-tests-directory (concat default-directory "tests/")
    324   "Directory containing all the unit tests."
    325   :type 'directory
    326   :group 'web-mode)
    327 
    328 (defcustom web-mode-jsx-depth-faces
    329   nil
    330   ;;'(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)
    331   "Each jsx depth has is own face."
    332   :type '(repeat face)
    333   :group 'web-mode)
    334 
    335 (defcustom web-mode-commands-like-expand-region
    336   '(web-mode-mark-and-expand er/expand-region mc/mark-next-like-this mc/mark-previous-like-this)
    337   "Add commmand here if you have some wrapper function for er/expand-region"
    338   :type '(repeat function)
    339   :group 'web-mode)
    340 
    341 (defcustom web-mode-comment-formats
    342   '(("java"       . "/*")
    343     ("javascript" . "/*")
    344     ("typescript" . "//")
    345     ("php"        . "/*")
    346     ("css"        . "/*"))
    347   "Default comment format for a language"
    348   :type '(alist :key-type string :value-type string)
    349   :group 'web-mode)
    350 
    351 (defcustom web-mode-script-template-types
    352   '("text/x-handlebars"
    353     "text/x-jquery-tmpl"
    354     "text/x-jsrender"
    355     "text/html"
    356     "text/ng-template"
    357     "text/x-template"
    358     "text/mustache"
    359     "text/x-dust-template")
    360   "<script> block types that are interpreted as HTML."
    361   :type '(repeat string)
    362   :group 'web-mode)
    363 
    364 ;; https://developer.mozilla.org/en-US/docs/Web/HTML/Element
    365 (defcustom web-mode-tag-list
    366   '("html" "base" "head" "link" "meta" "style" "title" "body" "address"
    367     "article" "aside" "footer" "header" "h1" "h2" "h3" "h4" "h5" "h6" "main"
    368     "nav" "section" "blockquote" "dd" "div" "dl" "dt" "figcaption" "figure"
    369     "hr" "li" "menu" "ol" "p" "pre" "ula" "a" "abbr" "b" "bdi" "bdo" "br"
    370     "cite" "code" "data" "dfn" "em" "i" "kbdmark" "q" "rp" "rt" "ruby" "s"
    371     "samp" "small" "span" "strong" "sub" "sup" "time" "u" "var" "wbr" "area"
    372     "audio" "img" "map" "track" "video" "embed" "iframe" "object" "picture"
    373     "portal" "source" "svg" "math" "canvas" "noscript" "script" "del" "ins"
    374     "caption" "col" "colgroup" "table" "tbody" "td" "tfoot" "th" "thead" "tr"
    375     "button" "datalist" "fieldset" "form" "input" "label" "legend" "meter"
    376     "optgroup" "option" "output" "progress" "select" "textarea" "details"
    377     "dialog" "summary" "slot" "template")
    378   "HTML tags used for completion."
    379   :type '(repeat string)
    380   :group 'web-mode)
    381 
    382 
    383 ;; https://www.w3schools.com/tags/ref_attributes.asp
    384 ;; Attributes marked as deprecated in HTML 5 are not added.
    385 (defcustom web-mode-attribute-list
    386   '("accept" "accesskey" "action" "alt" "async" "autocomplete" "autofocus"
    387     "autoplay" "charset" "checked" "cite" "class" "cols" "colspan" "content"
    388     "contenteditable" "controls" "coords" "data" "datetime" "default" "defer"
    389     "dir" "dirname" "disabled" "download" "draggable" "enctype" "for" "form"
    390     "formaction" "headers" "height" "hidden" "high" "href" "hreflang" "http"
    391     "id" "ismap" "kind" "label" "lang" "list" "loop" "low" "max" "maxlength"
    392     "media" "method" "min" "multiple" "muted" "name" "novalidate" "onabort"
    393     "onafterprint" "onbeforeprint" "onbeforeunload" "onblur" "oncanplay"
    394     "oncanplaythrough" "onchange" "onclick" "oncontextmenu" "oncopy"
    395     "oncuechange" "oncut" "ondblclick" "ondrag" "ondragend" "ondragenter"
    396     "ondragleave" "ondragover" "ondragstart" "ondrop" "ondurationchange"
    397     "onemptied" "onended" "onerror" "onfocus" "onhashchange" "oninput"
    398     "oninvalid" "onkeydown" "onkeypress" "onkeyup" "onload" "onloadeddata"
    399     "onloadedmetadata" "onloadstart" "onmousedown" "onmousemove" "onmouseout"
    400     "onmouseover" "onmouseup" "onmousewheel" "onoffline" "ononline"
    401     "onpagehide" "onpageshow" "onpaste" "onpause" "onplay" "onplaying"
    402     "onpopstate" "onprogress" "onratechange" "onreset" "onresize" "onscroll"
    403     "onsearch" "onseeked" "onseeking" "onselect" "onstalled" "onstorage"
    404     "onsubmit" "onsuspend" "ontimeupdate" "ontoggle" "onunload"
    405     "onvolumechange" "onwaiting" "onwheel" "open" "optimum" "pattern"
    406     "placeholder" "poster" "preload" "readonly" "rel" "required" "reversed"
    407     "rows" "rowspan" "sandbox" "scope" "selected" "shape" "size" "sizes"
    408     "span" "spellcheck" "src" "srcdoc" "srclang" "srcset" "start" "step"
    409     "style" "tabindex" "target" "title" "translate" "type" "usemap" "value"
    410     "width" "wrap")
    411   "HTML attributes used for completion."
    412   :type '(repeat string)
    413   :group 'web-mode)
    414 
    415 ;;---- FACES -------------------------------------------------------------------
    416 
    417 (defface web-mode-error-face
    418     '((t :background "red"))
    419   "Face for warning."
    420   :group 'web-mode-faces)
    421 
    422 (defface web-mode-warning-face
    423     '((t :inherit font-lock-warning-face))
    424   "Face for warning."
    425   :group 'web-mode-faces)
    426 
    427 (defface web-mode-preprocessor-face
    428     '((t :inherit font-lock-preprocessor-face))
    429   "Face for preprocessor commands."
    430   :group 'web-mode-faces)
    431 
    432 (defface web-mode-preprocessor-face
    433     '((t :inherit font-lock-preprocessor-face))
    434   "Face for preprocessor."
    435   :group 'web-mode-faces)
    436 
    437 (defface web-mode-block-delimiter-face
    438     '((t :inherit font-lock-preprocessor-face))
    439   "Face for block delimiters."
    440   :group 'web-mode-faces)
    441 
    442 (defface web-mode-block-control-face
    443     '((t :inherit font-lock-preprocessor-face))
    444   "Face for preprocessor."
    445   :group 'web-mode-faces)
    446 
    447 (defface web-mode-builtin-face
    448     '((t :inherit font-lock-builtin-face))
    449   "Face for builtins."
    450   :group 'web-mode-faces)
    451 
    452 (defface web-mode-symbol-face
    453     '((t :foreground "goldenrod2"))
    454   "Face for symbols."
    455   :group 'web-mode-faces)
    456 
    457 (defface web-mode-doctype-face
    458     '((t :foreground "Grey"))
    459   "Face for html doctype."
    460   :group 'web-mode-faces)
    461 
    462 (defface web-mode-html-tag-face
    463     '((((class color) (min-colors 88) (background dark))  :foreground "Snow4")
    464       (((class color) (min-colors 88) (background light)) :foreground "Snow4")
    465       (((class color) (min-colors 16) (background dark))  :foreground "Snow4")
    466       (((class color) (min-colors 16) (background light)) :foreground "Grey15")
    467       (((class color) (min-colors 8))                     :foreground "Snow4")
    468       (((type tty) (class mono))                          :inverse-video t)
    469       (t                                                  :foreground "Snow4"))
    470   "Face for html tags."
    471   :group 'web-mode-faces)
    472 
    473 (defface web-mode-html-tag-custom-face
    474     '((t :inherit web-mode-html-tag-face))
    475   "Face for html custom tags (e.g. <polymer-element>)."
    476   :group 'web-mode-faces)
    477 
    478 (defface web-mode-html-tag-unclosed-face
    479     '((t :inherit web-mode-html-tag-face :underline t))
    480   "Face for unclosed tags."
    481   :group 'web-mode-faces)
    482 
    483 (defface web-mode-html-tag-namespaced-face
    484     '((t :inherit web-mode-block-control-face))
    485   "Face for html namespaced tags (e.g. <c:forEach>)."
    486   :group 'web-mode-faces)
    487 
    488 (defface web-mode-html-tag-bracket-face
    489     '((((class color) (min-colors 88) (background dark))  :foreground "Snow3")
    490       (((class color) (min-colors 88) (background light)) :foreground "Grey14")
    491       (((class color) (min-colors 16) (background dark))  :foreground "Snow3")
    492       (((class color) (min-colors 16) (background light)) :foreground "Grey14")
    493       (((class color) (min-colors 8))                     :foreground "Snow3")
    494       (((type tty) (class mono))                          :inverse-video t)
    495       (t                                                  :foreground "Snow3"))
    496   "Face for html tags angle brackets (<, > and />)."
    497   :group 'web-mode-faces)
    498 
    499 (defface web-mode-html-attr-name-face
    500     '((((class color) (min-colors 88) (background dark))  :foreground "Snow3")
    501       (((class color) (min-colors 88) (background light)) :foreground "Snow4")
    502       (((class color) (min-colors 16) (background dark))  :foreground "Snow3")
    503       (((class color) (min-colors 16) (background light)) :foreground "Grey13")
    504       (((class color) (min-colors 8))                     :foreground "Snow3")
    505       (((type tty) (class mono))                          :inverse-video t)
    506       (t                                                  :foreground "Snow4"))
    507   "Face for html attribute names."
    508   :group 'web-mode-faces)
    509 
    510 (defface web-mode-html-attr-custom-face
    511     '((t :inherit web-mode-html-attr-name-face))
    512   "Face for custom attribute names (e.g. data-*)."
    513   :group 'web-mode-faces)
    514 
    515 (defface web-mode-html-attr-engine-face
    516     '((t :inherit web-mode-block-delimiter-face))
    517   "Face for custom engine attribute names (e.g. ng-*)."
    518   :group 'web-mode-faces)
    519 
    520 (defface web-mode-html-attr-equal-face
    521     '((t :inherit web-mode-html-attr-name-face))
    522   "Face for the = character between name and value."
    523   :group 'web-mode-faces)
    524 
    525 (defface web-mode-html-attr-value-face
    526     '((t :inherit font-lock-string-face))
    527   "Face for html attribute values."
    528   :group 'web-mode-faces)
    529 
    530 (defface web-mode-block-attr-name-face
    531     '((t :foreground "#8fbc8f"))
    532   "Face for block attribute names."
    533   :group 'web-mode-faces)
    534 
    535 (defface web-mode-block-attr-value-face
    536     '((t :foreground "#5f9ea0"))
    537   "Face for block attribute values."
    538   :group 'web-mode-faces)
    539 
    540 (defface web-mode-variable-name-face
    541     '((t :inherit font-lock-variable-name-face))
    542   "Face for variable names."
    543   :group 'web-mode-faces)
    544 
    545 (defface web-mode-css-selector-face
    546     '((t :inherit font-lock-keyword-face))
    547   "Face for CSS rules."
    548   :group 'web-mode-faces)
    549 
    550 (defface web-mode-css-selector-class-face
    551     '((t :inherit font-lock-keyword-face))
    552   "Face for CSS class rules."
    553   :group 'web-mode-faces)
    554 
    555 (defface web-mode-css-selector-tag-face
    556     '((t :inherit font-lock-keyword-face))
    557   "Face for CSS tag rules."
    558   :group 'web-mode-faces)
    559 
    560 (defface web-mode-css-pseudo-class-face
    561     '((t :inherit font-lock-builtin-face))
    562   "Face for CSS pseudo-classes."
    563   :group 'web-mode-faces)
    564 
    565 (defface web-mode-css-at-rule-face
    566     '((t :inherit font-lock-constant-face))
    567   "Face for CSS at-rules."
    568   :group 'web-mode-faces)
    569 
    570 (defface web-mode-css-property-name-face
    571     '((t :inherit font-lock-variable-name-face))
    572   "Face for CSS props."
    573   :group 'web-mode-faces)
    574 
    575 (defface web-mode-css-color-face
    576     '((t :inherit font-lock-builtin-face))
    577   "Face for CSS colors (#xxx)."
    578   :group 'web-mode-faces)
    579 
    580 (defface web-mode-css-priority-face
    581     '((t :inherit font-lock-builtin-face))
    582   "Face for CSS priority (!important)."
    583   :group 'web-mode-faces)
    584 
    585 (defface web-mode-css-function-face
    586     '((t :inherit font-lock-builtin-face))
    587   "Face for CSS functions."
    588   :group 'web-mode-faces)
    589 
    590 (defface web-mode-css-variable-face
    591     '((t :inherit web-mode-variable-name-face :slant italic))
    592   "Face for CSS vars."
    593   :group 'web-mode-faces)
    594 
    595 (defface web-mode-function-name-face
    596     '((t :inherit font-lock-function-name-face))
    597   "Face for function names."
    598   :group 'web-mode-faces)
    599 
    600 (defface web-mode-filter-face
    601     '((t :inherit font-lock-function-name-face))
    602   "Face for function names."
    603   :group 'web-mode-faces)
    604 
    605 (defface web-mode-function-call-face
    606     '((t :inherit font-lock-function-name-face))
    607   "Face for function calls."
    608   :group 'web-mode-faces)
    609 
    610 (defface web-mode-string-face
    611     '((t :inherit font-lock-string-face))
    612   "Face for strings."
    613   :group 'web-mode-faces)
    614 
    615 (defface web-mode-block-string-face
    616     '((t :inherit web-mode-string-face))
    617   "Face for block strings."
    618   :group 'web-mode-faces)
    619 
    620 (defface web-mode-part-string-face
    621     '((t :inherit web-mode-string-face))
    622   "Face for part strings."
    623   :group 'web-mode-faces)
    624 
    625 (defface web-mode-javascript-string-face
    626     '((t :inherit web-mode-string-face))
    627   "Face for javascript strings."
    628   :group 'web-mode-faces)
    629 
    630 (defface web-mode-interpolate-color1-face
    631     '((t :inherit web-mode-string-face))
    632   "Face for element interpolation strings."
    633   :group 'web-mode-faces)
    634 
    635 (defface web-mode-interpolate-color2-face
    636     '((t :inherit web-mode-string-face))
    637   "Face for element interpolation strings."
    638   :group 'web-mode-faces)
    639 
    640 (defface web-mode-interpolate-color3-face
    641     '((t :inherit web-mode-string-face))
    642   "Face for element interpolation strings."
    643   :group 'web-mode-faces)
    644 
    645 (defface web-mode-interpolate-color4-face
    646     '((t :inherit web-mode-string-face))
    647   "Face for element interpolation strings."
    648   :group 'web-mode-faces)
    649 
    650 (defface web-mode-css-string-face
    651     '((t :inherit web-mode-string-face))
    652   "Face for css strings."
    653   :group 'web-mode-faces)
    654 
    655 (defface web-mode-json-key-face
    656     '((t :foreground "plum"))
    657   "Face for json key strings."
    658   :group 'web-mode-faces)
    659 
    660 (defface web-mode-json-context-face
    661     '((t :foreground "orchid3"))
    662   "Face for json context strings."
    663   :group 'web-mode-faces)
    664 
    665 (defface web-mode-json-string-face
    666     '((t :inherit web-mode-string-face))
    667   "Face for json strings."
    668   :group 'web-mode-faces)
    669 
    670 (defface web-mode-comment-face
    671     '((t :inherit font-lock-comment-face))
    672   "Face for comments."
    673   :group 'web-mode-faces)
    674 
    675 (defface web-mode-block-comment-face
    676     '((t :inherit web-mode-comment-face))
    677   "Face for server comments."
    678   :group 'web-mode-faces)
    679 
    680 (defface web-mode-part-comment-face
    681     '((t :inherit web-mode-comment-face))
    682   "Face for part comments."
    683   :group 'web-mode-faces)
    684 
    685 (defface web-mode-json-comment-face
    686     '((t :inherit web-mode-comment-face))
    687   "Face for json comments."
    688   :group 'web-mode-faces)
    689 
    690 (defface web-mode-javascript-comment-face
    691     '((t :inherit web-mode-comment-face))
    692   "Face for javascript comments."
    693   :group 'web-mode-faces)
    694 
    695 (defface web-mode-css-comment-face
    696     '((t :inherit web-mode-comment-face))
    697   "Face for css comments."
    698   :group 'web-mode-faces)
    699 
    700 (defface web-mode-annotation-face
    701     '((t :inherit web-mode-comment-face))
    702   "Face for code annotations."
    703   :group 'web-mode-faces)
    704 
    705 (defface web-mode-annotation-tag-face
    706     '((t :inherit web-mode-annotation-face :underline t))
    707   "Face for @tags in code annotations."
    708   :group 'web-mode-faces)
    709 
    710 (defface web-mode-annotation-type-face
    711     '((t :inherit web-mode-annotation-face :weight bold))
    712   "Face for types in code annotations."
    713   :group 'web-mode-faces)
    714 
    715 (defface web-mode-annotation-value-face
    716     '((t :inherit web-mode-annotation-face :slant italic))
    717   "Face for values in code annotations."
    718   :group 'web-mode-faces)
    719 
    720 (defface web-mode-annotation-html-face
    721     '((t :inherit web-mode-annotation-face :slant italic))
    722   "Face for HTML tags in code annotations."
    723   :group 'web-mode-faces)
    724 
    725 (defface web-mode-constant-face
    726     '((t :inherit font-lock-constant-face))
    727   "Face for language constants."
    728   :group 'web-mode-faces)
    729 
    730 (defface web-mode-type-face
    731     '((t :inherit font-lock-type-face))
    732   "Face for language types."
    733   :group 'web-mode-faces)
    734 
    735 (defface web-mode-keyword-face
    736     '((t :inherit font-lock-keyword-face))
    737   "Face for language keywords."
    738   :group 'web-mode-faces)
    739 
    740 (defface web-mode-param-name-face
    741     '((t :foreground "Snow3"))
    742   "Face for server attribute names."
    743   :group 'web-mode-faces)
    744 
    745 (defface web-mode-whitespace-face
    746     '((t :background "DarkOrchid4"))
    747   "Face for whitespaces."
    748   :group 'web-mode-faces)
    749 
    750 (defface web-mode-inlay-face
    751     '((((class color) (min-colors 88) (background dark))  :background "Black")
    752       (((class color) (min-colors 88) (background light)) :background "LightYellow1")
    753       (((class color) (min-colors 16) (background dark))  :background "Brey18")
    754       (((class color) (min-colors 16) (background light)) :background "LightYellow1")
    755       (((class color) (min-colors 8))                     :background "Black")
    756       (((type tty) (class mono))                          :inverse-video t)
    757       (t                                                  :background "Grey"))
    758   "Face for inlays. Must be used in conjunction with web-mode-enable-inlays."
    759   :group 'web-mode-faces)
    760 
    761 (defface web-mode-block-face
    762     '((((class color) (min-colors 88) (background dark))  :background "Black")
    763       (((class color) (min-colors 88) (background light)) :background "LightYellow1")
    764       (((class color) (min-colors 16) (background dark))  :background "Grey18")
    765       (((class color) (min-colors 16) (background light)) :background "LightYellow1")
    766       (((class color) (min-colors 8))                     :background "Black")
    767       (((type tty) (class mono))                          :inverse-video t)
    768       (t                                                  :background "Grey"))
    769   "Face for blocks (useful for setting a background for example).
    770 Must be used in conjunction with web-mode-enable-block-face."
    771   :group 'web-mode-faces)
    772 
    773 (defface web-mode-part-face
    774     '((t :inherit web-mode-block-face))
    775   "Face for parts."
    776   :group 'web-mode-faces)
    777 
    778 (defface web-mode-script-face
    779     '((t :inherit web-mode-part-face))
    780   "Face for javascript inside a script element."
    781   :group 'web-mode-faces)
    782 
    783 (defface web-mode-style-face
    784     '((t :inherit web-mode-part-face))
    785   "Face for css inside a style element."
    786   :group 'web-mode-faces)
    787 
    788 (defface web-mode-folded-face
    789     '((t :underline t))
    790   "Overlay face for folded."
    791   :group 'web-mode-faces)
    792 
    793 (defface web-mode-bold-face
    794     '((t :weight bold))
    795   "bold face."
    796   :group 'web-mode-faces)
    797 
    798 (defface web-mode-italic-face
    799     '((t :slant italic))
    800   "bold face."
    801   :group 'web-mode-faces)
    802 
    803 (defface web-mode-underline-face
    804     '((t :underline t))
    805   "bold face."
    806   :group 'web-mode-faces)
    807 
    808 (defface web-mode-current-element-highlight-face
    809     '((t :background "#000000" :foreground "#ffffff"))
    810   "Overlay face for element highlight."
    811   :group 'web-mode-faces)
    812 
    813 (defface web-mode-current-column-highlight-face
    814     '((t :background "#3e3c36"))
    815   "Overlay face for current column."
    816   :group 'web-mode-faces)
    817 
    818 (defface web-mode-comment-keyword-face
    819     '((t :weight bold :box t))
    820   "Comment keywords."
    821   :group 'web-mode-faces)
    822 
    823 (defface web-mode-sql-keyword-face
    824     '((t :weight bold :slant italic))
    825   "Sql keywords."
    826   :group 'web-mode-faces)
    827 
    828 (defface web-mode-html-entity-face
    829     '((t :slant italic))
    830   "Face html entities (e.g. &#8211;, &eacute;)."
    831   :group 'web-mode-faces)
    832 
    833 ;; https://material.io/tools/color/#!/?view.left=0&view.right=0
    834 (defface web-mode-jsx-depth-1-face
    835     '((t :background "#000053"))
    836   "jsx depth 1"
    837   :group 'web-mode-faces)
    838 
    839 (defface web-mode-jsx-depth-2-face
    840     '((t :background "#001970"))
    841   "jsx"
    842   :group 'web-mode-faces)
    843 
    844 (defface web-mode-jsx-depth-3-face
    845     '((t :background "#002984"))
    846   "jsx"
    847   :group 'web-mode-faces)
    848 
    849 (defface web-mode-jsx-depth-4-face
    850     '((t :background "#49599a"))
    851   "jsx"
    852   :group 'web-mode-faces)
    853 
    854 (defface web-mode-jsx-depth-5-face
    855     '((t :background "#9499b7"))
    856   "jsx"
    857   :group 'web-mode-faces)
    858 
    859 ;;---- VARS --------------------------------------------------------------------
    860 
    861 (defvar font-lock-beg)
    862 (defvar font-lock-end)
    863 
    864 (defvar web-mode-auto-pairs nil)
    865 (defvar web-mode-block-regexp nil)
    866 (defvar web-mode-change-beg nil)
    867 (defvar web-mode-change-end nil)
    868 (defvar web-mode-chunk-length 64)
    869 (defvar web-mode-column-overlays nil)
    870 (defvar web-mode-comments-invisible nil)
    871 (defvar web-mode-content-type "")
    872 (defvar web-mode-engine nil)
    873 ;;(defvar web-mode-engine-attr-regexp nil)
    874 (defvar web-mode-engine-font-lock-keywords nil)
    875 (defvar web-mode-engine-token-regexp nil)
    876 (defvar web-mode-expand-initial-pos nil)
    877 (defvar web-mode-expand-initial-scroll nil)
    878 (defvar web-mode-expand-previous-state "")
    879 ;;(defvar web-mode-font-lock-keywords '(web-mode-font-lock-highlight))
    880 (defvar web-mode-skip-fontification nil)
    881 (defvar web-mode-inlay-regexp nil)
    882 (defvar web-mode-is-scratch nil)
    883 (defvar web-mode-jshint-errors 0)
    884 (defvar web-mode-minor-engine nil)
    885 (defvar web-mode-obarray nil)
    886 (defvar web-mode-overlay-tag-start nil)
    887 (defvar web-mode-overlay-tag-end nil)
    888 (defvar web-mode-part-beg nil)
    889 (defvar web-mode-scan-beg nil)
    890 (defvar web-mode-scan-end nil)
    891 (defvar web-mode-snippets nil)
    892 (defvar web-mode-time nil)
    893 
    894 (defvar web-mode-offsetless-elements
    895   '())
    896 
    897 (defvar web-mode-indentless-elements
    898   '("code" "pre" "textarea"))
    899 
    900 (defvar web-mode-indentless-attributes
    901   '("onclick" "onmouseover" "onmouseout" "onsubmit"))
    902 
    903 (defvar web-mode-void-elements
    904   '("area" "base" "br" "col" "command" "embed" "hr" "img" "input" "keygen"
    905     "link" "meta" "param" "source" "track" "wbr" "tmpl_var"))
    906 
    907 (defvar web-mode-part-content-types
    908   '("css" "javascript" "json" "jsx" "markdown" "pug" "ruby"
    909     "sass" "sql" "stylus" "typescript"))
    910 
    911 (defvar web-mode-javascript-languages '("javascript" "jsx" "ejs"))
    912 
    913 ;; NOTE: without 'syntax-table forward-word fails (#377)
    914 (defvar web-mode-scan-properties
    915   (list 'tag-beg 'tag-end 'tag-name 'tag-type
    916         'tag-attr 'tag-attr-beg 'tag-attr-end
    917         'part-side 'part-token
    918         'jsx-beg 'jsx-end 'jsx-depth
    919         'block-side 'block-token 'block-controls 'block-beg 'block-end
    920         'syntax-table)
    921   "Text properties used for code regions/tokens and html nodes.")
    922 
    923 (defvar web-mode-start-tag-regexp "<\\([[:alpha:]][[:alnum:].:_-]*\\|>\\)"
    924   "Regular expression for HTML/XML start tag.")
    925 
    926 (defvar web-mode-tag-regexp "</?\\([[:alpha:]][[:alnum:].:_-]*\\)"
    927   "Regular expression for HTML/XML tag.")
    928 
    929 (defvar web-mode-dom-regexp "<\\(/?>\\|/?[[:alpha:]][[:alnum:].:_-]*\\|!--\\|!\\[CDATA\\[\\|!doctype\\|!DOCTYPE\\|\?xml\\)")
    930 
    931 (defvar web-mode-whitespaces-regexp
    932   "^[ \t]\\{2,\\}$\\| \t\\|\t \\|[ \t]+$\\|^[ \n\t]+\\'\\|^[ \t]?[\n]\\{2,\\}"
    933   "Regular expression for whitespaces.")
    934 
    935 (defvar web-mode-imenu-regexp-list
    936   '(("<\\(h[1-9]\\)\\([^>]*\\)>\\([^<]*\\)" 1 3 ">")
    937     ("^[ \t]*<\\([@a-z]+\\)[^>]*>? *$" 1 "id=\"\\([a-zA-Z0-9_]+\\)\"" "#" ">"))
    938   "Regexps to match imenu items (see https://web-mode.org/doc/imenu.txt)")
    939 
    940 ;; https://www.gnu.org/software/emacs/manual/html_node/ccmode/Syntactic-Symbols.html
    941 (defvar web-mode-indentation-params
    942   '(("lineup-args"       . t)
    943     ("lineup-calls"      . t)
    944     ("lineup-concats"    . t)
    945     ("lineup-quotes"     . t)
    946     ("lineup-ternary"    . t)
    947     ("case-extra-offset" . t)
    948     ))
    949 
    950 (defvar web-mode-tag-history nil)
    951 (defvar web-mode-attribute-history nil)
    952 (defvar web-mode-attribute-value-history nil)
    953 
    954 (defvar web-mode-engines
    955   '(("angular"          . ("angularjs"))
    956     ("anki"             . ())
    957     ("antlers"          . ())
    958     ("archibus"         . ())
    959     ("artanis"          . ())
    960     ("asp"              . ())
    961     ("aspx"             . ())
    962     ("astro"            . ())
    963     ("blade"            . ("laravel"))
    964     ("cl-emb"           . ())
    965     ("clip"             . ())
    966     ("closure"          . ("soy"))
    967     ("ctemplate"        . ("mustache" "handlebars" "hapax" "ngtemplate" "ember"
    968                            "kite" "meteor" "blaze" "ractive" "velvet"))
    969     ("django"           . ("dtl" "twig" "swig" "jinja" "jinja2" "erlydtl" "liquid"
    970                            "clabango" "selmer" "nunjucks"))
    971     ("dust"             . ("dustjs"))
    972     ("ejs"              . ())
    973     ("elixir"           . ("phoenix"))
    974     ("erb"              . ("eruby" "erubis" "crystal"))
    975     ("expressionengine" . ("ee"))
    976     ("freemarker"       . ())
    977     ("go"               . ("gtl" "hugo"))
    978     ("hero"             . ())
    979     ("json-t"           . ())
    980     ("jsp"              . ("grails"))
    981     ("mako"             . ())
    982     ("marko"            . ())
    983     ("mason"            . ("poet"))
    984     ("lsp"              . ("lisp"))
    985     ("mojolicious"      . ())
    986     ("php"              . ())
    987     ("python"           . ())
    988     ("razor"            . ("play" "play2"))
    989     ("riot"             . ())
    990     ("smarty"           . ())
    991     ("spip"             . ())
    992     ("svelte"           . ("svelte"))
    993     ("template-toolkit" . ())
    994     ("thymeleaf"        . ())
    995     ("perl"             . ())
    996     ("underscore"       . ("underscore.js"))
    997     ("velocity"         . ("vtl" "cheetah" "ssp"))
    998     ("vue"              . ("vuejs" "vue.js"))
    999     ("web2py"           . ())
   1000     ("xoops"            . ())
   1001     )
   1002   "Engine name aliases")
   1003 
   1004 (defvar web-mode-content-types
   1005   '(("css"        . "\\.\\(s?css\\|css\\.erb\\)\\'")
   1006     ("javascript" . "\\.\\([mc]?js\\|js\\.erb\\)\\'")
   1007     ("typescript" . "\\.\\([mc]?ts\\|ts\\.erb\\)\\'")
   1008     ("json"       . "\\.\\(api\\|json\\|jsonld\\)\\'")
   1009     ("jsx"        . "\\.[jt]sx\\'")
   1010     ("xml"        . "\\.xml\\'")
   1011     ("html"       . "."))
   1012   "content types")
   1013 
   1014 (defvar web-mode-engine-attr-regexps
   1015   '(("angular"   . "ng-")
   1016     ("thymeleaf" . "th:")
   1017     ("vue"       . "v-"))
   1018   "Engine custom attributes")
   1019 
   1020 (defvar web-mode-engine-attr-regexp
   1021   "^ng[-]\\|^th[:]\\|^v[-]\\|^[@:#(\[*]"
   1022   "Engine custom attributes")
   1023 
   1024 (defvar web-mode-last-enabled-feature nil)
   1025 
   1026 (defvar web-mode-features
   1027   '(("css-colorization"          . web-mode-enable-css-colorization)
   1028     ("element-highlight"         . web-mode-enable-current-element-highlight)
   1029     ("column-highlight"          . web-mode-enable-current-column-highlight)
   1030     ("whitespace-fontification"  . web-mode-enable-whitespace-fontification)
   1031     ("element-tag-fontification" . web-mode-enable-element-tag-fontification)
   1032     ("block-face"                . web-mode-enable-block-face)
   1033     ("part-face"                 . web-mode-enable-part-face)))
   1034 
   1035 (defvar web-mode-comment-prefixing t)
   1036 
   1037 (defvar web-mode-engine-file-regexps
   1038   '(("angular"          . "\\.component\\.html\\'")
   1039     ("anki"             . "\\.anki\\'")
   1040     ("antlers"          . "\\.antlers\\.html\\'")
   1041     ("archibus"         . "\\.axvw\\'")
   1042     ("artanis"          . "\\.html\\.tpl\\'")
   1043     ("asp"              . "\\.asp\\'")
   1044     ("aspx"             . "\\.as[cp]x\\'")
   1045     ("astro"            . "\\.astro\\'")
   1046     ("blade"            . "\\.blade\\.php\\'")
   1047     ("cl-emb"           . "\\.clemb\\'")
   1048     ("clip"             . "\\.ctml\\'")
   1049     ("closure"          . "\\.soy\\'")
   1050     ("ctemplate"        . "\\.\\(chtml\\|mustache\\)\\'")
   1051     ("django"           . "\\.\\(djhtml\\|tmpl\\|dtl\\|liquid\\|j2\\|njk\\)\\'")
   1052     ("dust"             . "\\.dust\\'")
   1053     ("elixir"           . "\\.[hl]?eex\\'")
   1054     ("ejs"              . "\\.ejs\\'")
   1055     ("erb"              . "\\.\\(erb\\|rhtml\\|erb\\.html\\|ecr\\)\\'")
   1056     ("expressionengine" . "\\.ee\\'")
   1057     ("freemarker"       . "\\.ftl\\'")
   1058     ("go"               . "\\.go\\(html\\|tmpl\\)\\'")
   1059     ("handlebars"       . "\\.\\(hb\\.html\\|hbs\\)\\'")
   1060     ("hero"             . "\\.hero\\'")
   1061     ("jinja"            . "\\.\\(jinja\\|nwt\\)\\'")
   1062     ("jsp"              . "\\.[gj]sp\\'")
   1063     ("lsp"              . "\\.lsp\\'")
   1064     ("mako"             . "\\.mako?\\'")
   1065     ("marko"            . "\\.marko\\'")
   1066     ("mason"            . "\\.mas\\'")
   1067     ("mojolicious"      . "\\.epl?\\'")
   1068     ("perl"             . "\\.\\(ptmpl\\|perl\\.html\\)\\'")
   1069     ("php"              . "\\.\\(p[hs]p\\|ctp\\|inc\\)\\'")
   1070     ("python"           . "\\.pml\\'")
   1071     ("razor"            . "\\.\\(cs\\|vb\\)html\\|\\.razor\\'")
   1072     ("riot"             . "\\.tag\\'")
   1073     ("smarty"           . "\\.tpl\\'")
   1074     ("svelte"           . "\\.svelte\\'")
   1075     ("template-toolkit" . "\\.tt.?\\'")
   1076     ("thymeleaf"        . "\\.thtml\\'")
   1077     ("velocity"         . "\\.v\\(sl\\|tl\\|m\\)\\'")
   1078     ("vue"              . "\\.vue\\'")
   1079     ("xoops"            . "\\.xoops'")
   1080     ;; regexp on the path, not just the extension
   1081     ("django"           . "[st]wig")
   1082     ("razor"            . "scala")
   1083     ("spip"             . "spip")
   1084     )
   1085   "Engine file extensions.")
   1086 
   1087 (defvar web-mode-content-types-alist nil
   1088   "A list of filename patterns and corresponding web-mode content types.
   1089 For example,
   1090 (setq web-mode-content-types-alist
   1091   '((\"json\" . \"/some/path/.*\\.api\\'\")
   1092     (\"jsx\"  . \"/some/react/path/.*\\.js[x]?\\'\")))")
   1093 
   1094 (defvar web-mode-engines-alist nil
   1095   "A list of filename patterns and corresponding web-mode engine. For example,
   1096 (setq web-mode-engines-alist
   1097       '((\"php\"    . \"\\\\.phtml\\\\'\")
   1098         (\"blade\"  . \"\\\\.blade\\\\.\")))")
   1099 
   1100 (defvar web-mode-smart-quotes
   1101   '("«" . "»")
   1102   "Preferred smart quotes")
   1103 
   1104 (defvar web-mode-xml-chars
   1105   '((?\& . "&amp;")
   1106     (?\< . "&lt;")
   1107     (?\> . "&gt;"))
   1108   "XML chars")
   1109 
   1110 ;; #1254 : https://html.spec.whatwg.org/entities.json
   1111 (defvar web-mode-html-entities
   1112   ;; #985
   1113   ;; remove ("gt" . 62) ("lt" . 60) ("amp" . 38)
   1114   '(("AElig" . 198) ("Aacute" . 193) ("Acirc" . 194) ("Agrave" . 192)
   1115     ("Alpha" . 913) ("Aring" . 197) ("Atilde" . 195) ("Auml" . 196)
   1116     ("Beta" . 914)
   1117     ("Ccedil" . 199) ("Chi" . 935)
   1118     ("Dagger" . 8225) ("Delta" . 916)
   1119     ("ETH" . 208) ("Eacute" . 201) ("Ecirc" . 202) ("Egrave" . 200)
   1120     ("Epsilon" . 917) ("Eta" . 919) ("Euml" . 203)
   1121     ("Gamma" . 915)
   1122     ("Iacute" . 205) ("Icirc" . 206) ("Igrave" . 204) ("Iota" . 921)
   1123     ("Iuml" . 207)
   1124     ("Kappa" . 922)
   1125     ("Lambda" . 923)
   1126     ("Mu" . 924)
   1127     ("Ntilde" . 209) ("Nu" . 925)
   1128     ("OElig" . 338) ("Oacute" . 211) ("Ocirc" . 212) ("Ograve" . 210)
   1129     ("Omega" . 937) ("Omicron" . 927) ("Oslash" . 216) ("Otilde" . 213)
   1130     ("Ouml" . 214)
   1131     ("Phi" . 934) ("Pi" . 928) ("Prime" . 8243) ("Psi" . 936)
   1132     ("Rho" . 929)
   1133     ("Scaron" . 352) ("Sigma" . 931)
   1134     ("THORN" . 222) ("Tau" . 932) ("Theta" . 920)
   1135     ("UArr" . 8657) ("Uacute" . 218) ("Uacute" . 250) ("Ucirc" . 219)
   1136     ("Ugrave" . 217)  ("Upsih" . 978)
   1137     ("Upsilon" . 933) ("Uuml" . 220) ("Uuml" . 252)
   1138     ("Xi" . 926)
   1139     ("Yacute" . 221) ("Yuml" . 376)
   1140     ("Zeta" . 918)
   1141     ("aacute" . 225) ("acirc" . 226) ("acute" . 180) ("aelig" . 230)
   1142     ("agrave" . 224) ("alefsym" . 8501) ("alpha" . 945)
   1143     ("ang" . 8736) ("apos" . 39) ("aring" . 229) ("asymp" . 8776)
   1144     ("atilde" . 227) ("auml" . 228)
   1145     ("bdquo" . 8222) ("beta" . 946) ("brvbar" . 166) ("bull" . 8226)
   1146     ("cap" . 8745) ("ccedil" . 231) ("cedil" . 184) ("cent" . 162)
   1147     ("chi" . 967) ("circ" . 710) ("clubs" . 9827) ("cong" . 8773)
   1148     ("copy" . 169) ("crarr"  . 8629) ("cup" . 8746) ("curren" . 164)
   1149     ("dArr" . 8659) ("dagger" . 8224) ("darr" . 8595) ("deg" . 176)
   1150     ("delta" . 948) ("diams" . 9830) ("divide" . 247)
   1151     ("eacute" . 233) ("ecirc"  . 234) ("egrave" . 232) ("empty" . 8709)
   1152     ("emsp" . 8195) ("ensp" . 8194) ("epsilon" . 949) ("equiv" . 8801)
   1153     ("eta" . 951) ("eth" . 240) ("euml" . 235) ("euro" . 8364) ("exist" . 8707)
   1154     ("fnof" . 402) ("forall" . 8704) ("frac12" . 189) ("frac14" . 188)
   1155     ("frac34" . 190) ("frasl" . 8260)
   1156     ("gamma" . 947) ("ge" . 8805)
   1157     ("hArr" . 8660) ("harr" . 8596) ("hearts" . 9829) ("hellip" . 8230)
   1158     ("iacute" . 237) ("icirc" . 238) ("iexcl" . 161) ("igrave" . 236)
   1159     ("image" . 8465) ("infin" . 8734) ("int" . 8747) ("iota" . 953)
   1160     ("iquest" . 191) ("isin" . 8712) ("iuml" . 239)
   1161     ("kappa" . 954)
   1162     ("lArr" . 8656) ("lambda" . 955) ("lang" . 9001) ("laquo" . 171)
   1163     ("larr" . 8592) ("lceil" . 8968) ("ldquo" . 8220) ("le" . 8804)
   1164     ("lfloor" . 8970) ("lowast" . 8727) ("loz" . 9674) ("lrm" . 8206)
   1165     ("lsaquo" . 8249) ("lsquo" . 8249)
   1166     ("macr" . 175) ("mdash" . 8212) ("micro" . 181) ("middot" . 183)
   1167     ("minus" . 8722) ("mu" . 956)
   1168     ("nabla" . 8711) ("nbsp" . 160) ("ndash" . 8211) ("ne" . 8800)
   1169     ("ni" . 8715) ("not" . 172) ("notin" . 8713) ("nsub" . 8836)
   1170     ("ntilde" . 241) ("nu" . 957) ("oacute" . 243) ("ocirc" . 244)
   1171     ("oelig" . 339) ("ograve" . 242) ("oline" . 8254) ("omega" . 969)
   1172     ("omicron" . 959) ("oplus" . 8853) ("or" . 8744) ("ordf" . 170)
   1173     ("ordm" . 186) ("oslash" . 248) ("otilde" . 245) ("otimes" . 8855)
   1174     ("ouml" . 246)
   1175     ("para" . 182) ("part" . 8706) ("permil" . 8240) ("perp" . 8869)
   1176     ("phi" . 966) ("pi" . 960) ("piv" . 982) ("plusmn" . 177) ("pound" . 163)
   1177     ("prime" . 8242) ("prod" . 8719) ("prop" . 8733) ("psi" . 968)
   1178     ("quot" . 34)
   1179     ("rArr" . 8658) ("radic" . 8730) ("rang" . 9002) ("raquo" . 187)
   1180     ("rarr" . 8594) ("rceil" . 8969) ("rdquo" . 8221) ("real" . 8476)
   1181     ("reg" . 174) ("rfloor" . 8971) ("rho" . 961) ("rlm" . 8207)
   1182     ("rsaquo" . 8250) ("rsquo" . 8250) ("sbquo" . 8218)
   1183     ("scaron" . 353) ("sdot" . 8901) ("sect" . 167) ("shy" . 173)
   1184     ("sigma" . 963) ("sigmaf" . 962) ("sim" . 8764) ("spades" . 9824)
   1185     ("sub" . 8834) ("sube" . 8838) ("sum" . 8721) ("sup" . 8835)
   1186     ("sup1" . 185) ("sup2" . 178) ("sup3" . 179) ("supe" . 8839)
   1187     ("szlig" . 223)
   1188     ("tau" . 964) ("there4" . 8756) ("theta" . 952) ("thetasym" . 977)
   1189     ("thinsp" . 8201) ("thorn" . 254) ("tilde" . 732) ("times" . 215)
   1190     ("trade" . 8482)
   1191     ("uarr" . 8593) ("ucirc" . 251) ("ugrave" . 249) ("uml" . 168)
   1192     ("upsilon" . 965)
   1193     ("weierp" . 8472)
   1194     ("xi" . 958)
   1195     ("yacute" . 253) ("yen" . 165) ("yuml" . 255)
   1196     ("zeta" . 950) ("zwj" . 8205) ("zwnj" . 8204)))
   1197 
   1198 ;; http://webdesign.about.com/od/localization/l/blhtmlcodes-ascii.htm
   1199 (defvar web-mode-display-table
   1200   (let ((table (make-display-table)))
   1201     (aset table 9  (vector ?\xBB ?\t))
   1202     (aset table 10 (vector ?\xB6 ?\n))
   1203     (aset table 32 (vector ?\xB7))
   1204     table)
   1205   "Display table used when switching to the whitespace visualization.")
   1206 
   1207 (defvar web-mode-expanders
   1208   '(("a/" . "<a href=\"|\"></a>")
   1209     ("b/" . "<table><tbody><tr><td>|</td><td></td></tr></tbody></table>")
   1210     ("c/" . "<div class=\"|\"></div>")
   1211     ("d/" . "<div>|</div>")
   1212     ("e/" . "<em>|</em>")
   1213     ("f/" . "<form>|</form>")
   1214     ("g/" . "<strong>|</strong>")
   1215     ("h/" . "<h1>|</h1>")
   1216     ("i/" . "<img src=\"|\" />")
   1217     ("j/" . "<script>|</script>")
   1218     ("l/" . "<li>|</li>")
   1219     ("m/" . "<main>|</main>")
   1220     ("n/" . "<input type=\"|\" />")
   1221     ("p/" . "<p>|</p>")
   1222     ("q/" . "<quote>|</quote>")
   1223     ("s/" . "<span>|</span>")
   1224     ("t/" . "<td>|</td>")
   1225     ("u/" . "<ul><li>|</li><li></li></ul>")
   1226     ("x/" . "<textarea>|</textarea>")
   1227     ("2/" . "<h2>|</h2>")
   1228     ("3/" . "<h3>|</h3>")
   1229     ("?/" . "<?php | ?>")))
   1230 
   1231 (defvar web-mode-engines-auto-pairs
   1232   '(("angular"          . (("{{ " . " }}")))
   1233     ("anki"             . (("{{ " . " }}")))
   1234     ("antlers"          . (("{{ "  . " }}")
   1235                            ("{{$ " . "| $}}")
   1236                            ("{{? " . "| ?}}")
   1237                            ("{{# " . "| #}}")))
   1238     ("artanis"          . (("<% "       . " %>")
   1239                            ("<%="       . " | %>")
   1240                            ("<@css"     . " | %>")
   1241                            ("<@icon"    . " | %>")
   1242                            ("<@include" . " | %>")
   1243                            ("<@js"      . " | %>")))
   1244     ("asp"              . (("<% " . " %>")))
   1245     ("aspx"             . (("<% " . " %>")
   1246                            ("<%=" . "%>")
   1247                            ("<%#" . "%>")
   1248                            ("<%$" . "%>")
   1249                            ("<%@" . "%>")
   1250                            ("<%:" . "%>")
   1251                            ("<%-" . "- | --%>")))
   1252     ("astro"            . (("{ " . " }")))
   1253     ("blade"            . (("{{{" . " | }}}")
   1254                            ("{{ " . " }}")
   1255                            ("{!!" . " | !!}")
   1256                            ("@{{" . " | }}")
   1257                            ("{{-" . "- | --}}")))
   1258     ("cl-emb"           . (("<% " . " %>")
   1259                            ("<%=" . " | %>")
   1260                            ("<%#" . " | %>")))
   1261     ("ctemplate"        . (("{{ " . "| }}")
   1262                            ("{{~ " . "| }}")
   1263                            ("{{{" . " | }}}")
   1264                            ("{~{" . " | }}")
   1265                            ("{{~{" . " | }}}")
   1266                            ("{{!" . "-- | --}}")
   1267                            ("{{^" . "}}")
   1268                            ("{{/" . "}}")
   1269                            ("{{#" . "}}")))
   1270     ("django"           . (("{{ " . " }}")
   1271                            ("{% " . " %}")
   1272                            ("{%-" . " | %}")
   1273                            ("{# " . " #}")))
   1274     ("elixir"           . (("<% " . " %>")
   1275                            ("<%=" . " | %>")
   1276                            ("<%%" . " | %>")
   1277                            ("<%#" . " | %>")))
   1278     ("ejs"              . (("<% " . " %>")
   1279                            ("<%=" . "%>")
   1280                            ("<%#" . "%>")
   1281                            ("<%-" . "%>")))
   1282     ("erb"              . (("<% " . " %>")
   1283                            ("<%=" . " %>")
   1284                            ("<%#" . "%>")
   1285                            ("<%-" . " %>")))
   1286     ("freemarker"       . (("<% " . " %>")
   1287                            ("<#-" . "- | -->")
   1288                            ("${ " . " }")
   1289                            ("[% " . " %]")
   1290                            ("[# " . " #]")
   1291                            ("[#-" . "- | --]")))
   1292     ("go"               . (("{{ " . " }}")
   1293                            ("{{-" . " | -}}")))
   1294     ("hero"             . (("<% " . " %>")
   1295                            ("<%=" . " | %>")
   1296                            ("<%!" . " | %>")
   1297                            ("<%:" . " | %>")
   1298                            ("<%#" . " | %>")
   1299                            ("<%@" . " | %>")
   1300                            ("<%~" . " | %>")
   1301                            ("<%+" . " | %>")))
   1302     ("jsp"              . (("<% " . " %>")
   1303                            ("<%-" . "- | --%>")
   1304                            ("<%=" . "%>")
   1305                            ("<%!" . "%>")
   1306                            ("<%@" . "%>")
   1307                            ("${ " . " }")))
   1308     ("lsp"              . (("<% " . " %>")
   1309                            ("<%%" . " | %>")
   1310                            ("<%#" . " | %>")))
   1311     ("mako"             . (("<% " . " %>")
   1312                            ("<%!" . " | %>")
   1313                            ("${ " . " }")))
   1314     ("marko"            . (("${ " . " }")))
   1315     ("mason"            . (("<% " . " %>")
   1316                            ("<& " . " &>")))
   1317     ("mojolicious"      . (("<% " . " %>")
   1318                            ("<%=" . " | %>")
   1319                            ("<%%" . " | %>")
   1320                            ("<%#" . " | %>")))
   1321     ("php"              . (("<?p" . "hp | ?>")
   1322                            ("<? " . " ?>")
   1323                            ("<?=" . "?>")))
   1324     ("template-toolkit" . (("[% " . " %]")
   1325                            ("[%-" . " | %]")
   1326                            ("[%#" . " | %]")))
   1327     ("riot"             . (("={ " . " }")))
   1328     ("underscore"       . (("<% " . " %>")))
   1329     ("vue"              . (("{{ " . " }}")))
   1330     ("web2py"           . (("{{ " . " }}")
   1331                            ("{{=" . "}}")))
   1332     (nil                . (("<!-" . "- | -->")))
   1333     ))
   1334 
   1335 (defvar web-mode-engines-snippets
   1336   '(("artanis" . (("if"       . "<% (if (|) %>\n\n<% ) %>")
   1337                   ("when"     . "<% (when (|) %>\n\n<% ) %>")
   1338                   ("unless"   . "<% (unless (|) %>\n\n<% ) %>")
   1339                   ("cond"     . "<% (cond %>\n<%  [(|) %>\n\n<%  ] %>\n<%  [else %>\n\n<%  ] %>\n<% ) %>")
   1340                   ("let"      . "<% (let ([|]) %>\n\n<% ) %>")
   1341                   ("let*"     . "<% (let* ([|]) %>\n\n<% ) %>")
   1342                   ("do"       . "<% (do ([|]) %>\n<%     [()] %>\n\n<% ) %>")
   1343                   ("for-each" . "<% (for-each %>\n|\n\n<% ) %>")
   1344                   ("case"     . "<% (case | %>\n<%   [() %>\n\n<%   ] %>\n<%   [() %>\n\n<%   ] %>\n<% ) %>")))
   1345     ("ejs" . (("for"     . "<% for (|) { %>\n\n<% } %>")
   1346               ("if"      . "<% if (|) { %>\n\n<% } %>")))
   1347     ("erb" . (("each"    . "<% |.each do  %>\n\n<% end %>")
   1348               ("if"      . "<% if | %>\n\n<% end %>")
   1349               ("when"    . "<% when | %>\n\n<% end %>")
   1350               ("unless"  . "<% unless | %>\n\n<% end %>")))
   1351     ("php" . (("if"      . "<?php if (|): ?>\n\n<?php endif; ?>")
   1352               ("while"   . "<?php while (|): ?>\n\n<?php endwhile; ?>")
   1353               ("for"     . "<?php for (| ; ; ): ?>\n\n<?php endfor; ?>")
   1354               ("foreach" . "<?php foreach (| as ): ?>\n\n<?php endforeach; ?>")
   1355               ("each"    . "<?php foreach (| as ): ?>\n\n<?php endforeach; ?>")
   1356               ("switch"  . "<?php switch (|): ?>\n<?php case 1: ?>\n\n<?php break ;?>\n<?php case 2: ?>\n\n<?php break ;?>\n<?php endswitch;?>")))
   1357     ("django" . (("block"      . "{% block | %}\n\n{% endblock %}")
   1358                  ("comment"    . "{% comment | %}\n\n{% endcomment %}")
   1359                  ("css"        . "{% stylesheet  %}\n\n{% endstylesheet  %}")
   1360                  ("cycle"      . "{% cycle | as  %}\n\n{% endcycle  %}")
   1361                  ("filter"     . "{% filter | %}\n\n{% endfilter %}")
   1362                  ("for"        . "{% for | in  %}\n\n{% endfor %}")
   1363                  ("if"         . "{% if | %}\n\n{% endif %}")
   1364                  ("ifequal"    . "{% ifequal | %}\n\n{% endifequal %}")
   1365                  ("ifnotequal" . "{% ifnotequal | %}\n\n{% endifnotequal %}")
   1366                  ("js"         . "{% javascript | %}\n\n{% endjavascript %}")
   1367                  ("schema"     . "{% javascript | %}\n\n{% endschema %}")
   1368                  ("safe"       . "{% safe | %}\n\n{% endsafe %}")))
   1369     ("mako" . (("if"        . "% if |:\n% endif")
   1370                ("for"       . "% for | in :\n% endfor")
   1371                ("doc"       . "<%doc>\n|\n</%doc>")
   1372                ("inherit"   . "<%inherit file=\"|\" />")
   1373                ("namespace" . "<%namespace name=\"|\" file=\"\" import=\"\"/>")
   1374                ("block"     . "<%block name=\"|\">\n</%block>")))
   1375     ("template-toolkit" . (("if"      . "[% IF | %]\n\n[% END %]")))
   1376     (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>")
   1377             ("table" . "<table><tbody>\n<tr>\n<td>|</td>\n<td></td>\n</tr>\n</tbody></table>")
   1378             ("ul"    . "<ul>\n<li>|</li>\n<li></li>\n</ul>")))
   1379     ))
   1380 
   1381 (defvar web-mode-engine-token-regexps
   1382   (list
   1383    '("antlers"     . "\"\\|'")
   1384    '("artanis"     . "\"\\|#|\\|;")
   1385    '("asp"         . "//\\|/\\*\\|\"\\|''")
   1386    '("ejs"         . "//\\|/\\*\\|\"\\|'")
   1387    '("erb"         . "\"\\|'\\|#\\|<<[-]?['\"]?\\([[:alnum:]_]+\\)['\"]?")
   1388    '("lsp"         . "\"\\|#|\\|;")
   1389    '("mako"        . "\"\\|'\\|#")
   1390    '("mason"       . "\"\\|'\\|#")
   1391    '("mojolicious" . "\"\\|'")
   1392    '("php"         . "//\\|/\\*\\|#\\|\"\\|'\\|<<<['\"]?\\([[:alnum:]]+\\)['\"]?")
   1393    '("python"      . "\"\\|'\\|#")
   1394    '("web2py"      . "\"\\|'"))
   1395   "Engine regexps used to identify tokens (strings / comments) in blocks.")
   1396 
   1397 (defvar web-mode-engine-open-delimiter-regexps
   1398   (list
   1399    '("angular"          . "{{")
   1400    '("anki"             . "{{")
   1401    '("antlers"          . "{{[@#$]?")
   1402    '("artanis"          . "<%\\|<@\\(css\\|icon\\|include\\|js\\)")
   1403    '("asp"              . "<%\\|</?[[:alpha:]]+:[[:alpha:]]+\\|</?[[:alpha:]]+Template")
   1404    '("aspx"             . "<%.")
   1405    '("astro"            . "---")
   1406    '("blade"            . "{{.\\|{!!\\|@{{\\|@[[:alpha:]]")
   1407    '("cl-emb"           . "<%")
   1408    '("closure"          . "{.\\|/\\*\\| //")
   1409    '("clip"             . "</?c:[[:alpha:]-]+")
   1410    '("ctemplate"        . "[$]?{[{~].")
   1411    '("django"           . "{[#{%]\\|^#")
   1412    '("dust"             . "{.")
   1413    '("elixir"           . "<%\\|</?[.:]")
   1414    '("ejs"              . "<%")
   1415    '("erb"              . "<%\\|^%.")
   1416    '("expressionengine" . "{.")
   1417    '("freemarker"       . "<%\\|${\\|</?[[:alpha:]]+:[[:alpha:]]\\|</?[@#]\\|\\[/?[@#].")
   1418    '("go"               . "{{.")
   1419    '("hero"             . "<%")
   1420    '("jsp"              . "<%\\|${")
   1421    '("lsp"              . "<%")
   1422    '("mako"             . "</?%\\|${\\|^[ \t]*%.\\|^[ \t]*##")
   1423    '("marko"            . "${")
   1424    '("mason"            . "</?[&%]\\|^%.")
   1425    '("mojolicious"      . "<%\\|^[ \t]*%.")
   1426    '("perl"             . "</?TMPL_[[:alpha:]]+")
   1427    '("php"              . "<\\?")
   1428    '("python"           . "<\\?")
   1429    '("razor"            . "@.\\|^[ \t]*}")
   1430    '("riot"             . "{.\\|/// begin script")
   1431    '("smarty"           . "{[[:alpha:]#$/*\"]")
   1432    '("spip"             . "\\[(#REM)\\|(\\|#[A-Z0-9_]\\|{\\|<:")
   1433    '("template-toolkit" . "\\[%\\(.\\|$\\)\\|%%#")
   1434    '("underscore"       . "<%")
   1435    '("velocity"         . "#[[:alpha:]#*]\\|$[[:alpha:]!{]")
   1436    '("vue"              . "{{\\|[:@][-[:alpha:]]+=\"")
   1437    '("web2py"           . "{{")
   1438    '("xoops"            . "<{[[:alpha:]#$/*\"]")
   1439    '("svelte"           . "{.")
   1440    )
   1441   "Engine regexps used to identify blocks.")
   1442 
   1443 (defvar web-mode-normalization-rules
   1444   '(("tag-case"          . "lower-case")
   1445     ("attr-case"         . "lower-case")
   1446     ("special-chars"     . "unicode") ;"unicode" "entities"
   1447     ("css-indentation"   . t)
   1448     ("smart-apostrophes" . t)
   1449     ("smart-quotes"      . t)
   1450     ("whitespaces"       . t)
   1451     ("indentation"       . t))
   1452   "Normalization rules")
   1453 
   1454 (defvar web-mode-element-tag-faces
   1455   (list
   1456    '("h1"     . web-mode-underline-face)
   1457    '("h2"     . web-mode-underline-face)
   1458    '("h3"     . web-mode-underline-face)
   1459    '("h4"     . web-mode-underline-face)
   1460    '("title"  . web-mode-underline-face)
   1461    '("em"     . web-mode-italic-face)
   1462    '("strong" . web-mode-bold-face)
   1463    ))
   1464 
   1465 (defvar web-mode-element-content-faces
   1466   (list
   1467    '("h1"     . web-mode-underline-face)
   1468    '("h2"     . web-mode-underline-face)
   1469    '("h3"     . web-mode-underline-face)
   1470    '("h4"     . web-mode-underline-face)
   1471    '("title"  . web-mode-underline-face)
   1472    '("em"     . web-mode-italic-face)
   1473    '("strong" . web-mode-bold-face)
   1474    ))
   1475 
   1476 (defvar web-mode-comment-keywords
   1477   (regexp-opt
   1478    (append
   1479     (cdr (assoc "comment" web-mode-extra-keywords))
   1480     '("FIXME" "TODO" "BUG" "KLUDGE" "WORKAROUND" "OPTIMIZE" "HACK" "REFACTOR" "REVIEW"))))
   1481 
   1482 (defvar web-mode-links
   1483   '(("\\.\\(png\\|jpe?g\\|gif\\|webp\\)$" "<img src=\"%s\" alt=\"\" />" nil 4)
   1484     ("\\.svg$" "<object data=\"%s\" type=\"image/svg+xml\"></object>" nil 0)
   1485     ("\\.js$" "<script type=\"text/javascript\" src=\"%s\"></script>" t 0)
   1486     ("\\.css$" "<link rel=\"stylesheet\" type=\"text/css\" href=\"%s\" />" t 0)
   1487     ("\\.html?$" "<a href=\"%s\"></a>" nil 4))
   1488   "List of elements and extensions for `web-mode-file-link'. It
   1489 consists of a string that contains the regular expression that
   1490 matches the appropriate files, a format string with element that
   1491 contains the link (%s should be put where the path goes,) a bool
   1492 that tells if the element belongs in the <head> element, and
   1493 number of characters to move back if needed (or 0 if point
   1494 shouldn't be moved back.)")
   1495 
   1496 (defvar web-mode-sql-queries
   1497   (regexp-opt
   1498    '("SELECT" "INSERT" "UPDATE" "DELETE" "select" "insert" "update" "delete")))
   1499 
   1500 (defvar web-mode-sql-keywords
   1501   (regexp-opt
   1502    (append
   1503     (cdr (assoc "sql" web-mode-extra-keywords))
   1504     '("SELECT" "INSERT" "UPDATE" "DELETE"
   1505       "FROM" "WHERE" "GROUP BY" "LIKE" "LIMIT" "HAVING" "JOIN" "LEFT" "INNER"
   1506       "FULL" "OUTER" "VALUES" "ORDER BY" "SEPARATOR" "ASC" "DESC"
   1507       "AND" "OR" "ON" "WHEN" "ELSE" "END" "THEN"))))
   1508 
   1509 (defvar web-mode-python-constants
   1510   (regexp-opt
   1511    (append
   1512     (cdr (assoc "python" web-mode-extra-constants))
   1513     '("True" "False" "None" "__debug__" "NotImplemented" "Ellipsis"))))
   1514 
   1515 (defvar web-mode-elixir-keywords
   1516   (regexp-opt
   1517    (append
   1518     (cdr (assoc "elixir" web-mode-extra-keywords))
   1519     '("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"))))
   1520 
   1521 
   1522 (defvar web-mode-elixir-constants
   1523   (regexp-opt
   1524    (append
   1525     (cdr (assoc "elixir" web-mode-extra-constants))
   1526     '("nil" "true" "false"))))
   1527 
   1528 (defvar web-mode-erlang-constants
   1529   (regexp-opt
   1530    (append
   1531     (cdr (assoc "erlang" web-mode-extra-constants))
   1532     '("true" "false"))))
   1533 
   1534 (defvar web-mode-erlang-keywords
   1535   (regexp-opt
   1536    (append
   1537     (cdr (assoc "erlang" web-mode-extra-keywords))
   1538     '("else" "if" "do" "end"))))
   1539 
   1540 (defvar web-mode-cl-emb-constants
   1541   (regexp-opt
   1542    '("nil" "t" "raw" "escape")))
   1543 
   1544 (defvar web-mode-cl-emb-keywords
   1545   (regexp-opt
   1546    '("if" "else" "endif" "unless" "endunless" "var" "repeat"
   1547      "endrepeat" "loop" "endloop" "include" "call" "with"
   1548      "endwith" "set" "genloop" "endgenloop" "insert")))
   1549 
   1550 (defvar web-mode-artanis-constants
   1551   (regexp-opt
   1552    '("#f" "#t")))
   1553 
   1554 (defvar web-mode-artanis-keywords
   1555   (regexp-opt
   1556    (append
   1557     (cdr (assoc "artanis" web-mode-extra-keywords))
   1558     '("begin" "cut" "cute" "if" "when" "unless" "cond" "case"
   1559       "do" "quote" "syntax" "lambda" "lambda*" "and" "and-let*"
   1560       "or" "else" "delay" "receive" "use-modules" "match"
   1561       "match-lambda" "match-lambda*" "match-let" "match-let*"
   1562       "match-letrec" "let" "let*" "letrec" "letrec*" "and-let*"
   1563       "let-syntax" "letrec-syntax" "syntax-rules" "syntax-case"
   1564       "define" "define-syntax" "define-macro"
   1565       "define-condition-type" "define-immutable-record-type"
   1566       "define-record-type" "define-values" "parameterize" "for-each"
   1567       "require-extension" "set!" "test-approximate" "test-assert"
   1568       "test-begin" "test-end" "test-eq" "test-equal" "test-eqv"
   1569       "test-error" "test-group" "test-group-with-cleanup" "test-with-runner"))))
   1570 
   1571 (defvar web-mode-lsp-constants
   1572   (regexp-opt
   1573    '("nil" "t")))
   1574 
   1575 (defvar web-mode-lsp-keywords
   1576   (regexp-opt
   1577    '("dolist" "let" "while" "cond" "when" "progn" "if"
   1578      "dotimes" "unless" "lambda"
   1579      "loop" "for" "and" "or" "in" "do" "defun")))
   1580 
   1581 (defvar web-mode-php-constants
   1582   (regexp-opt
   1583    (append
   1584     (cdr (assoc "php" web-mode-extra-constants))
   1585     '("TRUE" "FALSE" "NULL" "true" "false" "null"
   1586       "STR_PAD_LEFT" "STR_PAD_RIGHT"
   1587       "ENT_COMPAT" "ENT_QUOTES" "ENT_NOQUOTES" "ENT_IGNORE"
   1588       "ENT_SUBSTITUTE" "ENT_DISALLOWED" "ENT_HTML401" "ENT_XML1"
   1589       "ENT_XHTML" "ENT_HTML5" "JSON_PRETTY_PRINT"
   1590       "LIBXML_NOBLANKS"))))
   1591 
   1592 (defvar web-mode-php-keywords
   1593   (regexp-opt
   1594    (append
   1595     (cdr (assoc "php" web-mode-extra-keywords))
   1596     '("abstract" "and" "array" "as" "break" "case" "catch" "class" "clone"
   1597       "const" "continue" "declare" "default" "die" "do" "echo" "else" "elseif"
   1598       "empty" "enddeclare" "endfor" "endforeach" "endif" "endswitch" "endwhile"
   1599       "eval" "exit" "extends" "final" "finally" "fn" "for" "foreach" "function"
   1600       "global" "goto" "if" "implements" "include" "include_once" "instanceof"
   1601       "insteadof" "interface" "isset" "list" "namespace" "new" "or" "parent"
   1602       "print" "private" "protected" "public" "require" "require_once" "return"
   1603       "self" "static" "switch" "trait" "try" "throw" "unset" "use" "var"
   1604       "while" "xor" "yield" "yield from"))))
   1605 
   1606 (defvar web-mode-php-types
   1607   (eval-when-compile
   1608     (regexp-opt
   1609      '("array" "bool" "boolean" "callable" "float" "int" "integer"
   1610        "iterable" "mixed" "object" "resource" "string" "void"))))
   1611 
   1612 (defvar web-mode-css-at-rules
   1613   (eval-when-compile
   1614     (regexp-opt
   1615      '("charset" "import" "media" "page" "font-face"
   1616        "namespace" "supports" "document"
   1617        "keyframes" "-moz-keyframes" "-webkit-keyframes"
   1618        "mixin" "viewport"))))
   1619 
   1620 (defvar web-mode-css-pseudo-classes
   1621   (eval-when-compile
   1622     (regexp-opt
   1623      '("active" "after" "before" "checked" "disabled" "empty" "enabled"
   1624        "first" "first-child" "first-letter" "first-line" "first-of-type" "focus"
   1625        "hover" "lang" "last-child" "last-of-type" "left" "link"
   1626        "not" "nth-child" "nth-last-child" "nth-last-of-type" "nth-of-type"
   1627        "only-child" "only-of-type"
   1628        "right" "root" "selection" "target" "visited"))))
   1629 
   1630 (defvar web-mode-python-keywords
   1631   (regexp-opt
   1632    (append
   1633     (cdr (assoc "python" web-mode-extra-keywords))
   1634     '("and" "as" "assert" "break" "class" "continue" "def" "del"
   1635       "elif" "else" "except" "finally" "for" "from" "global"
   1636       "if" "import" "in" "is" "lambda" "nonlocal" "not" "or" "pass"
   1637       "raise" "return" "try" "while" "with" "yield"))))
   1638 
   1639 (defvar web-mode-jsp-keywords
   1640   (regexp-opt
   1641    (append
   1642     (cdr (assoc "jsp" web-mode-extra-keywords))
   1643     '("case" "catch" "do" "else" "end" "false" "for" "function"
   1644       "if" "in" "include"
   1645       "new" "package" "page" "private" "protected" "public"
   1646       "return" "tag" "taglib" "throw" "throws" "true" "try" "void" "while"))))
   1647 
   1648 (defvar web-mode-erb-keywords
   1649   (regexp-opt
   1650    (append
   1651     (cdr (assoc "erb" web-mode-extra-keywords))
   1652     '("alias" "and" "begin" "break" "case" "class" "def" "defined?" "do"
   1653       "elsif" "else" "end" "ensure" "fail" "for" "if" "in"
   1654       "module" "next" "not" "or" "redo" "rescue" "retry" "return"
   1655       "then" "super" "unless" "undef" "until" "when" "while" "yield"
   1656       "__ENCODING__" "__FILE__" "__LINE__"))))
   1657 
   1658 (defvar web-mode-mason-keywords
   1659   (regexp-opt
   1660    (append
   1661     (cdr (assoc "mason" web-mode-extra-keywords))
   1662     '("and" "base" "close" "die" "each" "else" "elsif" "eval" "exists"
   1663       "foreach" "grep" "if" "length" "local" "my" "next" "open" "or"
   1664       "package" "pop" "ref" "return" "stat" "sub" "tie"
   1665       "undef" "unless" "use" "while"))))
   1666 
   1667 (defvar web-mode-erb-builtins
   1668   (regexp-opt
   1669    (append
   1670     (cdr (assoc "erb" web-mode-extra-builtins))
   1671 
   1672     '("__callee__" "__dir__" "__method__"
   1673       "abort" "at_exit" "autoload" "autoload?"
   1674       "binding" "block_given?" "caller" "catch"
   1675       "eval" "exec" "exit" "exit!" "fail" "fork" "format"
   1676       "lambda" "load" "loop" "open"
   1677       "p" "print" "printf" "proc" "putc" "puts"
   1678       "raise" "rand" "readline" "readlines" "require" "require_relative"
   1679       "sleep" "spawn" "sprintf" "srand" "syscall" "system"
   1680       "throw" "trap" "warn"
   1681       "alias_method" "attr" "attr_accessor" "attr_reader" "attr_writer"
   1682       "define_method" "extend" "include" "module_function"
   1683       "prepend" "private" "protected" "public"
   1684       "refine" "using"
   1685 
   1686       "error_message_on" "error_messages_for" "form" "input"
   1687       "auto_discovery_link_tag" "image_tag" "javascript_include_tag"
   1688       "stylesheet_link_tag" "image_path" "path_to_image"" "
   1689       "javascript_path" "path_to_javascript" "register_javascript_expansion"
   1690       "register_javascript_include_default" "register_stylesheet_expansion"
   1691       "stylesheet_path" "path_to_stylesheet" "atom_feed" "entry" "updated"
   1692       "benchmark" "cache" "capture" "content_for" "distance_of_time_in_words"
   1693       "distance_of_time_in_words_to_now" "time_ago_in_words" "date_select"
   1694       "datetime_select" "time_select" "select_date" "select_datetime"
   1695       "select_day" "select_hour" "select_minute" "select_month" "select_second"
   1696       "select_time" "select_year" "debug"
   1697       "check_box" "fields_for" "file_field" "form_for" "hidden_field"
   1698       "label" "password_field" "radio_button" "text_area" "text_field"
   1699       "check_box_tag" "field_set_tag" "file_field_tag" "form_with" "form_tag"
   1700       "hidden_field_tag" "image_submit_tag" "label_tag" "password_field_tag"
   1701       "radio_button_tag" "select_tag" "submit_tag" "text_area_tag"
   1702       "text_field_tag"
   1703       "collection_select" "country_options_for_select" "country_select"
   1704       "option_groups_from_collection_for_select" "options_for_select"
   1705       "options_from_collection_for_select" "select"
   1706       "time_zone_options_for_select"
   1707       "time_zone_select" "button_to_function" "define_javascript_functions"
   1708       "escape_javascript" "javascript_tag" "link_to_function"" "
   1709       "number_to_currency" "number_to_human_size" "number_to_percentage"
   1710       "number_to_phone" "number_with_delimiter" "number_with_precision"
   1711       "evaluate_remote_response" "form_remote_for" "form_remote_tag"
   1712       "link_to_remote" "observe_field" "observe_field"
   1713       "periodically_call_remote"
   1714       "remote_form_for" "remote_function" "submit_to_remote" "update_page"
   1715       "update_page_tag" "dom_class" "dom_id" "partial_path" "sanitize"
   1716       "sanitize_css" "strip_links" "strip_tags"
   1717       "cdata_section" "content_tag" "escape_once" "tag"
   1718       "auto_link" "concat" "cycle" "excerpt" "highlight" "markdown" "pluralize"
   1719       "reset_cycle" "simple_format" "textilize" "textilize_without_paragraph"
   1720       "truncate" "word_wrap" "button_to" "current_page?" "link_to" "link_to_if"
   1721       "link_to_unless" "link_to_unless_current" "mail_to" "url_for"
   1722       "action_name" "atom_feed" "audio_path" "audio_tag"
   1723       "content_tag_for" "controller" "controller_name" "action_name"
   1724       "controller_path" "convert_to_model" "cookies" "csrf_meta_tag"
   1725       "csrf_meta_tags" "headers"
   1726       "current_cycle" "div_for" "email_field" "email_field_tag"
   1727       "favicon_link_tag" "flash" "l" "button_tag"
   1728       "grouped_collection_select" "grouped_options_for_select"
   1729       "image_alt" "j" "javascript_cdata_section"
   1730       "localize" "logger" "number_field"
   1731       "number_field_tag" "number_to_human" "params" "path_to_audio"
   1732       "path_to_video" "phone_field" "phone_field_tag" "provide"
   1733       "range_field" "range_field_tag" "raw" "render" "request"
   1734       "request_forgery_protection_token" "response" "safe_concat"
   1735       "safe_join" "search_field" "search_field_tag"
   1736       "session" "t" "telephone_field" "telephone_field_tag"
   1737       "time_tag" "translate" "url_field" "url_field_tag"
   1738       "url_options" "video_path" "video_tag" "simple_form_for"
   1739       "javascript_pack_tag" "stylesheet_pack_tag" "csp_meta_tag"
   1740 
   1741       ))))
   1742 
   1743 (defvar web-mode-asp-constants
   1744   (regexp-opt
   1745    (append
   1746     (cdr (assoc "asp" web-mode-extra-constants))
   1747     '("adAsyncExecute" "adAsyncFetch" "adAsyncFetchNonBlocking" "adCmdFile"
   1748       "adCmdStoredProc" "adCmdTable" "adCmdTableDirect" "adCmdText" "adCmdUnknown"
   1749       "adCmdUnspecified" "adExecuteNoRecords" "adExecuteRecord" "adExecuteStream"
   1750       "adLockBatchOptimistic" "adLockOptimistic" "adLockPessimistic"
   1751       "adLockReadOnly" "adLockUnspecified" "adOpenDynamic" "adOpenForwardOnly"
   1752       "adOpenKeyset" "adOpenStatic" "adOpenUnspecified" "adOptionUnspecified"
   1753       "Empty" "Nothing" "Null" "True" "False"
   1754       "vbBack" "vbCr" "vbCrLf" "vbFormFeed" "vbLf" "vbNewLine" "vbNullChar"
   1755       "vbNullString" "vbObjectError" "vbScript" "vbTab" "vbVerticalTab"))))
   1756 
   1757 (defvar web-mode-asp-keywords
   1758   (regexp-opt
   1759    (append
   1760     (cdr (assoc "asp" web-mode-extra-keywords))
   1761     '("Abs" "And" "Array" "Asc" "Atn"
   1762       "CBool" "CByte" "CCur" "CDate" "CDbl" "CInt" "CLng" "CSng" "CStr"
   1763       "Call" "Case" "Chr" "Class" "Const" "Cos" "CreateObject"
   1764       "Date" "DateAdd" "DateDiff" "DatePart" "DateSerial" "DateValue"
   1765       "Day" "Dim" "Do"
   1766       "Each" "Else" "ElseIf" "End" "Erase" "Err" "Eval" "Exit" "Exp"
   1767       "Explicit"
   1768       "Filter" "Fix" "For" "FormatCurrency" "FormatDateTime"
   1769       "FormatNumber" "FormatPercent" "Function"
   1770       "GetLocale" "GetObject" "GetRef" "Hex" "Hour"
   1771       "If" "In" "InStr" "InStrRev" "InputBox" "Int" "IsArray" "IsDate"
   1772       "IsEmpty" "IsNull" "IsNumeric" "IsObject" "Join"
   1773       "LBound" "LCase" "LTrim" "Language" "Left" "Len" "Let"
   1774       "LoadPicture" "Log" "Loop"
   1775       "Mid" "Minute" "Month" "MonthName" "MsgBox"
   1776       "New" "Next" "Not" "Now"
   1777       "Oct" "On" "Option" "Or" "Preserve" "Private" "Public"
   1778       "RGB" "RTrim" "Redim" "Rem" "Replace" "Right" "Rnd" "Round"
   1779       "ScriptEngine" "ScriptEngineBuildVersion"
   1780       "ScriptEngineMajorVersion" "ScriptEngineMinorVersion"
   1781       "Second" "Select" "Set" "SetLocale" "Sgn" "Sin" "Space" "Split"
   1782       "Sqr" "StrComp" "StrReverse" "String" "Sub"
   1783       "Tan" "Then" "Time" "TimeSerial" "TimeValue" "Timer" "To" "Trim"
   1784       "TypeName"
   1785       "UBound" "UCase" "Until" "VarType"
   1786       "Weekday" "WeekdayName" "Wend" "With" "While" "Year"))))
   1787 
   1788 (defvar web-mode-asp-types
   1789   (regexp-opt
   1790    (append
   1791     (cdr (assoc "asp" web-mode-extra-types))
   1792     '("Application" "ASPError" "Request" "Response" "Server" "Session"))))
   1793 
   1794 (defvar web-mode-aspx-keywords
   1795   (regexp-opt
   1796    (append
   1797     (cdr (assoc "aspx" web-mode-extra-keywords))
   1798     '("case" "catch" "do" "else" "end" "for" "foreach" "function"
   1799       "if" "in" "include" "new" "package" "page" "return"
   1800       "tag" "throw" "throws" "try" "while"))))
   1801 
   1802 (defvar web-mode-smarty-keywords
   1803   (regexp-opt '("as")))
   1804 
   1805 (defvar web-mode-velocity-keywords
   1806   (eval-when-compile
   1807     (regexp-opt '("in" "true" "false"))))
   1808 
   1809 (defvar web-mode-freemarker-keywords
   1810   (eval-when-compile
   1811     (regexp-opt '("as" "list"))))
   1812 
   1813 (defvar web-mode-go-keywords
   1814   (eval-when-compile
   1815     (regexp-opt
   1816      '("const" "define" "else" "end"
   1817        "for" "func" "if" "import"
   1818        "pipeline" "range" "return" "struct"
   1819        "template" "type" "var" "with"))))
   1820 
   1821 (defvar web-mode-go-functions
   1822   (eval-when-compile
   1823     (regexp-opt
   1824      '("and" "call" "ge" "html" "index" "js" "len" "not" "or"
   1825        "print" "printf" "println" "urlquery" "where"))))
   1826 
   1827 (defvar web-mode-go-types
   1828   (regexp-opt
   1829    (append
   1830     (cdr (assoc "go" web-mode-extra-types))
   1831     '("int" "string"))))
   1832 
   1833 (defvar web-mode-closure-keywords
   1834   (eval-when-compile
   1835     (regexp-opt '("in" "and" "not" "or"))))
   1836 
   1837 (defvar web-mode-svelte-keywords
   1838   (regexp-opt '("as")))
   1839 
   1840 (defvar web-mode-django-control-blocks
   1841   (append
   1842    (cdr (assoc "django" web-mode-extra-control-blocks))
   1843    '(
   1844 
   1845      "assets" "autoescape"
   1846      "block" "blocktrans"
   1847      "cache" "call" "capture" "comment"
   1848      "draw"
   1849      "embed"
   1850      "filter" "for" "foreach" "form"
   1851      "if" "ifchanged" "ifequal" "ifnotequal"
   1852      "macro"
   1853      "random" "raw"
   1854      "safe" "sandbox" "spaceless"
   1855      "tablerow"
   1856      "unless"
   1857      "verbatim"
   1858      "with"
   1859 
   1860      "endassets" "endautoescape"
   1861      "endblock" "endblocktrans"
   1862      "endcache" "endcall" "endcapture" "endcomment"
   1863      "draw"
   1864      "endembed"
   1865      "endfilter" "endfor" "endforeach" "endform"
   1866      "endif" "endifchanged" "endifequal" "endifnotequal"
   1867      "endmacro"
   1868      "endrandom" "endraw"
   1869      "endsafe" "endsandbox" "endspaceless"
   1870      "endtablerow"
   1871      "endunless"
   1872      "endverbatim"
   1873      "endwith"
   1874 
   1875      ;; "set" "endset" ;#504
   1876 
   1877      "csrf_token" "cycle" "debug"
   1878      "elif" "else" "elseif" "elsif" "empty" "extends"
   1879      "firstof" "include" "load" "lorem" "now" "regroup" "ssi"
   1880      "trans" "templatetag" "url" "widthratio"
   1881 
   1882      ;; #805
   1883      "graph" "endgraph"
   1884      "javascript" "endjavascript"
   1885      "schema" "endschema"
   1886      "stylesheet" "endstylesheet"
   1887 
   1888      )))
   1889 
   1890 (defvar web-mode-django-control-blocks-regexp
   1891   (regexp-opt web-mode-django-control-blocks t))
   1892 
   1893 (defvar web-mode-django-keywords
   1894   (eval-when-compile
   1895     (regexp-opt
   1896      '("and" "as" "assign"
   1897        "break"
   1898        "cache" "call" "case" "context" "continue"
   1899        "do"
   1900        "flush" "from"
   1901        "ignore" "import" "in" "is"
   1902        "layout" "load"
   1903        "missing"
   1904        "none" "not"
   1905        "or"
   1906        "pluralize"
   1907        "random"
   1908        "set" ;#504
   1909        "unless" "use"
   1910        "var"
   1911        ))))
   1912 
   1913 (defvar web-mode-django-types
   1914   (eval-when-compile
   1915     (regexp-opt '("null" "false" "true"))))
   1916 
   1917 (defvar web-mode-blade-control-blocks
   1918   (append
   1919    (cdr (assoc "blade" web-mode-extra-control-blocks))
   1920    '("component" "foreach" "forelse" "for" "if" "section" "slot" "switch" "unless" "while")
   1921    ))
   1922 
   1923 (defvar web-mode-blade-control-blocks-regexp
   1924   (regexp-opt web-mode-blade-control-blocks t))
   1925 
   1926 (defvar web-mode-directives
   1927   (eval-when-compile
   1928     (regexp-opt
   1929      '("include" "page" "taglib"
   1930        "Assembly" "Control" "Implements" "Import"
   1931        "Master" "OutputCache" "Page" "Reference" "Register"))))
   1932 
   1933 (defvar web-mode-template-toolkit-keywords
   1934   (regexp-opt
   1935    '("block" "call" "case" "catch" "clear" "default" "do"
   1936      "else" "elsif" "end" "filter" "final" "for"
   1937      "foreach" "get" "if" "in" "include" "insert" "is" "last"
   1938      "macro" "meta" "or" "perl" "process" "rawperl" "return"
   1939      "set" "stop" "switch" "tags" "throw" "try"
   1940      "unless" "use" "while" "wrapper")))
   1941 
   1942 (defvar web-mode-perl-keywords
   1943   (regexp-opt
   1944    '("__DATA__" "__END__" "__FILE__" "__LINE__" "__PACKAGE__"
   1945      "and" "cmp" "continue" "CORE" "do" "else" "elsif" "eq" "exp"
   1946      "for" "foreach" "ge" "gt" "if" "le" "lock" "lt" "m" "ne" "no"
   1947      "or" "package" "q" "qq" "qr" "qw" "qx" "s" "sub"
   1948      "tr" "unless" "until" "while" "xor" "y"
   1949      "my" "use" "print" "say")))
   1950 
   1951 (defvar web-mode-javascript-keywords
   1952   (regexp-opt
   1953    (append
   1954     (cdr (assoc "javascript" web-mode-extra-keywords))
   1955     '("as" "async" "await" "break" "case" "catch" "class" "const" "continue"
   1956       "debugger" "default" "delete" "do" "else" "enum" "eval"
   1957       "export" "extends" "finally" "for" "from" "function" "get" "if"
   1958       "implements" "import" "in" "instanceof" "interface" "let"
   1959       "new" "of" "package" "private" "protected" "public"
   1960       "return" "set" "static" "super" "switch"
   1961       "throw" "try" "type" "typeof" "var" "void" "while" "with" "yield"))))
   1962 
   1963 (defvar web-mode-javascript-constants
   1964   (regexp-opt
   1965    '("false" "null" "undefined" "Infinity" "NaN" "true" "arguments" "this")))
   1966 
   1967 (defvar web-mode-razor-keywords
   1968   (regexp-opt
   1969    (append
   1970     (cdr (assoc "razor" web-mode-extra-keywords))
   1971     '("false" "true" "foreach" "if" "else" "in" "var" "for" "display"
   1972       "match" "case" "to"
   1973       "Html"))))
   1974 
   1975 (defvar web-mode-selector-font-lock-keywords
   1976   (list
   1977    '("$[[:alnum:]-]+" 0 'web-mode-css-variable-face)
   1978    (cons (concat "@\\(" web-mode-css-at-rules "\\)\\_>")
   1979          '(0 'web-mode-css-at-rule-face))
   1980    '("\\_<\\(all\|braille\\|embossed\\|handheld\\|print\\|projection\\|screen\\|speech\\|tty\\|tv\\|and\\|or\\)\\_>"
   1981      1 'web-mode-keyword-face)
   1982    '("\\.[^ ,]+" 0 'web-mode-css-selector-class-face)
   1983    '("[^,]+" 0 'web-mode-css-selector-tag-face)
   1984    (cons (concat ":\\([ ]*[[:alpha:]][^,{]*\\)") '(0 'web-mode-css-pseudo-class-face t t))
   1985    ))
   1986 
   1987 (defvar web-mode-declaration-font-lock-keywords
   1988   (list
   1989    '("--[[:alnum:]-]+" 0 'web-mode-css-variable-face)
   1990    '("$[[:alnum:]-]+" 0 'web-mode-css-variable-face)
   1991    (cons (concat "@\\(" web-mode-css-at-rules "\\)\\_>") '(1 'web-mode-css-at-rule-face))
   1992    '("\\([[:alpha:]-]+\\)[ ]?:" 0 'web-mode-css-property-name-face)
   1993    '("\\([[:alpha:]-]+\\)[ ]?(" 1 'web-mode-css-function-face)
   1994    '("#[[:alnum:]]\\{1,6\\}" 0 'web-mode-css-color-face t t)
   1995    '("![ ]?important" 0 'web-mode-css-priority-face t t)
   1996    '("\\([^,]+\\)[ ]+{" 1 'web-mode-css-selector-face)
   1997    '("'[^']*'\\|\"[^\"]*\"" 0 'web-mode-string-face t t)
   1998    ))
   1999 
   2000 (defvar web-mode-html-font-lock-keywords
   2001   (list
   2002    '("</?[[:alnum:]]+[ >]\\|>" 0 'web-mode-html-tag-face t)
   2003    '(" \\([[:alnum:]-]+=\\)\\(\"[^\"]+\"\\)"
   2004      (1 'web-mode-html-attr-name-face)
   2005      (2 'web-mode-html-attr-value-face))
   2006    ))
   2007 
   2008 ;; voir https://www.gnu.org/software/emacs/manual/html_node/elisp/Search_002dbased-Fontification.html
   2009 (defvar web-mode-javascript-font-lock-keywords
   2010   (list
   2011    '("@\\([[:alnum:]_]+\\)\\_>" 0 'web-mode-keyword-face)
   2012    '("\\([[:alnum:]]+\\)[`]" 0 'web-mode-preprocessor-face)
   2013    (cons (concat "\\_<\\(function\\*\\)\\_>") '(1 'web-mode-keyword-face))
   2014    (cons (concat "\\([ \t}{(]\\|^\\)\\(" web-mode-javascript-keywords "\\)\\_>") '(2 'web-mode-keyword-face))
   2015    (cons (concat "\\_<\\(" web-mode-javascript-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2016    '("\\_<\\([$]\\)(" 1 'web-mode-type-face)
   2017    '("\\_<\\(new\\|instanceof\\|class\\|extends\\|import\\) \\([[:alnum:]_.]+\\)\\_>" 2 'web-mode-type-face)
   2018    '("\\_<\\([[:alnum:]_]+\\):[ ]*function[ ]*(" 1 'web-mode-function-name-face)
   2019    '("\\_<\\(function\\|get\\|set\\)[ ]+\\([[:alnum:]_]+\\)"
   2020      (1 'web-mode-keyword-face)
   2021      (2 'web-mode-function-name-face))
   2022    '("\\([[:alnum:]_]+\\)[ ]*([^)]*)[ \n]*{" 1 'web-mode-function-name-face)
   2023    '("([ ]*\\([[:alnum:]_]+\\)[ ]*=>" 1 'web-mode-function-name-face)
   2024    '("[ ]*\\([[:alnum:]_]+\\)[ ]*=[ ]*([^)]*)[ ]*=>[ ]*{" 1 'web-mode-function-name-face)
   2025    '("\\_<\\(var\\|let\\|const\\)[ ]+\\([[:alnum:]_]+\\)" 2 'web-mode-variable-name-face)
   2026    '("({" "\\([[:alnum:]_]+\\)[, }]+" nil nil (1 'web-mode-variable-name-face)) ;#738
   2027    '("\\([[:alnum:]_]+\\)[ ]*=> [{(]" 1 'web-mode-variable-name-face)
   2028    ;; #989
   2029    ;; '("\\(function\\|[,=]\\|^\\)[ ]*("
   2030    ;;   ("\\([[:alnum:]_]+\\)\\([ ]*=[^,)]*\\)?[,)]" nil nil (1 'web-mode-variable-name-face)))
   2031    '("\\([[:alnum:]_]+\\):" 1 'web-mode-variable-name-face)
   2032    '("\\_<\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2033    '("[a-zA-Z]<\\([a-zA-Z]+\\)[,>]" 1 'web-mode-type-face)
   2034    ))
   2035 
   2036 (defvar web-mode-stylus-font-lock-keywords
   2037   (list
   2038    '("^[ \t]*\\([[:alnum:]().-]+\\)$" 1 'web-mode-css-selector-face)
   2039    '("^[ \t]*\\([[:alnum:]-]+[ ]*:\\)" 1 'web-mode-css-property-name-face)
   2040    ))
   2041 
   2042 (defvar web-mode-sass-font-lock-keywords
   2043   (list
   2044    '("^[ \t]*\\([[:alnum:]().-]+\\|&:\\(before\\|after\\)\\)$" 1 'web-mode-css-selector-face)
   2045    '("^[ \t]*\\([[:alnum:]-]+[ ]*:\\)" 1 'web-mode-css-property-name-face)
   2046    ))
   2047 
   2048 (defvar web-mode-pug-font-lock-keywords
   2049   (list
   2050    '("^[ \t]*\\(#?[[:alnum:].-]+\\)" 1 'web-mode-css-selector-face)
   2051    ;;'("^[ \t]*\\(#[[:alnum:]-]+\\)" 0 'web-mode-css-selector-face)
   2052    '(" \\([@:]?\\sw+[ ]?=\\)" 1 'web-mode-param-name-face)
   2053    ))
   2054 
   2055 (defvar web-mode-sql-font-lock-keywords
   2056   (list
   2057    (cons (concat "\\_<\\(" web-mode-sql-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2058    '("\\_<\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2059    ))
   2060 
   2061 (defvar web-mode-markdown-font-lock-keywords
   2062   (list
   2063    '("^[ ]*[*].*$" 0 'web-mode-variable-name-face)
   2064    '("^[ ]*#.*$" 0 'web-mode-comment-face)
   2065    ))
   2066 
   2067 (defvar web-mode-html-tag-font-lock-keywords
   2068   (list
   2069    '("\\(</?\\)\\([[:alnum:]]+\\)"
   2070      (1 'web-mode-html-tag-bracket-face)
   2071      (2 'web-mode-html-tag-face))
   2072    '("\"[^\"]*\"" 0 'web-mode-html-attr-value-face)
   2073    '("\\([[:alnum:]]+\\)" 1 'web-mode-html-attr-name-face)
   2074    '("/?>" 0 'web-mode-html-tag-bracket-face)
   2075    ))
   2076 
   2077 (defvar web-mode-anki-font-lock-keywords
   2078   (list
   2079    '("{{[#/^]\\([[:alnum:]_.]+\\)" 1 'web-mode-block-control-face)
   2080    ;;'("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_.: ]*\\)"
   2081    ;;  (1 'web-mode-block-attr-name-face)
   2082    ;;  (2 'web-mode-block-attr-value-face))
   2083    '("{{\\(.+\\)}}" 1 'web-mode-variable-name-face)
   2084    ))
   2085 
   2086 (defvar web-mode-dust-font-lock-keywords
   2087   (list
   2088    '("{[#:/?@><+^]\\([[:alpha:]_.]+\\)" 1 'web-mode-block-control-face)
   2089    '(":\\([[:alpha:]]+\\)" 1 'web-mode-keyword-face)
   2090    '("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_]*\\)"
   2091      (1 'web-mode-block-attr-name-face)
   2092      (2 'web-mode-block-attr-value-face))
   2093    '("\\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face)
   2094    ))
   2095 
   2096 (defvar web-mode-expressionengine-font-lock-keywords
   2097   (list
   2098    '("{/?\\([[:alpha:]_]+:[[:alpha:]_:]+\\|if\\)" 1 'web-mode-block-control-face)
   2099    '(":\\([[:alpha:]_]+\\)" 1 'web-mode-keyword-face)
   2100    '(" {\\([[:alpha:]_]+\\)}" 1 'web-mode-keyword-face t)
   2101    '("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_]*\\)"
   2102      (1 'web-mode-block-attr-name-face)
   2103      (2 'web-mode-block-attr-value-face))
   2104    '("\\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face)
   2105    ))
   2106 
   2107 (defvar web-mode-svelte-font-lock-keywords
   2108   (list
   2109    (cons (concat "[ ]\\(" web-mode-svelte-keywords "\\)[ ]") '(1 'web-mode-keyword-face))
   2110    '("{[#:/@]\\([[:alpha:]_.]+\\)" 1 'web-mode-block-control-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    '("\\_<\\([$]\\)\\([[:alnum:]_]+\\)" (1 'web-mode-constant-face) (2 'web-mode-variable-name-face))
   2116    ))
   2117 
   2118 (defvar web-mode-template-toolkit-font-lock-keywords
   2119   (list
   2120    (cons (concat "\\_<\\(" web-mode-template-toolkit-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2121    '("\\\([[:alpha:]][[:alnum:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2122    '("\\\([[:alpha:]][[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2123    ))
   2124 
   2125 (defvar web-mode-smarty-font-lock-keywords
   2126   (list
   2127    (cons (concat "[ ]\\(" web-mode-smarty-keywords "\\)[ ]") '(1 'web-mode-keyword-face))
   2128    '("{/?\\([[:alpha:]_]+\\)" 1 'web-mode-block-control-face)
   2129    '("\\([}{]\\)" 0 'web-mode-block-delimiter-face)
   2130    '("\\_<\\([$]\\)\\([[:alnum:]_]+\\)" (1 nil) (2 'web-mode-variable-name-face))
   2131    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2132    '(" \\(\\sw+[ ]?=\\)" 1 'web-mode-param-name-face)
   2133    '(" \\(\\sw+\\)[ }]" 1 'web-mode-param-name-face)
   2134    '("|\\([[:alnum:]_]+\\)" 1 'web-mode-function-call-face)
   2135    '("\\(->\\)\\(\\sw+\\)" (1 nil) (2 'web-mode-variable-name-face))
   2136    '("[.]\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2137    '("[.]\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2138    '("#\\([[:alnum:]_]+\\)#" 1 'web-mode-variable-name-face)
   2139    ))
   2140 
   2141 (defvar web-mode-velocity-font-lock-keywords
   2142   (list
   2143    '("#{?\\([[:alpha:]_]+\\)\\_>" (1 'web-mode-block-control-face))
   2144    (cons (concat "\\_<\\(" web-mode-velocity-keywords "\\)\\_>") '(1 'web-mode-keyword-face t t))
   2145    '("#macro([ ]*\\([[:alpha:]]+\\)[ ]+" 1 'web-mode-function-name-face)
   2146    '("\\(def\\|define\\) \\([[:alnum:]_-]+\\)(" 2 'web-mode-function-name-face)
   2147    '("[.]\\([[:alnum:]_-]+\\)" 1 'web-mode-variable-name-face)
   2148    '("\\_<\\($[!]?[{]?\\)\\([[:alnum:]_-]+\\)[}]?" (1 nil) (2 'web-mode-variable-name-face))
   2149    ))
   2150 
   2151 (defvar web-mode-mako-tag-font-lock-keywords
   2152   (list
   2153    '("</?%\\([[:alpha:]:]+\\)" 1 'web-mode-block-control-face)
   2154    '("\\_<\\([[:alpha:]]+=\\)\\(\"[^\"]*\"\\)"
   2155      (1 'web-mode-block-attr-name-face t t)
   2156      (2 'web-mode-block-attr-value-face t t))
   2157    ))
   2158 
   2159 (defvar web-mode-mako-block-font-lock-keywords
   2160   (list
   2161    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2162    (cons (concat "\\_<\\(" web-mode-python-constants "\\)\\_>") '(1 'web-mode-constant-face))
   2163    (cons (concat "\\_<\\(" web-mode-python-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2164    (cons (concat "\\_<\\(endfor\\|endif\\|endwhile\\)\\_>") '(1 'web-mode-keyword-face))
   2165    ))
   2166 
   2167 (defvar web-mode-web2py-font-lock-keywords
   2168   (list
   2169    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2170    (cons (concat "\\_<\\(" web-mode-python-constants "\\)\\_>") '(1 'web-mode-constant-face))
   2171    (cons (concat "\\_<\\(" web-mode-python-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2172    (cons (concat "\\_<\\(block\\|extend\\|super\\|end\\|include\\)\\_>") '(1 'web-mode-keyword-face))
   2173    ))
   2174 
   2175 (defvar web-mode-django-expr-font-lock-keywords
   2176   (list
   2177    '("|[ ]?\\([[:alpha:]_]+\\)\\_>" 1 'web-mode-filter-face)
   2178    (cons (concat "\\_<\\(" web-mode-django-types "\\)\\_>") '(1 'web-mode-type-face))
   2179    '("\\_<\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2180    '("[[:alnum:]_]+" 0 'web-mode-variable-name-face)
   2181    ))
   2182 
   2183 (defvar web-mode-django-code-font-lock-keywords
   2184   (list
   2185    '("{%[ ]*\\(set\\)[ ]+\\([[:alpha:]]+\\)[ ]*%}"
   2186      (1 'web-mode-block-control-face)
   2187      (2 'web-mode-variable-name-face))
   2188    (cons (concat "\\({%\\|#\\)[ ]*\\(" web-mode-django-control-blocks-regexp "\\)[ %]") '(2 'web-mode-block-control-face))
   2189    '("\\({%\\|#\\)[ ]*\\(end[[:alpha:]]+\\)\\_>" 2 'web-mode-block-control-face) ;#504
   2190    (cons (concat "\\_<\\(" web-mode-django-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2191    (cons (concat "\\_<\\(" web-mode-django-types "\\)\\_>") '(1 'web-mode-type-face))
   2192    '("|[ ]?\\([[:alpha:]_]+\\)\\_>" 1 'web-mode-function-call-face)
   2193    '("\\_<\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2194    '("[[:alnum:]_.]+" 0 'web-mode-variable-name-face)
   2195    '("[[:alnum:]_]+\\([.][[:alnum:]_]+\\)+" 0 'web-mode-variable-name-face t t)
   2196    ))
   2197 
   2198 (defvar web-mode-ctemplate-font-lock-keywords
   2199   (list
   2200    '("{[~]?{[#/>^]?[ ]*\\([[:alnum:]_.-]+\\)" 1 'web-mode-block-control-face)
   2201    '("[ \t]+\\([[:alnum:]_-]+\\)="
   2202      (1 'web-mode-block-attr-name-face))
   2203    '("\"[^\"]+\"" 0 'web-mode-block-string-face)
   2204    ))
   2205 
   2206 (defvar web-mode-astro-font-lock-keywords
   2207   (append
   2208    (list
   2209     '("\\({\\)\\([[:alpha:]]+\\)\\(}\\)"
   2210       (1 'web-mode-block-control-face)
   2211       (2 'web-mode-variable-name-face)
   2212       (3 'web-mode-block-control-face)))
   2213     web-mode-javascript-font-lock-keywords
   2214     ))
   2215 
   2216 (defvar web-mode-antlers-font-lock-keywords
   2217   (list
   2218    '("{{[ ]*\\(/?\\(if\\|elseif\\|else\\|unless\\|switch\\)\\)" 1 'web-mode-block-control-face)
   2219    '("[ \t]+\\(:?[[:alnum:]_-]+\\)=" (1 'web-mode-block-attr-name-face))
   2220    '("[[:alnum:]_.]+" 0 'web-mode-variable-name-face)
   2221    '("\"[^\"]+\"" 0 'web-mode-block-string-face)
   2222    '("'[^']+'" 0 'web-mode-block-string-face)
   2223    ))
   2224 
   2225 (defvar web-mode-razor-font-lock-keywords
   2226   (list
   2227    '("@\\([[:alnum:]_.]+\\)[ ]*[({]" 1 'web-mode-block-control-face)
   2228    (cons (concat "\\_<\\(" web-mode-razor-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2229    '("\\_<\\(String\\)\\_>" 1 'web-mode-type-face)
   2230    '("\\([[:alnum:]]+:\\)" 1 'web-mode-symbol-face)
   2231    '("\\(@[[:alnum:]_.]+\\)" 1 'web-mode-variable-name-face)
   2232    ))
   2233 
   2234 (defvar web-mode-riot-font-lock-keywords
   2235   (list
   2236    '("\\(parent\\|opts\\|tags\\|this\\)\\.\\([[:alnum:]_.]+\\)"
   2237      (1 'web-mode-constant-face)
   2238      (2 'web-mode-variable-name-face))
   2239    '("\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face)
   2240    ))
   2241 
   2242 (defvar web-mode-closure-font-lock-keywords
   2243   (list
   2244    '("{\\([@/]?[[:alpha:]]+[?]?\\)" 1 'web-mode-block-control-face)
   2245    '("{[@]?param[?]?[ ]+\\([[:alnum:]]+[:]?\\)" 1 'web-mode-symbol-face)
   2246    '("\\_<\\(true\\|false\\|null\\)\\_>" 1 'web-mode-type-face)
   2247    '("\\\_<[[:alpha:]]+:[ ]+\\([[:alpha:]]+\\)" 1 'web-mode-type-face)
   2248    (cons (concat "\\_<\\(" web-mode-closure-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2249    '("{\\(alias\\|call\\|delcall\\|delpackage\\|deltemplate\\|namespace\\|template\\)[ ]+\\([[:alnum:].]+\\)" 2 'web-mode-constant-face)
   2250    '("\\(allowemptydefault\\|data\\|desc\\|meaning\\|autoescape\\|private\\|variant\\)=" 0 'web-mode-block-attr-name-face)
   2251    '("|\\([[:alpha:]]+\\)" 1 'web-mode-function-call-face)
   2252    '("\\_<\\([[:alnum:]]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2253    '("$\\([[:alnum:]._]+\\)" 1 'web-mode-variable-name-face)
   2254    ))
   2255 
   2256 (defvar web-mode-go-font-lock-keywords
   2257   (list
   2258    '("{{[-]?[ ]*\\([[:alpha:]]+\\)" 1 'web-mode-block-control-face)
   2259    '("\\_<func \\([[:alnum:]]+\\)" 1 'web-mode-function-name-face)
   2260    '("\\_<type \\([[:alnum:]]+\\)" 1 'web-mode-type-face)
   2261    (cons (concat "\\_<\\(" web-mode-go-types "\\)\\_>") '(0 'web-mode-type-face))
   2262    (cons (concat "\\_<\\(" web-mode-go-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2263    (cons (concat "\\_<\\(" web-mode-go-functions "\\)\\_>") '(1 'web-mode-function-call-face))
   2264    '("[$.]\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face t t)
   2265    '("|[ ]?\\([[:alpha:]_]+\\)\\_>" 1 'web-mode-filter-face)
   2266    ))
   2267 
   2268 (defvar web-mode-expression-font-lock-keywords
   2269   (list
   2270    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2271    ))
   2272 
   2273 (defvar web-mode-angular-font-lock-keywords
   2274   (list
   2275    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2276    ))
   2277 
   2278 (defvar web-mode-underscore-font-lock-keywords
   2279   (list
   2280    (cons (concat "\\_<\\(" web-mode-javascript-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2281    '("\\_<\\(_\.[[:alpha:]]+\\)(" 1 'web-mode-function-call-face)
   2282    '("\\_<new \\([[:alnum:]_.]+\\)\\_>" 1 'web-mode-type-face)
   2283    '("\\_<\\([[:alnum:]_]+\\):[ ]*function[ ]*(" 1 'web-mode-function-name-face)
   2284    '("\\_<\\(var\\)\\_>[ ]+\\([[:alnum:]_]+\\)"
   2285      (1 'web-mode-keyword-face)
   2286      (2 'web-mode-variable-name-face))
   2287    ))
   2288 
   2289 (defvar web-mode-vue-font-lock-keywords
   2290   (list
   2291    '("\\_<\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2292    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2293    ))
   2294 
   2295 (defvar web-mode-engine-tag-font-lock-keywords
   2296   (list
   2297    '("</?\\([[:alpha:]]+\\(?:Template\\|[:.][[:alpha:]-]+\\)\\|TMPL_[[:alpha:]]+\\)" 1 'web-mode-block-control-face)
   2298    '("\\_<\\([[:alpha:]-]+=\\)\\(\"[^\"]*\"\\)"
   2299      (1 'web-mode-block-attr-name-face t t)
   2300      (2 'web-mode-block-attr-value-face t t))
   2301    '("\\_<\\([[:alpha:]-]+=\\)\\('[^']*\'\\)"
   2302      (1 'web-mode-block-attr-name-face t t)
   2303      (2 'web-mode-block-attr-value-face t t))
   2304    ))
   2305 
   2306 (defvar web-mode-jsp-font-lock-keywords
   2307   (list
   2308    '("\\(throws\\|new\\|extends\\)[ ]+\\([[:alnum:].]+\\)" 2 'web-mode-type-face)
   2309    (cons (concat "\\_<\\(" web-mode-jsp-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2310    '("\\(public\\|private\\)[ ]+\\([[:alpha:]]+\\)[ ]+\\([[:alnum:]._]+\\)[ ]?("
   2311      (2 'web-mode-type-face)
   2312      (3 'web-mode-function-name-face))
   2313    '("\\_<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2314    '("@\\(\\sw*\\)" 1 'web-mode-variable-name-face)
   2315    '("\\_<\\([[:alnum:].]+\\)[ ]+[{[:alpha:]]+" 1 'web-mode-type-face)
   2316    ))
   2317 
   2318 (defvar web-mode-asp-font-lock-keywords
   2319   (list
   2320    (cons (concat "\\_<\\(" web-mode-asp-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2321    (cons (concat "\\_<\\(" web-mode-asp-types "\\)\\_>") '(0 'web-mode-type-face))
   2322    (cons (concat "\\_<\\(" web-mode-asp-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2323    '("\\(Class\\|new\\) \\([[:alnum:]_]+\\)" 2 'web-mode-type-face)
   2324    '("Const \\([[:alnum:]_]+\\)" 1 'web-mode-constant-face)
   2325    '("\\_<dim\\_>"
   2326      (0 'web-mode-keyword-face)
   2327      ("[[:alnum:]_]+" nil nil (0 'web-mode-variable-name-face)))
   2328    '("\\_<\\(public\\|private\\|sub\\|function\\)\\_> \\([[:alnum:]_]+\\)[ ]*(" 2 'web-mode-function-name-face)
   2329    '("\\_<\\(public\\|private\\|dim\\)\\_> \\([[:alnum:]_]+\\)" 2 'web-mode-variable-name-face)
   2330    ))
   2331 
   2332 (defvar web-mode-aspx-font-lock-keywords
   2333   (list
   2334    (cons (concat "\\_<\\(" web-mode-aspx-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2335    '("\\_<\\([[:alnum:].]+\\)[ ]+[[:alpha:]]+" 1 'web-mode-type-face)
   2336    ))
   2337 
   2338 (defvar web-mode-uel-font-lock-keywords
   2339   (list
   2340    '("[$#{]{\\|}" 0 'web-mode-preprocessor-face)
   2341    '("\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2342    '("|[ ]*\\(trim\\|x\\|u\\)" 1 'web-mode-function-call-face)
   2343    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2344    ))
   2345 
   2346 (defvar web-mode-php-var-interpolation-font-lock-keywords
   2347   (list
   2348    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2349    '("\".+\"\\|'.*'" 0 'web-mode-string-face)
   2350    ))
   2351 
   2352 (defvar web-mode-marko-font-lock-keywords
   2353   (list
   2354    '("[[:alnum:]_]+" 0 'web-mode-variable-name-face)
   2355    ))
   2356 
   2357 (defvar web-mode-freemarker-square-font-lock-keywords
   2358   (list
   2359    '("\\[/?[#@]\\([[:alpha:]_.]*\\)" 1 'web-mode-block-control-face)
   2360    '("#\\(macro\\|function\\) \\([[:alpha:]]+\\)" 2 'web-mode-function-name-face)
   2361    (cons (concat "\\_<\\(" web-mode-freemarker-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2362    '("\\_<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2363    '("[[:alpha:]]\\([[:alnum:]_]+\\)?" 0 'web-mode-variable-name-face)
   2364    ))
   2365 
   2366 (defvar web-mode-freemarker-font-lock-keywords
   2367   (list
   2368    '("</?[#@]\\([[:alpha:]_.]*\\)" 1 'web-mode-block-control-face)
   2369    '("#\\(macro\\|function\\) \\([[:alpha:]]+\\)" 2 'web-mode-function-name-face)
   2370    (cons (concat "\\_<\\(" web-mode-freemarker-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2371    '("\\_<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2372    '("[[:alpha:]]\\([[:alnum:]_]+\\)?" 0 'web-mode-variable-name-face)
   2373    ))
   2374 
   2375 (defvar web-mode-directive-font-lock-keywords
   2376   (list
   2377    '("<%@[ ]*\\([[:alpha:]]+\\)[ ]+" 1 'web-mode-block-control-face)
   2378    '("\\_<\\([[:alpha:]]+=\\)\\(\"[^\"]*\"\\)"
   2379      (1 'web-mode-block-attr-name-face t t)
   2380      (2 'web-mode-block-attr-value-face t t))
   2381    ))
   2382 
   2383 (defvar web-mode-erb-font-lock-keywords
   2384   (list
   2385    '("[^:]\\(:[[:alnum:]_]+\\)" 1 'web-mode-symbol-face)
   2386    '("\\([[:alnum:]_]+:\\)[ ]+" 1 'web-mode-symbol-face)
   2387    (cons (concat "\\_<\\(" web-mode-erb-builtins "\\)\\_>") '(0 'web-mode-builtin-face))
   2388    (cons (concat "\\_<\\(" web-mode-erb-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2389    '("\\_<\\(self\\|true\\|false\\|nil\\)\\_>" 0 'web-mode-variable-name-face)
   2390    '("[@$]@?\\([[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2391    '("class[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-type-face)
   2392    '("def[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2393    '("\\(?:\\_<\\|::\\)\\([A-Z]+[[:alnum:]_]+\\)" 1 (unless (eq (char-after) ?\() 'web-mode-type-face))
   2394    '("/[^/]+/" 0 'web-mode-string-face)
   2395    ))
   2396 
   2397 (defvar web-mode-ejs-font-lock-keywords
   2398   web-mode-javascript-font-lock-keywords)
   2399 
   2400 (defvar web-mode-python-font-lock-keywords
   2401   (list
   2402    (cons (concat "\\_<\\(" web-mode-python-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2403    ))
   2404 
   2405 (defvar web-mode-elixir-font-lock-keywords
   2406   (list
   2407    '("@\\([[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2408    '("[ ]\\(:[[:alnum:]-_]+\\)" 1 'web-mode-symbol-face)
   2409    '("def[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2410    (cons (concat "\\_<\\(" web-mode-elixir-keywords "\\)\\_>") '(0 'web-mode-builtin-face))
   2411    (cons (concat "\\_<\\(" web-mode-elixir-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2412    ))
   2413 
   2414 (defvar web-mode-erlang-font-lock-keywords
   2415   (list
   2416    (cons (concat "\\_<\\(" web-mode-erlang-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2417    (cons (concat "\\_<\\(" web-mode-erlang-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2418    '("@\\([[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2419    '("[ ]\\(:[[:alnum:]-_]+\\)" 1 'web-mode-symbol-face)
   2420    ))
   2421 
   2422 (defvar web-mode-mason-code-font-lock-keywords
   2423   (list
   2424    (cons (concat "\\_<\\(" web-mode-mason-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2425    '("sub[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2426    '("\\_<\\([[:alnum:]_]+\\)[ ]?::" 1 'web-mode-type-face)
   2427    '("\\([@]\\)\\([[:alnum:]#_]*\\)" (1 nil) (2 'web-mode-variable-name-face))
   2428    '("\\_<\\([$%]\\)\\([[:alnum:]@#_]*\\)" (1 nil) (2 'web-mode-variable-name-face))
   2429    '("{\\([[:alnum:]_]+\\)}" 1 'web-mode-variable-name-face)
   2430    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2431    '("[[:alnum:]_][ ]?::[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2432    '("->[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2433    '("\\(?:method\\|def\\) \\([[:alnum:]._]+\\)" 1 'web-mode-function-name-face)
   2434    '("|[ ]*\\([[:alnum:],]+\\)[ ]*%>" 1 'web-mode-filter-face)
   2435    ))
   2436 
   2437 (defvar web-mode-mason-block-font-lock-keywords
   2438   (list
   2439    '("<[/]?%\\([[:alpha:]]+\\)" 1 'web-mode-block-control-face)
   2440    '("[[:alpha:]]" 0 'web-mode-block-attr-value-face)
   2441    ))
   2442 
   2443 (defvar web-mode-mojolicious-font-lock-keywords
   2444   (list
   2445    (cons (concat "\\_<\\(" web-mode-perl-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2446    '("\\_<\\(begin\\|end\\)\\_>" 1 'web-mode-constant-face)
   2447    '("\\_<\\([$]\\)\\([[:alnum:]_]*\\)" (1 nil) (2 'web-mode-variable-name-face))
   2448    ))
   2449 
   2450 (defvar web-mode-lsp-font-lock-keywords
   2451   (list
   2452    (cons (concat "\\_<\\(" web-mode-lsp-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2453    (cons (concat "\\_<\\(" web-mode-lsp-constants "\\)\\_>") '(1 'web-mode-constant-face))
   2454    '("[ ]\\(:[[:alnum:]-_]+\\)" 1 'web-mode-symbol-face)
   2455    '("(defun \\([[:alnum:]-:]+\\)" 1 'web-mode-function-name-face)
   2456    '("(defvar \\([[:alnum:]-:]+\\)" 1 'web-mode-variable-name-face)
   2457    ))
   2458 
   2459 (defvar web-mode-cl-emb-font-lock-keywords
   2460   (list
   2461    (cons (concat "\\_<\\(" web-mode-cl-emb-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2462    (cons (concat "\\_<\\(" web-mode-cl-emb-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2463    '("\\(@\\)" 1 'web-mode-function-call-face)
   2464    (list (concat "\\(@" web-mode-cl-emb-keywords "\\)[ ]+\\([[:alnum:]_]+\\)")
   2465          '(1 'web-mode-keyword-face)
   2466          '(2 'web-mode-variable-name-face))
   2467    ))
   2468 
   2469 (defvar web-mode-artanis-font-lock-keywords
   2470   (list
   2471    (cons (concat "\\_<\\(" web-mode-artanis-keywords  "\\)\\_>") '(0 'web-mode-keyword-face))
   2472    (cons (concat "\\_<\\(" web-mode-artanis-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2473    '("(define[*]? (\\([[:alnum:]-:_!#$%^&*=+/?<>.]+\\)" 1 'web-mode-function-name-face)
   2474    '("\\(#:[[:alnum:]-:_!#$%^&*=+/?<>.]+\\)"            1 'web-mode-builtin-face)
   2475    ))
   2476 
   2477 (defvar web-mode-php-font-lock-keywords
   2478   (list
   2479    (cons (concat "\\_<\\(" web-mode-php-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2480    (cons (concat "\\_<\\(" web-mode-php-types "\\)\\_>") '(1 'web-mode-type-face))
   2481    (cons (concat "\\_<\\(" web-mode-php-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2482    '("function[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2483    '("\\_<\\([[:alnum:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2484    '("[[:alnum:]_][ ]?::[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-constant-face)
   2485    '("->[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2486    '("\\_<\\([[:alnum:]_]+\\)[ ]?::" 1 'web-mode-type-face)
   2487    '("\\_<\\(instanceof\\|class\\|extends\\|new\\)[ ]+\\([[:alnum:]_]+\\)" 2 'web-mode-type-face)
   2488    '("\\(\\_<\\|[+-]\\)\\([$]\\)\\([[:alnum:]_]*\\)" (2 nil) (3 'web-mode-variable-name-face))
   2489    ))
   2490 
   2491 (defvar web-mode-spip-font-lock-keywords
   2492   (list
   2493    '("<:.+:>" 0 'web-mode-block-string-face)
   2494    '("#[A-Z0-9_]+" 0 'web-mode-variable-name-face)
   2495    '("|[a-z0-9_=!?<>]+" 0 'web-mode-function-call-face)
   2496    '("(\\([[:alnum:]_ ]+\\))" 1 'web-mode-constant-face)
   2497    ))
   2498 
   2499 (defvar web-mode-latex-font-lock-keywords
   2500   (list
   2501    '("[[:alnum:]_]+" 0 'web-mode-function-name-face t t)
   2502    ))
   2503 
   2504 (defvar web-mode-blade-font-lock-keywords
   2505   (append
   2506    (list
   2507     '("@\\([[:alpha:]_]+\\)" (1 'web-mode-block-control-face)))
   2508    web-mode-php-font-lock-keywords))
   2509 
   2510 (defvar web-mode-engines-font-lock-keywords
   2511   '(("angular"          . web-mode-angular-font-lock-keywords)
   2512     ("anki"             . web-mode-anki-font-lock-keywords)
   2513     ("antlers"          . web-mode-antlers-font-lock-keywords)
   2514     ("artanis"          . web-mode-artanis-font-lock-keywords)
   2515     ("astro"            . web-mode-astro-font-lock-keywords)
   2516     ("blade"            . web-mode-blade-font-lock-keywords)
   2517     ("cl-emb"           . web-mode-cl-emb-font-lock-keywords)
   2518     ("closure"          . web-mode-closure-font-lock-keywords)
   2519     ("ctemplate"        . web-mode-ctemplate-font-lock-keywords)
   2520     ("dust"             . web-mode-dust-font-lock-keywords)
   2521     ("elixir"           . web-mode-elixir-font-lock-keywords)
   2522     ("ejs"              . web-mode-ejs-font-lock-keywords)
   2523     ("erb"              . web-mode-erb-font-lock-keywords)
   2524     ("expressionengine" . web-mode-expressionengine-font-lock-keywords)
   2525     ("go"               . web-mode-go-font-lock-keywords)
   2526     ("hero"             . web-mode-go-font-lock-keywords)
   2527     ("lsp"              . web-mode-lsp-font-lock-keywords)
   2528     ("marko"            . web-mode-marko-font-lock-keywords)
   2529     ("mojolicious"      . web-mode-mojolicious-font-lock-keywords)
   2530     ("php"              . web-mode-php-font-lock-keywords)
   2531     ("python"           . web-mode-python-font-lock-keywords)
   2532     ("razor"            . web-mode-razor-font-lock-keywords)
   2533     ("riot"             . web-mode-riot-font-lock-keywords)
   2534     ("smarty"           . web-mode-smarty-font-lock-keywords)
   2535     ("spip"             . web-mode-spip-font-lock-keywords)
   2536     ("template-toolkit" . web-mode-template-toolkit-font-lock-keywords)
   2537     ("underscore"       . web-mode-underscore-font-lock-keywords)
   2538     ("web2py"           . web-mode-web2py-font-lock-keywords)
   2539     ("velocity"         . web-mode-velocity-font-lock-keywords)
   2540     ("vue"              . web-mode-vue-font-lock-keywords)
   2541     ("xoops"            . web-mode-smarty-font-lock-keywords)
   2542     ("svelte"           . web-mode-svelte-font-lock-keywords)
   2543     )
   2544   "Engines font-lock keywords")
   2545 
   2546 (defvar web-mode-prettify-symbols-alist
   2547   '(("=>" . 8658)
   2548     (">=" . 8805)
   2549     ("<=" . 8804)))
   2550 
   2551 (defvar web-mode-before-auto-complete-hooks nil
   2552   "List of functions to run before triggering the auto-complete library.
   2553 
   2554 Auto-complete sources will sometimes need some tweaking to work
   2555 nicely with web-mode. This hook gives users the chance to adjust
   2556 the environment as needed for ac-sources, right before they're used.")
   2557 
   2558 (defvar web-mode-ignore-ac-start-advice nil
   2559   "If not nil 'defadvice' for 'ac-start' will be ignored.
   2560 
   2561 Can be set inside a hook in 'web-mode-before-auto-complete-hooks' to
   2562 non nil to ignore the defadvice which sets ac-sources according to current
   2563 language. This is needed if the corresponding auto-completion triggers
   2564 another auto-completion with different ac-sources (e.g. ac-php)")
   2565 
   2566 (defvar web-mode-ac-sources-alist nil
   2567   "alist mapping language names to ac-sources for that language.")
   2568 
   2569 (defvar web-mode-trace nil
   2570   "Activate debug tracing.")
   2571 
   2572 (defvar web-mode-syntax-table
   2573   (let ((table (make-syntax-table)))
   2574     (modify-syntax-entry ?- "_" table)
   2575     (modify-syntax-entry ?_ "_" table) ;#563
   2576     (modify-syntax-entry ?< "." table)
   2577     (modify-syntax-entry ?> "." table)
   2578     (modify-syntax-entry ?& "." table)
   2579     (modify-syntax-entry ?/ "." table)
   2580     (modify-syntax-entry ?= "." table)
   2581     (modify-syntax-entry ?% "." table)
   2582     table)
   2583   "Syntax table used to reveal whitespaces.")
   2584 
   2585 (defvar web-mode-map
   2586   (let ((map (make-sparse-keymap)))
   2587 
   2588     (define-key map [menu-bar wm]             (cons "Web-Mode" (make-sparse-keymap)))
   2589     (define-key map [menu-bar wm dom]         (cons "Dom" (make-sparse-keymap)))
   2590     (define-key map [menu-bar wm blk]         (cons "Block" (make-sparse-keymap)))
   2591     (define-key map [menu-bar wm attr]        (cons "Html Attr" (make-sparse-keymap)))
   2592     (define-key map [menu-bar wm tag]         (cons "Html Tag" (make-sparse-keymap)))
   2593     (define-key map [menu-bar wm elt]         (cons "Html Element" (make-sparse-keymap)))
   2594 
   2595     (define-key map [menu-bar wm sep-1]       '(menu-item "--"))
   2596 
   2597     (define-key map [menu-bar wm dom dom-xpa] '(menu-item "XPath" web-mode-dom-xpath))
   2598     (define-key map [menu-bar wm dom dom-tra] '(menu-item "Traverse" web-mode-dom-traverse))
   2599     (define-key map [menu-bar wm dom dom-err] '(menu-item "Show error(s)" web-mode-dom-errors-show))
   2600     (define-key map [menu-bar wm dom dom-ent] '(menu-item "Replace html entities" web-mode-dom-entities-replace))
   2601     (define-key map [menu-bar wm dom dom-quo] '(menu-item "Replace dumb quotes" web-mode-dom-quotes-replace))
   2602     (define-key map [menu-bar wm dom dom-apo] '(menu-item "Replace apostrophes" web-mode-dom-apostrophes-replace))
   2603     (define-key map [menu-bar wm dom dom-nor] '(menu-item "Normalize" web-mode-dom-normalize))
   2604 
   2605     (define-key map [menu-bar wm blk blk-sel] '(menu-item "Select" web-mode-block-select))
   2606     (define-key map [menu-bar wm blk blk-pre] '(menu-item "Previous" web-mode-block-previous))
   2607     (define-key map [menu-bar wm blk blk-nex] '(menu-item "Next" web-mode-block-next))
   2608     (define-key map [menu-bar wm blk blk-kil] '(menu-item "Kill" web-mode-block-kill))
   2609     (define-key map [menu-bar wm blk blk-end] '(menu-item "End" web-mode-block-end))
   2610     (define-key map [menu-bar wm blk blk-clo] '(menu-item "Close" web-mode-block-close))
   2611     (define-key map [menu-bar wm blk blk-beg] '(menu-item "Beginning" web-mode-block-beginning))
   2612 
   2613     (define-key map [menu-bar wm attr attr-ins] '(menu-item "Insert" web-mode-attribute-insert))
   2614     (define-key map [menu-bar wm attr attr-end] '(menu-item "End" web-mode-attribute-end))
   2615     (define-key map [menu-bar wm attr attr-beg] '(menu-item "Beginning" web-mode-attribute-beginning))
   2616     (define-key map [menu-bar wm attr attr-sel] '(menu-item "Select" web-mode-attribute-select))
   2617     (define-key map [menu-bar wm attr attr-kil] '(menu-item "Kill" web-mode-attribute-kill))
   2618     (define-key map [menu-bar wm attr attr-nex] '(menu-item "Next" web-mode-attribute-next))
   2619     (define-key map [menu-bar wm attr attr-pre] '(menu-item "Previous" web-mode-attribute-previous))
   2620     (define-key map [menu-bar wm attr attr-tra] '(menu-item "Transpose" web-mode-attribute-transpose))
   2621 
   2622     (define-key map [menu-bar wm tag tag-beg] '(menu-item "Sort Attributes" web-mode-tag-attributes-sort))
   2623     (define-key map [menu-bar wm tag tag-sel] '(menu-item "Select" web-mode-tag-select))
   2624     (define-key map [menu-bar wm tag tag-pre] '(menu-item "Previous" web-mode-tag-previous))
   2625     (define-key map [menu-bar wm tag tag-nex] '(menu-item "Next" web-mode-tag-next))
   2626     (define-key map [menu-bar wm tag tag-end] '(menu-item "End" web-mode-tag-end))
   2627     (define-key map [menu-bar wm tag tag-beg] '(menu-item "Beginning" web-mode-tag-beginning))
   2628 
   2629     (define-key map [menu-bar wm elt elt-con] '(menu-item "Contract" web-mode-element-contract))
   2630     (define-key map [menu-bar wm elt elt-ext] '(menu-item "Extract" web-mode-element-extract))
   2631     (define-key map [menu-bar wm elt elt-van] '(menu-item "Vanish" web-mode-element-vanish))
   2632     (define-key map [menu-bar wm elt elt-exc] '(menu-item "Transpose" web-mode-element-transpose))
   2633     (define-key map [menu-bar wm elt elt-sel] '(menu-item "Select" web-mode-element-select))
   2634     (define-key map [menu-bar wm elt elt-ren] '(menu-item "Rename" web-mode-element-rename))
   2635     (define-key map [menu-bar wm elt elt-pre] '(menu-item "Previous" web-mode-element-previous))
   2636     (define-key map [menu-bar wm elt elt-par] '(menu-item "Parent" web-mode-element-parent))
   2637     (define-key map [menu-bar wm elt elt-nex] '(menu-item "Next" web-mode-element-next))
   2638     (define-key map [menu-bar wm elt elt-mut] '(menu-item "Mute blanks" web-mode-element-mute-blanks))
   2639     (define-key map [menu-bar wm elt elt-del] '(menu-item "Kill" web-mode-element-kill))
   2640     (define-key map [menu-bar wm elt elt-end] '(menu-item "End" web-mode-element-end))
   2641     (define-key map [menu-bar wm elt elt-inn] '(menu-item "Content (select)" web-mode-element-content-select))
   2642     (define-key map [menu-bar wm elt elt-clo] '(menu-item "Close" web-mode-element-close))
   2643     (define-key map [menu-bar wm elt elt-ins] '(menu-item "Insert" web-mode-element-insert))
   2644     (define-key map [menu-bar wm elt elt-ins] '(menu-item "Word to tag" web-mode-element-insert-at-point))
   2645     (define-key map [menu-bar wm elt elt-dup] '(menu-item "Clone" web-mode-element-clone))
   2646     (define-key map [menu-bar wm elt elt-cfo] '(menu-item "Children fold" web-mode-element-children-fold-or-unfold))
   2647     (define-key map [menu-bar wm elt elt-chi] '(menu-item "Child" web-mode-element-child))
   2648     (define-key map [menu-bar wm elt elt-beg] '(menu-item "Beginning" web-mode-element-beginning))
   2649 
   2650     (define-key map [menu-bar wm fol]         '(menu-item "Fold/Unfold" web-mode-fold-or-unfold))
   2651     (define-key map [menu-bar wm hig]         '(menu-item "Fontify buffer" web-mode-buffer-fontify))
   2652     (define-key map [menu-bar wm ind]         '(menu-item "Indent buffer" web-mode-buffer-indent))
   2653     (define-key map [menu-bar wm nav]         '(menu-item "Tag/Block navigation" web-mode-navigate))
   2654     (define-key map [menu-bar wm exp]         '(menu-item "Mark and Expand" web-mode-mark-and-expand))
   2655     (define-key map [menu-bar wm spa]         '(menu-item "Toggle whitespaces" web-mode-whitespaces-show))
   2656     (define-key map [menu-bar wm sni]         '(menu-item "Insert snippet" web-mode-snippet-insert))
   2657 
   2658     ;;--------------------------------------------------------------------------
   2659     ;; "C-c <LETTER>" are reserved for users
   2660 
   2661     (define-key map (kbd "C-c C-a b") 'web-mode-attribute-beginning)
   2662     (define-key map (kbd "C-c C-a e") 'web-mode-attribute-end)
   2663     (define-key map (kbd "C-c C-a i") 'web-mode-attribute-insert)
   2664     (define-key map (kbd "C-c C-a n") 'web-mode-attribute-next)
   2665     (define-key map (kbd "C-c C-a s") 'web-mode-attribute-select)
   2666     (define-key map (kbd "C-c C-a k") 'web-mode-attribute-kill)
   2667     (define-key map (kbd "C-c C-a p") 'web-mode-attribute-previous)
   2668     (define-key map (kbd "C-c C-a t") 'web-mode-attribute-transpose)
   2669 
   2670     (define-key map (kbd "C-c C-b b") 'web-mode-block-beginning)
   2671     (define-key map (kbd "C-c C-b c") 'web-mode-block-close)
   2672     (define-key map (kbd "C-c C-b e") 'web-mode-block-end)
   2673     (define-key map (kbd "C-c C-b k") 'web-mode-block-kill)
   2674     (define-key map (kbd "C-c C-b n") 'web-mode-block-next)
   2675     (define-key map (kbd "C-c C-b p") 'web-mode-block-previous)
   2676     (define-key map (kbd "C-c C-b s") 'web-mode-block-select)
   2677 
   2678     (define-key map (kbd "C-c C-d a") 'web-mode-dom-apostrophes-replace)
   2679     (define-key map (kbd "C-c C-d d") 'web-mode-dom-errors-show)
   2680     (define-key map (kbd "C-c C-d e") 'web-mode-dom-entities-replace)
   2681     (define-key map (kbd "C-c C-d n") 'web-mode-dom-normalize)
   2682     (define-key map (kbd "C-c C-d q") 'web-mode-dom-quotes-replace)
   2683     (define-key map (kbd "C-c C-d t") 'web-mode-dom-traverse)
   2684     (define-key map (kbd "C-c C-d x") 'web-mode-dom-xpath)
   2685 
   2686     (define-key map (kbd "C-c C-e /") 'web-mode-element-close)
   2687     (define-key map (kbd "C-c C-e a") 'web-mode-element-content-select)
   2688     (define-key map (kbd "C-c C-e b") 'web-mode-element-beginning)
   2689     (define-key map (kbd "C-c C-e c") 'web-mode-element-clone)
   2690     (define-key map (kbd "C-c C-e d") 'web-mode-element-child)
   2691     (define-key map (kbd "C-c C-e e") 'web-mode-element-end)
   2692     (define-key map (kbd "C-c C-e f") 'web-mode-element-children-fold-or-unfold)
   2693     (define-key map (kbd "C-c C-e i") 'web-mode-element-insert)
   2694     (define-key map (kbd "C-c C-e I") 'web-mode-element-insert-at-point)
   2695     (define-key map (kbd "C-c C-e k") 'web-mode-element-kill)
   2696     (define-key map (kbd "C-c C-e m") 'web-mode-element-mute-blanks)
   2697     (define-key map (kbd "C-c C-e n") 'web-mode-element-next)
   2698     (define-key map (kbd "C-c C-e p") 'web-mode-element-previous)
   2699     (define-key map (kbd "C-c C-e r") 'web-mode-element-rename)
   2700     (define-key map (kbd "C-c C-e s") 'web-mode-element-select)
   2701     (define-key map (kbd "C-c C-e t") 'web-mode-element-transpose)
   2702     (define-key map (kbd "C-c C-e u") 'web-mode-element-parent)
   2703     (define-key map (kbd "C-c C-e v") 'web-mode-element-vanish)
   2704     (define-key map (kbd "C-c C-e w") 'web-mode-element-wrap)
   2705     (define-key map (kbd "C-c C-e +") 'web-mode-element-extract)
   2706     (define-key map (kbd "C-c C-e -") 'web-mode-element-contract)
   2707 
   2708     (define-key map (kbd "C-c C-t a") 'web-mode-tag-attributes-sort)
   2709     (define-key map (kbd "C-c C-t b") 'web-mode-tag-beginning)
   2710     (define-key map (kbd "C-c C-t e") 'web-mode-tag-end)
   2711     (define-key map (kbd "C-c C-t m") 'web-mode-tag-match)
   2712     (define-key map (kbd "C-c C-t n") 'web-mode-tag-next)
   2713     (define-key map (kbd "C-c C-t p") 'web-mode-tag-previous)
   2714     (define-key map (kbd "C-c C-t s") 'web-mode-tag-select)
   2715 
   2716     ;;--------------------------------------------------------------------------
   2717 
   2718     ;;(define-key map (kbd "M-q")       'fill-paragraph)
   2719     (define-key map (kbd "M-;")       'web-mode-comment-or-uncomment)
   2720 
   2721     ;;C-c C-a : attribute
   2722     ;;C-c C-b : block
   2723     ;;C-c C-d : dom
   2724     ;;C-c C-e : element
   2725     (define-key map (kbd "C-c C-f")   'web-mode-fold-or-unfold)
   2726     (define-key map (kbd "C-c C-h")   'web-mode-buffer-fontify)
   2727     (define-key map (kbd "C-c C-i")   'web-mode-buffer-indent)
   2728     (define-key map (kbd "C-c C-j")   'web-mode-jshint)
   2729     (define-key map (kbd "C-c C-l")   'web-mode-file-link)
   2730     (define-key map (kbd "C-c C-m")   'web-mode-mark-and-expand)
   2731     (define-key map (kbd "C-c C-n")   'web-mode-navigate)
   2732     (define-key map (kbd "C-c C-r")   'web-mode-reload)
   2733     (define-key map (kbd "C-c C-s")   'web-mode-snippet-insert)
   2734     ;;C-c C-t : tag
   2735     (define-key map (kbd "C-c C-w")   'web-mode-whitespaces-show)
   2736 
   2737     map)
   2738   "Keymap for `web-mode'.")
   2739 
   2740 ;;---- COMPATIBILITY -----------------------------------------------------------
   2741 
   2742 (eval-and-compile
   2743 
   2744   ;; compatibility with emacs < 23
   2745   (defun web-mode-string-match-p (regexp string &optional start)
   2746     "Same as `string-match' except it does not change the match data."
   2747     (let ((inhibit-changing-match-data t))
   2748       (string-match regexp string start)))
   2749 
   2750   (unless (fboundp 'string-match-p)
   2751     (fset 'string-match-p (symbol-function 'web-mode-string-match-p)))
   2752 
   2753   ;; compatibility with emacs < 23.3
   2754   (if (fboundp 'with-silent-modifications)
   2755       (defalias 'web-mode-with-silent-modifications 'with-silent-modifications)
   2756       (defmacro web-mode-with-silent-modifications (&rest body)
   2757         `(let ((old-modified-p (buffer-modified-p))
   2758                (inhibit-modification-hooks t)
   2759                (buffer-undo-list t))
   2760            (unwind-protect
   2761                 ,@body
   2762              (restore-buffer-modified-p old-modified-p)))))
   2763 
   2764   ;; compatibility with emacs < 24.3
   2765   (defun web-mode-buffer-narrowed-p ()
   2766     (if (fboundp 'buffer-narrowed-p)
   2767         (buffer-narrowed-p)
   2768         (/= (- (point-max) (point-min)) (buffer-size))))
   2769 
   2770   ;; compatibility with emacs < 24
   2771   (defalias 'web-mode-prog-mode
   2772       (if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode))
   2773 
   2774   ;; compatibility with emacs < 24.3
   2775   (unless (fboundp 'setq-local)
   2776     (defmacro setq-local (var val)
   2777       `(set (make-local-variable ',var) ,val)))
   2778 
   2779   ;; compatability with emacs < 24.4
   2780   (defun web-mode-string-suffix-p (suffix string)
   2781     "Return t if STRING ends with SUFFIX."
   2782     (and (string-match (rx-to-string `(: ,suffix eos) t)
   2783                        string)
   2784          t))
   2785 
   2786   (unless (fboundp 'string-suffix-p)
   2787     (fset 'string-suffix-p (symbol-function 'web-mode-string-suffix-p)))
   2788 
   2789   (unless (fboundp 'seq-some)
   2790     (defun seq-some (pred seq)
   2791       (unless (null seq)
   2792         (or (funcall pred (car seq))
   2793             (seq-some pred (cdr seq))))))
   2794   ) ;eval-and-compile
   2795 
   2796 ;;---- MAJOR MODE --------------------------------------------------------------
   2797 
   2798 ;;;###autoload
   2799 (define-derived-mode
   2800     web-mode web-mode-prog-mode "Web"
   2801     "Major mode for editing web templates."
   2802 
   2803     (make-local-variable 'web-mode-attr-indent-offset)
   2804     (make-local-variable 'web-mode-attr-value-indent-offset)
   2805     (make-local-variable 'web-mode-auto-pairs)
   2806     (make-local-variable 'web-mode-block-regexp)
   2807     (make-local-variable 'web-mode-change-beg)
   2808     (make-local-variable 'web-mode-change-end)
   2809     (make-local-variable 'web-mode-code-indent-offset)
   2810     (make-local-variable 'web-mode-column-overlays)
   2811     (make-local-variable 'web-mode-comment-formats)
   2812     (make-local-variable 'web-mode-comment-style)
   2813     (make-local-variable 'web-mode-content-type)
   2814     (make-local-variable 'web-mode-css-indent-offset)
   2815     (make-local-variable 'web-mode-display-table)
   2816     (make-local-variable 'web-mode-django-control-blocks)
   2817     (make-local-variable 'web-mode-django-control-blocks-regexp)
   2818     (make-local-variable 'web-mode-enable-block-face)
   2819     (make-local-variable 'web-mode-enable-inlays)
   2820     (make-local-variable 'web-mode-enable-part-face)
   2821     (make-local-variable 'web-mode-enable-sexp-functions)
   2822     (make-local-variable 'web-mode-engine)
   2823     (make-local-variable 'web-mode-engine-attr-regexp)
   2824     (make-local-variable 'web-mode-engine-file-regexps)
   2825     (make-local-variable 'web-mode-engine-open-delimiter-regexps)
   2826     (make-local-variable 'web-mode-engine-token-regexp)
   2827     (make-local-variable 'web-mode-expand-initial-pos)
   2828     (make-local-variable 'web-mode-expand-initial-scroll)
   2829     (make-local-variable 'web-mode-expand-previous-state)
   2830     (make-local-variable 'web-mode-indent-style)
   2831     (make-local-variable 'web-mode-indentless-attributes)
   2832     (make-local-variable 'web-mode-indentless-elements)
   2833     (make-local-variable 'web-mode-is-scratch)
   2834     (make-local-variable 'web-mode-skip-fontification)
   2835     (make-local-variable 'web-mode-jshint-errors)
   2836     (make-local-variable 'web-mode-last-enabled-feature)
   2837     (make-local-variable 'web-mode-markup-indent-offset)
   2838     (make-local-variable 'web-mode-minor-engine)
   2839     (make-local-variable 'web-mode-overlay-tag-end)
   2840     (make-local-variable 'web-mode-overlay-tag-start)
   2841     (make-local-variable 'web-mode-part-beg)
   2842     (make-local-variable 'web-mode-scan-beg)
   2843     (make-local-variable 'web-mode-scan-end)
   2844     (make-local-variable 'web-mode-sql-indent-offset)
   2845     (make-local-variable 'web-mode-time)
   2846     (make-local-variable 'web-mode-trace)
   2847 
   2848     (make-local-variable 'font-lock-beg)
   2849     (make-local-variable 'font-lock-end)
   2850 
   2851     (make-local-variable 'comment-end)
   2852     (make-local-variable 'comment-region-function)
   2853     (make-local-variable 'comment-start)
   2854     (make-local-variable 'fill-paragraph-function)
   2855     (make-local-variable 'font-lock-defaults)
   2856     (make-local-variable 'font-lock-extend-region-functions)
   2857     (make-local-variable 'font-lock-support-mode)
   2858     (make-local-variable 'font-lock-unfontify-region-function)
   2859     (make-local-variable 'imenu-case-fold-search)
   2860     (make-local-variable 'imenu-create-index-function)
   2861     (make-local-variable 'imenu-generic-expression)
   2862     (make-local-variable 'indent-line-function)
   2863     (make-local-variable 'parse-sexp-lookup-properties)
   2864     (make-local-variable 'uncomment-region-function)
   2865     (make-local-variable 'yank-excluded-properties)
   2866 
   2867     (setq web-mode-time (current-time))
   2868 
   2869     (setq comment-end "-->"
   2870           comment-region-function 'web-mode-comment-or-uncomment-region
   2871           comment-start "<!--"
   2872           fill-paragraph-function 'web-mode-fill-paragraph
   2873           ;;font-lock-defaults '(web-mode-font-lock-keywords t)
   2874           font-lock-defaults '('(web-mode-fontify) t)
   2875           font-lock-extend-region-functions '(web-mode-extend-region)
   2876           font-lock-support-mode nil
   2877           font-lock-unfontify-region-function 'web-mode-unfontify-region
   2878           imenu-case-fold-search t
   2879           imenu-create-index-function 'web-mode-imenu-index
   2880           indent-line-function 'web-mode-indent-line
   2881           parse-sexp-lookup-properties t
   2882           yank-excluded-properties t
   2883           uncomment-region-function 'web-mode-comment-or-uncomment-region
   2884           prettify-symbols-alist web-mode-prettify-symbols-alist)
   2885 
   2886     (substitute-key-definition #'indent-new-comment-line
   2887                                #'web-mode-comment-indent-new-line
   2888                                web-mode-map global-map)
   2889 
   2890     (add-hook 'after-change-functions #'web-mode-on-after-change nil t)
   2891     (add-hook 'after-save-hook        #'web-mode-on-after-save t t)
   2892     (add-hook 'change-major-mode-hook #'web-mode-on-exit nil t)
   2893     (add-hook 'post-command-hook      #'web-mode-on-post-command nil t)
   2894 
   2895     (cond
   2896       ((boundp 'yas-after-exit-snippet-hook)
   2897        (add-hook 'yas-after-exit-snippet-hook
   2898                  'web-mode-yasnippet-exit-hook
   2899                  t t))
   2900       ((boundp 'yas/after-exit-snippet-hook)
   2901        (add-hook 'yas/after-exit-snippet-hook
   2902                  'web-mode-yasnippet-exit-hook
   2903                  t t))
   2904       )
   2905 
   2906     (when web-mode-enable-whitespace-fontification
   2907       (web-mode-whitespaces-on))
   2908 
   2909     (when web-mode-enable-sexp-functions
   2910       (setq-local forward-sexp-function #'web-mode-forward-sexp))
   2911 
   2912     (web-mode-guess-engine-and-content-type)
   2913     (setq web-mode-change-beg (point-min)
   2914           web-mode-change-end (point-max))
   2915     (when (> (point-max) 256000)
   2916       (web-mode-buffer-fontify))
   2917 
   2918     (when (and (boundp 'hs-special-modes-alist)
   2919                (not (assoc major-mode hs-special-modes-alist)))
   2920       (add-to-list 'hs-special-modes-alist '(web-mode "{" "}" "/[*/]" web-mode-forward-sexp nil))
   2921       ) ;when
   2922 
   2923     ;; compatibility with emacs < 24
   2924     (if (fboundp 'prog-mode)
   2925         (put 'web-mode 'derived-mode-parent 'prog-mode))
   2926 
   2927     (cond
   2928       ((not (buffer-file-name))
   2929        )
   2930       ((string-match-p "web-mode-benchmark.html" (buffer-file-name))
   2931        (web-mode-measure "end"))
   2932       ) ;cond
   2933 
   2934     )
   2935 
   2936 ;;---- INVALIDATION ------------------------------------------------------------
   2937 
   2938 ;; 1/ after-change
   2939 ;; 2/ extend-region
   2940 ;; 3/ scan
   2941 ;; 4/ fontify
   2942 ;; 5/ post-command
   2943 
   2944 (defun web-mode-on-after-change (beg end len)
   2945   (when web-mode-trace
   2946     (message "after-change: pos(%d) beg(%d) end(%d) len(%d) this-command(%S)"
   2947              (point) beg end len this-command))
   2948   (when (or (null web-mode-change-beg) (< beg web-mode-change-beg))
   2949     (setq web-mode-change-beg beg))
   2950   (when (or (null web-mode-change-end) (> end web-mode-change-end))
   2951     (setq web-mode-change-end end)))
   2952 
   2953 (defun web-mode-extend-region ()
   2954   (when web-mode-trace
   2955     (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)"
   2956              font-lock-beg font-lock-end web-mode-change-beg web-mode-change-end web-mode-skip-fontification))
   2957   (when (and (string= web-mode-engine "php")
   2958              (and (>= font-lock-beg 6) (<= font-lock-beg 9))
   2959              (or (message (buffer-substring-no-properties 1 6)) t)
   2960              (string= (buffer-substring-no-properties 1 6) "<?php"))
   2961     (setq font-lock-beg (point-min)
   2962           font-lock-end (point-max))
   2963     )
   2964   (when (or (null web-mode-change-beg) (< font-lock-beg web-mode-change-beg))
   2965     (when web-mode-trace (message "extend-region: font-lock-beg(%S) < web-mode-change-beg(%S)" font-lock-beg web-mode-change-beg))
   2966     (setq web-mode-change-beg font-lock-beg))
   2967   (when (or (null web-mode-change-end) (> font-lock-end web-mode-change-end))
   2968     (when web-mode-trace (message "extend-region: font-lock-end(%S) > web-mode-change-end(%S)" font-lock-end web-mode-change-end))
   2969     (setq web-mode-change-end font-lock-end))
   2970   (when font-lock-dont-widen
   2971     (setq web-mode-change-beg (max web-mode-change-beg (point-min))
   2972           web-mode-change-end (min web-mode-change-end (point-max))))
   2973   (let ((region (web-mode-scan web-mode-change-beg web-mode-change-end)))
   2974     (when region
   2975       ;;(message "region: %S" region)
   2976       (setq font-lock-beg (car region)
   2977             font-lock-end (cdr region))
   2978       ) ;when
   2979     ) ;let
   2980   nil)
   2981 
   2982 (defun web-mode-scan (&optional beg end)
   2983   (when web-mode-trace
   2984     (message "scan: beg(%S) end(%S) web-mode-change-beg(%S) web-mode-change-end(%S)"
   2985              beg end web-mode-change-beg web-mode-change-end))
   2986   (unless beg (setq beg web-mode-change-beg))
   2987   (unless end (setq end web-mode-change-end))
   2988   ;;(message "%S %S %S" web-mode-content-type (get-text-property beg 'part-side) (get-text-property end 'part-side))
   2989   (when (and end (> end (point-max)))
   2990     (setq end (point-max)))
   2991   (setq web-mode-change-beg nil
   2992         web-mode-change-end nil)
   2993   (cond
   2994     ((or (null beg) (null end))
   2995      nil)
   2996     ((and (member web-mode-engine '("php" "asp"))
   2997           (get-text-property beg 'block-side)
   2998           (get-text-property end 'block-side)
   2999           (> beg (point-min))
   3000           (not (eq (get-text-property (1- beg) 'block-token) 'delimiter-beg))
   3001           (not (eq (get-text-property end 'block-token) 'delimiter-end)))
   3002      ;;(message "invalidate block (%S > %S)" beg end)
   3003      (web-mode-invalidate-block-region beg end))
   3004     ((and (or (member web-mode-content-type
   3005                       '("css" "javascript" "json" "jsx" "sass" "stylus" "typescript"))
   3006               (and (get-text-property beg 'part-side)
   3007                    (get-text-property end 'part-side)
   3008                    (> beg (point-min))
   3009                    (get-text-property (1- beg) 'part-side))
   3010               ))
   3011      ;;(message "invalidate part (%S > %S)" beg end)
   3012      (web-mode-invalidate-part-region beg end))
   3013     (t
   3014      ;;(message "invalidate default (%S > %S)" beg end)
   3015      (web-mode-invalidate-region beg end))
   3016     ) ;cond
   3017   )
   3018 
   3019 (defun web-mode-invalidate-region (reg-beg reg-end)
   3020   (when web-mode-trace
   3021     (message "invalidate-region: point(%S) reg-beg(%S) reg-end(%S)" (point) reg-beg reg-end))
   3022   (setq reg-beg (web-mode-invalidate-region-beginning-position reg-beg)
   3023         reg-end (web-mode-invalidate-region-end-position reg-end))
   3024   ;;(message "invalidate-region: reg-beg(%S) reg-end(%S)" reg-beg reg-end)
   3025   (web-mode-scan-region reg-beg reg-end))
   3026 
   3027 (defun web-mode--command-is-self-insert-p ()
   3028   "Return non-nil if `this-command' is `self-insert-command'.
   3029 Also return non-nil if it is the command `self-insert-command' is remapped to."
   3030   (memq this-command (list 'self-insert-command
   3031                            (key-binding [remap self-insert-command]))))
   3032 
   3033 (defun web-mode-on-post-command ()
   3034   (when (and web-mode-trace
   3035              (not (member this-command
   3036                           '(left-char right-char previous-line next-line save-buffer mwheel-scroll end-of-line beginning-of-line))))
   3037     (message "post-command: this-command(%S) web-mode-change-beg(%S) web-mode-change-end(%S) previous-state(%S)"
   3038              this-command web-mode-change-beg web-mode-change-end web-mode-expand-previous-state))
   3039   (let (ctx n char)
   3040     (when (and web-mode-expand-previous-state
   3041                (not (member this-command web-mode-commands-like-expand-region)))
   3042       (when (eq this-command 'keyboard-quit)
   3043         (goto-char web-mode-expand-initial-pos))
   3044       (deactivate-mark)
   3045       (when web-mode-expand-initial-scroll
   3046         (set-window-start (selected-window) web-mode-expand-initial-scroll)
   3047         )
   3048       (setq web-mode-expand-previous-state nil
   3049             web-mode-expand-initial-pos nil
   3050             web-mode-expand-initial-scroll nil))
   3051 
   3052     (when (member this-command '(yank))
   3053       ;;(setq web-mode-skip-fontification nil)
   3054       (when (and web-mode-scan-beg web-mode-scan-end global-font-lock-mode)
   3055         (save-excursion
   3056           (font-lock-fontify-region web-mode-scan-beg web-mode-scan-end))
   3057         (when web-mode-enable-auto-indentation
   3058           (indent-region web-mode-scan-beg web-mode-scan-end))
   3059         ) ;and
   3060       )
   3061 
   3062     (when (and (< (point) 16) web-mode-change-beg web-mode-change-end)
   3063       (web-mode-detect-content-type))
   3064 
   3065     (when (and web-mode-change-beg web-mode-change-end
   3066                web-mode-enable-engine-detection
   3067                (or (null web-mode-engine) (string= web-mode-engine "none"))
   3068                (< (point) web-mode-chunk-length)
   3069                (web-mode-detect-engine))
   3070       (web-mode-on-engine-setted)
   3071       (web-mode-buffer-fontify))
   3072 
   3073     (when (> (point) 1)
   3074       (setq char (char-before)))
   3075 
   3076     (cond
   3077       ((null char)
   3078        )
   3079       ((and (>= (point) 3)
   3080             (web-mode--command-is-self-insert-p)
   3081             (not (member (get-text-property (point) 'part-token) '(comment string)))
   3082             (not (eq (get-text-property (point) 'tag-type) 'comment))
   3083             )
   3084        (setq ctx (web-mode-auto-complete)))
   3085       ((and web-mode-enable-auto-opening
   3086             (member this-command '(newline electric-newline-and-maybe-indent newline-and-indent))
   3087             (or (and (not (eobp))
   3088                      (eq (char-after) ?\<)
   3089                      (eq (get-text-property (point) 'tag-type) 'end)
   3090                      (looking-back ">\n[ \t]*" (point-min))
   3091                      (setq n (length (match-string-no-properties 0)))
   3092                      (eq (get-text-property (- (point) n) 'tag-type) 'start)
   3093                      (string= (get-text-property (- (point) n) 'tag-name)
   3094                               (get-text-property (point) 'tag-name))
   3095                      )
   3096                 (and (get-text-property (1- (point)) 'block-side)
   3097                      (string= web-mode-engine "php")
   3098                      (looking-back "<\\?php[ ]*\n" (point-min))
   3099                      (looking-at-p "[ ]*\\?>"))))
   3100        (newline-and-indent)
   3101        (forward-line -1)
   3102        (indent-according-to-mode)
   3103        )
   3104       ) ;cond
   3105 
   3106     (cond
   3107 
   3108       ((not web-mode-enable-auto-opening)
   3109        )
   3110       ((and (member this-command '(newline electric-newline-and-maybe-indent newline-and-indent))
   3111             (get-text-property (point) 'part-side)
   3112             (eq (get-text-property (point) 'part-token) 'string))
   3113        (indent-according-to-mode)
   3114        (when (and web-mode-change-end (> web-mode-change-end (point-max)))
   3115          (message "post-command: enlarge web-mode-change-end")
   3116          (setq web-mode-change-end (point-max))
   3117          )
   3118        )
   3119       ((and (web-mode--command-is-self-insert-p)
   3120             (or (and ctx
   3121                      (or (plist-get ctx :auto-closed)
   3122                          (plist-get ctx :auto-expanded)))
   3123                 (and (> (point) (point-min))
   3124                      (get-text-property (1- (point)) 'tag-end)
   3125                      (get-text-property (line-beginning-position) 'tag-beg))))
   3126        (indent-according-to-mode)
   3127        (when (and web-mode-change-end (> web-mode-change-end (point-max)))
   3128          (message "post-command: enlarge web-mode-change-end")
   3129          (setq web-mode-change-end (point-max))
   3130          )
   3131        )
   3132       ((and (web-mode--command-is-self-insert-p)
   3133             (member (get-text-property (point) 'part-side) '(javascript jsx css))
   3134             (looking-back "^[ \t]+[]})]" (point-min)))
   3135        (indent-according-to-mode)
   3136        (when (and web-mode-change-end (> web-mode-change-end (point-max)))
   3137          (message "post-command: enlarge web-mode-change-end")
   3138          (setq web-mode-change-end (point-max))
   3139          )
   3140        )
   3141       ) ; cond web-mode-enable-auto-opening
   3142 
   3143     (when web-mode-enable-current-element-highlight
   3144       (web-mode-highlight-current-element))
   3145 
   3146     (when (and web-mode-enable-current-column-highlight
   3147                (not (web-mode-buffer-narrowed-p)))
   3148       (web-mode-column-show))
   3149 
   3150     (when (and web-mode-trace (not (member this-command
   3151                                            '(left-char right-char previous-line next-line save-buffer mwheel-scroll end-of-line beginning-of-line))))
   3152       (when (or web-mode-change-beg web-mode-change-end)
   3153         (message "post-command: web-mode-change-beg(%S) web-mode-change-end(%S)"
   3154                  web-mode-change-end web-mode-change-end))
   3155       (message "-------------------------------------------------------------------")
   3156       )
   3157 
   3158     ))
   3159 
   3160 ;; NOTE: il est important d'identifier des caractères en fin de ligne
   3161 ;; web-mode-block-tokenize travaille en effet sur les fins de lignes pour
   3162 ;; les commentaires de type //
   3163 (defun web-mode-invalidate-block-region (pos-beg pos-end)
   3164   ;;  (message "pos-beg(%S) pos-end(%S)" pos-beg pos-end)
   3165   (save-excursion
   3166     (let (beg end code-beg code-end)
   3167       ;;(message "invalidate-block-region: pos-beg(%S)=%S" pos-beg (get-text-property pos 'block-side))
   3168       ;;(message "code-beg(%S) code-end(%S) pos-beg(%S) pos-end(%S)" code-beg code-end pos-beg pos-end)
   3169       (cond
   3170         ((not (and (setq code-beg (web-mode-block-code-beginning-position pos-beg))
   3171                    (setq code-end (web-mode-block-code-end-position pos-beg))
   3172                    (>= pos-beg code-beg)
   3173                    (<= pos-end code-end)
   3174                    (> code-end code-beg)))
   3175          (web-mode-invalidate-region pos-beg pos-end))
   3176         ((member web-mode-engine '("asp"))
   3177          (goto-char pos-beg)
   3178          (forward-line -1)
   3179          (setq beg (line-beginning-position))
   3180          (when (> code-beg beg)
   3181            (setq beg code-beg))
   3182          (goto-char pos-beg)
   3183          (forward-line)
   3184          (setq end (line-end-position))
   3185          (when (< code-end end)
   3186            (setq end code-end))
   3187          ;; ?? pas de (web-mode-block-tokenize beg end) ?
   3188          (web-mode-block-tokenize beg end)
   3189          (cons beg end)
   3190          ) ;asp
   3191         (t
   3192          (goto-char pos-beg)
   3193          ;;(message "pos-beg=%S" pos-beg)
   3194          (when (string= web-mode-engine "php")
   3195            (cond
   3196              ((and (looking-back "\*" (point-min))
   3197                    (looking-at-p "/"))
   3198               (search-backward "/*" code-beg))
   3199              ) ;cond
   3200            ) ;when
   3201          (if (web-mode-block-rsb "[;{}(][ ]*\n" code-beg)
   3202              (setq beg (match-end 0))
   3203              (setq beg code-beg))
   3204          (goto-char pos-end)
   3205          (if (web-mode-block-rsf "[;{})][ ]*\n" code-end)
   3206              (setq end (1- (match-end 0)))
   3207              (setq end code-end))
   3208          (web-mode-block-tokenize beg end)
   3209          ;;(message "beg(%S) end(%S)" beg end)
   3210          (cons beg end)
   3211          )
   3212         ) ;cond
   3213       )))
   3214 
   3215 (defun web-mode-invalidate-part-region (pos-beg pos-end)
   3216   (save-excursion
   3217     (let (beg end part-beg part-end language)
   3218       (if (member web-mode-content-type web-mode-part-content-types)
   3219           (setq language web-mode-content-type)
   3220           (setq language (symbol-name (get-text-property pos-beg 'part-side))))
   3221       (setq part-beg (web-mode-part-beginning-position pos-beg)
   3222             part-end (web-mode-part-end-position pos-beg))
   3223       ;;(message "language(%S) pos-beg(%S) pos-end(%S) part-beg(%S) part-end(%S)"
   3224       ;;         language pos-beg pos-end part-beg part-end)
   3225       (goto-char pos-beg)
   3226       (cond
   3227         ((not (and part-beg part-end
   3228                    (>= pos-beg part-beg)
   3229                    (<= pos-end part-end)
   3230                    (> part-end part-beg)))
   3231          (web-mode-invalidate-region pos-beg pos-end))
   3232         ((member language '("javascript" "json" "jsx" "typescript"))
   3233          (if (web-mode-javascript-rsb "[;{}(][ ]*\n" part-beg)
   3234              (setq beg (match-end 0))
   3235              (setq beg part-beg))
   3236          (goto-char pos-end)
   3237          (if (web-mode-javascript-rsf "[;{})][ ]*\n" part-end)
   3238              (setq end (match-end 0))
   3239              (setq end part-end))
   3240          (web-mode-scan-region beg end language))
   3241         ((member language '("css" "sass"))
   3242          (let (rule1 rule2)
   3243            (setq rule1 (web-mode-css-rule-current pos-beg))
   3244            (setq rule2 rule1)
   3245            (when (> pos-end (cdr rule1))
   3246              (setq rule2 (web-mode-css-rule-current pos-end)))
   3247            (setq beg (car rule1)
   3248                  end (cdr rule2))
   3249            )
   3250          (web-mode-scan-region beg end language))
   3251         (t
   3252          (setq beg part-beg
   3253                end part-end)
   3254          (web-mode-scan-region beg end language))
   3255         ) ;cond
   3256       )))
   3257 
   3258 (defun web-mode-invalidate-region-beginning-position (pos)
   3259   (save-excursion
   3260     (goto-char pos)
   3261 
   3262     (cond
   3263       ((and (looking-at-p ">") ;#1151
   3264             (looking-back "--" (point-min)))
   3265        (search-backward "<!--" nil t))
   3266       ((and (bolp) (not (bobp)))
   3267        (backward-char))
   3268       )
   3269 
   3270     (beginning-of-line)
   3271     ;;(message "pos=%S point=%S %S" pos (point) (text-properties-at (point)))
   3272     (setq pos (point-min))
   3273     (let ((continue (not (bobp))))
   3274       (while continue
   3275         (cond
   3276           ((bobp)
   3277            (setq continue nil))
   3278           ;; NOTE: Going back to the previous start tag is necessary
   3279           ;; when inserting a part endtag (e.g. </script>).
   3280           ;; Indeed, parts must be identified asap.
   3281           ((and (progn (back-to-indentation) t)
   3282                 (get-text-property (point) 'tag-beg)
   3283                 (eq (get-text-property (point) 'tag-type) 'start))
   3284            (setq pos (point)
   3285                  continue nil))
   3286           (t
   3287            (forward-line -1))
   3288           ) ;cond
   3289         ) ;while
   3290       ;;(message "pos=%S" pos)
   3291       pos)))
   3292 
   3293 (defun web-mode-invalidate-region-end-position (pos)
   3294   (save-excursion
   3295     (goto-char pos)
   3296     ;;(message "pos=%S %S" pos (get-text-property pos 'block-token))
   3297     (when (string= web-mode-engine "jsp")
   3298       (cond
   3299         ((and (looking-back "<%" (point-min))
   3300               (looking-at-p "--"))
   3301          (search-forward "--%>"))
   3302         ((and (looking-back "-- %" (point-min))
   3303               (looking-at-p ">"))
   3304          (search-forward "--%>"))
   3305         ) ;cond
   3306       ) ;when
   3307     (setq pos (point-max))
   3308     (let ((continue (not (eobp))))
   3309       (while continue
   3310         (end-of-line)
   3311         ;;(message "%S %S" (point) (get-text-property (point) 'block-token))
   3312         (cond
   3313           ((eobp)
   3314            (setq continue nil))
   3315           ((and (not (get-text-property (point) 'tag-type))
   3316                 (not (get-text-property (point) 'part-side))
   3317                 (not (get-text-property (point) 'block-side)))
   3318            (setq pos (point)
   3319                  continue nil))
   3320           (t
   3321            (forward-line))
   3322           ) ;cond
   3323         ) ;while
   3324       pos)))
   3325 
   3326 (defun web-mode-buffer-scan ()
   3327   "Scan entine buffer."
   3328   (interactive)
   3329   (web-mode-scan-region (point-min) (point-max)))
   3330 
   3331 (defun web-mode-scan-region (beg end &optional content-type)
   3332   "Identify nodes/parts/blocks and syntactic symbols (strings/comments/etc.)."
   3333   ;;(message "scan-region: beg(%d) end(%d) content-type(%S)" beg end content-type)
   3334   (setq web-mode-scan-beg beg
   3335         web-mode-scan-end end)
   3336   (web-mode-with-silent-modifications
   3337    (save-excursion
   3338      (save-restriction
   3339        (save-match-data
   3340          (let ((inhibit-point-motion-hooks t)
   3341                (inhibit-quit t))
   3342            (remove-list-of-text-properties beg end web-mode-scan-properties)
   3343            (cond
   3344              ((and content-type (string= content-type "php"))
   3345               )
   3346              ((and content-type (member content-type web-mode-part-content-types))
   3347               (put-text-property beg end 'part-side
   3348                                  (cond
   3349                                    ((string= content-type "javascript") 'javascript)
   3350                                    ((string= content-type "json") 'json)
   3351                                    ((string= content-type "jsx") 'jsx)
   3352                                    ((string= content-type "css") 'css)
   3353                                    ((string= content-type "sql") 'sql)
   3354                                    ((string= content-type "pug") 'pug)
   3355                                    ((string= content-type "sass") 'sass)
   3356                                    ((string= content-type "stylus") 'stylus)
   3357                                    ((string= content-type "markdown") 'markdown)
   3358                                    ((string= content-type "ruby") 'ruby)
   3359                                    ((string= content-type "typescript") 'typescript)
   3360                                    ))
   3361               (web-mode-scan-blocks beg end)
   3362               (web-mode-part-scan beg end content-type))
   3363              ((member web-mode-content-type web-mode-part-content-types)
   3364               (web-mode-scan-blocks beg end)
   3365               (web-mode-part-scan beg end))
   3366              ((string= web-mode-engine "riot")
   3367               (web-mode-scan-elements beg end)
   3368               (web-mode-scan-blocks beg end)
   3369               (web-mode-part-foreach beg end 'web-mode-part-scan))
   3370              (t
   3371               (web-mode-scan-blocks beg end)
   3372               (web-mode-scan-elements beg end)
   3373               (web-mode-part-foreach beg end 'web-mode-part-scan))
   3374              ) ;cond
   3375            (cons beg end)
   3376            ))))))
   3377 
   3378 ;;---- LEXER BLOCKS ------------------------------------------------------------
   3379 
   3380 (defun web-mode-scan-blocks (reg-beg reg-end)
   3381   "Identifies blocks (with block-side, block-beg, block-end text properties)."
   3382   (save-excursion
   3383 
   3384     (let ((i 0) open close closing-string sub1 sub2 pos tagopen tmp delim-open delim-close part-beg part-end tagclose)
   3385 
   3386       (goto-char reg-beg)
   3387 
   3388       ;;(message "%S: %Sx%S" (point) reg-beg reg-end)
   3389       ;;(message "regexp=%S" web-mode-block-regexp)
   3390       (while (and (< i 2000)
   3391                   (> reg-end (point))
   3392                   web-mode-block-regexp
   3393                   (re-search-forward web-mode-block-regexp reg-end t)
   3394                   (not (eobp)))
   3395 
   3396         (setq i (1+ i)
   3397               closing-string nil
   3398               close nil
   3399               tagopen (match-string 0)
   3400               open (match-beginning 0)
   3401               delim-open nil
   3402               delim-close nil
   3403               pos nil)
   3404 
   3405         (let ((l (length tagopen)))
   3406           (when (member (string-to-char tagopen) '(?\s ?\t))
   3407             (setq tagopen (replace-regexp-in-string "\\`[ \t]*" "" tagopen))
   3408             (setq open (+ open (- l (length tagopen))))
   3409             (setq l (length tagopen))
   3410             )
   3411           (setq sub1 (substring tagopen 0 1)
   3412                 sub2 (substring tagopen 0 (if (>= l 2) 2 1)))
   3413           )
   3414         ;;(message " found block #(%S) at pos=(%S), part-type=(%S)" i open (get-text-property open 'part-side))
   3415         (cond
   3416 
   3417           ((string= web-mode-engine "php")
   3418            (unless (member (char-after) '(?x ?X))
   3419              (setq closing-string '("<\\?". "\\?>")))
   3420            (cond
   3421              ((looking-at-p "<?php")
   3422               (setq delim-open "<?php"))
   3423              ((eq (char-after) ?\=)
   3424               (setq delim-open "<?="))
   3425              (t
   3426               (setq delim-open "<?"))
   3427              ) ;cond
   3428            (setq delim-close "?>")
   3429            ) ;php
   3430 
   3431           ((string= web-mode-engine "erb")
   3432            (cond
   3433              ((string= sub2 "<%")
   3434               (setq closing-string '("<%". "%>")
   3435                     delim-open "<%\\(==\\|[=-]\\)?"
   3436                     delim-close "[-]?%>"))
   3437              (t
   3438               (setq closing-string "EOL"
   3439                     delim-open "%"))
   3440              )
   3441            ) ;erb
   3442 
   3443           ((string= web-mode-engine "django")
   3444            (cond
   3445              ((string= sub2 "{{")
   3446               (setq closing-string "EODQ"
   3447                     ;;(setq closing-string '("{{" . "}}")
   3448                     delim-open "{{"
   3449                     delim-close "}}"))
   3450              ((string= sub2 "{%")
   3451               (setq closing-string "%}"
   3452                     delim-open "{%[+-]?"
   3453                     delim-close "[-]?%}"))
   3454              ((string= sub2 "{#")
   3455               (setq closing-string "#}"))
   3456              (t
   3457               (setq closing-string "EOL"
   3458                     delim-open "#[#]?"))
   3459              )
   3460            ) ;django
   3461 
   3462           ((string= web-mode-engine "anki")
   3463            (setq closing-string "}}"
   3464                  delim-open "{{[#/^]?"
   3465                  delim-close "}}")
   3466            ) ;anki
   3467 
   3468           ((string= web-mode-engine "ejs")
   3469            (setq closing-string "%>"
   3470                  delim-open "<%[=-]?"
   3471                  delim-close "[-]?%>")
   3472            ) ;ejs
   3473 
   3474           ((string= web-mode-engine "lsp")
   3475            (setq closing-string "%>"
   3476                  delim-open "<%[%#]?"
   3477                  delim-close "%>")
   3478            ) ;lsp
   3479 
   3480           ((string= web-mode-engine "mako")
   3481            (cond
   3482              ((and (string= tagopen "<%")
   3483                    (member (char-after) '(?\s ?\n ?\!)))
   3484               (setq closing-string "%>"
   3485                     delim-open "<%[!]?"
   3486                     delim-close "%>"))
   3487              ((member sub2 '("<%" "</"))
   3488               (setq closing-string ">"
   3489                     delim-open "</?%"
   3490                     delim-close "/?>"))
   3491              ((string= sub2 "${")
   3492               (setq closing-string "}"
   3493                     delim-open "${"
   3494                     delim-close "}"))
   3495              (t
   3496               (setq closing-string "EOL"
   3497                     delim-open "%"))
   3498              )
   3499            ) ;mako
   3500 
   3501           ((string= web-mode-engine "cl-emb")
   3502            (cond
   3503              ((string= tagopen "<%#")
   3504               (setq closing-string "#%>"))
   3505              ((string= sub2 "<%")
   3506               (setq closing-string "%>"
   3507                     delim-open "<%[=%]?"
   3508                     delim-close "%>"))
   3509              )
   3510            ) ;cl-emb
   3511 
   3512           ((string= web-mode-engine "artanis")
   3513            (cond
   3514              ((string= tagopen "<%;")
   3515               (setq closing-string "%>"))
   3516              ((string= tagopen "<%#|")
   3517               (setq closing-string "|#%>"))
   3518              ((string= sub2 "<@")
   3519               (setq closing-string "%>"
   3520                     delim-open "<@\\(css\\|icon\\|include\\|js\\)"
   3521                     delim-close "%>"))
   3522              ((string= sub2 "<%")
   3523               (setq closing-string "%>"
   3524                     delim-open "<%[=]?"
   3525                     delim-close "%>"))
   3526              )
   3527            ) ;artanis
   3528 
   3529           ((string= web-mode-engine "elixir")
   3530            (cond
   3531              ((member (char-after) '(?\#))
   3532               (setq closing-string "%>"))
   3533              (t
   3534               (setq closing-string "%>"
   3535                     delim-open "<%[=%]?"
   3536                     delim-close "%>"))
   3537              )
   3538            ) ;elixir
   3539 
   3540           ((string= web-mode-engine "mojolicious")
   3541            (cond
   3542              ((string= tagopen "<%#")
   3543               (setq closing-string "%>"))
   3544              ((string= sub2 "<%")
   3545               (setq closing-string "%>"
   3546                     delim-open "<%\\(==\\|[=%]\\)?"
   3547                     delim-close "%>"))
   3548              ((string= sub2 "%#")
   3549               (setq closing-string "EOL"))
   3550              (t
   3551               (setq closing-string "EOL"
   3552                     delim-open "%\\(==\\|[=%]\\)?"))
   3553              )
   3554            ) ;mojolicious
   3555 
   3556           ((string= web-mode-engine "ctemplate")
   3557            (cond
   3558              ((member tagopen '("{{{" "{{~"))
   3559               (setq closing-string "}~?}}"
   3560                     delim-open "{{~?{"
   3561                     delim-close "}~?}}")
   3562               )
   3563              ((string= tagopen "{~{")
   3564               (setq closing-string "}~?}"
   3565                     delim-open "{~{"
   3566                     delim-close "}~?}")
   3567               )
   3568              ((string= tagopen "{{!")
   3569               (setq closing-string (if (looking-at-p "--") "--}}" "}}"))
   3570               )
   3571              ((string= sub2 "{{")
   3572               (setq closing-string "}~?}"
   3573                     delim-open "{{[>#/%^&]?"
   3574                     delim-close "}~?}"))
   3575              (t
   3576               (setq closing-string "}}"
   3577                     delim-open "${{"
   3578                     delim-close "}}"))
   3579              )
   3580            ) ;ctemplate
   3581 
   3582           ((string= web-mode-engine "antlers")
   3583            (cond
   3584              ((string= tagopen "{{$")
   3585               (setq closing-string "$}}"
   3586                     delim-open "{{$"
   3587                     delim-close "$}}")
   3588               )
   3589              ((string= tagopen "{{?")
   3590               (setq closing-string "?}}"
   3591                     delim-open "{{?"
   3592                     delim-close "?}}")
   3593               )
   3594              ((string= tagopen "{{$")
   3595               (setq closing-string "$}}"
   3596                     delim-open "{{$"
   3597                     delim-close "$}}")
   3598               )
   3599              ((string= sub2 "{{")
   3600               (setq closing-string "}}"
   3601                     delim-open "{{"
   3602                     delim-close "}}"))
   3603              )
   3604            ) ;antlers
   3605 
   3606           ((string= web-mode-engine "astro")
   3607            (cond
   3608              ((string= tagopen "---")
   3609               (setq closing-string "---"
   3610                     delim-open "---"
   3611                     delim-close "---")
   3612               )
   3613              )
   3614            ) ;astro
   3615 
   3616           ((string= web-mode-engine "aspx")
   3617            (setq closing-string "%>"
   3618                  delim-open "<%[:=#@$]?"
   3619                  delim-close "%>")
   3620            ) ;aspx
   3621 
   3622           ((string= web-mode-engine "asp")
   3623            (cond
   3624              ((string= sub2 "<%")
   3625               (setq closing-string "%>"
   3626                     delim-open "<%[:=#@$]?"
   3627                     delim-close "%>"))
   3628              (t
   3629               (setq closing-string ">"
   3630                     delim-open "</?"
   3631                     delim-close "/?>"))
   3632              )
   3633            ) ;asp
   3634 
   3635           ((string= web-mode-engine "jsp")
   3636            (cond
   3637              ((looking-at-p "--")
   3638               (setq closing-string "--%>"))
   3639              ((string= sub2 "<%")
   3640               (setq closing-string "%>"
   3641                     delim-open "<%\\([!=@]\\|#=\\)?"
   3642                     delim-close "[-]?%>"))
   3643              ((string= sub2 "${")
   3644               (setq closing-string "}"
   3645                     delim-open "${"
   3646                     delim-close "}"))
   3647              )
   3648            ) ;jsp
   3649 
   3650           ((string= web-mode-engine "clip")
   3651            (setq closing-string ">"
   3652                  delim-open "</?"
   3653                  delim-close "/?>")
   3654            ) ;clip
   3655 
   3656           ((string= web-mode-engine "perl")
   3657            (setq closing-string ">"
   3658                  delim-open "</?"
   3659                  delim-close "/?>")
   3660            ) ;perl
   3661 
   3662           ((string= web-mode-engine "blade")
   3663            (cond
   3664              ((string= tagopen "{{-")
   3665               (setq closing-string "--}}"))
   3666              ((string= tagopen "{!!")
   3667               (setq closing-string "!!}"
   3668                     delim-open "{!!"
   3669                     delim-close "!!}"))
   3670              ((string= tagopen "@{{")
   3671               (setq closing-string nil))
   3672              ((string= tagopen "{{{")
   3673               (setq closing-string "}}}"
   3674                     delim-open "{{{"
   3675                     delim-close "}}}"))
   3676              ((string= sub2 "{{")
   3677               (setq closing-string "}}"
   3678                     delim-open "{{"
   3679                     delim-close "}}"))
   3680              ((looking-at-p "[[:alnum:]]+\\.[[:alpha:]]+")
   3681               )
   3682              ((looking-at-p "[[:alnum:]]+(")
   3683               (setq closing-string ")"
   3684                     delim-open "@"))
   3685              ((string= sub1 "@")
   3686               (setq closing-string "EOB"
   3687                     delim-open "@"))
   3688              )
   3689            ) ;blade
   3690 
   3691           ((string= web-mode-engine "smarty")
   3692            (cond
   3693              ((string= tagopen "{*")
   3694               (setq closing-string "*}")
   3695               )
   3696              ((string= tagopen "{#")
   3697               (setq closing-string "#}"
   3698                     delim-open "{#"
   3699                     delim-close "#}")
   3700               )
   3701              (t
   3702               (setq closing-string (cons "{" "}")
   3703                     delim-open "{/?"
   3704                     delim-close "}")
   3705               ) ;t
   3706              ) ;cond
   3707            ) ;smarty
   3708 
   3709           ((string= web-mode-engine "hero")
   3710            (setq closing-string "%>"
   3711                  delim-open "<%==?\\([biufsv]\\|bs\\)?\\|<%[:~@+!]?"
   3712                  delim-close "%>")
   3713            ) ;hero
   3714 
   3715           ((string= web-mode-engine "xoops")
   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            ) ;xoops
   3732 
   3733           ((string= web-mode-engine "web2py")
   3734            (setq closing-string "}}"
   3735                  delim-open "{{[=]?"
   3736                  delim-close "}}")
   3737            ) ;web2py
   3738 
   3739           ((string= web-mode-engine "expressionengine")
   3740            (cond
   3741              ((string= sub2 "{!--")
   3742               (setq closing-string "--}"))
   3743              (t
   3744               (setq closing-string '("{". "}")
   3745                     delim-open "{/?"
   3746                     delim-close "}")
   3747               )
   3748              )
   3749            ) ;expressionengine
   3750 
   3751           ((string= web-mode-engine "dust")
   3752            (cond
   3753              ((string= sub2 "{!")
   3754               (setq closing-string "!}"))
   3755              (t
   3756               (setq closing-string '("{". "}")
   3757                     delim-open "{[#/:?@><+^]?"
   3758                     delim-close "/?}")
   3759               )
   3760              )
   3761            ) ;dust
   3762 
   3763           ((string= web-mode-engine "svelte")
   3764            (cond
   3765              ((string= sub2 "{!")
   3766               (setq closing-string "!}"))
   3767              ((string= sub2 "{}")
   3768               (setq closing-string nil
   3769                     delim-open nil
   3770                     delim-close nil))
   3771              (t
   3772               (setq closing-string '("{". "}")
   3773                     delim-open "{[#/:?@><+^]?"
   3774                     delim-close "/?}")
   3775               )
   3776              )
   3777            ) ;svelte
   3778 
   3779           ((string= web-mode-engine "closure")
   3780            (cond
   3781              ((string= sub2 "//")
   3782               (setq closing-string "EOL")
   3783               )
   3784              ((string= sub2 "/*")
   3785               (setq closing-string "*/")
   3786               )
   3787              (t
   3788               (setq closing-string "}"
   3789                     delim-open "{/?"
   3790                     delim-close "/?}")
   3791               )
   3792              )
   3793            ) ;closure
   3794 
   3795           ((string= web-mode-engine "go")
   3796            (setq closing-string "}}"
   3797                  delim-open "{{-?"
   3798                  delim-close "-?}}")
   3799            ) ;go
   3800 
   3801           ((string= web-mode-engine "angular")
   3802            (setq closing-string "}}"
   3803                  delim-open "{{"
   3804                  delim-close "}}")
   3805            ) ;angular
   3806 
   3807           ((string= web-mode-engine "vue")
   3808            (cond
   3809              ((string-match-p "[:@][-[:alpha:]]+=\"" tagopen)
   3810               (setq closing-string "\""
   3811                     delim-open tagopen
   3812                     delim-close "\""))
   3813              ((string= tagopen "{{")
   3814               (setq closing-string "}}"
   3815                     delim-open "{{"
   3816                     delim-close "}}")))
   3817            ) ;vue
   3818 
   3819           ((string= web-mode-engine "mason")
   3820            (cond
   3821              ((and (member sub2 '("<%" "</"))
   3822                    (looking-at "[[:alpha:]]+"))
   3823               (if (member (match-string-no-properties 0) '("after" "around" "augment" "before" "def" "filter" "method" "override"))
   3824                   (setq closing-string ">"
   3825                         delim-open "<[/]?%"
   3826                         delim-close ">")
   3827                   (setq closing-string (concat "</%" (match-string-no-properties 0) ">")
   3828                         delim-open "<[^>]+>"
   3829                         delim-close "<[^>]+>")
   3830                   ) ;if
   3831               )
   3832              ((and (string= sub2 "<%")
   3833                    (eq (char-after) ?\s))
   3834               (setq closing-string "%>"
   3835                     delim-open "<%"
   3836                     delim-close "%>"))
   3837              ((string= tagopen "</&")
   3838               (setq closing-string ">"
   3839                     delim-open "</&"
   3840                     delim-close ">")
   3841               )
   3842              ((string= sub2 "<&")
   3843               (setq closing-string "&>"
   3844                     delim-open "<&[|]?"
   3845                     delim-close "&>"))
   3846              (t
   3847               (setq closing-string "EOL"
   3848                     delim-open "%"))
   3849              )
   3850            ) ;mason
   3851 
   3852           ((string= web-mode-engine "underscore")
   3853            (setq closing-string "%>"
   3854                  delim-open "<%"
   3855                  delim-close "%>")
   3856            ) ;underscore
   3857 
   3858           ((string= web-mode-engine "template-toolkit")
   3859            (cond
   3860              ((string= tagopen "%%#")
   3861               (setq closing-string "EOL"))
   3862              ((string= tagopen "[%#")
   3863               (setq closing-string "%]"))
   3864              (t
   3865               (setq closing-string "%]"
   3866                     delim-open "\\[%[-+]?"
   3867                     delim-close "[-=+]?%\\]"))
   3868              )
   3869            ) ;template-toolkit
   3870 
   3871           ((string= web-mode-engine "freemarker")
   3872            (cond
   3873              ((and (string= sub2 "<#") (eq (char-after) ?\-))
   3874               (setq closing-string "-->"))
   3875              ((string= sub1 "<")
   3876               (setq closing-string ">"
   3877                     delim-open "</?[#@]"
   3878                     delim-close "/?>"))
   3879              ((string= sub1 "[")
   3880               (setq closing-string "]"
   3881                     delim-open "\\[/?[#@]"
   3882                     delim-close "/?\\]"))
   3883              (t
   3884               (setq closing-string "}"
   3885                     delim-open "${"
   3886                     delim-close "}"))
   3887              )
   3888            ) ;freemarker
   3889 
   3890           ((string= web-mode-engine "velocity")
   3891            (cond
   3892              ((string= sub2 "##")
   3893               (setq closing-string "EOL"))
   3894              ((string= sub2 "#*")
   3895               (setq closing-string "*#"))
   3896              (t
   3897               (setq closing-string "EOV"
   3898                     delim-open "#"))
   3899              )
   3900            ) ;velocity
   3901 
   3902           ((string= web-mode-engine "razor")
   3903            (cond
   3904              ((string= sub2 "@@")
   3905               (forward-char 2)
   3906               (setq closing-string nil))
   3907              ((string= sub2 "@*")
   3908               (setq closing-string "*@"))
   3909              ((string= sub1 "@")
   3910               (setq closing-string "EOR"
   3911                     delim-open "@"))
   3912              ((and (string= sub1 "}")
   3913                    (looking-at-p "[ ]*\n"))
   3914               ;;(setq closing-string "EOC")
   3915               (save-excursion
   3916                 (let (paren-pos)
   3917                   (setq paren-pos (web-mode-part-opening-paren-position (1- (point))))
   3918                   (if (and paren-pos (get-text-property paren-pos 'block-side))
   3919                       (setq closing-string "EOC")
   3920                       (setq closing-string nil)
   3921                       ) ;if
   3922                   ) ;let
   3923                 ) ;save-excursion
   3924               ;;(message "%s %S %S" sub2 (point) (get-text-property (point) 'part-side))
   3925               )
   3926              ((string= sub1 "}")
   3927               ;;(message "%s: %s" (point) sub1)
   3928               (save-excursion
   3929                 (let (paren-pos)
   3930                   (setq paren-pos (web-mode-part-opening-paren-position (1- (point))))
   3931                   (if (and paren-pos (get-text-property paren-pos 'block-side))
   3932                       (setq closing-string "EOR")
   3933                       (setq closing-string nil)
   3934                       ) ;if
   3935                   ) ;let
   3936                 ) ;save-excursion
   3937               ) ;case }
   3938              ) ;cond
   3939            ) ;razor
   3940 
   3941           ((and (string= web-mode-engine "riot")
   3942                 (not (get-text-property open 'part-side)))
   3943            (setq closing-string (if (string= tagopen "{") "}" "/// end script")
   3944                  delim-open "{"
   3945                  delim-close "}")
   3946            ) ;riot
   3947 
   3948           ((string= web-mode-engine "spip")
   3949            (cond
   3950              ((and (string= sub1 "#")
   3951                    (looking-at "[A-Z0-9_]+"))
   3952               (setq closing-string (match-string-no-properties 0)))
   3953              ((string= sub1 "(")
   3954               (setq closing-string '("(" . ")")))
   3955              ((string= sub1 "{")
   3956               (setq closing-string '("{" . "}")))
   3957              ((string= sub2 "<:")
   3958               (setq closing-string ":>"))
   3959              (t
   3960               (setq closing-string "]"))
   3961              ))
   3962 
   3963           ((string= web-mode-engine "marko")
   3964            (setq closing-string "}"
   3965                  delim-open "${"
   3966                  delim-close "}")
   3967            ) ;marko
   3968 
   3969           ) ;cond
   3970 
   3971         (when closing-string
   3972           (cond
   3973 
   3974             ((listp closing-string)
   3975              (cond
   3976                ((web-mode-rsf-balanced (car closing-string) (cdr closing-string) reg-end t)
   3977                 (setq close (match-end 0)
   3978                       pos (point))
   3979                 )
   3980                ((and (string= web-mode-engine "php")
   3981                      (string= "<?" sub2))
   3982 
   3983                 (if (or (text-property-not-all (1+ open) (point-max) 'tag-beg nil)
   3984                         (text-property-not-all (1+ open) (point-max) 'block-beg nil)
   3985                         (looking-at-p "[ \t\n]*<"))
   3986                     (setq close nil
   3987                           delim-close nil
   3988                           pos (point))
   3989                     (setq close (point-max)
   3990                           delim-close nil
   3991                           pos (point-max))
   3992                     ) ;if
   3993                 ) ;case
   3994                ) ;cond
   3995              ) ;case listp
   3996 
   3997             ((and (string= web-mode-engine "smarty")
   3998                   (string= closing-string "}"))
   3999              (goto-char open)
   4000              (setq tmp (web-mode-closing-delimiter-position
   4001                         "}"
   4002                         (point)
   4003                         (line-end-position)))
   4004              (if tmp
   4005                  (setq tmp (1+ tmp))
   4006                  (setq tmp (line-end-position)))
   4007              (goto-char tmp)
   4008              (setq close (point)
   4009                    pos (point))
   4010              )
   4011 
   4012             ((and (member web-mode-engine '("closure"))
   4013                   (string= closing-string "}"))
   4014              (when (web-mode-closure-skip reg-beg reg-end)
   4015                (setq close (point)
   4016                      pos (point))
   4017                ;;(message "close=%S pos=%S" close pos)
   4018                ) ;when
   4019              )
   4020 
   4021             ((string= closing-string "EOB")
   4022              (web-mode-blade-skip open)
   4023              (setq close (point)
   4024                    pos (point)))
   4025 
   4026             ((string= closing-string "EOL")
   4027              (end-of-line)
   4028              (setq close (point)
   4029                    pos (point)))
   4030 
   4031             ((string= closing-string "EOC")
   4032              (setq close (point)
   4033                    pos (point)))
   4034 
   4035             ((string= closing-string "EODQ")
   4036              (when (web-mode-django-skip reg-beg reg-end)
   4037                (setq close (point)
   4038                      pos (point))
   4039                ))
   4040 
   4041             ((string= closing-string "EOR")
   4042              (web-mode-razor-skip open)
   4043              (setq close (if (> (point) reg-end) reg-end (point))
   4044                    pos (if (> (point) reg-end) reg-end (point)))
   4045              (goto-char pos))
   4046 
   4047             ((string= closing-string "EOV")
   4048              (web-mode-velocity-skip open)
   4049              (setq close (point)
   4050                    pos (point)))
   4051 
   4052             ((and (member web-mode-engine '("ctemplate"))
   4053                   (re-search-forward closing-string reg-end t))
   4054              (setq close (match-end 0)
   4055                    pos (point)))
   4056 
   4057             ((and (member web-mode-engine '("antlers"))
   4058                   (re-search-forward closing-string reg-end t))
   4059              (setq close (match-end 0)
   4060                    pos (point)))
   4061 
   4062             ((and (member web-mode-engine '("astro"))
   4063                   (re-search-forward closing-string reg-end t))
   4064              (setq close (match-end 0)
   4065                    pos (point)))
   4066 
   4067             ((search-forward closing-string reg-end t)
   4068              (setq close (match-end 0)
   4069                    pos (point)))
   4070             ) ;cond
   4071 
   4072           (when (and close (>= reg-end pos))
   4073             ;;(message "pos(%S) : open(%S) close(%S)" pos open close)
   4074             (put-text-property open (1+ open) 'block-beg 0)
   4075             (put-text-property open (1+ open) 'block-controls 0)
   4076             (put-text-property open close 'block-side t)
   4077             (put-text-property (1- close) close 'block-end t)
   4078             (when delim-open
   4079               (web-mode-block-delimiters-set open close delim-open delim-close))
   4080             (web-mode-block-scan open close)
   4081             (cond
   4082               ((and (string= web-mode-engine "erb")
   4083                     (looking-at-p "<%= javascript_tag do %>"))
   4084                (setq tagopen "<%= javascript_tag do %>"))
   4085               ((and (string= web-mode-engine "mojolicious")
   4086                     (looking-at-p "%= javascript begin"))
   4087                (setq tagopen "%= javascript begin"))
   4088               ((and (string= web-mode-engine "mako")
   4089                     (looking-at-p "<%block filter=\"collect_js\">"))
   4090                (setq tagopen "<%block filter=\"collect_js\">"))
   4091               ((and (string= web-mode-engine "mako")
   4092                     (looking-at-p "<%block filter=\"collect_css\">"))
   4093                (setq tagopen "<%block filter=\"collect_css\">"))
   4094               ((and (string= web-mode-engine "django")
   4095                     (looking-at-p "{% javascript %}"))
   4096                (setq tagopen "{% javascript %}"))
   4097               ((and (string= web-mode-engine "django")
   4098                     (looking-at-p "{% schema %}"))
   4099                (setq tagopen "{% schema %}"))
   4100               ((and (string= web-mode-engine "django")
   4101                     (looking-at-p "{% stylesheet %}"))
   4102                (setq tagopen "{% stylesheet %}"))
   4103               )
   4104             ;;(message "%S %s" (point) tagopen)
   4105             (when (and (member tagopen '("<r:script" "<r:style"
   4106                                          "<c:js" "<c:css"
   4107                                          "<%= javascript_tag do %>"
   4108                                          "<%block filter=\"collect_js\">"
   4109                                          "<%block filter=\"collect_css\">"
   4110                                          "{% javascript %}"
   4111                                          "{% schema %}"
   4112                                          "{% stylesheet %}"
   4113                                          "%= javascript begin"
   4114                                          "---"))
   4115                        (setq part-beg close)
   4116                        (setq tagclose
   4117                              (cond
   4118                                ((string= tagopen "<r:script") "</r:script")
   4119                                ((string= tagopen "<r:style") "</r:style")
   4120                                ((string= tagopen "<c:js") "</c:js")
   4121                                ((string= tagopen "<c:css") "</c:css")
   4122                                ((string= tagopen "{% javascript %}") "{% endjavascript %}")
   4123                                ((string= tagopen "{% schema %}") "{% endschema %}")
   4124                                ((string= tagopen "{% stylesheet %}") "{% endstylesheet %}")
   4125                                ((string= tagopen "%= javascript begin") "% end")
   4126                                ((string= tagopen "---") "---")
   4127                                ((string= tagopen "<%= javascript_tag do %>") "<% end %>")
   4128                                ((member tagopen '("<%block filter=\"collect_js\">"
   4129                                                   "<%block filter=\"collect_css\">")) "</%block")
   4130                                ))
   4131                        (web-mode-sf tagclose)
   4132                        (setq part-end (match-beginning 0))
   4133                        (> part-end part-beg))
   4134               ;;(message "end=%S" (point))
   4135               (put-text-property part-beg part-end
   4136                                  'part-side
   4137                                  (cond
   4138                                    ((member tagopen '("<r:style" "<c:css" "<%block filter=\"collect_css\">" "{% stylesheet %}")) 'css)
   4139                                    (t 'javascript)))
   4140               (setq pos part-beg
   4141                     part-beg nil
   4142                     part-end nil)
   4143               ) ;when
   4144             ) ;when close
   4145 
   4146           (if pos (goto-char pos))
   4147 
   4148           ) ;when closing-string
   4149 
   4150         ) ;while
   4151 
   4152       (cond
   4153         ((>= i 2000)
   4154          (message "scan-blocks ** warning (%S) **" i))
   4155         ((string= web-mode-engine "razor")
   4156          (web-mode-block-foreach reg-beg reg-end 'web-mode-block-scan))
   4157         ((string= web-mode-engine "django")
   4158          (web-mode-scan-engine-comments reg-beg reg-end
   4159                                         "{% comment %}" "{% endcomment %}"))
   4160         ((string= web-mode-engine "mako")
   4161          (web-mode-scan-engine-comments reg-beg reg-end
   4162                                         "<%doc>" "</%doc>"))
   4163         ((string= web-mode-engine "mason")
   4164          (web-mode-scan-engine-comments reg-beg reg-end
   4165                                         "<%doc>" "</%doc>"))
   4166         ) ;cond
   4167 
   4168       )))
   4169 
   4170 (defun web-mode-scan-engine-comments (reg-beg reg-end tag-start tag-end)
   4171   "Scan engine comments (mako, django)."
   4172   (save-excursion
   4173     (let (beg end (continue t))
   4174       (goto-char reg-beg)
   4175       (while (and continue
   4176                   (< (point) reg-end)
   4177                   (re-search-forward tag-start reg-end t))
   4178         (goto-char (match-beginning 0))
   4179         (setq beg (point))
   4180         (if (not (re-search-forward tag-end reg-end t))
   4181             (setq continue nil)
   4182             (setq end (point))
   4183             (remove-list-of-text-properties beg end web-mode-scan-properties)
   4184             (add-text-properties beg end '(block-side t block-token comment))
   4185             (put-text-property beg (1+ beg) 'block-beg 0)
   4186             (put-text-property (1- end) end 'block-end t)
   4187             ) ;if
   4188         ) ;while
   4189       )))
   4190 
   4191 (defun web-mode-closure-skip (reg-beg reg-end)
   4192   (let (regexp char pos inc continue found)
   4193     (setq regexp "[\"'{}]"
   4194           inc 0)
   4195     (while (and (not found) (re-search-forward regexp reg-end t))
   4196       (setq char (char-before))
   4197       (cond
   4198         ((get-text-property (point) 'block-side)
   4199          (setq found t))
   4200         ((eq char ?\{)
   4201          (setq inc (1+ inc)))
   4202         ((eq char ?\})
   4203          (cond
   4204            ((and (not (eobp))
   4205                  (< inc 1))
   4206             (setq found t
   4207                   pos (point)))
   4208            ((> inc 0)
   4209             (setq inc (1- inc)))
   4210            )
   4211          )
   4212         ((eq char ?\')
   4213          (setq continue t)
   4214          (while (and continue (search-forward "'" reg-end t))
   4215            (setq continue (web-mode-string-continue-p reg-beg))
   4216            )
   4217          )
   4218         ((eq char ?\")
   4219          (setq continue t)
   4220          (while (and continue (search-forward "\"" reg-end t))
   4221            (setq continue (web-mode-string-continue-p reg-beg))
   4222            )
   4223          )
   4224         ) ;cond
   4225       ) ;while
   4226     pos))
   4227 
   4228 (defun web-mode-django-skip (reg-beg reg-end)
   4229   (let (regexp char pos inc continue found)
   4230     (setq regexp "[\"'{}]"
   4231           inc 0)
   4232     (while (and (not found) (re-search-forward regexp reg-end t))
   4233       (setq char (char-before))
   4234       (cond
   4235         ((get-text-property (point) 'block-side)
   4236          (setq found t))
   4237         ((eq char ?\{)
   4238          (setq inc (1+ inc)))
   4239         ((eq char ?\})
   4240          (cond
   4241            ((and (not (eobp))
   4242                  (eq (char-after) ?\})
   4243                  (< inc 2))
   4244             (forward-char)
   4245             (setq found t
   4246                   pos (1+ (point))))
   4247            ((> inc 0)
   4248             (setq inc (1- inc)))
   4249            )
   4250          )
   4251         ((eq char ?\')
   4252          (setq continue t)
   4253          (while (and continue (search-forward "'" reg-end t))
   4254            (setq continue (web-mode-string-continue-p reg-beg))
   4255            )
   4256          )
   4257         ((eq char ?\")
   4258          (setq continue t)
   4259          (while (and continue (search-forward "\"" reg-end t))
   4260            (setq continue (web-mode-string-continue-p reg-beg))
   4261            )
   4262          )
   4263         ) ;cond
   4264       ) ;while
   4265     pos))
   4266 
   4267 (defun web-mode-blade-skip (pos)
   4268   (goto-char pos)
   4269   (forward-char)
   4270   (skip-chars-forward "a-zA-Z0-9_-"))
   4271 
   4272 (defun web-mode-velocity-skip (pos)
   4273   (goto-char pos)
   4274   (let ((continue t) (i 0))
   4275     (when (eq ?\# (char-after))
   4276       (forward-char))
   4277     (when (member (char-after) '(?\$ ?\@))
   4278       (forward-char))
   4279     (when (member (char-after) '(?\!))
   4280       (forward-char))
   4281     (cond
   4282       ((member (char-after) '(?\{))
   4283        (search-forward "}" nil t))
   4284       ((looking-at-p "def \\|define ")
   4285        (search-forward ")" (line-end-position) t))
   4286       (t
   4287        (setq continue t)
   4288        (while continue
   4289          (skip-chars-forward "a-zA-Z0-9_-")
   4290          (when (> (setq i (1+ i)) 500)
   4291            (message "velocity-skip ** warning (%S) **" pos)
   4292            (setq continue nil))
   4293          (when (member (char-after) '(?\())
   4294            (search-forward ")" nil t))
   4295          (if (member (char-after) '(?\.))
   4296              (forward-char)
   4297              (setq continue nil))
   4298          ) ;while
   4299        ) ;t
   4300       ) ;cond
   4301     ))
   4302 
   4303 (defun web-mode-razor-skip (pos)
   4304   (goto-char pos)
   4305   (let ((continue t) (i 0))
   4306     (while continue
   4307       (skip-chars-forward " =@a-zA-Z0-9_-")
   4308       (cond
   4309         ((> (setq i (1+ i)) 500)
   4310          (message "razor-skip ** warning **")
   4311          (setq continue nil))
   4312         ((and (eq (char-after) ?\*)
   4313               (eq (char-before) ?@))
   4314          (when (not (search-forward "*@" nil t))
   4315            (setq continue nil))
   4316          )
   4317         ((looking-at-p "@[({]")
   4318          (forward-char)
   4319          (when (setq pos (web-mode-closing-paren-position (point)))
   4320            (goto-char pos))
   4321          (forward-char)
   4322          )
   4323         ((and (not (eobp)) (eq ?\( (char-after)))
   4324          (cond
   4325            ((looking-at-p "[ \n]*[<@]")
   4326             (setq continue nil))
   4327            ((setq pos (web-mode-closing-paren-position))
   4328             (goto-char pos)
   4329             (forward-char))
   4330            (t
   4331             (forward-char))
   4332            ) ;cond
   4333          )
   4334         ((and (not (eobp)) (eq ?\< (char-after)) (looking-back "[a-z]" (point-min)))
   4335          (setq pos (point))
   4336          (cond
   4337            ;; #988
   4338            ((search-forward ">" (line-end-position) t)
   4339             (goto-char pos)
   4340             (setq continue nil)
   4341             )
   4342            (t
   4343             (setq continue nil))
   4344            ) ;cond
   4345          )
   4346         ((and (not (eobp)) (eq ?\. (char-after)))
   4347          (forward-char))
   4348         ((and (not (eobp)) (looking-at-p "[ \n]*else"))
   4349          (re-search-forward "[ \t]*else")
   4350          )
   4351         ((looking-at-p "[ \n]*{")
   4352          (search-forward "{")
   4353          (search-forward "=>" (point-at-eol) 't)
   4354          (if (looking-at-p "[ \n]*[<@]")
   4355              (setq continue nil)
   4356              (backward-char)
   4357              (when (setq pos (web-mode-closing-paren-position))
   4358                (goto-char pos))
   4359              (forward-char)
   4360              ) ;if
   4361          )
   4362         ((looking-at-p "}")
   4363          (forward-char))
   4364         (t
   4365          (setq continue nil))
   4366         ) ;cond
   4367       ) ;while
   4368     ))
   4369 
   4370 (defun web-mode-block-delimiters-set (reg-beg reg-end delim-open delim-close)
   4371   "Set text-property 'block-token to 'delimiter-(beg|end) on block delimiters
   4372  (e.g. <?php and ?>)"
   4373   ;;(message "reg-beg(%S) reg-end(%S) delim-open(%S) delim-close(%S)" reg-beg reg-end delim-open delim-close)
   4374   (when (member web-mode-engine
   4375                 '("artanis" "anki" "antlers" "asp" "aspx"
   4376                   "cl-emb" "clip" "closure" "ctemplate" "django" "dust"
   4377                   "elixir" "ejs" "erb" "expressionengine" "freemarker" "go" "hero" "jsp" "lsp"
   4378                   "mako" "mason" "mojolicious"
   4379                   "perl"
   4380                   "smarty" "template-toolkit" "web2py" "xoops" "svelte"))
   4381     (save-excursion
   4382       (when delim-open
   4383         (goto-char reg-beg)
   4384         (looking-at delim-open)
   4385         (setq delim-open (match-string-no-properties 0)))
   4386       (when delim-close
   4387         (goto-char reg-end)
   4388         (looking-back delim-close reg-beg t)
   4389         (setq delim-close (match-string-no-properties 0)))
   4390       ))
   4391   (when delim-open
   4392     (put-text-property reg-beg (+ reg-beg (length delim-open))
   4393                        'block-token 'delimiter-beg))
   4394   (when delim-close
   4395     (put-text-property (- reg-end (length delim-close)) reg-end
   4396                        'block-token 'delimiter-end))
   4397   )
   4398 
   4399 (defun web-mode-block-foreach (reg-beg reg-end func)
   4400   (let ((i 0) (continue t) (block-beg reg-beg) (block-end nil))
   4401     (while continue
   4402       (setq block-end nil)
   4403       (unless (get-text-property block-beg 'block-beg)
   4404         (setq block-beg (web-mode-block-next-position block-beg)))
   4405       (when (and block-beg (< block-beg reg-end))
   4406         (setq block-end (web-mode-block-end-position block-beg)))
   4407       (cond
   4408         ((> (setq i (1+ i)) 2000)
   4409          (message "process-blocks ** warning (%S) **" (point))
   4410          (setq continue nil))
   4411         ((or (null block-end) (> block-end reg-end))
   4412          (setq continue nil))
   4413         (t
   4414          (setq block-end (1+ block-end))
   4415          (funcall func block-beg block-end)
   4416          (setq block-beg block-end)
   4417          ) ;t
   4418         ) ;cond
   4419       ) ;while
   4420     ))
   4421 
   4422 (defun web-mode-block-scan (block-beg block-end)
   4423   (let (sub1 sub2 sub3 regexp token-type)
   4424 
   4425     ;;(message "block-beg=%S block-end=%S" block-beg block-end)
   4426     ;;(remove-text-properties block-beg block-end web-mode-scan-properties)
   4427 
   4428     (goto-char block-beg)
   4429 
   4430     (cond
   4431       ((>= (point-max) (+ block-beg 3))
   4432        (setq sub3 (buffer-substring-no-properties block-beg (+ block-beg 3))
   4433              sub2 (buffer-substring-no-properties block-beg (+ block-beg 2))
   4434              sub1 (buffer-substring-no-properties block-beg (+ block-beg 1)))
   4435        )
   4436       ((>= (point-max) (+ block-beg 2))
   4437        (setq sub3 (buffer-substring-no-properties block-beg (+ block-beg 2))
   4438              sub2 (buffer-substring-no-properties block-beg (+ block-beg 2))
   4439              sub1 (buffer-substring-no-properties block-beg (+ block-beg 1)))
   4440        )
   4441       (t
   4442        (setq sub1 (buffer-substring-no-properties block-beg (+ block-beg 1)))
   4443        (setq sub2 sub1
   4444              sub3 sub1)
   4445        )
   4446       )
   4447 
   4448     (cond
   4449 
   4450       ((member web-mode-engine '("php" "lsp" "python" "web2py" "mason"))
   4451        (setq regexp web-mode-engine-token-regexp))
   4452 
   4453       ((string= web-mode-engine "mako")
   4454        (cond
   4455          ((string= sub2 "##")
   4456           (setq token-type 'comment)
   4457           )
   4458          (t
   4459           (setq regexp web-mode-engine-token-regexp))
   4460          )
   4461        ) ;mako
   4462 
   4463       ((string= web-mode-engine "django")
   4464        (cond
   4465          ((member sub2 '("{{" "{%"))
   4466           (setq regexp "\"\\|'"))
   4467          ((string= sub2 "{#")
   4468           (setq token-type 'comment))
   4469          )
   4470        ) ;django
   4471 
   4472       ((string= web-mode-engine "ctemplate")
   4473        (cond
   4474          ((string= sub3 "{{!")
   4475           (setq token-type 'comment))
   4476          ((member sub2 '("{{"))
   4477           )
   4478          )
   4479        ) ;ctemplate
   4480 
   4481       ((string= web-mode-engine "antlers")
   4482        (cond
   4483          ((string= sub3 "{{#")
   4484           (setq token-type 'comment))
   4485          ((member sub2 '("{{"))
   4486           )
   4487          )
   4488        ) ;antlers
   4489 
   4490       ((string= web-mode-engine "astro")
   4491        (setq regexp "\"\\|'")
   4492        ) ;astro
   4493 
   4494       ((string= web-mode-engine "go")
   4495        (cond
   4496          ((string= sub3 "{{/")
   4497           (setq token-type 'comment))
   4498          ((string= sub2 "{{")
   4499           (setq regexp "\"\\|'"))
   4500          )
   4501        ) ;go
   4502 
   4503       ((string= web-mode-engine "hero")
   4504        (cond
   4505          ((string= sub3 "<%#")
   4506           (setq token-type 'comment))
   4507          (t
   4508           (setq regexp "\"\\|'"))
   4509          )
   4510        ) ;hero
   4511 
   4512       ((string= web-mode-engine "razor")
   4513        (cond
   4514          ((string= sub2 "@*")
   4515           (setq token-type 'comment))
   4516          (t
   4517           (setq regexp "//\\|@\\*\\|\"\\|'"))
   4518          )
   4519        ) ;razor
   4520 
   4521       ((string= web-mode-engine "blade")
   4522        (cond
   4523          ((string= sub3 "{{-")
   4524           (setq token-type 'comment))
   4525          (t
   4526           (setq regexp "\"\\|'"))
   4527          )
   4528        ) ;blade
   4529 
   4530       ((string= web-mode-engine "cl-emb")
   4531        (cond
   4532          ((string= sub3 "<%#")
   4533           (setq token-type 'comment))
   4534          (t
   4535           (setq regexp "\"\\|'"))
   4536          )
   4537        ) ;cl-emb
   4538 
   4539       ((string= web-mode-engine "artanis")
   4540        (cond
   4541          ((string= sub3 "<%;")
   4542           (setq token-type 'comment))
   4543          ((string= sub3 "<%#|")
   4544           (setq token-type 'comment))
   4545          (t
   4546           (setq regexp "\""))
   4547          )
   4548        ) ;artanis
   4549 
   4550       ((string= web-mode-engine "elixir")
   4551        (cond
   4552          ((string= sub3 "<%#")
   4553           (setq token-type 'comment))
   4554          (t
   4555           (setq regexp "\"\\|'"))
   4556          )
   4557        ) ;elixir
   4558 
   4559       ((string= web-mode-engine "mojolicious")
   4560        (cond
   4561          ((or (string= sub2 "%#") (string= sub3 "<%#"))
   4562           (setq token-type 'comment))
   4563          (t
   4564           (setq regexp "\"\\|'"))
   4565          )
   4566        ) ;mojolicious
   4567 
   4568       ((string= web-mode-engine "velocity")
   4569        (cond
   4570          ((member sub2 '("##" "#*"))
   4571           (setq token-type 'comment))
   4572          ((member sub1 '("$" "#"))
   4573           (setq regexp "\"\\|'"))
   4574          )
   4575        ) ;velocity
   4576 
   4577       ((string= web-mode-engine "jsp")
   4578        (cond
   4579          ((string= sub3 "<%-")
   4580           (setq token-type 'comment))
   4581          ((string= sub3 "<%@")
   4582           (setq regexp "/\\*"))
   4583          ((member sub2 '("${" "#{"))
   4584           (setq regexp "\"\\|'"))
   4585          ((string= sub2 "<%")
   4586           (setq regexp "//\\|/\\*\\|\"\\|'"))
   4587          )
   4588        ) ;jsp
   4589 
   4590       ((string= web-mode-engine "clip")
   4591        (setq regexp nil)
   4592        ) ;clip
   4593 
   4594       ((string= web-mode-engine "perl")
   4595        (setq regexp nil)
   4596        ) ;perl
   4597 
   4598       ((and (string= web-mode-engine "asp")
   4599             (string= sub2 "<%"))
   4600        (setq regexp "//\\|/\\*\\|\"\\|''")
   4601        ) ;asp
   4602 
   4603       ((string= web-mode-engine "aspx")
   4604        (cond
   4605          ((string= sub3 "<%-")
   4606           (setq token-type 'comment))
   4607          ((string= sub3 "<%@")
   4608           (setq regexp "/\\*"))
   4609          ((string= sub3 "<%$")
   4610           (setq regexp "\"\\|'"))
   4611          (t
   4612           (setq regexp "//\\|/\\*\\|\"\\|'"))
   4613          )
   4614        ) ;aspx
   4615 
   4616       ((string= web-mode-engine "freemarker")
   4617        (cond
   4618          ((member sub3 '("<#-" "[#-"))
   4619           (setq token-type 'comment))
   4620          ((member sub2 '("${" "#{"))
   4621           (setq regexp "\"\\|'"))
   4622          ((or (member sub2 '("<@" "[@" "<#" "[#"))
   4623               (member sub3 '("</@" "[/@" "</#" "[/#")))
   4624           (setq regexp "\"\\|'"))
   4625          )
   4626        ) ;freemarker
   4627 
   4628       ((member web-mode-engine '("ejs" "erb"))
   4629        (cond
   4630          ((string= sub3 "<%#")
   4631           (setq token-type 'comment))
   4632          (t
   4633           (setq regexp web-mode-engine-token-regexp))
   4634          )
   4635        ) ;erb
   4636 
   4637       ((string= web-mode-engine "template-toolkit")
   4638        (cond
   4639          ((member sub3 '("[%#" "%%#"))
   4640           (setq token-type 'comment))
   4641          (t
   4642           (setq regexp "#\\|\"\\|'"))
   4643          )
   4644        ) ;template-toolkit
   4645 
   4646       ((string= web-mode-engine "underscore")
   4647        (setq regexp "/\\*\\|\"\\|'")
   4648        ) ;underscore
   4649 
   4650       ((string= web-mode-engine "angular")
   4651        (setq regexp "#\\|\"\\|'")) ;angular
   4652 
   4653       ((string= web-mode-engine "vue")
   4654        ) ;vue
   4655 
   4656       ((string= web-mode-engine "smarty")
   4657        (cond
   4658          ((string= sub2 "{*")
   4659           (setq token-type 'comment))
   4660          (t
   4661           (setq regexp "\"\\|'")))
   4662        ) ;smarty
   4663 
   4664       ((string= web-mode-engine "xoops")
   4665        (cond
   4666          ((string= sub3 "<{*")
   4667           (setq token-type 'comment))
   4668          (t
   4669           (setq regexp "\"\\|'")))
   4670        ) ;xoops
   4671 
   4672       ((string= web-mode-engine "spip")
   4673        (if (string= (buffer-substring-no-properties
   4674                      block-beg (+ block-beg 7))
   4675                     "[(#REM)")
   4676            (setq token-type 'comment
   4677                  regexp "\\]")))
   4678 
   4679       ((string= web-mode-engine "dust")
   4680        (cond
   4681          ((string= sub2 "{!")
   4682           (setq token-type 'comment))
   4683          (t
   4684           (setq regexp "\"\\|'"))
   4685          )
   4686        ) ;dust
   4687 
   4688       ((string= web-mode-engine "expressionengine")
   4689        (cond
   4690          ((string= sub2 "{!")
   4691           (setq token-type 'comment))
   4692          (t
   4693           (setq regexp "\"\\|'")))
   4694        ) ;expressionengine
   4695 
   4696       ((string= web-mode-engine "closure")
   4697        (cond
   4698          ((member sub2 '("/*" "//"))
   4699           (setq token-type 'comment))
   4700          (t
   4701           (setq regexp "\"\\|'"))
   4702          )
   4703        ) ;closure
   4704 
   4705       ((string= web-mode-engine "svelte")
   4706        ) ;svelte
   4707 
   4708       ) ;cond
   4709 
   4710     (cond
   4711       (token-type
   4712        (put-text-property block-beg block-end 'block-token token-type))
   4713       ((and regexp
   4714             (> (- block-end block-beg) 6))
   4715        (web-mode-block-tokenize
   4716         (web-mode-block-code-beginning-position block-beg)
   4717         (web-mode-block-code-end-position block-beg)
   4718         regexp)
   4719        )
   4720       ) ;cond
   4721 
   4722     ))
   4723 
   4724 (defun web-mode-block-tokenize (reg-beg reg-end &optional regexp)
   4725   (unless regexp (setq regexp web-mode-engine-token-regexp))
   4726   ;;(message "tokenize: reg-beg(%S) reg-end(%S) regexp(%S)" reg-beg reg-end regexp)
   4727   ;;(message "tokenize: reg-beg(%S) reg-end(%S) command(%S)" reg-beg reg-end this-command)
   4728   ;;(message "%S>%S : %S" reg-beg reg-end (buffer-substring-no-properties reg-beg reg-end))
   4729   (save-excursion
   4730     (let ((pos reg-beg) beg char match continue token-type token-end)
   4731 
   4732       (remove-list-of-text-properties reg-beg reg-end '(block-token))
   4733 
   4734       ;; TODO : vérifier la cohérence
   4735       (put-text-property reg-beg reg-end 'block-side t)
   4736 
   4737       (goto-char reg-beg)
   4738 
   4739       (when (> (point) reg-end)
   4740         (message "block-tokenize ** reg-beg(%S) > reg-end(%S) **" reg-beg reg-end))
   4741 
   4742       (while (and (< (point) reg-end) (re-search-forward regexp reg-end t))
   4743         (setq beg (match-beginning 0)
   4744               match (match-string 0)
   4745               continue t
   4746               token-type 'comment
   4747               token-end (if (< reg-end (line-end-position)) reg-end (line-end-position))
   4748               char (aref match 0))
   4749         (cond
   4750 
   4751           ((and (string= web-mode-engine "asp") (string= match "''"))
   4752            (goto-char token-end))
   4753 
   4754           ((and (string= web-mode-engine "razor") (eq char ?\'))
   4755            (cond
   4756              ((looking-at-p "\\(.\\|[\\][bfntr]\\|[\\]u....\\)'")
   4757               (search-forward "'" reg-end t)
   4758               (setq token-type 'string)
   4759               )
   4760              (t
   4761               (re-search-forward "[[:alnum:]_-]+")
   4762               (setq token-type 'symbol)
   4763               )))
   4764 
   4765           ((eq char ?\')
   4766            (setq token-type 'string)
   4767            (while (and continue (search-forward "'" reg-end t))
   4768              (setq continue (web-mode-string-continue-p reg-beg))
   4769              ))
   4770 
   4771           ((eq char ?\")
   4772            (setq token-type 'string)
   4773            (while (and continue (search-forward "\"" reg-end t))
   4774              (setq continue (web-mode-string-continue-p reg-beg))
   4775              ))
   4776 
   4777           ((string= match "//")
   4778            (goto-char token-end))
   4779 
   4780           ((eq char ?\;)
   4781            (goto-char token-end))
   4782 
   4783           ((string= match "#|")
   4784            (unless (search-forward "|#" reg-end t)
   4785              (goto-char token-end)))
   4786 
   4787           ((eq char ?\#)
   4788            (goto-char token-end))
   4789 
   4790           ((string= match "/*")
   4791            (unless (search-forward "*/" reg-end t)
   4792              (goto-char token-end))
   4793            )
   4794 
   4795           ((string= match "@*")
   4796            (unless (search-forward "*@" reg-end t)
   4797              (goto-char token-end)))
   4798 
   4799           ((eq char ?\<)
   4800            (setq token-type 'string)
   4801            (re-search-forward (concat "^[ ]*" (match-string 1)) reg-end t))
   4802 
   4803           (t
   4804            (message "block-tokenize ** token end (%S) **" beg)
   4805            (setq token-type nil))
   4806 
   4807           ) ;cond
   4808 
   4809         (put-text-property beg (point) 'block-token token-type)
   4810 
   4811         (when (eq token-type 'comment)
   4812           (put-text-property beg (1+ beg) 'syntax-table (string-to-syntax "<"))
   4813           (if (or (< (point) (line-end-position)) (= (point) (point-max)))
   4814               (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax ">")) ;#445 #480
   4815               (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax ">")) ;#377
   4816               )
   4817           )
   4818 
   4819         ) ;while
   4820 
   4821       (web-mode-block-controls-unset pos)
   4822 
   4823       )))
   4824 
   4825 (defun web-mode-set-php-controls (reg-beg reg-end)
   4826   (goto-char reg-beg)
   4827   (let (match controls
   4828               (continue t)
   4829               (regexp "endif\\|endforeach\\|endfor\\|endwhile\\|elseif\\|else\\|if\\|foreach\\|for\\|while"))
   4830     (while continue
   4831       (if (not (web-mode-block-rsf regexp reg-end))
   4832           (setq continue nil)
   4833           (setq match (match-string-no-properties 0))
   4834           ;;        (message "%S %S" match (point))
   4835           (cond
   4836             ((and (member match '("else" "elseif"))
   4837                   (looking-at-p "[ ]*[:(]"))
   4838              (setq controls (append controls (list (cons 'inside "if"))))
   4839              )
   4840             ((and (>= (length match) 3)
   4841                   (string= (substring match 0 3) "end"))
   4842              (setq controls (append controls (list (cons 'close (substring match 3)))))
   4843              )
   4844             ((and (progn (skip-chars-forward "[ ]") t)
   4845                   (eq (char-after) ?\()
   4846                   (web-mode-closing-paren reg-end)
   4847                   ;;(progn (message "ixi%S" (point)))
   4848                   (looking-at-p ")[ ]*:"))
   4849              (setq controls (append controls (list (cons 'open match))))
   4850              )
   4851             ) ;cond
   4852           ) ;if
   4853       ) ;while
   4854     ;;(message "%S-%S %S" reg-beg reg-end controls)
   4855     (when (and controls (> (length controls) 1))
   4856       (setq controls (web-mode-block-controls-reduce controls)))
   4857     controls))
   4858 
   4859 (defun web-mode-block-controls-reduce (controls)
   4860   (when (and (eq (car (car controls)) 'open)
   4861              (member (cons 'close (cdr (car controls))) controls))
   4862     (setq controls nil))
   4863   controls)
   4864 
   4865 (defun web-mode-block-controls-unset (pos)
   4866   (cond
   4867     ((null (get-text-property pos 'block-side))
   4868      (message "block-controls-unset ** invalid value (%S) **" pos))
   4869     ((or (get-text-property pos 'block-beg)
   4870          (setq pos (web-mode-block-beginning-position pos)))
   4871      (put-text-property pos (1+ pos) 'block-controls 0))
   4872     (t
   4873      (message "block-controls-unset ** failure (%S) **" (point)))
   4874     ))
   4875 
   4876 (defun web-mode-block-controls-get (pos)
   4877   (web-mode-with-silent-modifications
   4878    (let ((controls nil))
   4879      (cond
   4880        ((null (get-text-property pos 'block-side))
   4881         (message "block-controls-get ** invalid value (%S) **" pos))
   4882        ((or (get-text-property pos 'block-beg)
   4883             (setq pos (web-mode-block-beginning-position pos)))
   4884         (setq controls (get-text-property pos 'block-controls))
   4885         (when (integerp controls)
   4886           (web-mode-block-controls-set pos (web-mode-block-end-position pos))
   4887           (setq controls (get-text-property pos 'block-controls))
   4888           )
   4889         )
   4890        (t
   4891         (message "block-controls-get ** failure (%S) **" (point)))
   4892        ) ;cond
   4893      controls)))
   4894 
   4895 (defun web-mode-block-controls-set (reg-beg reg-end)
   4896   (save-excursion
   4897     (goto-char reg-beg)
   4898     (let (controls pos type control)
   4899 
   4900       (cond
   4901 
   4902         ((null web-mode-engine)
   4903          (message "block-controls-set ** unknown engine (%S) **" web-mode-engine)
   4904          )
   4905 
   4906         ((string= web-mode-engine "php")
   4907          (setq controls (web-mode-set-php-controls reg-beg reg-end))
   4908          (when (web-mode-block-starts-with "}" reg-beg)
   4909            (setq controls (append controls (list (cons 'close "{")))))
   4910          (when (web-mode-block-ends-with (cons "{" "}") reg-beg)
   4911            (setq controls (append controls (list (cons 'open "{")))))
   4912          ) ;php
   4913 
   4914         ((string= web-mode-engine "ejs")
   4915          (cond
   4916            ((web-mode-block-ends-with "}[ ]*else[ ]*{" reg-beg)
   4917             (setq controls (append controls (list (cons 'inside "{")))))
   4918            ((web-mode-block-starts-with "}" reg-beg)
   4919             (setq controls (append controls (list (cons 'close "{")))))
   4920            ((web-mode-block-ends-with "{" reg-beg)
   4921             (setq controls (append controls (list (cons 'open "{")))))
   4922            )
   4923          ) ;ejs
   4924 
   4925         ((string= web-mode-engine "erb")
   4926          (cond
   4927            ((web-mode-block-starts-with "else\\|elsif\\|when" reg-beg)
   4928             (setq controls (append controls (list (cons 'inside "ctrl")))))
   4929            ((web-mode-block-starts-with "end" reg-beg)
   4930             (setq controls (append controls (list (cons 'close "ctrl")))))
   4931            ((web-mode-block-ends-with " do\\( |.*|\\)?" reg-beg)
   4932             (setq controls (append controls (list (cons 'open "ctrl")))))
   4933            ((and (web-mode-block-starts-with "\\(for\\|if\\|unless\\|case\\)\\_>" reg-beg)
   4934                  (not (web-mode-block-ends-with "end" reg-end)))
   4935             (setq controls (append controls (list (cons 'open "ctrl")))))
   4936            )
   4937          ) ;erb
   4938 
   4939         ((string= web-mode-engine "django")
   4940          (cond
   4941            ((and (string= web-mode-minor-engine "jinja") ;#504
   4942                  (web-mode-block-starts-with "else\\_>" reg-beg))
   4943             (let ((continue t)
   4944                   (pos reg-beg)
   4945                   (ctrl nil))
   4946               (while continue
   4947                 (cond
   4948                   ((null (setq pos (web-mode-block-control-previous-position 'open pos)))
   4949                    (setq continue nil))
   4950                   ((member (setq ctrl (cdr (car (get-text-property pos 'block-controls)))) '("if" "ifequal" "ifnotequal" "for"))
   4951                    (setq continue nil)
   4952                    )
   4953                   ) ;cond
   4954                 )
   4955               (setq controls (append controls (list (cons 'inside (or ctrl "if")))))
   4956               )
   4957             )
   4958            ((web-mode-block-starts-with "form_start[ ]*(" reg-beg)
   4959             (setq controls (append controls (list (cons 'open "form_start")))))
   4960            ((web-mode-block-starts-with "form_end[ ]*(" reg-beg)
   4961             (setq controls (append controls (list (cons 'close "form_start")))))
   4962            ((not (eq (char-after (1+ reg-beg)) ?\%))
   4963             )
   4964            ((web-mode-block-starts-with "\\(else\\|els?if\\)" reg-beg)
   4965             (let ((continue t)
   4966                   (pos reg-beg)
   4967                   (ctrl nil))
   4968               (while continue
   4969                 (cond
   4970                   ((null (setq pos (web-mode-block-control-previous-position 'open pos)))
   4971                    (setq continue nil))
   4972                   ((member (setq ctrl (cdr (car (get-text-property pos 'block-controls)))) '("if" "ifequal" "ifnotequal"))
   4973                    (setq continue nil)
   4974                    )
   4975                   ) ;cond
   4976                 ) ;while
   4977               (setq controls (append controls (list (cons 'inside (or ctrl "if")))))
   4978               ) ;let
   4979             ) ;case else
   4980            ((web-mode-block-starts-with "\\(empty\\)" reg-beg)
   4981             (setq controls (append controls (list (cons 'inside "for")))))
   4982            ((web-mode-block-starts-with "end\\([[:alpha:]]+\\)" reg-beg)
   4983             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   4984            ((web-mode-block-starts-with "set [[:alpha:]]+[ ]*%}" reg-beg)
   4985             (setq controls (append controls (list (cons 'open "set")))))
   4986            ((web-mode-block-starts-with (concat web-mode-django-control-blocks-regexp "[ %]") reg-beg)
   4987             (let (control)
   4988               (setq control (match-string-no-properties 1))
   4989               ;;(message "%S %S %S" control (concat "end" control) web-mode-django-control-blocks)
   4990               (when (member (concat "end" control) web-mode-django-control-blocks)
   4991                 (setq controls (append controls (list (cons 'open control))))
   4992                 ) ;when
   4993               ) ;let
   4994             ) ;case
   4995            ) ;cond
   4996          ) ;django
   4997 
   4998         ((string= web-mode-engine "smarty")
   4999          (cond
   5000            ((and (eq (char-after (1+ reg-beg)) ?\/)
   5001                  (web-mode-block-starts-with "\\([[:alpha:]]+\\)" reg-beg))
   5002             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5003            ((web-mode-block-starts-with "\\(else\\|elseif\\)" reg-beg)
   5004             (setq controls (append controls (list (cons 'inside "if")))))
   5005            ((web-mode-block-starts-with "\\(block\\|foreach\\|for\\|if\\|section\\|while\\)")
   5006             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5007            )
   5008          ) ;smarty
   5009 
   5010         ((string= web-mode-engine "expressionengine")
   5011          (cond
   5012            ((and (eq (char-after (1+ reg-beg)) ?\/)
   5013                  (web-mode-block-starts-with "\\(if\\)" reg-beg))
   5014             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5015            ((web-mode-block-starts-with "\\(if:else\\|if:ifelse\\)" reg-beg)
   5016             (setq controls (append controls (list (cons 'inside "if")))))
   5017            ((web-mode-block-starts-with "\\(if\\)")
   5018             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5019            )
   5020          ) ;expressionengine
   5021 
   5022         ((string= web-mode-engine "xoops")
   5023          (cond
   5024            ((and (eq (char-after (+ reg-beg 2)) ?\/)
   5025                  (web-mode-block-starts-with "\\([[:alpha:]]+\\)" reg-beg))
   5026             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5027            ((web-mode-block-starts-with "\\(else\\|elseif\\)" reg-beg)
   5028             (setq controls (append controls (list (cons 'inside "if")))))
   5029            ((web-mode-block-starts-with "\\(block\\|foreach\\|for\\|if\\|section\\|while\\)")
   5030             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5031            )
   5032          ) ;xoops
   5033 
   5034         ((string= web-mode-engine "web2py")
   5035          (cond
   5036            ((web-mode-block-starts-with "def" reg-beg)
   5037             (setq controls (append controls (list (cons 'open "def")))))
   5038            ((web-mode-block-starts-with "return" reg-beg)
   5039             (setq controls (append controls (list (cons 'close "def")))))
   5040            ((web-mode-block-starts-with "block" reg-beg)
   5041             (setq controls (append controls (list (cons 'open "block")))))
   5042            ((web-mode-block-starts-with "end" reg-beg)
   5043             (setq controls (append controls (list (cons 'close "block")))))
   5044            ((web-mode-block-starts-with "pass" reg-beg)
   5045             (setq controls (append controls (list (cons 'close "ctrl")))))
   5046            ((web-mode-block-starts-with "\\(except\\|finally\\|els\\)" reg-beg)
   5047             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5048            ((web-mode-block-starts-with "\\(if\\|for\\|try\\|while\\)")
   5049             (setq controls (append controls (list (cons 'open "ctrl")))))
   5050            )
   5051          ) ;web2py
   5052 
   5053         ((string= web-mode-engine "dust")
   5054          (cond
   5055            ((eq (char-after (1- reg-end)) ?\/)
   5056             )
   5057            ((eq (char-after (1+ reg-beg)) ?\:)
   5058             (setq pos (web-mode-block-control-previous-position 'open reg-beg))
   5059             (when pos
   5060               (setq controls (append controls
   5061                                      (list
   5062                                       (cons 'inside
   5063                                             (cdr (car (web-mode-block-controls-get pos))))))))
   5064             )
   5065            ((looking-at "{/\\([[:alpha:].]+\\)")
   5066             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5067            ((looking-at "{[#?@><+^]\\([[:alpha:].]+\\)")
   5068             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5069            )
   5070          ) ;dust
   5071 
   5072         ((string= web-mode-engine "anki")
   5073          (cond
   5074            ((looking-at "{{[#^]\\([[:alpha:].]+\\)")
   5075             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5076            ((looking-at "{{/\\([[:alpha:].]+\\)")
   5077             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5078            )
   5079          ) ;anki
   5080 
   5081         ((member web-mode-engine '("mojolicious"))
   5082          (cond
   5083            ((web-mode-block-ends-with "begin" reg-beg)
   5084             (setq controls (append controls (list (cons 'open "begin")))))
   5085            ((web-mode-block-starts-with "end" reg-beg)
   5086             (setq controls (append controls (list (cons 'close "begin")))))
   5087            ((web-mode-block-starts-with "}[ ]*else[ ]*{" reg-beg)
   5088             (setq controls (append controls (list (cons 'inside "{")))))
   5089            ((web-mode-block-starts-with "}" reg-beg)
   5090             (setq controls (append controls (list (cons 'close "{")))))
   5091            ((web-mode-block-ends-with "{" reg-beg)
   5092             (setq controls (append controls (list (cons 'open "{")))))
   5093            )
   5094          ) ;mojolicious
   5095 
   5096         ((member web-mode-engine '("aspx" "underscore"))
   5097          (cond
   5098            ((and (web-mode-block-starts-with "}" reg-beg)
   5099                  (web-mode-block-ends-with "{" reg-beg))
   5100             (setq controls (append controls (list (cons 'inside "{")))))
   5101            ((web-mode-block-starts-with "}" reg-beg)
   5102             (setq controls (append controls (list (cons 'close "{")))))
   5103            ((web-mode-block-ends-with "{" reg-beg)
   5104             (setq controls (append controls (list (cons 'open "{")))))
   5105            )
   5106          ) ;aspx underscore
   5107 
   5108         ((member web-mode-engine '("jsp" "asp" "clip" "perl"))
   5109          (cond
   5110            ((eq (char-after (1- reg-end)) ?\/)
   5111             )
   5112            ((looking-at "<TMPL_ELSE")
   5113             (setq controls (append controls (list (cons 'inside "TMPL_IF")))))
   5114            ((looking-at "</?\\([[:alpha:]]+\\(?:[:.][[:alpha:]]+\\)\\|[[:alpha:]]+Template\\|TMPL_[[:alpha:]]+\\)")
   5115             (setq control (match-string-no-properties 1)
   5116                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5117             (when (not (member control '("h:inputtext" "jsp:usebean" "jsp:forward" "struts:property")))
   5118               (setq controls (append controls (list (cons type control)))))
   5119             )
   5120            (t
   5121             (when (web-mode-block-starts-with "}" reg-beg)
   5122               (setq controls (append controls (list (cons 'close "{")))))
   5123             (when (web-mode-block-ends-with "{" reg-beg)
   5124               (setq controls (append controls (list (cons 'open "{")))))
   5125             )
   5126            )
   5127          ) ;jsp asp
   5128 
   5129         ((string= web-mode-engine "mako")
   5130          (cond
   5131            ((looking-at "</?%\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)")
   5132             (cond
   5133               ((eq (char-after (- (web-mode-block-end-position reg-beg) 1)) ?\/)
   5134                )
   5135               (t
   5136                (setq control (match-string-no-properties 1)
   5137                      type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5138                (setq controls (append controls (list (cons type control)))))
   5139               )
   5140             )
   5141            ((web-mode-block-starts-with "\\(else\\|elif\\)" reg-beg)
   5142             (setq controls (append controls (list (cons 'inside "if")))))
   5143            ((web-mode-block-starts-with "end\\(if\\|for\\)" reg-beg)
   5144             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5145            ((and (web-mode-block-starts-with "if\\|for" reg-beg)
   5146                  (web-mode-block-ends-with ":" reg-beg))
   5147             (setq controls (append controls (list (cons 'open (match-string-no-properties 0))))))
   5148            )
   5149          ) ;mako
   5150 
   5151         ((string= web-mode-engine "mason")
   5152          (cond
   5153            ((looking-at "</?%\\(after\\|around\\|augment\\|before\\|def\\|filter\\|method\\|override\\)")
   5154             (setq control (match-string-no-properties 1)
   5155                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5156             (setq controls (append controls (list (cons type control))))
   5157             )
   5158            )
   5159          ) ;mason
   5160 
   5161         ((string= web-mode-engine "ctemplate")
   5162          (cond
   5163            ((looking-at-p "{{else") ;#721
   5164             (let ((continue t)
   5165                   (pos reg-beg)
   5166                   (ctrl nil))
   5167               (while continue
   5168                 (cond
   5169                   ((null (setq pos (web-mode-block-control-previous-position 'open pos)))
   5170                    (setq continue nil))
   5171                   ((member (setq ctrl (cdr (car (get-text-property pos 'block-controls)))) '("if" "each"))
   5172                    (setq continue nil)
   5173                    )
   5174                   ) ;cond
   5175                 ) ;while
   5176               (setq controls (append controls (list (cons 'inside (or ctrl "if")))))
   5177               )
   5178             )
   5179 
   5180            ((looking-at "{{[#^/][ ]*\\([[:alpha:]_.-]+\\)")
   5181             (setq control (match-string-no-properties 1)
   5182                   type (if (eq (aref (match-string-no-properties 0) 2) ?\/) 'close 'open))
   5183             (setq controls (append controls (list (cons type control))))
   5184             )
   5185            )
   5186          ) ;ctemplate
   5187 
   5188         ((string= web-mode-engine "antlers")
   5189          (cond
   5190            ((web-mode-block-starts-with "\\(else\\|elseif\\)" reg-beg)
   5191             (setq controls (append controls (list (cons 'inside "if")))))
   5192            ((looking-at  "{{[ ]*/?\\(if\\|unless\\)")
   5193             (setq control (match-string-no-properties 1)
   5194                   type (if (eq (aref (match-string-no-properties 0) 3) ?\/) 'close 'open))
   5195             (setq controls (append controls (list (cons type control))))
   5196             )
   5197            )
   5198          ) ;antlers
   5199 
   5200         ((string= web-mode-engine "blade")
   5201          (cond
   5202            ((not (eq (char-after) ?\@))
   5203             )
   5204            ((web-mode-block-starts-with
   5205              "section\(\s*\\(['\"]\\).*\\1\s*,\s*\\(['\"]\\).*\\2\s*\)" reg-beg)
   5206             )
   5207            ((web-mode-block-starts-with "case\\|break" reg-beg)
   5208             (setq type (if (eq (aref (match-string-no-properties 0) 0) ?b) 'close 'open))
   5209             (setq controls (append controls (list (cons type "case"))))
   5210             )
   5211            ((web-mode-block-starts-with
   5212              (concat "\\(?:end\\)?\\(" web-mode-blade-control-blocks-regexp "\\)")
   5213              reg-beg)
   5214             (setq control (match-string-no-properties 1)
   5215                   type (if (eq (aref (match-string-no-properties 0) 0) ?e) 'close 'open))
   5216             (setq controls (append controls (list (cons type control))))
   5217             )
   5218            ((web-mode-block-starts-with "stop\\|show\\|overwrite" reg-beg)
   5219             (setq controls (append controls (list (cons 'close "section")))))
   5220            ((web-mode-block-starts-with "else\\|elseif" reg-beg)
   5221             (setq controls (append controls (list (cons 'inside "if")))))
   5222            ((web-mode-block-starts-with "empty" reg-beg)
   5223             (setq controls (append controls (list (cons 'inside "forelse")))))
   5224            )
   5225          ) ;blade
   5226 
   5227         ((string= web-mode-engine "closure")
   5228          (cond
   5229            ((eq (char-after (1- reg-end)) ?\/)
   5230             )
   5231            ((looking-at "alias\\|namespace")
   5232             )
   5233            ((web-mode-block-starts-with "ifempty" reg-beg)
   5234             (setq controls (append controls (list (cons 'inside "foreach")))))
   5235            ((web-mode-block-starts-with "else\\|elseif" reg-beg)
   5236             (setq controls (append controls (list (cons 'inside "if")))))
   5237            ((web-mode-block-starts-with "case\\|default" reg-beg)
   5238             (setq controls (append controls (list (cons 'inside "switch")))))
   5239            ((looking-at
   5240              "{/?\\(call\\|deltemplate\\|for\\|foreach\\|if\\|let\\|literal\\|msg\\|param\\|switch\\|template\\)")
   5241             (setq control (match-string-no-properties 1)
   5242                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5243             (setq controls (append controls (list (cons type control))))
   5244             )
   5245            )
   5246          ) ;closure
   5247 
   5248         ((string= web-mode-engine "go")
   5249          (cond
   5250            ((web-mode-block-starts-with "end\\_>" reg-beg)
   5251             (setq controls (append controls (list (cons 'close "ctrl")))))
   5252            ((web-mode-block-starts-with "else\\_>" reg-beg)
   5253             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5254            ((web-mode-block-starts-with "\\(range\\|with\\|if\\|define\\|block\\)\\_>" reg-beg)
   5255             (setq controls (append controls (list (cons 'open "ctrl")))))
   5256            )
   5257          ) ;go
   5258 
   5259         ((string= web-mode-engine "template-toolkit")
   5260          (cond
   5261            ((web-mode-block-starts-with "end" reg-beg)
   5262             (setq controls (append controls (list (cons 'close "ctrl")))))
   5263            ((web-mode-block-starts-with "els\\|catch\\|final" reg-beg)
   5264             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5265            ((web-mode-block-starts-with "filter\\|foreach\\|if\\|last\\|next\\|perl\\|rawperl\\|try\\|unless\\|while" reg-beg)
   5266             (setq controls (append controls (list (cons 'open "ctrl")))))
   5267            )
   5268          ) ;template-toolkit
   5269 
   5270         ((string= web-mode-engine "cl-emb")
   5271          (cond
   5272            ((web-mode-block-starts-with "@else" reg-beg)
   5273             (setq controls (append controls (list (cons 'inside "if")))))
   5274            ((web-mode-block-starts-with "@\\(?:end\\)?\\(if\\|unless\\|repeat\\|loop\\|with\\|genloop\\)" reg-beg)
   5275             (setq control (match-string-no-properties 1)
   5276                   type (if (eq (aref (match-string-no-properties 0) 1) ?e) 'close 'open))
   5277             (setq controls (append controls (list (cons type control)))))
   5278            )
   5279          ) ;cl-emb
   5280 
   5281         ((string= web-mode-engine "elixir")
   5282          (cond
   5283            ((web-mode-block-starts-with "end" reg-beg)
   5284             (setq controls (append controls (list (cons 'close "ctrl")))))
   5285            ((web-mode-block-starts-with "else" reg-beg)
   5286             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5287            ((web-mode-block-ends-with " do" reg-beg)
   5288             (setq controls (append controls (list (cons 'open "ctrl")))))
   5289            ((web-mode-block-ends-with " ->" reg-beg)
   5290             (setq controls (append controls (list (cons 'open "ctrl")))))
   5291            )
   5292          ) ;elixir
   5293 
   5294         ((string= web-mode-engine "velocity")
   5295          (cond
   5296            ((web-mode-block-starts-with "{?end" reg-beg)
   5297             (setq controls (append controls (list (cons 'close "ctrl")))))
   5298            ((web-mode-block-starts-with "{?els" reg-beg)
   5299             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5300            ((web-mode-block-starts-with "{?\\(def\\|if\\|for\\|foreach\\|macro\\)" reg-beg)
   5301             ;;((web-mode-block-starts-with "{?\\(define\\|\\|if\\|for\\|foreach\\|macro\\)" reg-beg)
   5302             (setq controls (append controls (list (cons 'open "ctrl")))))
   5303            )
   5304          ) ;velocity
   5305 
   5306         ((string= web-mode-engine "freemarker")
   5307          (cond
   5308            ((looking-at "[<[]#\\(import\\|include\\|assign\\|return\\|local\\)")
   5309             )
   5310            ((eq (char-after (1- reg-end)) ?\/)
   5311             )
   5312            ((looking-at "[<[]#\\(break\\|case\\|default\\)")
   5313             (setq controls (append controls (list (cons 'inside "switch"))))
   5314             )
   5315            ((looking-at "[<[]#els")
   5316             (setq controls (append controls (list (cons 'inside "if"))))
   5317             )
   5318            ((looking-at "</?\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)")
   5319             (setq control (match-string-no-properties 1)
   5320                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5321             (setq controls (append controls (list (cons type control))))
   5322             )
   5323            ((looking-at "[<[]/?\\(@\\)")
   5324             (setq control (match-string-no-properties 1)
   5325                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5326             (setq controls (append controls (list (cons type control))))
   5327             )
   5328            ((looking-at "[<[]/?#\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)")
   5329             (setq control (match-string-no-properties 1)
   5330                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5331             (setq controls (append controls (list (cons type control))))
   5332             )
   5333            (t
   5334             (when (web-mode-block-starts-with "}" reg-beg)
   5335               (setq controls (append controls (list (cons 'close "{")))))
   5336             (when (web-mode-block-ends-with "{" reg-beg)
   5337               (setq controls (append controls (list (cons 'open "{")))))
   5338             )
   5339            )
   5340          ) ;freemarker
   5341 
   5342         ((string= web-mode-engine "razor")
   5343          (when (web-mode-block-starts-with "}" reg-beg)
   5344            (setq controls (append controls (list (cons 'close "{")))))
   5345          (when (web-mode-block-ends-with "{" reg-beg)
   5346            (setq controls (append controls (list (cons 'open "{")))))
   5347          ) ;razor
   5348 
   5349         ((string= web-mode-engine "lsp")
   5350          (when (web-mode-block-starts-with ")" reg-beg)
   5351            (setq controls (append controls (list (cons 'close "(")))))
   5352          (when (web-mode-block-is-opened-sexp reg-beg reg-end)
   5353            (setq controls (append controls (list (cons 'open "(")))))
   5354          ) ;lsp
   5355 
   5356         ((string= web-mode-engine "hero")
   5357          (cond
   5358            ((web-mode-block-ends-with "}[ ]*else[ ]*{" reg-beg)
   5359             (setq controls (append controls (list (cons 'inside "{")))))
   5360            ((web-mode-block-starts-with "}" reg-beg)
   5361             (setq controls (append controls (list (cons 'close "{")))))
   5362            ((web-mode-block-ends-with "{" reg-beg)
   5363             (setq controls (append controls (list (cons 'open "{")))))
   5364            )
   5365          ) ;hero
   5366 
   5367         ((string= web-mode-engine "svelte")
   5368          (cond
   5369            ((eq (char-after (1- reg-end)) ?\/)
   5370             )
   5371            ((eq (char-after (1+ reg-beg)) ?\:)
   5372             (setq pos (web-mode-block-control-previous-position 'open reg-beg))
   5373             (when pos
   5374               (setq controls (append controls
   5375                                      (list
   5376                                       (cons 'inside
   5377                                             (cdr (car (web-mode-block-controls-get pos))))))))
   5378             )
   5379            ((looking-at "{/\\([[:alpha:].]+\\)")
   5380             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5381            ((looking-at "{[#?><+^]\\([[:alpha:].]+\\)")
   5382             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5383            )
   5384          ) ;svelte
   5385 
   5386         ) ;cond engine
   5387 
   5388       (put-text-property reg-beg (1+ reg-beg) 'block-controls controls)
   5389       ;;(message "(%S) controls=%S" reg-beg controls)
   5390 
   5391       )))
   5392 
   5393 (defun web-mode-block-is-opened-sexp (reg-beg reg-end)
   5394   (let ((n 0))
   5395     (save-excursion
   5396       (goto-char reg-beg)
   5397       (while (web-mode-block-rsf "[()]" reg-end)
   5398         (if (eq (char-before) ?\() (setq n (1+ n)) (setq n (1- n)))))
   5399     (> n 0)))
   5400 
   5401 ;;---- LEXER PARTS -------------------------------------------------------------
   5402 
   5403 (defun web-mode-scan-elements (reg-beg reg-end)
   5404   (save-excursion
   5405     (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)
   5406       ;;(message "scan-elements: reg-beg(%S) reg-end(%S)" reg-beg reg-end)
   5407       (goto-char reg-beg)
   5408 
   5409       (while (web-mode-dom-rsf regexp reg-end)
   5410 
   5411         ;;(message "%S: %S (%S %S)" (point) (match-string-no-properties 0) reg-beg reg-end)
   5412 
   5413         (setq flags 0
   5414               tname (downcase (match-string-no-properties 1))
   5415               char (aref tname 0)
   5416               tbeg (match-beginning 0)
   5417               tend nil
   5418               element-content-type nil
   5419               limit reg-end
   5420               part-beg nil
   5421               part-end nil
   5422               props nil
   5423               close-expr nil
   5424               part-close-tag nil)
   5425 
   5426         ;;(message "tname[%S] tbeg(%S) point(%S)" tname tbeg (point))
   5427 
   5428         (cond
   5429 
   5430           ((member tname '("/>" ">")) ;;jsx fragment #952
   5431            (setq tname "_fragment_"
   5432                  tend (point))
   5433            (if (eq char ?\/)
   5434                (setq props (list 'tag-name tname 'tag-type 'end)
   5435                      flags (logior flags 20)) ;; 16 + 4
   5436                (setq props (list 'tag-name tname 'tag-type 'start)
   5437                      flags (logior flags 16))
   5438                ) ;if
   5439            )
   5440 
   5441           ((not (member char '(?\! ?\?)))
   5442            (cond
   5443              ((string-match-p "-" tname)
   5444               (setq flags (logior flags 2)))
   5445              ((string-match-p ":" tname)
   5446               (setq flags (logior flags 32)))
   5447              )
   5448            (cond
   5449              ((eq char ?\/)
   5450               (setq props (list 'tag-name (substring tname 1) 'tag-type 'end)
   5451                     flags (logior flags 4)
   5452                     limit (if (> reg-end (line-end-position)) (line-end-position) reg-end))
   5453               )
   5454              ((web-mode-element-is-void tname)
   5455               ;;(message "void: tag=%S" tname)
   5456               (setq props (list 'tag-name tname 'tag-type 'void)))
   5457              (t
   5458               (setq props (list 'tag-name tname 'tag-type 'start)))
   5459              ) ;cond
   5460            ) ; not <! <?
   5461           ((and (eq char ?\!) (eq (aref tname 1) ?\-))
   5462            (setq close-expr "-->"
   5463                  props '(tag-type comment)))
   5464           ((string= tname "?xml")
   5465            (setq ;;regexp web-mode-tag-regexp2
   5466             close-expr "?>"
   5467             props '(tag-type declaration)))
   5468           ((string= tname "![cdata[")
   5469            (setq close-expr "]]>"
   5470                  props '(tag-type cdata)))
   5471           ((string= tname "!doctype")
   5472            (setq ;;regexp web-mode-tag-regexp2
   5473             props '(tag-type doctype)))
   5474           ) ;cond - special tags
   5475 
   5476         (cond
   5477 
   5478           (tend
   5479            )
   5480 
   5481           ((and (null close-expr) (eq (char-after) ?\>))
   5482            (setq flags (logior flags 16)
   5483                  tend (1+ (point)))
   5484            ;;(message "end=%S" tend)
   5485            )
   5486 
   5487           ((and (null close-expr)
   5488                 (looking-at "[ ]\\(class\\|id\\|href\\|style\\)=\"[[:alnum:]_=:/?;#. -]*\">"))
   5489            (let ((beg (1+ (point)))
   5490                  (end (+ (point) (length (match-string-no-properties 0)))))
   5491              (setq flags (logior flags 17)
   5492                    tend end)
   5493              (put-text-property beg (1+ beg) 'tag-attr-beg 0)
   5494              (put-text-property beg (1- end) 'tag-attr t)
   5495              (put-text-property (- end 2) (1- end) 'tag-attr-end (length (match-string-no-properties 1)))
   5496              ) ;let
   5497            )
   5498 
   5499           ((null close-expr)
   5500            (setq flags (logior flags (web-mode-attr-skip reg-end)))
   5501            (when (> (logand flags 8) 0)
   5502              (setq props (plist-put props 'tag-type 'void)))
   5503            (setq tend (point)))
   5504 
   5505           ((web-mode-dom-sf close-expr limit t)
   5506            (setq tend (point)))
   5507 
   5508           (t
   5509            (setq tend (line-end-position)))
   5510 
   5511           ) ;cond
   5512 
   5513         (cond
   5514           ((string= tname "style")
   5515            (let (style)
   5516              (setq style (buffer-substring-no-properties tbeg tend)
   5517                    part-close-tag "</style>")
   5518              (cond
   5519                ((string-match-p " lang[ ]*=[ ]*[\"']stylus" style)
   5520                 (setq element-content-type "stylus"))
   5521                ((string-match-p " lang[ ]*=[ ]*[\"']sass" style)
   5522                 (setq element-content-type "sass"))
   5523                (t
   5524                 (setq element-content-type "css"))
   5525                ) ;cond
   5526              ) ;let
   5527            ) ;style
   5528           ((string= tname "script")
   5529            (let (script)
   5530              (setq script (buffer-substring-no-properties tbeg tend)
   5531                    part-close-tag "</script>")
   5532              (cond
   5533                ((string-match-p " type[ ]*=[ ]*[\"']text/\\(jsx\\|babel\\)" script)
   5534                 (setq element-content-type "jsx"))
   5535                ((string-match-p " type[ ]*=[ ]*[\"']text/\\(markdown\\|template\\)" script)
   5536                 (setq element-content-type "markdown"))
   5537                ((string-match-p " type[ ]*=[ ]*[\"']text/ruby" script)
   5538                 (setq element-content-type "ruby"))
   5539                ((seq-some (lambda (x)
   5540                             (string-match-p (concat "type[ ]*=[ ]*[\"']" x) script))
   5541                           web-mode-script-template-types)
   5542                 (setq element-content-type "html"
   5543                       part-close-tag nil))
   5544                ((string-match-p " type[ ]*=[ ]*[\"']application/\\(ld\\+json\\|json\\)" script)
   5545                 (setq element-content-type "json"))
   5546                ((string-match-p " lang[ ]*=[ ]*[\"']\\(typescript\\|ts\\)" script)
   5547                 (setq element-content-type "typescript"))
   5548                (t
   5549                 (setq element-content-type "javascript"))
   5550                ) ;cond
   5551              ) ;let
   5552            ) ;script
   5553           ((and (string= tname "template") (string-match-p " lang" (buffer-substring-no-properties tbeg tend)))
   5554            (let (template)
   5555              (setq template (buffer-substring-no-properties tbeg tend)
   5556                    part-close-tag "</template>")
   5557              (cond
   5558                ((string-match-p " lang[ ]*=[ ]*[\"']pug" template)
   5559                 (setq element-content-type "pug"))
   5560                (t
   5561                 (setq element-content-type "html"))
   5562                ) ;cond
   5563              ) ;let
   5564            ) ;style
   5565           ((and (string= web-mode-engine "archibus")
   5566                 (string= tname "sql"))
   5567            (setq element-content-type "sql"
   5568                  part-close-tag "</sql>"))
   5569           )
   5570 
   5571         (add-text-properties tbeg tend props)
   5572         (put-text-property tbeg (1+ tbeg) 'tag-beg flags)
   5573         (put-text-property (1- tend) tend 'tag-end t)
   5574 
   5575         (when (and part-close-tag
   5576                    (web-mode-dom-sf part-close-tag reg-end t)
   5577                    (setq part-beg tend)
   5578                    (setq part-end (match-beginning 0))
   5579                    (> part-end part-beg))
   5580           (put-text-property part-beg part-end 'part-side
   5581                              (intern element-content-type web-mode-obarray))
   5582           (setq tend part-end)
   5583           ) ;when
   5584 
   5585         (goto-char tend)
   5586 
   5587         ) ;while
   5588 
   5589       )))
   5590 
   5591 ;; FLAGS: tag
   5592 ;; (1)attrs (2)custom (4)slash-beg (8)slash-end (16)bracket-end (32)namespaced
   5593 
   5594 ;; FLAGS: attr
   5595 ;; (1)custom-attr (2)engine-attr (4)spread-attr[jsx] (8)code-value
   5596 ;; https://www.w3.org/TR/2012/WD-html-markup-20120329/syntax.html#attr-value-unquoted
   5597 
   5598 ;; STATES: attr
   5599 ;; (0)nil (1)space (2)name (3)space-before (4)equal (5)space-after
   5600 ;; (6)value-uq (7)value-sq (8)value-dq (9)value-bq : jsx attr={}
   5601 
   5602 (defun web-mode-attr-skip (limit)
   5603 
   5604   (let ((tag-flags 0) (attr-flags 0) (continue t) (attrs 0) (brace-depth 0)
   5605         (state 0) (equal-offset 0) (go-back nil)
   5606         (is-jsx (or (string= web-mode-content-type "jsx") (eq (get-text-property (point) 'part-type) 'jsx)))
   5607         attr name-beg name-end val-beg char pos escaped spaced quoted)
   5608 
   5609     (while continue
   5610 
   5611       (setq pos (point)
   5612             char (char-after)
   5613             mem state
   5614             ;;spaced (eq char ?\s)
   5615             spaced (member char '(?\s ?\n))
   5616             step nil)
   5617 
   5618       (when quoted (setq quoted (1+ quoted)))
   5619 
   5620       (cond
   5621 
   5622         ((>= pos limit)
   5623          (setq continue nil)
   5624          (setq go-back t)
   5625          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5626          )
   5627 
   5628         ((or (and (= state 8) (not (member char '(?\" ?\\))))
   5629              (and (= state 7) (not (member char '(?\' ?\\))))
   5630              (and (= state 9) (not (member char '(?} ?\\))))
   5631              )
   5632          (when (and (= state 9) (eq char ?\{))
   5633            (setq brace-depth (1+ brace-depth)))
   5634          )
   5635 
   5636         ((and (= state 9) (eq char ?\}) (> brace-depth 1))
   5637          (setq brace-depth (1- brace-depth)))
   5638 
   5639         ;; #1233
   5640         ;;((get-text-property pos 'block-side)
   5641         ;; (when (= state 2)
   5642         ;;   (setq name-end pos))
   5643         ;; )
   5644 
   5645         ((and (= state 2) is-jsx (eq char ?\}) (eq attr-flags 4))
   5646          (setq name-end pos)
   5647          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5648          (setq state 0
   5649                attr-flags 0
   5650                equal-offset 0
   5651                name-beg nil
   5652                name-end nil
   5653                val-beg nil)
   5654          )
   5655 
   5656         ((or (and (= state 8) (eq ?\" char) (not escaped))
   5657              (and (= state 7) (eq ?\' char) (not escaped))
   5658              (and (= state 9) (eq ?\} char) (= brace-depth 1))
   5659              )
   5660          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5661          (setq state 0
   5662                attr-flags 0
   5663                equal-offset 0
   5664                name-beg nil
   5665                name-end nil
   5666                val-beg nil)
   5667          )
   5668 
   5669         ((and (member state '(4 5)) (member char '(?\' ?\" ?\{)))
   5670          (setq val-beg pos)
   5671          (setq quoted 1)
   5672          (setq state (cond ((eq ?\' char) 7)
   5673                            ((eq ?\" char) 8)
   5674                            (t             9)))
   5675          (setq step 100)
   5676          (when (= state 9) (setq brace-depth 1))
   5677          )
   5678 
   5679         ((and (eq ?\= char) (member state '(2 3)))
   5680          (setq equal-offset (- pos name-beg)
   5681                name-end (1- pos))
   5682          (setq state 4)
   5683          (setq attr (buffer-substring-no-properties name-beg (1+ name-end)))
   5684          (when (and web-mode-indentless-attributes (member (downcase attr) web-mode-indentless-attributes))
   5685            (setq attr-flags (logior attr-flags 8)))
   5686          )
   5687 
   5688         ((and spaced (= state 0))
   5689          (setq state 1)
   5690          )
   5691 
   5692         ((and (eq char ?\<) (not (member state '(7 8 9))))
   5693          (setq continue nil)
   5694          (setq go-back t)
   5695          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5696          )
   5697 
   5698         ((and (eq char ?\>) (not (member state '(7 8 9))))
   5699          (setq tag-flags (logior tag-flags 16))
   5700          (when (eq (char-before) ?\/)
   5701            (setq tag-flags (logior tag-flags 8))
   5702            )
   5703          (setq continue nil)
   5704          (when name-beg
   5705            (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags))))
   5706          )
   5707 
   5708         ((and spaced (member state '(1 3 5)))
   5709          )
   5710 
   5711         ((and spaced (= state 2))
   5712          (setq state 3)
   5713          )
   5714 
   5715         ((and (eq char ?\/) (member state '(4 5)))
   5716          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5717          (setq state 1
   5718                attr-flags 0
   5719                equal-offset 0
   5720                name-beg nil
   5721                name-end nil
   5722                val-beg nil)
   5723          )
   5724 
   5725         ((and (eq char ?\/) (member state '(0 1)))
   5726          )
   5727 
   5728         ((and spaced (= state 4))
   5729          (setq state 5)
   5730          )
   5731 
   5732         ((and (= state 3)
   5733               (or (and (>= char 97) (<= char 122)) ;a - z
   5734                   (and (>= char 65) (<= char 90)) ;A - Z
   5735                   (eq char ?\-)))
   5736          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5737          (setq state 2
   5738                attr-flags 0
   5739                equal-offset 0
   5740                name-beg pos
   5741                name-end pos
   5742                val-beg nil)
   5743          )
   5744 
   5745         ((and (eq char ?\n) (not (member state '(7 8 9))))
   5746          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5747          (setq state 1
   5748                attr-flags 0
   5749                equal-offset 0
   5750                name-beg nil
   5751                name-end nil
   5752                val-beg nil)
   5753          )
   5754 
   5755         ((and (= state 6) (member char '(?\s ?\n))) ;#1150
   5756          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5757          (setq state 1
   5758                attr-flags 0
   5759                equal-offset 0
   5760                name-beg nil
   5761                name-end nil
   5762                val-beg nil)
   5763          )
   5764 
   5765         ((and quoted (= quoted 2) (member char '(?\s ?\n ?\>)))
   5766          (when (eq char ?\>)
   5767            (setq tag-flags (logior tag-flags 16))
   5768            (setq continue nil))
   5769          (setq state 6)
   5770          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5771          (setq state 1
   5772                attr-flags 0
   5773                equal-offset 0
   5774                name-beg nil
   5775                name-end nil
   5776                val-beg nil)
   5777          )
   5778 
   5779         ((and (not spaced) (= state 1))
   5780          (when (and is-jsx (eq char ?\{))
   5781            (setq attr-flags 4))
   5782          (setq state 2)
   5783          (setq name-beg pos
   5784                name-end pos)
   5785          )
   5786 
   5787         ((member state '(4 5))
   5788          (setq val-beg pos)
   5789          (setq state 6)
   5790          )
   5791 
   5792         ((= state 1)
   5793          (setq state 2)
   5794          )
   5795 
   5796         ((= state 2)
   5797          (setq name-end pos)
   5798          (when (and nil (= attr-flags 0) (member char '(?\- ?\:)))
   5799            (let (attr)
   5800              (setq attr (buffer-substring-no-properties name-beg (1+ name-end)))
   5801              (cond
   5802                ((member attr '("http-equiv"))
   5803                 (setq attr-flags (1- attr-flags))
   5804                 )
   5805                ((and (eq char ?\-) (not (string= attr "http-")))
   5806                 (setq attr-flags (logior attr-flags 1)))
   5807                ) ;cond
   5808              ) ;let
   5809            ) ;when attr-flags = 1
   5810          ) ;state=2
   5811 
   5812         ) ;cond
   5813 
   5814       ;;(message "point(%S) end(%S) state(%S) c(%S) name-beg(%S) name-end(%S) val-beg(%S) attr-flags(%S) equal-offset(%S)" pos end state char name-beg name-end val-beg attr-flags equal-offset tag-flags)
   5815 
   5816       (when (and quoted (>= quoted 2))
   5817         (setq quoted nil))
   5818 
   5819       (setq escaped (eq ?\\ char))
   5820       (when (null go-back)
   5821         (forward-char))
   5822 
   5823       ;;(when (not (= mem state)) (message "pos=%S before=%S after=%S step=%S" pos mem state step))
   5824 
   5825       ) ;while
   5826 
   5827     (when (> attrs 0) (setq tag-flags (logior tag-flags 1)))
   5828 
   5829     tag-flags))
   5830 
   5831 (defun web-mode-attr-scan (pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)
   5832   ;;(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)
   5833   (when (null attr-flags) (setq attr-flags 0))
   5834   (when (and name-beg name-end web-mode-engine-attr-regexp)
   5835     (let (name)
   5836       (setq name (buffer-substring-no-properties name-beg (1+ name-end)))
   5837       (cond
   5838         ((string-match-p "^data[-]" name)
   5839          (setq attr-flags (logior attr-flags 1))
   5840          )
   5841         ((string-match-p web-mode-engine-attr-regexp name)
   5842          (setq attr-flags (logior attr-flags 2))
   5843          )
   5844         )
   5845       ) ;name
   5846     )
   5847   ;;(message "%S" name)
   5848   (cond
   5849     ((null name-beg)
   5850      0)
   5851     ((or (and (= state 8) (not (eq ?\" char)))
   5852          (and (= state 7) (not (eq ?\' char))))
   5853      (put-text-property name-beg (1+ name-beg) 'tag-attr-beg attr-flags)
   5854      (put-text-property name-beg val-beg 'tag-attr t)
   5855      (put-text-property (1- val-beg) val-beg 'tag-attr-end equal-offset)
   5856      1)
   5857     ((and (member state '(4 5)) (null val-beg))
   5858      (put-text-property name-beg (1+ name-beg) 'tag-attr-beg attr-flags)
   5859      (put-text-property name-beg (+ name-beg equal-offset 1) 'tag-attr t)
   5860      (put-text-property (+ name-beg equal-offset) (+ name-beg equal-offset 1) 'tag-attr-end equal-offset)
   5861      1)
   5862     (t
   5863      (let (val-end)
   5864        (if (null val-beg)
   5865            (setq val-end name-end)
   5866            (setq val-end pos)
   5867            (cond
   5868              ((null char)
   5869               (setq val-end (1- val-end)))
   5870              ((member char '(?\s ?\n ?\/))
   5871               (setq val-end (1- val-end)))
   5872              ((eq char ?\>)
   5873               (if (= (logand tag-flags 8) 8)
   5874                   (progn
   5875                     ;;(message "tag-flags=%S %S" tag-flags (logand tag-flags 8))
   5876                     (setq val-end (- val-end 2)))
   5877                   (setq val-end (- val-end 1)))
   5878               ;; (message "val-end=%S" val-end)
   5879               )
   5880              )
   5881            )
   5882        (put-text-property name-beg (1+ name-beg) 'tag-attr-beg attr-flags)
   5883        (put-text-property name-beg (1+ val-end) 'tag-attr t)
   5884        (put-text-property val-end (1+ val-end) 'tag-attr-end equal-offset)
   5885        ) ;let
   5886      1) ;t
   5887     ) ;cond
   5888   )
   5889 
   5890 (defun web-mode-part-foreach (reg-beg reg-end func)
   5891   (let ((i 0) (continue t) (part-beg reg-beg) (part-end nil))
   5892     (while continue
   5893       (setq part-end nil)
   5894       (unless (get-text-property part-beg 'part-side)
   5895         (setq part-beg (web-mode-part-next-position part-beg)))
   5896       (when (and part-beg (< part-beg reg-end))
   5897         (setq part-end (web-mode-part-end-position part-beg)))
   5898       (cond
   5899         ((> (setq i (1+ i)) 100)
   5900          (message "process-parts ** warning (%S) **" (point))
   5901          (setq continue nil))
   5902         ((or (null part-end) (> part-end reg-end))
   5903          (setq continue nil))
   5904         (t
   5905          (setq part-end (1+ part-end))
   5906          (funcall func part-beg part-end)
   5907          (setq part-beg part-end))
   5908         ) ;cond
   5909       ) ;while
   5910     ))
   5911 
   5912 (defun web-mode-part-scan (reg-beg reg-end &optional content-type depth)
   5913   (save-excursion
   5914     (let (token-re ch-before ch-at ch-next token-type beg continue)
   5915       ;;(message "%S %S" reg-beg reg-end)
   5916       (cond
   5917         (content-type
   5918          )
   5919         ((member web-mode-content-type web-mode-part-content-types)
   5920          (setq content-type web-mode-content-type))
   5921         (t
   5922          (setq content-type (symbol-name (get-text-property reg-beg 'part-side))))
   5923         ) ;cond
   5924 
   5925       (goto-char reg-beg)
   5926 
   5927       (cond
   5928         ((member content-type '("javascript" "json"))
   5929          (setq token-re "/\\|\"\\|'\\|`"))
   5930         ((member content-type '("typescript"))
   5931          (setq token-re "/\\|\"\\|'\\|`\\|//\\|/\\*"))
   5932         ((member content-type '("jsx"))
   5933          (setq token-re "/\\|\"\\|'\\|`\\|</?[[:alpha:]>]"))
   5934         ((string= web-mode-content-type "css")
   5935          (setq token-re "\"\\|'\\|/\\*\\|//"))
   5936         ((string= content-type "css")
   5937          (setq token-re "\"\\|'\\|/\\*"))
   5938         (t
   5939          (setq token-re "/\\*\\|\"\\|'"))
   5940         )
   5941 
   5942       (while (and token-re (< (point) reg-end) (web-mode-dom-rsf token-re reg-end t))
   5943 
   5944         (setq beg (match-beginning 0)
   5945               token-type nil
   5946               continue t
   5947               ch-at (char-after beg)
   5948               ch-next (or (char-after (1+ beg)) ?\d)
   5949               ch-before (or (char-before beg) ?\d))
   5950 
   5951         ;;(message "[%S>%S|%S] %S %c %c %c" reg-beg reg-end depth beg ch-before ch-at ch-next)
   5952 
   5953         (cond
   5954 
   5955           ((eq ?\' ch-at)
   5956            (while (and continue (search-forward "'" reg-end t))
   5957              (cond
   5958                ((get-text-property (1- (point)) 'block-side)
   5959                 (setq continue t))
   5960                (t
   5961                 (setq continue (web-mode-string-continue-p reg-beg)))
   5962                )
   5963              ) ;while
   5964            (setq token-type 'string))
   5965 
   5966           ((eq ?\` ch-at)
   5967            (while (and continue (search-forward "`" reg-end t))
   5968              (cond
   5969                ((get-text-property (1- (point)) 'block-side)
   5970                 (setq continue t))
   5971                (t
   5972                 (setq continue (web-mode-string-continue-p reg-beg)))
   5973                )
   5974              ) ;while
   5975            (setq token-type 'string))
   5976 
   5977           ((eq ?\" ch-at)
   5978            (while (and continue (search-forward "\"" reg-end t))
   5979              (cond
   5980                ((get-text-property (1- (point)) 'block-side)
   5981                 (setq continue t))
   5982                (t
   5983                 (setq continue (web-mode-string-continue-p reg-beg)))
   5984                ) ;cond
   5985              ) ;while
   5986            (cond
   5987              ((string= content-type "json")
   5988               (if (looking-at-p "[ ]*:")
   5989                   (cond
   5990                     ((eq ?\@ (char-after (1+ beg)))
   5991                      (setq token-type 'context))
   5992                     (t
   5993                      (setq token-type 'key))
   5994                     )
   5995                   (setq token-type 'string))
   5996               ) ;json
   5997              (t
   5998               (setq token-type 'string))
   5999              ) ;cond
   6000            )
   6001 
   6002           ((and (eq ?\< ch-at)
   6003                 (not (or (and (>= ch-before 97) (<= ch-before 122))
   6004                          (and (>= ch-before 65) (<= ch-before 90)))))
   6005            ;;(message "before [%S>%S|%S] pt=%S" reg-beg reg-end depth (point))
   6006            (search-backward "<")
   6007            (if (web-mode-jsx-skip reg-end)
   6008                (web-mode-jsx-scan-element beg (point) depth)
   6009                (forward-char))
   6010            ;;(message "after [%S>%S|%S] pt=%S" reg-beg reg-end depth (point))
   6011            )
   6012 
   6013           ((and (eq ?\/ ch-at) (member content-type '("javascript" "jsx" "typescript")))
   6014            (cond
   6015              ((eq ?\\ ch-before)
   6016               )
   6017              ((eq ?\* ch-next)
   6018               ;;(message "--> %S %S" (point) reg-end)
   6019               (when (search-forward "*/" reg-end t)
   6020                 (setq token-type 'comment))
   6021               )
   6022              ((eq ?\/ ch-next)
   6023               (setq token-type 'comment)
   6024               (goto-char (if (< reg-end (line-end-position)) reg-end (line-end-position)))
   6025               )
   6026              ((and (looking-at-p ".*/")
   6027                    (looking-back "\\(^\\|case\\|[[(,=:!&|?{};]\\)[ ]*/" (point-min)))
   6028               ;;(re-search-forward "/[gimyu]*" reg-end t))
   6029               (let ((eol (line-end-position)))
   6030                 (while (and continue (search-forward "/" eol t))
   6031                   (cond
   6032                     ((get-text-property (1- (point)) 'block-side)
   6033                      (setq continue t))
   6034                     ((looking-back "\\\\+/" reg-beg t)
   6035                      (setq continue (= (mod (- (point) (match-beginning 0)) 2) 0)))
   6036                     (t
   6037                      (re-search-forward "[gimyu]*" eol t)
   6038                      (setq token-type 'string)
   6039                      (setq continue nil))
   6040                     )
   6041                   ) ;while
   6042                 ) ;let
   6043               )
   6044              ) ;cond
   6045            )
   6046 
   6047           ((eq ?\/ ch-next)
   6048            ;;(message "%S" (point))
   6049            (cond
   6050              ((and (string= content-type "css")
   6051                    (eq ?/ ch-at)
   6052                    (eq ?: ch-before))
   6053               )
   6054              (t
   6055               (unless (eq ?\\ ch-before)
   6056                 (setq token-type 'comment)
   6057                 (goto-char (if (< reg-end (line-end-position)) reg-end (line-end-position)))
   6058                 )
   6059               )
   6060              )
   6061 
   6062            )
   6063 
   6064           ((eq ?\* ch-next)
   6065            (cond
   6066              ((search-forward "*/" reg-end t)
   6067               (setq token-type 'comment))
   6068              ((not (eobp))
   6069               (forward-char))
   6070              ) ;cond
   6071            )
   6072 
   6073           ) ;cond
   6074 
   6075         (when (and beg (>= reg-end (point)) token-type)
   6076           (put-text-property beg (point) 'part-token token-type)
   6077           (cond
   6078             ((eq token-type 'comment)
   6079              (put-text-property beg (1+ beg) 'syntax-table (string-to-syntax "<"))
   6080              (when (< (point) (point-max))
   6081                (if (< (point) (line-end-position))
   6082                    (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax ">")) ;#445
   6083                    (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax ">")) ;#377
   6084                    )
   6085                ) ;when
   6086              ) ;comment
   6087             ((eq token-type 'string)
   6088              (put-text-property beg (1+ beg) 'syntax-table (string-to-syntax "|"))
   6089              (when (< (point) (point-max))
   6090                (if (< (point) (line-end-position))
   6091                    (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax "|"))
   6092                    (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax "|"))
   6093                    )
   6094                ) ;when
   6095              ) ;string
   6096             ) ;cond
   6097           ) ;when
   6098 
   6099         (when (> (point) reg-end)
   6100           (message "reg-beg(%S) reg-end(%S) token-type(%S) point(%S)" reg-beg reg-end token-type (point)))
   6101 
   6102         ;;(message "#[%S>%S|%S] %S %c %c %c | (%S)" reg-beg reg-end depth beg ch-before ch-at ch-next (point))
   6103 
   6104         ) ;while
   6105 
   6106       )))
   6107 
   6108 (defun web-mode-string-continue-p (reg-beg)
   6109   "Is `point' preceeded by an odd number of backslashes?"
   6110   (let ((p (1- (point))))
   6111     (while (and (< reg-beg p) (eq ?\\ (char-before p)))
   6112       (setq p (1- p)))
   6113     (= (mod (- (point) p) 2) 0)))
   6114 
   6115 ;; css rule = selector(s) + declaration (properties)
   6116 (defun web-mode-css-rule-next (limit)
   6117   (let (at-rule var-rule sel-beg sel-end dec-beg dec-end chunk)
   6118     (skip-chars-forward "\n\t ")
   6119     (setq sel-beg (point))
   6120     (when (and (< (point) limit)
   6121                (web-mode-part-rsf "[{;]" limit))
   6122       (setq sel-end (1- (point)))
   6123       (cond
   6124         ((eq (char-before) ?\{)
   6125          (setq dec-beg (point))
   6126          (setq dec-end (web-mode-closing-paren-position (1- dec-beg) limit))
   6127          (if dec-end
   6128              (progn
   6129                (goto-char dec-end)
   6130                (forward-char))
   6131              (setq dec-end limit)
   6132              (goto-char limit))
   6133          )
   6134         (t
   6135          )
   6136         ) ;cond
   6137       (setq chunk (buffer-substring-no-properties sel-beg sel-end))
   6138       (cond
   6139         ((string-match "@\\([[:alpha:]-]+\\)" chunk)
   6140          (setq at-rule (match-string-no-properties 1 chunk)))
   6141         ((string-match "\\$\\([[:alpha:]-]+\\)" chunk)
   6142          (setq var-rule (match-string-no-properties 1 chunk)))
   6143         ) ;cond
   6144       ) ;when
   6145     (if (not sel-end)
   6146         (progn (goto-char limit) nil)
   6147         (list :at-rule at-rule
   6148               :var-rule var-rule
   6149               :sel-beg sel-beg
   6150               :sel-end sel-end
   6151               :dec-beg dec-beg
   6152               :dec-end dec-end)
   6153         ) ;if
   6154     ))
   6155 
   6156 (defun web-mode-css-rule-current (&optional pos part-beg part-end)
   6157   "Current CSS rule boundaries."
   6158   (unless pos (setq pos (point)))
   6159   (unless part-beg (setq part-beg (web-mode-part-beginning-position pos)))
   6160   (unless part-end (setq part-end (web-mode-part-end-position pos)))
   6161   (save-excursion
   6162     (let (beg end)
   6163       (goto-char pos)
   6164       (if (not (web-mode-part-sb "{" part-beg))
   6165           (progn
   6166             (setq beg part-beg)
   6167             (if (web-mode-part-sf ";" part-end)
   6168                 (setq end (1+ (point)))
   6169                 (setq end part-end))
   6170             ) ;progn
   6171           (setq beg (point))
   6172           (setq end (web-mode-closing-paren-position beg part-end))
   6173           (if end
   6174               (setq end (1+ end))
   6175               (setq end (line-end-position)))
   6176           ;;        (message "%S >>beg%S >>end%S" pos beg end)
   6177           (if (> pos end)
   6178 
   6179               ;;selectors
   6180               (progn
   6181                 (goto-char pos)
   6182                 (if (web-mode-part-rsb "[};]" part-beg)
   6183                     (setq beg (1+ (point)))
   6184                     (setq beg part-beg)
   6185                     ) ;if
   6186                 (goto-char pos)
   6187                 (if (web-mode-part-rsf "[{;]" part-end)
   6188                     (cond
   6189                       ((eq (char-before) ?\;)
   6190                        (setq end (point))
   6191                        )
   6192                       (t
   6193                        (setq end (web-mode-closing-paren-position (1- (point)) part-end))
   6194                        (if end
   6195                            (setq end (1+ end))
   6196                            (setq end part-end))
   6197                        )
   6198                       ) ;cond
   6199                     (setq end part-end)
   6200                     )
   6201                 ) ;progn selectors
   6202 
   6203               ;; declaration
   6204               (goto-char beg)
   6205               (if (web-mode-part-rsb "[}{;]" part-beg)
   6206                   (setq beg (1+ (point)))
   6207                   (setq beg part-beg)
   6208                   ) ;if
   6209               ) ;if > pos end
   6210           )
   6211       ;;      (message "beg(%S) end(%S)" beg end)
   6212       (when (eq (char-after beg) ?\n)
   6213         (setq beg (1+ beg)))
   6214       (cons beg end)
   6215       )))
   6216 
   6217 (defun web-mode-jsx-skip (reg-end)
   6218   (let ((continue t) (pos nil) (i 0))
   6219     (looking-at "<\\([[:alpha:]][[:alnum:]:-]*\\)")
   6220     (setq tag (match-string-no-properties 1))
   6221     ;;(message "point=%S tag=%S" (point) tag)
   6222     (save-excursion
   6223       (while continue
   6224         (cond
   6225           ((> (setq i (1+ i)) 1000)
   6226            (message "jsx-skip ** warning **")
   6227            (setq continue nil))
   6228           ((looking-at "<[[:alpha:]][[:alnum:]:-]*[ ]*/>")
   6229            (goto-char (match-end 0))
   6230            (setq pos (point))
   6231            (setq continue nil))
   6232           ((not (web-mode-dom-rsf ">\\([ \t\n]*[\];,)':}|&]\\)\\|{" reg-end))
   6233            (setq continue nil)
   6234            )
   6235           ((eq (char-before) ?\{)
   6236            (backward-char)
   6237            (web-mode-closing-paren reg-end)
   6238            (forward-char)
   6239            )
   6240           (t
   6241            (setq continue nil)
   6242            (setq pos (match-beginning 1))
   6243            ) ;t
   6244           ) ;cond
   6245         ) ;while
   6246       ) ;save-excursion
   6247     (when pos (goto-char pos))
   6248     ;;(message "jsx-skip: %S" pos)
   6249     pos))
   6250 
   6251 ;; (defun web-mode-jsx-skip2 (reg-end)
   6252 ;;   (let ((continue t) (pos nil) (i 0) (tag nil) (regexp nil) (counter 1))
   6253 ;;     (looking-at "<\\([[:alpha:]][[:alnum:]:-]*\\)")
   6254 ;;     (setq tag (match-string-no-properties 1))
   6255 ;;     (setq regexp (concat "</?" tag))
   6256 ;;     ;;(message "point=%S tag=%S" (point) tag)
   6257 ;;     (save-excursion
   6258 ;;       (while continue
   6259 ;;         (cond
   6260 ;;          ((> (setq i (1+ i)) 100)
   6261 ;;           (message "jsx-skip ** warning **")
   6262 ;;           (setq continue nil))
   6263 ;;          ((looking-at "<[[:alpha:]][[:alnum:]:-]*[ ]*/>")
   6264 ;;           (goto-char (match-end 0))
   6265 ;;           (setq pos (point))
   6266 ;;           (setq continue nil))
   6267 ;;          ((not (web-mode-dom-rsf ">\\([ \t\n]*[\];,)':}]\\)\\|{" reg-end))
   6268 ;;           (setq continue nil)
   6269 ;;           )
   6270 ;;          ((eq (char-before) ?\{)
   6271 ;;           (backward-char)
   6272 ;;           (web-mode-closing-paren reg-end)
   6273 ;;           (forward-char)
   6274 ;;           )
   6275 ;;          (t
   6276 ;;           (setq continue nil)
   6277 ;;           (setq pos (match-beginning 1))
   6278 ;;           ) ;t
   6279 ;;          ) ;cond
   6280 ;;         ) ;while
   6281 ;;       ) ;save-excursion
   6282 ;;     (when pos (goto-char pos))
   6283 ;;     ;;(message "jsx-skip: %S" pos)
   6284 ;;     pos))
   6285 
   6286 ;; http://facebook.github.io/jsx/
   6287 ;; https://github.com/facebook/jsx/blob/master/AST.md
   6288 (defun web-mode-jsx-scan-element (reg-beg reg-end depth)
   6289   (unless depth (setq depth 1))
   6290   (save-excursion
   6291     (goto-char reg-beg)
   6292     (put-text-property reg-beg (1+ reg-beg) 'jsx-beg depth)
   6293     (put-text-property (1- reg-end) reg-end 'jsx-end depth)
   6294     (put-text-property reg-beg reg-end 'jsx-depth depth)
   6295     (goto-char reg-beg)
   6296     (web-mode-scan-elements reg-beg reg-end)
   6297     (web-mode-jsx-scan-expression reg-beg reg-end (1+ depth))
   6298     ))
   6299 
   6300 (defun web-mode-jsx-scan-expression (reg-beg reg-end depth)
   6301   (let ((continue t) beg end)
   6302     (save-excursion
   6303       (goto-char reg-beg)
   6304       ;;(message "reg-beg=%S reg-end=%S" reg-beg reg-end)
   6305       (while (and continue (search-forward "{" reg-end t))
   6306         (backward-char)
   6307         (setq beg (point)
   6308               end (web-mode-closing-paren reg-end))
   6309         (cond
   6310           ((eq (get-text-property beg 'part-token) 'comment)
   6311            (forward-char))
   6312           ((not end)
   6313            (setq continue nil))
   6314           (t
   6315            (setq end (1+ end))
   6316            (put-text-property beg end 'jsx-depth depth)
   6317            (put-text-property beg (1+ beg) 'jsx-beg depth)
   6318            (put-text-property (1- end) end 'jsx-end depth)
   6319            (web-mode-part-scan beg end "jsx" (1+ depth))
   6320            ) ;t
   6321           ) ;cond
   6322         ) ;while
   6323       ) ;save-excursion
   6324     ))
   6325 
   6326 (defun web-mode-jsx-is-html (&optional pos)
   6327   (interactive)
   6328   (unless pos (setq pos (point)))
   6329   (let (ret (depth (get-text-property pos 'jsx-depth)))
   6330     (cond
   6331       ((or (null depth) (<= pos 2))
   6332        (setq pos nil))
   6333       ((and (= depth 1) (get-text-property pos 'jsx-beg))
   6334        (setq pos nil))
   6335       ((get-text-property pos 'tag-end)
   6336        (setq pos nil))
   6337       ((get-text-property pos 'tag-attr-beg)
   6338        (setq pos nil))
   6339       ((get-text-property pos 'jsx-beg)
   6340        (setq pos (null (get-text-property pos 'tag-beg))))
   6341       ((setq pos (web-mode-jsx-depth-beginning-position pos))
   6342        (setq pos (not (null (get-text-property pos 'tag-beg)))))
   6343       (t
   6344        (setq pos nil))
   6345       ) ;cond
   6346     ;;(message "is-html: %S (depth=%S)" pos depth)
   6347     pos))
   6348 
   6349 (defun web-mode-jsx-is-expr (&optional pos)
   6350   (cond
   6351     ((and (get-text-property pos 'jsx-beg)
   6352           (not (get-text-property pos 'tag-beg)))
   6353      nil)
   6354     (t
   6355      (setq pos (web-mode-jsx-depth-beginning-position pos))
   6356      (null (get-text-property pos 'tag-beg)))
   6357     ) ;cond
   6358   )
   6359 
   6360 (defun web-mode-jsx-depth-beginning-position (&optional pos target-depth)
   6361   (interactive)
   6362   (unless pos (setq pos (point)))
   6363   (unless target-depth (setq target-depth (get-text-property pos 'jsx-depth)))
   6364   (cond
   6365     ((or (null target-depth) (bobp))
   6366      (setq pos nil))
   6367     ((and (get-text-property pos 'jsx-beg) (= target-depth (get-text-property pos 'jsx-depth)))
   6368      )
   6369     (t
   6370      (let ((continue t) depth)
   6371        (while continue
   6372          (setq pos (previous-single-property-change pos 'jsx-depth))
   6373          (cond
   6374            ((or (null pos)
   6375                 (null (setq depth (get-text-property pos 'jsx-depth))))
   6376             (setq continue nil
   6377                   pos nil))
   6378            ((and (get-text-property pos 'jsx-beg) (= target-depth depth))
   6379             (setq continue nil))
   6380            ) ;cond
   6381          ) ;while
   6382        ) ;let
   6383      ) ;t
   6384     ) ;cond
   6385   ;;(message "beg: %S" pos)
   6386   pos)
   6387 
   6388 (defun web-mode-jsx-element-next (reg-end)
   6389   (let (continue beg end)
   6390     (setq beg (point))
   6391     (unless (get-text-property beg 'jsx-depth)
   6392       (setq beg (next-single-property-change beg 'jsx-beg)))
   6393     (setq continue (and beg (< beg reg-end))
   6394           end beg)
   6395     (while continue
   6396       (setq end (next-single-property-change end 'jsx-end))
   6397       (cond
   6398         ((or (null end) (> end reg-end))
   6399          (setq continue nil
   6400                end nil))
   6401         ((eq (get-text-property end 'jsx-depth) 1)
   6402          (setq continue nil))
   6403         (t
   6404          (setq end (1+ end)))
   6405         ) ;cond
   6406       ) ;while
   6407     ;;(message "beg=%S end=%S" beg end)
   6408     (if (and beg end (< beg end)) (cons beg end) nil)))
   6409 
   6410 (defun web-mode-jsx-expression-next (reg-end)
   6411   (let (beg end depth continue pos)
   6412     (setq beg (point))
   6413     ;;(message "pt=%S" beg)
   6414     (unless (and (get-text-property beg 'jsx-beg) (null (get-text-property beg 'tag-beg)))
   6415       ;;(setq beg (next-single-property-change beg 'jsx-beg))
   6416       (setq continue t
   6417             pos (1+ beg))
   6418       (while continue
   6419         (setq pos (next-single-property-change pos 'jsx-beg))
   6420         (cond
   6421           ((null pos)
   6422            (setq continue nil
   6423                  beg nil))
   6424           ((> pos reg-end)
   6425            (setq continue nil
   6426                  beg nil))
   6427           ((null (get-text-property pos 'jsx-beg))
   6428            )
   6429           ((null (get-text-property pos 'tag-beg))
   6430            (setq continue nil
   6431                  beg pos))
   6432           ;;(t
   6433           ;; (setq pos (1+ pos)))
   6434           ) ;cond
   6435         ) ;while
   6436       ) ;unless
   6437     ;;(message "beg=%S" beg)
   6438     (when (and beg (< beg reg-end))
   6439       (setq depth (get-text-property beg 'jsx-beg)
   6440             continue (not (null depth))
   6441             pos beg)
   6442       ;;(message "beg=%S" beg)
   6443       (while continue
   6444         (setq pos (next-single-property-change pos 'jsx-end))
   6445         ;;(message "pos=%S" pos)
   6446         (cond
   6447           ((null pos)
   6448            (setq continue nil))
   6449           ((> pos reg-end)
   6450            (setq continue nil))
   6451           ((eq depth (get-text-property pos 'jsx-end))
   6452            (setq continue nil
   6453                  end pos))
   6454           (t
   6455            ;;(setq pos (1+ pos))
   6456            )
   6457           ) ;cond
   6458         ) ;while
   6459       ) ;when
   6460     ;;(message "%S > %S" beg end)
   6461     (if (and beg end) (cons beg end) nil)))
   6462 
   6463 (defun web-mode-jsx-depth-next (reg-end)
   6464   (let (beg end depth continue pos)
   6465     (setq beg (point))
   6466     ;;(message "pt=%S" beg)
   6467     (unless (get-text-property beg 'jsx-beg)
   6468       ;;(setq beg (next-single-property-change beg 'jsx-beg))
   6469       ;;(setq pos (1+ beg))
   6470       (setq pos (next-single-property-change (1+ beg) 'jsx-beg))
   6471       (cond
   6472         ((null pos)
   6473          (setq beg nil))
   6474         ((>= pos reg-end)
   6475          (setq beg nil))
   6476         (t
   6477          (setq beg pos))
   6478         ) ;cond
   6479       ) ;unless
   6480     ;;(message "beg=%S" beg)
   6481     (when beg
   6482       (setq depth (get-text-property beg 'jsx-beg)
   6483             continue (not (null depth))
   6484             pos beg)
   6485       ;;(message "beg=%S" beg)
   6486       (while continue
   6487         (setq pos (next-single-property-change pos 'jsx-end))
   6488         ;;(message "pos=%S" pos)
   6489         (cond
   6490           ((null pos)
   6491            (setq continue nil))
   6492           ((> pos reg-end)
   6493            (setq continue nil))
   6494           ((eq depth (get-text-property pos 'jsx-end))
   6495            (setq continue nil
   6496                  end pos))
   6497           (t
   6498            ;;(setq pos (1+ pos))
   6499            )
   6500           ) ;cond
   6501         ) ;while
   6502       ) ;when
   6503     ;;(message "%S > %S" beg end)
   6504     (if (and beg end) (cons beg end) nil)))
   6505 
   6506 (defun web-mode-jsx-beginning ()
   6507   (interactive)
   6508   (let (depth (continue t) (reg-beg (point-min)) (pos (point)))
   6509     (setq depth (get-text-property pos 'jsx-depth))
   6510     (cond
   6511       ((not depth)
   6512        )
   6513       ((get-text-property (1- pos) 'jsx-beg)
   6514        (goto-char (1- pos)))
   6515       (t
   6516        (while continue
   6517          (setq pos (previous-single-property-change pos 'jsx-beg))
   6518          ;;(message "pos=%S" pos)
   6519          (cond
   6520            ((null pos)
   6521             (setq continue nil))
   6522            ((<= pos reg-beg)
   6523             (setq continue nil))
   6524            ((eq depth (get-text-property pos 'jsx-beg))
   6525             (setq continue nil))
   6526            ) ;cond
   6527          ) ;while
   6528        (web-mode-go pos)
   6529        ) ;t
   6530       ) ;cond
   6531     ))
   6532 
   6533 (defun web-mode-jsx-end ()
   6534   (interactive)
   6535   (let (depth (continue t) (reg-end (point-max)) (pos (point)))
   6536     (setq depth (get-text-property pos 'jsx-depth))
   6537     (cond
   6538       ((not depth)
   6539        )
   6540       ((get-text-property pos 'jsx-end)
   6541        (goto-char (+ pos 1)))
   6542       (t
   6543        (while continue
   6544          (setq pos (next-single-property-change pos 'jsx-end))
   6545          ;;(message "pos=%S" pos)
   6546          (cond
   6547            ((null pos)
   6548             (setq continue nil))
   6549            ((> pos reg-end)
   6550             (setq continue nil))
   6551            ((eq depth (get-text-property pos 'jsx-end))
   6552             (setq continue nil))
   6553            ) ;cond
   6554          ) ;while
   6555        (web-mode-go pos 1)
   6556        ) ;t
   6557       ) ;cond
   6558     ))
   6559 
   6560 ;;---- FONTIFICATION -----------------------------------------------------------
   6561 
   6562 (defun web-mode-fontify (limit)
   6563   (when web-mode-trace
   6564     (message "fontify: point(%S) limit(%S)" (point) limit))
   6565   (cond
   6566     ;;(web-mode-skip-fontification
   6567     ;; nil)
   6568     (t
   6569      (web-mode-with-silent-modifications
   6570       (save-excursion
   6571         (save-restriction
   6572           (save-match-data
   6573             (let ((beg (point))
   6574                   (buffer-undo-list t)
   6575                   (end limit)
   6576                   (inhibit-point-motion-hooks t)
   6577                   (inhibit-quit t))
   6578               (remove-list-of-text-properties beg end '(font-lock-face face))
   6579               (cond
   6580                 ((and (get-text-property beg 'block-side)
   6581                       (not (get-text-property beg 'block-beg)))
   6582                  (web-mode-fontify-block beg end))
   6583                 ((or (member web-mode-content-type web-mode-part-content-types)
   6584                      (get-text-property beg 'part-side))
   6585                  (web-mode-fontify-part beg end)
   6586                  (web-mode-block-foreach beg end 'web-mode-fontify-block))
   6587                 ((string= web-mode-engine "none")
   6588                  (web-mode-fontify-tags beg end)
   6589                  (web-mode-part-foreach beg end 'web-mode-fontify-part))
   6590                 (t
   6591                  (web-mode-fontify-tags beg end)
   6592                  (web-mode-part-foreach beg end 'web-mode-fontify-part)
   6593                  (web-mode-block-foreach beg end 'web-mode-fontify-block))
   6594                 ) ;cond
   6595               (when web-mode-enable-element-content-fontification
   6596                 (web-mode-fontify-elements beg end))
   6597               (when web-mode-enable-whitespace-fontification
   6598                 (web-mode-fontify-whitespaces beg end))
   6599               ) ;let
   6600             ))))
   6601      nil) ;t
   6602     ))
   6603 
   6604 (defun web-mode-buffer-fontify ()
   6605   (interactive)
   6606   (cond
   6607     ((and (fboundp 'font-lock-flush) global-font-lock-mode)
   6608      (font-lock-flush)
   6609      (font-lock-ensure))
   6610     (t  ;emacs 24
   6611      ;;(font-lock-fontify-buffer)
   6612      (and global-font-lock-mode
   6613           (font-lock-fontify-region (point-min) (point-max))))
   6614     ))
   6615 
   6616 (defun web-mode-unfontify-region (beg end)
   6617   ;;(message "unfontify: %S %S" beg end)
   6618   )
   6619 
   6620 (defun web-mode-fontify-region (beg end keywords)
   6621   ;;  (message "beg=%S end=%S keywords=%S" beg end (symbol-name keywords))
   6622   (save-excursion
   6623     (let ((font-lock-keywords keywords)
   6624           (font-lock-multiline nil)
   6625           (font-lock-keywords-case-fold-search
   6626            (member web-mode-engine '("archibus" "asp" "template-toolkit")))
   6627           (font-lock-keywords-only t)
   6628           (font-lock-extend-region-functions nil))
   6629       (when (and (listp font-lock-keywords) global-font-lock-mode)
   6630         (font-lock-fontify-region beg end)
   6631         )
   6632       )))
   6633 
   6634 (defun web-mode-fontify-tags (reg-beg reg-end &optional depth)
   6635   (let ((continue t))
   6636     (goto-char reg-beg)
   6637     (when (and (not (get-text-property (point) 'tag-beg))
   6638                (not (web-mode-tag-next)))
   6639       (setq continue nil))
   6640     (when (and continue (>= (point) reg-end))
   6641       (setq continue nil))
   6642     (while continue
   6643       (cond
   6644         (depth
   6645          (when (eq depth (get-text-property (point) 'jsx-depth))
   6646            (web-mode-fontify-tag))
   6647          )
   6648         (t
   6649          (web-mode-fontify-tag))
   6650         ) ;cond
   6651       (when (or (not (web-mode-tag-next))
   6652                 (>= (point) reg-end))
   6653         (setq continue nil))
   6654       ) ;while
   6655     (when web-mode-enable-inlays
   6656       (when (null web-mode-inlay-regexp)
   6657         (setq web-mode-inlay-regexp (regexp-opt '("\\[" "\\(" "\\begin{align}"))))
   6658       (let (beg end expr)
   6659         (goto-char reg-beg)
   6660         (while (web-mode-dom-rsf web-mode-inlay-regexp reg-end)
   6661           (setq beg (match-beginning 0)
   6662                 end nil
   6663                 expr (substring (match-string-no-properties 0) 0 2))
   6664           (setq expr (cond
   6665                        ((string= expr "\\[") "\\]")
   6666                        ((string= expr "\\(") "\\)")
   6667                        (t "\\end{align}")))
   6668           (when (and (web-mode-dom-sf expr reg-end)
   6669                      (setq end (match-end 0))
   6670                      (not (text-property-any beg end 'tag-end t)))
   6671             (font-lock-append-text-property beg end 'font-lock-face 'web-mode-inlay-face)
   6672             ) ;when
   6673           ) ;while
   6674         ) ;let
   6675       ) ;when
   6676     (when web-mode-enable-html-entities-fontification
   6677       (let (beg end)
   6678         (goto-char reg-beg)
   6679         (while (web-mode-dom-rsf "&\\([#]?[[:alnum:]]\\{2,8\\}\\);" reg-end)
   6680           (setq beg (match-beginning 0)
   6681                 end (match-end 0))
   6682           (when (not (text-property-any beg end 'tag-end t))
   6683             (font-lock-append-text-property beg end 'font-lock-face 'web-mode-html-entity-face)
   6684             ) ;when
   6685           ) ;while
   6686         ) ;let
   6687       ) ;when
   6688     ))
   6689 
   6690 (defun web-mode-fontify-tag (&optional beg end)
   6691   (unless beg (setq beg (point)))
   6692   (unless end (setq end (1+ (web-mode-tag-end-position beg))))
   6693   (let (name type face flags slash-beg slash-end bracket-end)
   6694     (setq flags (get-text-property beg 'tag-beg)
   6695           type (get-text-property beg 'tag-type)
   6696           name (get-text-property beg 'tag-name))
   6697     (setq bracket-end (> (logand flags 16) 0))
   6698     (cond
   6699       ((eq type 'comment)
   6700        (put-text-property beg end 'font-lock-face 'web-mode-comment-face)
   6701        (when (and web-mode-enable-comment-interpolation (> (- end beg) 5))
   6702          (web-mode-interpolate-comment beg end nil)))
   6703       ((eq type 'cdata)
   6704        (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
   6705       ((eq type 'doctype)
   6706        (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
   6707       ((eq type 'declaration)
   6708        (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
   6709       (name
   6710        (setq slash-beg (> (logand flags 4) 0)
   6711              slash-end (> (logand flags 8) 0)
   6712              bracket-end (> (logand flags 16) 0))
   6713        (setq face (cond
   6714                     ((not bracket-end)       'web-mode-html-tag-unclosed-face)
   6715                     ((and web-mode-enable-element-tag-fontification
   6716                           (setq face (cdr (assoc name web-mode-element-tag-faces))))
   6717                      face)
   6718                     ((> (logand flags 32) 0) 'web-mode-html-tag-namespaced-face)
   6719                     ((> (logand flags 2) 0)  'web-mode-html-tag-custom-face)
   6720                     (t                       'web-mode-html-tag-face)))
   6721        (put-text-property beg (+ beg (if slash-beg 2 1))
   6722                           'font-lock-face 'web-mode-html-tag-bracket-face)
   6723        (unless (string= name "_fragment_")
   6724          (put-text-property (+ beg (if slash-beg 2 1))
   6725                             (+ beg (if slash-beg 2 1) (length name))
   6726                             'font-lock-face face))
   6727        (when (or slash-end bracket-end)
   6728          (put-text-property (- end (if slash-end 2 1)) end 'font-lock-face 'web-mode-html-tag-bracket-face)
   6729          ) ;when
   6730        (when (> (logand flags 1) 0)
   6731          ;;(message "%S>%S" beg end)
   6732          (web-mode-fontify-attrs beg end))
   6733        ) ;case name
   6734       ) ;cond
   6735     ))
   6736 
   6737 (defun web-mode-fontify-attrs (reg-beg reg-end)
   6738   (let ((continue t) (pos reg-beg) beg end flags offset face)
   6739     ;;(message "fontify-attrs %S>%S" reg-beg reg-end)
   6740     (while continue
   6741       (setq beg (web-mode-attribute-next-position pos reg-end))
   6742       (cond
   6743         ((or (null beg) (>= beg reg-end))
   6744          (setq continue nil))
   6745         (t
   6746          (setq flags (or (get-text-property beg 'tag-attr-beg) 0))
   6747          (setq face (cond
   6748                       ((= (logand flags 1) 1) 'web-mode-html-attr-custom-face)
   6749                       ((= (logand flags 2) 2) 'web-mode-html-attr-engine-face)
   6750                       ((= (logand flags 4) 4) nil)
   6751                       (t                      'web-mode-html-attr-name-face)))
   6752          ;;(setq end (if (get-text-property beg 'tag-attr-end) beg (web-mode-attribute-end-position beg)))
   6753          (setq end (web-mode-attribute-end-position beg))
   6754          ;;(message "beg=%S end=%S" beg end)
   6755          (cond
   6756            ((or (null end) (>= end reg-end))
   6757             (setq continue nil))
   6758            (t
   6759             (setq offset (get-text-property end 'tag-attr-end))
   6760             (if (= offset 0)
   6761                 (put-text-property beg (1+ end) 'font-lock-face face)
   6762                 (put-text-property beg (+ beg offset) 'font-lock-face face)
   6763                 (put-text-property (+ beg offset) (+ beg offset 1)
   6764                                    'font-lock-face
   6765                                    'web-mode-html-attr-equal-face)
   6766                 (when (not (get-text-property (+ beg offset 1) 'jsx-beg))
   6767                   (put-text-property (+ beg offset 1) (1+ end)
   6768                                      'font-lock-face
   6769                                      'web-mode-html-attr-value-face)
   6770                   )
   6771                 ) ;if offset
   6772             (setq pos (1+ end))
   6773             ) ;t
   6774            ) ;cond
   6775          ) ;t
   6776         );cond
   6777       ) ;while
   6778     ))
   6779 
   6780 (defun web-mode-fontify-block (reg-beg reg-end)
   6781   (when web-mode-trace
   6782     (message "fontify-block: reg-beg(%S) reg-end(%S) engine(%S) keywords(%S)"
   6783              reg-beg reg-end web-mode-engine (not (null web-mode-engine-font-lock-keywords))))
   6784 
   6785   (let (sub1 sub2 sub3 continue char keywords token-type face beg end (buffer (current-buffer)))
   6786 
   6787     ;; NOTE: required for blocks inside tag attrs
   6788     (remove-list-of-text-properties reg-beg reg-end '(font-lock-face))
   6789 
   6790     (goto-char reg-beg)
   6791 
   6792     (when (null web-mode-engine-font-lock-keywords)
   6793       (setq sub1 (buffer-substring-no-properties
   6794                   reg-beg (+ reg-beg 1))
   6795             sub2 (buffer-substring-no-properties
   6796                   reg-beg (+ reg-beg 2))
   6797             sub3 (buffer-substring-no-properties
   6798                   reg-beg (+ reg-beg (if (>= (point-max) (+ reg-beg 3)) 3 2))))
   6799       )
   6800 
   6801     (cond
   6802 
   6803       ((and (get-text-property reg-beg 'block-beg)
   6804             (eq (get-text-property reg-beg 'block-token) 'comment))
   6805        (put-text-property reg-beg reg-end 'font-lock-face 'web-mode-comment-face)
   6806        ) ;comment block
   6807 
   6808       (web-mode-engine-font-lock-keywords
   6809        (setq keywords web-mode-engine-font-lock-keywords))
   6810 
   6811       ((string= web-mode-engine "django")
   6812        (cond
   6813          ((string= sub2 "{{")
   6814           (setq keywords web-mode-django-expr-font-lock-keywords))
   6815          ((string= sub2 "{%")
   6816           (setq keywords web-mode-django-code-font-lock-keywords))
   6817          ((string= sub1 "#")
   6818           (setq keywords web-mode-django-code-font-lock-keywords))
   6819          )) ;django
   6820 
   6821       ((string= web-mode-engine "mako")
   6822        (cond
   6823          ((member sub3 '("<% " "<%\n" "<%!"))
   6824           (setq keywords web-mode-mako-block-font-lock-keywords))
   6825          ((eq (aref sub2 0) ?\%)
   6826           (setq keywords web-mode-mako-block-font-lock-keywords))
   6827          ((member sub2 '("<%" "</"))
   6828           (setq keywords web-mode-mako-tag-font-lock-keywords))
   6829          ((member sub2 '("${"))
   6830           (setq keywords web-mode-uel-font-lock-keywords))
   6831          )) ;mako
   6832 
   6833       ((string= web-mode-engine "mason")
   6834        ;;(message "%S %S" sub2 sub3)
   6835        (cond
   6836          ((member sub3 '("<% " "<%\n" "<&|"))
   6837           (setq keywords web-mode-mason-code-font-lock-keywords))
   6838          ((eq (aref sub2 0) ?\%)
   6839           (setq keywords web-mode-mason-code-font-lock-keywords))
   6840          ((and (or (string= sub2 "<%") (string= sub3 "</%"))
   6841                (not (member sub3 '("<%c" "<%i" "<%p"))))
   6842           (setq keywords web-mode-mason-block-font-lock-keywords))
   6843          (t
   6844           (setq keywords web-mode-mason-code-font-lock-keywords))
   6845          )) ;mason
   6846 
   6847       ((string= web-mode-engine "jsp")
   6848        (cond
   6849          ((string= sub3 "<%@")
   6850           (setq keywords web-mode-directive-font-lock-keywords))
   6851          ((member sub2 '("${" "#{"))
   6852           (setq keywords web-mode-uel-font-lock-keywords))
   6853          ((string= sub2 "<%")
   6854           (setq keywords web-mode-jsp-font-lock-keywords))
   6855          )) ;jsp
   6856 
   6857       ((string= web-mode-engine "asp")
   6858        (cond
   6859          ((or (string= sub2 "<%")
   6860               (not (string= sub1 "<")))
   6861           (setq keywords web-mode-asp-font-lock-keywords))
   6862          (t
   6863           (setq keywords web-mode-engine-tag-font-lock-keywords))
   6864          )) ;asp
   6865 
   6866       ((string= web-mode-engine "clip")
   6867        (setq keywords web-mode-engine-tag-font-lock-keywords)
   6868        ) ;clip
   6869 
   6870       ((string= web-mode-engine "perl")
   6871        (setq keywords web-mode-engine-tag-font-lock-keywords)
   6872        ) ;perl
   6873 
   6874       ((string= web-mode-engine "aspx")
   6875        (cond
   6876          ((string= sub3 "<%@")
   6877           (setq keywords web-mode-directive-font-lock-keywords))
   6878          ((string= sub3 "<%$")
   6879           (setq keywords web-mode-expression-font-lock-keywords))
   6880          (t
   6881           (setq keywords web-mode-aspx-font-lock-keywords))
   6882          )) ;aspx
   6883 
   6884       ((string= web-mode-engine "freemarker")
   6885        (cond
   6886          ((member sub2 '("${" "#{"))
   6887           (setq keywords web-mode-uel-font-lock-keywords))
   6888          ((or (member sub2 '("<@" "[@" "<#" "[#"))
   6889               (member sub3 '("</@" "[/@" "</#" "[/#")))
   6890           (setq keywords (if (eq ?\[ (aref sub2 0))
   6891                              web-mode-freemarker-square-font-lock-keywords
   6892                              web-mode-freemarker-font-lock-keywords)))
   6893          (t
   6894           (setq keywords web-mode-engine-tag-font-lock-keywords))
   6895          )) ;freemarker
   6896 
   6897       ) ;cond
   6898 
   6899     (when keywords
   6900       (web-mode-fontify-region reg-beg reg-end keywords)
   6901       (setq continue t)
   6902       (setq end reg-beg)
   6903       (while continue
   6904         (if (get-text-property end 'block-token)
   6905             (setq beg end)
   6906             (setq beg (next-single-property-change end 'block-token buffer reg-end)))
   6907         (setq end nil)
   6908         (when beg (setq char (char-after beg)))
   6909         (if (and beg (< beg reg-end))
   6910             (progn
   6911               (setq token-type (get-text-property beg 'block-token))
   6912               (setq face (cond
   6913                            ((eq token-type 'string)  'web-mode-block-string-face)
   6914                            ((eq token-type 'comment) 'web-mode-block-comment-face)
   6915                            ((eq token-type 'symbol)  'web-mode-symbol-face)
   6916                            (t                        'web-mode-block-delimiter-face)))
   6917               (setq end (next-single-property-change beg 'block-token buffer reg-end))
   6918               ;;              (message "end=%S" end)
   6919               (if (and end (<= end reg-end))
   6920                   (progn
   6921                     ;;(message "%S > %S face(%S)" beg end face)
   6922                     (remove-list-of-text-properties beg end '(face))
   6923                     (put-text-property beg end 'font-lock-face face)
   6924                     )
   6925                   (setq continue nil
   6926                         end nil)
   6927                   ) ;if end
   6928               ) ;progn beg
   6929             (setq continue nil
   6930                   end nil)
   6931             ) ;if beg
   6932         (when (and beg end)
   6933           (save-match-data
   6934             (when (and web-mode-enable-heredoc-fontification
   6935                        (eq char ?\<)
   6936                        (> (- end beg) 8)
   6937                        (string-match-p "JS\\|JAVASCRIPT\\|HTM\\|CSS" (buffer-substring-no-properties beg end)))
   6938               (setq keywords
   6939                     (cond
   6940                       ((string-match-p "H" (buffer-substring-no-properties beg (+ beg 8)))
   6941                        web-mode-html-font-lock-keywords)
   6942                       (t
   6943                        web-mode-javascript-font-lock-keywords)
   6944                       ))
   6945               (web-mode-fontify-region beg end keywords)
   6946               )
   6947             ) ;save-match-data
   6948           (when (and web-mode-enable-string-interpolation
   6949                      (member char '(?\" ?\<))
   6950                      (member web-mode-engine '("php" "erb"))
   6951                      (> (- end beg) 4))
   6952             (web-mode-interpolate-block-string beg end)
   6953             ) ;when
   6954           (when (and web-mode-enable-comment-interpolation
   6955                      (eq token-type 'comment)
   6956                      (> (- end beg) 3))
   6957             (web-mode-interpolate-comment beg end t)
   6958             ) ;when
   6959           (when (and web-mode-enable-comment-annotation
   6960                      (eq token-type 'comment)
   6961                      (> (- end beg) 3))
   6962             (web-mode-annotate-comment beg end)
   6963             ) ;when
   6964           (when (and web-mode-enable-sql-detection
   6965                      (eq token-type 'string)
   6966                      (> (- end beg) 6)
   6967                      (web-mode-looking-at-p (concat "\\(.\\|<<<[[:alnum:]]+\\)[ \n]*" web-mode-sql-queries) beg)
   6968                      )
   6969             (web-mode-interpolate-sql-string beg end)
   6970             ) ;when
   6971           ) ;when beg end
   6972         ) ;while continue
   6973       ) ;when keywords
   6974 
   6975     (when (and (member web-mode-engine '("mako"))
   6976                (> (- reg-end reg-beg) 12)
   6977                (eq ?\< (char-after reg-beg)))
   6978       (web-mode-interpolate-block-tag reg-beg reg-end))
   6979 
   6980     (when web-mode-enable-block-face
   6981       (font-lock-append-text-property reg-beg reg-end 'face 'web-mode-block-face))
   6982 
   6983     ))
   6984 
   6985 (defun web-mode-fontify-part (reg-beg reg-end &optional depth)
   6986   (save-excursion
   6987     (let (start continue token-type face pos beg end string-face comment-face content-type)
   6988       ;;(message "fontify-part: reg-beg(%S) reg-end(%S)" reg-beg reg-end)
   6989       (if (member web-mode-content-type web-mode-part-content-types)
   6990           (setq content-type web-mode-content-type)
   6991           (setq content-type (symbol-name (get-text-property reg-beg 'part-side))))
   6992       ;;(message "content-type=%S" content-type)
   6993       (unless depth
   6994         (when (string= content-type "jsx") (setq depth 0))
   6995         )
   6996       (setq string-face 'web-mode-part-string-face
   6997             comment-face 'web-mode-part-comment-face)
   6998       (cond
   6999         ((member content-type '("javascript" "jsx"))
   7000          (setq string-face 'web-mode-javascript-string-face
   7001                comment-face 'web-mode-javascript-comment-face)
   7002          (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
   7003         ((string= content-type "json")
   7004          (setq string-face 'web-mode-json-string-face
   7005                comment-face 'web-mode-json-comment-face)
   7006          (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
   7007         ((string= content-type "css")
   7008          (setq string-face 'web-mode-css-string-face
   7009                comment-face 'web-mode-css-comment-face)
   7010          (web-mode-fontify-css-rules reg-beg reg-end))
   7011         ((string= content-type "sql")
   7012          (web-mode-fontify-region reg-beg reg-end web-mode-sql-font-lock-keywords))
   7013         ((string= content-type "stylus")
   7014          (web-mode-fontify-region reg-beg reg-end web-mode-stylus-font-lock-keywords))
   7015         ((string= content-type "sass")
   7016          (web-mode-fontify-region reg-beg reg-end web-mode-sass-font-lock-keywords))
   7017         ((string= content-type "pug")
   7018          (web-mode-fontify-region reg-beg reg-end web-mode-pug-font-lock-keywords))
   7019         ((string= content-type "markdown")
   7020          (web-mode-fontify-region reg-beg reg-end web-mode-markdown-font-lock-keywords))
   7021         ((string= content-type "ruby")
   7022          (web-mode-fontify-region reg-beg reg-end web-mode-erb-font-lock-keywords))
   7023         ((string= content-type "typescript")
   7024          (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
   7025         ) ;cond
   7026 
   7027       (goto-char reg-beg)
   7028 
   7029       ;;(when (string= content-type "jsx") (web-mode-fontify-tags reg-beg reg-end))
   7030       ;;(setq continue (and pos (< pos reg-end)))
   7031       (setq continue t
   7032             pos reg-beg)
   7033       (while continue
   7034         (if (get-text-property pos 'part-token)
   7035             (setq beg pos)
   7036             (setq beg (next-single-property-change pos 'part-token)))
   7037         (cond
   7038           ((or (null beg) (>= beg reg-end))
   7039            (setq continue nil
   7040                  end nil))
   7041           ((and (eq depth 0) (get-text-property beg 'jsx-depth))
   7042            (setq pos (or (next-single-property-change beg 'jsx-depth) (point-max))))
   7043           (t
   7044            ;;(message "%c" (char-after beg))
   7045            (setq token-type (get-text-property beg 'part-token))
   7046            (setq face (cond
   7047                         ((eq token-type 'string)  string-face)
   7048                         ((eq token-type 'comment) comment-face)
   7049                         ((eq token-type 'context) 'web-mode-json-context-face)
   7050                         ((eq token-type 'key)     'web-mode-json-key-face)
   7051                         (t                        nil)))
   7052            (setq end (or (next-single-property-change beg 'part-token) (point-max))
   7053                  pos end)
   7054            (cond
   7055              ((or (null end) (> end reg-end))
   7056               (setq continue nil
   7057                     end nil))
   7058              (t
   7059               (when face
   7060                 (remove-list-of-text-properties beg end '(face))
   7061                 (put-text-property beg end 'font-lock-face face))
   7062               (cond
   7063                 ((< (- end beg) 6)
   7064                  )
   7065                 ((eq token-type 'string)
   7066                  (cond
   7067                    ((and (eq (char-after beg) ?\`)
   7068                          web-mode-enable-literal-interpolation
   7069                          (member content-type '("javascript" "jsx" "typescript")))
   7070                     (web-mode-interpolate-javascript-literal beg end)
   7071                     )
   7072                    ((and (eq (char-after beg) ?\")
   7073                          web-mode-enable-string-interpolation
   7074                          (member content-type '("javascript" "jsx" "typescript")))
   7075                     (web-mode-interpolate-javascript-string beg end))
   7076                    ) ;cond
   7077                  ) ;case string
   7078                 ((eq token-type 'comment)
   7079                  (when web-mode-enable-comment-interpolation
   7080                    (web-mode-interpolate-comment beg end t))
   7081                  (when web-mode-enable-comment-annotation
   7082                    (web-mode-annotate-comment beg end))
   7083                  )
   7084                 ) ;cond
   7085               ) ;t
   7086              ) ;cond
   7087            ) ;t
   7088           ) ;cond
   7089         ) ;while
   7090 
   7091       (when (and (string= web-mode-content-type "html") web-mode-enable-part-face)
   7092         (font-lock-append-text-property reg-beg reg-end 'face
   7093                                         (cond
   7094                                           ((string= content-type "javascript")
   7095                                            'web-mode-script-face)
   7096                                           ((string= content-type "css")
   7097                                            'web-mode-style-face)
   7098                                           (t
   7099                                            'web-mode-part-face)))
   7100         )
   7101 
   7102       (when (and web-mode-enable-css-colorization (string= content-type "stylus"))
   7103         (goto-char reg-beg)
   7104         (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)
   7105                     (<= (point) reg-end))
   7106           (web-mode-colorize (match-beginning 0) (match-end 0))
   7107           )
   7108         )
   7109 
   7110       (when (and (eq depth 0) (string= content-type "jsx"))
   7111         (let (pair elt-beg elt-end exp-beg exp-end exp-depth)
   7112           (goto-char reg-beg)
   7113           (while (setq pair (web-mode-jsx-element-next reg-end))
   7114             ;;(message "elt-pair=%S" pair)
   7115             (setq elt-beg (car pair)
   7116                   elt-end (cdr pair))
   7117             (remove-list-of-text-properties elt-beg (1+ elt-end) '(face))
   7118             (web-mode-fontify-tags elt-beg elt-end 1)
   7119             (goto-char elt-beg)
   7120             (while (setq pair (web-mode-jsx-expression-next elt-end))
   7121               ;;(message "exp-pair=%S elt-end=%S" pair elt-end)
   7122               (setq exp-beg (car pair)
   7123                     exp-end (cdr pair))
   7124               (when (eq (char-after exp-beg) ?\{)
   7125                 ;;(message "%S : %c %c" exp-beg (char-after (+ exp-beg 1)) (char-after (+ exp-beg 2)))
   7126                 (cond
   7127                   ;;((and (eq (char-after (+ exp-beg 1)) ?\/) (eq (char-after (+ exp-beg 2)) ?\*))
   7128                   ;; (put-text-property exp-beg (1+ exp-end) 'font-lock-face 'web-mode-part-comment-face)
   7129                   ;; )
   7130                   (t
   7131                    (setq exp-depth (get-text-property exp-beg 'jsx-depth))
   7132                    (remove-list-of-text-properties exp-beg exp-end '(font-lock-face))
   7133                    (put-text-property exp-beg (1+ exp-beg) 'font-lock-face 'web-mode-block-delimiter-face)
   7134                    (when (and (eq (get-text-property exp-beg 'tag-attr-beg) 4) (web-mode-looking-at-p "\.\.\." (1+ exp-beg)))
   7135                      (put-text-property exp-beg (+ exp-beg 4) 'font-lock-face 'web-mode-block-delimiter-face))
   7136                    (put-text-property exp-end (1+ exp-end) 'font-lock-face 'web-mode-block-delimiter-face)
   7137                    (web-mode-fontify-tags (1+ exp-beg) exp-end (1+ exp-depth))
   7138                    (web-mode-fontify-part (1+ exp-beg) exp-end exp-depth)
   7139                    (web-mode-fontify-region (1+ exp-beg) exp-end web-mode-javascript-font-lock-keywords)
   7140                    ) ;t
   7141                   ) ;cond
   7142                 ) ;when
   7143               (goto-char (1+ exp-beg))
   7144               ) ;while exp
   7145 
   7146             (when (and elt-beg web-mode-jsx-depth-faces)
   7147               (let (depth-beg depth-end jsx-face)
   7148                 (goto-char elt-beg)
   7149                 (while (setq pair (web-mode-jsx-depth-next reg-end))
   7150                   ;;(message "depth-pair=%S" pair)
   7151                   (setq depth-beg (car pair)
   7152                         depth-end (cdr pair)
   7153                         depth (get-text-property depth-beg 'jsx-depth)
   7154                         jsx-face (elt web-mode-jsx-depth-faces (1- depth)))
   7155                   ;;(message "%S" jsx-face)
   7156                   (font-lock-prepend-text-property depth-beg (1+ depth-end) 'face jsx-face)
   7157                   (goto-char (+ depth-beg 2))
   7158                   )
   7159                 ) ;let
   7160               )
   7161 
   7162             (goto-char (1+ elt-end))
   7163             ) ;while elt
   7164           ) ;let
   7165         ) ;when
   7166 
   7167       ) ;let
   7168     ) ;save-excursion
   7169   )
   7170 
   7171 (defun web-mode-fontify-css-rules (part-beg part-end)
   7172   (save-excursion
   7173     (goto-char part-beg)
   7174     (let (rule (continue t) (i 0) (at-rule nil))
   7175       (while continue
   7176         (setq rule (web-mode-css-rule-next part-end))
   7177         ;;(message "rule=%S" rule)
   7178         (cond
   7179           ((> (setq i (1+ i)) 1000)
   7180            (message "fontify-css-rules ** too much rules **")
   7181            (setq continue nil))
   7182           ((null rule)
   7183            (setq continue nil))
   7184           ((and (setq at-rule (plist-get rule :at-rule))
   7185                 (not (member at-rule '("charset" "font-face" "import" "viewport")))
   7186                 (plist-get rule :dec-end))
   7187            (web-mode-fontify-css-rule (plist-get rule :sel-beg)
   7188                                       (plist-get rule :sel-end)
   7189                                       nil nil)
   7190            (web-mode-fontify-css-rules (plist-get rule :dec-beg)
   7191                                        (plist-get rule :dec-end)))
   7192           (t
   7193            (web-mode-fontify-css-rule (plist-get rule :sel-beg)
   7194                                       (plist-get rule :sel-end)
   7195                                       (plist-get rule :dec-beg)
   7196                                       (plist-get rule :dec-end)))
   7197           ) ;cond
   7198         ) ;while
   7199       ) ;let
   7200     ))
   7201 
   7202 (defun web-mode-fontify-css-rule (sel-beg sel-end dec-beg dec-end)
   7203   (save-excursion
   7204     ;;(let ((end sel-end))
   7205     ;;(message "sel-beg=%S sel-end=%S dec-beg=%S dec-end=%S" sel-beg sel-end dec-beg dec-end)
   7206     (web-mode-fontify-region sel-beg sel-end web-mode-selector-font-lock-keywords)
   7207     (when (and dec-beg dec-end)
   7208       ;;(setq end dec-end)
   7209       (web-mode-fontify-region dec-beg dec-end web-mode-declaration-font-lock-keywords)
   7210       ) ;when
   7211     (when (and dec-beg dec-end)
   7212       (goto-char dec-beg)
   7213       (while (and web-mode-enable-css-colorization
   7214                   (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)
   7215                   ;;(progn (message "%S %S" end (point)) t)
   7216                   (<= (point) dec-end))
   7217         ;;(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)))
   7218         (web-mode-colorize (match-beginning 1) (match-end 1))
   7219         ) ;while
   7220       ) ;when
   7221     ;;) ;let
   7222     ))
   7223 
   7224 (defun web-mode-colorize-foreground (color)
   7225   (let* ((values (x-color-values color))
   7226          (r (car values))
   7227          (g (cadr values))
   7228          (b (car (cdr (cdr values)))))
   7229     (if (> 128.0 (floor (+ (* .3 r) (* .59 g) (* .11 b)) 256))
   7230         "white" "black")))
   7231 
   7232 (defun web-mode-colorize (beg end)
   7233   (let (str plist)
   7234     (setq str (buffer-substring-no-properties beg end))
   7235     ;;(setq str1 (match-string-no-properties 1))
   7236     ;;(message "str=%S" str str1)
   7237     (cond
   7238       ;;(t
   7239       ;; (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))
   7240       ;; )
   7241       ((string= (substring str 0 1) "#")
   7242        (setq plist (list :background str
   7243                          :foreground (web-mode-colorize-foreground str))))
   7244       ((and (>= (length str) 3) (string= (substring str 0 3) "rgb"))
   7245        (setq str (format "#%02X%02X%02X"
   7246                          (string-to-number (match-string-no-properties 2))
   7247                          (string-to-number (match-string-no-properties 3))
   7248                          (string-to-number (match-string-no-properties 4))))
   7249        (setq plist (list :background str
   7250                          :foreground (web-mode-colorize-foreground str))))
   7251       ((string= str "black") (setq plist (list :background "#000000" :foreground (web-mode-colorize-foreground "#000000"))))
   7252       ((string= str "silver") (setq plist (list :background "#c0c0c0" :foreground (web-mode-colorize-foreground "#c0c0c0"))))
   7253       ((string= str "gray") (setq plist (list :background "#808080" :foreground (web-mode-colorize-foreground "#808080"))))
   7254       ((string= str "white") (setq plist (list :background "#ffffff" :foreground (web-mode-colorize-foreground "#ffffff"))))
   7255       ((string= str "maroon") (setq plist (list :background "#800000" :foreground (web-mode-colorize-foreground "#800000"))))
   7256       ((string= str "red") (setq plist (list :background "#ff0000" :foreground (web-mode-colorize-foreground "#ff0000"))))
   7257       ((string= str "purple") (setq plist (list :background "#800080" :foreground (web-mode-colorize-foreground "#800080"))))
   7258       ((string= str "fuchsia") (setq plist (list :background "#ff00ff" :foreground (web-mode-colorize-foreground "#ff00ff"))))
   7259       ((string= str "green") (setq plist (list :background "#008000" :foreground (web-mode-colorize-foreground "#008000"))))
   7260       ((string= str "lime") (setq plist (list :background "#00ff00" :foreground (web-mode-colorize-foreground "#00ff00"))))
   7261       ((string= str "olive") (setq plist (list :background "#808000" :foreground (web-mode-colorize-foreground "#808000"))))
   7262       ((string= str "yellow") (setq plist (list :background "#ffff00" :foreground (web-mode-colorize-foreground "#ffff00"))))
   7263       ((string= str "navy") (setq plist (list :background "#000080" :foreground (web-mode-colorize-foreground "#000080"))))
   7264       ((string= str "blue") (setq plist (list :background "#0000ff" :foreground (web-mode-colorize-foreground "#0000ff"))))
   7265       ((string= str "teal") (setq plist (list :background "#008080" :foreground (web-mode-colorize-foreground "#008080"))))
   7266       ((string= str "aqua") (setq plist (list :background "#00ffff" :foreground (web-mode-colorize-foreground "#00ffff"))))
   7267       ((string= str "orange") (setq plist (list :background "#ffa500" :foreground (web-mode-colorize-foreground "#ffa500"))))
   7268       ((string= str "aliceblue") (setq plist (list :background "#f0f8ff" :foreground (web-mode-colorize-foreground "#f0f8ff"))))
   7269       ((string= str "antiquewhite") (setq plist (list :background "#faebd7" :foreground (web-mode-colorize-foreground "#faebd7"))))
   7270       ((string= str "aquamarine") (setq plist (list :background "#7fffd4" :foreground (web-mode-colorize-foreground "#7fffd4"))))
   7271       ((string= str "azure") (setq plist (list :background "#f0ffff" :foreground (web-mode-colorize-foreground "#f0ffff"))))
   7272       ((string= str "beige") (setq plist (list :background "#f5f5dc" :foreground (web-mode-colorize-foreground "#f5f5dc"))))
   7273       ((string= str "bisque") (setq plist (list :background "#ffe4c4" :foreground (web-mode-colorize-foreground "#ffe4c4"))))
   7274       ((string= str "blanchedalmond") (setq plist (list :background "#ffebcd" :foreground (web-mode-colorize-foreground "#ffebcd"))))
   7275       ((string= str "blueviolet") (setq plist (list :background "#8a2be2" :foreground (web-mode-colorize-foreground "#8a2be2"))))
   7276       ((string= str "brown") (setq plist (list :background "#a52a2a" :foreground (web-mode-colorize-foreground "#a52a2a"))))
   7277       ((string= str "burlywood") (setq plist (list :background "#deb887" :foreground (web-mode-colorize-foreground "#deb887"))))
   7278       ((string= str "cadetblue") (setq plist (list :background "#5f9ea0" :foreground (web-mode-colorize-foreground "#5f9ea0"))))
   7279       ((string= str "chartreuse") (setq plist (list :background "#7fff00" :foreground (web-mode-colorize-foreground "#7fff00"))))
   7280       ((string= str "chocolate") (setq plist (list :background "#d2691e" :foreground (web-mode-colorize-foreground "#d2691e"))))
   7281       ((string= str "coral") (setq plist (list :background "#ff7f50" :foreground (web-mode-colorize-foreground "#ff7f50"))))
   7282       ((string= str "cornflowerblue") (setq plist (list :background "#6495ed" :foreground (web-mode-colorize-foreground "#6495ed"))))
   7283       ((string= str "cornsilk") (setq plist (list :background "#fff8dc" :foreground (web-mode-colorize-foreground "#fff8dc"))))
   7284       ((string= str "crimson") (setq plist (list :background "#dc143c" :foreground (web-mode-colorize-foreground "#dc143c"))))
   7285       ((string= str "cyan") (setq plist (list :background "#00ffff" :foreground (web-mode-colorize-foreground "#00ffff"))))
   7286       ((string= str "darkblue") (setq plist (list :background "#00008b" :foreground (web-mode-colorize-foreground "#00008b"))))
   7287       ((string= str "darkcyan") (setq plist (list :background "#008b8b" :foreground (web-mode-colorize-foreground "#008b8b"))))
   7288       ((string= str "darkgoldenrod") (setq plist (list :background "#b8860b" :foreground (web-mode-colorize-foreground "#b8860b"))))
   7289       ((string= str "darkgray") (setq plist (list :background "#a9a9a9" :foreground (web-mode-colorize-foreground "#a9a9a9"))))
   7290       ((string= str "darkgreen") (setq plist (list :background "#006400" :foreground (web-mode-colorize-foreground "#006400"))))
   7291       ((string= str "darkgrey") (setq plist (list :background "#a9a9a9" :foreground (web-mode-colorize-foreground "#a9a9a9"))))
   7292       ((string= str "darkkhaki") (setq plist (list :background "#bdb76b" :foreground (web-mode-colorize-foreground "#bdb76b"))))
   7293       ((string= str "darkmagenta") (setq plist (list :background "#8b008b" :foreground (web-mode-colorize-foreground "#8b008b"))))
   7294       ((string= str "darkolivegreen") (setq plist (list :background "#556b2f" :foreground (web-mode-colorize-foreground "#556b2f"))))
   7295       ((string= str "darkorange") (setq plist (list :background "#ff8c00" :foreground (web-mode-colorize-foreground "#ff8c00"))))
   7296       ((string= str "darkorchid") (setq plist (list :background "#9932cc" :foreground (web-mode-colorize-foreground "#9932cc"))))
   7297       ((string= str "darkred") (setq plist (list :background "#8b0000" :foreground (web-mode-colorize-foreground "#8b0000"))))
   7298       ((string= str "darksalmon") (setq plist (list :background "#e9967a" :foreground (web-mode-colorize-foreground "#e9967a"))))
   7299       ((string= str "darkseagreen") (setq plist (list :background "#8fbc8f" :foreground (web-mode-colorize-foreground "#8fbc8f"))))
   7300       ((string= str "darkslateblue") (setq plist (list :background "#483d8b" :foreground (web-mode-colorize-foreground "#483d8b"))))
   7301       ((string= str "darkslategray") (setq plist (list :background "#2f4f4f" :foreground (web-mode-colorize-foreground "#2f4f4f"))))
   7302       ((string= str "darkslategrey") (setq plist (list :background "#2f4f4f" :foreground (web-mode-colorize-foreground "#2f4f4f"))))
   7303       ((string= str "darkturquoise") (setq plist (list :background "#00ced1" :foreground (web-mode-colorize-foreground "#00ced1"))))
   7304       ((string= str "darkviolet") (setq plist (list :background "#9400d3" :foreground (web-mode-colorize-foreground "#9400d3"))))
   7305       ((string= str "deeppink") (setq plist (list :background "#ff1493" :foreground (web-mode-colorize-foreground "#ff1493"))))
   7306       ((string= str "deepskyblue") (setq plist (list :background "#00bfff" :foreground (web-mode-colorize-foreground "#00bfff"))))
   7307       ((string= str "dimgray") (setq plist (list :background "#696969" :foreground (web-mode-colorize-foreground "#696969"))))
   7308       ((string= str "dimgrey") (setq plist (list :background "#696969" :foreground (web-mode-colorize-foreground "#696969"))))
   7309       ((string= str "dodgerblue") (setq plist (list :background "#1e90ff" :foreground (web-mode-colorize-foreground "#1e90ff"))))
   7310       ((string= str "firebrick") (setq plist (list :background "#b22222" :foreground (web-mode-colorize-foreground "#b22222"))))
   7311       ((string= str "floralwhite") (setq plist (list :background "#fffaf0" :foreground (web-mode-colorize-foreground "#fffaf0"))))
   7312       ((string= str "forestgreen") (setq plist (list :background "#228b22" :foreground (web-mode-colorize-foreground "#228b22"))))
   7313       ((string= str "gainsboro") (setq plist (list :background "#dcdcdc" :foreground (web-mode-colorize-foreground "#dcdcdc"))))
   7314       ((string= str "ghostwhite") (setq plist (list :background "#f8f8ff" :foreground (web-mode-colorize-foreground "#f8f8ff"))))
   7315       ((string= str "gold") (setq plist (list :background "#ffd700" :foreground (web-mode-colorize-foreground "#ffd700"))))
   7316       ((string= str "goldenrod") (setq plist (list :background "#daa520" :foreground (web-mode-colorize-foreground "#daa520"))))
   7317       ((string= str "greenyellow") (setq plist (list :background "#adff2f" :foreground (web-mode-colorize-foreground "#adff2f"))))
   7318       ((string= str "grey") (setq plist (list :background "#808080" :foreground (web-mode-colorize-foreground "#808080"))))
   7319       ((string= str "honeydew") (setq plist (list :background "#f0fff0" :foreground (web-mode-colorize-foreground "#f0fff0"))))
   7320       ((string= str "hotpink") (setq plist (list :background "#ff69b4" :foreground (web-mode-colorize-foreground "#ff69b4"))))
   7321       ((string= str "indianred") (setq plist (list :background "#cd5c5c" :foreground (web-mode-colorize-foreground "#cd5c5c"))))
   7322       ((string= str "indigo") (setq plist (list :background "#4b0082" :foreground (web-mode-colorize-foreground "#4b0082"))))
   7323       ((string= str "ivory") (setq plist (list :background "#fffff0" :foreground (web-mode-colorize-foreground "#fffff0"))))
   7324       ((string= str "khaki") (setq plist (list :background "#f0e68c" :foreground (web-mode-colorize-foreground "#f0e68c"))))
   7325       ((string= str "lavender") (setq plist (list :background "#e6e6fa" :foreground (web-mode-colorize-foreground "#e6e6fa"))))
   7326       ((string= str "lavenderblush") (setq plist (list :background "#fff0f5" :foreground (web-mode-colorize-foreground "#fff0f5"))))
   7327       ((string= str "lawngreen") (setq plist (list :background "#7cfc00" :foreground (web-mode-colorize-foreground "#7cfc00"))))
   7328       ((string= str "lemonchiffon") (setq plist (list :background "#fffacd" :foreground (web-mode-colorize-foreground "#fffacd"))))
   7329       ((string= str "lightblue") (setq plist (list :background "#add8e6" :foreground (web-mode-colorize-foreground "#add8e6"))))
   7330       ((string= str "lightcoral") (setq plist (list :background "#f08080" :foreground (web-mode-colorize-foreground "#f08080"))))
   7331       ((string= str "lightcyan") (setq plist (list :background "#e0ffff" :foreground (web-mode-colorize-foreground "#e0ffff"))))
   7332       ((string= str "lightgoldenrodyellow") (setq plist (list :background "#fafad2" :foreground (web-mode-colorize-foreground "#fafad2"))))
   7333       ((string= str "lightgray") (setq plist (list :background "#d3d3d3" :foreground (web-mode-colorize-foreground "#d3d3d3"))))
   7334       ((string= str "lightgreen") (setq plist (list :background "#90ee90" :foreground (web-mode-colorize-foreground "#90ee90"))))
   7335       ((string= str "lightgrey") (setq plist (list :background "#d3d3d3" :foreground (web-mode-colorize-foreground "#d3d3d3"))))
   7336       ((string= str "lightpink") (setq plist (list :background "#ffb6c1" :foreground (web-mode-colorize-foreground "#ffb6c1"))))
   7337       ((string= str "lightsalmon") (setq plist (list :background "#ffa07a" :foreground (web-mode-colorize-foreground "#ffa07a"))))
   7338       ((string= str "lightseagreen") (setq plist (list :background "#20b2aa" :foreground (web-mode-colorize-foreground "#20b2aa"))))
   7339       ((string= str "lightskyblue") (setq plist (list :background "#87cefa" :foreground (web-mode-colorize-foreground "#87cefa"))))
   7340       ((string= str "lightslategray") (setq plist (list :background "#778899" :foreground (web-mode-colorize-foreground "#778899"))))
   7341       ((string= str "lightslategrey") (setq plist (list :background "#778899" :foreground (web-mode-colorize-foreground "#778899"))))
   7342       ((string= str "lightsteelblue") (setq plist (list :background "#b0c4de" :foreground (web-mode-colorize-foreground "#b0c4de"))))
   7343       ((string= str "lightyellow") (setq plist (list :background "#ffffe0" :foreground (web-mode-colorize-foreground "#ffffe0"))))
   7344       ((string= str "limegreen") (setq plist (list :background "#32cd32" :foreground (web-mode-colorize-foreground "#32cd32"))))
   7345       ((string= str "linen") (setq plist (list :background "#faf0e6" :foreground (web-mode-colorize-foreground "#faf0e6"))))
   7346       ((string= str "magenta") (setq plist (list :background "#ff00ff" :foreground (web-mode-colorize-foreground "#ff00ff"))))
   7347       ((string= str "mediumaquamarine") (setq plist (list :background "#66cdaa" :foreground (web-mode-colorize-foreground "#66cdaa"))))
   7348       ((string= str "mediumblue") (setq plist (list :background "#0000cd" :foreground (web-mode-colorize-foreground "#0000cd"))))
   7349       ((string= str "mediumorchid") (setq plist (list :background "#ba55d3" :foreground (web-mode-colorize-foreground "#ba55d3"))))
   7350       ((string= str "mediumpurple") (setq plist (list :background "#9370db" :foreground (web-mode-colorize-foreground "#9370db"))))
   7351       ((string= str "mediumseagreen") (setq plist (list :background "#3cb371" :foreground (web-mode-colorize-foreground "#3cb371"))))
   7352       ((string= str "mediumslateblue") (setq plist (list :background "#7b68ee" :foreground (web-mode-colorize-foreground "#7b68ee"))))
   7353       ((string= str "mediumspringgreen") (setq plist (list :background "#00fa9a" :foreground (web-mode-colorize-foreground "#00fa9a"))))
   7354       ((string= str "mediumturquoise") (setq plist (list :background "#48d1cc" :foreground (web-mode-colorize-foreground "#48d1cc"))))
   7355       ((string= str "mediumvioletred") (setq plist (list :background "#c71585" :foreground (web-mode-colorize-foreground "#c71585"))))
   7356       ((string= str "midnightblue") (setq plist (list :background "#191970" :foreground (web-mode-colorize-foreground "#191970"))))
   7357       ((string= str "mintcream") (setq plist (list :background "#f5fffa" :foreground (web-mode-colorize-foreground "#f5fffa"))))
   7358       ((string= str "mistyrose") (setq plist (list :background "#ffe4e1" :foreground (web-mode-colorize-foreground "#ffe4e1"))))
   7359       ((string= str "moccasin") (setq plist (list :background "#ffe4b5" :foreground (web-mode-colorize-foreground "#ffe4b5"))))
   7360       ((string= str "navajowhite") (setq plist (list :background "#ffdead" :foreground (web-mode-colorize-foreground "#ffdead"))))
   7361       ((string= str "oldlace") (setq plist (list :background "#fdf5e6" :foreground (web-mode-colorize-foreground "#fdf5e6"))))
   7362       ((string= str "olivedrab") (setq plist (list :background "#6b8e23" :foreground (web-mode-colorize-foreground "#6b8e23"))))
   7363       ((string= str "orangered") (setq plist (list :background "#ff4500" :foreground (web-mode-colorize-foreground "#ff4500"))))
   7364       ((string= str "orchid") (setq plist (list :background "#da70d6" :foreground (web-mode-colorize-foreground "#da70d6"))))
   7365       ((string= str "palegoldenrod") (setq plist (list :background "#eee8aa" :foreground (web-mode-colorize-foreground "#eee8aa"))))
   7366       ((string= str "palegreen") (setq plist (list :background "#98fb98" :foreground (web-mode-colorize-foreground "#98fb98"))))
   7367       ((string= str "paleturquoise") (setq plist (list :background "#afeeee" :foreground (web-mode-colorize-foreground "#afeeee"))))
   7368       ((string= str "palevioletred") (setq plist (list :background "#db7093" :foreground (web-mode-colorize-foreground "#db7093"))))
   7369       ((string= str "papayawhip") (setq plist (list :background "#ffefd5" :foreground (web-mode-colorize-foreground "#ffefd5"))))
   7370       ((string= str "peachpuff") (setq plist (list :background "#ffdab9" :foreground (web-mode-colorize-foreground "#ffdab9"))))
   7371       ((string= str "peru") (setq plist (list :background "#cd853f" :foreground (web-mode-colorize-foreground "#cd853f"))))
   7372       ((string= str "pink") (setq plist (list :background "#ffc0cb" :foreground (web-mode-colorize-foreground "#ffc0cb"))))
   7373       ((string= str "plum") (setq plist (list :background "#dda0dd" :foreground (web-mode-colorize-foreground "#dda0dd"))))
   7374       ((string= str "powderblue") (setq plist (list :background "#b0e0e6" :foreground (web-mode-colorize-foreground "#b0e0e6"))))
   7375       ((string= str "rosybrown") (setq plist (list :background "#bc8f8f" :foreground (web-mode-colorize-foreground "#bc8f8f"))))
   7376       ((string= str "royalblue") (setq plist (list :background "#4169e1" :foreground (web-mode-colorize-foreground "#4169e1"))))
   7377       ((string= str "saddlebrown") (setq plist (list :background "#8b4513" :foreground (web-mode-colorize-foreground "#8b4513"))))
   7378       ((string= str "salmon") (setq plist (list :background "#fa8072" :foreground (web-mode-colorize-foreground "#fa8072"))))
   7379       ((string= str "sandybrown") (setq plist (list :background "#f4a460" :foreground (web-mode-colorize-foreground "#f4a460"))))
   7380       ((string= str "seagreen") (setq plist (list :background "#2e8b57" :foreground (web-mode-colorize-foreground "#2e8b57"))))
   7381       ((string= str "seashell") (setq plist (list :background "#fff5ee" :foreground (web-mode-colorize-foreground "#fff5ee"))))
   7382       ((string= str "sienna") (setq plist (list :background "#a0522d" :foreground (web-mode-colorize-foreground "#a0522d"))))
   7383       ((string= str "skyblue") (setq plist (list :background "#87ceeb" :foreground (web-mode-colorize-foreground "#87ceeb"))))
   7384       ((string= str "slateblue") (setq plist (list :background "#6a5acd" :foreground (web-mode-colorize-foreground "#6a5acd"))))
   7385       ((string= str "slategray") (setq plist (list :background "#708090" :foreground (web-mode-colorize-foreground "#708090"))))
   7386       ((string= str "slategrey") (setq plist (list :background "#708090" :foreground (web-mode-colorize-foreground "#708090"))))
   7387       ((string= str "snow") (setq plist (list :background "#fffafa" :foreground (web-mode-colorize-foreground "#fffafa"))))
   7388       ((string= str "springgreen") (setq plist (list :background "#00ff7f" :foreground (web-mode-colorize-foreground "#00ff7f"))))
   7389       ((string= str "steelblue") (setq plist (list :background "#4682b4" :foreground (web-mode-colorize-foreground "#4682b4"))))
   7390       ((string= str "tan") (setq plist (list :background "#d2b48c" :foreground (web-mode-colorize-foreground "#d2b48c"))))
   7391       ((string= str "thistle") (setq plist (list :background "#d8bfd8" :foreground (web-mode-colorize-foreground "#d8bfd8"))))
   7392       ((string= str "tomato") (setq plist (list :background "#ff6347" :foreground (web-mode-colorize-foreground "#ff6347"))))
   7393       ((string= str "turquoise") (setq plist (list :background "#40e0d0" :foreground (web-mode-colorize-foreground "#40e0d0"))))
   7394       ((string= str "violet") (setq plist (list :background "#ee82ee" :foreground (web-mode-colorize-foreground "#ee82ee"))))
   7395       ((string= str "wheat") (setq plist (list :background "#f5deb3" :foreground (web-mode-colorize-foreground "#f5deb3"))))
   7396       ((string= str "whitesmoke") (setq plist (list :background "#f5f5f5" :foreground (web-mode-colorize-foreground "#f5f5f5"))))
   7397       ((string= str "yellowgreen") (setq plist (list :background "#9acd32" :foreground (web-mode-colorize-foreground "#9acd32"))))
   7398       ) ;cond
   7399     (put-text-property beg end 'face plist)
   7400     ))
   7401 
   7402 (defun web-mode-interpolate-block-tag (beg end)
   7403   (save-excursion
   7404     (goto-char (+ 4 beg))
   7405     (setq end (1- end))
   7406     (while (re-search-forward "${.*?}" end t)
   7407       (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(face))
   7408       (web-mode-fontify-region (match-beginning 0) (match-end 0)
   7409                                web-mode-uel-font-lock-keywords))
   7410     ))
   7411 
   7412 (defun web-mode-interpolate-javascript-string (beg end)
   7413   (save-excursion
   7414     (goto-char (1+ beg))
   7415     (setq end (1- end))
   7416     (while (re-search-forward "${.*?}" end t)
   7417       (put-text-property (match-beginning 0) (match-end 0)
   7418                          'font-lock-face
   7419                          'web-mode-variable-name-face)
   7420       )
   7421     ))
   7422 
   7423 (defun web-mode-interpolate-javascript-literal (beg end)
   7424   (save-excursion
   7425     (setq end (1- end))
   7426     (goto-char (1+ beg))
   7427     (cond
   7428       ((web-mode-looking-back "\\(css\\|styled[[:alnum:].]+\\|css = \\)" beg)
   7429        (goto-char (1+ beg))
   7430        (while (re-search-forward ".*?:" end t)
   7431          (put-text-property (match-beginning 0) (match-end 0)
   7432                             'font-lock-face
   7433                             'web-mode-interpolate-color1-face)
   7434          )
   7435        ) ;case css
   7436       ((web-mode-looking-back "\\(template\\|html\\|html = \\)" beg)
   7437        (goto-char (1+ beg))
   7438        (while (re-search-forward web-mode-tag-regexp end t)
   7439          (put-text-property (match-beginning 1) (match-end 1)
   7440                             'font-lock-face
   7441                             'web-mode-interpolate-color1-face)
   7442          )
   7443        (goto-char (1+ beg))
   7444        (while (re-search-forward "</?\\|/?>\\| [.@?]?[[:alnum:]]+=" end t)
   7445          (cond
   7446            ((member (char-after (match-beginning 0)) '(?\< ?\/ ?\>))
   7447             (put-text-property (match-beginning 0) (match-end 0)
   7448                                'font-lock-face
   7449                                'web-mode-interpolate-color2-face)
   7450             )
   7451            (t
   7452             (put-text-property (1+ (match-beginning 0)) (1- (match-end 0))
   7453                                'font-lock-face
   7454                                'web-mode-interpolate-color3-face)
   7455             ) ;t
   7456            ) ;cond
   7457          ) ;while
   7458        (goto-char (1+ beg))
   7459        (while (re-search-forward "<\\(script\\|style\\)>\\(.*\\)</\\(script\\|style\\)>" end t)
   7460          (put-text-property (match-beginning 2) (match-end 2)
   7461                             'font-lock-face
   7462                             'web-mode-interpolate-color4-face)
   7463          )
   7464        ) ;case html
   7465       ) ;cond type of literal
   7466     (goto-char (1+ beg))
   7467     (while (re-search-forward "${.*?}" end t)
   7468       (put-text-property (match-beginning 0) (match-end 0)
   7469                          'font-lock-face
   7470                          'web-mode-variable-name-face)
   7471       ) ;while
   7472     ))
   7473 
   7474 ;; todo : parsing plus compliqué: {$obj->values[3]->name}
   7475 (defun web-mode-interpolate-block-string (beg end)
   7476   (save-excursion
   7477     (goto-char (1+ beg))
   7478     (setq end (1- end))
   7479     (cond
   7480       ((string= web-mode-engine "php")
   7481        (while (re-search-forward "$[[:alnum:]_]+\\(->[[:alnum:]_]+\\)*\\|{[ ]*$.+?}" end t)
   7482          ;;        (message "%S > %S" (match-beginning 0) (match-end 0))
   7483          (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(font-lock-face))
   7484          (web-mode-fontify-region (match-beginning 0) (match-end 0)
   7485                                   web-mode-php-var-interpolation-font-lock-keywords)
   7486          ))
   7487       ((string= web-mode-engine "erb")
   7488        (while (re-search-forward "#{.*?}" end t)
   7489          (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(font-lock-face))
   7490          (put-text-property (match-beginning 0) (match-end 0)
   7491                             'font-lock-face 'web-mode-variable-name-face)
   7492          ))
   7493       ) ;cond
   7494     ))
   7495 
   7496 (defun web-mode-interpolate-comment (beg end block-side)
   7497   (save-excursion
   7498     (let ((regexp (concat "\\_<\\(" web-mode-comment-keywords "\\)\\_>")))
   7499       (goto-char beg)
   7500       (while (re-search-forward regexp end t)
   7501         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7502                                          'font-lock-face
   7503                                          'web-mode-comment-keyword-face)
   7504         ) ;while
   7505       )))
   7506 
   7507 (defun web-mode-annotate-comment (beg end)
   7508   (save-excursion
   7509     ;;(message "beg=%S end=%S" beg end)
   7510     (goto-char beg)
   7511     (when (looking-at-p "/\\*\\*")
   7512       (while (re-search-forward "\\(.+\\)" end t)
   7513         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7514                                          'font-lock-face
   7515                                          'web-mode-annotation-face))
   7516       (goto-char beg)
   7517       (while (re-search-forward "[ ]+\\({[^}]+}\\)" end t)
   7518         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7519                                          'font-lock-face
   7520                                          'web-mode-annotation-type-face))
   7521       (goto-char beg)
   7522       (while (re-search-forward "\\(@[[:alnum:]]+\\)" end t)
   7523         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7524                                          'font-lock-face
   7525                                          'web-mode-annotation-tag-face))
   7526       (goto-char beg)
   7527       (while (re-search-forward "}[[:blank:]]+\\([[:graph:]]+\\)" end t)
   7528         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7529                                          'font-lock-face
   7530                                          'web-mode-annotation-value-face))
   7531       (goto-char beg)
   7532       (while (re-search-forward "@see[[:blank:]]+\\([[:graph:]]+\\)" end t)
   7533         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7534                                          'font-lock-face
   7535                                          'web-mode-annotation-value-face))
   7536       (goto-char beg)
   7537       (while (re-search-forward "{\\(@\\(?:link\\|code\\)\\)\\s-+\\([^}\n]+\\)\\(#.+\\)?}" end t)
   7538         (font-lock-prepend-text-property (match-beginning 2) (match-end 2)
   7539                                          'font-lock-face
   7540                                          'web-mode-annotation-value-face))
   7541       (goto-char beg)
   7542       (while (re-search-forward "\\(</?\\)\\([[:alnum:]]+\\)\\s-*\\(/?>\\)" end t)
   7543         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7544                                          'font-lock-face
   7545                                          'web-mode-annotation-html-face)
   7546         (font-lock-prepend-text-property (match-beginning 2) (match-end 2)
   7547                                          'font-lock-face
   7548                                          'web-mode-annotation-html-face)
   7549         (font-lock-prepend-text-property (match-beginning 3) (match-end 3)
   7550                                          'font-lock-face
   7551                                          'web-mode-annotation-html-face))
   7552       ) ;when
   7553     ))
   7554 
   7555 (defun web-mode-interpolate-sql-string (beg end)
   7556   (save-excursion
   7557     (let ((case-fold-search t)
   7558           (regexp (concat "\\_<\\(" web-mode-sql-keywords "\\)\\_>")))
   7559       (goto-char beg)
   7560       (while (re-search-forward regexp end t)
   7561         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7562                                          'font-lock-face
   7563                                          'web-mode-sql-keyword-face)
   7564         ) ;while
   7565       )))
   7566 
   7567 ;;---- EFFECTS -----------------------------------------------------------------
   7568 
   7569 (defun web-mode-fill-paragraph (&optional justify)
   7570   (save-excursion
   7571     (let ((pos (point))
   7572           prop pair beg end delim-beg delim-end chunk fill-col)
   7573       (cond
   7574         ((or (eq (get-text-property pos 'part-token) 'comment)
   7575              (eq (get-text-property pos 'block-token) 'comment))
   7576          (setq prop
   7577                (if (get-text-property pos 'part-token) 'part-token 'block-token))
   7578          (setq pair (web-mode-property-boundaries prop pos))
   7579          (when (and pair (> (- (cdr pair) (car pair)) 6))
   7580            (setq fill-coll (if (< fill-column 10) 70 fill-column))
   7581            (setq beg (car pair)
   7582                  end (cdr pair))
   7583            (goto-char beg)
   7584            (setq chunk (buffer-substring-no-properties beg (+ beg 2)))
   7585            (cond
   7586              ((string= chunk "//")
   7587               (setq delim-beg "//"
   7588                     delim-end "EOL"))
   7589              ((string= chunk "/*")
   7590               (setq delim-beg "/*"
   7591                     delim-end "*/"))
   7592              ((string= chunk "{#")
   7593               (setq delim-beg "{#"
   7594                     delim-end "#}"))
   7595              ((string= chunk "<!")
   7596               (setq delim-beg "<!--"
   7597                     delim-end "-->"))
   7598              )
   7599            )
   7600          ) ;comment - case
   7601         ((web-mode-is-content)
   7602          (setq pair (web-mode-content-boundaries pos))
   7603          (setq beg (car pair)
   7604                end (cdr pair))
   7605          )
   7606         ) ;cond
   7607       ;;(message "beg(%S) end(%S)" beg end)
   7608       (when (and beg end)
   7609         (fill-region beg end))
   7610       t)))
   7611 
   7612 (defun web-mode-engine-syntax-check ()
   7613   (interactive)
   7614   (let ((proc nil) (errors nil)
   7615         (file (concat temporary-file-directory "emacs-web-mode-tmp")))
   7616     (write-region (point-min) (point-max) file)
   7617     (cond
   7618       ;; ((null (buffer-file-name))
   7619       ;; )
   7620       ((string= web-mode-engine "php")
   7621        (setq proc (start-process "php-proc" nil "php" "-l" file))
   7622        (set-process-filter
   7623         proc
   7624         (lambda (proc output)
   7625           (cond
   7626             ((string-match-p "No syntax errors" output)
   7627              (message "No syntax errors")
   7628              )
   7629             (t
   7630              ;; (setq output (replace-regexp-in-string temporary-file-directory "" output))
   7631              ;; (message output)
   7632              (message "Syntax error")
   7633              (setq errors t))
   7634             ) ;cond
   7635           ;; (delete-file file)
   7636           ) ;lambda
   7637         )
   7638        ) ;php
   7639       (t
   7640        (message "no syntax checker found")
   7641        ) ;t
   7642       ) ;cond
   7643     errors))
   7644 
   7645 (defun web-mode-jshint ()
   7646   "Run JSHint on all the JavaScript parts."
   7647   (interactive)
   7648   (let (proc lines)
   7649     (when (buffer-file-name)
   7650       (setq proc (start-process
   7651                   "jshint-proc"
   7652                   nil
   7653                   (or (executable-find "jshint") "/usr/local/bin/jshint")
   7654                   "--extract=auto"
   7655                   (buffer-file-name)))
   7656       (setq web-mode-jshint-errors 0)
   7657       (set-process-filter proc
   7658                           (lambda (proc output)
   7659                             (let ((offset 0) overlay pos (old 0) msg)
   7660                               (remove-overlays (point-min) (point-max) 'font-lock-face 'web-mode-error-face)
   7661                               (while (string-match
   7662                                       "line \\([[:digit:]]+\\), col \\([[:digit:]]+\\), \\(.+\\)\\.$"
   7663                                       output offset)
   7664                                 (setq web-mode-jshint-errors (1+ web-mode-jshint-errors))
   7665                                 (setq offset (match-end 0))
   7666                                 (setq pos (web-mode-coord-position
   7667                                            (match-string-no-properties 1 output)
   7668                                            (match-string-no-properties 2 output)))
   7669                                 (when (get-text-property pos 'tag-beg)
   7670                                   (setq pos (1- pos)))
   7671                                 (when (not (= pos old))
   7672                                   (setq old pos)
   7673                                   (setq overlay (make-overlay pos (1+ pos)))
   7674                                   (overlay-put overlay 'font-lock-face 'web-mode-error-face)
   7675                                   )
   7676                                 (setq msg (or (overlay-get overlay 'help-echo)
   7677                                               (concat "line="
   7678                                                       (match-string-no-properties 1 output)
   7679                                                       " column="
   7680                                                       (match-string-no-properties 2 output)
   7681                                                       )))
   7682                                 (overlay-put overlay 'help-echo
   7683                                              (concat msg " ## " (match-string-no-properties 3 output)))
   7684                                 ) ;while
   7685                               ))
   7686                           )
   7687       ) ;when
   7688     ))
   7689 
   7690 (defun web-mode-dom-errors-show ()
   7691   "Show unclosed tags."
   7692   (interactive)
   7693   (let (beg end tag pos l n tags i cont cell overlay overlays first
   7694             (ori (point))
   7695             (errors 0)
   7696             (continue t)
   7697             )
   7698     (setq overlays (overlays-in (point-min) (point-max)))
   7699     (when overlays
   7700       (dolist (overlay overlays)
   7701         (when (eq (overlay-get overlay 'face) 'web-mode-warning-face)
   7702           (delete-overlay overlay)
   7703           )
   7704         )
   7705       )
   7706     (goto-char (point-min))
   7707     (when (not (or (get-text-property (point) 'tag-beg)
   7708                    (web-mode-tag-next)))
   7709       (setq continue nil))
   7710     (while continue
   7711       (setq pos (point))
   7712       (setq tag (get-text-property pos 'tag-name))
   7713       (cond
   7714         ((eq (get-text-property (point) 'tag-type) 'start)
   7715          (setq tags (push (list tag pos) tags))
   7716          ;;        (message "(%S) opening %S" pos tag)
   7717          )
   7718         ((eq (get-text-property (point) 'tag-type) 'end)
   7719          (setq i 0
   7720                l (length tags)
   7721                cont t)
   7722          (while (and (< i l) cont)
   7723            (setq cell (nth i tags))
   7724            ;;          (message "cell=%S" cell)
   7725            (setq i (1+ i))
   7726            (cond
   7727              ((string= tag (nth 0 cell))
   7728               (setq cont nil)
   7729               )
   7730              (t
   7731               (setq errors (1+ errors))
   7732               (setq beg (nth 1 cell))
   7733               (setq end (web-mode-tag-end-position beg))
   7734               (unless first
   7735                 (setq first beg))
   7736               (setq overlay (make-overlay beg (1+ end)))
   7737               (overlay-put overlay 'font-lock-face 'web-mode-warning-face)
   7738               ;;            (message "invalid <%S> at %S" (nth 0 cell) (nth 1 cell))
   7739               )
   7740              ) ;cond
   7741            ) ;while
   7742 
   7743          (dotimes (i i)
   7744            (setq tags (cdr tags)))
   7745 
   7746          )
   7747         ) ;cond
   7748       (when (not (web-mode-tag-next))
   7749         (setq continue nil))
   7750       ) ;while
   7751     (message "%S error(s) detected" errors)
   7752     (if (< errors 1)
   7753         (goto-char ori)
   7754         (goto-char first)
   7755         (recenter))
   7756     ;;    (message "%S" tags)
   7757     ))
   7758 
   7759 (defun web-mode-fontify-elements (beg end)
   7760   (save-excursion
   7761     (goto-char beg)
   7762     (let ((continue (or (get-text-property (point) 'tag-beg) (web-mode-tag-next)))
   7763           (i 0) (ctx nil) (face nil))
   7764       (while continue
   7765         (cond
   7766           ((> (setq i (1+ i)) 1000)
   7767            (message "fontify-elements ** too much tags **")
   7768            (setq continue nil))
   7769           ((> (point) end)
   7770            (setq continue nil))
   7771           ((not (get-text-property (point) 'tag-beg))
   7772            (setq continue nil))
   7773           ((eq (get-text-property (point) 'tag-type) 'start)
   7774            (when (and (setq ctx (web-mode-element-boundaries (point)))
   7775                       (<= (car (cdr ctx)) end)
   7776                       (setq face (cdr (assoc (get-text-property (point) 'tag-name) web-mode-element-content-faces))))
   7777              (font-lock-prepend-text-property (1+ (cdr (car ctx))) (car (cdr ctx))
   7778                                               'font-lock-face face))
   7779            )
   7780           ) ;cond
   7781         (when (not (web-mode-tag-next))
   7782           (setq continue nil))
   7783         ) ;while
   7784       )))
   7785 
   7786 (defun web-mode-enable (feature)
   7787   "Enable one feature."
   7788   (interactive
   7789    (list (completing-read
   7790           "Feature: "
   7791           (let (features)
   7792             (dolist (elt web-mode-features)
   7793               (setq features (append features (list (car elt)))))
   7794             features))))
   7795   (when (and (or (not feature) (< (length feature) 1)) web-mode-last-enabled-feature)
   7796     (setq feature web-mode-last-enabled-feature))
   7797   (when feature
   7798     (setq web-mode-last-enabled-feature feature)
   7799     (setq feature (cdr (assoc feature web-mode-features)))
   7800     (cond
   7801       ((eq feature 'web-mode-enable-current-column-highlight)
   7802        (web-mode-column-show))
   7803       ((eq feature 'web-mode-enable-current-element-highlight)
   7804        (when (not web-mode-enable-current-element-highlight)
   7805          (web-mode-toggle-current-element-highlight))
   7806        )
   7807       ((eq feature 'web-mode-enable-whitespace-fontification)
   7808        (web-mode-whitespaces-on))
   7809       (t
   7810        (set feature t)
   7811        (web-mode-buffer-fontify))
   7812       )
   7813     ) ;when
   7814   )
   7815 
   7816 (defun web-mode-disable (feature)
   7817   "Disable one feature."
   7818   (interactive
   7819    (list (completing-read
   7820           "Feature: "
   7821           (let (features)
   7822             (dolist (elt web-mode-features)
   7823               (setq features (append features (list (car elt)))))
   7824             features))))
   7825   (when (and (or (not feature) (< (length feature) 1)) web-mode-last-enabled-feature)
   7826     (setq feature web-mode-last-enabled-feature))
   7827   (when feature
   7828     (setq feature (cdr (assoc feature web-mode-features)))
   7829     (cond
   7830       ((eq feature 'web-mode-enable-current-column-highlight)
   7831        (web-mode-column-hide))
   7832       ((eq feature 'web-mode-enable-current-element-highlight)
   7833        (when web-mode-enable-current-element-highlight
   7834          (web-mode-toggle-current-element-highlight))
   7835        )
   7836       ((eq feature 'web-mode-enable-whitespace-fontification)
   7837        (web-mode-whitespaces-off))
   7838       (t
   7839        (set feature nil)
   7840        (web-mode-buffer-fontify))
   7841       )
   7842     ) ;when
   7843   )
   7844 
   7845 (defun web-mode-toggle-current-element-highlight ()
   7846   "Toggle highlighting of the current html element."
   7847   (interactive)
   7848   (if web-mode-enable-current-element-highlight
   7849       (progn
   7850         (web-mode-delete-tag-overlays)
   7851         (setq web-mode-enable-current-element-highlight nil))
   7852       (setq web-mode-enable-current-element-highlight t)
   7853       ))
   7854 
   7855 (defun web-mode-make-tag-overlays ()
   7856   (unless web-mode-overlay-tag-start
   7857     (setq web-mode-overlay-tag-start (make-overlay 1 1)
   7858           web-mode-overlay-tag-end (make-overlay 1 1))
   7859     (overlay-put web-mode-overlay-tag-start
   7860                  'font-lock-face
   7861                  'web-mode-current-element-highlight-face)
   7862     (overlay-put web-mode-overlay-tag-end
   7863                  'font-lock-face
   7864                  'web-mode-current-element-highlight-face)))
   7865 
   7866 (defun web-mode-delete-tag-overlays ()
   7867   (when web-mode-overlay-tag-start
   7868     (delete-overlay web-mode-overlay-tag-start)
   7869     (delete-overlay web-mode-overlay-tag-end)))
   7870 
   7871 (defun web-mode-column-overlay-factory (index)
   7872   (let (overlay)
   7873     (when (null web-mode-column-overlays)
   7874       (dotimes (i 100)
   7875         (setq overlay (make-overlay 1 1))
   7876         (overlay-put overlay 'font-lock-face 'web-mode-current-column-highlight-face)
   7877         (setq web-mode-column-overlays (append web-mode-column-overlays (list overlay)))
   7878         )
   7879       ) ;when
   7880     (setq overlay (nth index web-mode-column-overlays))
   7881     (when (null overlay)
   7882       (setq overlay (make-overlay 1 1))
   7883       (overlay-put overlay 'font-lock-face 'web-mode-current-column-highlight-face)
   7884       (setq web-mode-column-overlays (append web-mode-column-overlays (list overlay)))
   7885       ) ;when
   7886     overlay))
   7887 
   7888 (defun web-mode-column-hide ()
   7889   (setq web-mode-enable-current-column-highlight nil)
   7890   (remove-overlays (point-min) (point-max)
   7891                    'font-lock-face
   7892                    'web-mode-current-column-highlight-face))
   7893 
   7894 (defun web-mode-column-show ()
   7895   (let ((index 0) overlay diff column line-to line-from)
   7896     (web-mode-column-hide)
   7897     (setq web-mode-enable-current-column-highlight t)
   7898     (save-excursion
   7899       (back-to-indentation)
   7900       (setq column (current-column)
   7901             line-to (web-mode-line-number))
   7902       (when (and (get-text-property (point) 'tag-beg)
   7903                  (member (get-text-property (point) 'tag-type) '(start end))
   7904                  (web-mode-tag-match)
   7905                  (setq line-from (web-mode-line-number))
   7906                  (not (= line-from line-to)))
   7907         (when (> line-from line-to)
   7908           (let (tmp)
   7909             (setq tmp line-from)
   7910             (setq line-from line-to)
   7911             (setq line-to tmp))
   7912           ) ;when
   7913         ;;(message "column(%S) line-from(%S) line-to(%S)" column line-from line-to)
   7914         (goto-char (point-min))
   7915         (when (> line-from 1)
   7916           (forward-line (1- line-from)))
   7917         (while (<= line-from line-to)
   7918           (setq overlay (web-mode-column-overlay-factory index))
   7919           (setq diff (- (line-end-position) (point)))
   7920           (cond
   7921             ((or (and (= column 0) (= diff 0))
   7922                  (> column diff))
   7923              (end-of-line)
   7924              (move-overlay overlay (point) (point))
   7925              (overlay-put overlay
   7926                           'after-string
   7927                           (concat
   7928                            (if (> column diff) (make-string (- column diff) ?\s) "")
   7929                            (propertize " "
   7930                                        'font-lock-face
   7931                                        'web-mode-current-column-highlight-face)
   7932                            ) ;concat
   7933                           )
   7934              )
   7935             (t
   7936              (move-to-column column)
   7937              (overlay-put overlay 'after-string nil)
   7938              (move-overlay overlay (point) (1+ (point)))
   7939              )
   7940             ) ;cond
   7941           (setq line-from (1+ line-from))
   7942           (forward-line)
   7943           (setq index (1+ index))
   7944           ) ;while
   7945         ) ;when
   7946       ) ;save-excursion
   7947     ) ;let
   7948   )
   7949 
   7950 (defun web-mode-highlight-current-element ()
   7951   (let ((ctx (web-mode-element-boundaries)) len)
   7952     (cond
   7953       ((null ctx)
   7954        (web-mode-delete-tag-overlays))
   7955       ((eq (get-text-property (caar ctx) 'tag-type) 'void) ;; #1046
   7956        (web-mode-make-tag-overlays)
   7957        (setq len (length (get-text-property (caar ctx) 'tag-name)))
   7958        (move-overlay web-mode-overlay-tag-start (+ (caar ctx) 1) (+ (caar ctx) 1 len))
   7959        )
   7960       (t
   7961        (web-mode-make-tag-overlays)
   7962        (setq len (length (get-text-property (caar ctx) 'tag-name)))
   7963        (move-overlay web-mode-overlay-tag-start (+ (caar ctx) 1) (+ (caar ctx) 1 len))
   7964        (move-overlay web-mode-overlay-tag-end (+ (cadr ctx) 2) (+ (cadr ctx) 2 len))
   7965        ) ;t
   7966       ) ;cond
   7967     ))
   7968 
   7969 (defun web-mode-fontify-whitespaces (beg end)
   7970   (save-excursion
   7971     (goto-char beg)
   7972     (while (re-search-forward web-mode-whitespaces-regexp end t)
   7973       (add-text-properties (match-beginning 0) (match-end 0)
   7974                            '(face web-mode-whitespace-face))
   7975       ) ;while
   7976     ))
   7977 
   7978 (defun web-mode-whitespaces-show ()
   7979   "Toggle whitespaces."
   7980   (interactive)
   7981   (if web-mode-enable-whitespace-fontification
   7982       (web-mode-whitespaces-off)
   7983       (web-mode-whitespaces-on)))
   7984 
   7985 (defun web-mode-whitespaces-on ()
   7986   "Show whitespaces."
   7987   (interactive)
   7988   (when web-mode-display-table
   7989     (setq buffer-display-table web-mode-display-table))
   7990   (setq web-mode-enable-whitespace-fontification t))
   7991 
   7992 (defun web-mode-whitespaces-off ()
   7993   (setq buffer-display-table nil)
   7994   (setq web-mode-enable-whitespace-fontification nil))
   7995 
   7996 (defun web-mode-use-tabs ()
   7997   "Tweaks vars to be compatible with TAB indentation."
   7998   (let (offset)
   7999     (setq web-mode-block-padding 0)
   8000     (setq web-mode-script-padding 0)
   8001     (setq web-mode-style-padding 0)
   8002     (setq offset
   8003           (cond
   8004             ((and (boundp 'tab-width) tab-width) tab-width)
   8005             ((and (boundp 'standard-indent) standard-indent) standard-indent)
   8006             (t 4)))
   8007     ;;    (message "offset(%S)" offset)
   8008     (setq web-mode-attr-indent-offset offset)
   8009     (setq web-mode-code-indent-offset offset)
   8010     (setq web-mode-css-indent-offset offset)
   8011     (setq web-mode-markup-indent-offset offset)
   8012     (setq web-mode-sql-indent-offset offset)
   8013     (add-to-list 'web-mode-indentation-params '("lineup-args" . nil))
   8014     (add-to-list 'web-mode-indentation-params '("lineup-calls" . nil))
   8015     (add-to-list 'web-mode-indentation-params '("lineup-concats" . nil))
   8016     (add-to-list 'web-mode-indentation-params '("lineup-ternary" . nil))
   8017     ))
   8018 
   8019 (defun web-mode-element-children-fold-or-unfold (&optional pos)
   8020   "Fold/Unfold all the children of the current html element."
   8021   (interactive)
   8022   (unless pos (setq pos (point)))
   8023   (save-excursion
   8024     (dolist (child (reverse (web-mode-element-children pos)))
   8025       (goto-char child)
   8026       (web-mode-fold-or-unfold))
   8027     ))
   8028 
   8029 (defun web-mode-fold-or-unfold (&optional pos)
   8030   "Toggle folding on an html element or a control block."
   8031   (interactive)
   8032   (web-mode-scan)
   8033   (web-mode-with-silent-modifications
   8034    (save-excursion
   8035      (if pos (goto-char pos))
   8036      (let (beg-inside beg-outside end-inside end-outside overlay overlays regexp)
   8037        (when (looking-back "^[\t ]*" (point-min))
   8038          (back-to-indentation))
   8039        (setq overlays (overlays-at (point)))
   8040        (dolist (elt overlays)
   8041          (when (and (not overlay)
   8042                     (eq (overlay-get elt 'font-lock-face) 'web-mode-folded-face))
   8043            (setq overlay elt)))
   8044        (cond
   8045          ;; *** unfolding
   8046          (overlay
   8047           (setq beg-inside (overlay-start overlay)
   8048                 end-inside (overlay-end overlay))
   8049           (remove-overlays beg-inside end-inside)
   8050           (put-text-property beg-inside end-inside 'invisible nil)
   8051           )
   8052          ;; *** block folding
   8053          ((and (get-text-property (point) 'block-side)
   8054                (cdr (web-mode-block-is-control (point))))
   8055           (setq beg-outside (web-mode-block-beginning-position (point)))
   8056           (setq beg-inside (1+ (web-mode-block-end-position (point))))
   8057           (when (web-mode-block-match)
   8058             (setq end-inside (point))
   8059             (setq end-outside (1+ (web-mode-block-end-position (point)))))
   8060           )
   8061          ;; *** html comment folding
   8062          ((eq (get-text-property (point) 'tag-type) 'comment)
   8063           (setq beg-outside (web-mode-tag-beginning-position))
   8064           (setq beg-inside (+ beg-outside 4))
   8065           (setq end-outside (web-mode-tag-end-position))
   8066           (setq end-inside (- end-outside 3))
   8067           )
   8068          ;; *** tag folding
   8069          ((or (member (get-text-property (point) 'tag-type) '(start end))
   8070               (web-mode-element-parent))
   8071           (when (not (web-mode-element-is-collapsed (point)))
   8072             (web-mode-tag-beginning)
   8073             (when (eq (get-text-property (point) 'tag-type) 'end)
   8074               (web-mode-tag-match))
   8075             (setq beg-outside (point))
   8076             (web-mode-tag-end)
   8077             (setq beg-inside (point))
   8078             (goto-char beg-outside)
   8079             (when (web-mode-tag-match)
   8080               (setq end-inside (point))
   8081               (web-mode-tag-end)
   8082               (setq end-outside (point)))
   8083             )
   8084           )
   8085          ) ;cond
   8086        (when (and beg-inside beg-outside end-inside end-outside)
   8087          (setq overlay (make-overlay beg-outside end-outside))
   8088          (overlay-put overlay 'font-lock-face 'web-mode-folded-face)
   8089          (put-text-property beg-inside end-inside 'invisible t))
   8090        ))))
   8091 
   8092 ;;---- TRANSFORMATION ----------------------------------------------------------
   8093 
   8094 (defun web-mode-buffer-change-tag-case (&optional type)
   8095   "Change html tag case."
   8096   (interactive)
   8097   (save-excursion
   8098     (goto-char (point-min))
   8099     (let ((continue t) f)
   8100       (setq f (if (member type '("upper" "uppercase" "upper-case")) 'uppercase 'downcase))
   8101       (when (and (not (get-text-property (point) 'tag-beg))
   8102                  (not (web-mode-tag-next)))
   8103         (setq continue nil))
   8104       (while continue
   8105         (skip-chars-forward "<!/")
   8106         (if (looking-at "\\([[:alnum:]:-]+\\)")
   8107             (replace-match (funcall f (match-string 0)) t))
   8108         ;;        (message "tag: %S (%S)"
   8109         ;;                 (get-text-property (point) 'tag-name)
   8110         ;;                 (point))
   8111         (unless (web-mode-tag-next)
   8112           (setq continue nil))
   8113         ) ;while
   8114       )))
   8115 
   8116 (defun web-mode-buffer-change-attr-case (&optional type)
   8117   "Change case of html attribute names."
   8118   (interactive)
   8119   (unless type (setq type "downcase"))
   8120   (save-excursion
   8121     (goto-char (point-min))
   8122     (let ((continue t)
   8123           (fun (if (eq (aref (downcase type) 0) ?u) 'uppercase 'downcase)))
   8124       (while continue
   8125         (cond
   8126           ((not (web-mode-attribute-next))
   8127            (setq continue nil))
   8128           ((looking-at "\\([[:alnum:]-]+\\)")
   8129            (replace-match (funcall fun (match-string 0)) t)
   8130            )
   8131           ) ;cond
   8132         ) ;while
   8133       )))
   8134 
   8135 ;; tag-case=lower|upper-case , attr-case=lower|upper-case
   8136 ;; special-chars=unicode|html-entities
   8137 ;; smart-apostrophes=bool , smart-quotes=bool , indentation=bool
   8138 (defun web-mode-dom-normalize ()
   8139   "Normalize buffer"
   8140   (interactive)
   8141   (save-excursion
   8142     (let ((rules web-mode-normalization-rules) elt)
   8143       (when (setq elt (cdr (assoc "tag-case" rules)))
   8144         (web-mode-buffer-change-tag-case elt))
   8145       (when (setq elt (cdr (assoc "attr-case" rules)))
   8146         (web-mode-buffer-change-attr-case elt))
   8147       (when (setq elt (cdr (assoc "css-indentation" rules)))
   8148         (web-mode-css-indent))
   8149       (when (setq elt (cdr (assoc "smart-apostrophes" rules)))
   8150         (web-mode-dom-apostrophes-replace))
   8151       (when (setq elt (cdr (assoc "smart-quotes" rules)))
   8152         (web-mode-dom-quotes-replace))
   8153       (when (setq elt (cdr (assoc "special-chars" rules)))
   8154         (if (string= elt "entities")
   8155             (web-mode-dom-entities-encode)
   8156             (web-mode-dom-entities-replace)))
   8157       (when (setq elt (cdr (assoc "whitespaces" rules)))
   8158         (goto-char (point-min))
   8159         (while (not (eobp))
   8160           (forward-line)
   8161           (delete-blank-lines))
   8162         (delete-trailing-whitespace)
   8163         (untabify (point-min) (point-max)))
   8164       (when (setq elt (cdr (assoc "indentation" rules)))
   8165         (web-mode-buffer-indent))
   8166       )))
   8167 
   8168 (defun web-mode-dom-apostrophes-replace ()
   8169   "Replace char(') with char(’) in the innerText of html elements."
   8170   (interactive)
   8171   (save-excursion
   8172     (let ((min (point-min)) (max (point-max)))
   8173       (when mark-active
   8174         (setq min (region-beginning)
   8175               max (region-end))
   8176         (deactivate-mark))
   8177       (goto-char min)
   8178       (while (web-mode-content-rsf "\\([[:alpha:]]\\)'\\([[:alpha:]]\\)" max)
   8179         (replace-match "\\1’\\2"))
   8180       )))
   8181 
   8182 (defun web-mode-dom-entities-encode ()
   8183   (save-excursion
   8184     (let (regexp ms elt (min (point-min)) (max (point-max)))
   8185       (when mark-active
   8186         (setq min (region-beginning)
   8187               max (region-end))
   8188         (deactivate-mark))
   8189       (goto-char min)
   8190       (setq regexp "[")
   8191       (dolist (pair web-mode-html-entities)
   8192         (setq regexp (concat regexp (char-to-string (cdr pair))))
   8193         )
   8194       (setq regexp (concat regexp "]"))
   8195       (while (web-mode-content-rsf regexp max)
   8196         (setq elt (match-string-no-properties 0))
   8197         (setq elt (aref elt 0))
   8198         (setq elt (car (rassoc elt web-mode-html-entities)))
   8199         (replace-match (concat "&" elt ";"))
   8200         (setq max (+ max (length elt) 1))
   8201         ) ;while
   8202       )))
   8203 
   8204 (defun web-mode-dom-entities-replace ()
   8205   "Replace html entities (e.g. &eacute; &#233; or &#x00E9; become é)"
   8206   (interactive)
   8207   (save-excursion
   8208     (let (ms pair elt (min (point-min)) (max (point-max)))
   8209       (when mark-active
   8210         (setq min (region-beginning)
   8211               max (region-end))
   8212         (deactivate-mark))
   8213       (goto-char min)
   8214       (while (web-mode-content-rsf "&\\([#]?[[:alnum:]]\\{2,8\\}\\);" max)
   8215         (setq elt nil)
   8216         (setq ms (match-string-no-properties 1))
   8217         (cond
   8218           ((not (eq (aref ms 0) ?\#))
   8219            (and (setq pair (assoc ms web-mode-html-entities))
   8220                 (setq elt (cdr pair))
   8221                 (setq elt (char-to-string elt))))
   8222           ((eq (aref ms 1) ?x)
   8223            (setq elt (substring ms 2))
   8224            (setq elt (downcase elt))
   8225            (setq elt (string-to-number elt 16))
   8226            (setq elt (char-to-string elt)))
   8227           (t
   8228            (setq elt (substring ms 1))
   8229            (setq elt (char-to-string (string-to-number elt))))
   8230           ) ;cond
   8231         (when elt (replace-match elt))
   8232         ) ;while
   8233       )))
   8234 
   8235 (defun web-mode-dom-xml-replace ()
   8236   "Replace &, > and < in html content."
   8237   (interactive)
   8238   (save-excursion
   8239     (let (expr (min (point-min)) (max (point-max)))
   8240       (when mark-active
   8241         (setq min (region-beginning)
   8242               max (region-end))
   8243         (deactivate-mark))
   8244       (goto-char min)
   8245       (while (web-mode-content-rsf "[&<>]" max)
   8246         (replace-match (cdr (assq (char-before) web-mode-xml-chars)) t t))
   8247       )))
   8248 
   8249 (defun web-mode-dom-quotes-replace ()
   8250   "Replace dumb quotes."
   8251   (interactive)
   8252   (save-excursion
   8253     (let (expr (min (point-min)) (max (point-max)))
   8254       (when mark-active
   8255         (setq min (region-beginning)
   8256               max (region-end))
   8257         (deactivate-mark))
   8258       (goto-char min)
   8259       (setq expr (concat (car web-mode-smart-quotes) "\\2" (cdr web-mode-smart-quotes)))
   8260       (while (web-mode-content-rsf "\\(\"\\)\\(.\\{1,200\\}\\)\\(\"\\)" max)
   8261         (replace-match expr)
   8262         ) ;while
   8263       )))
   8264 
   8265 ;;---- INDENTATION -------------------------------------------------------------
   8266 
   8267 ;; todo : passer de règle en règle et mettre un \n à la fin
   8268 (defun web-mode-css-indent ()
   8269   (save-excursion
   8270     (goto-char (point-min))
   8271     (let ((continue t) rule part-end)
   8272       (while continue
   8273         (cond
   8274           ((not (web-mode-part-next))
   8275            (setq continue nil))
   8276           ((eq (get-text-property (point) 'part-side) 'css)
   8277            (setq part-end (web-mode-part-end-position))
   8278            (while (setq rule (web-mode-css-rule-next part-end))
   8279              (when (not (looking-at-p "[[:space:]]*\\($\\|<\\)"))
   8280                (newline)
   8281                (indent-according-to-mode)
   8282                (setq part-end (web-mode-part-end-position)))
   8283              )
   8284            )
   8285           ) ;cond
   8286         )
   8287       )))
   8288 
   8289 (defun web-mode-buffer-indent ()
   8290   "Indent all buffer."
   8291   (interactive)
   8292   (let ((debug t) (ts (current-time)) (sub nil))
   8293     (indent-region (point-min) (point-max))
   8294     (when debug
   8295       (setq sub (time-subtract (current-time) ts))
   8296       (message "buffer-indent: time elapsed = %Ss %9Sµs" (nth 1 sub) (nth 2 sub)))
   8297     (delete-trailing-whitespace)))
   8298 
   8299 (defun web-mode-point-context (pos)
   8300   "POS should be at the beginning of the indentation."
   8301   (save-excursion
   8302     (let (curr-char curr-indentation curr-line
   8303                     language
   8304                     options
   8305                     reg-beg reg-col
   8306                     prev-char prev-indentation prev-line prev-pos
   8307                     token
   8308                     part-language
   8309                     depth)
   8310 
   8311       (setq reg-beg (point-min)
   8312             reg-col 0
   8313             token "live"
   8314             options ""
   8315             language ""
   8316             prev-line ""
   8317             prev-char 0
   8318             prev-pos nil)
   8319 
   8320       (when (get-text-property pos 'part-side)
   8321         (setq part-language (symbol-name (get-text-property pos 'part-side))))
   8322 
   8323       ;;(message "part-language=%S" part-language)
   8324 
   8325       (cond
   8326 
   8327         ((and (bobp) (member web-mode-content-type '("html" "xml")))
   8328          (setq language web-mode-content-type)
   8329          )
   8330 
   8331         ((string= web-mode-content-type "css")
   8332          (setq language "css"
   8333                curr-indentation web-mode-css-indent-offset))
   8334 
   8335         ((member web-mode-content-type '("javascript" "json" "typescript"))
   8336          (setq language web-mode-content-type
   8337                curr-indentation web-mode-code-indent-offset))
   8338 
   8339         ((or (string= web-mode-content-type "jsx")
   8340              (and part-language (string= part-language "jsx")))
   8341          (setq language "jsx"
   8342                curr-indentation web-mode-code-indent-offset)
   8343          (cond
   8344            ((web-mode-jsx-is-html pos)
   8345             (setq curr-indentation web-mode-markup-indent-offset
   8346                   options "is-html"))
   8347            ((and (setq depth (get-text-property pos 'jsx-depth)) (> depth 1))
   8348             (when (get-text-property pos 'jsx-beg)
   8349               (setq depth (1- depth)))
   8350             (setq reg-beg (web-mode-jsx-depth-beginning-position pos depth))
   8351             (setq reg-beg (1+ reg-beg))
   8352             ;;(message "%S" (point))
   8353             (save-excursion
   8354               (goto-char reg-beg)
   8355               ;;(message "pt=%S" reg-beg)
   8356               (cond
   8357                 ((and (not (looking-at-p "[ ]*$"))
   8358                       (looking-back "^[[:space:]]*{" (point-min)))
   8359                  (setq reg-col (+ (current-indentation) ;; #1027
   8360                                   (cond
   8361                                     ((looking-at "[ ]+") (1+ (length (match-string-no-properties 0))))
   8362                                     (t 0))
   8363                                   ))
   8364                  )
   8365                 ((looking-at-p "[ ]*\\[[ ]*$") ;; #0659
   8366                  (setq reg-col (current-indentation))
   8367                  )
   8368                 ((and (looking-back "=[ ]*{" (point-min)) ;; #0739 #1022
   8369                       (not (looking-at-p "[[:space:]]*<")))
   8370                  (setq reg-col (current-indentation))
   8371                  )
   8372                 ;;((and (looking-back "=[ ]*{" (point-min)) ;; #0739
   8373                 ;;      (looking-at-p "{[ ]*"))
   8374                 ;; (setq reg-col (current-indentation))
   8375                 ;; )
   8376                 ((get-text-property (1- (point)) 'tag-beg)
   8377                  ;;(message "point=%S" (point))
   8378                  (setq reg-col (current-indentation))
   8379                  )
   8380                 (t
   8381                  (message "%S : %S %S" (point) (current-indentation) web-mode-code-indent-offset)
   8382                  ;;(setq reg-col (+ (current-indentation) web-mode-code-indent-offset web-mode-jsx-expression-padding)))
   8383                  (setq reg-col (+ (current-indentation) web-mode-code-indent-offset)))
   8384                 )
   8385 
   8386               ;;(message "%S %S %S" (point) (current-indentation) reg-col)
   8387               ) ;save-excursion
   8388             )
   8389            ((string= web-mode-content-type "jsx")
   8390             (setq reg-beg (point-min)))
   8391            (t
   8392             (setq reg-beg (or (web-mode-part-beginning-position pos) (point-min)))
   8393             (save-excursion
   8394               (goto-char reg-beg)
   8395               (search-backward "<" nil t)
   8396               (setq reg-col (current-column))
   8397               ) ;save-excursion
   8398             )
   8399            ) ;cond
   8400          ;;(message "jsx reg-beg=%S" reg-beg)
   8401          ) ;jsx
   8402 
   8403         ((string= web-mode-content-type "php")
   8404          (setq language "php"
   8405                curr-indentation web-mode-code-indent-offset))
   8406 
   8407         ((or (string= web-mode-content-type "xml"))
   8408          (setq language "xml"
   8409                curr-indentation web-mode-markup-indent-offset))
   8410 
   8411         ;; TODO: est ce util ?
   8412         ((and (get-text-property pos 'tag-beg)
   8413               (get-text-property pos 'tag-name)
   8414               ;;(not (get-text-property pos 'part-side))
   8415               )
   8416          (setq language "html"
   8417                curr-indentation web-mode-markup-indent-offset))
   8418 
   8419         ((and (get-text-property pos 'block-side)
   8420               (not (get-text-property pos 'block-beg)))
   8421 
   8422          (setq reg-beg (or (web-mode-block-beginning-position pos) (point-min)))
   8423          (goto-char reg-beg)
   8424          (setq reg-col (current-column))
   8425          ;;(message "%S %S" reg-beg reg-col)
   8426          (setq language web-mode-engine)
   8427          (setq curr-indentation web-mode-code-indent-offset)
   8428 
   8429          (cond
   8430            ((string= web-mode-engine "blade")
   8431             (save-excursion
   8432               (when (web-mode-rsf "{[{!]+[ ]*")
   8433                 (setq reg-col (current-column))))
   8434             (setq reg-beg (+ reg-beg 2))
   8435             )
   8436            ((string= web-mode-engine "razor")
   8437             ;;(setq reg-beg (+ reg-beg 2))
   8438             ;;(setq reg-col (current-column))
   8439             )
   8440            ;; tests/demo.chtml
   8441            ((string= web-mode-engine "ctemplate")
   8442             (save-excursion
   8443               (when (web-mode-rsf "{{#?")
   8444                 (setq reg-col (current-column))))
   8445             )
   8446            ((string= web-mode-engine "dust")
   8447             (save-excursion
   8448               (when (web-mode-rsf "{@")
   8449                 (setq reg-col (current-column))))
   8450             )
   8451            ((string= web-mode-engine "svelte")
   8452             (save-excursion
   8453               (when (web-mode-rsf "{@")
   8454                 (setq reg-col (current-column))))
   8455             )
   8456            ((string= web-mode-engine "template-toolkit")
   8457             (setq reg-beg (+ reg-beg 3)
   8458                   reg-col (+ reg-col 3))
   8459             )
   8460            ((and (string= web-mode-engine "jsp")
   8461                  (web-mode-looking-at "<%@" reg-beg))
   8462             (save-excursion
   8463               (goto-char reg-beg)
   8464               (looking-at "<%@[ ]*[[:alpha:]]+[ ]+\\|</?[[:alpha:]]+[:.][[:alpha:]]+[ ]+")
   8465               (goto-char (match-end 0))
   8466               (setq reg-col (current-column))
   8467               )
   8468             )
   8469            ((and (string= web-mode-engine "freemarker")
   8470                  (web-mode-looking-at "<@\\|<%@\\|<[[:alpha:]]" reg-beg))
   8471             (save-excursion
   8472               (goto-char reg-beg)
   8473               (looking-at "<@[[:alpha:].]+[ ]+\\|<%@[ ]*[[:alpha:]]+[ ]+\\|<[[:alpha:]]+:[[:alpha:]]+[ ]+")
   8474               (goto-char (match-end 0))
   8475               (setq reg-col (current-column))
   8476               )
   8477             )
   8478            ) ;cond
   8479          ) ;block-side
   8480 
   8481         ((and part-language (member part-language
   8482                                     '("css" "javascript" "json" "sql" "markdown"
   8483                                       "pug" "ruby" "sass" "stylus" "typescript")))
   8484          (setq reg-beg (or (web-mode-part-beginning-position pos) (point-min)))
   8485          (goto-char reg-beg)
   8486          (if (and (string= web-mode-engine "mojolicious")
   8487                   (looking-back "javascript begin" (point-min)))
   8488              (search-backward "%" nil t)
   8489              (search-backward "<" nil t))
   8490          (setq reg-col (current-column))
   8491          (setq language part-language)
   8492          (cond
   8493            ((string= language "css")
   8494             (setq curr-indentation web-mode-css-indent-offset))
   8495            ((string= language "sql")
   8496             (setq curr-indentation web-mode-sql-indent-offset))
   8497            ((string= language "markdown")
   8498             (setq curr-indentation web-mode-code-indent-offset))
   8499            ((string= language "pug")
   8500             (setq curr-indentation web-mode-code-indent-offset))
   8501            ((string= language "sass")
   8502             (setq curr-indentation web-mode-code-indent-offset))
   8503            ((string= language "stylus")
   8504             (setq curr-indentation web-mode-code-indent-offset))
   8505            ((string= language "ruby")
   8506             (setq curr-indentation web-mode-code-indent-offset))
   8507            ((string= language "typescript")
   8508             (setq curr-indentation web-mode-code-indent-offset))
   8509            (t
   8510             (setq language "javascript"
   8511                   curr-indentation web-mode-code-indent-offset))
   8512            )
   8513          ) ;part-side
   8514 
   8515         (t
   8516          (setq language "html"
   8517                curr-indentation web-mode-markup-indent-offset)
   8518          )
   8519 
   8520         ) ;cond
   8521 
   8522       (cond
   8523         ((or (and (> pos (point-min))
   8524                   (eq (get-text-property pos 'part-token) 'comment)
   8525                   (eq (get-text-property (1- pos) 'part-token) 'comment)
   8526                   (progn
   8527                     (setq reg-beg (previous-single-property-change pos 'part-token))
   8528                     t))
   8529              (and (> pos (point-min))
   8530                   (eq (get-text-property pos 'block-token) 'comment)
   8531                   (eq (get-text-property (1- pos) 'block-token) 'comment)
   8532                   (progn
   8533                     (setq reg-beg (previous-single-property-change pos 'block-token))
   8534                     t))
   8535              (and (> pos (point-min))
   8536                   (eq (get-text-property pos 'tag-type) 'comment)
   8537                   (not (get-text-property pos 'tag-beg))
   8538                   (progn
   8539                     (setq reg-beg (web-mode-tag-beginning-position pos))
   8540                     t))
   8541              )
   8542          (setq token "comment"))
   8543         ((or (and (> pos (point-min))
   8544                   (member (get-text-property pos 'part-token)
   8545                           '(string context key))
   8546                   (member (get-text-property (1- pos) 'part-token)
   8547                           '(string context key)))
   8548              (and (eq (get-text-property pos 'block-token) 'string)
   8549                   (eq (get-text-property (1- pos) 'block-token) 'string)))
   8550          (setq token "string"))
   8551         )
   8552 
   8553       (goto-char pos)
   8554       (setq curr-line (web-mode-trim
   8555                        (buffer-substring-no-properties
   8556                         (line-beginning-position)
   8557                         (line-end-position))))
   8558       (setq curr-char (if (string= curr-line "") 0 (aref curr-line 0)))
   8559 
   8560       (when (or (member language '("php" "blade" "javascript" "typescript" "jsx" "razor" "css"))
   8561                 (and (member language '("html" "xml"))
   8562                      (not (eq ?\< curr-char))))
   8563         (let (prev)
   8564           (cond
   8565             ((member language '("html" "xml" "javascript" "typescript" "jsx" "css"))
   8566              (when (setq prev (web-mode-part-previous-live-line reg-beg))
   8567                (setq prev-line (nth 0 prev)
   8568                      prev-indentation (nth 1 prev)
   8569                      prev-pos (nth 2 prev))
   8570                )
   8571              )
   8572             ((setq prev (web-mode-block-previous-live-line))
   8573              (setq prev-line (car prev)
   8574                    prev-indentation (cdr prev))
   8575              (setq prev-line (web-mode-clean-block-line prev-line)))
   8576             ) ;cond
   8577           ) ;let
   8578         (when (>= (length prev-line) 1)
   8579           (setq prev-char (aref prev-line (1- (length prev-line))))
   8580           (setq prev-line (substring-no-properties prev-line))
   8581           )
   8582         )
   8583 
   8584       (cond
   8585         ((not (member web-mode-content-type '("html" "xml")))
   8586          )
   8587         ((member language '("javascript" "typescript" "jsx" "ruby"))
   8588          (setq reg-col (if web-mode-script-padding (+ reg-col web-mode-script-padding) 0)))
   8589         ((member language '("css" "sql" "markdown" "pug" "sass" "stylus"))
   8590          (setq reg-col (if web-mode-style-padding (+ reg-col web-mode-style-padding) 0)))
   8591         ((not (member language '("html" "xml")))
   8592          (setq reg-col
   8593                (cond
   8594                  ((not web-mode-block-padding) reg-col)
   8595                  ((eq web-mode-block-padding -1) 0)
   8596                  (t (+ reg-col web-mode-block-padding))
   8597                  ) ;cond
   8598                ) ;setq
   8599          )
   8600         )
   8601 
   8602       (list :curr-char curr-char
   8603             :curr-indentation curr-indentation
   8604             :curr-line curr-line
   8605             :language language
   8606             :options options
   8607             :prev-char prev-char
   8608             :prev-indentation prev-indentation
   8609             :prev-line prev-line
   8610             :prev-pos prev-pos
   8611             :reg-beg reg-beg
   8612             :reg-col reg-col
   8613             :token token)
   8614       )))
   8615 
   8616 (defun web-mode-indent-line ()
   8617 
   8618   (web-mode-scan)
   8619 
   8620   (let ((offset nil)
   8621         (char nil)
   8622         (debug nil)
   8623         (inhibit-modification-hooks nil)
   8624         (adjust t))
   8625 
   8626     (save-excursion
   8627       (back-to-indentation)
   8628       (setq char (char-after))
   8629       (let* ((pos (point))
   8630              (ctx (web-mode-point-context pos))
   8631              (curr-char (plist-get ctx :curr-char))
   8632              (curr-indentation (plist-get ctx :curr-indentation))
   8633              (curr-line (plist-get ctx :curr-line))
   8634              (language (plist-get ctx :language))
   8635              (prev-char (plist-get ctx :prev-char))
   8636              (prev-indentation (plist-get ctx :prev-indentation))
   8637              (prev-line (plist-get ctx :prev-line))
   8638              (prev-pos (plist-get ctx :prev-pos))
   8639              (reg-beg (plist-get ctx :reg-beg))
   8640              (reg-col (plist-get ctx :reg-col))
   8641              (token (plist-get ctx :token))
   8642              (options (plist-get ctx :options))
   8643              (chars (list curr-char prev-char))
   8644              (tmp nil)
   8645              (is-js (member language '("javascript" "jsx" "ejs" "typescript"))))
   8646 
   8647         (when (member language '("json" "typescript"))
   8648           (setq language "javascript"))
   8649 
   8650         ;;(message "%S %S" (plist-get ctx :language) language)
   8651         ;;(message "curr-char=[%c] prev-char=[%c]\n%S" curr-char prev-char ctx)
   8652         ;;(message "options=%S" ctx)
   8653 
   8654         (cond
   8655 
   8656           ((or (bobp) (= (line-number-at-pos pos) 1))
   8657            (when debug (message "I100(%S) first line" pos))
   8658            (setq offset 0))
   8659 
   8660           ;; #123 #1145
   8661           ((and web-mode-enable-front-matter-block
   8662                 (eq (char-after (point-min)) ?\-)
   8663                 (or (looking-at-p "---")
   8664                     (search-forward "---" (point-max) t)))
   8665            (when debug (message "I108(%S) front-matter-block" pos))
   8666            (setq offset nil))
   8667 
   8668           ;; #1073
   8669           ((get-text-property pos 'invisible)
   8670            (when debug (message "I110(%S) invible" pos))
   8671            (setq offset nil))
   8672 
   8673           ((string= token "string")
   8674            (when debug (message "I120(%S) string" pos))
   8675            (cond
   8676              ((web-mode-is-token-end pos)
   8677               (if (get-text-property pos 'block-side)
   8678                   (web-mode-block-token-beginning)
   8679                   (web-mode-part-token-beginning))
   8680               (setq offset (current-indentation))
   8681               )
   8682              ((and web-mode-enable-sql-detection
   8683                    (web-mode-block-token-starts-with (concat "[ \n]*" web-mode-sql-queries)))
   8684               (save-excursion
   8685                 (let (col)
   8686                   (web-mode-block-string-beginning)
   8687                   (skip-chars-forward "[ \"'\n]")
   8688                   (setq col (current-column))
   8689                   (goto-char pos)
   8690                   (if (looking-at-p "\\(SELECT\\|INSERT\\|DELETE\\|UPDATE\\|FROM\\|LEFT\\|JOIN\\|WHERE\\|GROUP BY\\|LIMIT\\|HAVING\\|\)\\)")
   8691                       (setq offset col)
   8692                       (setq offset (+ col web-mode-sql-indent-offset)))
   8693                   )
   8694                 ) ;save-excursion
   8695               )
   8696              ((and is-js
   8697                    (web-mode-is-ql-string pos "Relay\.QL"))
   8698               (setq offset (web-mode-relayql-indentation pos))
   8699               )
   8700              ((and is-js
   8701                    (web-mode-is-ql-string pos "gql"))
   8702               (setq offset (web-mode-relayql-indentation pos "gql"))
   8703               )
   8704              ((and is-js
   8705                    (web-mode-is-ql-string pos "graphql"))
   8706               (setq offset (web-mode-relayql-indentation pos "graphql"))
   8707               )
   8708              ((and is-js
   8709                    (web-mode-is-css-string pos))
   8710               (when debug (message "I127(%S) css string" pos))
   8711               (setq offset (web-mode-token-css-indentation pos))
   8712               )
   8713              ((and is-js
   8714                    (web-mode-is-html-string pos))
   8715               (when debug (message "I128(%S) html string" pos))
   8716               (setq offset (web-mode-token-html-indentation pos))
   8717               )
   8718              (t
   8719               (setq offset nil))
   8720              ) ;cond
   8721            ) ;case string
   8722 
   8723           ((string= token "comment")
   8724            (when debug (message "I130(%S) comment" pos))
   8725            (if (eq (get-text-property pos 'tag-type) 'comment)
   8726                (web-mode-tag-beginning)
   8727                (goto-char (car
   8728                            (web-mode-property-boundaries
   8729                             (if (eq (get-text-property pos 'part-token) 'comment)
   8730                                 'part-token
   8731                                 'block-token)
   8732                             pos))))
   8733            (setq offset (current-column))
   8734            (cond
   8735              ((string= web-mode-engine "freemarker")
   8736               (setq offset (+ (current-indentation) 2)))
   8737              ((member (buffer-substring-no-properties (point) (+ (point) 2)) '("/*" "{*" "@*"))
   8738               (cond
   8739                 ((eq ?\* curr-char)
   8740                  (setq offset (+ offset 1)))
   8741                 (t
   8742                  (setq offset (+ offset 3)))
   8743                 ) ;cond
   8744               )
   8745              ((string= (buffer-substring-no-properties (point) (+ (point) 4)) "<!--")
   8746               (cond
   8747                 ((string-match-p "^<!\\[endif" curr-line)
   8748                  )
   8749                 ((looking-at-p "<!--\\[if")
   8750                  (setq offset (+ offset web-mode-markup-indent-offset)))
   8751                 ((string-match-p "^-->" curr-line)
   8752                  (setq offset offset))
   8753                 ((string-match-p "^-" curr-line)
   8754                  (setq offset (+ offset 3)))
   8755                 (t
   8756                  (setq offset (+ offset 5)))
   8757                 ) ;cond
   8758               )
   8759              ((and (string= web-mode-engine "django") (looking-back "{% comment %}" (point-min)))
   8760               (setq offset (- offset 12)))
   8761              ((and (string= web-mode-engine "mako") (looking-back "<%doc%>" (point-min)))
   8762               (setq offset (- offset 6)))
   8763              ((and (string= web-mode-engine "mason") (looking-back "<%doc%>" (point-min)))
   8764               (setq offset (- offset 6)))
   8765              ) ;cond
   8766            ) ;case comment
   8767 
   8768           ((and (string= web-mode-engine "mason")
   8769                 (string-match-p "^%" curr-line))
   8770            (when debug (message "I140(%S) mason" pos))
   8771            (setq offset 0))
   8772 
   8773           ((and (string= web-mode-engine "razor")
   8774                 (string-match-p "^\\([{}]\\|else\\)" curr-line))
   8775            (when debug (message "I142(%S) razor" pos))
   8776            (save-excursion
   8777              (web-mode-block-previous)
   8778              (setq offset (current-indentation))
   8779              ))
   8780 
   8781           ((and (string= web-mode-engine "django")
   8782                 (string-match-p "^#" curr-line))
   8783            (when debug (message "I144(%S) django line statements" pos))
   8784            (setq offset 0))
   8785 
   8786           ((and (get-text-property pos 'block-beg)
   8787                 (or (web-mode-block-is-close pos)
   8788                     (web-mode-block-is-inside pos)))
   8789            (when debug (message "I150(%S) block-match" pos))
   8790            (cond
   8791              ((not (web-mode-block-match))
   8792               )
   8793              ((and (string= web-mode-engine "closure")
   8794                    (string-match-p "{\\(case\\|default\\)" curr-line))
   8795               (setq offset (+ (current-indentation) web-mode-markup-indent-offset)))
   8796              (t
   8797               (setq offset (current-indentation))
   8798               (if (and (string= web-mode-engine "blade")
   8799                        (string-match-p "@break" curr-line))
   8800                   (setq offset (+ (current-indentation) offset)))
   8801               )
   8802              ) ;cond
   8803            )
   8804 
   8805           ((eq (get-text-property pos 'block-token) 'delimiter-end)
   8806            (when debug (message "I160(%S) block-beginning" pos))
   8807            (when (web-mode-block-beginning)
   8808              (setq reg-col (current-indentation))
   8809              (setq offset (current-column))))
   8810 
   8811           ((or (and (get-text-property pos 'tag-beg)
   8812                     (eq (get-text-property pos 'tag-type) 'end))
   8813                (and (eq (get-text-property pos 'tag-type) 'comment)
   8814                     (string-match-p "<!--#\\(else\\|elif\\|endif\\)" curr-line)))
   8815            (when debug (message "I170(%S) tag-match" pos))
   8816            (when (web-mode-tag-match)
   8817              (setq offset (current-indentation))))
   8818 
   8819           ((and (member language '("jsx"))
   8820                 (eq curr-char ?\})
   8821                 (get-text-property pos 'jsx-end))
   8822            (when debug (message "I180(%S) jsx-expr-end" pos))
   8823            (web-mode-go (1- reg-beg))
   8824            (setq reg-col nil)
   8825            ;;(setq offset (current-column)))
   8826            (setq offset (current-indentation)))
   8827 
   8828           ((and (member language '("html" "xml" "javascript" "jsx"))
   8829                 (get-text-property pos 'tag-type)
   8830                 (not (get-text-property pos 'tag-beg))
   8831                 ;;(or (not (string= language "jsx"))
   8832                 ;;    (string= options "is-html"))
   8833                 (not (and (string= language "jsx")
   8834                           (web-mode-jsx-is-expr pos)))
   8835                 )
   8836            (when debug (message "I190(%S) attr-indent" pos))
   8837            (cond
   8838              ((and (not (get-text-property pos 'tag-attr-beg))
   8839                    (get-text-property pos 'tag-attr)
   8840                    (get-text-property (1- pos) 'tag-attr)
   8841                    (web-mode-attribute-beginning)
   8842                    (not (string-match-p "^/?>" curr-line))
   8843                    ;;(progn (message "pos=%S point=%S" pos (point)) t)
   8844                    )
   8845 
   8846               (cond
   8847                 ((eq (logand (get-text-property (point) 'tag-attr-beg) 8) 8)
   8848                  (setq offset nil))
   8849                 ((not (web-mode-tag-beginning))
   8850                  (message "** tag-beginning ** failure")
   8851                  (setq offset nil))
   8852                 (web-mode-attr-value-indent-offset
   8853                  (setq offset (+ (current-column) web-mode-attr-value-indent-offset)))
   8854                 ((web-mode-dom-rsf "=[ ]*[\"']?" pos)
   8855                  ;;(message "%S" (point))
   8856                  (setq offset (current-column)))
   8857                 (t
   8858                  (setq offset (+ (current-column) web-mode-markup-indent-offset)))
   8859                 ) ;cond
   8860               ) ;and
   8861              ((not (web-mode-tag-beginning))
   8862               (message "** error ** unable to jump to tag beg"))
   8863              ((string-match-p "^/?>" curr-line)
   8864               (setq offset (web-mode-column-at-pos (web-mode-tag-beginning-position pos)))
   8865               )
   8866              (web-mode-attr-indent-offset
   8867               (setq offset (+ (current-column) web-mode-attr-indent-offset)))
   8868              ((looking-at-p (concat web-mode-start-tag-regexp "[ ]*\n"))
   8869               ;;(message "%S: %S" (point) (web-mode-inside-block-control pos))
   8870               (setq offset (+ (current-column) (or web-mode-attr-indent-offset web-mode-code-indent-offset)))
   8871               ;; #1109
   8872               (setq tmp (web-mode-inside-block-control pos))
   8873               (when (and tmp (> tmp (point)))
   8874                 (setq offset (+ offset (or web-mode-attr-indent-offset web-mode-code-indent-offset))))
   8875               )
   8876              ((web-mode-attribute-next)
   8877               (setq offset (current-column)))
   8878              ) ;cond
   8879            ) ;attr-indent
   8880 
   8881           ((or (member language '("html" "xml"))
   8882                (and (member language '("jsx"))
   8883                     (string= options "is-html")))
   8884            (when debug (message "I200(%S) web-mode-markup-indentation" pos))
   8885            ;; https://www.w3.org/TR/html5/syntax.html#optional-tags
   8886            (when web-mode-enable-optional-tags
   8887              (save-excursion
   8888                (let (tag-name parent-tag-name parent-tag-pos)
   8889                  (when (and (setq tag-name (get-text-property pos 'tag-name))
   8890                             (setq parent-tag-pos (web-mode-element-parent-position pos))
   8891                             (setq parent-tag-name (get-text-property parent-tag-pos 'tag-name))
   8892                             (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")))
   8893                                 (and (string= parent-tag-name "li") (member tag-name '("li")))
   8894                                 (and (string= parent-tag-name "dt") (member tag-name '("dt" "dd")))
   8895                                 (and (string= parent-tag-name "td") (member tag-name '("td" "th")))
   8896                                 (and (string= parent-tag-name "th") (member tag-name '("td" "th")))
   8897                                 ))
   8898                    (when debug (message "I205(%S) %S(%S) auto-closing" pos parent-tag-name parent-tag-pos))
   8899                    (setq offset (web-mode-indentation-at-pos parent-tag-pos))
   8900                    )))) ; when let save-excursion when
   8901 
   8902            (when (string= web-mode-engine "closure")
   8903              (save-excursion
   8904                (when (and (re-search-backward "{/?switch" nil t)
   8905                           (string= (match-string-no-properties 0) "{switch"))
   8906                  (setq offset (+ (current-indentation) (* 2 web-mode-markup-indent-offset)))
   8907                  )
   8908                ))
   8909            (cond
   8910              ((not (null offset))
   8911               )
   8912              ((get-text-property pos 'tag-beg)
   8913               (setq offset (web-mode-markup-indentation pos))
   8914               )
   8915              ((and web-mode-indentless-elements
   8916                    (not (string= language "jsx"))
   8917                    (null (get-text-property pos 'block-side))
   8918                    (null (get-text-property pos 'part-side))
   8919                    (and (null (get-text-property pos 'tag-beg))
   8920                         (save-excursion
   8921                           (and (web-mode-element-parent)
   8922                                (member (get-text-property (point) 'tag-name) web-mode-indentless-elements))))
   8923                    )
   8924               (setq offset nil))
   8925              ((or (eq (length curr-line) 0)
   8926                   (= web-mode-indent-style 2)
   8927                   (get-text-property pos 'tag-beg)
   8928                   (get-text-property pos 'reg-beg))
   8929               (setq offset (web-mode-markup-indentation pos))
   8930               )
   8931              )
   8932            )
   8933 
   8934           ((string= language "ctemplate")
   8935            (when debug (message "I210(%S) ctemplate" pos))
   8936            (setq offset reg-col))
   8937 
   8938           ((string= language "antlers")
   8939            (when debug (message "I214(%S) antlers" pos))
   8940            (setq offset reg-col))
   8941 
   8942           ((string= language "expressionengine")
   8943            (when debug (message "I220(%S) expressionengine" pos))
   8944            (setq offset (+ reg-col (or web-mode-attr-indent-offset web-mode-code-indent-offset))))
   8945 
   8946           ((string= language "asp")
   8947            (when debug (message "I230(%S) asp" pos))
   8948            (setq offset (web-mode-asp-indentation pos
   8949                                                   curr-line
   8950                                                   reg-col
   8951                                                   curr-indentation
   8952                                                   reg-beg)))
   8953 
   8954           ((member language '("lsp" "cl-emb" "artanis"))
   8955            (when debug (message "I240(%S) lsp" pos))
   8956            (setq offset (web-mode-lisp-indentation pos ctx)))
   8957 
   8958           ((and (member curr-char '(?\}))
   8959                 (string= language "razor")
   8960                 (get-text-property pos 'block-end))
   8961            (when debug (message "I245(%S) razor closing" pos))
   8962            (goto-char reg-beg)
   8963            ;;(message "%S %S" (point) (current-column))
   8964            (setq offset (current-column)
   8965                  reg-col nil)
   8966            )
   8967 
   8968           ((member curr-char '(?\} ?\) ?\]))
   8969            (when debug (message "I250(%S) closing-paren" pos))
   8970            (let (ori pos2)
   8971              (setq pos2 pos)
   8972              ;; #1096
   8973              (when (looking-at-p ".[\]})]+")
   8974                (skip-chars-forward "[\]})]")
   8975                (backward-char)
   8976                (setq pos2 (point))
   8977                ) ;when
   8978              (if (get-text-property pos 'block-side)
   8979                  (setq ori (web-mode-block-opening-paren-position pos2 reg-beg))
   8980                  (setq ori (web-mode-part-opening-paren-position pos2 reg-beg)))
   8981              ;;(message "ori=%S" ori)
   8982              (cond
   8983                ((null ori)
   8984                 (setq offset reg-col))
   8985                ((and (goto-char ori)
   8986                      (looking-back ")[ ]*" (point-min)) ;; peut-on se passer du looking-back ?
   8987                      (re-search-backward ")[ ]*" nil t)
   8988                      (web-mode-block-opening-paren reg-beg))
   8989                 (back-to-indentation)
   8990                 (setq offset (current-indentation))
   8991                 )
   8992                (t
   8993                 (goto-char ori)
   8994                 (back-to-indentation)
   8995                 (setq offset (current-indentation))
   8996                 ;;(message "ori=%S offset=%S" ori offset)
   8997                 (when (get-text-property pos 'jsx-depth)
   8998                   ;;(when (get-text-property pos 'jsx-end)
   8999                   (setq adjust nil))
   9000                 ) ;t
   9001                ) ;cond
   9002              ) ;let
   9003            )
   9004 
   9005           ((member language '("mako" "web2py"))
   9006            (when debug (message "I254(%S) python (mako/web2py)" pos))
   9007            (setq offset (web-mode-python-indentation pos
   9008                                                      curr-line
   9009                                                      reg-col
   9010                                                      curr-indentation
   9011                                                      reg-beg)))
   9012 
   9013           ((member language '("erb" "ruby"))
   9014            (when debug (message "I260(%S) erb" pos))
   9015            (setq offset (web-mode-ruby-indentation pos
   9016                                                    curr-line
   9017                                                    reg-col
   9018                                                    curr-indentation
   9019                                                    reg-beg)))
   9020 
   9021           ((string= language "css")
   9022            (when debug (message "I270(%S) css-indentation" pos))
   9023            ;;(message "prev=%c" prev-char)
   9024            (cond
   9025              ((eq prev-char ?:)
   9026               (setq offset (+ prev-indentation web-mode-css-indent-offset)))
   9027              ((eq prev-char ?,)
   9028               (setq offset prev-indentation))
   9029              (t
   9030               (setq offset (car (web-mode-css-indentation pos
   9031                                                           reg-col
   9032                                                           curr-indentation
   9033                                                           language
   9034                                                           reg-beg))))))
   9035 
   9036           ((string= language "sql")
   9037            (when debug (message "I280(%S) sql" pos))
   9038            (setq offset (car (web-mode-sql-indentation pos
   9039                                                        reg-col
   9040                                                        curr-indentation
   9041                                                        language
   9042                                                        reg-beg))))
   9043 
   9044           ((string= language "markdown")
   9045            (when debug (message "I290(%S) markdown" pos))
   9046            (setq offset (car (web-mode-markdown-indentation pos
   9047                                                             reg-col
   9048                                                             curr-indentation
   9049                                                             language
   9050                                                             reg-beg))))
   9051 
   9052           ((string= language "stylus")
   9053            (when debug (message "I294(%S) stylus" pos))
   9054            (setq offset (car (web-mode-stylus-indentation pos
   9055                                                           reg-col
   9056                                                           curr-indentation
   9057                                                           language
   9058                                                           reg-beg))))
   9059           ((string= language "sass")
   9060            (when debug (message "I296(%S) sass" pos))
   9061            (setq offset (car (web-mode-stylus-indentation pos
   9062                                                           reg-col
   9063                                                           curr-indentation
   9064                                                           language
   9065                                                           reg-beg))))
   9066 
   9067           ((string= language "pug")
   9068            (when debug (message "I298(%S) pug" pos))
   9069            (setq offset (car (web-mode-pug-indentation pos
   9070                                                        reg-col
   9071                                                        curr-indentation
   9072                                                        language
   9073                                                        reg-beg))))
   9074 
   9075           ((and (string= language "razor")
   9076                 (string-match-p "^\\." curr-line)
   9077                 (string-match-p "^\\." prev-line))
   9078            (when debug (message "I300(%S) razor" pos))
   9079            (setq offset prev-indentation))
   9080 
   9081           ((and (string= language "razor")
   9082                 (string-match-p "^case " curr-line)
   9083                 (string-match-p "^case " prev-line))
   9084            (when debug (message "I310(%S) razor case" pos))
   9085            (search-backward "case ")
   9086            (setq offset (current-column)))
   9087 
   9088           ((and is-js
   9089                 (member ?\. chars)
   9090                 (not (string-match-p "^\\.\\.\\." curr-line)))
   9091            (when debug (message "I320(%S) javascript-calls" pos))
   9092            (let (pair)
   9093              (setq pair (web-mode-javascript-calls-beginning-position pos reg-beg))
   9094              ;;(message "%S" pair)
   9095              (when pair
   9096                (goto-char (car pair))
   9097                ;;(message "%S %S" (point) pair)
   9098                (cond
   9099                  ((cdr (assoc "lineup-calls" web-mode-indentation-params))
   9100                   ;;(message "ici")
   9101                   ;;(search-forward ".")
   9102                   (if (cdr pair)
   9103                       (progn
   9104                         (goto-char (cdr pair))
   9105                         (setq offset (current-column))
   9106                         (looking-at "\\.\\([ \t\n]*\\)")
   9107                         (setq offset (- offset (length (match-string-no-properties 1))))
   9108                         (unless (eq curr-char ?\.) (setq offset (1+ offset)))
   9109                         ) ;progn
   9110                       ;; TODO: cela devrait etre fait dans web-mode-javascript-calls-beginning-position
   9111                       (skip-chars-forward " \t\n")
   9112                       (setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9113                       ) ;if
   9114                   )
   9115                  (t
   9116                   (setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9117                   ) ;t
   9118                  ) ;cond
   9119                ) ;when
   9120              ) ;let
   9121            )
   9122 
   9123           ((and is-js
   9124                 (member ?\+ chars))
   9125            (when debug (message "I330(%S) javascript-string" pos))
   9126            ;;(message "js-concat")
   9127            (cond
   9128              ((not (web-mode-javascript-string-beginning pos reg-beg))
   9129               )
   9130              ((null (cdr (assoc "lineup-concats" web-mode-indentation-params)))
   9131               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9132              ((not (eq curr-char ?\+))
   9133               (setq offset (current-column)))
   9134              (t
   9135               (setq offset (current-column))
   9136               (when (not (looking-back "\\(^[ \t]+\\|if[ ]*[(]?\\)" (point-min)))
   9137                 (goto-char pos)
   9138                 (looking-at "\\+[ \t\n]*")
   9139                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9140               )
   9141              )
   9142            )
   9143 
   9144           ;; #579 , #742
   9145           ((and (member language '("javascript" "jsx" "ejs" "php"))
   9146                 (string-match-p "=[>]?$" prev-line))
   9147            (when debug (message "I340(%S)" pos))
   9148            (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9149            ;;(message "ici%S" offset)
   9150            )
   9151 
   9152           ;; #1016
   9153           ((and (member language '("javascript" "jsx" "ejs"))
   9154                 (string-match-p "^[ \t]*|}" curr-line))
   9155            (when debug (message "I346(%S) flow-exact-object-type-end" pos))
   9156            (when (re-search-backward "{|" reg-beg t)
   9157              (setq offset (current-indentation))
   9158              )
   9159            )
   9160 
   9161           ;; #446, #638, #800, #978, #998
   9162           ((and (member language '("javascript" "jsx" "ejs" "php"))
   9163                 (or (string-match-p "[&|?:+-]$" prev-line)
   9164                     (string-match-p "^[&|?:+-]" curr-line))
   9165                 (not (and (string= language "php")
   9166                           (string-match-p "^->" curr-line)))
   9167                 (not (and (string= language "php")
   9168                           (string-match-p "^?[a-zA-z]*" curr-line)))
   9169                 (not (and (string= language "php")
   9170                           (string-match-p "\\(else[ ]?:\\|if[ ]?([^)]*)[ ]?:\\)" prev-line)))
   9171                 (not (string-match-p "^\\(++\\|--\\)" curr-line))
   9172                 (not (and is-js
   9173                           (string-match-p "]:\\|{|$" prev-line)))
   9174                 (not (and (eq prev-char ?\:)
   9175                           (string-match-p "^\\(case\\|default\\)" prev-line)))
   9176                 )
   9177            ;;(message "prev=%S" prev-line)
   9178            (when debug (message "I350(%S) multiline statement" pos))
   9179            (let (is-ternary)
   9180              (setq is-ternary (or (string-match-p "[?:]$" prev-line)
   9181                                   (string-match-p "^[?:]" curr-line)))
   9182              (cond
   9183                ((not (funcall (if is-js
   9184                                   'web-mode-javascript-statement-beginning
   9185                                   'web-mode-block-statement-beginning)
   9186                               pos reg-beg is-ternary))
   9187                 )
   9188                ((null (cdr (assoc "lineup-ternary" web-mode-indentation-params)))
   9189                 (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9190                (t
   9191                 (setq offset (current-column))
   9192                 (when (and (member curr-char '(?\+ ?\- ?\& ?\| ?\? ?\:))
   9193                            (not (looking-back "\\(^[ \t]+\\|if[ ]*[(]?\\)" (point-min)))) ; #743
   9194                   (goto-char pos)
   9195                   (looking-at "\\(||\\|&&\\|[&|?:+-]\\)[ \t\n]*")
   9196                   (setq offset (- offset (length (match-string-no-properties 0)))))
   9197                 )
   9198                ) ;cond
   9199              ) ;let
   9200            )
   9201 
   9202           ((and is-js
   9203                 (eq prev-char ?\()
   9204                 (string-match-p "=>[ ]*([ ]*$" prev-line))
   9205            (when debug (message "I355(%S) => (" pos))
   9206            (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9207            )
   9208 
   9209           ((and is-js
   9210                 (or (member ?\, chars)
   9211                     (member prev-char '(?\( ?\[))))
   9212            (when debug (message "I360(%S) javascript-args" pos))
   9213            (cond
   9214              ((not (web-mode-javascript-args-beginning pos reg-beg))
   9215               (message "no js args beg")
   9216               )
   9217              ((or (not (cdr (assoc "lineup-args" web-mode-indentation-params)))
   9218                   (looking-at-p "|?\n") ;; #1016
   9219                   ;;(eq (char-after) ?\n)
   9220                   )
   9221               (if (and reg-col (> reg-col (current-indentation)))
   9222                   (setq offset (+ reg-col web-mode-code-indent-offset))
   9223                   (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9224               )
   9225              ((not (eq curr-char ?\,))
   9226               (setq offset (current-column)))
   9227              (t
   9228               (setq offset (current-column))
   9229               (goto-char pos)
   9230               (looking-at ",[ \t\n]*")
   9231               (setq offset (- offset (length (match-string-no-properties 0)))))
   9232              ) ;cond
   9233            )
   9234 
   9235           ((and is-js
   9236                 (or (eq prev-char ?\))
   9237                     (string-match-p "\\(^\\|[}[:space:]]+\\)else$" prev-line)))
   9238            (when debug (message "I370(%S)" pos))
   9239            (cond
   9240              ((and (string-match-p "else$" prev-line)
   9241                    (not (string-match-p "^{" curr-line)))
   9242               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9243               )
   9244              ((and (string-match-p "else$" prev-line)
   9245                    (string-match-p "^{" curr-line)
   9246                    web-mode-enable-curly-brace-indentation)
   9247               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9248               )
   9249              ((setq tmp (web-mode-part-is-opener prev-pos reg-beg))
   9250               ;;(message "is-opener")
   9251               (if (or (not (looking-at-p "{")) ;; #1020, #1053, #1160
   9252                       web-mode-enable-curly-brace-indentation)
   9253                   (setq offset (+ tmp web-mode-code-indent-offset))
   9254                   (setq offset tmp))
   9255               )
   9256              (t
   9257               (setq offset
   9258                     (car (web-mode-javascript-indentation pos
   9259                                                           reg-col
   9260                                                           curr-indentation
   9261                                                           language
   9262                                                           reg-beg)))
   9263               ) ;t
   9264              ) ;cond
   9265 
   9266            )
   9267 
   9268           ;; TODO : a retoucher completement car le code js a ete place ci-dessus
   9269           ;;((and (member language '("javascript" "jsx" "ejs" "php"))
   9270           ((and (member language '("php"))
   9271                 (or (and (eq prev-char ?\))
   9272                          (string-match-p "^\\(for\\|foreach\\|if\\|else[ ]*if\\|while\\)[ ]*(" prev-line))
   9273                     (and is-js
   9274                          (web-mode-part-is-opener prev-pos reg-beg))
   9275                     (string-match-p "^else$" prev-line))
   9276                 (not (string-match-p "^\\([{.]\\|->\\)" curr-line)))
   9277            (when debug (message "I380(%S)" pos))
   9278            (cond
   9279              ((and (eq prev-char ?\))
   9280                    (string-match-p "^\\(for\\|if\\|while\\)[ ]*(" prev-line))
   9281               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9282               )
   9283              ((member language '("javascript" "jsx"))
   9284               (setq offset
   9285                     (+ (car (web-mode-javascript-indentation pos
   9286                                                              reg-col
   9287                                                              curr-indentation
   9288                                                              language
   9289                                                              reg-beg))
   9290                        web-mode-code-indent-offset))
   9291               )
   9292              (t
   9293               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9294               )
   9295              )
   9296            )
   9297 
   9298           ((and (member language '("php" "blade")) (string-match-p "^->" curr-line))
   9299            (when debug (message "I390(%S) block-calls" pos))
   9300            (cond
   9301              ((not (web-mode-block-calls-beginning pos reg-beg))
   9302               )
   9303              ((cdr (assoc "lineup-calls" web-mode-indentation-params))
   9304               ;;(message "point=%S" (point))
   9305               (if (looking-back "::[ ]*" (point-min))
   9306                   (progn
   9307                     (re-search-backward "::[ ]*")
   9308                     (setq offset (current-column))
   9309                     ;;(message "ici%S offset=%S" (point) offset)
   9310                     )
   9311                   (search-forward "->")
   9312                   (setq offset (- (current-column) 2)))
   9313               )
   9314              (t
   9315               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9316              ))
   9317 
   9318           ((and is-js (member ?\, chars))
   9319            (when debug (message "I400(%S) part-args" pos))
   9320            (cond
   9321              ((not (web-mode-part-args-beginning pos reg-beg))
   9322               ;;(message "ici")
   9323               )
   9324              ((cdr (assoc "lineup-args" web-mode-indentation-params))
   9325               (setq offset (current-column))
   9326               ;;(message "offset=%S" offset)
   9327               (when (eq curr-char ?\,)
   9328                 (goto-char pos)
   9329                 (looking-at ",[ \t\n]*")
   9330                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9331               )
   9332              (t
   9333               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9334              ))
   9335 
   9336           ((member ?\, chars)
   9337            (when debug (message "I401(%S) block-args" pos))
   9338            (cond
   9339              ((not (web-mode-block-args-beginning pos reg-beg))
   9340               ;;(message "ici")
   9341               )
   9342              ((cdr (assoc "lineup-args" web-mode-indentation-params))
   9343               (setq offset (current-column))
   9344               ;;(message "offset=%S" offset)
   9345               (when (eq curr-char ?\,)
   9346                 (goto-char pos)
   9347                 (looking-at ",[ \t\n]*")
   9348                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9349               )
   9350              (t
   9351               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9352              ))
   9353 
   9354 
   9355           ((and (string= language "php") (member ?\. chars))
   9356            (when debug (message "I410(%S) block-string" pos))
   9357            (cond
   9358              ((not (web-mode-block-string-beginning pos reg-beg))
   9359               )
   9360              ((null (cdr (assoc "lineup-concats" web-mode-indentation-params)))
   9361               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9362              ((not (eq curr-char ?\.))
   9363               (setq offset (current-column)))
   9364              (t
   9365               (setq offset (current-column))
   9366               (goto-char pos)
   9367               (when (cdr (assoc "lineup-quotes" web-mode-indentation-params))
   9368                 (looking-at "\\.[ \t\n]*")
   9369                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9370               )))
   9371 
   9372           ((member language '("javascript" "jsx" "ejs" "underscore"))
   9373            (when debug (message "I420(%S) javascript-indentation" pos))
   9374            (setq offset (car (web-mode-javascript-indentation pos
   9375                                                               reg-col
   9376                                                               curr-indentation
   9377                                                               language
   9378                                                               reg-beg))))
   9379 
   9380           (t
   9381            (when debug (message "I430(%S) bracket-indentation" pos))
   9382            (setq offset (car (web-mode-bracket-indentation pos
   9383                                                            reg-col
   9384                                                            curr-indentation
   9385                                                            language
   9386                                                            reg-beg))))
   9387 
   9388           ) ;cond
   9389 
   9390         (when (and offset reg-col adjust (< offset reg-col)) (setq offset reg-col))
   9391 
   9392         ) ;let
   9393       ) ;save-excursion
   9394 
   9395     (when offset
   9396       ;;(message "offset=%S" offset)
   9397       (let ((diff (- (current-column) (current-indentation))))
   9398         (when (not (= offset (current-indentation)))
   9399           (setq web-mode-change-beg (line-beginning-position)
   9400                 web-mode-change-end (+ web-mode-change-beg offset)))
   9401         (setq offset (max 0 offset))
   9402         (indent-line-to offset)
   9403         (if (> diff 0) (move-to-column (+ (current-column) diff)))
   9404         (when (and (string= web-mode-engine "mason")
   9405                    (= offset 0)
   9406                    (eq char ?\%))
   9407           (save-excursion
   9408             (font-lock-fontify-region (line-beginning-position) (line-end-position)))
   9409           ) ;when
   9410         ) ;let
   9411       ) ;when
   9412 
   9413     ))
   9414 
   9415 (defun web-mode-bracket-level (pos limit)
   9416   (save-excursion
   9417     (let ((continue t)
   9418           (regexp "[\]\[}{)(]")
   9419           (char nil)
   9420           (map nil)
   9421           (key nil)
   9422           (value 0)
   9423           (open '(?\( ?\{ ?\[)))
   9424       (goto-char pos)
   9425       (while (and continue (re-search-backward regexp limit t))
   9426         (setq char (aref (match-string-no-properties 0) 0))
   9427         (setq key (cond ((eq char ?\)) ?\()
   9428                         ((eq char ?\}) ?\{)
   9429                         ((eq char ?\]) ?\[)
   9430                         (t             char)))
   9431         (setq value (or (plist-get map key) 0))
   9432         (setq value (if (member char open) (1+ value) (1- value)))
   9433         (setq map (plist-put map key value))
   9434         (setq continue (< value 1))
   9435         ;;(message "pos=%S char=%c key=%c value=%S" (point) char key value)
   9436         ) ;while
   9437       (if (>= value 1) (current-indentation) nil)
   9438       )))
   9439 
   9440 (defun web-mode-token-html-indentation (pos)
   9441   (save-excursion
   9442     (let (beg (continue t) end level map offset regexp tag val void (css-beg 0))
   9443       (goto-char pos)
   9444       ;;(message "pos=%S" pos)
   9445       (setq beg (web-mode-part-token-beginning-position pos))
   9446       (save-excursion
   9447         (when (and (> (- pos beg) 5)
   9448                    (re-search-backward "</?[a-zA-Z0-9]+" beg t)
   9449                    (string= "<style" (downcase (match-string-no-properties 0))))
   9450           (setq css-beg (point))
   9451           )
   9452         )
   9453       ;;(message "beg=%S" beg)
   9454       (cond
   9455         ((eq (char-after pos) ?\`)
   9456          (setq offset (web-mode-indentation-at-pos beg)))
   9457         ((web-mode-looking-back "`[ \n\t]*" pos)
   9458          (setq offset (+ (web-mode-indentation-at-pos beg) web-mode-markup-indent-offset)))
   9459         ((looking-at "</\\([a-zA-Z0-9]+\\)")
   9460          (setq tag (match-string-no-properties 1)
   9461                regexp (concat "</?" tag)
   9462                level -1)
   9463          (while (and continue (re-search-backward regexp beg t))
   9464            (cond
   9465              ((eq (aref (match-string-no-properties 0) 1) ?\/)
   9466               (setq level (1- level)))
   9467              (t
   9468               (setq level (1+ level)))
   9469              ) ;cond
   9470            (when (= level 0)
   9471              (setq continue nil
   9472                    offset (current-indentation)))
   9473            ) ;while
   9474          )
   9475         ((> css-beg 0)
   9476          ;;(message "CSS")
   9477          (cond
   9478            ((member (char-after) '(?\) ?\} ?\]))
   9479             (web-mode-go (web-mode-token-opening-paren-position pos (+ css-beg 8) ""))
   9480             (setq offset (current-indentation))
   9481             )
   9482            ((setq level (web-mode-bracket-level pos (+ css-beg 8)))
   9483             (setq offset (+ level web-mode-css-indent-offset))
   9484             )
   9485            (t
   9486             (setq offset (+ (web-mode-indentation-at-pos css-beg) web-mode-style-padding))
   9487             ) ;t
   9488            )
   9489          )
   9490         ((looking-at "[a-zA-Z-]+[ ]?=")
   9491          (re-search-backward "<[a-zA-Z]+[ ]*" beg t)
   9492          (setq offset (+ (current-column) (length (match-string-no-properties 0))))
   9493          )
   9494         ((looking-at-p "/>")
   9495          (search-backward "<" beg t)
   9496          (setq offset (current-column))
   9497          )
   9498         (t
   9499          (setq regexp "</?\\([a-zA-Z0-9]+\\)")
   9500          ;;(message "point=%S" (point))
   9501          (while (and continue (re-search-backward regexp beg t))
   9502            (setq tag (downcase (match-string-no-properties 1))
   9503                  end nil
   9504                  void nil)
   9505            (cond
   9506              ((eq (aref (match-string-no-properties 0) 1) ?/)
   9507               (setq end t))
   9508              ((web-mode-element-is-void tag)
   9509               (setq void t))
   9510              (t
   9511               (save-excursion
   9512                 (when (and (search-forward ">" pos t) (eq (char-before (1- (point))) ?\/))
   9513                   (setq void t))
   9514                 ) ;save-excursion
   9515               ) ;t
   9516              ) ;cond
   9517            (unless void
   9518              (setq val (or (lax-plist-get map tag) 0))
   9519              (setq val (if end (1- val) (1+ val)))
   9520              (setq map (lax-plist-put map tag val))
   9521              ;;(message "val=%S tag=%S end=%S | %S" val tag end (plist-get map tag))
   9522              (setq continue (not (> val 0)))
   9523              ) ;unless
   9524                                         ;(message "pos=%S tag=%S val=%S end=%S void=%S" (point) tag val end void)
   9525            ) ;while
   9526          (cond
   9527            ((> val 0)
   9528             ;;(message "point=%S" (point))
   9529             ;;(goto-char (1+ beg))
   9530             ;;(forward-char)
   9531             ;;(re-search-forward "[[:space:]]*")
   9532             (setq offset (+ (current-indentation) web-mode-markup-indent-offset)))
   9533            (t
   9534             (setq offset (current-indentation)))
   9535            )
   9536          ) ;t
   9537         ) ;cond
   9538       offset)))
   9539 
   9540 (defun web-mode-token-css-indentation (pos)
   9541   (save-excursion
   9542     (let (offset)
   9543       (goto-char pos)
   9544       (web-mode-part-token-beginning)
   9545       (setq offset (+ web-mode-css-indent-offset (current-indentation)))
   9546       ) ;let
   9547     ))
   9548 
   9549 (defun web-mode-relayql-indentation (pos &optional prefix)
   9550   (unless prefix (setq prefix "relayql"))
   9551   (let (beg offset level char)
   9552     (setq char (char-after))
   9553     (setq beg (web-mode-part-token-beginning-position pos))
   9554     (goto-char beg)
   9555     (cond
   9556       ((member char '(?\`))
   9557        (setq offset (current-indentation))
   9558        )
   9559       ((member char '(?\) ?\} ?\]))
   9560        (web-mode-go (web-mode-token-opening-paren-position pos beg prefix))
   9561        (setq offset (current-indentation))
   9562        )
   9563       ((setq level (web-mode-bracket-level pos beg))
   9564        (setq offset (+ level web-mode-code-indent-offset))
   9565        )
   9566       (t
   9567        (setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9568        )
   9569       )
   9570     offset))
   9571 
   9572 (defun web-mode-markup-indentation (pos)
   9573   (let (offset beg ret jsx-depth)
   9574     (when (and (setq jsx-depth (get-text-property pos 'jsx-depth))
   9575                (get-text-property pos 'jsx-beg)
   9576                (not (get-text-property pos 'tag-beg)))
   9577       (setq jsx-depth (1- jsx-depth)))
   9578     ;;(when (setq beg (web-mode-markup-indentation-origin pos jsx-depth))
   9579     (cond
   9580       ((not (setq beg (web-mode-markup-indentation-origin pos jsx-depth)))
   9581        (setq offset 0))
   9582       ((null (setq ret (web-mode-element-is-opened beg pos)))
   9583        (setq offset (web-mode-indentation-at-pos beg)))
   9584       ((eq ret t)
   9585        (setq offset (+ (web-mode-indentation-at-pos beg)
   9586                        web-mode-markup-indent-offset)))
   9587       (t
   9588        (setq offset ret))
   9589       ) ;cond
   9590     ;;(message "markup-indentation-origin=%S (jsx-depth=%S)" beg jsx-depth)
   9591     ;;) ;when beg
   9592     offset))
   9593 
   9594 (defun web-mode-css-indentation (pos initial-column language-offset language &optional limit)
   9595   (let ((open-ctx (web-mode-bracket-up pos language limit)) offset)
   9596     (cond
   9597       ((or (null open-ctx) (null (plist-get open-ctx :pos)))
   9598        (setq offset initial-column))
   9599       (t
   9600        (setq offset (+ (plist-get open-ctx :indentation) language-offset)))
   9601       ) ;cond
   9602     (cons (if (< offset initial-column) initial-column offset) open-ctx)
   9603     ))
   9604 
   9605 (defun web-mode-sql-indentation (pos initial-column language-offset language &optional limit)
   9606   (let ((open-ctx (web-mode-bracket-up pos language limit)) offset)
   9607     ;;(message "%S %S %S %S %S" pos (point) initial-column language-offset open-ctx)
   9608     (cond
   9609       ((and (not (null open-ctx)) (not (null (plist-get open-ctx :pos))))
   9610        (setq offset (+ (plist-get open-ctx :column) 1)))
   9611       ((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\\)")
   9612        (setq offset initial-column))
   9613       (t
   9614        (setq offset (+ initial-column language-offset)))
   9615       ) ;cond
   9616     (cons (if (< offset initial-column) initial-column offset) open-ctx)
   9617     ))
   9618 
   9619 (defun web-mode-markdown-indentation (pos initial-column language-offset language &optional limit)
   9620   (let (offset)
   9621     (save-excursion
   9622       (goto-char pos)
   9623       (setq offset (current-column))
   9624       ) ;save-excursion
   9625     ;;(message "%S %S %S %S" pos (point) initial-column language-offset)
   9626     (cons (if (<= offset initial-column) initial-column offset) nil)))
   9627 
   9628 (defun web-mode-stylus-indentation (pos initial-column language-offset language &optional limit)
   9629   (let (offset)
   9630     (save-excursion
   9631       (goto-char pos)
   9632       (setq offset (current-column))
   9633       (if (looking-at-p "[[:alnum:]-]+:")
   9634           (setq offset (+ initial-column language-offset))
   9635           (setq offset initial-column))
   9636       ) ;save-excursion
   9637     ;;(message "%S %S %S %S" pos (point) initial-column language-offset)
   9638     (cons (if (<= offset initial-column) initial-column offset) nil)))
   9639 
   9640 (defun web-mode-sass-indentation (pos initial-column language-offset language &optional limit)
   9641   (let (offset)
   9642     (save-excursion
   9643       (goto-char pos)
   9644       (setq offset (current-column))
   9645       (if (looking-at-p "[[:alnum:]-]+:")
   9646           (setq offset (+ initial-column language-offset))
   9647           (setq offset initial-column))
   9648       ) ;save-excursion
   9649     ;;(message "%S %S %S %S" pos (point) initial-column language-offset)
   9650     (cons (if (<= offset initial-column) initial-column offset) nil)))
   9651 
   9652 (defun web-mode-pug-indentation (pos initial-column language-offset language &optional limit)
   9653   nil
   9654   )
   9655 
   9656 (defun web-mode-javascript-indentation (pos initial-column language-offset language &optional limit)
   9657   (let (open-ctx indentation offset sub)
   9658     (setq open-ctx (web-mode-bracket-up pos language limit))
   9659     ;;(message "pos(%S) initial-column(%S) language-offset(%S) language(%S) limit(%S)" pos initial-column language-offset language limit)
   9660     ;;(message "javascript-indentation: %S\nchar=%c" open-ctx (plist-get open-ctx :char))
   9661     (setq indentation (plist-get open-ctx :indentation))
   9662     (when (and initial-column (> initial-column indentation))
   9663       (setq indentation initial-column)
   9664       )
   9665     (setq case-fold-search nil) ; #1006
   9666     (cond
   9667       ((or (null open-ctx) (null (plist-get open-ctx :pos)))
   9668        (setq offset initial-column))
   9669       ((and (member language '("javascript" "jsx" "ejs"))
   9670             (eq (plist-get open-ctx :char) ?\{)
   9671             (web-mode-looking-back "switch[ ]*" (plist-get open-ctx :pos)))
   9672        (setq sub (if (cdr (assoc "case-extra-offset" web-mode-indentation-params)) 0 1))
   9673        (cond
   9674          ((looking-at-p "case\\|default")
   9675           (setq offset (+ indentation (* language-offset (- 1 sub)))))
   9676          (t
   9677           (setq offset (+ indentation (* language-offset (- 2 sub)))))
   9678          ) ;cond switch
   9679        )
   9680       (t
   9681        (setq offset (+ indentation language-offset)))
   9682       ) ;cond
   9683     (setq case-fold-search t)
   9684     (cons (if (< offset initial-column) initial-column offset) open-ctx)
   9685     ))
   9686 
   9687 (defun web-mode-bracket-indentation (pos initial-column language-offset language &optional limit)
   9688   (save-excursion
   9689     (let* ((ctx (web-mode-bracket-up pos language limit))
   9690            (char (plist-get ctx :char))
   9691            (pos (plist-get ctx :pos))
   9692            (indentation (plist-get ctx :indentation)))
   9693       ;;(message "pos(%S) initial-column(%S) language-offset(%S) language(%S) limit(%S)" pos initial-column language-offset language limit)
   9694       ;;(message "bracket-up: %S, %c" ctx char)
   9695       (cond
   9696         ((null pos)
   9697          (setq indentation initial-column))
   9698         ((and (member language '("php"))
   9699               (eq char ?\{)
   9700               (web-mode-looking-back "switch[ ]*" pos)
   9701               (not (looking-at-p "case\\|default")))
   9702          (setq indentation (+ indentation (* language-offset 2)))
   9703          )
   9704         ((and (member language '("php"))
   9705               (eq char ?\{)
   9706               (goto-char pos)
   9707               (web-mode-looking-back "[)][ ]*" pos)
   9708               (search-backward ")")
   9709               (web-mode-block-opening-paren limit))
   9710          (setq indentation (+ (current-indentation) language-offset))
   9711          )
   9712         (t
   9713          (setq indentation (+ indentation language-offset))
   9714          )
   9715         ) ;cond
   9716       (cons (if (< indentation initial-column) initial-column indentation) ctx)
   9717       )))
   9718 
   9719 (defun web-mode-ruby-indentation (pos line initial-column language-offset limit)
   9720   (unless limit (setq limit nil))
   9721   (let (h offset prev-line prev-indentation open-ctx)
   9722     (setq open-ctx (web-mode-bracket-up pos "ruby" limit))
   9723     ;;(message "%S" open-ctx)
   9724     (if (plist-get open-ctx :pos)
   9725         (cond
   9726           ((web-mode-looking-at-p ".[ \t\n]+" (plist-get open-ctx :pos))
   9727            (setq offset (+ (plist-get open-ctx :indentation) language-offset)))
   9728           (t
   9729            (setq offset (1+ (plist-get open-ctx :column))))
   9730           )
   9731         (setq h (web-mode-previous-line pos limit))
   9732         (setq offset initial-column)
   9733         (when h
   9734           (setq prev-line (car h))
   9735           (setq prev-indentation (cdr h))
   9736           (cond
   9737             ((string-match-p ",$" prev-line)
   9738              (save-excursion
   9739                (goto-char limit)
   9740                (looking-at "<%=? [a-z]+ ")
   9741                (setq offset (+ initial-column (length (match-string-no-properties 0))))
   9742                ) ;save-excursion
   9743              )
   9744             ((string-match-p "^[ ]*\\(end\\|else\\|elsif\\|when\\)" line)
   9745              (setq offset (- prev-indentation language-offset))
   9746              )
   9747             ((string-match-p "[ ]+\\(do\\)" prev-line)
   9748              (setq offset (+ prev-indentation language-offset))
   9749              )
   9750             ((string-match-p "^[ ]*\\(when\\|if\\|else\\|elsif\\|unless\\|for\\|while\\|def\\|class\\)" prev-line)
   9751              (setq offset (+ prev-indentation language-offset))
   9752              )
   9753             (t
   9754              (setq offset prev-indentation)
   9755              )
   9756             )
   9757           ) ;when
   9758         ) ;if
   9759     offset))
   9760 
   9761 (defun web-mode-python-indentation (pos line initial-column language-offset limit)
   9762   (unless limit (setq limit nil))
   9763   (let (h offset prev-line prev-indentation ctx)
   9764     (setq ctx (web-mode-bracket-up pos "python" limit))
   9765     ;;(message "point-ctx=%S" ctx)
   9766     (if (plist-get ctx :pos)
   9767         (cond
   9768           ((web-mode-looking-at-p ".[ \t\n]+" (plist-get ctx :pos))
   9769            (setq offset (+ (plist-get ctx :indentation) language-offset)))
   9770           (t
   9771            (setq offset (1+ (plist-get ctx :column))))
   9772           )
   9773         ;; else
   9774         (setq h (web-mode-previous-line pos limit))
   9775         (setq offset initial-column)
   9776         (when h
   9777           (setq prev-line (car h))
   9778           (setq prev-indentation (cdr h))
   9779           (cond
   9780             ((string-match-p "^\\(pass\\|else\\|elif\\|when\\|except\\)" line)
   9781              (setq offset (- prev-indentation language-offset))
   9782              )
   9783             ((string-match-p "\\(if\\|else\\|elif\\|for\\|while\\|try\\|except\\)" prev-line)
   9784              (setq offset (+ prev-indentation language-offset))
   9785              )
   9786             (t
   9787              (setq offset prev-indentation)
   9788              )
   9789             ) ;cond
   9790           ) ;when
   9791         ) ;if
   9792     ;;offset
   9793     (if (< offset initial-column) initial-column offset)
   9794     ))
   9795 
   9796 (defun web-mode-lisp-indentation (pos point-ctx)
   9797   (let (offset open-ctx)
   9798     (setq open-ctx (web-mode-bracket-up pos "lsp" (plist-get point-ctx :reg-beg)))
   9799     ;;(message "point-ctx=%S" point-ctx)
   9800     ;;(message "open-ctx=%S" open-ctx)
   9801     (cond
   9802       ((null (plist-get open-ctx :pos))
   9803        (setq offset (plist-get point-ctx :reg-col)))
   9804       ((member (plist-get point-ctx :curr-char) '(?\( ?\)))
   9805        (if (web-mode-looking-at-p "((" (plist-get open-ctx :pos))
   9806            (setq offset (+ (plist-get open-ctx :column) 1))
   9807            (setq offset (+ (plist-get open-ctx :column) web-mode-code-indent-offset)))
   9808        )
   9809       (t
   9810        (goto-char (plist-get open-ctx :pos))
   9811        (forward-char)
   9812        (web-mode-rsf "[[:alnum:]-:]+ ")
   9813        (setq offset (current-column))
   9814        )
   9815       ) ;cond
   9816     offset))
   9817 
   9818 (defun web-mode-asp-indentation (pos line initial-column language-offset limit)
   9819   (unless limit (setq limit nil))
   9820   (let (h out prev-line prev-indentation)
   9821     (setq h (web-mode-previous-line pos limit))
   9822     (setq out initial-column)
   9823     (when h
   9824       (setq prev-line (car h))
   9825       (setq prev-indentation (cdr h))
   9826       ;;(message "line=%S" line)
   9827       (cond
   9828         ((string-match-p "''" line)
   9829          (setq out prev-indentation))
   9830         ;; ----------------------------------------------------------------------
   9831         ;; unindent
   9832         ((string-match-p "\\_<\\(\\(end \\(if\\|function\\|class\\|sub\\|with\\)\\)\\|else\\|elseif\\|next\\|loop\\)\\_>" line)
   9833          (setq out (- prev-indentation language-offset)))
   9834         ;; ----------------------------------------------------------------------
   9835         ;; select case statement
   9836         ((string-match-p "\\_<\\(select case\\)\\_>" line)
   9837          (setq out (- prev-indentation 0)))
   9838         ((string-match-p "\\_<\\(end select\\)" line)
   9839          (setq out (- prev-indentation (* 2 language-offset))))
   9840         ((and (string-match-p "\\_<\\(case\\)\\_>" line) (not (string-match-p "\\_<\\(select case\\)\\_>" prev-line)))
   9841          (setq out (- prev-indentation language-offset)))
   9842         ;; ----------------------------------------------------------------------
   9843         ;; do nothing
   9844         ((string-match-p "\\_<\\(\\(end \\(if\\|function\\|class\\|sub\\|select\\|with\\)\\)\\|loop\\( until\\| while\\)?\\)\\_>" prev-line)
   9845          (setq out (+ prev-indentation 0)))
   9846         ;; indent
   9847         ((string-match-p "\\_<\\(\\(select \\)?case\\|else\\|elseif\\|unless\\|for\\|class\\|with\\|do\\( until\\| while\\)?\\|while\\|\\(public \\|private \\)?\\(function\\|sub\\|class\\)\\)\\_>" prev-line)
   9848          (setq out (+ prev-indentation language-offset)))
   9849         ;; single line if statement
   9850         ((string-match-p "\\_<if\\_>.*\\_<then\\_>[ \t]*[[:alpha:]]+" prev-line)
   9851          (setq out (+ prev-indentation 0)))
   9852         ;; normal if statement
   9853         ((string-match-p "\\_<\\if\\_>" prev-line)
   9854          (setq out (+ prev-indentation language-offset)))
   9855         (t
   9856          (setq out prev-indentation))
   9857         )
   9858       ) ;when
   9859     out))
   9860 
   9861 (defun web-mode-block-previous-live-line ()
   9862   (save-excursion
   9863     (let ((continue t) (line "") (pos (point)))
   9864       (beginning-of-line)
   9865       (while (and continue (not (bobp)) (forward-line -1))
   9866         (when (not (web-mode-block-is-token-line))
   9867           (setq line (web-mode-trim (buffer-substring (point) (line-end-position)))))
   9868         (when (not (string= line ""))
   9869           (setq continue nil))
   9870         ) ;while
   9871       (if (string= line "")
   9872           (progn (goto-char pos) nil)
   9873           (cons line (current-indentation)))
   9874       )))
   9875 
   9876 (defun web-mode-part-is-opener (pos reg-beg)
   9877   (save-excursion
   9878     (save-match-data
   9879       (if (and pos
   9880                (web-mode-go (web-mode-part-opening-paren-position pos))
   9881                (>= (point) reg-beg)
   9882                (looking-back "\\(^\\|[ \t]\\)\\(if\\|for\\|while\\)[ ]*" (point-min)))
   9883           (current-indentation)
   9884           nil)
   9885       )))
   9886 
   9887 (defun web-mode-part-previous-live-line (reg-beg)
   9888   (unless reg-beg (setq reg-beg (point-min)))
   9889   ;;(message "reg-beg=%S" reg-beg)
   9890   (save-excursion
   9891     (let ((continue (> (point) reg-beg))
   9892           (line "")
   9893           bol-pos
   9894           eol-pos
   9895           pos)
   9896       (beginning-of-line)
   9897       (while (and continue (> (point) reg-beg) (forward-line -1))
   9898         (setq bol-pos (point)
   9899               eol-pos (line-end-position))
   9900         (when (> reg-beg bol-pos)
   9901           (setq bol-pos reg-beg))
   9902         (when (not (web-mode-part-is-token-line bol-pos))
   9903           (setq line (web-mode-trim (buffer-substring bol-pos eol-pos)))
   9904           (when (not (string= line "")) (setq continue nil))
   9905           ) ;when
   9906         ) ;while
   9907       (cond
   9908         ((string= line "")
   9909          nil)
   9910         (t
   9911          (setq continue t)
   9912          (setq pos (1- eol-pos))
   9913          (while (and (>= pos bol-pos) continue)
   9914            (cond
   9915              ((eq (char-after pos) ?\s)
   9916               (setq pos (1- pos)))
   9917              ((get-text-property pos 'part-token)
   9918               (setq pos (1- pos)))
   9919              (t
   9920               (setq continue nil))
   9921              ) ;cond
   9922            ) ;while
   9923          ;;(message "%S %S : %S" bol-pos eol-pos pos)
   9924          (setq line (web-mode-clean-part-line line))
   9925          (list line (current-indentation) pos))
   9926         ) ;cond
   9927       )))
   9928 
   9929 (defun web-mode-in-code-block (open close &optional prop)
   9930   (save-excursion
   9931     (let ((pos (point)) pos-open pos-close start end ret)
   9932       (when prop
   9933         (setq start pos
   9934               end pos)
   9935         (when (eq (get-text-property pos prop) (get-text-property (1- pos) prop))
   9936           (setq start (or (previous-single-property-change pos prop) (point-min))))
   9937         (when (eq (get-text-property pos prop) (get-text-property (1+ pos) prop))
   9938           (setq end (next-single-property-change pos prop)))
   9939         ;;        (message "start(%S) end(%S)" start end)
   9940         )
   9941       (setq ret (and (web-mode-sb open start t)
   9942                      (setq pos-open (point))
   9943                      (web-mode-sf close end t)
   9944                      (setq pos-close (point))
   9945                      (>= pos-close pos)))
   9946       (if ret
   9947           (cons pos-open pos-close)
   9948           ret)
   9949       )))
   9950 
   9951 (defun web-mode-clean-part-line (input)
   9952   (let ((out "")
   9953         (beg 0)
   9954         (keep t)
   9955         (n (length input)))
   9956     (dotimes (i n)
   9957       (if (or (get-text-property i 'block-side input)
   9958               (eq (get-text-property i 'part-token input) 'comment)
   9959               (eq (get-text-property i 'tag-type input) 'comment))
   9960           (when keep
   9961             (setq out (concat out (substring input beg i))
   9962                   beg 0
   9963                   keep nil))
   9964           (when (null keep)
   9965             (setq beg i
   9966                   keep t))
   9967           ) ;if
   9968       ) ;dotimes
   9969     (if (> beg 0) (setq out (concat out (substring input beg n))))
   9970     (setq out (if (= (length out) 0) input out))
   9971     (web-mode-trim out)
   9972     ))
   9973 
   9974 (defun web-mode-clean-block-line (input)
   9975   (let ((out "")
   9976         (beg 0)
   9977         (keep t)
   9978         (n (length input)))
   9979     (dotimes (i n)
   9980       (if (or (not (get-text-property i 'block-side input))
   9981               (member (get-text-property i 'block-token input)
   9982                       '(comment delimiter-beg delimiter-end)))
   9983           (when keep
   9984             (setq out (concat out (substring input beg i))
   9985                   beg 0
   9986                   keep nil))
   9987           (when (null keep)
   9988             (setq beg i
   9989                   keep t))
   9990           ) ;if
   9991       ) ;dotimes
   9992     (if (> beg 0) (setq out (concat out (substring input beg n))))
   9993     (setq out (if (= (length out) 0) input out))
   9994     (web-mode-trim out)
   9995     ;;    (message "%S [%s] > [%s]" beg input out)
   9996     ))
   9997 
   9998 (defun web-mode-language-at-pos (&optional pos)
   9999   (unless pos (setq pos (point)))
  10000   (cond
  10001     ((get-text-property pos 'block-side)
  10002      web-mode-engine)
  10003     ((get-text-property pos 'part-side)
  10004      (symbol-name (get-text-property pos 'part-side)))
  10005     (t
  10006      web-mode-content-type)
  10007     ) ;cond
  10008   )
  10009 
  10010 (defun web-mode-coord-position (line column)
  10011   (save-excursion
  10012     (when (stringp line) (setq line (string-to-number line)))
  10013     (when (stringp column) (setq column (string-to-number column)))
  10014     (goto-char (point-min))
  10015     (forward-line (1- line))
  10016     (move-to-column (1- column))
  10017     (point)))
  10018 
  10019 (defun web-mode-is-single-line-block (pos)
  10020   (= (web-mode-line-number (web-mode-block-beginning-position pos))
  10021      (web-mode-line-number (web-mode-block-end-position pos))))
  10022 
  10023 (defun web-mode-line-number (&optional pos)
  10024   (setq pos (or pos (point)))
  10025   (+ (count-lines 1 pos) (if (= (web-mode-column-at-pos pos) 0) 1 0)))
  10026 
  10027 (defun web-mode-block-is-control (pos)
  10028   (save-excursion
  10029     (let (control state controls pair)
  10030       (goto-char pos)
  10031       (setq controls (web-mode-block-controls-get pos))
  10032       (setq pair (car controls))
  10033       (cond
  10034         ((eq (car pair) 'inside)
  10035          )
  10036         ((eq (car pair) 'open)
  10037          (setq state t
  10038                control (cdr pair)))
  10039         ((eq (car pair) 'close)
  10040          (setq state nil
  10041                control (cdr pair)))
  10042         ) ;cond
  10043       ;;      (message "engine=%S control=%S state=%S" web-mode-engine control state)
  10044       (if control (cons control state) nil)
  10045       )))
  10046 
  10047 (defun web-mode-block-is-opening-control (pos)
  10048   (save-excursion
  10049     (let (controls pair)
  10050       (goto-char pos)
  10051       (if (and (setq controls (web-mode-block-controls-get pos))
  10052                (= (length controls) 1)
  10053                (setq pair (car controls))
  10054                (eq (car pair) 'open))
  10055           (cdr pair)
  10056           nil)
  10057       )))
  10058 
  10059 (defun web-mode-markup-indentation-origin (pos jsx-depth)
  10060   (save-excursion
  10061     (let* ((found (bobp))
  10062            (jsx-beg nil)
  10063            (types '(start end void))
  10064            (type nil))
  10065       (when jsx-depth
  10066         (setq jsx-beg (web-mode-jsx-depth-beginning-position pos jsx-depth)))
  10067       (while (not found)
  10068         (forward-line -1)
  10069         (if (bobp)
  10070             (setq pos (point)
  10071                   found t)
  10072             (back-to-indentation)
  10073             (when (and jsx-beg (< (point) jsx-beg))
  10074               (goto-char jsx-beg))
  10075             (setq pos (point))
  10076             (setq type (get-text-property pos 'tag-type))
  10077             (setq found (or (and (null jsx-depth)
  10078                                  (null (get-text-property pos 'part-side))
  10079                                  (get-text-property pos 'tag-beg)
  10080                                  (member type types)
  10081                                  (null (get-text-property (1- pos) 'invisible)))
  10082                             (and (null jsx-depth)
  10083                                  (null (get-text-property pos 'part-side))
  10084                                  (eq (get-text-property pos 'tag-type) 'comment)
  10085                                  (web-mode-looking-at-p "<!--#\\(endif\\|if\\)" pos)
  10086                                  (null (get-text-property (1- pos) 'invisible)))
  10087                             (and jsx-depth
  10088                                  (get-text-property pos 'tag-beg)
  10089                                  (member type types)
  10090                                  (null (get-text-property (1- pos) 'invisible))
  10091                                  (eq (get-text-property pos 'jsx-depth) jsx-depth))
  10092                             (and (get-text-property pos 'block-beg)
  10093                                  (not type)
  10094                                  (web-mode-block-is-control pos)
  10095                                  (not (looking-at-p "{% commen\\|@break")))))
  10096             ) ;if
  10097         ) ;while
  10098       ;;(message "indent-origin=%S" pos)
  10099       pos)))
  10100 
  10101 ;;TODO : prendre en compte part-token
  10102 ;; state=t <=> start tag
  10103 (defun web-mode-element-is-opened (pos limit)
  10104   (let (tag
  10105         last-end-tag
  10106         tag-pos block-pos
  10107         state
  10108         n
  10109         ret
  10110         (continue t)
  10111         controls
  10112         control
  10113         (buffer (current-buffer))
  10114         (h (make-hash-table :test 'equal))
  10115         (h2 (make-hash-table :test 'equal)))
  10116 
  10117     ;;    (message "pos-ori=%S limit=%S" pos limit)
  10118 
  10119     (while continue
  10120       (setq control nil
  10121             controls nil
  10122             last-end-tag nil
  10123             tag nil)
  10124 
  10125       (cond
  10126         ((and (eq (get-text-property pos 'tag-type) 'comment)
  10127               (web-mode-looking-at "<!--#\\(endif\\|if\\)" pos))
  10128          ;;(message "pos=%S" pos)
  10129          (setq tag "#if")
  10130          (setq n (gethash tag h 0))
  10131          (if (string= (match-string-no-properties 1) "if")
  10132              (puthash tag (1+ n) h)
  10133              (puthash tag (1- n) h))
  10134          ;;(setq tag-pos pos)
  10135          )
  10136         ((get-text-property pos 'tag-beg)
  10137          (when (member (get-text-property pos 'tag-type) '(start end))
  10138            (setq tag (get-text-property pos 'tag-name)
  10139                  state (eq (get-text-property pos 'tag-type) 'start))
  10140            (if (null state) (setq last-end-tag (cons tag pos)))
  10141            (setq n (gethash tag h 0))
  10142            (cond
  10143              ((null state)
  10144               (when (> n 0) (puthash tag (1- n) h))
  10145               (puthash tag (1- n) h2))
  10146              ((member tag web-mode-offsetless-elements)
  10147               )
  10148              (t
  10149               (puthash tag (1+ n) h)
  10150               (puthash tag (1+ n) h2))
  10151              ) ;cond
  10152            ) ;when
  10153          (when (setq pos (web-mode-tag-end-position pos))
  10154            (setq tag-pos nil)
  10155            (when (and block-pos (> pos block-pos))
  10156              (setq block-pos nil))
  10157            ) ;when
  10158          )
  10159         ((and web-mode-enable-control-block-indentation
  10160               (get-text-property pos 'block-beg))
  10161          (when (setq controls (web-mode-block-controls-get pos))
  10162            (dolist (control controls)
  10163              (setq tag (cdr control))
  10164              (setq n (gethash tag h 0))
  10165              (cond
  10166                ((eq (car control) 'inside)
  10167                 )
  10168                ((eq (car control) 'open)
  10169                 (puthash tag (1+ n) h))
  10170                ((> n 0)
  10171                 (puthash tag (1- n) h))
  10172                ) ;cond
  10173              ) ;dolist
  10174            )
  10175          (when (setq pos (web-mode-block-end-position pos))
  10176            (setq block-pos nil)
  10177            (when (and tag-pos (> pos tag-pos))
  10178              (setq tag-pos nil))
  10179            )
  10180          )
  10181         ) ;cond
  10182 
  10183       ;;      (message "tag=%S end-pos=%S" tag pos)
  10184 
  10185       (when (and pos (< pos limit))
  10186         (when (or (null tag-pos) (>= pos tag-pos))
  10187           (setq tag-pos (web-mode-tag-next-position pos limit))
  10188           ;;          (message "from=%S tag-next-pos=%S" pos tag-pos)
  10189           )
  10190         (when (or (null block-pos) (>= pos block-pos))
  10191           (setq block-pos (web-mode-block-next-position pos limit))
  10192           ;;          (message "from=%S block-next-pos=%S" pos block-pos)
  10193           )
  10194         )
  10195 
  10196       (cond
  10197         ((null pos)
  10198          )
  10199         ((and (null tag-pos)
  10200               (null block-pos))
  10201          (setq pos nil))
  10202         ((and tag-pos block-pos)
  10203          (if (< tag-pos block-pos)
  10204              (progn
  10205                (setq pos tag-pos)
  10206                (setq tag-pos nil))
  10207              (setq pos block-pos)
  10208              (setq block-pos nil))
  10209          )
  10210         ((null tag-pos)
  10211          (setq pos block-pos)
  10212          (setq block-pos nil))
  10213         (t
  10214          (setq pos tag-pos)
  10215          (setq tag-pos nil))
  10216         )
  10217 
  10218       (when (or (null pos)
  10219                 (>= pos limit))
  10220         (setq continue nil))
  10221       ) ;while
  10222 
  10223     ;;(message "hashtable=%S" h)
  10224     (maphash (lambda (k v) (if (> v 0) (setq ret t))) h)
  10225 
  10226     (when (and (null ret)
  10227                last-end-tag
  10228                (> (hash-table-count h2) 1)
  10229                (< (gethash (car last-end-tag) h2) 0))
  10230       ;;      (message "last-end-tag=%S" last-end-tag)
  10231       (save-excursion
  10232         (goto-char (cdr last-end-tag))
  10233         (web-mode-tag-match)
  10234         (when (not (= (point) (cdr last-end-tag)))
  10235           (setq n (point))
  10236           (back-to-indentation)
  10237           (if (= n (point)) (setq ret (current-indentation))))
  10238         ))
  10239 
  10240     ret))
  10241 
  10242 (defun web-mode-previous-line (pos limit)
  10243   (save-excursion
  10244     (let (beg end line (continue t))
  10245       (goto-char pos)
  10246       (while continue
  10247         (forward-line -1)
  10248         (setq end (line-end-position))
  10249         (setq line (buffer-substring-no-properties (point) end))
  10250         (when (or (not (string-match-p "^[ \t]*$" line))
  10251                   (bobp)
  10252                   (<= (point) limit))
  10253           (setq continue nil))
  10254         )
  10255       (if (<= (point) limit)
  10256           ;;todo : affiner (le + 3 n est pas générique cf. <?php <% <%- etc.)
  10257           (setq beg (if (< (+ limit 3) end) (+ limit 3) end))
  10258           (setq beg (line-beginning-position))
  10259           ) ;if
  10260       (setq line (buffer-substring-no-properties beg end))
  10261       (cons line (current-indentation))
  10262       )))
  10263 
  10264 (defun web-mode-bracket-up (pos language &optional limit)
  10265   (unless limit (setq limit nil))
  10266   ;;(message "pos(%S) language(%S) limit(%S)" pos language limit)
  10267   (save-excursion
  10268     (goto-char pos)
  10269     (let ((continue t)
  10270           (regexp "[\]\[}{)(]")
  10271           (char nil)
  10272           (column nil)
  10273           (indentation nil)
  10274           (map nil)
  10275           (key nil)
  10276           (value 0)
  10277           (open '(?\( ?\{ ?\[))
  10278           (searcher nil)
  10279           (opener nil))
  10280       (cond
  10281         ((get-text-property pos 'block-side)
  10282          (setq searcher 'web-mode-block-rsb
  10283                opener 'web-mode-block-opening-paren-position))
  10284         (t
  10285          (setq searcher 'web-mode-part-rsb
  10286                opener 'web-mode-part-opening-paren-position))
  10287         )
  10288       (while (and continue (funcall searcher regexp limit))
  10289         (setq char (aref (match-string-no-properties 0) 0))
  10290         (setq key (cond ((eq char ?\)) ?\()
  10291                         ((eq char ?\}) ?\{)
  10292                         ((eq char ?\]) ?\[)
  10293                         (t             char)))
  10294         (setq value (or (plist-get map key) 0))
  10295         (setq value (if (member char open) (1+ value) (1- value)))
  10296         (setq map (plist-put map key value))
  10297         (setq continue (< value 1))
  10298         ;;(message "pos=%S char=%c key=%c value=%S map=%S" (point) char key value map)
  10299         ) ;while
  10300       (setq column (current-column)
  10301             indentation (current-indentation))
  10302       (when (and (> value 0)
  10303                  (eq char ?\{)
  10304                  (looking-back ")[ ]*" (point-min)))
  10305         (search-backward ")")
  10306         (when (setq pos (funcall opener (point) limit))
  10307           (goto-char pos)
  10308           ;;(message "pos=%S" pos)
  10309           (setq indentation (current-indentation)))
  10310         ) ;when
  10311       (list :pos (if (> value 0) (point) nil)
  10312             :char char
  10313             :column column
  10314             :indentation indentation)
  10315       ) ;let
  10316     ))
  10317 
  10318 (defun web-mode-count-char-in-string (char string)
  10319   (let ((n 0))
  10320     (dotimes (i (length string))
  10321       (if (eq (elt string i) char)
  10322           (setq n (1+ n))))
  10323     n))
  10324 
  10325 (defun web-mode-mark-and-expand ()
  10326   "Mark and expand."
  10327   (interactive)
  10328   (web-mode-mark (point)))
  10329 
  10330 (defun web-mode-mark (pos)
  10331   (let ((beg pos) (end pos) prop reg-beg boundaries)
  10332 
  10333     (if mark-active
  10334         (setq reg-beg (region-beginning))
  10335         (setq web-mode-expand-initial-pos (point)
  10336               web-mode-expand-initial-scroll (window-start))
  10337         )
  10338 
  10339     ;; (message "regs=%S %S %S %S" (region-beginning) (region-end) (point-min) (point-max))
  10340     ;; (message "before=%S" web-mode-expand-previous-state)
  10341 
  10342     (cond
  10343 
  10344       ((and mark-active
  10345             (= (region-beginning) (point-min))
  10346             (or (= (region-end) (point-max))
  10347                 (= (1+ (region-end)) (point-max))))
  10348        (deactivate-mark)
  10349        (goto-char (or web-mode-expand-initial-pos (point-min)))
  10350        (setq web-mode-expand-previous-state nil)
  10351        (when web-mode-expand-initial-scroll
  10352          (set-window-start (selected-window) web-mode-expand-initial-scroll))
  10353        )
  10354 
  10355       ((string= web-mode-expand-previous-state "elt-content")
  10356        (web-mode-element-parent)
  10357        ;;(message "pos=%S" (point))
  10358        (web-mode-element-select)
  10359        (setq web-mode-expand-previous-state "html-parent"))
  10360 
  10361       ((and (member (get-text-property pos 'block-token) '(comment string))
  10362             (not (member web-mode-expand-previous-state '("block-token" "block-body" "block-side"))))
  10363        (when (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token))
  10364          (setq beg (or (previous-single-property-change pos 'block-token) (point-min))))
  10365        (when (eq (get-text-property pos 'block-token) (get-text-property (1+ pos) 'block-token))
  10366          (setq end (next-single-property-change pos 'block-token)))
  10367        (set-mark beg)
  10368        (goto-char end)
  10369        (exchange-point-and-mark)
  10370        (setq web-mode-expand-previous-state "block-token"))
  10371 
  10372       ((and (get-text-property pos 'block-side)
  10373             (not (member web-mode-expand-previous-state '("block-body" "block-side")))
  10374             (not (member web-mode-engine '(django go)))
  10375             (setq boundaries (web-mode-in-code-block "{" "}" 'block-side)))
  10376        (set-mark (car boundaries))
  10377        (goto-char (cdr boundaries))
  10378        (exchange-point-and-mark)
  10379        (setq web-mode-expand-previous-state "block-body"))
  10380 
  10381       ((and (get-text-property pos 'block-side)
  10382             (not (member web-mode-expand-previous-state '("block-side"))))
  10383        (set-mark (web-mode-block-beginning-position pos))
  10384        (goto-char (1+ (web-mode-block-end-position pos)))
  10385        (exchange-point-and-mark)
  10386        (setq web-mode-expand-previous-state "block-side"))
  10387 
  10388       ((and (get-text-property pos 'part-token)
  10389             (not (string= web-mode-expand-previous-state "part-token")))
  10390        (when (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token))
  10391          (setq beg (previous-single-property-change pos 'part-token)))
  10392        (when (eq (get-text-property pos 'part-token) (get-text-property (1+ pos) 'part-token))
  10393          (setq end (next-single-property-change pos 'part-token)))
  10394        (set-mark beg)
  10395        (goto-char end)
  10396        (exchange-point-and-mark)
  10397        (setq web-mode-expand-previous-state "part-token"))
  10398 
  10399       ((and (get-text-property pos 'part-side)
  10400             (not (string= web-mode-expand-previous-state "client-part"))
  10401             (setq boundaries (web-mode-in-code-block "{" "}" 'part-side)))
  10402        (set-mark (car boundaries))
  10403        (goto-char (cdr boundaries))
  10404        (exchange-point-and-mark)
  10405        (setq web-mode-expand-previous-state "client-part"))
  10406 
  10407       ((and (get-text-property pos 'part-side)
  10408             (not (string= web-mode-expand-previous-state "part-side")))
  10409        (when (eq (get-text-property pos 'part-side) (get-text-property (1- pos) 'part-side))
  10410          (setq beg (previous-single-property-change pos 'part-side)))
  10411        (when (eq (get-text-property pos 'part-side) (get-text-property (1+ pos) 'part-side))
  10412          (setq end (next-single-property-change pos 'part-side)))
  10413        (when (eq (char-after beg) ?\n)
  10414          (setq beg (1+ beg)))
  10415        (set-mark beg)
  10416        (goto-char end)
  10417        (when (looking-back "^[ \t]+" (point-min))
  10418          (beginning-of-line))
  10419        (exchange-point-and-mark)
  10420        (setq web-mode-expand-previous-state "part-side"))
  10421 
  10422       ((and (get-text-property pos 'tag-attr)
  10423             (not (member web-mode-expand-previous-state '("html-attr" "html-tag"))))
  10424        (web-mode-attribute-select pos)
  10425        (setq web-mode-expand-previous-state "html-attr"))
  10426 
  10427       ((and (eq (get-text-property pos 'tag-type) 'comment)
  10428             (not (member web-mode-expand-previous-state '("html-tag" "html-comment" "html-elt" "html-parent"))))
  10429        (web-mode-tag-select)
  10430        (setq web-mode-expand-previous-state "html-comment"))
  10431 
  10432       ((and (get-text-property pos 'tag-name)
  10433             (not (member web-mode-expand-previous-state '("html-tag" "html-elt" "html-parent"))))
  10434        (web-mode-tag-select)
  10435        (setq web-mode-expand-previous-state "html-tag"))
  10436 
  10437       ((and (get-text-property pos 'tag-beg)
  10438             (string= web-mode-expand-previous-state "html-tag"))
  10439        (web-mode-element-select)
  10440        (setq web-mode-expand-previous-state "html-elt"))
  10441 
  10442       (t
  10443        (cond
  10444          ((not (web-mode-element-parent))
  10445           (push-mark (point))
  10446           (push-mark (point-max) nil t)
  10447           (goto-char (point-min))
  10448           (setq web-mode-expand-previous-state "mark-whole"))
  10449          ((not (= (web-mode-tag-end-position (point)) (1- beg)))
  10450           (web-mode-element-content-select)
  10451           (setq web-mode-expand-previous-state "elt-content"))
  10452          (t
  10453           (web-mode-element-select)
  10454           (setq web-mode-expand-previous-state "html-parent"))
  10455          )
  10456        ) ;t
  10457 
  10458       ) ;cond
  10459 
  10460     ;;(message "w=%S" (window-end))
  10461     ;;(message "after=%S" web-mode-expand-previous-state)
  10462 
  10463     ))
  10464 
  10465 (defun web-mode-block-kill ()
  10466   "Kill the current block."
  10467   (interactive)
  10468   (web-mode-block-select)
  10469   (when mark-active
  10470     (kill-region (region-beginning) (region-end))))
  10471 
  10472 (defun web-mode-block-select ()
  10473   "Select the current block."
  10474   (interactive)
  10475   (let (beg)
  10476     (when (setq beg (web-mode-block-beginning-position (point)))
  10477       (goto-char beg)
  10478       (set-mark (point))
  10479       (web-mode-block-end)
  10480       (exchange-point-and-mark))
  10481     beg))
  10482 
  10483 (defun web-mode-tag-select ()
  10484   "Select the current html tag."
  10485   (interactive)
  10486   (let (beg)
  10487     (when (setq beg (web-mode-tag-beginning-position (point)))
  10488       (goto-char beg)
  10489       (set-mark (point))
  10490       (web-mode-tag-end)
  10491       (exchange-point-and-mark))
  10492     beg))
  10493 
  10494 (defun web-mode-element-content-select ()
  10495   "Select the content of a html element."
  10496   (interactive)
  10497   (let (pos beg end)
  10498     (web-mode-element-select)
  10499     (when mark-active
  10500       (setq pos (point))
  10501       (deactivate-mark)
  10502       (web-mode-tag-match)
  10503       (setq end (point))
  10504       (goto-char pos)
  10505       (web-mode-tag-end)
  10506       (set-mark (point))
  10507       (goto-char end)
  10508       (exchange-point-and-mark)
  10509       )))
  10510 
  10511 (defun web-mode-element-select ()
  10512   "Select the current html element (including opening and closing tags)."
  10513   (interactive)
  10514   (let* ((pos (point))
  10515          (type (get-text-property pos 'tag-type)))
  10516     (cond
  10517       ((not type)
  10518        (web-mode-element-parent)
  10519        (unless (= (point) pos) (web-mode-element-select)))
  10520       ((member type '(start void))
  10521        (web-mode-tag-beginning)
  10522        (set-mark (point))
  10523        (web-mode-tag-match)
  10524        (web-mode-tag-end)
  10525        (exchange-point-and-mark))
  10526       (t
  10527        (web-mode-tag-match)
  10528        (set-mark (point))
  10529        (web-mode-tag-match)
  10530        (web-mode-tag-end)
  10531        (exchange-point-and-mark))
  10532       )))
  10533 
  10534 (defun web-mode-element-is-collapsed (&optional pos)
  10535   (unless pos (setq pos (point)))
  10536   (let (boundaries)
  10537     (and (setq boundaries (web-mode-element-boundaries pos))
  10538          (or (= (car (car boundaries)) (car (cdr boundaries)))
  10539              (= (cdr (car boundaries)) (1- (car (cdr boundaries)))))
  10540          )))
  10541 
  10542 (defun web-mode-element-contract ()
  10543   "Flatten elements."
  10544   (interactive)
  10545   (let (beg end (continue t) replacement boundaries)
  10546     (cond
  10547       ((or (not (get-text-property (point) 'tag-type))
  10548            (not (member (get-text-property (point) 'tag-type) '(start end))))
  10549        (web-mode-element-parent))
  10550       ((eq (get-text-property (point) 'tag-type) 'end)
  10551        (web-mode-tag-match))
  10552       ) ;cond
  10553     (setq boundaries (web-mode-element-boundaries (point)))
  10554     (setq beg (car (car boundaries))
  10555           end (cdr (cdr boundaries)))
  10556     (goto-char beg)
  10557     ;;(message "beg(%S) end(%S)" beg end)
  10558     (while continue
  10559       (if (or (not (re-search-forward ">[ \t\r\n]+\\|[ \t\r\n]+<"))
  10560               (>= (point) end))
  10561           (setq continue nil)
  10562           (setq end (+ (- end (length (match-string-no-properties 0))) 1))
  10563           (setq replacement (if (eq (char-before) ?\<) "<" ">"))
  10564           (replace-match replacement nil nil)
  10565           ;;(message "end(%S)" end))
  10566           )
  10567       ) ;while
  10568     (goto-char beg)
  10569     ))
  10570 
  10571 (defun web-mode-element-extract ()
  10572   "Flatten element."
  10573   (interactive)
  10574   (let (beg end (continue t) save boundaries)
  10575     (cond
  10576       ((or (not (get-text-property (point) 'tag-type))
  10577            (not (member (get-text-property (point) 'tag-type) '(start end))))
  10578        (web-mode-element-parent))
  10579       ((eq (get-text-property (point) 'tag-type) 'end)
  10580        (web-mode-tag-match))
  10581       ) ;cond
  10582     (setq boundaries (web-mode-element-boundaries (point)))
  10583     (setq beg (car (car boundaries))
  10584           end (cdr (cdr boundaries)))
  10585     (goto-char beg)
  10586     (while continue
  10587       (if (or (not (and (or (get-text-property (point) 'tag-type) (web-mode-tag-next))
  10588                         (web-mode-tag-end)))
  10589               (>= (point) end))
  10590           (setq continue nil)
  10591           (setq save (point))
  10592           ;;(message "point(%S)" (point))
  10593           (skip-chars-forward "\n\t ")
  10594           (when (get-text-property (point) 'tag-type)
  10595             (newline)
  10596             (indent-according-to-mode)
  10597             (setq end (+ end (- (point) save))))
  10598           ) ;if
  10599       ) ;while
  10600     (goto-char beg)
  10601     ))
  10602 
  10603 (defun web-mode-element-transpose ()
  10604   "Transpose two html elements."
  10605   (interactive)
  10606   (let (pos start1 end1 start2 end2)
  10607     (save-excursion
  10608       (setq pos (point))
  10609       (cond
  10610         ((get-text-property pos 'tag-type)
  10611          (setq start1 (web-mode-element-beginning-position pos)
  10612                end1 (1+ (web-mode-element-end-position pos)))
  10613          )
  10614         ((setq start1 (web-mode-element-parent-position pos))
  10615          (setq end1 (1+ (web-mode-element-end-position pos)))
  10616          )
  10617         ) ;cond
  10618       (when (and start1 end1 (> end1 0))
  10619         (goto-char end1)
  10620         (unless (get-text-property (point) 'tag-beg)
  10621           (skip-chars-forward "\n\t "))
  10622         (when (get-text-property (point) 'tag-beg)
  10623           (setq start2 (web-mode-element-beginning-position (point))
  10624                 end2 (1+ (web-mode-element-end-position (point))))
  10625           )
  10626         )
  10627       (transpose-regions start1 end1 start2 end2)
  10628       ) ;save-excursion
  10629     start2))
  10630 
  10631 (defun web-mode-element-children-comment (&optional pos)
  10632   "Comment all the children of the current html element."
  10633   (interactive)
  10634   (unless pos (setq pos (point)))
  10635   (save-excursion
  10636     (dolist (child (reverse (web-mode-element-children pos)))
  10637       (goto-char child)
  10638       (web-mode-comment (point)))
  10639     ))
  10640 
  10641 (defun web-mode-element-mute-blanks ()
  10642   "Mute blanks."
  10643   (interactive)
  10644   (let (pos parent beg end children elt)
  10645     (setq pos (point))
  10646     (save-excursion
  10647       (when (and (setq parent (web-mode-element-boundaries pos))
  10648                  (web-mode-element-child-position (point)))
  10649         (setq children (reverse (web-mode-element-children)))
  10650         (goto-char (car (cdr parent)))
  10651         (dolist (child children)
  10652           (setq elt (web-mode-element-boundaries child))
  10653           (when (> (point) (1+ (cddr elt)))
  10654             (when (and (not (eq (get-text-property (point) 'part-token) 'comment))
  10655                        (not (eq (get-text-property (1+ (cddr elt)) 'part-token) 'comment)))
  10656               (web-mode-insert-text-at-pos "-->" (point))
  10657               (web-mode-insert-text-at-pos "<!--" (1+ (cddr elt))))
  10658             )
  10659           (goto-char child)
  10660           )
  10661         (when (and (> (point) (1+ (cdr (car parent))))
  10662                    (not (eq (get-text-property (point) 'part-token) 'comment))
  10663                    (not (eq (get-text-property (1+ (cdr (car parent))) 'part-token) 'comment)))
  10664           (web-mode-insert-text-at-pos "-->" (point))
  10665           (web-mode-insert-text-at-pos "<!--" (1+ (cdr (car parent)))))
  10666         ) ;when
  10667       )))
  10668 
  10669 (defun web-mode-element-children (&optional pos)
  10670   (unless pos (setq pos (point)))
  10671   (let ((continue t) (i 0) child children)
  10672     (save-excursion
  10673       (when (and (member (get-text-property pos 'tag-type) '(start end))
  10674                  (setq child (web-mode-element-child-position pos)))
  10675         (while continue
  10676           (cond
  10677             ((> (setq i (1+ i)) 100)
  10678              (setq continue nil)
  10679              (message "element-children ** warning **"))
  10680             ((= i 1)
  10681              (goto-char child))
  10682             ((web-mode-element-sibling-next)
  10683              )
  10684             (t
  10685              (setq continue nil))
  10686             ) ;cond
  10687           (when continue
  10688             (setq children (append children (list (point)))))
  10689           ) ;while
  10690         ) ;when
  10691       ) ;save-excursion
  10692     ;;(message "%S" children)
  10693     children))
  10694 
  10695 (defun web-mode-property-boundaries (prop &optional pos)
  10696   "property boundaries (cdr is 1+)"
  10697   (unless pos (setq pos (point)))
  10698   (let (beg end val)
  10699     (setq val (get-text-property pos prop))
  10700     (if (null val)
  10701         val
  10702         (if (or (bobp)
  10703                 (not (eq (get-text-property (1- pos) prop) val)))
  10704             (setq beg pos)
  10705             (setq beg (previous-single-property-change pos prop))
  10706             (when (null beg) (setq beg (point-min))))
  10707         (if (or (eobp)
  10708                 (not (eq (get-text-property (1+ pos) prop) val)))
  10709             (setq end pos)
  10710             (setq end (next-single-property-change pos prop))
  10711             (when (null end) (setq end (point-min))))
  10712         (cons beg end))))
  10713 
  10714 (defun web-mode-content-boundaries (&optional pos)
  10715   (unless pos (setq pos (point)))
  10716   (let (beg end)
  10717     (setq beg (or (previous-property-change pos (current-buffer))
  10718                   (point-max)))
  10719     (setq end (or (next-property-change pos (current-buffer))
  10720                   (point-min)))
  10721     (while (and (< beg end) (member (char-after beg) '(?\s ?\n)))
  10722       (setq beg (1+ beg)))
  10723     (while (and (> end beg) (member (char-after (1- end)) '(?\s ?\n)))
  10724       (setq end (1- end)))
  10725     ;;    (message "beg(%S) end(%S)" beg end)
  10726     (cons beg end)
  10727     ))
  10728 
  10729 (defun web-mode-element-boundaries (&optional pos)
  10730   "Return ((start-tag-beg . start-tag-end) . (end-tag-beg . end-tag-end))
  10731 First level car and cdr are the same with void elements.
  10732 Pos should be in a tag."
  10733   (unless pos (setq pos (point)))
  10734   (let (start-tag-beg start-tag-end end-tag-beg end-tag-end)
  10735     (cond
  10736       ((eq (get-text-property pos 'tag-type) 'start)
  10737        (setq start-tag-beg (web-mode-tag-beginning-position pos)
  10738              start-tag-end (web-mode-tag-end-position pos))
  10739        (when (setq pos (web-mode-tag-match-position pos))
  10740          (setq end-tag-beg pos
  10741                end-tag-end (web-mode-tag-end-position pos)))
  10742        )
  10743       ((eq (get-text-property pos 'tag-type) 'end)
  10744        (setq end-tag-beg (web-mode-tag-beginning-position pos)
  10745              end-tag-end (web-mode-tag-end-position pos))
  10746        (when (setq pos (web-mode-tag-match-position pos))
  10747          (setq start-tag-beg pos
  10748                start-tag-end (web-mode-tag-end-position pos)))
  10749        )
  10750       ((eq (get-text-property pos 'tag-type) 'void)
  10751        (setq start-tag-beg (web-mode-tag-beginning-position pos)
  10752              start-tag-end (web-mode-tag-end-position pos))
  10753        (setq end-tag-beg start-tag-beg
  10754              end-tag-end start-tag-end)
  10755        )
  10756       ) ;cond
  10757     (if (and start-tag-beg start-tag-end end-tag-beg end-tag-end)
  10758         (cons (cons start-tag-beg start-tag-end) (cons end-tag-beg end-tag-end))
  10759         nil)
  10760     ))
  10761 
  10762 (defun web-mode-surround ()
  10763   "Surround each line of the current REGION with a start/end tag."
  10764   (interactive)
  10765   (when mark-active
  10766     (let (beg end line-beg line-end pos tag tag-start tag-end)
  10767       (save-excursion
  10768         (combine-after-change-calls
  10769           (setq tag (web-mode-element-complete)
  10770                 tag-start (concat "<" tag ">")
  10771                 tag-end (concat "</" tag ">")
  10772                 pos (point)
  10773                 beg (region-beginning)
  10774                 end (region-end)
  10775                 line-beg (web-mode-line-number beg)
  10776                 line-end (web-mode-line-number end))
  10777           (goto-char end)
  10778           (unless (bolp)
  10779             (insert tag-end)
  10780             (back-to-indentation)
  10781             (when (> beg (point))
  10782               (goto-char beg))
  10783             (insert tag-start))
  10784           (while (> line-end line-beg)
  10785             (forward-line -1)
  10786             (setq line-end (1- line-end))
  10787             (unless (looking-at-p "[[:space:]]*$")
  10788               (end-of-line)
  10789               (insert tag-end)
  10790               (back-to-indentation)
  10791               (when (> beg (point))
  10792                 (goto-char beg))
  10793               (insert tag-start))
  10794             ) ;while
  10795           (deactivate-mark)
  10796           ) ;combine-after-change-calls
  10797         ) ;save-excursion
  10798       )))
  10799 
  10800 (defun web-mode-lify-region ()
  10801   "Transform current REGION in an html list (<li>line1</li>...)"
  10802   (interactive)
  10803   (let (beg end lines)
  10804     (save-excursion
  10805       (combine-after-change-calls
  10806         (when  mark-active
  10807           (setq beg (region-beginning)
  10808                 end (region-end))
  10809           (setq lines (buffer-substring beg end))
  10810           (kill-region beg end)
  10811           (setq lines (replace-regexp-in-string "^[ \t]*" "<li>" lines))
  10812           (setq lines (replace-regexp-in-string "$" "</li>" lines))
  10813           (web-mode-insert-and-indent lines)
  10814           ) ;when
  10815         ) ;combine-after-change-calls
  10816       ) ;save-excursion
  10817     ) ;let
  10818   )
  10819 
  10820 (defun web-mode-element-complete (&optional prompt)
  10821   "Completes for an element tag."
  10822   (completing-read
  10823    (or prompt "Tag name: ")
  10824    (append
  10825     web-mode-tag-list
  10826     web-mode-tag-history)
  10827    nil nil nil 'web-mode-tag-history))
  10828 
  10829 (defun web-mode-element-wrap (&optional tag-name)
  10830   "Wrap current REGION with start and end tags.
  10831 Prompt user if TAG-NAME isn't provided."
  10832   (interactive)
  10833   (let (beg end pos tag sep)
  10834     (save-excursion
  10835       (setq tag (or tag-name (web-mode-element-complete)))
  10836       (setq pos (point))
  10837       (cond
  10838         (mark-active
  10839          (setq beg (region-beginning)
  10840                end (region-end)))
  10841         ((get-text-property pos 'tag-type)
  10842          (setq beg (web-mode-element-beginning-position pos)
  10843                end (1+ (web-mode-element-end-position pos))))
  10844         ((setq beg (web-mode-element-parent-position pos))
  10845          (setq end (1+ (web-mode-element-end-position pos))))
  10846         )
  10847       ;;      (message "beg(%S) end(%S)" beg end)
  10848       (when (and beg end (> end 0))
  10849         (setq sep (if (get-text-property beg 'tag-beg) "\n" ""))
  10850         (web-mode-insert-text-at-pos (concat sep "</" tag ">") end)
  10851         (web-mode-insert-text-at-pos (concat "<" tag ">" sep) beg)
  10852         (when (string= sep "\n") (indent-region beg (+ end (* (+ 3 (length tag)) 2))))
  10853         )
  10854       ) ;save-excursion
  10855     (web-mode-go beg)))
  10856 
  10857 (defun web-mode-element-vanish (&optional arg)
  10858   "Vanish the current html element. The content of the element is kept."
  10859   (interactive "p")
  10860   (let (type (pos (point)) start-b start-e end-b end-e)
  10861     (while (>= arg 1)
  10862       (setq type (get-text-property pos 'tag-type))
  10863       (when type
  10864         (cond
  10865           ((member type '(void))
  10866            (web-mode-element-kill)
  10867            (set-mark (point))
  10868            (web-mode-tag-match)
  10869            (web-mode-tag-end)
  10870            (exchange-point-and-mark))
  10871           ((member type '(start))
  10872            (setq start-b (web-mode-tag-beginning-position)
  10873                  start-e (web-mode-tag-end-position))
  10874            (when (web-mode-tag-match)
  10875              (setq end-b (web-mode-tag-beginning-position)
  10876                    end-e (web-mode-tag-end-position)))
  10877            )
  10878           (t
  10879            (setq end-b (web-mode-tag-beginning-position)
  10880                  end-e (web-mode-tag-end-position))
  10881            (when (web-mode-tag-match)
  10882              (setq start-b (web-mode-tag-beginning-position)
  10883                    start-e (web-mode-tag-end-position)))
  10884            ) ;t
  10885           ) ;cond
  10886         (when (and start-b end-b)
  10887           (goto-char end-b)
  10888           (delete-region end-b (1+ end-e))
  10889           (delete-blank-lines)
  10890           (goto-char start-b)
  10891           (delete-region start-b (1+ start-e))
  10892           (delete-blank-lines)
  10893           (web-mode-buffer-indent)
  10894           )
  10895         ;;        (message "start %S %S - end %S %S" start-b start-e end-b end-e))
  10896         ) ;when
  10897       (skip-chars-forward "[:space:]\n")
  10898       (setq arg (1- arg))
  10899       ) ;while
  10900     ) ;let
  10901   )
  10902 
  10903 (defun web-mode-element-kill (&optional arg)
  10904   "Kill the current html element."
  10905   (interactive "p")
  10906   (while (>= arg 1)
  10907     (setq arg (1- arg))
  10908     (web-mode-element-select)
  10909     (when mark-active
  10910       (kill-region (region-beginning) (region-end)))
  10911     ) ;while
  10912   )
  10913 
  10914 (defun web-mode-element-clone (&optional arg)
  10915   "Clone the current html element."
  10916   (interactive "p")
  10917   (let (col pos)
  10918     (while (>= arg 1)
  10919       (setq arg (1- arg)
  10920             col 0)
  10921       (web-mode-element-select)
  10922       (when mark-active
  10923         (save-excursion
  10924           (goto-char (region-beginning))
  10925           (setq col (current-column)))
  10926         (kill-region (region-beginning) (region-end))
  10927         (yank)
  10928         (newline)
  10929         (indent-line-to col)
  10930         (setq pos (point))
  10931         (yank)
  10932         (goto-char pos))
  10933       )
  10934     ) ;let
  10935   )
  10936 
  10937 (defun web-mode-element-insert ()
  10938   "Insert an html element."
  10939   (interactive)
  10940   (let (tag-name)
  10941     (cond
  10942       ((and (get-text-property (point) 'tag-type)
  10943             (not (get-text-property (point) 'tag-beg)))
  10944        (message "element-insert ** invalid context **"))
  10945       ((not (and (setq tag-name (web-mode-element-complete))
  10946                  (> (length tag-name) 0)))
  10947        (message "element-insert ** failure **"))
  10948       ((web-mode-element-is-void tag-name)
  10949        (insert (concat "<" (replace-regexp-in-string "/" "" tag-name) "/>"))
  10950        )
  10951       (mark-active
  10952        (let ((beg (region-beginning)) (end (region-end)))
  10953          (deactivate-mark)
  10954          (goto-char end)
  10955          (insert "</" tag-name ">")
  10956          (goto-char beg)
  10957          (insert "<" tag-name ">")
  10958          )
  10959        )
  10960       (t
  10961        (insert (concat "<" tag-name ">" "</" tag-name ">"))
  10962        (web-mode-sb "</")
  10963        )
  10964       ) ;cond
  10965     ))
  10966 
  10967 (defun web-mode-element-insert-at-point ()
  10968   "Replace the word at point with a html tag of it."
  10969   (interactive)
  10970   (let ((tag-name (thing-at-point 'word)))
  10971     (cond
  10972       ((web-mode-element-is-void tag-name)
  10973        (backward-kill-word 1)
  10974        (insert (concat "<" (replace-regexp-in-string "/" "" tag-name) "/>"))
  10975        )
  10976       (mark-active
  10977        (setq tag-name (buffer-substring (region-beginning) (region-end)))
  10978        (delete-region (region-beginning) (region-end))
  10979        (insert (concat "<" tag-name ">" "</" tag-name ">"))
  10980        (web-mode-sb "</")
  10981        )
  10982       (tag-name ; do nothing is there isn's word at point
  10983        (backward-kill-word 1)
  10984        (insert (concat "<" tag-name ">" "</" tag-name ">"))
  10985        (web-mode-sb "</")
  10986        )
  10987       ) ;cond
  10988     ))
  10989 
  10990 (defun web-mode-element-rename (&optional tag-name)
  10991   "Rename the current html element."
  10992   (interactive)
  10993   (save-excursion
  10994     (let (pos)
  10995       (unless tag-name (setq tag-name (web-mode-element-complete "New tag name: ")))
  10996       (when (and (> (length tag-name) 0)
  10997                  (web-mode-element-beginning)
  10998                  (looking-at "<\\([[:alnum:]]+\\(:?[[:alpha:]_-]+\\)?\\)"))
  10999         (setq pos (point))
  11000         (unless (web-mode-element-is-void)
  11001           (save-match-data
  11002             (web-mode-tag-match)
  11003             (if (looking-at "</[ ]*\\([[:alnum:]]+\\(:?[[:alpha:]_-]+\\)?\\)")
  11004                 (replace-match (concat "</" tag-name))
  11005                 )))
  11006         (goto-char pos)
  11007         (replace-match (concat "<" tag-name))
  11008         ))))
  11009 
  11010 (defun web-mode-current-trimmed-line ()
  11011   (web-mode-trim (buffer-substring-no-properties
  11012                   (line-beginning-position)
  11013                   (line-end-position))))
  11014 
  11015 (defun web-mode-trim (string)
  11016   (replace-regexp-in-string "\\`[ \t\n]*" "" (replace-regexp-in-string "[ \t\n]*\\'" "" string)))
  11017 
  11018 (defun web-mode-is-token-end (pos)
  11019   (let (block-token part-token)
  11020     (setq block-token (get-text-property pos 'block-token))
  11021     (setq part-token (get-text-property pos 'part-token))
  11022     (cond
  11023       ((not (or block-token part-token))
  11024        nil)
  11025       ((>= (1+ pos) (point-max))
  11026        t)
  11027       ((and block-token
  11028             (not (string= (get-text-property (1+ pos) 'block-token) block-token)))
  11029        t)
  11030       ((and part-token
  11031             (not (string= (get-text-property (1+ pos) 'part-token) part-token)))
  11032        t)
  11033       (t
  11034        nil)
  11035       ) ;cond
  11036     ))
  11037 
  11038 (defun web-mode-block-is-token-line ()
  11039   (save-excursion
  11040     (let ((continue t) (counter 0))
  11041       (beginning-of-line)
  11042       (back-to-indentation)
  11043       (while (and continue (not (eolp)))
  11044         (cond
  11045           ((get-text-property (point) 'block-token)
  11046            (setq counter (1+ counter)))
  11047           ((not (member (following-char) '(?\s ?\t)))
  11048            (setq continue nil
  11049                  counter 0))
  11050           ) ;cond
  11051         (forward-char)
  11052         ) ;while
  11053       (> counter 0)
  11054       )))
  11055 
  11056 (defun web-mode-part-is-token-line (pos)
  11057   (save-excursion
  11058     (let ((continue t)
  11059           (counter 0))
  11060       (goto-char pos)
  11061       (setq continue (not (eolp)))
  11062       (while continue
  11063         (forward-char)
  11064         (cond
  11065           ((eolp)
  11066            (setq continue nil))
  11067           ((or (get-text-property (point) 'block-side)
  11068                (member (get-text-property (point) 'part-token) '(comment string)))
  11069            (setq counter (1+ counter)))
  11070           ((not (member (following-char) '(?\s ?\t)))
  11071            (setq continue nil
  11072                  counter 0))
  11073           )
  11074         ) ;while
  11075       (> counter 0))))
  11076 
  11077 (defun web-mode-is-content (&optional pos)
  11078   (unless pos (setq pos (point)))
  11079   (not (or (get-text-property pos 'part-side)
  11080            (get-text-property pos 'tag-type)
  11081            (get-text-property pos 'block-side)
  11082            )))
  11083 
  11084 (defun web-mode-is-comment-or-string (&optional pos)
  11085   (unless pos (setq pos (point)))
  11086   (not (null (or (eq (get-text-property pos 'tag-type) 'comment)
  11087                  (member (get-text-property pos 'block-token) '(comment string))
  11088                  (member (get-text-property pos 'part-token) '(comment string))))))
  11089 
  11090 ;; NOTE: we look at the firt one
  11091 (defun web-mode-block-is-open (&optional pos)
  11092   (unless pos (setq pos (point))))
  11093 
  11094 ;; NOTE: we look at the last one
  11095 (defun web-mode-block-is-close (&optional pos)
  11096   (unless pos (setq pos (point)))
  11097   (and (get-text-property pos 'block-side)
  11098        (eq (caar (web-mode-block-controls-get pos)) 'close)))
  11099 
  11100 ;; NOTE: we look at the first one
  11101 (defun web-mode-block-is-inside (&optional pos)
  11102   (unless pos (setq pos (point)))
  11103   (and (get-text-property pos 'block-side)
  11104        (eq (caar (web-mode-block-controls-get pos)) 'inside)))
  11105 
  11106 (defun web-mode-element-is-void (&optional tag)
  11107   (cond
  11108     ((and (not tag) (eq (get-text-property (point) 'tag-type) 'void))
  11109      t)
  11110     ((and tag (member tag '("div" "li" "a" "p" "h1" "h2" "h3" "ul" "span" "article" "section" "td" "tr")))
  11111      nil)
  11112     ((and tag (string-suffix-p "/" tag))
  11113      t)
  11114     ((and tag (string= web-mode-content-type "jsx"))
  11115      (member (downcase tag) '("img" "br" "hr")))
  11116     (tag
  11117      (car (member (downcase tag) web-mode-void-elements)))
  11118     (t
  11119      nil)
  11120     ))
  11121 
  11122 ;;---- COMMENT ------------------------------------------------------------------
  11123 
  11124 (defun web-mode-toggle-comments ()
  11125   "Toggle comments visbility."
  11126   (interactive)
  11127   (web-mode-with-silent-modifications
  11128    (save-excursion
  11129      (if web-mode-comments-invisible
  11130          (remove-overlays))
  11131      (setq web-mode-comments-invisible (null web-mode-comments-invisible))
  11132      (let ((continue t)
  11133            (pos (point-min))
  11134            (visibility web-mode-comments-invisible)
  11135            overlay end)
  11136        (while continue
  11137          (setq pos (next-single-property-change pos 'font-lock-face))
  11138          (if (null pos)
  11139              (setq continue nil)
  11140              (when (eq (get-text-property pos 'font-lock-face) 'web-mode-comment-face)
  11141                (setq end (next-single-property-change pos 'font-lock-face))
  11142                (put-text-property pos end 'invisible visibility)
  11143                (when visibility
  11144                  (setq overlay (make-overlay pos end)))
  11145                (goto-char pos)
  11146                )
  11147              )
  11148          )
  11149        ) ;let
  11150      )))
  11151 
  11152 (defun web-mode-comment-or-uncomment-region (beg end &optional arg)
  11153   (interactive)
  11154   (save-excursion
  11155     (push-mark end)
  11156     (goto-char beg)
  11157     (setq mark-active t)
  11158     (web-mode-comment-or-uncomment)
  11159     (pop-mark)))
  11160 
  11161 (defun web-mode-comment-or-uncomment ()
  11162   "Comment or uncomment line(s), block or region at POS."
  11163   (interactive)
  11164   ;; TODO : if mark is at eol, mark--
  11165   (if (and (not mark-active) (looking-at-p "[[:space:]]*$"))
  11166       (web-mode-comment-insert)
  11167       (when (and (use-region-p) (eq (point) (region-end)))
  11168         (if (bolp) (backward-char))
  11169         (exchange-point-and-mark))
  11170       (if (eq (get-text-property (point) 'block-token) 'delimiter-beg)
  11171           (web-mode-block-skip-blank-forward (point) '(delimiter-beg))
  11172           (skip-chars-forward "[:space:]" (line-end-position)))
  11173       (cond
  11174         ;; #1147
  11175         ((and (get-text-property (point) 'jsx-beg)
  11176               (eq (get-text-property (1+ (point)) 'part-token) 'comment))
  11177          (web-mode-uncomment (1+ (point))))
  11178         ((or (eq (get-text-property (point) 'tag-type) 'comment)
  11179              (eq (get-text-property (point) 'block-token) 'comment)
  11180              (eq (get-text-property (point) 'part-token) 'comment))
  11181          (web-mode-uncomment (point)))
  11182         (t
  11183          (web-mode-comment (point)))
  11184         )
  11185       ) ;if
  11186   )
  11187 
  11188 (defun web-mode-comment-indent-new-line (&optional soft)
  11189   (interactive)
  11190   (let (ctx)
  11191     (setq ctx (web-mode-comment-context))
  11192     (cond
  11193       ((null ctx)
  11194        (newline 1))
  11195       (t
  11196        (newline 1)
  11197        (indent-line-to (plist-get ctx :col))
  11198        (let ((prefix (plist-get ctx :prefix)))
  11199          (insert
  11200           (concat prefix
  11201                   ;; Check if the comment ends with a space, and if not, insert one.
  11202                   (if
  11203                    (string-equal (substring prefix -1 (length prefix)) " ")
  11204                    ""
  11205                    " ")))))
  11206       ) ;cond
  11207     ))
  11208 
  11209 (defun web-mode-comment-context (&optional pos)
  11210   (cond
  11211     (pos
  11212      )
  11213     ((and (eolp) (not (bobp)))
  11214      (setq pos (1- (point))))
  11215     (t
  11216      (setq pos (point)))
  11217     ) ;cond
  11218   (let (beg col prefix type format)
  11219     (cond
  11220       ((eq (get-text-property pos 'block-token) 'comment)
  11221        (setq type "block"))
  11222       ((eq (get-text-property pos 'tag-type) 'comment)
  11223        (setq type "tag"))
  11224       ((eq (get-text-property pos 'part-token) 'comment)
  11225        (setq type "part"))
  11226       )
  11227     (if (null type) nil
  11228         (save-excursion
  11229           (goto-char pos)
  11230           (web-mode-comment-beginning)
  11231           (setq beg (point)
  11232                 col (current-column))
  11233           (cond
  11234             ((looking-at-p "/\\*")
  11235              (setq format "/*"
  11236                    prefix " * "))
  11237             ((looking-at-p "//")
  11238              (setq format "//"
  11239                    prefix "//"))
  11240             ((looking-at-p "#")
  11241              (setq format "#"
  11242                    prefix "#"))
  11243             ((looking-at-p ";")
  11244              (setq format ";"
  11245                    prefix ";"))
  11246             ((looking-at-p "''")
  11247              (setq format "''"
  11248                    prefix "''"))
  11249             ) ;cond
  11250           (list :beg beg :col col :prefix prefix :type type :format format)))))
  11251 
  11252 (defun web-mode-comment-insert ()
  11253   (let ((alt nil) (language nil) (pos (point)))
  11254     (setq language (web-mode-language-at-pos pos))
  11255     (setq alt (cdr (assoc language web-mode-comment-formats)))
  11256     ;;(message "language=%S" language)
  11257     (cond
  11258       ((get-text-property pos 'block-side)
  11259        (cond
  11260          ((and alt (string= alt "//"))
  11261           (insert "// "))
  11262          (t
  11263           (insert "/*  */")
  11264           (search-backward " */"))
  11265          ) ;cond
  11266        ) ;case block-side
  11267       ((get-text-property pos 'part-side)
  11268        (cond
  11269          ((and alt (string= alt "//"))
  11270           (insert "// "))
  11271          (t
  11272           (insert "/*  */")
  11273           (search-backward " */"))
  11274          ) ;cond
  11275        ) ;case part-side
  11276       (t
  11277        (insert "<!--  -->")
  11278        (search-backward " -->")
  11279        ) ;case html
  11280       ) ;cond
  11281     ))
  11282 
  11283 (defun web-mode-comment (pos)
  11284   (let (ctx language col sel beg end tmp block-side single-line-block pos-after content)
  11285 
  11286     (setq pos-after pos)
  11287 
  11288     (setq block-side (get-text-property pos 'block-side))
  11289     (setq single-line-block (web-mode-is-single-line-block pos))
  11290 
  11291     (cond
  11292 
  11293       ((and block-side (string= web-mode-engine "erb"))
  11294        (web-mode-comment-erb-block pos)
  11295        )
  11296 
  11297       ((and block-side (string= web-mode-engine "artanis"))
  11298        (web-mode-comment-artanis-block pos)
  11299        )
  11300 
  11301       ((and single-line-block block-side
  11302             (intern-soft (concat "web-mode-comment-" web-mode-engine "-block")))
  11303        (funcall (intern (concat "web-mode-comment-" web-mode-engine "-block")) pos)
  11304        )
  11305 
  11306       (t
  11307        (setq ctx (web-mode-point-context
  11308                   (if mark-active (region-beginning) (line-beginning-position))))
  11309        ;;(message "%S" ctx)
  11310        (setq language (plist-get ctx :language))
  11311        (setq col (current-column))
  11312        (cond
  11313          (mark-active
  11314           ;;(message "%S %S" (point) col)
  11315           )
  11316          ((and (member language '("html" "xml"))
  11317                (get-text-property (progn (back-to-indentation) (point)) 'tag-beg))
  11318           (web-mode-element-select))
  11319          (t
  11320           (end-of-line)
  11321           (set-mark (line-beginning-position)))
  11322          ) ;cond
  11323 
  11324        (setq beg (region-beginning)
  11325              end (region-end))
  11326 
  11327        (when (> (point) (mark))
  11328          (exchange-point-and-mark))
  11329 
  11330        (if (and (eq (char-before end) ?\n)
  11331                 (not (eq (char-after end) ?\n)))
  11332            (setq end (1- end)))
  11333 
  11334        (setq sel (buffer-substring-no-properties beg end))
  11335 
  11336        (cond
  11337 
  11338          ((member language '("html" "xml"))
  11339           (cond
  11340             ((and (= web-mode-comment-style 2) (string= web-mode-engine "django"))
  11341              (setq content (concat "{# " sel " #}")))
  11342             ((and (= web-mode-comment-style 2) (member web-mode-engine '("ejs" "erb")))
  11343              (setq content (concat "<%# " sel " %>")))
  11344             ((and (= web-mode-comment-style 2) (string= web-mode-engine "artanis"))
  11345              (setq content (concat "<%; " sel " %>")))
  11346             ((and (= web-mode-comment-style 2) (string= web-mode-engine "aspx"))
  11347              (setq content (concat "<%-- " sel " --%>")))
  11348             ((and (= web-mode-comment-style 2) (string= web-mode-engine "smarty"))
  11349              (setq content (concat "{* " sel " *}")))
  11350             ((and (= web-mode-comment-style 2) (string= web-mode-engine "expressionengine"))
  11351              (setq content (concat "{!-- " sel " --}")))
  11352             ((and (= web-mode-comment-style 2) (string= web-mode-engine "xoops"))
  11353              (setq content (concat "<{* " sel " *}>")))
  11354             ((and (= web-mode-comment-style 2) (string= web-mode-engine "hero"))
  11355              (setq content (concat "<%# " sel " %>")))
  11356             ((and (= web-mode-comment-style 2) (string= web-mode-engine "blade"))
  11357              (setq content (concat "{{-- " sel " --}}")))
  11358             ((and (= web-mode-comment-style 2) (string= web-mode-engine "ctemplate"))
  11359              (setq content (concat "{{!-- " sel " --}}")))
  11360             ((and (= web-mode-comment-style 2) (string= web-mode-engine "antlers"))
  11361              (setq content (concat "{{# " sel " #}}")))
  11362             ((and (= web-mode-comment-style 2) (string= web-mode-engine "razor"))
  11363              (setq content (concat "@* " sel " *@")))
  11364             (t
  11365              (setq content (concat "<!-- " sel " -->"))
  11366              (when (< (length sel) 1)
  11367                (search-backward " -->")
  11368                (setq pos-after nil))
  11369              ))
  11370           ) ;case html
  11371 
  11372          ((member language '("php" "javascript" "typescript" "java" "jsx"))
  11373           (let (alt)
  11374             (setq alt (cdr (assoc language web-mode-comment-formats)))
  11375             ;;(message "language=%S alt=%S sel=%S col=%S" language alt sel col)
  11376             (cond
  11377               ((and alt (string= alt "//"))
  11378                (setq content (replace-regexp-in-string (concat "\n[ ]\\{" (number-to-string col) "\\}") "\n" sel))
  11379                (setq content (replace-regexp-in-string (concat "\n") "\n// " content))
  11380                (setq content (concat "// " content)))
  11381               ((get-text-property pos 'jsx-depth)
  11382                (setq content (concat "{/* " sel " */}")))
  11383               (web-mode-comment-prefixing
  11384                (setq content (replace-regexp-in-string (concat "\n[ ]\\{" (number-to-string col) "\\}") "\n* " sel))
  11385                (setq content (concat "/* " content " */")))
  11386               (t
  11387                (setq content (concat "/* " sel " */")))
  11388               ) ;cond
  11389             ) ;let
  11390           )
  11391 
  11392          ((member language '("erb"))
  11393           (setq content (replace-regexp-in-string "^[ ]*" "#" sel)))
  11394 
  11395          ((member language '("asp"))
  11396           (setq content (replace-regexp-in-string "^[ ]*" "''" sel)))
  11397 
  11398          (t
  11399           (setq content (concat "/* " sel " */")))
  11400 
  11401          ) ;cond
  11402 
  11403        (when content
  11404          (delete-region beg end)
  11405          (deactivate-mark)
  11406          (let (beg end)
  11407            (setq beg (point-at-bol))
  11408            (insert content)
  11409            (setq end (point-at-eol))
  11410            (indent-region beg end)
  11411            )
  11412          ) ;when
  11413 
  11414        ) ;t
  11415       ) ;cond
  11416 
  11417     (when pos-after (goto-char pos-after))
  11418 
  11419     ))
  11420 
  11421 (defun web-mode-comment-ejs-block (pos)
  11422   (let (beg end)
  11423     (setq beg (web-mode-block-beginning-position pos)
  11424           end (web-mode-block-end-position pos))
  11425     (web-mode-insert-text-at-pos "//" (+ beg 2))))
  11426 
  11427 (defun web-mode-comment-erb-block (pos)
  11428   (let (beg end)
  11429     (setq beg (web-mode-block-beginning-position pos)
  11430           end (web-mode-block-end-position pos))
  11431     (web-mode-insert-text-at-pos "#" (+ beg 2))))
  11432 
  11433 (defun web-mode-comment-artanis-block (pos)
  11434   (let (beg end)
  11435     (setq beg (web-mode-block-beginning-position pos)
  11436           end (web-mode-block-end-position pos))
  11437     (web-mode-insert-text-at-pos ";" (+ beg 2))))
  11438 
  11439 (defun web-mode-comment-django-block (pos)
  11440   (let (beg end)
  11441     (setq beg (web-mode-block-beginning-position pos)
  11442           end (web-mode-block-end-position pos))
  11443     (web-mode-insert-text-at-pos "#" end)
  11444     (web-mode-insert-text-at-pos "#" (1+ beg))))
  11445 
  11446 (defun web-mode-comment-dust-block (pos)
  11447   (let (beg end)
  11448     (setq beg (web-mode-block-beginning-position pos)
  11449           end (web-mode-block-end-position pos))
  11450     (web-mode-insert-text-at-pos "!" end)
  11451     (web-mode-insert-text-at-pos "!" (1+ beg))))
  11452 
  11453 (defun web-mode-comment-aspx-block (pos)
  11454   (let (beg end)
  11455     (setq beg (web-mode-block-beginning-position pos)
  11456           end (web-mode-block-end-position pos))
  11457     (web-mode-insert-text-at-pos "#" end)
  11458     (web-mode-insert-text-at-pos "#" (1+ beg))))
  11459 
  11460 (defun web-mode-comment-jsp-block (pos)
  11461   (let (beg end)
  11462     (setq beg (web-mode-block-beginning-position pos)
  11463           end (web-mode-block-end-position pos))
  11464     (web-mode-insert-text-at-pos "--" (+ beg 2))))
  11465 
  11466 (defun web-mode-comment-go-block (pos)
  11467   (let (beg end)
  11468     (setq beg (web-mode-block-beginning-position pos)
  11469           end (web-mode-block-end-position pos))
  11470     (web-mode-insert-text-at-pos "*/" (1- end))
  11471     (web-mode-insert-text-at-pos "/*" (+ beg (if (web-mode-looking-at "{{" beg) 2 0)))))
  11472 
  11473 (defun web-mode-comment-php-block (pos)
  11474   (let (beg end)
  11475     (setq beg (web-mode-block-beginning-position pos)
  11476           end (web-mode-block-end-position pos))
  11477     (web-mode-insert-text-at-pos "*/" (- end 2))
  11478     (web-mode-insert-text-at-pos "/*" (+ beg 1 (if (web-mode-looking-at "<\\?php" beg) 5 3)))))
  11479 
  11480 (defun web-mode-comment-svelte-block (pos)
  11481   (let (beg end)
  11482     (setq beg (web-mode-block-beginning-position pos)
  11483           end (web-mode-block-end-position pos))
  11484     (web-mode-insert-text-at-pos "!" end)
  11485     (web-mode-insert-text-at-pos "!" (1+ beg))))
  11486 
  11487 (defun web-mode-comment-boundaries (&optional pos)
  11488   (interactive)
  11489   (unless pos (setq pos (point)))
  11490   (let ((beg pos) (end pos) prop)
  11491     (save-excursion
  11492       (goto-char pos)
  11493       (setq prop
  11494             (cond
  11495               ((eq (get-text-property pos 'block-token) 'comment) 'block-token)
  11496               ((eq (get-text-property pos 'tag-type) 'comment) 'tag-type)
  11497               ((eq (get-text-property pos 'part-token) 'comment) 'part-token)
  11498               (t nil)
  11499               ))
  11500       (if (null prop)
  11501           (setq beg nil
  11502                 end nil)
  11503           (when (and (not (bobp))
  11504                      (eq (get-text-property pos prop) (get-text-property (1- pos) prop)))
  11505             (setq beg (or (previous-single-property-change pos prop) (point-min))))
  11506           (when (and (not (eobp))
  11507                      (eq (get-text-property pos prop) (get-text-property (1+ pos) prop)))
  11508             (setq end (or (next-single-property-change pos prop) (point-max)))))
  11509       (message "beg(%S) end(%S) point-max(%S)" beg end (point-max))
  11510       (when (and beg (string= (buffer-substring-no-properties beg (+ beg 2)) "//"))
  11511         (goto-char end)
  11512         (while (and (looking-at-p "\n[ ]*//")
  11513                     (not (eobp)))
  11514           (search-forward "//")
  11515           (backward-char 2)
  11516           ;;(message "%S" (point))
  11517           (setq end (next-single-property-change (point) prop))
  11518           (goto-char end)
  11519           ;;(message "%S" (point))
  11520           ) ;while
  11521         ) ;when
  11522       ;;(when end (setq end (1- end))) ;; #1021
  11523       ) ;save-excursion
  11524     ;;(message "beg=%S end=%S" beg end)
  11525     (if (and beg end) (cons beg end) nil)
  11526     ))
  11527 
  11528 (defun web-mode-uncomment (pos)
  11529   (let ((beg pos) (end pos) (sub2 "") comment boundaries)
  11530     (save-excursion
  11531       (cond
  11532         ((and (get-text-property pos 'block-side)
  11533               (intern-soft (concat "web-mode-uncomment-" web-mode-engine "-block")))
  11534          (funcall (intern (concat "web-mode-uncomment-" web-mode-engine "-block")) pos))
  11535         ((and (setq boundaries (web-mode-comment-boundaries pos))
  11536               (setq beg (car boundaries))
  11537               (setq end (1+ (cdr boundaries)))
  11538               (> (- end beg) 4))
  11539          (when (and (eq (get-text-property beg 'part-token) 'comment)
  11540                     (> beg 1) ;#1158
  11541                     (get-text-property (1- beg) 'jsx-beg))
  11542            (setq beg (1- beg)
  11543                  end (1+ end)))
  11544          (setq comment (buffer-substring-no-properties beg end))
  11545          (setq sub2 (substring comment 0 2))
  11546          (cond
  11547            ((member sub2 '("<!" "<%"))
  11548             (setq comment (replace-regexp-in-string "\\(^<[!%]--[ ]?\\|[ ]?--[%]?>$\\)" "" comment)))
  11549            ((string= sub2 "{#")
  11550             (setq comment (replace-regexp-in-string "\\(^{#[ ]?\\|[ ]?#}$\\)" "" comment)))
  11551            ((string= sub2 "{/") ;jsx comments
  11552             (setq comment (replace-regexp-in-string "\\(^{/\\*[ ]?\\|[ ]?\\*/}$\\)" "" comment)))
  11553            ((string= sub2 "/*")
  11554             ;;(message "%S" comment)
  11555             ;;(setq comment (replace-regexp-in-string "\\(\\*/\\|^/\\*[ ]?\\|^[ \t]*\\*\\)" "" comment))
  11556             (setq comment (replace-regexp-in-string "\\([ ]?\\*/$\\|^/\\*[ ]?\\)" "" comment))
  11557             (setq comment (replace-regexp-in-string "\\(^[ \t]*\\*\\)" "" comment))
  11558             ;;(message "%S" comment)
  11559             )
  11560            ((string= sub2 "''")
  11561             (setq comment (replace-regexp-in-string "''" "" comment)))
  11562            ((string= sub2 "//")
  11563             (setq comment (replace-regexp-in-string "^ *//" "" comment)))
  11564            ) ;cond
  11565          (delete-region beg end)
  11566          (web-mode-insert-and-indent comment)
  11567          (goto-char beg)
  11568          )
  11569         ) ;cond
  11570       (indent-according-to-mode)
  11571       )))
  11572 
  11573 (defun web-mode-uncomment-erb-block (pos)
  11574   (let (beg end)
  11575     (setq beg (web-mode-block-beginning-position pos)
  11576           end (web-mode-block-end-position pos))
  11577     (cond
  11578       ((string= (buffer-substring-no-properties beg (+ beg 4)) "<%#=")
  11579        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11580       ((string-match-p "<[%[:alpha:]]" (buffer-substring-no-properties (+ beg 2) (- end 2)))
  11581        (web-mode-remove-text-at-pos 2 (1- end))
  11582        (web-mode-remove-text-at-pos 3 beg))
  11583       (t
  11584        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11585       ) ;cond
  11586     )
  11587   )
  11588 
  11589 (defun web-mode-uncomment-artanis-block (pos)
  11590   (let (beg end)
  11591     (setq beg (web-mode-block-beginning-position pos)
  11592           end (web-mode-block-end-position pos))
  11593     (cond
  11594       ((string= (buffer-substring-no-properties beg (+ beg 4)) "<%;=")
  11595        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11596       ((string-match-p "<[%[:alpha:]]" (buffer-substring-no-properties (+ beg 2) (- end 2)))
  11597        (web-mode-remove-text-at-pos 2 (1- end))
  11598        (web-mode-remove-text-at-pos 3 beg))
  11599       (t
  11600        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11601       ) ;cond
  11602     )
  11603   )
  11604 
  11605 (defun web-mode-uncomment-ejs-block (pos)
  11606   (let (beg end)
  11607     (setq beg (web-mode-block-beginning-position pos)
  11608           end (web-mode-block-end-position pos))
  11609     (web-mode-remove-text-at-pos 1 (+ beg 2))))
  11610 
  11611 (defun web-mode-uncomment-django-block (pos)
  11612   (let (beg end)
  11613     (setq beg (web-mode-block-beginning-position pos)
  11614           end (web-mode-block-end-position pos))
  11615     (cond
  11616       ((web-mode-looking-at-p "{#[{%]" beg)
  11617        (web-mode-remove-text-at-pos 1 (1- end))
  11618        (web-mode-remove-text-at-pos 1 (1+ beg))
  11619        )
  11620       (t
  11621        (web-mode-remove-text-at-pos 2 (1- end))
  11622        (web-mode-remove-text-at-pos 2 beg))
  11623       ) ;cond
  11624     ))
  11625 
  11626 (defun web-mode-uncomment-ctemplate-block (pos)
  11627   (let (beg end)
  11628     (setq beg (web-mode-block-beginning-position pos)
  11629           end (web-mode-block-end-position pos))
  11630     (web-mode-remove-text-at-pos 5 (- end 4))
  11631     (web-mode-remove-text-at-pos 5 beg)))
  11632 
  11633 (defun web-mode-uncomment-antlers-block (pos)
  11634   (let (beg end)
  11635     (setq beg (web-mode-block-beginning-position pos)
  11636           end (web-mode-block-end-position pos))
  11637     (web-mode-remove-text-at-pos 3 (- end 2))
  11638     (web-mode-remove-text-at-pos 3 beg)))
  11639 
  11640 (defun web-mode-uncomment-dust-block (pos)
  11641   (let (beg end)
  11642     (setq beg (web-mode-block-beginning-position pos)
  11643           end (web-mode-block-end-position pos))
  11644     (web-mode-remove-text-at-pos 1 (1- end))
  11645     (web-mode-remove-text-at-pos 1 (1+ beg))))
  11646 
  11647 (defun web-mode-uncomment-aspx-block (pos)
  11648   (let (beg end)
  11649     (setq beg (web-mode-block-beginning-position pos)
  11650           end (web-mode-block-end-position pos))
  11651     (web-mode-remove-text-at-pos 1 (1- end))
  11652     (web-mode-remove-text-at-pos 1 (1+ beg))))
  11653 
  11654 (defun web-mode-uncomment-jsp-block (pos)
  11655   (let (beg end)
  11656     (setq beg (web-mode-block-beginning-position pos)
  11657           end (web-mode-block-end-position pos))
  11658     (web-mode-remove-text-at-pos 2 (+ beg 2))))
  11659 
  11660 (defun web-mode-uncomment-go-block (pos)
  11661   (let (beg end)
  11662     (setq beg (web-mode-block-beginning-position pos)
  11663           end (web-mode-block-end-position pos))
  11664     (web-mode-remove-text-at-pos 2 (+ beg 2))
  11665     (web-mode-remove-text-at-pos 2 (- end 5))))
  11666 
  11667 (defun web-mode-uncomment-svelte-block (pos)
  11668   (let (beg end)
  11669     (setq beg (web-mode-block-beginning-position pos)
  11670           end (web-mode-block-end-position pos))
  11671     (web-mode-remove-text-at-pos 1 (1- end))
  11672     (web-mode-remove-text-at-pos 1 (1+ beg))))
  11673 
  11674 (defun web-mode-snippet-names ()
  11675   (mapcar #'car web-mode-snippets))
  11676 
  11677 (defun web-mode-snippet-insert (code)
  11678   "Insert a snippet."
  11679   (interactive
  11680    (list (completing-read "Snippet: " (web-mode-snippet-names))))
  11681   (let (beg
  11682         (continue t)
  11683         (counter 0)
  11684         end
  11685         sel
  11686         snippet
  11687         (l (length web-mode-snippets))
  11688         pos)
  11689     (when mark-active
  11690       (setq sel (web-mode-trim (buffer-substring-no-properties
  11691                                 (region-beginning) (region-end))))
  11692       (delete-region (region-beginning) (region-end)))
  11693     (while (and continue (< counter l))
  11694       (setq snippet (nth counter web-mode-snippets))
  11695       (when (string= (car snippet) code)
  11696         (setq continue nil))
  11697       (setq counter (1+ counter)))
  11698     (when snippet
  11699       (setq snippet (cdr snippet))
  11700       (setq beg (point-at-bol))
  11701       (insert snippet)
  11702       (setq pos (point)
  11703             end (point))
  11704       (cond
  11705         ((string-match-p "¦" snippet)
  11706          (search-backward "¦")
  11707          (delete-char 1)
  11708          (setq pos (point)
  11709                end (1- end)))
  11710         ((string-match-p "|" snippet)
  11711          (search-backward "|")
  11712          (delete-char 1)
  11713          (setq pos (point)
  11714                end (1- end)))
  11715         ) ;cond
  11716       (when sel
  11717         (insert sel)
  11718         (setq pos (point)
  11719               end (+ end (length sel))))
  11720       (goto-char end)
  11721       (setq end (point-at-eol))
  11722       (unless sel (goto-char pos))
  11723       (indent-region beg end))
  11724     ))
  11725 
  11726 (defun web-mode-looking-at (regexp pos)
  11727   (save-excursion
  11728     (goto-char pos)
  11729     (looking-at regexp)))
  11730 
  11731 (defun web-mode-looking-at-p (regexp pos)
  11732   (save-excursion
  11733     (goto-char pos)
  11734     (looking-at-p regexp)))
  11735 
  11736 (defun web-mode-looking-back (regexp pos &optional limit greedy)
  11737   (save-excursion
  11738     (goto-char pos)
  11739     (if limit
  11740         (looking-back regexp limit greedy)
  11741         (looking-back regexp (point-min)))))
  11742 
  11743 (defun web-mode-insert-text-at-pos (text pos)
  11744   (let ((mem web-mode-enable-auto-pairing))
  11745     (setq web-mode-enable-auto-pairing nil)
  11746     (save-excursion
  11747       (goto-char pos)
  11748       (insert text)
  11749       (setq web-mode-enable-auto-pairing mem)
  11750       )))
  11751 
  11752 (defun web-mode-remove-text-at-pos (n &optional pos)
  11753   (unless pos (setq pos (point)))
  11754   (delete-region pos (+ pos n)))
  11755 
  11756 (defun web-mode-insert-and-indent (text)
  11757   (let (beg end)
  11758     (setq beg (point-at-bol))
  11759     (insert text)
  11760     (setq end (point-at-eol))
  11761     (indent-region beg end)
  11762     ))
  11763 
  11764 (defun web-mode-column-at-pos (pos)
  11765   (save-excursion
  11766     (goto-char pos)
  11767     (current-column)))
  11768 
  11769 (defun web-mode-indentation-at-pos (pos)
  11770   (save-excursion
  11771     (goto-char pos)
  11772     (current-indentation)))
  11773 
  11774 (defun web-mode-navigate (&optional pos)
  11775   "Move point to the matching opening/closing tag/block."
  11776   (interactive)
  11777   (unless pos (setq pos (point)))
  11778   (let (init)
  11779     (goto-char pos)
  11780     (setq init (point))
  11781     (when (> (current-indentation) (current-column))
  11782       (back-to-indentation))
  11783     (setq pos (point))
  11784     (cond
  11785       ((and (get-text-property pos 'block-side)
  11786             (web-mode-block-beginning)
  11787             (web-mode-block-controls-get (point)))
  11788        (web-mode-block-match))
  11789       ((member (get-text-property pos 'tag-type) '(start end))
  11790        (web-mode-tag-beginning)
  11791        (web-mode-tag-match))
  11792       (t
  11793        (goto-char init))
  11794       )
  11795     ))
  11796 
  11797 (defun web-mode-block-match (&optional pos)
  11798   (unless pos (setq pos (point)))
  11799   (let (pos-ori controls control (counter 1) type (continue t) pair)
  11800     (setq pos-ori pos)
  11801     (goto-char pos)
  11802     (setq controls (web-mode-block-controls-get pos))
  11803     ;;(message "controls=%S" controls)
  11804     (cond
  11805       (controls
  11806        (setq pair (car controls))
  11807        (setq control (cdr pair))
  11808        (setq type (car pair))
  11809        (when (eq type 'inside) (setq type 'close))
  11810        (while continue
  11811          (cond
  11812            ((and (> pos-ori 1) (bobp))
  11813             (setq continue nil))
  11814            ((or (and (eq type 'open) (not (web-mode-block-next)))
  11815                 (and (eq type 'close) (not (web-mode-block-previous))))
  11816             (setq continue nil)
  11817             )
  11818            ((null (setq controls (web-mode-block-controls-get (point))))
  11819             )
  11820            (t
  11821             ;;TODO : est il nécessaire de faire un reverse sur controls si on doit matcher backward
  11822             (dolist (pair controls)
  11823               (cond
  11824                 ((not (string= (cdr pair) control))
  11825                  )
  11826                 ((eq (car pair) 'inside)
  11827                  )
  11828                 ((eq (car pair) type)
  11829                  (setq counter (1+ counter)))
  11830                 (t
  11831                  (setq counter (1- counter)))
  11832                 )
  11833               ) ;dolist
  11834             (when (= counter 0)
  11835               (setq continue nil))
  11836             ) ;t
  11837            ) ;cond
  11838          ) ;while
  11839        (if (= counter 0) (point) nil)
  11840        ) ;controls
  11841       (t
  11842        (goto-char pos-ori)
  11843        nil
  11844        ) ;controls = nul
  11845       ) ;conf
  11846     ))
  11847 
  11848 (defun web-mode-tag-match (&optional pos)
  11849   "Move point to the matching opening/closing tag."
  11850   (interactive)
  11851   (unless pos (setq pos (point)))
  11852   (let (regexp name)
  11853     (cond
  11854       ((eq (get-text-property pos 'tag-type) 'void)
  11855        (web-mode-tag-beginning))
  11856       ((and (eq (get-text-property pos 'tag-type) 'comment)
  11857             (web-mode-looking-at-p "<!--#\\(elif\\|else\\|endif\\|if\\)" pos))
  11858        (setq regexp "<!--#\\(end\\)?if")
  11859        (if (web-mode-looking-at-p "<!--#if" pos)
  11860            (web-mode-tag-fetch-closing regexp pos)
  11861            (web-mode-tag-fetch-opening regexp pos))
  11862        )
  11863       (t
  11864        (setq name (get-text-property pos 'tag-name))
  11865        (when (string= name "_fragment_") (setq name ">"))
  11866        (setq regexp (concat "</?" name))
  11867        (when (member (get-text-property pos 'tag-type) '(start end))
  11868          (web-mode-tag-beginning)
  11869          (setq pos (point)))
  11870        (if (eq (get-text-property pos 'tag-type) 'end)
  11871            (web-mode-tag-fetch-opening regexp pos)
  11872            (web-mode-tag-fetch-closing regexp pos))
  11873        ) ;t
  11874       ) ;cond
  11875     t))
  11876 
  11877 (defun web-mode-tag-fetch-opening (regexp pos)
  11878   (let ((counter 1) (n 0) (is-comment nil) (types '(start end)))
  11879     (when (eq (aref regexp 1) ?\!)
  11880       (setq types '(comment)
  11881             is-comment t))
  11882     (goto-char pos)
  11883     (while (and (> counter 0) (re-search-backward regexp nil t))
  11884       (when (and (get-text-property (point) 'tag-beg)
  11885                  (member (get-text-property (point) 'tag-type) types))
  11886         (setq n (1+ n))
  11887         (cond
  11888           ((and is-comment
  11889                 (eq (aref (match-string-no-properties 0) 5) ?e))
  11890            (setq counter (1+ counter)))
  11891           (is-comment
  11892            (setq counter (1- counter)))
  11893           ((eq (get-text-property (point) 'tag-type) 'end)
  11894            (setq counter (1+ counter)))
  11895           (t
  11896            (setq counter (1- counter))
  11897            )
  11898           )
  11899         )
  11900       )
  11901     (if (= n 0) (goto-char pos))
  11902     ))
  11903 
  11904 (defun web-mode-tag-fetch-closing (regexp pos)
  11905   (let ((counter 1) (is-comment nil) (n 0))
  11906     (when (eq (aref regexp 1) ?\!)
  11907       (setq is-comment t))
  11908     (goto-char pos)
  11909     (web-mode-tag-end)
  11910     (while (and (> counter 0) (re-search-forward regexp nil t))
  11911       (when (get-text-property (match-beginning 0) 'tag-beg)
  11912         (setq n (1+ n))
  11913         (cond
  11914           ((and is-comment
  11915                 (eq (aref (match-string-no-properties 0) 5) ?e))
  11916            (setq counter (1- counter)))
  11917           (is-comment
  11918            (setq counter (1+ counter)))
  11919           ((eq (get-text-property (point) 'tag-type) 'end)
  11920            (setq counter (1- counter)))
  11921           (t
  11922            (setq counter (1+ counter)))
  11923           )
  11924         ) ;when
  11925       ) ;while
  11926     (if (> n 0)
  11927         (web-mode-tag-beginning)
  11928         (goto-char pos))
  11929     ))
  11930 
  11931 (defun web-mode-element-tag-name (&optional pos)
  11932   (unless pos (setq pos (point)))
  11933   (save-excursion
  11934     (goto-char pos)
  11935     (if (and (web-mode-tag-beginning)
  11936              (looking-at web-mode-tag-regexp))
  11937         (match-string-no-properties 1)
  11938         nil)))
  11939 
  11940 (defun web-mode-element-close ()
  11941   "Close html element."
  11942   (interactive)
  11943   (let (jmp epp ins tag)
  11944 
  11945     (if (and (eq (char-before) ?\>)
  11946              (web-mode-element-is-void (get-text-property (1- (point)) 'tag-name)))
  11947         (unless (eq (char-before (1- (point))) ?\/)
  11948           (backward-char)
  11949           (insert "/")
  11950           (forward-char))
  11951         (setq epp (web-mode-element-parent-position)))
  11952 
  11953     ;;(message "epp=%S" epp)
  11954     (when epp
  11955       (setq tag (get-text-property epp 'tag-name))
  11956       (setq tag (web-mode-element-tag-name epp))
  11957       ;;(message "tag=%S %c" tag (char-before))
  11958       (cond
  11959         ((or (null tag) (web-mode-element-is-void tag))
  11960          (setq epp nil))
  11961         ((looking-back "</" (point-min))
  11962          (setq ins tag))
  11963         ((looking-back "<" (point-min))
  11964          (setq ins (concat "/" tag)))
  11965         (t
  11966          ;;auto-close-style = 2
  11967          ;;(message "%S %c" (point) (char-after))
  11968          (when (and (looking-at-p "[[:alpha:]]") (> (length tag) 4))
  11969            (dolist (elt '("div" "span" "strong" "pre" "li"))
  11970              (when (and (string-match-p (concat "^" elt) tag) (not (string= tag elt)))
  11971                (setq tag elt)
  11972                (put-text-property epp (point) 'tag-name tag))
  11973              )
  11974            ) ;when
  11975          (if (web-mode-element-is-void (get-text-property (point) 'tag-name))
  11976              (setq ins nil
  11977                    epp nil)
  11978              (setq ins (concat "</" tag)))
  11979          )
  11980         ) ;cond
  11981       (when ins
  11982         (unless (looking-at-p "[ ]*>")
  11983           (setq ins (concat ins ">")))
  11984         (insert ins)
  11985         (setq tag (downcase tag))
  11986         (save-excursion
  11987           (search-backward "<")
  11988           (setq jmp (and (eq (char-before) ?\>)
  11989                          (string= (get-text-property (1- (point)) 'tag-name) tag)))
  11990           (if jmp (setq jmp (point)))
  11991           ) ;save-excursion
  11992         (if jmp (goto-char jmp))
  11993         ) ;when not ins
  11994       ) ;when epp
  11995     epp))
  11996 
  11997 (defun web-mode-detect-content-type ()
  11998   (cond
  11999     ((and (string= web-mode-engine "none")
  12000           (< (point) 16)
  12001           (eq (char-after 1) ?\#)
  12002           (string-match-p "php" (buffer-substring-no-properties
  12003                                  (line-beginning-position)
  12004                                  (line-end-position))))
  12005      (web-mode-set-engine "php"))
  12006     ((and (string= web-mode-content-type "javascript")
  12007           (< (point) web-mode-chunk-length)
  12008           (eq (char-after (point-min)) ?\/)
  12009           (string-match-p "@jsx" (buffer-substring-no-properties
  12010                                   (line-beginning-position)
  12011                                   (line-end-position))))
  12012      (web-mode-set-content-type "jsx"))
  12013     ))
  12014 
  12015 (defun web-mode-auto-complete ()
  12016   "Autocomple at point."
  12017   (interactive)
  12018   (let ((pos (point))
  12019         (char (char-before))
  12020         (chunk (buffer-substring-no-properties (- (point) 2) (point)))
  12021         (expanders nil) (tag nil)
  12022         (auto-closed   nil)
  12023         (auto-expanded nil)
  12024         (auto-paired   nil)
  12025         (auto-quoted   nil))
  12026 
  12027     ;;-- auto-closing
  12028     (when web-mode-enable-auto-closing
  12029 
  12030       (cond
  12031 
  12032         ((and (= web-mode-auto-close-style 3)
  12033               (eq char ?\<))
  12034          (insert "/>")
  12035          (backward-char 2)
  12036          (setq auto-closed t))
  12037 
  12038         ((and (= web-mode-auto-close-style 3)
  12039               (eq char ?\>)
  12040               (looking-at-p "/>"))
  12041          (save-excursion
  12042            (re-search-backward web-mode-start-tag-regexp)
  12043            (setq tag (match-string-no-properties 1)))
  12044          (insert "<")
  12045          (forward-char)
  12046          (insert tag)
  12047          (setq auto-closed t))
  12048 
  12049         ((and (>= pos 4)
  12050               (or (string= "</" chunk)
  12051                   ;;(progn (message "%c" char) nil)
  12052                   (and (= web-mode-auto-close-style 2)
  12053                        (or (string= web-mode-content-type "jsx")
  12054                            (not (get-text-property pos 'part-side)))
  12055                        (string-match-p "[[:alnum:]'\"]>" chunk)))
  12056               (not (get-text-property (- pos 2) 'block-side))
  12057               (web-mode-element-close))
  12058          (setq auto-closed t))
  12059 
  12060         ) ;cond
  12061       ) ;when
  12062 
  12063     ;;-- auto-pairing
  12064     (when (and web-mode-enable-auto-pairing
  12065                (>= pos 4)
  12066                (not auto-closed))
  12067       (let ((i 0) expr after pos-end (l (length web-mode-auto-pairs)))
  12068         (setq pos-end (if (> (+ pos 32) (line-end-position))
  12069                           (line-end-position)
  12070                           (+ pos 10)))
  12071         (setq chunk (buffer-substring-no-properties (- pos 3) pos)
  12072               after (buffer-substring-no-properties pos pos-end))
  12073         (while (and (< i l) (not auto-paired))
  12074           (setq expr (elt web-mode-auto-pairs i)
  12075                 i (1+ i))
  12076           ;;(message "chunk=%S expr=%S after=%S" chunk expr after)
  12077           (when (and (string= (car expr) chunk)
  12078                      (not (string-match-p (regexp-quote (cdr expr)) after)))
  12079             (setq auto-paired t)
  12080             (insert (cdr expr))
  12081             (if (string-match-p "|" (cdr expr))
  12082                 (progn
  12083                   (search-backward "|")
  12084                   (delete-char 1))
  12085                 (goto-char pos))
  12086             ) ;when
  12087           ) ;while
  12088         ) ;let
  12089       )
  12090 
  12091     ;;-- auto-expanding
  12092     (when (and web-mode-enable-auto-expanding
  12093                (not auto-closed)
  12094                (not auto-paired)
  12095                (eq char ?\/)
  12096                (looking-back "\\(^\\|[[:punct:][:space:]>]\\)./" (point-min))
  12097                (or (web-mode-jsx-is-html (1- pos))
  12098                    (and (not (get-text-property (1- pos) 'tag-type))
  12099                         (not (get-text-property (1- pos) 'part-side))))
  12100                (not (get-text-property (1- pos) 'block-side))
  12101                )
  12102       (setq expanders (append web-mode-extra-expanders web-mode-expanders))
  12103       (let ((i 0) pair (l (length expanders)))
  12104         (setq chunk (buffer-substring-no-properties (- pos 2) pos))
  12105         ;;(message "%S" chunk)
  12106         (while (and (< i l) (not auto-expanded))
  12107           (setq pair (elt expanders i)
  12108                 i (1+ i))
  12109           (when (string= (car pair) chunk)
  12110             (setq auto-expanded t)
  12111             (delete-char -2)
  12112             (insert (cdr pair))
  12113             (when (string-match-p "|" (cdr pair))
  12114               (search-backward "|")
  12115               (delete-char 1))
  12116             ) ;when
  12117           ) ;while
  12118         ) ;let
  12119       )
  12120 
  12121     ;;-- auto-quoting
  12122     (when (and web-mode-enable-auto-quoting
  12123                (>= pos 4)
  12124                (not (get-text-property pos 'block-side))
  12125                (not auto-closed)
  12126                (not auto-paired)
  12127                (not auto-expanded)
  12128                (get-text-property (- pos 2) 'tag-attr))
  12129       (cond
  12130         ((and (eq char ?\=)
  12131               (not (looking-at-p "[ ]*[\"']")))
  12132          (cond ((= web-mode-auto-quote-style 2)
  12133                 (insert "''"))
  12134                ((= web-mode-auto-quote-style 3)
  12135                 (insert "{}"))
  12136                (t
  12137                 (insert "\"\"")))
  12138          (if (looking-at-p "[ \n>]")
  12139              (backward-char)
  12140              (insert " ")
  12141              (backward-char 2)
  12142              )
  12143          (setq auto-quoted t))
  12144         ((and (eq char ?\")
  12145               (looking-back "=[ ]*\"" (point-min))
  12146               (not (looking-at-p "[ ]*[\"]")))
  12147          (insert-and-inherit "\"")
  12148          (backward-char)
  12149          (setq auto-quoted t))
  12150         ((and (eq char ?\')
  12151               (looking-back "=[ ]*'" (point-min))
  12152               (not (looking-at-p "[ ]*[']")))
  12153          (insert-and-inherit "'")
  12154          (backward-char)
  12155          (setq auto-quoted t))
  12156         ((and (eq char ?\{)
  12157               (eq (get-text-property pos 'part-side) 'jsx)
  12158               (looking-back "=[ ]*{" (point-min))
  12159               (not (looking-at-p "[ ]*[}]")))
  12160          (insert-and-inherit "}")
  12161          (backward-char)
  12162          (setq auto-quoted t))
  12163         ((and (eq char ?\")
  12164               (eq (char-after) ?\"))
  12165          (delete-char 1)
  12166          (cond
  12167            ((looking-back "=\"\"" (point-min))
  12168             (backward-char))
  12169            ((eq (char-after) ?\s)
  12170             (forward-char))
  12171            (t
  12172             (insert " "))
  12173            ) ;cond
  12174          )
  12175         ) ;cond
  12176       ) ;when
  12177 
  12178     ;;--
  12179     (cond
  12180       ((or auto-closed auto-paired auto-expanded auto-quoted)
  12181        (when (and web-mode-change-end (>= (line-end-position) web-mode-change-end))
  12182          (setq web-mode-change-end (line-end-position)))
  12183        (list :auto-closed auto-closed
  12184              :auto-paired auto-paired
  12185              :auto-expanded auto-expanded
  12186              :auto-quoted auto-quoted))
  12187       (t
  12188        nil)
  12189       )
  12190 
  12191     ))
  12192 
  12193 (defun web-mode-dom-xpath (&optional pos)
  12194   "Display html path."
  12195   (interactive)
  12196   (unless pos (setq pos (point)))
  12197   (save-excursion
  12198     (goto-char pos)
  12199     (let (path tag)
  12200       (while (web-mode-element-parent)
  12201         (looking-at web-mode-tag-regexp)
  12202         (setq tag (match-string-no-properties 1))
  12203         (setq path (cons tag path))
  12204         )
  12205       (message "/%s" (mapconcat 'identity path "/"))
  12206       )))
  12207 
  12208 (defun web-mode-block-ends-with (regexp &optional pos)
  12209   (unless pos (setq pos (point)))
  12210   (save-excursion
  12211     (goto-char pos)
  12212     (save-match-data
  12213       (if (stringp regexp)
  12214           (and (web-mode-block-end)
  12215                (progn (backward-char) t)
  12216                (web-mode-block-skip-blank-backward)
  12217                (progn (forward-char) t)
  12218                (looking-back regexp (point-min)))
  12219           (let ((pair regexp)
  12220                 (block-beg (web-mode-block-beginning-position pos))
  12221                 (block-end (web-mode-block-end-position pos)))
  12222             (and (web-mode-block-end)
  12223                  (web-mode-block-sb (car pair) block-beg)
  12224                  (not (web-mode-sf (cdr pair) block-end)))
  12225             ) ;let
  12226           ) ;if
  12227       )))
  12228 
  12229 (defun web-mode-block-token-starts-with (regexp &optional pos)
  12230   (unless pos (setq pos (point)))
  12231   (save-excursion
  12232     (and (goto-char pos)
  12233          (web-mode-block-token-beginning)
  12234          (skip-chars-forward "[\"']")
  12235          (looking-at regexp))
  12236     ))
  12237 
  12238 (defun web-mode-block-starts-with (regexp &optional pos)
  12239   (unless pos (setq pos (point)))
  12240   (save-excursion
  12241     (and (web-mode-block-beginning)
  12242          (web-mode-block-skip-blank-forward)
  12243          (looking-at regexp))
  12244     ))
  12245 
  12246 (defun web-mode-block-skip-blank-backward (&optional pos)
  12247   (unless pos (setq pos (point)))
  12248   (let ((continue t))
  12249     (goto-char pos)
  12250     (while continue
  12251       (if (and (get-text-property (point) 'block-side)
  12252                (not (bobp))
  12253                (or (member (char-after) '(?\s ?\n))
  12254                    (member (get-text-property (point) 'block-token)
  12255                            '(delimiter-beg delimiter-end comment))))
  12256           (backward-char)
  12257           (setq continue nil))
  12258       ) ;while
  12259     (point)))
  12260 
  12261 (defun web-mode-block-skip-blank-forward (&optional pos props)
  12262   (unless pos (setq pos (point)))
  12263   (unless props (setq props '(delimiter-beg delimiter-end comment)))
  12264   (let ((continue t))
  12265     (goto-char pos)
  12266     (while continue
  12267       (if (and (get-text-property (point) 'block-side)
  12268                (or (member (char-after) '(?\s ?\n ?\t))
  12269                    (member (get-text-property (point) 'block-token) props)))
  12270           (forward-char)
  12271           (setq continue nil))
  12272       ) ;while
  12273     (point)))
  12274 
  12275 (defun web-mode-tag-attributes-sort (&optional pos)
  12276   "Sort the attributes inside the current html tag."
  12277   (interactive)
  12278   (unless pos (setq pos (point)))
  12279   (save-excursion
  12280     (let (attrs (continue t) min max tag-beg tag-end attr attr-name attr-beg attr-end indent indentation sorter ins)
  12281       (if (not (member (get-text-property pos 'tag-type) '(start void)))
  12282           nil
  12283           (setq tag-beg (web-mode-tag-beginning-position pos)
  12284                 tag-end (web-mode-tag-end-position))
  12285           ;;        (message "%S %S" tag-beg tag-end)
  12286           (goto-char tag-beg)
  12287           (while continue
  12288             (if (or (not (web-mode-attribute-next))
  12289                     (>= (point) tag-end))
  12290                 (setq continue nil)
  12291                 ;;(message "attr=%S" (point))
  12292                 (setq attr-beg (web-mode-attribute-beginning-position)
  12293                       attr-end (1+ (web-mode-attribute-end-position)))
  12294                 (when (null min)
  12295                   (setq min attr-beg))
  12296                 (setq max attr-end)
  12297                 (goto-char attr-beg)
  12298                 (setq attr (buffer-substring-no-properties attr-beg attr-end))
  12299                 (if (string-match "^\\([[:alnum:]-]+\\)=" attr)
  12300                     (setq attr-name (match-string-no-properties 1 attr))
  12301                     (setq attr-name attr))
  12302                 (setq indent (looking-back "^[ \t]*" (point-min)))
  12303                 (setq attrs (append attrs (list (list attr-beg attr-end attr-name attr indent))))
  12304                 ) ;if
  12305             ) ;while
  12306           ) ;if in tag
  12307       (when attrs
  12308         (setq sorter (function
  12309                       (lambda (elt1 elt2)
  12310                        (string< (nth 2 elt1) (nth 2 elt2))
  12311                        )))
  12312         (setq attrs (sort attrs sorter))
  12313         (delete-region (1- min) max)
  12314         (setq ins "")
  12315         (dolist (elt attrs)
  12316           (if (and (nth 4 elt) (> (length ins) 1))
  12317               (setq ins (concat ins "\n"))
  12318               (setq ins (concat ins " ")))
  12319           (setq ins (concat ins (nth 3 elt)))
  12320           )
  12321         (goto-char (1- min))
  12322         (insert ins)
  12323         (web-mode-tag-beginning)
  12324         (setq min (line-beginning-position))
  12325         (web-mode-tag-end)
  12326         (setq max (line-end-position))
  12327         (indent-region min max)
  12328         )
  12329       ;;(message "attrs=%S" attrs)
  12330       )))
  12331 
  12332 (defun web-mode-attribute-insert (&optional attr-name attr-value)
  12333   "Insert an attribute inside current tag."
  12334   (interactive)
  12335   (let (attr attr-name attr-value)
  12336     (cond
  12337       ((not (member (get-text-property (point) 'tag-type) '(start void)))
  12338        (message "attribute-insert ** invalid context **"))
  12339       ((not (and (setq attr-name (or attr-name (completing-read
  12340                                                 "Attribute name: "
  12341                                                 (append
  12342                                                  web-mode-attribute-list
  12343                                                  web-mode-attribute-history)
  12344                                                 nil nil nil 'web-mode-attribute-history)))
  12345                  (> (length attr-name) 0)))
  12346        (message "attribute-insert ** failure **"))
  12347       (t
  12348        (setq attr (concat " " attr-name))
  12349        (when (setq attr-value (or attr-value (completing-read
  12350                                               "Attribute value: "
  12351                                               web-mode-attribute-value-history
  12352                                               nil nil nil 'web-mode-attribute-value-history)))
  12353          (setq attr (concat attr "=\"" attr-value "\"")))
  12354        (web-mode-tag-end)
  12355        (if (looking-back "/>" (point-min))
  12356            (backward-char 2)
  12357            (backward-char))
  12358        (insert attr)
  12359        ) ;t
  12360       ) ;cond
  12361     ))
  12362 
  12363 (defun web-mode-attribute-transpose (&optional pos)
  12364   "Transpose the current html attribute."
  12365   (interactive)
  12366   (unless pos (setq pos (point)))
  12367   (let (ret attr-beg attr-end next-beg next-end tag-end)
  12368     (when (and (get-text-property pos 'tag-attr)
  12369                (setq next-beg (web-mode-attribute-next-position pos))
  12370                (setq next-end (web-mode-attribute-end-position next-beg))
  12371                (setq tag-end (web-mode-tag-end-position pos))
  12372                (> tag-end next-end))
  12373       (setq attr-beg (web-mode-attribute-beginning-position pos)
  12374             attr-end (web-mode-attribute-end-position pos))
  12375       ;;      (message "%S %S - %S %S" attr-beg attr-end next-beg next-end)
  12376       (transpose-regions attr-beg (1+ attr-end) next-beg (1+ next-end))
  12377       )))
  12378 
  12379 (defun web-mode-attribute-select (&optional pos)
  12380   "Select the current html attribute."
  12381   (interactive)
  12382   (unless pos (setq pos (point)))
  12383   (if (null (get-text-property pos 'tag-attr))
  12384       nil
  12385       (goto-char pos)
  12386       (web-mode-attribute-beginning)
  12387       (set-mark (point))
  12388       (web-mode-attribute-end)
  12389       (exchange-point-and-mark)
  12390       (point)
  12391       ))
  12392 
  12393 (defun web-mode-attribute-kill (&optional arg)
  12394   "Kill the current html attribute."
  12395   (interactive "p")
  12396   (unless arg (setq arg 1))
  12397   (while (>= arg 1)
  12398     (setq arg (1- arg))
  12399     (web-mode-attribute-select)
  12400     (when mark-active
  12401       (let ((beg (region-beginning)) (end (region-end)))
  12402         (save-excursion
  12403           (goto-char end)
  12404           (when (looking-at "[ \n\t]*")
  12405             (setq end (+ end (length (match-string-no-properties 0)))))
  12406           ) ;save-excursion
  12407         (kill-region beg end)
  12408         ) ;let
  12409       ) ;when
  12410     ) ;while
  12411   ;; Delete a potential space before the closing ">".
  12412   (when (and (looking-at ">")
  12413              (looking-back " " (point-min)))
  12414     (delete-char -1))
  12415   )
  12416 
  12417 (defun web-mode-block-close (&optional pos)
  12418   "Close the first unclosed control block."
  12419   (interactive)
  12420   (unless pos (setq pos (point)))
  12421   (let ((continue t)
  12422         (h (make-hash-table :test 'equal)) ctx ctrl n closing-block)
  12423     (save-excursion
  12424       (while (and continue (web-mode-block-previous))
  12425         (when (setq ctx (web-mode-block-is-control (point)))
  12426           (setq ctrl (car ctx))
  12427           (setq n (gethash ctrl h 0))
  12428           (if (cdr ctx)
  12429               (puthash ctrl (1+ n) h)
  12430               (puthash ctrl (1- n) h))
  12431           (when (> (gethash ctrl h) 0)
  12432             (setq continue nil))
  12433           )
  12434         ) ;while
  12435       ) ;save-excursion
  12436     (when (and (null continue)
  12437                (setq closing-block (web-mode-closing-block ctrl)))
  12438       (insert closing-block)
  12439       (indent-according-to-mode))
  12440     ))
  12441 
  12442 (defun web-mode-closing-block (type)
  12443   (cond
  12444     ((string= web-mode-engine "php")              (concat "<?php end" type "; ?>"))
  12445     ((string= web-mode-engine "django")           (concat "{% end" type " %}"))
  12446     ((string= web-mode-engine "antlers")          (concat "{{/" type "}}"))
  12447     ((string= web-mode-engine "ctemplate")        (concat "{{/" type "}}"))
  12448     ((string= web-mode-engine "blade")
  12449      (if (string= type "section") (concat "@show") (concat "@end" type)))
  12450     ((string= web-mode-engine "dust")             (concat "{/" type "}"))
  12451     ((string= web-mode-engine "mako")             (concat "% end" type))
  12452     ((string= web-mode-engine "closure")          (concat "{/" type "}"))
  12453     ((string= web-mode-engine "smarty")           (concat "{/" type "}"))
  12454     ((string= web-mode-engine "expressionengine") (concat "{/" type "}"))
  12455     ((string= web-mode-engine "xoops")            (concat "<{/" type "}>"))
  12456     ((string= web-mode-engine "svelte")           (concat "{/" type "}"))
  12457     ((string= web-mode-engine "underscore")        "<% } %>")
  12458     ((string= web-mode-engine "lsp")               "<% ) %>")
  12459     ((string= web-mode-engine "erb")               "<% } %>")
  12460     ((string= web-mode-engine "erb")               "<% end %>")
  12461     ((string= web-mode-engine "artanis")           "<% ) %>")
  12462     ((string= web-mode-engine "hero")              "<% } %>")
  12463     ((string= web-mode-engine "go")                "{{end}}")
  12464     ((string= web-mode-engine "velocity")          "#end")
  12465     ((string= web-mode-engine "velocity")          "#{end}")
  12466     ((string= web-mode-engine "template-toolkit")  "[% end %]")
  12467     ((member web-mode-engine '("asp" "jsp"))
  12468      (if (string-match-p "[:.]" type) (concat "</" type ">") "<% } %>"))
  12469     (t nil)
  12470     ) ;cond
  12471   )
  12472 
  12473 ;;---- POSITION ----------------------------------------------------------------
  12474 
  12475 (defun web-mode-comment-beginning-position (&optional pos)
  12476   (unless pos (setq pos (point)))
  12477   (car (web-mode-comment-boundaries pos)))
  12478 
  12479 (defun web-mode-comment-end-position (&optional pos)
  12480   (unless pos (setq pos (point)))
  12481   (cdr (web-mode-comment-boundaries pos)))
  12482 
  12483 (defun web-mode-part-opening-paren-position (pos &optional limit)
  12484   (save-restriction
  12485     (unless limit (setq limit nil))
  12486     (goto-char pos)
  12487     (let* ((n -1)
  12488            (paren (char-after))
  12489            (pairs '((?\) . "[)(]")
  12490                     (?\] . "[\]\[]")
  12491                     (?\} . "[}{]")
  12492                     (?\> . "[><]")))
  12493            (regexp (cdr (assoc paren pairs)))
  12494            (continue (not (null regexp)))
  12495            (counter 0))
  12496       (while (and continue (re-search-backward regexp limit t))
  12497         (cond
  12498           ((> (setq counter (1+ counter)) 500)
  12499            (message "part-opening-paren-position ** warning **")
  12500            (setq continue nil))
  12501           ((or (web-mode-is-comment-or-string)
  12502                (get-text-property (point) 'block-side))
  12503            )
  12504           ((eq (char-after) paren)
  12505            (setq n (1- n)))
  12506           (t
  12507            (setq n (1+ n))
  12508            (setq continue (not (= n 0))))
  12509           )
  12510         ) ;while
  12511       (if (= n 0) (point) nil)
  12512       )))
  12513 
  12514 (defun web-mode-token-opening-paren-position (pos limit context)
  12515   (save-restriction
  12516     (unless limit (setq limit nil))
  12517     (goto-char pos)
  12518     (let* ((n -1)
  12519            (paren (char-after))
  12520            (pairs '((?\) . "[)(]")
  12521                     (?\] . "[\]\[]")
  12522                     (?\} . "[}{]")
  12523                     (?\> . "[><]")))
  12524            (regexp (cdr (assoc paren pairs)))
  12525            (continue (not (null regexp)))
  12526            (counter 0))
  12527       (while (and continue (re-search-backward regexp limit t))
  12528         (cond
  12529           ((> (setq counter (1+ counter)) 200)
  12530            (message "token-opening-paren-position ** warning **")
  12531            (setq continue nil))
  12532           ((get-text-property (point) 'block-side)
  12533            )
  12534           ((eq (char-after) paren)
  12535            (setq n (1- n)))
  12536           (t
  12537            (setq n (1+ n))
  12538            (setq continue (not (= n 0))))
  12539           )
  12540         ) ;while
  12541       (if (= n 0) (point) nil)
  12542       )))
  12543 
  12544 (defun web-mode-closing-paren-position (&optional pos limit)
  12545   (save-excursion
  12546     (unless pos (setq pos (point)))
  12547     (unless limit (setq limit nil))
  12548     (goto-char pos)
  12549     (let* ((n 0)
  12550            (block-side (and (get-text-property pos 'block-side)
  12551                             (not (string= web-mode-engine "razor"))))
  12552            (paren (char-after))
  12553            (pairs '((?\( . "[)(]")
  12554                     (?\[ . "[\]\[]")
  12555                     (?\{ . "[}{]")
  12556                     (?\< . "[><]")))
  12557            (regexp (cdr (assoc paren pairs)))
  12558            (continue (not (null regexp))))
  12559       (while (and continue (re-search-forward regexp limit t))
  12560         (cond
  12561           ((or (web-mode-is-comment-or-string (1- (point)))
  12562                (and block-side (not (get-text-property (point) 'block-side))))
  12563            ;;(message "pt=%S" (point))
  12564            )
  12565           ((eq (char-before) paren)
  12566            (setq n (1+ n)))
  12567           (t
  12568            (setq n (1- n))
  12569            (setq continue (not (= n 0)))
  12570            )
  12571           ) ;cond
  12572         ) ;while
  12573       (if (= n 0) (1- (point)) nil)
  12574       )))
  12575 
  12576 (defun web-mode-closing-delimiter-position (delimiter &optional pos limit)
  12577   (unless pos (setq pos (point)))
  12578   (unless limit (setq limit nil))
  12579   (save-excursion
  12580     (goto-char pos)
  12581     (setq pos nil)
  12582     (let ((continue t))
  12583       (while (and continue (re-search-forward delimiter limit t))
  12584         (setq continue nil
  12585               pos (1- (point)))
  12586         ) ;while
  12587       pos)))
  12588 
  12589 (defun web-mode-tag-match-position (&optional pos)
  12590   (unless pos (setq pos (point)))
  12591   (save-excursion
  12592     (web-mode-tag-match pos)
  12593     (if (= pos (point)) nil (point))))
  12594 
  12595 (defun web-mode-tag-beginning-position (&optional pos)
  12596   (unless pos (setq pos (point)))
  12597   (let (beg end depth)
  12598     (setq depth (get-text-property pos 'jsx-depth))
  12599     (when (and depth (get-text-property pos 'tag-attr-beg))
  12600       (setq depth (get-text-property (1- pos) 'jsx-depth)))
  12601     (cond
  12602       ((null pos)
  12603        (setq end nil))
  12604       ((get-text-property pos 'tag-beg)
  12605        (setq beg pos))
  12606       ((and (> pos 1) (get-text-property (1- pos) 'tag-beg))
  12607        (setq beg (1- pos)))
  12608       ((get-text-property pos 'tag-type)
  12609        (setq beg (previous-single-property-change pos 'tag-beg))
  12610        (when beg (setq beg (1- beg)))
  12611        (cond
  12612          ((not (get-text-property beg 'tag-beg))
  12613           (setq beg nil))
  12614          ((and depth (not (eq depth (get-text-property beg 'jsx-depth))))
  12615           (let ((continue (> beg (point-min))))
  12616             (while continue
  12617               (setq beg (previous-single-property-change beg 'tag-beg))
  12618               (when beg (setq beg (1- beg)))
  12619               (cond
  12620                 ((null beg)
  12621                  (setq continue nil))
  12622                 ((not (get-text-property beg 'tag-beg))
  12623                  (setq continue nil
  12624                        beg nil))
  12625                 ((eq depth (get-text-property beg 'jsx-depth))
  12626                  (setq continue nil))
  12627                 ) ;cond
  12628               ) ;while
  12629             ) ;let
  12630           )
  12631          ) ;cond
  12632        )
  12633       (t
  12634        (setq beg nil))
  12635       ) ;cond
  12636     beg))
  12637 
  12638 (defun web-mode-tag-end-position (&optional pos)
  12639   (unless pos (setq pos (point)))
  12640   (let (end depth)
  12641     (setq depth (get-text-property pos 'jsx-depth))
  12642     (when (and depth (get-text-property pos 'tag-attr-beg))
  12643       (setq depth (get-text-property (1- pos) 'jsx-depth)))
  12644     (cond
  12645       ((null pos)
  12646        (setq end nil))
  12647       ((get-text-property pos 'tag-end)
  12648        (setq end pos))
  12649       ((get-text-property pos 'tag-type)
  12650        (setq end (next-single-property-change pos 'tag-end))
  12651        (cond
  12652          ((not (get-text-property end 'tag-end))
  12653           (setq end nil))
  12654          ((and depth (not (eq depth (get-text-property end 'jsx-depth))))
  12655           (let ((continue (< end (point-max))))
  12656             (while continue
  12657               (setq end (1+ end))
  12658               (setq end (next-single-property-change end 'tag-end))
  12659               (cond
  12660                 ((null end)
  12661                  (setq continue nil))
  12662                 ((not (get-text-property end 'tag-end))
  12663                  (setq continue nil
  12664                        end nil))
  12665                 ((eq depth (get-text-property end 'jsx-depth))
  12666                  (setq continue nil))
  12667                 ) ;cond
  12668               ) ;while
  12669             ) ;let
  12670           )
  12671          ) ;cond
  12672        )
  12673       (t
  12674        (setq end nil))
  12675       ) ;cond
  12676     end))
  12677 
  12678 ;; TODO: prendre en compte jsx-depth
  12679 (defun web-mode-tag-next-position (&optional pos limit)
  12680   (unless pos (setq pos (point)))
  12681   (unless limit (setq limit (point-max)))
  12682   (cond
  12683     ((or (>= pos (point-max)) (>= pos limit)) nil)
  12684     (t
  12685      (when (get-text-property pos 'tag-beg) (setq pos (1+ pos)))
  12686      (setq pos (next-single-property-change pos 'tag-beg))
  12687      (if (and pos (<= pos limit)) pos nil))
  12688     ))
  12689 
  12690 ;; TODO: prendre en compte jsx-depth
  12691 (defun web-mode-tag-previous-position (&optional pos limit)
  12692   (unless pos (setq pos (point)))
  12693   (unless limit (setq limit (point-min)))
  12694   (cond
  12695     ((or (<= pos (point-min)) (<= pos limit)) nil)
  12696     (t
  12697      (when (get-text-property pos 'tag-beg) (setq pos (1- pos)))
  12698      (web-mode-go (previous-single-property-change pos 'tag-beg) -1))
  12699     ))
  12700 
  12701 ;; TODO: prendre en compte jsx-depth
  12702 (defun web-mode-attribute-beginning-position (&optional pos)
  12703   (unless pos (setq pos (point)))
  12704   (cond
  12705     ((null (get-text-property pos 'tag-attr))
  12706      nil)
  12707     ((get-text-property pos 'tag-attr-beg)
  12708      pos)
  12709     ((and (> pos (point-min)) (get-text-property (1- pos) 'tag-attr-beg))
  12710      (1- pos))
  12711     (t
  12712      (setq pos (previous-single-property-change pos 'tag-attr-beg))
  12713      (setq pos (1- pos)))
  12714     ))
  12715 
  12716 ;; TODO: retoucher en incluant un param limit et en s'inspirant de
  12717 ;;       web-mode-attribute-next-position
  12718 (defun web-mode-attribute-end-position (&optional pos)
  12719   (unless pos (setq pos (point)))
  12720   (let (beg end depth flags)
  12721     ;;(message "pos=%S" pos)
  12722     (setq depth (get-text-property pos 'jsx-depth))
  12723     (cond
  12724       ((null pos)
  12725        (setq end nil))
  12726       ((get-text-property pos 'tag-attr-end)
  12727        (setq end pos))
  12728       ((get-text-property pos 'tag-attr)
  12729        (setq end (next-single-property-change pos 'tag-attr-end))
  12730        (when (and depth
  12731                   end
  12732                   (setq beg (web-mode-attribute-beginning-position end))
  12733                   (setq flags (get-text-property pos 'tag-attr-beg))
  12734                   (eq (logand flags 4) 4))
  12735          (setq depth (1- (get-text-property beg 'jsx-depth)))
  12736          ;;(message "%S %S" beg end)
  12737          )
  12738        (cond
  12739          ((not (get-text-property end 'tag-attr-end))
  12740           (setq end nil))
  12741          ((and depth
  12742                (eq depth (get-text-property end 'jsx-depth))
  12743                (not (eq depth (get-text-property end 'jsx-end))))
  12744           )
  12745          ((and depth (eq (1+ depth) (get-text-property end 'jsx-depth)))
  12746           )
  12747          ((and depth (not (eq (1+ depth) (get-text-property end 'jsx-depth))))
  12748           (let ((continue (< end (point-max))))
  12749             (while continue
  12750               (setq end (1+ end))
  12751               (setq end (next-single-property-change end 'tag-attr-end))
  12752               (cond
  12753                 ((null end)
  12754                  (setq continue nil))
  12755                 ((not (get-text-property end 'tag-attr-end))
  12756                  (setq continue nil
  12757                        end nil))
  12758                 ((eq (1+ depth) (get-text-property end 'jsx-depth))
  12759                  (setq continue nil))
  12760                 ) ;cond
  12761               ) ;while
  12762             ) ;let
  12763           )
  12764          ) ;cond
  12765        )
  12766       (t
  12767        (setq end nil))
  12768       ) ;cond
  12769     end))
  12770 
  12771 ;; attention si pos est au debut d'un spread attributes, cela
  12772 ;; risque de poser pb
  12773 (defun web-mode-attribute-next-position (&optional pos limit)
  12774   (unless pos (setq pos (point)))
  12775   (unless limit (setq limit (point-max)))
  12776   (let (continue depth)
  12777     (when (get-text-property pos 'tag-attr-beg)
  12778       (setq pos (1+ pos)))
  12779     (if (< pos limit)
  12780         (setq continue t
  12781               depth (get-text-property pos 'jsx-depth))
  12782         (setq continue nil
  12783               pos nil))
  12784     (while continue
  12785       (setq pos (next-single-property-change pos 'tag-attr-beg))
  12786       (cond
  12787         ((null pos)
  12788          (setq continue nil))
  12789         ((>= pos limit)
  12790          (setq continue nil
  12791                pos nil))
  12792         ((null depth)
  12793          (setq continue nil))
  12794         ((and (eq (get-text-property pos 'tag-attr-beg) 4)
  12795               (eq (1+ depth) (get-text-property pos 'jsx-depth)))
  12796          (setq continue nil))
  12797         ((eq depth (get-text-property pos 'jsx-depth))
  12798          (setq continue nil))
  12799         (t
  12800          (setq pos (1+ pos)
  12801                continue (< pos limit)))
  12802         )
  12803       ) ;while
  12804     pos))
  12805 
  12806 (defun web-mode-attribute-previous-position (&optional pos limit)
  12807   (unless pos (setq pos (point)))
  12808   (unless limit (setq limit (point-min)))
  12809   (let (continue depth)
  12810     (cond
  12811       ((and (> pos (point-min)) (get-text-property (1- pos) 'tag-attr-beg))
  12812        (setq pos (1- pos)
  12813              continue nil))
  12814       (t
  12815        (when (get-text-property pos 'tag-attr-beg)
  12816          (setq pos (1- pos)))
  12817        (if (> pos limit)
  12818            (setq continue t
  12819                  depth (get-text-property pos 'jsx-depth))
  12820            (setq continue nil
  12821                  pos nil))
  12822        ) ;t
  12823       ) ;cond
  12824     (while continue
  12825       (setq pos (previous-single-property-change pos 'tag-attr-beg))
  12826       (cond
  12827         ((null pos)
  12828          (setq continue nil))
  12829         ((< pos limit)
  12830          (setq continue nil
  12831                pos nil))
  12832         ;;((null depth)
  12833         ;; (setq continue nil))
  12834         ((and depth (eq depth (get-text-property pos 'jsx-depth)))
  12835          (setq  pos (1- pos)
  12836                 continue nil))
  12837         (depth
  12838          (setq pos nil
  12839                continue (> pos limit)))
  12840         (t
  12841          (setq pos (1- pos)
  12842                continue nil))
  12843         ) ;cond
  12844       ) ;while
  12845     pos))
  12846 
  12847 ;; TODO: prendre en compte jsx-depth
  12848 (defun web-mode-element-beginning-position (&optional pos)
  12849   (unless pos (setq pos (point)))
  12850   (cond
  12851     ((null (get-text-property pos 'tag-type))
  12852      (setq pos (web-mode-element-parent-position)))
  12853     ((eq (get-text-property pos 'tag-type) 'end)
  12854      (setq pos (web-mode-tag-match-position pos))
  12855      (setq pos (if (get-text-property pos 'tag-beg) pos nil)))
  12856     ((member (get-text-property pos 'tag-type) '(start void))
  12857      (setq pos (web-mode-tag-beginning-position pos)))
  12858     (t
  12859      (setq pos nil))
  12860     ) ;cond
  12861   pos)
  12862 
  12863 ;; TODO: prendre en compte jsx-depth
  12864 (defun web-mode-element-end-position (&optional pos)
  12865   (unless pos (setq pos (point)))
  12866   (cond
  12867     ((null (get-text-property pos 'tag-type))
  12868      (setq pos (web-mode-element-parent-position pos))
  12869      (when pos
  12870        (setq pos (web-mode-tag-match-position pos))
  12871        (when pos (setq pos (web-mode-tag-end-position pos)))
  12872        )
  12873      )
  12874     ((member (get-text-property pos 'tag-type) '(end void comment))
  12875      (setq pos (web-mode-tag-end-position pos))
  12876      )
  12877     ((member (get-text-property pos 'tag-type) '(start))
  12878      (setq pos (web-mode-tag-match-position pos))
  12879      (when pos (setq pos (web-mode-tag-end-position pos))))
  12880     (t
  12881      (setq pos nil))
  12882     ) ;cond
  12883   pos)
  12884 
  12885 (defun web-mode-element-child-position (&optional pos)
  12886   (save-excursion
  12887     (let (child close)
  12888       (unless pos (setq pos (point)))
  12889       (goto-char pos)
  12890       (cond
  12891         ((eq (get-text-property pos 'tag-type) 'start)
  12892          (web-mode-tag-match)
  12893          (setq close (point))
  12894          (goto-char pos)
  12895          )
  12896         ((eq (get-text-property pos 'tag-type) 'void)
  12897          )
  12898         ((eq (get-text-property pos 'tag-type) 'end)
  12899          (web-mode-tag-beginning)
  12900          (setq close (point))
  12901          (web-mode-tag-match)
  12902          )
  12903         ((web-mode-element-parent-position pos)
  12904          (setq pos (point))
  12905          (web-mode-tag-match)
  12906          (setq close (point))
  12907          (goto-char pos)
  12908          )
  12909         ) ;cond
  12910       (when (and close
  12911                  (web-mode-element-next)
  12912                  (< (point) close))
  12913         (setq child (point))
  12914         )
  12915       child)))
  12916 
  12917 (defun web-mode-element-parent-position (&optional pos)
  12918   (let (n tag-type tag-name (continue t) (tags (make-hash-table :test 'equal)))
  12919     (save-excursion
  12920       (if pos (goto-char pos))
  12921       (while (and continue (web-mode-tag-previous))
  12922         (setq pos (point)
  12923               tag-type (get-text-property pos 'tag-type)
  12924               tag-name (get-text-property pos 'tag-name)
  12925               n (gethash tag-name tags 0))
  12926         (when (member tag-type '(end start))
  12927           (if (eq tag-type 'end)
  12928               (puthash tag-name (1- n) tags)
  12929               (puthash tag-name (1+ n) tags)
  12930               (when (= n 0) (setq continue nil))
  12931               ) ;if
  12932           ) ;when
  12933         ) ;while
  12934       ) ;save-excursion
  12935     (if (null continue) pos nil)))
  12936 
  12937 (defun web-mode-element-previous-position (&optional pos limit)
  12938   (unless pos (setq pos (point)))
  12939   (unless limit (setq limit (point-min)))
  12940   (save-excursion
  12941     (goto-char pos)
  12942     (let ((continue (not (bobp)))
  12943           (props '(start void comment)))
  12944       (while continue
  12945         (setq pos (web-mode-tag-previous))
  12946         (cond
  12947           ((or (null pos) (< (point) limit))
  12948            (setq continue nil
  12949                  pos nil))
  12950           ((member (get-text-property (point) 'tag-type) props)
  12951            (setq continue nil))
  12952           )
  12953         ) ;while
  12954       pos)))
  12955 
  12956 (defun web-mode-element-next-position (&optional pos limit)
  12957   (unless pos (setq pos (point)))
  12958   (unless limit (setq limit (point-max)))
  12959   (save-excursion
  12960     (goto-char pos)
  12961     (let ((continue (not (eobp)))
  12962           (props '(start void comment)))
  12963       (while continue
  12964         (setq pos (web-mode-tag-next))
  12965         (cond
  12966           ((or (null pos) (> (point) limit))
  12967            (setq continue nil
  12968                  pos nil))
  12969           ((member (get-text-property (point) 'tag-type) props)
  12970            (setq continue nil))
  12971           )
  12972         ) ;while
  12973       ;;      (message "pos=%S" pos)
  12974       pos)))
  12975 
  12976 (defun web-mode-part-end-position (&optional pos)
  12977   (unless pos (setq pos (point)))
  12978   (cond
  12979     ((member web-mode-content-type web-mode-part-content-types)
  12980      (setq pos (point-max)))
  12981     ((not (get-text-property pos 'part-side))
  12982      (setq pos nil))
  12983     ((= pos (point-max))
  12984      (setq pos nil))
  12985     ((not (get-text-property (1+ pos) 'part-side))
  12986      pos)
  12987     (t
  12988      (setq pos (next-single-property-change pos 'part-side)))
  12989     ) ;cond
  12990   pos)
  12991 
  12992 (defun web-mode-part-beginning-position (&optional pos)
  12993   (unless pos (setq pos (point)))
  12994   (cond
  12995     (web-mode-part-beg
  12996      (setq pos web-mode-part-beg))
  12997     ((member web-mode-content-type web-mode-part-content-types)
  12998      (setq pos (point-min)
  12999            web-mode-part-beg (point-min)))
  13000     ((not (get-text-property pos 'part-side))
  13001      (setq pos nil))
  13002     ((= pos (point-min))
  13003      (setq pos nil))
  13004     ((not (get-text-property (1- pos) 'part-side))
  13005      pos)
  13006     (t
  13007      (setq pos (previous-single-property-change pos 'part-side)))
  13008     ) ;cond
  13009   pos)
  13010 
  13011 (defun web-mode-part-next-position (&optional pos)
  13012   (unless pos (setq pos (point)))
  13013   (cond
  13014     ((and (= pos (point-min)) (get-text-property pos 'part-side))
  13015      )
  13016     ((not (get-text-property pos 'part-side))
  13017      (setq pos (next-single-property-change pos 'part-side)))
  13018     ((and (setq pos (web-mode-part-end-position pos)) (>= pos (point-max)))
  13019      (setq pos nil))
  13020     ((and (setq pos (1+ pos)) (not (get-text-property pos 'part-side)))
  13021      (setq pos (next-single-property-change pos 'part-side)))
  13022     ) ;cond
  13023   pos)
  13024 
  13025 (defun web-mode-block-match-position (&optional pos)
  13026   (unless pos (setq pos (point)))
  13027   (save-excursion
  13028     (web-mode-block-match pos)
  13029     (if (= pos (point)) nil (point))))
  13030 
  13031 ;; type may be nil
  13032 (defun web-mode-block-control-previous-position (type &optional pos)
  13033   (unless pos (setq pos (point)))
  13034   (let ((continue t) controls)
  13035     (while continue
  13036       (setq pos (web-mode-block-previous-position pos))
  13037       (cond
  13038         ((null pos)
  13039          (setq continue nil
  13040                pos nil))
  13041         ((null type)
  13042          (setq continue nil))
  13043         ((and (setq controls (web-mode-block-controls-get pos))
  13044               (eq (car (car controls)) type))
  13045          (setq continue nil))
  13046         ) ;cond
  13047       ) ;while
  13048     pos))
  13049 
  13050 (defun web-mode-inside-block-control (&optional pos)
  13051   (unless pos (setq pos (point)))
  13052   (setq pos (web-mode-block-control-previous-position nil pos))
  13053   (if (and pos (member (car (car (web-mode-block-controls-get pos))) '(open inside)))
  13054       pos
  13055       nil))
  13056 
  13057 (defun web-mode-block-opening-paren-position (pos limit)
  13058   (save-excursion
  13059     (when (> limit pos)
  13060       (message "block-opening-paren-position: limit(%S) > pos(%S)" limit pos))
  13061     (goto-char pos)
  13062     (let (c
  13063           n
  13064           pt
  13065           (continue (> pos limit))
  13066           (pairs '((?\) . ?\()
  13067                    (?\] . ?\[)
  13068                    (?\} . ?\{)))
  13069           (h (make-hash-table :test 'equal))
  13070           (regexp "[\]\[)(}{]"))
  13071       (while (and continue (re-search-backward regexp limit t))
  13072         (cond
  13073           ((web-mode-is-comment-or-string)
  13074            )
  13075           (t
  13076            (setq c (char-after))
  13077            (cond
  13078              ((member c '(?\( ?\{ ?\[))
  13079               (setq n (gethash c h 0))
  13080               (if (= n 0)
  13081                   (setq continue nil
  13082                         pt (point))
  13083                   (puthash c (1+ n) h)
  13084                   ))
  13085              (t
  13086               (setq c (cdr (assoc c pairs)))
  13087               (setq n (gethash c h 0))
  13088               (puthash c (1- n) h))
  13089              ) ;cond
  13090            ) ;t
  13091           ) ;cond
  13092         ) ;while
  13093       pt)))
  13094 
  13095 (defun web-mode-block-code-beginning-position (&optional pos)
  13096   (unless pos (setq pos (point)))
  13097   (when (and (setq pos (web-mode-block-beginning-position pos))
  13098              (eq (get-text-property pos 'block-token) 'delimiter-beg))
  13099     (setq pos (next-single-property-change pos 'block-token)))
  13100   pos)
  13101 
  13102 (defun web-mode-block-beginning-position (&optional pos)
  13103   (unless pos (setq pos (point)))
  13104   (cond
  13105     ((or (and (get-text-property pos 'block-side) (= pos (point-min)))
  13106          (get-text-property pos 'block-beg))
  13107      )
  13108     ((and (> pos (point-min)) (get-text-property (1- pos) 'block-beg))
  13109      (setq pos (1- pos)))
  13110     ((get-text-property pos 'block-side)
  13111      (setq pos (previous-single-property-change pos 'block-beg))
  13112      (setq pos (if (and pos (> pos (point-min))) (1- pos) (point-min))))
  13113     (t
  13114      (setq pos nil))
  13115     ) ;cond
  13116   pos)
  13117 
  13118 (defun web-mode-block-string-beginning-position (pos &optional block-beg)
  13119   (unless pos (setq pos (point)))
  13120   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13121   (let (char (ori pos) (continue (not (null pos))))
  13122     (while continue
  13123       (setq char (char-after pos))
  13124       (cond
  13125         ((< pos block-beg)
  13126          (setq continue nil
  13127                pos block-beg))
  13128         ((and (member (get-text-property pos 'block-token) '(string comment))
  13129               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13130          (setq pos (web-mode-block-token-beginning-position pos))
  13131          )
  13132         ((member char '(?\) ?\]))
  13133          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13134          (setq pos (1- pos))
  13135          )
  13136         ((and (> ori pos) (member char '(?\( ?\= ?\[ ?\? ?\: ?\; ?\, ?\`)))
  13137          (if (and (eq char ?\:) ; #1024
  13138                   (web-mode-looking-at ":" pos))
  13139              (setq pos (1- pos))
  13140              (web-mode-looking-at ".[ \t\n]*" pos)
  13141              (setq pos (+ pos (length (match-string-no-properties 0)))
  13142                    continue nil)
  13143              )
  13144          )
  13145         ((web-mode-looking-at "\\(return\\|echo\\|include\\|print\\)[ \n]" pos)
  13146          (setq pos (+ pos (length (match-string-no-properties 0)))
  13147                continue nil))
  13148         (t
  13149          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?;,`:]\\|\\(return\\|echo\\|include\\|print\\)" block-beg))
  13150          (when (not pos)
  13151            (message "block-string-beginning-position ** search failure **")
  13152            (setq continue nil
  13153                  pos block-beg)))
  13154         ) ;cond
  13155       ) ;while
  13156     ;;(message "pos=%S" pos)
  13157     pos))
  13158 
  13159 (defun web-mode-block-statement-beginning-position (pos block-beg is-ternary)
  13160   (unless pos (setq pos (point)))
  13161   (setq pos (1- pos))
  13162   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13163   (let (char (continue (not (null pos))))
  13164     (while continue
  13165       (setq char (char-after pos))
  13166       (cond
  13167         ((< pos block-beg)
  13168          (setq continue nil
  13169                pos block-beg))
  13170         ((and (member (get-text-property pos 'block-token) '(string comment))
  13171               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13172          (setq pos (web-mode-block-token-beginning-position pos)))
  13173         ((member char '(?\) ?\] ?\}))
  13174          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13175          (setq pos (1- pos)))
  13176         ((and (eq char ?\=)
  13177               (web-mode-looking-back "[<>!=]+" pos block-beg t))
  13178          (setq pos (- pos 1 (length (match-string-no-properties 0))))
  13179          ;;(setq pos (1- pos))
  13180          ;;(message "%S pos=%S" (match-string-no-properties 0) pos)
  13181          )
  13182         ((member char '(?\( ?\[ ?\{ ?\=))
  13183          (setq continue nil)
  13184          (web-mode-looking-at ".[ \t\n]*" pos)
  13185          (setq pos (+ pos (length (match-string-no-properties 0)))))
  13186         ((web-mode-looking-at "\\(return\\|echo\\|include\\|print\\)[ \n]" pos)
  13187          (setq pos (+ pos (length (match-string-no-properties 0)))
  13188                continue nil))
  13189         (t
  13190          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=]\\|\\(return\\|echo\\|include\\|print\\)" block-beg))
  13191          (when (not pos)
  13192            (message "block-statement-beginning-position ** search failure **")
  13193            (setq continue nil
  13194                  pos block-beg)))
  13195         ) ;cond
  13196       ) ;while
  13197     pos))
  13198 
  13199 (defun web-mode-block-args-beginning-position (pos &optional block-beg)
  13200   (unless pos (setq pos (point)))
  13201   (setq pos (1- pos)) ;#512
  13202   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13203   (let (char (continue (not (null pos))))
  13204     (while continue
  13205       (setq char (char-after pos))
  13206       (cond
  13207         ((< pos block-beg)
  13208          (message "block-args-beginning-position ** failure **")
  13209          (setq continue nil
  13210                pos block-beg))
  13211         ((and (member (get-text-property pos 'block-token) '(string comment))
  13212               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13213          (setq pos (web-mode-block-token-beginning-position pos)))
  13214         ((member char '(?\) ?\] ?\}))
  13215          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13216          (setq pos (1- pos)))
  13217         ((member char '(?\( ?\[ ?\{))
  13218          (setq continue nil)
  13219          (web-mode-looking-at ".[ \t\n]*" pos)
  13220          (setq pos (+ pos (length (match-string-no-properties 0)))))
  13221         ((and (string= web-mode-engine "php")
  13222               (web-mode-looking-at "\\(extends\\|implements\\)[ \n]" pos))
  13223          (setq pos (+ pos (length (match-string-no-properties 0)))
  13224                continue nil))
  13225         (t
  13226          (setq pos (web-mode-rsb-position pos "[\]\[}{)(]\\|\\(extends\\|implements\\)" block-beg))
  13227          (when (not pos)
  13228            (message "block-args-beginning-position ** search failure **")
  13229            (setq pos block-beg
  13230                  continue nil))
  13231          ) ;t
  13232         ) ;cond
  13233       ) ;while
  13234     pos))
  13235 
  13236 (defun web-mode-block-calls-beginning-position (pos &optional block-beg)
  13237   (unless pos (setq pos (point)))
  13238   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13239   (let (char (continue (not (null pos))))
  13240     (while continue
  13241       (setq char (char-after pos))
  13242       (cond
  13243         ((< pos block-beg)
  13244          (message "block-calls-beginning-position ** failure **")
  13245          (setq continue nil
  13246                pos block-beg))
  13247         ((and (member (get-text-property pos 'block-token) '(string comment))
  13248               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13249          (setq pos (web-mode-block-token-beginning-position pos)))
  13250         ((member char '(?\) ?\]))
  13251          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13252          (setq pos (1- pos)))
  13253         ((member char '(?\( ?\[ ?\{ ?\} ?\= ?\? ?\: ?\; ?\,))
  13254          (web-mode-looking-at ".[ \t\n]*" pos)
  13255          (setq pos (+ pos (length (match-string-no-properties 0)))
  13256                continue nil))
  13257         ((web-mode-looking-at "\\(return\\|else\\)[ \n]" pos)
  13258          (setq pos (+ pos (length (match-string-no-properties 0)))
  13259                continue nil))
  13260         (t
  13261          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,]\\|\\(return\\|else\\)" block-beg))
  13262          (when (not pos)
  13263            (message "block-calls-beginning-position ** search failure **")
  13264            (setq pos block-beg
  13265                  continue nil))
  13266          ) ;t
  13267         ) ;cond
  13268       ) ;while
  13269     pos))
  13270 
  13271 (defun web-mode-javascript-string-beginning-position (pos &optional reg-beg)
  13272   (unless pos (setq pos (point)))
  13273   (let ((char nil)
  13274         (blockside (get-text-property pos 'block-side))
  13275         (i 0)
  13276         (continue (not (null pos))))
  13277     (unless reg-beg
  13278       (if blockside
  13279           (setq reg-beg (web-mode-block-beginning-position pos))
  13280           (setq reg-beg (web-mode-part-beginning-position pos)))
  13281       )
  13282     (while continue
  13283       (setq char (char-after pos))
  13284       (cond
  13285         ((> (setq i (1+ i)) 20000)
  13286          (message "javascript-string-beginning-position ** warning (%S) **" pos)
  13287          (setq continue nil
  13288                pos nil))
  13289         ((null pos)
  13290          (message "javascript-string-beginning-position ** invalid pos **")
  13291          (setq continue nil))
  13292         ((< pos reg-beg)
  13293          (message "javascript-string-beginning-position ** failure **")
  13294          (setq continue nil
  13295                pos reg-beg))
  13296         ((and blockside
  13297               (member (get-text-property pos 'block-token) '(string comment))
  13298               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13299          (setq pos (web-mode-block-token-beginning-position pos)))
  13300         ((and (not blockside)
  13301               (member (get-text-property pos 'part-token) '(string comment))
  13302               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13303          (setq pos (web-mode-part-token-beginning-position pos)))
  13304         ((and (not blockside)
  13305               (get-text-property pos 'block-side))
  13306          (when (setq pos (web-mode-block-beginning-position pos))
  13307            (setq pos (1- pos))))
  13308         ((member char '(?\) ?\] ?\}))
  13309          (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13310          (setq pos (1- pos)))
  13311         ((member char '(?\( ?\{ ?\[ ?\= ?\? ?\: ?\; ?\, ?\& ?\|))
  13312          (setq continue nil)
  13313          (web-mode-looking-at ".[ \t\n]*" pos)
  13314          (setq pos (+ pos (length (match-string-no-properties 0)))))
  13315         ((web-mode-looking-at "\\(return\\)[ \n]" pos)
  13316          (setq pos (+ pos (length (match-string-no-properties 0)))
  13317                continue nil))
  13318         (t
  13319          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,&|]\\|\\(return\\)" reg-beg))
  13320          (when (not pos)
  13321            (message "javascript-string-beginning-position ** search failure **")
  13322            (setq continue nil
  13323                  pos reg-beg)))
  13324         ) ;cond
  13325       ) ;while
  13326     ;;(message "js-statement-beg:%S" pos)
  13327     pos))
  13328 
  13329 ;; TODO: reg-beg : jsx-beg
  13330 ;; TODO: skipper les expr dont la depth est superieure
  13331 
  13332 ;; NOTE: blockside is useful for ejs
  13333 (defun web-mode-javascript-statement-beginning-position (pos reg-beg is-ternary)
  13334   (unless pos (setq pos (point)))
  13335   (setq pos (1- pos))
  13336   (let ((char nil)
  13337         (blockside (get-text-property pos 'block-side))
  13338         (i 0)
  13339         (is-jsx (string= web-mode-content-type "jsx"))
  13340         (depth-o nil) (depth-l nil)
  13341         (continue (not (null pos)))
  13342         (regexp "[\]\[}{)(=:]\\|\\(return\\)"))
  13343     (when is-ternary
  13344       (setq regexp (concat regexp "\\|[><]")))
  13345     (setq depth-o (get-text-property pos 'jsx-depth))
  13346     (unless reg-beg
  13347       (cond
  13348         (blockside
  13349          (setq reg-beg (web-mode-block-beginning-position pos)))
  13350         (is-jsx
  13351          (setq reg-beg (web-mode-jsx-depth-beginning-position pos)))
  13352         (t
  13353          (setq reg-beg (web-mode-part-beginning-position pos)))
  13354         ) ;cond
  13355       ) ;unless
  13356     (while continue
  13357       (setq char (char-after pos))
  13358       (cond
  13359         ((> (setq i (1+ i)) 20000)
  13360          (message "javascript-statement-beginning-position ** warning (%S) **" pos)
  13361          (setq continue nil
  13362                pos nil))
  13363         ((null pos)
  13364          (message "javascript-statement-beginning-position ** invalid pos **")
  13365          (setq continue nil))
  13366         ((< pos reg-beg)
  13367          (when (not is-jsx)
  13368            (message "javascript-statement-beginning-position ** failure **"))
  13369          (setq continue nil
  13370                pos reg-beg))
  13371         ((and is-jsx
  13372               (progn (setq depth-l (get-text-property pos 'jsx-depth)) t)
  13373               (not (eq depth-l depth-o)))
  13374          ;;(message "%S > depth-o(%S) depth-l(%S)" pos depth-o depth-l)
  13375          (setq pos (previous-single-property-change pos 'jsx-depth))
  13376          (setq pos (1- pos))
  13377          ;;(message "--> %S %S" pos (get-text-property pos 'jsx-depth))
  13378          )
  13379         ((and blockside
  13380               (member (get-text-property pos 'block-token) '(string comment))
  13381               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13382          (setq pos (web-mode-block-token-beginning-position pos)))
  13383         ((and (not blockside)
  13384               (member (get-text-property pos 'part-token) '(string comment))
  13385               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13386          (setq pos (web-mode-part-token-beginning-position pos)))
  13387         ((and (not blockside)
  13388               (get-text-property pos 'block-side))
  13389          (when (setq pos (web-mode-block-beginning-position pos))
  13390            (setq pos (1- pos))))
  13391         ((member char '(?\) ?\] ?\}))
  13392          (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13393          (setq pos (1- pos)))
  13394         ((and (eq char ?\=)
  13395               (web-mode-looking-back "[<>!=]+" pos reg-beg t))
  13396          (setq pos (- pos 1 (length (match-string-no-properties 0)))))
  13397         ((member char '(?\( ?\{ ?\[ ?\= ?\< ?\>))
  13398          (web-mode-looking-at ".[ \t\n]*" pos)
  13399          (setq continue nil
  13400                pos (+ pos (length (match-string-no-properties 0)))))
  13401 
  13402         ((web-mode-looking-at "\\(return\\)[ \n]" pos)
  13403          (setq continue nil
  13404                pos (+ pos (length (match-string-no-properties 0)))))
  13405         ((and (eq char ?\:)
  13406               (web-mode-looking-back "[{,][ \t\n]*[[:alnum:]_]+[ ]*" pos))
  13407          (web-mode-looking-at ".[ \t\n]*" pos)
  13408          (setq continue nil
  13409                pos (+ pos (length (match-string-no-properties 0)))))
  13410         (t
  13411          (setq pos (web-mode-rsb-position pos regexp reg-beg))
  13412          (when (not pos)
  13413            (cond
  13414              (is-jsx
  13415               (when (web-mode-looking-at "[ \n]*" reg-beg)
  13416                 (setq pos (+ reg-beg (length (match-string-no-properties 0)))))
  13417               (setq continue nil))
  13418              (t
  13419               (message "javascript-statement-beginning-position ** search failure **")
  13420               (setq continue nil
  13421                     pos reg-beg))
  13422              ) ;cond
  13423            )
  13424          ) ;t
  13425         ) ;cond
  13426       ) ;while
  13427     ;;(message "%S -------" pos)
  13428     pos))
  13429 
  13430 (defun web-mode-javascript-args-beginning-position (pos &optional reg-beg)
  13431   (unless pos (setq pos (point)))
  13432   (setq pos (1- pos))
  13433   (let ((char nil)
  13434         (blockside (get-text-property pos 'block-side))
  13435         (i 0)
  13436         (continue (not (null pos))))
  13437     (unless reg-beg
  13438       (if blockside
  13439           (setq reg-beg (web-mode-block-beginning-position pos))
  13440           (setq reg-beg (web-mode-part-beginning-position pos)))
  13441       )
  13442     (while continue
  13443       (setq char (char-after pos))
  13444       ;;(message "pos(%S) char(%c)" pos char)
  13445       (cond
  13446         ((> (setq i (1+ i)) 20000)
  13447          (message "javascript-args-beginning-position ** warning (%S) **" pos)
  13448          (setq continue nil
  13449                pos nil))
  13450         ((null pos)
  13451          (message "javascript-args-beginning-position ** invalid pos **")
  13452          (setq continue nil))
  13453         ((< pos reg-beg)
  13454          (message "javascript-args-beginning-position ** failure(position) **")
  13455          (setq continue nil
  13456                pos reg-beg))
  13457         ((and blockside
  13458               (member (get-text-property pos 'block-token) '(string comment))
  13459               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13460          (setq pos (web-mode-block-token-beginning-position pos)))
  13461         ((and (not blockside)
  13462               (member (get-text-property pos 'part-token) '(string comment))
  13463               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13464          (setq pos (web-mode-part-token-beginning-position pos)))
  13465         ((and (not blockside)
  13466               (get-text-property pos 'block-side))
  13467          (when (setq pos (web-mode-block-beginning-position pos))
  13468            (setq pos (1- pos)))
  13469          )
  13470         ((member char '(?\) ?\] ?\}))
  13471          (when (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13472            (setq pos (1- pos))))
  13473         ((member char '(?\( ?\[ ?\{))
  13474          (web-mode-looking-at ".[ ]*" pos)
  13475          (setq pos (+ pos (length (match-string-no-properties 0)))
  13476                continue nil)
  13477          )
  13478         ((web-mode-looking-at "\\(var\\|let\\|return\\|const\\)[ \n]" pos)
  13479          (setq pos (+ pos (length (match-string-no-properties 0)))
  13480                continue nil))
  13481         (t
  13482          (setq pos (web-mode-rsb-position pos "[\]\[}{)(]\\|\\(var\\|let\\|return\\|const\\)" reg-beg))
  13483          (when (not pos)
  13484            (message "javascript-args-beginning-position ** search failure **")
  13485            (setq continue nil
  13486                  pos reg-beg)))
  13487         ) ;cond
  13488       ) ;while
  13489     ;;(message "=%S" pos)
  13490     pos))
  13491 
  13492 (defun web-mode-javascript-calls-beginning-position (pos &optional reg-beg)
  13493   (unless pos (setq pos (point)))
  13494   ;;(message "pos=%S" pos)
  13495   (let ((char nil)
  13496         (dot-pos nil)
  13497         (blockside (get-text-property pos 'block-side))
  13498         (i 0)
  13499         (continue (not (null pos))))
  13500     (unless reg-beg
  13501       (setq reg-beg (if blockside
  13502                         (web-mode-block-beginning-position pos)
  13503                         (web-mode-part-beginning-position pos))))
  13504     (while continue
  13505       (setq char (char-after pos))
  13506       ;;(message "%S| %S=%c" reg-beg pos char)
  13507       (cond
  13508         ((> (setq i (1+ i)) 20000)
  13509          (message "javascript-calls-beginning-position ** warning (%S) **" pos)
  13510          (setq continue nil
  13511                pos nil))
  13512         ((null pos)
  13513          (message "javascript-calls-beginning-position ** invalid pos **")
  13514          (setq continue nil))
  13515         ((< pos reg-beg)
  13516          (setq continue nil
  13517                pos reg-beg))
  13518         ((and blockside
  13519               (member (get-text-property pos 'block-token) '(string comment))
  13520               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13521          (setq pos (web-mode-block-token-beginning-position pos)))
  13522         ((and (not blockside)
  13523               (member (get-text-property pos 'part-token) '(string comment))
  13524               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13525          (setq pos (web-mode-part-token-beginning-position pos)))
  13526         ((and (not blockside)
  13527               (get-text-property pos 'block-side))
  13528          (when (setq pos (web-mode-block-beginning-position pos))
  13529            (setq pos (1- pos))))
  13530         ((and (member char '(?\.)) (> i 1))
  13531          (setq dot-pos pos
  13532                pos (1- pos)))
  13533         ((member char '(?\) ?\]))
  13534          (when (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13535            (setq pos (1- pos)))
  13536          )
  13537         ((member char '(?\( ?\{ ?\} ?\[ ?\= ?\? ?\: ?\; ?\, ?\& ?\| ?\>))
  13538          (web-mode-looking-at ".[ \t\n]*" pos)
  13539          (setq pos (+ pos (length (match-string-no-properties 0)))
  13540                continue nil))
  13541         ((web-mode-looking-at "\\(return\\|else\\|const\\)[ \n]" pos)
  13542          (setq pos (+ pos (length (match-string-no-properties 0)))
  13543                continue nil))
  13544         (t
  13545          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,&|>.]\\|\\(return\\|else\\|const\\)" reg-beg))
  13546          (when (not pos)
  13547            (message "javascript-calls-beginning-position ** search failure **")
  13548            (setq pos reg-beg
  13549                  continue nil))
  13550          ) ;t
  13551         ) ;cond
  13552       ) ;while
  13553     ;;(message "pos=%S dot-pos=%S" pos dot-pos)
  13554     (if (null pos) pos (cons pos dot-pos))
  13555     ))
  13556 
  13557 (defun web-mode-part-token-beginning-position (&optional pos)
  13558   (unless pos (setq pos (point)))
  13559   (cond
  13560     ((not (get-text-property pos 'part-token))
  13561      nil)
  13562     ((or (= pos (point-min))
  13563          (and (> pos (point-min))
  13564               (not (get-text-property (1- pos) 'part-token))))
  13565      pos)
  13566     (t
  13567      (setq pos (previous-single-property-change pos 'part-token))
  13568      (if (and pos (> pos (point-min))) pos (point-min)))
  13569     ))
  13570 
  13571 (defun web-mode-part-token-end-position (&optional pos)
  13572   (unless pos (setq pos (point)))
  13573   (cond
  13574     ((not (get-text-property pos 'part-token))
  13575      nil)
  13576     ((or (= pos (point-max))
  13577          (not (get-text-property (1+ pos) 'part-token)))
  13578      pos)
  13579     (t
  13580      (1- (next-single-property-change pos 'part-token)))
  13581     ))
  13582 
  13583 (defun web-mode-block-token-beginning-position (&optional pos)
  13584   (unless pos (setq pos (point)))
  13585   (cond
  13586     ((not (get-text-property pos 'block-token))
  13587      nil)
  13588     ((or (= pos (point-min))
  13589          (and (> pos (point-min))
  13590               (not (get-text-property (1- pos) 'block-token))))
  13591      pos)
  13592     (t
  13593      (setq pos (previous-single-property-change pos 'block-token))
  13594      (if (and pos (> pos (point-min))) pos (point-min)))
  13595     ))
  13596 
  13597 (defun web-mode-block-token-end-position (&optional pos)
  13598   (unless pos (setq pos (point)))
  13599   (cond
  13600     ((not (get-text-property pos 'block-token))
  13601      nil)
  13602     ((or (= pos (point-max))
  13603          (not (get-text-property (1+ pos) 'block-token)))
  13604      pos)
  13605     (t
  13606      (1- (next-single-property-change pos 'block-token)))
  13607     ))
  13608 
  13609 (defun web-mode-block-code-end-position (&optional pos)
  13610   (unless pos (setq pos (point)))
  13611   (setq pos (web-mode-block-end-position pos))
  13612   (cond
  13613     ((not pos)
  13614      nil)
  13615     ((and (eq (get-text-property pos 'block-token) 'delimiter-end)
  13616           (eq (get-text-property (1- pos) 'block-token) 'delimiter-end))
  13617      (previous-single-property-change pos 'block-token))
  13618     ((= pos (1- (point-max))) ;; TODO: comparer plutot avec line-end-position
  13619      (point-max))
  13620     (t
  13621      pos)
  13622     ))
  13623 
  13624 (defun web-mode-block-end-position (&optional pos)
  13625   (unless pos (setq pos (point)))
  13626   (cond
  13627     ((get-text-property pos 'block-end)
  13628      pos)
  13629     ((get-text-property pos 'block-side)
  13630      (or (next-single-property-change pos 'block-end)
  13631          (point-max)))
  13632     (t
  13633      nil)
  13634     ))
  13635 
  13636 (defun web-mode-block-previous-position (&optional pos)
  13637   (unless pos (setq pos (point)))
  13638   (cond
  13639     ((= pos (point-min))
  13640      (setq pos nil))
  13641     ((get-text-property pos 'block-side)
  13642      (setq pos (web-mode-block-beginning-position pos))
  13643      (cond
  13644        ((or (null pos) (= pos (point-min)))
  13645         (setq pos nil)
  13646         )
  13647        ((and (setq pos (previous-single-property-change pos 'block-beg))
  13648              (> pos (point-min)))
  13649         (setq pos (1- pos))
  13650         )
  13651        )
  13652      ) ;block-side
  13653     ((get-text-property (1- pos) 'block-side)
  13654      (setq pos (web-mode-block-beginning-position (1- pos)))
  13655      )
  13656     (t
  13657      (setq pos (previous-single-property-change pos 'block-side))
  13658      (cond
  13659        ((and (null pos) (get-text-property (point-min) 'block-beg))
  13660         (setq pos (point-min)))
  13661        ((and pos (> pos (point-min)))
  13662         (setq pos (web-mode-block-beginning-position (1- pos))))
  13663        )
  13664      )
  13665     ) ;conf
  13666   pos)
  13667 
  13668 (defun web-mode-block-next-position (&optional pos limit)
  13669   (unless pos (setq pos (point)))
  13670   (unless limit (setq limit (point-max)))
  13671   (cond
  13672     ((and (get-text-property pos 'block-side)
  13673           (setq pos (web-mode-block-end-position pos))
  13674           (< pos (point-max))
  13675           (setq pos (1+ pos)))
  13676      (unless (get-text-property pos 'block-beg)
  13677        (setq pos (next-single-property-change pos 'block-side)))
  13678      )
  13679     (t
  13680      (setq pos (next-single-property-change pos 'block-side)))
  13681     ) ;cond
  13682   (if (and pos (<= pos limit)) pos nil))
  13683 
  13684 (defun web-mode-is-css-string (pos)
  13685   (let (beg)
  13686     (cond
  13687       ((and (setq beg (web-mode-part-token-beginning-position pos))
  13688             (web-mode-looking-at-p "`" beg)
  13689             (web-mode-looking-back "\\(styled[[:alnum:].]+\\|css\\)" beg))
  13690        beg)
  13691       (t
  13692        nil)
  13693       ) ;cond
  13694     ))
  13695 
  13696 ;; Relay.QL , gql, graphql
  13697 (defun web-mode-is-ql-string (pos prefix-regexp)
  13698   (let (beg)
  13699     (cond
  13700       ((and (setq beg (web-mode-part-token-beginning-position pos))
  13701             (web-mode-looking-back prefix-regexp beg))
  13702        beg)
  13703       (t
  13704        nil)
  13705       ) ;cond
  13706     ))
  13707 
  13708 (defun web-mode-is-html-string (pos)
  13709   (let (beg)
  13710     (cond
  13711       ((and (setq beg (web-mode-part-token-beginning-position pos))
  13712             (web-mode-looking-at-p "`[ \t\n]*<[a-zA-Z]" beg)
  13713             (web-mode-looking-back "\\(template\\|html\\)\\([ ]*[=:][ ]*\\)?" beg))
  13714        beg)
  13715       (t
  13716        nil)
  13717       ) ;cond
  13718     ))
  13719 
  13720 ;;---- EXCURSION ---------------------------------------------------------------
  13721 
  13722 (defun web-mode-backward-sexp (n)
  13723   (interactive "p")
  13724   (if (< n 0) (web-mode-forward-sexp (- n))
  13725       (let (pos)
  13726         (dotimes (_ n)
  13727           (skip-chars-backward "[:space:]")
  13728           (setq pos (point))
  13729           (cond
  13730             ((bobp) nil)
  13731             ((get-text-property (1- pos) 'block-end)
  13732              (backward-char 1)
  13733              (web-mode-block-beginning))
  13734             ((get-text-property (1- pos) 'block-token)
  13735              (backward-char 1)
  13736              (web-mode-block-token-beginning))
  13737             ((get-text-property (1- pos) 'part-token)
  13738              (backward-char 1)
  13739              (web-mode-part-token-beginning))
  13740             ((get-text-property (1- pos) 'tag-end)
  13741              (backward-char 1)
  13742              (web-mode-element-beginning))
  13743             ((get-text-property (1- pos) 'tag-attr)
  13744              (backward-char 1)
  13745              (web-mode-attribute-beginning))
  13746             ((get-text-property (1- pos) 'tag-type)
  13747              (backward-char 1)
  13748              (web-mode-tag-beginning))
  13749             ((get-text-property (1- pos) 'jsx-end)
  13750              (backward-char 1)
  13751              (web-mode-jsx-beginning))
  13752             (t
  13753              (let ((forward-sexp-function nil))
  13754                (backward-sexp))
  13755              ) ;case t
  13756             ) ;cond
  13757           ) ;dotimes
  13758         ))) ;let if defun
  13759 
  13760 (defun web-mode-forward-sexp (n)
  13761   (interactive "p")
  13762   (if (< n 0) (web-mode-backward-sexp (- n))
  13763       (let (pos)
  13764         (dotimes (_ n)
  13765           (skip-chars-forward "[:space:]")
  13766           (setq pos (point))
  13767           (cond
  13768             ((eobp) nil)
  13769             ((get-text-property pos 'block-beg)
  13770              (web-mode-block-end))
  13771             ((get-text-property pos 'block-token)
  13772              (web-mode-block-token-end))
  13773             ((get-text-property pos 'part-token)
  13774              (web-mode-part-token-end))
  13775             ((get-text-property pos 'tag-beg)
  13776              (web-mode-element-end))
  13777             ((get-text-property pos 'tag-attr)
  13778              (web-mode-attribute-end))
  13779             ((get-text-property pos 'tag-type)
  13780              (web-mode-tag-end))
  13781             ((get-text-property pos 'jsx-beg)
  13782              (web-mode-jsx-end))
  13783             (t
  13784              (let ((forward-sexp-function nil))
  13785                (forward-sexp))
  13786              ) ;case t
  13787             ) ;cond
  13788           ) ;dotimes
  13789         ))) ;let if defun
  13790 
  13791 (defun web-mode-comment-beginning ()
  13792   "Fetch current comment beg."
  13793   (interactive)
  13794   (web-mode-go (web-mode-comment-beginning-position (point))))
  13795 
  13796 (defun web-mode-comment-end ()
  13797   "Fetch current comment end."
  13798   (interactive)
  13799   (web-mode-go (web-mode-comment-end-position (point)) 1))
  13800 
  13801 (defun web-mode-tag-beginning ()
  13802   "Fetch current html tag beg."
  13803   (interactive)
  13804   (web-mode-go (web-mode-tag-beginning-position (point))))
  13805 
  13806 (defun web-mode-tag-end ()
  13807   "Fetch current html tag end."
  13808   (interactive)
  13809   (web-mode-go (web-mode-tag-end-position (point)) 1))
  13810 
  13811 (defun web-mode-tag-previous ()
  13812   "Fetch previous tag."
  13813   (interactive)
  13814   (web-mode-go (web-mode-tag-previous-position (point))))
  13815 
  13816 (defun web-mode-tag-next ()
  13817   "Fetch next tag. Might be html comment or server tag (e.g. jsp)."
  13818   (interactive)
  13819   (web-mode-go (web-mode-tag-next-position (point))))
  13820 
  13821 (defun web-mode-attribute-beginning ()
  13822   "Fetch html attribute beginning."
  13823   (interactive)
  13824   (web-mode-go (web-mode-attribute-beginning-position (point))))
  13825 
  13826 (defun web-mode-attribute-end ()
  13827   "Fetch html attribute end."
  13828   (interactive)
  13829   (web-mode-go (web-mode-attribute-end-position (point)) 1))
  13830 
  13831 (defun web-mode-attribute-next (&optional arg)
  13832   "Fetch next attribute."
  13833   (interactive "p")
  13834   (unless arg (setq arg 1))
  13835   (cond
  13836     ((= arg 1) (web-mode-go (web-mode-attribute-next-position (point))))
  13837     ((< arg 1) (web-mode-element-previous (* arg -1)))
  13838     (t
  13839      (while (>= arg 1)
  13840        (setq arg (1- arg))
  13841        (web-mode-go (web-mode-attribute-next-position (point)))
  13842        )
  13843      )
  13844     )
  13845   )
  13846 
  13847 (defun web-mode-attribute-previous (&optional arg)
  13848   "Fetch previous attribute."
  13849   (interactive "p")
  13850   (unless arg (setq arg 1))
  13851   (unless arg (setq arg 1))
  13852   (cond
  13853     ((= arg 1) (web-mode-go (web-mode-attribute-previous-position (point))))
  13854     ((< arg 1) (web-mode-element-next (* arg -1)))
  13855     (t
  13856      (while (>= arg 1)
  13857        (setq arg (1- arg))
  13858        (web-mode-go (web-mode-attribute-previous-position (point)))
  13859        )
  13860      )
  13861     )
  13862   )
  13863 
  13864 (defun web-mode-element-previous (&optional arg)
  13865   "Fetch previous element."
  13866   (interactive "p")
  13867   (unless arg (setq arg 1))
  13868   (cond
  13869     ((= arg 1) (web-mode-go (web-mode-element-previous-position (point))))
  13870     ((< arg 1) (web-mode-element-next (* arg -1)))
  13871     (t
  13872      (while (>= arg 1)
  13873        (setq arg (1- arg))
  13874        (web-mode-go (web-mode-element-previous-position (point)))
  13875        ) ;while
  13876      ) ;t
  13877     ) ;cond
  13878   )
  13879 
  13880 (defun web-mode-element-next (&optional arg)
  13881   "Fetch next element."
  13882   (interactive "p")
  13883   (unless arg (setq arg 1))
  13884   (cond
  13885     ((= arg 1) (web-mode-go (web-mode-element-next-position (point))))
  13886     ((< arg 1) (web-mode-element-previous (* arg -1)))
  13887     (t
  13888      (while (>= arg 1)
  13889        (setq arg (1- arg))
  13890        (web-mode-go (web-mode-element-next-position (point)))
  13891        ) ;while
  13892      ) ;t
  13893     ) ;cond
  13894   )
  13895 
  13896 (defun web-mode-element-sibling-next ()
  13897   "Fetch next sibling element."
  13898   (interactive)
  13899   (let ((pos (point)))
  13900     (save-excursion
  13901       (cond
  13902         ((not (get-text-property pos 'tag-type))
  13903          (if (and (web-mode-element-parent)
  13904                   (web-mode-tag-match)
  13905                   (web-mode-tag-next)
  13906                   (member (get-text-property (point) 'tag-type) '(start void comment)))
  13907              (setq pos (point))
  13908              (setq pos nil))
  13909          )
  13910         ((member (get-text-property pos 'tag-type) '(start void))
  13911          (if (and (web-mode-tag-match)
  13912                   (web-mode-tag-next)
  13913                   (member (get-text-property (point) 'tag-type) '(start void comment)))
  13914              (setq pos (point))
  13915              (setq pos nil))
  13916          )
  13917         ((and (web-mode-tag-next)
  13918               (member (get-text-property (point) 'tag-type) '(start void comment)))
  13919          (setq pos (point)))
  13920         (t
  13921          (setq pos nil))
  13922         ) ;cond
  13923       ) ;save-excursion
  13924     (web-mode-go pos)))
  13925 
  13926 (defun web-mode-element-sibling-previous ()
  13927   "Fetch previous sibling element."
  13928   (interactive)
  13929   (let ((pos (point)))
  13930     (save-excursion
  13931       (cond
  13932         ((not (get-text-property pos 'tag-type))
  13933          (if (and (web-mode-element-parent)
  13934                   (web-mode-tag-previous)
  13935                   (web-mode-element-beginning))
  13936              (setq pos (point))
  13937              (setq pos nil))
  13938          )
  13939         ((eq (get-text-property pos 'tag-type) 'start)
  13940          (if (and (web-mode-tag-beginning)
  13941                   (web-mode-tag-previous)
  13942                   (web-mode-element-beginning))
  13943              (setq pos (point))
  13944              (setq pos nil))
  13945          )
  13946         ((and (web-mode-element-beginning)
  13947               (web-mode-tag-previous)
  13948               (web-mode-element-beginning))
  13949          (setq pos (point)))
  13950         (t
  13951          (setq pos nil))
  13952         ) ;cond
  13953       ) ;save-excursion
  13954     (web-mode-go pos)))
  13955 
  13956 (defun web-mode-element-beginning ()
  13957   "Move to beginning of element."
  13958   (interactive)
  13959   (web-mode-go (web-mode-element-beginning-position (point))))
  13960 
  13961 (defun web-mode-element-end ()
  13962   "Move to end of element."
  13963   (interactive)
  13964   (web-mode-go (web-mode-element-end-position (point)) 1))
  13965 
  13966 (defun web-mode-element-parent ()
  13967   "Fetch parent element."
  13968   (interactive)
  13969   (web-mode-go (web-mode-element-parent-position (point))))
  13970 
  13971 (defun web-mode-element-child ()
  13972   "Fetch child element."
  13973   (interactive)
  13974   (web-mode-go (web-mode-element-child-position (point))))
  13975 
  13976 (defun web-mode-dom-traverse ()
  13977   "Traverse html dom tree."
  13978   (interactive)
  13979   (cond
  13980     ((web-mode-element-child)
  13981      )
  13982     ((web-mode-element-sibling-next)
  13983      )
  13984     ((and (web-mode-element-parent)
  13985           (not (web-mode-element-sibling-next)))
  13986      (goto-char (point-min)))
  13987     (t
  13988      (goto-char (point-min)))
  13989     ) ;cond
  13990   )
  13991 
  13992 (defun web-mode-closing-paren (limit)
  13993   (let ((pos (web-mode-closing-paren-position (point) limit)))
  13994     (if (or (null pos) (> pos limit))
  13995         nil
  13996         (goto-char pos)
  13997         pos)
  13998     ))
  13999 
  14000 (defun web-mode-part-next ()
  14001   "Move point to the beginning of the next part."
  14002   (interactive)
  14003   (web-mode-go (web-mode-part-next-position (point))))
  14004 
  14005 (defun web-mode-part-beginning ()
  14006   "Move point to the beginning of the current part."
  14007   (interactive)
  14008   (web-mode-go (web-mode-part-beginning-position (point))))
  14009 
  14010 (defun web-mode-part-end ()
  14011   "Move point to the end of the current part."
  14012   (interactive)
  14013   (web-mode-go (web-mode-part-end-position (point)) 1))
  14014 
  14015 (defun web-mode-block-previous ()
  14016   "Move point to the beginning of the previous block."
  14017   (interactive)
  14018   (web-mode-go (web-mode-block-previous-position (point))))
  14019 
  14020 (defun web-mode-block-next ()
  14021   "Move point to the beginning of the next block."
  14022   (interactive)
  14023   (web-mode-go (web-mode-block-next-position (point))))
  14024 
  14025 (defun web-mode-block-beginning ()
  14026   "Move point to the beginning of the current block."
  14027   (interactive)
  14028   (web-mode-go (web-mode-block-beginning-position (point))))
  14029 
  14030 (defun web-mode-block-end ()
  14031   "Move point to the end of the current block."
  14032   (interactive)
  14033   (web-mode-go (web-mode-block-end-position (point)) 1))
  14034 
  14035 (defun web-mode-block-token-beginning ()
  14036   (web-mode-go (web-mode-block-token-beginning-position (point))))
  14037 
  14038 (defun web-mode-block-token-end ()
  14039   (web-mode-go (web-mode-block-token-end-position (point)) 1))
  14040 
  14041 (defun web-mode-part-token-beginning ()
  14042   (web-mode-go (web-mode-part-token-beginning-position (point))))
  14043 
  14044 (defun web-mode-part-token-end ()
  14045   (web-mode-go (web-mode-part-token-end-position (point)) 1))
  14046 
  14047 (defun web-mode-block-opening-paren (limit)
  14048   (web-mode-go (web-mode-block-opening-paren-position (point) limit)))
  14049 
  14050 (defun web-mode-block-string-beginning (&optional pos block-beg)
  14051   (unless pos (setq pos (point)))
  14052   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14053   (web-mode-go (web-mode-block-string-beginning-position pos block-beg)))
  14054 
  14055 (defun web-mode-block-statement-beginning (pos block-beg is-ternary)
  14056   (unless pos (setq pos (point)))
  14057   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14058   (web-mode-go (web-mode-block-statement-beginning-position pos block-beg is-ternary)))
  14059 
  14060 (defun web-mode-block-args-beginning (&optional pos block-beg)
  14061   (unless pos (setq pos (point)))
  14062   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14063   (web-mode-go (web-mode-block-args-beginning-position pos block-beg)))
  14064 
  14065 (defun web-mode-block-calls-beginning (&optional pos block-beg)
  14066   (unless pos (setq pos (point)))
  14067   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14068   (web-mode-go (web-mode-block-calls-beginning-position pos block-beg)))
  14069 
  14070 (defun web-mode-javascript-string-beginning (&optional pos reg-beg)
  14071   (unless pos (setq pos (point)))
  14072   (unless reg-beg
  14073     (if (get-text-property pos 'block-side)
  14074         (setq reg-beg (web-mode-block-beginning-position pos))
  14075         (setq reg-beg (web-mode-part-beginning-position pos))))
  14076   (web-mode-go (web-mode-javascript-string-beginning-position pos reg-beg)))
  14077 
  14078 (defun web-mode-javascript-statement-beginning (pos reg-beg is-ternary)
  14079   (unless pos (setq pos (point)))
  14080   (unless reg-beg
  14081     (if (get-text-property pos 'block-side)
  14082         (setq reg-beg (web-mode-block-beginning-position pos))
  14083         (setq reg-beg (web-mode-part-beginning-position pos))))
  14084   (web-mode-go (web-mode-javascript-statement-beginning-position pos reg-beg is-ternary)))
  14085 
  14086 (defun web-mode-javascript-args-beginning (&optional pos reg-beg)
  14087   (unless pos (setq pos (point)))
  14088   (unless reg-beg
  14089     (setq reg-beg (if (get-text-property pos 'block-side)
  14090                       (web-mode-block-beginning-position pos)
  14091                       (web-mode-part-beginning-position pos))))
  14092   ;;(message "reg-beg%S" reg-beg)
  14093   (web-mode-go (web-mode-javascript-args-beginning-position pos reg-beg)))
  14094 
  14095 (defun web-mode-javascript-calls-beginning (&optional pos reg-beg)
  14096   (unless pos (setq pos (point)))
  14097   (unless reg-beg
  14098     (if (get-text-property pos 'block-side)
  14099         (setq reg-beg (web-mode-block-beginning-position pos))
  14100         (setq reg-beg (web-mode-part-beginning-position pos))))
  14101   (let (pair)
  14102     (setq pair (web-mode-javascript-calls-beginning-position pos reg-beg))
  14103     (when pair (web-mode-go (car pair)))
  14104     ))
  14105 
  14106 (defun web-mode-go (pos &optional offset)
  14107   (unless offset (setq offset 0))
  14108   (when pos
  14109     (cond
  14110       ((and (> offset 0) (<= (+ pos offset) (point-max)))
  14111        (setq pos (+ pos offset)))
  14112       ((and (< offset 0) (>= (+ pos offset) (point-min)))
  14113        (setq pos (+ pos offset)))
  14114       ) ;cond
  14115     (goto-char pos))
  14116   pos)
  14117 
  14118 ;;---- SEARCH ------------------------------------------------------------------
  14119 
  14120 (defun web-mode-rsf-balanced (regexp-open regexp-close &optional limit noerror)
  14121   (unless noerror (setq noerror t))
  14122   (let ((continue t)
  14123         (level 1)
  14124         (pos (point))
  14125         ret
  14126         (regexp (concat regexp-open "\\|" regexp-close)))
  14127     (while continue
  14128       (setq ret (re-search-forward regexp limit noerror))
  14129       (cond
  14130         ((null ret)
  14131          (setq continue nil)
  14132          )
  14133         (t
  14134          (if (string-match-p regexp-open (match-string-no-properties 0))
  14135              (setq level (1+ level))
  14136              (setq level (1- level)))
  14137          (when (< level 1)
  14138            (setq continue nil)
  14139            )
  14140          ) ;t
  14141         ) ;cond
  14142       ) ;while
  14143     (when (not (= level 0)) (goto-char pos))
  14144     ret))
  14145 
  14146 (defun web-mode-block-sb (expr &optional limit noerror)
  14147   (unless limit (setq limit (web-mode-block-beginning-position (point))))
  14148   (unless noerror (setq noerror t))
  14149   (let ((continue t) ret)
  14150     (while continue
  14151       (setq ret (search-backward expr limit noerror))
  14152       (when (or (null ret)
  14153                 (not (get-text-property (point) 'block-token)))
  14154         (setq continue nil)
  14155         ) ;when
  14156       ) ;while
  14157     ret))
  14158 
  14159 (defun web-mode-block-sf (expr &optional limit noerror)
  14160   (unless limit (setq limit (web-mode-block-end-position (point))))
  14161   (unless noerror (setq noerror t))
  14162   (let ((continue t) ret)
  14163     (while continue
  14164       (setq ret (search-forward expr limit noerror))
  14165       (when (or (null ret)
  14166                 (not (get-text-property (point) 'block-token)))
  14167         (setq continue nil)
  14168         ) ;when
  14169       ) ;while
  14170     ret))
  14171 
  14172 (defun web-mode-block-rsb (regexp &optional limit noerror)
  14173   (unless limit (setq limit (web-mode-block-beginning-position (point))))
  14174   (unless noerror (setq noerror t))
  14175   (let ((continue t) ret)
  14176     (while continue
  14177       (setq ret (re-search-backward regexp limit noerror))
  14178       (when (or (null ret)
  14179                 (not (get-text-property (point) 'block-token)))
  14180         (setq continue nil)
  14181         ) ;when
  14182       ) ;while
  14183     ret))
  14184 
  14185 (defun web-mode-block-rsf (regexp &optional limit noerror)
  14186   (unless limit (setq limit (web-mode-block-end-position (point))))
  14187   (unless noerror (setq noerror t))
  14188   (let ((continue t) ret)
  14189     (while continue
  14190       (setq ret (re-search-forward regexp limit noerror))
  14191       (when (or (null ret)
  14192                 (not (get-text-property (point) 'block-token)))
  14193         (setq continue nil)
  14194         ) ;when
  14195       ) ;while
  14196     ret))
  14197 
  14198 (defun web-mode-part-sb (expr &optional limit noerror)
  14199   (unless limit (setq limit (web-mode-part-beginning-position (point))))
  14200   (unless noerror (setq noerror t))
  14201   (let ((continue t) ret)
  14202     (while continue
  14203       (setq ret (search-backward expr limit noerror))
  14204       (when (or (null ret)
  14205                 (and (not (get-text-property (point) 'part-token))
  14206                      (not (get-text-property (point) 'block-side)))
  14207                 )
  14208         (setq continue nil)
  14209         ) ;when
  14210       ) ;while
  14211     ret))
  14212 
  14213 (defun web-mode-part-sf (expr &optional limit noerror)
  14214   (unless limit (setq limit (web-mode-part-end-position (point))))
  14215   (unless noerror (setq noerror t))
  14216   (let ((continue t) ret)
  14217     (while continue
  14218       (setq ret (search-forward expr limit noerror))
  14219       (when (or (null ret)
  14220                 (and (not (get-text-property (point) 'part-token))
  14221                      (not (get-text-property (point) 'block-side)))
  14222                 )
  14223         (setq continue nil)
  14224         ) ;when
  14225       ) ;while
  14226     ret))
  14227 
  14228 (defun web-mode-part-rsb (regexp &optional limit noerror)
  14229   (unless limit (setq limit (web-mode-part-beginning-position (point))))
  14230   (unless noerror (setq noerror t))
  14231   (let ((continue t) ret)
  14232     (while continue
  14233       (setq ret (re-search-backward regexp limit noerror))
  14234       (when (or (null ret)
  14235                 (and (not (get-text-property (point) 'part-token))
  14236                      (not (get-text-property (point) 'block-side)))
  14237                 )
  14238         (setq continue nil)
  14239         ) ;when
  14240       ) ;while
  14241     ret))
  14242 
  14243 (defun web-mode-part-rsf (regexp &optional limit noerror)
  14244   (unless limit (setq limit (web-mode-part-end-position (point))))
  14245   (unless noerror (setq noerror t))
  14246   (let ((continue t) ret)
  14247     (while continue
  14248       (setq ret (re-search-forward regexp limit t))
  14249       (when (or (null ret)
  14250                 (and (not (get-text-property (point) 'part-token))
  14251                      (not (get-text-property (point) 'block-side)))
  14252                 )
  14253         (setq continue nil)
  14254         ) ;when
  14255       ) ;while
  14256     ret))
  14257 
  14258 (defun web-mode-javascript-rsb (regexp &optional limit noerror)
  14259   (unless limit (setq limit (web-mode-part-beginning-position (point))))
  14260   (unless noerror (setq noerror t))
  14261   (let ((continue t) ret)
  14262     (while continue
  14263       (setq ret (re-search-backward regexp limit noerror))
  14264       (when (or (null ret)
  14265                 (and (not (get-text-property (point) 'part-token))
  14266                      (not (get-text-property (point) 'block-side))
  14267                      (not (get-text-property (point) 'jsx-depth)))
  14268                 )
  14269         (setq continue nil)
  14270         ) ;when
  14271       ) ;while
  14272     ret))
  14273 
  14274 (defun web-mode-javascript-rsf (regexp &optional limit noerror)
  14275   (unless limit (setq limit (web-mode-part-end-position (point))))
  14276   (unless noerror (setq noerror t))
  14277   (let ((continue t) ret)
  14278     (while continue
  14279       (setq ret (re-search-forward regexp limit t))
  14280       (when (or (null ret)
  14281                 (and (not (get-text-property (point) 'part-token))
  14282                      (not (get-text-property (point) 'block-side))
  14283                      (not (get-text-property (point) 'jsx-depth)))
  14284                 )
  14285         (setq continue nil)
  14286         ) ;when
  14287       ) ;while
  14288     ret))
  14289 
  14290 (defun web-mode-dom-sf (expr &optional limit noerror)
  14291   (unless noerror (setq noerror t))
  14292   (let ((continue t) ret)
  14293     (while continue
  14294       (setq ret (search-forward expr limit noerror))
  14295       (if (or (null ret)
  14296               (not (get-text-property (- (point) (length expr)) 'block-side)))
  14297           (setq continue nil))
  14298       )
  14299     ret))
  14300 
  14301 (defun web-mode-dom-rsf (regexp &optional limit noerror)
  14302   (unless noerror (setq noerror t))
  14303   (let ((continue t) (ret nil))
  14304     (while continue
  14305       (setq ret (re-search-forward regexp limit noerror))
  14306       ;;      (message "ret=%S point=%S limit=%S i=%S" ret (point) limit 0)
  14307       (cond
  14308         ((null ret)
  14309          (setq continue nil))
  14310         ((or (get-text-property (match-beginning 0) 'block-side)
  14311              (get-text-property (match-beginning 0) 'part-token))
  14312          )
  14313         (t
  14314          (setq continue nil))
  14315         ) ;cond
  14316       ) ;while
  14317     ret))
  14318 
  14319 (defun web-mode-rsb-position (pos regexp &optional limit noerror)
  14320   (unless noerror (setq noerror t))
  14321   (save-excursion
  14322     (goto-char pos)
  14323     (if (re-search-backward regexp limit noerror) (point) nil)
  14324     ))
  14325 
  14326 (defun web-mode-rsb (regexp &optional limit noerror)
  14327   (unless noerror (setq noerror t))
  14328   (let ((continue t) ret)
  14329     (while continue
  14330       (setq ret (re-search-backward regexp limit noerror))
  14331       (if (or (null ret)
  14332               (not (web-mode-is-comment-or-string)))
  14333           (setq continue nil)))
  14334     ret))
  14335 
  14336 (defun web-mode-rsf (regexp &optional limit noerror)
  14337   (unless noerror (setq noerror t))
  14338   (let ((continue t) ret)
  14339     (while continue
  14340       (setq ret (re-search-forward regexp limit noerror))
  14341       (if (or (null ret)
  14342               (not (web-mode-is-comment-or-string)))
  14343           (setq continue nil))
  14344       )
  14345     ret))
  14346 
  14347 (defun web-mode-sb (expr &optional limit noerror)
  14348   (unless noerror (setq noerror t))
  14349   (let ((continue t) ret)
  14350     (while continue
  14351       (setq ret (search-backward expr limit noerror))
  14352       (if (or (null ret)
  14353               (not (web-mode-is-comment-or-string)))
  14354           (setq continue nil)))
  14355     ret))
  14356 
  14357 (defun web-mode-sf (expr &optional limit noerror)
  14358   (unless noerror (setq noerror t))
  14359   (let ((continue t) ret)
  14360     (while continue
  14361       (setq ret (search-forward expr limit noerror))
  14362       (if (or (null ret)
  14363               (not (web-mode-is-comment-or-string)))
  14364           (setq continue nil)))
  14365     ret))
  14366 
  14367 (defun web-mode-content-rsf (regexp &optional limit noerror)
  14368   (unless noerror (setq noerror t))
  14369   (let ((continue t) ret beg end)
  14370     (while continue
  14371       (setq ret (re-search-forward regexp limit noerror)
  14372             beg (if (null ret) (point) (match-beginning 0))
  14373             end (if (null ret) (point) (1- (match-end 0))))
  14374       (if (or (null ret)
  14375               (and (web-mode-is-content beg)
  14376                    (web-mode-is-content end)))
  14377           (setq continue nil)))
  14378     ret))
  14379 
  14380 ;;---- ADVICES -----------------------------------------------------------------
  14381 
  14382 (defadvice ac-start (before web-mode-set-up-ac-sources activate)
  14383   "Set `ac-sources' based on current language before running auto-complete."
  14384   (when (equal major-mode 'web-mode)
  14385     ;; set ignore each time to nil. User has to implement a hook to change it
  14386     ;; for each completion
  14387     (setq web-mode-ignore-ac-start-advice nil)
  14388     (run-hooks 'web-mode-before-auto-complete-hooks)
  14389     (unless web-mode-ignore-ac-start-advice
  14390       (when web-mode-ac-sources-alist
  14391         (let ((new-web-mode-ac-sources
  14392                (assoc (web-mode-language-at-pos)
  14393                       web-mode-ac-sources-alist)))
  14394           (setq ac-sources (cdr new-web-mode-ac-sources)))))))
  14395 
  14396 ;;---- MINOR MODE ADDONS -------------------------------------------------------
  14397 
  14398 (defun web-mode-yasnippet-exit-hook ()
  14399   "Yasnippet exit hook"
  14400   (when (and (boundp 'yas-snippet-beg) (boundp 'yas-snippet-end))
  14401     (indent-region yas-snippet-beg yas-snippet-end)))
  14402 
  14403 (defun web-mode-imenu-index ()
  14404   (interactive)
  14405   "Returns imenu items."
  14406   (let (toc-index
  14407         line)
  14408     (save-excursion
  14409       (goto-char (point-min))
  14410       (while (not (eobp))
  14411         (setq line (buffer-substring-no-properties
  14412                     (line-beginning-position)
  14413                     (line-end-position)))
  14414         (let (found
  14415               (i 0)
  14416               item
  14417               regexp
  14418               type
  14419               type-idx
  14420               content
  14421               content-idx
  14422               content-regexp
  14423               close-tag-regexp
  14424               concat-str
  14425               jumpto
  14426               str)
  14427           (while (and (not found ) (< i (length web-mode-imenu-regexp-list)))
  14428             (setq item (nth i web-mode-imenu-regexp-list))
  14429             (setq regexp (nth 0 item))
  14430             (setq type-idx (nth 1 item))
  14431             (setq content-idx (nth 2 item))
  14432             (setq concat-str (nth 3 item))
  14433             (when (not (numberp content-idx))
  14434               (setq content-regexp (nth 2 item)
  14435                     close-tag-regexp (nth 4 item)
  14436                     content-idx nil))
  14437 
  14438             (when (string-match regexp line)
  14439 
  14440               (cond
  14441                 (content-idx
  14442                  (setq type (match-string type-idx line))
  14443                  (setq content (match-string content-idx line))
  14444                  (setq str (concat type concat-str content))
  14445                  (setq jumpto (line-beginning-position)))
  14446                 (t
  14447                  (let (limit)
  14448                    (setq type (match-string type-idx line))
  14449                    (goto-char (line-beginning-position))
  14450                    (save-excursion
  14451                      (setq limit (re-search-forward close-tag-regexp (point-max) t)))
  14452 
  14453                    (when limit
  14454                      (when (re-search-forward content-regexp limit t)
  14455                        (setq content (match-string 1))
  14456                        (setq str (concat type concat-str content))
  14457                        (setq jumpto (line-beginning-position))
  14458                        )
  14459                      )))
  14460                 )
  14461               (when str (setq toc-index
  14462                               (cons (cons str jumpto)
  14463                                     toc-index)
  14464                               )
  14465                     (setq found t))
  14466               )
  14467             (setq i (1+ i))))
  14468         (forward-line)
  14469         (goto-char (line-end-position)) ;; make sure we are at eobp
  14470         ))
  14471     (nreverse toc-index)))
  14472 
  14473 ;;---- UNIT TESTING ------------------------------------------------------------
  14474 
  14475 (defun web-mode-test ()
  14476   "Executes web-mode unit tests. See `web-mode-tests-directory'."
  14477   (interactive)
  14478   (let (files ret regexp)
  14479     (setq regexp "^[[:alnum:]][[:alnum:]._]+\\'")
  14480     (setq files (directory-files web-mode-tests-directory t regexp))
  14481     (dolist (file files)
  14482       (cond
  14483         ((eq (string-to-char (file-name-nondirectory file)) ?\_)
  14484          (delete-file file))
  14485         (t
  14486          (setq ret (web-mode-test-process file)))
  14487         ) ;cond
  14488       ) ;dolist
  14489     ))
  14490 
  14491 (defun web-mode-test-process (file)
  14492   (with-temp-buffer
  14493     (let (out sig1 sig2 success err)
  14494       (setq-default indent-tabs-mode nil)
  14495       (if (string-match-p "sql" file)
  14496           (setq web-mode-enable-sql-detection t)
  14497           (setq web-mode-enable-sql-detection nil))
  14498       (insert-file-contents file)
  14499       (set-visited-file-name file)
  14500       (web-mode)
  14501       (setq sig1 (md5 (current-buffer)))
  14502       (delete-horizontal-space)
  14503       (while (not (eobp))
  14504         (forward-line)
  14505         (delete-horizontal-space)
  14506         (end-of-line))
  14507       (web-mode-buffer-indent)
  14508       (setq sig2 (md5 (current-buffer)))
  14509       (setq success (string= sig1 sig2))
  14510       (setq out (concat (if success "ok" "ko") " : " (file-name-nondirectory file) "\n"))
  14511       (princ out)
  14512       (setq err (concat (file-name-directory file) "_err." (file-name-nondirectory file)))
  14513       (if success
  14514           (when (file-readable-p err)
  14515             (delete-file err))
  14516           (write-file err)
  14517           (message "[%s]" (buffer-string))
  14518           ) ;if
  14519       out)))
  14520 
  14521 ;;---- MISC --------------------------------------------------------------------
  14522 
  14523 (defun web-mode-set-engine (engine)
  14524   "Set the engine for the current buffer."
  14525   (interactive
  14526    (list (completing-read
  14527           "Engine: "
  14528           (let (engines)
  14529             (dolist (elt web-mode-engines)
  14530               (setq engines (append engines (list (car elt)))))
  14531             engines))))
  14532   (setq web-mode-content-type "html"
  14533         web-mode-engine (web-mode-engine-canonical-name engine)
  14534         web-mode-minor-engine engine)
  14535   (web-mode-on-engine-setted)
  14536   (web-mode-buffer-fontify))
  14537 
  14538 (defun web-mode-set-content-type (content-type)
  14539   "Set the content-type for the current buffer"
  14540   (interactive (list (completing-read "Content-type: " web-mode-part-content-types)))
  14541   (setq web-mode-content-type content-type)
  14542   (when (called-interactively-p 'any)
  14543     )
  14544   (web-mode-buffer-fontify))
  14545 
  14546 (defun web-mode-on-engine-setted ()
  14547   (let (elt elts)
  14548 
  14549     (when (string= web-mode-engine "razor") (setq web-mode-enable-block-face t))
  14550     ;;(setq web-mode-engine-attr-regexp (cdr (assoc web-mode-engine web-mode-engine-attr-regexps)))
  14551     (setq web-mode-engine-token-regexp (cdr (assoc web-mode-engine web-mode-engine-token-regexps)))
  14552 
  14553     ;;(message "%S %S %S" web-mode-engine web-mode-engine-attr-regexp web-mode-engine-token-regexp)
  14554 
  14555     (when (null web-mode-minor-engine)
  14556       (setq web-mode-minor-engine "none"))
  14557 
  14558     (setq elt (assoc web-mode-engine web-mode-engine-open-delimiter-regexps))
  14559     (cond
  14560       (elt
  14561        (setq web-mode-block-regexp (cdr elt)))
  14562       ((string= web-mode-engine "archibus")
  14563        (setq web-mode-block-regexp nil))
  14564       (t
  14565        (setq web-mode-engine "none"))
  14566       )
  14567 
  14568     (unless (boundp 'web-mode-extra-auto-pairs)
  14569       (setq web-mode-extra-auto-pairs nil))
  14570 
  14571     (setq web-mode-auto-pairs
  14572           (append
  14573            (cdr (assoc web-mode-engine web-mode-engines-auto-pairs))
  14574            (cdr (assoc nil web-mode-engines-auto-pairs))
  14575            (cdr (assoc web-mode-engine web-mode-extra-auto-pairs))
  14576            (cdr (assoc nil web-mode-extra-auto-pairs))))
  14577 
  14578     (unless (boundp 'web-mode-extra-snippets)
  14579       (setq web-mode-extra-snippets nil))
  14580 
  14581     (setq elts
  14582           (append
  14583            (cdr (assoc web-mode-engine web-mode-extra-snippets))
  14584            (cdr (assoc nil             web-mode-extra-snippets))
  14585            (cdr (assoc web-mode-engine web-mode-engines-snippets))
  14586            (cdr (assoc nil             web-mode-engines-snippets))))
  14587 
  14588     ;;(message "%S" elts)
  14589 
  14590     (dolist (elt elts)
  14591       (unless (assoc (car elt) web-mode-snippets)
  14592         (setq web-mode-snippets (cons elt web-mode-snippets)))
  14593       )
  14594 
  14595     (setq web-mode-engine-font-lock-keywords
  14596           (symbol-value (cdr (assoc web-mode-engine web-mode-engines-font-lock-keywords))))
  14597 
  14598     (when (and (string= web-mode-minor-engine "jinja")
  14599                (not (member "endtrans" web-mode-django-control-blocks)))
  14600       (add-to-list 'web-mode-django-control-blocks "endtrans")
  14601       (setq web-mode-django-control-blocks-regexp
  14602             (regexp-opt web-mode-django-control-blocks t))
  14603       )
  14604 
  14605     (when (string= web-mode-engine "spip")
  14606       (modify-syntax-entry ?# "w" (syntax-table)))
  14607 
  14608     ;;(message "%S" (symbol-value (cdr (assoc web-mode-engine web-mode-engines-font-lock-keywords))))
  14609 
  14610     ))
  14611 
  14612 (defun web-mode-detect-engine ()
  14613   (save-excursion
  14614     (goto-char (point-min))
  14615     (when (re-search-forward "-\\*- engine:[ ]*\\([[:alnum:]-]+\\)[ ]*-\\*-" web-mode-chunk-length t)
  14616       (setq web-mode-minor-engine (match-string-no-properties 1))
  14617       (setq web-mode-engine (web-mode-engine-canonical-name web-mode-minor-engine)))
  14618     web-mode-minor-engine))
  14619 
  14620 (defun web-mode-guess-engine-and-content-type ()
  14621   (let (buff-name found)
  14622 
  14623     (setq buff-name (buffer-file-name))
  14624     (unless buff-name (setq buff-name (buffer-name)))
  14625     (setq web-mode-is-scratch (string= buff-name "*scratch*"))
  14626     (setq web-mode-content-type nil)
  14627 
  14628     (when (boundp 'web-mode-content-types-alist)
  14629       (setq found nil)
  14630       (dolist (elt web-mode-content-types-alist)
  14631         (when (and (not found) (string-match-p (cdr elt) buff-name))
  14632           (setq web-mode-content-type (car elt)
  14633                 found t))
  14634         ) ;dolist
  14635       ) ;when
  14636 
  14637     (unless web-mode-content-type
  14638       (setq found nil)
  14639       (dolist (elt web-mode-content-types)
  14640         (when (and (not found) (string-match-p (cdr elt) buff-name))
  14641           (setq web-mode-content-type (car elt)
  14642                 found t)
  14643           ;;(message "%S" web-mode-content-type)
  14644           ) ;when
  14645         ) ;dolist
  14646       ) ;unless
  14647 
  14648     (when (boundp 'web-mode-engines-alist)
  14649       (setq found nil)
  14650       (dolist (elt web-mode-engines-alist)
  14651         (cond
  14652           ((stringp (cdr elt))
  14653            (when (string-match-p (cdr elt) buff-name)
  14654              (setq web-mode-engine (car elt))))
  14655           ((functionp (cdr elt))
  14656            (when (funcall (cdr elt))
  14657              (setq web-mode-engine (car elt))))
  14658           ) ;cond
  14659         ) ;dolist
  14660       ) ;when
  14661 
  14662     (unless web-mode-engine
  14663       (setq found nil)
  14664       (dolist (elt web-mode-engine-file-regexps)
  14665         ;;(message "%S %S %S" (cdr elt) (car elt) buff-name)
  14666         (when (and (not found) (string-match-p (cdr elt) buff-name))
  14667           ;;(message "%S %S %S" (cdr elt) (car elt) buff-name)
  14668           (setq web-mode-engine (car elt)
  14669                 found t)
  14670           ;;(when (and web-mode-engine (string= web-mode-engine "astro"))
  14671           ;;  (setq web-mode-enable-front-matter-block t)
  14672           ;;) ;when
  14673           ) ;when
  14674         )
  14675       )
  14676 
  14677     (when (and (or (null web-mode-engine) (string= web-mode-engine "none"))
  14678                (string-match-p "php" (buffer-substring-no-properties
  14679                                       (line-beginning-position)
  14680                                       (line-end-position))))
  14681       (setq web-mode-engine "php"))
  14682 
  14683     (when (and (string= web-mode-content-type "javascript")
  14684                (string-match-p "@jsx"
  14685                                (buffer-substring-no-properties
  14686                                 (point-min)
  14687                                 (if (< (point-max) web-mode-chunk-length)
  14688                                     (point-max)
  14689                                     web-mode-chunk-length)
  14690                                 )))
  14691       (setq web-mode-content-type "jsx"))
  14692 
  14693     (when web-mode-engine
  14694       (setq web-mode-minor-engine web-mode-engine
  14695             web-mode-engine (web-mode-engine-canonical-name web-mode-engine))
  14696       )
  14697 
  14698     ;;(message "%S %S" web-mode-engine web-mode-enable-engine-detection)
  14699 
  14700     (when (and (or (null web-mode-engine)
  14701                    (string= web-mode-engine "none"))
  14702                web-mode-enable-engine-detection)
  14703       (web-mode-detect-engine))
  14704 
  14705     (web-mode-on-engine-setted)
  14706 
  14707     ))
  14708 
  14709 (defun web-mode-engine-canonical-name (name)
  14710   (let (engine)
  14711     (cond
  14712       ((null name)
  14713        nil)
  14714       ((assoc name web-mode-engines)
  14715        name)
  14716       (t
  14717        (dolist (elt web-mode-engines)
  14718          (when (and (null engine) (member name (cdr elt)))
  14719            (setq engine (car elt)))
  14720          ) ;dolist
  14721        engine)
  14722       )))
  14723 
  14724 (defun web-mode-on-after-save ()
  14725   (when web-mode-is-scratch
  14726     (web-mode-guess-engine-and-content-type)
  14727     (web-mode-buffer-fontify))
  14728   nil)
  14729 
  14730 (defun web-mode-on-exit ()
  14731   (web-mode-with-silent-modifications
  14732    (put-text-property (point-min) (point-max) 'invisible nil)
  14733    (remove-overlays)
  14734    (remove-hook 'change-major-mode-hook 'web-mode-on-exit t)
  14735    ))
  14736 
  14737 (defun web-mode-file-link (file)
  14738   "Insert a link to a file in html document. This function can be
  14739 extended to support more filetypes by customizing
  14740 `web-mode-links'."
  14741   (interactive
  14742    (list (file-relative-name (read-file-name "Link file: "))))
  14743   (let ((matched nil)
  14744         (point-line (line-number-at-pos))
  14745         (point-column (current-column)))
  14746     (dolist (type web-mode-links)
  14747       (when (string-match (car type) file)
  14748         (setq matched t)
  14749         (when (nth 2 type)
  14750           (goto-char (point-min))
  14751           (search-forward "</head>")
  14752           (backward-char 7)
  14753           (open-line 1))
  14754         (insert (format (cadr type) file))
  14755         (indent-for-tab-command)
  14756         (when (nth 2 type)
  14757           ;; return point where it was and fix indentation
  14758           (forward-line)
  14759           (indent-for-tab-command)
  14760           (if (> point-line (- (line-number-at-pos) 2))
  14761               (forward-line (+ (- point-line (line-number-at-pos)) 1))
  14762               (forward-line (- point-line (line-number-at-pos))))
  14763           (move-to-column point-column))
  14764         ;; move point back if needed
  14765         (backward-char (nth 3 type))))
  14766     (when (not matched)
  14767       (user-error "Unknown file type"))))
  14768 
  14769 (defun web-mode-reload ()
  14770   "Reload web-mode."
  14771   (interactive)
  14772   (web-mode-with-silent-modifications
  14773    (put-text-property (point-min) (point-max) 'invisible nil)
  14774    (remove-overlays)
  14775    (setq font-lock-unfontify-region-function 'font-lock-default-unfontify-region)
  14776    (load "web-mode.el")
  14777    (setq web-mode-change-beg nil
  14778          web-mode-change-end nil)
  14779    (web-mode)
  14780    ))
  14781 
  14782 (defun web-mode-measure (msg)
  14783   (let (sub)
  14784     (when (null web-mode-time) (setq web-mode-time (current-time)))
  14785     (setq sub (time-subtract (current-time) web-mode-time))
  14786     (when nil
  14787       (save-excursion
  14788         (let ((n 0))
  14789           (goto-char (point-min))
  14790           (while (web-mode-tag-next)
  14791             (setq n (1+ n))
  14792             )
  14793           (message "%S tags found" n)
  14794           )))
  14795     (message "%18s: time elapsed = %Ss %9Sµs" msg (nth 1 sub) (nth 2 sub))
  14796     ))
  14797 
  14798 (defun web-mode-reveal ()
  14799   "Display text properties at point."
  14800   (interactive)
  14801   (let (symbols out)
  14802     (setq out (format
  14803                "[point=%S engine=%S minor=%S content-type=%S language-at-pos=%S]\n"
  14804                (point)
  14805                web-mode-engine
  14806                web-mode-minor-engine
  14807                web-mode-content-type
  14808                (web-mode-language-at-pos (point))))
  14809     (setq symbols (append web-mode-scan-properties '(font-lock-face face)))
  14810     (dolist (symbol symbols)
  14811       (when symbol
  14812         (setq out (concat out (format "%s(%S) " (symbol-name symbol) (get-text-property (point) symbol)))))
  14813       )
  14814     (message "%s\n" out)
  14815     ;;(message "syntax-class=%S" (syntax-class (syntax-after (point))))
  14816     (message nil)))
  14817 
  14818 (defun web-mode-toggle-tracing ()
  14819   "Toggle tracing."
  14820   (interactive)
  14821   (if web-mode-trace
  14822       (setq web-mode-trace nil)
  14823       (message "** tracing on ** point(%S) web-mode-change-beg(%S) web-mode-change-end(%S) web-mode-skip-fontification(%S)"
  14824                (point) web-mode-change-beg web-mode-change-end web-mode-skip-fontification)
  14825       (setq web-mode-trace t)))
  14826 
  14827 (defun web-mode-debug ()
  14828   "Display informations useful for debugging."
  14829   (interactive)
  14830   (let ((modes nil)
  14831         (customs '(web-mode-enable-current-column-highlight web-mode-enable-current-element-highlight indent-tabs-mode))
  14832         (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)))
  14833     (message "\n")
  14834     (message "--- WEB-MODE DEBUG BEG ---")
  14835     (message "versions: emacs(%S.%S) web-mode(%S)"
  14836              emacs-major-version emacs-minor-version web-mode-version)
  14837     (message "vars: engine(%S) minor(%S) content-type(%S) file(%S)"
  14838              web-mode-engine
  14839              web-mode-minor-engine
  14840              web-mode-content-type
  14841              (or (buffer-file-name) (buffer-name)))
  14842     (message "system: window(%S) config(%S)" window-system system-configuration)
  14843     (message "colors: fg(%S) bg(%S) "
  14844              (cdr (assoc 'foreground-color default-frame-alist))
  14845              (cdr (assoc 'background-color default-frame-alist)))
  14846     (mapc (lambda (mode)
  14847             (condition-case nil
  14848                 (if (and (symbolp mode) (symbol-value mode) (not (member mode ignore)))
  14849                     (push mode modes))
  14850               (error nil))
  14851             ) ;lambda
  14852           minor-mode-list)
  14853     (message "minor modes: %S" modes)
  14854     (message "vars:")
  14855     (dolist (custom customs)
  14856       (message (format "%s=%S " (symbol-name custom) (symbol-value custom))))
  14857     (message "--- WEB-MODE DEBUG END ---")
  14858     (switch-to-buffer "*Messages*")
  14859     (goto-char (point-max))
  14860     (recenter)
  14861     ))
  14862 
  14863 (provide 'web-mode)
  14864 
  14865 ;;; web-mode.el ends here
  14866 
  14867 ;; Local Variables:
  14868 ;; coding: utf-8
  14869 ;; indent-tabs-mode: nil
  14870 ;; End: