dotemacs

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

web-mode.el (584283B)


      1 ;;; web-mode.el --- major mode for editing web templates -*- coding: utf-8; lexical-binding: t; -*-
      2 
      3 ;; Copyright 2011-2024 François-Xavier Bois
      4 
      5 ;; Version: 17.3.19
      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.19"
     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-markup-comment-indent-offset
     92   5
     93   "Html comment indentation level."
     94   :type 'integer
     95   :safe #'integerp
     96   :group 'web-mode)
     97 
     98 (defcustom web-mode-css-indent-offset
     99   (if (and (boundp 'standard-indent) standard-indent) standard-indent 2)
    100   "CSS indentation level."
    101   :type 'integer
    102   :safe #'integerp
    103   :group 'web-mode)
    104 
    105 (defcustom web-mode-code-indent-offset
    106   (if (and (boundp 'standard-indent) standard-indent) standard-indent 2)
    107   "Code (javascript, php, etc.) indentation level."
    108   :type 'integer
    109   :safe #'integerp
    110   :group 'web-mode)
    111 
    112 (defcustom web-mode-sql-indent-offset 4
    113   "Sql (inside strings) indentation level."
    114   :type 'integer
    115   :safe #'integerp
    116   :group 'web-mode)
    117 
    118 (defcustom web-mode-enable-css-colorization (display-graphic-p)
    119   "In a CSS part, set background according to the color: #xxx, rgb(x,x,x)."
    120   :type 'boolean
    121   :group 'web-mode)
    122 
    123 (defcustom web-mode-enable-comment-interpolation nil
    124   "Enable highlight of keywords like FIXME, TODO, etc. in comments."
    125   :type 'boolean
    126   :group 'web-mode)
    127 
    128 (defcustom web-mode-enable-comment-annotation nil
    129   "Enable annotation in comments (jsdoc, phpdoc, etc.)."
    130   :type 'boolean
    131   :group 'web-mode)
    132 
    133 (defcustom web-mode-enable-auto-indentation (display-graphic-p)
    134   "Auto-indentation."
    135   :type 'boolean
    136   :group 'web-mode)
    137 
    138 (defcustom web-mode-enable-auto-closing (display-graphic-p)
    139   "Auto-closing."
    140   :type 'boolean
    141   :group 'web-mode)
    142 
    143 (defcustom web-mode-enable-auto-pairing (display-graphic-p)
    144   "Auto-pairing."
    145   :type 'boolean
    146   :group 'web-mode)
    147 
    148 (defcustom web-mode-enable-auto-opening (display-graphic-p)
    149   "Html element auto-opening."
    150   :type 'boolean
    151   :group 'web-mode)
    152 
    153 (defcustom web-mode-enable-auto-quoting (display-graphic-p)
    154   "Add double quotes after the character = in a tag."
    155   :type 'boolean
    156   :group 'web-mode)
    157 
    158 (defcustom web-mode-enable-auto-expanding nil
    159   "e.g. s/ expands to <span>|</span>."
    160   :type 'boolean
    161   :group 'web-mode)
    162 
    163 (defcustom web-mode-enable-curly-brace-indentation nil
    164   "Indent lines beginning with {."
    165   :type 'boolean
    166   :group 'web-mode)
    167 
    168 (defcustom web-mode-enable-control-block-indentation t
    169   "Control blocks increase indentation."
    170   :type 'boolean
    171   :group 'web-mode)
    172 
    173 (defcustom web-mode-enable-current-element-highlight nil
    174   "Enable current element highlight."
    175   :type 'boolean
    176   :group 'web-mode)
    177 
    178 (defcustom web-mode-enable-current-column-highlight nil
    179   "Show column for current element."
    180   :type 'boolean
    181   :group 'web-mode)
    182 
    183 (defcustom web-mode-enable-whitespace-fontification nil
    184   "Enable whitespaces."
    185   :type 'boolean
    186   :group 'web-mode)
    187 
    188 (defcustom web-mode-enable-html-entities-fontification nil
    189   "Enable html entities fontification."
    190   :type 'boolean
    191   :group 'web-mode)
    192 
    193 (defcustom web-mode-enable-block-face nil
    194   "Enable block face (useful for setting a background for example).
    195 See web-mode-block-face."
    196   :type 'boolean
    197   :group 'web-mode)
    198 
    199 (defcustom web-mode-enable-part-face nil
    200   "Enable part face (useful for setting background of <style> or <script>
    201  elements for example). See web-mode-part-face."
    202   :type 'boolean
    203   :group 'web-mode)
    204 
    205 (defcustom web-mode-enable-inlays nil
    206   "Enable inlays (e.g. LaTeX) highlighting."
    207   :type 'boolean
    208   :group 'web-mode)
    209 
    210 (defcustom web-mode-enable-sexp-functions t
    211   "Enable specific sexp functions."
    212   :type 'boolean
    213   :group 'web-mode)
    214 
    215 (defcustom web-mode-enable-string-interpolation t
    216   "Enable string interpolation fontification (php and erb)."
    217   :type 'boolean
    218   :group 'web-mode)
    219 
    220 (defcustom web-mode-enable-literal-interpolation t
    221   "Enable template literal fontification. e.g. css` `."
    222   :type 'boolean
    223   :group 'web-mode)
    224 
    225 (defcustom web-mode-enable-sql-detection nil
    226   "Enable fontification and indentation of sql queries in strings."
    227   :type 'boolean
    228   :group 'web-mode)
    229 
    230 (defcustom web-mode-enable-heredoc-fontification t
    231   "Enable heredoc fontification. The identifier should contain JS, JAVASCRIPT,
    232  CSS or HTML."
    233   :type 'boolean
    234   :group 'web-mode)
    235 
    236 (defcustom web-mode-enable-element-content-fontification nil
    237   "Enable element content fontification. The content of an element can have a
    238 face associated."
    239   :type 'boolean
    240   :group 'web-mode)
    241 
    242 (defcustom web-mode-enable-element-tag-fontification nil
    243   "Enable tag name fontification."
    244   :type 'boolean
    245   :group 'web-mode)
    246 
    247 (defcustom web-mode-enable-front-matter-block nil
    248   "Enable front matter block (data at the beginning the template
    249 between --- and ---)."
    250   :type 'boolean
    251   :group 'web-mode)
    252 
    253 (defcustom web-mode-enable-engine-detection nil
    254   "Detect such directive -*- engine: ENGINE -*- at the top of the file."
    255   :type 'boolean
    256   :group 'web-mode)
    257 
    258 (defcustom web-mode-enable-optional-tags nil
    259   "Enable omission of certain closing tags (e.g. a li open tag followed
    260 by a li open tag is valid)."
    261   :type 'boolean
    262   :group 'web-mode)
    263 
    264 (defcustom web-mode-comment-style 1
    265   "Comment style : 1 = default, 2 = force server comments outside a block."
    266   :group 'web-mode
    267   :type '(choice (const :tag "Default" 1)
    268           (const :tag "Force engine comments" 2)))
    269 
    270 (defcustom web-mode-indent-style 2
    271   "Indentation style."
    272   :group 'web-mode
    273   :type '(choice (const :tag "Default (all lines are indented)" 2)
    274           (const :tag "Text at the beginning of line is not indented" 1)))
    275 
    276 (defcustom web-mode-auto-close-style 1
    277   "Auto-close style."
    278   :group 'web-mode
    279   :type '(choice (const :tag "Auto-close on </" 1)
    280           (const :tag "Auto-close on > and </" 2)
    281           (const :tag "Auto-close on < and >/>" 3)))
    282 
    283 (defcustom web-mode-auto-quote-style 1
    284   "Auto-quoting style."
    285   :group 'web-mode
    286   :type '(choice (const :tag "Auto-quotes with double quote" 1)
    287           (const :tag "Auto-quotes with single quote" 2)
    288           (const :tag "Auto-quotes with paren (for jsx)" 3)))
    289 
    290 (defcustom web-mode-extra-expanders '()
    291   "A list of additional expanders."
    292   :type '(alist :key-type string :value-type string)
    293   :group 'web-mode)
    294 
    295 (defcustom web-mode-extra-auto-pairs '()
    296   "A list of additional auto-pairs."
    297   :type '(alist :key-type string :value-type string)
    298   :group 'web-mode)
    299 
    300 (defcustom web-mode-extra-snippets '()
    301   "A list of additional snippets."
    302   :type '(alist :key-type string :value-type string)
    303   :group 'web-mode)
    304 
    305 (defcustom web-mode-extra-builtins '()
    306   "A list of additional builtins."
    307   :type '(alist :key-type string :value-type string)
    308   :group 'web-mode)
    309 
    310 (defcustom web-mode-extra-constants '()
    311   "A list of additional constants."
    312   :type '(alist :key-type string :value-type string)
    313   :group 'web-mode)
    314 
    315 (defcustom web-mode-extra-keywords '()
    316   "A list of additional keywords."
    317   :type '(alist :key-type string :value-type string)
    318   :group 'web-mode)
    319 
    320 (defcustom web-mode-extra-types '()
    321   "A list of additional types."
    322   :type '(alist :key-type string :value-type string)
    323   :group 'web-mode)
    324 
    325 (defcustom web-mode-extra-control-blocks '()
    326   "A list of additional control blocks."
    327   :type '(alist :key-type string :value-type (repeat string))
    328   :group 'web-mode)
    329 
    330 (defcustom web-mode-tests-directory (concat default-directory "tests/")
    331   "Directory containing all the unit tests."
    332   :type 'directory
    333   :group 'web-mode)
    334 
    335 (defcustom web-mode-jsx-depth-faces
    336   nil
    337   ;;'(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)
    338   "Each jsx depth has is own face."
    339   :type '(repeat face)
    340   :group 'web-mode)
    341 
    342 (defcustom web-mode-commands-like-expand-region
    343   '(web-mode-mark-and-expand er/expand-region mc/mark-next-like-this mc/mark-previous-like-this)
    344   "Add commmand here if you have some wrapper function for er/expand-region"
    345   :type '(repeat function)
    346   :group 'web-mode)
    347 
    348 (defcustom web-mode-comment-formats
    349   '(("java"       . "/*")
    350     ("javascript" . "/*")
    351     ("typescript" . "//")
    352     ("php"        . "/*")
    353     ("css"        . "/*"))
    354   "Default comment format for a language"
    355   :type '(alist :key-type string :value-type string)
    356   :group 'web-mode)
    357 
    358 (defcustom web-mode-script-template-types
    359   '("text/x-handlebars"
    360     "text/x-jquery-tmpl"
    361     "text/x-jsrender"
    362     "text/html"
    363     "text/ng-template"
    364     "text/x-template"
    365     "text/mustache"
    366     "text/x-dust-template")
    367   "<script> block types that are interpreted as HTML."
    368   :type '(repeat string)
    369   :group 'web-mode)
    370 
    371 ;; https://developer.mozilla.org/en-US/docs/Web/HTML/Element
    372 (defcustom web-mode-tag-list
    373   '("a" "abbr" "address" "area" "article" "aside" "audio" "b"
    374     "base" "bdi" "bdo" "blockquote" "body" "br" "button" "canvas"
    375     "caption" "cite" "code" "col" "colgroup" "data" "datalist"
    376     "dd" "del" "details" "dfn" "dialog" "div" "dl" "dt" "em"
    377     "embed" "fieldset" "figcaption" "figure" "footer" "form" "h1"
    378     "h2" "h3" "h4" "h5" "h6" "head" "header" "hgroup" "hr" "html"
    379     "i" "iframe" "img" "input" "ins" "kbd" "label" "legend" "li"
    380     "link" "main" "map" "mark" "math" "menu" "meta" "meter" "nav"
    381     "noscript" "object" "ol" "optgroup" "option" "output" "p"
    382     "picture" "pre" "progress" "q" "rp" "rt" "ruby" "s" "samp"
    383     "script" "search" "section" "select" "slot" "small" "source"
    384     "span" "strong" "style" "sub" "summary" "sup" "svg" "table"
    385     "tbody" "td" "template" "textarea" "tfoot" "th" "thead" "time"
    386     "title" "tr" "track" "u" "ul" "var" "video" "wbr")
    387   "HTML tags used for completion."
    388   :type '(repeat string)
    389   :group 'web-mode)
    390 
    391 
    392 ;; https://www.w3schools.com/tags/ref_attributes.asp
    393 ;; Attributes marked as deprecated in HTML 5 are not added.
    394 (defcustom web-mode-attribute-list
    395   '("accept" "accesskey" "action" "alt" "async" "autocomplete" "autofocus"
    396     "autoplay" "charset" "checked" "cite" "class" "cols" "colspan" "content"
    397     "contenteditable" "controls" "coords" "data" "datetime" "default" "defer"
    398     "dir" "dirname" "disabled" "download" "draggable" "enctype" "for" "form"
    399     "formaction" "headers" "height" "hidden" "high" "href" "hreflang" "http"
    400     "id" "ismap" "kind" "label" "lang" "list" "loop" "low" "max" "maxlength"
    401     "media" "method" "min" "multiple" "muted" "name" "novalidate" "onabort"
    402     "onafterprint" "onbeforeprint" "onbeforeunload" "onblur" "oncanplay"
    403     "oncanplaythrough" "onchange" "onclick" "oncontextmenu" "oncopy"
    404     "oncuechange" "oncut" "ondblclick" "ondrag" "ondragend" "ondragenter"
    405     "ondragleave" "ondragover" "ondragstart" "ondrop" "ondurationchange"
    406     "onemptied" "onended" "onerror" "onfocus" "onhashchange" "oninput"
    407     "oninvalid" "onkeydown" "onkeypress" "onkeyup" "onload" "onloadeddata"
    408     "onloadedmetadata" "onloadstart" "onmousedown" "onmousemove" "onmouseout"
    409     "onmouseover" "onmouseup" "onmousewheel" "onoffline" "ononline"
    410     "onpagehide" "onpageshow" "onpaste" "onpause" "onplay" "onplaying"
    411     "onpopstate" "onprogress" "onratechange" "onreset" "onresize" "onscroll"
    412     "onsearch" "onseeked" "onseeking" "onselect" "onstalled" "onstorage"
    413     "onsubmit" "onsuspend" "ontimeupdate" "ontoggle" "onunload"
    414     "onvolumechange" "onwaiting" "onwheel" "open" "optimum" "pattern"
    415     "placeholder" "poster" "preload" "readonly" "rel" "required" "reversed"
    416     "rows" "rowspan" "sandbox" "scope" "selected" "shape" "size" "sizes"
    417     "span" "spellcheck" "src" "srcdoc" "srclang" "srcset" "start" "step"
    418     "style" "tabindex" "target" "title" "translate" "type" "usemap" "value"
    419     "width" "wrap")
    420   "HTML attributes used for completion."
    421   :type '(repeat string)
    422   :group 'web-mode)
    423 
    424 (defcustom web-mode-engines-alist nil
    425   "A list of filename patterns and corresponding `web-mode' engine.
    426 For example,
    427 \(setq web-mode-engines-alist
    428        \\='((\"php\"    . \"\\\\.phtml\\\\\\='\")
    429          (\"blade\"  . \"\\\\.blade\\\\.\")))"
    430   :type '(alist :key-type string :value-type string)
    431   :group 'web-mode)
    432 
    433 ;;---- FACES -------------------------------------------------------------------
    434 
    435 (defface web-mode-error-face
    436     '((t :background "red"))
    437   "Face for warning."
    438   :group 'web-mode-faces)
    439 
    440 (defface web-mode-warning-face
    441     '((t :inherit font-lock-warning-face))
    442   "Face for warning."
    443   :group 'web-mode-faces)
    444 
    445 (defface web-mode-preprocessor-face
    446     '((t :inherit font-lock-preprocessor-face))
    447   "Face for preprocessor commands."
    448   :group 'web-mode-faces)
    449 
    450 (defface web-mode-preprocessor-face
    451     '((t :inherit font-lock-preprocessor-face))
    452   "Face for preprocessor."
    453   :group 'web-mode-faces)
    454 
    455 (defface web-mode-block-delimiter-face
    456     '((t :inherit font-lock-preprocessor-face))
    457   "Face for block delimiters."
    458   :group 'web-mode-faces)
    459 
    460 (defface web-mode-block-control-face
    461     '((t :inherit font-lock-preprocessor-face))
    462   "Face for preprocessor."
    463   :group 'web-mode-faces)
    464 
    465 (defface web-mode-builtin-face
    466     '((t :inherit font-lock-builtin-face))
    467   "Face for builtins."
    468   :group 'web-mode-faces)
    469 
    470 (defface web-mode-symbol-face
    471     '((t :foreground "goldenrod2"))
    472   "Face for symbols."
    473   :group 'web-mode-faces)
    474 
    475 (defface web-mode-doctype-face
    476     '((t :foreground "Grey"))
    477   "Face for html doctype."
    478   :group 'web-mode-faces)
    479 
    480 (defface web-mode-html-tag-face
    481     '((((class color) (min-colors 88) (background dark))  :foreground "Snow4")
    482       (((class color) (min-colors 88) (background light)) :foreground "Snow4")
    483       (((class color) (min-colors 16) (background dark))  :foreground "Snow4")
    484       (((class color) (min-colors 16) (background light)) :foreground "Grey15")
    485       (((class color) (min-colors 8))                     :foreground "Snow4")
    486       (((type tty) (class mono))                          :inverse-video t)
    487       (t                                                  :foreground "Snow4"))
    488   "Face for html tags."
    489   :group 'web-mode-faces)
    490 
    491 (defface web-mode-html-tag-custom-face
    492     '((t :inherit web-mode-html-tag-face))
    493   "Face for html custom tags (e.g. <polymer-element>)."
    494   :group 'web-mode-faces)
    495 
    496 (defface web-mode-html-tag-unclosed-face
    497     '((t :inherit web-mode-html-tag-face :underline t))
    498   "Face for unclosed tags."
    499   :group 'web-mode-faces)
    500 
    501 (defface web-mode-html-tag-namespaced-face
    502     '((t :inherit web-mode-block-control-face))
    503   "Face for html namespaced tags (e.g. <c:forEach>)."
    504   :group 'web-mode-faces)
    505 
    506 (defface web-mode-html-tag-bracket-face
    507     '((((class color) (min-colors 88) (background dark))  :foreground "Snow3")
    508       (((class color) (min-colors 88) (background light)) :foreground "Grey14")
    509       (((class color) (min-colors 16) (background dark))  :foreground "Snow3")
    510       (((class color) (min-colors 16) (background light)) :foreground "Grey14")
    511       (((class color) (min-colors 8))                     :foreground "Snow3")
    512       (((type tty) (class mono))                          :inverse-video t)
    513       (t                                                  :foreground "Snow3"))
    514   "Face for html tags angle brackets (<, > and />)."
    515   :group 'web-mode-faces)
    516 
    517 (defface web-mode-html-attr-name-face
    518     '((((class color) (min-colors 88) (background dark))  :foreground "Snow3")
    519       (((class color) (min-colors 88) (background light)) :foreground "Snow4")
    520       (((class color) (min-colors 16) (background dark))  :foreground "Snow3")
    521       (((class color) (min-colors 16) (background light)) :foreground "Grey13")
    522       (((class color) (min-colors 8))                     :foreground "Snow3")
    523       (((type tty) (class mono))                          :inverse-video t)
    524       (t                                                  :foreground "Snow4"))
    525   "Face for html attribute names."
    526   :group 'web-mode-faces)
    527 
    528 (defface web-mode-html-attr-custom-face
    529     '((t :inherit web-mode-html-attr-name-face))
    530   "Face for custom attribute names (e.g. data-*)."
    531   :group 'web-mode-faces)
    532 
    533 (defface web-mode-html-attr-engine-face
    534     '((t :inherit web-mode-block-delimiter-face))
    535   "Face for custom engine attribute names (e.g. ng-*)."
    536   :group 'web-mode-faces)
    537 
    538 (defface web-mode-html-attr-equal-face
    539     '((t :inherit web-mode-html-attr-name-face))
    540   "Face for the = character between name and value."
    541   :group 'web-mode-faces)
    542 
    543 (defface web-mode-html-attr-value-face
    544     '((t :inherit font-lock-string-face))
    545   "Face for html attribute values."
    546   :group 'web-mode-faces)
    547 
    548 (defface web-mode-block-attr-name-face
    549     '((t :foreground "#8fbc8f"))
    550   "Face for block attribute names."
    551   :group 'web-mode-faces)
    552 
    553 (defface web-mode-block-attr-value-face
    554     '((t :foreground "#5f9ea0"))
    555   "Face for block attribute values."
    556   :group 'web-mode-faces)
    557 
    558 (defface web-mode-variable-name-face
    559     '((t :inherit font-lock-variable-name-face))
    560   "Face for variable names."
    561   :group 'web-mode-faces)
    562 
    563 (defface web-mode-css-selector-face
    564     '((t :inherit font-lock-keyword-face))
    565   "Face for CSS rules."
    566   :group 'web-mode-faces)
    567 
    568 (defface web-mode-css-selector-class-face
    569     '((t :inherit font-lock-keyword-face))
    570   "Face for CSS class rules."
    571   :group 'web-mode-faces)
    572 
    573 (defface web-mode-css-selector-tag-face
    574     '((t :inherit font-lock-keyword-face))
    575   "Face for CSS tag rules."
    576   :group 'web-mode-faces)
    577 
    578 (defface web-mode-css-pseudo-class-face
    579     '((t :inherit font-lock-builtin-face))
    580   "Face for CSS pseudo-classes."
    581   :group 'web-mode-faces)
    582 
    583 (defface web-mode-css-at-rule-face
    584     '((t :inherit font-lock-constant-face))
    585   "Face for CSS at-rules."
    586   :group 'web-mode-faces)
    587 
    588 (defface web-mode-css-property-name-face
    589     '((t :inherit font-lock-variable-name-face))
    590   "Face for CSS props."
    591   :group 'web-mode-faces)
    592 
    593 (defface web-mode-css-color-face
    594     '((t :inherit font-lock-builtin-face))
    595   "Face for CSS colors (#xxx)."
    596   :group 'web-mode-faces)
    597 
    598 (defface web-mode-css-priority-face
    599     '((t :inherit font-lock-builtin-face))
    600   "Face for CSS priority (!important)."
    601   :group 'web-mode-faces)
    602 
    603 (defface web-mode-css-function-face
    604     '((t :inherit font-lock-builtin-face))
    605   "Face for CSS functions."
    606   :group 'web-mode-faces)
    607 
    608 (defface web-mode-css-variable-face
    609     '((t :inherit web-mode-variable-name-face :slant italic))
    610   "Face for CSS vars."
    611   :group 'web-mode-faces)
    612 
    613 (defface web-mode-function-name-face
    614     '((t :inherit font-lock-function-name-face))
    615   "Face for function names."
    616   :group 'web-mode-faces)
    617 
    618 (defface web-mode-filter-face
    619     '((t :inherit font-lock-function-name-face))
    620   "Face for function names."
    621   :group 'web-mode-faces)
    622 
    623 (defface web-mode-function-call-face
    624     '((t :inherit font-lock-function-name-face))
    625   "Face for function calls."
    626   :group 'web-mode-faces)
    627 
    628 (defface web-mode-string-face
    629     '((t :inherit font-lock-string-face))
    630   "Face for strings."
    631   :group 'web-mode-faces)
    632 
    633 (defface web-mode-block-string-face
    634     '((t :inherit web-mode-string-face))
    635   "Face for block strings."
    636   :group 'web-mode-faces)
    637 
    638 (defface web-mode-part-string-face
    639     '((t :inherit web-mode-string-face))
    640   "Face for part strings."
    641   :group 'web-mode-faces)
    642 
    643 (defface web-mode-javascript-string-face
    644     '((t :inherit web-mode-string-face))
    645   "Face for javascript strings."
    646   :group 'web-mode-faces)
    647 
    648 (defface web-mode-interpolate-color1-face
    649     '((t :inherit web-mode-string-face))
    650   "Face for element interpolation strings."
    651   :group 'web-mode-faces)
    652 
    653 (defface web-mode-interpolate-color2-face
    654     '((t :inherit web-mode-string-face))
    655   "Face for element interpolation strings."
    656   :group 'web-mode-faces)
    657 
    658 (defface web-mode-interpolate-color3-face
    659     '((t :inherit web-mode-string-face))
    660   "Face for element interpolation strings."
    661   :group 'web-mode-faces)
    662 
    663 (defface web-mode-interpolate-color4-face
    664     '((t :inherit web-mode-string-face))
    665   "Face for element interpolation strings."
    666   :group 'web-mode-faces)
    667 
    668 (defface web-mode-css-string-face
    669     '((t :inherit web-mode-string-face))
    670   "Face for css strings."
    671   :group 'web-mode-faces)
    672 
    673 (defface web-mode-json-key-face
    674     '((t :foreground "plum"))
    675   "Face for json key strings."
    676   :group 'web-mode-faces)
    677 
    678 (defface web-mode-json-context-face
    679     '((t :foreground "orchid3"))
    680   "Face for json context strings."
    681   :group 'web-mode-faces)
    682 
    683 (defface web-mode-json-string-face
    684     '((t :inherit web-mode-string-face))
    685   "Face for json strings."
    686   :group 'web-mode-faces)
    687 
    688 (defface web-mode-comment-face
    689     '((t :inherit font-lock-comment-face))
    690   "Face for comments."
    691   :group 'web-mode-faces)
    692 
    693 (defface web-mode-block-comment-face
    694     '((t :inherit web-mode-comment-face))
    695   "Face for server comments."
    696   :group 'web-mode-faces)
    697 
    698 (defface web-mode-part-comment-face
    699     '((t :inherit web-mode-comment-face))
    700   "Face for part comments."
    701   :group 'web-mode-faces)
    702 
    703 (defface web-mode-json-comment-face
    704     '((t :inherit web-mode-comment-face))
    705   "Face for json comments."
    706   :group 'web-mode-faces)
    707 
    708 (defface web-mode-javascript-comment-face
    709     '((t :inherit web-mode-comment-face))
    710   "Face for javascript comments."
    711   :group 'web-mode-faces)
    712 
    713 (defface web-mode-css-comment-face
    714     '((t :inherit web-mode-comment-face))
    715   "Face for css comments."
    716   :group 'web-mode-faces)
    717 
    718 (defface web-mode-annotation-face
    719     '((t :inherit web-mode-comment-face))
    720   "Face for code annotations."
    721   :group 'web-mode-faces)
    722 
    723 (defface web-mode-annotation-tag-face
    724     '((t :inherit web-mode-annotation-face :underline t))
    725   "Face for @tags in code annotations."
    726   :group 'web-mode-faces)
    727 
    728 (defface web-mode-annotation-type-face
    729     '((t :inherit web-mode-annotation-face :weight bold))
    730   "Face for types in code annotations."
    731   :group 'web-mode-faces)
    732 
    733 (defface web-mode-annotation-value-face
    734     '((t :inherit web-mode-annotation-face :slant italic))
    735   "Face for values in code annotations."
    736   :group 'web-mode-faces)
    737 
    738 (defface web-mode-annotation-html-face
    739     '((t :inherit web-mode-annotation-face :slant italic))
    740   "Face for HTML tags in code annotations."
    741   :group 'web-mode-faces)
    742 
    743 (defface web-mode-constant-face
    744     '((t :inherit font-lock-constant-face))
    745   "Face for language constants."
    746   :group 'web-mode-faces)
    747 
    748 (defface web-mode-type-face
    749     '((t :inherit font-lock-type-face))
    750   "Face for language types."
    751   :group 'web-mode-faces)
    752 
    753 (defface web-mode-keyword-face
    754     '((t :inherit font-lock-keyword-face))
    755   "Face for language keywords."
    756   :group 'web-mode-faces)
    757 
    758 (defface web-mode-param-name-face
    759     '((t :foreground "Snow3"))
    760   "Face for server attribute names."
    761   :group 'web-mode-faces)
    762 
    763 (defface web-mode-whitespace-face
    764     '((t :background "DarkOrchid4"))
    765   "Face for whitespaces."
    766   :group 'web-mode-faces)
    767 
    768 (defface web-mode-inlay-face
    769     '((((class color) (min-colors 88) (background dark))  :background "Black")
    770       (((class color) (min-colors 88) (background light)) :background "LightYellow1")
    771       (((class color) (min-colors 16) (background dark))  :background "Brey18")
    772       (((class color) (min-colors 16) (background light)) :background "LightYellow1")
    773       (((class color) (min-colors 8))                     :background "Black")
    774       (((type tty) (class mono))                          :inverse-video t)
    775       (t                                                  :background "Grey"))
    776   "Face for inlays. Must be used in conjunction with web-mode-enable-inlays."
    777   :group 'web-mode-faces)
    778 
    779 (defface web-mode-block-face
    780     '((((class color) (min-colors 88) (background dark))  :background "Black")
    781       (((class color) (min-colors 88) (background light)) :background "LightYellow1")
    782       (((class color) (min-colors 16) (background dark))  :background "Grey18")
    783       (((class color) (min-colors 16) (background light)) :background "LightYellow1")
    784       (((class color) (min-colors 8))                     :background "Black")
    785       (((type tty) (class mono))                          :inverse-video t)
    786       (t                                                  :background "Grey"))
    787   "Face for blocks (useful for setting a background for example).
    788 Must be used in conjunction with web-mode-enable-block-face."
    789   :group 'web-mode-faces)
    790 
    791 (defface web-mode-part-face
    792     '((t :inherit web-mode-block-face))
    793   "Face for parts."
    794   :group 'web-mode-faces)
    795 
    796 (defface web-mode-script-face
    797     '((t :inherit web-mode-part-face))
    798   "Face for javascript inside a script element."
    799   :group 'web-mode-faces)
    800 
    801 (defface web-mode-style-face
    802     '((t :inherit web-mode-part-face))
    803   "Face for css inside a style element."
    804   :group 'web-mode-faces)
    805 
    806 (defface web-mode-folded-face
    807     '((t :underline t))
    808   "Overlay face for folded."
    809   :group 'web-mode-faces)
    810 
    811 (defface web-mode-bold-face
    812     '((t :weight bold))
    813   "bold face."
    814   :group 'web-mode-faces)
    815 
    816 (defface web-mode-italic-face
    817     '((t :slant italic))
    818   "bold face."
    819   :group 'web-mode-faces)
    820 
    821 (defface web-mode-underline-face
    822     '((t :underline t))
    823   "bold face."
    824   :group 'web-mode-faces)
    825 
    826 (defface web-mode-current-element-highlight-face
    827     '((t :background "#000000" :foreground "#ffffff"))
    828   "Overlay face for element highlight."
    829   :group 'web-mode-faces)
    830 
    831 (defface web-mode-current-column-highlight-face
    832     '((t :background "#3e3c36"))
    833   "Overlay face for current column."
    834   :group 'web-mode-faces)
    835 
    836 (defface web-mode-comment-keyword-face
    837     '((t :weight bold :box t))
    838   "Comment keywords."
    839   :group 'web-mode-faces)
    840 
    841 (defface web-mode-sql-keyword-face
    842     '((t :weight bold :slant italic))
    843   "Sql keywords."
    844   :group 'web-mode-faces)
    845 
    846 (defface web-mode-html-entity-face
    847     '((t :slant italic))
    848   "Face html entities (e.g. &#8211;, &eacute;)."
    849   :group 'web-mode-faces)
    850 
    851 ;; https://material.io/tools/color/#!/?view.left=0&view.right=0
    852 (defface web-mode-jsx-depth-1-face
    853     '((t :background "#000053"))
    854   "jsx depth 1"
    855   :group 'web-mode-faces)
    856 
    857 (defface web-mode-jsx-depth-2-face
    858     '((t :background "#001970"))
    859   "jsx"
    860   :group 'web-mode-faces)
    861 
    862 (defface web-mode-jsx-depth-3-face
    863     '((t :background "#002984"))
    864   "jsx"
    865   :group 'web-mode-faces)
    866 
    867 (defface web-mode-jsx-depth-4-face
    868     '((t :background "#49599a"))
    869   "jsx"
    870   :group 'web-mode-faces)
    871 
    872 (defface web-mode-jsx-depth-5-face
    873     '((t :background "#9499b7"))
    874   "jsx"
    875   :group 'web-mode-faces)
    876 
    877 ;;---- VARS --------------------------------------------------------------------
    878 
    879 (defvar font-lock-beg)
    880 (defvar font-lock-end)
    881 
    882 (defvar web-mode-auto-pairs nil)
    883 (defvar web-mode-block-regexp nil)
    884 (defvar web-mode-change-beg nil)
    885 (defvar web-mode-change-end nil)
    886 (defvar web-mode-chunk-length 64)
    887 (defvar web-mode-column-overlays nil)
    888 (defvar web-mode-comments-invisible nil)
    889 (defvar web-mode-content-type "")
    890 (defvar web-mode-engine nil)
    891 ;;(defvar web-mode-engine-attr-regexp nil)
    892 (defvar web-mode-engine-font-lock-keywords nil)
    893 (defvar web-mode-engine-token-regexp nil)
    894 (defvar web-mode-expand-initial-pos nil)
    895 (defvar web-mode-expand-initial-scroll nil)
    896 (defvar web-mode-expand-previous-state "")
    897 ;;(defvar web-mode-font-lock-keywords '(web-mode-font-lock-highlight))
    898 (defvar web-mode-skip-fontification nil)
    899 (defvar web-mode-inlay-regexp nil)
    900 (defvar web-mode-is-scratch nil)
    901 (defvar web-mode-jshint-errors 0)
    902 (defvar web-mode-minor-engine nil)
    903 (defvar web-mode-obarray nil)
    904 (defvar web-mode-overlay-tag-start nil)
    905 (defvar web-mode-overlay-tag-end nil)
    906 (defvar web-mode-part-beg nil)
    907 (defvar web-mode-scan-beg nil)
    908 (defvar web-mode-scan-end nil)
    909 (defvar web-mode-snippets nil)
    910 (defvar web-mode-time nil)
    911 
    912 (defvar web-mode-offsetless-elements
    913   '())
    914 
    915 (defvar web-mode-indentless-elements
    916   '("code" "pre" "textarea"))
    917 
    918 (defvar web-mode-indentless-attributes
    919   '("onclick" "onmouseover" "onmouseout" "onsubmit"))
    920 
    921 (defvar web-mode-void-elements
    922   '("area" "base" "br" "col" "command" "embed" "hr" "img" "input" "keygen"
    923     "link" "meta" "param" "source" "track" "wbr" "tmpl_var"))
    924 
    925 (defvar web-mode-part-content-types
    926   '("css" "javascript" "json" "jsx" "markdown" "pug" "ruby"
    927     "sass" "sql" "stylus" "typescript"))
    928 
    929 (defvar web-mode-javascript-languages '("javascript" "jsx" "ejs"))
    930 
    931 ;; NOTE: without 'syntax-table forward-word fails (#377)
    932 (defvar web-mode-scan-properties
    933   (list 'tag-beg 'tag-end 'tag-name 'tag-type
    934         'tag-attr 'tag-attr-beg 'tag-attr-end
    935         'part-side 'part-token
    936         'jsx-beg 'jsx-end 'jsx-depth
    937         'block-side 'block-token 'block-controls 'block-beg 'block-end
    938         'syntax-table)
    939   "Text properties used for code regions/tokens and html nodes.")
    940 
    941 (defvar web-mode-start-tag-regexp "<\\([[:alnum:].:_-]+\\|>\\)"
    942   "Regular expression for HTML/XML start tag.")
    943 
    944 (defvar web-mode-tag-regexp "</?\\([[:alnum:].:_-]+\\)"
    945   "Regular expression for HTML/XML tag.")
    946 
    947 (defvar web-mode-dom-regexp "<\\(/?>\\|/?[[:alnum:].:_-]+\\|!--\\|!\\[CDATA\\[\\|!doctype\\|!DOCTYPE\\|\?xml\\)")
    948 
    949 (defvar web-mode-whitespaces-regexp
    950   "^[ \t]\\{2,\\}$\\| \t\\|\t \\|[ \t]+$\\|^[ \n\t]+\\'\\|^[ \t]?[\n]\\{2,\\}"
    951   "Regular expression for whitespaces.")
    952 
    953 (defvar web-mode-imenu-regexp-list
    954   '(("<\\(h[1-9]\\)\\([^>]*\\)>\\([^<]*\\)" 1 3 ">")
    955     ("^[ \t]*<\\([@a-z]+\\)[^>]*>? *$" 1 "id=\"\\([a-zA-Z0-9_]+\\)\"" "#" ">"))
    956   "Regexps to match imenu items (see https://web-mode.org/doc/imenu.txt)")
    957 
    958 ;; https://www.gnu.org/software/emacs/manual/html_node/ccmode/Syntactic-Symbols.html
    959 (defvar web-mode-indentation-params
    960   '(("lineup-args"       . t)
    961     ("lineup-calls"      . t)
    962     ("lineup-concats"    . t)
    963     ("lineup-quotes"     . t)
    964     ("lineup-ternary"    . t)
    965     ("case-extra-offset" . t)
    966     ))
    967 
    968 (defvar web-mode-tag-history nil)
    969 (defvar web-mode-attribute-history nil)
    970 (defvar web-mode-attribute-value-history nil)
    971 
    972 (defvar web-mode-engines
    973   '(("angular"          . ("angularjs"))
    974     ("anki"             . ())
    975     ("antlers"          . ())
    976     ("archibus"         . ())
    977     ("artanis"          . ())
    978     ("asp"              . ())
    979     ("aspx"             . ())
    980     ("astro"            . ())
    981     ("blade"            . ("laravel"))
    982     ("cl-emb"           . ())
    983     ("clip"             . ())
    984     ("closure"          . ("soy"))
    985     ("ctemplate"        . ("mustache" "handlebars" "hapax" "ngtemplate" "ember"
    986                            "kite" "meteor" "blaze" "ractive" "velvet"))
    987     ("django"           . ("dtl" "twig" "swig" "jinja" "jinja2" "erlydtl" "liquid"
    988                            "clabango" "selmer" "nunjucks"))
    989     ("dust"             . ("dustjs"))
    990     ("ejs"              . ())
    991     ("elixir"           . ("phoenix"))
    992     ("erb"              . ("eruby" "erubis" "crystal"))
    993     ("expressionengine" . ("ee"))
    994     ("freemarker"       . ())
    995     ("go"               . ("gtl" "hugo"))
    996     ("hero"             . ())
    997     ("json-t"           . ())
    998     ("jsp"              . ("grails"))
    999     ("mako"             . ())
   1000     ("marko"            . ())
   1001     ("mason"            . ("poet"))
   1002     ("lsp"              . ("lisp"))
   1003     ("mojolicious"      . ())
   1004     ("php"              . ())
   1005     ("python"           . ())
   1006     ("razor"            . ("play" "play2"))
   1007     ("riot"             . ())
   1008     ("smarty"           . ())
   1009     ("spip"             . ())
   1010     ("svelte"           . ("svelte"))
   1011     ("template-toolkit" . ())
   1012     ("thymeleaf"        . ())
   1013     ("perl"             . ())
   1014     ("underscore"       . ("underscore.js"))
   1015     ("velocity"         . ("vtl" "cheetah" "ssp"))
   1016     ("vue"              . ("vuejs" "vue.js"))
   1017     ("web2py"           . ())
   1018     ("xoops"            . ())
   1019     )
   1020   "Engine name aliases")
   1021 
   1022 (defvar web-mode-content-types
   1023   '(("css"        . "\\.\\(s?css\\|css\\.erb\\)\\'")
   1024     ("javascript" . "\\.\\([mc]?js\\|js\\.erb\\)\\'")
   1025     ("typescript" . "\\.\\([mc]?ts\\|ts\\.erb\\)\\'")
   1026     ("json"       . "\\.\\(api\\|json\\|jsonld\\)\\'")
   1027     ("jsx"        . "\\.[jt]sx\\'")
   1028     ("xml"        . "\\.xml\\'")
   1029     ("html"       . "."))
   1030   "content types")
   1031 
   1032 (defvar web-mode-engine-attr-regexps
   1033   '(("angular"   . "ng-")
   1034     ("thymeleaf" . "th:")
   1035     ("vue"       . "v-"))
   1036   "Engine custom attributes")
   1037 
   1038 (defvar web-mode-engine-attr-regexp
   1039   "^ng[-]\\|^th[:]\\|^v[-]\\|^[@:#(\[*]"
   1040   "Engine custom attributes")
   1041 
   1042 (defvar web-mode-last-enabled-feature nil)
   1043 
   1044 (defvar web-mode-features
   1045   '(("css-colorization"          . web-mode-enable-css-colorization)
   1046     ("element-highlight"         . web-mode-enable-current-element-highlight)
   1047     ("column-highlight"          . web-mode-enable-current-column-highlight)
   1048     ("whitespace-fontification"  . web-mode-enable-whitespace-fontification)
   1049     ("element-tag-fontification" . web-mode-enable-element-tag-fontification)
   1050     ("block-face"                . web-mode-enable-block-face)
   1051     ("part-face"                 . web-mode-enable-part-face)))
   1052 
   1053 (defvar web-mode-comment-prefixing t)
   1054 
   1055 (defvar web-mode-engine-file-regexps
   1056   '(("angular"          . "\\.component\\.html\\'")
   1057     ("anki"             . "\\.anki\\'")
   1058     ("antlers"          . "\\.antlers\\.html\\'")
   1059     ("archibus"         . "\\.axvw\\'")
   1060     ("artanis"          . "\\.html\\.tpl\\'")
   1061     ("asp"              . "\\.asp\\'")
   1062     ("aspx"             . "\\.as[cp]x\\'")
   1063     ("astro"            . "\\.astro\\'")
   1064     ("blade"            . "\\.blade\\.php\\'")
   1065     ("cl-emb"           . "\\.clemb\\'")
   1066     ("clip"             . "\\.ctml\\'")
   1067     ("closure"          . "\\.soy\\'")
   1068     ("ctemplate"        . "\\.\\(chtml\\|mustache\\)\\'")
   1069     ("django"           . "\\.\\(djhtml\\|tmpl\\|dtl\\|liquid\\|j2\\|njk\\)\\'")
   1070     ("dust"             . "\\.dust\\'")
   1071     ("elixir"           . "\\.[hl]?eex\\'")
   1072     ("ejs"              . "\\.ejs\\'")
   1073     ("erb"              . "\\.\\(erb\\|rhtml\\|erb\\.html\\|ecr\\)\\'")
   1074     ("expressionengine" . "\\.ee\\'")
   1075     ("freemarker"       . "\\.ftl\\'")
   1076     ("go"               . "\\.go\\(html\\|tmpl\\)\\'")
   1077     ("handlebars"       . "\\.\\(hb\\.html\\|hbs\\)\\'")
   1078     ("hero"             . "\\.hero\\'")
   1079     ("jinja"            . "\\.\\(jinja\\|nwt\\)\\'")
   1080     ("jsp"              . "\\.[gj]sp\\'")
   1081     ("lsp"              . "\\.lsp\\'")
   1082     ("mako"             . "\\.mako?\\'")
   1083     ("marko"            . "\\.marko\\'")
   1084     ("mason"            . "\\.mas\\'")
   1085     ("mojolicious"      . "\\.epl?\\'")
   1086     ("perl"             . "\\.\\(ptmpl\\|perl\\.html\\)\\'")
   1087     ("php"              . "\\.\\(p[hs]p\\|ctp\\|inc\\)\\'")
   1088     ("python"           . "\\.pml\\'")
   1089     ("razor"            . "\\.\\(cs\\|vb\\)html\\|\\.razor\\'")
   1090     ("riot"             . "\\.tag\\'")
   1091     ("smarty"           . "\\.tpl\\'")
   1092     ("svelte"           . "\\.svelte\\'")
   1093     ("template-toolkit" . "\\.tt.?\\'")
   1094     ("thymeleaf"        . "\\.thtml\\'")
   1095     ("velocity"         . "\\.v\\(sl\\|tl\\|m\\)\\'")
   1096     ("vue"              . "\\.vue\\'")
   1097     ("xoops"            . "\\.xoops'")
   1098     ;; regexp on the path, not just the extension
   1099     ("django"           . "[st]wig")
   1100     ("razor"            . "scala")
   1101     ("spip"             . "spip")
   1102     )
   1103   "Engine file extensions.")
   1104 
   1105 (defvar web-mode-content-types-alist nil
   1106   "A list of filename patterns and corresponding web-mode content types.
   1107 For example,
   1108 (setq web-mode-content-types-alist
   1109   \\='((\"json\" . \"/some/path/.*\\.api\\\\='\")
   1110     (\"jsx\"  . \"/some/react/path/.*\\.js[x]?\\\\='\")))")
   1111 
   1112 (defvar web-mode-smart-quotes
   1113   '("«" . "»")
   1114   "Preferred smart quotes")
   1115 
   1116 (defvar web-mode-xml-chars
   1117   '((?\& . "&amp;")
   1118     (?\< . "&lt;")
   1119     (?\> . "&gt;"))
   1120   "XML chars")
   1121 
   1122 ;; #1254 : https://html.spec.whatwg.org/entities.json
   1123 (defvar web-mode-html-entities
   1124   ;; #985
   1125   ;; remove ("gt" . 62) ("lt" . 60) ("amp" . 38)
   1126   '(("AElig" . 198) ("Aacute" . 193) ("Acirc" . 194) ("Agrave" . 192)
   1127     ("Alpha" . 913) ("Aring" . 197) ("Atilde" . 195) ("Auml" . 196)
   1128     ("Beta" . 914)
   1129     ("Ccedil" . 199) ("Chi" . 935)
   1130     ("Dagger" . 8225) ("Delta" . 916)
   1131     ("ETH" . 208) ("Eacute" . 201) ("Ecirc" . 202) ("Egrave" . 200)
   1132     ("Epsilon" . 917) ("Eta" . 919) ("Euml" . 203)
   1133     ("Gamma" . 915)
   1134     ("Iacute" . 205) ("Icirc" . 206) ("Igrave" . 204) ("Iota" . 921)
   1135     ("Iuml" . 207)
   1136     ("Kappa" . 922)
   1137     ("Lambda" . 923)
   1138     ("Mu" . 924)
   1139     ("Ntilde" . 209) ("Nu" . 925)
   1140     ("OElig" . 338) ("Oacute" . 211) ("Ocirc" . 212) ("Ograve" . 210)
   1141     ("Omega" . 937) ("Omicron" . 927) ("Oslash" . 216) ("Otilde" . 213)
   1142     ("Ouml" . 214)
   1143     ("Phi" . 934) ("Pi" . 928) ("Prime" . 8243) ("Psi" . 936)
   1144     ("Rho" . 929)
   1145     ("Scaron" . 352) ("Sigma" . 931)
   1146     ("THORN" . 222) ("Tau" . 932) ("Theta" . 920)
   1147     ("UArr" . 8657) ("Uacute" . 218) ("Uacute" . 250) ("Ucirc" . 219)
   1148     ("Ugrave" . 217)  ("Upsih" . 978)
   1149     ("Upsilon" . 933) ("Uuml" . 220) ("Uuml" . 252)
   1150     ("Xi" . 926)
   1151     ("Yacute" . 221) ("Yuml" . 376)
   1152     ("Zeta" . 918)
   1153     ("aacute" . 225) ("acirc" . 226) ("acute" . 180) ("aelig" . 230)
   1154     ("agrave" . 224) ("alefsym" . 8501) ("alpha" . 945)
   1155     ("ang" . 8736) ("apos" . 39) ("aring" . 229) ("asymp" . 8776)
   1156     ("atilde" . 227) ("auml" . 228)
   1157     ("bdquo" . 8222) ("beta" . 946) ("brvbar" . 166) ("bull" . 8226)
   1158     ("cap" . 8745) ("ccedil" . 231) ("cedil" . 184) ("cent" . 162)
   1159     ("chi" . 967) ("circ" . 710) ("clubs" . 9827) ("cong" . 8773)
   1160     ("copy" . 169) ("crarr"  . 8629) ("cup" . 8746) ("curren" . 164)
   1161     ("dArr" . 8659) ("dagger" . 8224) ("darr" . 8595) ("deg" . 176)
   1162     ("delta" . 948) ("diams" . 9830) ("divide" . 247)
   1163     ("eacute" . 233) ("ecirc"  . 234) ("egrave" . 232) ("empty" . 8709)
   1164     ("emsp" . 8195) ("ensp" . 8194) ("epsilon" . 949) ("equiv" . 8801)
   1165     ("eta" . 951) ("eth" . 240) ("euml" . 235) ("euro" . 8364) ("exist" . 8707)
   1166     ("fnof" . 402) ("forall" . 8704) ("frac12" . 189) ("frac14" . 188)
   1167     ("frac34" . 190) ("frasl" . 8260)
   1168     ("gamma" . 947) ("ge" . 8805)
   1169     ("hArr" . 8660) ("harr" . 8596) ("hearts" . 9829) ("hellip" . 8230)
   1170     ("iacute" . 237) ("icirc" . 238) ("iexcl" . 161) ("igrave" . 236)
   1171     ("image" . 8465) ("infin" . 8734) ("int" . 8747) ("iota" . 953)
   1172     ("iquest" . 191) ("isin" . 8712) ("iuml" . 239)
   1173     ("kappa" . 954)
   1174     ("lArr" . 8656) ("lambda" . 955) ("lang" . 9001) ("laquo" . 171)
   1175     ("larr" . 8592) ("lceil" . 8968) ("ldquo" . 8220) ("le" . 8804)
   1176     ("lfloor" . 8970) ("lowast" . 8727) ("loz" . 9674) ("lrm" . 8206)
   1177     ("lsaquo" . 8249) ("lsquo" . 8249)
   1178     ("macr" . 175) ("mdash" . 8212) ("micro" . 181) ("middot" . 183)
   1179     ("minus" . 8722) ("mu" . 956)
   1180     ("nabla" . 8711) ("nbsp" . 160) ("ndash" . 8211) ("ne" . 8800)
   1181     ("ni" . 8715) ("not" . 172) ("notin" . 8713) ("nsub" . 8836)
   1182     ("ntilde" . 241) ("nu" . 957) ("oacute" . 243) ("ocirc" . 244)
   1183     ("oelig" . 339) ("ograve" . 242) ("oline" . 8254) ("omega" . 969)
   1184     ("omicron" . 959) ("oplus" . 8853) ("or" . 8744) ("ordf" . 170)
   1185     ("ordm" . 186) ("oslash" . 248) ("otilde" . 245) ("otimes" . 8855)
   1186     ("ouml" . 246)
   1187     ("para" . 182) ("part" . 8706) ("permil" . 8240) ("perp" . 8869)
   1188     ("phi" . 966) ("pi" . 960) ("piv" . 982) ("plusmn" . 177) ("pound" . 163)
   1189     ("prime" . 8242) ("prod" . 8719) ("prop" . 8733) ("psi" . 968)
   1190     ("quot" . 34)
   1191     ("rArr" . 8658) ("radic" . 8730) ("rang" . 9002) ("raquo" . 187)
   1192     ("rarr" . 8594) ("rceil" . 8969) ("rdquo" . 8221) ("real" . 8476)
   1193     ("reg" . 174) ("rfloor" . 8971) ("rho" . 961) ("rlm" . 8207)
   1194     ("rsaquo" . 8250) ("rsquo" . 8250) ("sbquo" . 8218)
   1195     ("scaron" . 353) ("sdot" . 8901) ("sect" . 167) ("shy" . 173)
   1196     ("sigma" . 963) ("sigmaf" . 962) ("sim" . 8764) ("spades" . 9824)
   1197     ("sub" . 8834) ("sube" . 8838) ("sum" . 8721) ("sup" . 8835)
   1198     ("sup1" . 185) ("sup2" . 178) ("sup3" . 179) ("supe" . 8839)
   1199     ("szlig" . 223)
   1200     ("tau" . 964) ("there4" . 8756) ("theta" . 952) ("thetasym" . 977)
   1201     ("thinsp" . 8201) ("thorn" . 254) ("tilde" . 732) ("times" . 215)
   1202     ("trade" . 8482)
   1203     ("uarr" . 8593) ("ucirc" . 251) ("ugrave" . 249) ("uml" . 168)
   1204     ("upsilon" . 965)
   1205     ("weierp" . 8472)
   1206     ("xi" . 958)
   1207     ("yacute" . 253) ("yen" . 165) ("yuml" . 255)
   1208     ("zeta" . 950) ("zwj" . 8205) ("zwnj" . 8204)))
   1209 
   1210 ;; http://webdesign.about.com/od/localization/l/blhtmlcodes-ascii.htm
   1211 (defvar web-mode-display-table
   1212   (let ((table (make-display-table)))
   1213     (aset table 9  (vector ?\xBB ?\t))
   1214     (aset table 10 (vector ?\xB6 ?\n))
   1215     (aset table 32 (vector ?\xB7))
   1216     table)
   1217   "Display table used when switching to the whitespace visualization.")
   1218 
   1219 (defvar web-mode-expanders
   1220   '(("a/" . "<a href=\"|\"></a>")
   1221     ("b/" . "<table><tbody><tr><td>|</td><td></td></tr></tbody></table>")
   1222     ("c/" . "<div class=\"|\"></div>")
   1223     ("d/" . "<div>|</div>")
   1224     ("e/" . "<em>|</em>")
   1225     ("f/" . "<form>|</form>")
   1226     ("g/" . "<strong>|</strong>")
   1227     ("h/" . "<h1>|</h1>")
   1228     ("i/" . "<img src=\"|\" />")
   1229     ("j/" . "<script>|</script>")
   1230     ("l/" . "<li>|</li>")
   1231     ("m/" . "<main>|</main>")
   1232     ("n/" . "<input type=\"|\" />")
   1233     ("p/" . "<p>|</p>")
   1234     ("q/" . "<quote>|</quote>")
   1235     ("s/" . "<span>|</span>")
   1236     ("t/" . "<td>|</td>")
   1237     ("u/" . "<ul><li>|</li><li></li></ul>")
   1238     ("x/" . "<textarea>|</textarea>")
   1239     ("2/" . "<h2>|</h2>")
   1240     ("3/" . "<h3>|</h3>")
   1241     ("?/" . "<?php | ?>")))
   1242 
   1243 (defvar web-mode-engines-auto-pairs
   1244   '(("angular"          . (("{{ " . " }}")))
   1245     ("anki"             . (("{{ " . " }}")))
   1246     ("antlers"          . (("{{ "  . " }}")
   1247                            ("{{$ " . "| $}}")
   1248                            ("{{? " . "| ?}}")
   1249                            ("{{# " . "| #}}")))
   1250     ("artanis"          . (("<% "       . " %>")
   1251                            ("<%="       . " | %>")
   1252                            ("<@css"     . " | %>")
   1253                            ("<@icon"    . " | %>")
   1254                            ("<@include" . " | %>")
   1255                            ("<@js"      . " | %>")))
   1256     ("asp"              . (("<% " . " %>")))
   1257     ("aspx"             . (("<% " . " %>")
   1258                            ("<%=" . "%>")
   1259                            ("<%#" . "%>")
   1260                            ("<%$" . "%>")
   1261                            ("<%@" . "%>")
   1262                            ("<%:" . "%>")
   1263                            ("<%-" . "- | --%>")))
   1264     ("astro"            . (("{ " . " }")))
   1265     ("blade"            . (("{{{" . " | }}}")
   1266                            ("{{ " . " }}")
   1267                            ("{!!" . " | !!}")
   1268                            ("@{{" . " | }}")
   1269                            ("{{-" . "- | --}}")))
   1270     ("cl-emb"           . (("<% " . " %>")
   1271                            ("<%=" . " | %>")
   1272                            ("<%#" . " | %>")))
   1273     ("ctemplate"        . (("{{ " . "| }}")
   1274                            ("{{~ " . "| }}")
   1275                            ("{{{" . " | }}}")
   1276                            ("{~{" . " | }}")
   1277                            ("{{~{" . " | }}}")
   1278                            ("{{!" . "-- | --}}")
   1279                            ("{{^" . "}}")
   1280                            ("{{/" . "}}")
   1281                            ("{{#" . "}}")))
   1282     ("django"           . (("{{ " . " }}")
   1283                            ("{% " . " %}")
   1284                            ("{%-" . " | %}")
   1285                            ("{# " . " #}")))
   1286     ("elixir"           . (("<% " . " %>")
   1287                            ("<%=" . " | %>")
   1288                            ("<%%" . " | %>")
   1289                            ("<%#" . " | %>")))
   1290     ("ejs"              . (("<% " . " %>")
   1291                            ("<%=" . "%>")
   1292                            ("<%#" . "%>")
   1293                            ("<%-" . "%>")))
   1294     ("erb"              . (("<% " . " %>")
   1295                            ("<%=" . " %>")
   1296                            ("<%#" . "%>")
   1297                            ("<%-" . " %>")))
   1298     ("freemarker"       . (("<% " . " %>")
   1299                            ("<#-" . "- | -->")
   1300                            ("${ " . " }")
   1301                            ("[% " . " %]")
   1302                            ("[# " . " #]")
   1303                            ("[#-" . "- | --]")))
   1304     ("go"               . (("{{ " . " }}")
   1305                            ("{{-" . " | -}}")))
   1306     ("hero"             . (("<% " . " %>")
   1307                            ("<%=" . " | %>")
   1308                            ("<%!" . " | %>")
   1309                            ("<%:" . " | %>")
   1310                            ("<%#" . " | %>")
   1311                            ("<%@" . " | %>")
   1312                            ("<%~" . " | %>")
   1313                            ("<%+" . " | %>")))
   1314     ("jsp"              . (("<% " . " %>")
   1315                            ("<%-" . "- | --%>")
   1316                            ("<%=" . "%>")
   1317                            ("<%!" . "%>")
   1318                            ("<%@" . "%>")
   1319                            ("${ " . " }")))
   1320     ("lsp"              . (("<% " . " %>")
   1321                            ("<%%" . " | %>")
   1322                            ("<%#" . " | %>")))
   1323     ("mako"             . (("<% " . " %>")
   1324                            ("<%!" . " | %>")
   1325                            ("${ " . " }")))
   1326     ("marko"            . (("${ " . " }")))
   1327     ("mason"            . (("<% " . " %>")
   1328                            ("<& " . " &>")))
   1329     ("mojolicious"      . (("<% " . " %>")
   1330                            ("<%=" . " | %>")
   1331                            ("<%%" . " | %>")
   1332                            ("<%#" . " | %>")))
   1333     ("php"              . (("<?p" . "hp | ?>")
   1334                            ("<? " . " ?>")
   1335                            ("<?=" . "?>")))
   1336     ("template-toolkit" . (("[% " . " %]")
   1337                            ("[%-" . " | %]")
   1338                            ("[%#" . " | %]")))
   1339     ("riot"             . (("={ " . " }")))
   1340     ("underscore"       . (("<% " . " %>")))
   1341     ("vue"              . (("{{ " . " }}")))
   1342     ("web2py"           . (("{{ " . " }}")
   1343                            ("{{=" . "}}")))
   1344     (nil                . (("<!-" . "- | -->")))
   1345     ))
   1346 
   1347 (defvar web-mode-engines-snippets
   1348   '(("artanis" . (("if"       . "<% (if (|) %>\n\n<% ) %>")
   1349                   ("when"     . "<% (when (|) %>\n\n<% ) %>")
   1350                   ("unless"   . "<% (unless (|) %>\n\n<% ) %>")
   1351                   ("cond"     . "<% (cond %>\n<%  [(|) %>\n\n<%  ] %>\n<%  [else %>\n\n<%  ] %>\n<% ) %>")
   1352                   ("let"      . "<% (let ([|]) %>\n\n<% ) %>")
   1353                   ("let*"     . "<% (let* ([|]) %>\n\n<% ) %>")
   1354                   ("do"       . "<% (do ([|]) %>\n<%     [()] %>\n\n<% ) %>")
   1355                   ("for-each" . "<% (for-each %>\n|\n\n<% ) %>")
   1356                   ("case"     . "<% (case | %>\n<%   [() %>\n\n<%   ] %>\n<%   [() %>\n\n<%   ] %>\n<% ) %>")))
   1357     ("ejs" . (("for"     . "<% for (|) { %>\n\n<% } %>")
   1358               ("if"      . "<% if (|) { %>\n\n<% } %>")))
   1359     ("erb" . (("each"    . "<% |.each do  %>\n\n<% end %>")
   1360               ("if"      . "<% if | %>\n\n<% end %>")
   1361               ("when"    . "<% when | %>\n\n<% end %>")
   1362               ("unless"  . "<% unless | %>\n\n<% end %>")))
   1363     ("php" . (("if"      . "<?php if (|): ?>\n\n<?php endif; ?>")
   1364               ("while"   . "<?php while (|): ?>\n\n<?php endwhile; ?>")
   1365               ("for"     . "<?php for (| ; ; ): ?>\n\n<?php endfor; ?>")
   1366               ("foreach" . "<?php foreach (| as ): ?>\n\n<?php endforeach; ?>")
   1367               ("each"    . "<?php foreach (| as ): ?>\n\n<?php endforeach; ?>")
   1368               ("switch"  . "<?php switch (|): ?>\n<?php case 1: ?>\n\n<?php break ;?>\n<?php case 2: ?>\n\n<?php break ;?>\n<?php endswitch;?>")))
   1369     ("django" . (("block"      . "{% block | %}\n\n{% endblock %}")
   1370                  ("comment"    . "{% comment | %}\n\n{% endcomment %}")
   1371                  ("css"        . "{% stylesheet  %}\n\n{% endstylesheet  %}")
   1372                  ("cycle"      . "{% cycle | as  %}\n\n{% endcycle  %}")
   1373                  ("filter"     . "{% filter | %}\n\n{% endfilter %}")
   1374                  ("for"        . "{% for | in  %}\n\n{% endfor %}")
   1375                  ("if"         . "{% if | %}\n\n{% endif %}")
   1376                  ("ifequal"    . "{% ifequal | %}\n\n{% endifequal %}")
   1377                  ("ifnotequal" . "{% ifnotequal | %}\n\n{% endifnotequal %}")
   1378                  ("js"         . "{% javascript | %}\n\n{% endjavascript %}")
   1379                  ("schema"     . "{% javascript | %}\n\n{% endschema %}")
   1380                  ("safe"       . "{% safe | %}\n\n{% endsafe %}")))
   1381     ("mako" . (("if"        . "% if |:\n% endif")
   1382                ("for"       . "% for | in :\n% endfor")
   1383                ("doc"       . "<%doc>\n|\n</%doc>")
   1384                ("inherit"   . "<%inherit file=\"|\" />")
   1385                ("namespace" . "<%namespace name=\"|\" file=\"\" import=\"\"/>")
   1386                ("block"     . "<%block name=\"|\">\n</%block>")))
   1387     ("template-toolkit" . (("if"      . "[% IF | %]\n\n[% END %]")))
   1388     (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>")
   1389             ("table" . "<table><tbody>\n<tr>\n<td>|</td>\n<td></td>\n</tr>\n</tbody></table>")
   1390             ("ul"    . "<ul>\n<li>|</li>\n<li></li>\n</ul>")))
   1391     ))
   1392 
   1393 (defvar web-mode-engine-token-regexps
   1394   (list
   1395    '("antlers"     . "\"\\|'")
   1396    '("artanis"     . "\"\\|#|\\|;")
   1397    '("asp"         . "//\\|/\\*\\|\"\\|'")
   1398    '("ejs"         . "//\\|/\\*\\|\"\\|'")
   1399    '("erb"         . "\"\\|'\\|#\\|<<[-]?['\"]?\\([[:alnum:]_]+\\)['\"]?")
   1400    '("lsp"         . "\"\\|#|\\|;")
   1401    '("mako"        . "\"\\|'\\|#")
   1402    '("mason"       . "\"\\|'\\|#")
   1403    '("mojolicious" . "\"\\|'")
   1404    '("php"         . "//\\|/\\*\\|#\\|\"\\|'\\|<<<['\"]?\\([[:alnum:]]+\\)['\"]?")
   1405    '("python"      . "\"\\|'\\|#")
   1406    '("web2py"      . "\"\\|'"))
   1407   "Engine regexps used to identify tokens (strings / comments) in blocks.")
   1408 
   1409 (defvar web-mode-engine-open-delimiter-regexps
   1410   (list
   1411    '("angular"          . "{{")
   1412    '("anki"             . "{{")
   1413    '("antlers"          . "{{[@#$]?")
   1414    '("artanis"          . "<%\\|<@\\(css\\|icon\\|include\\|js\\)")
   1415    '("asp"              . "<%\\|</?[[:alpha:]]+:[[:alpha:]]+\\|</?[[:alpha:]]+Template")
   1416    '("aspx"             . "<%.")
   1417    '("astro"            . "---")
   1418    '("blade"            . "{{.\\|{!!\\|@{{\\|@[[:alpha:]]")
   1419    '("cl-emb"           . "<%")
   1420    '("closure"          . "{.\\|/\\*\\| //")
   1421    '("clip"             . "</?c:[[:alpha:]-]+")
   1422    '("ctemplate"        . "[$]?{[{~].")
   1423    '("django"           . "{[#{%]\\|^#")
   1424    '("dust"             . "{.")
   1425    '("elixir"           . "<%\\|</?[.:]")
   1426    '("ejs"              . "<%")
   1427    '("erb"              . "<%\\|^%.")
   1428    '("expressionengine" . "{.")
   1429    '("freemarker"       . "<%\\|${\\|</?[[:alpha:]]+:[[:alpha:]]\\|</?[@#]\\|\\[/?[@#].")
   1430    '("go"               . "{{.")
   1431    '("hero"             . "<%")
   1432    '("jsp"              . "<%\\|${")
   1433    '("lsp"              . "<%")
   1434    '("mako"             . "</?%\\|${\\|^[ \t]*%.\\|^[ \t]*##")
   1435    '("marko"            . "${")
   1436    '("mason"            . "</?[&%]\\|^%.")
   1437    '("mojolicious"      . "<%\\|^[ \t]*%.")
   1438    '("perl"             . "</?TMPL_[[:alpha:]]+")
   1439    '("php"              . "<\\?")
   1440    '("python"           . "<\\?")
   1441    '("razor"            . "@.\\|^[ \t]*}")
   1442    '("riot"             . "{.\\|/// begin script")
   1443    '("smarty"           . "{[[:alpha:]#$/*\"]")
   1444    '("spip"             . "\\[(#REM)\\|(\\|#[A-Z0-9_]\\|{\\|<:")
   1445    '("template-toolkit" . "\\[%\\(.\\|$\\)\\|%%#")
   1446    '("underscore"       . "<%")
   1447    '("velocity"         . "#[[:alpha:]#*]\\|$[[:alpha:]!{]")
   1448    '("vue"              . "{{\\|[:@][-[:alpha:]]+=\"")
   1449    '("web2py"           . "{{")
   1450    '("xoops"            . "<{[[:alpha:]#$/*\"]")
   1451    '("svelte"           . "{.")
   1452    )
   1453   "Engine regexps used to identify blocks.")
   1454 
   1455 (defvar web-mode-normalization-rules
   1456   '(("tag-case"          . "lower-case")
   1457     ("attr-case"         . "lower-case")
   1458     ("special-chars"     . "unicode") ;"unicode" "entities"
   1459     ("css-indentation"   . t)
   1460     ("smart-apostrophes" . t)
   1461     ("smart-quotes"      . t)
   1462     ("whitespaces"       . t)
   1463     ("indentation"       . t))
   1464   "Normalization rules")
   1465 
   1466 (defvar web-mode-element-tag-faces
   1467   (list
   1468    '("h1"     . web-mode-underline-face)
   1469    '("h2"     . web-mode-underline-face)
   1470    '("h3"     . web-mode-underline-face)
   1471    '("h4"     . web-mode-underline-face)
   1472    '("title"  . web-mode-underline-face)
   1473    '("em"     . web-mode-italic-face)
   1474    '("strong" . web-mode-bold-face)
   1475    ))
   1476 
   1477 (defvar web-mode-element-content-faces
   1478   (list
   1479    '("h1"     . web-mode-underline-face)
   1480    '("h2"     . web-mode-underline-face)
   1481    '("h3"     . web-mode-underline-face)
   1482    '("h4"     . web-mode-underline-face)
   1483    '("title"  . web-mode-underline-face)
   1484    '("em"     . web-mode-italic-face)
   1485    '("strong" . web-mode-bold-face)
   1486    ))
   1487 
   1488 (defvar web-mode-comment-keywords
   1489   (regexp-opt
   1490    (append
   1491     (cdr (assoc "comment" web-mode-extra-keywords))
   1492     '("FIXME" "TODO" "BUG" "KLUDGE" "WORKAROUND" "OPTIMIZE" "HACK" "REFACTOR" "REVIEW"))))
   1493 
   1494 (defvar web-mode-links
   1495   '(("\\.\\(png\\|jpe?g\\|gif\\|webp\\)$" "<img src=\"%s\" alt=\"\" />" nil 4)
   1496     ("\\.svg$" "<object data=\"%s\" type=\"image/svg+xml\"></object>" nil 0)
   1497     ("\\.js$" "<script type=\"text/javascript\" src=\"%s\"></script>" t 0)
   1498     ("\\.css$" "<link rel=\"stylesheet\" type=\"text/css\" href=\"%s\" />" t 0)
   1499     ("\\.html?$" "<a href=\"%s\"></a>" nil 4))
   1500   "List of elements and extensions for `web-mode-file-link'. It
   1501 consists of a string that contains the regular expression that
   1502 matches the appropriate files, a format string with element that
   1503 contains the link (%s should be put where the path goes,) a bool
   1504 that tells if the element belongs in the <head> element, and
   1505 number of characters to move back if needed (or 0 if point
   1506 shouldn't be moved back.)")
   1507 
   1508 (defvar web-mode-sql-queries
   1509   (regexp-opt
   1510    '("SELECT" "INSERT" "UPDATE" "DELETE" "select" "insert" "update" "delete")))
   1511 
   1512 (defvar web-mode-sql-keywords
   1513   (regexp-opt
   1514    (append
   1515     (cdr (assoc "sql" web-mode-extra-keywords))
   1516     '("SELECT" "INSERT" "UPDATE" "DELETE"
   1517       "FROM" "WHERE" "GROUP BY" "LIKE" "LIMIT" "HAVING" "JOIN" "LEFT" "INNER"
   1518       "FULL" "OUTER" "VALUES" "ORDER BY" "SEPARATOR" "ASC" "DESC"
   1519       "AND" "OR" "ON" "WHEN" "ELSE" "END" "THEN"))))
   1520 
   1521 (defvar web-mode-python-constants
   1522   (regexp-opt
   1523    (append
   1524     (cdr (assoc "python" web-mode-extra-constants))
   1525     '("True" "False" "None" "__debug__" "NotImplemented" "Ellipsis"))))
   1526 
   1527 (defvar web-mode-elixir-keywords
   1528   (regexp-opt
   1529    (append
   1530     (cdr (assoc "elixir" web-mode-extra-keywords))
   1531     '("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"))))
   1532 
   1533 
   1534 (defvar web-mode-elixir-constants
   1535   (regexp-opt
   1536    (append
   1537     (cdr (assoc "elixir" web-mode-extra-constants))
   1538     '("nil" "true" "false"))))
   1539 
   1540 (defvar web-mode-erlang-constants
   1541   (regexp-opt
   1542    (append
   1543     (cdr (assoc "erlang" web-mode-extra-constants))
   1544     '("true" "false"))))
   1545 
   1546 (defvar web-mode-erlang-keywords
   1547   (regexp-opt
   1548    (append
   1549     (cdr (assoc "erlang" web-mode-extra-keywords))
   1550     '("else" "if" "do" "end"))))
   1551 
   1552 (defvar web-mode-cl-emb-constants
   1553   (regexp-opt
   1554    '("nil" "t" "raw" "escape")))
   1555 
   1556 (defvar web-mode-cl-emb-keywords
   1557   (regexp-opt
   1558    '("if" "else" "endif" "unless" "endunless" "var" "repeat"
   1559      "endrepeat" "loop" "endloop" "include" "call" "with"
   1560      "endwith" "set" "genloop" "endgenloop" "insert")))
   1561 
   1562 (defvar web-mode-artanis-constants
   1563   (regexp-opt
   1564    '("#f" "#t")))
   1565 
   1566 (defvar web-mode-artanis-keywords
   1567   (regexp-opt
   1568    (append
   1569     (cdr (assoc "artanis" web-mode-extra-keywords))
   1570     '("begin" "cut" "cute" "if" "when" "unless" "cond" "case"
   1571       "do" "quote" "syntax" "lambda" "lambda*" "and" "and-let*"
   1572       "or" "else" "delay" "receive" "use-modules" "match"
   1573       "match-lambda" "match-lambda*" "match-let" "match-let*"
   1574       "match-letrec" "let" "let*" "letrec" "letrec*" "and-let*"
   1575       "let-syntax" "letrec-syntax" "syntax-rules" "syntax-case"
   1576       "define" "define-syntax" "define-macro"
   1577       "define-condition-type" "define-immutable-record-type"
   1578       "define-record-type" "define-values" "parameterize" "for-each"
   1579       "require-extension" "set!" "test-approximate" "test-assert"
   1580       "test-begin" "test-end" "test-eq" "test-equal" "test-eqv"
   1581       "test-error" "test-group" "test-group-with-cleanup" "test-with-runner"))))
   1582 
   1583 (defvar web-mode-lsp-constants
   1584   (regexp-opt
   1585    '("nil" "t")))
   1586 
   1587 (defvar web-mode-lsp-keywords
   1588   (regexp-opt
   1589    '("dolist" "let" "while" "cond" "when" "progn" "if"
   1590      "dotimes" "unless" "lambda"
   1591      "loop" "for" "and" "or" "in" "do" "defun")))
   1592 
   1593 (defvar web-mode-php-constants
   1594   (regexp-opt
   1595    (append
   1596     (cdr (assoc "php" web-mode-extra-constants))
   1597     '("TRUE" "FALSE" "NULL" "true" "false" "null"
   1598       "STR_PAD_LEFT" "STR_PAD_RIGHT"
   1599       "ENT_COMPAT" "ENT_QUOTES" "ENT_NOQUOTES" "ENT_IGNORE"
   1600       "ENT_SUBSTITUTE" "ENT_DISALLOWED" "ENT_HTML401" "ENT_XML1"
   1601       "ENT_XHTML" "ENT_HTML5" "JSON_PRETTY_PRINT" "JSON_UNESCAPED_SLASHES"
   1602       "LIBXML_NOBLANKS"))))
   1603 
   1604 (defvar web-mode-php-keywords
   1605   (regexp-opt
   1606    (append
   1607     (cdr (assoc "php" web-mode-extra-keywords))
   1608     '("abstract" "and" "array" "as" "break" "case" "catch" "class" "clone"
   1609       "const" "continue" "declare" "default" "die" "do" "echo" "else" "elseif"
   1610       "empty" "enddeclare" "endfor" "endforeach" "endif" "endswitch" "endwhile"
   1611       "eval" "exit" "extends" "final" "finally" "fn" "for" "foreach" "function"
   1612       "global" "goto" "if" "implements" "include" "include_once" "instanceof"
   1613       "insteadof" "interface" "isset" "list" "namespace" "new" "or" "parent"
   1614       "print" "private" "protected" "public" "require" "require_once" "return"
   1615       "self" "static" "switch" "trait" "try" "throw" "unset" "use" "var"
   1616       "while" "xor" "yield" "yield from"))))
   1617 
   1618 (defvar web-mode-php-types
   1619   (eval-when-compile
   1620     (regexp-opt
   1621      '("array" "bool" "boolean" "callable" "float" "int" "integer"
   1622        "iterable" "mixed" "object" "resource" "string" "void"))))
   1623 
   1624 (defvar web-mode-css-at-rules
   1625   (eval-when-compile
   1626     (regexp-opt
   1627      '("charset" "import" "media" "page" "font-face"
   1628        "namespace" "supports" "document"
   1629        "keyframes" "-moz-keyframes" "-webkit-keyframes"
   1630        "mixin" "viewport"))))
   1631 
   1632 (defvar web-mode-css-pseudo-classes
   1633   (eval-when-compile
   1634     (regexp-opt
   1635      '("active" "after" "before" "checked" "disabled" "empty" "enabled"
   1636        "first" "first-child" "first-letter" "first-line" "first-of-type" "focus"
   1637        "hover" "lang" "last-child" "last-of-type" "left" "link"
   1638        "not" "nth-child" "nth-last-child" "nth-last-of-type" "nth-of-type"
   1639        "only-child" "only-of-type"
   1640        "right" "root" "selection" "target" "visited"))))
   1641 
   1642 (defvar web-mode-python-keywords
   1643   (regexp-opt
   1644    (append
   1645     (cdr (assoc "python" web-mode-extra-keywords))
   1646     '("and" "as" "assert" "break" "class" "continue" "def" "del"
   1647       "elif" "else" "except" "finally" "for" "from" "global"
   1648       "if" "import" "in" "is" "lambda" "nonlocal" "not" "or" "pass"
   1649       "raise" "return" "try" "while" "with" "yield"))))
   1650 
   1651 (defvar web-mode-jsp-keywords
   1652   (regexp-opt
   1653    (append
   1654     (cdr (assoc "jsp" web-mode-extra-keywords))
   1655     '("case" "catch" "do" "else" "end" "false" "for" "function"
   1656       "if" "in" "include"
   1657       "new" "package" "page" "private" "protected" "public"
   1658       "return" "tag" "taglib" "throw" "throws" "true" "try" "void" "while"))))
   1659 
   1660 (defvar web-mode-erb-keywords
   1661   (regexp-opt
   1662    (append
   1663     (cdr (assoc "erb" web-mode-extra-keywords))
   1664     '("alias" "and" "begin" "break" "case" "class" "def" "defined?" "do"
   1665       "elsif" "else" "end" "ensure" "fail" "for" "if" "in"
   1666       "module" "next" "not" "or" "redo" "rescue" "retry" "return"
   1667       "then" "super" "unless" "undef" "until" "when" "while" "yield"
   1668       "__ENCODING__" "__FILE__" "__LINE__"))))
   1669 
   1670 (defvar web-mode-mason-keywords
   1671   (regexp-opt
   1672    (append
   1673     (cdr (assoc "mason" web-mode-extra-keywords))
   1674     '("and" "base" "close" "die" "each" "else" "elsif" "eval" "exists"
   1675       "foreach" "grep" "if" "length" "local" "my" "next" "open" "or"
   1676       "package" "pop" "ref" "return" "stat" "sub" "tie"
   1677       "undef" "unless" "use" "while"))))
   1678 
   1679 (defvar web-mode-erb-builtins
   1680   (regexp-opt
   1681    (append
   1682     (cdr (assoc "erb" web-mode-extra-builtins))
   1683 
   1684     '("__callee__" "__dir__" "__method__"
   1685       "abort" "at_exit" "autoload" "autoload?"
   1686       "binding" "block_given?" "caller" "catch"
   1687       "eval" "exec" "exit" "exit!" "fail" "fork" "format"
   1688       "lambda" "load" "loop" "open"
   1689       "p" "print" "printf" "proc" "putc" "puts"
   1690       "raise" "rand" "readline" "readlines" "require" "require_relative"
   1691       "sleep" "spawn" "sprintf" "srand" "syscall" "system"
   1692       "throw" "trap" "warn"
   1693       "alias_method" "attr" "attr_accessor" "attr_reader" "attr_writer"
   1694       "define_method" "extend" "include" "module_function"
   1695       "prepend" "private" "protected" "public"
   1696       "refine" "using"
   1697 
   1698       "error_message_on" "error_messages_for" "form" "input"
   1699       "auto_discovery_link_tag" "image_tag" "javascript_include_tag"
   1700       "stylesheet_link_tag" "image_path" "path_to_image"" "
   1701       "javascript_path" "path_to_javascript" "register_javascript_expansion"
   1702       "register_javascript_include_default" "register_stylesheet_expansion"
   1703       "stylesheet_path" "path_to_stylesheet" "atom_feed" "entry" "updated"
   1704       "benchmark" "cache" "capture" "content_for" "distance_of_time_in_words"
   1705       "distance_of_time_in_words_to_now" "time_ago_in_words" "date_select"
   1706       "datetime_select" "time_select" "select_date" "select_datetime"
   1707       "select_day" "select_hour" "select_minute" "select_month" "select_second"
   1708       "select_time" "select_year" "debug"
   1709       "check_box" "fields_for" "file_field" "form_for" "hidden_field"
   1710       "label" "password_field" "radio_button" "text_area" "text_field"
   1711       "check_box_tag" "field_set_tag" "file_field_tag" "form_with" "form_tag"
   1712       "hidden_field_tag" "image_submit_tag" "label_tag" "password_field_tag"
   1713       "radio_button_tag" "select_tag" "submit_tag" "text_area_tag"
   1714       "text_field_tag"
   1715       "collection_select" "country_options_for_select" "country_select"
   1716       "option_groups_from_collection_for_select" "options_for_select"
   1717       "options_from_collection_for_select" "select"
   1718       "time_zone_options_for_select"
   1719       "time_zone_select" "button_to_function" "define_javascript_functions"
   1720       "escape_javascript" "javascript_tag" "link_to_function"" "
   1721       "number_to_currency" "number_to_human_size" "number_to_percentage"
   1722       "number_to_phone" "number_with_delimiter" "number_with_precision"
   1723       "evaluate_remote_response" "form_remote_for" "form_remote_tag"
   1724       "link_to_remote" "observe_field" "observe_field"
   1725       "periodically_call_remote"
   1726       "remote_form_for" "remote_function" "submit_to_remote" "update_page"
   1727       "update_page_tag" "dom_class" "dom_id" "partial_path" "sanitize"
   1728       "sanitize_css" "strip_links" "strip_tags"
   1729       "cdata_section" "content_tag" "escape_once" "tag"
   1730       "auto_link" "concat" "cycle" "excerpt" "highlight" "markdown" "pluralize"
   1731       "reset_cycle" "simple_format" "textilize" "textilize_without_paragraph"
   1732       "truncate" "word_wrap" "button_to" "current_page?" "link_to" "link_to_if"
   1733       "link_to_unless" "link_to_unless_current" "mail_to" "url_for"
   1734       "action_name" "atom_feed" "audio_path" "audio_tag"
   1735       "content_tag_for" "controller" "controller_name" "action_name"
   1736       "controller_path" "convert_to_model" "cookies" "csrf_meta_tag"
   1737       "csrf_meta_tags" "headers"
   1738       "current_cycle" "div_for" "email_field" "email_field_tag"
   1739       "favicon_link_tag" "flash" "l" "button_tag"
   1740       "grouped_collection_select" "grouped_options_for_select"
   1741       "image_alt" "j" "javascript_cdata_section"
   1742       "localize" "logger" "number_field"
   1743       "number_field_tag" "number_to_human" "params" "path_to_audio"
   1744       "path_to_video" "phone_field" "phone_field_tag" "provide"
   1745       "range_field" "range_field_tag" "raw" "render" "render_to_string" "request"
   1746       "request_forgery_protection_token" "response" "safe_concat"
   1747       "safe_join" "search_field" "search_field_tag"
   1748       "session" "t" "telephone_field" "telephone_field_tag"
   1749       "time_tag" "translate" "url_field" "url_field_tag"
   1750       "url_options" "video_path" "video_tag" "simple_form_for"
   1751       "javascript_pack_tag" "stylesheet_pack_tag" "csp_meta_tag"
   1752 
   1753       ))))
   1754 
   1755 (defvar web-mode-asp-constants
   1756   (regexp-opt
   1757    (append
   1758     (cdr (assoc "asp" web-mode-extra-constants))
   1759     '("adAsyncExecute" "adAsyncFetch" "adAsyncFetchNonBlocking" "adCmdFile"
   1760       "adCmdStoredProc" "adCmdTable" "adCmdTableDirect" "adCmdText" "adCmdUnknown"
   1761       "adCmdUnspecified" "adExecuteNoRecords" "adExecuteRecord" "adExecuteStream"
   1762       "adLockBatchOptimistic" "adLockOptimistic" "adLockPessimistic"
   1763       "adLockReadOnly" "adLockUnspecified" "adOpenDynamic" "adOpenForwardOnly"
   1764       "adOpenKeyset" "adOpenStatic" "adOpenUnspecified" "adOptionUnspecified"
   1765       "Empty" "Nothing" "Null" "True" "False"
   1766       "vbBack" "vbCr" "vbCrLf" "vbFormFeed" "vbLf" "vbNewLine" "vbNullChar"
   1767       "vbNullString" "vbObjectError" "vbScript" "vbTab" "vbVerticalTab"))))
   1768 
   1769 (defvar web-mode-asp-keywords
   1770   (regexp-opt
   1771    (append
   1772     (cdr (assoc "asp" web-mode-extra-keywords))
   1773     '("Abs" "And" "Array" "Asc" "Atn"
   1774       "CBool" "CByte" "CCur" "CDate" "CDbl" "CInt" "CLng" "CSng" "CStr"
   1775       "Call" "Case" "Chr" "Class" "Const" "Cos" "CreateObject"
   1776       "Date" "DateAdd" "DateDiff" "DatePart" "DateSerial" "DateValue"
   1777       "Day" "Dim" "Do"
   1778       "Each" "Else" "ElseIf" "End" "Erase" "Err" "Eval" "Exit" "Exp"
   1779       "Explicit"
   1780       "Filter" "Fix" "For" "FormatCurrency" "FormatDateTime"
   1781       "FormatNumber" "FormatPercent" "Function"
   1782       "GetLocale" "GetObject" "GetRef" "Hex" "Hour"
   1783       "If" "In" "InStr" "InStrRev" "InputBox" "Int" "IsArray" "IsDate"
   1784       "IsEmpty" "IsNull" "IsNumeric" "IsObject" "Join"
   1785       "LBound" "LCase" "LTrim" "Language" "Left" "Len" "Let"
   1786       "LoadPicture" "Log" "Loop"
   1787       "Mid" "Minute" "Month" "MonthName" "MsgBox"
   1788       "New" "Next" "Not" "Now"
   1789       "Oct" "On" "Option" "Or" "Preserve" "Private" "Public"
   1790       "RGB" "RTrim" "Redim" "Rem" "Replace" "Right" "Rnd" "Round"
   1791       "ScriptEngine" "ScriptEngineBuildVersion"
   1792       "ScriptEngineMajorVersion" "ScriptEngineMinorVersion"
   1793       "Second" "Select" "Set" "SetLocale" "Sgn" "Sin" "Space" "Split"
   1794       "Sqr" "StrComp" "StrReverse" "String" "Sub"
   1795       "Tan" "Then" "Time" "TimeSerial" "TimeValue" "Timer" "To" "Trim"
   1796       "TypeName"
   1797       "UBound" "UCase" "Until" "VarType"
   1798       "Weekday" "WeekdayName" "Wend" "With" "While" "Year"))))
   1799 
   1800 (defvar web-mode-asp-types
   1801   (regexp-opt
   1802    (append
   1803     (cdr (assoc "asp" web-mode-extra-types))
   1804     '("Application" "ASPError" "Request" "Response" "Server" "Session"))))
   1805 
   1806 (defvar web-mode-aspx-keywords
   1807   (regexp-opt
   1808    (append
   1809     (cdr (assoc "aspx" web-mode-extra-keywords))
   1810     '("case" "catch" "do" "else" "end" "for" "foreach" "function"
   1811       "if" "in" "include" "new" "package" "page" "return"
   1812       "tag" "throw" "throws" "try" "while"))))
   1813 
   1814 (defvar web-mode-smarty-keywords
   1815   (regexp-opt '("as")))
   1816 
   1817 (defvar web-mode-velocity-keywords
   1818   (eval-when-compile
   1819     (regexp-opt '("in" "true" "false"))))
   1820 
   1821 (defvar web-mode-freemarker-keywords
   1822   (eval-when-compile
   1823     (regexp-opt '("as" "list"))))
   1824 
   1825 (defvar web-mode-go-keywords
   1826   (eval-when-compile
   1827     (regexp-opt
   1828      '("const" "define" "else" "end"
   1829        "for" "func" "if" "import"
   1830        "pipeline" "range" "return" "struct"
   1831        "template" "type" "var" "with"))))
   1832 
   1833 (defvar web-mode-go-functions
   1834   (eval-when-compile
   1835     (regexp-opt
   1836      '("and" "call" "ge" "html" "index" "js" "len" "not" "or"
   1837        "print" "printf" "println" "urlquery" "where"))))
   1838 
   1839 (defvar web-mode-go-types
   1840   (regexp-opt
   1841    (append
   1842     (cdr (assoc "go" web-mode-extra-types))
   1843     '("int" "string"))))
   1844 
   1845 (defvar web-mode-closure-keywords
   1846   (eval-when-compile
   1847     (regexp-opt '("in" "and" "not" "or"))))
   1848 
   1849 (defvar web-mode-svelte-keywords
   1850   (regexp-opt '("as")))
   1851 
   1852 (defvar web-mode-django-control-blocks
   1853   (append
   1854    (cdr (assoc "django" web-mode-extra-control-blocks))
   1855    '(
   1856 
   1857      "assets" "autoescape"
   1858      "block" "blocktrans" "blocktranslate"
   1859      "cache" "call" "capture" "comment"
   1860      "draw"
   1861      "embed"
   1862      "filter" "for" "foreach" "form"
   1863      "if" "ifchanged" "ifequal" "ifnotequal"
   1864      "macro"
   1865      "random" "raw"
   1866      "safe" "sandbox" "spaceless"
   1867      "tablerow"
   1868      "unless"
   1869      "verbatim"
   1870      "with"
   1871 
   1872      "endassets" "endautoescape"
   1873      "endblock" "endblocktrans" "endblocktranslate"
   1874      "endcache" "endcall" "endcapture" "endcomment"
   1875      "draw"
   1876      "endembed"
   1877      "endfilter" "endfor" "endforeach" "endform"
   1878      "endif" "endifchanged" "endifequal" "endifnotequal"
   1879      "endmacro"
   1880      "endrandom" "endraw"
   1881      "endsafe" "endsandbox" "endspaceless"
   1882      "endtablerow"
   1883      "endunless"
   1884      "endverbatim"
   1885      "endwith"
   1886 
   1887      ;; "set" "endset" ;#504
   1888 
   1889      "csrf_token" "cycle" "debug"
   1890      "elif" "else" "elseif" "elsif" "empty" "extends"
   1891      "firstof" "include" "load" "lorem" "now" "regroup" "ssi"
   1892      "trans" "templatetag" "url" "widthratio"
   1893 
   1894      ;; #805
   1895      "graph" "endgraph"
   1896      "javascript" "endjavascript"
   1897      "schema" "endschema"
   1898      "stylesheet" "endstylesheet"
   1899 
   1900      )))
   1901 
   1902 (defvar web-mode-django-control-blocks-regexp
   1903   (regexp-opt web-mode-django-control-blocks t))
   1904 
   1905 (defvar web-mode-django-keywords
   1906   (eval-when-compile
   1907     (regexp-opt
   1908      '("and" "as" "assign"
   1909        "break"
   1910        "cache" "call" "case" "context" "continue"
   1911        "do"
   1912        "flush" "from"
   1913        "ignore" "import" "in" "is"
   1914        "layout" "load"
   1915        "missing"
   1916        "none" "not"
   1917        "or"
   1918        "pluralize"
   1919        "random"
   1920        "set" ;#504
   1921        "unless" "use"
   1922        "var"
   1923        ))))
   1924 
   1925 (defvar web-mode-django-types
   1926   (eval-when-compile
   1927     (regexp-opt '("null" "false" "true"))))
   1928 
   1929 (defvar web-mode-blade-control-blocks
   1930   (append
   1931    (cdr (assoc "blade" web-mode-extra-control-blocks))
   1932    '("component" "foreach" "forelse" "for" "if" "section" "slot" "switch" "unless" "while")
   1933    ))
   1934 
   1935 (defvar web-mode-blade-control-blocks-regexp
   1936   (regexp-opt web-mode-blade-control-blocks t))
   1937 
   1938 (defvar web-mode-directives
   1939   (eval-when-compile
   1940     (regexp-opt
   1941      '("include" "page" "taglib"
   1942        "Assembly" "Control" "Implements" "Import"
   1943        "Master" "OutputCache" "Page" "Reference" "Register"))))
   1944 
   1945 (defvar web-mode-template-toolkit-keywords
   1946   (regexp-opt
   1947    '("block" "call" "case" "catch" "clear" "default" "do"
   1948      "else" "elsif" "end" "filter" "final" "for"
   1949      "foreach" "get" "if" "in" "include" "insert" "is" "last"
   1950      "macro" "meta" "or" "perl" "process" "rawperl" "return"
   1951      "set" "stop" "switch" "tags" "throw" "try"
   1952      "unless" "use" "while" "wrapper")))
   1953 
   1954 (defvar web-mode-perl-keywords
   1955   (regexp-opt
   1956    '("__DATA__" "__END__" "__FILE__" "__LINE__" "__PACKAGE__"
   1957      "and" "cmp" "continue" "CORE" "do" "else" "elsif" "eq" "exp"
   1958      "for" "foreach" "ge" "gt" "if" "le" "lock" "lt" "m" "ne" "no"
   1959      "or" "package" "q" "qq" "qr" "qw" "qx" "s" "sub"
   1960      "tr" "unless" "until" "while" "xor" "y"
   1961      "my" "use" "print" "say")))
   1962 
   1963 (defvar web-mode-javascript-keywords
   1964   (regexp-opt
   1965    (append
   1966     (cdr (assoc "javascript" web-mode-extra-keywords))
   1967     '("as" "async" "await" "break" "case" "catch" "class" "const" "continue"
   1968       "debugger" "default" "delete" "do" "else" "enum" "eval"
   1969       "export" "extends" "finally" "for" "from" "function" "get" "if"
   1970       "implements" "import" "in" "instanceof" "interface" "let"
   1971       "new" "of" "package" "private" "protected" "public"
   1972       "return" "set" "static" "super" "switch"
   1973       "throw" "try" "type" "typeof" "var" "void" "while" "with" "yield"))))
   1974 
   1975 (defvar web-mode-javascript-constants
   1976   (regexp-opt
   1977    '("false" "null" "undefined" "Infinity" "NaN" "true" "arguments" "this")))
   1978 
   1979 (defvar web-mode-razor-keywords
   1980   (regexp-opt
   1981    (append
   1982     (cdr (assoc "razor" web-mode-extra-keywords))
   1983     '("false" "true" "foreach" "if" "else" "in" "var" "for" "display"
   1984       "match" "case" "to"
   1985       "Html"))))
   1986 
   1987 (defvar web-mode-selector-font-lock-keywords
   1988   (list
   1989    '("$[[:alnum:]-]+" 0 'web-mode-css-variable-face)
   1990    (cons (concat "@\\(" web-mode-css-at-rules "\\)\\_>")
   1991          '(0 'web-mode-css-at-rule-face))
   1992    '("\\_<\\(all\|braille\\|embossed\\|handheld\\|print\\|projection\\|screen\\|speech\\|tty\\|tv\\|and\\|or\\)\\_>"
   1993      1 'web-mode-keyword-face)
   1994    '("\\.[^ ,]+" 0 'web-mode-css-selector-class-face)
   1995    '("[^,]+" 0 'web-mode-css-selector-tag-face)
   1996    (cons (concat ":\\([ ]*[[:alpha:]][^,{]*\\)") '(0 'web-mode-css-pseudo-class-face t t))
   1997    ))
   1998 
   1999 (defvar web-mode-declaration-font-lock-keywords
   2000   (list
   2001    '("--[[:alnum:]-]+" 0 'web-mode-css-variable-face)
   2002    '("$[[:alnum:]-]+" 0 'web-mode-css-variable-face)
   2003    (cons (concat "@\\(" web-mode-css-at-rules "\\)\\_>") '(1 'web-mode-css-at-rule-face))
   2004    '("\\([[:alpha:]-]+\\)[ ]?:" 0 'web-mode-css-property-name-face)
   2005    '("\\([[:alpha:]-]+\\)[ ]?(" 1 'web-mode-css-function-face)
   2006    '("#[[:alnum:]]\\{1,6\\}" 0 'web-mode-css-color-face t t)
   2007    '("![ ]?important" 0 'web-mode-css-priority-face t t)
   2008    '("\\([^,]+\\)[ ]+{" 1 'web-mode-css-selector-face)
   2009    '("'[^']*'\\|\"[^\"]*\"" 0 'web-mode-string-face t t)
   2010    ))
   2011 
   2012 (defvar web-mode-html-font-lock-keywords
   2013   (list
   2014    '("</?[[:alnum:]]+[ >]\\|>" 0 'web-mode-html-tag-face t)
   2015    '(" \\([[:alnum:]-]+=\\)\\(\"[^\"]+\"\\)"
   2016      (1 'web-mode-html-attr-name-face)
   2017      (2 'web-mode-html-attr-value-face))
   2018    ))
   2019 
   2020 ;; voir https://www.gnu.org/software/emacs/manual/html_node/elisp/Search_002dbased-Fontification.html
   2021 (defvar web-mode-javascript-font-lock-keywords
   2022   (list
   2023    '("@\\([[:alnum:]_]+\\)\\_>" 0 'web-mode-keyword-face)
   2024    '("\\([[:alnum:]]+\\)[`]" 0 'web-mode-preprocessor-face)
   2025    (cons (concat "\\_<\\(function\\*\\)\\_>") '(1 'web-mode-keyword-face))
   2026    (cons (concat "\\([ \t}{(]\\|^\\)\\(" web-mode-javascript-keywords "\\)\\_>") '(2 'web-mode-keyword-face))
   2027    (cons (concat "\\_<\\(" web-mode-javascript-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2028    '("\\_<\\([$]\\)(" 1 'web-mode-type-face)
   2029    '("\\_<\\(new\\|instanceof\\|class\\|extends\\|import\\) \\([[:alnum:]_.]+\\)\\_>" 2 'web-mode-type-face)
   2030    '("\\_<\\([[:alnum:]_]+\\):[ ]*function[ ]*(" 1 'web-mode-function-name-face)
   2031    '("\\_<\\(function\\|get\\|set\\)[ ]+\\([[:alnum:]_]+\\)"
   2032      (1 'web-mode-keyword-face)
   2033      (2 'web-mode-function-name-face))
   2034    '("\\([[:alnum:]_]+\\)[ ]*([^)]*)[ \n]*{" 1 'web-mode-function-name-face)
   2035    '("([ ]*\\([[:alnum:]_]+\\)[ ]*=>" 1 'web-mode-function-name-face)
   2036    '("[ ]*\\([[:alnum:]_]+\\)[ ]*=[ ]*([^)]*)[ ]*=>[ ]*{" 1 'web-mode-function-name-face)
   2037    '("\\_<\\(var\\|let\\|const\\)[ ]+\\([[:alnum:]_]+\\)" 2 'web-mode-variable-name-face)
   2038    '("({" "\\([[:alnum:]_]+\\)[, }]+" nil nil (1 'web-mode-variable-name-face)) ;#738
   2039    '("\\([[:alnum:]_]+\\)[ ]*=> [{(]" 1 'web-mode-variable-name-face)
   2040    ;; #989
   2041    ;; '("\\(function\\|[,=]\\|^\\)[ ]*("
   2042    ;;   ("\\([[:alnum:]_]+\\)\\([ ]*=[^,)]*\\)?[,)]" nil nil (1 'web-mode-variable-name-face)))
   2043    '("\\([[:alnum:]_]+\\):" 1 'web-mode-variable-name-face)
   2044    '("\\_<\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2045    '("[a-zA-Z]<\\([a-zA-Z]+\\)[,>]" 1 'web-mode-type-face)
   2046    ))
   2047 
   2048 (defvar web-mode-stylus-font-lock-keywords
   2049   (list
   2050    '("^[ \t]*\\([[:alnum:]().-]+\\)$" 1 'web-mode-css-selector-face)
   2051    '("^[ \t]*\\([[:alnum:]-]+[ ]*:\\)" 1 'web-mode-css-property-name-face)
   2052    ))
   2053 
   2054 (defvar web-mode-sass-font-lock-keywords
   2055   (list
   2056    '("^[ \t]*\\([[:alnum:]().-]+\\|&:\\(before\\|after\\)\\)$" 1 'web-mode-css-selector-face)
   2057    '("^[ \t]*\\([[:alnum:]-]+[ ]*:\\)" 1 'web-mode-css-property-name-face)
   2058    ))
   2059 
   2060 (defvar web-mode-pug-font-lock-keywords
   2061   (list
   2062    '("^[ \t]*\\(#?[[:alnum:].-]+\\)" 1 'web-mode-css-selector-face)
   2063    ;;'("^[ \t]*\\(#[[:alnum:]-]+\\)" 0 'web-mode-css-selector-face)
   2064    '(" \\([@:]?\\sw+[ ]?=\\)" 1 'web-mode-param-name-face)
   2065    ))
   2066 
   2067 (defvar web-mode-sql-font-lock-keywords
   2068   (list
   2069    (cons (concat "\\_<\\(" web-mode-sql-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2070    '("\\_<\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2071    ))
   2072 
   2073 (defvar web-mode-markdown-font-lock-keywords
   2074   (list
   2075    '("^[ ]*[*].*$" 0 'web-mode-variable-name-face)
   2076    '("^[ ]*#.*$" 0 'web-mode-comment-face)
   2077    ))
   2078 
   2079 (defvar web-mode-html-tag-font-lock-keywords
   2080   (list
   2081    '("\\(</?\\)\\([[:alnum:]]+\\)"
   2082      (1 'web-mode-html-tag-bracket-face)
   2083      (2 'web-mode-html-tag-face))
   2084    '("\"[^\"]*\"" 0 'web-mode-html-attr-value-face)
   2085    '("\\([[:alnum:]]+\\)" 1 'web-mode-html-attr-name-face)
   2086    '("/?>" 0 'web-mode-html-tag-bracket-face)
   2087    ))
   2088 
   2089 (defvar web-mode-anki-font-lock-keywords
   2090   (list
   2091    '("{{[#/^]\\([[:alnum:]_.]+\\)" 1 'web-mode-block-control-face)
   2092    ;;'("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_.: ]*\\)"
   2093    ;;  (1 'web-mode-block-attr-name-face)
   2094    ;;  (2 'web-mode-block-attr-value-face))
   2095    '("{{\\(.+\\)}}" 1 'web-mode-variable-name-face)
   2096    ))
   2097 
   2098 (defvar web-mode-dust-font-lock-keywords
   2099   (list
   2100    '("{[#:/?@><+^]\\([[:alpha:]_.]+\\)" 1 'web-mode-block-control-face)
   2101    '(":\\([[:alpha:]]+\\)" 1 'web-mode-keyword-face)
   2102    '("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_]*\\)"
   2103      (1 'web-mode-block-attr-name-face)
   2104      (2 'web-mode-block-attr-value-face))
   2105    '("\\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face)
   2106    ))
   2107 
   2108 (defvar web-mode-expressionengine-font-lock-keywords
   2109   (list
   2110    '("{/?\\([[:alpha:]_]+:[[:alpha:]_:]+\\|if\\)" 1 'web-mode-block-control-face)
   2111    '(":\\([[:alpha:]_]+\\)" 1 'web-mode-keyword-face)
   2112    '(" {\\([[:alpha:]_]+\\)}" 1 'web-mode-keyword-face t)
   2113    '("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_]*\\)"
   2114      (1 'web-mode-block-attr-name-face)
   2115      (2 'web-mode-block-attr-value-face))
   2116    '("\\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face)
   2117    ))
   2118 
   2119 (defvar web-mode-svelte-font-lock-keywords
   2120   (list
   2121    (cons (concat "[ ]\\(" web-mode-svelte-keywords "\\)[ ]") '(1 'web-mode-keyword-face))
   2122    '("{[#:/@]\\([[:alpha:]_.]+\\)" 1 'web-mode-block-control-face)
   2123    '("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_]*\\)"
   2124      (1 'web-mode-block-attr-name-face)
   2125      (2 'web-mode-block-attr-value-face))
   2126    '("\\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face)
   2127    '("\\_<\\([$]\\)\\([[:alnum:]_]+\\)" (1 'web-mode-constant-face) (2 'web-mode-variable-name-face))
   2128    ))
   2129 
   2130 (defvar web-mode-template-toolkit-font-lock-keywords
   2131   (list
   2132    (cons (concat "\\_<\\(" web-mode-template-toolkit-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2133    '("\\\([[:alpha:]][[:alnum:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2134    '("\\\([[:alpha:]][[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2135    ))
   2136 
   2137 (defvar web-mode-smarty-font-lock-keywords
   2138   (list
   2139    (cons (concat "[ ]\\(" web-mode-smarty-keywords "\\)[ ]") '(1 'web-mode-keyword-face))
   2140    '("{/?\\([[:alpha:]_]+\\)" 1 'web-mode-block-control-face)
   2141    '("\\([}{]\\)" 0 'web-mode-block-delimiter-face)
   2142    '("\\_<\\([$]\\)\\([[:alnum:]_]+\\)" (1 nil) (2 'web-mode-variable-name-face))
   2143    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2144    '(" \\(\\sw+[ ]?=\\)" 1 'web-mode-param-name-face)
   2145    '(" \\(\\sw+\\)[ }]" 1 'web-mode-param-name-face)
   2146    '("|\\([[:alnum:]_]+\\)" 1 'web-mode-function-call-face)
   2147    '("\\(->\\)\\(\\sw+\\)" (1 nil) (2 'web-mode-variable-name-face))
   2148    '("[.]\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2149    '("[.]\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2150    '("#\\([[:alnum:]_]+\\)#" 1 'web-mode-variable-name-face)
   2151    ))
   2152 
   2153 (defvar web-mode-velocity-font-lock-keywords
   2154   (list
   2155    '("#{?\\([[:alpha:]_]+\\)\\_>" (1 'web-mode-block-control-face))
   2156    (cons (concat "\\_<\\(" web-mode-velocity-keywords "\\)\\_>") '(1 'web-mode-keyword-face t t))
   2157    '("#macro([ ]*\\([[:alpha:]]+\\)[ ]+" 1 'web-mode-function-name-face)
   2158    '("\\(def\\|define\\) \\([[:alnum:]_-]+\\)(" 2 'web-mode-function-name-face)
   2159    '("[.]\\([[:alnum:]_-]+\\)" 1 'web-mode-variable-name-face)
   2160    '("\\_<\\($[!]?[{]?\\)\\([[:alnum:]_-]+\\)[}]?" (1 nil) (2 'web-mode-variable-name-face))
   2161    ))
   2162 
   2163 (defvar web-mode-mako-tag-font-lock-keywords
   2164   (list
   2165    '("</?%\\([[:alpha:]:]+\\)" 1 'web-mode-block-control-face)
   2166    '("\\_<\\([[:alpha:]]+=\\)\\(\"[^\"]*\"\\)"
   2167      (1 'web-mode-block-attr-name-face t t)
   2168      (2 'web-mode-block-attr-value-face t t))
   2169    ))
   2170 
   2171 (defvar web-mode-mako-block-font-lock-keywords
   2172   (list
   2173    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2174    (cons (concat "\\_<\\(" web-mode-python-constants "\\)\\_>") '(1 'web-mode-constant-face))
   2175    (cons (concat "\\_<\\(" web-mode-python-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2176    (cons (concat "\\_<\\(endfor\\|endif\\|endwhile\\)\\_>") '(1 'web-mode-keyword-face))
   2177    ))
   2178 
   2179 (defvar web-mode-web2py-font-lock-keywords
   2180   (list
   2181    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2182    (cons (concat "\\_<\\(" web-mode-python-constants "\\)\\_>") '(1 'web-mode-constant-face))
   2183    (cons (concat "\\_<\\(" web-mode-python-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2184    (cons (concat "\\_<\\(block\\|extend\\|super\\|end\\|include\\)\\_>") '(1 'web-mode-keyword-face))
   2185    ))
   2186 
   2187 (defvar web-mode-django-expr-font-lock-keywords
   2188   (list
   2189    '("|[ ]?\\([[:alpha:]_]+\\)\\_>" 1 'web-mode-filter-face)
   2190    (cons (concat "\\_<\\(" web-mode-django-types "\\)\\_>") '(1 'web-mode-type-face))
   2191    '("\\_<\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2192    '("[[:alnum:]_]+" 0 'web-mode-variable-name-face)
   2193    ))
   2194 
   2195 (defvar web-mode-django-code-font-lock-keywords
   2196   (list
   2197    '("{%[ ]*\\(set\\)[ ]+\\([[:alpha:]]+\\)[ ]*%}"
   2198      (1 'web-mode-block-control-face)
   2199      (2 'web-mode-variable-name-face))
   2200    (cons (concat "\\({%\\|#\\)[ ]*\\(" web-mode-django-control-blocks-regexp "\\)[ %]") '(2 'web-mode-block-control-face))
   2201    '("\\({%\\|#\\)[ ]*\\(end[[:alpha:]]+\\)\\_>" 2 'web-mode-block-control-face) ;#504
   2202    (cons (concat "\\_<\\(" web-mode-django-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2203    (cons (concat "\\_<\\(" web-mode-django-types "\\)\\_>") '(1 'web-mode-type-face))
   2204    '("|[ ]?\\([[:alpha:]_]+\\)\\_>" 1 'web-mode-function-call-face)
   2205    '("\\_<\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2206    '("[[:alnum:]_.]+" 0 'web-mode-variable-name-face)
   2207    '("[[:alnum:]_]+\\([.][[:alnum:]_]+\\)+" 0 'web-mode-variable-name-face t t)
   2208    ))
   2209 
   2210 (defvar web-mode-ctemplate-font-lock-keywords
   2211   (list
   2212    '("{[~]?{[#/>^]?[ ]*\\([[:alnum:]_.-]+\\)" 1 'web-mode-block-control-face)
   2213    '("[ \t]+\\([[:alnum:]_-]+\\)="
   2214      (1 'web-mode-block-attr-name-face))
   2215    '("\"[^\"]+\"" 0 'web-mode-block-string-face)
   2216    ))
   2217 
   2218 (defvar web-mode-astro-font-lock-keywords
   2219   (append
   2220    (list
   2221     '("\\({\\)\\([[:alpha:]]+\\)\\(}\\)"
   2222       (1 'web-mode-block-control-face)
   2223       (2 'web-mode-variable-name-face)
   2224       (3 'web-mode-block-control-face)))
   2225     web-mode-javascript-font-lock-keywords
   2226     ))
   2227 
   2228 (defvar web-mode-antlers-font-lock-keywords
   2229   (list
   2230    '("{{[ ]*\\(/?\\(if\\|elseif\\|else\\|unless\\|switch\\)\\)" 1 'web-mode-block-control-face)
   2231    '("[ \t]+\\(:?[[:alnum:]_-]+\\)=" (1 'web-mode-block-attr-name-face))
   2232    '("[[:alnum:]_.]+" 0 'web-mode-variable-name-face)
   2233    '("\"[^\"]+\"" 0 'web-mode-block-string-face)
   2234    '("'[^']+'" 0 'web-mode-block-string-face)
   2235    ))
   2236 
   2237 (defvar web-mode-razor-font-lock-keywords
   2238   (list
   2239    '("@\\([[:alnum:]_.]+\\)[ ]*[({]" 1 'web-mode-block-control-face)
   2240    (cons (concat "\\_<\\(" web-mode-razor-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2241    '("\\_<\\(String\\)\\_>" 1 'web-mode-type-face)
   2242    '("\\([[:alnum:]]+:\\)" 1 'web-mode-symbol-face)
   2243    '("\\(@[[:alnum:]_.]+\\)" 1 'web-mode-variable-name-face)
   2244    ))
   2245 
   2246 (defvar web-mode-riot-font-lock-keywords
   2247   (list
   2248    '("\\(parent\\|opts\\|tags\\|this\\)\\.\\([[:alnum:]_.]+\\)"
   2249      (1 'web-mode-constant-face)
   2250      (2 'web-mode-variable-name-face))
   2251    '("\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face)
   2252    ))
   2253 
   2254 (defvar web-mode-closure-font-lock-keywords
   2255   (list
   2256    '("{\\([@/]?[[:alpha:]]+[?]?\\)" 1 'web-mode-block-control-face)
   2257    '("{[@]?param[?]?[ ]+\\([[:alnum:]]+[:]?\\)" 1 'web-mode-symbol-face)
   2258    '("\\_<\\(true\\|false\\|null\\)\\_>" 1 'web-mode-type-face)
   2259    '("\\\_<[[:alpha:]]+:[ ]+\\([[:alpha:]]+\\)" 1 'web-mode-type-face)
   2260    (cons (concat "\\_<\\(" web-mode-closure-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2261    '("{\\(alias\\|call\\|delcall\\|delpackage\\|deltemplate\\|namespace\\|template\\)[ ]+\\([[:alnum:].]+\\)" 2 'web-mode-constant-face)
   2262    '("\\(allowemptydefault\\|data\\|desc\\|meaning\\|autoescape\\|private\\|variant\\)=" 0 'web-mode-block-attr-name-face)
   2263    '("|\\([[:alpha:]]+\\)" 1 'web-mode-function-call-face)
   2264    '("\\_<\\([[:alnum:]]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2265    '("$\\([[:alnum:]._]+\\)" 1 'web-mode-variable-name-face)
   2266    ))
   2267 
   2268 (defvar web-mode-go-font-lock-keywords
   2269   (list
   2270    '("{{[-]?[ ]*\\([[:alpha:]]+\\)" 1 'web-mode-block-control-face)
   2271    '("\\_<func \\([[:alnum:]]+\\)" 1 'web-mode-function-name-face)
   2272    '("\\_<type \\([[:alnum:]]+\\)" 1 'web-mode-type-face)
   2273    (cons (concat "\\_<\\(" web-mode-go-types "\\)\\_>") '(0 'web-mode-type-face))
   2274    (cons (concat "\\_<\\(" web-mode-go-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2275    (cons (concat "\\_<\\(" web-mode-go-functions "\\)\\_>") '(1 'web-mode-function-call-face))
   2276    '("[$.]\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face t t)
   2277    '("|[ ]?\\([[:alpha:]_]+\\)\\_>" 1 'web-mode-filter-face)
   2278    ))
   2279 
   2280 (defvar web-mode-expression-font-lock-keywords
   2281   (list
   2282    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2283    ))
   2284 
   2285 (defvar web-mode-angular-font-lock-keywords
   2286   (list
   2287    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2288    ))
   2289 
   2290 (defvar web-mode-underscore-font-lock-keywords
   2291   (list
   2292    (cons (concat "\\_<\\(" web-mode-javascript-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2293    '("\\_<\\(_\.[[:alpha:]]+\\)(" 1 'web-mode-function-call-face)
   2294    '("\\_<new \\([[:alnum:]_.]+\\)\\_>" 1 'web-mode-type-face)
   2295    '("\\_<\\([[:alnum:]_]+\\):[ ]*function[ ]*(" 1 'web-mode-function-name-face)
   2296    '("\\_<\\(var\\)\\_>[ ]+\\([[:alnum:]_]+\\)"
   2297      (1 'web-mode-keyword-face)
   2298      (2 'web-mode-variable-name-face))
   2299    ))
   2300 
   2301 (defvar web-mode-vue-font-lock-keywords
   2302   (list
   2303    '("\\_<\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2304    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2305    ))
   2306 
   2307 (defvar web-mode-engine-tag-font-lock-keywords
   2308   (list
   2309    '("</?\\([[:alpha:]]+\\(?:Template\\|[:.][[:alpha:]-]+\\)\\|TMPL_[[:alpha:]]+\\)" 1 'web-mode-block-control-face)
   2310    '("\\_<\\([[:alpha:]-]+=\\)\\(\"[^\"]*\"\\)"
   2311      (1 'web-mode-block-attr-name-face t t)
   2312      (2 'web-mode-block-attr-value-face t t))
   2313    '("\\_<\\([[:alpha:]-]+=\\)\\('[^']*\'\\)"
   2314      (1 'web-mode-block-attr-name-face t t)
   2315      (2 'web-mode-block-attr-value-face t t))
   2316    ))
   2317 
   2318 (defvar web-mode-jsp-font-lock-keywords
   2319   (list
   2320    '("\\(throws\\|new\\|extends\\)[ ]+\\([[:alnum:].]+\\)" 2 'web-mode-type-face)
   2321    (cons (concat "\\_<\\(" web-mode-jsp-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2322    '("\\(public\\|private\\)[ ]+\\([[:alpha:]]+\\)[ ]+\\([[:alnum:]._]+\\)[ ]?("
   2323      (2 'web-mode-type-face)
   2324      (3 'web-mode-function-name-face))
   2325    '("\\_<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2326    '("@\\(\\sw*\\)" 1 'web-mode-variable-name-face)
   2327    '("\\_<\\([[:alnum:].]+\\)[ ]+[{[:alpha:]]+" 1 'web-mode-type-face)
   2328    ))
   2329 
   2330 (defvar web-mode-asp-font-lock-keywords
   2331   (list
   2332    (cons (concat "\\_<\\(" web-mode-asp-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2333    (cons (concat "\\_<\\(" web-mode-asp-types "\\)\\_>") '(0 'web-mode-type-face))
   2334    (cons (concat "\\_<\\(" web-mode-asp-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2335    '("\\(Class\\|new\\) \\([[:alnum:]_]+\\)" 2 'web-mode-type-face)
   2336    '("Const \\([[:alnum:]_]+\\)" 1 'web-mode-constant-face)
   2337    '("\\_<dim\\_>"
   2338      (0 'web-mode-keyword-face)
   2339      ("[[:alnum:]_]+" nil nil (0 'web-mode-variable-name-face)))
   2340    '("\\_<\\(public\\|private\\|sub\\|function\\)\\_> \\([[:alnum:]_]+\\)[ ]*(" 2 'web-mode-function-name-face)
   2341    '("\\_<\\(public\\|private\\|dim\\)\\_> \\([[:alnum:]_]+\\)" 2 'web-mode-variable-name-face)
   2342    ))
   2343 
   2344 (defvar web-mode-aspx-font-lock-keywords
   2345   (list
   2346    (cons (concat "\\_<\\(" web-mode-aspx-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2347    '("\\_<\\([[:alnum:].]+\\)[ ]+[[:alpha:]]+" 1 'web-mode-type-face)
   2348    ))
   2349 
   2350 (defvar web-mode-uel-font-lock-keywords
   2351   (list
   2352    '("[$#{]{\\|}" 0 'web-mode-preprocessor-face)
   2353    '("\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2354    '("|[ ]*\\(trim\\|x\\|u\\)" 1 'web-mode-function-call-face)
   2355    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2356    ))
   2357 
   2358 (defvar web-mode-php-var-interpolation-font-lock-keywords
   2359   (list
   2360    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2361    '("\".+\"\\|'.*'" 0 'web-mode-string-face)
   2362    ))
   2363 
   2364 (defvar web-mode-marko-font-lock-keywords
   2365   (list
   2366    '("[[:alnum:]_]+" 0 'web-mode-variable-name-face)
   2367    ))
   2368 
   2369 (defvar web-mode-freemarker-square-font-lock-keywords
   2370   (list
   2371    '("\\[/?[#@]\\([[:alpha:]_.]*\\)" 1 'web-mode-block-control-face)
   2372    '("#\\(macro\\|function\\) \\([[:alpha:]]+\\)" 2 'web-mode-function-name-face)
   2373    (cons (concat "\\_<\\(" web-mode-freemarker-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2374    '("\\_<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2375    '("[[:alpha:]]\\([[:alnum:]_]+\\)?" 0 'web-mode-variable-name-face)
   2376    ))
   2377 
   2378 (defvar web-mode-freemarker-font-lock-keywords
   2379   (list
   2380    '("</?[#@]\\([[:alpha:]_.]*\\)" 1 'web-mode-block-control-face)
   2381    '("#\\(macro\\|function\\) \\([[:alpha:]]+\\)" 2 'web-mode-function-name-face)
   2382    (cons (concat "\\_<\\(" web-mode-freemarker-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2383    '("\\_<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2384    '("[[:alpha:]]\\([[:alnum:]_]+\\)?" 0 'web-mode-variable-name-face)
   2385    ))
   2386 
   2387 (defvar web-mode-directive-font-lock-keywords
   2388   (list
   2389    '("<%@[ ]*\\([[:alpha:]]+\\)[ ]+" 1 'web-mode-block-control-face)
   2390    '("\\_<\\([[:alpha:]]+=\\)\\(\"[^\"]*\"\\)"
   2391      (1 'web-mode-block-attr-name-face t t)
   2392      (2 'web-mode-block-attr-value-face t t))
   2393    ))
   2394 
   2395 (defvar web-mode-erb-font-lock-keywords
   2396   (list
   2397    '("[^:]\\(:[[:alnum:]_]+\\)" 1 'web-mode-symbol-face)
   2398    '("\\([[:alnum:]_]+:\\)[ ]+" 1 'web-mode-symbol-face)
   2399    (cons (concat "\\_<\\(" web-mode-erb-builtins "\\)\\_>") '(0 'web-mode-builtin-face))
   2400    (cons (concat "\\_<\\(" web-mode-erb-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2401    '("\\_<\\(self\\|true\\|false\\|nil\\)\\_>" 0 'web-mode-variable-name-face)
   2402    '("[@$]@?\\([[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2403    '("class[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-type-face)
   2404    '("def[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2405    '("\\(?:\\_<\\|::\\)\\([A-Z]+[[:alnum:]_]+\\)" 1 (unless (eq (char-after) ?\() 'web-mode-type-face))
   2406    '("/[^/]+/" 0 'web-mode-string-face)
   2407    ))
   2408 
   2409 (defvar web-mode-ejs-font-lock-keywords
   2410   web-mode-javascript-font-lock-keywords)
   2411 
   2412 (defvar web-mode-python-font-lock-keywords
   2413   (list
   2414    (cons (concat "\\_<\\(" web-mode-python-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2415    ))
   2416 
   2417 (defvar web-mode-elixir-font-lock-keywords
   2418   (list
   2419    '("@\\([[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2420    '("[ ]\\(:[[:alnum:]-_]+\\)" 1 'web-mode-symbol-face)
   2421    '("def[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2422    (cons (concat "\\_<\\(" web-mode-elixir-keywords "\\)\\_>") '(0 'web-mode-builtin-face))
   2423    (cons (concat "\\_<\\(" web-mode-elixir-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2424    ))
   2425 
   2426 (defvar web-mode-erlang-font-lock-keywords
   2427   (list
   2428    (cons (concat "\\_<\\(" web-mode-erlang-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2429    (cons (concat "\\_<\\(" web-mode-erlang-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2430    '("@\\([[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2431    '("[ ]\\(:[[:alnum:]-_]+\\)" 1 'web-mode-symbol-face)
   2432    ))
   2433 
   2434 (defvar web-mode-mason-code-font-lock-keywords
   2435   (list
   2436    (cons (concat "\\_<\\(" web-mode-mason-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2437    '("sub[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2438    '("\\_<\\([[:alnum:]_]+\\)[ ]?::" 1 'web-mode-type-face)
   2439    '("\\([@]\\)\\([[:alnum:]#_]*\\)" (1 nil) (2 'web-mode-variable-name-face))
   2440    '("\\_<\\([$%]\\)\\([[:alnum:]@#_]*\\)" (1 nil) (2 'web-mode-variable-name-face))
   2441    '("{\\([[:alnum:]_]+\\)}" 1 'web-mode-variable-name-face)
   2442    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2443    '("[[:alnum:]_][ ]?::[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2444    '("->[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2445    '("\\(?:method\\|def\\) \\([[:alnum:]._]+\\)" 1 'web-mode-function-name-face)
   2446    '("|[ ]*\\([[:alnum:],]+\\)[ ]*%>" 1 'web-mode-filter-face)
   2447    ))
   2448 
   2449 (defvar web-mode-mason-block-font-lock-keywords
   2450   (list
   2451    '("<[/]?%\\([[:alpha:]]+\\)" 1 'web-mode-block-control-face)
   2452    '("[[:alpha:]]" 0 'web-mode-block-attr-value-face)
   2453    ))
   2454 
   2455 (defvar web-mode-mojolicious-font-lock-keywords
   2456   (list
   2457    (cons (concat "\\_<\\(" web-mode-perl-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2458    '("\\_<\\(begin\\|end\\)\\_>" 1 'web-mode-constant-face)
   2459    '("\\_<\\([$]\\)\\([[:alnum:]_]*\\)" (1 nil) (2 'web-mode-variable-name-face))
   2460    ))
   2461 
   2462 (defvar web-mode-lsp-font-lock-keywords
   2463   (list
   2464    (cons (concat "\\_<\\(" web-mode-lsp-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2465    (cons (concat "\\_<\\(" web-mode-lsp-constants "\\)\\_>") '(1 'web-mode-constant-face))
   2466    '("[ ]\\(:[[:alnum:]-_]+\\)" 1 'web-mode-symbol-face)
   2467    '("(defun \\([[:alnum:]-:]+\\)" 1 'web-mode-function-name-face)
   2468    '("(defvar \\([[:alnum:]-:]+\\)" 1 'web-mode-variable-name-face)
   2469    ))
   2470 
   2471 (defvar web-mode-cl-emb-font-lock-keywords
   2472   (list
   2473    (cons (concat "\\_<\\(" web-mode-cl-emb-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2474    (cons (concat "\\_<\\(" web-mode-cl-emb-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2475    '("\\(@\\)" 1 'web-mode-function-call-face)
   2476    (list (concat "\\(@" web-mode-cl-emb-keywords "\\)[ ]+\\([[:alnum:]_]+\\)")
   2477          '(1 'web-mode-keyword-face)
   2478          '(2 'web-mode-variable-name-face))
   2479    ))
   2480 
   2481 (defvar web-mode-artanis-font-lock-keywords
   2482   (list
   2483    (cons (concat "\\_<\\(" web-mode-artanis-keywords  "\\)\\_>") '(0 'web-mode-keyword-face))
   2484    (cons (concat "\\_<\\(" web-mode-artanis-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2485    '("(define[*]? (\\([[:alnum:]-:_!#$%^&*=+/?<>.]+\\)" 1 'web-mode-function-name-face)
   2486    '("\\(#:[[:alnum:]-:_!#$%^&*=+/?<>.]+\\)"            1 'web-mode-builtin-face)
   2487    ))
   2488 
   2489 (defvar web-mode-php-font-lock-keywords
   2490   (list
   2491    (cons (concat "\\_<\\(" web-mode-php-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2492    (cons (concat "\\_<\\(" web-mode-php-types "\\)\\_>") '(1 'web-mode-type-face))
   2493    (cons (concat "\\(" web-mode-php-constants "\\)") '(0 'web-mode-constant-face))
   2494    '("function[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2495    '("\\_<\\([[:alnum:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2496    '("[[:alnum:]_][ ]?::[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-constant-face)
   2497    '("->[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2498    '("\\_<\\([[:alnum:]_]+\\)[ ]?::" 1 'web-mode-type-face)
   2499    '("\\_<\\(instanceof\\|class\\|extends\\|new\\)[ ]+\\([[:alnum:]_]+\\)" 2 'web-mode-type-face)
   2500    '("\\(\\_<\\|[+-]\\)\\([$]\\)\\([[:alnum:]_]*\\)" (2 nil) (3 'web-mode-variable-name-face))
   2501    ))
   2502 
   2503 (defvar web-mode-spip-font-lock-keywords
   2504   (list
   2505    '("<:.+:>" 0 'web-mode-block-string-face)
   2506    '("#[A-Z0-9_]+" 0 'web-mode-variable-name-face)
   2507    '("|[a-z0-9_=!?<>]+" 0 'web-mode-function-call-face)
   2508    '("(\\([[:alnum:]_ ]+\\))" 1 'web-mode-constant-face)
   2509    ))
   2510 
   2511 (defvar web-mode-latex-font-lock-keywords
   2512   (list
   2513    '("[[:alnum:]_]+" 0 'web-mode-function-name-face t t)
   2514    ))
   2515 
   2516 (defvar web-mode-blade-font-lock-keywords
   2517   (append
   2518    (list
   2519     '("@\\([[:alpha:]_]+\\)" (1 'web-mode-block-control-face)))
   2520    web-mode-php-font-lock-keywords))
   2521 
   2522 (defvar web-mode-engines-font-lock-keywords
   2523   '(("angular"          . web-mode-angular-font-lock-keywords)
   2524     ("anki"             . web-mode-anki-font-lock-keywords)
   2525     ("antlers"          . web-mode-antlers-font-lock-keywords)
   2526     ("artanis"          . web-mode-artanis-font-lock-keywords)
   2527     ("astro"            . web-mode-astro-font-lock-keywords)
   2528     ("blade"            . web-mode-blade-font-lock-keywords)
   2529     ("cl-emb"           . web-mode-cl-emb-font-lock-keywords)
   2530     ("closure"          . web-mode-closure-font-lock-keywords)
   2531     ("ctemplate"        . web-mode-ctemplate-font-lock-keywords)
   2532     ("dust"             . web-mode-dust-font-lock-keywords)
   2533     ("elixir"           . web-mode-elixir-font-lock-keywords)
   2534     ("ejs"              . web-mode-ejs-font-lock-keywords)
   2535     ("erb"              . web-mode-erb-font-lock-keywords)
   2536     ("expressionengine" . web-mode-expressionengine-font-lock-keywords)
   2537     ("go"               . web-mode-go-font-lock-keywords)
   2538     ("hero"             . web-mode-go-font-lock-keywords)
   2539     ("lsp"              . web-mode-lsp-font-lock-keywords)
   2540     ("marko"            . web-mode-marko-font-lock-keywords)
   2541     ("mojolicious"      . web-mode-mojolicious-font-lock-keywords)
   2542     ("php"              . web-mode-php-font-lock-keywords)
   2543     ("python"           . web-mode-python-font-lock-keywords)
   2544     ("razor"            . web-mode-razor-font-lock-keywords)
   2545     ("riot"             . web-mode-riot-font-lock-keywords)
   2546     ("smarty"           . web-mode-smarty-font-lock-keywords)
   2547     ("spip"             . web-mode-spip-font-lock-keywords)
   2548     ("template-toolkit" . web-mode-template-toolkit-font-lock-keywords)
   2549     ("underscore"       . web-mode-underscore-font-lock-keywords)
   2550     ("web2py"           . web-mode-web2py-font-lock-keywords)
   2551     ("velocity"         . web-mode-velocity-font-lock-keywords)
   2552     ("vue"              . web-mode-vue-font-lock-keywords)
   2553     ("xoops"            . web-mode-smarty-font-lock-keywords)
   2554     ("svelte"           . web-mode-svelte-font-lock-keywords)
   2555     )
   2556   "Engines font-lock keywords")
   2557 
   2558 (defvar web-mode-prettify-symbols-alist
   2559   '(("=>" . 8658)
   2560     (">=" . 8805)
   2561     ("<=" . 8804)))
   2562 
   2563 (defvar web-mode-before-auto-complete-hooks nil
   2564   "List of functions to run before triggering the auto-complete library.
   2565 
   2566 Auto-complete sources will sometimes need some tweaking to work
   2567 nicely with web-mode. This hook gives users the chance to adjust
   2568 the environment as needed for ac-sources, right before they're used.")
   2569 
   2570 (defvar web-mode-ignore-ac-start-advice nil
   2571   "If not nil `defadvice' for `ac-start' will be ignored.
   2572 
   2573 Can be set inside a hook in `web-mode-before-auto-complete-hooks' to
   2574 non nil to ignore the defadvice which sets ac-sources according to current
   2575 language. This is needed if the corresponding auto-completion triggers
   2576 another auto-completion with different ac-sources (e.g. ac-php)")
   2577 
   2578 (defvar web-mode-ac-sources-alist nil
   2579   "alist mapping language names to ac-sources for that language.")
   2580 
   2581 (defvar web-mode-trace nil
   2582   "Activate debug tracing.")
   2583 
   2584 (defvar web-mode-syntax-table
   2585   (let ((table (make-syntax-table)))
   2586     (modify-syntax-entry ?- "_" table)
   2587     (modify-syntax-entry ?_ "_" table) ;#563
   2588     (modify-syntax-entry ?< "." table)
   2589     (modify-syntax-entry ?> "." table)
   2590     (modify-syntax-entry ?& "." table)
   2591     (modify-syntax-entry ?/ "." table)
   2592     (modify-syntax-entry ?= "." table)
   2593     (modify-syntax-entry ?% "." table)
   2594     table)
   2595   "Syntax table used to reveal whitespaces.")
   2596 
   2597 (defvar web-mode-map
   2598   (let ((map (make-sparse-keymap)))
   2599 
   2600     (define-key map [menu-bar wm]             (cons "Web-Mode" (make-sparse-keymap)))
   2601     (define-key map [menu-bar wm dom]         (cons "Dom" (make-sparse-keymap)))
   2602     (define-key map [menu-bar wm blk]         (cons "Block" (make-sparse-keymap)))
   2603     (define-key map [menu-bar wm attr]        (cons "Html Attr" (make-sparse-keymap)))
   2604     (define-key map [menu-bar wm tag]         (cons "Html Tag" (make-sparse-keymap)))
   2605     (define-key map [menu-bar wm elt]         (cons "Html Element" (make-sparse-keymap)))
   2606 
   2607     (define-key map [menu-bar wm sep-1]       '(menu-item "--"))
   2608 
   2609     (define-key map [menu-bar wm dom dom-xpa] '(menu-item "XPath" web-mode-dom-xpath))
   2610     (define-key map [menu-bar wm dom dom-tra] '(menu-item "Traverse" web-mode-dom-traverse))
   2611     (define-key map [menu-bar wm dom dom-err] '(menu-item "Show error(s)" web-mode-dom-errors-show))
   2612     (define-key map [menu-bar wm dom dom-ent] '(menu-item "Replace html entities" web-mode-dom-entities-replace))
   2613     (define-key map [menu-bar wm dom dom-quo] '(menu-item "Replace dumb quotes" web-mode-dom-quotes-replace))
   2614     (define-key map [menu-bar wm dom dom-apo] '(menu-item "Replace apostrophes" web-mode-dom-apostrophes-replace))
   2615     (define-key map [menu-bar wm dom dom-nor] '(menu-item "Normalize" web-mode-dom-normalize))
   2616 
   2617     (define-key map [menu-bar wm blk blk-sel] '(menu-item "Select" web-mode-block-select))
   2618     (define-key map [menu-bar wm blk blk-pre] '(menu-item "Previous" web-mode-block-previous))
   2619     (define-key map [menu-bar wm blk blk-nex] '(menu-item "Next" web-mode-block-next))
   2620     (define-key map [menu-bar wm blk blk-kil] '(menu-item "Kill" web-mode-block-kill))
   2621     (define-key map [menu-bar wm blk blk-end] '(menu-item "End" web-mode-block-end))
   2622     (define-key map [menu-bar wm blk blk-clo] '(menu-item "Close" web-mode-block-close))
   2623     (define-key map [menu-bar wm blk blk-beg] '(menu-item "Beginning" web-mode-block-beginning))
   2624 
   2625     (define-key map [menu-bar wm attr attr-ins] '(menu-item "Insert" web-mode-attribute-insert))
   2626     (define-key map [menu-bar wm attr attr-end] '(menu-item "End" web-mode-attribute-end))
   2627     (define-key map [menu-bar wm attr attr-beg] '(menu-item "Beginning" web-mode-attribute-beginning))
   2628     (define-key map [menu-bar wm attr attr-sel] '(menu-item "Select" web-mode-attribute-select))
   2629     (define-key map [menu-bar wm attr attr-kil] '(menu-item "Kill" web-mode-attribute-kill))
   2630     (define-key map [menu-bar wm attr attr-nex] '(menu-item "Next" web-mode-attribute-next))
   2631     (define-key map [menu-bar wm attr attr-pre] '(menu-item "Previous" web-mode-attribute-previous))
   2632     (define-key map [menu-bar wm attr attr-tra] '(menu-item "Transpose" web-mode-attribute-transpose))
   2633 
   2634     (define-key map [menu-bar wm tag tag-beg] '(menu-item "Sort Attributes" web-mode-tag-attributes-sort))
   2635     (define-key map [menu-bar wm tag tag-sel] '(menu-item "Select" web-mode-tag-select))
   2636     (define-key map [menu-bar wm tag tag-pre] '(menu-item "Previous" web-mode-tag-previous))
   2637     (define-key map [menu-bar wm tag tag-nex] '(menu-item "Next" web-mode-tag-next))
   2638     (define-key map [menu-bar wm tag tag-end] '(menu-item "End" web-mode-tag-end))
   2639     (define-key map [menu-bar wm tag tag-beg] '(menu-item "Beginning" web-mode-tag-beginning))
   2640 
   2641     (define-key map [menu-bar wm elt elt-con] '(menu-item "Contract" web-mode-element-contract))
   2642     (define-key map [menu-bar wm elt elt-ext] '(menu-item "Extract" web-mode-element-extract))
   2643     (define-key map [menu-bar wm elt elt-van] '(menu-item "Vanish" web-mode-element-vanish))
   2644     (define-key map [menu-bar wm elt elt-exc] '(menu-item "Transpose" web-mode-element-transpose))
   2645     (define-key map [menu-bar wm elt elt-sel] '(menu-item "Select" web-mode-element-select))
   2646     (define-key map [menu-bar wm elt elt-ren] '(menu-item "Rename" web-mode-element-rename))
   2647     (define-key map [menu-bar wm elt elt-pre] '(menu-item "Previous" web-mode-element-previous))
   2648     (define-key map [menu-bar wm elt elt-par] '(menu-item "Parent" web-mode-element-parent))
   2649     (define-key map [menu-bar wm elt elt-nex] '(menu-item "Next" web-mode-element-next))
   2650     (define-key map [menu-bar wm elt elt-mut] '(menu-item "Mute blanks" web-mode-element-mute-blanks))
   2651     (define-key map [menu-bar wm elt elt-del] '(menu-item "Kill" web-mode-element-kill))
   2652     (define-key map [menu-bar wm elt elt-end] '(menu-item "End" web-mode-element-end))
   2653     (define-key map [menu-bar wm elt elt-inn] '(menu-item "Content (select)" web-mode-element-content-select))
   2654     (define-key map [menu-bar wm elt elt-clo] '(menu-item "Close" web-mode-element-close))
   2655     (define-key map [menu-bar wm elt elt-ins] '(menu-item "Insert" web-mode-element-insert))
   2656     (define-key map [menu-bar wm elt elt-ins] '(menu-item "Word to tag" web-mode-element-insert-at-point))
   2657     (define-key map [menu-bar wm elt elt-dup] '(menu-item "Clone" web-mode-element-clone))
   2658     (define-key map [menu-bar wm elt elt-cfo] '(menu-item "Children fold" web-mode-element-children-fold-or-unfold))
   2659     (define-key map [menu-bar wm elt elt-chi] '(menu-item "Child" web-mode-element-child))
   2660     (define-key map [menu-bar wm elt elt-beg] '(menu-item "Beginning" web-mode-element-beginning))
   2661 
   2662     (define-key map [menu-bar wm fol]         '(menu-item "Fold/Unfold" web-mode-fold-or-unfold))
   2663     (define-key map [menu-bar wm hig]         '(menu-item "Fontify buffer" web-mode-buffer-fontify))
   2664     (define-key map [menu-bar wm ind]         '(menu-item "Indent buffer" web-mode-buffer-indent))
   2665     (define-key map [menu-bar wm nav]         '(menu-item "Tag/Block navigation" web-mode-navigate))
   2666     (define-key map [menu-bar wm exp]         '(menu-item "Mark and Expand" web-mode-mark-and-expand))
   2667     (define-key map [menu-bar wm spa]         '(menu-item "Toggle whitespaces" web-mode-whitespaces-show))
   2668     (define-key map [menu-bar wm sni]         '(menu-item "Insert snippet" web-mode-snippet-insert))
   2669 
   2670     ;;--------------------------------------------------------------------------
   2671     ;; "C-c <LETTER>" are reserved for users
   2672 
   2673     (define-key map (kbd "C-c C-a b") 'web-mode-attribute-beginning)
   2674     (define-key map (kbd "C-c C-a e") 'web-mode-attribute-end)
   2675     (define-key map (kbd "C-c C-a i") 'web-mode-attribute-insert)
   2676     (define-key map (kbd "C-c C-a n") 'web-mode-attribute-next)
   2677     (define-key map (kbd "C-c C-a s") 'web-mode-attribute-select)
   2678     (define-key map (kbd "C-c C-a k") 'web-mode-attribute-kill)
   2679     (define-key map (kbd "C-c C-a p") 'web-mode-attribute-previous)
   2680     (define-key map (kbd "C-c C-a t") 'web-mode-attribute-transpose)
   2681 
   2682     (define-key map (kbd "C-c C-b b") 'web-mode-block-beginning)
   2683     (define-key map (kbd "C-c C-b c") 'web-mode-block-close)
   2684     (define-key map (kbd "C-c C-b e") 'web-mode-block-end)
   2685     (define-key map (kbd "C-c C-b k") 'web-mode-block-kill)
   2686     (define-key map (kbd "C-c C-b n") 'web-mode-block-next)
   2687     (define-key map (kbd "C-c C-b p") 'web-mode-block-previous)
   2688     (define-key map (kbd "C-c C-b s") 'web-mode-block-select)
   2689 
   2690     (define-key map (kbd "C-c C-d a") 'web-mode-dom-apostrophes-replace)
   2691     (define-key map (kbd "C-c C-d d") 'web-mode-dom-errors-show)
   2692     (define-key map (kbd "C-c C-d e") 'web-mode-dom-entities-replace)
   2693     (define-key map (kbd "C-c C-d n") 'web-mode-dom-normalize)
   2694     (define-key map (kbd "C-c C-d q") 'web-mode-dom-quotes-replace)
   2695     (define-key map (kbd "C-c C-d t") 'web-mode-dom-traverse)
   2696     (define-key map (kbd "C-c C-d x") 'web-mode-dom-xpath)
   2697 
   2698     (define-key map (kbd "C-c C-e /") 'web-mode-element-close)
   2699     (define-key map (kbd "C-c C-e a") 'web-mode-element-content-select)
   2700     (define-key map (kbd "C-c C-e b") 'web-mode-element-beginning)
   2701     (define-key map (kbd "C-c C-e c") 'web-mode-element-clone)
   2702     (define-key map (kbd "C-c C-e d") 'web-mode-element-child)
   2703     (define-key map (kbd "C-c C-e e") 'web-mode-element-end)
   2704     (define-key map (kbd "C-c C-e f") 'web-mode-element-children-fold-or-unfold)
   2705     (define-key map (kbd "C-c C-e i") 'web-mode-element-insert)
   2706     (define-key map (kbd "C-c C-e I") 'web-mode-element-insert-at-point)
   2707     (define-key map (kbd "C-c C-e k") 'web-mode-element-kill)
   2708     (define-key map (kbd "C-c C-e m") 'web-mode-element-mute-blanks)
   2709     (define-key map (kbd "C-c C-e n") 'web-mode-element-next)
   2710     (define-key map (kbd "C-c C-e p") 'web-mode-element-previous)
   2711     (define-key map (kbd "C-c C-e r") 'web-mode-element-rename)
   2712     (define-key map (kbd "C-c C-e s") 'web-mode-element-select)
   2713     (define-key map (kbd "C-c C-e t") 'web-mode-element-transpose)
   2714     (define-key map (kbd "C-c C-e u") 'web-mode-element-parent)
   2715     (define-key map (kbd "C-c C-e v") 'web-mode-element-vanish)
   2716     (define-key map (kbd "C-c C-e w") 'web-mode-element-wrap)
   2717     (define-key map (kbd "C-c C-e +") 'web-mode-element-extract)
   2718     (define-key map (kbd "C-c C-e -") 'web-mode-element-contract)
   2719 
   2720     (define-key map (kbd "C-c C-t a") 'web-mode-tag-attributes-sort)
   2721     (define-key map (kbd "C-c C-t b") 'web-mode-tag-beginning)
   2722     (define-key map (kbd "C-c C-t e") 'web-mode-tag-end)
   2723     (define-key map (kbd "C-c C-t m") 'web-mode-tag-match)
   2724     (define-key map (kbd "C-c C-t n") 'web-mode-tag-next)
   2725     (define-key map (kbd "C-c C-t p") 'web-mode-tag-previous)
   2726     (define-key map (kbd "C-c C-t s") 'web-mode-tag-select)
   2727 
   2728     ;;--------------------------------------------------------------------------
   2729 
   2730     ;;(define-key map (kbd "M-q")       'fill-paragraph)
   2731     (define-key map (kbd "M-;")       'web-mode-comment-or-uncomment)
   2732 
   2733     ;;C-c C-a : attribute
   2734     ;;C-c C-b : block
   2735     ;;C-c C-d : dom
   2736     ;;C-c C-e : element
   2737     (define-key map (kbd "C-c C-f")   'web-mode-fold-or-unfold)
   2738     (define-key map (kbd "C-c C-h")   'web-mode-buffer-fontify)
   2739     (define-key map (kbd "C-c C-i")   'web-mode-buffer-indent)
   2740     (define-key map (kbd "C-c C-j")   'web-mode-jshint)
   2741     (define-key map (kbd "C-c C-l")   'web-mode-file-link)
   2742     (define-key map (kbd "C-c C-m")   'web-mode-mark-and-expand)
   2743     (define-key map (kbd "C-c C-n")   'web-mode-navigate)
   2744     (define-key map (kbd "C-c C-r")   'web-mode-reload)
   2745     (define-key map (kbd "C-c C-s")   'web-mode-snippet-insert)
   2746     ;;C-c C-t : tag
   2747     (define-key map (kbd "C-c C-w")   'web-mode-whitespaces-show)
   2748 
   2749     map)
   2750   "Keymap for `web-mode'.")
   2751 
   2752 ;;---- COMPATIBILITY -----------------------------------------------------------
   2753 
   2754 (eval-and-compile
   2755 
   2756   ;; compatibility with emacs < 23
   2757   (defun web-mode-string-match-p (regexp string &optional start)
   2758     "Same as `string-match' except it does not change the match data."
   2759     (save-match-data
   2760       (string-match regexp string start)))
   2761 
   2762   (unless (fboundp 'string-match-p)
   2763     (fset 'string-match-p (symbol-function 'web-mode-string-match-p)))
   2764 
   2765   ;; compatibility with emacs < 23.3
   2766   (if (fboundp 'with-silent-modifications)
   2767       (defalias 'web-mode-with-silent-modifications 'with-silent-modifications)
   2768       (defmacro web-mode-with-silent-modifications (&rest body)
   2769         `(let ((old-modified-p (buffer-modified-p))
   2770                (inhibit-modification-hooks t)
   2771                (buffer-undo-list t))
   2772            (unwind-protect
   2773                 ,@body
   2774              (restore-buffer-modified-p old-modified-p)))))
   2775 
   2776   ;; compatibility with emacs < 24.3
   2777   (defun web-mode-buffer-narrowed-p ()
   2778     (if (fboundp 'buffer-narrowed-p)
   2779         (buffer-narrowed-p)
   2780         (/= (- (point-max) (point-min)) (buffer-size))))
   2781 
   2782   ;; compatibility with emacs < 24
   2783   (defalias 'web-mode-prog-mode
   2784       (if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode))
   2785 
   2786   ;; compatibility with emacs < 24.3
   2787   (unless (fboundp 'setq-local)
   2788     (defmacro setq-local (var val)
   2789       `(set (make-local-variable ',var) ,val)))
   2790 
   2791   ;; compatability with emacs < 24.4
   2792   (defun web-mode-string-suffix-p (suffix string)
   2793     "Return t if STRING ends with SUFFIX."
   2794     (and (string-match (rx-to-string `(: ,suffix eos) t)
   2795                        string)
   2796          t))
   2797 
   2798   (unless (fboundp 'string-suffix-p)
   2799     (fset 'string-suffix-p (symbol-function 'web-mode-string-suffix-p)))
   2800 
   2801   (unless (fboundp 'seq-some)
   2802     (defun seq-some (pred seq)
   2803       (unless (null seq)
   2804         (or (funcall pred (car seq))
   2805             (seq-some pred (cdr seq))))))
   2806   ) ;eval-and-compile
   2807 
   2808 ;;---- MAJOR MODE --------------------------------------------------------------
   2809 
   2810 ;;;###autoload
   2811 (define-derived-mode
   2812     web-mode web-mode-prog-mode "Web"
   2813     "Major mode for editing web templates."
   2814 
   2815     (make-local-variable 'web-mode-attr-indent-offset)
   2816     (make-local-variable 'web-mode-attr-value-indent-offset)
   2817     (make-local-variable 'web-mode-auto-pairs)
   2818     (make-local-variable 'web-mode-block-regexp)
   2819     (make-local-variable 'web-mode-change-beg)
   2820     (make-local-variable 'web-mode-change-end)
   2821     (make-local-variable 'web-mode-code-indent-offset)
   2822     (make-local-variable 'web-mode-column-overlays)
   2823     (make-local-variable 'web-mode-comment-formats)
   2824     (make-local-variable 'web-mode-comment-style)
   2825     (make-local-variable 'web-mode-content-type)
   2826     (make-local-variable 'web-mode-css-indent-offset)
   2827     (make-local-variable 'web-mode-display-table)
   2828     (make-local-variable 'web-mode-django-control-blocks)
   2829     (make-local-variable 'web-mode-django-control-blocks-regexp)
   2830     (make-local-variable 'web-mode-enable-block-face)
   2831     (make-local-variable 'web-mode-enable-inlays)
   2832     (make-local-variable 'web-mode-enable-part-face)
   2833     (make-local-variable 'web-mode-enable-sexp-functions)
   2834     (make-local-variable 'web-mode-engine)
   2835     (make-local-variable 'web-mode-engine-attr-regexp)
   2836     (make-local-variable 'web-mode-engine-file-regexps)
   2837     (make-local-variable 'web-mode-engine-open-delimiter-regexps)
   2838     (make-local-variable 'web-mode-engine-token-regexp)
   2839     (make-local-variable 'web-mode-expand-initial-pos)
   2840     (make-local-variable 'web-mode-expand-initial-scroll)
   2841     (make-local-variable 'web-mode-expand-previous-state)
   2842     (make-local-variable 'web-mode-indent-style)
   2843     (make-local-variable 'web-mode-indentless-attributes)
   2844     (make-local-variable 'web-mode-indentless-elements)
   2845     (make-local-variable 'web-mode-is-scratch)
   2846     (make-local-variable 'web-mode-skip-fontification)
   2847     (make-local-variable 'web-mode-jshint-errors)
   2848     (make-local-variable 'web-mode-last-enabled-feature)
   2849     (make-local-variable 'web-mode-markup-indent-offset)
   2850     (make-local-variable 'web-mode-minor-engine)
   2851     (make-local-variable 'web-mode-overlay-tag-end)
   2852     (make-local-variable 'web-mode-overlay-tag-start)
   2853     (make-local-variable 'web-mode-part-beg)
   2854     (make-local-variable 'web-mode-scan-beg)
   2855     (make-local-variable 'web-mode-scan-end)
   2856     (make-local-variable 'web-mode-sql-indent-offset)
   2857     (make-local-variable 'web-mode-time)
   2858     (make-local-variable 'web-mode-trace)
   2859 
   2860     (make-local-variable 'font-lock-beg)
   2861     (make-local-variable 'font-lock-end)
   2862 
   2863     (make-local-variable 'comment-end)
   2864     (make-local-variable 'comment-region-function)
   2865     (make-local-variable 'comment-start)
   2866     (make-local-variable 'fill-paragraph-function)
   2867     (make-local-variable 'font-lock-defaults)
   2868     (make-local-variable 'font-lock-extend-region-functions)
   2869     (make-local-variable 'font-lock-support-mode)
   2870     (make-local-variable 'font-lock-unfontify-region-function)
   2871     (make-local-variable 'imenu-case-fold-search)
   2872     (make-local-variable 'imenu-create-index-function)
   2873     (make-local-variable 'imenu-generic-expression)
   2874     (make-local-variable 'indent-line-function)
   2875     (make-local-variable 'parse-sexp-lookup-properties)
   2876     (make-local-variable 'uncomment-region-function)
   2877     (make-local-variable 'yank-excluded-properties)
   2878 
   2879     (setq web-mode-time (current-time))
   2880 
   2881     (setq comment-end "-->"
   2882           comment-region-function 'web-mode-comment-or-uncomment-region
   2883           comment-start "<!--"
   2884           fill-paragraph-function 'web-mode-fill-paragraph
   2885           ;;font-lock-defaults '(web-mode-font-lock-keywords t)
   2886           font-lock-defaults '('(web-mode-fontify) t)
   2887           font-lock-extend-region-functions '(web-mode-extend-region)
   2888           font-lock-support-mode nil
   2889           font-lock-unfontify-region-function 'web-mode-unfontify-region
   2890           imenu-case-fold-search t
   2891           imenu-create-index-function 'web-mode-imenu-index
   2892           indent-line-function 'web-mode-indent-line
   2893           parse-sexp-lookup-properties t
   2894           yank-excluded-properties t
   2895           uncomment-region-function 'web-mode-comment-or-uncomment-region
   2896           prettify-symbols-alist web-mode-prettify-symbols-alist)
   2897 
   2898     (substitute-key-definition #'indent-new-comment-line
   2899                                #'web-mode-comment-indent-new-line
   2900                                web-mode-map global-map)
   2901 
   2902     (add-hook 'after-change-functions #'web-mode-on-after-change nil t)
   2903     (add-hook 'after-save-hook        #'web-mode-on-after-save t t)
   2904     (add-hook 'change-major-mode-hook #'web-mode-on-exit nil t)
   2905     (add-hook 'post-command-hook      #'web-mode-on-post-command nil t)
   2906     (add-hook 'hack-local-variables-hook #'web-mode-guess-engine-and-content-type t t)
   2907 
   2908     (cond
   2909       ((boundp 'yas-after-exit-snippet-hook)
   2910        (add-hook 'yas-after-exit-snippet-hook
   2911                  'web-mode-yasnippet-exit-hook
   2912                  t t))
   2913       ((boundp 'yas/after-exit-snippet-hook)
   2914        (add-hook 'yas/after-exit-snippet-hook
   2915                  'web-mode-yasnippet-exit-hook
   2916                  t t))
   2917       )
   2918 
   2919     (when web-mode-enable-whitespace-fontification
   2920       (web-mode-whitespaces-on))
   2921 
   2922     (when web-mode-enable-sexp-functions
   2923       (setq-local forward-sexp-function #'web-mode-forward-sexp))
   2924 
   2925     (setq web-mode-change-beg (point-min)
   2926           web-mode-change-end (point-max))
   2927     (when (> (point-max) 256000)
   2928       (web-mode-buffer-fontify))
   2929 
   2930     (when (and (boundp 'hs-special-modes-alist)
   2931                (not (assoc major-mode hs-special-modes-alist)))
   2932       (add-to-list 'hs-special-modes-alist '(web-mode "{" "}" "/[*/]" web-mode-forward-sexp nil))
   2933       ) ;when
   2934 
   2935     ;; compatibility with emacs < 24
   2936     (if (fboundp 'prog-mode)
   2937         (put 'web-mode 'derived-mode-parent 'prog-mode))
   2938 
   2939     (cond
   2940       ((not (buffer-file-name))
   2941        )
   2942       ((string-match-p "web-mode-benchmark.html" (buffer-file-name))
   2943        (web-mode-measure "end"))
   2944       ) ;cond
   2945 
   2946     )
   2947 
   2948 ;;---- INVALIDATION ------------------------------------------------------------
   2949 
   2950 ;; 1/ after-change
   2951 ;; 2/ extend-region
   2952 ;; 3/ scan
   2953 ;; 4/ fontify
   2954 ;; 5/ post-command
   2955 
   2956 (defun web-mode-on-after-change (beg end len)
   2957   (when web-mode-trace
   2958     (message "after-change: pos(%d) beg(%d) end(%d) len(%d) this-command(%S)"
   2959              (point) beg end len this-command))
   2960   (when (or (null web-mode-change-beg) (< beg web-mode-change-beg))
   2961     (setq web-mode-change-beg beg))
   2962   (when (or (null web-mode-change-end) (> end web-mode-change-end))
   2963     (setq web-mode-change-end end)))
   2964 
   2965 (defun web-mode-extend-region ()
   2966   (when web-mode-trace
   2967     (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)"
   2968              font-lock-beg font-lock-end web-mode-change-beg web-mode-change-end web-mode-skip-fontification))
   2969   (when (and (string= web-mode-engine "php")
   2970              (and (>= font-lock-beg 6) (<= font-lock-beg 9))
   2971              (or (message (buffer-substring-no-properties 1 6)) t)
   2972              (string= (buffer-substring-no-properties 1 6) "<?php"))
   2973     (setq font-lock-beg (point-min)
   2974           font-lock-end (point-max))
   2975     )
   2976   (when (or (null web-mode-change-beg) (< font-lock-beg web-mode-change-beg))
   2977     (when web-mode-trace (message "extend-region: font-lock-beg(%S) < web-mode-change-beg(%S)" font-lock-beg web-mode-change-beg))
   2978     (setq web-mode-change-beg font-lock-beg))
   2979   (when (or (null web-mode-change-end) (> font-lock-end web-mode-change-end))
   2980     (when web-mode-trace (message "extend-region: font-lock-end(%S) > web-mode-change-end(%S)" font-lock-end web-mode-change-end))
   2981     (setq web-mode-change-end font-lock-end))
   2982   (when font-lock-dont-widen
   2983     (setq web-mode-change-beg (max web-mode-change-beg (point-min))
   2984           web-mode-change-end (min web-mode-change-end (point-max))))
   2985   (let ((region (web-mode-scan web-mode-change-beg web-mode-change-end)))
   2986     (when region
   2987       ;;(message "region: %S" region)
   2988       (setq font-lock-beg (car region)
   2989             font-lock-end (cdr region))
   2990       ) ;when
   2991     ) ;let
   2992   nil)
   2993 
   2994 (defun web-mode-scan (&optional beg end)
   2995   (when web-mode-trace
   2996     (message "scan: beg(%S) end(%S) web-mode-change-beg(%S) web-mode-change-end(%S)"
   2997              beg end web-mode-change-beg web-mode-change-end))
   2998   (unless beg (setq beg web-mode-change-beg))
   2999   (unless end (setq end web-mode-change-end))
   3000   ;;(message "%S %S %S" web-mode-content-type (get-text-property beg 'part-side) (get-text-property end 'part-side))
   3001   (when (and end (> end (point-max)))
   3002     (setq end (point-max)))
   3003   (setq web-mode-change-beg nil
   3004         web-mode-change-end nil)
   3005   (cond
   3006     ((or (null beg) (null end))
   3007      nil)
   3008     ((and (member web-mode-engine '("php" "asp"))
   3009           (get-text-property beg 'block-side)
   3010           (get-text-property end 'block-side)
   3011           (> beg (point-min))
   3012           (not (eq (get-text-property (1- beg) 'block-token) 'delimiter-beg))
   3013           (not (eq (get-text-property end 'block-token) 'delimiter-end)))
   3014      ;;(message "invalidate block (%S > %S)" beg end)
   3015      (web-mode-invalidate-block-region beg end))
   3016     ((and (or (member web-mode-content-type
   3017                       '("css" "javascript" "json" "jsx" "sass" "stylus" "typescript"))
   3018               (and (get-text-property beg 'part-side)
   3019                    (get-text-property end 'part-side)
   3020                    (> beg (point-min))
   3021                    (get-text-property (1- beg) 'part-side))
   3022               ))
   3023      ;;(message "invalidate part (%S > %S)" beg end)
   3024      (web-mode-invalidate-part-region beg end))
   3025     (t
   3026      ;;(message "invalidate default (%S > %S)" beg end)
   3027      (web-mode-invalidate-region beg end))
   3028     ) ;cond
   3029   )
   3030 
   3031 (defun web-mode-invalidate-region (reg-beg reg-end)
   3032   (when web-mode-trace
   3033     (message "invalidate-region: point(%S) reg-beg(%S) reg-end(%S)" (point) reg-beg reg-end))
   3034   (setq reg-beg (web-mode-invalidate-region-beginning-position reg-beg)
   3035         reg-end (web-mode-invalidate-region-end-position reg-end))
   3036   ;;(message "invalidate-region: reg-beg(%S) reg-end(%S)" reg-beg reg-end)
   3037   (web-mode-scan-region reg-beg reg-end))
   3038 
   3039 (defun web-mode--command-is-self-insert-p ()
   3040   "Return non-nil if `this-command' is `self-insert-command'.
   3041 Also return non-nil if it is the command `self-insert-command' is remapped to."
   3042   (memq this-command (list 'self-insert-command
   3043                            (key-binding [remap self-insert-command]))))
   3044 
   3045 (defun web-mode-on-post-command ()
   3046   (when (and web-mode-trace
   3047              (not (member this-command
   3048                           '(left-char right-char previous-line next-line save-buffer mwheel-scroll end-of-line beginning-of-line))))
   3049     (message "post-command: this-command(%S) web-mode-change-beg(%S) web-mode-change-end(%S) previous-state(%S)"
   3050              this-command web-mode-change-beg web-mode-change-end web-mode-expand-previous-state))
   3051   (let (ctx n char)
   3052     (when (and web-mode-expand-previous-state
   3053                (not (member this-command web-mode-commands-like-expand-region)))
   3054       (when (eq this-command 'keyboard-quit)
   3055         (goto-char web-mode-expand-initial-pos))
   3056       (deactivate-mark)
   3057       (when web-mode-expand-initial-scroll
   3058         (set-window-start (selected-window) web-mode-expand-initial-scroll)
   3059         )
   3060       (setq web-mode-expand-previous-state nil
   3061             web-mode-expand-initial-pos nil
   3062             web-mode-expand-initial-scroll nil))
   3063 
   3064     (when (member this-command '(yank))
   3065       ;;(setq web-mode-skip-fontification nil)
   3066       (when (and web-mode-scan-beg web-mode-scan-end global-font-lock-mode)
   3067         (save-excursion
   3068           (font-lock-fontify-region web-mode-scan-beg web-mode-scan-end))
   3069         (when web-mode-enable-auto-indentation
   3070           (indent-region web-mode-scan-beg web-mode-scan-end))
   3071         ) ;and
   3072       )
   3073 
   3074     (when (and (< (point) 16) web-mode-change-beg web-mode-change-end)
   3075       (web-mode-detect-content-type))
   3076 
   3077     (when (and web-mode-change-beg web-mode-change-end
   3078                web-mode-enable-engine-detection
   3079                (or (null web-mode-engine) (string= web-mode-engine "none"))
   3080                (< (point) web-mode-chunk-length)
   3081                (web-mode-detect-engine))
   3082       (web-mode-on-engine-setted)
   3083       (web-mode-buffer-fontify))
   3084 
   3085     (when (> (point) 1)
   3086       (setq char (char-before)))
   3087 
   3088     (cond
   3089       ((null char)
   3090        )
   3091       ((and (>= (point) 3)
   3092             (web-mode--command-is-self-insert-p)
   3093             (not (member (get-text-property (point) 'part-token) '(comment string)))
   3094             (not (eq (get-text-property (point) 'tag-type) 'comment))
   3095             )
   3096        (setq ctx (web-mode-auto-complete)))
   3097       ((and web-mode-enable-auto-opening
   3098             (member this-command '(newline electric-newline-and-maybe-indent newline-and-indent))
   3099             (or (and (not (eobp))
   3100                      (eq (char-after) ?\<)
   3101                      (eq (get-text-property (point) 'tag-type) 'end)
   3102                      (looking-back ">\n[ \t]*" (point-min))
   3103                      (setq n (length (match-string-no-properties 0)))
   3104                      (eq (get-text-property (- (point) n) 'tag-type) 'start)
   3105                      (string= (get-text-property (- (point) n) 'tag-name)
   3106                               (get-text-property (point) 'tag-name))
   3107                      )
   3108                 (and (get-text-property (1- (point)) 'block-side)
   3109                      (string= web-mode-engine "php")
   3110                      (looking-back "<\\?php[ ]*\n" (point-min))
   3111                      (looking-at-p "[ ]*\\?>"))))
   3112        (newline-and-indent)
   3113        (forward-line -1)
   3114        (indent-according-to-mode)
   3115        )
   3116       ) ;cond
   3117 
   3118     (cond
   3119 
   3120       ((not web-mode-enable-auto-opening)
   3121        )
   3122       ((and (member this-command '(newline electric-newline-and-maybe-indent newline-and-indent))
   3123             (get-text-property (point) 'part-side)
   3124             (eq (get-text-property (point) 'part-token) 'string))
   3125        (indent-according-to-mode)
   3126        (when (and web-mode-change-end (> web-mode-change-end (point-max)))
   3127          (message "post-command: enlarge web-mode-change-end")
   3128          (setq web-mode-change-end (point-max))
   3129          )
   3130        )
   3131       ((and (web-mode--command-is-self-insert-p)
   3132             (or (and ctx
   3133                      (or (plist-get ctx :auto-closed)
   3134                          (plist-get ctx :auto-expanded)))
   3135                 (and (> (point) (point-min))
   3136                      (get-text-property (1- (point)) 'tag-end)
   3137                      (get-text-property (line-beginning-position) 'tag-beg))))
   3138        (indent-according-to-mode)
   3139        (when (and web-mode-change-end (> web-mode-change-end (point-max)))
   3140          (message "post-command: enlarge web-mode-change-end")
   3141          (setq web-mode-change-end (point-max))
   3142          )
   3143        )
   3144       ((and (web-mode--command-is-self-insert-p)
   3145             (member (get-text-property (point) 'part-side) '(javascript jsx css))
   3146             (looking-back "^[ \t]+[]})]" (point-min)))
   3147        (indent-according-to-mode)
   3148        (when (and web-mode-change-end (> web-mode-change-end (point-max)))
   3149          (message "post-command: enlarge web-mode-change-end")
   3150          (setq web-mode-change-end (point-max))
   3151          )
   3152        )
   3153       ) ; cond web-mode-enable-auto-opening
   3154 
   3155     (when web-mode-enable-current-element-highlight
   3156       (web-mode-highlight-current-element))
   3157 
   3158     (when (and web-mode-enable-current-column-highlight
   3159                (not (web-mode-buffer-narrowed-p)))
   3160       (web-mode-column-show))
   3161 
   3162     (when (and web-mode-trace (not (member this-command
   3163                                            '(left-char right-char previous-line next-line save-buffer mwheel-scroll end-of-line beginning-of-line))))
   3164       (when (or web-mode-change-beg web-mode-change-end)
   3165         (message "post-command: web-mode-change-beg(%S) web-mode-change-end(%S)"
   3166                  web-mode-change-end web-mode-change-end))
   3167       (message "-------------------------------------------------------------------")
   3168       )
   3169 
   3170     ))
   3171 
   3172 ;; NOTE: il est important d'identifier des caractères en fin de ligne
   3173 ;; web-mode-block-tokenize travaille en effet sur les fins de lignes pour
   3174 ;; les commentaires de type //
   3175 (defun web-mode-invalidate-block-region (pos-beg pos-end)
   3176   ;;  (message "pos-beg(%S) pos-end(%S)" pos-beg pos-end)
   3177   (save-excursion
   3178     (let (beg end code-beg code-end)
   3179       ;;(message "invalidate-block-region: pos-beg(%S)=%S" pos-beg (get-text-property pos 'block-side))
   3180       ;;(message "code-beg(%S) code-end(%S) pos-beg(%S) pos-end(%S)" code-beg code-end pos-beg pos-end)
   3181       (cond
   3182         ((not (and (setq code-beg (web-mode-block-code-beginning-position pos-beg))
   3183                    (setq code-end (web-mode-block-code-end-position pos-beg))
   3184                    (>= pos-beg code-beg)
   3185                    (<= pos-end code-end)
   3186                    (> code-end code-beg)))
   3187          (web-mode-invalidate-region pos-beg pos-end))
   3188         ((member web-mode-engine '("asp"))
   3189          (goto-char pos-beg)
   3190          (forward-line -1)
   3191          (setq beg (line-beginning-position))
   3192          (when (> code-beg beg)
   3193            (setq beg code-beg))
   3194          (goto-char pos-beg)
   3195          (forward-line)
   3196          (setq end (line-end-position))
   3197          (when (< code-end end)
   3198            (setq end code-end))
   3199          ;; ?? pas de (web-mode-block-tokenize beg end) ?
   3200          (web-mode-block-tokenize beg end)
   3201          (cons beg end)
   3202          ) ;asp
   3203         (t
   3204          (goto-char pos-beg)
   3205          ;;(message "pos-beg=%S" pos-beg)
   3206          (when (string= web-mode-engine "php")
   3207            (cond
   3208              ((and (looking-back "\*" (point-min))
   3209                    (looking-at-p "/"))
   3210               (search-backward "/*" code-beg))
   3211              ) ;cond
   3212            ) ;when
   3213          (if (web-mode-block-rsb "[;{}(][ ]*\n" code-beg)
   3214              (setq beg (match-end 0))
   3215              (setq beg code-beg))
   3216          (goto-char pos-end)
   3217          (if (web-mode-block-rsf "[;{})][ ]*\n" code-end)
   3218              (setq end (1- (match-end 0)))
   3219              (setq end code-end))
   3220          (web-mode-block-tokenize beg end)
   3221          ;;(message "beg(%S) end(%S)" beg end)
   3222          (cons beg end)
   3223          )
   3224         ) ;cond
   3225       )))
   3226 
   3227 (defun web-mode-invalidate-part-region (pos-beg pos-end)
   3228   (save-excursion
   3229     (let (beg end part-beg part-end language)
   3230       (if (member web-mode-content-type web-mode-part-content-types)
   3231           (setq language web-mode-content-type)
   3232           (setq language (symbol-name (get-text-property pos-beg 'part-side))))
   3233       (setq part-beg (web-mode-part-beginning-position pos-beg)
   3234             part-end (web-mode-part-end-position pos-beg))
   3235       ;;(message "language(%S) pos-beg(%S) pos-end(%S) part-beg(%S) part-end(%S)"
   3236       ;;         language pos-beg pos-end part-beg part-end)
   3237       (goto-char pos-beg)
   3238       (cond
   3239         ((not (and part-beg part-end
   3240                    (>= pos-beg part-beg)
   3241                    (<= pos-end part-end)
   3242                    (> part-end part-beg)))
   3243          (web-mode-invalidate-region pos-beg pos-end))
   3244         ((member language '("javascript" "json" "jsx" "typescript"))
   3245          (if (web-mode-javascript-rsb "[;{}(][ ]*\n" part-beg)
   3246              (setq beg (match-end 0))
   3247              (setq beg part-beg))
   3248          (goto-char pos-end)
   3249          (if (web-mode-javascript-rsf "[;{})][ ]*\n" part-end)
   3250              (setq end (match-end 0))
   3251              (setq end part-end))
   3252          (web-mode-scan-region beg end language))
   3253         ((member language '("css" "sass"))
   3254          (let (rule1 rule2)
   3255            (setq rule1 (web-mode-css-rule-current pos-beg))
   3256            (setq rule2 rule1)
   3257            (when (> pos-end (cdr rule1))
   3258              (setq rule2 (web-mode-css-rule-current pos-end)))
   3259            (setq beg (car rule1)
   3260                  end (cdr rule2))
   3261            )
   3262          (web-mode-scan-region beg end language))
   3263         (t
   3264          (setq beg part-beg
   3265                end part-end)
   3266          (web-mode-scan-region beg end language))
   3267         ) ;cond
   3268       )))
   3269 
   3270 (defun web-mode-invalidate-region-beginning-position (pos)
   3271   (save-excursion
   3272     (goto-char pos)
   3273 
   3274     (cond
   3275       ((and (looking-at-p ">") ;#1151
   3276             (looking-back "--" (point-min)))
   3277        (search-backward "<!--" nil t))
   3278       ((and (bolp) (not (bobp)))
   3279        (backward-char))
   3280       )
   3281 
   3282     (beginning-of-line)
   3283     ;;(message "pos=%S point=%S %S" pos (point) (text-properties-at (point)))
   3284     (setq pos (point-min))
   3285     (let ((continue (not (bobp))))
   3286       (while continue
   3287         (cond
   3288           ((bobp)
   3289            (setq continue nil))
   3290           ;; NOTE: Going back to the previous start tag is necessary
   3291           ;; when inserting a part endtag (e.g. </script>).
   3292           ;; Indeed, parts must be identified asap.
   3293           ((and (progn (back-to-indentation) t)
   3294                 (get-text-property (point) 'tag-beg)
   3295                 (eq (get-text-property (point) 'tag-type) 'start))
   3296            (setq pos (point)
   3297                  continue nil))
   3298           (t
   3299            (forward-line -1))
   3300           ) ;cond
   3301         ) ;while
   3302       ;;(message "pos=%S" pos)
   3303       pos)))
   3304 
   3305 (defun web-mode-invalidate-region-end-position (pos)
   3306   (save-excursion
   3307     (goto-char pos)
   3308     ;;(message "pos=%S %S" pos (get-text-property pos 'block-token))
   3309     (when (string= web-mode-engine "jsp")
   3310       (cond
   3311         ((and (looking-back "<%" (point-min))
   3312               (looking-at-p "--"))
   3313          (search-forward "--%>"))
   3314         ((and (looking-back "-- %" (point-min))
   3315               (looking-at-p ">"))
   3316          (search-forward "--%>"))
   3317         ) ;cond
   3318       ) ;when
   3319     (setq pos (point-max))
   3320     (let ((continue (not (eobp))))
   3321       (while continue
   3322         (end-of-line)
   3323         ;;(message "%S %S" (point) (get-text-property (point) 'block-token))
   3324         (cond
   3325           ((eobp)
   3326            (setq continue nil))
   3327           ((and (not (get-text-property (point) 'tag-type))
   3328                 (not (get-text-property (point) 'part-side))
   3329                 (not (get-text-property (point) 'block-side)))
   3330            (setq pos (point)
   3331                  continue nil))
   3332           (t
   3333            (forward-line))
   3334           ) ;cond
   3335         ) ;while
   3336       pos)))
   3337 
   3338 (defun web-mode-buffer-scan ()
   3339   "Scan entine buffer."
   3340   (interactive)
   3341   (web-mode-scan-region (point-min) (point-max)))
   3342 
   3343 (defun web-mode-scan-region (beg end &optional content-type)
   3344   "Identify nodes/parts/blocks and syntactic symbols (strings/comments/etc.)."
   3345   ;;(message "scan-region: beg(%d) end(%d) content-type(%S)" beg end content-type)
   3346   (setq web-mode-scan-beg beg
   3347         web-mode-scan-end end)
   3348   (web-mode-with-silent-modifications
   3349    (save-excursion
   3350      (save-restriction
   3351        (save-match-data
   3352          (let ((inhibit-point-motion-hooks t)
   3353                (inhibit-quit t))
   3354            (remove-list-of-text-properties beg end web-mode-scan-properties)
   3355            (cond
   3356              ((and content-type (string= content-type "php"))
   3357               )
   3358              ((and content-type (member content-type web-mode-part-content-types))
   3359               (put-text-property beg end 'part-side
   3360                                  (cond
   3361                                    ((string= content-type "javascript") 'javascript)
   3362                                    ((string= content-type "json") 'json)
   3363                                    ((string= content-type "jsx") 'jsx)
   3364                                    ((string= content-type "css") 'css)
   3365                                    ((string= content-type "sql") 'sql)
   3366                                    ((string= content-type "pug") 'pug)
   3367                                    ((string= content-type "sass") 'sass)
   3368                                    ((string= content-type "stylus") 'stylus)
   3369                                    ((string= content-type "markdown") 'markdown)
   3370                                    ((string= content-type "ruby") 'ruby)
   3371                                    ((string= content-type "typescript") 'typescript)
   3372                                    ))
   3373               (web-mode-scan-blocks beg end)
   3374               (web-mode-part-scan beg end content-type))
   3375              ((member web-mode-content-type web-mode-part-content-types)
   3376               (web-mode-scan-blocks beg end)
   3377               (web-mode-part-scan beg end))
   3378              ((string= web-mode-engine "riot")
   3379               (web-mode-scan-elements beg end)
   3380               (web-mode-scan-blocks beg end)
   3381               (web-mode-part-foreach beg end 'web-mode-part-scan))
   3382              (t
   3383               (web-mode-scan-blocks beg end)
   3384               (web-mode-scan-elements beg end)
   3385               (web-mode-part-foreach beg end 'web-mode-part-scan))
   3386              ) ;cond
   3387            (cons beg end)
   3388            ))))))
   3389 
   3390 ;;---- LEXER BLOCKS ------------------------------------------------------------
   3391 
   3392 (defun web-mode-scan-blocks (reg-beg reg-end)
   3393   "Identifies blocks (with block-side, block-beg, block-end text properties)."
   3394   (save-excursion
   3395 
   3396     (let ((i 0) open close closing-string sub1 sub2 pos tagopen tmp delim-open delim-close part-beg part-end tagclose)
   3397 
   3398       (goto-char reg-beg)
   3399 
   3400       ;;(message "%S: %Sx%S" (point) reg-beg reg-end)
   3401       ;;(message "regexp=%S" web-mode-block-regexp)
   3402       (while (and (< i 2000)
   3403                   (> reg-end (point))
   3404                   web-mode-block-regexp
   3405                   (re-search-forward web-mode-block-regexp reg-end t)
   3406                   (not (eobp)))
   3407 
   3408         (setq i (1+ i)
   3409               closing-string nil
   3410               close nil
   3411               tagopen (match-string 0)
   3412               open (match-beginning 0)
   3413               delim-open nil
   3414               delim-close nil
   3415               pos nil)
   3416 
   3417         (let ((l (length tagopen)))
   3418           (when (member (string-to-char tagopen) '(?\s ?\t))
   3419             (setq tagopen (replace-regexp-in-string "\\`[ \t]*" "" tagopen))
   3420             (setq open (+ open (- l (length tagopen))))
   3421             (setq l (length tagopen))
   3422             )
   3423           (setq sub1 (substring tagopen 0 1)
   3424                 sub2 (substring tagopen 0 (if (>= l 2) 2 1)))
   3425           )
   3426         ;;(message " found block #(%S) at pos=(%S), part-type=(%S)" i open (get-text-property open 'part-side))
   3427         (cond
   3428 
   3429           ((string= web-mode-engine "php")
   3430            (unless (member (char-after) '(?x ?X))
   3431              (setq closing-string '("<\\?". "\\?>")))
   3432            (cond
   3433              ((looking-at-p "<?php")
   3434               (setq delim-open "<?php")
   3435               (setq delim-close "?>"))
   3436              ((eq (char-after) ?\=)
   3437               (setq delim-open "<?=")
   3438               (setq delim-close "?>"))
   3439              (t
   3440               (setq delim-open "<?")
   3441               (setq delim-close "?>"))
   3442              ) ;cond
   3443            ) ;php
   3444 
   3445           ((string= web-mode-engine "erb")
   3446            (cond
   3447              ((string= sub2 "<%")
   3448               (setq closing-string '("<%". "%>")
   3449                     delim-open "<%\\(==\\|[=-]\\)?"
   3450                     delim-close "[-]?%>"))
   3451              (t
   3452               (setq closing-string "EOL"
   3453                     delim-open "%"))
   3454              )
   3455            ) ;erb
   3456 
   3457           ((string= web-mode-engine "django")
   3458            (cond
   3459              ((string= sub2 "{{")
   3460               (setq closing-string "EODQ"
   3461                     ;;(setq closing-string '("{{" . "}}")
   3462                     delim-open "{{"
   3463                     delim-close "}}"))
   3464              ((string= sub2 "{%")
   3465               (setq closing-string "%}"
   3466                     delim-open "{%[+-]?"
   3467                     delim-close "[-]?%}"))
   3468              ((string= sub2 "{#")
   3469               (setq closing-string "#}"))
   3470              (t
   3471               (setq closing-string "EOL"
   3472                     delim-open "#[#]?"))
   3473              )
   3474            ) ;django
   3475 
   3476           ((string= web-mode-engine "anki")
   3477            (setq closing-string "}}"
   3478                  delim-open "{{[#/^]?"
   3479                  delim-close "}}")
   3480            ) ;anki
   3481 
   3482           ((string= web-mode-engine "ejs")
   3483            (setq closing-string "%>"
   3484                  delim-open "<%[=-]?"
   3485                  delim-close "[-]?%>")
   3486            ) ;ejs
   3487 
   3488           ((string= web-mode-engine "lsp")
   3489            (setq closing-string "%>"
   3490                  delim-open "<%[%#]?"
   3491                  delim-close "%>")
   3492            ) ;lsp
   3493 
   3494           ((string= web-mode-engine "mako")
   3495            (cond
   3496              ((and (string= tagopen "<%")
   3497                    (member (char-after) '(?\s ?\n ?\!)))
   3498               (setq closing-string "%>"
   3499                     delim-open "<%[!]?"
   3500                     delim-close "%>"))
   3501              ((member sub2 '("<%" "</"))
   3502               (setq closing-string ">"
   3503                     delim-open "</?%"
   3504                     delim-close "/?>"))
   3505              ((string= sub2 "${")
   3506               (setq closing-string "}"
   3507                     delim-open "${"
   3508                     delim-close "}"))
   3509              (t
   3510               (setq closing-string "EOL"
   3511                     delim-open "%"))
   3512              )
   3513            ) ;mako
   3514 
   3515           ((string= web-mode-engine "cl-emb")
   3516            (cond
   3517              ((string= tagopen "<%#")
   3518               (setq closing-string "#%>"))
   3519              ((string= sub2 "<%")
   3520               (setq closing-string "%>"
   3521                     delim-open "<%[=%]?"
   3522                     delim-close "%>"))
   3523              )
   3524            ) ;cl-emb
   3525 
   3526           ((string= web-mode-engine "artanis")
   3527            (cond
   3528              ((string= tagopen "<%;")
   3529               (setq closing-string "%>"))
   3530              ((string= tagopen "<%#|")
   3531               (setq closing-string "|#%>"))
   3532              ((string= sub2 "<@")
   3533               (setq closing-string "%>"
   3534                     delim-open "<@\\(css\\|icon\\|include\\|js\\)"
   3535                     delim-close "%>"))
   3536              ((string= sub2 "<%")
   3537               (setq closing-string "%>"
   3538                     delim-open "<%[=]?"
   3539                     delim-close "%>"))
   3540              )
   3541            ) ;artanis
   3542 
   3543           ((string= web-mode-engine "elixir")
   3544            (cond
   3545              ((member (char-after) '(?\#))
   3546               (setq closing-string "%>"))
   3547              (t
   3548               (setq closing-string "%>"
   3549                     delim-open "<%[=%]?"
   3550                     delim-close "%>"))
   3551              )
   3552            ) ;elixir
   3553 
   3554           ((string= web-mode-engine "mojolicious")
   3555            (cond
   3556              ((string= tagopen "<%#")
   3557               (setq closing-string "%>"))
   3558              ((string= sub2 "<%")
   3559               (setq closing-string "%>"
   3560                     delim-open "<%\\(==\\|[=%]\\)?"
   3561                     delim-close "%>"))
   3562              ((string= sub2 "%#")
   3563               (setq closing-string "EOL"))
   3564              (t
   3565               (setq closing-string "EOL"
   3566                     delim-open "%\\(==\\|[=%]\\)?"))
   3567              )
   3568            ) ;mojolicious
   3569 
   3570           ((string= web-mode-engine "ctemplate")
   3571            (cond
   3572              ((member tagopen '("{{{" "{{~"))
   3573               (setq closing-string "}~?}}"
   3574                     delim-open "{{~?{"
   3575                     delim-close "}~?}}")
   3576               )
   3577              ((string= tagopen "{~{")
   3578               (setq closing-string "}~?}"
   3579                     delim-open "{~{"
   3580                     delim-close "}~?}")
   3581               )
   3582              ((string= tagopen "{{!")
   3583               (setq closing-string (if (looking-at-p "--") "--}}" "}}"))
   3584               )
   3585              ((string= sub2 "{{")
   3586               (setq closing-string "}~?}"
   3587                     delim-open "{{[>#/%^&]?"
   3588                     delim-close "}~?}"))
   3589              (t
   3590               (setq closing-string "}}"
   3591                     delim-open "${{"
   3592                     delim-close "}}"))
   3593              )
   3594            ) ;ctemplate
   3595 
   3596           ((string= web-mode-engine "antlers")
   3597            (cond
   3598              ((string= tagopen "{{$")
   3599               (setq closing-string "$}}"
   3600                     delim-open "{{$"
   3601                     delim-close "$}}")
   3602               )
   3603              ((string= tagopen "{{?")
   3604               (setq closing-string "?}}"
   3605                     delim-open "{{?"
   3606                     delim-close "?}}")
   3607               )
   3608              ((string= tagopen "{{$")
   3609               (setq closing-string "$}}"
   3610                     delim-open "{{$"
   3611                     delim-close "$}}")
   3612               )
   3613              ((string= sub2 "{{")
   3614               (setq closing-string "}}"
   3615                     delim-open "{{"
   3616                     delim-close "}}"))
   3617              )
   3618            ) ;antlers
   3619 
   3620           ((string= web-mode-engine "astro")
   3621            (cond
   3622              ((string= tagopen "---")
   3623               (setq closing-string "---"
   3624                     delim-open "---"
   3625                     delim-close "---")
   3626               )
   3627              )
   3628            ) ;astro
   3629 
   3630           ((string= web-mode-engine "aspx")
   3631            (setq closing-string "%>"
   3632                  delim-open "<%[:=#@$]?"
   3633                  delim-close "%>")
   3634            ) ;aspx
   3635 
   3636           ((string= web-mode-engine "asp")
   3637            (cond
   3638              ((string= sub2 "<%")
   3639               (setq closing-string "%>"
   3640                     delim-open "<%[:=#@$]?"
   3641                     delim-close "%>"))
   3642              (t
   3643               (setq closing-string ">"
   3644                     delim-open "</?"
   3645                     delim-close "/?>"))
   3646              )
   3647            ) ;asp
   3648 
   3649           ((string= web-mode-engine "jsp")
   3650            (cond
   3651              ((looking-at-p "--")
   3652               (setq closing-string "--%>"))
   3653              ((string= sub2 "<%")
   3654               (setq closing-string "%>"
   3655                     delim-open "<%\\([!=@]\\|#=\\)?"
   3656                     delim-close "[-]?%>"))
   3657              ((string= sub2 "${")
   3658               (setq closing-string "}"
   3659                     delim-open "${"
   3660                     delim-close "}"))
   3661              )
   3662            ) ;jsp
   3663 
   3664           ((string= web-mode-engine "clip")
   3665            (setq closing-string ">"
   3666                  delim-open "</?"
   3667                  delim-close "/?>")
   3668            ) ;clip
   3669 
   3670           ((string= web-mode-engine "perl")
   3671            (setq closing-string ">"
   3672                  delim-open "</?"
   3673                  delim-close "/?>")
   3674            ) ;perl
   3675 
   3676           ((string= web-mode-engine "blade")
   3677            (cond
   3678              ((string= tagopen "{{-")
   3679               (setq closing-string "--}}"))
   3680              ((string= tagopen "{!!")
   3681               (setq closing-string "!!}"
   3682                     delim-open "{!!"
   3683                     delim-close "!!}"))
   3684              ((string= tagopen "@{{")
   3685               (setq closing-string nil))
   3686              ((string= tagopen "{{{")
   3687               (setq closing-string "}}}"
   3688                     delim-open "{{{"
   3689                     delim-close "}}}"))
   3690              ((string= sub2 "{{")
   3691               (setq closing-string "}}"
   3692                     delim-open "{{"
   3693                     delim-close "}}"))
   3694              ((looking-at-p "[[:alnum:]]+\\.[[:alpha:]]+")
   3695               )
   3696              ((string= sub1 "@")
   3697               (setq closing-string "EOB"
   3698                     delim-open "@"))
   3699              ((looking-at-p "[[:alnum:]]+(")
   3700               (setq closing-string ")"
   3701                     delim-open "@"))
   3702              )
   3703            ;;(message "closing-string=%S delim-open=%S delim-close=%S" closing-string delim-open delim-close)
   3704            ) ;blade
   3705 
   3706           ((string= web-mode-engine "smarty")
   3707            (cond
   3708              ((string= tagopen "{*")
   3709               (setq closing-string "*}")
   3710               )
   3711              ((string= tagopen "{#")
   3712               (setq closing-string "#}"
   3713                     delim-open "{#"
   3714                     delim-close "#}")
   3715               )
   3716              (t
   3717               (setq closing-string (cons "{" "}")
   3718                     delim-open "{/?"
   3719                     delim-close "}")
   3720               ) ;t
   3721              ) ;cond
   3722            ) ;smarty
   3723 
   3724           ((string= web-mode-engine "hero")
   3725            (setq closing-string "%>"
   3726                  delim-open "<%==?\\([biufsv]\\|bs\\)?\\|<%[:~@+!]?"
   3727                  delim-close "%>")
   3728            ) ;hero
   3729 
   3730           ((string= web-mode-engine "xoops")
   3731            (cond
   3732              ((string= tagopen "<{*")
   3733               (setq closing-string "*}>")
   3734               )
   3735              ((string= tagopen "<{#")
   3736               (setq closing-string "#}>"
   3737                     delim-open "<{#"
   3738                     delim-close "#}>")
   3739               )
   3740              (t
   3741               (setq closing-string (cons "<{" "}>")
   3742                     delim-open "<{/?"
   3743                     delim-close "}>")
   3744               ) ;t
   3745              ) ;cond
   3746            ) ;xoops
   3747 
   3748           ((string= web-mode-engine "web2py")
   3749            (setq closing-string "}}"
   3750                  delim-open "{{[=]?"
   3751                  delim-close "}}")
   3752            ) ;web2py
   3753 
   3754           ((string= web-mode-engine "expressionengine")
   3755            (cond
   3756              ((string= sub2 "{!--")
   3757               (setq closing-string "--}"))
   3758              (t
   3759               (setq closing-string '("{". "}")
   3760                     delim-open "{/?"
   3761                     delim-close "}")
   3762               )
   3763              )
   3764            ) ;expressionengine
   3765 
   3766           ((string= web-mode-engine "dust")
   3767            (cond
   3768              ((string= sub2 "{!")
   3769               (setq closing-string "!}"))
   3770              (t
   3771               (setq closing-string '("{". "}")
   3772                     delim-open "{[#/:?@><+^]?"
   3773                     delim-close "/?}")
   3774               )
   3775              )
   3776            ) ;dust
   3777 
   3778           ((string= web-mode-engine "svelte")
   3779            (cond
   3780              ((string= sub2 "{!")
   3781               (setq closing-string "!}"))
   3782              ((string= sub2 "{}")
   3783               (setq closing-string nil
   3784                     delim-open nil
   3785                     delim-close nil))
   3786              (t
   3787               (setq closing-string '("{". "}")
   3788                     delim-open "{[#/:?@><+^]?"
   3789                     delim-close "/?}")
   3790               )
   3791              )
   3792            ) ;svelte
   3793 
   3794           ((string= web-mode-engine "closure")
   3795            (cond
   3796              ((string= sub2 "//")
   3797               (setq closing-string "EOL")
   3798               )
   3799              ((string= sub2 "/*")
   3800               (setq closing-string "*/")
   3801               )
   3802              (t
   3803               (setq closing-string "}"
   3804                     delim-open "{/?"
   3805                     delim-close "/?}")
   3806               )
   3807              )
   3808            ) ;closure
   3809 
   3810           ((string= web-mode-engine "go")
   3811            (setq closing-string "}}"
   3812                  delim-open "{{-?"
   3813                  delim-close "-?}}")
   3814            ) ;go
   3815 
   3816           ((string= web-mode-engine "angular")
   3817            (setq closing-string "}}"
   3818                  delim-open "{{"
   3819                  delim-close "}}")
   3820            ) ;angular
   3821 
   3822           ((string= web-mode-engine "vue")
   3823            (cond
   3824              ((string-match-p "[:@][-[:alpha:]]+=\"" tagopen)
   3825               (setq closing-string "\""
   3826                     delim-open tagopen
   3827                     delim-close "\""))
   3828              ((string= tagopen "{{")
   3829               (setq closing-string "}}"
   3830                     delim-open "{{"
   3831                     delim-close "}}")))
   3832            ) ;vue
   3833 
   3834           ((string= web-mode-engine "mason")
   3835            (cond
   3836              ((and (member sub2 '("<%" "</"))
   3837                    (looking-at "[[:alpha:]]+"))
   3838               (if (member (match-string-no-properties 0) '("after" "around" "augment" "before" "def" "filter" "method" "override"))
   3839                   (setq closing-string ">"
   3840                         delim-open "<[/]?%"
   3841                         delim-close ">")
   3842                   (setq closing-string (concat "</%" (match-string-no-properties 0) ">")
   3843                         delim-open "<[^>]+>"
   3844                         delim-close "<[^>]+>")
   3845                   ) ;if
   3846               )
   3847              ((and (string= sub2 "<%")
   3848                    (eq (char-after) ?\s))
   3849               (setq closing-string "%>"
   3850                     delim-open "<%"
   3851                     delim-close "%>"))
   3852              ((string= tagopen "</&")
   3853               (setq closing-string ">"
   3854                     delim-open "</&"
   3855                     delim-close ">")
   3856               )
   3857              ((string= sub2 "<&")
   3858               (setq closing-string "&>"
   3859                     delim-open "<&[|]?"
   3860                     delim-close "&>"))
   3861              (t
   3862               (setq closing-string "EOL"
   3863                     delim-open "%"))
   3864              )
   3865            ) ;mason
   3866 
   3867           ((string= web-mode-engine "underscore")
   3868            (setq closing-string "%>"
   3869                  delim-open "<%"
   3870                  delim-close "%>")
   3871            ) ;underscore
   3872 
   3873           ((string= web-mode-engine "template-toolkit")
   3874            (cond
   3875              ((string= tagopen "%%#")
   3876               (setq closing-string "EOL"))
   3877              ((string= tagopen "[%#")
   3878               (setq closing-string "%]"))
   3879              (t
   3880               (setq closing-string "%]"
   3881                     delim-open "\\[%[-+]?"
   3882                     delim-close "[-=+]?%\\]"))
   3883              )
   3884            ) ;template-toolkit
   3885 
   3886           ((string= web-mode-engine "freemarker")
   3887            (cond
   3888              ((and (string= sub2 "<#") (eq (char-after) ?\-))
   3889               (setq closing-string "-->"))
   3890              ((string= sub1 "<")
   3891               (setq closing-string ">"
   3892                     delim-open "</?[#@]"
   3893                     delim-close "/?>"))
   3894              ((string= sub1 "[")
   3895               (setq closing-string "]"
   3896                     delim-open "\\[/?[#@]"
   3897                     delim-close "/?\\]"))
   3898              (t
   3899               (setq closing-string "}"
   3900                     delim-open "${"
   3901                     delim-close "}"))
   3902              )
   3903            ) ;freemarker
   3904 
   3905           ((string= web-mode-engine "velocity")
   3906            (cond
   3907              ((string= sub2 "##")
   3908               (setq closing-string "EOL"))
   3909              ((string= sub2 "#*")
   3910               (setq closing-string "*#"))
   3911              (t
   3912               (setq closing-string "EOV"
   3913                     delim-open "#"))
   3914              )
   3915            ) ;velocity
   3916 
   3917           ((string= web-mode-engine "razor")
   3918            (cond
   3919              ((string= sub2 "@@")
   3920               (forward-char 2)
   3921               (setq closing-string nil))
   3922              ((string= sub2 "@*")
   3923               (setq closing-string "*@"))
   3924              ((string= sub1 "@")
   3925               (setq closing-string "EOR"
   3926                     delim-open "@"))
   3927              ((and (string= sub1 "}")
   3928                    (looking-at-p "[ ]*\n"))
   3929               ;;(setq closing-string "EOC")
   3930               (save-excursion
   3931                 (let (paren-pos)
   3932                   (setq paren-pos (web-mode-part-opening-paren-position (1- (point))))
   3933                   (if (and paren-pos (get-text-property paren-pos 'block-side))
   3934                       (setq closing-string "EOC")
   3935                       (setq closing-string nil)
   3936                       ) ;if
   3937                   ) ;let
   3938                 ) ;save-excursion
   3939               ;;(message "%s %S %S" sub2 (point) (get-text-property (point) 'part-side))
   3940               )
   3941              ((string= sub1 "}")
   3942               ;;(message "%s: %s" (point) sub1)
   3943               (save-excursion
   3944                 (let (paren-pos)
   3945                   (setq paren-pos (web-mode-part-opening-paren-position (1- (point))))
   3946                   (if (and paren-pos (get-text-property paren-pos 'block-side))
   3947                       (setq closing-string "EOR")
   3948                       (setq closing-string nil)
   3949                       ) ;if
   3950                   ) ;let
   3951                 ) ;save-excursion
   3952               ) ;case }
   3953              ) ;cond
   3954            ) ;razor
   3955 
   3956           ((and (string= web-mode-engine "riot")
   3957                 (not (get-text-property open 'part-side)))
   3958            (setq closing-string (if (string= tagopen "{") "}" "/// end script")
   3959                  delim-open "{"
   3960                  delim-close "}")
   3961            ) ;riot
   3962 
   3963           ((string= web-mode-engine "spip")
   3964            (cond
   3965              ((and (string= sub1 "#")
   3966                    (looking-at "[A-Z0-9_]+"))
   3967               (setq closing-string (match-string-no-properties 0)))
   3968              ((string= sub1 "(")
   3969               (setq closing-string '("(" . ")")))
   3970              ((string= sub1 "{")
   3971               (setq closing-string '("{" . "}")))
   3972              ((string= sub2 "<:")
   3973               (setq closing-string ":>"))
   3974              (t
   3975               (setq closing-string "]"))
   3976              ))
   3977 
   3978           ((string= web-mode-engine "marko")
   3979            (setq closing-string "}"
   3980                  delim-open "${"
   3981                  delim-close "}")
   3982            ) ;marko
   3983 
   3984           ) ;cond
   3985 
   3986         (when closing-string
   3987           (cond
   3988 
   3989             ((listp closing-string)
   3990              (cond
   3991                ((web-mode-rsf-balanced (car closing-string) (cdr closing-string) reg-end t)
   3992                 (setq close (match-end 0)
   3993                       pos (point))
   3994                 )
   3995                ((and (string= web-mode-engine "php")
   3996                      (string= "<?" sub2))
   3997 
   3998                 (if (or (text-property-not-all (1+ open) (point-max) 'tag-beg nil)
   3999                         (text-property-not-all (1+ open) (point-max) 'block-beg nil)
   4000                         (looking-at-p "[ \t\n]*<"))
   4001                     (setq close nil
   4002                           delim-close nil
   4003                           pos (point))
   4004                     (setq close (point-max)
   4005                           delim-close nil
   4006                           pos (point-max))
   4007                     ) ;if
   4008                 ) ;case
   4009                ) ;cond
   4010              ) ;case listp
   4011 
   4012             ((and (string= web-mode-engine "smarty")
   4013                   (string= closing-string "}"))
   4014              (goto-char open)
   4015              (setq tmp (web-mode-closing-delimiter-position
   4016                         "}"
   4017                         (point)
   4018                         (line-end-position)))
   4019              (if tmp
   4020                  (setq tmp (1+ tmp))
   4021                  (setq tmp (line-end-position)))
   4022              (goto-char tmp)
   4023              (setq close (point)
   4024                    pos (point))
   4025              )
   4026 
   4027             ((and (member web-mode-engine '("closure"))
   4028                   (string= closing-string "}"))
   4029              (when (web-mode-closure-skip reg-beg reg-end)
   4030                (setq close (point)
   4031                      pos (point))
   4032                ;;(message "close=%S pos=%S" close pos)
   4033                ) ;when
   4034              )
   4035 
   4036             ((string= closing-string "EOB")
   4037              (web-mode-blade-skip open)
   4038              (setq close (point)
   4039                    pos (point)))
   4040 
   4041             ((string= closing-string "EOL")
   4042              (end-of-line)
   4043              (setq close (point)
   4044                    pos (point)))
   4045 
   4046             ((string= closing-string "EOC")
   4047              (setq close (point)
   4048                    pos (point)))
   4049 
   4050             ((string= closing-string "EODQ")
   4051              (when (web-mode-django-skip reg-beg reg-end)
   4052                (setq close (point)
   4053                      pos (point))
   4054                ))
   4055 
   4056             ((string= closing-string "EOR")
   4057              (web-mode-razor-skip open)
   4058              (setq close (if (> (point) reg-end) reg-end (point))
   4059                    pos (if (> (point) reg-end) reg-end (point)))
   4060              (goto-char pos))
   4061 
   4062             ((string= closing-string "EOV")
   4063              (web-mode-velocity-skip open)
   4064              (setq close (point)
   4065                    pos (point)))
   4066 
   4067             ((and (member web-mode-engine '("ctemplate"))
   4068                   (re-search-forward closing-string reg-end t))
   4069              (setq close (match-end 0)
   4070                    pos (point)))
   4071 
   4072             ((and (member web-mode-engine '("antlers"))
   4073                   (re-search-forward closing-string reg-end t))
   4074              (setq close (match-end 0)
   4075                    pos (point)))
   4076 
   4077             ((and (member web-mode-engine '("astro"))
   4078                   (re-search-forward closing-string reg-end t))
   4079              (setq close (match-end 0)
   4080                    pos (point)))
   4081 
   4082             ((search-forward closing-string reg-end t)
   4083              (setq close (match-end 0)
   4084                    pos (point)))
   4085             ) ;cond
   4086 
   4087           (when (and close (>= reg-end pos))
   4088             ;;(message "pos(%S) : open(%S) close(%S)" pos open close)
   4089             (put-text-property open (1+ open) 'block-beg 0)
   4090             (put-text-property open (1+ open) 'block-controls 0)
   4091             (put-text-property open close 'block-side t)
   4092             (put-text-property (1- close) close 'block-end t)
   4093             (when delim-open
   4094               (web-mode-block-delimiters-set open close delim-open delim-close))
   4095             (web-mode-block-scan open close)
   4096             (cond
   4097               ((and (string= web-mode-engine "erb")
   4098                     (looking-at-p "<%= javascript_tag do %>"))
   4099                (setq tagopen "<%= javascript_tag do %>"))
   4100               ((and (string= web-mode-engine "mojolicious")
   4101                     (looking-at-p "%= javascript begin"))
   4102                (setq tagopen "%= javascript begin"))
   4103               ((and (string= web-mode-engine "mako")
   4104                     (looking-at-p "<%block filter=\"collect_js\">"))
   4105                (setq tagopen "<%block filter=\"collect_js\">"))
   4106               ((and (string= web-mode-engine "mako")
   4107                     (looking-at-p "<%block filter=\"collect_css\">"))
   4108                (setq tagopen "<%block filter=\"collect_css\">"))
   4109               ((and (string= web-mode-engine "django")
   4110                     (looking-at-p "{% javascript %}"))
   4111                (setq tagopen "{% javascript %}"))
   4112               ((and (string= web-mode-engine "django")
   4113                     (looking-at-p "{% schema %}"))
   4114                (setq tagopen "{% schema %}"))
   4115               ((and (string= web-mode-engine "django")
   4116                     (looking-at-p "{% stylesheet %}"))
   4117                (setq tagopen "{% stylesheet %}"))
   4118               )
   4119             ;;(message "%S %s" (point) tagopen)
   4120             (when (and (member tagopen '("<r:script" "<r:style"
   4121                                          "<c:js" "<c:css"
   4122                                          "<%= javascript_tag do %>"
   4123                                          "<%block filter=\"collect_js\">"
   4124                                          "<%block filter=\"collect_css\">"
   4125                                          "{% javascript %}"
   4126                                          "{% schema %}"
   4127                                          "{% stylesheet %}"
   4128                                          "%= javascript begin"
   4129                                          "---"))
   4130                        (setq part-beg close)
   4131                        (setq tagclose
   4132                              (cond
   4133                                ((string= tagopen "<r:script") "</r:script")
   4134                                ((string= tagopen "<r:style") "</r:style")
   4135                                ((string= tagopen "<c:js") "</c:js")
   4136                                ((string= tagopen "<c:css") "</c:css")
   4137                                ((string= tagopen "{% javascript %}") "{% endjavascript %}")
   4138                                ((string= tagopen "{% schema %}") "{% endschema %}")
   4139                                ((string= tagopen "{% stylesheet %}") "{% endstylesheet %}")
   4140                                ((string= tagopen "%= javascript begin") "% end")
   4141                                ((string= tagopen "---") "---")
   4142                                ((string= tagopen "<%= javascript_tag do %>") "<% end %>")
   4143                                ((member tagopen '("<%block filter=\"collect_js\">"
   4144                                                   "<%block filter=\"collect_css\">")) "</%block")
   4145                                ))
   4146                        (web-mode-sf tagclose)
   4147                        (setq part-end (match-beginning 0))
   4148                        (> part-end part-beg))
   4149               ;;(message "tagopen=%S tagclose=%S end=%S" tagopen tagclose (point))
   4150               (put-text-property part-beg part-end
   4151                                  'part-side
   4152                                  (cond
   4153                                    ((member tagopen '("<r:style" "<c:css" "<%block filter=\"collect_css\">" "{% stylesheet %}")) 'css)
   4154                                    (t 'javascript)))
   4155               (setq pos part-beg
   4156                     part-beg nil
   4157                     part-end nil)
   4158               ) ;when
   4159             ) ;when close
   4160 
   4161           (if pos (goto-char pos))
   4162 
   4163           ) ;when closing-string
   4164 
   4165         ) ;while
   4166 
   4167       (cond
   4168         ((>= i 2000)
   4169          (message "scan-blocks ** warning (%S) **" i))
   4170         ((string= web-mode-engine "razor")
   4171          (web-mode-block-foreach reg-beg reg-end 'web-mode-block-scan))
   4172         ((string= web-mode-engine "django")
   4173          (web-mode-scan-engine-comments reg-beg reg-end
   4174                                         "{% comment %}" "{% endcomment %}"))
   4175         ((string= web-mode-engine "mako")
   4176          (web-mode-scan-engine-comments reg-beg reg-end
   4177                                         "<%doc>" "</%doc>"))
   4178         ((string= web-mode-engine "mason")
   4179          (web-mode-scan-engine-comments reg-beg reg-end
   4180                                         "<%doc>" "</%doc>"))
   4181         ) ;cond
   4182 
   4183       )))
   4184 
   4185 (defun web-mode-scan-engine-comments (reg-beg reg-end tag-start tag-end)
   4186   "Scan engine comments (mako, django)."
   4187   (save-excursion
   4188     (let (beg end (continue t))
   4189       (goto-char reg-beg)
   4190       (while (and continue
   4191                   (< (point) reg-end)
   4192                   (re-search-forward tag-start reg-end t))
   4193         (goto-char (match-beginning 0))
   4194         (setq beg (point))
   4195         (if (not (re-search-forward tag-end reg-end t))
   4196             (setq continue nil)
   4197             (setq end (point))
   4198             (remove-list-of-text-properties beg end web-mode-scan-properties)
   4199             (add-text-properties beg end '(block-side t block-token comment))
   4200             (put-text-property beg (1+ beg) 'block-beg 0)
   4201             (put-text-property (1- end) end 'block-end t)
   4202             ) ;if
   4203         ) ;while
   4204       )))
   4205 
   4206 (defun web-mode-closure-skip (reg-beg reg-end)
   4207   (let (regexp char pos inc continue found)
   4208     (setq regexp "[\"'{}]"
   4209           inc 0)
   4210     (while (and (not found) (re-search-forward regexp reg-end t))
   4211       (setq char (char-before))
   4212       (cond
   4213         ((get-text-property (point) 'block-side)
   4214          (setq found t))
   4215         ((eq char ?\{)
   4216          (setq inc (1+ inc)))
   4217         ((eq char ?\})
   4218          (cond
   4219            ((and (not (eobp))
   4220                  (< inc 1))
   4221             (setq found t
   4222                   pos (point)))
   4223            ((> inc 0)
   4224             (setq inc (1- inc)))
   4225            )
   4226          )
   4227         ((eq char ?\')
   4228          (setq continue t)
   4229          (while (and continue (search-forward "'" reg-end t))
   4230            (setq continue (web-mode-string-continue-p reg-beg))
   4231            )
   4232          )
   4233         ((eq char ?\")
   4234          (setq continue t)
   4235          (while (and continue (search-forward "\"" reg-end t))
   4236            (setq continue (web-mode-string-continue-p reg-beg))
   4237            )
   4238          )
   4239         ) ;cond
   4240       ) ;while
   4241     pos))
   4242 
   4243 (defun web-mode-django-skip (reg-beg reg-end)
   4244   (let (regexp char pos inc continue found)
   4245     (setq regexp "[\"'{}]"
   4246           inc 0)
   4247     (while (and (not found) (re-search-forward regexp reg-end t))
   4248       (setq char (char-before))
   4249       (cond
   4250         ((get-text-property (point) 'block-side)
   4251          (setq found t))
   4252         ((eq char ?\{)
   4253          (setq inc (1+ inc)))
   4254         ((eq char ?\})
   4255          (cond
   4256            ((and (not (eobp))
   4257                  (eq (char-after) ?\})
   4258                  (< inc 2))
   4259             (forward-char)
   4260             (setq found t
   4261                   pos (1+ (point))))
   4262            ((> inc 0)
   4263             (setq inc (1- inc)))
   4264            )
   4265          )
   4266         ((eq char ?\')
   4267          (setq continue t)
   4268          (while (and continue (search-forward "'" reg-end t))
   4269            (setq continue (web-mode-string-continue-p reg-beg))
   4270            )
   4271          )
   4272         ((eq char ?\")
   4273          (setq continue t)
   4274          (while (and continue (search-forward "\"" reg-end t))
   4275            (setq continue (web-mode-string-continue-p reg-beg))
   4276            )
   4277          )
   4278         ) ;cond
   4279       ) ;while
   4280     pos))
   4281 
   4282 (defun web-mode-blade-skip (pos)
   4283   (let (regexp char inc continue found (reg-beg pos) (reg-end (point-max)))
   4284     ;;(message "pos=%S" pos)
   4285     (goto-char pos)
   4286     (forward-char)
   4287     (skip-chars-forward "a-zA-Z0-9_-")
   4288     (when (eq (char-after) ?\()
   4289       (setq regexp "[\"'()]"
   4290             inc 0)
   4291       (while (and (not found) (re-search-forward regexp reg-end t))
   4292         (setq char (char-before))
   4293         ;;(message "point=%S char=%c inc=%S" (point) char inc)
   4294         (cond
   4295          ((eq char ?\()
   4296           (setq inc (1+ inc)))
   4297          ((eq char ?\))
   4298           (cond
   4299            ((and (not (eobp))
   4300                  (< inc 2))
   4301             (forward-char)
   4302             (setq inc (1- inc))
   4303             (setq found t)
   4304             )
   4305            ((> inc 0)
   4306             (setq inc (1- inc)))
   4307            )
   4308           )
   4309          ((eq char ?\')
   4310           (setq continue t)
   4311           (while (and continue (search-forward "'" reg-end t))
   4312             (setq continue (web-mode-string-continue-p reg-beg))
   4313             )
   4314           )
   4315          ((eq char ?\")
   4316           (setq continue t)
   4317           (while (and continue (search-forward "\"" reg-end t))
   4318             (setq continue (web-mode-string-continue-p reg-beg))
   4319             )
   4320           )
   4321          ) ;cond
   4322         ;;(message "inc=%S found=%S" inc found)
   4323         ) ;while
   4324       ) ; when
   4325     ;;(message "point=%S inc=%S" (point) inc)
   4326     (when found (backward-char))
   4327   ))
   4328 
   4329 (defun web-mode-velocity-skip (pos)
   4330   (goto-char pos)
   4331   (let ((continue t) (i 0))
   4332     (when (eq ?\# (char-after))
   4333       (forward-char))
   4334     (when (member (char-after) '(?\$ ?\@))
   4335       (forward-char))
   4336     (when (member (char-after) '(?\!))
   4337       (forward-char))
   4338     (cond
   4339       ((member (char-after) '(?\{))
   4340        (search-forward "}" nil t))
   4341       ((looking-at-p "def \\|define ")
   4342        (search-forward ")" (line-end-position) t))
   4343       (t
   4344        (setq continue t)
   4345        (while continue
   4346          (skip-chars-forward "a-zA-Z0-9_-")
   4347          (when (> (setq i (1+ i)) 500)
   4348            (message "velocity-skip ** warning (%S) **" pos)
   4349            (setq continue nil))
   4350          (when (member (char-after) '(?\())
   4351            (search-forward ")" nil t))
   4352          (if (member (char-after) '(?\.))
   4353              (forward-char)
   4354              (setq continue nil))
   4355          ) ;while
   4356        ) ;t
   4357       ) ;cond
   4358     ))
   4359 
   4360 (defun web-mode-razor-skip (pos)
   4361   (goto-char pos)
   4362   (let ((continue t) (i 0))
   4363     (while continue
   4364       (skip-chars-forward " =@a-zA-Z0-9_-")
   4365       (cond
   4366         ((> (setq i (1+ i)) 500)
   4367          (message "razor-skip ** warning **")
   4368          (setq continue nil))
   4369         ((and (eq (char-after) ?\*)
   4370               (eq (char-before) ?@))
   4371          (when (not (search-forward "*@" nil t))
   4372            (setq continue nil))
   4373          )
   4374         ((looking-at-p "@[({]")
   4375          (forward-char)
   4376          (when (setq pos (web-mode-closing-paren-position (point)))
   4377            (goto-char pos))
   4378          (forward-char)
   4379          )
   4380         ((and (not (eobp)) (eq ?\( (char-after)))
   4381          (cond
   4382            ((looking-at-p "[ \n]*[<@]")
   4383             (setq continue nil))
   4384            ((setq pos (web-mode-closing-paren-position))
   4385             (goto-char pos)
   4386             (forward-char))
   4387            (t
   4388             (forward-char))
   4389            ) ;cond
   4390          )
   4391         ((and (not (eobp)) (eq ?\< (char-after)) (looking-back "[a-z]" (point-min)))
   4392          (setq pos (point))
   4393          (cond
   4394            ;; #988
   4395            ((search-forward ">" (line-end-position) t)
   4396             (goto-char pos)
   4397             (setq continue nil)
   4398             )
   4399            (t
   4400             (setq continue nil))
   4401            ) ;cond
   4402          )
   4403         ((and (not (eobp)) (eq ?\. (char-after)))
   4404          (forward-char))
   4405         ((and (not (eobp)) (looking-at-p "[ \n]*else"))
   4406          (re-search-forward "[ \t]*else")
   4407          )
   4408         ((looking-at-p "[ \n]*{")
   4409          (search-forward "{")
   4410          (search-forward "=>" (line-end-position) 't)
   4411          (if (looking-at-p "[ \n]*[<@]")
   4412              (setq continue nil)
   4413              (backward-char)
   4414              (when (setq pos (web-mode-closing-paren-position))
   4415                (goto-char pos))
   4416              (forward-char)
   4417              ) ;if
   4418          )
   4419         ((looking-at-p "}")
   4420          (forward-char))
   4421         (t
   4422          (setq continue nil))
   4423         ) ;cond
   4424       ) ;while
   4425     ))
   4426 
   4427 (defun web-mode-block-delimiters-set (reg-beg reg-end delim-open delim-close)
   4428   "Set text-property `block-token' to `delimiter-(beg|end)' on block delimiters
   4429 (e.g. <?php and ?>)"
   4430   ;;(message "reg-beg(%S) reg-end(%S) delim-open(%S) delim-close(%S)" reg-beg reg-end delim-open delim-close)
   4431   (when (member web-mode-engine
   4432                 '("artanis" "anki" "antlers" "asp" "aspx"
   4433                   "cl-emb" "clip" "closure" "ctemplate" "django" "dust"
   4434                   "elixir" "ejs" "erb" "expressionengine" "freemarker" "go" "hero" "jsp" "lsp"
   4435                   "mako" "mason" "mojolicious"
   4436                   "perl"
   4437                   "smarty" "template-toolkit" "web2py" "xoops" "svelte"))
   4438     (save-excursion
   4439       (when delim-open
   4440         (goto-char reg-beg)
   4441         (looking-at delim-open)
   4442         (setq delim-open (match-string-no-properties 0)))
   4443       (when delim-close
   4444         (goto-char reg-end)
   4445         (looking-back delim-close reg-beg t)
   4446         (setq delim-close (match-string-no-properties 0)))
   4447       ))
   4448   (when delim-open
   4449     (put-text-property reg-beg (+ reg-beg (length delim-open))
   4450                        'block-token 'delimiter-beg))
   4451   (when delim-close
   4452     (put-text-property (- reg-end (length delim-close)) reg-end
   4453                        'block-token 'delimiter-end))
   4454   )
   4455 
   4456 (defun web-mode-block-foreach (reg-beg reg-end func)
   4457   (let ((i 0) (continue t) (block-beg reg-beg) (block-end nil))
   4458     (while continue
   4459       (setq block-end nil)
   4460       (unless (get-text-property block-beg 'block-beg)
   4461         (setq block-beg (web-mode-block-next-position block-beg)))
   4462       (when (and block-beg (< block-beg reg-end))
   4463         (setq block-end (web-mode-block-end-position block-beg)))
   4464       (cond
   4465         ((> (setq i (1+ i)) 2000)
   4466          (message "process-blocks ** warning (%S) **" (point))
   4467          (setq continue nil))
   4468         ((or (null block-end) (> block-end reg-end))
   4469          (setq continue nil))
   4470         (t
   4471          (setq block-end (1+ block-end))
   4472          (funcall func block-beg block-end)
   4473          (setq block-beg block-end)
   4474          ) ;t
   4475         ) ;cond
   4476       ) ;while
   4477     ))
   4478 
   4479 (defun web-mode-block-scan (block-beg block-end)
   4480   (let (sub1 sub2 sub3 regexp token-type)
   4481 
   4482     ;;(message "block-beg=%S block-end=%S" block-beg block-end)
   4483     ;;(remove-text-properties block-beg block-end web-mode-scan-properties)
   4484 
   4485     (goto-char block-beg)
   4486 
   4487     (cond
   4488       ((>= (point-max) (+ block-beg 3))
   4489        (setq sub3 (buffer-substring-no-properties block-beg (+ block-beg 3))
   4490              sub2 (buffer-substring-no-properties block-beg (+ block-beg 2))
   4491              sub1 (buffer-substring-no-properties block-beg (+ block-beg 1)))
   4492        )
   4493       ((>= (point-max) (+ block-beg 2))
   4494        (setq sub3 (buffer-substring-no-properties block-beg (+ block-beg 2))
   4495              sub2 (buffer-substring-no-properties block-beg (+ block-beg 2))
   4496              sub1 (buffer-substring-no-properties block-beg (+ block-beg 1)))
   4497        )
   4498       (t
   4499        (setq sub1 (buffer-substring-no-properties block-beg (+ block-beg 1)))
   4500        (setq sub2 sub1
   4501              sub3 sub1)
   4502        )
   4503       )
   4504 
   4505     (cond
   4506 
   4507       ((member web-mode-engine '("php" "lsp" "python" "web2py" "mason"))
   4508        (setq regexp web-mode-engine-token-regexp))
   4509 
   4510       ((string= web-mode-engine "mako")
   4511        (cond
   4512          ((string= sub2 "##")
   4513           (setq token-type 'comment)
   4514           )
   4515          (t
   4516           (setq regexp web-mode-engine-token-regexp))
   4517          )
   4518        ) ;mako
   4519 
   4520       ((string= web-mode-engine "django")
   4521        (cond
   4522          ((member sub2 '("{{" "{%"))
   4523           (setq regexp "\"\\|'"))
   4524          ((string= sub2 "{#")
   4525           (setq token-type 'comment))
   4526          )
   4527        ) ;django
   4528 
   4529       ((string= web-mode-engine "ctemplate")
   4530        (cond
   4531          ((string= sub3 "{{!")
   4532           (setq token-type 'comment))
   4533          ((member sub2 '("{{"))
   4534           )
   4535          )
   4536        ) ;ctemplate
   4537 
   4538       ((string= web-mode-engine "antlers")
   4539        (cond
   4540          ((string= sub3 "{{#")
   4541           (setq token-type 'comment))
   4542          ((member sub2 '("{{"))
   4543           )
   4544          )
   4545        ) ;antlers
   4546 
   4547       ((string= web-mode-engine "astro")
   4548        (setq regexp "\"\\|'")
   4549        ) ;astro
   4550 
   4551       ((string= web-mode-engine "go")
   4552        (cond
   4553          ((string= sub3 "{{/")
   4554           (setq token-type 'comment))
   4555          ((string= sub2 "{{")
   4556           (setq regexp "\"\\|'"))
   4557          )
   4558        ) ;go
   4559 
   4560       ((string= web-mode-engine "hero")
   4561        (cond
   4562          ((string= sub3 "<%#")
   4563           (setq token-type 'comment))
   4564          (t
   4565           (setq regexp "\"\\|'"))
   4566          )
   4567        ) ;hero
   4568 
   4569       ((string= web-mode-engine "razor")
   4570        (cond
   4571          ((string= sub2 "@*")
   4572           (setq token-type 'comment))
   4573          (t
   4574           (setq regexp "//\\|@\\*\\|\"\\|'"))
   4575          )
   4576        ) ;razor
   4577 
   4578       ((string= web-mode-engine "blade")
   4579        (cond
   4580          ((string= sub3 "{{-")
   4581           (setq token-type 'comment))
   4582          (t
   4583           (setq regexp "\"\\|'"))
   4584          )
   4585        ) ;blade
   4586 
   4587       ((string= web-mode-engine "cl-emb")
   4588        (cond
   4589          ((string= sub3 "<%#")
   4590           (setq token-type 'comment))
   4591          (t
   4592           (setq regexp "\"\\|'"))
   4593          )
   4594        ) ;cl-emb
   4595 
   4596       ((string= web-mode-engine "artanis")
   4597        (cond
   4598          ((string= sub3 "<%;")
   4599           (setq token-type 'comment))
   4600          ((string= sub3 "<%#|")
   4601           (setq token-type 'comment))
   4602          (t
   4603           (setq regexp "\""))
   4604          )
   4605        ) ;artanis
   4606 
   4607       ((string= web-mode-engine "elixir")
   4608        (cond
   4609          ((string= sub3 "<%#")
   4610           (setq token-type 'comment))
   4611          (t
   4612           (setq regexp "\"\\|'"))
   4613          )
   4614        ) ;elixir
   4615 
   4616       ((string= web-mode-engine "mojolicious")
   4617        (cond
   4618          ((or (string= sub2 "%#") (string= sub3 "<%#"))
   4619           (setq token-type 'comment))
   4620          (t
   4621           (setq regexp "\"\\|'"))
   4622          )
   4623        ) ;mojolicious
   4624 
   4625       ((string= web-mode-engine "velocity")
   4626        (cond
   4627          ((member sub2 '("##" "#*"))
   4628           (setq token-type 'comment))
   4629          ((member sub1 '("$" "#"))
   4630           (setq regexp "\"\\|'"))
   4631          )
   4632        ) ;velocity
   4633 
   4634       ((string= web-mode-engine "jsp")
   4635        (cond
   4636          ((string= sub3 "<%-")
   4637           (setq token-type 'comment))
   4638          ((string= sub3 "<%@")
   4639           (setq regexp "/\\*"))
   4640          ((member sub2 '("${" "#{"))
   4641           (setq regexp "\"\\|'"))
   4642          ((string= sub2 "<%")
   4643           (setq regexp "//\\|/\\*\\|\"\\|'"))
   4644          )
   4645        ) ;jsp
   4646 
   4647       ((string= web-mode-engine "clip")
   4648        (setq regexp nil)
   4649        ) ;clip
   4650 
   4651       ((string= web-mode-engine "perl")
   4652        (setq regexp nil)
   4653        ) ;perl
   4654 
   4655       ((and (string= web-mode-engine "asp")
   4656             (string= sub2 "<%"))
   4657        (setq regexp "//\\|/\\*\\|\"\\|'")
   4658        ) ;asp
   4659 
   4660       ((string= web-mode-engine "aspx")
   4661        (cond
   4662          ((string= sub3 "<%-")
   4663           (setq token-type 'comment))
   4664          ((string= sub3 "<%@")
   4665           (setq regexp "/\\*"))
   4666          ((string= sub3 "<%$")
   4667           (setq regexp "\"\\|'"))
   4668          (t
   4669           (setq regexp "//\\|/\\*\\|\"\\|'"))
   4670          )
   4671        ) ;aspx
   4672 
   4673       ((string= web-mode-engine "freemarker")
   4674        (cond
   4675          ((member sub3 '("<#-" "[#-"))
   4676           (setq token-type 'comment))
   4677          ((member sub2 '("${" "#{"))
   4678           (setq regexp "\"\\|'"))
   4679          ((or (member sub2 '("<@" "[@" "<#" "[#"))
   4680               (member sub3 '("</@" "[/@" "</#" "[/#")))
   4681           (setq regexp "\"\\|'"))
   4682          )
   4683        ) ;freemarker
   4684 
   4685       ((member web-mode-engine '("ejs" "erb"))
   4686        (cond
   4687          ((string= sub3 "<%#")
   4688           (setq token-type 'comment))
   4689          (t
   4690           (setq regexp web-mode-engine-token-regexp))
   4691          )
   4692        ) ;erb
   4693 
   4694       ((string= web-mode-engine "template-toolkit")
   4695        (cond
   4696          ((member sub3 '("[%#" "%%#"))
   4697           (setq token-type 'comment))
   4698          (t
   4699           (setq regexp "#\\|\"\\|'"))
   4700          )
   4701        ) ;template-toolkit
   4702 
   4703       ((string= web-mode-engine "underscore")
   4704        (setq regexp "/\\*\\|\"\\|'")
   4705        ) ;underscore
   4706 
   4707       ((string= web-mode-engine "angular")
   4708        (setq regexp "#\\|\"\\|'")) ;angular
   4709 
   4710       ((string= web-mode-engine "vue")
   4711        ) ;vue
   4712 
   4713       ((string= web-mode-engine "smarty")
   4714        (cond
   4715          ((string= sub2 "{*")
   4716           (setq token-type 'comment))
   4717          (t
   4718           (setq regexp "\"\\|'")))
   4719        ) ;smarty
   4720 
   4721       ((string= web-mode-engine "xoops")
   4722        (cond
   4723          ((string= sub3 "<{*")
   4724           (setq token-type 'comment))
   4725          (t
   4726           (setq regexp "\"\\|'")))
   4727        ) ;xoops
   4728 
   4729       ((string= web-mode-engine "spip")
   4730        (if (string= (buffer-substring-no-properties
   4731                      block-beg (+ block-beg 7))
   4732                     "[(#REM)")
   4733            (setq token-type 'comment
   4734                  regexp "\\]")))
   4735 
   4736       ((string= web-mode-engine "dust")
   4737        (cond
   4738          ((string= sub2 "{!")
   4739           (setq token-type 'comment))
   4740          (t
   4741           (setq regexp "\"\\|'"))
   4742          )
   4743        ) ;dust
   4744 
   4745       ((string= web-mode-engine "expressionengine")
   4746        (cond
   4747          ((string= sub2 "{!")
   4748           (setq token-type 'comment))
   4749          (t
   4750           (setq regexp "\"\\|'")))
   4751        ) ;expressionengine
   4752 
   4753       ((string= web-mode-engine "closure")
   4754        (cond
   4755          ((member sub2 '("/*" "//"))
   4756           (setq token-type 'comment))
   4757          (t
   4758           (setq regexp "\"\\|'"))
   4759          )
   4760        ) ;closure
   4761 
   4762       ((string= web-mode-engine "svelte")
   4763        ) ;svelte
   4764 
   4765       ) ;cond
   4766 
   4767     (cond
   4768       (token-type
   4769        (put-text-property block-beg block-end 'block-token token-type))
   4770       ((and regexp
   4771             (> (- block-end block-beg) 6))
   4772        (web-mode-block-tokenize
   4773         (web-mode-block-code-beginning-position block-beg)
   4774         (web-mode-block-code-end-position block-beg)
   4775         regexp)
   4776        )
   4777       ) ;cond
   4778 
   4779     ))
   4780 
   4781 (defun web-mode-block-tokenize (reg-beg reg-end &optional regexp)
   4782   (unless regexp (setq regexp web-mode-engine-token-regexp))
   4783   ;;(message "tokenize: reg-beg(%S) reg-end(%S) regexp(%S)" reg-beg reg-end regexp)
   4784   ;;(message "tokenize: reg-beg(%S) reg-end(%S) command(%S)" reg-beg reg-end this-command)
   4785   ;;(message "%S>%S : %S" reg-beg reg-end (buffer-substring-no-properties reg-beg reg-end))
   4786   (save-excursion
   4787     (let ((pos reg-beg) beg char match continue token-type token-end)
   4788 
   4789       (remove-list-of-text-properties reg-beg reg-end '(block-token))
   4790 
   4791       ;; TODO : vérifier la cohérence
   4792       (put-text-property reg-beg reg-end 'block-side t)
   4793 
   4794       (goto-char reg-beg)
   4795 
   4796       (when (> (point) reg-end)
   4797         (message "block-tokenize ** reg-beg(%S) > reg-end(%S) **" reg-beg reg-end))
   4798 
   4799       (while (and (< (point) reg-end) (re-search-forward regexp reg-end t))
   4800         (setq beg (match-beginning 0)
   4801               match (match-string 0)
   4802               continue t
   4803               token-type 'comment
   4804               token-end (if (< reg-end (line-end-position)) reg-end (line-end-position))
   4805               char (aref match 0))
   4806         (cond
   4807 
   4808           ((and (string= web-mode-engine "asp") (string= match "'"))
   4809            (goto-char token-end))
   4810 
   4811           ((and (string= web-mode-engine "razor") (eq char ?\'))
   4812            (cond
   4813              ((looking-at-p "\\(.\\|[\\][bfntr]\\|[\\]u....\\)'")
   4814               (search-forward "'" reg-end t)
   4815               (setq token-type 'string)
   4816               )
   4817              (t
   4818               (re-search-forward "[[:alnum:]_-]+")
   4819               (setq token-type 'symbol)
   4820               )))
   4821 
   4822           ((eq char ?\')
   4823            (setq token-type 'string)
   4824            (while (and continue (search-forward "'" reg-end t))
   4825              (setq continue (web-mode-string-continue-p reg-beg))
   4826              ))
   4827 
   4828           ((eq char ?\")
   4829            (setq token-type 'string)
   4830            (while (and continue (search-forward "\"" reg-end t))
   4831              (setq continue (web-mode-string-continue-p reg-beg))
   4832              ))
   4833 
   4834           ((string= match "//")
   4835            (goto-char token-end))
   4836 
   4837           ((eq char ?\;)
   4838            (goto-char token-end))
   4839 
   4840           ((string= match "#|")
   4841            (unless (search-forward "|#" reg-end t)
   4842              (goto-char token-end)))
   4843 
   4844           ((eq char ?\#)
   4845            (goto-char token-end))
   4846 
   4847           ((string= match "/*")
   4848            (unless (search-forward "*/" reg-end t)
   4849              (goto-char token-end))
   4850            )
   4851 
   4852           ((string= match "@*")
   4853            (unless (search-forward "*@" reg-end t)
   4854              (goto-char token-end)))
   4855 
   4856           ((eq char ?\<)
   4857            (setq token-type 'string)
   4858            (re-search-forward (concat "^[ ]*" (match-string 1)) reg-end t))
   4859 
   4860           (t
   4861            (message "block-tokenize ** token end (%S) **" beg)
   4862            (setq token-type nil))
   4863 
   4864           ) ;cond
   4865 
   4866         (put-text-property beg (point) 'block-token token-type)
   4867 
   4868         (when (eq token-type 'comment)
   4869           (put-text-property beg (1+ beg) 'syntax-table (string-to-syntax "<"))
   4870           (if (or (< (point) (line-end-position)) (= (point) (point-max)))
   4871               (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax ">")) ;#445 #480
   4872               (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax ">")) ;#377
   4873               )
   4874           )
   4875 
   4876         ) ;while
   4877 
   4878       (web-mode-block-controls-unset pos)
   4879 
   4880       )))
   4881 
   4882 (defun web-mode-set-php-controls (reg-beg reg-end)
   4883   (goto-char reg-beg)
   4884   (let (match controls
   4885               (continue t)
   4886               (regexp "endif\\|endforeach\\|endfor\\|endwhile\\|elseif\\|else\\|if\\|foreach\\|for\\|while"))
   4887     (while continue
   4888       (if (not (web-mode-block-rsf regexp reg-end))
   4889           (setq continue nil)
   4890           (setq match (match-string-no-properties 0))
   4891           ;;        (message "%S %S" match (point))
   4892           (cond
   4893             ((and (member match '("else" "elseif"))
   4894                   (looking-at-p "[ ]*[:(]"))
   4895              (setq controls (append controls (list (cons 'inside "if"))))
   4896              )
   4897             ((and (>= (length match) 3)
   4898                   (string= (substring match 0 3) "end"))
   4899              (setq controls (append controls (list (cons 'close (substring match 3)))))
   4900              )
   4901             ((and (progn (skip-chars-forward "[ ]") t)
   4902                   (eq (char-after) ?\()
   4903                   (web-mode-closing-paren reg-end)
   4904                   ;;(progn (message "ixi%S" (point)))
   4905                   (looking-at-p ")[ ]*:"))
   4906              (setq controls (append controls (list (cons 'open match))))
   4907              )
   4908             ) ;cond
   4909           ) ;if
   4910       ) ;while
   4911     ;;(message "%S-%S %S" reg-beg reg-end controls)
   4912     (when (and controls (> (length controls) 1))
   4913       (setq controls (web-mode-block-controls-reduce controls)))
   4914     controls))
   4915 
   4916 (defun web-mode-block-controls-reduce (controls)
   4917   (when (and (eq (car (car controls)) 'open)
   4918              (member (cons 'close (cdr (car controls))) controls))
   4919     (setq controls nil))
   4920   controls)
   4921 
   4922 (defun web-mode-block-controls-unset (pos)
   4923   (cond
   4924     ((null (get-text-property pos 'block-side))
   4925      (message "block-controls-unset ** invalid value (%S) **" pos))
   4926     ((or (get-text-property pos 'block-beg)
   4927          (setq pos (web-mode-block-beginning-position pos)))
   4928      (put-text-property pos (1+ pos) 'block-controls 0))
   4929     (t
   4930      (message "block-controls-unset ** failure (%S) **" (point)))
   4931     ))
   4932 
   4933 (defun web-mode-block-controls-get (pos)
   4934   (web-mode-with-silent-modifications
   4935    (let ((controls nil))
   4936      (cond
   4937        ((null (get-text-property pos 'block-side))
   4938         (message "block-controls-get ** invalid value (%S) **" pos))
   4939        ((or (get-text-property pos 'block-beg)
   4940             (setq pos (web-mode-block-beginning-position pos)))
   4941         (setq controls (get-text-property pos 'block-controls))
   4942         (when (integerp controls)
   4943           (web-mode-block-controls-set pos (web-mode-block-end-position pos))
   4944           (setq controls (get-text-property pos 'block-controls))
   4945           )
   4946         )
   4947        (t
   4948         (message "block-controls-get ** failure (%S) **" (point)))
   4949        ) ;cond
   4950      controls)))
   4951 
   4952 (defun web-mode-block-controls-set (reg-beg reg-end)
   4953   (save-excursion
   4954     (goto-char reg-beg)
   4955     (let (controls pos type control)
   4956 
   4957       (cond
   4958 
   4959         ((null web-mode-engine)
   4960          (message "block-controls-set ** unknown engine (%S) **" web-mode-engine)
   4961          )
   4962 
   4963         ((string= web-mode-engine "php")
   4964          (setq controls (web-mode-set-php-controls reg-beg reg-end))
   4965          (when (web-mode-block-starts-with "}" reg-beg)
   4966            (setq controls (append controls (list (cons 'close "{")))))
   4967          (when (web-mode-block-ends-with (cons "{" "}") reg-beg)
   4968            (setq controls (append controls (list (cons 'open "{")))))
   4969          ) ;php
   4970 
   4971         ((string= web-mode-engine "ejs")
   4972          (cond
   4973            ((web-mode-block-ends-with "}[ ]*else[ ]*{" reg-beg)
   4974             (setq controls (append controls (list (cons 'inside "{")))))
   4975            ((web-mode-block-starts-with "}" reg-beg)
   4976             (setq controls (append controls (list (cons 'close "{")))))
   4977            ((web-mode-block-ends-with "{" reg-beg)
   4978             (setq controls (append controls (list (cons 'open "{")))))
   4979            )
   4980          ) ;ejs
   4981 
   4982         ((string= web-mode-engine "erb")
   4983          (cond
   4984            ((web-mode-block-starts-with "else\\|elsif\\|when" reg-beg)
   4985             (setq controls (append controls (list (cons 'inside "ctrl")))))
   4986            ((web-mode-block-starts-with "end" reg-beg)
   4987             (setq controls (append controls (list (cons 'close "ctrl")))))
   4988            ((web-mode-block-ends-with " do\\( |.*|\\)?" reg-beg)
   4989             (setq controls (append controls (list (cons 'open "ctrl")))))
   4990            ((and (web-mode-block-starts-with "\\(for\\|if\\|unless\\|case\\)\\_>" reg-beg)
   4991                  (not (web-mode-block-ends-with "end" reg-end)))
   4992             (setq controls (append controls (list (cons 'open "ctrl")))))
   4993            )
   4994          ) ;erb
   4995 
   4996         ((string= web-mode-engine "django")
   4997          (cond
   4998            ((and (string= web-mode-minor-engine "jinja") ;#504
   4999                  (web-mode-block-starts-with "else\\_>" reg-beg))
   5000             (let ((continue t)
   5001                   (pos reg-beg)
   5002                   (ctrl nil))
   5003               (while continue
   5004                 (cond
   5005                   ((null (setq pos (web-mode-block-control-previous-position 'open pos)))
   5006                    (setq continue nil))
   5007                   ((member (setq ctrl (cdr (car (get-text-property pos 'block-controls)))) '("if" "ifequal" "ifnotequal" "for"))
   5008                    (setq continue nil)
   5009                    )
   5010                   ) ;cond
   5011                 )
   5012               (setq controls (append controls (list (cons 'inside (or ctrl "if")))))
   5013               )
   5014             )
   5015            ((web-mode-block-starts-with "form_start[ ]*(" reg-beg)
   5016             (setq controls (append controls (list (cons 'open "form_start")))))
   5017            ((web-mode-block-starts-with "form_end[ ]*(" reg-beg)
   5018             (setq controls (append controls (list (cons 'close "form_start")))))
   5019            ((not (eq (char-after (1+ reg-beg)) ?\%))
   5020             )
   5021            ((web-mode-block-starts-with "\\(else\\|els?if\\)" reg-beg)
   5022             (let ((continue t)
   5023                   (pos reg-beg)
   5024                   (ctrl nil))
   5025               (while continue
   5026                 (cond
   5027                   ((null (setq pos (web-mode-block-control-previous-position 'open pos)))
   5028                    (setq continue nil))
   5029                   ((member (setq ctrl (cdr (car (get-text-property pos 'block-controls)))) '("if" "ifequal" "ifnotequal"))
   5030                    (setq continue nil)
   5031                    )
   5032                   ) ;cond
   5033                 ) ;while
   5034               (setq controls (append controls (list (cons 'inside (or ctrl "if")))))
   5035               ) ;let
   5036             ) ;case else
   5037            ((web-mode-block-starts-with "\\(empty\\)" reg-beg)
   5038             (setq controls (append controls (list (cons 'inside "for")))))
   5039            ((web-mode-block-starts-with "end\\([[:alpha:]]+\\)" reg-beg)
   5040             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5041            ((web-mode-block-starts-with "set [[:alpha:]]+[ ]*%}" reg-beg)
   5042             (setq controls (append controls (list (cons 'open "set")))))
   5043            ((web-mode-block-starts-with (concat web-mode-django-control-blocks-regexp "[ %]") reg-beg)
   5044             (let (control)
   5045               (setq control (match-string-no-properties 1))
   5046               ;;(message "%S %S %S" control (concat "end" control) web-mode-django-control-blocks)
   5047               (when (member (concat "end" control) web-mode-django-control-blocks)
   5048                 (setq controls (append controls (list (cons 'open control))))
   5049                 ) ;when
   5050               ) ;let
   5051             ) ;case
   5052            ) ;cond
   5053          ) ;django
   5054 
   5055         ((string= web-mode-engine "smarty")
   5056          (cond
   5057            ((and (eq (char-after (1+ reg-beg)) ?\/)
   5058                  (web-mode-block-starts-with "\\([[:alpha:]]+\\)" reg-beg))
   5059             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5060            ((web-mode-block-starts-with "\\(else\\|elseif\\)" reg-beg)
   5061             (setq controls (append controls (list (cons 'inside "if")))))
   5062            ((web-mode-block-starts-with "\\(block\\|foreach\\|for\\|if\\|section\\|while\\)")
   5063             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5064            )
   5065          ) ;smarty
   5066 
   5067         ((string= web-mode-engine "expressionengine")
   5068          (cond
   5069            ((and (eq (char-after (1+ reg-beg)) ?\/)
   5070                  (web-mode-block-starts-with "\\(if\\)" reg-beg))
   5071             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5072            ((web-mode-block-starts-with "\\(if:else\\|if:ifelse\\)" reg-beg)
   5073             (setq controls (append controls (list (cons 'inside "if")))))
   5074            ((web-mode-block-starts-with "\\(if\\)")
   5075             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5076            )
   5077          ) ;expressionengine
   5078 
   5079         ((string= web-mode-engine "xoops")
   5080          (cond
   5081            ((and (eq (char-after (+ reg-beg 2)) ?\/)
   5082                  (web-mode-block-starts-with "\\([[:alpha:]]+\\)" reg-beg))
   5083             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5084            ((web-mode-block-starts-with "\\(else\\|elseif\\)" reg-beg)
   5085             (setq controls (append controls (list (cons 'inside "if")))))
   5086            ((web-mode-block-starts-with "\\(block\\|foreach\\|for\\|if\\|section\\|while\\)")
   5087             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5088            )
   5089          ) ;xoops
   5090 
   5091         ((string= web-mode-engine "web2py")
   5092          (cond
   5093            ((web-mode-block-starts-with "def" reg-beg)
   5094             (setq controls (append controls (list (cons 'open "def")))))
   5095            ((web-mode-block-starts-with "return" reg-beg)
   5096             (setq controls (append controls (list (cons 'close "def")))))
   5097            ((web-mode-block-starts-with "block" reg-beg)
   5098             (setq controls (append controls (list (cons 'open "block")))))
   5099            ((web-mode-block-starts-with "end" reg-beg)
   5100             (setq controls (append controls (list (cons 'close "block")))))
   5101            ((web-mode-block-starts-with "pass" reg-beg)
   5102             (setq controls (append controls (list (cons 'close "ctrl")))))
   5103            ((web-mode-block-starts-with "\\(except\\|finally\\|els\\)" reg-beg)
   5104             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5105            ((web-mode-block-starts-with "\\(if\\|for\\|try\\|while\\)")
   5106             (setq controls (append controls (list (cons 'open "ctrl")))))
   5107            )
   5108          ) ;web2py
   5109 
   5110         ((string= web-mode-engine "dust")
   5111          (cond
   5112            ((eq (char-after (1- reg-end)) ?\/)
   5113             )
   5114            ((eq (char-after (1+ reg-beg)) ?\:)
   5115             (setq pos (web-mode-block-control-previous-position 'open reg-beg))
   5116             (when pos
   5117               (setq controls (append controls
   5118                                      (list
   5119                                       (cons 'inside
   5120                                             (cdr (car (web-mode-block-controls-get pos))))))))
   5121             )
   5122            ((looking-at "{/\\([[:alpha:].]+\\)")
   5123             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5124            ((looking-at "{[#?@><+^]\\([[:alpha:].]+\\)")
   5125             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5126            )
   5127          ) ;dust
   5128 
   5129         ((string= web-mode-engine "anki")
   5130          (cond
   5131            ((looking-at "{{[#^]\\([[:alpha:].]+\\)")
   5132             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5133            ((looking-at "{{/\\([[:alpha:].]+\\)")
   5134             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5135            )
   5136          ) ;anki
   5137 
   5138         ((member web-mode-engine '("mojolicious"))
   5139          (cond
   5140            ((web-mode-block-ends-with "begin" reg-beg)
   5141             (setq controls (append controls (list (cons 'open "begin")))))
   5142            ((web-mode-block-starts-with "end" reg-beg)
   5143             (setq controls (append controls (list (cons 'close "begin")))))
   5144            ((web-mode-block-starts-with "}[ ]*else[ ]*{" reg-beg)
   5145             (setq controls (append controls (list (cons 'inside "{")))))
   5146            ((web-mode-block-starts-with "}" reg-beg)
   5147             (setq controls (append controls (list (cons 'close "{")))))
   5148            ((web-mode-block-ends-with "{" reg-beg)
   5149             (setq controls (append controls (list (cons 'open "{")))))
   5150            )
   5151          ) ;mojolicious
   5152 
   5153         ((member web-mode-engine '("aspx" "underscore"))
   5154          (cond
   5155            ((and (web-mode-block-starts-with "}" reg-beg)
   5156                  (web-mode-block-ends-with "{" reg-beg))
   5157             (setq controls (append controls (list (cons 'inside "{")))))
   5158            ((web-mode-block-starts-with "}" reg-beg)
   5159             (setq controls (append controls (list (cons 'close "{")))))
   5160            ((web-mode-block-ends-with "{" reg-beg)
   5161             (setq controls (append controls (list (cons 'open "{")))))
   5162            )
   5163          ) ;aspx underscore
   5164 
   5165         ((member web-mode-engine '("jsp" "asp" "clip" "perl"))
   5166          (cond
   5167            ((eq (char-after (1- reg-end)) ?\/)
   5168             )
   5169            ((looking-at "<TMPL_ELSE")
   5170             (setq controls (append controls (list (cons 'inside "TMPL_IF")))))
   5171            ((looking-at "</?\\([[:alpha:]]+\\(?:[:.][[:alpha:]]+\\)\\|[[:alpha:]]+Template\\|TMPL_[[:alpha:]]+\\)")
   5172             (setq control (match-string-no-properties 1)
   5173                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5174             (when (not (member control '("h:inputtext" "jsp:usebean" "jsp:forward" "struts:property")))
   5175               (setq controls (append controls (list (cons type control)))))
   5176             )
   5177            (t
   5178             (when (web-mode-block-starts-with "}" reg-beg)
   5179               (setq controls (append controls (list (cons 'close "{")))))
   5180             (when (web-mode-block-ends-with "{" reg-beg)
   5181               (setq controls (append controls (list (cons 'open "{")))))
   5182             )
   5183            )
   5184          ) ;jsp asp
   5185 
   5186         ((string= web-mode-engine "mako")
   5187          (cond
   5188            ((looking-at "</?%\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)")
   5189             (cond
   5190               ((eq (char-after (- (web-mode-block-end-position reg-beg) 1)) ?\/)
   5191                )
   5192               (t
   5193                (setq control (match-string-no-properties 1)
   5194                      type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5195                (setq controls (append controls (list (cons type control)))))
   5196               )
   5197             )
   5198            ((web-mode-block-starts-with "\\(else\\|elif\\)" reg-beg)
   5199             (setq controls (append controls (list (cons 'inside "if")))))
   5200            ((web-mode-block-starts-with "end\\(if\\|for\\)" reg-beg)
   5201             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5202            ((and (web-mode-block-starts-with "if\\|for" reg-beg)
   5203                  (web-mode-block-ends-with ":" reg-beg))
   5204             (setq controls (append controls (list (cons 'open (match-string-no-properties 0))))))
   5205            )
   5206          ) ;mako
   5207 
   5208         ((string= web-mode-engine "mason")
   5209          (cond
   5210            ((looking-at "</?%\\(after\\|around\\|augment\\|before\\|def\\|filter\\|method\\|override\\)")
   5211             (setq control (match-string-no-properties 1)
   5212                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5213             (setq controls (append controls (list (cons type control))))
   5214             )
   5215            )
   5216          ) ;mason
   5217 
   5218         ((string= web-mode-engine "ctemplate")
   5219          (cond
   5220            ((looking-at-p "{{else") ;#721
   5221             (let ((continue t)
   5222                   (pos reg-beg)
   5223                   (ctrl nil))
   5224               (while continue
   5225                 (cond
   5226                   ((null (setq pos (web-mode-block-control-previous-position 'open pos)))
   5227                    (setq continue nil))
   5228                   ((member (setq ctrl (cdr (car (get-text-property pos 'block-controls)))) '("if" "each"))
   5229                    (setq continue nil)
   5230                    )
   5231                   ) ;cond
   5232                 ) ;while
   5233               (setq controls (append controls (list (cons 'inside (or ctrl "if")))))
   5234               )
   5235             )
   5236 
   5237            ((looking-at "{{[#^/][ ]*\\([[:alpha:]_.-]+\\)")
   5238             (setq control (match-string-no-properties 1)
   5239                   type (if (eq (aref (match-string-no-properties 0) 2) ?\/) 'close 'open))
   5240             (setq controls (append controls (list (cons type control))))
   5241             )
   5242            )
   5243          ) ;ctemplate
   5244 
   5245         ((string= web-mode-engine "antlers")
   5246          (cond
   5247            ((web-mode-block-starts-with "\\(else\\|elseif\\)" reg-beg)
   5248             (setq controls (append controls (list (cons 'inside "if")))))
   5249            ((looking-at  "{{[ ]*/?\\(if\\|unless\\)")
   5250             (setq control (match-string-no-properties 1)
   5251                   type (if (eq (aref (match-string-no-properties 0) 3) ?\/) 'close 'open))
   5252             (setq controls (append controls (list (cons type control))))
   5253             )
   5254            )
   5255          ) ;antlers
   5256 
   5257         ((string= web-mode-engine "blade")
   5258          (cond
   5259            ((not (eq (char-after) ?\@))
   5260             )
   5261            ((web-mode-block-starts-with
   5262              "section\(\s*\\(['\"]\\).*\\1\s*,\s*\\(['\"]\\).*\\2\s*\)" reg-beg)
   5263             )
   5264            ((web-mode-block-starts-with "case\\|break" reg-beg)
   5265             (setq type (if (eq (aref (match-string-no-properties 0) 0) ?b) 'close 'open))
   5266             (setq controls (append controls (list (cons type "case"))))
   5267             )
   5268            ((web-mode-block-starts-with
   5269              (concat "\\(?:end\\)?\\(" web-mode-blade-control-blocks-regexp "\\)")
   5270              reg-beg)
   5271             (setq control (match-string-no-properties 1)
   5272                   type (if (eq (aref (match-string-no-properties 0) 0) ?e) 'close 'open))
   5273             (setq controls (append controls (list (cons type control))))
   5274             )
   5275            ((web-mode-block-starts-with "stop\\|show\\|overwrite" reg-beg)
   5276             (setq controls (append controls (list (cons 'close "section")))))
   5277            ((web-mode-block-starts-with "else\\|elseif" reg-beg)
   5278             (setq controls (append controls (list (cons 'inside "if")))))
   5279            ((web-mode-block-starts-with "empty" reg-beg)
   5280             (setq controls (append controls (list (cons 'inside "forelse")))))
   5281            )
   5282          ) ;blade
   5283 
   5284         ((string= web-mode-engine "closure")
   5285          (cond
   5286            ((eq (char-after (1- reg-end)) ?\/)
   5287             )
   5288            ((looking-at "alias\\|namespace")
   5289             )
   5290            ((web-mode-block-starts-with "ifempty" reg-beg)
   5291             (setq controls (append controls (list (cons 'inside "foreach")))))
   5292            ((web-mode-block-starts-with "else\\|elseif" reg-beg)
   5293             (setq controls (append controls (list (cons 'inside "if")))))
   5294            ((web-mode-block-starts-with "case\\|default" reg-beg)
   5295             (setq controls (append controls (list (cons 'inside "switch")))))
   5296            ((looking-at
   5297              "{/?\\(call\\|deltemplate\\|for\\|foreach\\|if\\|let\\|literal\\|msg\\|param\\|switch\\|template\\)")
   5298             (setq control (match-string-no-properties 1)
   5299                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5300             (setq controls (append controls (list (cons type control))))
   5301             )
   5302            )
   5303          ) ;closure
   5304 
   5305         ((string= web-mode-engine "go")
   5306          (cond
   5307            ((web-mode-block-starts-with "end\\_>" reg-beg)
   5308             (setq controls (append controls (list (cons 'close "ctrl")))))
   5309            ((web-mode-block-starts-with "else\\_>" reg-beg)
   5310             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5311            ((web-mode-block-starts-with "\\(range\\|with\\|if\\|define\\|block\\)\\_>" reg-beg)
   5312             (setq controls (append controls (list (cons 'open "ctrl")))))
   5313            )
   5314          ) ;go
   5315 
   5316         ((string= web-mode-engine "template-toolkit")
   5317          (cond
   5318            ((web-mode-block-starts-with "end" reg-beg)
   5319             (setq controls (append controls (list (cons 'close "ctrl")))))
   5320            ((web-mode-block-starts-with "els\\|catch\\|final" reg-beg)
   5321             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5322            ((web-mode-block-starts-with "filter\\|foreach\\|if\\|last\\|next\\|perl\\|rawperl\\|try\\|unless\\|while" reg-beg)
   5323             (setq controls (append controls (list (cons 'open "ctrl")))))
   5324            )
   5325          ) ;template-toolkit
   5326 
   5327         ((string= web-mode-engine "cl-emb")
   5328          (cond
   5329            ((web-mode-block-starts-with "@else" reg-beg)
   5330             (setq controls (append controls (list (cons 'inside "if")))))
   5331            ((web-mode-block-starts-with "@\\(?:end\\)?\\(if\\|unless\\|repeat\\|loop\\|with\\|genloop\\)" reg-beg)
   5332             (setq control (match-string-no-properties 1)
   5333                   type (if (eq (aref (match-string-no-properties 0) 1) ?e) 'close 'open))
   5334             (setq controls (append controls (list (cons type control)))))
   5335            )
   5336          ) ;cl-emb
   5337 
   5338         ((string= web-mode-engine "elixir")
   5339          (cond
   5340            ((web-mode-block-starts-with "end" reg-beg)
   5341             (setq controls (append controls (list (cons 'close "ctrl")))))
   5342            ((web-mode-block-starts-with "else" reg-beg)
   5343             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5344            ((web-mode-block-ends-with " do" reg-beg)
   5345             (setq controls (append controls (list (cons 'open "ctrl")))))
   5346            ((web-mode-block-ends-with " ->" reg-beg)
   5347             (setq controls (append controls (list (cons 'open "ctrl")))))
   5348            )
   5349          ) ;elixir
   5350 
   5351         ((string= web-mode-engine "velocity")
   5352          (cond
   5353            ((web-mode-block-starts-with "{?end" reg-beg)
   5354             (setq controls (append controls (list (cons 'close "ctrl")))))
   5355            ((web-mode-block-starts-with "{?els" reg-beg)
   5356             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5357            ((web-mode-block-starts-with "{?\\(def\\|if\\|for\\|foreach\\|macro\\)" reg-beg)
   5358             ;;((web-mode-block-starts-with "{?\\(define\\|\\|if\\|for\\|foreach\\|macro\\)" reg-beg)
   5359             (setq controls (append controls (list (cons 'open "ctrl")))))
   5360            )
   5361          ) ;velocity
   5362 
   5363         ((string= web-mode-engine "freemarker")
   5364          (cond
   5365            ((looking-at "[<[]#\\(import\\|include\\|assign\\|return\\|local\\)")
   5366             )
   5367            ((eq (char-after (1- reg-end)) ?\/)
   5368             )
   5369            ((looking-at "[<[]#\\(break\\|case\\|default\\)")
   5370             (setq controls (append controls (list (cons 'inside "switch"))))
   5371             )
   5372            ((looking-at "[<[]#els")
   5373             (setq controls (append controls (list (cons 'inside "if"))))
   5374             )
   5375            ((looking-at "</?\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)")
   5376             (setq control (match-string-no-properties 1)
   5377                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5378             (setq controls (append controls (list (cons type control))))
   5379             )
   5380            ((looking-at "[<[]/?\\(@\\)")
   5381             (setq control (match-string-no-properties 1)
   5382                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5383             (setq controls (append controls (list (cons type control))))
   5384             )
   5385            ((looking-at "[<[]/?#\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)")
   5386             (setq control (match-string-no-properties 1)
   5387                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5388             (setq controls (append controls (list (cons type control))))
   5389             )
   5390            (t
   5391             (when (web-mode-block-starts-with "}" reg-beg)
   5392               (setq controls (append controls (list (cons 'close "{")))))
   5393             (when (web-mode-block-ends-with "{" reg-beg)
   5394               (setq controls (append controls (list (cons 'open "{")))))
   5395             )
   5396            )
   5397          ) ;freemarker
   5398 
   5399         ((string= web-mode-engine "razor")
   5400          (when (web-mode-block-starts-with "}" reg-beg)
   5401            (setq controls (append controls (list (cons 'close "{")))))
   5402          (when (web-mode-block-ends-with "{" reg-beg)
   5403            (setq controls (append controls (list (cons 'open "{")))))
   5404          ) ;razor
   5405 
   5406         ((string= web-mode-engine "lsp")
   5407          (when (web-mode-block-starts-with ")" reg-beg)
   5408            (setq controls (append controls (list (cons 'close "(")))))
   5409          (when (web-mode-block-is-opened-sexp reg-beg reg-end)
   5410            (setq controls (append controls (list (cons 'open "(")))))
   5411          ) ;lsp
   5412 
   5413         ((string= web-mode-engine "hero")
   5414          (cond
   5415            ((web-mode-block-ends-with "}[ ]*else[ ]*{" reg-beg)
   5416             (setq controls (append controls (list (cons 'inside "{")))))
   5417            ((web-mode-block-starts-with "}" reg-beg)
   5418             (setq controls (append controls (list (cons 'close "{")))))
   5419            ((web-mode-block-ends-with "{" reg-beg)
   5420             (setq controls (append controls (list (cons 'open "{")))))
   5421            )
   5422          ) ;hero
   5423 
   5424         ((string= web-mode-engine "svelte")
   5425          (cond
   5426            ((eq (char-after (1- reg-end)) ?\/)
   5427             )
   5428            ((eq (char-after (1+ reg-beg)) ?\:)
   5429             (setq pos (web-mode-block-control-previous-position 'open reg-beg))
   5430             (when pos
   5431               (setq controls (append controls
   5432                                      (list
   5433                                       (cons 'inside
   5434                                             (cdr (car (web-mode-block-controls-get pos))))))))
   5435             )
   5436            ((looking-at "{/\\([[:alpha:].]+\\)")
   5437             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5438            ((looking-at "{[#?><+^]\\([[:alpha:].]+\\)")
   5439             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5440            )
   5441          ) ;svelte
   5442 
   5443         ) ;cond engine
   5444 
   5445       (put-text-property reg-beg (1+ reg-beg) 'block-controls controls)
   5446       ;;(message "(%S) controls=%S" reg-beg controls)
   5447 
   5448       )))
   5449 
   5450 (defun web-mode-block-is-opened-sexp (reg-beg reg-end)
   5451   (let ((n 0))
   5452     (save-excursion
   5453       (goto-char reg-beg)
   5454       (while (web-mode-block-rsf "[()]" reg-end)
   5455         (if (eq (char-before) ?\() (setq n (1+ n)) (setq n (1- n)))))
   5456     (> n 0)))
   5457 
   5458 ;;---- LEXER PARTS -------------------------------------------------------------
   5459 
   5460 (defun web-mode-scan-elements (reg-beg reg-end)
   5461   (save-excursion
   5462     (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)
   5463       ;;(message "scan-elements: reg-beg(%S) reg-end(%S)" reg-beg reg-end)
   5464       (goto-char reg-beg)
   5465 
   5466       (while (web-mode-dom-rsf regexp reg-end)
   5467 
   5468         ;;(message "%S: %S (%S %S)" (point) (match-string-no-properties 0) reg-beg reg-end)
   5469 
   5470         (setq flags 0
   5471               tname (downcase (match-string-no-properties 1))
   5472               char (aref tname 0)
   5473               tbeg (match-beginning 0)
   5474               tend nil
   5475               element-content-type nil
   5476               limit reg-end
   5477               part-beg nil
   5478               part-end nil
   5479               props nil
   5480               close-expr nil
   5481               part-close-tag nil)
   5482 
   5483         ;;(message "tname[%S] tbeg(%S) point(%S)" tname tbeg (point))
   5484 
   5485         (cond
   5486 
   5487           ((member tname '("/>" ">")) ;;jsx fragment #952
   5488            (setq tname "_fragment_"
   5489                  tend (point))
   5490            (if (eq char ?\/)
   5491                (setq props (list 'tag-name tname 'tag-type 'end)
   5492                      flags (logior flags 20)) ;; 16 + 4
   5493                (setq props (list 'tag-name tname 'tag-type 'start)
   5494                      flags (logior flags 16))
   5495                ) ;if
   5496            )
   5497 
   5498           ((not (member char '(?\! ?\?)))
   5499            (cond
   5500              ((string-match-p "-" tname)
   5501               (setq flags (logior flags 2)))
   5502              ;;((string-match-p ":" tname)
   5503              ;; (setq flags (logior flags 32)))
   5504              ((string-match-p "[._:]" tname)
   5505               (setq flags (logior flags 32)))
   5506              )
   5507            (cond
   5508              ((eq char ?\/)
   5509               (setq props (list 'tag-name (substring tname 1) 'tag-type 'end)
   5510                     flags (logior flags 4)
   5511                     limit (if (> reg-end (line-end-position)) (line-end-position) reg-end))
   5512               )
   5513              ((web-mode-element-is-void tname)
   5514               ;;(message "void: tag=%S" tname)
   5515               (setq props (list 'tag-name tname 'tag-type 'void)))
   5516              (t
   5517               (setq props (list 'tag-name tname 'tag-type 'start)))
   5518              ) ;cond
   5519            ) ; not <! <?
   5520           ((and (eq char ?\!) (eq (aref tname 1) ?\-))
   5521            (setq close-expr "-->"
   5522                  props '(tag-type comment)))
   5523           ((string= tname "?xml")
   5524            (setq ;;regexp web-mode-tag-regexp2
   5525             close-expr "?>"
   5526             props '(tag-type declaration)))
   5527           ((string= tname "![cdata[")
   5528            (setq close-expr "]]>"
   5529                  props '(tag-type cdata)))
   5530           ((string= tname "!doctype")
   5531            (setq ;;regexp web-mode-tag-regexp2
   5532             props '(tag-type doctype)))
   5533           ) ;cond - special tags
   5534 
   5535         (cond
   5536 
   5537           (tend
   5538            )
   5539 
   5540           ((and (null close-expr) (eq (char-after) ?\>))
   5541            (setq flags (logior flags 16)
   5542                  tend (1+ (point)))
   5543            ;;(message "end=%S" tend)
   5544            )
   5545 
   5546           ((and (null close-expr)
   5547                 (looking-at "[ ]\\(class\\|id\\|href\\|style\\)=\"[[:alnum:]_=:/?;#. -]*\">"))
   5548            (let ((beg (1+ (point)))
   5549                  (end (+ (point) (length (match-string-no-properties 0)))))
   5550              (setq flags (logior flags 17)
   5551                    tend end)
   5552              (put-text-property beg (1+ beg) 'tag-attr-beg 0)
   5553              (put-text-property beg (1- end) 'tag-attr t)
   5554              (put-text-property (- end 2) (1- end) 'tag-attr-end (length (match-string-no-properties 1)))
   5555              ) ;let
   5556            )
   5557 
   5558           ((null close-expr)
   5559            (setq flags (logior flags (web-mode-attr-skip reg-end)))
   5560            (when (> (logand flags 8) 0)
   5561              (setq props (plist-put props 'tag-type 'void)))
   5562            (setq tend (point)))
   5563 
   5564           ((web-mode-dom-sf close-expr limit t)
   5565            (setq tend (point)))
   5566 
   5567           (t
   5568            (setq tend (line-end-position)))
   5569 
   5570           ) ;cond
   5571 
   5572         (cond
   5573           ((string= tname "style")
   5574            (let (style)
   5575              (setq style (buffer-substring-no-properties tbeg tend)
   5576                    part-close-tag "</style>")
   5577              (cond
   5578                ((string-match-p " lang[ ]*=[ ]*[\"']stylus" style)
   5579                 (setq element-content-type "stylus"))
   5580                ((string-match-p " lang[ ]*=[ ]*[\"']sass" style)
   5581                 (setq element-content-type "sass"))
   5582                (t
   5583                 (setq element-content-type "css"))
   5584                ) ;cond
   5585              ) ;let
   5586            ) ;style
   5587           ((string= tname "script")
   5588            (let (script)
   5589              (setq script (buffer-substring-no-properties tbeg tend)
   5590                    part-close-tag "</script>")
   5591              (cond
   5592                ((string-match-p " type[ ]*=[ ]*[\"']text/\\(jsx\\|babel\\)" script)
   5593                 (setq element-content-type "jsx"))
   5594                ((string-match-p " type[ ]*=[ ]*[\"']text/\\(markdown\\|template\\)" script)
   5595                 (setq element-content-type "markdown"))
   5596                ((string-match-p " type[ ]*=[ ]*[\"']text/ruby" script)
   5597                 (setq element-content-type "ruby"))
   5598                ((seq-some (lambda (x)
   5599                             (string-match-p (concat "type[ ]*=[ ]*[\"']" x) script))
   5600                           web-mode-script-template-types)
   5601                 (setq element-content-type "html"
   5602                       part-close-tag nil))
   5603                ((string-match-p " type[ ]*=[ ]*[\"']application/\\(ld\\+json\\|json\\)" script)
   5604                 (setq element-content-type "json"))
   5605                ((string-match-p " lang[ ]*=[ ]*[\"']\\(typescript\\|ts\\)" script)
   5606                 (setq element-content-type "typescript"))
   5607                (t
   5608                 (setq element-content-type "javascript"))
   5609                ) ;cond
   5610              ) ;let
   5611            ) ;script
   5612           ((string= tname "i18n")
   5613            (setq element-content-type "javascript"
   5614                  part-close-tag "</i18n>"))
   5615           ((and (string= tname "template") (string-match-p " lang" (buffer-substring-no-properties tbeg tend)))
   5616            (let (template)
   5617              (setq template (buffer-substring-no-properties tbeg tend)
   5618                    part-close-tag "</template>")
   5619              (cond
   5620                ((string-match-p " lang[ ]*=[ ]*[\"']pug" template)
   5621                 (setq element-content-type "pug"))
   5622                (t
   5623                 (setq element-content-type "html"))
   5624                ) ;cond
   5625              ) ;let
   5626            ) ;style
   5627           ((and (string= web-mode-engine "archibus")
   5628                 (string= tname "sql"))
   5629            (setq element-content-type "sql"
   5630                  part-close-tag "</sql>"))
   5631           )
   5632 
   5633         (add-text-properties tbeg tend props)
   5634         (put-text-property tbeg (1+ tbeg) 'tag-beg flags)
   5635         (put-text-property (1- tend) tend 'tag-end t)
   5636 
   5637         (when (and part-close-tag
   5638                    (web-mode-dom-sf part-close-tag reg-end t)
   5639                    (setq part-beg tend)
   5640                    (setq part-end (match-beginning 0))
   5641                    (> part-end part-beg))
   5642           (put-text-property part-beg part-end 'part-side
   5643                              (intern element-content-type web-mode-obarray))
   5644           (setq tend part-end)
   5645           ) ;when
   5646 
   5647         (goto-char tend)
   5648 
   5649         ) ;while
   5650 
   5651       )))
   5652 
   5653 ;; FLAGS: tag
   5654 ;; (1)attrs (2)custom (4)slash-beg (8)slash-end (16)bracket-end (32)namespaced
   5655 
   5656 ;; FLAGS: attr
   5657 ;; (1)custom-attr (2)engine-attr (4)spread-attr[jsx] (8)code-value
   5658 ;; https://www.w3.org/TR/2012/WD-html-markup-20120329/syntax.html#attr-value-unquoted
   5659 
   5660 ;; STATES: attr
   5661 ;; (0)nil (1)space (2)name (3)space-before (4)equal (5)space-after
   5662 ;; (6)value-uq (7)value-sq (8)value-dq (9)value-bq : jsx attr={}
   5663 ;; (10)value-block
   5664 
   5665 (defun web-mode-attr-skip (limit)
   5666 
   5667   (let ((tag-flags 0) (attr-flags 0) (continue t) (attrs 0) (brace-depth 0)
   5668         (state 0) (equal-offset 0) (go-back nil)
   5669         (is-jsx (or (string= web-mode-content-type "jsx") (eq (get-text-property (point) 'part-type) 'jsx)))
   5670         attr name-beg name-end val-beg char pos mem step escaped spaced quoted)
   5671 
   5672     (while continue
   5673 
   5674       (setq pos (point)
   5675             char (char-after)
   5676             mem state
   5677             ;;spaced (eq char ?\s)
   5678             spaced (member char '(?\s ?\n))
   5679             step nil)
   5680 
   5681       (ignore mem step) ;; Only used in debug print
   5682       (when quoted (setq quoted (1+ quoted)))
   5683 
   5684       (cond
   5685 
   5686         ((>= pos limit)
   5687          (setq continue nil)
   5688          (setq go-back t)
   5689          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5690          )
   5691 
   5692         ((and (or (= state 0) (= state 1)) (get-text-property pos 'block-side))
   5693          )
   5694 
   5695         ((or (and (= state 8) (not (member char '(?\" ?\\))))
   5696              (and (= state 7) (not (member char '(?\' ?\\))))
   5697              (and (= state 9) (not (member char '(?} ?\\))))
   5698              )
   5699          (when (and (= state 9) (eq char ?\{))
   5700            (setq brace-depth (1+ brace-depth)))
   5701          )
   5702 
   5703         ((and (= state 9) (eq char ?\}) (> brace-depth 1))
   5704          (setq brace-depth (1- brace-depth)))
   5705 
   5706         ;; #1233
   5707         ;;((get-text-property pos 'block-side)
   5708         ;; (when (= state 2)
   5709         ;;   (setq name-end pos))
   5710         ;; )
   5711 
   5712         ((and (= state 2) is-jsx (eq char ?\}) (eq attr-flags 4))
   5713          (setq name-end pos)
   5714          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5715          (setq state 0
   5716                attr-flags 0
   5717                equal-offset 0
   5718                name-beg nil
   5719                name-end nil
   5720                val-beg nil)
   5721          )
   5722 
   5723         ((or (and (= state 8) (eq ?\" char) (not escaped))
   5724              (and (= state 7) (eq ?\' char) (not escaped))
   5725              (and (= state 9) (eq ?\} char) (= brace-depth 1))
   5726              (and (= state 10) (get-text-property pos 'block-end))
   5727              )
   5728          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5729          (setq state 0
   5730                attr-flags 0
   5731                equal-offset 0
   5732                name-beg nil
   5733                name-end nil
   5734                val-beg nil)
   5735          )
   5736 
   5737         ((and (member state '(4 5)) (get-text-property pos 'block-beg))
   5738          (setq val-beg pos)
   5739          (setq state 10))
   5740 
   5741         ((and (member state '(4 5)) (member char '(?\' ?\" ?\{)))
   5742          (setq val-beg pos)
   5743          (setq quoted 1)
   5744          (setq state (cond ((eq ?\' char) 7)
   5745                            ((eq ?\" char) 8)
   5746                            (t             9)))
   5747          (setq step 100)
   5748          (when (= state 9) (setq brace-depth 1))
   5749          )
   5750 
   5751         ((and (eq ?\= char) (member state '(2 3)))
   5752          (setq equal-offset (- pos name-beg)
   5753                name-end (1- pos))
   5754          (setq state 4)
   5755          (setq attr (buffer-substring-no-properties name-beg (1+ name-end)))
   5756          (when (and web-mode-indentless-attributes (member (downcase attr) web-mode-indentless-attributes))
   5757            (setq attr-flags (logior attr-flags 8)))
   5758          )
   5759 
   5760         ((and spaced (= state 0))
   5761          (setq state 1)
   5762          )
   5763 
   5764         ((and (eq char ?\<) (not (member state '(7 8 9))))
   5765          (setq continue nil)
   5766          (setq go-back t)
   5767          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5768          )
   5769 
   5770         ((and (eq char ?\>) (not (member state '(7 8 9))))
   5771          (setq tag-flags (logior tag-flags 16))
   5772          (when (eq (char-before) ?\/)
   5773            (setq tag-flags (logior tag-flags 8))
   5774            )
   5775          (setq continue nil)
   5776          (when name-beg
   5777            (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags))))
   5778          )
   5779 
   5780         ((and spaced (member state '(1 3 5)))
   5781          )
   5782 
   5783         ((and spaced (= state 2))
   5784          (setq state 3)
   5785          )
   5786 
   5787         ((and (eq char ?\/) (member state '(4 5)))
   5788          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5789          (setq state 1
   5790                attr-flags 0
   5791                equal-offset 0
   5792                name-beg nil
   5793                name-end nil
   5794                val-beg nil)
   5795          )
   5796 
   5797         ((and (eq char ?\/) (member state '(0 1)))
   5798          )
   5799 
   5800         ((and spaced (= state 4))
   5801          (setq state 5)
   5802          )
   5803 
   5804         ((and (= state 3)
   5805               (or (and (>= char 97) (<= char 122)) ;a - z
   5806                   (and (>= char 65) (<= char 90)) ;A - Z
   5807                   (eq char ?\-)))
   5808          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5809          (setq state 2
   5810                attr-flags 0
   5811                equal-offset 0
   5812                name-beg pos
   5813                name-end pos
   5814                val-beg nil)
   5815          )
   5816 
   5817         ((and (eq char ?\n) (not (member state '(7 8 9))))
   5818          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5819          (setq state 1
   5820                attr-flags 0
   5821                equal-offset 0
   5822                name-beg nil
   5823                name-end nil
   5824                val-beg nil)
   5825          )
   5826 
   5827         ((and (= state 6) (member char '(?\s ?\n))) ;#1150
   5828          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5829          (setq state 1
   5830                attr-flags 0
   5831                equal-offset 0
   5832                name-beg nil
   5833                name-end nil
   5834                val-beg nil)
   5835          )
   5836 
   5837         ((and quoted (= quoted 2) (member char '(?\s ?\n ?\>)))
   5838          (when (eq char ?\>)
   5839            (setq tag-flags (logior tag-flags 16))
   5840            (setq continue nil))
   5841          (setq state 6)
   5842          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5843          (setq state 1
   5844                attr-flags 0
   5845                equal-offset 0
   5846                name-beg nil
   5847                name-end nil
   5848                val-beg nil)
   5849          )
   5850 
   5851         ((and (not spaced) (= state 1))
   5852          (when (and is-jsx (eq char ?\{))
   5853            (setq attr-flags 4))
   5854          (setq state 2)
   5855          (setq name-beg pos
   5856                name-end pos)
   5857          )
   5858 
   5859         ((member state '(4 5))
   5860          (setq val-beg pos)
   5861          (setq state 6)
   5862          )
   5863 
   5864         ((= state 1)
   5865          (setq state 2)
   5866          )
   5867 
   5868         ((= state 2)
   5869          (setq name-end pos)
   5870          (when (and nil (= attr-flags 0) (member char '(?\- ?\:)))
   5871            (let (attr)
   5872              (setq attr (buffer-substring-no-properties name-beg (1+ name-end)))
   5873              (cond
   5874                ((member attr '("http-equiv"))
   5875                 (setq attr-flags (1- attr-flags))
   5876                 )
   5877                ((and (eq char ?\-) (not (string= attr "http-")))
   5878                 (setq attr-flags (logior attr-flags 1)))
   5879                ) ;cond
   5880              ) ;let
   5881            ) ;when attr-flags = 1
   5882          ) ;state=2
   5883 
   5884         ) ;cond
   5885 
   5886       ;;(message "point(%S) state(%S) c(%S) name-beg(%S) name-end(%S) val-beg(%S) attr-flags(%S) equal-offset(%S)" pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)
   5887 
   5888       (when (and quoted (>= quoted 2))
   5889         (setq quoted nil))
   5890 
   5891       (setq escaped (eq ?\\ char))
   5892       (when (null go-back)
   5893         (forward-char))
   5894 
   5895       ;;(when (not (= mem state)) (message "pos=%S before=%S after=%S step=%S" pos mem state step))
   5896 
   5897       ) ;while
   5898 
   5899     (when (> attrs 0) (setq tag-flags (logior tag-flags 1)))
   5900 
   5901     tag-flags))
   5902 
   5903 (defun web-mode-attr-scan (pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)
   5904   ;;(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)
   5905   (when (null attr-flags) (setq attr-flags 0))
   5906   (when (and name-beg name-end web-mode-engine-attr-regexp)
   5907     (let (name)
   5908       (setq name (buffer-substring-no-properties name-beg (1+ name-end)))
   5909       (cond
   5910         ((string-match-p "^data[-]" name)
   5911          (setq attr-flags (logior attr-flags 1))
   5912          )
   5913         ((string-match-p web-mode-engine-attr-regexp name)
   5914          (setq attr-flags (logior attr-flags 2))
   5915          )
   5916         )
   5917       ) ;name
   5918     )
   5919   ;;(message "%S" name)
   5920   (cond
   5921     ((null name-beg)
   5922      0)
   5923     ((or (and (= state 8) (not (eq ?\" char)))
   5924          (and (= state 7) (not (eq ?\' char))))
   5925      (put-text-property name-beg (1+ name-beg) 'tag-attr-beg attr-flags)
   5926      (put-text-property name-beg val-beg 'tag-attr t)
   5927      (put-text-property (1- val-beg) val-beg 'tag-attr-end equal-offset)
   5928      1)
   5929     ((and (member state '(4 5)) (null val-beg))
   5930      (put-text-property name-beg (1+ name-beg) 'tag-attr-beg attr-flags)
   5931      (put-text-property name-beg (+ name-beg equal-offset 1) 'tag-attr t)
   5932      (put-text-property (+ name-beg equal-offset) (+ name-beg equal-offset 1) 'tag-attr-end equal-offset)
   5933      1)
   5934     (t
   5935      (let (val-end)
   5936        (if (null val-beg)
   5937            (setq val-end name-end)
   5938            (setq val-end pos)
   5939            (cond
   5940              ((null char)
   5941               (setq val-end (1- val-end)))
   5942              ((member char '(?\s ?\n ?\/))
   5943               (setq val-end (1- val-end)))
   5944              ((eq char ?\>)
   5945               (if (= (logand tag-flags 8) 8)
   5946                   (progn
   5947                     ;;(message "tag-flags=%S %S" tag-flags (logand tag-flags 8))
   5948                     (setq val-end (- val-end 2)))
   5949                   (setq val-end (- val-end 1)))
   5950               ;; (message "val-end=%S" val-end)
   5951               )
   5952              )
   5953            )
   5954        (put-text-property name-beg (1+ name-beg) 'tag-attr-beg attr-flags)
   5955        (put-text-property name-beg (1+ val-end) 'tag-attr t)
   5956        (put-text-property val-end (1+ val-end) 'tag-attr-end equal-offset)
   5957        ) ;let
   5958      1) ;t
   5959     ) ;cond
   5960   )
   5961 
   5962 (defun web-mode-part-foreach (reg-beg reg-end func)
   5963   (let ((i 0) (continue t) (part-beg reg-beg) (part-end nil))
   5964     (while continue
   5965       (setq part-end nil)
   5966       (unless (get-text-property part-beg 'part-side)
   5967         (setq part-beg (web-mode-part-next-position part-beg)))
   5968       (when (and part-beg (< part-beg reg-end))
   5969         (setq part-end (web-mode-part-end-position part-beg)))
   5970       (cond
   5971         ((> (setq i (1+ i)) 100)
   5972          (message "process-parts ** warning (%S) **" (point))
   5973          (setq continue nil))
   5974         ((or (null part-end) (> part-end reg-end))
   5975          (setq continue nil))
   5976         (t
   5977          (setq part-end (1+ part-end))
   5978          (funcall func part-beg part-end)
   5979          (setq part-beg part-end))
   5980         ) ;cond
   5981       ) ;while
   5982     ))
   5983 
   5984 (defun web-mode-part-scan (reg-beg reg-end &optional content-type depth)
   5985   (save-excursion
   5986     (let (token-re ch-before ch-at ch-next token-type beg continue)
   5987       ;;(message "%S %S" reg-beg reg-end)
   5988       (cond
   5989         (content-type
   5990          )
   5991         ((member web-mode-content-type web-mode-part-content-types)
   5992          (setq content-type web-mode-content-type))
   5993         (t
   5994          (setq content-type (symbol-name (get-text-property reg-beg 'part-side))))
   5995         ) ;cond
   5996 
   5997       (goto-char reg-beg)
   5998 
   5999       (cond
   6000         ((member content-type '("javascript" "json"))
   6001          (setq token-re "/\\|\"\\|'\\|`"))
   6002         ((member content-type '("typescript"))
   6003          (setq token-re "/\\|\"\\|'\\|`\\|//\\|/\\*"))
   6004         ((member content-type '("jsx"))
   6005          (setq token-re "/\\|\"\\|'\\|`\\|</?[[:alpha:]>]"))
   6006         ((string= web-mode-content-type "css")
   6007          (setq token-re "\"\\|'\\|/\\*\\|//"))
   6008         ((string= content-type "css")
   6009          (setq token-re "\"\\|'\\|/\\*"))
   6010         (t
   6011          (setq token-re "/\\*\\|\"\\|'"))
   6012         )
   6013 
   6014       (while (and token-re (< (point) reg-end) (web-mode-dom-rsf token-re reg-end t))
   6015 
   6016         (setq beg (match-beginning 0)
   6017               token-type nil
   6018               continue t
   6019               ch-at (char-after beg)
   6020               ch-next (or (char-after (1+ beg)) ?\d)
   6021               ch-before (or (char-before beg) ?\d))
   6022 
   6023         ;;(message "[%S>%S|%S] %S %c %c %c" reg-beg reg-end depth beg ch-before ch-at ch-next)
   6024 
   6025         (cond
   6026 
   6027           ((eq ?\' ch-at)
   6028            (while (and continue (search-forward "'" reg-end t))
   6029              (cond
   6030                ((get-text-property (1- (point)) 'block-side)
   6031                 (setq continue t))
   6032                (t
   6033                 (setq continue (web-mode-string-continue-p reg-beg)))
   6034                )
   6035              ) ;while
   6036            (setq token-type 'string))
   6037 
   6038           ((eq ?\` ch-at)
   6039            (while (and continue (search-forward "`" reg-end t))
   6040              (cond
   6041                ((get-text-property (1- (point)) 'block-side)
   6042                 (setq continue t))
   6043                (t
   6044                 (setq continue (web-mode-string-continue-p reg-beg)))
   6045                )
   6046              ) ;while
   6047            (setq token-type 'string))
   6048 
   6049           ((eq ?\" ch-at)
   6050            (while (and continue (search-forward "\"" reg-end t))
   6051              (cond
   6052                ((get-text-property (1- (point)) 'block-side)
   6053                 (setq continue t))
   6054                (t
   6055                 (setq continue (web-mode-string-continue-p reg-beg)))
   6056                ) ;cond
   6057              ) ;while
   6058            (cond
   6059              ((string= content-type "json")
   6060               (if (looking-at-p "[ ]*:")
   6061                   (cond
   6062                     ((eq ?\@ (char-after (1+ beg)))
   6063                      (setq token-type 'context))
   6064                     (t
   6065                      (setq token-type 'key))
   6066                     )
   6067                   (setq token-type 'string))
   6068               ) ;json
   6069              (t
   6070               (setq token-type 'string))
   6071              ) ;cond
   6072            )
   6073 
   6074           ((and (eq ?\< ch-at)
   6075                 (not (or (and (>= ch-before 97) (<= ch-before 122))
   6076                          (and (>= ch-before 65) (<= ch-before 90)))))
   6077            ;;(message "before [%S>%S|%S] pt=%S" reg-beg reg-end depth (point))
   6078            (search-backward "<")
   6079            (if (web-mode-jsx-skip reg-end)
   6080                (web-mode-jsx-scan-element beg (point) depth)
   6081                (forward-char))
   6082            ;;(message "after [%S>%S|%S] pt=%S" reg-beg reg-end depth (point))
   6083            )
   6084 
   6085           ((and (eq ?\/ ch-at) (member content-type '("javascript" "jsx" "typescript")))
   6086            (cond
   6087              ((eq ?\\ ch-before)
   6088               )
   6089              ((eq ?\* ch-next)
   6090               ;;(message "--> %S %S" (point) reg-end)
   6091               (when (search-forward "*/" reg-end t)
   6092                 (setq token-type 'comment))
   6093               )
   6094              ((eq ?\/ ch-next)
   6095               (setq token-type 'comment)
   6096               (goto-char (if (< reg-end (line-end-position)) reg-end (line-end-position)))
   6097               )
   6098              ((and (looking-at-p ".*/")
   6099                    (looking-back "\\(^\\|case\\|[[(,=:!&|?{};]\\)[ ]*/" (point-min)))
   6100               ;;(re-search-forward "/[gimyu]*" reg-end t))
   6101               (let ((eol (line-end-position)))
   6102                 (while (and continue (search-forward "/" eol t))
   6103                   (cond
   6104                     ((get-text-property (1- (point)) 'block-side)
   6105                      (setq continue t))
   6106                     ((looking-back "\\\\+/" reg-beg t)
   6107                      (setq continue (= (mod (- (point) (match-beginning 0)) 2) 0)))
   6108                     (t
   6109                      (re-search-forward "[gimyu]*" eol t)
   6110                      (setq token-type 'string)
   6111                      (setq continue nil))
   6112                     )
   6113                   ) ;while
   6114                 ) ;let
   6115               )
   6116              ) ;cond
   6117            )
   6118 
   6119           ((eq ?\/ ch-next)
   6120            ;;(message "%S" (point))
   6121            (cond
   6122              ((and (string= content-type "css")
   6123                    (eq ?/ ch-at)
   6124                    (eq ?: ch-before))
   6125               )
   6126              (t
   6127               (unless (eq ?\\ ch-before)
   6128                 (setq token-type 'comment)
   6129                 (goto-char (if (< reg-end (line-end-position)) reg-end (line-end-position)))
   6130                 )
   6131               )
   6132              )
   6133 
   6134            )
   6135 
   6136           ((eq ?\* ch-next)
   6137            (cond
   6138              ((search-forward "*/" reg-end t)
   6139               (setq token-type 'comment))
   6140              ((not (eobp))
   6141               (forward-char))
   6142              ) ;cond
   6143            )
   6144 
   6145           ) ;cond
   6146 
   6147         (when (and beg (>= reg-end (point)) token-type)
   6148           (put-text-property beg (point) 'part-token token-type)
   6149           (cond
   6150             ((eq token-type 'comment)
   6151              (put-text-property beg (1+ beg) 'syntax-table (string-to-syntax "<"))
   6152              (when (< (point) (point-max))
   6153                (if (< (point) (line-end-position))
   6154                    (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax ">")) ;#445
   6155                    (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax ">")) ;#377
   6156                    )
   6157                ) ;when
   6158              ) ;comment
   6159             ((eq token-type 'string)
   6160              (put-text-property beg (1+ beg) 'syntax-table (string-to-syntax "|"))
   6161              (when (< (point) (point-max))
   6162                (if (< (point) (line-end-position))
   6163                    (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax "|"))
   6164                    (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax "|"))
   6165                    )
   6166                ) ;when
   6167              ) ;string
   6168             ) ;cond
   6169           ) ;when
   6170 
   6171         (when (> (point) reg-end)
   6172           (message "reg-beg(%S) reg-end(%S) token-type(%S) point(%S)" reg-beg reg-end token-type (point)))
   6173 
   6174         ;;(message "#[%S>%S|%S] %S %c %c %c | (%S)" reg-beg reg-end depth beg ch-before ch-at ch-next (point))
   6175 
   6176         ) ;while
   6177 
   6178       )))
   6179 
   6180 (defun web-mode-string-continue-p (reg-beg)
   6181   "Is `point' preceeded by an odd number of backslashes?"
   6182   (let ((p (1- (point))))
   6183     (while (and (< reg-beg p) (eq ?\\ (char-before p)))
   6184       (setq p (1- p)))
   6185     (= (mod (- (point) p) 2) 0)))
   6186 
   6187 ;; css rule = selector(s) + declaration (properties)
   6188 (defun web-mode-css-rule-next (limit)
   6189   (let (at-rule var-rule sel-beg sel-end dec-beg dec-end chunk)
   6190     (skip-chars-forward "\n\t ")
   6191     (setq sel-beg (point))
   6192     (when (and (< (point) limit)
   6193                (web-mode-part-rsf "[{;]" limit))
   6194       (setq sel-end (1- (point)))
   6195       (cond
   6196         ((eq (char-before) ?\{)
   6197          (setq dec-beg (point))
   6198          (setq dec-end (web-mode-closing-paren-position (1- dec-beg) limit))
   6199          (if dec-end
   6200              (progn
   6201                (goto-char dec-end)
   6202                (forward-char))
   6203              (setq dec-end limit)
   6204              (goto-char limit))
   6205          )
   6206         (t
   6207          )
   6208         ) ;cond
   6209       (setq chunk (buffer-substring-no-properties sel-beg sel-end))
   6210       (cond
   6211         ((string-match "@\\([[:alpha:]-]+\\)" chunk)
   6212          (setq at-rule (match-string-no-properties 1 chunk)))
   6213         ((string-match "\\$\\([[:alpha:]-]+\\)" chunk)
   6214          (setq var-rule (match-string-no-properties 1 chunk)))
   6215         ) ;cond
   6216       ) ;when
   6217     (if (not sel-end)
   6218         (progn (goto-char limit) nil)
   6219         (list :at-rule at-rule
   6220               :var-rule var-rule
   6221               :sel-beg sel-beg
   6222               :sel-end sel-end
   6223               :dec-beg dec-beg
   6224               :dec-end dec-end)
   6225         ) ;if
   6226     ))
   6227 
   6228 (defun web-mode-css-rule-current (&optional pos part-beg part-end)
   6229   "Current CSS rule boundaries."
   6230   (unless pos (setq pos (point)))
   6231   (unless part-beg (setq part-beg (web-mode-part-beginning-position pos)))
   6232   (unless part-end (setq part-end (web-mode-part-end-position pos)))
   6233   (save-excursion
   6234     (let (beg end)
   6235       (goto-char pos)
   6236       (if (not (web-mode-part-sb "{" part-beg))
   6237           (progn
   6238             (setq beg part-beg)
   6239             (if (web-mode-part-sf ";" part-end)
   6240                 (setq end (1+ (point)))
   6241                 (setq end part-end))
   6242             ) ;progn
   6243           (setq beg (point))
   6244           (setq end (web-mode-closing-paren-position beg part-end))
   6245           (if end
   6246               (setq end (1+ end))
   6247               (setq end (line-end-position)))
   6248           ;;        (message "%S >>beg%S >>end%S" pos beg end)
   6249           (if (> pos end)
   6250 
   6251               ;;selectors
   6252               (progn
   6253                 (goto-char pos)
   6254                 (if (web-mode-part-rsb "[};]" part-beg)
   6255                     (setq beg (1+ (point)))
   6256                     (setq beg part-beg)
   6257                     ) ;if
   6258                 (goto-char pos)
   6259                 (if (web-mode-part-rsf "[{;]" part-end)
   6260                     (cond
   6261                       ((eq (char-before) ?\;)
   6262                        (setq end (point))
   6263                        )
   6264                       (t
   6265                        (setq end (web-mode-closing-paren-position (1- (point)) part-end))
   6266                        (if end
   6267                            (setq end (1+ end))
   6268                            (setq end part-end))
   6269                        )
   6270                       ) ;cond
   6271                     (setq end part-end)
   6272                     )
   6273                 ) ;progn selectors
   6274 
   6275               ;; declaration
   6276               (goto-char beg)
   6277               (if (web-mode-part-rsb "[}{;]" part-beg)
   6278                   (setq beg (1+ (point)))
   6279                   (setq beg part-beg)
   6280                   ) ;if
   6281               ) ;if > pos end
   6282           )
   6283       ;;      (message "beg(%S) end(%S)" beg end)
   6284       (when (eq (char-after beg) ?\n)
   6285         (setq beg (1+ beg)))
   6286       (cons beg end)
   6287       )))
   6288 
   6289 (defun web-mode-jsx-skip (reg-end)
   6290   (let ((continue t) (pos nil) (i 0))
   6291     (looking-at "<\\([[:alpha:]][[:alnum:]:-]*\\)")
   6292     ;; (let ((tag (match-string-no-properties 1)))
   6293     ;;   (message "point=%S tag=%S" (point) tag))
   6294     (save-excursion
   6295       (while continue
   6296         (cond
   6297           ((> (setq i (1+ i)) 1000)
   6298            (message "jsx-skip ** warning **")
   6299            (setq continue nil))
   6300           ((looking-at "<[[:alpha:]][[:alnum:]:-]*[ ]*/>")
   6301            (goto-char (match-end 0))
   6302            (setq pos (point))
   6303            (setq continue nil))
   6304           ((not (web-mode-dom-rsf ">\\([ \t\n]*[\];,)':}|&]\\)\\|{" reg-end))
   6305            (setq continue nil)
   6306            )
   6307           ((eq (char-before) ?\{)
   6308            (backward-char)
   6309            (web-mode-closing-paren reg-end)
   6310            (forward-char)
   6311            )
   6312           (t
   6313            (setq continue nil)
   6314            (setq pos (match-beginning 1))
   6315            ) ;t
   6316           ) ;cond
   6317         ) ;while
   6318       ) ;save-excursion
   6319     (when pos (goto-char pos))
   6320     ;;(message "jsx-skip: %S" pos)
   6321     pos))
   6322 
   6323 ;; (defun web-mode-jsx-skip2 (reg-end)
   6324 ;;   (let ((continue t) (pos nil) (i 0) (tag nil) (regexp nil) (counter 1))
   6325 ;;     (looking-at "<\\([[:alpha:]][[:alnum:]:-]*\\)")
   6326 ;;     (setq tag (match-string-no-properties 1))
   6327 ;;     (setq regexp (concat "</?" tag))
   6328 ;;     ;;(message "point=%S tag=%S" (point) tag)
   6329 ;;     (save-excursion
   6330 ;;       (while continue
   6331 ;;         (cond
   6332 ;;          ((> (setq i (1+ i)) 100)
   6333 ;;           (message "jsx-skip ** warning **")
   6334 ;;           (setq continue nil))
   6335 ;;          ((looking-at "<[[:alpha:]][[:alnum:]:-]*[ ]*/>")
   6336 ;;           (goto-char (match-end 0))
   6337 ;;           (setq pos (point))
   6338 ;;           (setq continue nil))
   6339 ;;          ((not (web-mode-dom-rsf ">\\([ \t\n]*[\];,)':}]\\)\\|{" reg-end))
   6340 ;;           (setq continue nil)
   6341 ;;           )
   6342 ;;          ((eq (char-before) ?\{)
   6343 ;;           (backward-char)
   6344 ;;           (web-mode-closing-paren reg-end)
   6345 ;;           (forward-char)
   6346 ;;           )
   6347 ;;          (t
   6348 ;;           (setq continue nil)
   6349 ;;           (setq pos (match-beginning 1))
   6350 ;;           ) ;t
   6351 ;;          ) ;cond
   6352 ;;         ) ;while
   6353 ;;       ) ;save-excursion
   6354 ;;     (when pos (goto-char pos))
   6355 ;;     ;;(message "jsx-skip: %S" pos)
   6356 ;;     pos))
   6357 
   6358 ;; http://facebook.github.io/jsx/
   6359 ;; https://github.com/facebook/jsx/blob/master/AST.md
   6360 (defun web-mode-jsx-scan-element (reg-beg reg-end depth)
   6361   (unless depth (setq depth 1))
   6362   (save-excursion
   6363     (goto-char reg-beg)
   6364     (put-text-property reg-beg (1+ reg-beg) 'jsx-beg depth)
   6365     (put-text-property (1- reg-end) reg-end 'jsx-end depth)
   6366     (put-text-property reg-beg reg-end 'jsx-depth depth)
   6367     (goto-char reg-beg)
   6368     (web-mode-scan-elements reg-beg reg-end)
   6369     (web-mode-jsx-scan-expression reg-beg reg-end (1+ depth))
   6370     ))
   6371 
   6372 (defun web-mode-jsx-scan-expression (reg-beg reg-end depth)
   6373   (let ((continue t) beg end)
   6374     (save-excursion
   6375       (goto-char reg-beg)
   6376       ;;(message "reg-beg=%S reg-end=%S" reg-beg reg-end)
   6377       (while (and continue (search-forward "{" reg-end t))
   6378         (backward-char)
   6379         (setq beg (point)
   6380               end (web-mode-closing-paren reg-end))
   6381         (cond
   6382           ((eq (get-text-property beg 'part-token) 'comment)
   6383            (forward-char))
   6384           ((not end)
   6385            (setq continue nil))
   6386           (t
   6387            (setq end (1+ end))
   6388            (put-text-property beg end 'jsx-depth depth)
   6389            (put-text-property beg (1+ beg) 'jsx-beg depth)
   6390            (put-text-property (1- end) end 'jsx-end depth)
   6391            (web-mode-part-scan beg end "jsx" (1+ depth))
   6392            ) ;t
   6393           ) ;cond
   6394         ) ;while
   6395       ) ;save-excursion
   6396     ))
   6397 
   6398 (defun web-mode-jsx-is-html (&optional pos)
   6399   (interactive)
   6400   (unless pos (setq pos (point)))
   6401   (let ((depth (get-text-property pos 'jsx-depth)))
   6402     (cond
   6403       ((or (null depth) (<= pos 2))
   6404        (setq pos nil))
   6405       ((and (= depth 1) (get-text-property pos 'jsx-beg))
   6406        (setq pos nil))
   6407       ((get-text-property pos 'tag-end)
   6408        (setq pos nil))
   6409       ((get-text-property pos 'tag-attr-beg)
   6410        (setq pos nil))
   6411       ((get-text-property pos 'jsx-beg)
   6412        (setq pos (null (get-text-property pos 'tag-beg))))
   6413       ((setq pos (web-mode-jsx-depth-beginning-position pos))
   6414        (setq pos (not (null (get-text-property pos 'tag-beg)))))
   6415       (t
   6416        (setq pos nil))
   6417       ) ;cond
   6418     ;;(message "is-html: %S (depth=%S)" pos depth)
   6419     pos))
   6420 
   6421 (defun web-mode-jsx-is-expr (&optional pos)
   6422   (cond
   6423     ((and (get-text-property pos 'jsx-beg)
   6424           (not (get-text-property pos 'tag-beg)))
   6425      nil)
   6426     (t
   6427      (setq pos (web-mode-jsx-depth-beginning-position pos))
   6428      (null (get-text-property pos 'tag-beg)))
   6429     ) ;cond
   6430   )
   6431 
   6432 (defun web-mode-jsx-depth-beginning-position (&optional pos target-depth)
   6433   (interactive)
   6434   (unless pos (setq pos (point)))
   6435   (unless target-depth (setq target-depth (get-text-property pos 'jsx-depth)))
   6436   (cond
   6437     ((or (null target-depth) (bobp))
   6438      (setq pos nil))
   6439     ((and (get-text-property pos 'jsx-beg) (= target-depth (get-text-property pos 'jsx-depth)))
   6440      )
   6441     (t
   6442      (let ((continue t) depth)
   6443        (while continue
   6444          (setq pos (previous-single-property-change pos 'jsx-depth))
   6445          (cond
   6446            ((or (null pos)
   6447                 (null (setq depth (get-text-property pos 'jsx-depth))))
   6448             (setq continue nil
   6449                   pos nil))
   6450            ((and (get-text-property pos 'jsx-beg) (= target-depth depth))
   6451             (setq continue nil))
   6452            ) ;cond
   6453          ) ;while
   6454        ) ;let
   6455      ) ;t
   6456     ) ;cond
   6457   ;;(message "beg: %S" pos)
   6458   pos)
   6459 
   6460 (defun web-mode-jsx-element-next (reg-end)
   6461   (let (continue beg end)
   6462     (setq beg (point))
   6463     (unless (get-text-property beg 'jsx-depth)
   6464       (setq beg (next-single-property-change beg 'jsx-beg)))
   6465     (setq continue (and beg (< beg reg-end))
   6466           end beg)
   6467     (while continue
   6468       (setq end (next-single-property-change end 'jsx-end))
   6469       (cond
   6470         ((or (null end) (> end reg-end))
   6471          (setq continue nil
   6472                end nil))
   6473         ((eq (get-text-property end 'jsx-depth) 1)
   6474          (setq continue nil))
   6475         (t
   6476          (setq end (1+ end)))
   6477         ) ;cond
   6478       ) ;while
   6479     ;;(message "beg=%S end=%S" beg end)
   6480     (if (and beg end (< beg end)) (cons beg end) nil)))
   6481 
   6482 (defun web-mode-jsx-expression-next (reg-end)
   6483   (let (beg end depth continue pos)
   6484     (setq beg (point))
   6485     ;;(message "pt=%S" beg)
   6486     (unless (and (get-text-property beg 'jsx-beg) (null (get-text-property beg 'tag-beg)))
   6487       ;;(setq beg (next-single-property-change beg 'jsx-beg))
   6488       (setq continue t
   6489             pos (1+ beg))
   6490       (while continue
   6491         (setq pos (next-single-property-change pos 'jsx-beg))
   6492         (cond
   6493           ((null pos)
   6494            (setq continue nil
   6495                  beg nil))
   6496           ((> pos reg-end)
   6497            (setq continue nil
   6498                  beg nil))
   6499           ((null (get-text-property pos 'jsx-beg))
   6500            )
   6501           ((null (get-text-property pos 'tag-beg))
   6502            (setq continue nil
   6503                  beg pos))
   6504           ;;(t
   6505           ;; (setq pos (1+ pos)))
   6506           ) ;cond
   6507         ) ;while
   6508       ) ;unless
   6509     ;;(message "beg=%S" beg)
   6510     (when (and beg (< beg reg-end))
   6511       (setq depth (get-text-property beg 'jsx-beg)
   6512             continue (not (null depth))
   6513             pos beg)
   6514       ;;(message "beg=%S" beg)
   6515       (while continue
   6516         (setq pos (next-single-property-change pos 'jsx-end))
   6517         ;;(message "pos=%S" pos)
   6518         (cond
   6519           ((null pos)
   6520            (setq continue nil))
   6521           ((> pos reg-end)
   6522            (setq continue nil))
   6523           ((eq depth (get-text-property pos 'jsx-end))
   6524            (setq continue nil
   6525                  end pos))
   6526           (t
   6527            ;;(setq pos (1+ pos))
   6528            )
   6529           ) ;cond
   6530         ) ;while
   6531       ) ;when
   6532     ;;(message "%S > %S" beg end)
   6533     (if (and beg end) (cons beg end) nil)))
   6534 
   6535 (defun web-mode-jsx-depth-next (reg-end)
   6536   (let (beg end depth continue pos)
   6537     (setq beg (point))
   6538     ;;(message "pt=%S" beg)
   6539     (unless (get-text-property beg 'jsx-beg)
   6540       ;;(setq beg (next-single-property-change beg 'jsx-beg))
   6541       ;;(setq pos (1+ beg))
   6542       (setq pos (next-single-property-change (1+ beg) 'jsx-beg))
   6543       (cond
   6544         ((null pos)
   6545          (setq beg nil))
   6546         ((>= pos reg-end)
   6547          (setq beg nil))
   6548         (t
   6549          (setq beg pos))
   6550         ) ;cond
   6551       ) ;unless
   6552     ;;(message "beg=%S" beg)
   6553     (when beg
   6554       (setq depth (get-text-property beg 'jsx-beg)
   6555             continue (not (null depth))
   6556             pos beg)
   6557       ;;(message "beg=%S" beg)
   6558       (while continue
   6559         (setq pos (next-single-property-change pos 'jsx-end))
   6560         ;;(message "pos=%S" pos)
   6561         (cond
   6562           ((null pos)
   6563            (setq continue nil))
   6564           ((> pos reg-end)
   6565            (setq continue nil))
   6566           ((eq depth (get-text-property pos 'jsx-end))
   6567            (setq continue nil
   6568                  end pos))
   6569           (t
   6570            ;;(setq pos (1+ pos))
   6571            )
   6572           ) ;cond
   6573         ) ;while
   6574       ) ;when
   6575     ;;(message "%S > %S" beg end)
   6576     (if (and beg end) (cons beg end) nil)))
   6577 
   6578 (defun web-mode-jsx-beginning ()
   6579   (interactive)
   6580   (let (depth (continue t) (reg-beg (point-min)) (pos (point)))
   6581     (setq depth (get-text-property pos 'jsx-depth))
   6582     (cond
   6583       ((not depth)
   6584        )
   6585       ((get-text-property (1- pos) 'jsx-beg)
   6586        (goto-char (1- pos)))
   6587       (t
   6588        (while continue
   6589          (setq pos (previous-single-property-change pos 'jsx-beg))
   6590          ;;(message "pos=%S" pos)
   6591          (cond
   6592            ((null pos)
   6593             (setq continue nil))
   6594            ((<= pos reg-beg)
   6595             (setq continue nil))
   6596            ((eq depth (get-text-property pos 'jsx-beg))
   6597             (setq continue nil))
   6598            ) ;cond
   6599          ) ;while
   6600        (web-mode-go pos)
   6601        ) ;t
   6602       ) ;cond
   6603     ))
   6604 
   6605 (defun web-mode-jsx-end ()
   6606   (interactive)
   6607   (let (depth (continue t) (reg-end (point-max)) (pos (point)))
   6608     (setq depth (get-text-property pos 'jsx-depth))
   6609     (cond
   6610       ((not depth)
   6611        )
   6612       ((get-text-property pos 'jsx-end)
   6613        (goto-char (+ pos 1)))
   6614       (t
   6615        (while continue
   6616          (setq pos (next-single-property-change pos 'jsx-end))
   6617          ;;(message "pos=%S" pos)
   6618          (cond
   6619            ((null pos)
   6620             (setq continue nil))
   6621            ((> pos reg-end)
   6622             (setq continue nil))
   6623            ((eq depth (get-text-property pos 'jsx-end))
   6624             (setq continue nil))
   6625            ) ;cond
   6626          ) ;while
   6627        (web-mode-go pos 1)
   6628        ) ;t
   6629       ) ;cond
   6630     ))
   6631 
   6632 ;;---- FONTIFICATION -----------------------------------------------------------
   6633 
   6634 (defun web-mode-fontify (limit)
   6635   (when web-mode-trace
   6636     (message "fontify: point(%S) limit(%S)" (point) limit))
   6637   (cond
   6638     ;;(web-mode-skip-fontification
   6639     ;; nil)
   6640     (t
   6641      (web-mode-with-silent-modifications
   6642       (save-excursion
   6643         (save-restriction
   6644           (save-match-data
   6645             (let ((beg (point))
   6646                   (buffer-undo-list t)
   6647                   (end limit)
   6648                   (inhibit-point-motion-hooks t)
   6649                   (inhibit-quit t))
   6650               (remove-list-of-text-properties beg end '(font-lock-face face))
   6651               (cond
   6652                 ((and (get-text-property beg 'block-side)
   6653                       (not (get-text-property beg 'block-beg)))
   6654                  (web-mode-fontify-block beg end))
   6655                 ((or (member web-mode-content-type web-mode-part-content-types)
   6656                      (get-text-property beg 'part-side))
   6657                  (web-mode-fontify-part beg end)
   6658                  (web-mode-block-foreach beg end 'web-mode-fontify-block))
   6659                 ((string= web-mode-engine "none")
   6660                  (web-mode-fontify-tags beg end)
   6661                  (web-mode-part-foreach beg end 'web-mode-fontify-part))
   6662                 (t
   6663                  (web-mode-fontify-tags beg end)
   6664                  (web-mode-part-foreach beg end 'web-mode-fontify-part)
   6665                  (web-mode-block-foreach beg end 'web-mode-fontify-block))
   6666                 ) ;cond
   6667               (when web-mode-enable-element-content-fontification
   6668                 (web-mode-fontify-elements beg end))
   6669               (when web-mode-enable-whitespace-fontification
   6670                 (web-mode-fontify-whitespaces beg end))
   6671               ) ;let
   6672             ))))
   6673      nil) ;t
   6674     ))
   6675 
   6676 (defun web-mode-buffer-fontify ()
   6677   (interactive)
   6678   (cond
   6679     ((and (fboundp 'font-lock-flush) global-font-lock-mode)
   6680      (font-lock-flush)
   6681      (font-lock-ensure))
   6682     (t  ;emacs 24
   6683      ;;(font-lock-fontify-buffer)
   6684      (and global-font-lock-mode
   6685           (font-lock-fontify-region (point-min) (point-max))))
   6686     ))
   6687 
   6688 (defun web-mode-unfontify-region (beg end)
   6689   (ignore beg end)
   6690   ;;(message "unfontify: %S %S" beg end)
   6691   )
   6692 
   6693 (defun web-mode-fontify-region (beg end keywords)
   6694   ;;  (message "beg=%S end=%S keywords=%S" beg end (symbol-name keywords))
   6695   (save-excursion
   6696     (let ((font-lock-keywords keywords)
   6697           (font-lock-multiline nil)
   6698           (font-lock-keywords-case-fold-search
   6699            (member web-mode-engine '("archibus" "asp" "template-toolkit")))
   6700           (font-lock-keywords-only t)
   6701           (font-lock-extend-region-functions nil))
   6702       (when (and (listp font-lock-keywords) global-font-lock-mode)
   6703         (font-lock-fontify-region beg end)
   6704         )
   6705       )))
   6706 
   6707 (defun web-mode-fontify-tags (reg-beg reg-end &optional depth)
   6708   (let ((continue t))
   6709     (goto-char reg-beg)
   6710     (when (and (not (get-text-property (point) 'tag-beg))
   6711                (not (web-mode-tag-next)))
   6712       (setq continue nil))
   6713     (when (and continue (>= (point) reg-end))
   6714       (setq continue nil))
   6715     (while continue
   6716       (cond
   6717         (depth
   6718          (when (eq depth (get-text-property (point) 'jsx-depth))
   6719            (web-mode-fontify-tag))
   6720          )
   6721         (t
   6722          (web-mode-fontify-tag))
   6723         ) ;cond
   6724       (when (or (not (web-mode-tag-next))
   6725                 (>= (point) reg-end))
   6726         (setq continue nil))
   6727       ) ;while
   6728     (when web-mode-enable-inlays
   6729       (when (null web-mode-inlay-regexp)
   6730         (setq web-mode-inlay-regexp (regexp-opt '("\\[" "\\(" "\\begin{align}"))))
   6731       (let (beg end expr)
   6732         (goto-char reg-beg)
   6733         (while (web-mode-dom-rsf web-mode-inlay-regexp reg-end)
   6734           (setq beg (match-beginning 0)
   6735                 end nil
   6736                 expr (substring (match-string-no-properties 0) 0 2))
   6737           (setq expr (cond
   6738                        ((string= expr "\\[") "\\]")
   6739                        ((string= expr "\\(") "\\)")
   6740                        (t "\\end{align}")))
   6741           (when (and (web-mode-dom-sf expr reg-end)
   6742                      (setq end (match-end 0))
   6743                      (not (text-property-any beg end 'tag-end t)))
   6744             (font-lock-append-text-property beg end 'font-lock-face 'web-mode-inlay-face)
   6745             ) ;when
   6746           ) ;while
   6747         ) ;let
   6748       ) ;when
   6749     (when web-mode-enable-html-entities-fontification
   6750       (let (beg end)
   6751         (goto-char reg-beg)
   6752         (while (web-mode-dom-rsf "&\\([#]?[[:alnum:]]\\{2,8\\}\\);" reg-end)
   6753           (setq beg (match-beginning 0)
   6754                 end (match-end 0))
   6755           (when (not (text-property-any beg end 'tag-end t))
   6756             (font-lock-append-text-property beg end 'font-lock-face 'web-mode-html-entity-face)
   6757             ) ;when
   6758           ) ;while
   6759         ) ;let
   6760       ) ;when
   6761     ))
   6762 
   6763 (defun web-mode-fontify-tag (&optional beg end)
   6764   (unless beg (setq beg (point)))
   6765   (unless end (setq end (1+ (web-mode-tag-end-position beg))))
   6766   (let (name type face flags slash-beg slash-end bracket-end)
   6767     (setq flags (get-text-property beg 'tag-beg)
   6768           type (get-text-property beg 'tag-type)
   6769           name (get-text-property beg 'tag-name))
   6770     (setq bracket-end (> (logand flags 16) 0))
   6771     (cond
   6772       ((eq type 'comment)
   6773        (put-text-property beg end 'font-lock-face 'web-mode-comment-face)
   6774        (when (and web-mode-enable-comment-interpolation (> (- end beg) 5))
   6775          (web-mode-interpolate-comment beg end nil)))
   6776       ((eq type 'cdata)
   6777        (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
   6778       ((eq type 'doctype)
   6779        (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
   6780       ((eq type 'declaration)
   6781        (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
   6782       (name
   6783        (setq slash-beg (> (logand flags 4) 0)
   6784              slash-end (> (logand flags 8) 0)
   6785              bracket-end (> (logand flags 16) 0))
   6786        (setq face (cond
   6787                     ((not bracket-end)       'web-mode-html-tag-unclosed-face)
   6788                     ((and web-mode-enable-element-tag-fontification
   6789                           (setq face (cdr (assoc name web-mode-element-tag-faces))))
   6790                      face)
   6791                     ((> (logand flags 32) 0) 'web-mode-html-tag-namespaced-face)
   6792                     ((> (logand flags 2) 0)  'web-mode-html-tag-custom-face)
   6793                     (t                       'web-mode-html-tag-face)))
   6794        (put-text-property beg (+ beg (if slash-beg 2 1))
   6795                           'font-lock-face 'web-mode-html-tag-bracket-face)
   6796        (unless (string= name "_fragment_")
   6797          (put-text-property (+ beg (if slash-beg 2 1))
   6798                             (+ beg (if slash-beg 2 1) (length name))
   6799                             'font-lock-face face))
   6800        (when (or slash-end bracket-end)
   6801          (put-text-property (- end (if slash-end 2 1)) end 'font-lock-face 'web-mode-html-tag-bracket-face)
   6802          ) ;when
   6803        (when (> (logand flags 1) 0)
   6804          ;;(message "%S>%S" beg end)
   6805          (web-mode-fontify-attrs beg end))
   6806        ) ;case name
   6807       ) ;cond
   6808     ))
   6809 
   6810 (defun web-mode-fontify-attrs (reg-beg reg-end)
   6811   (let ((continue t) (pos reg-beg) beg end flags offset face)
   6812     ;;(message "fontify-attrs %S>%S" reg-beg reg-end)
   6813     (while continue
   6814       (setq beg (web-mode-attribute-next-position pos reg-end))
   6815       (cond
   6816         ((or (null beg) (>= beg reg-end))
   6817          (setq continue nil))
   6818         (t
   6819          (setq flags (or (get-text-property beg 'tag-attr-beg) 0))
   6820          (setq face (cond
   6821                       ((= (logand flags 1) 1) 'web-mode-html-attr-custom-face)
   6822                       ((= (logand flags 2) 2) 'web-mode-html-attr-engine-face)
   6823                       ((= (logand flags 4) 4) nil)
   6824                       (t                      'web-mode-html-attr-name-face)))
   6825          ;;(setq end (if (get-text-property beg 'tag-attr-end) beg (web-mode-attribute-end-position beg)))
   6826          (setq end (web-mode-attribute-end-position beg))
   6827          ;;(message "beg=%S end=%S" beg end)
   6828          (cond
   6829            ((or (null end) (>= end reg-end))
   6830             (setq continue nil))
   6831            (t
   6832             (setq offset (get-text-property end 'tag-attr-end))
   6833             (if (= offset 0)
   6834                 (put-text-property beg (1+ end) 'font-lock-face face)
   6835                 (put-text-property beg (+ beg offset) 'font-lock-face face)
   6836                 (put-text-property (+ beg offset) (+ beg offset 1)
   6837                                    'font-lock-face
   6838                                    'web-mode-html-attr-equal-face)
   6839                 (when (not (get-text-property (+ beg offset 1) 'jsx-beg))
   6840                   (put-text-property (+ beg offset 1) (1+ end)
   6841                                      'font-lock-face
   6842                                      'web-mode-html-attr-value-face)
   6843                   )
   6844                 ) ;if offset
   6845             (setq pos (1+ end))
   6846             ) ;t
   6847            ) ;cond
   6848          ) ;t
   6849         );cond
   6850       ) ;while
   6851     ))
   6852 
   6853 (defun web-mode-fontify-block (reg-beg reg-end)
   6854   (when web-mode-trace
   6855     (message "fontify-block: reg-beg(%S) reg-end(%S) engine(%S) keywords(%S)"
   6856              reg-beg reg-end web-mode-engine (not (null web-mode-engine-font-lock-keywords))))
   6857 
   6858   (let (sub1 sub2 sub3 continue char keywords token-type face beg end (buffer (current-buffer)))
   6859 
   6860     ;; NOTE: required for blocks inside tag attrs
   6861     ;; NOTE: ajout de face dans la liste pour sucharger la couleur définie par
   6862     ;;       un prealable web-mode-fontity-part (2022-12-25 #1230)
   6863     (remove-list-of-text-properties reg-beg reg-end '(font-lock-face face))
   6864     ;;(message "reg-beg=%S reg-end=%S" reg-beg reg-end)
   6865 
   6866     (goto-char reg-beg)
   6867 
   6868     (when (null web-mode-engine-font-lock-keywords)
   6869       (setq sub1 (buffer-substring-no-properties
   6870                   reg-beg (+ reg-beg 1))
   6871             sub2 (buffer-substring-no-properties
   6872                   reg-beg (+ reg-beg 2))
   6873             sub3 (buffer-substring-no-properties
   6874                   reg-beg (+ reg-beg (if (>= (point-max) (+ reg-beg 3)) 3 2))))
   6875       )
   6876 
   6877     (cond
   6878 
   6879       ((and (get-text-property reg-beg 'block-beg)
   6880             (eq (get-text-property reg-beg 'block-token) 'comment))
   6881        (put-text-property reg-beg reg-end 'font-lock-face 'web-mode-comment-face)
   6882        ) ;comment block
   6883 
   6884       (web-mode-engine-font-lock-keywords
   6885        (setq keywords web-mode-engine-font-lock-keywords))
   6886 
   6887       ((string= web-mode-engine "django")
   6888        (cond
   6889          ((string= sub2 "{{")
   6890           (setq keywords web-mode-django-expr-font-lock-keywords))
   6891          ((string= sub2 "{%")
   6892           (setq keywords web-mode-django-code-font-lock-keywords))
   6893          ((string= sub1 "#")
   6894           (setq keywords web-mode-django-code-font-lock-keywords))
   6895          )) ;django
   6896 
   6897       ((string= web-mode-engine "mako")
   6898        (cond
   6899          ((member sub3 '("<% " "<%\n" "<%!"))
   6900           (setq keywords web-mode-mako-block-font-lock-keywords))
   6901          ((eq (aref sub2 0) ?\%)
   6902           (setq keywords web-mode-mako-block-font-lock-keywords))
   6903          ((member sub2 '("<%" "</"))
   6904           (setq keywords web-mode-mako-tag-font-lock-keywords))
   6905          ((member sub2 '("${"))
   6906           (setq keywords web-mode-uel-font-lock-keywords))
   6907          )) ;mako
   6908 
   6909       ((string= web-mode-engine "mason")
   6910        ;;(message "%S %S" sub2 sub3)
   6911        (cond
   6912          ((member sub3 '("<% " "<%\n" "<&|"))
   6913           (setq keywords web-mode-mason-code-font-lock-keywords))
   6914          ((eq (aref sub2 0) ?\%)
   6915           (setq keywords web-mode-mason-code-font-lock-keywords))
   6916          ((and (or (string= sub2 "<%") (string= sub3 "</%"))
   6917                (not (member sub3 '("<%c" "<%i" "<%p"))))
   6918           (setq keywords web-mode-mason-block-font-lock-keywords))
   6919          (t
   6920           (setq keywords web-mode-mason-code-font-lock-keywords))
   6921          )) ;mason
   6922 
   6923       ((string= web-mode-engine "jsp")
   6924        (cond
   6925          ((string= sub3 "<%@")
   6926           (setq keywords web-mode-directive-font-lock-keywords))
   6927          ((member sub2 '("${" "#{"))
   6928           (setq keywords web-mode-uel-font-lock-keywords))
   6929          ((string= sub2 "<%")
   6930           (setq keywords web-mode-jsp-font-lock-keywords))
   6931          )) ;jsp
   6932 
   6933       ((string= web-mode-engine "asp")
   6934        (cond
   6935          ((or (string= sub2 "<%")
   6936               (not (string= sub1 "<")))
   6937           (setq keywords web-mode-asp-font-lock-keywords))
   6938          (t
   6939           (setq keywords web-mode-engine-tag-font-lock-keywords))
   6940          )) ;asp
   6941 
   6942       ((string= web-mode-engine "clip")
   6943        (setq keywords web-mode-engine-tag-font-lock-keywords)
   6944        ) ;clip
   6945 
   6946       ((string= web-mode-engine "perl")
   6947        (setq keywords web-mode-engine-tag-font-lock-keywords)
   6948        ) ;perl
   6949 
   6950       ((string= web-mode-engine "aspx")
   6951        (cond
   6952          ((string= sub3 "<%@")
   6953           (setq keywords web-mode-directive-font-lock-keywords))
   6954          ((string= sub3 "<%$")
   6955           (setq keywords web-mode-expression-font-lock-keywords))
   6956          (t
   6957           (setq keywords web-mode-aspx-font-lock-keywords))
   6958          )) ;aspx
   6959 
   6960       ((string= web-mode-engine "freemarker")
   6961        (cond
   6962          ((member sub2 '("${" "#{"))
   6963           (setq keywords web-mode-uel-font-lock-keywords))
   6964          ((or (member sub2 '("<@" "[@" "<#" "[#"))
   6965               (member sub3 '("</@" "[/@" "</#" "[/#")))
   6966           (setq keywords (if (eq ?\[ (aref sub2 0))
   6967                              web-mode-freemarker-square-font-lock-keywords
   6968                              web-mode-freemarker-font-lock-keywords)))
   6969          (t
   6970           (setq keywords web-mode-engine-tag-font-lock-keywords))
   6971          )) ;freemarker
   6972 
   6973       ) ;cond
   6974 
   6975     (when keywords
   6976       (web-mode-fontify-region reg-beg reg-end keywords)
   6977       (setq continue t)
   6978       (setq end reg-beg)
   6979       (while continue
   6980         (if (get-text-property end 'block-token)
   6981             (setq beg end)
   6982             (setq beg (next-single-property-change end 'block-token buffer reg-end)))
   6983         (setq end nil)
   6984         (when beg (setq char (char-after beg)))
   6985         (if (and beg (< beg reg-end))
   6986             (progn
   6987               (setq token-type (get-text-property beg 'block-token))
   6988               (setq face (cond
   6989                            ((eq token-type 'string)  'web-mode-block-string-face)
   6990                            ((eq token-type 'comment) 'web-mode-block-comment-face)
   6991                            ((eq token-type 'symbol)  'web-mode-symbol-face)
   6992                            (t                        'web-mode-block-delimiter-face)))
   6993               (setq end (next-single-property-change beg 'block-token buffer reg-end))
   6994               ;;              (message "end=%S" end)
   6995               (if (and end (<= end reg-end))
   6996                   (progn
   6997                     ;;(message "%S > %S face(%S)" beg end face)
   6998                     (remove-list-of-text-properties beg end '(face))
   6999                     (put-text-property beg end 'font-lock-face face)
   7000                     )
   7001                   (setq continue nil
   7002                         end nil)
   7003                   ) ;if end
   7004               ) ;progn beg
   7005             (setq continue nil
   7006                   end nil)
   7007             ) ;if beg
   7008         (when (and beg end)
   7009           (save-match-data
   7010             (when (and web-mode-enable-heredoc-fontification
   7011                        (eq char ?\<)
   7012                        (> (- end beg) 8)
   7013                        (string-match-p "JS\\|JAVASCRIPT\\|HTM\\|CSS" (buffer-substring-no-properties beg end)))
   7014               (setq keywords
   7015                     (cond
   7016                       ((string-match-p "H" (buffer-substring-no-properties beg (+ beg 8)))
   7017                        web-mode-html-font-lock-keywords)
   7018                       (t
   7019                        web-mode-javascript-font-lock-keywords)
   7020                       ))
   7021               (web-mode-fontify-region beg end keywords)
   7022               )
   7023             ) ;save-match-data
   7024           (when (and web-mode-enable-string-interpolation
   7025                      (member char '(?\" ?\<))
   7026                      (member web-mode-engine '("php" "erb"))
   7027                      (> (- end beg) 4))
   7028             (web-mode-interpolate-block-string beg end)
   7029             ) ;when
   7030           (when (and web-mode-enable-comment-interpolation
   7031                      (eq token-type 'comment)
   7032                      (> (- end beg) 3))
   7033             (web-mode-interpolate-comment beg end t)
   7034             ) ;when
   7035           (when (and web-mode-enable-comment-annotation
   7036                      (eq token-type 'comment)
   7037                      (> (- end beg) 3))
   7038             (web-mode-annotate-comment beg end)
   7039             ) ;when
   7040           (when (and web-mode-enable-sql-detection
   7041                      (eq token-type 'string)
   7042                      (> (- end beg) 6)
   7043                      (web-mode-looking-at-p (concat "\\(.\\|<<<[[:alnum:]]+\\)[ \n]*" web-mode-sql-queries) beg)
   7044                      )
   7045             (web-mode-interpolate-sql-string beg end)
   7046             ) ;when
   7047           ) ;when beg end
   7048         ) ;while continue
   7049       ) ;when keywords
   7050 
   7051     (when (and (member web-mode-engine '("mako"))
   7052                (> (- reg-end reg-beg) 12)
   7053                (eq ?\< (char-after reg-beg)))
   7054       (web-mode-interpolate-block-tag reg-beg reg-end))
   7055 
   7056     (when web-mode-enable-block-face
   7057       (font-lock-append-text-property reg-beg reg-end 'face 'web-mode-block-face))
   7058 
   7059     ))
   7060 
   7061 (defun web-mode-fontify-part (reg-beg reg-end &optional depth)
   7062   (save-excursion
   7063     (let (continue token-type face pos beg end string-face comment-face content-type)
   7064       ;;(message "fontify-part: reg-beg(%S) reg-end(%S)" reg-beg reg-end)
   7065       (if (member web-mode-content-type web-mode-part-content-types)
   7066           (setq content-type web-mode-content-type)
   7067           (setq content-type (symbol-name (get-text-property reg-beg 'part-side))))
   7068       ;;(message "content-type=%S" content-type)
   7069       (unless depth
   7070         (when (string= content-type "jsx") (setq depth 0))
   7071         )
   7072       (setq string-face 'web-mode-part-string-face
   7073             comment-face 'web-mode-part-comment-face)
   7074       (cond
   7075         ((member content-type '("javascript" "jsx"))
   7076          (setq string-face 'web-mode-javascript-string-face
   7077                comment-face 'web-mode-javascript-comment-face)
   7078          (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
   7079         ((string= content-type "json")
   7080          (setq string-face 'web-mode-json-string-face
   7081                comment-face 'web-mode-json-comment-face)
   7082          (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
   7083         ((string= content-type "css")
   7084          (setq string-face 'web-mode-css-string-face
   7085                comment-face 'web-mode-css-comment-face)
   7086          (web-mode-fontify-css-rules reg-beg reg-end))
   7087         ((string= content-type "sql")
   7088          (web-mode-fontify-region reg-beg reg-end web-mode-sql-font-lock-keywords))
   7089         ((string= content-type "stylus")
   7090          (web-mode-fontify-region reg-beg reg-end web-mode-stylus-font-lock-keywords))
   7091         ((string= content-type "sass")
   7092          (web-mode-fontify-region reg-beg reg-end web-mode-sass-font-lock-keywords))
   7093         ((string= content-type "pug")
   7094          (web-mode-fontify-region reg-beg reg-end web-mode-pug-font-lock-keywords))
   7095         ((string= content-type "markdown")
   7096          (web-mode-fontify-region reg-beg reg-end web-mode-markdown-font-lock-keywords))
   7097         ((string= content-type "ruby")
   7098          (web-mode-fontify-region reg-beg reg-end web-mode-erb-font-lock-keywords))
   7099         ((string= content-type "typescript")
   7100          (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
   7101         ) ;cond
   7102 
   7103       (goto-char reg-beg)
   7104 
   7105       ;;(when (string= content-type "jsx") (web-mode-fontify-tags reg-beg reg-end))
   7106       ;;(setq continue (and pos (< pos reg-end)))
   7107       (setq continue t
   7108             pos reg-beg)
   7109       (while continue
   7110         (if (get-text-property pos 'part-token)
   7111             (setq beg pos)
   7112             (setq beg (next-single-property-change pos 'part-token)))
   7113         (cond
   7114           ((or (null beg) (>= beg reg-end))
   7115            (setq continue nil
   7116                  end nil))
   7117           ((and (eq depth 0) (get-text-property beg 'jsx-depth))
   7118            (setq pos (or (next-single-property-change beg 'jsx-depth) (point-max))))
   7119           (t
   7120            ;;(message "%c" (char-after beg))
   7121            (setq token-type (get-text-property beg 'part-token))
   7122            (setq face (cond
   7123                         ((eq token-type 'string)  string-face)
   7124                         ((eq token-type 'comment) comment-face)
   7125                         ((eq token-type 'context) 'web-mode-json-context-face)
   7126                         ((eq token-type 'key)     'web-mode-json-key-face)
   7127                         (t                        nil)))
   7128            (setq end (or (next-single-property-change beg 'part-token) (point-max))
   7129                  pos end)
   7130            (cond
   7131              ((or (null end) (> end reg-end))
   7132               (setq continue nil
   7133                     end nil))
   7134              (t
   7135               (when face
   7136                 (remove-list-of-text-properties beg end '(face))
   7137                 (put-text-property beg end 'font-lock-face face))
   7138               (cond
   7139                 ((< (- end beg) 6)
   7140                  )
   7141                 ((eq token-type 'string)
   7142                  (cond
   7143                    ((and (eq (char-after beg) ?\`)
   7144                          web-mode-enable-literal-interpolation
   7145                          (member content-type '("javascript" "jsx" "typescript")))
   7146                     (web-mode-interpolate-javascript-literal beg end)
   7147                     )
   7148                    ((and (eq (char-after beg) ?\")
   7149                          web-mode-enable-string-interpolation
   7150                          (member content-type '("javascript" "jsx" "typescript")))
   7151                     (web-mode-interpolate-javascript-string beg end))
   7152                    ) ;cond
   7153                  ) ;case string
   7154                 ((eq token-type 'comment)
   7155                  (when web-mode-enable-comment-interpolation
   7156                    (web-mode-interpolate-comment beg end t))
   7157                  (when web-mode-enable-comment-annotation
   7158                    (web-mode-annotate-comment beg end))
   7159                  )
   7160                 ) ;cond
   7161               ) ;t
   7162              ) ;cond
   7163            ) ;t
   7164           ) ;cond
   7165         ) ;while
   7166 
   7167       (when (and (string= web-mode-content-type "html") web-mode-enable-part-face)
   7168         (font-lock-append-text-property reg-beg reg-end 'face
   7169                                         (cond
   7170                                           ((string= content-type "javascript")
   7171                                            'web-mode-script-face)
   7172                                           ((string= content-type "css")
   7173                                            'web-mode-style-face)
   7174                                           (t
   7175                                            'web-mode-part-face)))
   7176         )
   7177 
   7178       (when (and web-mode-enable-css-colorization (string= content-type "stylus"))
   7179         (goto-char reg-beg)
   7180         (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)
   7181                     (<= (point) reg-end))
   7182           (web-mode-colorize (match-beginning 0) (match-end 0))
   7183           )
   7184         )
   7185 
   7186       (when (and (eq depth 0) (string= content-type "jsx"))
   7187         (let (pair elt-beg elt-end exp-beg exp-end exp-depth)
   7188           (goto-char reg-beg)
   7189           (while (setq pair (web-mode-jsx-element-next reg-end))
   7190             ;;(message "elt-pair=%S" pair)
   7191             (setq elt-beg (car pair)
   7192                   elt-end (cdr pair))
   7193             (remove-list-of-text-properties elt-beg (1+ elt-end) '(face))
   7194             (web-mode-fontify-tags elt-beg elt-end 1)
   7195             (goto-char elt-beg)
   7196             (while (setq pair (web-mode-jsx-expression-next elt-end))
   7197               ;;(message "exp-pair=%S elt-end=%S" pair elt-end)
   7198               (setq exp-beg (car pair)
   7199                     exp-end (cdr pair))
   7200               (when (eq (char-after exp-beg) ?\{)
   7201                 ;;(message "%S : %c %c" exp-beg (char-after (+ exp-beg 1)) (char-after (+ exp-beg 2)))
   7202                 (cond
   7203                   ;;((and (eq (char-after (+ exp-beg 1)) ?\/) (eq (char-after (+ exp-beg 2)) ?\*))
   7204                   ;; (put-text-property exp-beg (1+ exp-end) 'font-lock-face 'web-mode-part-comment-face)
   7205                   ;; )
   7206                   (t
   7207                    (setq exp-depth (get-text-property exp-beg 'jsx-depth))
   7208                    (remove-list-of-text-properties exp-beg exp-end '(font-lock-face))
   7209                    (put-text-property exp-beg (1+ exp-beg) 'font-lock-face 'web-mode-block-delimiter-face)
   7210                    (when (and (eq (get-text-property exp-beg 'tag-attr-beg) 4) (web-mode-looking-at-p "\.\.\." (1+ exp-beg)))
   7211                      (put-text-property exp-beg (+ exp-beg 4) 'font-lock-face 'web-mode-block-delimiter-face))
   7212                    (put-text-property exp-end (1+ exp-end) 'font-lock-face 'web-mode-block-delimiter-face)
   7213                    (web-mode-fontify-tags (1+ exp-beg) exp-end (1+ exp-depth))
   7214                    (web-mode-fontify-part (1+ exp-beg) exp-end exp-depth)
   7215                    (web-mode-fontify-region (1+ exp-beg) exp-end web-mode-javascript-font-lock-keywords)
   7216                    ) ;t
   7217                   ) ;cond
   7218                 ) ;when
   7219               (goto-char (1+ exp-beg))
   7220               ) ;while exp
   7221 
   7222             (when (and elt-beg web-mode-jsx-depth-faces)
   7223               (let (depth-beg depth-end jsx-face)
   7224                 (goto-char elt-beg)
   7225                 (while (setq pair (web-mode-jsx-depth-next reg-end))
   7226                   ;;(message "depth-pair=%S" pair)
   7227                   (setq depth-beg (car pair)
   7228                         depth-end (cdr pair)
   7229                         depth (get-text-property depth-beg 'jsx-depth)
   7230                         jsx-face (elt web-mode-jsx-depth-faces (1- depth)))
   7231                   ;;(message "%S" jsx-face)
   7232                   (font-lock-prepend-text-property depth-beg (1+ depth-end) 'face jsx-face)
   7233                   (goto-char (+ depth-beg 2))
   7234                   )
   7235                 ) ;let
   7236               )
   7237 
   7238             (goto-char (1+ elt-end))
   7239             ) ;while elt
   7240           ) ;let
   7241         ) ;when
   7242 
   7243       ) ;let
   7244     ) ;save-excursion
   7245   )
   7246 
   7247 (defun web-mode-fontify-css-rules (part-beg part-end)
   7248   (save-excursion
   7249     (goto-char part-beg)
   7250     (let (rule (continue t) (i 0) (at-rule nil))
   7251       (while continue
   7252         (setq rule (web-mode-css-rule-next part-end))
   7253         ;;(message "rule=%S" rule)
   7254         (cond
   7255           ((> (setq i (1+ i)) 1000)
   7256            (message "fontify-css-rules ** too much rules **")
   7257            (setq continue nil))
   7258           ((null rule)
   7259            (setq continue nil))
   7260           ((and (setq at-rule (plist-get rule :at-rule))
   7261                 (not (member at-rule '("charset" "font-face" "import" "viewport")))
   7262                 (plist-get rule :dec-end))
   7263            (web-mode-fontify-css-rule (plist-get rule :sel-beg)
   7264                                       (plist-get rule :sel-end)
   7265                                       nil nil)
   7266            (web-mode-fontify-css-rules (plist-get rule :dec-beg)
   7267                                        (plist-get rule :dec-end)))
   7268           (t
   7269            (web-mode-fontify-css-rule (plist-get rule :sel-beg)
   7270                                       (plist-get rule :sel-end)
   7271                                       (plist-get rule :dec-beg)
   7272                                       (plist-get rule :dec-end)))
   7273           ) ;cond
   7274         ) ;while
   7275       ) ;let
   7276     ))
   7277 
   7278 (defun web-mode-fontify-css-rule (sel-beg sel-end dec-beg dec-end)
   7279   (save-excursion
   7280     ;;(let ((end sel-end))
   7281     ;;(message "sel-beg=%S sel-end=%S dec-beg=%S dec-end=%S" sel-beg sel-end dec-beg dec-end)
   7282     (web-mode-fontify-region sel-beg sel-end web-mode-selector-font-lock-keywords)
   7283     (when (and dec-beg dec-end)
   7284       ;;(setq end dec-end)
   7285       (web-mode-fontify-region dec-beg dec-end web-mode-declaration-font-lock-keywords)
   7286       ) ;when
   7287     (when (and dec-beg dec-end)
   7288       (goto-char dec-beg)
   7289       (while (and web-mode-enable-css-colorization
   7290                   (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)
   7291                   ;;(progn (message "%S %S" end (point)) t)
   7292                   (<= (point) dec-end))
   7293         ;;(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)))
   7294         (web-mode-colorize (match-beginning 1) (match-end 1))
   7295         ) ;while
   7296       ) ;when
   7297     ;;) ;let
   7298     ))
   7299 
   7300 (defun web-mode-colorize-foreground (color)
   7301   (let* ((values (x-color-values color))
   7302          (r (car values))
   7303          (g (cadr values))
   7304          (b (car (cdr (cdr values)))))
   7305     (if (> 128.0 (floor (+ (* .3 r) (* .59 g) (* .11 b)) 256))
   7306         "white" "black")))
   7307 
   7308 (defun web-mode-colorize (beg end)
   7309   (let (str plist)
   7310     (setq str (buffer-substring-no-properties beg end))
   7311     ;;(setq str1 (match-string-no-properties 1))
   7312     ;;(message "str=%S" str str1)
   7313     (cond
   7314       ;;(t
   7315       ;; (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))
   7316       ;; )
   7317       ((string= (substring str 0 1) "#")
   7318        (setq plist (list :background str
   7319                          :foreground (web-mode-colorize-foreground str))))
   7320       ((and (>= (length str) 3) (string= (substring str 0 3) "rgb"))
   7321        (setq str (format "#%02X%02X%02X"
   7322                          (string-to-number (match-string-no-properties 2))
   7323                          (string-to-number (match-string-no-properties 3))
   7324                          (string-to-number (match-string-no-properties 4))))
   7325        (setq plist (list :background str
   7326                          :foreground (web-mode-colorize-foreground str))))
   7327       ((string= str "black") (setq plist (list :background "#000000" :foreground (web-mode-colorize-foreground "#000000"))))
   7328       ((string= str "silver") (setq plist (list :background "#c0c0c0" :foreground (web-mode-colorize-foreground "#c0c0c0"))))
   7329       ((string= str "gray") (setq plist (list :background "#808080" :foreground (web-mode-colorize-foreground "#808080"))))
   7330       ((string= str "white") (setq plist (list :background "#ffffff" :foreground (web-mode-colorize-foreground "#ffffff"))))
   7331       ((string= str "maroon") (setq plist (list :background "#800000" :foreground (web-mode-colorize-foreground "#800000"))))
   7332       ((string= str "red") (setq plist (list :background "#ff0000" :foreground (web-mode-colorize-foreground "#ff0000"))))
   7333       ((string= str "purple") (setq plist (list :background "#800080" :foreground (web-mode-colorize-foreground "#800080"))))
   7334       ((string= str "fuchsia") (setq plist (list :background "#ff00ff" :foreground (web-mode-colorize-foreground "#ff00ff"))))
   7335       ((string= str "green") (setq plist (list :background "#008000" :foreground (web-mode-colorize-foreground "#008000"))))
   7336       ((string= str "lime") (setq plist (list :background "#00ff00" :foreground (web-mode-colorize-foreground "#00ff00"))))
   7337       ((string= str "olive") (setq plist (list :background "#808000" :foreground (web-mode-colorize-foreground "#808000"))))
   7338       ((string= str "yellow") (setq plist (list :background "#ffff00" :foreground (web-mode-colorize-foreground "#ffff00"))))
   7339       ((string= str "navy") (setq plist (list :background "#000080" :foreground (web-mode-colorize-foreground "#000080"))))
   7340       ((string= str "blue") (setq plist (list :background "#0000ff" :foreground (web-mode-colorize-foreground "#0000ff"))))
   7341       ((string= str "teal") (setq plist (list :background "#008080" :foreground (web-mode-colorize-foreground "#008080"))))
   7342       ((string= str "aqua") (setq plist (list :background "#00ffff" :foreground (web-mode-colorize-foreground "#00ffff"))))
   7343       ((string= str "orange") (setq plist (list :background "#ffa500" :foreground (web-mode-colorize-foreground "#ffa500"))))
   7344       ((string= str "aliceblue") (setq plist (list :background "#f0f8ff" :foreground (web-mode-colorize-foreground "#f0f8ff"))))
   7345       ((string= str "antiquewhite") (setq plist (list :background "#faebd7" :foreground (web-mode-colorize-foreground "#faebd7"))))
   7346       ((string= str "aquamarine") (setq plist (list :background "#7fffd4" :foreground (web-mode-colorize-foreground "#7fffd4"))))
   7347       ((string= str "azure") (setq plist (list :background "#f0ffff" :foreground (web-mode-colorize-foreground "#f0ffff"))))
   7348       ((string= str "beige") (setq plist (list :background "#f5f5dc" :foreground (web-mode-colorize-foreground "#f5f5dc"))))
   7349       ((string= str "bisque") (setq plist (list :background "#ffe4c4" :foreground (web-mode-colorize-foreground "#ffe4c4"))))
   7350       ((string= str "blanchedalmond") (setq plist (list :background "#ffebcd" :foreground (web-mode-colorize-foreground "#ffebcd"))))
   7351       ((string= str "blueviolet") (setq plist (list :background "#8a2be2" :foreground (web-mode-colorize-foreground "#8a2be2"))))
   7352       ((string= str "brown") (setq plist (list :background "#a52a2a" :foreground (web-mode-colorize-foreground "#a52a2a"))))
   7353       ((string= str "burlywood") (setq plist (list :background "#deb887" :foreground (web-mode-colorize-foreground "#deb887"))))
   7354       ((string= str "cadetblue") (setq plist (list :background "#5f9ea0" :foreground (web-mode-colorize-foreground "#5f9ea0"))))
   7355       ((string= str "chartreuse") (setq plist (list :background "#7fff00" :foreground (web-mode-colorize-foreground "#7fff00"))))
   7356       ((string= str "chocolate") (setq plist (list :background "#d2691e" :foreground (web-mode-colorize-foreground "#d2691e"))))
   7357       ((string= str "coral") (setq plist (list :background "#ff7f50" :foreground (web-mode-colorize-foreground "#ff7f50"))))
   7358       ((string= str "cornflowerblue") (setq plist (list :background "#6495ed" :foreground (web-mode-colorize-foreground "#6495ed"))))
   7359       ((string= str "cornsilk") (setq plist (list :background "#fff8dc" :foreground (web-mode-colorize-foreground "#fff8dc"))))
   7360       ((string= str "crimson") (setq plist (list :background "#dc143c" :foreground (web-mode-colorize-foreground "#dc143c"))))
   7361       ((string= str "cyan") (setq plist (list :background "#00ffff" :foreground (web-mode-colorize-foreground "#00ffff"))))
   7362       ((string= str "darkblue") (setq plist (list :background "#00008b" :foreground (web-mode-colorize-foreground "#00008b"))))
   7363       ((string= str "darkcyan") (setq plist (list :background "#008b8b" :foreground (web-mode-colorize-foreground "#008b8b"))))
   7364       ((string= str "darkgoldenrod") (setq plist (list :background "#b8860b" :foreground (web-mode-colorize-foreground "#b8860b"))))
   7365       ((string= str "darkgray") (setq plist (list :background "#a9a9a9" :foreground (web-mode-colorize-foreground "#a9a9a9"))))
   7366       ((string= str "darkgreen") (setq plist (list :background "#006400" :foreground (web-mode-colorize-foreground "#006400"))))
   7367       ((string= str "darkgrey") (setq plist (list :background "#a9a9a9" :foreground (web-mode-colorize-foreground "#a9a9a9"))))
   7368       ((string= str "darkkhaki") (setq plist (list :background "#bdb76b" :foreground (web-mode-colorize-foreground "#bdb76b"))))
   7369       ((string= str "darkmagenta") (setq plist (list :background "#8b008b" :foreground (web-mode-colorize-foreground "#8b008b"))))
   7370       ((string= str "darkolivegreen") (setq plist (list :background "#556b2f" :foreground (web-mode-colorize-foreground "#556b2f"))))
   7371       ((string= str "darkorange") (setq plist (list :background "#ff8c00" :foreground (web-mode-colorize-foreground "#ff8c00"))))
   7372       ((string= str "darkorchid") (setq plist (list :background "#9932cc" :foreground (web-mode-colorize-foreground "#9932cc"))))
   7373       ((string= str "darkred") (setq plist (list :background "#8b0000" :foreground (web-mode-colorize-foreground "#8b0000"))))
   7374       ((string= str "darksalmon") (setq plist (list :background "#e9967a" :foreground (web-mode-colorize-foreground "#e9967a"))))
   7375       ((string= str "darkseagreen") (setq plist (list :background "#8fbc8f" :foreground (web-mode-colorize-foreground "#8fbc8f"))))
   7376       ((string= str "darkslateblue") (setq plist (list :background "#483d8b" :foreground (web-mode-colorize-foreground "#483d8b"))))
   7377       ((string= str "darkslategray") (setq plist (list :background "#2f4f4f" :foreground (web-mode-colorize-foreground "#2f4f4f"))))
   7378       ((string= str "darkslategrey") (setq plist (list :background "#2f4f4f" :foreground (web-mode-colorize-foreground "#2f4f4f"))))
   7379       ((string= str "darkturquoise") (setq plist (list :background "#00ced1" :foreground (web-mode-colorize-foreground "#00ced1"))))
   7380       ((string= str "darkviolet") (setq plist (list :background "#9400d3" :foreground (web-mode-colorize-foreground "#9400d3"))))
   7381       ((string= str "deeppink") (setq plist (list :background "#ff1493" :foreground (web-mode-colorize-foreground "#ff1493"))))
   7382       ((string= str "deepskyblue") (setq plist (list :background "#00bfff" :foreground (web-mode-colorize-foreground "#00bfff"))))
   7383       ((string= str "dimgray") (setq plist (list :background "#696969" :foreground (web-mode-colorize-foreground "#696969"))))
   7384       ((string= str "dimgrey") (setq plist (list :background "#696969" :foreground (web-mode-colorize-foreground "#696969"))))
   7385       ((string= str "dodgerblue") (setq plist (list :background "#1e90ff" :foreground (web-mode-colorize-foreground "#1e90ff"))))
   7386       ((string= str "firebrick") (setq plist (list :background "#b22222" :foreground (web-mode-colorize-foreground "#b22222"))))
   7387       ((string= str "floralwhite") (setq plist (list :background "#fffaf0" :foreground (web-mode-colorize-foreground "#fffaf0"))))
   7388       ((string= str "forestgreen") (setq plist (list :background "#228b22" :foreground (web-mode-colorize-foreground "#228b22"))))
   7389       ((string= str "gainsboro") (setq plist (list :background "#dcdcdc" :foreground (web-mode-colorize-foreground "#dcdcdc"))))
   7390       ((string= str "ghostwhite") (setq plist (list :background "#f8f8ff" :foreground (web-mode-colorize-foreground "#f8f8ff"))))
   7391       ((string= str "gold") (setq plist (list :background "#ffd700" :foreground (web-mode-colorize-foreground "#ffd700"))))
   7392       ((string= str "goldenrod") (setq plist (list :background "#daa520" :foreground (web-mode-colorize-foreground "#daa520"))))
   7393       ((string= str "greenyellow") (setq plist (list :background "#adff2f" :foreground (web-mode-colorize-foreground "#adff2f"))))
   7394       ((string= str "grey") (setq plist (list :background "#808080" :foreground (web-mode-colorize-foreground "#808080"))))
   7395       ((string= str "honeydew") (setq plist (list :background "#f0fff0" :foreground (web-mode-colorize-foreground "#f0fff0"))))
   7396       ((string= str "hotpink") (setq plist (list :background "#ff69b4" :foreground (web-mode-colorize-foreground "#ff69b4"))))
   7397       ((string= str "indianred") (setq plist (list :background "#cd5c5c" :foreground (web-mode-colorize-foreground "#cd5c5c"))))
   7398       ((string= str "indigo") (setq plist (list :background "#4b0082" :foreground (web-mode-colorize-foreground "#4b0082"))))
   7399       ((string= str "ivory") (setq plist (list :background "#fffff0" :foreground (web-mode-colorize-foreground "#fffff0"))))
   7400       ((string= str "khaki") (setq plist (list :background "#f0e68c" :foreground (web-mode-colorize-foreground "#f0e68c"))))
   7401       ((string= str "lavender") (setq plist (list :background "#e6e6fa" :foreground (web-mode-colorize-foreground "#e6e6fa"))))
   7402       ((string= str "lavenderblush") (setq plist (list :background "#fff0f5" :foreground (web-mode-colorize-foreground "#fff0f5"))))
   7403       ((string= str "lawngreen") (setq plist (list :background "#7cfc00" :foreground (web-mode-colorize-foreground "#7cfc00"))))
   7404       ((string= str "lemonchiffon") (setq plist (list :background "#fffacd" :foreground (web-mode-colorize-foreground "#fffacd"))))
   7405       ((string= str "lightblue") (setq plist (list :background "#add8e6" :foreground (web-mode-colorize-foreground "#add8e6"))))
   7406       ((string= str "lightcoral") (setq plist (list :background "#f08080" :foreground (web-mode-colorize-foreground "#f08080"))))
   7407       ((string= str "lightcyan") (setq plist (list :background "#e0ffff" :foreground (web-mode-colorize-foreground "#e0ffff"))))
   7408       ((string= str "lightgoldenrodyellow") (setq plist (list :background "#fafad2" :foreground (web-mode-colorize-foreground "#fafad2"))))
   7409       ((string= str "lightgray") (setq plist (list :background "#d3d3d3" :foreground (web-mode-colorize-foreground "#d3d3d3"))))
   7410       ((string= str "lightgreen") (setq plist (list :background "#90ee90" :foreground (web-mode-colorize-foreground "#90ee90"))))
   7411       ((string= str "lightgrey") (setq plist (list :background "#d3d3d3" :foreground (web-mode-colorize-foreground "#d3d3d3"))))
   7412       ((string= str "lightpink") (setq plist (list :background "#ffb6c1" :foreground (web-mode-colorize-foreground "#ffb6c1"))))
   7413       ((string= str "lightsalmon") (setq plist (list :background "#ffa07a" :foreground (web-mode-colorize-foreground "#ffa07a"))))
   7414       ((string= str "lightseagreen") (setq plist (list :background "#20b2aa" :foreground (web-mode-colorize-foreground "#20b2aa"))))
   7415       ((string= str "lightskyblue") (setq plist (list :background "#87cefa" :foreground (web-mode-colorize-foreground "#87cefa"))))
   7416       ((string= str "lightslategray") (setq plist (list :background "#778899" :foreground (web-mode-colorize-foreground "#778899"))))
   7417       ((string= str "lightslategrey") (setq plist (list :background "#778899" :foreground (web-mode-colorize-foreground "#778899"))))
   7418       ((string= str "lightsteelblue") (setq plist (list :background "#b0c4de" :foreground (web-mode-colorize-foreground "#b0c4de"))))
   7419       ((string= str "lightyellow") (setq plist (list :background "#ffffe0" :foreground (web-mode-colorize-foreground "#ffffe0"))))
   7420       ((string= str "limegreen") (setq plist (list :background "#32cd32" :foreground (web-mode-colorize-foreground "#32cd32"))))
   7421       ((string= str "linen") (setq plist (list :background "#faf0e6" :foreground (web-mode-colorize-foreground "#faf0e6"))))
   7422       ((string= str "magenta") (setq plist (list :background "#ff00ff" :foreground (web-mode-colorize-foreground "#ff00ff"))))
   7423       ((string= str "mediumaquamarine") (setq plist (list :background "#66cdaa" :foreground (web-mode-colorize-foreground "#66cdaa"))))
   7424       ((string= str "mediumblue") (setq plist (list :background "#0000cd" :foreground (web-mode-colorize-foreground "#0000cd"))))
   7425       ((string= str "mediumorchid") (setq plist (list :background "#ba55d3" :foreground (web-mode-colorize-foreground "#ba55d3"))))
   7426       ((string= str "mediumpurple") (setq plist (list :background "#9370db" :foreground (web-mode-colorize-foreground "#9370db"))))
   7427       ((string= str "mediumseagreen") (setq plist (list :background "#3cb371" :foreground (web-mode-colorize-foreground "#3cb371"))))
   7428       ((string= str "mediumslateblue") (setq plist (list :background "#7b68ee" :foreground (web-mode-colorize-foreground "#7b68ee"))))
   7429       ((string= str "mediumspringgreen") (setq plist (list :background "#00fa9a" :foreground (web-mode-colorize-foreground "#00fa9a"))))
   7430       ((string= str "mediumturquoise") (setq plist (list :background "#48d1cc" :foreground (web-mode-colorize-foreground "#48d1cc"))))
   7431       ((string= str "mediumvioletred") (setq plist (list :background "#c71585" :foreground (web-mode-colorize-foreground "#c71585"))))
   7432       ((string= str "midnightblue") (setq plist (list :background "#191970" :foreground (web-mode-colorize-foreground "#191970"))))
   7433       ((string= str "mintcream") (setq plist (list :background "#f5fffa" :foreground (web-mode-colorize-foreground "#f5fffa"))))
   7434       ((string= str "mistyrose") (setq plist (list :background "#ffe4e1" :foreground (web-mode-colorize-foreground "#ffe4e1"))))
   7435       ((string= str "moccasin") (setq plist (list :background "#ffe4b5" :foreground (web-mode-colorize-foreground "#ffe4b5"))))
   7436       ((string= str "navajowhite") (setq plist (list :background "#ffdead" :foreground (web-mode-colorize-foreground "#ffdead"))))
   7437       ((string= str "oldlace") (setq plist (list :background "#fdf5e6" :foreground (web-mode-colorize-foreground "#fdf5e6"))))
   7438       ((string= str "olivedrab") (setq plist (list :background "#6b8e23" :foreground (web-mode-colorize-foreground "#6b8e23"))))
   7439       ((string= str "orangered") (setq plist (list :background "#ff4500" :foreground (web-mode-colorize-foreground "#ff4500"))))
   7440       ((string= str "orchid") (setq plist (list :background "#da70d6" :foreground (web-mode-colorize-foreground "#da70d6"))))
   7441       ((string= str "palegoldenrod") (setq plist (list :background "#eee8aa" :foreground (web-mode-colorize-foreground "#eee8aa"))))
   7442       ((string= str "palegreen") (setq plist (list :background "#98fb98" :foreground (web-mode-colorize-foreground "#98fb98"))))
   7443       ((string= str "paleturquoise") (setq plist (list :background "#afeeee" :foreground (web-mode-colorize-foreground "#afeeee"))))
   7444       ((string= str "palevioletred") (setq plist (list :background "#db7093" :foreground (web-mode-colorize-foreground "#db7093"))))
   7445       ((string= str "papayawhip") (setq plist (list :background "#ffefd5" :foreground (web-mode-colorize-foreground "#ffefd5"))))
   7446       ((string= str "peachpuff") (setq plist (list :background "#ffdab9" :foreground (web-mode-colorize-foreground "#ffdab9"))))
   7447       ((string= str "peru") (setq plist (list :background "#cd853f" :foreground (web-mode-colorize-foreground "#cd853f"))))
   7448       ((string= str "pink") (setq plist (list :background "#ffc0cb" :foreground (web-mode-colorize-foreground "#ffc0cb"))))
   7449       ((string= str "plum") (setq plist (list :background "#dda0dd" :foreground (web-mode-colorize-foreground "#dda0dd"))))
   7450       ((string= str "powderblue") (setq plist (list :background "#b0e0e6" :foreground (web-mode-colorize-foreground "#b0e0e6"))))
   7451       ((string= str "rosybrown") (setq plist (list :background "#bc8f8f" :foreground (web-mode-colorize-foreground "#bc8f8f"))))
   7452       ((string= str "royalblue") (setq plist (list :background "#4169e1" :foreground (web-mode-colorize-foreground "#4169e1"))))
   7453       ((string= str "saddlebrown") (setq plist (list :background "#8b4513" :foreground (web-mode-colorize-foreground "#8b4513"))))
   7454       ((string= str "salmon") (setq plist (list :background "#fa8072" :foreground (web-mode-colorize-foreground "#fa8072"))))
   7455       ((string= str "sandybrown") (setq plist (list :background "#f4a460" :foreground (web-mode-colorize-foreground "#f4a460"))))
   7456       ((string= str "seagreen") (setq plist (list :background "#2e8b57" :foreground (web-mode-colorize-foreground "#2e8b57"))))
   7457       ((string= str "seashell") (setq plist (list :background "#fff5ee" :foreground (web-mode-colorize-foreground "#fff5ee"))))
   7458       ((string= str "sienna") (setq plist (list :background "#a0522d" :foreground (web-mode-colorize-foreground "#a0522d"))))
   7459       ((string= str "skyblue") (setq plist (list :background "#87ceeb" :foreground (web-mode-colorize-foreground "#87ceeb"))))
   7460       ((string= str "slateblue") (setq plist (list :background "#6a5acd" :foreground (web-mode-colorize-foreground "#6a5acd"))))
   7461       ((string= str "slategray") (setq plist (list :background "#708090" :foreground (web-mode-colorize-foreground "#708090"))))
   7462       ((string= str "slategrey") (setq plist (list :background "#708090" :foreground (web-mode-colorize-foreground "#708090"))))
   7463       ((string= str "snow") (setq plist (list :background "#fffafa" :foreground (web-mode-colorize-foreground "#fffafa"))))
   7464       ((string= str "springgreen") (setq plist (list :background "#00ff7f" :foreground (web-mode-colorize-foreground "#00ff7f"))))
   7465       ((string= str "steelblue") (setq plist (list :background "#4682b4" :foreground (web-mode-colorize-foreground "#4682b4"))))
   7466       ((string= str "tan") (setq plist (list :background "#d2b48c" :foreground (web-mode-colorize-foreground "#d2b48c"))))
   7467       ((string= str "thistle") (setq plist (list :background "#d8bfd8" :foreground (web-mode-colorize-foreground "#d8bfd8"))))
   7468       ((string= str "tomato") (setq plist (list :background "#ff6347" :foreground (web-mode-colorize-foreground "#ff6347"))))
   7469       ((string= str "turquoise") (setq plist (list :background "#40e0d0" :foreground (web-mode-colorize-foreground "#40e0d0"))))
   7470       ((string= str "violet") (setq plist (list :background "#ee82ee" :foreground (web-mode-colorize-foreground "#ee82ee"))))
   7471       ((string= str "wheat") (setq plist (list :background "#f5deb3" :foreground (web-mode-colorize-foreground "#f5deb3"))))
   7472       ((string= str "whitesmoke") (setq plist (list :background "#f5f5f5" :foreground (web-mode-colorize-foreground "#f5f5f5"))))
   7473       ((string= str "yellowgreen") (setq plist (list :background "#9acd32" :foreground (web-mode-colorize-foreground "#9acd32"))))
   7474       ) ;cond
   7475     (put-text-property beg end 'face plist)
   7476     ))
   7477 
   7478 (defun web-mode-interpolate-block-tag (beg end)
   7479   (save-excursion
   7480     (goto-char (+ 4 beg))
   7481     (setq end (1- end))
   7482     (while (re-search-forward "${.*?}" end t)
   7483       (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(face))
   7484       (web-mode-fontify-region (match-beginning 0) (match-end 0)
   7485                                web-mode-uel-font-lock-keywords))
   7486     ))
   7487 
   7488 (defun web-mode-interpolate-javascript-string (beg end)
   7489   (save-excursion
   7490     (goto-char (1+ beg))
   7491     (setq end (1- end))
   7492     (while (re-search-forward "${.*?}" end t)
   7493       (put-text-property (match-beginning 0) (match-end 0)
   7494                          'font-lock-face
   7495                          'web-mode-variable-name-face)
   7496       )
   7497     ))
   7498 
   7499 (defun web-mode-interpolate-javascript-literal (beg end)
   7500   (save-excursion
   7501     (setq end (1- end))
   7502     (goto-char (1+ beg))
   7503     (cond
   7504       ((web-mode-looking-back "\\(css\\|styled[[:alnum:].]+\\|css = \\)" beg)
   7505        (goto-char (1+ beg))
   7506        (while (re-search-forward ".*?:" end t)
   7507          (put-text-property (match-beginning 0) (match-end 0)
   7508                             'font-lock-face
   7509                             'web-mode-interpolate-color1-face)
   7510          )
   7511        ) ;case css
   7512       ((web-mode-looking-back "\\(template\\|html\\|html = \\)" beg)
   7513        (goto-char (1+ beg))
   7514        (while (re-search-forward web-mode-tag-regexp end t)
   7515          (put-text-property (match-beginning 1) (match-end 1)
   7516                             'font-lock-face
   7517                             'web-mode-interpolate-color1-face)
   7518          )
   7519        (goto-char (1+ beg))
   7520        (while (re-search-forward "</?\\|/?>\\| [.@?]?[[:alnum:]]+=" end t)
   7521          (cond
   7522            ((member (char-after (match-beginning 0)) '(?\< ?\/ ?\>))
   7523             (put-text-property (match-beginning 0) (match-end 0)
   7524                                'font-lock-face
   7525                                'web-mode-interpolate-color2-face)
   7526             )
   7527            (t
   7528             (put-text-property (1+ (match-beginning 0)) (1- (match-end 0))
   7529                                'font-lock-face
   7530                                'web-mode-interpolate-color3-face)
   7531             ) ;t
   7532            ) ;cond
   7533          ) ;while
   7534        (goto-char (1+ beg))
   7535        (while (re-search-forward "<\\(script\\|style\\)>\\(.*\\)</\\(script\\|style\\)>" end t)
   7536          (put-text-property (match-beginning 2) (match-end 2)
   7537                             'font-lock-face
   7538                             'web-mode-interpolate-color4-face)
   7539          )
   7540        ) ;case html
   7541       ) ;cond type of literal
   7542     (goto-char (1+ beg))
   7543     (while (re-search-forward "${.*?}" end t)
   7544       (put-text-property (match-beginning 0) (match-end 0)
   7545                          'font-lock-face
   7546                          'web-mode-variable-name-face)
   7547       ) ;while
   7548     ))
   7549 
   7550 ;; todo : parsing plus compliqué: {$obj->values[3]->name}
   7551 (defun web-mode-interpolate-block-string (beg end)
   7552   (save-excursion
   7553     (goto-char (1+ beg))
   7554     (setq end (1- end))
   7555     (cond
   7556       ((string= web-mode-engine "php")
   7557        (while (re-search-forward "$[[:alnum:]_]+\\(->[[:alnum:]_]+\\)*\\|{[ ]*$.+?}" end t)
   7558          ;;        (message "%S > %S" (match-beginning 0) (match-end 0))
   7559          (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(font-lock-face))
   7560          (web-mode-fontify-region (match-beginning 0) (match-end 0)
   7561                                   web-mode-php-var-interpolation-font-lock-keywords)
   7562          ))
   7563       ((string= web-mode-engine "erb")
   7564        (while (re-search-forward "#{.*?}" end t)
   7565          (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(font-lock-face))
   7566          (put-text-property (match-beginning 0) (match-end 0)
   7567                             'font-lock-face 'web-mode-variable-name-face)
   7568          ))
   7569       ) ;cond
   7570     ))
   7571 
   7572 (defun web-mode-interpolate-comment (beg end _block-side)
   7573   (save-excursion
   7574     (let ((regexp (concat "\\_<\\(" web-mode-comment-keywords "\\)\\_>")))
   7575       (goto-char beg)
   7576       (while (re-search-forward regexp end t)
   7577         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7578                                          'font-lock-face
   7579                                          'web-mode-comment-keyword-face)
   7580         ) ;while
   7581       )))
   7582 
   7583 (defun web-mode-annotate-comment (beg end)
   7584   (save-excursion
   7585     ;;(message "beg=%S end=%S" beg end)
   7586     (goto-char beg)
   7587     (when (looking-at-p "/\\*\\*")
   7588       (while (re-search-forward "\\(.+\\)" end t)
   7589         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7590                                          'font-lock-face
   7591                                          'web-mode-annotation-face))
   7592       (goto-char beg)
   7593       (while (re-search-forward "[ ]+\\({[^}]+}\\)" end t)
   7594         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7595                                          'font-lock-face
   7596                                          'web-mode-annotation-type-face))
   7597       (goto-char beg)
   7598       (while (re-search-forward "\\(@[[:alnum:]]+\\)" end t)
   7599         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7600                                          'font-lock-face
   7601                                          'web-mode-annotation-tag-face))
   7602       (goto-char beg)
   7603       (while (re-search-forward "}[[:blank:]]+\\([[:graph:]]+\\)" end t)
   7604         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7605                                          'font-lock-face
   7606                                          'web-mode-annotation-value-face))
   7607       (goto-char beg)
   7608       (while (re-search-forward "@see[[:blank:]]+\\([[:graph:]]+\\)" end t)
   7609         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7610                                          'font-lock-face
   7611                                          'web-mode-annotation-value-face))
   7612       (goto-char beg)
   7613       (while (re-search-forward "{\\(@\\(?:link\\|code\\)\\)\\s-+\\([^}\n]+\\)\\(#.+\\)?}" end t)
   7614         (font-lock-prepend-text-property (match-beginning 2) (match-end 2)
   7615                                          'font-lock-face
   7616                                          'web-mode-annotation-value-face))
   7617       (goto-char beg)
   7618       (while (re-search-forward "\\(</?\\)\\([[:alnum:]]+\\)\\s-*\\(/?>\\)" end t)
   7619         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7620                                          'font-lock-face
   7621                                          'web-mode-annotation-html-face)
   7622         (font-lock-prepend-text-property (match-beginning 2) (match-end 2)
   7623                                          'font-lock-face
   7624                                          'web-mode-annotation-html-face)
   7625         (font-lock-prepend-text-property (match-beginning 3) (match-end 3)
   7626                                          'font-lock-face
   7627                                          'web-mode-annotation-html-face))
   7628       ) ;when
   7629     ))
   7630 
   7631 (defun web-mode-interpolate-sql-string (beg end)
   7632   (save-excursion
   7633     (let ((case-fold-search t)
   7634           (regexp (concat "\\_<\\(" web-mode-sql-keywords "\\)\\_>")))
   7635       (goto-char beg)
   7636       (while (re-search-forward regexp end t)
   7637         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7638                                          'font-lock-face
   7639                                          'web-mode-sql-keyword-face)
   7640         ) ;while
   7641       )))
   7642 
   7643 ;;---- EFFECTS -----------------------------------------------------------------
   7644 
   7645 (defun web-mode-fill-paragraph (&optional _justify)
   7646   (save-excursion
   7647     (let ((pos (point))
   7648           prop pair beg end delim-beg delim-end chunk fill-coll)
   7649       (ignore delim-beg delim-end fill-coll)
   7650       (cond
   7651         ((or (eq (get-text-property pos 'part-token) 'comment)
   7652              (eq (get-text-property pos 'block-token) 'comment))
   7653          (setq prop
   7654                (if (get-text-property pos 'part-token) 'part-token 'block-token))
   7655          (setq pair (web-mode-property-boundaries prop pos))
   7656          (when (and pair (> (- (cdr pair) (car pair)) 6))
   7657            (setq fill-coll (if (< fill-column 10) 70 fill-column))
   7658            (setq beg (car pair)
   7659                  end (cdr pair))
   7660            (goto-char beg)
   7661            (setq chunk (buffer-substring-no-properties beg (+ beg 2)))
   7662            (cond
   7663              ((string= chunk "//")
   7664               (setq delim-beg "//"
   7665                     delim-end "EOL"))
   7666              ((string= chunk "/*")
   7667               (setq delim-beg "/*"
   7668                     delim-end "*/"))
   7669              ((string= chunk "{#")
   7670               (setq delim-beg "{#"
   7671                     delim-end "#}"))
   7672              ((string= chunk "<!")
   7673               (setq delim-beg "<!--"
   7674                     delim-end "-->"))
   7675              )
   7676            )
   7677          ) ;comment - case
   7678         ((web-mode-is-content)
   7679          (setq pair (web-mode-content-boundaries pos))
   7680          (setq beg (car pair)
   7681                end (cdr pair))
   7682          )
   7683         ) ;cond
   7684       ;;(message "beg(%S) end(%S)" beg end)
   7685       (when (and beg end)
   7686         (fill-region beg end))
   7687       t)))
   7688 
   7689 (defun web-mode-engine-syntax-check ()
   7690   (interactive)
   7691   (let ((proc nil) (errors nil)
   7692         (file (concat temporary-file-directory "emacs-web-mode-tmp")))
   7693     (write-region (point-min) (point-max) file)
   7694     (cond
   7695       ;; ((null (buffer-file-name))
   7696       ;; )
   7697       ((string= web-mode-engine "php")
   7698        (setq proc (start-process "php-proc" nil "php" "-l" file))
   7699        (set-process-filter
   7700         proc
   7701         (lambda (_proc output)
   7702           (cond
   7703             ((string-match-p "No syntax errors" output)
   7704              (message "No syntax errors")
   7705              )
   7706             (t
   7707              ;; (setq output (replace-regexp-in-string temporary-file-directory "" output))
   7708              ;; (message output)
   7709              (message "Syntax error")
   7710              (setq errors t))
   7711             ) ;cond
   7712           ;; (delete-file file)
   7713           ) ;lambda
   7714         )
   7715        ) ;php
   7716       (t
   7717        (message "no syntax checker found")
   7718        ) ;t
   7719       ) ;cond
   7720     errors))
   7721 
   7722 (defun web-mode-jshint ()
   7723   "Run JSHint on all the JavaScript parts."
   7724   (interactive)
   7725   (let (proc)
   7726     (when (buffer-file-name)
   7727       (setq proc (start-process
   7728                   "jshint-proc"
   7729                   nil
   7730                   (or (executable-find "jshint") "/usr/local/bin/jshint")
   7731                   "--extract=auto"
   7732                   (buffer-file-name)))
   7733       (setq web-mode-jshint-errors 0)
   7734       (set-process-filter proc
   7735                           (lambda (_proc output)
   7736                             (let ((offset 0) overlay pos (old 0) msg)
   7737                               (remove-overlays (point-min) (point-max) 'font-lock-face 'web-mode-error-face)
   7738                               (while (string-match
   7739                                       "line \\([[:digit:]]+\\), col \\([[:digit:]]+\\), \\(.+\\)\\.$"
   7740                                       output offset)
   7741                                 (setq web-mode-jshint-errors (1+ web-mode-jshint-errors))
   7742                                 (setq offset (match-end 0))
   7743                                 (setq pos (web-mode-coord-position
   7744                                            (match-string-no-properties 1 output)
   7745                                            (match-string-no-properties 2 output)))
   7746                                 (when (get-text-property pos 'tag-beg)
   7747                                   (setq pos (1- pos)))
   7748                                 (when (not (= pos old))
   7749                                   (setq old pos)
   7750                                   (setq overlay (make-overlay pos (1+ pos)))
   7751                                   (overlay-put overlay 'font-lock-face 'web-mode-error-face)
   7752                                   )
   7753                                 (setq msg (or (overlay-get overlay 'help-echo)
   7754                                               (concat "line="
   7755                                                       (match-string-no-properties 1 output)
   7756                                                       " column="
   7757                                                       (match-string-no-properties 2 output)
   7758                                                       )))
   7759                                 (overlay-put overlay 'help-echo
   7760                                              (concat msg " ## " (match-string-no-properties 3 output)))
   7761                                 ) ;while
   7762                               ))
   7763                           )
   7764       ) ;when
   7765     ))
   7766 
   7767 (defun web-mode-dom-errors-show ()
   7768   "Show unclosed tags."
   7769   (interactive)
   7770   (let (beg end tag pos l tags i cont cell overlay overlays first
   7771             (ori (point))
   7772             (errors 0)
   7773             (continue t)
   7774             )
   7775     (setq overlays (overlays-in (point-min) (point-max)))
   7776     (when overlays
   7777       (dolist (overlay overlays)
   7778         (when (eq (overlay-get overlay 'face) 'web-mode-warning-face)
   7779           (delete-overlay overlay)
   7780           )
   7781         )
   7782       )
   7783     (goto-char (point-min))
   7784     (when (not (or (get-text-property (point) 'tag-beg)
   7785                    (web-mode-tag-next)))
   7786       (setq continue nil))
   7787     (while continue
   7788       (setq pos (point))
   7789       (setq tag (get-text-property pos 'tag-name))
   7790       (cond
   7791         ((eq (get-text-property (point) 'tag-type) 'start)
   7792          (setq tags (push (list tag pos) tags))
   7793          ;;        (message "(%S) opening %S" pos tag)
   7794          )
   7795         ((eq (get-text-property (point) 'tag-type) 'end)
   7796          (setq i 0
   7797                l (length tags)
   7798                cont t)
   7799          (while (and (< i l) cont)
   7800            (setq cell (nth i tags))
   7801            ;;          (message "cell=%S" cell)
   7802            (setq i (1+ i))
   7803            (cond
   7804              ((string= tag (nth 0 cell))
   7805               (setq cont nil)
   7806               )
   7807              (t
   7808               (setq errors (1+ errors))
   7809               (setq beg (nth 1 cell))
   7810               (setq end (web-mode-tag-end-position beg))
   7811               (unless first
   7812                 (setq first beg))
   7813               (setq overlay (make-overlay beg (1+ end)))
   7814               (overlay-put overlay 'font-lock-face 'web-mode-warning-face)
   7815               ;;            (message "invalid <%S> at %S" (nth 0 cell) (nth 1 cell))
   7816               )
   7817              ) ;cond
   7818            ) ;while
   7819 
   7820          (dotimes (_i i)
   7821            (setq tags (cdr tags)))
   7822 
   7823          )
   7824         ) ;cond
   7825       (when (not (web-mode-tag-next))
   7826         (setq continue nil))
   7827       ) ;while
   7828     (message "%S error(s) detected" errors)
   7829     (if (< errors 1)
   7830         (goto-char ori)
   7831         (goto-char first)
   7832         (recenter))
   7833     ;;    (message "%S" tags)
   7834     ))
   7835 
   7836 (defun web-mode-fontify-elements (beg end)
   7837   (save-excursion
   7838     (goto-char beg)
   7839     (let ((continue (or (get-text-property (point) 'tag-beg) (web-mode-tag-next)))
   7840           (i 0) (ctx nil) (face nil))
   7841       (while continue
   7842         (cond
   7843           ((> (setq i (1+ i)) 1000)
   7844            (message "fontify-elements ** too much tags **")
   7845            (setq continue nil))
   7846           ((> (point) end)
   7847            (setq continue nil))
   7848           ((not (get-text-property (point) 'tag-beg))
   7849            (setq continue nil))
   7850           ((eq (get-text-property (point) 'tag-type) 'start)
   7851            (when (and (setq ctx (web-mode-element-boundaries (point)))
   7852                       (<= (car (cdr ctx)) end)
   7853                       (setq face (cdr (assoc (get-text-property (point) 'tag-name) web-mode-element-content-faces))))
   7854              (font-lock-prepend-text-property (1+ (cdr (car ctx))) (car (cdr ctx))
   7855                                               'font-lock-face face))
   7856            )
   7857           ) ;cond
   7858         (when (not (web-mode-tag-next))
   7859           (setq continue nil))
   7860         ) ;while
   7861       )))
   7862 
   7863 (defun web-mode-enable (feature)
   7864   "Enable one feature."
   7865   (interactive
   7866    (list (completing-read
   7867           "Feature: "
   7868           (let (features)
   7869             (dolist (elt web-mode-features)
   7870               (setq features (append features (list (car elt)))))
   7871             features))))
   7872   (when (and (or (not feature) (< (length feature) 1)) web-mode-last-enabled-feature)
   7873     (setq feature web-mode-last-enabled-feature))
   7874   (when feature
   7875     (setq web-mode-last-enabled-feature feature)
   7876     (setq feature (cdr (assoc feature web-mode-features)))
   7877     (cond
   7878       ((eq feature 'web-mode-enable-current-column-highlight)
   7879        (web-mode-column-show))
   7880       ((eq feature 'web-mode-enable-current-element-highlight)
   7881        (when (not web-mode-enable-current-element-highlight)
   7882          (web-mode-toggle-current-element-highlight))
   7883        )
   7884       ((eq feature 'web-mode-enable-whitespace-fontification)
   7885        (web-mode-whitespaces-on))
   7886       (t
   7887        (set feature t)
   7888        (web-mode-buffer-fontify))
   7889       )
   7890     ) ;when
   7891   )
   7892 
   7893 (defun web-mode-disable (feature)
   7894   "Disable one feature."
   7895   (interactive
   7896    (list (completing-read
   7897           "Feature: "
   7898           (let (features)
   7899             (dolist (elt web-mode-features)
   7900               (setq features (append features (list (car elt)))))
   7901             features))))
   7902   (when (and (or (not feature) (< (length feature) 1)) web-mode-last-enabled-feature)
   7903     (setq feature web-mode-last-enabled-feature))
   7904   (when feature
   7905     (setq feature (cdr (assoc feature web-mode-features)))
   7906     (cond
   7907       ((eq feature 'web-mode-enable-current-column-highlight)
   7908        (web-mode-column-hide))
   7909       ((eq feature 'web-mode-enable-current-element-highlight)
   7910        (when web-mode-enable-current-element-highlight
   7911          (web-mode-toggle-current-element-highlight))
   7912        )
   7913       ((eq feature 'web-mode-enable-whitespace-fontification)
   7914        (web-mode-whitespaces-off))
   7915       (t
   7916        (set feature nil)
   7917        (web-mode-buffer-fontify))
   7918       )
   7919     ) ;when
   7920   )
   7921 
   7922 (defun web-mode-toggle-current-element-highlight ()
   7923   "Toggle highlighting of the current html element."
   7924   (interactive)
   7925   (if web-mode-enable-current-element-highlight
   7926       (progn
   7927         (web-mode-delete-tag-overlays)
   7928         (setq web-mode-enable-current-element-highlight nil))
   7929       (setq web-mode-enable-current-element-highlight t)
   7930       ))
   7931 
   7932 (defun web-mode-make-tag-overlays ()
   7933   (unless web-mode-overlay-tag-start
   7934     (setq web-mode-overlay-tag-start (make-overlay 1 1)
   7935           web-mode-overlay-tag-end (make-overlay 1 1))
   7936     (overlay-put web-mode-overlay-tag-start
   7937                  'font-lock-face
   7938                  'web-mode-current-element-highlight-face)
   7939     (overlay-put web-mode-overlay-tag-end
   7940                  'font-lock-face
   7941                  'web-mode-current-element-highlight-face)))
   7942 
   7943 (defun web-mode-delete-tag-overlays ()
   7944   (when web-mode-overlay-tag-start
   7945     (delete-overlay web-mode-overlay-tag-start)
   7946     (delete-overlay web-mode-overlay-tag-end)))
   7947 
   7948 (defun web-mode-column-overlay-factory (index)
   7949   (let (overlay)
   7950     (when (null web-mode-column-overlays)
   7951       (dotimes (_i 100)
   7952         (setq overlay (make-overlay 1 1))
   7953         (overlay-put overlay 'font-lock-face 'web-mode-current-column-highlight-face)
   7954         (setq web-mode-column-overlays (append web-mode-column-overlays (list overlay)))
   7955         )
   7956       ) ;when
   7957     (setq overlay (nth index web-mode-column-overlays))
   7958     (when (null overlay)
   7959       (setq overlay (make-overlay 1 1))
   7960       (overlay-put overlay 'font-lock-face 'web-mode-current-column-highlight-face)
   7961       (setq web-mode-column-overlays (append web-mode-column-overlays (list overlay)))
   7962       ) ;when
   7963     overlay))
   7964 
   7965 (defun web-mode-column-hide ()
   7966   (setq web-mode-enable-current-column-highlight nil)
   7967   (remove-overlays (point-min) (point-max)
   7968                    'font-lock-face
   7969                    'web-mode-current-column-highlight-face))
   7970 
   7971 (defun web-mode-count-invisible-character-ranges (min max)
   7972   (interactive "r")
   7973   (let ((count 0) (current-pos min))
   7974     (save-excursion
   7975       (while (<= current-pos max)
   7976         (goto-char current-pos)
   7977         (if (get-text-property current-pos 'invisible)
   7978             (progn
   7979               (setq count (1+ count))
   7980               (setq current-pos (1+ current-pos))
   7981               (while (and (<= current-pos max)
   7982                           (get-text-property current-pos 'invisible))
   7983                 (setq current-pos (1+ current-pos))))
   7984           (setq current-pos (1+ current-pos)))))
   7985     count))
   7986 
   7987 (defun web-mode-column-show ()
   7988   (let ((index 0) overlay diff column line-to line-from line-delta regions (overlay-skip nil) last-line-no)
   7989     (web-mode-column-hide)
   7990     (setq web-mode-enable-current-column-highlight t)
   7991     (save-excursion ;;save-mark-and-excursion
   7992       (back-to-indentation)
   7993       (setq column (current-column)
   7994             line-to (web-mode-line-number))
   7995       (when (and (get-text-property (point) 'tag-beg)
   7996                  (member (get-text-property (point) 'tag-type) '(start end))
   7997                  (web-mode-tag-match)
   7998                  (setq line-from (web-mode-line-number))
   7999                  (not (= line-from line-to)))
   8000         (when (> line-from line-to)
   8001           (let (tmp)
   8002             (setq tmp line-from)
   8003             (setq line-from line-to)
   8004             (setq line-to tmp))
   8005           ) ;when
   8006         ;;(message "column(%S) line-from(%S) line-to(%S)" column line-from line-to)
   8007         (goto-char (point-min))
   8008         (when (> line-from 1)
   8009           (forward-line (1- line-from)))
   8010         ;; Added by JMA
   8011         (save-excursion ;;save-mark-and-excursion
   8012           (let (start-point end-point)
   8013             (goto-line line-from)
   8014             (move-to-column column)
   8015             (setq start-point (point))
   8016             (goto-line line-to)
   8017             (move-to-column column)
   8018             (setq end-point (point))
   8019             (setq line-delta (count-lines start-point end-point t))
   8020             (setq line-delta (+ line-delta (web-mode-count-invisible-character-ranges start-point end-point))))
   8021           (setq line-to (+ line-from (1- line-delta))))
   8022         ;(message (format "Currently at line: %d" (line-number-at-pos)))
   8023         (setq last-line-no (line-number-at-pos))
   8024         ;; end JMA add
   8025         (while (<= line-from line-to)
   8026           (setq overlay (web-mode-column-overlay-factory index))
   8027           (setq diff (- (line-end-position) (point)))
   8028           (cond
   8029             ((or (and (= column 0) (= diff 0))
   8030                  (> column diff))
   8031              (end-of-line)
   8032              (move-overlay overlay (point) (point))
   8033              (overlay-put overlay
   8034                           'after-string
   8035                           (concat
   8036                            (if (> column diff) (make-string (- column diff) ?\s) "")
   8037                            (propertize " "
   8038                                        'font-lock-face
   8039                                        'web-mode-current-column-highlight-face)
   8040                            ) ;concat
   8041                           )
   8042              )
   8043             (t
   8044              (move-to-column column)
   8045              (overlay-put overlay 'after-string nil)
   8046              (move-overlay overlay (point) (1+ (point)))
   8047              )
   8048             ) ;cond
   8049           (setq line-from (1+ line-from))
   8050           (forward-line)
   8051           ;; JMA ADD
   8052           ;(message (format "Currently at line: %d" (line-number-at-pos)))
   8053           (if (not (= (1+ last-line-no) (line-number-at-pos)))
   8054               (delete-overlay overlay))
   8055           (setq last-line-no (line-number-at-pos))
   8056           ;; END JMA ADD
   8057           (setq index (1+ index))
   8058           ) ;while
   8059         ) ;when
   8060       ) ;save-excursion
   8061     ) ;let
   8062   )
   8063 
   8064 (defun web-mode-column-show2 ()
   8065   (let ((index 0) overlay diff column line-to line-from
   8066         line-delta regions (overlay-skip nil) last-line-no)
   8067     (web-mode-column-hide)
   8068     (setq web-mode-enable-current-column-highlight t)
   8069     (save-excursion
   8070       (back-to-indentation)
   8071       (setq column (current-column)
   8072             line-to (web-mode-line-number))
   8073       (when (and (get-text-property (point) 'tag-beg)
   8074                  (member (get-text-property (point) 'tag-type) '(start end))
   8075                  (web-mode-tag-match)
   8076                  (setq line-from (web-mode-line-number))
   8077                  (not (= line-from line-to)))
   8078         (when (> line-from line-to)
   8079           (let (tmp)
   8080             (setq tmp line-from)
   8081             (setq line-from line-to)
   8082             (setq line-to tmp))
   8083           ) ;when
   8084         ;;(message "column(%S) line-from(%S) line-to(%S)" column line-from line-to)
   8085         (goto-char (point-min))
   8086         (when (> line-from 1)
   8087           (forward-line (1- line-from)))
   8088         (while (<= line-from line-to)
   8089           (setq overlay (web-mode-column-overlay-factory index))
   8090           (setq diff (- (line-end-position) (point)))
   8091           (cond
   8092             ((or (and (= column 0) (= diff 0))
   8093                  (> column diff))
   8094              (end-of-line)
   8095              (move-overlay overlay (point) (point))
   8096              (overlay-put overlay
   8097                           'after-string
   8098                           (concat
   8099                            (if (> column diff) (make-string (- column diff) ?\s) "")
   8100                            (propertize " "
   8101                                        'font-lock-face
   8102                                        'web-mode-current-column-highlight-face)
   8103                            ) ;concat
   8104                           )
   8105              )
   8106             (t
   8107              (move-to-column column)
   8108              (overlay-put overlay 'after-string nil)
   8109              (move-overlay overlay (point) (1+ (point)))
   8110              )
   8111             ) ;cond
   8112           (setq line-from (1+ line-from))
   8113           (forward-line)
   8114           (setq index (1+ index))
   8115           ) ;while
   8116         ) ;when
   8117       ) ;save-excursion
   8118     ) ;let
   8119   )
   8120 
   8121 (defun web-mode-highlight-current-element ()
   8122   (let ((ctx (web-mode-element-boundaries)) len)
   8123     (cond
   8124       ((null ctx)
   8125        (web-mode-delete-tag-overlays))
   8126       ((eq (get-text-property (caar ctx) 'tag-type) 'void) ;; #1046
   8127        (web-mode-make-tag-overlays)
   8128        (setq len (length (get-text-property (caar ctx) 'tag-name)))
   8129        (move-overlay web-mode-overlay-tag-start (+ (caar ctx) 1) (+ (caar ctx) 1 len))
   8130        (move-overlay web-mode-overlay-tag-end (+ (cadr ctx) 1) (+ (cadr ctx) 1 len)) ;; #1257
   8131        )
   8132       (t
   8133        (web-mode-make-tag-overlays)
   8134        (setq len (length (get-text-property (caar ctx) 'tag-name)))
   8135        (move-overlay web-mode-overlay-tag-start (+ (caar ctx) 1) (+ (caar ctx) 1 len))
   8136        (move-overlay web-mode-overlay-tag-end (+ (cadr ctx) 2) (+ (cadr ctx) 2 len))
   8137        ) ;t
   8138       ) ;cond
   8139     ))
   8140 
   8141 (defun web-mode-fontify-whitespaces (beg end)
   8142   (save-excursion
   8143     (goto-char beg)
   8144     (while (re-search-forward web-mode-whitespaces-regexp end t)
   8145       (add-text-properties (match-beginning 0) (match-end 0)
   8146                            '(face web-mode-whitespace-face))
   8147       ) ;while
   8148     ))
   8149 
   8150 (defun web-mode-whitespaces-show ()
   8151   "Toggle whitespaces."
   8152   (interactive)
   8153   (if web-mode-enable-whitespace-fontification
   8154       (web-mode-whitespaces-off)
   8155       (web-mode-whitespaces-on)))
   8156 
   8157 (defun web-mode-whitespaces-on ()
   8158   "Show whitespaces."
   8159   (interactive)
   8160   (when web-mode-display-table
   8161     (setq buffer-display-table web-mode-display-table))
   8162   (setq web-mode-enable-whitespace-fontification t))
   8163 
   8164 (defun web-mode-whitespaces-off ()
   8165   (setq buffer-display-table nil)
   8166   (setq web-mode-enable-whitespace-fontification nil))
   8167 
   8168 (defun web-mode-use-tabs ()
   8169   "Tweaks vars to be compatible with TAB indentation."
   8170   (let (offset)
   8171     (setq web-mode-block-padding 0)
   8172     (setq web-mode-script-padding 0)
   8173     (setq web-mode-style-padding 0)
   8174     (setq offset
   8175           (cond
   8176             ((and (boundp 'tab-width) tab-width) tab-width)
   8177             ((and (boundp 'standard-indent) standard-indent) standard-indent)
   8178             (t 4)))
   8179     ;;    (message "offset(%S)" offset)
   8180     (setq web-mode-attr-indent-offset offset)
   8181     (setq web-mode-code-indent-offset offset)
   8182     (setq web-mode-css-indent-offset offset)
   8183     (setq web-mode-markup-indent-offset offset)
   8184     (setq web-mode-sql-indent-offset offset)
   8185     (add-to-list 'web-mode-indentation-params '("lineup-args" . nil))
   8186     (add-to-list 'web-mode-indentation-params '("lineup-calls" . nil))
   8187     (add-to-list 'web-mode-indentation-params '("lineup-concats" . nil))
   8188     (add-to-list 'web-mode-indentation-params '("lineup-ternary" . nil))
   8189     ))
   8190 
   8191 (defun web-mode-element-children-fold-or-unfold (&optional pos)
   8192   "Fold/Unfold all the children of the current html element."
   8193   (interactive)
   8194   (unless pos (setq pos (point)))
   8195   (save-excursion
   8196     (dolist (child (reverse (web-mode-element-children pos)))
   8197       (goto-char child)
   8198       (web-mode-fold-or-unfold))
   8199     ))
   8200 
   8201 (defun web-mode-fold-or-unfold (&optional pos)
   8202   "Toggle folding on an html element or a control block."
   8203   (interactive)
   8204   (web-mode-scan)
   8205   (web-mode-with-silent-modifications
   8206    (save-excursion
   8207      (if pos (goto-char pos))
   8208      (let (beg-inside beg-outside end-inside end-outside overlay overlays)
   8209        (when (looking-back "^[\t ]*" (point-min))
   8210          (back-to-indentation))
   8211        (setq overlays (overlays-at (point)))
   8212        (dolist (elt overlays)
   8213          (when (and (not overlay)
   8214                     (eq (overlay-get elt 'font-lock-face) 'web-mode-folded-face))
   8215            (setq overlay elt)))
   8216        (cond
   8217          ;; *** unfolding
   8218          (overlay
   8219           (setq beg-inside (overlay-start overlay)
   8220                 end-inside (overlay-end overlay))
   8221           (remove-overlays beg-inside end-inside)
   8222           (put-text-property beg-inside end-inside 'invisible nil)
   8223           )
   8224          ;; *** block folding
   8225          ((and (get-text-property (point) 'block-side)
   8226                (cdr (web-mode-block-is-control (point))))
   8227           (setq beg-outside (web-mode-block-beginning-position (point)))
   8228           (setq beg-inside (1+ (web-mode-block-end-position (point))))
   8229           (when (web-mode-block-match)
   8230             (setq end-inside (point))
   8231             (setq end-outside (1+ (web-mode-block-end-position (point)))))
   8232           )
   8233          ;; *** html comment folding
   8234          ((eq (get-text-property (point) 'tag-type) 'comment)
   8235           (setq beg-outside (web-mode-tag-beginning-position))
   8236           (setq beg-inside (+ beg-outside 4))
   8237           (setq end-outside (web-mode-tag-end-position))
   8238           (setq end-inside (- end-outside 3))
   8239           )
   8240          ;; *** tag folding
   8241          ((or (member (get-text-property (point) 'tag-type) '(start end))
   8242               (web-mode-element-parent))
   8243           (when (not (web-mode-element-is-collapsed (point)))
   8244             (web-mode-tag-beginning)
   8245             (when (eq (get-text-property (point) 'tag-type) 'end)
   8246               (web-mode-tag-match))
   8247             (setq beg-outside (point))
   8248             (web-mode-tag-end)
   8249             (setq beg-inside (point))
   8250             (goto-char beg-outside)
   8251             (when (web-mode-tag-match)
   8252               (setq end-inside (point))
   8253               (web-mode-tag-end)
   8254               (setq end-outside (point)))
   8255             )
   8256           )
   8257          ) ;cond
   8258        (when (and beg-inside beg-outside end-inside end-outside)
   8259          (setq overlay (make-overlay beg-outside end-outside))
   8260          (overlay-put overlay 'font-lock-face 'web-mode-folded-face)
   8261          (put-text-property beg-inside end-inside 'invisible t))
   8262        ))))
   8263 
   8264 ;;---- TRANSFORMATION ----------------------------------------------------------
   8265 
   8266 (defun web-mode-buffer-change-tag-case (&optional type)
   8267   "Change html tag case."
   8268   (interactive)
   8269   (save-excursion
   8270     (goto-char (point-min))
   8271     (let ((continue t) f)
   8272       (setq f (if (member type '("upper" "uppercase" "upper-case")) 'uppercase 'downcase))
   8273       (when (and (not (get-text-property (point) 'tag-beg))
   8274                  (not (web-mode-tag-next)))
   8275         (setq continue nil))
   8276       (while continue
   8277         (skip-chars-forward "<!/")
   8278         (if (looking-at "\\([[:alnum:]:-]+\\)")
   8279             (replace-match (funcall f (match-string 0)) t))
   8280         ;;        (message "tag: %S (%S)"
   8281         ;;                 (get-text-property (point) 'tag-name)
   8282         ;;                 (point))
   8283         (unless (web-mode-tag-next)
   8284           (setq continue nil))
   8285         ) ;while
   8286       )))
   8287 
   8288 (defun web-mode-buffer-change-attr-case (&optional type)
   8289   "Change case of html attribute names."
   8290   (interactive)
   8291   (unless type (setq type "downcase"))
   8292   (save-excursion
   8293     (goto-char (point-min))
   8294     (let ((continue t)
   8295           (fun (if (eq (aref (downcase type) 0) ?u) 'uppercase 'downcase)))
   8296       (while continue
   8297         (cond
   8298           ((not (web-mode-attribute-next))
   8299            (setq continue nil))
   8300           ((looking-at "\\([[:alnum:]-]+\\)")
   8301            (replace-match (funcall fun (match-string 0)) t)
   8302            )
   8303           ) ;cond
   8304         ) ;while
   8305       )))
   8306 
   8307 ;; tag-case=lower|upper-case , attr-case=lower|upper-case
   8308 ;; special-chars=unicode|html-entities
   8309 ;; smart-apostrophes=bool , smart-quotes=bool , indentation=bool
   8310 (defun web-mode-dom-normalize ()
   8311   "Normalize buffer"
   8312   (interactive)
   8313   (save-excursion
   8314     (let ((rules web-mode-normalization-rules) elt)
   8315       (when (setq elt (cdr (assoc "tag-case" rules)))
   8316         (web-mode-buffer-change-tag-case elt))
   8317       (when (setq elt (cdr (assoc "attr-case" rules)))
   8318         (web-mode-buffer-change-attr-case elt))
   8319       (when (setq elt (cdr (assoc "css-indentation" rules)))
   8320         (web-mode-css-indent))
   8321       (when (setq elt (cdr (assoc "smart-apostrophes" rules)))
   8322         (web-mode-dom-apostrophes-replace))
   8323       (when (setq elt (cdr (assoc "smart-quotes" rules)))
   8324         (web-mode-dom-quotes-replace))
   8325       (when (setq elt (cdr (assoc "special-chars" rules)))
   8326         (if (string= elt "entities")
   8327             (web-mode-dom-entities-encode)
   8328             (web-mode-dom-entities-replace)))
   8329       (when (setq elt (cdr (assoc "whitespaces" rules)))
   8330         (goto-char (point-min))
   8331         (while (not (eobp))
   8332           (forward-line)
   8333           (delete-blank-lines))
   8334         (delete-trailing-whitespace)
   8335         (untabify (point-min) (point-max)))
   8336       (when (setq elt (cdr (assoc "indentation" rules)))
   8337         (web-mode-buffer-indent))
   8338       )))
   8339 
   8340 (defun web-mode-dom-apostrophes-replace ()
   8341   "Replace char(') with char(’) in the innerText of html elements."
   8342   (interactive)
   8343   (save-excursion
   8344     (let ((min (point-min)) (max (point-max)))
   8345       (when mark-active
   8346         (setq min (region-beginning)
   8347               max (region-end))
   8348         (deactivate-mark))
   8349       (goto-char min)
   8350       (while (web-mode-content-rsf "\\([[:alpha:]]\\)'\\([[:alpha:]]\\)" max)
   8351         (replace-match "\\1’\\2"))
   8352       )))
   8353 
   8354 (defun web-mode-dom-entities-encode ()
   8355   (save-excursion
   8356     (let (regexp elt (min (point-min)) (max (point-max)))
   8357       (when mark-active
   8358         (setq min (region-beginning)
   8359               max (region-end))
   8360         (deactivate-mark))
   8361       (goto-char min)
   8362       (setq regexp "[")
   8363       (dolist (pair web-mode-html-entities)
   8364         (setq regexp (concat regexp (char-to-string (cdr pair))))
   8365         )
   8366       (setq regexp (concat regexp "]"))
   8367       (while (web-mode-content-rsf regexp max)
   8368         (setq elt (match-string-no-properties 0))
   8369         (setq elt (aref elt 0))
   8370         (setq elt (car (rassoc elt web-mode-html-entities)))
   8371         (replace-match (concat "&" elt ";"))
   8372         (setq max (+ max (length elt) 1))
   8373         ) ;while
   8374       )))
   8375 
   8376 (defun web-mode-dom-entities-replace ()
   8377   "Replace html entities (e.g. &eacute; &#233; or &#x00E9; become é)"
   8378   (interactive)
   8379   (save-excursion
   8380     (let (ms pair elt (min (point-min)) (max (point-max)))
   8381       (when mark-active
   8382         (setq min (region-beginning)
   8383               max (region-end))
   8384         (deactivate-mark))
   8385       (goto-char min)
   8386       (while (web-mode-content-rsf "&\\([#]?[[:alnum:]]\\{2,8\\}\\);" max)
   8387         (setq elt nil)
   8388         (setq ms (match-string-no-properties 1))
   8389         (cond
   8390           ((not (eq (aref ms 0) ?\#))
   8391            (and (setq pair (assoc ms web-mode-html-entities))
   8392                 (setq elt (cdr pair))
   8393                 (setq elt (char-to-string elt))))
   8394           ((eq (aref ms 1) ?x)
   8395            (setq elt (substring ms 2))
   8396            (setq elt (downcase elt))
   8397            (setq elt (string-to-number elt 16))
   8398            (setq elt (char-to-string elt)))
   8399           (t
   8400            (setq elt (substring ms 1))
   8401            (setq elt (char-to-string (string-to-number elt))))
   8402           ) ;cond
   8403         (when elt (replace-match elt))
   8404         ) ;while
   8405       )))
   8406 
   8407 (defun web-mode-dom-xml-replace ()
   8408   "Replace &, > and < in html content."
   8409   (interactive)
   8410   (save-excursion
   8411     (let ((min (point-min)) (max (point-max)))
   8412       (when mark-active
   8413         (setq min (region-beginning)
   8414               max (region-end))
   8415         (deactivate-mark))
   8416       (goto-char min)
   8417       (while (web-mode-content-rsf "[&<>]" max)
   8418         (replace-match (cdr (assq (char-before) web-mode-xml-chars)) t t))
   8419       )))
   8420 
   8421 (defun web-mode-dom-quotes-replace ()
   8422   "Replace dumb quotes."
   8423   (interactive)
   8424   (save-excursion
   8425     (let (expr (min (point-min)) (max (point-max)))
   8426       (when mark-active
   8427         (setq min (region-beginning)
   8428               max (region-end))
   8429         (deactivate-mark))
   8430       (goto-char min)
   8431       (setq expr (concat (car web-mode-smart-quotes) "\\2" (cdr web-mode-smart-quotes)))
   8432       (while (web-mode-content-rsf "\\(\"\\)\\(.\\{1,200\\}\\)\\(\"\\)" max)
   8433         (replace-match expr)
   8434         ) ;while
   8435       )))
   8436 
   8437 ;;---- INDENTATION -------------------------------------------------------------
   8438 
   8439 ;; todo : passer de règle en règle et mettre un \n à la fin
   8440 (defun web-mode-css-indent ()
   8441   (save-excursion
   8442     (goto-char (point-min))
   8443     (let ((continue t) part-end)
   8444       (while continue
   8445         (cond
   8446           ((not (web-mode-part-next))
   8447            (setq continue nil))
   8448           ((eq (get-text-property (point) 'part-side) 'css)
   8449            (setq part-end (web-mode-part-end-position))
   8450            (while (web-mode-css-rule-next part-end)
   8451              (when (not (looking-at-p "[[:space:]]*\\($\\|<\\)"))
   8452                (newline)
   8453                (indent-according-to-mode)
   8454                (setq part-end (web-mode-part-end-position)))
   8455              )
   8456            )
   8457           ) ;cond
   8458         )
   8459       )))
   8460 
   8461 (defun web-mode-buffer-indent ()
   8462   "Indent all buffer."
   8463   (interactive)
   8464   (let ((debug t) (ts (current-time)) (sub nil))
   8465     (indent-region (point-min) (point-max))
   8466     (when debug
   8467       (setq sub (time-subtract (current-time) ts))
   8468       (message "buffer-indent: time elapsed = %Ss %9Sµs" (nth 1 sub) (nth 2 sub)))
   8469     (delete-trailing-whitespace)))
   8470 
   8471 (defun web-mode-point-context (pos)
   8472   "POS should be at the beginning of the indentation."
   8473   (save-excursion
   8474     (let (curr-char curr-indentation curr-line
   8475                     language
   8476                     options
   8477                     reg-beg reg-col
   8478                     prev-char prev-indentation prev-line prev-pos
   8479                     token
   8480                     part-language
   8481                     depth)
   8482 
   8483       (setq reg-beg (point-min)
   8484             reg-col 0
   8485             token "live"
   8486             options ""
   8487             language ""
   8488             prev-line ""
   8489             prev-char 0
   8490             prev-pos nil)
   8491 
   8492       (when (get-text-property pos 'part-side)
   8493         (setq part-language (symbol-name (get-text-property pos 'part-side))))
   8494 
   8495       ;;(message "part-language=%S" part-language)
   8496 
   8497       (cond
   8498 
   8499         ((and (bobp) (member web-mode-content-type '("html" "xml")))
   8500          (setq language web-mode-content-type)
   8501          )
   8502 
   8503         ((string= web-mode-content-type "css")
   8504          (setq language "css"
   8505                curr-indentation web-mode-css-indent-offset))
   8506 
   8507         ((member web-mode-content-type '("javascript" "json" "typescript"))
   8508          (setq language web-mode-content-type
   8509                curr-indentation web-mode-code-indent-offset))
   8510 
   8511         ((or (string= web-mode-content-type "jsx")
   8512              (and part-language (string= part-language "jsx")))
   8513          (setq language "jsx"
   8514                curr-indentation web-mode-code-indent-offset)
   8515          (cond
   8516            ((web-mode-jsx-is-html pos)
   8517             (setq curr-indentation web-mode-markup-indent-offset
   8518                   options "is-html"))
   8519            ((and (setq depth (get-text-property pos 'jsx-depth)) (> depth 1))
   8520             (when (get-text-property pos 'jsx-beg)
   8521               (setq depth (1- depth)))
   8522             (setq reg-beg (web-mode-jsx-depth-beginning-position pos depth))
   8523             (setq reg-beg (1+ reg-beg))
   8524             ;;(message "%S" (point))
   8525             (save-excursion
   8526               (goto-char reg-beg)
   8527               ;;(message "pt=%S" reg-beg)
   8528               (cond
   8529                 ((and (not (looking-at-p "[ ]*$"))
   8530                       (looking-back "^[[:space:]]*{" (point-min)))
   8531                  (setq reg-col (+ (current-indentation) ;; #1027
   8532                                   (cond
   8533                                     ((looking-at "[ ]+") (1+ (length (match-string-no-properties 0))))
   8534                                     (t 0))
   8535                                   ))
   8536                  )
   8537                 ((looking-at-p "[ ]*\\[[ ]*$") ;; #0659
   8538                  (setq reg-col (current-indentation))
   8539                  )
   8540                 ((and (looking-back "=[ ]*{" (point-min)) ;; #0739 #1022
   8541                       (not (looking-at-p "[[:space:]]*<")))
   8542                  (setq reg-col (current-indentation))
   8543                  )
   8544                 ;;((and (looking-back "=[ ]*{" (point-min)) ;; #0739
   8545                 ;;      (looking-at-p "{[ ]*"))
   8546                 ;; (setq reg-col (current-indentation))
   8547                 ;; )
   8548                 ((get-text-property (1- (point)) 'tag-beg)
   8549                  ;;(message "point=%S" (point))
   8550                  (setq reg-col (current-indentation))
   8551                  )
   8552                 (t
   8553                  (message "%S : %S %S" (point) (current-indentation) web-mode-code-indent-offset)
   8554                  ;;(setq reg-col (+ (current-indentation) web-mode-code-indent-offset web-mode-jsx-expression-padding)))
   8555                  (setq reg-col (+ (current-indentation) web-mode-code-indent-offset)))
   8556                 )
   8557 
   8558               ;;(message "%S %S %S" (point) (current-indentation) reg-col)
   8559               ) ;save-excursion
   8560             )
   8561            ((string= web-mode-content-type "jsx")
   8562             (setq reg-beg (point-min)))
   8563            (t
   8564             (setq reg-beg (or (web-mode-part-beginning-position pos) (point-min)))
   8565             (save-excursion
   8566               (goto-char reg-beg)
   8567               (search-backward "<" nil t)
   8568               (setq reg-col (current-column))
   8569               ) ;save-excursion
   8570             )
   8571            ) ;cond
   8572          ;;(message "jsx reg-beg=%S" reg-beg)
   8573          ) ;jsx
   8574 
   8575         ((string= web-mode-content-type "php")
   8576          (setq language "php"
   8577                curr-indentation web-mode-code-indent-offset))
   8578 
   8579         ((or (string= web-mode-content-type "xml"))
   8580          (setq language "xml"
   8581                curr-indentation web-mode-markup-indent-offset))
   8582 
   8583         ;; TODO: est ce util ?
   8584         ((and (get-text-property pos 'tag-beg)
   8585               (get-text-property pos 'tag-name)
   8586               ;;(not (get-text-property pos 'part-side))
   8587               )
   8588          (setq language "html"
   8589                curr-indentation web-mode-markup-indent-offset))
   8590 
   8591         ((and (get-text-property pos 'block-side)
   8592               (not (get-text-property pos 'block-beg)))
   8593 
   8594          (setq reg-beg (or (web-mode-block-beginning-position pos) (point-min)))
   8595          (goto-char reg-beg)
   8596          (setq reg-col (current-column))
   8597          ;;(message "%S %S" reg-beg reg-col)
   8598          (setq language web-mode-engine)
   8599          (setq curr-indentation web-mode-code-indent-offset)
   8600 
   8601          (cond
   8602            ((string= web-mode-engine "blade")
   8603             (save-excursion
   8604               (when (web-mode-rsf "{[{!]+[ ]*")
   8605                 (setq reg-col (current-column))))
   8606             (setq reg-beg (+ reg-beg 2))
   8607             )
   8608            ((string= web-mode-engine "razor")
   8609             ;;(setq reg-beg (+ reg-beg 2))
   8610             ;;(setq reg-col (current-column))
   8611             )
   8612            ;; tests/demo.chtml
   8613            ((string= web-mode-engine "ctemplate")
   8614             (save-excursion
   8615               (when (web-mode-rsf "{{#?")
   8616                 (setq reg-col (current-column))))
   8617             )
   8618            ((string= web-mode-engine "dust")
   8619             (save-excursion
   8620               (when (web-mode-rsf "{@")
   8621                 (setq reg-col (current-column))))
   8622             )
   8623            ((string= web-mode-engine "svelte")
   8624             (save-excursion
   8625               (when (web-mode-rsf "{@")
   8626                 (setq reg-col (current-column))))
   8627             )
   8628            ((string= web-mode-engine "template-toolkit")
   8629             (setq reg-beg (+ reg-beg 3)
   8630                   reg-col (+ reg-col 3))
   8631             )
   8632            ((and (string= web-mode-engine "jsp")
   8633                  (web-mode-looking-at "<%@" reg-beg))
   8634             (save-excursion
   8635               (goto-char reg-beg)
   8636               (looking-at "<%@[ ]*[[:alpha:]]+[ ]+\\|</?[[:alpha:]]+[:.][[:alpha:]]+[ ]+")
   8637               (goto-char (match-end 0))
   8638               (setq reg-col (current-column))
   8639               )
   8640             )
   8641            ((and (string= web-mode-engine "freemarker")
   8642                  (web-mode-looking-at "<@\\|<%@\\|<[[:alpha:]]" reg-beg))
   8643             (save-excursion
   8644               (goto-char reg-beg)
   8645               (looking-at "<@[[:alpha:].]+[ ]+\\|<%@[ ]*[[:alpha:]]+[ ]+\\|<[[:alpha:]]+:[[:alpha:]]+[ ]+")
   8646               (goto-char (match-end 0))
   8647               (setq reg-col (current-column))
   8648               )
   8649             )
   8650            ) ;cond
   8651          ) ;block-side
   8652 
   8653         ((and part-language (member part-language
   8654                                     '("css" "javascript" "json" "sql" "markdown"
   8655                                       "pug" "ruby" "sass" "stylus" "typescript")))
   8656          (setq reg-beg (or (web-mode-part-beginning-position pos) (point-min)))
   8657          (goto-char reg-beg)
   8658          (if (and (string= web-mode-engine "mojolicious")
   8659                   (looking-back "javascript begin" (point-min)))
   8660              (search-backward "%" nil t)
   8661              (search-backward "<" nil t))
   8662          (setq reg-col (current-column))
   8663          (setq language part-language)
   8664          (cond
   8665            ((string= language "css")
   8666             (setq curr-indentation web-mode-css-indent-offset))
   8667            ((string= language "sql")
   8668             (setq curr-indentation web-mode-sql-indent-offset))
   8669            ((string= language "markdown")
   8670             (setq curr-indentation web-mode-code-indent-offset))
   8671            ((string= language "pug")
   8672             (setq curr-indentation web-mode-code-indent-offset))
   8673            ((string= language "sass")
   8674             (setq curr-indentation web-mode-code-indent-offset))
   8675            ((string= language "stylus")
   8676             (setq curr-indentation web-mode-code-indent-offset))
   8677            ((string= language "ruby")
   8678             (setq curr-indentation web-mode-code-indent-offset))
   8679            ((string= language "typescript")
   8680             (setq curr-indentation web-mode-code-indent-offset))
   8681            (t
   8682             (setq language "javascript"
   8683                   curr-indentation web-mode-code-indent-offset))
   8684            )
   8685          ) ;part-side
   8686 
   8687         (t
   8688          (setq language "html"
   8689                curr-indentation web-mode-markup-indent-offset)
   8690          )
   8691 
   8692         ) ;cond
   8693 
   8694       (cond
   8695         ((or (and (> pos (point-min))
   8696                   (eq (get-text-property pos 'part-token) 'comment)
   8697                   (eq (get-text-property (1- pos) 'part-token) 'comment)
   8698                   (progn
   8699                     (setq reg-beg (previous-single-property-change pos 'part-token))
   8700                     t))
   8701              (and (> pos (point-min))
   8702                   (eq (get-text-property pos 'block-token) 'comment)
   8703                   (eq (get-text-property (1- pos) 'block-token) 'comment)
   8704                   (progn
   8705                     (setq reg-beg (previous-single-property-change pos 'block-token))
   8706                     t))
   8707              (and (> pos (point-min))
   8708                   (eq (get-text-property pos 'tag-type) 'comment)
   8709                   (not (get-text-property pos 'tag-beg))
   8710                   (progn
   8711                     (setq reg-beg (web-mode-tag-beginning-position pos))
   8712                     t))
   8713              )
   8714          (setq token "comment"))
   8715         ((or (and (> pos (point-min))
   8716                   (member (get-text-property pos 'part-token)
   8717                           '(string context key))
   8718                   (member (get-text-property (1- pos) 'part-token)
   8719                           '(string context key)))
   8720              (and (eq (get-text-property pos 'block-token) 'string)
   8721                   (eq (get-text-property (1- pos) 'block-token) 'string)))
   8722          (setq token "string"))
   8723         )
   8724 
   8725       (goto-char pos)
   8726       (setq curr-line (web-mode-trim
   8727                        (buffer-substring-no-properties
   8728                         (line-beginning-position)
   8729                         (line-end-position))))
   8730       (setq curr-char (if (string= curr-line "") 0 (aref curr-line 0)))
   8731 
   8732       (when (or (member language '("php" "blade" "javascript" "typescript" "jsx" "razor" "css"))
   8733                 (and (member language '("html" "xml"))
   8734                      (not (eq ?\< curr-char))))
   8735         (let (prev)
   8736           (cond
   8737             ((member language '("html" "xml" "javascript" "typescript" "jsx" "css"))
   8738              (when (setq prev (web-mode-part-previous-live-line reg-beg))
   8739                (setq prev-line (nth 0 prev)
   8740                      prev-indentation (nth 1 prev)
   8741                      prev-pos (nth 2 prev))
   8742                )
   8743              )
   8744             ((setq prev (web-mode-block-previous-live-line))
   8745              (setq prev-line (car prev)
   8746                    prev-indentation (cdr prev))
   8747              (setq prev-line (web-mode-clean-block-line prev-line)))
   8748             ) ;cond
   8749           ) ;let
   8750         (when (>= (length prev-line) 1)
   8751           (setq prev-char (aref prev-line (1- (length prev-line))))
   8752           (setq prev-line (substring-no-properties prev-line))
   8753           )
   8754         )
   8755 
   8756       (cond
   8757         ((not (member web-mode-content-type '("html" "xml")))
   8758          )
   8759         ((member language '("javascript" "typescript" "jsx" "ruby"))
   8760          (setq reg-col (if web-mode-script-padding (+ reg-col web-mode-script-padding) 0)))
   8761         ((member language '("css" "sql" "markdown" "pug" "sass" "stylus"))
   8762          (setq reg-col (if web-mode-style-padding (+ reg-col web-mode-style-padding) 0)))
   8763         ((not (member language '("html" "xml")))
   8764          (setq reg-col
   8765                (cond
   8766                  ((not web-mode-block-padding) reg-col)
   8767                  ((eq web-mode-block-padding -1) 0)
   8768                  (t (+ reg-col web-mode-block-padding))
   8769                  ) ;cond
   8770                ) ;setq
   8771          )
   8772         )
   8773 
   8774       (list :curr-char curr-char
   8775             :curr-indentation curr-indentation
   8776             :curr-line curr-line
   8777             :language language
   8778             :options options
   8779             :prev-char prev-char
   8780             :prev-indentation prev-indentation
   8781             :prev-line prev-line
   8782             :prev-pos prev-pos
   8783             :reg-beg reg-beg
   8784             :reg-col reg-col
   8785             :token token)
   8786       )))
   8787 
   8788 (defun web-mode-indent-line ()
   8789 
   8790   (web-mode-scan)
   8791 
   8792   (let ((offset nil)
   8793         (char nil)
   8794         (debug nil)
   8795         (inhibit-modification-hooks nil)
   8796         (adjust t))
   8797 
   8798     (save-excursion
   8799       (back-to-indentation)
   8800       (setq char (char-after))
   8801       (let* ((pos (point))
   8802              (ctx (web-mode-point-context pos))
   8803              (curr-char (plist-get ctx :curr-char))
   8804              (curr-indentation (plist-get ctx :curr-indentation))
   8805              (curr-line (plist-get ctx :curr-line))
   8806              (language (plist-get ctx :language))
   8807              (prev-char (plist-get ctx :prev-char))
   8808              (prev-indentation (plist-get ctx :prev-indentation))
   8809              (prev-line (plist-get ctx :prev-line))
   8810              (prev-pos (plist-get ctx :prev-pos))
   8811              (reg-beg (plist-get ctx :reg-beg))
   8812              (reg-col (plist-get ctx :reg-col))
   8813              (token (plist-get ctx :token))
   8814              (options (plist-get ctx :options))
   8815              (chars (list curr-char prev-char))
   8816              (tmp nil)
   8817              (is-js (member language '("javascript" "jsx" "ejs" "typescript"))))
   8818 
   8819         (when (member language '("json" "typescript"))
   8820           (setq language "javascript"))
   8821 
   8822         ;;(message "%S %S" (plist-get ctx :language) language)
   8823         ;;(message "curr-char=[%c] prev-char=[%c]\n%S" curr-char prev-char ctx)
   8824         ;;(message "options=%S" ctx)
   8825 
   8826         (cond
   8827 
   8828           ((or (bobp) (= (line-number-at-pos pos) 1))
   8829            (when debug (message "I100(%S) first line" pos))
   8830            (setq offset 0))
   8831 
   8832           ;; #123 #1145
   8833           ((and web-mode-enable-front-matter-block
   8834                 (eq (char-after (point-min)) ?\-)
   8835                 (or (looking-at-p "---")
   8836                     (search-forward "---" (point-max) t)))
   8837            (when debug (message "I108(%S) front-matter-block" pos))
   8838            (setq offset nil))
   8839 
   8840           ;; #1073
   8841           ((get-text-property pos 'invisible)
   8842            (when debug (message "I110(%S) invible" pos))
   8843            (setq offset nil))
   8844 
   8845           ((string= token "string")
   8846            (when debug (message "I120(%S) string" pos))
   8847            (cond
   8848              ((web-mode-is-token-end pos)
   8849               (if (get-text-property pos 'block-side)
   8850                   (web-mode-block-token-beginning)
   8851                   (web-mode-part-token-beginning))
   8852               (setq offset (current-indentation))
   8853               )
   8854              ((and web-mode-enable-sql-detection
   8855                    (web-mode-block-token-starts-with (concat "[ \n]*" web-mode-sql-queries)))
   8856               (save-excursion
   8857                 (let (col)
   8858                   (web-mode-block-string-beginning)
   8859                   (skip-chars-forward "[ \"'\n]")
   8860                   (setq col (current-column))
   8861                   (goto-char pos)
   8862                   (if (looking-at-p "\\(SELECT\\|INSERT\\|DELETE\\|UPDATE\\|FROM\\|LEFT\\|JOIN\\|WHERE\\|GROUP BY\\|LIMIT\\|HAVING\\|\)\\)")
   8863                       (setq offset col)
   8864                       (setq offset (+ col web-mode-sql-indent-offset)))
   8865                   )
   8866                 ) ;save-excursion
   8867               )
   8868              ((and is-js
   8869                    (web-mode-is-ql-string pos "Relay\.QL"))
   8870               (setq offset (web-mode-relayql-indentation pos))
   8871               )
   8872              ((and is-js
   8873                    (web-mode-is-ql-string pos "gql"))
   8874               (setq offset (web-mode-relayql-indentation pos "gql"))
   8875               )
   8876              ((and is-js
   8877                    (web-mode-is-ql-string pos "graphql"))
   8878               (setq offset (web-mode-relayql-indentation pos "graphql"))
   8879               )
   8880              ((and is-js
   8881                    (web-mode-is-css-string pos))
   8882               (when debug (message "I127(%S) css string" pos))
   8883               (setq offset (web-mode-token-css-indentation pos))
   8884               )
   8885              ((and is-js
   8886                    (web-mode-is-html-string pos))
   8887               (when debug (message "I128(%S) html string" pos))
   8888               (setq offset (web-mode-token-html-indentation pos))
   8889               )
   8890              (t
   8891               (setq offset nil))
   8892              ) ;cond
   8893            ) ;case string
   8894 
   8895           ((string= token "comment")
   8896            (when debug (message "I130(%S) comment" pos))
   8897            (if (eq (get-text-property pos 'tag-type) 'comment)
   8898                (web-mode-tag-beginning)
   8899                (goto-char (car
   8900                            (web-mode-property-boundaries
   8901                             (if (eq (get-text-property pos 'part-token) 'comment)
   8902                                 'part-token
   8903                                 'block-token)
   8904                             pos))))
   8905            (setq offset (current-column))
   8906            (cond
   8907              ((string= web-mode-engine "freemarker")
   8908               (setq offset (+ (current-indentation) 2)))
   8909              ((member (buffer-substring-no-properties (point) (+ (point) 2)) '("/*" "{*" "@*"))
   8910               (cond
   8911                 ((eq ?\* curr-char)
   8912                  (setq offset (+ offset 1)))
   8913                 (t
   8914                  (setq offset (+ offset 3)))
   8915                 ) ;cond
   8916               )
   8917              ((string= (buffer-substring-no-properties (point) (+ (point) 4)) "<!--")
   8918               (cond
   8919                 ((string-match-p "^<!\\[endif" curr-line)
   8920                  )
   8921                 ((looking-at-p "<!--\\[if")
   8922                  (setq offset (+ offset web-mode-markup-indent-offset)))
   8923                 ((string-match-p "^-->" curr-line)
   8924                  (setq offset offset))
   8925                 ((string-match-p "^-" curr-line)
   8926                  (setq offset (+ offset 3)))
   8927                 (t
   8928                  (setq offset (+ offset web-mode-markup-comment-indent-offset)))
   8929                 ) ;cond
   8930               )
   8931              ((and (string= web-mode-engine "django") (looking-back "{% comment %}" (point-min)))
   8932               (setq offset (- offset 12)))
   8933              ((and (string= web-mode-engine "mako") (looking-back "<%doc%>" (point-min)))
   8934               (setq offset (- offset 6)))
   8935              ((and (string= web-mode-engine "mason") (looking-back "<%doc%>" (point-min)))
   8936               (setq offset (- offset 6)))
   8937              ) ;cond
   8938            ) ;case comment
   8939 
   8940           ((and (string= web-mode-engine "mason")
   8941                 (string-match-p "^%" curr-line))
   8942            (when debug (message "I140(%S) mason" pos))
   8943            (setq offset 0))
   8944 
   8945           ((and (string= web-mode-engine "razor")
   8946                 (string-match-p "^\\([{}]\\|else\\)" curr-line))
   8947            (when debug (message "I142(%S) razor" pos))
   8948            (save-excursion
   8949              (web-mode-block-previous)
   8950              (setq offset (current-indentation))
   8951              ))
   8952 
   8953           ((and (string= web-mode-engine "django")
   8954                 (string-match-p "^#" curr-line))
   8955            (when debug (message "I144(%S) django line statements" pos))
   8956            (setq offset 0))
   8957 
   8958           ((and (get-text-property pos 'block-beg)
   8959                 (or (web-mode-block-is-close pos)
   8960                     (web-mode-block-is-inside pos)))
   8961            (when debug (message "I150(%S) block-match" pos))
   8962            (cond
   8963              ((not (web-mode-block-match))
   8964               )
   8965              ((and (string= web-mode-engine "closure")
   8966                    (string-match-p "{\\(case\\|default\\)" curr-line))
   8967               (setq offset (+ (current-indentation) web-mode-markup-indent-offset)))
   8968              (t
   8969               (setq offset (current-indentation))
   8970               (if (and (string= web-mode-engine "blade")
   8971                        (string-match-p "@break" curr-line))
   8972                   (setq offset (+ (current-indentation) offset)))
   8973               )
   8974              ) ;cond
   8975            )
   8976 
   8977           ((eq (get-text-property pos 'block-token) 'delimiter-end)
   8978            (when debug (message "I160(%S) block-beginning" pos))
   8979            (when (web-mode-block-beginning)
   8980              (setq reg-col (current-indentation))
   8981              (setq offset (current-column))))
   8982 
   8983           ((or (and (get-text-property pos 'tag-beg)
   8984                     (eq (get-text-property pos 'tag-type) 'end))
   8985                (and (eq (get-text-property pos 'tag-type) 'comment)
   8986                     (string-match-p "<!--#\\(else\\|elif\\|endif\\)" curr-line)))
   8987            (when debug (message "I170(%S) tag-match" pos))
   8988            (when (web-mode-tag-match)
   8989              (setq offset (current-indentation))))
   8990 
   8991           ((and (member language '("jsx"))
   8992                 (eq curr-char ?\})
   8993                 (get-text-property pos 'jsx-end))
   8994            (when debug (message "I180(%S) jsx-expr-end" pos))
   8995            (web-mode-go (1- reg-beg))
   8996            (setq reg-col nil)
   8997            ;;(setq offset (current-column)))
   8998            (setq offset (current-indentation)))
   8999 
   9000           ((and (member language '("html" "xml" "javascript" "jsx"))
   9001                 (get-text-property pos 'tag-type)
   9002                 (not (get-text-property pos 'tag-beg))
   9003                 ;;(or (not (string= language "jsx"))
   9004                 ;;    (string= options "is-html"))
   9005                 (not (and (string= language "jsx")
   9006                           (web-mode-jsx-is-expr pos)))
   9007                 )
   9008            (when debug (message "I190(%S) attr-indent" pos))
   9009            (cond
   9010              ((and (not (get-text-property pos 'tag-attr-beg))
   9011                    (get-text-property pos 'tag-attr)
   9012                    (get-text-property (1- pos) 'tag-attr)
   9013                    (web-mode-attribute-beginning)
   9014                    (not (string-match-p "^/?>" curr-line))
   9015                    ;;(progn (message "pos=%S point=%S" pos (point)) t)
   9016                    )
   9017 
   9018               (cond
   9019                 ((eq (logand (get-text-property (point) 'tag-attr-beg) 8) 8)
   9020                  (setq offset nil))
   9021                 ((not (web-mode-tag-beginning))
   9022                  (message "** tag-beginning ** failure")
   9023                  (setq offset nil))
   9024                 (web-mode-attr-value-indent-offset
   9025                  (setq offset (+ (current-column) web-mode-attr-value-indent-offset)))
   9026                 ((web-mode-dom-rsf "=[ ]*[\"']?" pos)
   9027                  ;;(message "%S" (point))
   9028                  (setq offset (current-column)))
   9029                 (t
   9030                  (setq offset (+ (current-column) web-mode-markup-indent-offset)))
   9031                 ) ;cond
   9032               ) ;and
   9033              ((not (web-mode-tag-beginning))
   9034               (message "** error ** unable to jump to tag beg"))
   9035              ((string-match-p "^/?>" curr-line)
   9036               (setq offset (web-mode-column-at-pos (web-mode-tag-beginning-position pos)))
   9037               )
   9038              (web-mode-attr-indent-offset
   9039               (setq offset (+ (current-column) web-mode-attr-indent-offset)))
   9040              ((looking-at-p (concat web-mode-start-tag-regexp "[ ]*\n"))
   9041               ;;(message "%S: %S" (point) (web-mode-inside-block-control pos))
   9042               (setq offset (+ (current-column) (or web-mode-attr-indent-offset web-mode-code-indent-offset)))
   9043               ;; #1109
   9044               (setq tmp (web-mode-inside-block-control pos))
   9045               (when (and tmp (> tmp (point)))
   9046                 (setq offset (+ offset (or web-mode-attr-indent-offset web-mode-code-indent-offset))))
   9047               )
   9048              ((web-mode-attribute-next)
   9049               (setq offset (current-column)))
   9050              ) ;cond
   9051            ) ;attr-indent
   9052 
   9053           ((or (member language '("html" "xml"))
   9054                (and (member language '("jsx"))
   9055                     (string= options "is-html")))
   9056            (when debug (message "I200(%S) web-mode-markup-indentation" pos))
   9057            ;; https://www.w3.org/TR/html5/syntax.html#optional-tags
   9058            (when web-mode-enable-optional-tags
   9059              (save-excursion
   9060                (let (tag-name parent-tag-name parent-tag-pos)
   9061                  (when (and (setq tag-name (get-text-property pos 'tag-name))
   9062                             (setq parent-tag-pos (web-mode-element-parent-position pos))
   9063                             (setq parent-tag-name (get-text-property parent-tag-pos 'tag-name))
   9064                             (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")))
   9065                                 (and (string= parent-tag-name "li") (member tag-name '("li")))
   9066                                 (and (string= parent-tag-name "dt") (member tag-name '("dt" "dd")))
   9067                                 (and (string= parent-tag-name "td") (member tag-name '("td" "th")))
   9068                                 (and (string= parent-tag-name "th") (member tag-name '("td" "th")))
   9069                                 ))
   9070                    (when debug (message "I205(%S) %S(%S) auto-closing" pos parent-tag-name parent-tag-pos))
   9071                    (setq offset (web-mode-indentation-at-pos parent-tag-pos))
   9072                    )))) ; when let save-excursion when
   9073 
   9074            (when (string= web-mode-engine "closure")
   9075              (save-excursion
   9076                (when (and (re-search-backward "{/?switch" nil t)
   9077                           (string= (match-string-no-properties 0) "{switch"))
   9078                  (setq offset (+ (current-indentation) (* 2 web-mode-markup-indent-offset)))
   9079                  )
   9080                ))
   9081            (cond
   9082              ((not (null offset))
   9083               )
   9084              ((get-text-property pos 'tag-beg)
   9085               (setq offset (web-mode-markup-indentation pos))
   9086               )
   9087              ((and web-mode-indentless-elements
   9088                    (not (string= language "jsx"))
   9089                    (null (get-text-property pos 'block-side))
   9090                    (null (get-text-property pos 'part-side))
   9091                    (and (null (get-text-property pos 'tag-beg))
   9092                         (save-excursion
   9093                           (and (web-mode-element-parent)
   9094                                (member (get-text-property (point) 'tag-name) web-mode-indentless-elements))))
   9095                    )
   9096               (setq offset nil))
   9097              ((or (eq (length curr-line) 0)
   9098                   (= web-mode-indent-style 2)
   9099                   (get-text-property pos 'tag-beg)
   9100                   (get-text-property pos 'reg-beg))
   9101               (setq offset (web-mode-markup-indentation pos))
   9102               )
   9103              )
   9104            )
   9105 
   9106           ((string= language "ctemplate")
   9107            (when debug (message "I210(%S) ctemplate" pos))
   9108            (setq offset reg-col))
   9109 
   9110           ((string= language "antlers")
   9111            (when debug (message "I214(%S) antlers" pos))
   9112            (setq offset reg-col))
   9113 
   9114           ((string= language "expressionengine")
   9115            (when debug (message "I220(%S) expressionengine" pos))
   9116            (setq offset (+ reg-col (or web-mode-attr-indent-offset web-mode-code-indent-offset))))
   9117 
   9118           ((string= language "asp")
   9119            (when debug (message "I230(%S) asp" pos))
   9120            (setq offset (web-mode-asp-indentation pos
   9121                                                   curr-line
   9122                                                   reg-col
   9123                                                   curr-indentation
   9124                                                   reg-beg)))
   9125 
   9126           ((member language '("lsp" "cl-emb" "artanis"))
   9127            (when debug (message "I240(%S) lsp" pos))
   9128            (setq offset (web-mode-lisp-indentation pos ctx)))
   9129 
   9130           ((and (member curr-char '(?\}))
   9131                 (string= language "razor")
   9132                 (get-text-property pos 'block-end))
   9133            (when debug (message "I245(%S) razor closing" pos))
   9134            (goto-char reg-beg)
   9135            ;;(message "%S %S" (point) (current-column))
   9136            (setq offset (current-column)
   9137                  reg-col nil)
   9138            )
   9139 
   9140           ((member curr-char '(?\} ?\) ?\]))
   9141            (when debug (message "I250(%S) closing-paren" pos))
   9142            (let (ori pos2)
   9143              (setq pos2 pos)
   9144              ;; #1096
   9145              (when (looking-at-p ".[\]})]+")
   9146                (skip-chars-forward "[\]})]")
   9147                (backward-char)
   9148                (setq pos2 (point))
   9149                ) ;when
   9150              (if (get-text-property pos 'block-side)
   9151                  (setq ori (web-mode-block-opening-paren-position pos2 reg-beg))
   9152                  (setq ori (web-mode-part-opening-paren-position pos2 reg-beg)))
   9153              ;;(message "ori=%S" ori)
   9154              (cond
   9155                ((null ori)
   9156                 (setq offset reg-col))
   9157                ((and (goto-char ori)
   9158                      (looking-back ")[ ]*" (point-min)) ;; peut-on se passer du looking-back ?
   9159                      (re-search-backward ")[ ]*" nil t)
   9160                      (web-mode-block-opening-paren reg-beg))
   9161                 (back-to-indentation)
   9162                 (setq offset (current-indentation))
   9163                 )
   9164                (t
   9165                 (goto-char ori)
   9166                 (back-to-indentation)
   9167                 (setq offset (current-indentation))
   9168                 ;;(message "ori=%S offset=%S" ori offset)
   9169                 (when (get-text-property pos 'jsx-depth)
   9170                   ;;(when (get-text-property pos 'jsx-end)
   9171                   (setq adjust nil))
   9172                 ) ;t
   9173                ) ;cond
   9174              ) ;let
   9175            )
   9176 
   9177           ((member language '("mako" "web2py"))
   9178            (when debug (message "I254(%S) python (mako/web2py)" pos))
   9179            (setq offset (web-mode-python-indentation pos
   9180                                                      curr-line
   9181                                                      reg-col
   9182                                                      curr-indentation
   9183                                                      reg-beg)))
   9184 
   9185           ((member language '("erb" "ruby"))
   9186            (when debug (message "I260(%S) erb" pos))
   9187            (setq offset (web-mode-ruby-indentation pos
   9188                                                    curr-line
   9189                                                    reg-col
   9190                                                    curr-indentation
   9191                                                    reg-beg)))
   9192 
   9193           ((string= language "css")
   9194            (when debug (message "I270(%S) css-indentation" pos))
   9195            ;;(message "prev=%c" prev-char)
   9196            (cond
   9197              ((eq prev-char ?:)
   9198               (setq offset (+ prev-indentation web-mode-css-indent-offset)))
   9199              ((eq prev-char ?,)
   9200               (setq offset prev-indentation))
   9201              (t
   9202               (setq offset (car (web-mode-css-indentation pos
   9203                                                           reg-col
   9204                                                           curr-indentation
   9205                                                           language
   9206                                                           reg-beg))))))
   9207 
   9208           ((string= language "sql")
   9209            (when debug (message "I280(%S) sql" pos))
   9210            (setq offset (car (web-mode-sql-indentation pos
   9211                                                        reg-col
   9212                                                        curr-indentation
   9213                                                        language
   9214                                                        reg-beg))))
   9215 
   9216           ((string= language "markdown")
   9217            (when debug (message "I290(%S) markdown" pos))
   9218            (setq offset (car (web-mode-markdown-indentation pos
   9219                                                             reg-col
   9220                                                             curr-indentation
   9221                                                             language
   9222                                                             reg-beg))))
   9223 
   9224           ((string= language "stylus")
   9225            (when debug (message "I294(%S) stylus" pos))
   9226            (setq offset (car (web-mode-stylus-indentation pos
   9227                                                           reg-col
   9228                                                           curr-indentation
   9229                                                           language
   9230                                                           reg-beg))))
   9231           ((string= language "sass")
   9232            (when debug (message "I296(%S) sass" pos))
   9233            (setq offset (car (web-mode-stylus-indentation pos
   9234                                                           reg-col
   9235                                                           curr-indentation
   9236                                                           language
   9237                                                           reg-beg))))
   9238 
   9239           ((string= language "pug")
   9240            (when debug (message "I298(%S) pug" pos))
   9241            (setq offset (car (web-mode-pug-indentation pos
   9242                                                        reg-col
   9243                                                        curr-indentation
   9244                                                        language
   9245                                                        reg-beg))))
   9246 
   9247           ((and (string= language "razor")
   9248                 (string-match-p "^\\." curr-line)
   9249                 (string-match-p "^\\." prev-line))
   9250            (when debug (message "I300(%S) razor" pos))
   9251            (setq offset prev-indentation))
   9252 
   9253           ((and (string= language "razor")
   9254                 (string-match-p "^case " curr-line)
   9255                 (string-match-p "^case " prev-line))
   9256            (when debug (message "I310(%S) razor case" pos))
   9257            (search-backward "case ")
   9258            (setq offset (current-column)))
   9259 
   9260           ((and is-js
   9261                 (member ?\. chars)
   9262                 (not (string-match-p "^\\.\\.\\." curr-line)))
   9263            (when debug (message "I320(%S) javascript-calls" pos))
   9264            (let (pair)
   9265              (setq pair (web-mode-javascript-calls-beginning-position pos reg-beg))
   9266              ;;(message "%S" pair)
   9267              (when pair
   9268                (goto-char (car pair))
   9269                ;;(message "%S %S" (point) pair)
   9270                (cond
   9271                  ((cdr (assoc "lineup-calls" web-mode-indentation-params))
   9272                   ;;(message "ici")
   9273                   ;;(search-forward ".")
   9274                   (if (cdr pair)
   9275                       (progn
   9276                         (goto-char (cdr pair))
   9277                         (setq offset (current-column))
   9278                         (looking-at "\\.\\([ \t\n]*\\)")
   9279                         (setq offset (- offset (length (match-string-no-properties 1))))
   9280                         (unless (eq curr-char ?\.) (setq offset (1+ offset)))
   9281                         ) ;progn
   9282                       ;; TODO: cela devrait etre fait dans web-mode-javascript-calls-beginning-position
   9283                       (skip-chars-forward " \t\n")
   9284                       (setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9285                       ) ;if
   9286                   )
   9287                  (t
   9288                   (setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9289                   ) ;t
   9290                  ) ;cond
   9291                ) ;when
   9292              ) ;let
   9293            )
   9294 
   9295           ((and is-js
   9296                 (member ?\+ chars))
   9297            (when debug (message "I330(%S) javascript-string" pos))
   9298            ;;(message "js-concat")
   9299            (cond
   9300              ((not (web-mode-javascript-string-beginning pos reg-beg))
   9301               )
   9302              ((null (cdr (assoc "lineup-concats" web-mode-indentation-params)))
   9303               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9304              ((not (eq curr-char ?\+))
   9305               (setq offset (current-column)))
   9306              (t
   9307               (setq offset (current-column))
   9308               (when (not (looking-back "\\(^[ \t]+\\|if[ ]*[(]?\\)" (point-min)))
   9309                 (goto-char pos)
   9310                 (looking-at "\\+[ \t\n]*")
   9311                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9312               )
   9313              )
   9314            )
   9315 
   9316           ;; #579 , #742
   9317           ((and (member language '("javascript" "jsx" "ejs" "php"))
   9318                 (string-match-p "=[>]?$" prev-line))
   9319            (when debug (message "I340(%S)" pos))
   9320            (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9321            ;;(message "ici%S" offset)
   9322            )
   9323 
   9324           ;; #1016
   9325           ((and (member language '("javascript" "jsx" "ejs"))
   9326                 (string-match-p "^[ \t]*|}" curr-line))
   9327            (when debug (message "I346(%S) flow-exact-object-type-end" pos))
   9328            (when (re-search-backward "{|" reg-beg t)
   9329              (setq offset (current-indentation))
   9330              )
   9331            )
   9332 
   9333           ;; #446, #638, #800, #978, #998
   9334           ((and (member language '("javascript" "jsx" "ejs" "php"))
   9335                 (or (string-match-p "[&|?:+-]$" prev-line)
   9336                     (string-match-p "^[&|?:+-]" curr-line))
   9337                 (not (and (string= language "php")
   9338                           (string-match-p "^->" curr-line)))
   9339                 (not (and (string= language "php")
   9340                           (string-match-p "^?[a-zA-z]*" curr-line)))
   9341                 (not (and (string= language "php")
   9342                           (string-match-p "\\(else[ ]?:\\|if[ ]?([^)]*)[ ]?:\\)" prev-line)))
   9343                 (not (string-match-p "^\\(++\\|--\\)" curr-line))
   9344                 (not (and is-js
   9345                           (string-match-p "]:\\|{|$" prev-line)))
   9346                 (not (and (eq prev-char ?\:)
   9347                           (string-match-p "^\\(case\\|default\\)" prev-line)))
   9348                 )
   9349            ;;(message "prev=%S" prev-line)
   9350            (when debug (message "I350(%S) multiline statement" pos))
   9351            (let (is-ternary)
   9352              (setq is-ternary (or (string-match-p "[?:]$" prev-line)
   9353                                   (string-match-p "^[?:]" curr-line)))
   9354              (cond
   9355                ((not (funcall (if is-js
   9356                                   'web-mode-javascript-statement-beginning
   9357                                   'web-mode-block-statement-beginning)
   9358                               pos reg-beg is-ternary))
   9359                 )
   9360                ((null (cdr (assoc "lineup-ternary" web-mode-indentation-params)))
   9361                 (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9362                (t
   9363                 (setq offset (current-column))
   9364                 (when (and (member curr-char '(?\+ ?\- ?\& ?\| ?\? ?\:))
   9365                            (not (looking-back "\\(^[ \t]+\\|if[ ]*[(]?\\)" (point-min)))) ; #743
   9366                   (goto-char pos)
   9367                   (looking-at "\\(||\\|&&\\|[&|?:+-]\\)[ \t\n]*")
   9368                   (setq offset (- offset (length (match-string-no-properties 0)))))
   9369                 )
   9370                ) ;cond
   9371              ) ;let
   9372            )
   9373 
   9374           ((and is-js
   9375                 (eq prev-char ?\()
   9376                 (string-match-p "=>[ ]*([ ]*$" prev-line))
   9377            (when debug (message "I355(%S) => (" pos))
   9378            (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9379            )
   9380 
   9381           ((and is-js
   9382                 (or (member ?\, chars)
   9383                     (member prev-char '(?\( ?\[))))
   9384            (when debug (message "I360(%S) javascript-args" pos))
   9385            (cond
   9386              ((not (web-mode-javascript-args-beginning pos reg-beg))
   9387               (message "no js args beg")
   9388               )
   9389              ((or (not (cdr (assoc "lineup-args" web-mode-indentation-params)))
   9390                   (looking-at-p "|?\n") ;; #1016
   9391                   ;;(eq (char-after) ?\n)
   9392                   )
   9393               (if (and reg-col (> reg-col (current-indentation)))
   9394                   (setq offset (+ reg-col web-mode-code-indent-offset))
   9395                   (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9396               )
   9397              ((not (eq curr-char ?\,))
   9398               (setq offset (current-column)))
   9399              (t
   9400               (setq offset (current-column))
   9401               (goto-char pos)
   9402               (looking-at ",[ \t\n]*")
   9403               (setq offset (- offset (length (match-string-no-properties 0)))))
   9404              ) ;cond
   9405            )
   9406 
   9407           ((and is-js
   9408                 (or (eq prev-char ?\))
   9409                     (string-match-p "\\(^\\|[}[:space:]]+\\)else$" prev-line)))
   9410            (when debug (message "I370(%S)" pos))
   9411            (cond
   9412              ((and (string-match-p "else$" prev-line)
   9413                    (not (string-match-p "^{" curr-line)))
   9414               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9415               )
   9416              ((and (string-match-p "else$" prev-line)
   9417                    (string-match-p "^{" curr-line)
   9418                    web-mode-enable-curly-brace-indentation)
   9419               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9420               )
   9421              ((setq tmp (web-mode-part-is-opener prev-pos reg-beg))
   9422               ;;(message "is-opener")
   9423               (if (or (not (looking-at-p "{")) ;; #1020, #1053, #1160
   9424                       web-mode-enable-curly-brace-indentation)
   9425                   (setq offset (+ tmp web-mode-code-indent-offset))
   9426                   (setq offset tmp))
   9427               )
   9428              (t
   9429               (setq offset
   9430                     (car (web-mode-javascript-indentation pos
   9431                                                           reg-col
   9432                                                           curr-indentation
   9433                                                           language
   9434                                                           reg-beg)))
   9435               ) ;t
   9436              ) ;cond
   9437 
   9438            )
   9439 
   9440           ;; TODO : a retoucher completement car le code js a ete place ci-dessus
   9441           ;;((and (member language '("javascript" "jsx" "ejs" "php"))
   9442           ((and (member language '("php"))
   9443                 (or (and (eq prev-char ?\))
   9444                          (string-match-p "^\\(for\\|foreach\\|if\\|else[ ]*if\\|while\\)[ ]*(" prev-line))
   9445                     (and is-js
   9446                          (web-mode-part-is-opener prev-pos reg-beg))
   9447                     (string-match-p "^else$" prev-line))
   9448                 (not (string-match-p "^\\([{.]\\|->\\)" curr-line)))
   9449            (when debug (message "I380(%S)" pos))
   9450            (cond
   9451              ((and (eq prev-char ?\))
   9452                    (string-match-p "^\\(for\\|if\\|while\\)[ ]*(" prev-line))
   9453               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9454               )
   9455              ((member language '("javascript" "jsx"))
   9456               (setq offset
   9457                     (+ (car (web-mode-javascript-indentation pos
   9458                                                              reg-col
   9459                                                              curr-indentation
   9460                                                              language
   9461                                                              reg-beg))
   9462                        web-mode-code-indent-offset))
   9463               )
   9464              (t
   9465               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9466               )
   9467              )
   9468            )
   9469 
   9470           ((and (member language '("php" "blade")) (string-match-p "^->" curr-line))
   9471            (when debug (message "I390(%S) block-calls" pos))
   9472            (cond
   9473              ((not (web-mode-block-calls-beginning pos reg-beg))
   9474               )
   9475              ((cdr (assoc "lineup-calls" web-mode-indentation-params))
   9476               ;;(message "point=%S" (point))
   9477               (if (looking-back "::[ ]*" (point-min))
   9478                   (progn
   9479                     (re-search-backward "::[ ]*")
   9480                     (setq offset (current-column))
   9481                     ;;(message "ici%S offset=%S" (point) offset)
   9482                     )
   9483                   (search-forward "->")
   9484                   (setq offset (- (current-column) 2)))
   9485               )
   9486              (t
   9487               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9488              ))
   9489 
   9490           ((and is-js (member ?\, chars))
   9491            (when debug (message "I400(%S) part-args" pos))
   9492            (cond
   9493              ((not (web-mode-part-args-beginning pos reg-beg))
   9494               ;;(message "ici")
   9495               )
   9496              ((cdr (assoc "lineup-args" web-mode-indentation-params))
   9497               (setq offset (current-column))
   9498               ;;(message "offset=%S" offset)
   9499               (when (eq curr-char ?\,)
   9500                 (goto-char pos)
   9501                 (looking-at ",[ \t\n]*")
   9502                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9503               )
   9504              (t
   9505               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9506              ))
   9507 
   9508           ((member ?\, chars)
   9509            (when debug (message "I401(%S) block-args" pos))
   9510            (cond
   9511              ((not (web-mode-block-args-beginning pos reg-beg))
   9512               ;;(message "ici")
   9513               )
   9514              ((cdr (assoc "lineup-args" web-mode-indentation-params))
   9515               (setq offset (current-column))
   9516               ;;(message "offset=%S" offset)
   9517               (when (eq curr-char ?\,)
   9518                 (goto-char pos)
   9519                 (looking-at ",[ \t\n]*")
   9520                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9521               )
   9522              (t
   9523               (setq offset (current-column))
   9524               ;;(message "point=%S offset=%S" (point) offset)
   9525               (if (looking-back "[ ]+" (point-min))
   9526                   (progn
   9527                     (setq offset (current-indentation)))
   9528                 (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9529               ;;(when (eq curr-char ?\,)
   9530               ;;  (goto-char pos)
   9531               ;;  (looking-at ",[ \t\n]*")
   9532               ;;  (setq offset (- offset (length (match-string-no-properties 0)))))
   9533               ;;(setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9534               ) ;t
   9535              ))
   9536 
   9537 
   9538           ((and (string= language "php") (member ?\. chars))
   9539            (when debug (message "I410(%S) block-string" pos))
   9540            (cond
   9541              ((not (web-mode-block-string-beginning pos reg-beg))
   9542               )
   9543              ((null (cdr (assoc "lineup-concats" web-mode-indentation-params)))
   9544               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9545              ((not (eq curr-char ?\.))
   9546               (setq offset (current-column)))
   9547              (t
   9548               (setq offset (current-column))
   9549               (goto-char pos)
   9550               (when (cdr (assoc "lineup-quotes" web-mode-indentation-params))
   9551                 (looking-at "\\.[ \t\n]*")
   9552                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9553               )))
   9554 
   9555           ((member language '("javascript" "jsx" "ejs" "underscore"))
   9556            (when debug (message "I420(%S) javascript-indentation" pos))
   9557            (setq offset (car (web-mode-javascript-indentation pos
   9558                                                               reg-col
   9559                                                               curr-indentation
   9560                                                               language
   9561                                                               reg-beg))))
   9562 
   9563           (t
   9564            (when debug (message "I430(%S) bracket-indentation" pos))
   9565            (setq offset (car (web-mode-bracket-indentation pos
   9566                                                            reg-col
   9567                                                            curr-indentation
   9568                                                            language
   9569                                                            reg-beg))))
   9570 
   9571           ) ;cond
   9572 
   9573         (when (and offset reg-col adjust (< offset reg-col)) (setq offset reg-col))
   9574 
   9575         ) ;let
   9576       ) ;save-excursion
   9577 
   9578     (when offset
   9579       ;;(message "offset=%S" offset)
   9580       (let ((diff (- (current-column) (current-indentation))))
   9581         (when (not (= offset (current-indentation)))
   9582           (setq web-mode-change-beg (line-beginning-position)
   9583                 web-mode-change-end (+ web-mode-change-beg offset)))
   9584         (setq offset (max 0 offset))
   9585         (indent-line-to offset)
   9586         (if (> diff 0) (move-to-column (+ (current-column) diff)))
   9587         (when (and (string= web-mode-engine "mason")
   9588                    (= offset 0)
   9589                    (eq char ?\%))
   9590           (save-excursion
   9591             (font-lock-fontify-region (line-beginning-position) (line-end-position)))
   9592           ) ;when
   9593         ) ;let
   9594       ) ;when
   9595 
   9596     ))
   9597 
   9598 (defun web-mode-bracket-level (pos limit)
   9599   (save-excursion
   9600     (let ((continue t)
   9601           (regexp "[\]\[}{)(]")
   9602           (char nil)
   9603           (map nil)
   9604           (key nil)
   9605           (value 0)
   9606           (open '(?\( ?\{ ?\[)))
   9607       (goto-char pos)
   9608       (while (and continue (re-search-backward regexp limit t))
   9609         (setq char (aref (match-string-no-properties 0) 0))
   9610         (setq key (cond ((eq char ?\)) ?\()
   9611                         ((eq char ?\}) ?\{)
   9612                         ((eq char ?\]) ?\[)
   9613                         (t             char)))
   9614         (setq value (or (plist-get map key) 0))
   9615         (setq value (if (member char open) (1+ value) (1- value)))
   9616         (setq map (plist-put map key value))
   9617         (setq continue (< value 1))
   9618         ;;(message "pos=%S char=%c key=%c value=%S" (point) char key value)
   9619         ) ;while
   9620       (if (>= value 1) (current-indentation) nil)
   9621       )))
   9622 
   9623 (defun web-mode-token-html-indentation (pos)
   9624   (save-excursion
   9625     (let (beg (continue t) end level map offset regexp tag val void (css-beg 0))
   9626       (goto-char pos)
   9627       ;;(message "pos=%S" pos)
   9628       (setq beg (web-mode-part-token-beginning-position pos))
   9629       (save-excursion
   9630         (when (and (> (- pos beg) 5)
   9631                    (re-search-backward "</?[a-zA-Z0-9]+" beg t)
   9632                    (string= "<style" (downcase (match-string-no-properties 0))))
   9633           (setq css-beg (point))
   9634           )
   9635         )
   9636       ;;(message "beg=%S" beg)
   9637       (cond
   9638         ((eq (char-after pos) ?\`)
   9639          (setq offset (web-mode-indentation-at-pos beg)))
   9640         ((web-mode-looking-back "`[ \n\t]*" pos)
   9641          (setq offset (+ (web-mode-indentation-at-pos beg) web-mode-markup-indent-offset)))
   9642         ((looking-at "</\\([a-zA-Z0-9]+\\)")
   9643          (setq tag (match-string-no-properties 1)
   9644                regexp (concat "</?" tag)
   9645                level -1)
   9646          (while (and continue (re-search-backward regexp beg t))
   9647            (cond
   9648              ((eq (aref (match-string-no-properties 0) 1) ?\/)
   9649               (setq level (1- level)))
   9650              (t
   9651               (setq level (1+ level)))
   9652              ) ;cond
   9653            (when (= level 0)
   9654              (setq continue nil
   9655                    offset (current-indentation)))
   9656            ) ;while
   9657          )
   9658         ((> css-beg 0)
   9659          ;;(message "CSS")
   9660          (cond
   9661            ((member (char-after) '(?\) ?\} ?\]))
   9662             (web-mode-go (web-mode-token-opening-paren-position pos (+ css-beg 8) ""))
   9663             (setq offset (current-indentation))
   9664             )
   9665            ((setq level (web-mode-bracket-level pos (+ css-beg 8)))
   9666             (setq offset (+ level web-mode-css-indent-offset))
   9667             )
   9668            (t
   9669             (setq offset (+ (web-mode-indentation-at-pos css-beg) web-mode-style-padding))
   9670             ) ;t
   9671            )
   9672          )
   9673         ((looking-at "[a-zA-Z-]+[ ]?=")
   9674          (re-search-backward "<[a-zA-Z]+[ ]*" beg t)
   9675          (setq offset (+ (current-column) (length (match-string-no-properties 0))))
   9676          )
   9677         ((looking-at-p "/>")
   9678          (search-backward "<" beg t)
   9679          (setq offset (current-column))
   9680          )
   9681         (t
   9682          (setq regexp "</?\\([a-zA-Z0-9]+\\)")
   9683          ;;(message "point=%S" (point))
   9684          (while (and continue (re-search-backward regexp beg t))
   9685            (setq tag (downcase (match-string-no-properties 1))
   9686                  end nil
   9687                  void nil)
   9688            (cond
   9689              ((eq (aref (match-string-no-properties 0) 1) ?/)
   9690               (setq end t))
   9691              ((web-mode-element-is-void tag)
   9692               (setq void t))
   9693              (t
   9694               (save-excursion
   9695                 (when (and (search-forward ">" pos t) (eq (char-before (1- (point))) ?\/))
   9696                   (setq void t))
   9697                 ) ;save-excursion
   9698               ) ;t
   9699              ) ;cond
   9700            (unless void
   9701              (setq val (or (lax-plist-get map tag) 0))
   9702              (setq val (if end (1- val) (1+ val)))
   9703              (setq map (lax-plist-put map tag val))
   9704              ;;(message "val=%S tag=%S end=%S | %S" val tag end (plist-get map tag))
   9705              (setq continue (not (> val 0)))
   9706              ) ;unless
   9707                                         ;(message "pos=%S tag=%S val=%S end=%S void=%S" (point) tag val end void)
   9708            ) ;while
   9709          (cond
   9710            ((> val 0)
   9711             ;;(message "point=%S" (point))
   9712             ;;(goto-char (1+ beg))
   9713             ;;(forward-char)
   9714             ;;(re-search-forward "[[:space:]]*")
   9715             (setq offset (+ (current-indentation) web-mode-markup-indent-offset)))
   9716            (t
   9717             (setq offset (current-indentation)))
   9718            )
   9719          ) ;t
   9720         ) ;cond
   9721       offset)))
   9722 
   9723 (defun web-mode-token-css-indentation (pos)
   9724   (save-excursion
   9725     (goto-char pos)
   9726     (web-mode-part-token-beginning)
   9727     (+ web-mode-css-indent-offset (current-indentation))
   9728     ))
   9729 
   9730 (defun web-mode-relayql-indentation (pos &optional prefix)
   9731   (unless prefix (setq prefix "relayql"))
   9732   (let (beg offset level char)
   9733     (setq char (char-after))
   9734     (setq beg (web-mode-part-token-beginning-position pos))
   9735     (goto-char beg)
   9736     (cond
   9737       ((member char '(?\`))
   9738        (setq offset (current-indentation))
   9739        )
   9740       ((member char '(?\) ?\} ?\]))
   9741        (web-mode-go (web-mode-token-opening-paren-position pos beg prefix))
   9742        (setq offset (current-indentation))
   9743        )
   9744       ((setq level (web-mode-bracket-level pos beg))
   9745        (setq offset (+ level web-mode-code-indent-offset))
   9746        )
   9747       (t
   9748        (setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9749        )
   9750       )
   9751     offset))
   9752 
   9753 (defun web-mode-markup-indentation (pos)
   9754   (let (offset beg ret jsx-depth)
   9755     (when (and (setq jsx-depth (get-text-property pos 'jsx-depth))
   9756                (get-text-property pos 'jsx-beg)
   9757                (not (get-text-property pos 'tag-beg)))
   9758       (setq jsx-depth (1- jsx-depth)))
   9759     ;;(when (setq beg (web-mode-markup-indentation-origin pos jsx-depth))
   9760     (cond
   9761       ((not (setq beg (web-mode-markup-indentation-origin pos jsx-depth)))
   9762        (setq offset 0))
   9763       ((null (setq ret (web-mode-element-is-opened beg pos)))
   9764        (setq offset (web-mode-indentation-at-pos beg)))
   9765       ((eq ret t)
   9766        (setq offset (+ (web-mode-indentation-at-pos beg)
   9767                        web-mode-markup-indent-offset)))
   9768       (t
   9769        (setq offset ret))
   9770       ) ;cond
   9771     ;;(message "markup-indentation-origin=%S (jsx-depth=%S)" beg jsx-depth)
   9772     ;;) ;when beg
   9773     offset))
   9774 
   9775 (defun web-mode-css-indentation (pos initial-column language-offset language &optional limit)
   9776   (let ((open-ctx (web-mode-bracket-up pos language limit)) offset)
   9777     (cond
   9778       ((or (null open-ctx) (null (plist-get open-ctx :pos)))
   9779        (setq offset initial-column))
   9780       (t
   9781        (setq offset (+ (plist-get open-ctx :indentation) language-offset)))
   9782       ) ;cond
   9783     (cons (if (< offset initial-column) initial-column offset) open-ctx)
   9784     ))
   9785 
   9786 (defun web-mode-sql-indentation (pos initial-column language-offset language &optional limit)
   9787   (let ((open-ctx (web-mode-bracket-up pos language limit)) offset)
   9788     ;;(message "%S %S %S %S %S" pos (point) initial-column language-offset open-ctx)
   9789     (cond
   9790       ((and (not (null open-ctx)) (not (null (plist-get open-ctx :pos))))
   9791        (setq offset (+ (plist-get open-ctx :column) 1)))
   9792       ((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\\)")
   9793        (setq offset initial-column))
   9794       (t
   9795        (setq offset (+ initial-column language-offset)))
   9796       ) ;cond
   9797     (cons (if (< offset initial-column) initial-column offset) open-ctx)
   9798     ))
   9799 
   9800 (defun web-mode-markdown-indentation (pos initial-column _language-offset _language &optional _limit)
   9801   (let (offset)
   9802     (save-excursion
   9803       (goto-char pos)
   9804       (setq offset (current-column))
   9805       ) ;save-excursion
   9806     ;;(message "%S %S %S %S" pos (point) initial-column language-offset)
   9807     (cons (if (<= offset initial-column) initial-column offset) nil)))
   9808 
   9809 (defun web-mode-stylus-indentation (pos initial-column language-offset _language &optional _limit)
   9810   (let (offset)
   9811     (save-excursion
   9812       (goto-char pos)
   9813       (setq offset (current-column))
   9814       (if (looking-at-p "[[:alnum:]-]+:")
   9815           (setq offset (+ initial-column language-offset))
   9816           (setq offset initial-column))
   9817       ) ;save-excursion
   9818     ;;(message "%S %S %S %S" pos (point) initial-column language-offset)
   9819     (cons (if (<= offset initial-column) initial-column offset) nil)))
   9820 
   9821 (defun web-mode-sass-indentation (pos initial-column language-offset _language &optional _limit)
   9822   (let (offset)
   9823     (save-excursion
   9824       (goto-char pos)
   9825       (setq offset (current-column))
   9826       (if (looking-at-p "[[:alnum:]-]+:")
   9827           (setq offset (+ initial-column language-offset))
   9828           (setq offset initial-column))
   9829       ) ;save-excursion
   9830     ;;(message "%S %S %S %S" pos (point) initial-column language-offset)
   9831     (cons (if (<= offset initial-column) initial-column offset) nil)))
   9832 
   9833 (defun web-mode-pug-indentation (_pos _initial-column _language-offset _language &optional _limit)
   9834   nil
   9835   )
   9836 
   9837 (defun web-mode-javascript-indentation (pos initial-column language-offset language &optional limit)
   9838   (let (open-ctx open-pos indentation offset sub block-pos)
   9839     (setq open-ctx (web-mode-bracket-up pos language limit))
   9840     ;;(message "%S" open-ctx)
   9841     ;;(message "pos(%S) initial-column(%S) language-offset(%S) language(%S) limit(%S)" pos initial-column language-offset language limit)
   9842     ;;(message "javascript-indentation: %S\nchar=%c" open-ctx (plist-get open-ctx :char))
   9843     (setq indentation (plist-get open-ctx :indentation))
   9844     (when (and initial-column (> initial-column indentation))
   9845       (setq indentation initial-column))
   9846     (setq case-fold-search nil) ;#1006
   9847     (when open-ctx
   9848       (setq open-pos (plist-get open-ctx :pos)))
   9849     (setq block-pos (web-mode-inside-block-control pos))
   9850     (when (and block-pos (> limit block-pos)) ;#1275
   9851       (setq block-pos nil))
   9852     ;;(message "bracket-pos=%S block-pos=%S" open-pos block-pos)
   9853     (cond
   9854       ((and block-pos (or (null open-pos) (> block-pos open-pos))) ;#1230
   9855        (setq offset (+ indentation language-offset)))
   9856       ((null open-pos)
   9857        (setq offset initial-column))
   9858       ((and (member language '("javascript" "jsx" "ejs"))
   9859             (eq (plist-get open-ctx :char) ?\{)
   9860             (web-mode-looking-back "switch[ ]*" (plist-get open-ctx :pos)))
   9861        (setq sub (if (cdr (assoc "case-extra-offset" web-mode-indentation-params)) 0 1))
   9862        (cond
   9863          ((looking-at-p "case\\|default")
   9864           (setq offset (+ indentation (* language-offset (- 1 sub)))))
   9865          (t
   9866           (setq offset (+ indentation (* language-offset (- 2 sub)))))
   9867          ) ;cond switch
   9868        )
   9869       (t
   9870        (setq offset (+ indentation language-offset)))
   9871       ) ;cond
   9872     (setq case-fold-search t)
   9873     (cons (if (< offset initial-column) initial-column offset) open-ctx)
   9874     ))
   9875 
   9876 (defun web-mode-bracket-indentation (pos initial-column language-offset language &optional limit)
   9877   (save-excursion
   9878     (let* ((ctx (web-mode-bracket-up pos language limit))
   9879            (char (plist-get ctx :char))
   9880            (pos (plist-get ctx :pos))
   9881            (indentation (plist-get ctx :indentation)))
   9882       ;;(message "pos(%S) initial-column(%S) language-offset(%S) language(%S) limit(%S)" pos initial-column language-offset language limit)
   9883       ;;(message "bracket-up: %S, %c" ctx char)
   9884       (cond
   9885         ((null pos)
   9886          (setq indentation initial-column))
   9887         ((and (member language '("php"))
   9888               (eq char ?\{)
   9889               (web-mode-looking-back "switch[ ]*" pos)
   9890               (not (looking-at-p "case\\|default")))
   9891          (setq indentation (+ indentation (* language-offset 2)))
   9892          )
   9893         ((and (member language '("php"))
   9894               (eq char ?\{)
   9895               (goto-char pos)
   9896               (web-mode-looking-back "[)][ ]*" pos)
   9897               (search-backward ")")
   9898               (web-mode-block-opening-paren limit))
   9899          (setq indentation (+ (current-indentation) language-offset))
   9900          )
   9901         (t
   9902          (setq indentation (+ indentation language-offset))
   9903          )
   9904         ) ;cond
   9905       (cons (if (< indentation initial-column) initial-column indentation) ctx)
   9906       )))
   9907 
   9908 (defun web-mode-ruby-indentation (pos line initial-column language-offset limit)
   9909   (unless limit (setq limit nil))
   9910   (let (h offset prev-line prev-indentation open-ctx)
   9911     (setq open-ctx (web-mode-bracket-up pos "ruby" limit))
   9912     ;;(message "%S" open-ctx)
   9913     (if (plist-get open-ctx :pos)
   9914         (cond
   9915           ((web-mode-looking-at-p ".[ \t\n]+" (plist-get open-ctx :pos))
   9916            (setq offset (+ (plist-get open-ctx :indentation) language-offset)))
   9917           (t
   9918            (setq offset (1+ (plist-get open-ctx :column))))
   9919           )
   9920         (setq h (web-mode-previous-line pos limit))
   9921         (setq offset initial-column)
   9922         (when h
   9923           (setq prev-line (car h))
   9924           (setq prev-indentation (cdr h))
   9925           (cond
   9926             ((string-match-p ",$" prev-line)
   9927              (save-excursion
   9928                (goto-char limit)
   9929                (looking-at "<%=? [a-z_]+ ")
   9930                (setq offset (+ initial-column (length (match-string-no-properties 0))))
   9931                ) ;save-excursion
   9932              )
   9933             ((string-match-p "^[ ]*\\(end\\|else\\|elsif\\|when\\)" line)
   9934              (setq offset (- prev-indentation language-offset))
   9935              )
   9936             ((string-match-p "[ ]+\\(do\\)" prev-line)
   9937              (setq offset (+ prev-indentation language-offset))
   9938              )
   9939             ((string-match-p "^[ ]*\\(when\\|if\\|else\\|elsif\\|unless\\|for\\|while\\|def\\|class\\)" prev-line)
   9940              (setq offset (+ prev-indentation language-offset))
   9941              )
   9942             (t
   9943              (setq offset prev-indentation)
   9944              )
   9945             )
   9946           ) ;when
   9947         ) ;if
   9948     offset))
   9949 
   9950 (defun web-mode-python-indentation (pos line initial-column language-offset limit)
   9951   (unless limit (setq limit nil))
   9952   (let (h offset prev-line prev-indentation ctx)
   9953     (setq ctx (web-mode-bracket-up pos "python" limit))
   9954     ;;(message "point-ctx=%S" ctx)
   9955     (if (plist-get ctx :pos)
   9956         (cond
   9957           ((web-mode-looking-at-p ".[ \t\n]+" (plist-get ctx :pos))
   9958            (setq offset (+ (plist-get ctx :indentation) language-offset)))
   9959           (t
   9960            (setq offset (1+ (plist-get ctx :column))))
   9961           )
   9962         ;; else
   9963         (setq h (web-mode-previous-line pos limit))
   9964         (setq offset initial-column)
   9965         (when h
   9966           (setq prev-line (car h))
   9967           (setq prev-indentation (cdr h))
   9968           (cond
   9969             ((string-match-p "^\\(pass\\|else\\|elif\\|when\\|except\\)" line)
   9970              (setq offset (- prev-indentation language-offset))
   9971              )
   9972             ((string-match-p "\\(if\\|else\\|elif\\|for\\|while\\|try\\|except\\)" prev-line)
   9973              (setq offset (+ prev-indentation language-offset))
   9974              )
   9975             (t
   9976              (setq offset prev-indentation)
   9977              )
   9978             ) ;cond
   9979           ) ;when
   9980         ) ;if
   9981     ;;offset
   9982     (if (< offset initial-column) initial-column offset)
   9983     ))
   9984 
   9985 (defun web-mode-lisp-indentation (pos point-ctx)
   9986   (let (offset open-ctx)
   9987     (setq open-ctx (web-mode-bracket-up pos "lsp" (plist-get point-ctx :reg-beg)))
   9988     ;;(message "point-ctx=%S" point-ctx)
   9989     ;;(message "open-ctx=%S" open-ctx)
   9990     (cond
   9991       ((null (plist-get open-ctx :pos))
   9992        (setq offset (plist-get point-ctx :reg-col)))
   9993       ((member (plist-get point-ctx :curr-char) '(?\( ?\)))
   9994        (if (web-mode-looking-at-p "((" (plist-get open-ctx :pos))
   9995            (setq offset (+ (plist-get open-ctx :column) 1))
   9996            (setq offset (+ (plist-get open-ctx :column) web-mode-code-indent-offset)))
   9997        )
   9998       (t
   9999        (goto-char (plist-get open-ctx :pos))
  10000        (forward-char)
  10001        (web-mode-rsf "[[:alnum:]-:]+ ")
  10002        (setq offset (current-column))
  10003        )
  10004       ) ;cond
  10005     offset))
  10006 
  10007 (defun web-mode-asp-indentation (pos line initial-column language-offset limit)
  10008   (unless limit (setq limit nil))
  10009   (let (h out prev-line prev-indentation)
  10010     (setq h (web-mode-previous-line pos limit))
  10011     (setq out initial-column)
  10012     (when h
  10013       (setq prev-line (car h))
  10014       (setq prev-indentation (cdr h))
  10015       ;;(message "line=%S" line)
  10016       (cond
  10017         ((string-match-p "'" line)
  10018          (setq out prev-indentation))
  10019         ;; ----------------------------------------------------------------------
  10020         ;; unindent
  10021         ((string-match-p "\\_<\\(\\(end \\(if\\|function\\|class\\|sub\\|with\\)\\)\\|else\\|elseif\\|next\\|loop\\)\\_>" line)
  10022          (setq out (- prev-indentation language-offset)))
  10023         ;; ----------------------------------------------------------------------
  10024         ;; select case statement
  10025         ((string-match-p "\\_<\\(select case\\)\\_>" line)
  10026          (setq out (- prev-indentation 0)))
  10027         ((string-match-p "\\_<\\(end select\\)" line)
  10028          (setq out (- prev-indentation (* 2 language-offset))))
  10029         ((and (string-match-p "\\_<\\(case\\)\\_>" line) (not (string-match-p "\\_<\\(select case\\)\\_>" prev-line)))
  10030          (setq out (- prev-indentation language-offset)))
  10031         ;; ----------------------------------------------------------------------
  10032         ;; do nothing
  10033         ((string-match-p "\\_<\\(\\(end \\(if\\|function\\|class\\|sub\\|select\\|with\\)\\)\\|loop\\( until\\| while\\)?\\)\\_>" prev-line)
  10034          (setq out (+ prev-indentation 0)))
  10035         ;; indent
  10036         ((string-match-p "\\_<\\(\\(select \\)?case\\|else\\|elseif\\|unless\\|for\\|class\\|with\\|do\\( until\\| while\\)?\\|while\\|\\(public \\|private \\)?\\(function\\|sub\\|class\\)\\)\\_>" prev-line)
  10037          (setq out (+ prev-indentation language-offset)))
  10038         ;; single line if statement
  10039         ((string-match-p "\\_<if\\_>.*\\_<then\\_>[ \t]*[[:alpha:]]+" prev-line)
  10040          (setq out (+ prev-indentation 0)))
  10041         ;; normal if statement
  10042         ((string-match-p "\\_<\\if\\_>" prev-line)
  10043          (setq out (+ prev-indentation language-offset)))
  10044         (t
  10045          (setq out prev-indentation))
  10046         )
  10047       ) ;when
  10048     out))
  10049 
  10050 (defun web-mode-block-previous-live-line ()
  10051   (save-excursion
  10052     (let ((continue t) (line "") (pos (point)))
  10053       (beginning-of-line)
  10054       (while (and continue (not (bobp)) (forward-line -1))
  10055         (when (not (web-mode-block-is-token-line))
  10056           (setq line (web-mode-trim (buffer-substring (point) (line-end-position)))))
  10057         (when (not (string= line ""))
  10058           (setq continue nil))
  10059         ) ;while
  10060       (if (string= line "")
  10061           (progn (goto-char pos) nil)
  10062           (cons line (current-indentation)))
  10063       )))
  10064 
  10065 (defun web-mode-part-is-opener (pos reg-beg)
  10066   (save-excursion
  10067     (save-match-data
  10068       (if (and pos
  10069                (web-mode-go (web-mode-part-opening-paren-position pos))
  10070                (>= (point) reg-beg)
  10071                (looking-back "\\(^\\|[ \t]\\)\\(if\\|for\\|while\\)[ ]*" (point-min)))
  10072           (current-indentation)
  10073           nil)
  10074       )))
  10075 
  10076 (defun web-mode-part-previous-live-line (reg-beg)
  10077   (unless reg-beg (setq reg-beg (point-min)))
  10078   ;;(message "reg-beg=%S" reg-beg)
  10079   (save-excursion
  10080     (let ((continue (> (point) reg-beg))
  10081           (line "")
  10082           bol-pos
  10083           eol-pos
  10084           pos)
  10085       (beginning-of-line)
  10086       (while (and continue (> (point) reg-beg) (forward-line -1))
  10087         (setq bol-pos (point)
  10088               eol-pos (line-end-position))
  10089         (when (> reg-beg bol-pos)
  10090           (setq bol-pos reg-beg))
  10091         (when (not (web-mode-part-is-token-line bol-pos))
  10092           (setq line (web-mode-trim (buffer-substring bol-pos eol-pos)))
  10093           (when (not (string= line "")) (setq continue nil))
  10094           ) ;when
  10095         ) ;while
  10096       (cond
  10097         ((string= line "")
  10098          nil)
  10099         (t
  10100          (setq continue t)
  10101          (setq pos (1- eol-pos))
  10102          (while (and (>= pos bol-pos) continue)
  10103            (cond
  10104              ((eq (char-after pos) ?\s)
  10105               (setq pos (1- pos)))
  10106              ((get-text-property pos 'part-token)
  10107               (setq pos (1- pos)))
  10108              (t
  10109               (setq continue nil))
  10110              ) ;cond
  10111            ) ;while
  10112          ;;(message "%S %S : %S" bol-pos eol-pos pos)
  10113          (setq line (web-mode-clean-part-line line))
  10114          (list line (current-indentation) pos))
  10115         ) ;cond
  10116       )))
  10117 
  10118 (defun web-mode-in-code-block (open close &optional prop)
  10119   (save-excursion
  10120     (let ((pos (point)) pos-open pos-close start end ret)
  10121       (when prop
  10122         (setq start pos
  10123               end pos)
  10124         (when (eq (get-text-property pos prop) (get-text-property (1- pos) prop))
  10125           (setq start (or (previous-single-property-change pos prop) (point-min))))
  10126         (when (eq (get-text-property pos prop) (get-text-property (1+ pos) prop))
  10127           (setq end (next-single-property-change pos prop)))
  10128         ;;        (message "start(%S) end(%S)" start end)
  10129         )
  10130       (setq ret (and (web-mode-sb open start t)
  10131                      (setq pos-open (point))
  10132                      (web-mode-sf close end t)
  10133                      (setq pos-close (point))
  10134                      (>= pos-close pos)))
  10135       (if ret
  10136           (cons pos-open pos-close)
  10137           ret)
  10138       )))
  10139 
  10140 (defun web-mode-clean-part-line (input)
  10141   (let ((out "")
  10142         (beg 0)
  10143         (keep t)
  10144         (n (length input)))
  10145     (dotimes (i n)
  10146       (if (or (get-text-property i 'block-side input)
  10147               (eq (get-text-property i 'part-token input) 'comment)
  10148               (eq (get-text-property i 'tag-type input) 'comment))
  10149           (when keep
  10150             (setq out (concat out (substring input beg i))
  10151                   beg 0
  10152                   keep nil))
  10153           (when (null keep)
  10154             (setq beg i
  10155                   keep t))
  10156           ) ;if
  10157       ) ;dotimes
  10158     (if (> beg 0) (setq out (concat out (substring input beg n))))
  10159     (setq out (if (= (length out) 0) input out))
  10160     (web-mode-trim out)
  10161     ))
  10162 
  10163 (defun web-mode-clean-block-line (input)
  10164   (let ((out "")
  10165         (beg 0)
  10166         (keep t)
  10167         (n (length input)))
  10168     (dotimes (i n)
  10169       (if (or (not (get-text-property i 'block-side input))
  10170               (member (get-text-property i 'block-token input)
  10171                       '(comment delimiter-beg delimiter-end)))
  10172           (when keep
  10173             (setq out (concat out (substring input beg i))
  10174                   beg 0
  10175                   keep nil))
  10176           (when (null keep)
  10177             (setq beg i
  10178                   keep t))
  10179           ) ;if
  10180       ) ;dotimes
  10181     (if (> beg 0) (setq out (concat out (substring input beg n))))
  10182     (setq out (if (= (length out) 0) input out))
  10183     (web-mode-trim out)
  10184     ;;    (message "%S [%s] > [%s]" beg input out)
  10185     ))
  10186 
  10187 (defun web-mode-language-at-pos (&optional pos)
  10188   (unless pos (setq pos (point)))
  10189   (cond
  10190     ((get-text-property pos 'block-side)
  10191      web-mode-engine)
  10192     ((get-text-property pos 'part-side)
  10193      (symbol-name (get-text-property pos 'part-side)))
  10194     (t
  10195      web-mode-content-type)
  10196     ) ;cond
  10197   )
  10198 
  10199 (defun web-mode-coord-position (line column)
  10200   (save-excursion
  10201     (when (stringp line) (setq line (string-to-number line)))
  10202     (when (stringp column) (setq column (string-to-number column)))
  10203     (goto-char (point-min))
  10204     (forward-line (1- line))
  10205     (move-to-column (1- column))
  10206     (point)))
  10207 
  10208 (defun web-mode-is-single-line-block (pos)
  10209   (= (web-mode-line-number (web-mode-block-beginning-position pos))
  10210      (web-mode-line-number (web-mode-block-end-position pos))))
  10211 
  10212 (defun web-mode-line-number (&optional pos)
  10213   (setq pos (or pos (point)))
  10214   (+ (count-lines 1 pos) (if (= (web-mode-column-at-pos pos) 0) 1 0)))
  10215 
  10216 (defun web-mode-block-is-control (pos)
  10217   (save-excursion
  10218     (let (control state controls pair)
  10219       (goto-char pos)
  10220       (setq controls (web-mode-block-controls-get pos))
  10221       (setq pair (car controls))
  10222       (cond
  10223         ((eq (car pair) 'inside)
  10224          )
  10225         ((eq (car pair) 'open)
  10226          (setq state t
  10227                control (cdr pair)))
  10228         ((eq (car pair) 'close)
  10229          (setq state nil
  10230                control (cdr pair)))
  10231         ) ;cond
  10232       ;;      (message "engine=%S control=%S state=%S" web-mode-engine control state)
  10233       (if control (cons control state) nil)
  10234       )))
  10235 
  10236 (defun web-mode-block-is-opening-control (pos)
  10237   (save-excursion
  10238     (let (controls pair)
  10239       (goto-char pos)
  10240       (if (and (setq controls (web-mode-block-controls-get pos))
  10241                (= (length controls) 1)
  10242                (setq pair (car controls))
  10243                (eq (car pair) 'open))
  10244           (cdr pair)
  10245           nil)
  10246       )))
  10247 
  10248 (defun web-mode-markup-indentation-origin (pos jsx-depth)
  10249   (save-excursion
  10250     (let* ((found (bobp))
  10251            (jsx-beg nil)
  10252            (types '(start end void))
  10253            (type nil))
  10254       (when jsx-depth
  10255         (setq jsx-beg (web-mode-jsx-depth-beginning-position pos jsx-depth)))
  10256       (while (not found)
  10257         (forward-line -1)
  10258         (if (bobp)
  10259             (setq pos (point)
  10260                   found t)
  10261             (back-to-indentation)
  10262             (when (and jsx-beg (< (point) jsx-beg))
  10263               (goto-char jsx-beg))
  10264             (setq pos (point))
  10265             (setq type (get-text-property pos 'tag-type))
  10266             (setq found (or (and (null jsx-depth)
  10267                                  (null (get-text-property pos 'part-side))
  10268                                  (get-text-property pos 'tag-beg)
  10269                                  (member type types)
  10270                                  (null (get-text-property (1- pos) 'invisible)))
  10271                             (and (null jsx-depth)
  10272                                  (null (get-text-property pos 'part-side))
  10273                                  (eq (get-text-property pos 'tag-type) 'comment)
  10274                                  (web-mode-looking-at-p "<!--#\\(endif\\|if\\)" pos)
  10275                                  (null (get-text-property (1- pos) 'invisible)))
  10276                             (and jsx-depth
  10277                                  (get-text-property pos 'tag-beg)
  10278                                  (member type types)
  10279                                  (null (get-text-property (1- pos) 'invisible))
  10280                                  (eq (get-text-property pos 'jsx-depth) jsx-depth))
  10281                             (and (get-text-property pos 'block-beg)
  10282                                  (not type)
  10283                                  (web-mode-block-is-control pos)
  10284                                  (not (looking-at-p "{% commen\\|@break")))))
  10285             ) ;if
  10286         ) ;while
  10287       ;;(message "indent-origin=%S" pos)
  10288       pos)))
  10289 
  10290 ;;TODO : prendre en compte part-token
  10291 ;; state=t <=> start tag
  10292 (defun web-mode-element-is-opened (pos limit)
  10293   (let (tag
  10294         last-end-tag
  10295         tag-pos block-pos
  10296         state
  10297         n
  10298         ret
  10299         (continue t)
  10300         controls
  10301         (h (make-hash-table :test 'equal))
  10302         (h2 (make-hash-table :test 'equal)))
  10303 
  10304     ;;    (message "pos-ori=%S limit=%S" pos limit)
  10305 
  10306     (while continue
  10307       (setq controls nil
  10308             last-end-tag nil
  10309             tag nil)
  10310 
  10311       (cond
  10312         ((and (eq (get-text-property pos 'tag-type) 'comment)
  10313               (web-mode-looking-at "<!--#\\(endif\\|if\\)" pos))
  10314          ;;(message "pos=%S" pos)
  10315          (setq tag "#if")
  10316          (setq n (gethash tag h 0))
  10317          (if (string= (match-string-no-properties 1) "if")
  10318              (puthash tag (1+ n) h)
  10319              (puthash tag (1- n) h))
  10320          ;;(setq tag-pos pos)
  10321          )
  10322         ((get-text-property pos 'tag-beg)
  10323          (when (member (get-text-property pos 'tag-type) '(start end))
  10324            (setq tag (get-text-property pos 'tag-name)
  10325                  state (eq (get-text-property pos 'tag-type) 'start))
  10326            (if (null state) (setq last-end-tag (cons tag pos)))
  10327            (setq n (gethash tag h 0))
  10328            (cond
  10329              ((null state)
  10330               (when (> n 0) (puthash tag (1- n) h))
  10331               (puthash tag (1- n) h2))
  10332              ((member tag web-mode-offsetless-elements)
  10333               )
  10334              (t
  10335               (puthash tag (1+ n) h)
  10336               (puthash tag (1+ n) h2))
  10337              ) ;cond
  10338            ) ;when
  10339          (when (setq pos (web-mode-tag-end-position pos))
  10340            (setq tag-pos nil)
  10341            (when (and block-pos (> pos block-pos))
  10342              (setq block-pos nil))
  10343            ) ;when
  10344          )
  10345         ((and web-mode-enable-control-block-indentation
  10346               (get-text-property pos 'block-beg))
  10347          (when (setq controls (web-mode-block-controls-get pos))
  10348            (dolist (control controls)
  10349              (setq tag (cdr control))
  10350              (setq n (gethash tag h 0))
  10351              (cond
  10352                ((eq (car control) 'inside)
  10353                 )
  10354                ((eq (car control) 'open)
  10355                 (puthash tag (1+ n) h))
  10356                ((> n 0)
  10357                 (puthash tag (1- n) h))
  10358                ) ;cond
  10359              ) ;dolist
  10360            )
  10361          (when (setq pos (web-mode-block-end-position pos))
  10362            (setq block-pos nil)
  10363            (when (and tag-pos (> pos tag-pos))
  10364              (setq tag-pos nil))
  10365            )
  10366          )
  10367         ) ;cond
  10368 
  10369       ;;      (message "tag=%S end-pos=%S" tag pos)
  10370 
  10371       (when (and pos (< pos limit))
  10372         (when (or (null tag-pos) (>= pos tag-pos))
  10373           (setq tag-pos (web-mode-tag-next-position pos limit))
  10374           ;;          (message "from=%S tag-next-pos=%S" pos tag-pos)
  10375           )
  10376         (when (or (null block-pos) (>= pos block-pos))
  10377           (setq block-pos (web-mode-block-next-position pos limit))
  10378           ;;          (message "from=%S block-next-pos=%S" pos block-pos)
  10379           )
  10380         )
  10381 
  10382       (cond
  10383         ((null pos)
  10384          )
  10385         ((and (null tag-pos)
  10386               (null block-pos))
  10387          (setq pos nil))
  10388         ((and tag-pos block-pos)
  10389          (if (< tag-pos block-pos)
  10390              (progn
  10391                (setq pos tag-pos)
  10392                (setq tag-pos nil))
  10393              (setq pos block-pos)
  10394              (setq block-pos nil))
  10395          )
  10396         ((null tag-pos)
  10397          (setq pos block-pos)
  10398          (setq block-pos nil))
  10399         (t
  10400          (setq pos tag-pos)
  10401          (setq tag-pos nil))
  10402         )
  10403 
  10404       (when (or (null pos)
  10405                 (>= pos limit))
  10406         (setq continue nil))
  10407       ) ;while
  10408 
  10409     ;;(message "hashtable=%S" h)
  10410     (maphash (lambda (_k v) (if (> v 0) (setq ret t))) h)
  10411 
  10412     (when (and (null ret)
  10413                last-end-tag
  10414                (> (hash-table-count h2) 1)
  10415                (< (gethash (car last-end-tag) h2) 0))
  10416       ;;      (message "last-end-tag=%S" last-end-tag)
  10417       (save-excursion
  10418         (goto-char (cdr last-end-tag))
  10419         (web-mode-tag-match)
  10420         (when (not (= (point) (cdr last-end-tag)))
  10421           (setq n (point))
  10422           (back-to-indentation)
  10423           (if (= n (point)) (setq ret (current-indentation))))
  10424         ))
  10425 
  10426     ret))
  10427 
  10428 (defun web-mode-previous-line (pos limit)
  10429   (save-excursion
  10430     (let (beg end line (continue t))
  10431       (goto-char pos)
  10432       (while continue
  10433         (forward-line -1)
  10434         (setq end (line-end-position))
  10435         (setq line (buffer-substring-no-properties (point) end))
  10436         (when (or (not (string-match-p "^[ \t]*$" line))
  10437                   (bobp)
  10438                   (<= (point) limit))
  10439           (setq continue nil))
  10440         )
  10441       (if (<= (point) limit)
  10442           ;;todo : affiner (le + 3 n est pas générique cf. <?php <% <%- etc.)
  10443           (setq beg (if (< (+ limit 3) end) (+ limit 3) end))
  10444           (setq beg (line-beginning-position))
  10445           ) ;if
  10446       (setq line (buffer-substring-no-properties beg end))
  10447       (cons line (current-indentation))
  10448       )))
  10449 
  10450 (defun web-mode-bracket-up (pos _language &optional limit)
  10451   (unless limit (setq limit nil))
  10452   ;;(message "pos(%S) language(%S) limit(%S)" pos language limit)
  10453   (save-excursion
  10454     (goto-char pos)
  10455     (let ((continue t)
  10456           (regexp "[\]\[}{)(]")
  10457           (char nil)
  10458           (column nil)
  10459           (indentation nil)
  10460           (map nil)
  10461           (key nil)
  10462           (value 0)
  10463           (open '(?\( ?\{ ?\[))
  10464           (searcher nil)
  10465           (opener nil))
  10466       (cond
  10467         ((get-text-property pos 'block-side)
  10468          (setq searcher 'web-mode-block-rsb
  10469                opener 'web-mode-block-opening-paren-position))
  10470         (t
  10471          (setq searcher 'web-mode-part-rsb
  10472                opener 'web-mode-part-opening-paren-position))
  10473         )
  10474       (while (and continue (funcall searcher regexp limit))
  10475         (setq char (aref (match-string-no-properties 0) 0))
  10476         (setq key (cond ((eq char ?\)) ?\()
  10477                         ((eq char ?\}) ?\{)
  10478                         ((eq char ?\]) ?\[)
  10479                         (t             char)))
  10480         (setq value (or (plist-get map key) 0))
  10481         (setq value (if (member char open) (1+ value) (1- value)))
  10482         (setq map (plist-put map key value))
  10483         (setq continue (< value 1))
  10484         ;;(message "pos=%S char=%c key=%c value=%S map=%S" (point) char key value map)
  10485         ) ;while
  10486       (setq column (current-column)
  10487             indentation (current-indentation))
  10488       (when (and (> value 0)
  10489                  (eq char ?\{)
  10490                  (looking-back ")[ ]*" (point-min)))
  10491         (search-backward ")")
  10492         (when (setq pos (funcall opener (point) limit))
  10493           (goto-char pos)
  10494           ;;(message "pos=%S" pos)
  10495           (setq indentation (current-indentation)))
  10496         ) ;when
  10497       (list :pos (if (> value 0) (point) nil)
  10498             :char char
  10499             :column column
  10500             :indentation indentation)
  10501       ) ;let
  10502     ))
  10503 
  10504 (defun web-mode-count-char-in-string (char string)
  10505   (let ((n 0))
  10506     (dotimes (i (length string))
  10507       (if (eq (elt string i) char)
  10508           (setq n (1+ n))))
  10509     n))
  10510 
  10511 (defun web-mode-mark-and-expand ()
  10512   "Mark and expand."
  10513   (interactive)
  10514   (web-mode-mark (point)))
  10515 
  10516 (defun web-mode-mark (pos)
  10517   (let ((beg pos) (end pos) boundaries)
  10518 
  10519     (if mark-active
  10520         (setq web-mode-expand-initial-pos (point)
  10521               web-mode-expand-initial-scroll (window-start))
  10522         )
  10523 
  10524     ;; (message "regs=%S %S %S %S" (region-beginning) (region-end) (point-min) (point-max))
  10525     ;; (message "before=%S" web-mode-expand-previous-state)
  10526 
  10527     (cond
  10528 
  10529       ((and mark-active
  10530             (= (region-beginning) (point-min))
  10531             (or (= (region-end) (point-max))
  10532                 (= (1+ (region-end)) (point-max))))
  10533        (deactivate-mark)
  10534        (goto-char (or web-mode-expand-initial-pos (point-min)))
  10535        (setq web-mode-expand-previous-state nil)
  10536        (when web-mode-expand-initial-scroll
  10537          (set-window-start (selected-window) web-mode-expand-initial-scroll))
  10538        )
  10539 
  10540       ((string= web-mode-expand-previous-state "elt-content")
  10541        (web-mode-element-parent)
  10542        ;;(message "pos=%S" (point))
  10543        (web-mode-element-select)
  10544        (setq web-mode-expand-previous-state "html-parent"))
  10545 
  10546       ((and (member (get-text-property pos 'block-token) '(comment string))
  10547             (not (member web-mode-expand-previous-state '("block-token" "block-body" "block-side"))))
  10548        (when (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token))
  10549          (setq beg (or (previous-single-property-change pos 'block-token) (point-min))))
  10550        (when (eq (get-text-property pos 'block-token) (get-text-property (1+ pos) 'block-token))
  10551          (setq end (next-single-property-change pos 'block-token)))
  10552        (set-mark beg)
  10553        (goto-char end)
  10554        (exchange-point-and-mark)
  10555        (setq web-mode-expand-previous-state "block-token"))
  10556 
  10557       ((and (get-text-property pos 'block-side)
  10558             (not (member web-mode-expand-previous-state '("block-body" "block-side")))
  10559             (not (member web-mode-engine '(django go)))
  10560             (setq boundaries (web-mode-in-code-block "{" "}" 'block-side)))
  10561        (set-mark (car boundaries))
  10562        (goto-char (cdr boundaries))
  10563        (exchange-point-and-mark)
  10564        (setq web-mode-expand-previous-state "block-body"))
  10565 
  10566       ((and (get-text-property pos 'block-side)
  10567             (not (member web-mode-expand-previous-state '("block-side"))))
  10568        (set-mark (web-mode-block-beginning-position pos))
  10569        (goto-char (1+ (web-mode-block-end-position pos)))
  10570        (exchange-point-and-mark)
  10571        (setq web-mode-expand-previous-state "block-side"))
  10572 
  10573       ((and (get-text-property pos 'part-token)
  10574             (not (string= web-mode-expand-previous-state "part-token")))
  10575        (when (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token))
  10576          (setq beg (previous-single-property-change pos 'part-token)))
  10577        (when (eq (get-text-property pos 'part-token) (get-text-property (1+ pos) 'part-token))
  10578          (setq end (next-single-property-change pos 'part-token)))
  10579        (set-mark beg)
  10580        (goto-char end)
  10581        (exchange-point-and-mark)
  10582        (setq web-mode-expand-previous-state "part-token"))
  10583 
  10584       ((and (get-text-property pos 'part-side)
  10585             (not (string= web-mode-expand-previous-state "client-part"))
  10586             (setq boundaries (web-mode-in-code-block "{" "}" 'part-side)))
  10587        (set-mark (car boundaries))
  10588        (goto-char (cdr boundaries))
  10589        (exchange-point-and-mark)
  10590        (setq web-mode-expand-previous-state "client-part"))
  10591 
  10592       ((and (get-text-property pos 'part-side)
  10593             (not (string= web-mode-expand-previous-state "part-side")))
  10594        (when (eq (get-text-property pos 'part-side) (get-text-property (1- pos) 'part-side))
  10595          (setq beg (previous-single-property-change pos 'part-side)))
  10596        (when (eq (get-text-property pos 'part-side) (get-text-property (1+ pos) 'part-side))
  10597          (setq end (next-single-property-change pos 'part-side)))
  10598        (when (eq (char-after beg) ?\n)
  10599          (setq beg (1+ beg)))
  10600        (set-mark beg)
  10601        (goto-char end)
  10602        (when (looking-back "^[ \t]+" (point-min))
  10603          (beginning-of-line))
  10604        (exchange-point-and-mark)
  10605        (setq web-mode-expand-previous-state "part-side"))
  10606 
  10607       ((and (get-text-property pos 'tag-attr)
  10608             (not (member web-mode-expand-previous-state '("html-attr" "html-tag"))))
  10609        (web-mode-attribute-select pos)
  10610        (setq web-mode-expand-previous-state "html-attr"))
  10611 
  10612       ((and (eq (get-text-property pos 'tag-type) 'comment)
  10613             (not (member web-mode-expand-previous-state '("html-tag" "html-comment" "html-elt" "html-parent"))))
  10614        (web-mode-tag-select)
  10615        (setq web-mode-expand-previous-state "html-comment"))
  10616 
  10617       ((and (get-text-property pos 'tag-name)
  10618             (not (member web-mode-expand-previous-state '("html-tag" "html-elt" "html-parent"))))
  10619        (web-mode-tag-select)
  10620        (setq web-mode-expand-previous-state "html-tag"))
  10621 
  10622       ((and (get-text-property pos 'tag-beg)
  10623             (string= web-mode-expand-previous-state "html-tag"))
  10624        (web-mode-element-select)
  10625        (setq web-mode-expand-previous-state "html-elt"))
  10626 
  10627       (t
  10628        (cond
  10629          ((not (web-mode-element-parent))
  10630           (push-mark (point))
  10631           (push-mark (point-max) nil t)
  10632           (goto-char (point-min))
  10633           (setq web-mode-expand-previous-state "mark-whole"))
  10634          ((not (= (web-mode-tag-end-position (point)) (1- beg)))
  10635           (web-mode-element-content-select)
  10636           (setq web-mode-expand-previous-state "elt-content"))
  10637          (t
  10638           (web-mode-element-select)
  10639           (setq web-mode-expand-previous-state "html-parent"))
  10640          )
  10641        ) ;t
  10642 
  10643       ) ;cond
  10644 
  10645     ;;(message "w=%S" (window-end))
  10646     ;;(message "after=%S" web-mode-expand-previous-state)
  10647 
  10648     ))
  10649 
  10650 (defun web-mode-block-kill ()
  10651   "Kill the current block."
  10652   (interactive)
  10653   (web-mode-block-select)
  10654   (when mark-active
  10655     (kill-region (region-beginning) (region-end))))
  10656 
  10657 (defun web-mode-block-select ()
  10658   "Select the current block."
  10659   (interactive)
  10660   (let (beg)
  10661     (when (setq beg (web-mode-block-beginning-position (point)))
  10662       (goto-char beg)
  10663       (set-mark (point))
  10664       (web-mode-block-end)
  10665       (exchange-point-and-mark))
  10666     beg))
  10667 
  10668 (defun web-mode-tag-select ()
  10669   "Select the current html tag."
  10670   (interactive)
  10671   (let (beg)
  10672     (when (setq beg (web-mode-tag-beginning-position (point)))
  10673       (goto-char beg)
  10674       (set-mark (point))
  10675       (web-mode-tag-end)
  10676       (exchange-point-and-mark))
  10677     beg))
  10678 
  10679 (defun web-mode-element-content-select ()
  10680   "Select the content of a html element."
  10681   (interactive)
  10682   (let (pos end)
  10683     (web-mode-element-select)
  10684     (when mark-active
  10685       (setq pos (point))
  10686       (deactivate-mark)
  10687       (web-mode-tag-match)
  10688       (setq end (point))
  10689       (goto-char pos)
  10690       (web-mode-tag-end)
  10691       (set-mark (point))
  10692       (goto-char end)
  10693       (exchange-point-and-mark)
  10694       )))
  10695 
  10696 (defun web-mode-element-select ()
  10697   "Select the current html element (including opening and closing tags)."
  10698   (interactive)
  10699   (let* ((pos (point))
  10700          (type (get-text-property pos 'tag-type)))
  10701     (cond
  10702       ((not type)
  10703        (web-mode-element-parent)
  10704        (unless (= (point) pos) (web-mode-element-select)))
  10705       ((member type '(start void))
  10706        (web-mode-tag-beginning)
  10707        (set-mark (point))
  10708        (web-mode-tag-match)
  10709        (web-mode-tag-end)
  10710        (exchange-point-and-mark))
  10711       (t
  10712        (web-mode-tag-match)
  10713        (set-mark (point))
  10714        (web-mode-tag-match)
  10715        (web-mode-tag-end)
  10716        (exchange-point-and-mark))
  10717       )))
  10718 
  10719 (defun web-mode-element-is-collapsed (&optional pos)
  10720   (unless pos (setq pos (point)))
  10721   (let (boundaries)
  10722     (and (setq boundaries (web-mode-element-boundaries pos))
  10723          (or (= (car (car boundaries)) (car (cdr boundaries)))
  10724              (= (cdr (car boundaries)) (1- (car (cdr boundaries)))))
  10725          )))
  10726 
  10727 (defun web-mode-element-contract ()
  10728   "Flatten elements."
  10729   (interactive)
  10730   (let (beg end (continue t) replacement boundaries)
  10731     (cond
  10732       ((or (not (get-text-property (point) 'tag-type))
  10733            (not (member (get-text-property (point) 'tag-type) '(start end))))
  10734        (web-mode-element-parent))
  10735       ((eq (get-text-property (point) 'tag-type) 'end)
  10736        (web-mode-tag-match))
  10737       ) ;cond
  10738     (setq boundaries (web-mode-element-boundaries (point)))
  10739     (setq beg (car (car boundaries))
  10740           end (cdr (cdr boundaries)))
  10741     (goto-char beg)
  10742     ;;(message "beg(%S) end(%S)" beg end)
  10743     (while continue
  10744       (if (or (not (re-search-forward ">[ \t\r\n]+\\|[ \t\r\n]+<"))
  10745               (>= (point) end))
  10746           (setq continue nil)
  10747           (setq end (+ (- end (length (match-string-no-properties 0))) 1))
  10748           (setq replacement (if (eq (char-before) ?\<) "<" ">"))
  10749           (replace-match replacement nil nil)
  10750           ;;(message "end(%S)" end))
  10751           )
  10752       ) ;while
  10753     (goto-char beg)
  10754     ))
  10755 
  10756 (defun web-mode-element-extract ()
  10757   "Flatten element."
  10758   (interactive)
  10759   (let (beg end (continue t) save boundaries)
  10760     (cond
  10761       ((or (not (get-text-property (point) 'tag-type))
  10762            (not (member (get-text-property (point) 'tag-type) '(start end))))
  10763        (web-mode-element-parent))
  10764       ((eq (get-text-property (point) 'tag-type) 'end)
  10765        (web-mode-tag-match))
  10766       ) ;cond
  10767     (setq boundaries (web-mode-element-boundaries (point)))
  10768     (setq beg (car (car boundaries))
  10769           end (cdr (cdr boundaries)))
  10770     (goto-char beg)
  10771     (while continue
  10772       (if (or (not (and (or (get-text-property (point) 'tag-type) (web-mode-tag-next))
  10773                         (web-mode-tag-end)))
  10774               (>= (point) end))
  10775           (setq continue nil)
  10776           (setq save (point))
  10777           ;;(message "point(%S)" (point))
  10778           (skip-chars-forward "\n\t ")
  10779           (when (get-text-property (point) 'tag-type)
  10780             (newline)
  10781             (indent-according-to-mode)
  10782             (setq end (+ end (- (point) save))))
  10783           ) ;if
  10784       ) ;while
  10785     (goto-char beg)
  10786     ))
  10787 
  10788 (defun web-mode-element-transpose ()
  10789   "Transpose two html elements."
  10790   (interactive)
  10791   (let (pos start1 end1 start2 end2)
  10792     (save-excursion
  10793       (setq pos (point))
  10794       (cond
  10795         ((get-text-property pos 'tag-type)
  10796          (setq start1 (web-mode-element-beginning-position pos)
  10797                end1 (1+ (web-mode-element-end-position pos)))
  10798          )
  10799         ((setq start1 (web-mode-element-parent-position pos))
  10800          (setq end1 (1+ (web-mode-element-end-position pos)))
  10801          )
  10802         ) ;cond
  10803       (when (and start1 end1 (> end1 0))
  10804         (goto-char end1)
  10805         (unless (get-text-property (point) 'tag-beg)
  10806           (skip-chars-forward "\n\t "))
  10807         (when (get-text-property (point) 'tag-beg)
  10808           (setq start2 (web-mode-element-beginning-position (point))
  10809                 end2 (1+ (web-mode-element-end-position (point))))
  10810           )
  10811         )
  10812       (transpose-regions start1 end1 start2 end2)
  10813       ) ;save-excursion
  10814     start2))
  10815 
  10816 (defun web-mode-element-children-comment (&optional pos)
  10817   "Comment all the children of the current html element."
  10818   (interactive)
  10819   (unless pos (setq pos (point)))
  10820   (save-excursion
  10821     (dolist (child (reverse (web-mode-element-children pos)))
  10822       (goto-char child)
  10823       (web-mode-comment (point)))
  10824     ))
  10825 
  10826 (defun web-mode-element-mute-blanks ()
  10827   "Mute blanks."
  10828   (interactive)
  10829   (let (pos parent children elt)
  10830     (setq pos (point))
  10831     (save-excursion
  10832       (when (and (setq parent (web-mode-element-boundaries pos))
  10833                  (web-mode-element-child-position (point)))
  10834         (setq children (reverse (web-mode-element-children)))
  10835         (goto-char (car (cdr parent)))
  10836         (dolist (child children)
  10837           (setq elt (web-mode-element-boundaries child))
  10838           (when (> (point) (1+ (cddr elt)))
  10839             (when (and (not (eq (get-text-property (point) 'part-token) 'comment))
  10840                        (not (eq (get-text-property (1+ (cddr elt)) 'part-token) 'comment)))
  10841               (web-mode-insert-text-at-pos "-->" (point))
  10842               (web-mode-insert-text-at-pos "<!--" (1+ (cddr elt))))
  10843             )
  10844           (goto-char child)
  10845           )
  10846         (when (and (> (point) (1+ (cdr (car parent))))
  10847                    (not (eq (get-text-property (point) 'part-token) 'comment))
  10848                    (not (eq (get-text-property (1+ (cdr (car parent))) 'part-token) 'comment)))
  10849           (web-mode-insert-text-at-pos "-->" (point))
  10850           (web-mode-insert-text-at-pos "<!--" (1+ (cdr (car parent)))))
  10851         ) ;when
  10852       )))
  10853 
  10854 (defun web-mode-element-children (&optional pos)
  10855   (unless pos (setq pos (point)))
  10856   (let ((continue t) (i 0) child children)
  10857     (save-excursion
  10858       (when (and (member (get-text-property pos 'tag-type) '(start end))
  10859                  (setq child (web-mode-element-child-position pos)))
  10860         (while continue
  10861           (cond
  10862             ((> (setq i (1+ i)) 100)
  10863              (setq continue nil)
  10864              (message "element-children ** warning **"))
  10865             ((= i 1)
  10866              (goto-char child))
  10867             ((web-mode-element-sibling-next)
  10868              )
  10869             (t
  10870              (setq continue nil))
  10871             ) ;cond
  10872           (when continue
  10873             (setq children (append children (list (point)))))
  10874           ) ;while
  10875         ) ;when
  10876       ) ;save-excursion
  10877     ;;(message "%S" children)
  10878     children))
  10879 
  10880 (defun web-mode-property-boundaries (prop &optional pos)
  10881   "property boundaries (cdr is 1+)"
  10882   (unless pos (setq pos (point)))
  10883   (let (beg end val)
  10884     (setq val (get-text-property pos prop))
  10885     (if (null val)
  10886         val
  10887         (if (or (bobp)
  10888                 (not (eq (get-text-property (1- pos) prop) val)))
  10889             (setq beg pos)
  10890             (setq beg (previous-single-property-change pos prop))
  10891             (when (null beg) (setq beg (point-min))))
  10892         (if (or (eobp)
  10893                 (not (eq (get-text-property (1+ pos) prop) val)))
  10894             (setq end pos)
  10895             (setq end (next-single-property-change pos prop))
  10896             (when (null end) (setq end (point-min))))
  10897         (cons beg end))))
  10898 
  10899 (defun web-mode-content-boundaries (&optional pos)
  10900   (unless pos (setq pos (point)))
  10901   (let (beg end)
  10902     (setq beg (or (previous-property-change pos (current-buffer))
  10903                   (point-max)))
  10904     (setq end (or (next-property-change pos (current-buffer))
  10905                   (point-min)))
  10906     (while (and (< beg end) (member (char-after beg) '(?\s ?\n)))
  10907       (setq beg (1+ beg)))
  10908     (while (and (> end beg) (member (char-after (1- end)) '(?\s ?\n)))
  10909       (setq end (1- end)))
  10910     ;;    (message "beg(%S) end(%S)" beg end)
  10911     (cons beg end)
  10912     ))
  10913 
  10914 (defun web-mode-element-boundaries (&optional pos)
  10915   "Return ((start-tag-beg . start-tag-end) . (end-tag-beg . end-tag-end))
  10916 First level car and cdr are the same with void elements.
  10917 Pos should be in a tag."
  10918   (unless pos (setq pos (point)))
  10919   (let (start-tag-beg start-tag-end end-tag-beg end-tag-end)
  10920     (cond
  10921       ((eq (get-text-property pos 'tag-type) 'start)
  10922        (setq start-tag-beg (web-mode-tag-beginning-position pos)
  10923              start-tag-end (web-mode-tag-end-position pos))
  10924        (when (setq pos (web-mode-tag-match-position pos))
  10925          (setq end-tag-beg pos
  10926                end-tag-end (web-mode-tag-end-position pos)))
  10927        )
  10928       ((eq (get-text-property pos 'tag-type) 'end)
  10929        (setq end-tag-beg (web-mode-tag-beginning-position pos)
  10930              end-tag-end (web-mode-tag-end-position pos))
  10931        (when (setq pos (web-mode-tag-match-position pos))
  10932          (setq start-tag-beg pos
  10933                start-tag-end (web-mode-tag-end-position pos)))
  10934        )
  10935       ((eq (get-text-property pos 'tag-type) 'void)
  10936        (setq start-tag-beg (web-mode-tag-beginning-position pos)
  10937              start-tag-end (web-mode-tag-end-position pos))
  10938        (setq end-tag-beg start-tag-beg
  10939              end-tag-end start-tag-end)
  10940        )
  10941       ) ;cond
  10942     (if (and start-tag-beg start-tag-end end-tag-beg end-tag-end)
  10943         (cons (cons start-tag-beg start-tag-end) (cons end-tag-beg end-tag-end))
  10944         nil)
  10945     ))
  10946 
  10947 (defun web-mode-surround ()
  10948   "Surround each line of the current REGION with a start/end tag."
  10949   (interactive)
  10950   (when mark-active
  10951     (let (beg end line-beg line-end tag tag-start tag-end)
  10952       (save-excursion
  10953         (combine-after-change-calls
  10954           (setq tag (web-mode-element-complete)
  10955                 tag-start (concat "<" tag ">")
  10956                 tag-end (concat "</" tag ">")
  10957                 beg (region-beginning)
  10958                 end (region-end)
  10959                 line-beg (web-mode-line-number beg)
  10960                 line-end (web-mode-line-number end))
  10961           (goto-char end)
  10962           (unless (bolp)
  10963             (insert tag-end)
  10964             (back-to-indentation)
  10965             (when (> beg (point))
  10966               (goto-char beg))
  10967             (insert tag-start))
  10968           (while (> line-end line-beg)
  10969             (forward-line -1)
  10970             (setq line-end (1- line-end))
  10971             (unless (looking-at-p "[[:space:]]*$")
  10972               (end-of-line)
  10973               (insert tag-end)
  10974               (back-to-indentation)
  10975               (when (> beg (point))
  10976                 (goto-char beg))
  10977               (insert tag-start))
  10978             ) ;while
  10979           (deactivate-mark)
  10980           ) ;combine-after-change-calls
  10981         ) ;save-excursion
  10982       )))
  10983 
  10984 (defun web-mode-lify-region ()
  10985   "Transform current REGION in an html list (<li>line1</li>...)"
  10986   (interactive)
  10987   (let (beg end lines)
  10988     (save-excursion
  10989       (combine-after-change-calls
  10990         (when  mark-active
  10991           (setq beg (region-beginning)
  10992                 end (region-end))
  10993           (setq lines (buffer-substring beg end))
  10994           (kill-region beg end)
  10995           (setq lines (replace-regexp-in-string "^[ \t]*" "<li>" lines))
  10996           (setq lines (replace-regexp-in-string "$" "</li>" lines))
  10997           (web-mode-insert-and-indent lines)
  10998           ) ;when
  10999         ) ;combine-after-change-calls
  11000       ) ;save-excursion
  11001     ) ;let
  11002   )
  11003 
  11004 (defun web-mode-element-complete (&optional prompt)
  11005   "Completes for an element tag."
  11006   (completing-read
  11007    (or prompt "Tag name: ")
  11008    (append
  11009     web-mode-tag-list
  11010     web-mode-tag-history)
  11011    nil nil nil 'web-mode-tag-history))
  11012 
  11013 (defun web-mode-element-wrap (&optional tag-name)
  11014   "Wrap current REGION with start and end tags.
  11015 Prompt user if TAG-NAME isn't provided."
  11016   (interactive)
  11017   (let (beg end pos tag sep)
  11018     (save-excursion
  11019       (setq tag (or tag-name (web-mode-element-complete)))
  11020       (setq pos (point))
  11021       (cond
  11022         (mark-active
  11023          (setq beg (region-beginning)
  11024                end (region-end)))
  11025         ((get-text-property pos 'tag-type)
  11026          (setq beg (web-mode-element-beginning-position pos)
  11027                end (1+ (web-mode-element-end-position pos))))
  11028         ((setq beg (web-mode-element-parent-position pos))
  11029          (setq end (1+ (web-mode-element-end-position pos))))
  11030         )
  11031       ;;      (message "beg(%S) end(%S)" beg end)
  11032       (when (and beg end (> end 0))
  11033         (setq sep (if (get-text-property beg 'tag-beg) "\n" ""))
  11034         (web-mode-insert-text-at-pos (concat sep "</" tag ">") end)
  11035         (web-mode-insert-text-at-pos (concat "<" tag ">" sep) beg)
  11036         (when (string= sep "\n") (indent-region beg (+ end (* (+ 3 (length tag)) 2))))
  11037         )
  11038       ) ;save-excursion
  11039     (web-mode-go beg)))
  11040 
  11041 (defun web-mode-element-vanish (&optional arg)
  11042   "Vanish the current html element. The content of the element is kept."
  11043   (interactive "p")
  11044   (let (type (pos (point)) start-b start-e end-b end-e)
  11045     (while (>= arg 1)
  11046       (setq type (get-text-property pos 'tag-type))
  11047       (when type
  11048         (cond
  11049           ((member type '(void))
  11050            (web-mode-element-kill)
  11051            (set-mark (point))
  11052            (web-mode-tag-match)
  11053            (web-mode-tag-end)
  11054            (exchange-point-and-mark))
  11055           ((member type '(start))
  11056            (setq start-b (web-mode-tag-beginning-position)
  11057                  start-e (web-mode-tag-end-position))
  11058            (when (web-mode-tag-match)
  11059              (setq end-b (web-mode-tag-beginning-position)
  11060                    end-e (web-mode-tag-end-position)))
  11061            )
  11062           (t
  11063            (setq end-b (web-mode-tag-beginning-position)
  11064                  end-e (web-mode-tag-end-position))
  11065            (when (web-mode-tag-match)
  11066              (setq start-b (web-mode-tag-beginning-position)
  11067                    start-e (web-mode-tag-end-position)))
  11068            ) ;t
  11069           ) ;cond
  11070         (when (and start-b end-b)
  11071           (goto-char end-b)
  11072           (delete-region end-b (1+ end-e))
  11073           (delete-blank-lines)
  11074           (goto-char start-b)
  11075           (delete-region start-b (1+ start-e))
  11076           (delete-blank-lines)
  11077           (web-mode-buffer-indent)
  11078           )
  11079         ;;        (message "start %S %S - end %S %S" start-b start-e end-b end-e))
  11080         ) ;when
  11081       (skip-chars-forward "[:space:]\n")
  11082       (setq arg (1- arg))
  11083       ) ;while
  11084     ) ;let
  11085   )
  11086 
  11087 (defun web-mode-element-kill (&optional arg)
  11088   "Kill the current html element."
  11089   (interactive "p")
  11090   (while (>= arg 1)
  11091     (setq arg (1- arg))
  11092     (web-mode-element-select)
  11093     (when mark-active
  11094       (kill-region (region-beginning) (region-end)))
  11095     ) ;while
  11096   )
  11097 
  11098 (defun web-mode-element-clone (&optional arg)
  11099   "Clone the current html element."
  11100   (interactive "p")
  11101   (let (col pos)
  11102     (while (>= arg 1)
  11103       (setq arg (1- arg)
  11104             col 0)
  11105       (web-mode-element-select)
  11106       (when mark-active
  11107         (save-excursion
  11108           (goto-char (region-beginning))
  11109           (setq col (current-column)))
  11110         (kill-region (region-beginning) (region-end))
  11111         (yank)
  11112         (newline)
  11113         (indent-line-to col)
  11114         (setq pos (point))
  11115         (yank)
  11116         (goto-char pos))
  11117       )
  11118     ) ;let
  11119   )
  11120 
  11121 (defun web-mode-element-insert ()
  11122   "Insert an html element."
  11123   (interactive)
  11124   (let (tag-name)
  11125     (cond
  11126       ((and (get-text-property (point) 'tag-type)
  11127             (not (get-text-property (point) 'tag-beg)))
  11128        (message "element-insert ** invalid context **"))
  11129       ((not (and (setq tag-name (web-mode-element-complete))
  11130                  (> (length tag-name) 0)))
  11131        (message "element-insert ** failure **"))
  11132       ((web-mode-element-is-void tag-name)
  11133        (insert (concat "<" (replace-regexp-in-string "/" "" tag-name) "/>"))
  11134        )
  11135       (mark-active
  11136        (let ((beg (region-beginning)) (end (region-end)))
  11137          (deactivate-mark)
  11138          (goto-char end)
  11139          (insert "</" tag-name ">")
  11140          (goto-char beg)
  11141          (insert "<" tag-name ">")
  11142          )
  11143        )
  11144       (t
  11145        (insert (concat "<" tag-name ">" "</" tag-name ">"))
  11146        (web-mode-sb "</")
  11147        )
  11148       ) ;cond
  11149     ))
  11150 
  11151 (defun web-mode-element-insert-at-point ()
  11152   "Replace the word at point with a html tag of it."
  11153   (interactive)
  11154   (let ((tag-name (thing-at-point 'word)))
  11155     (cond
  11156       ((web-mode-element-is-void tag-name)
  11157        (backward-kill-word 1)
  11158        (insert (concat "<" (replace-regexp-in-string "/" "" tag-name) "/>"))
  11159        )
  11160       (mark-active
  11161        (setq tag-name (buffer-substring (region-beginning) (region-end)))
  11162        (delete-region (region-beginning) (region-end))
  11163        (insert (concat "<" tag-name ">" "</" tag-name ">"))
  11164        (web-mode-sb "</")
  11165        )
  11166       (tag-name ; do nothing is there isn's word at point
  11167        (backward-kill-word 1)
  11168        (insert (concat "<" tag-name ">" "</" tag-name ">"))
  11169        (web-mode-sb "</")
  11170        )
  11171       ) ;cond
  11172     ))
  11173 
  11174 (defun web-mode-element-rename (&optional tag-name)
  11175   "Rename the current html element."
  11176   (interactive)
  11177   (save-excursion
  11178     (let (pos)
  11179       (unless tag-name (setq tag-name (web-mode-element-complete "New tag name: ")))
  11180       (when (and (> (length tag-name) 0)
  11181                  (web-mode-element-beginning)
  11182                  (looking-at "<\\([[:alnum:]]+\\(:?[[:alpha:]_-]+\\)?\\)"))
  11183         (setq pos (point))
  11184         (unless (web-mode-element-is-void)
  11185           (save-match-data
  11186             (web-mode-tag-match)
  11187             (if (looking-at "</[ ]*\\([[:alnum:]]+\\(:?[[:alpha:]_-]+\\)?\\)")
  11188                 (replace-match (concat "</" tag-name))
  11189                 )))
  11190         (goto-char pos)
  11191         (replace-match (concat "<" tag-name))
  11192         ))))
  11193 
  11194 (defun web-mode-current-trimmed-line ()
  11195   (web-mode-trim (buffer-substring-no-properties
  11196                   (line-beginning-position)
  11197                   (line-end-position))))
  11198 
  11199 (defun web-mode-trim (string)
  11200   (replace-regexp-in-string "\\`[ \t\n]*" "" (replace-regexp-in-string "[ \t\n]*\\'" "" string)))
  11201 
  11202 (defun web-mode-is-token-end (pos)
  11203   (let (block-token part-token)
  11204     (setq block-token (get-text-property pos 'block-token))
  11205     (setq part-token (get-text-property pos 'part-token))
  11206     (cond
  11207       ((not (or block-token part-token))
  11208        nil)
  11209       ((>= (1+ pos) (point-max))
  11210        t)
  11211       ((and block-token
  11212             (not (string= (get-text-property (1+ pos) 'block-token) block-token)))
  11213        t)
  11214       ((and part-token
  11215             (not (string= (get-text-property (1+ pos) 'part-token) part-token)))
  11216        t)
  11217       (t
  11218        nil)
  11219       ) ;cond
  11220     ))
  11221 
  11222 (defun web-mode-block-is-token-line ()
  11223   (save-excursion
  11224     (let ((continue t) (counter 0))
  11225       (beginning-of-line)
  11226       (back-to-indentation)
  11227       (while (and continue (not (eolp)))
  11228         (cond
  11229           ((get-text-property (point) 'block-token)
  11230            (setq counter (1+ counter)))
  11231           ((not (member (following-char) '(?\s ?\t)))
  11232            (setq continue nil
  11233                  counter 0))
  11234           ) ;cond
  11235         (forward-char)
  11236         ) ;while
  11237       (> counter 0)
  11238       )))
  11239 
  11240 (defun web-mode-part-is-token-line (pos)
  11241   (save-excursion
  11242     (let ((continue t)
  11243           (counter 0))
  11244       (goto-char pos)
  11245       (setq continue (not (eolp)))
  11246       (while continue
  11247         (forward-char)
  11248         (cond
  11249           ((eolp)
  11250            (setq continue nil))
  11251           ((or (get-text-property (point) 'block-side)
  11252                (member (get-text-property (point) 'part-token) '(comment string)))
  11253            (setq counter (1+ counter)))
  11254           ((not (member (following-char) '(?\s ?\t)))
  11255            (setq continue nil
  11256                  counter 0))
  11257           )
  11258         ) ;while
  11259       (> counter 0))))
  11260 
  11261 (defun web-mode-is-content (&optional pos)
  11262   (unless pos (setq pos (point)))
  11263   (not (or (get-text-property pos 'part-side)
  11264            (get-text-property pos 'tag-type)
  11265            (get-text-property pos 'block-side)
  11266            )))
  11267 
  11268 (defun web-mode-is-comment-or-string (&optional pos)
  11269   (unless pos (setq pos (point)))
  11270   (not (null (or (eq (get-text-property pos 'tag-type) 'comment)
  11271                  (member (get-text-property pos 'block-token) '(comment string))
  11272                  (member (get-text-property pos 'part-token) '(comment string))))))
  11273 
  11274 ;; NOTE: we look at the firt one
  11275 (defun web-mode-block-is-open (&optional pos)
  11276   (unless pos (setq pos (point))))
  11277 
  11278 ;; NOTE: we look at the last one
  11279 (defun web-mode-block-is-close (&optional pos)
  11280   (unless pos (setq pos (point)))
  11281   (and (get-text-property pos 'block-side)
  11282        (eq (caar (web-mode-block-controls-get pos)) 'close)))
  11283 
  11284 ;; NOTE: we look at the first one
  11285 (defun web-mode-block-is-inside (&optional pos)
  11286   (unless pos (setq pos (point)))
  11287   (and (get-text-property pos 'block-side)
  11288        (eq (caar (web-mode-block-controls-get pos)) 'inside)))
  11289 
  11290 (defun web-mode-element-is-void (&optional tag)
  11291   (cond
  11292     ((and (not tag) (eq (get-text-property (point) 'tag-type) 'void))
  11293      t)
  11294     ((and tag (member tag '("div" "li" "a" "p" "h1" "h2" "h3" "ul" "span" "article" "section" "td" "tr")))
  11295      nil)
  11296     ((and tag (string-suffix-p "/" tag))
  11297      t)
  11298     ((and tag (string= web-mode-content-type "jsx"))
  11299      (member (downcase tag) '("img" "br" "hr")))
  11300     (tag
  11301      (car (member (downcase tag) web-mode-void-elements)))
  11302     (t
  11303      nil)
  11304     ))
  11305 
  11306 ;;---- COMMENT ------------------------------------------------------------------
  11307 
  11308 (defun web-mode-toggle-comments ()
  11309   "Toggle comments visbility."
  11310   (interactive)
  11311   (web-mode-with-silent-modifications
  11312    (save-excursion
  11313      (if web-mode-comments-invisible
  11314          (remove-overlays))
  11315      (setq web-mode-comments-invisible (null web-mode-comments-invisible))
  11316      (let ((continue t)
  11317            (pos (point-min))
  11318            (visibility web-mode-comments-invisible)
  11319            end)
  11320        (while continue
  11321          (setq pos (next-single-property-change pos 'font-lock-face))
  11322          (if (null pos)
  11323              (setq continue nil)
  11324              (when (eq (get-text-property pos 'font-lock-face) 'web-mode-comment-face)
  11325                (setq end (next-single-property-change pos 'font-lock-face))
  11326                (put-text-property pos end 'invisible visibility)
  11327                (when visibility
  11328                  (make-overlay pos end))
  11329                (goto-char pos)
  11330                )
  11331              )
  11332          )
  11333        ) ;let
  11334      )))
  11335 
  11336 (defun web-mode-comment-or-uncomment-region (beg end &optional _arg)
  11337   (interactive)
  11338   (save-excursion
  11339     (push-mark end)
  11340     (goto-char beg)
  11341     (setq mark-active t)
  11342     (web-mode-comment-or-uncomment)
  11343     (pop-mark)))
  11344 
  11345 (defun web-mode-comment-or-uncomment ()
  11346   "Comment or uncomment line(s), block or region at POS."
  11347   (interactive)
  11348   ;; TODO : if mark is at eol, mark--
  11349   (if (and (not mark-active) (looking-at-p "[[:space:]]*$"))
  11350       (web-mode-comment-insert)
  11351       (when (and (use-region-p) (eq (point) (region-end)))
  11352         (if (bolp) (backward-char))
  11353         (exchange-point-and-mark))
  11354       (if (eq (get-text-property (point) 'block-token) 'delimiter-beg)
  11355           (web-mode-block-skip-blank-forward (point) '(delimiter-beg))
  11356           (skip-chars-forward "[:space:]" (line-end-position)))
  11357       (cond
  11358         ;; #1147
  11359         ((and (get-text-property (point) 'jsx-beg)
  11360               (eq (get-text-property (1+ (point)) 'part-token) 'comment))
  11361          (web-mode-uncomment (1+ (point))))
  11362         ((or (eq (get-text-property (point) 'tag-type) 'comment)
  11363              (eq (get-text-property (point) 'block-token) 'comment)
  11364              (eq (get-text-property (point) 'part-token) 'comment))
  11365          (web-mode-uncomment (point)))
  11366         (t
  11367          (web-mode-comment (point)))
  11368         )
  11369       ) ;if
  11370   )
  11371 
  11372 (defun web-mode-comment-indent-new-line (&optional _soft)
  11373   (interactive)
  11374   (let (ctx)
  11375     (setq ctx (web-mode-comment-context))
  11376     (cond
  11377       ((null ctx)
  11378        (newline 1))
  11379       (t
  11380        (newline 1)
  11381        (indent-line-to (plist-get ctx :col))
  11382        (let ((prefix (plist-get ctx :prefix)))
  11383          (insert
  11384           (concat prefix
  11385                   ;; Check if the comment ends with a space, and if not, insert one.
  11386                   (if
  11387                    (string-equal (substring prefix -1 (length prefix)) " ")
  11388                    ""
  11389                    " ")))))
  11390       ) ;cond
  11391     ))
  11392 
  11393 (defun web-mode-comment-context (&optional pos)
  11394   (cond
  11395     (pos
  11396      )
  11397     ((and (eolp) (not (bobp)))
  11398      (setq pos (1- (point))))
  11399     (t
  11400      (setq pos (point)))
  11401     ) ;cond
  11402   (let (beg col prefix type format)
  11403     (cond
  11404       ((eq (get-text-property pos 'block-token) 'comment)
  11405        (setq type "block"))
  11406       ((eq (get-text-property pos 'tag-type) 'comment)
  11407        (setq type "tag"))
  11408       ((eq (get-text-property pos 'part-token) 'comment)
  11409        (setq type "part"))
  11410       )
  11411     (if (null type) nil
  11412         (save-excursion
  11413           (goto-char pos)
  11414           (web-mode-comment-beginning)
  11415           (setq beg (point)
  11416                 col (current-column))
  11417           (cond
  11418             ((looking-at-p "/\\*")
  11419              (setq format "/*"
  11420                    prefix " * "))
  11421             ((looking-at-p "//")
  11422              (setq format "//"
  11423                    prefix "//"))
  11424             ((looking-at-p "#")
  11425              (setq format "#"
  11426                    prefix "#"))
  11427             ((looking-at-p ";")
  11428              (setq format ";"
  11429                    prefix ";"))
  11430             ((looking-at-p "''")
  11431              (setq format "''"
  11432                    prefix "''"))
  11433             ) ;cond
  11434           (list :beg beg :col col :prefix prefix :type type :format format)))))
  11435 
  11436 (defun web-mode-comment-insert ()
  11437   (let ((alt nil) (language nil) (pos (point)))
  11438     (setq language (web-mode-language-at-pos pos))
  11439     (setq alt (cdr (assoc language web-mode-comment-formats)))
  11440     ;;(message "language=%S" language)
  11441     (cond
  11442       ((get-text-property pos 'block-side)
  11443        (cond
  11444          ((and alt (string= alt "//"))
  11445           (insert "// "))
  11446          (t
  11447           (insert "/*  */")
  11448           (search-backward " */"))
  11449          ) ;cond
  11450        ) ;case block-side
  11451       ((get-text-property pos 'part-side)
  11452        (cond
  11453          ((and alt (string= alt "//"))
  11454           (insert "// "))
  11455          (t
  11456           (insert "/*  */")
  11457           (search-backward " */"))
  11458          ) ;cond
  11459        ) ;case part-side
  11460       (t
  11461        (insert "<!--  -->")
  11462        (search-backward " -->")
  11463        ) ;case html
  11464       ) ;cond
  11465     ))
  11466 
  11467 (defun web-mode-comment (pos)
  11468   (let (ctx language col sel beg end block-side single-line-block pos-after content)
  11469 
  11470     (setq pos-after pos)
  11471 
  11472     (setq block-side (get-text-property pos 'block-side))
  11473     (setq single-line-block (web-mode-is-single-line-block pos))
  11474 
  11475     (cond
  11476 
  11477       ((and block-side (string= web-mode-engine "erb"))
  11478        (web-mode-comment-erb-block pos)
  11479        )
  11480 
  11481       ((and block-side (string= web-mode-engine "artanis"))
  11482        (web-mode-comment-artanis-block pos)
  11483        )
  11484 
  11485       ((and single-line-block block-side
  11486             (intern-soft (concat "web-mode-comment-" web-mode-engine "-block")))
  11487        (funcall (intern (concat "web-mode-comment-" web-mode-engine "-block")) pos)
  11488        )
  11489 
  11490       (t
  11491        (setq ctx (web-mode-point-context
  11492                   (if mark-active (region-beginning) (line-beginning-position))))
  11493        ;;(message "%S" ctx)
  11494        (setq language (plist-get ctx :language))
  11495        (setq col (current-column))
  11496        (cond
  11497          (mark-active
  11498           ;;(message "%S %S" (point) col)
  11499           )
  11500          ((and (member language '("html" "xml"))
  11501                (get-text-property (progn (back-to-indentation) (point)) 'tag-beg))
  11502           (web-mode-element-select))
  11503          (t
  11504           (end-of-line)
  11505           (set-mark (line-beginning-position)))
  11506          ) ;cond
  11507 
  11508        (setq beg (region-beginning)
  11509              end (region-end))
  11510 
  11511        (when (> (point) (mark))
  11512          (exchange-point-and-mark))
  11513 
  11514        (if (and (eq (char-before end) ?\n)
  11515                 (not (eq (char-after end) ?\n)))
  11516            (setq end (1- end)))
  11517 
  11518        (setq sel (buffer-substring-no-properties beg end))
  11519 
  11520        (cond
  11521 
  11522          ((member language '("html" "xml"))
  11523           (cond
  11524             ((and (= web-mode-comment-style 2) (string= web-mode-engine "django"))
  11525              (setq content (concat "{# " sel " #}")))
  11526             ((and (= web-mode-comment-style 2) (member web-mode-engine '("ejs" "erb")))
  11527              (setq content (concat "<%# " sel " %>")))
  11528             ((and (= web-mode-comment-style 2) (string= web-mode-engine "artanis"))
  11529              (setq content (concat "<%; " sel " %>")))
  11530             ((and (= web-mode-comment-style 2) (string= web-mode-engine "aspx"))
  11531              (setq content (concat "<%-- " sel " --%>")))
  11532             ((and (= web-mode-comment-style 2) (string= web-mode-engine "smarty"))
  11533              (setq content (concat "{* " sel " *}")))
  11534             ((and (= web-mode-comment-style 2) (string= web-mode-engine "expressionengine"))
  11535              (setq content (concat "{!-- " sel " --}")))
  11536             ((and (= web-mode-comment-style 2) (string= web-mode-engine "xoops"))
  11537              (setq content (concat "<{* " sel " *}>")))
  11538             ((and (= web-mode-comment-style 2) (string= web-mode-engine "hero"))
  11539              (setq content (concat "<%# " sel " %>")))
  11540             ((and (= web-mode-comment-style 2) (string= web-mode-engine "blade"))
  11541              (setq content (concat "{{-- " sel " --}}")))
  11542             ((and (= web-mode-comment-style 2) (string= web-mode-engine "ctemplate"))
  11543              (setq content (concat "{{!-- " sel " --}}")))
  11544             ((and (= web-mode-comment-style 2) (string= web-mode-engine "antlers"))
  11545              (setq content (concat "{{# " sel " #}}")))
  11546             ((and (= web-mode-comment-style 2) (string= web-mode-engine "razor"))
  11547              (setq content (concat "@* " sel " *@")))
  11548             (t
  11549              (setq content (concat "<!-- " sel " -->"))
  11550              (when (< (length sel) 1)
  11551                (search-backward " -->")
  11552                (setq pos-after nil))
  11553              ))
  11554           ) ;case html
  11555 
  11556          ((member language '("php" "javascript" "typescript" "java" "jsx"))
  11557           (let (alt)
  11558             (setq alt (cdr (assoc language web-mode-comment-formats)))
  11559             ;;(message "language=%S alt=%S sel=%S col=%S" language alt sel col)
  11560             (cond
  11561               ((and alt (string= alt "//"))
  11562                (setq content (replace-regexp-in-string (concat "\n[ ]\\{" (number-to-string col) "\\}") "\n" sel))
  11563                (setq content (replace-regexp-in-string (concat "\n") "\n// " content))
  11564                (setq content (concat "// " content)))
  11565               ((get-text-property pos 'jsx-depth)
  11566                (setq content (concat "{/* " sel " */}")))
  11567               (web-mode-comment-prefixing
  11568                (setq content (replace-regexp-in-string (concat "\n[ ]\\{" (number-to-string col) "\\}") "\n* " sel))
  11569                (setq content (concat "/* " content " */")))
  11570               (t
  11571                (setq content (concat "/* " sel " */")))
  11572               ) ;cond
  11573             ) ;let
  11574           )
  11575 
  11576          ((member language '("erb"))
  11577           (setq content (replace-regexp-in-string "^[ ]*" "#" sel)))
  11578 
  11579          ((member language '("asp"))
  11580           (setq content (replace-regexp-in-string "^[ ]*" "'" sel)))
  11581 
  11582          (t
  11583           (setq content (concat "/* " sel " */")))
  11584 
  11585          ) ;cond
  11586 
  11587        (when content
  11588          (delete-region beg end)
  11589          (deactivate-mark)
  11590          (let (beg end)
  11591            (setq beg (line-beginning-position))
  11592            (insert content)
  11593            (setq end (line-end-position))
  11594            (indent-region beg end)
  11595            )
  11596          ) ;when
  11597 
  11598        ) ;t
  11599       ) ;cond
  11600 
  11601     (when pos-after (goto-char pos-after))
  11602 
  11603     ))
  11604 
  11605 (defun web-mode-comment-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-insert-text-at-pos "//" (+ beg 2))))
  11610 
  11611 (defun web-mode-comment-erb-block (pos)
  11612   (let (beg end)
  11613     (setq beg (web-mode-block-beginning-position pos)
  11614           end (web-mode-block-end-position pos))
  11615     (web-mode-insert-text-at-pos "#" (+ beg 2))))
  11616 
  11617 (defun web-mode-comment-artanis-block (pos)
  11618   (let (beg end)
  11619     (setq beg (web-mode-block-beginning-position pos)
  11620           end (web-mode-block-end-position pos))
  11621     (web-mode-insert-text-at-pos ";" (+ beg 2))))
  11622 
  11623 (defun web-mode-comment-django-block (pos)
  11624   (let (beg end)
  11625     (setq beg (web-mode-block-beginning-position pos)
  11626           end (web-mode-block-end-position pos))
  11627     (web-mode-insert-text-at-pos "#" end)
  11628     (web-mode-insert-text-at-pos "#" (1+ beg))))
  11629 
  11630 (defun web-mode-comment-dust-block (pos)
  11631   (let (beg end)
  11632     (setq beg (web-mode-block-beginning-position pos)
  11633           end (web-mode-block-end-position pos))
  11634     (web-mode-insert-text-at-pos "!" end)
  11635     (web-mode-insert-text-at-pos "!" (1+ beg))))
  11636 
  11637 (defun web-mode-comment-aspx-block (pos)
  11638   (let (beg end)
  11639     (setq beg (web-mode-block-beginning-position pos)
  11640           end (web-mode-block-end-position pos))
  11641     (web-mode-insert-text-at-pos "#" end)
  11642     (web-mode-insert-text-at-pos "#" (1+ beg))))
  11643 
  11644 (defun web-mode-comment-jsp-block (pos)
  11645   (let (beg end)
  11646     (setq beg (web-mode-block-beginning-position pos)
  11647           end (web-mode-block-end-position pos))
  11648     (web-mode-insert-text-at-pos "--" (+ beg 2))))
  11649 
  11650 (defun web-mode-comment-go-block (pos)
  11651   (let (beg end)
  11652     (setq beg (web-mode-block-beginning-position pos)
  11653           end (web-mode-block-end-position pos))
  11654     (web-mode-insert-text-at-pos "*/" (1- end))
  11655     (web-mode-insert-text-at-pos "/*" (+ beg (if (web-mode-looking-at "{{" beg) 2 0)))))
  11656 
  11657 (defun web-mode-comment-php-block (pos)
  11658   (let (beg end)
  11659     (setq beg (web-mode-block-beginning-position pos)
  11660           end (web-mode-block-end-position pos))
  11661     (web-mode-insert-text-at-pos "*/" (- end 2))
  11662     (web-mode-insert-text-at-pos "/*" (+ beg 1 (if (web-mode-looking-at "<\\?php" beg) 5 3)))))
  11663 
  11664 (defun web-mode-comment-svelte-block (pos)
  11665   (let (beg end)
  11666     (setq beg (web-mode-block-beginning-position pos)
  11667           end (web-mode-block-end-position pos))
  11668     (web-mode-insert-text-at-pos "!" end)
  11669     (web-mode-insert-text-at-pos "!" (1+ beg))))
  11670 
  11671 (defun web-mode-comment-boundaries (&optional pos)
  11672   (interactive)
  11673   (unless pos (setq pos (point)))
  11674   (let ((beg pos) (end pos) prop)
  11675     (save-excursion
  11676       (goto-char pos)
  11677       (setq prop
  11678             (cond
  11679               ((eq (get-text-property pos 'block-token) 'comment) 'block-token)
  11680               ((eq (get-text-property pos 'tag-type) 'comment) 'tag-type)
  11681               ((eq (get-text-property pos 'part-token) 'comment) 'part-token)
  11682               (t nil)
  11683               ))
  11684       (if (null prop)
  11685           (setq beg nil
  11686                 end nil)
  11687           (when (and (not (bobp))
  11688                      (eq (get-text-property pos prop) (get-text-property (1- pos) prop)))
  11689             (setq beg (or (previous-single-property-change pos prop) (point-min))))
  11690           (when (and (not (eobp))
  11691                      (eq (get-text-property pos prop) (get-text-property (1+ pos) prop)))
  11692             (setq end (or (next-single-property-change pos prop) (point-max)))))
  11693       (message "beg(%S) end(%S) point-max(%S)" beg end (point-max))
  11694       (when (and beg (string= (buffer-substring-no-properties beg (+ beg 2)) "//"))
  11695         (goto-char end)
  11696         (while (and (looking-at-p "\n[ ]*//")
  11697                     (not (eobp)))
  11698           (search-forward "//")
  11699           (backward-char 2)
  11700           ;;(message "%S" (point))
  11701           (setq end (next-single-property-change (point) prop))
  11702           (goto-char end)
  11703           ;;(message "%S" (point))
  11704           ) ;while
  11705         ) ;when
  11706       ;;(when end (setq end (1- end))) ;; #1021
  11707       ) ;save-excursion
  11708     ;;(message "beg=%S end=%S" beg end)
  11709     (if (and beg end) (cons beg end) nil)
  11710     ))
  11711 
  11712 (defun web-mode-uncomment (pos)
  11713   (let ((beg pos) (end pos) (sub2 "") comment boundaries)
  11714     (save-excursion
  11715       (cond
  11716         ((and (get-text-property pos 'block-side)
  11717               (intern-soft (concat "web-mode-uncomment-" web-mode-engine "-block")))
  11718          (funcall (intern (concat "web-mode-uncomment-" web-mode-engine "-block")) pos))
  11719         ((and (setq boundaries (web-mode-comment-boundaries pos))
  11720               (setq beg (car boundaries))
  11721               (setq end (1+ (cdr boundaries)))
  11722               (> (- end beg) 4))
  11723          (when (and (eq (get-text-property beg 'part-token) 'comment)
  11724                     (> beg 1) ;#1158
  11725                     (get-text-property (1- beg) 'jsx-beg))
  11726            (setq beg (1- beg)
  11727                  end (1+ end)))
  11728          (setq comment (buffer-substring-no-properties beg end))
  11729          (setq sub2 (substring comment 0 2))
  11730          (cond
  11731            ((member sub2 '("<!" "<%"))
  11732             (setq comment (replace-regexp-in-string "\\(^<[!%]--[ ]?\\|[ ]?--[%]?>$\\)" "" comment)))
  11733            ((string= sub2 "{#")
  11734             (setq comment (replace-regexp-in-string "\\(^{#[ ]?\\|[ ]?#}$\\)" "" comment)))
  11735            ((string= sub2 "{/") ;jsx comments
  11736             (setq comment (replace-regexp-in-string "\\(^{/\\*[ ]?\\|[ ]?\\*/}$\\)" "" comment)))
  11737            ((string= sub2 "/*")
  11738             ;;(message "%S" comment)
  11739             ;;(setq comment (replace-regexp-in-string "\\(\\*/\\|^/\\*[ ]?\\|^[ \t]*\\*\\)" "" comment))
  11740             (setq comment (replace-regexp-in-string "\\([ ]?\\*/$\\|^/\\*[ ]?\\)" "" comment))
  11741             (setq comment (replace-regexp-in-string "\\(^[ \t]*\\*\\)" "" comment))
  11742             ;;(message "%S" comment)
  11743             )
  11744            ((string= sub2 "''")
  11745             (setq comment (replace-regexp-in-string "''" "" comment)))
  11746            ((string= sub2 "//")
  11747             (setq comment (replace-regexp-in-string "^ *//" "" comment)))
  11748            ) ;cond
  11749          (delete-region beg end)
  11750          (web-mode-insert-and-indent comment)
  11751          (goto-char beg)
  11752          )
  11753         ) ;cond
  11754       (indent-according-to-mode)
  11755       )))
  11756 
  11757 (defun web-mode-uncomment-erb-block (pos)
  11758   (let (beg end)
  11759     (setq beg (web-mode-block-beginning-position pos)
  11760           end (web-mode-block-end-position pos))
  11761     (cond
  11762       ((string= (buffer-substring-no-properties beg (+ beg 4)) "<%#=")
  11763        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11764       ((string-match-p "<[%[:alpha:]]" (buffer-substring-no-properties (+ beg 2) (- end 2)))
  11765        (web-mode-remove-text-at-pos 2 (1- end))
  11766        (web-mode-remove-text-at-pos 3 beg))
  11767       (t
  11768        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11769       ) ;cond
  11770     )
  11771   )
  11772 
  11773 (defun web-mode-uncomment-artanis-block (pos)
  11774   (let (beg end)
  11775     (setq beg (web-mode-block-beginning-position pos)
  11776           end (web-mode-block-end-position pos))
  11777     (cond
  11778       ((string= (buffer-substring-no-properties beg (+ beg 4)) "<%;=")
  11779        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11780       ((string-match-p "<[%[:alpha:]]" (buffer-substring-no-properties (+ beg 2) (- end 2)))
  11781        (web-mode-remove-text-at-pos 2 (1- end))
  11782        (web-mode-remove-text-at-pos 3 beg))
  11783       (t
  11784        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11785       ) ;cond
  11786     )
  11787   )
  11788 
  11789 (defun web-mode-uncomment-ejs-block (pos)
  11790   (let (beg end)
  11791     (setq beg (web-mode-block-beginning-position pos)
  11792           end (web-mode-block-end-position pos))
  11793     (web-mode-remove-text-at-pos 1 (+ beg 2))))
  11794 
  11795 (defun web-mode-uncomment-django-block (pos)
  11796   (let (beg end)
  11797     (setq beg (web-mode-block-beginning-position pos)
  11798           end (web-mode-block-end-position pos))
  11799     (cond
  11800       ((web-mode-looking-at-p "{#[{%]" beg)
  11801        (web-mode-remove-text-at-pos 1 (1- end))
  11802        (web-mode-remove-text-at-pos 1 (1+ beg))
  11803        )
  11804       (t
  11805        (web-mode-remove-text-at-pos 2 (1- end))
  11806        (web-mode-remove-text-at-pos 2 beg))
  11807       ) ;cond
  11808     ))
  11809 
  11810 (defun web-mode-uncomment-ctemplate-block (pos)
  11811   (let (beg end)
  11812     (setq beg (web-mode-block-beginning-position pos)
  11813           end (web-mode-block-end-position pos))
  11814     (web-mode-remove-text-at-pos 5 (- end 4))
  11815     (web-mode-remove-text-at-pos 5 beg)))
  11816 
  11817 (defun web-mode-uncomment-antlers-block (pos)
  11818   (let (beg end)
  11819     (setq beg (web-mode-block-beginning-position pos)
  11820           end (web-mode-block-end-position pos))
  11821     (web-mode-remove-text-at-pos 3 (- end 2))
  11822     (web-mode-remove-text-at-pos 3 beg)))
  11823 
  11824 (defun web-mode-uncomment-dust-block (pos)
  11825   (let (beg end)
  11826     (setq beg (web-mode-block-beginning-position pos)
  11827           end (web-mode-block-end-position pos))
  11828     (web-mode-remove-text-at-pos 1 (1- end))
  11829     (web-mode-remove-text-at-pos 1 (1+ beg))))
  11830 
  11831 (defun web-mode-uncomment-aspx-block (pos)
  11832   (let (beg end)
  11833     (setq beg (web-mode-block-beginning-position pos)
  11834           end (web-mode-block-end-position pos))
  11835     (web-mode-remove-text-at-pos 1 (1- end))
  11836     (web-mode-remove-text-at-pos 1 (1+ beg))))
  11837 
  11838 (defun web-mode-uncomment-jsp-block (pos)
  11839   (let (beg end)
  11840     (setq beg (web-mode-block-beginning-position pos)
  11841           end (web-mode-block-end-position pos))
  11842     (web-mode-remove-text-at-pos 2 (+ beg 2))))
  11843 
  11844 (defun web-mode-uncomment-go-block (pos)
  11845   (let (beg end)
  11846     (setq beg (web-mode-block-beginning-position pos)
  11847           end (web-mode-block-end-position pos))
  11848     (web-mode-remove-text-at-pos 2 (+ beg 2))
  11849     (web-mode-remove-text-at-pos 2 (- end 5))))
  11850 
  11851 (defun web-mode-uncomment-svelte-block (pos)
  11852   (let (beg end)
  11853     (setq beg (web-mode-block-beginning-position pos)
  11854           end (web-mode-block-end-position pos))
  11855     (web-mode-remove-text-at-pos 1 (1- end))
  11856     (web-mode-remove-text-at-pos 1 (1+ beg))))
  11857 
  11858 (defun web-mode-snippet-names ()
  11859   (mapcar #'car web-mode-snippets))
  11860 
  11861 (defun web-mode-snippet-insert (code)
  11862   "Insert a snippet."
  11863   (interactive
  11864    (list (completing-read "Snippet: " (web-mode-snippet-names))))
  11865   (let (beg
  11866         (continue t)
  11867         (counter 0)
  11868         end
  11869         sel
  11870         snippet
  11871         (l (length web-mode-snippets))
  11872         pos)
  11873     (when mark-active
  11874       (setq sel (web-mode-trim (buffer-substring-no-properties
  11875                                 (region-beginning) (region-end))))
  11876       (delete-region (region-beginning) (region-end)))
  11877     (while (and continue (< counter l))
  11878       (setq snippet (nth counter web-mode-snippets))
  11879       (when (string= (car snippet) code)
  11880         (setq continue nil))
  11881       (setq counter (1+ counter)))
  11882     (when snippet
  11883       (setq snippet (cdr snippet))
  11884       (setq beg (line-beginning-position))
  11885       (insert snippet)
  11886       (setq pos (point)
  11887             end (point))
  11888       (cond
  11889         ((string-match-p "¦" snippet)
  11890          (search-backward "¦")
  11891          (delete-char 1)
  11892          (setq pos (point)
  11893                end (1- end)))
  11894         ((string-match-p "|" snippet)
  11895          (search-backward "|")
  11896          (delete-char 1)
  11897          (setq pos (point)
  11898                end (1- end)))
  11899         ) ;cond
  11900       (when sel
  11901         (insert sel)
  11902         (setq pos (point)
  11903               end (+ end (length sel))))
  11904       (goto-char end)
  11905       (setq end (line-end-position))
  11906       (unless sel (goto-char pos))
  11907       (indent-region beg end))
  11908     ))
  11909 
  11910 (defun web-mode-looking-at (regexp pos)
  11911   (save-excursion
  11912     (goto-char pos)
  11913     (looking-at regexp)))
  11914 
  11915 (defun web-mode-looking-at-p (regexp pos)
  11916   (save-excursion
  11917     (goto-char pos)
  11918     (looking-at-p regexp)))
  11919 
  11920 (defun web-mode-looking-back (regexp pos &optional limit greedy)
  11921   (save-excursion
  11922     (goto-char pos)
  11923     (if limit
  11924         (looking-back regexp limit greedy)
  11925         (looking-back regexp (point-min)))))
  11926 
  11927 (defun web-mode-insert-text-at-pos (text pos)
  11928   (let ((mem web-mode-enable-auto-pairing))
  11929     (setq web-mode-enable-auto-pairing nil)
  11930     (save-excursion
  11931       (goto-char pos)
  11932       (insert text)
  11933       (setq web-mode-enable-auto-pairing mem)
  11934       )))
  11935 
  11936 (defun web-mode-remove-text-at-pos (n &optional pos)
  11937   (unless pos (setq pos (point)))
  11938   (delete-region pos (+ pos n)))
  11939 
  11940 (defun web-mode-insert-and-indent (text)
  11941   (let (beg end)
  11942     (setq beg (line-beginning-position))
  11943     (insert text)
  11944     (setq end (line-end-position))
  11945     (indent-region beg end)
  11946     ))
  11947 
  11948 (defun web-mode-column-at-pos (pos)
  11949   (save-excursion
  11950     (goto-char pos)
  11951     (current-column)))
  11952 
  11953 (defun web-mode-indentation-at-pos (pos)
  11954   (save-excursion
  11955     (goto-char pos)
  11956     (current-indentation)))
  11957 
  11958 (defun web-mode-navigate (&optional pos)
  11959   "Move point to the matching opening/closing tag/block."
  11960   (interactive)
  11961   (unless pos (setq pos (point)))
  11962   (let (init)
  11963     (goto-char pos)
  11964     (setq init (point))
  11965     (when (> (current-indentation) (current-column))
  11966       (back-to-indentation))
  11967     (setq pos (point))
  11968     (cond
  11969       ((and (get-text-property pos 'block-side)
  11970             (web-mode-block-beginning)
  11971             (web-mode-block-controls-get (point)))
  11972        (web-mode-block-match))
  11973       ((member (get-text-property pos 'tag-type) '(start end))
  11974        (web-mode-tag-beginning)
  11975        (web-mode-tag-match))
  11976       (t
  11977        (goto-char init))
  11978       )
  11979     ))
  11980 
  11981 (defun web-mode-block-match (&optional pos)
  11982   (unless pos (setq pos (point)))
  11983   (let (pos-ori controls control (counter 1) type (continue t) pair)
  11984     (setq pos-ori pos)
  11985     (goto-char pos)
  11986     (setq controls (web-mode-block-controls-get pos))
  11987     ;;(message "controls=%S" controls)
  11988     (cond
  11989       (controls
  11990        (setq pair (car controls))
  11991        (setq control (cdr pair))
  11992        (setq type (car pair))
  11993        (when (eq type 'inside) (setq type 'close))
  11994        (while continue
  11995          (cond
  11996            ((and (> pos-ori 1) (bobp))
  11997             (setq continue nil))
  11998            ((or (and (eq type 'open) (not (web-mode-block-next)))
  11999                 (and (eq type 'close) (not (web-mode-block-previous))))
  12000             (setq continue nil)
  12001             )
  12002            ((null (setq controls (web-mode-block-controls-get (point))))
  12003             )
  12004            (t
  12005             ;;TODO : est il nécessaire de faire un reverse sur controls si on doit matcher backward
  12006             (dolist (pair controls)
  12007               (cond
  12008                 ((not (string= (cdr pair) control))
  12009                  )
  12010                 ((eq (car pair) 'inside)
  12011                  )
  12012                 ((eq (car pair) type)
  12013                  (setq counter (1+ counter)))
  12014                 (t
  12015                  (setq counter (1- counter)))
  12016                 )
  12017               ) ;dolist
  12018             (when (= counter 0)
  12019               (setq continue nil))
  12020             ) ;t
  12021            ) ;cond
  12022          ) ;while
  12023        (if (= counter 0) (point) nil)
  12024        ) ;controls
  12025       (t
  12026        (goto-char pos-ori)
  12027        nil
  12028        ) ;controls = nul
  12029       ) ;conf
  12030     ))
  12031 
  12032 (defun web-mode-tag-match (&optional pos)
  12033   "Move point to the matching opening/closing tag."
  12034   (interactive)
  12035   (unless pos (setq pos (point)))
  12036   (let (regexp name)
  12037     (cond
  12038       ((eq (get-text-property pos 'tag-type) 'void)
  12039        (web-mode-tag-beginning))
  12040       ((and (eq (get-text-property pos 'tag-type) 'comment)
  12041             (web-mode-looking-at-p "<!--#\\(elif\\|else\\|endif\\|if\\)" pos))
  12042        (setq regexp "<!--#\\(end\\)?if")
  12043        (if (web-mode-looking-at-p "<!--#if" pos)
  12044            (web-mode-tag-fetch-closing regexp pos)
  12045            (web-mode-tag-fetch-opening regexp pos))
  12046        )
  12047       (t
  12048        (setq name (get-text-property pos 'tag-name))
  12049        (when (string= name "_fragment_") (setq name ">"))
  12050        (setq regexp (concat "</?" name))
  12051        (when (member (get-text-property pos 'tag-type) '(start end))
  12052          (web-mode-tag-beginning)
  12053          (setq pos (point)))
  12054        (if (eq (get-text-property pos 'tag-type) 'end)
  12055            (web-mode-tag-fetch-opening regexp pos)
  12056            (web-mode-tag-fetch-closing regexp pos))
  12057        ) ;t
  12058       ) ;cond
  12059     t))
  12060 
  12061 (defun web-mode-tag-fetch-opening (regexp pos)
  12062   (let ((counter 1) (n 0) (is-comment nil) (types '(start end)))
  12063     (when (eq (aref regexp 1) ?\!)
  12064       (setq types '(comment)
  12065             is-comment t))
  12066     (goto-char pos)
  12067     (while (and (> counter 0) (re-search-backward regexp nil t))
  12068       (when (and (get-text-property (point) 'tag-beg)
  12069                  (member (get-text-property (point) 'tag-type) types))
  12070         (setq n (1+ n))
  12071         (cond
  12072           ((and is-comment
  12073                 (eq (aref (match-string-no-properties 0) 5) ?e))
  12074            (setq counter (1+ counter)))
  12075           (is-comment
  12076            (setq counter (1- counter)))
  12077           ((eq (get-text-property (point) 'tag-type) 'end)
  12078            (setq counter (1+ counter)))
  12079           (t
  12080            (setq counter (1- counter))
  12081            )
  12082           )
  12083         )
  12084       )
  12085     (if (= n 0) (goto-char pos))
  12086     ))
  12087 
  12088 (defun web-mode-tag-fetch-closing (regexp pos)
  12089   (let ((counter 1) (is-comment nil) (n 0))
  12090     (when (eq (aref regexp 1) ?\!)
  12091       (setq is-comment t))
  12092     (goto-char pos)
  12093     (web-mode-tag-end)
  12094     (while (and (> counter 0) (re-search-forward regexp nil t))
  12095       (when (get-text-property (match-beginning 0) 'tag-beg)
  12096         (setq n (1+ n))
  12097         (cond
  12098           ((and is-comment
  12099                 (eq (aref (match-string-no-properties 0) 5) ?e))
  12100            (setq counter (1- counter)))
  12101           (is-comment
  12102            (setq counter (1+ counter)))
  12103           ((eq (get-text-property (point) 'tag-type) 'end)
  12104            (setq counter (1- counter)))
  12105           (t
  12106            (setq counter (1+ counter)))
  12107           )
  12108         ) ;when
  12109       ) ;while
  12110     (if (> n 0)
  12111         (web-mode-tag-beginning)
  12112         (goto-char pos))
  12113     ))
  12114 
  12115 (defun web-mode-element-tag-name (&optional pos)
  12116   (unless pos (setq pos (point)))
  12117   (save-excursion
  12118     (goto-char pos)
  12119     (if (and (web-mode-tag-beginning)
  12120              (looking-at web-mode-tag-regexp))
  12121         (match-string-no-properties 1)
  12122         nil)))
  12123 
  12124 (defun web-mode-element-close ()
  12125   "Close html element."
  12126   (interactive)
  12127   (let (jmp epp ins tag)
  12128 
  12129     (if (and (eq (char-before) ?\>)
  12130              (web-mode-element-is-void (get-text-property (1- (point)) 'tag-name)))
  12131         (unless (eq (char-before (1- (point))) ?\/)
  12132           (backward-char)
  12133           (insert "/")
  12134           (forward-char))
  12135         (setq epp (web-mode-element-parent-position)))
  12136 
  12137     ;;(message "epp=%S" epp)
  12138     (when epp
  12139       (setq tag (get-text-property epp 'tag-name))
  12140       (setq tag (web-mode-element-tag-name epp))
  12141       ;;(message "tag=%S %c" tag (char-before))
  12142       (cond
  12143         ((or (null tag) (web-mode-element-is-void tag))
  12144          (setq epp nil))
  12145         ((looking-back "</" (point-min))
  12146          (setq ins tag))
  12147         ((looking-back "<" (point-min))
  12148          (setq ins (concat "/" tag)))
  12149         (t
  12150          ;;auto-close-style = 2
  12151          ;;(message "%S %c" (point) (char-after))
  12152          (when (and (looking-at-p "[[:alpha:]]") (> (length tag) 4))
  12153            (dolist (elt '("div" "span" "strong" "pre" "li"))
  12154              (when (and (string-match-p (concat "^" elt) tag) (not (string= tag elt)))
  12155                (setq tag elt)
  12156                (put-text-property epp (point) 'tag-name tag))
  12157              )
  12158            ) ;when
  12159          (if (web-mode-element-is-void (get-text-property (point) 'tag-name))
  12160              (setq ins nil
  12161                    epp nil)
  12162              (setq ins (concat "</" tag)))
  12163          )
  12164         ) ;cond
  12165       (when ins
  12166         (unless (looking-at-p "[ ]*>")
  12167           (setq ins (concat ins ">")))
  12168         (insert ins)
  12169         (setq tag (downcase tag))
  12170         (save-excursion
  12171           (search-backward "<")
  12172           (setq jmp (and (eq (char-before) ?\>)
  12173                          (string= (get-text-property (1- (point)) 'tag-name) tag)))
  12174           (if jmp (setq jmp (point)))
  12175           ) ;save-excursion
  12176         (if jmp (goto-char jmp))
  12177         ) ;when not ins
  12178       ) ;when epp
  12179     epp))
  12180 
  12181 (defun web-mode-detect-content-type ()
  12182   (cond
  12183     ((and (string= web-mode-engine "none")
  12184           (< (point) 16)
  12185           (eq (char-after 1) ?\#)
  12186           (string-match-p "php" (buffer-substring-no-properties
  12187                                  (line-beginning-position)
  12188                                  (line-end-position))))
  12189      (web-mode-set-engine "php"))
  12190     ((and (string= web-mode-content-type "javascript")
  12191           (< (point) web-mode-chunk-length)
  12192           (eq (char-after (point-min)) ?\/)
  12193           (string-match-p "@jsx" (buffer-substring-no-properties
  12194                                   (line-beginning-position)
  12195                                   (line-end-position))))
  12196      (web-mode-set-content-type "jsx"))
  12197     ))
  12198 
  12199 (defun web-mode-auto-complete ()
  12200   "Autocomple at point."
  12201   (interactive)
  12202   (let ((pos (point))
  12203         (char (char-before))
  12204         (chunk (buffer-substring-no-properties (- (point) 2) (point)))
  12205         (expanders nil) (tag nil)
  12206         (auto-closed   nil)
  12207         (auto-expanded nil)
  12208         (auto-paired   nil)
  12209         (auto-quoted   nil))
  12210 
  12211     ;;-- auto-closing
  12212     (when web-mode-enable-auto-closing
  12213 
  12214       (cond
  12215 
  12216         ((and (= web-mode-auto-close-style 3)
  12217               (eq char ?\<))
  12218          (insert "/>")
  12219          (backward-char 2)
  12220          (setq auto-closed t))
  12221 
  12222         ((and (= web-mode-auto-close-style 3)
  12223               (eq char ?\>)
  12224               (looking-at-p "/>"))
  12225          (save-excursion
  12226            (re-search-backward web-mode-start-tag-regexp)
  12227            (setq tag (match-string-no-properties 1)))
  12228          (insert "<")
  12229          (forward-char)
  12230          (insert tag)
  12231          (setq auto-closed t))
  12232 
  12233         ((and (>= pos 4)
  12234               (or (string= "</" chunk)
  12235                   ;;(progn (message "%c" char) nil)
  12236                   (and (= web-mode-auto-close-style 2)
  12237                        (or (string= web-mode-content-type "jsx")
  12238                            (not (get-text-property pos 'part-side)))
  12239                        (string-match-p "[[:alnum:]'\"]>" chunk)))
  12240               (not (get-text-property (- pos 2) 'block-side))
  12241               (web-mode-element-close))
  12242          (setq auto-closed t))
  12243 
  12244         ) ;cond
  12245       ) ;when
  12246 
  12247     ;;-- auto-pairing
  12248     (when (and web-mode-enable-auto-pairing
  12249                (>= pos 4)
  12250                (not auto-closed))
  12251       (let ((i 0) expr after pos-end (l (length web-mode-auto-pairs)))
  12252         (setq pos-end (if (> (+ pos 32) (line-end-position))
  12253                           (line-end-position)
  12254                           (+ pos 10)))
  12255         (setq chunk (buffer-substring-no-properties (- pos 3) pos)
  12256               after (buffer-substring-no-properties pos pos-end))
  12257         (while (and (< i l) (not auto-paired))
  12258           (setq expr (elt web-mode-auto-pairs i)
  12259                 i (1+ i))
  12260           ;;(message "chunk=%S expr=%S after=%S" chunk expr after)
  12261           (when (and (string= (car expr) chunk)
  12262                      (not (string-match-p (regexp-quote (cdr expr)) after)))
  12263             (setq auto-paired t)
  12264             (insert (cdr expr))
  12265             (if (string-match-p "|" (cdr expr))
  12266                 (progn
  12267                   (search-backward "|")
  12268                   (delete-char 1))
  12269                 (goto-char pos))
  12270             ) ;when
  12271           ) ;while
  12272         ) ;let
  12273       )
  12274 
  12275     ;;-- auto-expanding
  12276     (when (and web-mode-enable-auto-expanding
  12277                (not auto-closed)
  12278                (not auto-paired)
  12279                (eq char ?\/)
  12280                (looking-back "\\(^\\|[[:punct:][:space:]>]\\)./" (point-min))
  12281                (or (web-mode-jsx-is-html (1- pos))
  12282                    (and (not (get-text-property (1- pos) 'tag-type))
  12283                         (not (get-text-property (1- pos) 'part-side))))
  12284                (not (get-text-property (1- pos) 'block-side))
  12285                )
  12286       (setq expanders (append web-mode-extra-expanders web-mode-expanders))
  12287       (let ((i 0) pair (l (length expanders)))
  12288         (setq chunk (buffer-substring-no-properties (- pos 2) pos))
  12289         ;;(message "%S" chunk)
  12290         (while (and (< i l) (not auto-expanded))
  12291           (setq pair (elt expanders i)
  12292                 i (1+ i))
  12293           (when (string= (car pair) chunk)
  12294             (setq auto-expanded t)
  12295             (delete-char -2)
  12296             (insert (cdr pair))
  12297             (when (string-match-p "|" (cdr pair))
  12298               (search-backward "|")
  12299               (delete-char 1))
  12300             ) ;when
  12301           ) ;while
  12302         ) ;let
  12303       )
  12304 
  12305     ;;-- auto-quoting
  12306     (when (and web-mode-enable-auto-quoting
  12307                (>= pos 4)
  12308                (not (get-text-property pos 'block-side))
  12309                (not auto-closed)
  12310                (not auto-paired)
  12311                (not auto-expanded)
  12312                (get-text-property (- pos 2) 'tag-attr))
  12313       (cond
  12314         ((and (eq char ?\=)
  12315               (not (looking-at-p "[ ]*[\"']")))
  12316          (cond ((= web-mode-auto-quote-style 2)
  12317                 (insert "''"))
  12318                ((= web-mode-auto-quote-style 3)
  12319                 (insert "{}"))
  12320                (t
  12321                 (insert "\"\"")))
  12322          (if (looking-at-p "[ \n>]")
  12323              (backward-char)
  12324              (insert " ")
  12325              (backward-char 2)
  12326              )
  12327          (setq auto-quoted t))
  12328         ((and (eq char ?\")
  12329               (looking-back "=[ ]*\"" (point-min))
  12330               (not (looking-at-p "[ ]*[\"]")))
  12331          (insert-and-inherit "\"")
  12332          (backward-char)
  12333          (setq auto-quoted t))
  12334         ((and (eq char ?\')
  12335               (looking-back "=[ ]*'" (point-min))
  12336               (not (looking-at-p "[ ]*[']")))
  12337          (insert-and-inherit "'")
  12338          (backward-char)
  12339          (setq auto-quoted t))
  12340         ((and (eq char ?\{)
  12341               (eq (get-text-property pos 'part-side) 'jsx)
  12342               (looking-back "=[ ]*{" (point-min))
  12343               (not (looking-at-p "[ ]*[}]")))
  12344          (insert-and-inherit "}")
  12345          (backward-char)
  12346          (setq auto-quoted t))
  12347         ((and (eq char ?\")
  12348               (eq (char-after) ?\"))
  12349          (delete-char 1)
  12350          (cond
  12351            ((looking-back "=\"\"" (point-min))
  12352             (backward-char))
  12353            ((eq (char-after) ?\s)
  12354             (forward-char))
  12355            (t
  12356             (insert " "))
  12357            ) ;cond
  12358          )
  12359         ) ;cond
  12360       ) ;when
  12361 
  12362     ;;--
  12363     (cond
  12364       ((or auto-closed auto-paired auto-expanded auto-quoted)
  12365        (when (and web-mode-change-end (>= (line-end-position) web-mode-change-end))
  12366          (setq web-mode-change-end (line-end-position)))
  12367        (list :auto-closed auto-closed
  12368              :auto-paired auto-paired
  12369              :auto-expanded auto-expanded
  12370              :auto-quoted auto-quoted))
  12371       (t
  12372        nil)
  12373       )
  12374 
  12375     ))
  12376 
  12377 (defun web-mode-dom-xpath (&optional pos)
  12378   "Display html path."
  12379   (interactive)
  12380   (unless pos (setq pos (point)))
  12381   (save-excursion
  12382     (goto-char pos)
  12383     (let (path tag)
  12384       (while (web-mode-element-parent)
  12385         (looking-at web-mode-tag-regexp)
  12386         (setq tag (match-string-no-properties 1))
  12387         (setq path (cons tag path))
  12388         )
  12389       (message "/%s" (mapconcat 'identity path "/"))
  12390       )))
  12391 
  12392 (defun web-mode-block-ends-with (regexp &optional pos)
  12393   (unless pos (setq pos (point)))
  12394   (save-excursion
  12395     (goto-char pos)
  12396     (save-match-data
  12397       (if (stringp regexp)
  12398           (and (web-mode-block-end)
  12399                (progn (backward-char) t)
  12400                (web-mode-block-skip-blank-backward)
  12401                (progn (forward-char) t)
  12402                (looking-back regexp (point-min)))
  12403           (let ((pair regexp)
  12404                 (block-beg (web-mode-block-beginning-position pos))
  12405                 (block-end (web-mode-block-end-position pos)))
  12406             (and (web-mode-block-end)
  12407                  (web-mode-block-sb (car pair) block-beg)
  12408                  (not (web-mode-sf (cdr pair) block-end)))
  12409             ) ;let
  12410           ) ;if
  12411       )))
  12412 
  12413 (defun web-mode-block-token-starts-with (regexp &optional pos)
  12414   (unless pos (setq pos (point)))
  12415   (save-excursion
  12416     (and (goto-char pos)
  12417          (web-mode-block-token-beginning)
  12418          (skip-chars-forward "[\"']")
  12419          (looking-at regexp))
  12420     ))
  12421 
  12422 (defun web-mode-block-starts-with (regexp &optional pos)
  12423   (unless pos (setq pos (point)))
  12424   (save-excursion
  12425     (and (web-mode-block-beginning)
  12426          (web-mode-block-skip-blank-forward)
  12427          (looking-at regexp))
  12428     ))
  12429 
  12430 (defun web-mode-block-skip-blank-backward (&optional pos)
  12431   (unless pos (setq pos (point)))
  12432   (let ((continue t))
  12433     (goto-char pos)
  12434     (while continue
  12435       (if (and (get-text-property (point) 'block-side)
  12436                (not (bobp))
  12437                (or (member (char-after) '(?\s ?\n))
  12438                    (member (get-text-property (point) 'block-token)
  12439                            '(delimiter-beg delimiter-end comment))))
  12440           (backward-char)
  12441           (setq continue nil))
  12442       ) ;while
  12443     (point)))
  12444 
  12445 (defun web-mode-block-skip-blank-forward (&optional pos props)
  12446   (unless pos (setq pos (point)))
  12447   (unless props (setq props '(delimiter-beg delimiter-end comment)))
  12448   (let ((continue t))
  12449     (goto-char pos)
  12450     (while continue
  12451       (if (and (get-text-property (point) 'block-side)
  12452                (or (member (char-after) '(?\s ?\n ?\t))
  12453                    (member (get-text-property (point) 'block-token) props)))
  12454           (forward-char)
  12455           (setq continue nil))
  12456       ) ;while
  12457     (point)))
  12458 
  12459 (defun web-mode-tag-attributes-sort (&optional pos)
  12460   "Sort the attributes inside the current html tag."
  12461   (interactive)
  12462   (unless pos (setq pos (point)))
  12463   (save-excursion
  12464     (let (attrs (continue t) min max tag-beg tag-end attr attr-name attr-beg attr-end indent sorter ins)
  12465       (if (not (member (get-text-property pos 'tag-type) '(start void)))
  12466           nil
  12467           (setq tag-beg (web-mode-tag-beginning-position pos)
  12468                 tag-end (web-mode-tag-end-position))
  12469           ;;        (message "%S %S" tag-beg tag-end)
  12470           (goto-char tag-beg)
  12471           (while continue
  12472             (if (or (not (web-mode-attribute-next))
  12473                     (>= (point) tag-end))
  12474                 (setq continue nil)
  12475                 ;;(message "attr=%S" (point))
  12476                 (setq attr-beg (web-mode-attribute-beginning-position)
  12477                       attr-end (1+ (web-mode-attribute-end-position)))
  12478                 (when (null min)
  12479                   (setq min attr-beg))
  12480                 (setq max attr-end)
  12481                 (goto-char attr-beg)
  12482                 (setq attr (buffer-substring-no-properties attr-beg attr-end))
  12483                 (if (string-match "^\\([[:alnum:]-]+\\)=" attr)
  12484                     (setq attr-name (match-string-no-properties 1 attr))
  12485                     (setq attr-name attr))
  12486                 (setq indent (looking-back "^[ \t]*" (point-min)))
  12487                 (setq attrs (append attrs (list (list attr-beg attr-end attr-name attr indent))))
  12488                 ) ;if
  12489             ) ;while
  12490           ) ;if in tag
  12491       (when attrs
  12492         (setq sorter (function
  12493                       (lambda (elt1 elt2)
  12494                        (string< (nth 2 elt1) (nth 2 elt2))
  12495                        )))
  12496         (setq attrs (sort attrs sorter))
  12497         (delete-region (1- min) max)
  12498         (setq ins "")
  12499         (dolist (elt attrs)
  12500           (if (and (nth 4 elt) (> (length ins) 1))
  12501               (setq ins (concat ins "\n"))
  12502               (setq ins (concat ins " ")))
  12503           (setq ins (concat ins (nth 3 elt)))
  12504           )
  12505         (goto-char (1- min))
  12506         (insert ins)
  12507         (web-mode-tag-beginning)
  12508         (setq min (line-beginning-position))
  12509         (web-mode-tag-end)
  12510         (setq max (line-end-position))
  12511         (indent-region min max)
  12512         )
  12513       ;;(message "attrs=%S" attrs)
  12514       )))
  12515 
  12516 (defun web-mode-attribute-insert (&optional _attr-name _attr-value)
  12517   "Insert an attribute inside current tag."
  12518   (interactive)
  12519   (let (attr attr-name attr-value)
  12520     (cond
  12521       ((not (member (get-text-property (point) 'tag-type) '(start void)))
  12522        (message "attribute-insert ** invalid context **"))
  12523       ((not (and (setq attr-name (or attr-name (completing-read
  12524                                                 "Attribute name: "
  12525                                                 (append
  12526                                                  web-mode-attribute-list
  12527                                                  web-mode-attribute-history)
  12528                                                 nil nil nil 'web-mode-attribute-history)))
  12529                  (> (length attr-name) 0)))
  12530        (message "attribute-insert ** failure **"))
  12531       (t
  12532        (setq attr (concat " " attr-name))
  12533        (when (setq attr-value (or attr-value (completing-read
  12534                                               "Attribute value: "
  12535                                               web-mode-attribute-value-history
  12536                                               nil nil nil 'web-mode-attribute-value-history)))
  12537          (setq attr (concat attr "=\"" attr-value "\"")))
  12538        (web-mode-tag-end)
  12539        (if (looking-back "/>" (point-min))
  12540            (backward-char 2)
  12541            (backward-char))
  12542        (insert attr)
  12543        ) ;t
  12544       ) ;cond
  12545     ))
  12546 
  12547 (defun web-mode-attribute-transpose (&optional pos)
  12548   "Transpose the current html attribute."
  12549   (interactive)
  12550   (unless pos (setq pos (point)))
  12551   (let (attr-beg attr-end next-beg next-end tag-end)
  12552     (when (and (get-text-property pos 'tag-attr)
  12553                (setq next-beg (web-mode-attribute-next-position pos))
  12554                (setq next-end (web-mode-attribute-end-position next-beg))
  12555                (setq tag-end (web-mode-tag-end-position pos))
  12556                (> tag-end next-end))
  12557       (setq attr-beg (web-mode-attribute-beginning-position pos)
  12558             attr-end (web-mode-attribute-end-position pos))
  12559       ;;      (message "%S %S - %S %S" attr-beg attr-end next-beg next-end)
  12560       (transpose-regions attr-beg (1+ attr-end) next-beg (1+ next-end))
  12561       )))
  12562 
  12563 (defun web-mode-attribute-select (&optional pos)
  12564   "Select the current html attribute."
  12565   (interactive)
  12566   (unless pos (setq pos (point)))
  12567   (if (null (get-text-property pos 'tag-attr))
  12568       nil
  12569       (goto-char pos)
  12570       (web-mode-attribute-beginning)
  12571       (set-mark (point))
  12572       (web-mode-attribute-end)
  12573       (exchange-point-and-mark)
  12574       (point)
  12575       ))
  12576 
  12577 (defun web-mode-attribute-kill (&optional arg)
  12578   "Kill the current html attribute."
  12579   (interactive "p")
  12580   (unless arg (setq arg 1))
  12581   (while (>= arg 1)
  12582     (setq arg (1- arg))
  12583     (web-mode-attribute-select)
  12584     (when mark-active
  12585       (let ((beg (region-beginning)) (end (region-end)))
  12586         (save-excursion
  12587           (goto-char end)
  12588           (when (looking-at "[ \n\t]*")
  12589             (setq end (+ end (length (match-string-no-properties 0)))))
  12590           ) ;save-excursion
  12591         (kill-region beg end)
  12592         ) ;let
  12593       ) ;when
  12594     ) ;while
  12595   ;; Delete a potential space before the closing ">".
  12596   (when (and (looking-at ">")
  12597              (looking-back " " (point-min)))
  12598     (delete-char -1))
  12599   )
  12600 
  12601 (defun web-mode-block-close (&optional pos)
  12602   "Close the first unclosed control block."
  12603   (interactive)
  12604   (unless pos (setq pos (point)))
  12605   (let ((continue t)
  12606         (h (make-hash-table :test 'equal)) ctx ctrl n closing-block)
  12607     (save-excursion
  12608       (while (and continue (web-mode-block-previous))
  12609         (when (setq ctx (web-mode-block-is-control (point)))
  12610           (setq ctrl (car ctx))
  12611           (setq n (gethash ctrl h 0))
  12612           (if (cdr ctx)
  12613               (puthash ctrl (1+ n) h)
  12614               (puthash ctrl (1- n) h))
  12615           (when (> (gethash ctrl h) 0)
  12616             (setq continue nil))
  12617           )
  12618         ) ;while
  12619       ) ;save-excursion
  12620     (when (and (null continue)
  12621                (setq closing-block (web-mode-closing-block ctrl)))
  12622       (insert closing-block)
  12623       (indent-according-to-mode))
  12624     ))
  12625 
  12626 (defun web-mode-closing-block (type)
  12627   (cond
  12628     ((string= web-mode-engine "php")              (concat "<?php end" type "; ?>"))
  12629     ((string= web-mode-engine "django")           (concat "{% end" type " %}"))
  12630     ((string= web-mode-engine "antlers")          (concat "{{/" type "}}"))
  12631     ((string= web-mode-engine "ctemplate")        (concat "{{/" type "}}"))
  12632     ((string= web-mode-engine "blade")
  12633      (if (string= type "section") (concat "@show") (concat "@end" type)))
  12634     ((string= web-mode-engine "dust")             (concat "{/" type "}"))
  12635     ((string= web-mode-engine "mako")             (concat "% end" type))
  12636     ((string= web-mode-engine "closure")          (concat "{/" type "}"))
  12637     ((string= web-mode-engine "smarty")           (concat "{/" type "}"))
  12638     ((string= web-mode-engine "expressionengine") (concat "{/" type "}"))
  12639     ((string= web-mode-engine "xoops")            (concat "<{/" type "}>"))
  12640     ((string= web-mode-engine "svelte")           (concat "{/" type "}"))
  12641     ((string= web-mode-engine "underscore")        "<% } %>")
  12642     ((string= web-mode-engine "lsp")               "<% ) %>")
  12643     ((string= web-mode-engine "erb")               "<% } %>")
  12644     ((string= web-mode-engine "erb")               "<% end %>")
  12645     ((string= web-mode-engine "artanis")           "<% ) %>")
  12646     ((string= web-mode-engine "hero")              "<% } %>")
  12647     ((string= web-mode-engine "go")                "{{end}}")
  12648     ((string= web-mode-engine "velocity")          "#end")
  12649     ((string= web-mode-engine "velocity")          "#{end}")
  12650     ((string= web-mode-engine "template-toolkit")  "[% end %]")
  12651     ((member web-mode-engine '("asp" "jsp"))
  12652      (if (string-match-p "[:.]" type) (concat "</" type ">") "<% } %>"))
  12653     (t nil)
  12654     ) ;cond
  12655   )
  12656 
  12657 ;;---- POSITION ----------------------------------------------------------------
  12658 
  12659 (defun web-mode-comment-beginning-position (&optional pos)
  12660   (unless pos (setq pos (point)))
  12661   (car (web-mode-comment-boundaries pos)))
  12662 
  12663 (defun web-mode-comment-end-position (&optional pos)
  12664   (unless pos (setq pos (point)))
  12665   (cdr (web-mode-comment-boundaries pos)))
  12666 
  12667 (defun web-mode-part-opening-paren-position (pos &optional limit)
  12668   (save-restriction
  12669     (unless limit (setq limit nil))
  12670     (goto-char pos)
  12671     (let* ((n -1)
  12672            (paren (char-after))
  12673            (pairs '((?\) . "[)(]")
  12674                     (?\] . "[\]\[]")
  12675                     (?\} . "[}{]")
  12676                     (?\> . "[><]")))
  12677            (regexp (cdr (assoc paren pairs)))
  12678            (continue (not (null regexp)))
  12679            (counter 0))
  12680       (while (and continue (re-search-backward regexp limit t))
  12681         (cond
  12682           ((> (setq counter (1+ counter)) 500)
  12683            (message "part-opening-paren-position ** warning **")
  12684            (setq continue nil))
  12685           ((or (web-mode-is-comment-or-string)
  12686                (get-text-property (point) 'block-side))
  12687            )
  12688           ((eq (char-after) paren)
  12689            (setq n (1- n)))
  12690           (t
  12691            (setq n (1+ n))
  12692            (setq continue (not (= n 0))))
  12693           )
  12694         ) ;while
  12695       (if (= n 0) (point) nil)
  12696       )))
  12697 
  12698 (defun web-mode-token-opening-paren-position (pos limit _context)
  12699   (save-restriction
  12700     (unless limit (setq limit nil))
  12701     (goto-char pos)
  12702     (let* ((n -1)
  12703            (paren (char-after))
  12704            (pairs '((?\) . "[)(]")
  12705                     (?\] . "[\]\[]")
  12706                     (?\} . "[}{]")
  12707                     (?\> . "[><]")))
  12708            (regexp (cdr (assoc paren pairs)))
  12709            (continue (not (null regexp)))
  12710            (counter 0))
  12711       (while (and continue (re-search-backward regexp limit t))
  12712         (cond
  12713           ((> (setq counter (1+ counter)) 200)
  12714            (message "token-opening-paren-position ** warning **")
  12715            (setq continue nil))
  12716           ((get-text-property (point) 'block-side)
  12717            )
  12718           ((eq (char-after) paren)
  12719            (setq n (1- n)))
  12720           (t
  12721            (setq n (1+ n))
  12722            (setq continue (not (= n 0))))
  12723           )
  12724         ) ;while
  12725       (if (= n 0) (point) nil)
  12726       )))
  12727 
  12728 (defun web-mode-closing-paren-position (&optional pos limit)
  12729   (save-excursion
  12730     (unless pos (setq pos (point)))
  12731     (unless limit (setq limit nil))
  12732     (goto-char pos)
  12733     (let* ((n 0)
  12734            (block-side (and (get-text-property pos 'block-side)
  12735                             (not (string= web-mode-engine "razor"))))
  12736            (paren (char-after))
  12737            (pairs '((?\( . "[)(]")
  12738                     (?\[ . "[\]\[]")
  12739                     (?\{ . "[}{]")
  12740                     (?\< . "[><]")))
  12741            (regexp (cdr (assoc paren pairs)))
  12742            (continue (not (null regexp))))
  12743       (while (and continue (re-search-forward regexp limit t))
  12744         (cond
  12745           ((or (web-mode-is-comment-or-string (1- (point)))
  12746                (and block-side (not (get-text-property (point) 'block-side))))
  12747            ;;(message "pt=%S" (point))
  12748            )
  12749           ((eq (char-before) paren)
  12750            (setq n (1+ n)))
  12751           (t
  12752            (setq n (1- n))
  12753            (setq continue (not (= n 0)))
  12754            )
  12755           ) ;cond
  12756         ) ;while
  12757       (if (= n 0) (1- (point)) nil)
  12758       )))
  12759 
  12760 (defun web-mode-closing-delimiter-position (delimiter &optional pos limit)
  12761   (unless pos (setq pos (point)))
  12762   (unless limit (setq limit nil))
  12763   (save-excursion
  12764     (goto-char pos)
  12765     (setq pos nil)
  12766     (let ((continue t))
  12767       (while (and continue (re-search-forward delimiter limit t))
  12768         (setq continue nil
  12769               pos (1- (point)))
  12770         ) ;while
  12771       pos)))
  12772 
  12773 (defun web-mode-tag-match-position (&optional pos)
  12774   (unless pos (setq pos (point)))
  12775   (save-excursion
  12776     (web-mode-tag-match pos)
  12777     (if (= pos (point)) nil (point))))
  12778 
  12779 (defun web-mode-tag-beginning-position (&optional pos)
  12780   (unless pos (setq pos (point)))
  12781   (let (beg depth)
  12782     (setq depth (get-text-property pos 'jsx-depth))
  12783     (when (and depth (get-text-property pos 'tag-attr-beg))
  12784       (setq depth (get-text-property (1- pos) 'jsx-depth)))
  12785     (cond
  12786       ((null pos))
  12787       ((get-text-property pos 'tag-beg)
  12788        (setq beg pos))
  12789       ((and (> pos 1) (get-text-property (1- pos) 'tag-beg))
  12790        (setq beg (1- pos)))
  12791       ((get-text-property pos 'tag-type)
  12792        (setq beg (previous-single-property-change pos 'tag-beg))
  12793        (when beg (setq beg (1- beg)))
  12794        (cond
  12795          ((not (get-text-property beg 'tag-beg))
  12796           (setq beg nil))
  12797          ((and depth (not (eq depth (get-text-property beg 'jsx-depth))))
  12798           (let ((continue (> beg (point-min))))
  12799             (while continue
  12800               (setq beg (previous-single-property-change beg 'tag-beg))
  12801               (when beg (setq beg (1- beg)))
  12802               (cond
  12803                 ((null beg)
  12804                  (setq continue nil))
  12805                 ((not (get-text-property beg 'tag-beg))
  12806                  (setq continue nil
  12807                        beg nil))
  12808                 ((eq depth (get-text-property beg 'jsx-depth))
  12809                  (setq continue nil))
  12810                 ) ;cond
  12811               ) ;while
  12812             ) ;let
  12813           )
  12814          ) ;cond
  12815        )
  12816       (t
  12817        (setq beg nil))
  12818       ) ;cond
  12819     beg))
  12820 
  12821 (defun web-mode-tag-end-position (&optional pos)
  12822   (unless pos (setq pos (point)))
  12823   (let (end depth)
  12824     (setq depth (get-text-property pos 'jsx-depth))
  12825     (when (and depth (get-text-property pos 'tag-attr-beg))
  12826       (setq depth (get-text-property (1- pos) 'jsx-depth)))
  12827     (cond
  12828       ((null pos)
  12829        (setq end nil))
  12830       ((get-text-property pos 'tag-end)
  12831        (setq end pos))
  12832       ((get-text-property pos 'tag-type)
  12833        (setq end (next-single-property-change pos 'tag-end))
  12834        (cond
  12835          ((not (get-text-property end 'tag-end))
  12836           (setq end nil))
  12837          ((and depth (not (eq depth (get-text-property end 'jsx-depth))))
  12838           (let ((continue (< end (point-max))))
  12839             (while continue
  12840               (setq end (1+ end))
  12841               (setq end (next-single-property-change end 'tag-end))
  12842               (cond
  12843                 ((null end)
  12844                  (setq continue nil))
  12845                 ((not (get-text-property end 'tag-end))
  12846                  (setq continue nil
  12847                        end nil))
  12848                 ((eq depth (get-text-property end 'jsx-depth))
  12849                  (setq continue nil))
  12850                 ) ;cond
  12851               ) ;while
  12852             ) ;let
  12853           )
  12854          ) ;cond
  12855        )
  12856       (t
  12857        (setq end nil))
  12858       ) ;cond
  12859     end))
  12860 
  12861 ;; TODO: prendre en compte jsx-depth
  12862 (defun web-mode-tag-next-position (&optional pos limit)
  12863   (unless pos (setq pos (point)))
  12864   (unless limit (setq limit (point-max)))
  12865   (cond
  12866     ((or (>= pos (point-max)) (>= pos limit)) nil)
  12867     (t
  12868      (when (get-text-property pos 'tag-beg) (setq pos (1+ pos)))
  12869      (setq pos (next-single-property-change pos 'tag-beg))
  12870      (if (and pos (<= pos limit)) pos nil))
  12871     ))
  12872 
  12873 ;; TODO: prendre en compte jsx-depth
  12874 (defun web-mode-tag-previous-position (&optional pos limit)
  12875   (unless pos (setq pos (point)))
  12876   (unless limit (setq limit (point-min)))
  12877   (cond
  12878     ((or (<= pos (point-min)) (<= pos limit)) nil)
  12879     (t
  12880      (when (get-text-property pos 'tag-beg) (setq pos (1- pos)))
  12881      (web-mode-go (previous-single-property-change pos 'tag-beg) -1))
  12882     ))
  12883 
  12884 ;; TODO: prendre en compte jsx-depth
  12885 (defun web-mode-attribute-beginning-position (&optional pos)
  12886   (unless pos (setq pos (point)))
  12887   (cond
  12888     ((null (get-text-property pos 'tag-attr))
  12889      nil)
  12890     ((get-text-property pos 'tag-attr-beg)
  12891      pos)
  12892     ((and (> pos (point-min)) (get-text-property (1- pos) 'tag-attr-beg))
  12893      (1- pos))
  12894     (t
  12895      (setq pos (previous-single-property-change pos 'tag-attr-beg))
  12896      (setq pos (1- pos)))
  12897     ))
  12898 
  12899 ;; TODO: retoucher en incluant un param limit et en s'inspirant de
  12900 ;;       web-mode-attribute-next-position
  12901 (defun web-mode-attribute-end-position (&optional pos)
  12902   (unless pos (setq pos (point)))
  12903   (let (beg end depth flags)
  12904     ;;(message "pos=%S" pos)
  12905     (setq depth (get-text-property pos 'jsx-depth))
  12906     (cond
  12907       ((null pos)
  12908        (setq end nil))
  12909       ((get-text-property pos 'tag-attr-end)
  12910        (setq end pos))
  12911       ((get-text-property pos 'tag-attr)
  12912        (setq end (next-single-property-change pos 'tag-attr-end))
  12913        (when (and depth
  12914                   end
  12915                   (setq beg (web-mode-attribute-beginning-position end))
  12916                   (setq flags (get-text-property pos 'tag-attr-beg))
  12917                   (eq (logand flags 4) 4))
  12918          (setq depth (1- (get-text-property beg 'jsx-depth)))
  12919          ;;(message "%S %S" beg end)
  12920          )
  12921        (cond
  12922          ((not (get-text-property end 'tag-attr-end))
  12923           (setq end nil))
  12924          ((and depth
  12925                (eq depth (get-text-property end 'jsx-depth))
  12926                (not (eq depth (get-text-property end 'jsx-end))))
  12927           )
  12928          ((and depth (eq (1+ depth) (get-text-property end 'jsx-depth)))
  12929           )
  12930          ((and depth (not (eq (1+ depth) (get-text-property end 'jsx-depth))))
  12931           (let ((continue (< end (point-max))))
  12932             (while continue
  12933               (setq end (1+ end))
  12934               (setq end (next-single-property-change end 'tag-attr-end))
  12935               (cond
  12936                 ((null end)
  12937                  (setq continue nil))
  12938                 ((not (get-text-property end 'tag-attr-end))
  12939                  (setq continue nil
  12940                        end nil))
  12941                 ((eq (1+ depth) (get-text-property end 'jsx-depth))
  12942                  (setq continue nil))
  12943                 ) ;cond
  12944               ) ;while
  12945             ) ;let
  12946           )
  12947          ) ;cond
  12948        )
  12949       (t
  12950        (setq end nil))
  12951       ) ;cond
  12952     end))
  12953 
  12954 ;; attention si pos est au debut d'un spread attributes, cela
  12955 ;; risque de poser pb
  12956 (defun web-mode-attribute-next-position (&optional pos limit)
  12957   (unless pos (setq pos (point)))
  12958   (unless limit (setq limit (point-max)))
  12959   (let (continue depth)
  12960     (when (get-text-property pos 'tag-attr-beg)
  12961       (setq pos (1+ pos)))
  12962     (if (< pos limit)
  12963         (setq continue t
  12964               depth (get-text-property pos 'jsx-depth))
  12965         (setq continue nil
  12966               pos nil))
  12967     (while continue
  12968       (setq pos (next-single-property-change pos 'tag-attr-beg))
  12969       (cond
  12970         ((null pos)
  12971          (setq continue nil))
  12972         ((>= pos limit)
  12973          (setq continue nil
  12974                pos nil))
  12975         ((null depth)
  12976          (setq continue nil))
  12977         ((and (eq (get-text-property pos 'tag-attr-beg) 4)
  12978               (eq (1+ depth) (get-text-property pos 'jsx-depth)))
  12979          (setq continue nil))
  12980         ((eq depth (get-text-property pos 'jsx-depth))
  12981          (setq continue nil))
  12982         (t
  12983          (setq pos (1+ pos)
  12984                continue (< pos limit)))
  12985         )
  12986       ) ;while
  12987     pos))
  12988 
  12989 (defun web-mode-attribute-previous-position (&optional pos limit)
  12990   (unless pos (setq pos (point)))
  12991   (unless limit (setq limit (point-min)))
  12992   (let (continue depth)
  12993     (cond
  12994       ((and (> pos (point-min)) (get-text-property (1- pos) 'tag-attr-beg))
  12995        (setq pos (1- pos)
  12996              continue nil))
  12997       (t
  12998        (when (get-text-property pos 'tag-attr-beg)
  12999          (setq pos (1- pos)))
  13000        (if (> pos limit)
  13001            (setq continue t
  13002                  depth (get-text-property pos 'jsx-depth))
  13003            (setq continue nil
  13004                  pos nil))
  13005        ) ;t
  13006       ) ;cond
  13007     (while continue
  13008       (setq pos (previous-single-property-change pos 'tag-attr-beg))
  13009       (cond
  13010         ((null pos)
  13011          (setq continue nil))
  13012         ((< pos limit)
  13013          (setq continue nil
  13014                pos nil))
  13015         ;;((null depth)
  13016         ;; (setq continue nil))
  13017         ((and depth (eq depth (get-text-property pos 'jsx-depth)))
  13018          (setq  pos (1- pos)
  13019                 continue nil))
  13020         (depth
  13021          (setq pos nil
  13022                continue (> pos limit)))
  13023         (t
  13024          (setq pos (1- pos)
  13025                continue nil))
  13026         ) ;cond
  13027       ) ;while
  13028     pos))
  13029 
  13030 ;; TODO: prendre en compte jsx-depth
  13031 (defun web-mode-element-beginning-position (&optional pos)
  13032   (unless pos (setq pos (point)))
  13033   (cond
  13034     ((null (get-text-property pos 'tag-type))
  13035      (setq pos (web-mode-element-parent-position)))
  13036     ((eq (get-text-property pos 'tag-type) 'end)
  13037      (setq pos (web-mode-tag-match-position pos))
  13038      (setq pos (if (get-text-property pos 'tag-beg) pos nil)))
  13039     ((member (get-text-property pos 'tag-type) '(start void))
  13040      (setq pos (web-mode-tag-beginning-position pos)))
  13041     (t
  13042      (setq pos nil))
  13043     ) ;cond
  13044   pos)
  13045 
  13046 ;; TODO: prendre en compte jsx-depth
  13047 (defun web-mode-element-end-position (&optional pos)
  13048   (unless pos (setq pos (point)))
  13049   (cond
  13050     ((null (get-text-property pos 'tag-type))
  13051      (setq pos (web-mode-element-parent-position pos))
  13052      (when pos
  13053        (setq pos (web-mode-tag-match-position pos))
  13054        (when pos (setq pos (web-mode-tag-end-position pos)))
  13055        )
  13056      )
  13057     ((member (get-text-property pos 'tag-type) '(end void comment))
  13058      (setq pos (web-mode-tag-end-position pos))
  13059      )
  13060     ((member (get-text-property pos 'tag-type) '(start))
  13061      (setq pos (web-mode-tag-match-position pos))
  13062      (when pos (setq pos (web-mode-tag-end-position pos))))
  13063     (t
  13064      (setq pos nil))
  13065     ) ;cond
  13066   pos)
  13067 
  13068 (defun web-mode-element-child-position (&optional pos)
  13069   (save-excursion
  13070     (let (child close)
  13071       (unless pos (setq pos (point)))
  13072       (goto-char pos)
  13073       (cond
  13074         ((eq (get-text-property pos 'tag-type) 'start)
  13075          (web-mode-tag-match)
  13076          (setq close (point))
  13077          (goto-char pos)
  13078          )
  13079         ((eq (get-text-property pos 'tag-type) 'void)
  13080          )
  13081         ((eq (get-text-property pos 'tag-type) 'end)
  13082          (web-mode-tag-beginning)
  13083          (setq close (point))
  13084          (web-mode-tag-match)
  13085          )
  13086         ((web-mode-element-parent-position pos)
  13087          (setq pos (point))
  13088          (web-mode-tag-match)
  13089          (setq close (point))
  13090          (goto-char pos)
  13091          )
  13092         ) ;cond
  13093       (when (and close
  13094                  (web-mode-element-next)
  13095                  (< (point) close))
  13096         (setq child (point))
  13097         )
  13098       child)))
  13099 
  13100 (defun web-mode-element-parent-position (&optional pos)
  13101   (let (n tag-type tag-name (continue t) (tags (make-hash-table :test 'equal)))
  13102     (save-excursion
  13103       (if pos (goto-char pos))
  13104       (while (and continue (web-mode-tag-previous))
  13105         (setq pos (point)
  13106               tag-type (get-text-property pos 'tag-type)
  13107               tag-name (get-text-property pos 'tag-name)
  13108               n (gethash tag-name tags 0))
  13109         (when (member tag-type '(end start))
  13110           (if (eq tag-type 'end)
  13111               (puthash tag-name (1- n) tags)
  13112               (puthash tag-name (1+ n) tags)
  13113               (when (= n 0) (setq continue nil))
  13114               ) ;if
  13115           ) ;when
  13116         ) ;while
  13117       ) ;save-excursion
  13118     (if (null continue) pos nil)))
  13119 
  13120 (defun web-mode-element-previous-position (&optional pos limit)
  13121   (unless pos (setq pos (point)))
  13122   (unless limit (setq limit (point-min)))
  13123   (save-excursion
  13124     (goto-char pos)
  13125     (let ((continue (not (bobp)))
  13126           (props '(start void comment)))
  13127       (while continue
  13128         (setq pos (web-mode-tag-previous))
  13129         (cond
  13130           ((or (null pos) (< (point) limit))
  13131            (setq continue nil
  13132                  pos nil))
  13133           ((member (get-text-property (point) 'tag-type) props)
  13134            (setq continue nil))
  13135           )
  13136         ) ;while
  13137       pos)))
  13138 
  13139 (defun web-mode-element-next-position (&optional pos limit)
  13140   (unless pos (setq pos (point)))
  13141   (unless limit (setq limit (point-max)))
  13142   (save-excursion
  13143     (goto-char pos)
  13144     (let ((continue (not (eobp)))
  13145           (props '(start void comment)))
  13146       (while continue
  13147         (setq pos (web-mode-tag-next))
  13148         (cond
  13149           ((or (null pos) (> (point) limit))
  13150            (setq continue nil
  13151                  pos nil))
  13152           ((member (get-text-property (point) 'tag-type) props)
  13153            (setq continue nil))
  13154           )
  13155         ) ;while
  13156       ;;      (message "pos=%S" pos)
  13157       pos)))
  13158 
  13159 (defun web-mode-part-end-position (&optional pos)
  13160   (unless pos (setq pos (point)))
  13161   (cond
  13162     ((member web-mode-content-type web-mode-part-content-types)
  13163      (setq pos (point-max)))
  13164     ((not (get-text-property pos 'part-side))
  13165      (setq pos nil))
  13166     ((= pos (point-max))
  13167      (setq pos nil))
  13168     ((not (get-text-property (1+ pos) 'part-side))
  13169      pos)
  13170     (t
  13171      (setq pos (next-single-property-change pos 'part-side)))
  13172     ) ;cond
  13173   pos)
  13174 
  13175 (defun web-mode-part-beginning-position (&optional pos)
  13176   (unless pos (setq pos (point)))
  13177   (cond
  13178     (web-mode-part-beg
  13179      (setq pos web-mode-part-beg))
  13180     ((member web-mode-content-type web-mode-part-content-types)
  13181      (setq pos (point-min)
  13182            web-mode-part-beg (point-min)))
  13183     ((not (get-text-property pos 'part-side))
  13184      (setq pos nil))
  13185     ((= pos (point-min))
  13186      (setq pos nil))
  13187     ((not (get-text-property (1- pos) 'part-side))
  13188      pos)
  13189     (t
  13190      (setq pos (previous-single-property-change pos 'part-side)))
  13191     ) ;cond
  13192   pos)
  13193 
  13194 (defun web-mode-part-next-position (&optional pos)
  13195   (unless pos (setq pos (point)))
  13196   (cond
  13197     ((and (= pos (point-min)) (get-text-property pos 'part-side))
  13198      )
  13199     ((not (get-text-property pos 'part-side))
  13200      (setq pos (next-single-property-change pos 'part-side)))
  13201     ((and (setq pos (web-mode-part-end-position pos)) (>= pos (point-max)))
  13202      (setq pos nil))
  13203     ((and (setq pos (1+ pos)) (not (get-text-property pos 'part-side)))
  13204      (setq pos (next-single-property-change pos 'part-side)))
  13205     ) ;cond
  13206   pos)
  13207 
  13208 (defun web-mode-block-match-position (&optional pos)
  13209   (unless pos (setq pos (point)))
  13210   (save-excursion
  13211     (web-mode-block-match pos)
  13212     (if (= pos (point)) nil (point))))
  13213 
  13214 ;; type may be nil
  13215 (defun web-mode-block-control-previous-position (type &optional pos)
  13216   (unless pos (setq pos (point)))
  13217   (let ((continue t) controls)
  13218     (while continue
  13219       (setq pos (web-mode-block-previous-position pos))
  13220       (cond
  13221         ((null pos)
  13222          (setq continue nil
  13223                pos nil))
  13224         ((null type)
  13225          (setq continue nil))
  13226         ((and (setq controls (web-mode-block-controls-get pos))
  13227               (eq (car (car controls)) type))
  13228          (setq continue nil))
  13229         ) ;cond
  13230       ) ;while
  13231     pos))
  13232 
  13233 (defun web-mode-inside-block-control (&optional pos)
  13234   (unless pos (setq pos (point)))
  13235   (setq pos (web-mode-block-control-previous-position nil pos))
  13236   (if (and pos (member (car (car (web-mode-block-controls-get pos))) '(open inside)))
  13237       pos
  13238       nil))
  13239 
  13240 (defun web-mode-block-opening-paren-position (pos limit)
  13241   (save-excursion
  13242     (when (> limit pos)
  13243       (message "block-opening-paren-position: limit(%S) > pos(%S)" limit pos))
  13244     (goto-char pos)
  13245     (let (c
  13246           n
  13247           pt
  13248           (continue (> pos limit))
  13249           (pairs '((?\) . ?\()
  13250                    (?\] . ?\[)
  13251                    (?\} . ?\{)))
  13252           (h (make-hash-table :test 'equal))
  13253           (regexp "[\]\[)(}{]"))
  13254       (while (and continue (re-search-backward regexp limit t))
  13255         (cond
  13256           ((web-mode-is-comment-or-string)
  13257            )
  13258           (t
  13259            (setq c (char-after))
  13260            (cond
  13261              ((member c '(?\( ?\{ ?\[))
  13262               (setq n (gethash c h 0))
  13263               (if (= n 0)
  13264                   (setq continue nil
  13265                         pt (point))
  13266                   (puthash c (1+ n) h)
  13267                   ))
  13268              (t
  13269               (setq c (cdr (assoc c pairs)))
  13270               (setq n (gethash c h 0))
  13271               (puthash c (1- n) h))
  13272              ) ;cond
  13273            ) ;t
  13274           ) ;cond
  13275         ) ;while
  13276       pt)))
  13277 
  13278 (defun web-mode-block-code-beginning-position (&optional pos)
  13279   (unless pos (setq pos (point)))
  13280   (when (and (setq pos (web-mode-block-beginning-position pos))
  13281              (eq (get-text-property pos 'block-token) 'delimiter-beg))
  13282     (setq pos (next-single-property-change pos 'block-token)))
  13283   pos)
  13284 
  13285 (defun web-mode-block-beginning-position (&optional pos)
  13286   (unless pos (setq pos (point)))
  13287   (cond
  13288     ((or (and (get-text-property pos 'block-side) (= pos (point-min)))
  13289          (get-text-property pos 'block-beg))
  13290      )
  13291     ((and (> pos (point-min)) (get-text-property (1- pos) 'block-beg))
  13292      (setq pos (1- pos)))
  13293     ((get-text-property pos 'block-side)
  13294      (setq pos (previous-single-property-change pos 'block-beg))
  13295      (setq pos (if (and pos (> pos (point-min))) (1- pos) (point-min))))
  13296     (t
  13297      (setq pos nil))
  13298     ) ;cond
  13299   pos)
  13300 
  13301 (defun web-mode-block-string-beginning-position (pos &optional block-beg)
  13302   (unless pos (setq pos (point)))
  13303   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13304   (let (char (ori pos) (continue (not (null pos))))
  13305     (while continue
  13306       (setq char (char-after pos))
  13307       (cond
  13308         ((< pos block-beg)
  13309          (setq continue nil
  13310                pos block-beg))
  13311         ((and (member (get-text-property pos 'block-token) '(string comment))
  13312               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13313          (setq pos (web-mode-block-token-beginning-position pos))
  13314          )
  13315         ((member char '(?\) ?\]))
  13316          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13317          (setq pos (1- pos))
  13318          )
  13319         ((and (> ori pos) (member char '(?\( ?\= ?\[ ?\? ?\: ?\; ?\, ?\`)))
  13320          (if (and (eq char ?\:) ; #1024
  13321                   (web-mode-looking-at ":" pos))
  13322              (setq pos (1- pos))
  13323              (web-mode-looking-at ".[ \t\n]*" pos)
  13324              (setq pos (+ pos (length (match-string-no-properties 0)))
  13325                    continue nil)
  13326              )
  13327          )
  13328         ((web-mode-looking-at "\\(return\\|echo\\|include\\|print\\)[ \n]" pos)
  13329          (setq pos (+ pos (length (match-string-no-properties 0)))
  13330                continue nil))
  13331         (t
  13332          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?;,`:]\\|\\(return\\|echo\\|include\\|print\\)" block-beg))
  13333          (when (not pos)
  13334            (message "block-string-beginning-position ** search failure **")
  13335            (setq continue nil
  13336                  pos block-beg)))
  13337         ) ;cond
  13338       ) ;while
  13339     ;;(message "pos=%S" pos)
  13340     pos))
  13341 
  13342 (defun web-mode-block-statement-beginning-position (pos block-beg _is-ternary)
  13343   (unless pos (setq pos (point)))
  13344   (setq pos (1- pos))
  13345   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13346   (let (char (continue (not (null pos))))
  13347     (while continue
  13348       (setq char (char-after pos))
  13349       (cond
  13350         ((< pos block-beg)
  13351          (setq continue nil
  13352                pos block-beg))
  13353         ((and (member (get-text-property pos 'block-token) '(string comment))
  13354               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13355          (setq pos (web-mode-block-token-beginning-position pos)))
  13356         ((member char '(?\) ?\] ?\}))
  13357          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13358          (setq pos (1- pos)))
  13359         ((and (eq char ?\=)
  13360               (web-mode-looking-back "[<>!=]+" pos block-beg t))
  13361          (setq pos (- pos 1 (length (match-string-no-properties 0))))
  13362          ;;(setq pos (1- pos))
  13363          ;;(message "%S pos=%S" (match-string-no-properties 0) pos)
  13364          )
  13365         ((member char '(?\( ?\[ ?\{ ?\=))
  13366          (setq continue nil)
  13367          (web-mode-looking-at ".[ \t\n]*" pos)
  13368          (setq pos (+ pos (length (match-string-no-properties 0)))))
  13369         ((web-mode-looking-at "\\(return\\|echo\\|include\\|print\\)[ \n]" pos)
  13370          (setq pos (+ pos (length (match-string-no-properties 0)))
  13371                continue nil))
  13372         (t
  13373          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=]\\|\\(return\\|echo\\|include\\|print\\)" block-beg))
  13374          (when (not pos)
  13375            (message "block-statement-beginning-position ** search failure **")
  13376            (setq continue nil
  13377                  pos block-beg)))
  13378         ) ;cond
  13379       ) ;while
  13380     pos))
  13381 
  13382 (defun web-mode-block-args-beginning-position (pos &optional block-beg)
  13383   (unless pos (setq pos (point)))
  13384   (setq pos (1- pos)) ;#512
  13385   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13386   (let (char (continue (not (null pos))))
  13387     (while continue
  13388       (setq char (char-after pos))
  13389       (cond
  13390         ((< pos block-beg)
  13391          (message "block-args-beginning-position ** failure **")
  13392          (setq continue nil
  13393                pos block-beg))
  13394         ((and (member (get-text-property pos 'block-token) '(string comment))
  13395               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13396          (setq pos (web-mode-block-token-beginning-position pos)))
  13397         ((member char '(?\) ?\] ?\}))
  13398          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13399          (setq pos (1- pos)))
  13400         ((member char '(?\( ?\[ ?\{))
  13401          (setq continue nil)
  13402          (web-mode-looking-at ".[ \t\n]*" pos)
  13403          (setq pos (+ pos (length (match-string-no-properties 0)))))
  13404         ((and (string= web-mode-engine "php")
  13405               (web-mode-looking-at "\\(extends\\|implements\\)[ \n]" pos))
  13406          (setq pos (+ pos (length (match-string-no-properties 0)))
  13407                continue nil))
  13408         (t
  13409          (setq pos (web-mode-rsb-position pos "[\]\[}{)(]\\|\\(extends\\|implements\\)" block-beg))
  13410          (when (not pos)
  13411            (message "block-args-beginning-position ** search failure **")
  13412            (setq pos block-beg
  13413                  continue nil))
  13414          ) ;t
  13415         ) ;cond
  13416       ) ;while
  13417     pos))
  13418 
  13419 (defun web-mode-block-calls-beginning-position (pos &optional block-beg)
  13420   (unless pos (setq pos (point)))
  13421   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13422   (let (char (continue (not (null pos))))
  13423     (while continue
  13424       (setq char (char-after pos))
  13425       (cond
  13426         ((< pos block-beg)
  13427          (message "block-calls-beginning-position ** failure **")
  13428          (setq continue nil
  13429                pos block-beg))
  13430         ((and (member (get-text-property pos 'block-token) '(string comment))
  13431               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13432          (setq pos (web-mode-block-token-beginning-position pos)))
  13433         ((member char '(?\) ?\]))
  13434          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13435          (setq pos (1- pos)))
  13436         ((member char '(?\( ?\[ ?\{ ?\} ?\= ?\? ?\: ?\; ?\,))
  13437          (web-mode-looking-at ".[ \t\n]*" pos)
  13438          (setq pos (+ pos (length (match-string-no-properties 0)))
  13439                continue nil))
  13440         ((web-mode-looking-at "\\(return\\|else\\)[ \n]" pos)
  13441          (setq pos (+ pos (length (match-string-no-properties 0)))
  13442                continue nil))
  13443         (t
  13444          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,]\\|\\(return\\|else\\)" block-beg))
  13445          (when (not pos)
  13446            (message "block-calls-beginning-position ** search failure **")
  13447            (setq pos block-beg
  13448                  continue nil))
  13449          ) ;t
  13450         ) ;cond
  13451       ) ;while
  13452     pos))
  13453 
  13454 (defun web-mode-javascript-string-beginning-position (pos &optional reg-beg)
  13455   (unless pos (setq pos (point)))
  13456   (let ((char nil)
  13457         (blockside (get-text-property pos 'block-side))
  13458         (i 0)
  13459         (continue (not (null pos))))
  13460     (unless reg-beg
  13461       (if blockside
  13462           (setq reg-beg (web-mode-block-beginning-position pos))
  13463           (setq reg-beg (web-mode-part-beginning-position pos)))
  13464       )
  13465     (while continue
  13466       (setq char (char-after pos))
  13467       (cond
  13468         ((> (setq i (1+ i)) 20000)
  13469          (message "javascript-string-beginning-position ** warning (%S) **" pos)
  13470          (setq continue nil
  13471                pos nil))
  13472         ((null pos)
  13473          (message "javascript-string-beginning-position ** invalid pos **")
  13474          (setq continue nil))
  13475         ((< pos reg-beg)
  13476          (message "javascript-string-beginning-position ** failure **")
  13477          (setq continue nil
  13478                pos reg-beg))
  13479         ((and blockside
  13480               (member (get-text-property pos 'block-token) '(string comment))
  13481               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13482          (setq pos (web-mode-block-token-beginning-position pos)))
  13483         ((and (not blockside)
  13484               (member (get-text-property pos 'part-token) '(string comment))
  13485               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13486          (setq pos (web-mode-part-token-beginning-position pos)))
  13487         ((and (not blockside)
  13488               (get-text-property pos 'block-side))
  13489          (when (setq pos (web-mode-block-beginning-position pos))
  13490            (setq pos (1- pos))))
  13491         ((member char '(?\) ?\] ?\}))
  13492          (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13493          (setq pos (1- pos)))
  13494         ((member char '(?\( ?\{ ?\[ ?\= ?\? ?\: ?\; ?\, ?\& ?\|))
  13495          (setq continue nil)
  13496          (web-mode-looking-at ".[ \t\n]*" pos)
  13497          (setq pos (+ pos (length (match-string-no-properties 0)))))
  13498         ((web-mode-looking-at "\\(return\\)[ \n]" pos)
  13499          (setq pos (+ pos (length (match-string-no-properties 0)))
  13500                continue nil))
  13501         (t
  13502          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,&|]\\|\\(return\\)" reg-beg))
  13503          (when (not pos)
  13504            (message "javascript-string-beginning-position ** search failure **")
  13505            (setq continue nil
  13506                  pos reg-beg)))
  13507         ) ;cond
  13508       ) ;while
  13509     ;;(message "js-statement-beg:%S" pos)
  13510     pos))
  13511 
  13512 ;; TODO: reg-beg : jsx-beg
  13513 ;; TODO: skipper les expr dont la depth est superieure
  13514 
  13515 ;; NOTE: blockside is useful for ejs
  13516 (defun web-mode-javascript-statement-beginning-position (pos reg-beg is-ternary)
  13517   (unless pos (setq pos (point)))
  13518   (setq pos (1- pos))
  13519   (let ((char nil)
  13520         (blockside (get-text-property pos 'block-side))
  13521         (i 0)
  13522         (is-jsx (string= web-mode-content-type "jsx"))
  13523         (depth-o nil) (depth-l nil)
  13524         (continue (not (null pos)))
  13525         (regexp "[\]\[}{)(=:]\\|\\(return\\)"))
  13526     (when is-ternary
  13527       (setq regexp (concat regexp "\\|[><]")))
  13528     (setq depth-o (get-text-property pos 'jsx-depth))
  13529     (unless reg-beg
  13530       (cond
  13531         (blockside
  13532          (setq reg-beg (web-mode-block-beginning-position pos)))
  13533         (is-jsx
  13534          (setq reg-beg (web-mode-jsx-depth-beginning-position pos)))
  13535         (t
  13536          (setq reg-beg (web-mode-part-beginning-position pos)))
  13537         ) ;cond
  13538       ) ;unless
  13539     (while continue
  13540       (setq char (char-after pos))
  13541       (cond
  13542         ((> (setq i (1+ i)) 20000)
  13543          (message "javascript-statement-beginning-position ** warning (%S) **" pos)
  13544          (setq continue nil
  13545                pos nil))
  13546         ((null pos)
  13547          (message "javascript-statement-beginning-position ** invalid pos **")
  13548          (setq continue nil))
  13549         ((< pos reg-beg)
  13550          (when (not is-jsx)
  13551            (message "javascript-statement-beginning-position ** failure **"))
  13552          (setq continue nil
  13553                pos reg-beg))
  13554         ((and is-jsx
  13555               (progn (setq depth-l (get-text-property pos 'jsx-depth)) t)
  13556               (not (eq depth-l depth-o)))
  13557          ;;(message "%S > depth-o(%S) depth-l(%S)" pos depth-o depth-l)
  13558          (setq pos (previous-single-property-change pos 'jsx-depth))
  13559          (setq pos (1- pos))
  13560          ;;(message "--> %S %S" pos (get-text-property pos 'jsx-depth))
  13561          )
  13562         ((and blockside
  13563               (member (get-text-property pos 'block-token) '(string comment))
  13564               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13565          (setq pos (web-mode-block-token-beginning-position pos)))
  13566         ((and (not blockside)
  13567               (member (get-text-property pos 'part-token) '(string comment))
  13568               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13569          (setq pos (web-mode-part-token-beginning-position pos)))
  13570         ((and (not blockside)
  13571               (get-text-property pos 'block-side))
  13572          (when (setq pos (web-mode-block-beginning-position pos))
  13573            (setq pos (1- pos))))
  13574         ((member char '(?\) ?\] ?\}))
  13575          (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13576          (setq pos (1- pos)))
  13577         ((and (eq char ?\=)
  13578               (web-mode-looking-back "[<>!=]+" pos reg-beg t))
  13579          (setq pos (- pos 1 (length (match-string-no-properties 0)))))
  13580         ((member char '(?\( ?\{ ?\[ ?\= ?\< ?\>))
  13581          (web-mode-looking-at ".[ \t\n]*" pos)
  13582          (setq continue nil
  13583                pos (+ pos (length (match-string-no-properties 0)))))
  13584 
  13585         ((web-mode-looking-at "\\(return\\)[ \n]" pos)
  13586          (setq continue nil
  13587                pos (+ pos (length (match-string-no-properties 0)))))
  13588         ((and (eq char ?\:)
  13589               (web-mode-looking-back "[{,][ \t\n]*[[:alnum:]_]+[ ]*" pos))
  13590          (web-mode-looking-at ".[ \t\n]*" pos)
  13591          (setq continue nil
  13592                pos (+ pos (length (match-string-no-properties 0)))))
  13593         (t
  13594          (setq pos (web-mode-rsb-position pos regexp reg-beg))
  13595          (when (not pos)
  13596            (cond
  13597              (is-jsx
  13598               (when (web-mode-looking-at "[ \n]*" reg-beg)
  13599                 (setq pos (+ reg-beg (length (match-string-no-properties 0)))))
  13600               (setq continue nil))
  13601              (t
  13602               (message "javascript-statement-beginning-position ** search failure **")
  13603               (setq continue nil
  13604                     pos reg-beg))
  13605              ) ;cond
  13606            )
  13607          ) ;t
  13608         ) ;cond
  13609       ) ;while
  13610     ;;(message "%S -------" pos)
  13611     pos))
  13612 
  13613 (defun web-mode-javascript-args-beginning-position (pos &optional reg-beg)
  13614   (unless pos (setq pos (point)))
  13615   (setq pos (1- pos))
  13616   (let ((char nil)
  13617         (blockside (get-text-property pos 'block-side))
  13618         (i 0)
  13619         (continue (not (null pos))))
  13620     (unless reg-beg
  13621       (if blockside
  13622           (setq reg-beg (web-mode-block-beginning-position pos))
  13623           (setq reg-beg (web-mode-part-beginning-position pos)))
  13624       )
  13625     (while continue
  13626       (setq char (char-after pos))
  13627       ;;(message "pos(%S) char(%c)" pos char)
  13628       (cond
  13629         ((> (setq i (1+ i)) 20000)
  13630          (message "javascript-args-beginning-position ** warning (%S) **" pos)
  13631          (setq continue nil
  13632                pos nil))
  13633         ((null pos)
  13634          (message "javascript-args-beginning-position ** invalid pos **")
  13635          (setq continue nil))
  13636         ((< pos reg-beg)
  13637          (message "javascript-args-beginning-position ** failure(position) **")
  13638          (setq continue nil
  13639                pos reg-beg))
  13640         ((and blockside
  13641               (member (get-text-property pos 'block-token) '(string comment))
  13642               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13643          (setq pos (web-mode-block-token-beginning-position pos)))
  13644         ((and (not blockside)
  13645               (member (get-text-property pos 'part-token) '(string comment))
  13646               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13647          (setq pos (web-mode-part-token-beginning-position pos)))
  13648         ((and (not blockside)
  13649               (get-text-property pos 'block-side))
  13650          (when (setq pos (web-mode-block-beginning-position pos))
  13651            (setq pos (1- pos)))
  13652          )
  13653         ((member char '(?\) ?\] ?\}))
  13654          (when (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13655            (setq pos (1- pos))))
  13656         ((member char '(?\( ?\[ ?\{))
  13657          (web-mode-looking-at ".[ ]*" pos)
  13658          (setq pos (+ pos (length (match-string-no-properties 0)))
  13659                continue nil)
  13660          )
  13661         ((web-mode-looking-at "\\(var\\|let\\|return\\|const\\)[ \n]" pos)
  13662          (setq pos (+ pos (length (match-string-no-properties 0)))
  13663                continue nil))
  13664         (t
  13665          (setq pos (web-mode-rsb-position pos "[\]\[}{)(]\\|\\(var\\|let\\|return\\|const\\)" reg-beg))
  13666          (when (not pos)
  13667            (message "javascript-args-beginning-position ** search failure **")
  13668            (setq continue nil
  13669                  pos reg-beg)))
  13670         ) ;cond
  13671       ) ;while
  13672     ;;(message "=%S" pos)
  13673     pos))
  13674 
  13675 (defun web-mode-javascript-calls-beginning-position (pos &optional reg-beg)
  13676   (unless pos (setq pos (point)))
  13677   ;;(message "pos=%S" pos)
  13678   (let ((char nil)
  13679         (dot-pos nil)
  13680         (blockside (get-text-property pos 'block-side))
  13681         (i 0)
  13682         (continue (not (null pos))))
  13683     (unless reg-beg
  13684       (setq reg-beg (if blockside
  13685                         (web-mode-block-beginning-position pos)
  13686                         (web-mode-part-beginning-position pos))))
  13687     (while continue
  13688       (setq char (char-after pos))
  13689       ;;(message "%S| %S=%c" reg-beg pos char)
  13690       (cond
  13691         ((> (setq i (1+ i)) 20000)
  13692          (message "javascript-calls-beginning-position ** warning (%S) **" pos)
  13693          (setq continue nil
  13694                pos nil))
  13695         ((null pos)
  13696          (message "javascript-calls-beginning-position ** invalid pos **")
  13697          (setq continue nil))
  13698         ((< pos reg-beg)
  13699          (setq continue nil
  13700                pos reg-beg))
  13701         ((and blockside
  13702               (member (get-text-property pos 'block-token) '(string comment))
  13703               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13704          (setq pos (web-mode-block-token-beginning-position pos)))
  13705         ((and (not blockside)
  13706               (member (get-text-property pos 'part-token) '(string comment))
  13707               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13708          (setq pos (web-mode-part-token-beginning-position pos)))
  13709         ((and (not blockside)
  13710               (get-text-property pos 'block-side))
  13711          (when (setq pos (web-mode-block-beginning-position pos))
  13712            (setq pos (1- pos))))
  13713         ((and (member char '(?\.)) (> i 1))
  13714          (setq dot-pos pos
  13715                pos (1- pos)))
  13716         ((member char '(?\) ?\]))
  13717          (when (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13718            (setq pos (1- pos)))
  13719          )
  13720         ((member char '(?\( ?\{ ?\} ?\[ ?\= ?\? ?\: ?\; ?\, ?\& ?\| ?\>))
  13721          (web-mode-looking-at ".[ \t\n]*" pos)
  13722          (setq pos (+ pos (length (match-string-no-properties 0)))
  13723                continue nil))
  13724         ((web-mode-looking-at "\\(return\\|else\\|const\\)[ \n]" pos)
  13725          (setq pos (+ pos (length (match-string-no-properties 0)))
  13726                continue nil))
  13727         (t
  13728          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,&|>.]\\|\\(return\\|else\\|const\\)" reg-beg))
  13729          (when (not pos)
  13730            (message "javascript-calls-beginning-position ** search failure **")
  13731            (setq pos reg-beg
  13732                  continue nil))
  13733          ) ;t
  13734         ) ;cond
  13735       ) ;while
  13736     ;;(message "pos=%S dot-pos=%S" pos dot-pos)
  13737     (if (null pos) pos (cons pos dot-pos))
  13738     ))
  13739 
  13740 (defun web-mode-part-token-beginning-position (&optional pos)
  13741   (unless pos (setq pos (point)))
  13742   (cond
  13743     ((not (get-text-property pos 'part-token))
  13744      nil)
  13745     ((or (= pos (point-min))
  13746          (and (> pos (point-min))
  13747               (not (get-text-property (1- pos) 'part-token))))
  13748      pos)
  13749     (t
  13750      (setq pos (previous-single-property-change pos 'part-token))
  13751      (if (and pos (> pos (point-min))) pos (point-min)))
  13752     ))
  13753 
  13754 (defun web-mode-part-token-end-position (&optional pos)
  13755   (unless pos (setq pos (point)))
  13756   (cond
  13757     ((not (get-text-property pos 'part-token))
  13758      nil)
  13759     ((or (= pos (point-max))
  13760          (not (get-text-property (1+ pos) 'part-token)))
  13761      pos)
  13762     (t
  13763      (1- (next-single-property-change pos 'part-token)))
  13764     ))
  13765 
  13766 (defun web-mode-block-token-beginning-position (&optional pos)
  13767   (unless pos (setq pos (point)))
  13768   (cond
  13769     ((not (get-text-property pos 'block-token))
  13770      nil)
  13771     ((or (= pos (point-min))
  13772          (and (> pos (point-min))
  13773               (not (get-text-property (1- pos) 'block-token))))
  13774      pos)
  13775     (t
  13776      (setq pos (previous-single-property-change pos 'block-token))
  13777      (if (and pos (> pos (point-min))) pos (point-min)))
  13778     ))
  13779 
  13780 (defun web-mode-block-token-end-position (&optional pos)
  13781   (unless pos (setq pos (point)))
  13782   (cond
  13783     ((not (get-text-property pos 'block-token))
  13784      nil)
  13785     ((or (= pos (point-max))
  13786          (not (get-text-property (1+ pos) 'block-token)))
  13787      pos)
  13788     (t
  13789      (1- (next-single-property-change pos 'block-token)))
  13790     ))
  13791 
  13792 (defun web-mode-block-code-end-position (&optional pos)
  13793   (unless pos (setq pos (point)))
  13794   (setq pos (web-mode-block-end-position pos))
  13795   (cond
  13796     ((not pos)
  13797      nil)
  13798     ((and (eq (get-text-property pos 'block-token) 'delimiter-end)
  13799           (eq (get-text-property (1- pos) 'block-token) 'delimiter-end))
  13800      (previous-single-property-change pos 'block-token))
  13801     ((= pos (1- (point-max))) ;; TODO: comparer plutot avec line-end-position
  13802      (point-max))
  13803     (t
  13804      pos)
  13805     ))
  13806 
  13807 (defun web-mode-block-end-position (&optional pos)
  13808   (unless pos (setq pos (point)))
  13809   (cond
  13810     ((get-text-property pos 'block-end)
  13811      pos)
  13812     ((get-text-property pos 'block-side)
  13813      (or (next-single-property-change pos 'block-end)
  13814          (point-max)))
  13815     (t
  13816      nil)
  13817     ))
  13818 
  13819 (defun web-mode-block-previous-position (&optional pos)
  13820   (unless pos (setq pos (point)))
  13821   (cond
  13822     ((= pos (point-min))
  13823      (setq pos nil))
  13824     ((get-text-property pos 'block-side)
  13825      (setq pos (web-mode-block-beginning-position pos))
  13826      (cond
  13827        ((or (null pos) (= pos (point-min)))
  13828         (setq pos nil)
  13829         )
  13830        ((and (setq pos (previous-single-property-change pos 'block-beg))
  13831              (> pos (point-min)))
  13832         (setq pos (1- pos))
  13833         )
  13834        )
  13835      ) ;block-side
  13836     ((get-text-property (1- pos) 'block-side)
  13837      (setq pos (web-mode-block-beginning-position (1- pos)))
  13838      )
  13839     (t
  13840      (setq pos (previous-single-property-change pos 'block-side))
  13841      (cond
  13842        ((and (null pos) (get-text-property (point-min) 'block-beg))
  13843         (setq pos (point-min)))
  13844        ((and pos (> pos (point-min)))
  13845         (setq pos (web-mode-block-beginning-position (1- pos))))
  13846        )
  13847      )
  13848     ) ;conf
  13849   pos)
  13850 
  13851 (defun web-mode-block-next-position (&optional pos limit)
  13852   (unless pos (setq pos (point)))
  13853   (unless limit (setq limit (point-max)))
  13854   (cond
  13855     ((and (get-text-property pos 'block-side)
  13856           (setq pos (web-mode-block-end-position pos))
  13857           (< pos (point-max))
  13858           (setq pos (1+ pos)))
  13859      (unless (get-text-property pos 'block-beg)
  13860        (setq pos (next-single-property-change pos 'block-side)))
  13861      )
  13862     (t
  13863      (setq pos (next-single-property-change pos 'block-side)))
  13864     ) ;cond
  13865   (if (and pos (<= pos limit)) pos nil))
  13866 
  13867 (defun web-mode-is-css-string (pos)
  13868   (let (beg)
  13869     (cond
  13870       ((and (setq beg (web-mode-part-token-beginning-position pos))
  13871             (web-mode-looking-at-p "`" beg)
  13872             (web-mode-looking-back "\\(styled[[:alnum:].]+\\|css\\)" beg))
  13873        beg)
  13874       (t
  13875        nil)
  13876       ) ;cond
  13877     ))
  13878 
  13879 ;; Relay.QL , gql, graphql
  13880 (defun web-mode-is-ql-string (pos prefix-regexp)
  13881   (let (beg)
  13882     (cond
  13883       ((and (setq beg (web-mode-part-token-beginning-position pos))
  13884             (web-mode-looking-back prefix-regexp beg))
  13885        beg)
  13886       (t
  13887        nil)
  13888       ) ;cond
  13889     ))
  13890 
  13891 (defun web-mode-is-html-string (pos)
  13892   (let (beg)
  13893     (cond
  13894       ((and (setq beg (web-mode-part-token-beginning-position pos))
  13895             (web-mode-looking-at-p "`[ \t\n]*<[a-zA-Z]" beg)
  13896             (web-mode-looking-back "\\(template\\|html\\)\\([ ]*[=:][ ]*\\)?" beg))
  13897        beg)
  13898       (t
  13899        nil)
  13900       ) ;cond
  13901     ))
  13902 
  13903 ;;---- EXCURSION ---------------------------------------------------------------
  13904 
  13905 (defun web-mode-backward-sexp (n)
  13906   (interactive "p")
  13907   (if (< n 0) (web-mode-forward-sexp (- n))
  13908       (let (pos)
  13909         (dotimes (_ n)
  13910           (skip-chars-backward "[:space:]")
  13911           (setq pos (point))
  13912           (cond
  13913             ((bobp) nil)
  13914             ((get-text-property (1- pos) 'block-end)
  13915              (backward-char 1)
  13916              (web-mode-block-beginning))
  13917             ((get-text-property (1- pos) 'block-token)
  13918              (backward-char 1)
  13919              (web-mode-block-token-beginning))
  13920             ((get-text-property (1- pos) 'part-token)
  13921              (backward-char 1)
  13922              (web-mode-part-token-beginning))
  13923             ((get-text-property (1- pos) 'tag-end)
  13924              (backward-char 1)
  13925              (web-mode-element-beginning))
  13926             ((get-text-property (1- pos) 'tag-attr)
  13927              (backward-char 1)
  13928              (web-mode-attribute-beginning))
  13929             ((get-text-property (1- pos) 'tag-type)
  13930              (backward-char 1)
  13931              (web-mode-tag-beginning))
  13932             ((get-text-property (1- pos) 'jsx-end)
  13933              (backward-char 1)
  13934              (web-mode-jsx-beginning))
  13935             (t
  13936              (let ((forward-sexp-function nil))
  13937                (backward-sexp))
  13938              ) ;case t
  13939             ) ;cond
  13940           ) ;dotimes
  13941         ))) ;let if defun
  13942 
  13943 (defun web-mode-forward-sexp (n)
  13944   (interactive "p")
  13945   (if (< n 0) (web-mode-backward-sexp (- n))
  13946       (let (pos)
  13947         (dotimes (_ n)
  13948           (skip-chars-forward "[:space:]")
  13949           (setq pos (point))
  13950           (cond
  13951             ((eobp) nil)
  13952             ((get-text-property pos 'block-beg)
  13953              (web-mode-block-end))
  13954             ((get-text-property pos 'block-token)
  13955              (web-mode-block-token-end))
  13956             ((get-text-property pos 'part-token)
  13957              (web-mode-part-token-end))
  13958             ((get-text-property pos 'tag-beg)
  13959              (web-mode-element-end))
  13960             ((get-text-property pos 'tag-attr)
  13961              (web-mode-attribute-end))
  13962             ((get-text-property pos 'tag-type)
  13963              (web-mode-tag-end))
  13964             ((get-text-property pos 'jsx-beg)
  13965              (web-mode-jsx-end))
  13966             (t
  13967              (let ((forward-sexp-function nil))
  13968                (forward-sexp))
  13969              ) ;case t
  13970             ) ;cond
  13971           ) ;dotimes
  13972         ))) ;let if defun
  13973 
  13974 (defun web-mode-comment-beginning ()
  13975   "Fetch current comment beg."
  13976   (interactive)
  13977   (web-mode-go (web-mode-comment-beginning-position (point))))
  13978 
  13979 (defun web-mode-comment-end ()
  13980   "Fetch current comment end."
  13981   (interactive)
  13982   (web-mode-go (web-mode-comment-end-position (point)) 1))
  13983 
  13984 (defun web-mode-tag-beginning ()
  13985   "Fetch current html tag beg."
  13986   (interactive)
  13987   (web-mode-go (web-mode-tag-beginning-position (point))))
  13988 
  13989 (defun web-mode-tag-end ()
  13990   "Fetch current html tag end."
  13991   (interactive)
  13992   (web-mode-go (web-mode-tag-end-position (point)) 1))
  13993 
  13994 (defun web-mode-tag-previous ()
  13995   "Fetch previous tag."
  13996   (interactive)
  13997   (web-mode-go (web-mode-tag-previous-position (point))))
  13998 
  13999 (defun web-mode-tag-next ()
  14000   "Fetch next tag. Might be html comment or server tag (e.g. jsp)."
  14001   (interactive)
  14002   (web-mode-go (web-mode-tag-next-position (point))))
  14003 
  14004 (defun web-mode-attribute-beginning ()
  14005   "Fetch html attribute beginning."
  14006   (interactive)
  14007   (web-mode-go (web-mode-attribute-beginning-position (point))))
  14008 
  14009 (defun web-mode-attribute-end ()
  14010   "Fetch html attribute end."
  14011   (interactive)
  14012   (web-mode-go (web-mode-attribute-end-position (point)) 1))
  14013 
  14014 (defun web-mode-attribute-next (&optional arg)
  14015   "Fetch next attribute."
  14016   (interactive "p")
  14017   (unless arg (setq arg 1))
  14018   (cond
  14019     ((= arg 1) (web-mode-go (web-mode-attribute-next-position (point))))
  14020     ((< arg 1) (web-mode-element-previous (* arg -1)))
  14021     (t
  14022      (while (>= arg 1)
  14023        (setq arg (1- arg))
  14024        (web-mode-go (web-mode-attribute-next-position (point)))
  14025        )
  14026      )
  14027     )
  14028   )
  14029 
  14030 (defun web-mode-attribute-previous (&optional arg)
  14031   "Fetch previous attribute."
  14032   (interactive "p")
  14033   (unless arg (setq arg 1))
  14034   (unless arg (setq arg 1))
  14035   (cond
  14036     ((= arg 1) (web-mode-go (web-mode-attribute-previous-position (point))))
  14037     ((< arg 1) (web-mode-element-next (* arg -1)))
  14038     (t
  14039      (while (>= arg 1)
  14040        (setq arg (1- arg))
  14041        (web-mode-go (web-mode-attribute-previous-position (point)))
  14042        )
  14043      )
  14044     )
  14045   )
  14046 
  14047 (defun web-mode-element-previous (&optional arg)
  14048   "Fetch previous element."
  14049   (interactive "p")
  14050   (unless arg (setq arg 1))
  14051   (cond
  14052     ((= arg 1) (web-mode-go (web-mode-element-previous-position (point))))
  14053     ((< arg 1) (web-mode-element-next (* arg -1)))
  14054     (t
  14055      (while (>= arg 1)
  14056        (setq arg (1- arg))
  14057        (web-mode-go (web-mode-element-previous-position (point)))
  14058        ) ;while
  14059      ) ;t
  14060     ) ;cond
  14061   )
  14062 
  14063 (defun web-mode-element-next (&optional arg)
  14064   "Fetch next element."
  14065   (interactive "p")
  14066   (unless arg (setq arg 1))
  14067   (cond
  14068     ((= arg 1) (web-mode-go (web-mode-element-next-position (point))))
  14069     ((< arg 1) (web-mode-element-previous (* arg -1)))
  14070     (t
  14071      (while (>= arg 1)
  14072        (setq arg (1- arg))
  14073        (web-mode-go (web-mode-element-next-position (point)))
  14074        ) ;while
  14075      ) ;t
  14076     ) ;cond
  14077   )
  14078 
  14079 (defun web-mode-element-sibling-next ()
  14080   "Fetch next sibling element."
  14081   (interactive)
  14082   (let ((pos (point)))
  14083     (save-excursion
  14084       (cond
  14085         ((not (get-text-property pos 'tag-type))
  14086          (if (and (web-mode-element-parent)
  14087                   (web-mode-tag-match)
  14088                   (web-mode-tag-next)
  14089                   (member (get-text-property (point) 'tag-type) '(start void comment)))
  14090              (setq pos (point))
  14091              (setq pos nil))
  14092          )
  14093         ((member (get-text-property pos 'tag-type) '(start void))
  14094          (if (and (web-mode-tag-match)
  14095                   (web-mode-tag-next)
  14096                   (member (get-text-property (point) 'tag-type) '(start void comment)))
  14097              (setq pos (point))
  14098              (setq pos nil))
  14099          )
  14100         ((and (web-mode-tag-next)
  14101               (member (get-text-property (point) 'tag-type) '(start void comment)))
  14102          (setq pos (point)))
  14103         (t
  14104          (setq pos nil))
  14105         ) ;cond
  14106       ) ;save-excursion
  14107     (web-mode-go pos)))
  14108 
  14109 (defun web-mode-element-sibling-previous ()
  14110   "Fetch previous sibling element."
  14111   (interactive)
  14112   (let ((pos (point)))
  14113     (save-excursion
  14114       (cond
  14115         ((not (get-text-property pos 'tag-type))
  14116          (if (and (web-mode-element-parent)
  14117                   (web-mode-tag-previous)
  14118                   (web-mode-element-beginning))
  14119              (setq pos (point))
  14120              (setq pos nil))
  14121          )
  14122         ((eq (get-text-property pos 'tag-type) 'start)
  14123          (if (and (web-mode-tag-beginning)
  14124                   (web-mode-tag-previous)
  14125                   (web-mode-element-beginning))
  14126              (setq pos (point))
  14127              (setq pos nil))
  14128          )
  14129         ((and (web-mode-element-beginning)
  14130               (web-mode-tag-previous)
  14131               (web-mode-element-beginning))
  14132          (setq pos (point)))
  14133         (t
  14134          (setq pos nil))
  14135         ) ;cond
  14136       ) ;save-excursion
  14137     (web-mode-go pos)))
  14138 
  14139 (defun web-mode-element-beginning ()
  14140   "Move to beginning of element."
  14141   (interactive)
  14142   (web-mode-go (web-mode-element-beginning-position (point))))
  14143 
  14144 (defun web-mode-element-end ()
  14145   "Move to end of element."
  14146   (interactive)
  14147   (web-mode-go (web-mode-element-end-position (point)) 1))
  14148 
  14149 (defun web-mode-element-parent ()
  14150   "Fetch parent element."
  14151   (interactive)
  14152   (web-mode-go (web-mode-element-parent-position (point))))
  14153 
  14154 (defun web-mode-element-child ()
  14155   "Fetch child element."
  14156   (interactive)
  14157   (web-mode-go (web-mode-element-child-position (point))))
  14158 
  14159 (defun web-mode-dom-traverse ()
  14160   "Traverse html dom tree."
  14161   (interactive)
  14162   (cond
  14163     ((web-mode-element-child)
  14164      )
  14165     ((web-mode-element-sibling-next)
  14166      )
  14167     ((and (web-mode-element-parent)
  14168           (not (web-mode-element-sibling-next)))
  14169      (goto-char (point-min)))
  14170     (t
  14171      (goto-char (point-min)))
  14172     ) ;cond
  14173   )
  14174 
  14175 (defun web-mode-closing-paren (limit)
  14176   (let ((pos (web-mode-closing-paren-position (point) limit)))
  14177     (if (or (null pos) (> pos limit))
  14178         nil
  14179         (goto-char pos)
  14180         pos)
  14181     ))
  14182 
  14183 (defun web-mode-part-next ()
  14184   "Move point to the beginning of the next part."
  14185   (interactive)
  14186   (web-mode-go (web-mode-part-next-position (point))))
  14187 
  14188 (defun web-mode-part-beginning ()
  14189   "Move point to the beginning of the current part."
  14190   (interactive)
  14191   (web-mode-go (web-mode-part-beginning-position (point))))
  14192 
  14193 (defun web-mode-part-end ()
  14194   "Move point to the end of the current part."
  14195   (interactive)
  14196   (web-mode-go (web-mode-part-end-position (point)) 1))
  14197 
  14198 (defun web-mode-block-previous ()
  14199   "Move point to the beginning of the previous block."
  14200   (interactive)
  14201   (web-mode-go (web-mode-block-previous-position (point))))
  14202 
  14203 (defun web-mode-block-next ()
  14204   "Move point to the beginning of the next block."
  14205   (interactive)
  14206   (web-mode-go (web-mode-block-next-position (point))))
  14207 
  14208 (defun web-mode-block-beginning ()
  14209   "Move point to the beginning of the current block."
  14210   (interactive)
  14211   (web-mode-go (web-mode-block-beginning-position (point))))
  14212 
  14213 (defun web-mode-block-end ()
  14214   "Move point to the end of the current block."
  14215   (interactive)
  14216   (web-mode-go (web-mode-block-end-position (point)) 1))
  14217 
  14218 (defun web-mode-block-token-beginning ()
  14219   (web-mode-go (web-mode-block-token-beginning-position (point))))
  14220 
  14221 (defun web-mode-block-token-end ()
  14222   (web-mode-go (web-mode-block-token-end-position (point)) 1))
  14223 
  14224 (defun web-mode-part-token-beginning ()
  14225   (web-mode-go (web-mode-part-token-beginning-position (point))))
  14226 
  14227 (defun web-mode-part-token-end ()
  14228   (web-mode-go (web-mode-part-token-end-position (point)) 1))
  14229 
  14230 (defun web-mode-block-opening-paren (limit)
  14231   (web-mode-go (web-mode-block-opening-paren-position (point) limit)))
  14232 
  14233 (defun web-mode-block-string-beginning (&optional pos block-beg)
  14234   (unless pos (setq pos (point)))
  14235   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14236   (web-mode-go (web-mode-block-string-beginning-position pos block-beg)))
  14237 
  14238 (defun web-mode-block-statement-beginning (pos block-beg is-ternary)
  14239   (unless pos (setq pos (point)))
  14240   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14241   (web-mode-go (web-mode-block-statement-beginning-position pos block-beg is-ternary)))
  14242 
  14243 (defun web-mode-block-args-beginning (&optional pos block-beg)
  14244   (unless pos (setq pos (point)))
  14245   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14246   (web-mode-go (web-mode-block-args-beginning-position pos block-beg)))
  14247 
  14248 (defun web-mode-block-calls-beginning (&optional pos block-beg)
  14249   (unless pos (setq pos (point)))
  14250   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14251   (web-mode-go (web-mode-block-calls-beginning-position pos block-beg)))
  14252 
  14253 (defun web-mode-javascript-string-beginning (&optional pos reg-beg)
  14254   (unless pos (setq pos (point)))
  14255   (unless reg-beg
  14256     (if (get-text-property pos 'block-side)
  14257         (setq reg-beg (web-mode-block-beginning-position pos))
  14258         (setq reg-beg (web-mode-part-beginning-position pos))))
  14259   (web-mode-go (web-mode-javascript-string-beginning-position pos reg-beg)))
  14260 
  14261 (defun web-mode-javascript-statement-beginning (pos reg-beg is-ternary)
  14262   (unless pos (setq pos (point)))
  14263   (unless reg-beg
  14264     (if (get-text-property pos 'block-side)
  14265         (setq reg-beg (web-mode-block-beginning-position pos))
  14266         (setq reg-beg (web-mode-part-beginning-position pos))))
  14267   (web-mode-go (web-mode-javascript-statement-beginning-position pos reg-beg is-ternary)))
  14268 
  14269 (defun web-mode-javascript-args-beginning (&optional pos reg-beg)
  14270   (unless pos (setq pos (point)))
  14271   (unless reg-beg
  14272     (setq reg-beg (if (get-text-property pos 'block-side)
  14273                       (web-mode-block-beginning-position pos)
  14274                       (web-mode-part-beginning-position pos))))
  14275   ;;(message "reg-beg%S" reg-beg)
  14276   (web-mode-go (web-mode-javascript-args-beginning-position pos reg-beg)))
  14277 
  14278 (defun web-mode-javascript-calls-beginning (&optional pos reg-beg)
  14279   (unless pos (setq pos (point)))
  14280   (unless reg-beg
  14281     (if (get-text-property pos 'block-side)
  14282         (setq reg-beg (web-mode-block-beginning-position pos))
  14283         (setq reg-beg (web-mode-part-beginning-position pos))))
  14284   (let (pair)
  14285     (setq pair (web-mode-javascript-calls-beginning-position pos reg-beg))
  14286     (when pair (web-mode-go (car pair)))
  14287     ))
  14288 
  14289 (defun web-mode-go (pos &optional offset)
  14290   (unless offset (setq offset 0))
  14291   (when pos
  14292     (cond
  14293       ((and (> offset 0) (<= (+ pos offset) (point-max)))
  14294        (setq pos (+ pos offset)))
  14295       ((and (< offset 0) (>= (+ pos offset) (point-min)))
  14296        (setq pos (+ pos offset)))
  14297       ) ;cond
  14298     (goto-char pos))
  14299   pos)
  14300 
  14301 ;;---- SEARCH ------------------------------------------------------------------
  14302 
  14303 (defun web-mode-rsf-balanced (regexp-open regexp-close &optional limit noerror)
  14304   (unless noerror (setq noerror t))
  14305   (let ((continue t)
  14306         (level 1)
  14307         (pos (point))
  14308         ret
  14309         (regexp (concat regexp-open "\\|" regexp-close)))
  14310     (while continue
  14311       (setq ret (re-search-forward regexp limit noerror))
  14312       (cond
  14313         ((null ret)
  14314          (setq continue nil)
  14315          )
  14316         (t
  14317          (if (string-match-p regexp-open (match-string-no-properties 0))
  14318              (setq level (1+ level))
  14319              (setq level (1- level)))
  14320          (when (< level 1)
  14321            (setq continue nil)
  14322            )
  14323          ) ;t
  14324         ) ;cond
  14325       ) ;while
  14326     (when (not (= level 0)) (goto-char pos))
  14327     ret))
  14328 
  14329 (defun web-mode-block-sb (expr &optional limit noerror)
  14330   (unless limit (setq limit (web-mode-block-beginning-position (point))))
  14331   (unless noerror (setq noerror t))
  14332   (let ((continue t) ret)
  14333     (while continue
  14334       (setq ret (search-backward expr limit noerror))
  14335       (when (or (null ret)
  14336                 (not (get-text-property (point) 'block-token)))
  14337         (setq continue nil)
  14338         ) ;when
  14339       ) ;while
  14340     ret))
  14341 
  14342 (defun web-mode-block-sf (expr &optional limit noerror)
  14343   (unless limit (setq limit (web-mode-block-end-position (point))))
  14344   (unless noerror (setq noerror t))
  14345   (let ((continue t) ret)
  14346     (while continue
  14347       (setq ret (search-forward expr limit noerror))
  14348       (when (or (null ret)
  14349                 (not (get-text-property (point) 'block-token)))
  14350         (setq continue nil)
  14351         ) ;when
  14352       ) ;while
  14353     ret))
  14354 
  14355 (defun web-mode-block-rsb (regexp &optional limit noerror)
  14356   (unless limit (setq limit (web-mode-block-beginning-position (point))))
  14357   (unless noerror (setq noerror t))
  14358   (let ((continue t) ret)
  14359     (while continue
  14360       (setq ret (re-search-backward regexp limit noerror))
  14361       (when (or (null ret)
  14362                 (not (get-text-property (point) 'block-token)))
  14363         (setq continue nil)
  14364         ) ;when
  14365       ) ;while
  14366     ret))
  14367 
  14368 (defun web-mode-block-rsf (regexp &optional limit noerror)
  14369   (unless limit (setq limit (web-mode-block-end-position (point))))
  14370   (unless noerror (setq noerror t))
  14371   (let ((continue t) ret)
  14372     (while continue
  14373       (setq ret (re-search-forward regexp limit noerror))
  14374       (when (or (null ret)
  14375                 (not (get-text-property (point) 'block-token)))
  14376         (setq continue nil)
  14377         ) ;when
  14378       ) ;while
  14379     ret))
  14380 
  14381 (defun web-mode-part-sb (expr &optional limit noerror)
  14382   (unless limit (setq limit (web-mode-part-beginning-position (point))))
  14383   (unless noerror (setq noerror t))
  14384   (let ((continue t) ret)
  14385     (while continue
  14386       (setq ret (search-backward expr limit noerror))
  14387       (when (or (null ret)
  14388                 (and (not (get-text-property (point) 'part-token))
  14389                      (not (get-text-property (point) 'block-side)))
  14390                 )
  14391         (setq continue nil)
  14392         ) ;when
  14393       ) ;while
  14394     ret))
  14395 
  14396 (defun web-mode-part-sf (expr &optional limit noerror)
  14397   (unless limit (setq limit (web-mode-part-end-position (point))))
  14398   (unless noerror (setq noerror t))
  14399   (let ((continue t) ret)
  14400     (while continue
  14401       (setq ret (search-forward expr limit noerror))
  14402       (when (or (null ret)
  14403                 (and (not (get-text-property (point) 'part-token))
  14404                      (not (get-text-property (point) 'block-side)))
  14405                 )
  14406         (setq continue nil)
  14407         ) ;when
  14408       ) ;while
  14409     ret))
  14410 
  14411 (defun web-mode-part-rsb (regexp &optional limit noerror)
  14412   (unless limit (setq limit (web-mode-part-beginning-position (point))))
  14413   (unless noerror (setq noerror t))
  14414   (let ((continue t) ret)
  14415     (while continue
  14416       (setq ret (re-search-backward regexp limit noerror))
  14417       (when (or (null ret)
  14418                 (and (not (get-text-property (point) 'part-token))
  14419                      (not (get-text-property (point) 'block-side)))
  14420                 )
  14421         (setq continue nil)
  14422         ) ;when
  14423       ) ;while
  14424     ret))
  14425 
  14426 (defun web-mode-part-rsf (regexp &optional limit noerror)
  14427   (unless limit (setq limit (web-mode-part-end-position (point))))
  14428   (unless noerror (setq noerror t))
  14429   (let ((continue t) ret)
  14430     (while continue
  14431       (setq ret (re-search-forward regexp limit t))
  14432       (when (or (null ret)
  14433                 (and (not (get-text-property (point) 'part-token))
  14434                      (not (get-text-property (point) 'block-side)))
  14435                 )
  14436         (setq continue nil)
  14437         ) ;when
  14438       ) ;while
  14439     ret))
  14440 
  14441 (defun web-mode-javascript-rsb (regexp &optional limit noerror)
  14442   (unless limit (setq limit (web-mode-part-beginning-position (point))))
  14443   (unless noerror (setq noerror t))
  14444   (let ((continue t) ret)
  14445     (while continue
  14446       (setq ret (re-search-backward regexp limit noerror))
  14447       (when (or (null ret)
  14448                 (and (not (get-text-property (point) 'part-token))
  14449                      (not (get-text-property (point) 'block-side))
  14450                      (not (get-text-property (point) 'jsx-depth)))
  14451                 )
  14452         (setq continue nil)
  14453         ) ;when
  14454       ) ;while
  14455     ret))
  14456 
  14457 (defun web-mode-javascript-rsf (regexp &optional limit noerror)
  14458   (unless limit (setq limit (web-mode-part-end-position (point))))
  14459   (unless noerror (setq noerror t))
  14460   (let ((continue t) ret)
  14461     (while continue
  14462       (setq ret (re-search-forward regexp limit t))
  14463       (when (or (null ret)
  14464                 (and (not (get-text-property (point) 'part-token))
  14465                      (not (get-text-property (point) 'block-side))
  14466                      (not (get-text-property (point) 'jsx-depth)))
  14467                 )
  14468         (setq continue nil)
  14469         ) ;when
  14470       ) ;while
  14471     ret))
  14472 
  14473 (defun web-mode-dom-sf (expr &optional limit noerror)
  14474   (unless noerror (setq noerror t))
  14475   (let ((continue t) ret)
  14476     (while continue
  14477       (setq ret (search-forward expr limit noerror))
  14478       (if (or (null ret)
  14479               (not (get-text-property (- (point) (length expr)) 'block-side)))
  14480           (setq continue nil))
  14481       )
  14482     ret))
  14483 
  14484 (defun web-mode-dom-rsf (regexp &optional limit noerror)
  14485   (unless noerror (setq noerror t))
  14486   (let ((continue t) (ret nil))
  14487     (while continue
  14488       (setq ret (re-search-forward regexp limit noerror))
  14489       ;;      (message "ret=%S point=%S limit=%S i=%S" ret (point) limit 0)
  14490       (cond
  14491         ((null ret)
  14492          (setq continue nil))
  14493         ((or (get-text-property (match-beginning 0) 'block-side)
  14494              (get-text-property (match-beginning 0) 'part-token))
  14495          )
  14496         (t
  14497          (setq continue nil))
  14498         ) ;cond
  14499       ) ;while
  14500     ret))
  14501 
  14502 (defun web-mode-rsb-position (pos regexp &optional limit noerror)
  14503   (unless noerror (setq noerror t))
  14504   (save-excursion
  14505     (goto-char pos)
  14506     (if (re-search-backward regexp limit noerror) (point) nil)
  14507     ))
  14508 
  14509 (defun web-mode-rsb (regexp &optional limit noerror)
  14510   (unless noerror (setq noerror t))
  14511   (let ((continue t) ret)
  14512     (while continue
  14513       (setq ret (re-search-backward regexp limit noerror))
  14514       (if (or (null ret)
  14515               (not (web-mode-is-comment-or-string)))
  14516           (setq continue nil)))
  14517     ret))
  14518 
  14519 (defun web-mode-rsf (regexp &optional limit noerror)
  14520   (unless noerror (setq noerror t))
  14521   (let ((continue t) ret)
  14522     (while continue
  14523       (setq ret (re-search-forward regexp limit noerror))
  14524       (if (or (null ret)
  14525               (not (web-mode-is-comment-or-string)))
  14526           (setq continue nil))
  14527       )
  14528     ret))
  14529 
  14530 (defun web-mode-sb (expr &optional limit noerror)
  14531   (unless noerror (setq noerror t))
  14532   (let ((continue t) ret)
  14533     (while continue
  14534       (setq ret (search-backward expr limit noerror))
  14535       (if (or (null ret)
  14536               (not (web-mode-is-comment-or-string)))
  14537           (setq continue nil)))
  14538     ret))
  14539 
  14540 (defun web-mode-sf (expr &optional limit noerror)
  14541   (unless noerror (setq noerror t))
  14542   (let ((continue t) ret)
  14543     (while continue
  14544       (setq ret (search-forward expr limit noerror))
  14545       (if (or (null ret)
  14546               (not (web-mode-is-comment-or-string)))
  14547           (setq continue nil)))
  14548     ret))
  14549 
  14550 (defun web-mode-content-rsf (regexp &optional limit noerror)
  14551   (unless noerror (setq noerror t))
  14552   (let ((continue t) ret beg end)
  14553     (while continue
  14554       (setq ret (re-search-forward regexp limit noerror)
  14555             beg (if (null ret) (point) (match-beginning 0))
  14556             end (if (null ret) (point) (1- (match-end 0))))
  14557       (if (or (null ret)
  14558               (and (web-mode-is-content beg)
  14559                    (web-mode-is-content end)))
  14560           (setq continue nil)))
  14561     ret))
  14562 
  14563 ;;---- ADVICES -----------------------------------------------------------------
  14564 
  14565 (defadvice ac-start (before web-mode-set-up-ac-sources activate)
  14566   "Set `ac-sources' based on current language before running auto-complete."
  14567   (when (equal major-mode 'web-mode)
  14568     ;; set ignore each time to nil. User has to implement a hook to change it
  14569     ;; for each completion
  14570     (setq web-mode-ignore-ac-start-advice nil)
  14571     (run-hooks 'web-mode-before-auto-complete-hooks)
  14572     (unless web-mode-ignore-ac-start-advice
  14573       (when web-mode-ac-sources-alist
  14574         (let ((new-web-mode-ac-sources
  14575                (assoc (web-mode-language-at-pos)
  14576                       web-mode-ac-sources-alist)))
  14577           (setq ac-sources (cdr new-web-mode-ac-sources)))))))
  14578 
  14579 ;;---- MINOR MODE ADDONS -------------------------------------------------------
  14580 
  14581 (defun web-mode-yasnippet-exit-hook ()
  14582   "Yasnippet exit hook"
  14583   (when (and (boundp 'yas-snippet-beg) (boundp 'yas-snippet-end))
  14584     (indent-region yas-snippet-beg yas-snippet-end)))
  14585 
  14586 (defun web-mode-imenu-index ()
  14587   "Returns imenu items."
  14588   (interactive)
  14589   (let (toc-index
  14590         line)
  14591     (save-excursion
  14592       (goto-char (point-min))
  14593       (while (not (eobp))
  14594         (setq line (buffer-substring-no-properties
  14595                     (line-beginning-position)
  14596                     (line-end-position)))
  14597         (let (found
  14598               (i 0)
  14599               item
  14600               regexp
  14601               type
  14602               type-idx
  14603               content
  14604               content-idx
  14605               content-regexp
  14606               close-tag-regexp
  14607               concat-str
  14608               jumpto
  14609               str)
  14610           (while (and (not found ) (< i (length web-mode-imenu-regexp-list)))
  14611             (setq item (nth i web-mode-imenu-regexp-list))
  14612             (setq regexp (nth 0 item))
  14613             (setq type-idx (nth 1 item))
  14614             (setq content-idx (nth 2 item))
  14615             (setq concat-str (nth 3 item))
  14616             (when (not (numberp content-idx))
  14617               (setq content-regexp (nth 2 item)
  14618                     close-tag-regexp (nth 4 item)
  14619                     content-idx nil))
  14620 
  14621             (when (string-match regexp line)
  14622 
  14623               (cond
  14624                 (content-idx
  14625                  (setq type (match-string type-idx line))
  14626                  (setq content (match-string content-idx line))
  14627                  (setq str (concat type concat-str content))
  14628                  (setq jumpto (line-beginning-position)))
  14629                 (t
  14630                  (let (limit)
  14631                    (setq type (match-string type-idx line))
  14632                    (goto-char (line-beginning-position))
  14633                    (save-excursion
  14634                      (setq limit (re-search-forward close-tag-regexp (point-max) t)))
  14635 
  14636                    (when limit
  14637                      (when (re-search-forward content-regexp limit t)
  14638                        (setq content (match-string 1))
  14639                        (setq str (concat type concat-str content))
  14640                        (setq jumpto (line-beginning-position))
  14641                        )
  14642                      )))
  14643                 )
  14644               (when str (setq toc-index
  14645                               (cons (cons str jumpto)
  14646                                     toc-index)
  14647                               )
  14648                     (setq found t))
  14649               )
  14650             (setq i (1+ i))))
  14651         (forward-line)
  14652         (goto-char (line-end-position)) ;; make sure we are at eobp
  14653         ))
  14654     (nreverse toc-index)))
  14655 
  14656 ;;---- UNIT TESTING ------------------------------------------------------------
  14657 
  14658 (defun web-mode-test ()
  14659   "Executes web-mode unit tests. See `web-mode-tests-directory'."
  14660   (interactive)
  14661   (let (files regexp)
  14662     (setq regexp "^[[:alnum:]][[:alnum:]._]+\\'")
  14663     (setq files (directory-files web-mode-tests-directory t regexp))
  14664     (dolist (file files)
  14665       (cond
  14666         ((eq (string-to-char (file-name-nondirectory file)) ?\_)
  14667          (delete-file file))
  14668         (t
  14669          (web-mode-test-process file))
  14670         ) ;cond
  14671       ) ;dolist
  14672     ))
  14673 
  14674 (defun web-mode-test-process (file)
  14675   (with-temp-buffer
  14676     (let (out sig1 sig2 success err)
  14677       (setq-default indent-tabs-mode nil)
  14678       (if (string-match-p "sql" file)
  14679           (setq web-mode-enable-sql-detection t)
  14680           (setq web-mode-enable-sql-detection nil))
  14681       (insert-file-contents file)
  14682       (set-visited-file-name file)
  14683       (web-mode)
  14684       (setq sig1 (md5 (current-buffer)))
  14685       (delete-horizontal-space)
  14686       (while (not (eobp))
  14687         (forward-line)
  14688         (delete-horizontal-space)
  14689         (end-of-line))
  14690       (web-mode-buffer-indent)
  14691       (setq sig2 (md5 (current-buffer)))
  14692       (setq success (string= sig1 sig2))
  14693       (setq out (concat (if success "ok" "ko") " : " (file-name-nondirectory file) "\n"))
  14694       (princ out)
  14695       (setq err (concat (file-name-directory file) "_err." (file-name-nondirectory file)))
  14696       (if success
  14697           (when (file-readable-p err)
  14698             (delete-file err))
  14699           (write-file err)
  14700           (message "[%s]" (buffer-string))
  14701           ) ;if
  14702       out)))
  14703 
  14704 ;;---- MISC --------------------------------------------------------------------
  14705 
  14706 (defun web-mode-set-engine (engine)
  14707   "Set the engine for the current buffer."
  14708   (interactive
  14709    (list (completing-read
  14710           "Engine: "
  14711           (let (engines)
  14712             (dolist (elt web-mode-engines)
  14713               (setq engines (append engines (list (car elt)))))
  14714             engines))))
  14715   (setq web-mode-content-type "html"
  14716         web-mode-engine (web-mode-engine-canonical-name engine)
  14717         web-mode-minor-engine engine)
  14718   (web-mode-on-engine-setted)
  14719   (web-mode-buffer-fontify))
  14720 
  14721 (defun web-mode-set-content-type (content-type)
  14722   "Set the content-type for the current buffer"
  14723   (interactive (list (completing-read "Content-type: " web-mode-part-content-types)))
  14724   (setq web-mode-content-type content-type)
  14725   (when (called-interactively-p 'any)
  14726     )
  14727   (web-mode-buffer-fontify))
  14728 
  14729 (defun web-mode-on-engine-setted ()
  14730   (let (elt elts)
  14731 
  14732     (when (string= web-mode-engine "razor") (setq web-mode-enable-block-face t))
  14733     ;;(setq web-mode-engine-attr-regexp (cdr (assoc web-mode-engine web-mode-engine-attr-regexps)))
  14734     (setq web-mode-engine-token-regexp (cdr (assoc web-mode-engine web-mode-engine-token-regexps)))
  14735 
  14736     ;;(message "%S %S %S" web-mode-engine web-mode-engine-attr-regexp web-mode-engine-token-regexp)
  14737 
  14738     (when (null web-mode-minor-engine)
  14739       (setq web-mode-minor-engine "none"))
  14740 
  14741     (setq elt (assoc web-mode-engine web-mode-engine-open-delimiter-regexps))
  14742     (cond
  14743       (elt
  14744        (setq web-mode-block-regexp (cdr elt)))
  14745       ((string= web-mode-engine "archibus")
  14746        (setq web-mode-block-regexp nil))
  14747       (t
  14748        (setq web-mode-engine "none"))
  14749       )
  14750 
  14751     (unless (boundp 'web-mode-extra-auto-pairs)
  14752       (setq web-mode-extra-auto-pairs nil))
  14753 
  14754     (setq web-mode-auto-pairs
  14755           (append
  14756            (cdr (assoc web-mode-engine web-mode-engines-auto-pairs))
  14757            (cdr (assoc nil web-mode-engines-auto-pairs))
  14758            (cdr (assoc web-mode-engine web-mode-extra-auto-pairs))
  14759            (cdr (assoc nil web-mode-extra-auto-pairs))))
  14760 
  14761     (unless (boundp 'web-mode-extra-snippets)
  14762       (setq web-mode-extra-snippets nil))
  14763 
  14764     (setq elts
  14765           (append
  14766            (cdr (assoc web-mode-engine web-mode-extra-snippets))
  14767            (cdr (assoc nil             web-mode-extra-snippets))
  14768            (cdr (assoc web-mode-engine web-mode-engines-snippets))
  14769            (cdr (assoc nil             web-mode-engines-snippets))))
  14770 
  14771     ;;(message "%S" elts)
  14772 
  14773     (dolist (elt elts)
  14774       (unless (assoc (car elt) web-mode-snippets)
  14775         (setq web-mode-snippets (cons elt web-mode-snippets)))
  14776       )
  14777 
  14778     (setq web-mode-engine-font-lock-keywords
  14779           (symbol-value (cdr (assoc web-mode-engine web-mode-engines-font-lock-keywords))))
  14780 
  14781     (when (and (string= web-mode-minor-engine "jinja")
  14782                (not (member "endtrans" web-mode-django-control-blocks)))
  14783       (add-to-list 'web-mode-django-control-blocks "endtrans")
  14784       (setq web-mode-django-control-blocks-regexp
  14785             (regexp-opt web-mode-django-control-blocks t))
  14786       )
  14787 
  14788     (when (string= web-mode-engine "spip")
  14789       (modify-syntax-entry ?# "w" (syntax-table)))
  14790 
  14791     ;;(message "%S" (symbol-value (cdr (assoc web-mode-engine web-mode-engines-font-lock-keywords))))
  14792 
  14793     ))
  14794 
  14795 (defun web-mode-detect-engine ()
  14796   (save-excursion
  14797     (goto-char (point-min))
  14798     (when (re-search-forward "-\\*- engine:[ ]*\\([[:alnum:]-]+\\)[ ]*-\\*-" web-mode-chunk-length t)
  14799       (setq web-mode-minor-engine (match-string-no-properties 1))
  14800       (setq web-mode-engine (web-mode-engine-canonical-name web-mode-minor-engine)))
  14801     web-mode-minor-engine))
  14802 
  14803 (defun web-mode-guess-engine-and-content-type ()
  14804   (let (buff-name found)
  14805 
  14806     (setq buff-name (buffer-file-name))
  14807     (unless buff-name (setq buff-name (buffer-name)))
  14808     (setq web-mode-is-scratch (string= buff-name "*scratch*"))
  14809     (setq web-mode-content-type nil)
  14810 
  14811     (when (boundp 'web-mode-content-types-alist)
  14812       (setq found nil)
  14813       (dolist (elt web-mode-content-types-alist)
  14814         (when (and (not found) (string-match-p (cdr elt) buff-name))
  14815           (setq web-mode-content-type (car elt)
  14816                 found t))
  14817         ) ;dolist
  14818       ) ;when
  14819 
  14820     (unless web-mode-content-type
  14821       (setq found nil)
  14822       (dolist (elt web-mode-content-types)
  14823         (when (and (not found) (string-match-p (cdr elt) buff-name))
  14824           (setq web-mode-content-type (car elt)
  14825                 found t)
  14826           ;;(message "%S" web-mode-content-type)
  14827           ) ;when
  14828         ) ;dolist
  14829       ) ;unless
  14830 
  14831     (when (boundp 'web-mode-engines-alist)
  14832       (setq found nil)
  14833       (dolist (elt web-mode-engines-alist)
  14834         (cond
  14835           ((stringp (cdr elt))
  14836            (when (string-match-p (cdr elt) buff-name)
  14837              (setq web-mode-engine (car elt))))
  14838           ((functionp (cdr elt))
  14839            (when (funcall (cdr elt))
  14840              (setq web-mode-engine (car elt))))
  14841           ) ;cond
  14842         ) ;dolist
  14843       ) ;when
  14844 
  14845     (unless web-mode-engine
  14846       (setq found nil)
  14847       (dolist (elt web-mode-engine-file-regexps)
  14848         ;;(message "%S %S %S" (cdr elt) (car elt) buff-name)
  14849         (when (and (not found) (string-match-p (cdr elt) buff-name))
  14850           ;;(message "%S %S %S" (cdr elt) (car elt) buff-name)
  14851           (setq web-mode-engine (car elt)
  14852                 found t)
  14853           ;;(when (and web-mode-engine (string= web-mode-engine "astro"))
  14854           ;;  (setq web-mode-enable-front-matter-block t)
  14855           ;;) ;when
  14856           ) ;when
  14857         )
  14858       )
  14859 
  14860     (when (and (or (null web-mode-engine) (string= web-mode-engine "none"))
  14861                (string-match-p "php" (buffer-substring-no-properties
  14862                                       (line-beginning-position)
  14863                                       (line-end-position))))
  14864       (setq web-mode-engine "php"))
  14865 
  14866     (when (and (string= web-mode-content-type "javascript")
  14867                (string-match-p "@jsx"
  14868                                (buffer-substring-no-properties
  14869                                 (point-min)
  14870                                 (if (< (point-max) web-mode-chunk-length)
  14871                                     (point-max)
  14872                                     web-mode-chunk-length)
  14873                                 )))
  14874       (setq web-mode-content-type "jsx"))
  14875 
  14876     (when web-mode-engine
  14877       (setq web-mode-minor-engine web-mode-engine
  14878             web-mode-engine (web-mode-engine-canonical-name web-mode-engine))
  14879       )
  14880 
  14881     ;;(message "%S %S" web-mode-engine web-mode-enable-engine-detection)
  14882 
  14883     (when (and (or (null web-mode-engine)
  14884                    (string= web-mode-engine "none"))
  14885                web-mode-enable-engine-detection)
  14886       (web-mode-detect-engine))
  14887 
  14888     (web-mode-on-engine-setted)
  14889 
  14890     ))
  14891 
  14892 (defun web-mode-engine-canonical-name (name)
  14893   (let (engine)
  14894     (cond
  14895       ((null name)
  14896        nil)
  14897       ((assoc name web-mode-engines)
  14898        name)
  14899       (t
  14900        (dolist (elt web-mode-engines)
  14901          (when (and (null engine) (member name (cdr elt)))
  14902            (setq engine (car elt)))
  14903          ) ;dolist
  14904        engine)
  14905       )))
  14906 
  14907 (defun web-mode-on-after-save ()
  14908   (when web-mode-is-scratch
  14909     (web-mode-guess-engine-and-content-type)
  14910     (web-mode-buffer-fontify))
  14911   nil)
  14912 
  14913 (defun web-mode-on-exit ()
  14914   (web-mode-with-silent-modifications
  14915    (put-text-property (point-min) (point-max) 'invisible nil)
  14916    (remove-overlays)
  14917    (remove-hook 'change-major-mode-hook 'web-mode-on-exit t)
  14918    ))
  14919 
  14920 (defun web-mode-file-link (file)
  14921   "Insert a link to a file in html document. This function can be
  14922 extended to support more filetypes by customizing
  14923 `web-mode-links'."
  14924   (interactive
  14925    (list (file-relative-name (read-file-name "Link file: "))))
  14926   (let ((matched nil)
  14927         (point-line (line-number-at-pos))
  14928         (point-column (current-column)))
  14929     (dolist (type web-mode-links)
  14930       (when (string-match (car type) file)
  14931         (setq matched t)
  14932         (when (nth 2 type)
  14933           (goto-char (point-min))
  14934           (search-forward "</head>")
  14935           (backward-char 7)
  14936           (open-line 1))
  14937         (insert (format (cadr type) file))
  14938         (indent-for-tab-command)
  14939         (when (nth 2 type)
  14940           ;; return point where it was and fix indentation
  14941           (forward-line)
  14942           (indent-for-tab-command)
  14943           (if (> point-line (- (line-number-at-pos) 2))
  14944               (forward-line (+ (- point-line (line-number-at-pos)) 1))
  14945               (forward-line (- point-line (line-number-at-pos))))
  14946           (move-to-column point-column))
  14947         ;; move point back if needed
  14948         (backward-char (nth 3 type))))
  14949     (when (not matched)
  14950       (user-error "Unknown file type"))))
  14951 
  14952 (defun web-mode-reload ()
  14953   "Reload web-mode."
  14954   (interactive)
  14955   (web-mode-with-silent-modifications
  14956    (put-text-property (point-min) (point-max) 'invisible nil)
  14957    (remove-overlays)
  14958    (setq font-lock-unfontify-region-function 'font-lock-default-unfontify-region)
  14959    (load "web-mode.el")
  14960    (setq web-mode-change-beg nil
  14961          web-mode-change-end nil)
  14962    (web-mode)
  14963    ))
  14964 
  14965 (defun web-mode-measure (msg)
  14966   (let (sub)
  14967     (when (null web-mode-time) (setq web-mode-time (current-time)))
  14968     (setq sub (time-subtract (current-time) web-mode-time))
  14969     (when nil
  14970       (save-excursion
  14971         (let ((n 0))
  14972           (goto-char (point-min))
  14973           (while (web-mode-tag-next)
  14974             (setq n (1+ n))
  14975             )
  14976           (message "%S tags found" n)
  14977           )))
  14978     (message "%18s: time elapsed = %Ss %9Sµs" msg (nth 1 sub) (nth 2 sub))
  14979     ))
  14980 
  14981 (defun web-mode-reveal ()
  14982   "Display text properties at point."
  14983   (interactive)
  14984   (let (symbols out)
  14985     (setq out (format
  14986                "[point=%S engine=%S minor=%S content-type=%S language-at-pos=%S]\n"
  14987                (point)
  14988                web-mode-engine
  14989                web-mode-minor-engine
  14990                web-mode-content-type
  14991                (web-mode-language-at-pos (point))))
  14992     (setq symbols (append web-mode-scan-properties '(font-lock-face face)))
  14993     (dolist (symbol symbols)
  14994       (when symbol
  14995         (setq out (concat out (format "%s(%S) " (symbol-name symbol) (get-text-property (point) symbol)))))
  14996       )
  14997     (message "%s\n" out)
  14998     ;;(message "syntax-class=%S" (syntax-class (syntax-after (point))))
  14999     (message nil)))
  15000 
  15001 (defun web-mode-toggle-tracing ()
  15002   "Toggle tracing."
  15003   (interactive)
  15004   (if web-mode-trace
  15005       (setq web-mode-trace nil)
  15006       (message "** tracing on ** point(%S) web-mode-change-beg(%S) web-mode-change-end(%S) web-mode-skip-fontification(%S)"
  15007                (point) web-mode-change-beg web-mode-change-end web-mode-skip-fontification)
  15008       (setq web-mode-trace t)))
  15009 
  15010 (defun web-mode-debug ()
  15011   "Display informations useful for debugging."
  15012   (interactive)
  15013   (let ((modes nil)
  15014         (customs '(web-mode-enable-current-column-highlight web-mode-enable-current-element-highlight indent-tabs-mode))
  15015         (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)))
  15016     (message "\n")
  15017     (message "--- WEB-MODE DEBUG BEG ---")
  15018     (message "versions: emacs(%S.%S) web-mode(%S)"
  15019              emacs-major-version emacs-minor-version web-mode-version)
  15020     (message "vars: engine(%S) minor(%S) content-type(%S) file(%S)"
  15021              web-mode-engine
  15022              web-mode-minor-engine
  15023              web-mode-content-type
  15024              (or (buffer-file-name) (buffer-name)))
  15025     (message "system: window(%S) config(%S)" window-system system-configuration)
  15026     (message "colors: fg(%S) bg(%S) "
  15027              (cdr (assoc 'foreground-color default-frame-alist))
  15028              (cdr (assoc 'background-color default-frame-alist)))
  15029     (mapc (lambda (mode)
  15030             (condition-case nil
  15031                 (if (and (symbolp mode) (symbol-value mode) (not (member mode ignore)))
  15032                     (push mode modes))
  15033               (error nil))
  15034             ) ;lambda
  15035           minor-mode-list)
  15036     (message "minor modes: %S" modes)
  15037     (message "vars:")
  15038     (dolist (custom customs)
  15039       (message (format "%s=%S " (symbol-name custom) (symbol-value custom))))
  15040     (message "--- WEB-MODE DEBUG END ---")
  15041     (switch-to-buffer "*Messages*")
  15042     (goto-char (point-max))
  15043     (recenter)
  15044     ))
  15045 
  15046 (provide 'web-mode)
  15047 
  15048 ;;; web-mode.el ends here
  15049 
  15050 ;; Local Variables:
  15051 ;; coding: utf-8
  15052 ;; indent-tabs-mode: nil
  15053 ;; sentence-end-double-space: nil
  15054 ;; End: