config

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

web-mode.el (586063B)


      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)) ;; a-z
   6076                          (and (>= ch-before 65) (<= ch-before 90))))) ;; A-Z
   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-skip2 (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-skip (reg-end) ;; #1299
   6324    (let ((continue t) (pos nil) (i 0) (tag nil) (regexp nil) (counter 0) (ret nil) (match nil) (inside t))
   6325      (looking-at "<\\([[:alpha:]][[:alnum:]:-]*\\)")
   6326      (setq tag (match-string-no-properties 1))
   6327      (setq regexp (concat "<" tag "[[:space:]/>]"))
   6328      ;;(message "-----\npoint=%S tag=%S reg-end=%S" (point) tag reg-end)
   6329      (save-excursion
   6330        (while continue
   6331          (setq ret (web-mode-dom-rsf regexp reg-end))
   6332          (if ret
   6333              (progn
   6334                (setq match (match-string-no-properties 0))
   6335                (when (and (eq (aref match 0) ?\<)
   6336                           (eq (char-before) ?\>))
   6337                  (backward-char)
   6338                  (when (eq (char-before) ?\/) (backward-char)))
   6339                )
   6340            (setq match nil)
   6341            ) ;if
   6342          ;;(message "point=%S regexp=%S match=%S" (point) regexp match)
   6343          (cond
   6344           ((> (setq i (1+ i)) 100)
   6345            (message "jsx-skip ** warning **")
   6346            (setq continue nil))
   6347           ((not ret)
   6348            (setq continue nil)
   6349            )
   6350           ((eq (aref match 0) ?\{)
   6351            (backward-char)
   6352            (web-mode-closing-paren reg-end)
   6353            (forward-char)
   6354            (if inside
   6355                (setq regexp (concat "[{]\\|/?>"))
   6356              (setq regexp (concat "[{]\\|</?" tag "[[:space:]/>]"))
   6357              )
   6358            )
   6359           ((and (eq (char-before) ?\>) (eq (char-before (1- (point))) ?\/)) ;; />
   6360            (setq inside nil)
   6361            (if (eq counter 1)
   6362                (progn
   6363                  (setq counter 0)
   6364                  (setq continue nil)
   6365                  (setq pos (point)))
   6366              (setq regexp (concat "[{]\\|<" tag "[[:space:]/>]"))
   6367              )
   6368            )
   6369           ((eq (char-before) ?\>) ;; >
   6370            (setq inside nil)
   6371            (if (= counter 0)
   6372                (progn
   6373                  (setq continue nil)
   6374                  (setq pos (point)))
   6375              (setq regexp (concat "[{]\\|</?" tag "[[:space:]/>]"))
   6376              )
   6377            )
   6378           ((and (> (length match) 1) (string= (substring match 0 2) "</"))
   6379            (setq inside t)
   6380            (setq counter (1- counter))
   6381            (setq regexp (concat "[{]\\|>"))
   6382            )
   6383           (t ;; <tag
   6384            (setq inside t)
   6385            (setq counter (1+ counter))
   6386            (setq regexp (concat "[{]\\|>"))
   6387            ) ;t
   6388           ) ;cond
   6389          ;;(message "point=%S counter=%S inside=%S" (point) counter inside)
   6390          ) ;while
   6391        ) ;save-excursion
   6392      (when pos (goto-char pos))
   6393      ;;(message "jsx-skip: %S" pos)
   6394      pos))
   6395 
   6396 ;; http://facebook.github.io/jsx/
   6397 ;; https://github.com/facebook/jsx/blob/master/AST.md
   6398 (defun web-mode-jsx-scan-element (reg-beg reg-end depth)
   6399   (unless depth (setq depth 1))
   6400   (save-excursion
   6401     (goto-char reg-beg)
   6402     (put-text-property reg-beg (1+ reg-beg) 'jsx-beg depth)
   6403     (put-text-property (1- reg-end) reg-end 'jsx-end depth)
   6404     (put-text-property reg-beg reg-end 'jsx-depth depth)
   6405     (goto-char reg-beg)
   6406     (web-mode-scan-elements reg-beg reg-end)
   6407     (web-mode-jsx-scan-expression reg-beg reg-end (1+ depth))
   6408     ))
   6409 
   6410 (defun web-mode-jsx-scan-expression (reg-beg reg-end depth)
   6411   (let ((continue t) beg end)
   6412     (save-excursion
   6413       (goto-char reg-beg)
   6414       ;;(message "reg-beg=%S reg-end=%S" reg-beg reg-end)
   6415       (while (and continue (search-forward "{" reg-end t))
   6416         (backward-char)
   6417         (setq beg (point)
   6418               end (web-mode-closing-paren reg-end))
   6419         (cond
   6420           ((eq (get-text-property beg 'part-token) 'comment)
   6421            (forward-char))
   6422           ((not end)
   6423            (setq continue nil))
   6424           (t
   6425            (setq end (1+ end))
   6426            (put-text-property beg end 'jsx-depth depth)
   6427            (put-text-property beg (1+ beg) 'jsx-beg depth)
   6428            (put-text-property (1- end) end 'jsx-end depth)
   6429            (web-mode-part-scan beg end "jsx" (1+ depth))
   6430            ) ;t
   6431           ) ;cond
   6432         ) ;while
   6433       ) ;save-excursion
   6434     ))
   6435 
   6436 (defun web-mode-jsx-is-html (&optional pos)
   6437   (interactive)
   6438   (unless pos (setq pos (point)))
   6439   (let ((depth (get-text-property pos 'jsx-depth)))
   6440     (cond
   6441       ((or (null depth) (<= pos 2))
   6442        (setq pos nil))
   6443       ((and (= depth 1) (get-text-property pos 'jsx-beg))
   6444        (setq pos nil))
   6445       ((get-text-property pos 'tag-end)
   6446        (setq pos nil))
   6447       ((get-text-property pos 'tag-attr-beg)
   6448        (setq pos nil))
   6449       ((get-text-property pos 'jsx-beg)
   6450        (setq pos (null (get-text-property pos 'tag-beg))))
   6451       ((setq pos (web-mode-jsx-depth-beginning-position pos))
   6452        (setq pos (not (null (get-text-property pos 'tag-beg)))))
   6453       (t
   6454        (setq pos nil))
   6455       ) ;cond
   6456     ;;(message "is-html: %S (depth=%S)" pos depth)
   6457     pos))
   6458 
   6459 (defun web-mode-jsx-is-expr (&optional pos)
   6460   (cond
   6461     ((and (get-text-property pos 'jsx-beg)
   6462           (not (get-text-property pos 'tag-beg)))
   6463      nil)
   6464     (t
   6465      (setq pos (web-mode-jsx-depth-beginning-position pos))
   6466      (null (get-text-property pos 'tag-beg)))
   6467     ) ;cond
   6468   )
   6469 
   6470 (defun web-mode-jsx-depth-beginning-position (&optional pos target-depth)
   6471   (interactive)
   6472   (unless pos (setq pos (point)))
   6473   (unless target-depth (setq target-depth (get-text-property pos 'jsx-depth)))
   6474   (cond
   6475     ((or (null target-depth) (bobp))
   6476      (setq pos nil))
   6477     ((and (get-text-property pos 'jsx-beg) (= target-depth (get-text-property pos 'jsx-depth)))
   6478      )
   6479     (t
   6480      (let ((continue t) depth)
   6481        (while continue
   6482          (setq pos (previous-single-property-change pos 'jsx-depth))
   6483          (cond
   6484            ((or (null pos)
   6485                 (null (setq depth (get-text-property pos 'jsx-depth))))
   6486             (setq continue nil
   6487                   pos nil))
   6488            ((and (get-text-property pos 'jsx-beg) (= target-depth depth))
   6489             (setq continue nil))
   6490            ) ;cond
   6491          ) ;while
   6492        ) ;let
   6493      ) ;t
   6494     ) ;cond
   6495   ;;(message "beg: %S" pos)
   6496   pos)
   6497 
   6498 (defun web-mode-jsx-element-next (reg-end)
   6499   (let (continue beg end)
   6500     (setq beg (point))
   6501     (unless (get-text-property beg 'jsx-depth)
   6502       (setq beg (next-single-property-change beg 'jsx-beg)))
   6503     (setq continue (and beg (< beg reg-end))
   6504           end beg)
   6505     (while continue
   6506       (setq end (next-single-property-change end 'jsx-end))
   6507       (cond
   6508         ((or (null end) (> end reg-end))
   6509          (setq continue nil
   6510                end nil))
   6511         ((eq (get-text-property end 'jsx-depth) 1)
   6512          (setq continue nil))
   6513         (t
   6514          (setq end (1+ end)))
   6515         ) ;cond
   6516       ) ;while
   6517     ;;(message "beg=%S end=%S" beg end)
   6518     (if (and beg end (< beg end)) (cons beg end) nil)))
   6519 
   6520 (defun web-mode-jsx-expression-next (reg-end)
   6521   (let (beg end depth continue pos)
   6522     (setq beg (point))
   6523     ;;(message "pt=%S" beg)
   6524     (unless (and (get-text-property beg 'jsx-beg) (null (get-text-property beg 'tag-beg)))
   6525       ;;(setq beg (next-single-property-change beg 'jsx-beg))
   6526       (setq continue t
   6527             pos (1+ beg))
   6528       (while continue
   6529         (setq pos (next-single-property-change pos 'jsx-beg))
   6530         (cond
   6531           ((null pos)
   6532            (setq continue nil
   6533                  beg nil))
   6534           ((> pos reg-end)
   6535            (setq continue nil
   6536                  beg nil))
   6537           ((null (get-text-property pos 'jsx-beg))
   6538            )
   6539           ((null (get-text-property pos 'tag-beg))
   6540            (setq continue nil
   6541                  beg pos))
   6542           ;;(t
   6543           ;; (setq pos (1+ pos)))
   6544           ) ;cond
   6545         ) ;while
   6546       ) ;unless
   6547     ;;(message "beg=%S" beg)
   6548     (when (and beg (< beg reg-end))
   6549       (setq depth (get-text-property beg 'jsx-beg)
   6550             continue (not (null depth))
   6551             pos beg)
   6552       ;;(message "beg=%S" beg)
   6553       (while continue
   6554         (setq pos (next-single-property-change pos 'jsx-end))
   6555         ;;(message "pos=%S" pos)
   6556         (cond
   6557           ((null pos)
   6558            (setq continue nil))
   6559           ((> pos reg-end)
   6560            (setq continue nil))
   6561           ((eq depth (get-text-property pos 'jsx-end))
   6562            (setq continue nil
   6563                  end pos))
   6564           (t
   6565            ;;(setq pos (1+ pos))
   6566            )
   6567           ) ;cond
   6568         ) ;while
   6569       ) ;when
   6570     ;;(message "%S > %S" beg end)
   6571     (if (and beg end) (cons beg end) nil)))
   6572 
   6573 (defun web-mode-jsx-depth-next (reg-end)
   6574   (let (beg end depth continue pos)
   6575     (setq beg (point))
   6576     ;;(message "pt=%S" beg)
   6577     (unless (get-text-property beg 'jsx-beg)
   6578       ;;(setq beg (next-single-property-change beg 'jsx-beg))
   6579       ;;(setq pos (1+ beg))
   6580       (setq pos (next-single-property-change (1+ beg) 'jsx-beg))
   6581       (cond
   6582         ((null pos)
   6583          (setq beg nil))
   6584         ((>= pos reg-end)
   6585          (setq beg nil))
   6586         (t
   6587          (setq beg pos))
   6588         ) ;cond
   6589       ) ;unless
   6590     ;;(message "beg=%S" beg)
   6591     (when beg
   6592       (setq depth (get-text-property beg 'jsx-beg)
   6593             continue (not (null depth))
   6594             pos beg)
   6595       ;;(message "beg=%S" beg)
   6596       (while continue
   6597         (setq pos (next-single-property-change pos 'jsx-end))
   6598         ;;(message "pos=%S" pos)
   6599         (cond
   6600           ((null pos)
   6601            (setq continue nil))
   6602           ((> pos reg-end)
   6603            (setq continue nil))
   6604           ((eq depth (get-text-property pos 'jsx-end))
   6605            (setq continue nil
   6606                  end pos))
   6607           (t
   6608            ;;(setq pos (1+ pos))
   6609            )
   6610           ) ;cond
   6611         ) ;while
   6612       ) ;when
   6613     ;;(message "%S > %S" beg end)
   6614     (if (and beg end) (cons beg end) nil)))
   6615 
   6616 (defun web-mode-jsx-beginning ()
   6617   (interactive)
   6618   (let (depth (continue t) (reg-beg (point-min)) (pos (point)))
   6619     (setq depth (get-text-property pos 'jsx-depth))
   6620     (cond
   6621       ((not depth)
   6622        )
   6623       ((get-text-property (1- pos) 'jsx-beg)
   6624        (goto-char (1- pos)))
   6625       (t
   6626        (while continue
   6627          (setq pos (previous-single-property-change pos 'jsx-beg))
   6628          ;;(message "pos=%S" pos)
   6629          (cond
   6630            ((null pos)
   6631             (setq continue nil))
   6632            ((<= pos reg-beg)
   6633             (setq continue nil))
   6634            ((eq depth (get-text-property pos 'jsx-beg))
   6635             (setq continue nil))
   6636            ) ;cond
   6637          ) ;while
   6638        (web-mode-go pos)
   6639        ) ;t
   6640       ) ;cond
   6641     ))
   6642 
   6643 (defun web-mode-jsx-end ()
   6644   (interactive)
   6645   (let (depth (continue t) (reg-end (point-max)) (pos (point)))
   6646     (setq depth (get-text-property pos 'jsx-depth))
   6647     (cond
   6648       ((not depth)
   6649        )
   6650       ((get-text-property pos 'jsx-end)
   6651        (goto-char (+ pos 1)))
   6652       (t
   6653        (while continue
   6654          (setq pos (next-single-property-change pos 'jsx-end))
   6655          ;;(message "pos=%S" pos)
   6656          (cond
   6657            ((null pos)
   6658             (setq continue nil))
   6659            ((> pos reg-end)
   6660             (setq continue nil))
   6661            ((eq depth (get-text-property pos 'jsx-end))
   6662             (setq continue nil))
   6663            ) ;cond
   6664          ) ;while
   6665        (web-mode-go pos 1)
   6666        ) ;t
   6667       ) ;cond
   6668     ))
   6669 
   6670 ;;---- FONTIFICATION -----------------------------------------------------------
   6671 
   6672 (defun web-mode-fontify (limit)
   6673   (when web-mode-trace
   6674     (message "fontify: point(%S) limit(%S)" (point) limit))
   6675   (cond
   6676     ;;(web-mode-skip-fontification
   6677     ;; nil)
   6678     (t
   6679      (web-mode-with-silent-modifications
   6680       (save-excursion
   6681         (save-restriction
   6682           (save-match-data
   6683             (let ((beg (point))
   6684                   (buffer-undo-list t)
   6685                   (end limit)
   6686                   (inhibit-point-motion-hooks t)
   6687                   (inhibit-quit t))
   6688               (remove-list-of-text-properties beg end '(font-lock-face face))
   6689               (cond
   6690                 ((and (get-text-property beg 'block-side)
   6691                       (not (get-text-property beg 'block-beg)))
   6692                  (web-mode-fontify-block beg end))
   6693                 ((or (member web-mode-content-type web-mode-part-content-types)
   6694                      (get-text-property beg 'part-side))
   6695                  (web-mode-fontify-part beg end)
   6696                  (web-mode-block-foreach beg end 'web-mode-fontify-block))
   6697                 ((string= web-mode-engine "none")
   6698                  (web-mode-fontify-tags beg end)
   6699                  (web-mode-part-foreach beg end 'web-mode-fontify-part))
   6700                 (t
   6701                  (web-mode-fontify-tags beg end)
   6702                  (web-mode-part-foreach beg end 'web-mode-fontify-part)
   6703                  (web-mode-block-foreach beg end 'web-mode-fontify-block))
   6704                 ) ;cond
   6705               (when web-mode-enable-element-content-fontification
   6706                 (web-mode-fontify-elements beg end))
   6707               (when web-mode-enable-whitespace-fontification
   6708                 (web-mode-fontify-whitespaces beg end))
   6709               ) ;let
   6710             ))))
   6711      nil) ;t
   6712     ))
   6713 
   6714 (defun web-mode-buffer-fontify ()
   6715   (interactive)
   6716   (cond
   6717     ((and (fboundp 'font-lock-flush) global-font-lock-mode)
   6718      (font-lock-flush)
   6719      (font-lock-ensure))
   6720     (t  ;emacs 24
   6721      ;;(font-lock-fontify-buffer)
   6722      (and global-font-lock-mode
   6723           (font-lock-fontify-region (point-min) (point-max))))
   6724     ))
   6725 
   6726 (defun web-mode-unfontify-region (beg end)
   6727   (ignore beg end)
   6728   ;;(message "unfontify: %S %S" beg end)
   6729   )
   6730 
   6731 (defun web-mode-fontify-region (beg end keywords)
   6732   ;;  (message "beg=%S end=%S keywords=%S" beg end (symbol-name keywords))
   6733   (save-excursion
   6734     (let ((font-lock-keywords keywords)
   6735           (font-lock-multiline nil)
   6736           (font-lock-keywords-case-fold-search
   6737            (member web-mode-engine '("archibus" "asp" "template-toolkit")))
   6738           (font-lock-keywords-only t)
   6739           (font-lock-extend-region-functions nil))
   6740       (when (and (listp font-lock-keywords) global-font-lock-mode)
   6741         (font-lock-fontify-region beg end)
   6742         )
   6743       )))
   6744 
   6745 (defun web-mode-fontify-tags (reg-beg reg-end &optional depth)
   6746   (let ((continue t))
   6747     (goto-char reg-beg)
   6748     (when (and (not (get-text-property (point) 'tag-beg))
   6749                (not (web-mode-tag-next)))
   6750       (setq continue nil))
   6751     (when (and continue (>= (point) reg-end))
   6752       (setq continue nil))
   6753     (while continue
   6754       (cond
   6755         (depth
   6756          (when (eq depth (get-text-property (point) 'jsx-depth))
   6757            (web-mode-fontify-tag))
   6758          )
   6759         (t
   6760          (web-mode-fontify-tag))
   6761         ) ;cond
   6762       (when (or (not (web-mode-tag-next))
   6763                 (>= (point) reg-end))
   6764         (setq continue nil))
   6765       ) ;while
   6766     (when web-mode-enable-inlays
   6767       (when (null web-mode-inlay-regexp)
   6768         (setq web-mode-inlay-regexp (regexp-opt '("\\[" "\\(" "\\begin{align}"))))
   6769       (let (beg end expr)
   6770         (goto-char reg-beg)
   6771         (while (web-mode-dom-rsf web-mode-inlay-regexp reg-end)
   6772           (setq beg (match-beginning 0)
   6773                 end nil
   6774                 expr (substring (match-string-no-properties 0) 0 2))
   6775           (setq expr (cond
   6776                        ((string= expr "\\[") "\\]")
   6777                        ((string= expr "\\(") "\\)")
   6778                        (t "\\end{align}")))
   6779           (when (and (web-mode-dom-sf expr reg-end)
   6780                      (setq end (match-end 0))
   6781                      (not (text-property-any beg end 'tag-end t)))
   6782             (font-lock-append-text-property beg end 'font-lock-face 'web-mode-inlay-face)
   6783             ) ;when
   6784           ) ;while
   6785         ) ;let
   6786       ) ;when
   6787     (when web-mode-enable-html-entities-fontification
   6788       (let (beg end)
   6789         (goto-char reg-beg)
   6790         (while (web-mode-dom-rsf "&\\([#]?[[:alnum:]]\\{2,8\\}\\);" reg-end)
   6791           (setq beg (match-beginning 0)
   6792                 end (match-end 0))
   6793           (when (not (text-property-any beg end 'tag-end t))
   6794             (font-lock-append-text-property beg end 'font-lock-face 'web-mode-html-entity-face)
   6795             ) ;when
   6796           ) ;while
   6797         ) ;let
   6798       ) ;when
   6799     ))
   6800 
   6801 (defun web-mode-fontify-tag (&optional beg end)
   6802   (unless beg (setq beg (point)))
   6803   (unless end (setq end (1+ (web-mode-tag-end-position beg))))
   6804   (let (name type face flags slash-beg slash-end bracket-end)
   6805     (setq flags (get-text-property beg 'tag-beg)
   6806           type (get-text-property beg 'tag-type)
   6807           name (get-text-property beg 'tag-name))
   6808     (setq bracket-end (> (logand flags 16) 0))
   6809     (cond
   6810       ((eq type 'comment)
   6811        (put-text-property beg end 'font-lock-face 'web-mode-comment-face)
   6812        (when (and web-mode-enable-comment-interpolation (> (- end beg) 5))
   6813          (web-mode-interpolate-comment beg end nil)))
   6814       ((eq type 'cdata)
   6815        (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
   6816       ((eq type 'doctype)
   6817        (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
   6818       ((eq type 'declaration)
   6819        (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
   6820       (name
   6821        (setq slash-beg (> (logand flags 4) 0)
   6822              slash-end (> (logand flags 8) 0)
   6823              bracket-end (> (logand flags 16) 0))
   6824        (setq face (cond
   6825                     ((not bracket-end)       'web-mode-html-tag-unclosed-face)
   6826                     ((and web-mode-enable-element-tag-fontification
   6827                           (setq face (cdr (assoc name web-mode-element-tag-faces))))
   6828                      face)
   6829                     ((> (logand flags 32) 0) 'web-mode-html-tag-namespaced-face)
   6830                     ((> (logand flags 2) 0)  'web-mode-html-tag-custom-face)
   6831                     (t                       'web-mode-html-tag-face)))
   6832        (put-text-property beg (+ beg (if slash-beg 2 1))
   6833                           'font-lock-face 'web-mode-html-tag-bracket-face)
   6834        (unless (string= name "_fragment_")
   6835          (put-text-property (+ beg (if slash-beg 2 1))
   6836                             (+ beg (if slash-beg 2 1) (length name))
   6837                             'font-lock-face face))
   6838        (when (or slash-end bracket-end)
   6839          (put-text-property (- end (if slash-end 2 1)) end 'font-lock-face 'web-mode-html-tag-bracket-face)
   6840          ) ;when
   6841        (when (> (logand flags 1) 0)
   6842          ;;(message "%S>%S" beg end)
   6843          (web-mode-fontify-attrs beg end))
   6844        ) ;case name
   6845       ) ;cond
   6846     ))
   6847 
   6848 (defun web-mode-fontify-attrs (reg-beg reg-end)
   6849   (let ((continue t) (pos reg-beg) beg end flags offset face)
   6850     ;;(message "fontify-attrs %S>%S" reg-beg reg-end)
   6851     (while continue
   6852       (setq beg (web-mode-attribute-next-position pos reg-end))
   6853       (cond
   6854         ((or (null beg) (>= beg reg-end))
   6855          (setq continue nil))
   6856         (t
   6857          (setq flags (or (get-text-property beg 'tag-attr-beg) 0))
   6858          (setq face (cond
   6859                       ((= (logand flags 1) 1) 'web-mode-html-attr-custom-face)
   6860                       ((= (logand flags 2) 2) 'web-mode-html-attr-engine-face)
   6861                       ((= (logand flags 4) 4) nil)
   6862                       (t                      'web-mode-html-attr-name-face)))
   6863          ;;(setq end (if (get-text-property beg 'tag-attr-end) beg (web-mode-attribute-end-position beg)))
   6864          (setq end (web-mode-attribute-end-position beg))
   6865          ;;(message "beg=%S end=%S" beg end)
   6866          (cond
   6867            ((or (null end) (>= end reg-end))
   6868             (setq continue nil))
   6869            (t
   6870             (setq offset (get-text-property end 'tag-attr-end))
   6871             (if (= offset 0)
   6872                 (put-text-property beg (1+ end) 'font-lock-face face)
   6873                 (put-text-property beg (+ beg offset) 'font-lock-face face)
   6874                 (put-text-property (+ beg offset) (+ beg offset 1)
   6875                                    'font-lock-face
   6876                                    'web-mode-html-attr-equal-face)
   6877                 (when (not (get-text-property (+ beg offset 1) 'jsx-beg))
   6878                   (put-text-property (+ beg offset 1) (1+ end)
   6879                                      'font-lock-face
   6880                                      'web-mode-html-attr-value-face)
   6881                   )
   6882                 ) ;if offset
   6883             (setq pos (1+ end))
   6884             ) ;t
   6885            ) ;cond
   6886          ) ;t
   6887         );cond
   6888       ) ;while
   6889     ))
   6890 
   6891 (defun web-mode-fontify-block (reg-beg reg-end)
   6892   (when web-mode-trace
   6893     (message "fontify-block: reg-beg(%S) reg-end(%S) engine(%S) keywords(%S)"
   6894              reg-beg reg-end web-mode-engine (not (null web-mode-engine-font-lock-keywords))))
   6895 
   6896   (let (sub1 sub2 sub3 continue char keywords token-type face beg end (buffer (current-buffer)))
   6897 
   6898     ;; NOTE: required for blocks inside tag attrs
   6899     ;; NOTE: ajout de face dans la liste pour sucharger la couleur définie par
   6900     ;;       un prealable web-mode-fontity-part (2022-12-25 #1230)
   6901     (remove-list-of-text-properties reg-beg reg-end '(font-lock-face face))
   6902     ;;(message "reg-beg=%S reg-end=%S" reg-beg reg-end)
   6903 
   6904     (goto-char reg-beg)
   6905 
   6906     (when (null web-mode-engine-font-lock-keywords)
   6907       (setq sub1 (buffer-substring-no-properties
   6908                   reg-beg (+ reg-beg 1))
   6909             sub2 (buffer-substring-no-properties
   6910                   reg-beg (+ reg-beg 2))
   6911             sub3 (buffer-substring-no-properties
   6912                   reg-beg (+ reg-beg (if (>= (point-max) (+ reg-beg 3)) 3 2))))
   6913       )
   6914 
   6915     (cond
   6916 
   6917       ((and (get-text-property reg-beg 'block-beg)
   6918             (eq (get-text-property reg-beg 'block-token) 'comment))
   6919        (put-text-property reg-beg reg-end 'font-lock-face 'web-mode-comment-face)
   6920        ) ;comment block
   6921 
   6922       (web-mode-engine-font-lock-keywords
   6923        (setq keywords web-mode-engine-font-lock-keywords))
   6924 
   6925       ((string= web-mode-engine "django")
   6926        (cond
   6927          ((string= sub2 "{{")
   6928           (setq keywords web-mode-django-expr-font-lock-keywords))
   6929          ((string= sub2 "{%")
   6930           (setq keywords web-mode-django-code-font-lock-keywords))
   6931          ((string= sub1 "#")
   6932           (setq keywords web-mode-django-code-font-lock-keywords))
   6933          )) ;django
   6934 
   6935       ((string= web-mode-engine "mako")
   6936        (cond
   6937          ((member sub3 '("<% " "<%\n" "<%!"))
   6938           (setq keywords web-mode-mako-block-font-lock-keywords))
   6939          ((eq (aref sub2 0) ?\%)
   6940           (setq keywords web-mode-mako-block-font-lock-keywords))
   6941          ((member sub2 '("<%" "</"))
   6942           (setq keywords web-mode-mako-tag-font-lock-keywords))
   6943          ((member sub2 '("${"))
   6944           (setq keywords web-mode-uel-font-lock-keywords))
   6945          )) ;mako
   6946 
   6947       ((string= web-mode-engine "mason")
   6948        ;;(message "%S %S" sub2 sub3)
   6949        (cond
   6950          ((member sub3 '("<% " "<%\n" "<&|"))
   6951           (setq keywords web-mode-mason-code-font-lock-keywords))
   6952          ((eq (aref sub2 0) ?\%)
   6953           (setq keywords web-mode-mason-code-font-lock-keywords))
   6954          ((and (or (string= sub2 "<%") (string= sub3 "</%"))
   6955                (not (member sub3 '("<%c" "<%i" "<%p"))))
   6956           (setq keywords web-mode-mason-block-font-lock-keywords))
   6957          (t
   6958           (setq keywords web-mode-mason-code-font-lock-keywords))
   6959          )) ;mason
   6960 
   6961       ((string= web-mode-engine "jsp")
   6962        (cond
   6963          ((string= sub3 "<%@")
   6964           (setq keywords web-mode-directive-font-lock-keywords))
   6965          ((member sub2 '("${" "#{"))
   6966           (setq keywords web-mode-uel-font-lock-keywords))
   6967          ((string= sub2 "<%")
   6968           (setq keywords web-mode-jsp-font-lock-keywords))
   6969          )) ;jsp
   6970 
   6971       ((string= web-mode-engine "asp")
   6972        (cond
   6973          ((or (string= sub2 "<%")
   6974               (not (string= sub1 "<")))
   6975           (setq keywords web-mode-asp-font-lock-keywords))
   6976          (t
   6977           (setq keywords web-mode-engine-tag-font-lock-keywords))
   6978          )) ;asp
   6979 
   6980       ((string= web-mode-engine "clip")
   6981        (setq keywords web-mode-engine-tag-font-lock-keywords)
   6982        ) ;clip
   6983 
   6984       ((string= web-mode-engine "perl")
   6985        (setq keywords web-mode-engine-tag-font-lock-keywords)
   6986        ) ;perl
   6987 
   6988       ((string= web-mode-engine "aspx")
   6989        (cond
   6990          ((string= sub3 "<%@")
   6991           (setq keywords web-mode-directive-font-lock-keywords))
   6992          ((string= sub3 "<%$")
   6993           (setq keywords web-mode-expression-font-lock-keywords))
   6994          (t
   6995           (setq keywords web-mode-aspx-font-lock-keywords))
   6996          )) ;aspx
   6997 
   6998       ((string= web-mode-engine "freemarker")
   6999        (cond
   7000          ((member sub2 '("${" "#{"))
   7001           (setq keywords web-mode-uel-font-lock-keywords))
   7002          ((or (member sub2 '("<@" "[@" "<#" "[#"))
   7003               (member sub3 '("</@" "[/@" "</#" "[/#")))
   7004           (setq keywords (if (eq ?\[ (aref sub2 0))
   7005                              web-mode-freemarker-square-font-lock-keywords
   7006                              web-mode-freemarker-font-lock-keywords)))
   7007          (t
   7008           (setq keywords web-mode-engine-tag-font-lock-keywords))
   7009          )) ;freemarker
   7010 
   7011       ) ;cond
   7012 
   7013     (when keywords
   7014       (web-mode-fontify-region reg-beg reg-end keywords)
   7015       (setq continue t)
   7016       (setq end reg-beg)
   7017       (while continue
   7018         (if (get-text-property end 'block-token)
   7019             (setq beg end)
   7020             (setq beg (next-single-property-change end 'block-token buffer reg-end)))
   7021         (setq end nil)
   7022         (when beg (setq char (char-after beg)))
   7023         (if (and beg (< beg reg-end))
   7024             (progn
   7025               (setq token-type (get-text-property beg 'block-token))
   7026               (setq face (cond
   7027                            ((eq token-type 'string)  'web-mode-block-string-face)
   7028                            ((eq token-type 'comment) 'web-mode-block-comment-face)
   7029                            ((eq token-type 'symbol)  'web-mode-symbol-face)
   7030                            (t                        'web-mode-block-delimiter-face)))
   7031               (setq end (next-single-property-change beg 'block-token buffer reg-end))
   7032               ;;              (message "end=%S" end)
   7033               (if (and end (<= end reg-end))
   7034                   (progn
   7035                     ;;(message "%S > %S face(%S)" beg end face)
   7036                     (remove-list-of-text-properties beg end '(face))
   7037                     (put-text-property beg end 'font-lock-face face)
   7038                     )
   7039                   (setq continue nil
   7040                         end nil)
   7041                   ) ;if end
   7042               ) ;progn beg
   7043             (setq continue nil
   7044                   end nil)
   7045             ) ;if beg
   7046         (when (and beg end)
   7047           (save-match-data
   7048             (when (and web-mode-enable-heredoc-fontification
   7049                        (eq char ?\<)
   7050                        (> (- end beg) 8)
   7051                        (string-match-p "JS\\|JAVASCRIPT\\|HTM\\|CSS" (buffer-substring-no-properties beg end)))
   7052               (setq keywords
   7053                     (cond
   7054                       ((string-match-p "H" (buffer-substring-no-properties beg (+ beg 8)))
   7055                        web-mode-html-font-lock-keywords)
   7056                       (t
   7057                        web-mode-javascript-font-lock-keywords)
   7058                       ))
   7059               (web-mode-fontify-region beg end keywords)
   7060               )
   7061             ) ;save-match-data
   7062           (when (and web-mode-enable-string-interpolation
   7063                      (member char '(?\" ?\<))
   7064                      (member web-mode-engine '("php" "erb"))
   7065                      (> (- end beg) 4))
   7066             (web-mode-interpolate-block-string beg end)
   7067             ) ;when
   7068           (when (and web-mode-enable-comment-interpolation
   7069                      (eq token-type 'comment)
   7070                      (> (- end beg) 3))
   7071             (web-mode-interpolate-comment beg end t)
   7072             ) ;when
   7073           (when (and web-mode-enable-comment-annotation
   7074                      (eq token-type 'comment)
   7075                      (> (- end beg) 3))
   7076             (web-mode-annotate-comment beg end)
   7077             ) ;when
   7078           (when (and web-mode-enable-sql-detection
   7079                      (eq token-type 'string)
   7080                      (> (- end beg) 6)
   7081                      (web-mode-looking-at-p (concat "\\(.\\|<<<[[:alnum:]]+\\)[ \n]*" web-mode-sql-queries) beg)
   7082                      )
   7083             (web-mode-interpolate-sql-string beg end)
   7084             ) ;when
   7085           ) ;when beg end
   7086         ) ;while continue
   7087       ) ;when keywords
   7088 
   7089     (when (and (member web-mode-engine '("mako"))
   7090                (> (- reg-end reg-beg) 12)
   7091                (eq ?\< (char-after reg-beg)))
   7092       (web-mode-interpolate-block-tag reg-beg reg-end))
   7093 
   7094     (when web-mode-enable-block-face
   7095       (font-lock-append-text-property reg-beg reg-end 'face 'web-mode-block-face))
   7096 
   7097     ))
   7098 
   7099 (defun web-mode-fontify-part (reg-beg reg-end &optional depth)
   7100   (save-excursion
   7101     (let (continue token-type face pos beg end string-face comment-face content-type)
   7102       ;;(message "fontify-part: reg-beg(%S) reg-end(%S)" reg-beg reg-end)
   7103       (if (member web-mode-content-type web-mode-part-content-types)
   7104           (setq content-type web-mode-content-type)
   7105           (setq content-type (symbol-name (get-text-property reg-beg 'part-side))))
   7106       ;;(message "content-type=%S" content-type)
   7107       (unless depth
   7108         (when (string= content-type "jsx") (setq depth 0))
   7109         )
   7110       (setq string-face 'web-mode-part-string-face
   7111             comment-face 'web-mode-part-comment-face)
   7112       (cond
   7113         ((member content-type '("javascript" "jsx"))
   7114          (setq string-face 'web-mode-javascript-string-face
   7115                comment-face 'web-mode-javascript-comment-face)
   7116          (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
   7117         ((string= content-type "json")
   7118          (setq string-face 'web-mode-json-string-face
   7119                comment-face 'web-mode-json-comment-face)
   7120          (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
   7121         ((string= content-type "css")
   7122          (setq string-face 'web-mode-css-string-face
   7123                comment-face 'web-mode-css-comment-face)
   7124          (web-mode-fontify-css-rules reg-beg reg-end))
   7125         ((string= content-type "sql")
   7126          (web-mode-fontify-region reg-beg reg-end web-mode-sql-font-lock-keywords))
   7127         ((string= content-type "stylus")
   7128          (web-mode-fontify-region reg-beg reg-end web-mode-stylus-font-lock-keywords))
   7129         ((string= content-type "sass")
   7130          (web-mode-fontify-region reg-beg reg-end web-mode-sass-font-lock-keywords))
   7131         ((string= content-type "pug")
   7132          (web-mode-fontify-region reg-beg reg-end web-mode-pug-font-lock-keywords))
   7133         ((string= content-type "markdown")
   7134          (web-mode-fontify-region reg-beg reg-end web-mode-markdown-font-lock-keywords))
   7135         ((string= content-type "ruby")
   7136          (web-mode-fontify-region reg-beg reg-end web-mode-erb-font-lock-keywords))
   7137         ((string= content-type "typescript")
   7138          (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
   7139         ) ;cond
   7140 
   7141       (goto-char reg-beg)
   7142 
   7143       ;;(when (string= content-type "jsx") (web-mode-fontify-tags reg-beg reg-end))
   7144       ;;(setq continue (and pos (< pos reg-end)))
   7145       (setq continue t
   7146             pos reg-beg)
   7147       (while continue
   7148         (if (get-text-property pos 'part-token)
   7149             (setq beg pos)
   7150             (setq beg (next-single-property-change pos 'part-token)))
   7151         (cond
   7152           ((or (null beg) (>= beg reg-end))
   7153            (setq continue nil
   7154                  end nil))
   7155           ((and (eq depth 0) (get-text-property beg 'jsx-depth))
   7156            (setq pos (or (next-single-property-change beg 'jsx-depth) (point-max))))
   7157           (t
   7158            ;;(message "%c" (char-after beg))
   7159            (setq token-type (get-text-property beg 'part-token))
   7160            (setq face (cond
   7161                         ((eq token-type 'string)  string-face)
   7162                         ((eq token-type 'comment) comment-face)
   7163                         ((eq token-type 'context) 'web-mode-json-context-face)
   7164                         ((eq token-type 'key)     'web-mode-json-key-face)
   7165                         (t                        nil)))
   7166            (setq end (or (next-single-property-change beg 'part-token) (point-max))
   7167                  pos end)
   7168            (cond
   7169              ((or (null end) (> end reg-end))
   7170               (setq continue nil
   7171                     end nil))
   7172              (t
   7173               (when face
   7174                 (remove-list-of-text-properties beg end '(face))
   7175                 (put-text-property beg end 'font-lock-face face))
   7176               (cond
   7177                 ((< (- end beg) 6)
   7178                  )
   7179                 ((eq token-type 'string)
   7180                  (cond
   7181                    ((and (eq (char-after beg) ?\`)
   7182                          web-mode-enable-literal-interpolation
   7183                          (member content-type '("javascript" "jsx" "typescript")))
   7184                     (web-mode-interpolate-javascript-literal beg end)
   7185                     )
   7186                    ((and (eq (char-after beg) ?\")
   7187                          web-mode-enable-string-interpolation
   7188                          (member content-type '("javascript" "jsx" "typescript")))
   7189                     (web-mode-interpolate-javascript-string beg end))
   7190                    ) ;cond
   7191                  ) ;case string
   7192                 ((eq token-type 'comment)
   7193                  (when web-mode-enable-comment-interpolation
   7194                    (web-mode-interpolate-comment beg end t))
   7195                  (when web-mode-enable-comment-annotation
   7196                    (web-mode-annotate-comment beg end))
   7197                  )
   7198                 ) ;cond
   7199               ) ;t
   7200              ) ;cond
   7201            ) ;t
   7202           ) ;cond
   7203         ) ;while
   7204 
   7205       (when (and (string= web-mode-content-type "html") web-mode-enable-part-face)
   7206         (font-lock-append-text-property reg-beg reg-end 'face
   7207                                         (cond
   7208                                           ((string= content-type "javascript")
   7209                                            'web-mode-script-face)
   7210                                           ((string= content-type "css")
   7211                                            'web-mode-style-face)
   7212                                           (t
   7213                                            'web-mode-part-face)))
   7214         )
   7215 
   7216       (when (and web-mode-enable-css-colorization (string= content-type "stylus"))
   7217         (goto-char reg-beg)
   7218         (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)
   7219                     (<= (point) reg-end))
   7220           (web-mode-colorize (match-beginning 0) (match-end 0))
   7221           )
   7222         )
   7223 
   7224       (when (and (eq depth 0) (string= content-type "jsx"))
   7225         (let (pair elt-beg elt-end exp-beg exp-end exp-depth)
   7226           (goto-char reg-beg)
   7227           (while (setq pair (web-mode-jsx-element-next reg-end))
   7228             ;;(message "elt-pair=%S" pair)
   7229             (setq elt-beg (car pair)
   7230                   elt-end (cdr pair))
   7231             (remove-list-of-text-properties elt-beg (1+ elt-end) '(face))
   7232             (web-mode-fontify-tags elt-beg elt-end 1)
   7233             (goto-char elt-beg)
   7234             (while (setq pair (web-mode-jsx-expression-next elt-end))
   7235               ;;(message "exp-pair=%S elt-end=%S" pair elt-end)
   7236               (setq exp-beg (car pair)
   7237                     exp-end (cdr pair))
   7238               (when (eq (char-after exp-beg) ?\{)
   7239                 ;;(message "%S : %c %c" exp-beg (char-after (+ exp-beg 1)) (char-after (+ exp-beg 2)))
   7240                 (cond
   7241                   ;;((and (eq (char-after (+ exp-beg 1)) ?\/) (eq (char-after (+ exp-beg 2)) ?\*))
   7242                   ;; (put-text-property exp-beg (1+ exp-end) 'font-lock-face 'web-mode-part-comment-face)
   7243                   ;; )
   7244                   (t
   7245                    (setq exp-depth (get-text-property exp-beg 'jsx-depth))
   7246                    (remove-list-of-text-properties exp-beg exp-end '(font-lock-face))
   7247                    (put-text-property exp-beg (1+ exp-beg) 'font-lock-face 'web-mode-block-delimiter-face)
   7248                    (when (and (eq (get-text-property exp-beg 'tag-attr-beg) 4) (web-mode-looking-at-p "\.\.\." (1+ exp-beg)))
   7249                      (put-text-property exp-beg (+ exp-beg 4) 'font-lock-face 'web-mode-block-delimiter-face))
   7250                    (put-text-property exp-end (1+ exp-end) 'font-lock-face 'web-mode-block-delimiter-face)
   7251                    (web-mode-fontify-tags (1+ exp-beg) exp-end (1+ exp-depth))
   7252                    (web-mode-fontify-part (1+ exp-beg) exp-end exp-depth)
   7253                    (web-mode-fontify-region (1+ exp-beg) exp-end web-mode-javascript-font-lock-keywords)
   7254                    ) ;t
   7255                   ) ;cond
   7256                 ) ;when
   7257               (goto-char (1+ exp-beg))
   7258               ) ;while exp
   7259 
   7260             (when (and elt-beg web-mode-jsx-depth-faces)
   7261               (let (depth-beg depth-end jsx-face)
   7262                 (goto-char elt-beg)
   7263                 (while (setq pair (web-mode-jsx-depth-next reg-end))
   7264                   ;;(message "depth-pair=%S" pair)
   7265                   (setq depth-beg (car pair)
   7266                         depth-end (cdr pair)
   7267                         depth (get-text-property depth-beg 'jsx-depth)
   7268                         jsx-face (elt web-mode-jsx-depth-faces (1- depth)))
   7269                   ;;(message "%S" jsx-face)
   7270                   (font-lock-prepend-text-property depth-beg (1+ depth-end) 'face jsx-face)
   7271                   (goto-char (+ depth-beg 2))
   7272                   )
   7273                 ) ;let
   7274               )
   7275 
   7276             (goto-char (1+ elt-end))
   7277             ) ;while elt
   7278           ) ;let
   7279         ) ;when
   7280 
   7281       ) ;let
   7282     ) ;save-excursion
   7283   )
   7284 
   7285 (defun web-mode-fontify-css-rules (part-beg part-end)
   7286   (save-excursion
   7287     (goto-char part-beg)
   7288     (let (rule (continue t) (i 0) (at-rule nil))
   7289       (while continue
   7290         (setq rule (web-mode-css-rule-next part-end))
   7291         ;;(message "rule=%S" rule)
   7292         (cond
   7293           ((> (setq i (1+ i)) 1000)
   7294            (message "fontify-css-rules ** too much rules **")
   7295            (setq continue nil))
   7296           ((null rule)
   7297            (setq continue nil))
   7298           ((and (setq at-rule (plist-get rule :at-rule))
   7299                 (not (member at-rule '("charset" "font-face" "import" "viewport")))
   7300                 (plist-get rule :dec-end))
   7301            (web-mode-fontify-css-rule (plist-get rule :sel-beg)
   7302                                       (plist-get rule :sel-end)
   7303                                       nil nil)
   7304            (web-mode-fontify-css-rules (plist-get rule :dec-beg)
   7305                                        (plist-get rule :dec-end)))
   7306           (t
   7307            (web-mode-fontify-css-rule (plist-get rule :sel-beg)
   7308                                       (plist-get rule :sel-end)
   7309                                       (plist-get rule :dec-beg)
   7310                                       (plist-get rule :dec-end)))
   7311           ) ;cond
   7312         ) ;while
   7313       ) ;let
   7314     ))
   7315 
   7316 (defun web-mode-fontify-css-rule (sel-beg sel-end dec-beg dec-end)
   7317   (save-excursion
   7318     ;;(let ((end sel-end))
   7319     ;;(message "sel-beg=%S sel-end=%S dec-beg=%S dec-end=%S" sel-beg sel-end dec-beg dec-end)
   7320     (web-mode-fontify-region sel-beg sel-end web-mode-selector-font-lock-keywords)
   7321     (when (and dec-beg dec-end)
   7322       ;;(setq end dec-end)
   7323       (web-mode-fontify-region dec-beg dec-end web-mode-declaration-font-lock-keywords)
   7324       ) ;when
   7325     (when (and dec-beg dec-end)
   7326       (goto-char dec-beg)
   7327       (while (and web-mode-enable-css-colorization
   7328                   (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)
   7329                   ;;(progn (message "%S %S" end (point)) t)
   7330                   (<= (point) dec-end))
   7331         ;;(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)))
   7332         (web-mode-colorize (match-beginning 1) (match-end 1))
   7333         ) ;while
   7334       ) ;when
   7335     ;;) ;let
   7336     ))
   7337 
   7338 (defun web-mode-colorize-foreground (color)
   7339   (let* ((values (x-color-values color))
   7340          (r (car values))
   7341          (g (cadr values))
   7342          (b (car (cdr (cdr values)))))
   7343     (if (> 128.0 (floor (+ (* .3 r) (* .59 g) (* .11 b)) 256))
   7344         "white" "black")))
   7345 
   7346 (defun web-mode-colorize (beg end)
   7347   (let (str plist)
   7348     (setq str (buffer-substring-no-properties beg end))
   7349     ;;(setq str1 (match-string-no-properties 1))
   7350     ;;(message "str=%S" str str1)
   7351     (cond
   7352       ;;(t
   7353       ;; (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))
   7354       ;; )
   7355       ((string= (substring str 0 1) "#")
   7356        (setq plist (list :background str
   7357                          :foreground (web-mode-colorize-foreground str))))
   7358       ((and (>= (length str) 3) (string= (substring str 0 3) "rgb"))
   7359        (setq str (format "#%02X%02X%02X"
   7360                          (string-to-number (match-string-no-properties 2))
   7361                          (string-to-number (match-string-no-properties 3))
   7362                          (string-to-number (match-string-no-properties 4))))
   7363        (setq plist (list :background str
   7364                          :foreground (web-mode-colorize-foreground str))))
   7365       ((string= str "black") (setq plist (list :background "#000000" :foreground (web-mode-colorize-foreground "#000000"))))
   7366       ((string= str "silver") (setq plist (list :background "#c0c0c0" :foreground (web-mode-colorize-foreground "#c0c0c0"))))
   7367       ((string= str "gray") (setq plist (list :background "#808080" :foreground (web-mode-colorize-foreground "#808080"))))
   7368       ((string= str "white") (setq plist (list :background "#ffffff" :foreground (web-mode-colorize-foreground "#ffffff"))))
   7369       ((string= str "maroon") (setq plist (list :background "#800000" :foreground (web-mode-colorize-foreground "#800000"))))
   7370       ((string= str "red") (setq plist (list :background "#ff0000" :foreground (web-mode-colorize-foreground "#ff0000"))))
   7371       ((string= str "purple") (setq plist (list :background "#800080" :foreground (web-mode-colorize-foreground "#800080"))))
   7372       ((string= str "fuchsia") (setq plist (list :background "#ff00ff" :foreground (web-mode-colorize-foreground "#ff00ff"))))
   7373       ((string= str "green") (setq plist (list :background "#008000" :foreground (web-mode-colorize-foreground "#008000"))))
   7374       ((string= str "lime") (setq plist (list :background "#00ff00" :foreground (web-mode-colorize-foreground "#00ff00"))))
   7375       ((string= str "olive") (setq plist (list :background "#808000" :foreground (web-mode-colorize-foreground "#808000"))))
   7376       ((string= str "yellow") (setq plist (list :background "#ffff00" :foreground (web-mode-colorize-foreground "#ffff00"))))
   7377       ((string= str "navy") (setq plist (list :background "#000080" :foreground (web-mode-colorize-foreground "#000080"))))
   7378       ((string= str "blue") (setq plist (list :background "#0000ff" :foreground (web-mode-colorize-foreground "#0000ff"))))
   7379       ((string= str "teal") (setq plist (list :background "#008080" :foreground (web-mode-colorize-foreground "#008080"))))
   7380       ((string= str "aqua") (setq plist (list :background "#00ffff" :foreground (web-mode-colorize-foreground "#00ffff"))))
   7381       ((string= str "orange") (setq plist (list :background "#ffa500" :foreground (web-mode-colorize-foreground "#ffa500"))))
   7382       ((string= str "aliceblue") (setq plist (list :background "#f0f8ff" :foreground (web-mode-colorize-foreground "#f0f8ff"))))
   7383       ((string= str "antiquewhite") (setq plist (list :background "#faebd7" :foreground (web-mode-colorize-foreground "#faebd7"))))
   7384       ((string= str "aquamarine") (setq plist (list :background "#7fffd4" :foreground (web-mode-colorize-foreground "#7fffd4"))))
   7385       ((string= str "azure") (setq plist (list :background "#f0ffff" :foreground (web-mode-colorize-foreground "#f0ffff"))))
   7386       ((string= str "beige") (setq plist (list :background "#f5f5dc" :foreground (web-mode-colorize-foreground "#f5f5dc"))))
   7387       ((string= str "bisque") (setq plist (list :background "#ffe4c4" :foreground (web-mode-colorize-foreground "#ffe4c4"))))
   7388       ((string= str "blanchedalmond") (setq plist (list :background "#ffebcd" :foreground (web-mode-colorize-foreground "#ffebcd"))))
   7389       ((string= str "blueviolet") (setq plist (list :background "#8a2be2" :foreground (web-mode-colorize-foreground "#8a2be2"))))
   7390       ((string= str "brown") (setq plist (list :background "#a52a2a" :foreground (web-mode-colorize-foreground "#a52a2a"))))
   7391       ((string= str "burlywood") (setq plist (list :background "#deb887" :foreground (web-mode-colorize-foreground "#deb887"))))
   7392       ((string= str "cadetblue") (setq plist (list :background "#5f9ea0" :foreground (web-mode-colorize-foreground "#5f9ea0"))))
   7393       ((string= str "chartreuse") (setq plist (list :background "#7fff00" :foreground (web-mode-colorize-foreground "#7fff00"))))
   7394       ((string= str "chocolate") (setq plist (list :background "#d2691e" :foreground (web-mode-colorize-foreground "#d2691e"))))
   7395       ((string= str "coral") (setq plist (list :background "#ff7f50" :foreground (web-mode-colorize-foreground "#ff7f50"))))
   7396       ((string= str "cornflowerblue") (setq plist (list :background "#6495ed" :foreground (web-mode-colorize-foreground "#6495ed"))))
   7397       ((string= str "cornsilk") (setq plist (list :background "#fff8dc" :foreground (web-mode-colorize-foreground "#fff8dc"))))
   7398       ((string= str "crimson") (setq plist (list :background "#dc143c" :foreground (web-mode-colorize-foreground "#dc143c"))))
   7399       ((string= str "cyan") (setq plist (list :background "#00ffff" :foreground (web-mode-colorize-foreground "#00ffff"))))
   7400       ((string= str "darkblue") (setq plist (list :background "#00008b" :foreground (web-mode-colorize-foreground "#00008b"))))
   7401       ((string= str "darkcyan") (setq plist (list :background "#008b8b" :foreground (web-mode-colorize-foreground "#008b8b"))))
   7402       ((string= str "darkgoldenrod") (setq plist (list :background "#b8860b" :foreground (web-mode-colorize-foreground "#b8860b"))))
   7403       ((string= str "darkgray") (setq plist (list :background "#a9a9a9" :foreground (web-mode-colorize-foreground "#a9a9a9"))))
   7404       ((string= str "darkgreen") (setq plist (list :background "#006400" :foreground (web-mode-colorize-foreground "#006400"))))
   7405       ((string= str "darkgrey") (setq plist (list :background "#a9a9a9" :foreground (web-mode-colorize-foreground "#a9a9a9"))))
   7406       ((string= str "darkkhaki") (setq plist (list :background "#bdb76b" :foreground (web-mode-colorize-foreground "#bdb76b"))))
   7407       ((string= str "darkmagenta") (setq plist (list :background "#8b008b" :foreground (web-mode-colorize-foreground "#8b008b"))))
   7408       ((string= str "darkolivegreen") (setq plist (list :background "#556b2f" :foreground (web-mode-colorize-foreground "#556b2f"))))
   7409       ((string= str "darkorange") (setq plist (list :background "#ff8c00" :foreground (web-mode-colorize-foreground "#ff8c00"))))
   7410       ((string= str "darkorchid") (setq plist (list :background "#9932cc" :foreground (web-mode-colorize-foreground "#9932cc"))))
   7411       ((string= str "darkred") (setq plist (list :background "#8b0000" :foreground (web-mode-colorize-foreground "#8b0000"))))
   7412       ((string= str "darksalmon") (setq plist (list :background "#e9967a" :foreground (web-mode-colorize-foreground "#e9967a"))))
   7413       ((string= str "darkseagreen") (setq plist (list :background "#8fbc8f" :foreground (web-mode-colorize-foreground "#8fbc8f"))))
   7414       ((string= str "darkslateblue") (setq plist (list :background "#483d8b" :foreground (web-mode-colorize-foreground "#483d8b"))))
   7415       ((string= str "darkslategray") (setq plist (list :background "#2f4f4f" :foreground (web-mode-colorize-foreground "#2f4f4f"))))
   7416       ((string= str "darkslategrey") (setq plist (list :background "#2f4f4f" :foreground (web-mode-colorize-foreground "#2f4f4f"))))
   7417       ((string= str "darkturquoise") (setq plist (list :background "#00ced1" :foreground (web-mode-colorize-foreground "#00ced1"))))
   7418       ((string= str "darkviolet") (setq plist (list :background "#9400d3" :foreground (web-mode-colorize-foreground "#9400d3"))))
   7419       ((string= str "deeppink") (setq plist (list :background "#ff1493" :foreground (web-mode-colorize-foreground "#ff1493"))))
   7420       ((string= str "deepskyblue") (setq plist (list :background "#00bfff" :foreground (web-mode-colorize-foreground "#00bfff"))))
   7421       ((string= str "dimgray") (setq plist (list :background "#696969" :foreground (web-mode-colorize-foreground "#696969"))))
   7422       ((string= str "dimgrey") (setq plist (list :background "#696969" :foreground (web-mode-colorize-foreground "#696969"))))
   7423       ((string= str "dodgerblue") (setq plist (list :background "#1e90ff" :foreground (web-mode-colorize-foreground "#1e90ff"))))
   7424       ((string= str "firebrick") (setq plist (list :background "#b22222" :foreground (web-mode-colorize-foreground "#b22222"))))
   7425       ((string= str "floralwhite") (setq plist (list :background "#fffaf0" :foreground (web-mode-colorize-foreground "#fffaf0"))))
   7426       ((string= str "forestgreen") (setq plist (list :background "#228b22" :foreground (web-mode-colorize-foreground "#228b22"))))
   7427       ((string= str "gainsboro") (setq plist (list :background "#dcdcdc" :foreground (web-mode-colorize-foreground "#dcdcdc"))))
   7428       ((string= str "ghostwhite") (setq plist (list :background "#f8f8ff" :foreground (web-mode-colorize-foreground "#f8f8ff"))))
   7429       ((string= str "gold") (setq plist (list :background "#ffd700" :foreground (web-mode-colorize-foreground "#ffd700"))))
   7430       ((string= str "goldenrod") (setq plist (list :background "#daa520" :foreground (web-mode-colorize-foreground "#daa520"))))
   7431       ((string= str "greenyellow") (setq plist (list :background "#adff2f" :foreground (web-mode-colorize-foreground "#adff2f"))))
   7432       ((string= str "grey") (setq plist (list :background "#808080" :foreground (web-mode-colorize-foreground "#808080"))))
   7433       ((string= str "honeydew") (setq plist (list :background "#f0fff0" :foreground (web-mode-colorize-foreground "#f0fff0"))))
   7434       ((string= str "hotpink") (setq plist (list :background "#ff69b4" :foreground (web-mode-colorize-foreground "#ff69b4"))))
   7435       ((string= str "indianred") (setq plist (list :background "#cd5c5c" :foreground (web-mode-colorize-foreground "#cd5c5c"))))
   7436       ((string= str "indigo") (setq plist (list :background "#4b0082" :foreground (web-mode-colorize-foreground "#4b0082"))))
   7437       ((string= str "ivory") (setq plist (list :background "#fffff0" :foreground (web-mode-colorize-foreground "#fffff0"))))
   7438       ((string= str "khaki") (setq plist (list :background "#f0e68c" :foreground (web-mode-colorize-foreground "#f0e68c"))))
   7439       ((string= str "lavender") (setq plist (list :background "#e6e6fa" :foreground (web-mode-colorize-foreground "#e6e6fa"))))
   7440       ((string= str "lavenderblush") (setq plist (list :background "#fff0f5" :foreground (web-mode-colorize-foreground "#fff0f5"))))
   7441       ((string= str "lawngreen") (setq plist (list :background "#7cfc00" :foreground (web-mode-colorize-foreground "#7cfc00"))))
   7442       ((string= str "lemonchiffon") (setq plist (list :background "#fffacd" :foreground (web-mode-colorize-foreground "#fffacd"))))
   7443       ((string= str "lightblue") (setq plist (list :background "#add8e6" :foreground (web-mode-colorize-foreground "#add8e6"))))
   7444       ((string= str "lightcoral") (setq plist (list :background "#f08080" :foreground (web-mode-colorize-foreground "#f08080"))))
   7445       ((string= str "lightcyan") (setq plist (list :background "#e0ffff" :foreground (web-mode-colorize-foreground "#e0ffff"))))
   7446       ((string= str "lightgoldenrodyellow") (setq plist (list :background "#fafad2" :foreground (web-mode-colorize-foreground "#fafad2"))))
   7447       ((string= str "lightgray") (setq plist (list :background "#d3d3d3" :foreground (web-mode-colorize-foreground "#d3d3d3"))))
   7448       ((string= str "lightgreen") (setq plist (list :background "#90ee90" :foreground (web-mode-colorize-foreground "#90ee90"))))
   7449       ((string= str "lightgrey") (setq plist (list :background "#d3d3d3" :foreground (web-mode-colorize-foreground "#d3d3d3"))))
   7450       ((string= str "lightpink") (setq plist (list :background "#ffb6c1" :foreground (web-mode-colorize-foreground "#ffb6c1"))))
   7451       ((string= str "lightsalmon") (setq plist (list :background "#ffa07a" :foreground (web-mode-colorize-foreground "#ffa07a"))))
   7452       ((string= str "lightseagreen") (setq plist (list :background "#20b2aa" :foreground (web-mode-colorize-foreground "#20b2aa"))))
   7453       ((string= str "lightskyblue") (setq plist (list :background "#87cefa" :foreground (web-mode-colorize-foreground "#87cefa"))))
   7454       ((string= str "lightslategray") (setq plist (list :background "#778899" :foreground (web-mode-colorize-foreground "#778899"))))
   7455       ((string= str "lightslategrey") (setq plist (list :background "#778899" :foreground (web-mode-colorize-foreground "#778899"))))
   7456       ((string= str "lightsteelblue") (setq plist (list :background "#b0c4de" :foreground (web-mode-colorize-foreground "#b0c4de"))))
   7457       ((string= str "lightyellow") (setq plist (list :background "#ffffe0" :foreground (web-mode-colorize-foreground "#ffffe0"))))
   7458       ((string= str "limegreen") (setq plist (list :background "#32cd32" :foreground (web-mode-colorize-foreground "#32cd32"))))
   7459       ((string= str "linen") (setq plist (list :background "#faf0e6" :foreground (web-mode-colorize-foreground "#faf0e6"))))
   7460       ((string= str "magenta") (setq plist (list :background "#ff00ff" :foreground (web-mode-colorize-foreground "#ff00ff"))))
   7461       ((string= str "mediumaquamarine") (setq plist (list :background "#66cdaa" :foreground (web-mode-colorize-foreground "#66cdaa"))))
   7462       ((string= str "mediumblue") (setq plist (list :background "#0000cd" :foreground (web-mode-colorize-foreground "#0000cd"))))
   7463       ((string= str "mediumorchid") (setq plist (list :background "#ba55d3" :foreground (web-mode-colorize-foreground "#ba55d3"))))
   7464       ((string= str "mediumpurple") (setq plist (list :background "#9370db" :foreground (web-mode-colorize-foreground "#9370db"))))
   7465       ((string= str "mediumseagreen") (setq plist (list :background "#3cb371" :foreground (web-mode-colorize-foreground "#3cb371"))))
   7466       ((string= str "mediumslateblue") (setq plist (list :background "#7b68ee" :foreground (web-mode-colorize-foreground "#7b68ee"))))
   7467       ((string= str "mediumspringgreen") (setq plist (list :background "#00fa9a" :foreground (web-mode-colorize-foreground "#00fa9a"))))
   7468       ((string= str "mediumturquoise") (setq plist (list :background "#48d1cc" :foreground (web-mode-colorize-foreground "#48d1cc"))))
   7469       ((string= str "mediumvioletred") (setq plist (list :background "#c71585" :foreground (web-mode-colorize-foreground "#c71585"))))
   7470       ((string= str "midnightblue") (setq plist (list :background "#191970" :foreground (web-mode-colorize-foreground "#191970"))))
   7471       ((string= str "mintcream") (setq plist (list :background "#f5fffa" :foreground (web-mode-colorize-foreground "#f5fffa"))))
   7472       ((string= str "mistyrose") (setq plist (list :background "#ffe4e1" :foreground (web-mode-colorize-foreground "#ffe4e1"))))
   7473       ((string= str "moccasin") (setq plist (list :background "#ffe4b5" :foreground (web-mode-colorize-foreground "#ffe4b5"))))
   7474       ((string= str "navajowhite") (setq plist (list :background "#ffdead" :foreground (web-mode-colorize-foreground "#ffdead"))))
   7475       ((string= str "oldlace") (setq plist (list :background "#fdf5e6" :foreground (web-mode-colorize-foreground "#fdf5e6"))))
   7476       ((string= str "olivedrab") (setq plist (list :background "#6b8e23" :foreground (web-mode-colorize-foreground "#6b8e23"))))
   7477       ((string= str "orangered") (setq plist (list :background "#ff4500" :foreground (web-mode-colorize-foreground "#ff4500"))))
   7478       ((string= str "orchid") (setq plist (list :background "#da70d6" :foreground (web-mode-colorize-foreground "#da70d6"))))
   7479       ((string= str "palegoldenrod") (setq plist (list :background "#eee8aa" :foreground (web-mode-colorize-foreground "#eee8aa"))))
   7480       ((string= str "palegreen") (setq plist (list :background "#98fb98" :foreground (web-mode-colorize-foreground "#98fb98"))))
   7481       ((string= str "paleturquoise") (setq plist (list :background "#afeeee" :foreground (web-mode-colorize-foreground "#afeeee"))))
   7482       ((string= str "palevioletred") (setq plist (list :background "#db7093" :foreground (web-mode-colorize-foreground "#db7093"))))
   7483       ((string= str "papayawhip") (setq plist (list :background "#ffefd5" :foreground (web-mode-colorize-foreground "#ffefd5"))))
   7484       ((string= str "peachpuff") (setq plist (list :background "#ffdab9" :foreground (web-mode-colorize-foreground "#ffdab9"))))
   7485       ((string= str "peru") (setq plist (list :background "#cd853f" :foreground (web-mode-colorize-foreground "#cd853f"))))
   7486       ((string= str "pink") (setq plist (list :background "#ffc0cb" :foreground (web-mode-colorize-foreground "#ffc0cb"))))
   7487       ((string= str "plum") (setq plist (list :background "#dda0dd" :foreground (web-mode-colorize-foreground "#dda0dd"))))
   7488       ((string= str "powderblue") (setq plist (list :background "#b0e0e6" :foreground (web-mode-colorize-foreground "#b0e0e6"))))
   7489       ((string= str "rosybrown") (setq plist (list :background "#bc8f8f" :foreground (web-mode-colorize-foreground "#bc8f8f"))))
   7490       ((string= str "royalblue") (setq plist (list :background "#4169e1" :foreground (web-mode-colorize-foreground "#4169e1"))))
   7491       ((string= str "saddlebrown") (setq plist (list :background "#8b4513" :foreground (web-mode-colorize-foreground "#8b4513"))))
   7492       ((string= str "salmon") (setq plist (list :background "#fa8072" :foreground (web-mode-colorize-foreground "#fa8072"))))
   7493       ((string= str "sandybrown") (setq plist (list :background "#f4a460" :foreground (web-mode-colorize-foreground "#f4a460"))))
   7494       ((string= str "seagreen") (setq plist (list :background "#2e8b57" :foreground (web-mode-colorize-foreground "#2e8b57"))))
   7495       ((string= str "seashell") (setq plist (list :background "#fff5ee" :foreground (web-mode-colorize-foreground "#fff5ee"))))
   7496       ((string= str "sienna") (setq plist (list :background "#a0522d" :foreground (web-mode-colorize-foreground "#a0522d"))))
   7497       ((string= str "skyblue") (setq plist (list :background "#87ceeb" :foreground (web-mode-colorize-foreground "#87ceeb"))))
   7498       ((string= str "slateblue") (setq plist (list :background "#6a5acd" :foreground (web-mode-colorize-foreground "#6a5acd"))))
   7499       ((string= str "slategray") (setq plist (list :background "#708090" :foreground (web-mode-colorize-foreground "#708090"))))
   7500       ((string= str "slategrey") (setq plist (list :background "#708090" :foreground (web-mode-colorize-foreground "#708090"))))
   7501       ((string= str "snow") (setq plist (list :background "#fffafa" :foreground (web-mode-colorize-foreground "#fffafa"))))
   7502       ((string= str "springgreen") (setq plist (list :background "#00ff7f" :foreground (web-mode-colorize-foreground "#00ff7f"))))
   7503       ((string= str "steelblue") (setq plist (list :background "#4682b4" :foreground (web-mode-colorize-foreground "#4682b4"))))
   7504       ((string= str "tan") (setq plist (list :background "#d2b48c" :foreground (web-mode-colorize-foreground "#d2b48c"))))
   7505       ((string= str "thistle") (setq plist (list :background "#d8bfd8" :foreground (web-mode-colorize-foreground "#d8bfd8"))))
   7506       ((string= str "tomato") (setq plist (list :background "#ff6347" :foreground (web-mode-colorize-foreground "#ff6347"))))
   7507       ((string= str "turquoise") (setq plist (list :background "#40e0d0" :foreground (web-mode-colorize-foreground "#40e0d0"))))
   7508       ((string= str "violet") (setq plist (list :background "#ee82ee" :foreground (web-mode-colorize-foreground "#ee82ee"))))
   7509       ((string= str "wheat") (setq plist (list :background "#f5deb3" :foreground (web-mode-colorize-foreground "#f5deb3"))))
   7510       ((string= str "whitesmoke") (setq plist (list :background "#f5f5f5" :foreground (web-mode-colorize-foreground "#f5f5f5"))))
   7511       ((string= str "yellowgreen") (setq plist (list :background "#9acd32" :foreground (web-mode-colorize-foreground "#9acd32"))))
   7512       ) ;cond
   7513     (put-text-property beg end 'face plist)
   7514     ))
   7515 
   7516 (defun web-mode-interpolate-block-tag (beg end)
   7517   (save-excursion
   7518     (goto-char (+ 4 beg))
   7519     (setq end (1- end))
   7520     (while (re-search-forward "${.*?}" end t)
   7521       (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(face))
   7522       (web-mode-fontify-region (match-beginning 0) (match-end 0)
   7523                                web-mode-uel-font-lock-keywords))
   7524     ))
   7525 
   7526 (defun web-mode-interpolate-javascript-string (beg end)
   7527   (save-excursion
   7528     (goto-char (1+ beg))
   7529     (setq end (1- end))
   7530     (while (re-search-forward "${.*?}" end t)
   7531       (put-text-property (match-beginning 0) (match-end 0)
   7532                          'font-lock-face
   7533                          'web-mode-variable-name-face)
   7534       )
   7535     ))
   7536 
   7537 (defun web-mode-interpolate-javascript-literal (beg end)
   7538   (save-excursion
   7539     (setq end (1- end))
   7540     (goto-char (1+ beg))
   7541     (cond
   7542       ((web-mode-looking-back "\\(css\\|styled[[:alnum:].]+\\|css = \\)" beg)
   7543        (goto-char (1+ beg))
   7544        (while (re-search-forward ".*?:" end t)
   7545          (put-text-property (match-beginning 0) (match-end 0)
   7546                             'font-lock-face
   7547                             'web-mode-interpolate-color1-face)
   7548          )
   7549        ) ;case css
   7550       ((web-mode-looking-back "\\(template\\|html\\|html = \\)" beg)
   7551        (goto-char (1+ beg))
   7552        (while (re-search-forward web-mode-tag-regexp end t)
   7553          (put-text-property (match-beginning 1) (match-end 1)
   7554                             'font-lock-face
   7555                             'web-mode-interpolate-color1-face)
   7556          )
   7557        (goto-char (1+ beg))
   7558        (while (re-search-forward "</?\\|/?>\\| [.@?]?[[:alnum:]]+=" end t)
   7559          (cond
   7560            ((member (char-after (match-beginning 0)) '(?\< ?\/ ?\>))
   7561             (put-text-property (match-beginning 0) (match-end 0)
   7562                                'font-lock-face
   7563                                'web-mode-interpolate-color2-face)
   7564             )
   7565            (t
   7566             (put-text-property (1+ (match-beginning 0)) (1- (match-end 0))
   7567                                'font-lock-face
   7568                                'web-mode-interpolate-color3-face)
   7569             ) ;t
   7570            ) ;cond
   7571          ) ;while
   7572        (goto-char (1+ beg))
   7573        (while (re-search-forward "<\\(script\\|style\\)>\\(.*\\)</\\(script\\|style\\)>" end t)
   7574          (put-text-property (match-beginning 2) (match-end 2)
   7575                             'font-lock-face
   7576                             'web-mode-interpolate-color4-face)
   7577          )
   7578        ) ;case html
   7579       ) ;cond type of literal
   7580     (goto-char (1+ beg))
   7581     (while (re-search-forward "${.*?}" end t)
   7582       (put-text-property (match-beginning 0) (match-end 0)
   7583                          'font-lock-face
   7584                          'web-mode-variable-name-face)
   7585       ) ;while
   7586     ))
   7587 
   7588 ;; todo : parsing plus compliqué: {$obj->values[3]->name}
   7589 (defun web-mode-interpolate-block-string (beg end)
   7590   (save-excursion
   7591     (goto-char (1+ beg))
   7592     (setq end (1- end))
   7593     (cond
   7594       ((string= web-mode-engine "php")
   7595        (while (re-search-forward "$[[:alnum:]_]+\\(->[[:alnum:]_]+\\)*\\|{[ ]*$.+?}" end t)
   7596          ;;        (message "%S > %S" (match-beginning 0) (match-end 0))
   7597          (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(font-lock-face))
   7598          (web-mode-fontify-region (match-beginning 0) (match-end 0)
   7599                                   web-mode-php-var-interpolation-font-lock-keywords)
   7600          ))
   7601       ((string= web-mode-engine "erb")
   7602        (while (re-search-forward "#{.*?}" end t)
   7603          (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(font-lock-face))
   7604          (put-text-property (match-beginning 0) (match-end 0)
   7605                             'font-lock-face 'web-mode-variable-name-face)
   7606          ))
   7607       ) ;cond
   7608     ))
   7609 
   7610 (defun web-mode-interpolate-comment (beg end _block-side)
   7611   (save-excursion
   7612     (let ((regexp (concat "\\_<\\(" web-mode-comment-keywords "\\)\\_>")))
   7613       (goto-char beg)
   7614       (while (re-search-forward regexp end t)
   7615         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7616                                          'font-lock-face
   7617                                          'web-mode-comment-keyword-face)
   7618         ) ;while
   7619       )))
   7620 
   7621 (defun web-mode-annotate-comment (beg end)
   7622   (save-excursion
   7623     ;;(message "beg=%S end=%S" beg end)
   7624     (goto-char beg)
   7625     (when (looking-at-p "/\\*\\*")
   7626       (while (re-search-forward "\\(.+\\)" end t)
   7627         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7628                                          'font-lock-face
   7629                                          'web-mode-annotation-face))
   7630       (goto-char beg)
   7631       (while (re-search-forward "[ ]+\\({[^}]+}\\)" end t)
   7632         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7633                                          'font-lock-face
   7634                                          'web-mode-annotation-type-face))
   7635       (goto-char beg)
   7636       (while (re-search-forward "\\(@[[:alnum:]]+\\)" end t)
   7637         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7638                                          'font-lock-face
   7639                                          'web-mode-annotation-tag-face))
   7640       (goto-char beg)
   7641       (while (re-search-forward "}[[:blank:]]+\\([[:graph:]]+\\)" end t)
   7642         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7643                                          'font-lock-face
   7644                                          'web-mode-annotation-value-face))
   7645       (goto-char beg)
   7646       (while (re-search-forward "@see[[:blank:]]+\\([[:graph:]]+\\)" end t)
   7647         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7648                                          'font-lock-face
   7649                                          'web-mode-annotation-value-face))
   7650       (goto-char beg)
   7651       (while (re-search-forward "{\\(@\\(?:link\\|code\\)\\)\\s-+\\([^}\n]+\\)\\(#.+\\)?}" end t)
   7652         (font-lock-prepend-text-property (match-beginning 2) (match-end 2)
   7653                                          'font-lock-face
   7654                                          'web-mode-annotation-value-face))
   7655       (goto-char beg)
   7656       (while (re-search-forward "\\(</?\\)\\([[:alnum:]]+\\)\\s-*\\(/?>\\)" end t)
   7657         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7658                                          'font-lock-face
   7659                                          'web-mode-annotation-html-face)
   7660         (font-lock-prepend-text-property (match-beginning 2) (match-end 2)
   7661                                          'font-lock-face
   7662                                          'web-mode-annotation-html-face)
   7663         (font-lock-prepend-text-property (match-beginning 3) (match-end 3)
   7664                                          'font-lock-face
   7665                                          'web-mode-annotation-html-face))
   7666       ) ;when
   7667     ))
   7668 
   7669 (defun web-mode-interpolate-sql-string (beg end)
   7670   (save-excursion
   7671     (let ((case-fold-search t)
   7672           (regexp (concat "\\_<\\(" web-mode-sql-keywords "\\)\\_>")))
   7673       (goto-char beg)
   7674       (while (re-search-forward regexp end t)
   7675         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7676                                          'font-lock-face
   7677                                          'web-mode-sql-keyword-face)
   7678         ) ;while
   7679       )))
   7680 
   7681 ;;---- EFFECTS -----------------------------------------------------------------
   7682 
   7683 (defun web-mode-fill-paragraph (&optional _justify)
   7684   (save-excursion
   7685     (let ((pos (point))
   7686           prop pair beg end delim-beg delim-end chunk fill-coll)
   7687       (ignore delim-beg delim-end fill-coll)
   7688       (cond
   7689         ((or (eq (get-text-property pos 'part-token) 'comment)
   7690              (eq (get-text-property pos 'block-token) 'comment))
   7691          (setq prop
   7692                (if (get-text-property pos 'part-token) 'part-token 'block-token))
   7693          (setq pair (web-mode-property-boundaries prop pos))
   7694          (when (and pair (> (- (cdr pair) (car pair)) 6))
   7695            (setq fill-coll (if (< fill-column 10) 70 fill-column))
   7696            (setq beg (car pair)
   7697                  end (cdr pair))
   7698            (goto-char beg)
   7699            (setq chunk (buffer-substring-no-properties beg (+ beg 2)))
   7700            (cond
   7701              ((string= chunk "//")
   7702               (setq delim-beg "//"
   7703                     delim-end "EOL"))
   7704              ((string= chunk "/*")
   7705               (setq delim-beg "/*"
   7706                     delim-end "*/"))
   7707              ((string= chunk "{#")
   7708               (setq delim-beg "{#"
   7709                     delim-end "#}"))
   7710              ((string= chunk "<!")
   7711               (setq delim-beg "<!--"
   7712                     delim-end "-->"))
   7713              )
   7714            )
   7715          ) ;comment - case
   7716         ((web-mode-is-content)
   7717          (setq pair (web-mode-content-boundaries pos))
   7718          (setq beg (car pair)
   7719                end (cdr pair))
   7720          )
   7721         ) ;cond
   7722       ;;(message "beg(%S) end(%S)" beg end)
   7723       (when (and beg end)
   7724         (fill-region beg end))
   7725       t)))
   7726 
   7727 (defun web-mode-engine-syntax-check ()
   7728   (interactive)
   7729   (let ((proc nil) (errors nil)
   7730         (file (concat temporary-file-directory "emacs-web-mode-tmp")))
   7731     (write-region (point-min) (point-max) file)
   7732     (cond
   7733       ;; ((null (buffer-file-name))
   7734       ;; )
   7735       ((string= web-mode-engine "php")
   7736        (setq proc (start-process "php-proc" nil "php" "-l" file))
   7737        (set-process-filter
   7738         proc
   7739         (lambda (_proc output)
   7740           (cond
   7741             ((string-match-p "No syntax errors" output)
   7742              (message "No syntax errors")
   7743              )
   7744             (t
   7745              ;; (setq output (replace-regexp-in-string temporary-file-directory "" output))
   7746              ;; (message output)
   7747              (message "Syntax error")
   7748              (setq errors t))
   7749             ) ;cond
   7750           ;; (delete-file file)
   7751           ) ;lambda
   7752         )
   7753        ) ;php
   7754       (t
   7755        (message "no syntax checker found")
   7756        ) ;t
   7757       ) ;cond
   7758     errors))
   7759 
   7760 (defun web-mode-jshint ()
   7761   "Run JSHint on all the JavaScript parts."
   7762   (interactive)
   7763   (let (proc)
   7764     (when (buffer-file-name)
   7765       (setq proc (start-process
   7766                   "jshint-proc"
   7767                   nil
   7768                   (or (executable-find "jshint") "/usr/local/bin/jshint")
   7769                   "--extract=auto"
   7770                   (buffer-file-name)))
   7771       (setq web-mode-jshint-errors 0)
   7772       (set-process-filter proc
   7773                           (lambda (_proc output)
   7774                             (let ((offset 0) overlay pos (old 0) msg)
   7775                               (remove-overlays (point-min) (point-max) 'font-lock-face 'web-mode-error-face)
   7776                               (while (string-match
   7777                                       "line \\([[:digit:]]+\\), col \\([[:digit:]]+\\), \\(.+\\)\\.$"
   7778                                       output offset)
   7779                                 (setq web-mode-jshint-errors (1+ web-mode-jshint-errors))
   7780                                 (setq offset (match-end 0))
   7781                                 (setq pos (web-mode-coord-position
   7782                                            (match-string-no-properties 1 output)
   7783                                            (match-string-no-properties 2 output)))
   7784                                 (when (get-text-property pos 'tag-beg)
   7785                                   (setq pos (1- pos)))
   7786                                 (when (not (= pos old))
   7787                                   (setq old pos)
   7788                                   (setq overlay (make-overlay pos (1+ pos)))
   7789                                   (overlay-put overlay 'font-lock-face 'web-mode-error-face)
   7790                                   )
   7791                                 (setq msg (or (overlay-get overlay 'help-echo)
   7792                                               (concat "line="
   7793                                                       (match-string-no-properties 1 output)
   7794                                                       " column="
   7795                                                       (match-string-no-properties 2 output)
   7796                                                       )))
   7797                                 (overlay-put overlay 'help-echo
   7798                                              (concat msg " ## " (match-string-no-properties 3 output)))
   7799                                 ) ;while
   7800                               ))
   7801                           )
   7802       ) ;when
   7803     ))
   7804 
   7805 (defun web-mode-dom-errors-show ()
   7806   "Show unclosed tags."
   7807   (interactive)
   7808   (let (beg end tag pos l tags i cont cell overlay overlays first
   7809             (ori (point))
   7810             (errors 0)
   7811             (continue t)
   7812             )
   7813     (setq overlays (overlays-in (point-min) (point-max)))
   7814     (when overlays
   7815       (dolist (overlay overlays)
   7816         (when (eq (overlay-get overlay 'face) 'web-mode-warning-face)
   7817           (delete-overlay overlay)
   7818           )
   7819         )
   7820       )
   7821     (goto-char (point-min))
   7822     (when (not (or (get-text-property (point) 'tag-beg)
   7823                    (web-mode-tag-next)))
   7824       (setq continue nil))
   7825     (while continue
   7826       (setq pos (point))
   7827       (setq tag (get-text-property pos 'tag-name))
   7828       (cond
   7829         ((eq (get-text-property (point) 'tag-type) 'start)
   7830          (setq tags (push (list tag pos) tags))
   7831          ;;        (message "(%S) opening %S" pos tag)
   7832          )
   7833         ((eq (get-text-property (point) 'tag-type) 'end)
   7834          (setq i 0
   7835                l (length tags)
   7836                cont t)
   7837          (while (and (< i l) cont)
   7838            (setq cell (nth i tags))
   7839            ;;          (message "cell=%S" cell)
   7840            (setq i (1+ i))
   7841            (cond
   7842              ((string= tag (nth 0 cell))
   7843               (setq cont nil)
   7844               )
   7845              (t
   7846               (setq errors (1+ errors))
   7847               (setq beg (nth 1 cell))
   7848               (setq end (web-mode-tag-end-position beg))
   7849               (unless first
   7850                 (setq first beg))
   7851               (setq overlay (make-overlay beg (1+ end)))
   7852               (overlay-put overlay 'font-lock-face 'web-mode-warning-face)
   7853               ;;            (message "invalid <%S> at %S" (nth 0 cell) (nth 1 cell))
   7854               )
   7855              ) ;cond
   7856            ) ;while
   7857 
   7858          (dotimes (_i i)
   7859            (setq tags (cdr tags)))
   7860 
   7861          )
   7862         ) ;cond
   7863       (when (not (web-mode-tag-next))
   7864         (setq continue nil))
   7865       ) ;while
   7866     (message "%S error(s) detected" errors)
   7867     (if (< errors 1)
   7868         (goto-char ori)
   7869         (goto-char first)
   7870         (recenter))
   7871     ;;    (message "%S" tags)
   7872     ))
   7873 
   7874 (defun web-mode-fontify-elements (beg end)
   7875   (save-excursion
   7876     (goto-char beg)
   7877     (let ((continue (or (get-text-property (point) 'tag-beg) (web-mode-tag-next)))
   7878           (i 0) (ctx nil) (face nil))
   7879       (while continue
   7880         (cond
   7881           ((> (setq i (1+ i)) 1000)
   7882            (message "fontify-elements ** too much tags **")
   7883            (setq continue nil))
   7884           ((> (point) end)
   7885            (setq continue nil))
   7886           ((not (get-text-property (point) 'tag-beg))
   7887            (setq continue nil))
   7888           ((eq (get-text-property (point) 'tag-type) 'start)
   7889            (when (and (setq ctx (web-mode-element-boundaries (point)))
   7890                       (<= (car (cdr ctx)) end)
   7891                       (setq face (cdr (assoc (get-text-property (point) 'tag-name) web-mode-element-content-faces))))
   7892              (font-lock-prepend-text-property (1+ (cdr (car ctx))) (car (cdr ctx))
   7893                                               'font-lock-face face))
   7894            )
   7895           ) ;cond
   7896         (when (not (web-mode-tag-next))
   7897           (setq continue nil))
   7898         ) ;while
   7899       )))
   7900 
   7901 (defun web-mode-enable (feature)
   7902   "Enable one feature."
   7903   (interactive
   7904    (list (completing-read
   7905           "Feature: "
   7906           (let (features)
   7907             (dolist (elt web-mode-features)
   7908               (setq features (append features (list (car elt)))))
   7909             features))))
   7910   (when (and (or (not feature) (< (length feature) 1)) web-mode-last-enabled-feature)
   7911     (setq feature web-mode-last-enabled-feature))
   7912   (when feature
   7913     (setq web-mode-last-enabled-feature feature)
   7914     (setq feature (cdr (assoc feature web-mode-features)))
   7915     (cond
   7916       ((eq feature 'web-mode-enable-current-column-highlight)
   7917        (web-mode-column-show))
   7918       ((eq feature 'web-mode-enable-current-element-highlight)
   7919        (when (not web-mode-enable-current-element-highlight)
   7920          (web-mode-toggle-current-element-highlight))
   7921        )
   7922       ((eq feature 'web-mode-enable-whitespace-fontification)
   7923        (web-mode-whitespaces-on))
   7924       (t
   7925        (set feature t)
   7926        (web-mode-buffer-fontify))
   7927       )
   7928     ) ;when
   7929   )
   7930 
   7931 (defun web-mode-disable (feature)
   7932   "Disable one feature."
   7933   (interactive
   7934    (list (completing-read
   7935           "Feature: "
   7936           (let (features)
   7937             (dolist (elt web-mode-features)
   7938               (setq features (append features (list (car elt)))))
   7939             features))))
   7940   (when (and (or (not feature) (< (length feature) 1)) web-mode-last-enabled-feature)
   7941     (setq feature web-mode-last-enabled-feature))
   7942   (when feature
   7943     (setq feature (cdr (assoc feature web-mode-features)))
   7944     (cond
   7945       ((eq feature 'web-mode-enable-current-column-highlight)
   7946        (web-mode-column-hide))
   7947       ((eq feature 'web-mode-enable-current-element-highlight)
   7948        (when web-mode-enable-current-element-highlight
   7949          (web-mode-toggle-current-element-highlight))
   7950        )
   7951       ((eq feature 'web-mode-enable-whitespace-fontification)
   7952        (web-mode-whitespaces-off))
   7953       (t
   7954        (set feature nil)
   7955        (web-mode-buffer-fontify))
   7956       )
   7957     ) ;when
   7958   )
   7959 
   7960 (defun web-mode-toggle-current-element-highlight ()
   7961   "Toggle highlighting of the current html element."
   7962   (interactive)
   7963   (if web-mode-enable-current-element-highlight
   7964       (progn
   7965         (web-mode-delete-tag-overlays)
   7966         (setq web-mode-enable-current-element-highlight nil))
   7967       (setq web-mode-enable-current-element-highlight t)
   7968       ))
   7969 
   7970 (defun web-mode-make-tag-overlays ()
   7971   (unless web-mode-overlay-tag-start
   7972     (setq web-mode-overlay-tag-start (make-overlay 1 1)
   7973           web-mode-overlay-tag-end (make-overlay 1 1))
   7974     (overlay-put web-mode-overlay-tag-start
   7975                  'font-lock-face
   7976                  'web-mode-current-element-highlight-face)
   7977     (overlay-put web-mode-overlay-tag-end
   7978                  'font-lock-face
   7979                  'web-mode-current-element-highlight-face)))
   7980 
   7981 (defun web-mode-delete-tag-overlays ()
   7982   (when web-mode-overlay-tag-start
   7983     (delete-overlay web-mode-overlay-tag-start)
   7984     (delete-overlay web-mode-overlay-tag-end)))
   7985 
   7986 (defun web-mode-column-overlay-factory (index)
   7987   (let (overlay)
   7988     (when (null web-mode-column-overlays)
   7989       (dotimes (_i 100)
   7990         (setq overlay (make-overlay 1 1))
   7991         (overlay-put overlay 'font-lock-face 'web-mode-current-column-highlight-face)
   7992         (setq web-mode-column-overlays (append web-mode-column-overlays (list overlay)))
   7993         )
   7994       ) ;when
   7995     (setq overlay (nth index web-mode-column-overlays))
   7996     (when (null overlay)
   7997       (setq overlay (make-overlay 1 1))
   7998       (overlay-put overlay 'font-lock-face 'web-mode-current-column-highlight-face)
   7999       (setq web-mode-column-overlays (append web-mode-column-overlays (list overlay)))
   8000       ) ;when
   8001     overlay))
   8002 
   8003 (defun web-mode-column-hide ()
   8004   (setq web-mode-enable-current-column-highlight nil)
   8005   (remove-overlays (point-min) (point-max)
   8006                    'font-lock-face
   8007                    'web-mode-current-column-highlight-face))
   8008 
   8009 (defun web-mode-count-invisible-character-ranges (min max)
   8010   (interactive "r")
   8011   (let ((count 0) (current-pos min))
   8012     (save-excursion
   8013       (while (<= current-pos max)
   8014         (goto-char current-pos)
   8015         (if (get-text-property current-pos 'invisible)
   8016             (progn
   8017               (setq count (1+ count))
   8018               (setq current-pos (1+ current-pos))
   8019               (while (and (<= current-pos max)
   8020                           (get-text-property current-pos 'invisible))
   8021                 (setq current-pos (1+ current-pos))))
   8022           (setq current-pos (1+ current-pos)))))
   8023     count))
   8024 
   8025 (defun web-mode-column-show ()
   8026   (let ((index 0) overlay diff column line-to line-from line-delta regions (overlay-skip nil) last-line-no)
   8027     (web-mode-column-hide)
   8028     (setq web-mode-enable-current-column-highlight t)
   8029     (save-excursion ;;save-mark-and-excursion
   8030       (back-to-indentation)
   8031       (setq column (current-column)
   8032             line-to (web-mode-line-number))
   8033       (when (and (get-text-property (point) 'tag-beg)
   8034                  (member (get-text-property (point) 'tag-type) '(start end))
   8035                  (web-mode-tag-match)
   8036                  (setq line-from (web-mode-line-number))
   8037                  (not (= line-from line-to)))
   8038         (when (> line-from line-to)
   8039           (let (tmp)
   8040             (setq tmp line-from)
   8041             (setq line-from line-to)
   8042             (setq line-to tmp))
   8043           ) ;when
   8044         ;;(message "column(%S) line-from(%S) line-to(%S)" column line-from line-to)
   8045         (goto-char (point-min))
   8046         (when (> line-from 1)
   8047           (forward-line (1- line-from)))
   8048         ;; Added by JMA
   8049         (save-excursion ;;save-mark-and-excursion
   8050           (let (start-point end-point)
   8051             (goto-line line-from)
   8052             (move-to-column column)
   8053             (setq start-point (point))
   8054             (goto-line line-to)
   8055             (move-to-column column)
   8056             (setq end-point (point))
   8057             (setq line-delta (count-lines start-point end-point t))
   8058             (setq line-delta (+ line-delta (web-mode-count-invisible-character-ranges start-point end-point))))
   8059           (setq line-to (+ line-from (1- line-delta))))
   8060         ;(message (format "Currently at line: %d" (line-number-at-pos)))
   8061         (setq last-line-no (line-number-at-pos))
   8062         ;; end JMA add
   8063         (while (<= line-from line-to)
   8064           (setq overlay (web-mode-column-overlay-factory index))
   8065           (setq diff (- (line-end-position) (point)))
   8066           (cond
   8067             ((or (and (= column 0) (= diff 0))
   8068                  (> column diff))
   8069              (end-of-line)
   8070              (move-overlay overlay (point) (point))
   8071              (overlay-put overlay
   8072                           'after-string
   8073                           (concat
   8074                            (if (> column diff) (make-string (- column diff) ?\s) "")
   8075                            (propertize " "
   8076                                        'font-lock-face
   8077                                        'web-mode-current-column-highlight-face)
   8078                            ) ;concat
   8079                           )
   8080              )
   8081             (t
   8082              (move-to-column column)
   8083              (overlay-put overlay 'after-string nil)
   8084              (move-overlay overlay (point) (1+ (point)))
   8085              )
   8086             ) ;cond
   8087           (setq line-from (1+ line-from))
   8088           (forward-line)
   8089           ;; JMA ADD
   8090           ;(message (format "Currently at line: %d" (line-number-at-pos)))
   8091           (if (not (= (1+ last-line-no) (line-number-at-pos)))
   8092               (delete-overlay overlay))
   8093           (setq last-line-no (line-number-at-pos))
   8094           ;; END JMA ADD
   8095           (setq index (1+ index))
   8096           ) ;while
   8097         ) ;when
   8098       ) ;save-excursion
   8099     ) ;let
   8100   )
   8101 
   8102 (defun web-mode-column-show2 ()
   8103   (let ((index 0) overlay diff column line-to line-from
   8104         line-delta regions (overlay-skip nil) last-line-no)
   8105     (web-mode-column-hide)
   8106     (setq web-mode-enable-current-column-highlight t)
   8107     (save-excursion
   8108       (back-to-indentation)
   8109       (setq column (current-column)
   8110             line-to (web-mode-line-number))
   8111       (when (and (get-text-property (point) 'tag-beg)
   8112                  (member (get-text-property (point) 'tag-type) '(start end))
   8113                  (web-mode-tag-match)
   8114                  (setq line-from (web-mode-line-number))
   8115                  (not (= line-from line-to)))
   8116         (when (> line-from line-to)
   8117           (let (tmp)
   8118             (setq tmp line-from)
   8119             (setq line-from line-to)
   8120             (setq line-to tmp))
   8121           ) ;when
   8122         ;;(message "column(%S) line-from(%S) line-to(%S)" column line-from line-to)
   8123         (goto-char (point-min))
   8124         (when (> line-from 1)
   8125           (forward-line (1- line-from)))
   8126         (while (<= line-from line-to)
   8127           (setq overlay (web-mode-column-overlay-factory index))
   8128           (setq diff (- (line-end-position) (point)))
   8129           (cond
   8130             ((or (and (= column 0) (= diff 0))
   8131                  (> column diff))
   8132              (end-of-line)
   8133              (move-overlay overlay (point) (point))
   8134              (overlay-put overlay
   8135                           'after-string
   8136                           (concat
   8137                            (if (> column diff) (make-string (- column diff) ?\s) "")
   8138                            (propertize " "
   8139                                        'font-lock-face
   8140                                        'web-mode-current-column-highlight-face)
   8141                            ) ;concat
   8142                           )
   8143              )
   8144             (t
   8145              (move-to-column column)
   8146              (overlay-put overlay 'after-string nil)
   8147              (move-overlay overlay (point) (1+ (point)))
   8148              )
   8149             ) ;cond
   8150           (setq line-from (1+ line-from))
   8151           (forward-line)
   8152           (setq index (1+ index))
   8153           ) ;while
   8154         ) ;when
   8155       ) ;save-excursion
   8156     ) ;let
   8157   )
   8158 
   8159 (defun web-mode-highlight-current-element ()
   8160   (let ((ctx (web-mode-element-boundaries)) len)
   8161     (cond
   8162       ((null ctx)
   8163        (web-mode-delete-tag-overlays))
   8164       ((eq (get-text-property (caar ctx) 'tag-type) 'void) ;; #1046
   8165        (web-mode-make-tag-overlays)
   8166        (setq len (length (get-text-property (caar ctx) 'tag-name)))
   8167        (move-overlay web-mode-overlay-tag-start (+ (caar ctx) 1) (+ (caar ctx) 1 len))
   8168        (move-overlay web-mode-overlay-tag-end (+ (cadr ctx) 1) (+ (cadr ctx) 1 len)) ;; #1257
   8169        )
   8170       (t
   8171        (web-mode-make-tag-overlays)
   8172        (setq len (length (get-text-property (caar ctx) 'tag-name)))
   8173        (move-overlay web-mode-overlay-tag-start (+ (caar ctx) 1) (+ (caar ctx) 1 len))
   8174        (move-overlay web-mode-overlay-tag-end (+ (cadr ctx) 2) (+ (cadr ctx) 2 len))
   8175        ) ;t
   8176       ) ;cond
   8177     ))
   8178 
   8179 (defun web-mode-fontify-whitespaces (beg end)
   8180   (save-excursion
   8181     (goto-char beg)
   8182     (while (re-search-forward web-mode-whitespaces-regexp end t)
   8183       (add-text-properties (match-beginning 0) (match-end 0)
   8184                            '(face web-mode-whitespace-face))
   8185       ) ;while
   8186     ))
   8187 
   8188 (defun web-mode-whitespaces-show ()
   8189   "Toggle whitespaces."
   8190   (interactive)
   8191   (if web-mode-enable-whitespace-fontification
   8192       (web-mode-whitespaces-off)
   8193       (web-mode-whitespaces-on)))
   8194 
   8195 (defun web-mode-whitespaces-on ()
   8196   "Show whitespaces."
   8197   (interactive)
   8198   (when web-mode-display-table
   8199     (setq buffer-display-table web-mode-display-table))
   8200   (setq web-mode-enable-whitespace-fontification t))
   8201 
   8202 (defun web-mode-whitespaces-off ()
   8203   (setq buffer-display-table nil)
   8204   (setq web-mode-enable-whitespace-fontification nil))
   8205 
   8206 (defun web-mode-use-tabs ()
   8207   "Tweaks vars to be compatible with TAB indentation."
   8208   (let (offset)
   8209     (setq web-mode-block-padding 0)
   8210     (setq web-mode-script-padding 0)
   8211     (setq web-mode-style-padding 0)
   8212     (setq offset
   8213           (cond
   8214             ((and (boundp 'tab-width) tab-width) tab-width)
   8215             ((and (boundp 'standard-indent) standard-indent) standard-indent)
   8216             (t 4)))
   8217     ;;    (message "offset(%S)" offset)
   8218     (setq web-mode-attr-indent-offset offset)
   8219     (setq web-mode-code-indent-offset offset)
   8220     (setq web-mode-css-indent-offset offset)
   8221     (setq web-mode-markup-indent-offset offset)
   8222     (setq web-mode-sql-indent-offset offset)
   8223     (add-to-list 'web-mode-indentation-params '("lineup-args" . nil))
   8224     (add-to-list 'web-mode-indentation-params '("lineup-calls" . nil))
   8225     (add-to-list 'web-mode-indentation-params '("lineup-concats" . nil))
   8226     (add-to-list 'web-mode-indentation-params '("lineup-ternary" . nil))
   8227     ))
   8228 
   8229 (defun web-mode-element-children-fold-or-unfold (&optional pos)
   8230   "Fold/Unfold all the children of the current html element."
   8231   (interactive)
   8232   (unless pos (setq pos (point)))
   8233   (save-excursion
   8234     (dolist (child (reverse (web-mode-element-children pos)))
   8235       (goto-char child)
   8236       (web-mode-fold-or-unfold))
   8237     ))
   8238 
   8239 (defun web-mode-fold-or-unfold (&optional pos)
   8240   "Toggle folding on an html element or a control block."
   8241   (interactive)
   8242   (web-mode-scan)
   8243   (web-mode-with-silent-modifications
   8244    (save-excursion
   8245      (if pos (goto-char pos))
   8246      (let (beg-inside beg-outside end-inside end-outside overlay overlays)
   8247        (when (looking-back "^[\t ]*" (point-min))
   8248          (back-to-indentation))
   8249        (setq overlays (overlays-at (point)))
   8250        (dolist (elt overlays)
   8251          (when (and (not overlay)
   8252                     (eq (overlay-get elt 'font-lock-face) 'web-mode-folded-face))
   8253            (setq overlay elt)))
   8254        (cond
   8255          ;; *** unfolding
   8256          (overlay
   8257           (setq beg-inside (overlay-start overlay)
   8258                 end-inside (overlay-end overlay))
   8259           (remove-overlays beg-inside end-inside)
   8260           (put-text-property beg-inside end-inside 'invisible nil)
   8261           )
   8262          ;; *** block folding
   8263          ((and (get-text-property (point) 'block-side)
   8264                (cdr (web-mode-block-is-control (point))))
   8265           (setq beg-outside (web-mode-block-beginning-position (point)))
   8266           (setq beg-inside (1+ (web-mode-block-end-position (point))))
   8267           (when (web-mode-block-match)
   8268             (setq end-inside (point))
   8269             (setq end-outside (1+ (web-mode-block-end-position (point)))))
   8270           )
   8271          ;; *** html comment folding
   8272          ((eq (get-text-property (point) 'tag-type) 'comment)
   8273           (setq beg-outside (web-mode-tag-beginning-position))
   8274           (setq beg-inside (+ beg-outside 4))
   8275           (setq end-outside (web-mode-tag-end-position))
   8276           (setq end-inside (- end-outside 3))
   8277           )
   8278          ;; *** tag folding
   8279          ((or (member (get-text-property (point) 'tag-type) '(start end))
   8280               (web-mode-element-parent))
   8281           (when (not (web-mode-element-is-collapsed (point)))
   8282             (web-mode-tag-beginning)
   8283             (when (eq (get-text-property (point) 'tag-type) 'end)
   8284               (web-mode-tag-match))
   8285             (setq beg-outside (point))
   8286             (web-mode-tag-end)
   8287             (setq beg-inside (point))
   8288             (goto-char beg-outside)
   8289             (when (web-mode-tag-match)
   8290               (setq end-inside (point))
   8291               (web-mode-tag-end)
   8292               (setq end-outside (point)))
   8293             )
   8294           )
   8295          ) ;cond
   8296        (when (and beg-inside beg-outside end-inside end-outside)
   8297          (setq overlay (make-overlay beg-outside end-outside))
   8298          (overlay-put overlay 'font-lock-face 'web-mode-folded-face)
   8299          (put-text-property beg-inside end-inside 'invisible t))
   8300        ))))
   8301 
   8302 ;;---- TRANSFORMATION ----------------------------------------------------------
   8303 
   8304 (defun web-mode-buffer-change-tag-case (&optional type)
   8305   "Change html tag case."
   8306   (interactive)
   8307   (save-excursion
   8308     (goto-char (point-min))
   8309     (let ((continue t) f)
   8310       (setq f (if (member type '("upper" "uppercase" "upper-case")) 'uppercase 'downcase))
   8311       (when (and (not (get-text-property (point) 'tag-beg))
   8312                  (not (web-mode-tag-next)))
   8313         (setq continue nil))
   8314       (while continue
   8315         (skip-chars-forward "<!/")
   8316         (if (looking-at "\\([[:alnum:]:-]+\\)")
   8317             (replace-match (funcall f (match-string 0)) t))
   8318         ;;        (message "tag: %S (%S)"
   8319         ;;                 (get-text-property (point) 'tag-name)
   8320         ;;                 (point))
   8321         (unless (web-mode-tag-next)
   8322           (setq continue nil))
   8323         ) ;while
   8324       )))
   8325 
   8326 (defun web-mode-buffer-change-attr-case (&optional type)
   8327   "Change case of html attribute names."
   8328   (interactive)
   8329   (unless type (setq type "downcase"))
   8330   (save-excursion
   8331     (goto-char (point-min))
   8332     (let ((continue t)
   8333           (fun (if (eq (aref (downcase type) 0) ?u) 'uppercase 'downcase)))
   8334       (while continue
   8335         (cond
   8336           ((not (web-mode-attribute-next))
   8337            (setq continue nil))
   8338           ((looking-at "\\([[:alnum:]-]+\\)")
   8339            (replace-match (funcall fun (match-string 0)) t)
   8340            )
   8341           ) ;cond
   8342         ) ;while
   8343       )))
   8344 
   8345 ;; tag-case=lower|upper-case , attr-case=lower|upper-case
   8346 ;; special-chars=unicode|html-entities
   8347 ;; smart-apostrophes=bool , smart-quotes=bool , indentation=bool
   8348 (defun web-mode-dom-normalize ()
   8349   "Normalize buffer"
   8350   (interactive)
   8351   (save-excursion
   8352     (let ((rules web-mode-normalization-rules) elt)
   8353       (when (setq elt (cdr (assoc "tag-case" rules)))
   8354         (web-mode-buffer-change-tag-case elt))
   8355       (when (setq elt (cdr (assoc "attr-case" rules)))
   8356         (web-mode-buffer-change-attr-case elt))
   8357       (when (setq elt (cdr (assoc "css-indentation" rules)))
   8358         (web-mode-css-indent))
   8359       (when (setq elt (cdr (assoc "smart-apostrophes" rules)))
   8360         (web-mode-dom-apostrophes-replace))
   8361       (when (setq elt (cdr (assoc "smart-quotes" rules)))
   8362         (web-mode-dom-quotes-replace))
   8363       (when (setq elt (cdr (assoc "special-chars" rules)))
   8364         (if (string= elt "entities")
   8365             (web-mode-dom-entities-encode)
   8366             (web-mode-dom-entities-replace)))
   8367       (when (setq elt (cdr (assoc "whitespaces" rules)))
   8368         (goto-char (point-min))
   8369         (while (not (eobp))
   8370           (forward-line)
   8371           (delete-blank-lines))
   8372         (delete-trailing-whitespace)
   8373         (untabify (point-min) (point-max)))
   8374       (when (setq elt (cdr (assoc "indentation" rules)))
   8375         (web-mode-buffer-indent))
   8376       )))
   8377 
   8378 (defun web-mode-dom-apostrophes-replace ()
   8379   "Replace char(') with char(’) in the innerText of html elements."
   8380   (interactive)
   8381   (save-excursion
   8382     (let ((min (point-min)) (max (point-max)))
   8383       (when mark-active
   8384         (setq min (region-beginning)
   8385               max (region-end))
   8386         (deactivate-mark))
   8387       (goto-char min)
   8388       (while (web-mode-content-rsf "\\([[:alpha:]]\\)'\\([[:alpha:]]\\)" max)
   8389         (replace-match "\\1’\\2"))
   8390       )))
   8391 
   8392 (defun web-mode-dom-entities-encode ()
   8393   (save-excursion
   8394     (let (regexp elt (min (point-min)) (max (point-max)))
   8395       (when mark-active
   8396         (setq min (region-beginning)
   8397               max (region-end))
   8398         (deactivate-mark))
   8399       (goto-char min)
   8400       (setq regexp "[")
   8401       (dolist (pair web-mode-html-entities)
   8402         (setq regexp (concat regexp (char-to-string (cdr pair))))
   8403         )
   8404       (setq regexp (concat regexp "]"))
   8405       (while (web-mode-content-rsf regexp max)
   8406         (setq elt (match-string-no-properties 0))
   8407         (setq elt (aref elt 0))
   8408         (setq elt (car (rassoc elt web-mode-html-entities)))
   8409         (replace-match (concat "&" elt ";"))
   8410         (setq max (+ max (length elt) 1))
   8411         ) ;while
   8412       )))
   8413 
   8414 (defun web-mode-dom-entities-replace ()
   8415   "Replace html entities (e.g. &eacute; &#233; or &#x00E9; become é)"
   8416   (interactive)
   8417   (save-excursion
   8418     (let (ms pair elt (min (point-min)) (max (point-max)))
   8419       (when mark-active
   8420         (setq min (region-beginning)
   8421               max (region-end))
   8422         (deactivate-mark))
   8423       (goto-char min)
   8424       (while (web-mode-content-rsf "&\\([#]?[[:alnum:]]\\{2,8\\}\\);" max)
   8425         (setq elt nil)
   8426         (setq ms (match-string-no-properties 1))
   8427         (cond
   8428           ((not (eq (aref ms 0) ?\#))
   8429            (and (setq pair (assoc ms web-mode-html-entities))
   8430                 (setq elt (cdr pair))
   8431                 (setq elt (char-to-string elt))))
   8432           ((eq (aref ms 1) ?x)
   8433            (setq elt (substring ms 2))
   8434            (setq elt (downcase elt))
   8435            (setq elt (string-to-number elt 16))
   8436            (setq elt (char-to-string elt)))
   8437           (t
   8438            (setq elt (substring ms 1))
   8439            (setq elt (char-to-string (string-to-number elt))))
   8440           ) ;cond
   8441         (when elt (replace-match elt))
   8442         ) ;while
   8443       )))
   8444 
   8445 (defun web-mode-dom-xml-replace ()
   8446   "Replace &, > and < in html content."
   8447   (interactive)
   8448   (save-excursion
   8449     (let ((min (point-min)) (max (point-max)))
   8450       (when mark-active
   8451         (setq min (region-beginning)
   8452               max (region-end))
   8453         (deactivate-mark))
   8454       (goto-char min)
   8455       (while (web-mode-content-rsf "[&<>]" max)
   8456         (replace-match (cdr (assq (char-before) web-mode-xml-chars)) t t))
   8457       )))
   8458 
   8459 (defun web-mode-dom-quotes-replace ()
   8460   "Replace dumb quotes."
   8461   (interactive)
   8462   (save-excursion
   8463     (let (expr (min (point-min)) (max (point-max)))
   8464       (when mark-active
   8465         (setq min (region-beginning)
   8466               max (region-end))
   8467         (deactivate-mark))
   8468       (goto-char min)
   8469       (setq expr (concat (car web-mode-smart-quotes) "\\2" (cdr web-mode-smart-quotes)))
   8470       (while (web-mode-content-rsf "\\(\"\\)\\(.\\{1,200\\}\\)\\(\"\\)" max)
   8471         (replace-match expr)
   8472         ) ;while
   8473       )))
   8474 
   8475 ;;---- INDENTATION -------------------------------------------------------------
   8476 
   8477 ;; todo : passer de règle en règle et mettre un \n à la fin
   8478 (defun web-mode-css-indent ()
   8479   (save-excursion
   8480     (goto-char (point-min))
   8481     (let ((continue t) part-end)
   8482       (while continue
   8483         (cond
   8484           ((not (web-mode-part-next))
   8485            (setq continue nil))
   8486           ((eq (get-text-property (point) 'part-side) 'css)
   8487            (setq part-end (web-mode-part-end-position))
   8488            (while (web-mode-css-rule-next part-end)
   8489              (when (not (looking-at-p "[[:space:]]*\\($\\|<\\)"))
   8490                (newline)
   8491                (indent-according-to-mode)
   8492                (setq part-end (web-mode-part-end-position)))
   8493              )
   8494            )
   8495           ) ;cond
   8496         )
   8497       )))
   8498 
   8499 (defun web-mode-buffer-indent ()
   8500   "Indent all buffer."
   8501   (interactive)
   8502   (let ((debug t) (ts (current-time)) (sub nil))
   8503     (indent-region (point-min) (point-max))
   8504     (when debug
   8505       (setq sub (time-subtract (current-time) ts))
   8506       (message "buffer-indent: time elapsed = %Ss %9Sµs" (nth 1 sub) (nth 2 sub)))
   8507     (delete-trailing-whitespace)))
   8508 
   8509 (defun web-mode-point-context (pos)
   8510   "POS should be at the beginning of the indentation."
   8511   (save-excursion
   8512     (let (curr-char curr-indentation curr-line
   8513                     language
   8514                     options
   8515                     reg-beg reg-col
   8516                     prev-char prev-indentation prev-line prev-pos
   8517                     token
   8518                     part-language
   8519                     depth)
   8520 
   8521       (setq reg-beg (point-min)
   8522             reg-col 0
   8523             token "live"
   8524             options ""
   8525             language ""
   8526             prev-line ""
   8527             prev-char 0
   8528             prev-pos nil
   8529             prev-line-end nil)
   8530 
   8531       (when (get-text-property pos 'part-side)
   8532         (setq part-language (symbol-name (get-text-property pos 'part-side))))
   8533 
   8534       ;;(message "part-language=%S" part-language)
   8535 
   8536       (cond
   8537 
   8538         ((and (bobp) (member web-mode-content-type '("html" "xml")))
   8539          (setq language web-mode-content-type)
   8540          )
   8541 
   8542         ((string= web-mode-content-type "css")
   8543          (setq language "css"
   8544                curr-indentation web-mode-css-indent-offset))
   8545 
   8546         ((member web-mode-content-type '("javascript" "json" "typescript"))
   8547          (setq language web-mode-content-type
   8548                curr-indentation web-mode-code-indent-offset))
   8549 
   8550         ((or (string= web-mode-content-type "jsx")
   8551              (and part-language (string= part-language "jsx")))
   8552          (setq language "jsx"
   8553                curr-indentation web-mode-code-indent-offset)
   8554          (cond
   8555            ((web-mode-jsx-is-html pos)
   8556             (setq curr-indentation web-mode-markup-indent-offset
   8557                   options "is-html"))
   8558            ((and (setq depth (get-text-property pos 'jsx-depth)) (> depth 1))
   8559             (when (get-text-property pos 'jsx-beg)
   8560               (setq depth (1- depth)))
   8561             (setq reg-beg (web-mode-jsx-depth-beginning-position pos depth))
   8562             (setq reg-beg (1+ reg-beg))
   8563             ;;(message "%S" (point))
   8564             (save-excursion
   8565               (goto-char reg-beg)
   8566               ;;(message "pt=%S" reg-beg)
   8567               (cond
   8568                 ((and (not (looking-at-p "[ ]*$"))
   8569                       (looking-back "^[[:space:]]*{" (point-min)))
   8570                  (setq reg-col (+ (current-indentation) ;; #1027
   8571                                   (cond
   8572                                     ((looking-at "[ ]+") (1+ (length (match-string-no-properties 0))))
   8573                                     (t 0))
   8574                                   ))
   8575                  )
   8576                 ((looking-at-p "[ ]*\\[[ ]*$") ;; #0659
   8577                  (setq reg-col (current-indentation))
   8578                  )
   8579                 ((and (looking-back "=[ ]*{" (point-min)) ;; #0739 #1022
   8580                       (not (looking-at-p "[[:space:]]*<")))
   8581                  (setq reg-col (current-indentation))
   8582                  )
   8583                 ;;((and (looking-back "=[ ]*{" (point-min)) ;; #0739
   8584                 ;;      (looking-at-p "{[ ]*"))
   8585                 ;; (setq reg-col (current-indentation))
   8586                 ;; )
   8587                 ((get-text-property (1- (point)) 'tag-beg)
   8588                  ;;(message "point=%S" (point))
   8589                  (setq reg-col (current-indentation))
   8590                  )
   8591                 (t
   8592                  (message "%S : %S %S" (point) (current-indentation) web-mode-code-indent-offset)
   8593                  ;;(setq reg-col (+ (current-indentation) web-mode-code-indent-offset web-mode-jsx-expression-padding)))
   8594                  (setq reg-col (+ (current-indentation) web-mode-code-indent-offset)))
   8595                 )
   8596 
   8597               ;;(message "%S %S %S" (point) (current-indentation) reg-col)
   8598               ) ;save-excursion
   8599             )
   8600            ((string= web-mode-content-type "jsx")
   8601             (setq reg-beg (point-min)))
   8602            (t
   8603             (setq reg-beg (or (web-mode-part-beginning-position pos) (point-min)))
   8604             (save-excursion
   8605               (goto-char reg-beg)
   8606               (search-backward "<" nil t)
   8607               (setq reg-col (current-column))
   8608               ) ;save-excursion
   8609             )
   8610            ) ;cond
   8611          ;;(message "jsx reg-beg=%S" reg-beg)
   8612          ) ;jsx
   8613 
   8614         ((string= web-mode-content-type "php")
   8615          (setq language "php"
   8616                curr-indentation web-mode-code-indent-offset))
   8617 
   8618         ((or (string= web-mode-content-type "xml"))
   8619          (setq language "xml"
   8620                curr-indentation web-mode-markup-indent-offset))
   8621 
   8622         ;; TODO: est ce util ?
   8623         ((and (get-text-property pos 'tag-beg)
   8624               (get-text-property pos 'tag-name)
   8625               ;;(not (get-text-property pos 'part-side))
   8626               )
   8627          (setq language "html"
   8628                curr-indentation web-mode-markup-indent-offset))
   8629 
   8630         ((and (get-text-property pos 'block-side)
   8631               (not (get-text-property pos 'block-beg)))
   8632 
   8633          (setq reg-beg (or (web-mode-block-beginning-position pos) (point-min)))
   8634          (goto-char reg-beg)
   8635          (setq reg-col (current-column))
   8636          ;;(message "%S %S" reg-beg reg-col)
   8637          (setq language web-mode-engine)
   8638          (setq curr-indentation web-mode-code-indent-offset)
   8639 
   8640          (cond
   8641            ((string= web-mode-engine "blade")
   8642             (save-excursion
   8643               (when (web-mode-rsf "{[{!]+[ ]*")
   8644                 (setq reg-col (current-column))))
   8645             (setq reg-beg (+ reg-beg 2))
   8646             )
   8647            ((string= web-mode-engine "razor")
   8648             ;;(setq reg-beg (+ reg-beg 2))
   8649             ;;(setq reg-col (current-column))
   8650             )
   8651            ;; tests/demo.chtml
   8652            ((string= web-mode-engine "ctemplate")
   8653             (save-excursion
   8654               (when (web-mode-rsf "{{#?")
   8655                 (setq reg-col (current-column))))
   8656             )
   8657            ((string= web-mode-engine "dust")
   8658             (save-excursion
   8659               (when (web-mode-rsf "{@")
   8660                 (setq reg-col (current-column))))
   8661             )
   8662            ((string= web-mode-engine "svelte")
   8663             (save-excursion
   8664               (when (web-mode-rsf "{@")
   8665                 (setq reg-col (current-column))))
   8666             )
   8667            ((string= web-mode-engine "template-toolkit")
   8668             (setq reg-beg (+ reg-beg 3)
   8669                   reg-col (+ reg-col 3))
   8670             )
   8671            ((and (string= web-mode-engine "jsp")
   8672                  (web-mode-looking-at "<%@" reg-beg))
   8673             (save-excursion
   8674               (goto-char reg-beg)
   8675               (looking-at "<%@[ ]*[[:alpha:]]+[ ]+\\|</?[[:alpha:]]+[:.][[:alpha:]]+[ ]+")
   8676               (goto-char (match-end 0))
   8677               (setq reg-col (current-column))
   8678               )
   8679             )
   8680            ((and (string= web-mode-engine "freemarker")
   8681                  (web-mode-looking-at "<@\\|<%@\\|<[[:alpha:]]" reg-beg))
   8682             (save-excursion
   8683               (goto-char reg-beg)
   8684               (looking-at "<@[[:alpha:].]+[ ]+\\|<%@[ ]*[[:alpha:]]+[ ]+\\|<[[:alpha:]]+:[[:alpha:]]+[ ]+")
   8685               (goto-char (match-end 0))
   8686               (setq reg-col (current-column))
   8687               )
   8688             )
   8689            ) ;cond
   8690          ) ;block-side
   8691 
   8692         ((and part-language (member part-language
   8693                                     '("css" "javascript" "json" "sql" "markdown"
   8694                                       "pug" "ruby" "sass" "stylus" "typescript")))
   8695          (setq reg-beg (or (web-mode-part-beginning-position pos) (point-min)))
   8696          (goto-char reg-beg)
   8697          (if (and (string= web-mode-engine "mojolicious")
   8698                   (looking-back "javascript begin" (point-min)))
   8699              (search-backward "%" nil t)
   8700              (search-backward "<" nil t))
   8701          (setq reg-col (current-column))
   8702          (setq language part-language)
   8703          (cond
   8704            ((string= language "css")
   8705             (setq curr-indentation web-mode-css-indent-offset))
   8706            ((string= language "sql")
   8707             (setq curr-indentation web-mode-sql-indent-offset))
   8708            ((string= language "markdown")
   8709             (setq curr-indentation web-mode-code-indent-offset))
   8710            ((string= language "pug")
   8711             (setq curr-indentation web-mode-code-indent-offset))
   8712            ((string= language "sass")
   8713             (setq curr-indentation web-mode-code-indent-offset))
   8714            ((string= language "stylus")
   8715             (setq curr-indentation web-mode-code-indent-offset))
   8716            ((string= language "ruby")
   8717             (setq curr-indentation web-mode-code-indent-offset))
   8718            ((string= language "typescript")
   8719             (setq curr-indentation web-mode-code-indent-offset))
   8720            (t
   8721             (setq language "javascript"
   8722                   curr-indentation web-mode-code-indent-offset))
   8723            )
   8724          ) ;part-side
   8725 
   8726         (t
   8727          (setq language "html"
   8728                curr-indentation web-mode-markup-indent-offset)
   8729          )
   8730 
   8731         ) ;cond
   8732 
   8733       (cond
   8734         ((or (and (> pos (point-min))
   8735                   (eq (get-text-property pos 'part-token) 'comment)
   8736                   (eq (get-text-property (1- pos) 'part-token) 'comment)
   8737                   (progn
   8738                     (setq reg-beg (previous-single-property-change pos 'part-token))
   8739                     t))
   8740              (and (> pos (point-min))
   8741                   (eq (get-text-property pos 'block-token) 'comment)
   8742                   (eq (get-text-property (1- pos) 'block-token) 'comment)
   8743                   (progn
   8744                     (setq reg-beg (previous-single-property-change pos 'block-token))
   8745                     t))
   8746              (and (> pos (point-min))
   8747                   (eq (get-text-property pos 'tag-type) 'comment)
   8748                   (not (get-text-property pos 'tag-beg))
   8749                   (progn
   8750                     (setq reg-beg (web-mode-tag-beginning-position pos))
   8751                     t))
   8752              )
   8753          (setq token "comment"))
   8754         ((or (and (> pos (point-min))
   8755                   (member (get-text-property pos 'part-token)
   8756                           '(string context key))
   8757                   (member (get-text-property (1- pos) 'part-token)
   8758                           '(string context key)))
   8759              (and (eq (get-text-property pos 'block-token) 'string)
   8760                   (eq (get-text-property (1- pos) 'block-token) 'string)))
   8761          (setq token "string"))
   8762         )
   8763 
   8764       (goto-char pos)
   8765       (setq curr-line (web-mode-trim
   8766                        (buffer-substring-no-properties
   8767                         (line-beginning-position)
   8768                         (line-end-position))))
   8769       (setq curr-char (if (string= curr-line "") 0 (aref curr-line 0)))
   8770 
   8771       (when (or (member language '("php" "blade" "javascript" "typescript" "jsx" "razor" "css"))
   8772                 (and (member language '("html" "xml"))
   8773                      (not (eq ?\< curr-char))))
   8774         (let (prev)
   8775           (cond
   8776             ((member language '("html" "xml" "javascript" "typescript" "jsx" "css"))
   8777              (when (setq prev (web-mode-part-previous-live-line reg-beg))
   8778                (setq prev-line (nth 0 prev)
   8779                      prev-indentation (nth 1 prev)
   8780                      prev-pos (nth 2 prev)
   8781                      prev-line-end (nth 3 prev))
   8782                )
   8783              )
   8784             ((setq prev (web-mode-block-previous-live-line))
   8785              (setq prev-line (nth 0 prev)
   8786                    prev-indentation (nth 1 prev)
   8787                    prev-pos (nth 2 prev)
   8788                    prev-line-end (nth 3 prev))
   8789              (setq prev-line (web-mode-clean-block-line prev-line)))
   8790             ) ;cond
   8791           ) ;let
   8792         (when (>= (length prev-line) 1)
   8793           (setq prev-char (aref prev-line (1- (length prev-line))))
   8794           (setq prev-line (substring-no-properties prev-line))
   8795           )
   8796         )
   8797 
   8798       (cond
   8799         ((not (member web-mode-content-type '("html" "xml")))
   8800          )
   8801         ((member language '("javascript" "typescript" "jsx" "ruby"))
   8802          (setq reg-col (if web-mode-script-padding (+ reg-col web-mode-script-padding) 0)))
   8803         ((member language '("css" "sql" "markdown" "pug" "sass" "stylus"))
   8804          (setq reg-col (if web-mode-style-padding (+ reg-col web-mode-style-padding) 0)))
   8805         ((not (member language '("html" "xml")))
   8806          (setq reg-col
   8807                (cond
   8808                  ((not web-mode-block-padding) reg-col)
   8809                  ((eq web-mode-block-padding -1) 0)
   8810                  (t (+ reg-col web-mode-block-padding))
   8811                  ) ;cond
   8812                ) ;setq
   8813          )
   8814         )
   8815 
   8816       (list :curr-char curr-char
   8817             :curr-indentation curr-indentation
   8818             :curr-line curr-line
   8819             :language language
   8820             :options options
   8821             :prev-char prev-char
   8822             :prev-indentation prev-indentation
   8823             :prev-line prev-line
   8824             :prev-line-end prev-line-end
   8825             :prev-pos prev-pos
   8826             :reg-beg reg-beg
   8827             :reg-col reg-col
   8828             :token token)
   8829       )))
   8830 
   8831 (defun web-mode-indent-line ()
   8832 
   8833   (web-mode-scan)
   8834 
   8835   (let ((offset nil)
   8836         (char nil)
   8837         (debug nil)
   8838         (inhibit-modification-hooks nil)
   8839         (adjust t))
   8840 
   8841     (save-excursion
   8842       (back-to-indentation)
   8843       (setq char (char-after))
   8844       (let* ((pos (point))
   8845              (ctx (web-mode-point-context pos))
   8846              (curr-char (plist-get ctx :curr-char))
   8847              (curr-indentation (plist-get ctx :curr-indentation))
   8848              (curr-line (plist-get ctx :curr-line))
   8849              (language (plist-get ctx :language))
   8850              (prev-char (plist-get ctx :prev-char))
   8851              (prev-indentation (plist-get ctx :prev-indentation))
   8852              (prev-line (plist-get ctx :prev-line))
   8853              (prev-line-end (plist-get ctx :prev-line-end))
   8854              (prev-pos (plist-get ctx :prev-pos))
   8855              (reg-beg (plist-get ctx :reg-beg))
   8856              (reg-col (plist-get ctx :reg-col))
   8857              (token (plist-get ctx :token))
   8858              (options (plist-get ctx :options))
   8859              (chars (list curr-char prev-char))
   8860              (tmp nil)
   8861              (is-js (member language '("javascript" "jsx" "ejs" "typescript"))))
   8862 
   8863         (when (member language '("json" "typescript"))
   8864           (setq language "javascript"))
   8865 
   8866         ;;(message "%S %S" (plist-get ctx :language) language)
   8867         ;;(message "curr-char=[%c] prev-char=[%c]\n%S" curr-char prev-char ctx)
   8868         ;;(message "options=%S" ctx)
   8869 
   8870         (cond
   8871 
   8872           ((or (bobp) (= (line-number-at-pos pos) 1))
   8873            (when debug (message "I100(%S) first line" pos))
   8874            (setq offset 0))
   8875 
   8876           ;; #123 #1145
   8877           ((and web-mode-enable-front-matter-block
   8878                 (eq (char-after (point-min)) ?\-)
   8879                 (or (looking-at-p "---")
   8880                     (search-forward "---" (point-max) t)))
   8881            (when debug (message "I108(%S) front-matter-block" pos))
   8882            (setq offset nil))
   8883 
   8884           ;; #1073
   8885           ((get-text-property pos 'invisible)
   8886            (when debug (message "I110(%S) invible" pos))
   8887            (setq offset nil))
   8888 
   8889           ((string= token "string")
   8890            (when debug (message "I120(%S) string" pos))
   8891            (cond
   8892              ((web-mode-is-token-end pos)
   8893               (if (get-text-property pos 'block-side)
   8894                   (web-mode-block-token-beginning)
   8895                   (web-mode-part-token-beginning))
   8896               (setq offset (current-indentation))
   8897               )
   8898              ((and web-mode-enable-sql-detection
   8899                    (web-mode-block-token-starts-with (concat "[ \n]*" web-mode-sql-queries)))
   8900               (save-excursion
   8901                 (let (col)
   8902                   (web-mode-block-string-beginning)
   8903                   (skip-chars-forward "[ \"'\n]")
   8904                   (setq col (current-column))
   8905                   (goto-char pos)
   8906                   (if (looking-at-p "\\(SELECT\\|INSERT\\|DELETE\\|UPDATE\\|FROM\\|LEFT\\|JOIN\\|WHERE\\|GROUP BY\\|LIMIT\\|HAVING\\|\)\\)")
   8907                       (setq offset col)
   8908                       (setq offset (+ col web-mode-sql-indent-offset)))
   8909                   )
   8910                 ) ;save-excursion
   8911               )
   8912              ((and is-js
   8913                    (web-mode-is-ql-string pos "Relay\.QL"))
   8914               (setq offset (web-mode-relayql-indentation pos))
   8915               )
   8916              ((and is-js
   8917                    (web-mode-is-ql-string pos "gql"))
   8918               (setq offset (web-mode-relayql-indentation pos "gql"))
   8919               )
   8920              ((and is-js
   8921                    (web-mode-is-ql-string pos "graphql"))
   8922               (setq offset (web-mode-relayql-indentation pos "graphql"))
   8923               )
   8924              ((and is-js
   8925                    (web-mode-is-css-string pos))
   8926               (when debug (message "I127(%S) css string" pos))
   8927               (setq offset (web-mode-token-css-indentation pos))
   8928               )
   8929              ((and is-js
   8930                    (web-mode-is-html-string pos))
   8931               (when debug (message "I128(%S) html string" pos))
   8932               (setq offset (web-mode-token-html-indentation pos))
   8933               )
   8934              (t
   8935               (setq offset nil))
   8936              ) ;cond
   8937            ) ;case string
   8938 
   8939           ((string= token "comment")
   8940            (when debug (message "I130(%S) comment" pos))
   8941            (if (eq (get-text-property pos 'tag-type) 'comment)
   8942                (web-mode-tag-beginning)
   8943                (goto-char (car
   8944                            (web-mode-property-boundaries
   8945                             (if (eq (get-text-property pos 'part-token) 'comment)
   8946                                 'part-token
   8947                                 'block-token)
   8948                             pos))))
   8949            (setq offset (current-column))
   8950            (cond
   8951              ((string= web-mode-engine "freemarker")
   8952               (setq offset (+ (current-indentation) 2)))
   8953              ((member (buffer-substring-no-properties (point) (+ (point) 2)) '("/*" "{*" "@*"))
   8954               (cond
   8955                 ((eq ?\* curr-char)
   8956                  (setq offset (+ offset 1)))
   8957                 (t
   8958                  (setq offset (+ offset 3)))
   8959                 ) ;cond
   8960               )
   8961              ((string= (buffer-substring-no-properties (point) (+ (point) 4)) "<!--")
   8962               (cond
   8963                 ((string-match-p "^<!\\[endif" curr-line)
   8964                  )
   8965                 ((looking-at-p "<!--\\[if")
   8966                  (setq offset (+ offset web-mode-markup-indent-offset)))
   8967                 ((string-match-p "^-->" curr-line)
   8968                  (setq offset offset))
   8969                 ((string-match-p "^-" curr-line)
   8970                  (setq offset (+ offset 3)))
   8971                 (t
   8972                  (setq offset (+ offset web-mode-markup-comment-indent-offset)))
   8973                 ) ;cond
   8974               )
   8975              ((and (string= web-mode-engine "django") (looking-back "{% comment %}" (point-min)))
   8976               (setq offset (- offset 12)))
   8977              ((and (string= web-mode-engine "mako") (looking-back "<%doc%>" (point-min)))
   8978               (setq offset (- offset 6)))
   8979              ((and (string= web-mode-engine "mason") (looking-back "<%doc%>" (point-min)))
   8980               (setq offset (- offset 6)))
   8981              ) ;cond
   8982            ) ;case comment
   8983 
   8984           ((and (string= web-mode-engine "mason")
   8985                 (string-match-p "^%" curr-line))
   8986            (when debug (message "I140(%S) mason" pos))
   8987            (setq offset 0))
   8988 
   8989           ((and (string= web-mode-engine "razor")
   8990                 (string-match-p "^\\([{}]\\|else\\)" curr-line))
   8991            (when debug (message "I142(%S) razor" pos))
   8992            (save-excursion
   8993              (web-mode-block-previous)
   8994              (setq offset (current-indentation))
   8995              ))
   8996 
   8997           ((and (string= web-mode-engine "django")
   8998                 (string-match-p "^#" curr-line))
   8999            (when debug (message "I144(%S) django line statements" pos))
   9000            (setq offset 0))
   9001 
   9002           ((and (get-text-property pos 'block-beg)
   9003                 (or (web-mode-block-is-close pos)
   9004                     (web-mode-block-is-inside pos)))
   9005            (when debug (message "I150(%S) block-match" pos))
   9006            (cond
   9007              ((not (web-mode-block-match))
   9008               )
   9009              ((and (string= web-mode-engine "closure")
   9010                    (string-match-p "{\\(case\\|default\\)" curr-line))
   9011               (setq offset (+ (current-indentation) web-mode-markup-indent-offset)))
   9012              (t
   9013               (setq offset (current-indentation))
   9014               (if (and (string= web-mode-engine "blade")
   9015                        (string-match-p "@break" curr-line))
   9016                   (setq offset (+ (current-indentation) offset)))
   9017               )
   9018              ) ;cond
   9019            )
   9020 
   9021           ((eq (get-text-property pos 'block-token) 'delimiter-end)
   9022            (when debug (message "I160(%S) block-beginning" pos))
   9023            (when (web-mode-block-beginning)
   9024              (setq reg-col (current-indentation))
   9025              (setq offset (current-column))))
   9026 
   9027           ((or (and (get-text-property pos 'tag-beg)
   9028                     (eq (get-text-property pos 'tag-type) 'end))
   9029                (and (eq (get-text-property pos 'tag-type) 'comment)
   9030                     (string-match-p "<!--#\\(else\\|elif\\|endif\\)" curr-line)))
   9031            (when debug (message "I170(%S) tag-match" pos))
   9032            (when (web-mode-tag-match)
   9033              (setq offset (current-indentation))))
   9034 
   9035           ((and (member language '("jsx"))
   9036                 (eq curr-char ?\})
   9037                 (get-text-property pos 'jsx-end))
   9038            (when debug (message "I180(%S) jsx-expr-end" pos))
   9039            (web-mode-go (1- reg-beg))
   9040            (setq reg-col nil)
   9041            ;;(setq offset (current-column)))
   9042            (setq offset (current-indentation)))
   9043 
   9044           ((and (member language '("html" "xml" "javascript" "jsx"))
   9045                 (get-text-property pos 'tag-type)
   9046                 (not (get-text-property pos 'tag-beg))
   9047                 ;;(or (not (string= language "jsx"))
   9048                 ;;    (string= options "is-html"))
   9049                 (not (and (string= language "jsx")
   9050                           (web-mode-jsx-is-expr pos)))
   9051                 )
   9052            (when debug (message "I190(%S) attr-indent" pos))
   9053            (cond
   9054              ((and (not (get-text-property pos 'tag-attr-beg))
   9055                    (get-text-property pos 'tag-attr)
   9056                    (get-text-property (1- pos) 'tag-attr)
   9057                    (web-mode-attribute-beginning)
   9058                    (not (string-match-p "^/?>" curr-line))
   9059                    ;;(progn (message "pos=%S point=%S" pos (point)) t)
   9060                    )
   9061 
   9062               (cond
   9063                 ((eq (logand (get-text-property (point) 'tag-attr-beg) 8) 8)
   9064                  (setq offset nil))
   9065                 ((not (web-mode-tag-beginning))
   9066                  (message "** tag-beginning ** failure")
   9067                  (setq offset nil))
   9068                 (web-mode-attr-value-indent-offset
   9069                  (setq offset (+ (current-column) web-mode-attr-value-indent-offset)))
   9070                 ((web-mode-dom-rsf "=[ ]*[\"']?" pos)
   9071                  ;;(message "%S" (point))
   9072                  (setq offset (current-column)))
   9073                 (t
   9074                  (setq offset (+ (current-column) web-mode-markup-indent-offset)))
   9075                 ) ;cond
   9076               ) ;and
   9077              ((not (web-mode-tag-beginning))
   9078               (message "** error ** unable to jump to tag beg"))
   9079              ((string-match-p "^/?>" curr-line)
   9080               (setq offset (web-mode-column-at-pos (web-mode-tag-beginning-position pos)))
   9081               )
   9082              (web-mode-attr-indent-offset
   9083               (setq offset (+ (current-column) web-mode-attr-indent-offset)))
   9084              ((looking-at-p (concat web-mode-start-tag-regexp "[ ]*\n"))
   9085               ;;(message "%S: %S" (point) (web-mode-inside-block-control pos))
   9086               (setq offset (+ (current-column) (or web-mode-attr-indent-offset web-mode-code-indent-offset)))
   9087               ;; #1109
   9088               (setq tmp (web-mode-inside-block-control pos))
   9089               (when (and tmp (> tmp (point)))
   9090                 (setq offset (+ offset (or web-mode-attr-indent-offset web-mode-code-indent-offset))))
   9091               )
   9092              ((web-mode-attribute-next)
   9093               (setq offset (current-column)))
   9094              ) ;cond
   9095            ) ;attr-indent
   9096 
   9097           ((or (member language '("html" "xml"))
   9098                (and (member language '("jsx"))
   9099                     (string= options "is-html")))
   9100            (when debug (message "I200(%S) web-mode-markup-indentation" pos))
   9101            ;; https://www.w3.org/TR/html5/syntax.html#optional-tags
   9102            (when web-mode-enable-optional-tags
   9103              (save-excursion
   9104                (let (tag-name parent-tag-name parent-tag-pos)
   9105                  (when (and (setq tag-name (get-text-property pos 'tag-name))
   9106                             (setq parent-tag-pos (web-mode-element-parent-position pos))
   9107                             (setq parent-tag-name (get-text-property parent-tag-pos 'tag-name))
   9108                             (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")))
   9109                                 (and (string= parent-tag-name "li") (member tag-name '("li")))
   9110                                 (and (string= parent-tag-name "dt") (member tag-name '("dt" "dd")))
   9111                                 (and (string= parent-tag-name "td") (member tag-name '("td" "th")))
   9112                                 (and (string= parent-tag-name "th") (member tag-name '("td" "th")))
   9113                                 ))
   9114                    (when debug (message "I205(%S) %S(%S) auto-closing" pos parent-tag-name parent-tag-pos))
   9115                    (setq offset (web-mode-indentation-at-pos parent-tag-pos))
   9116                    )))) ; when let save-excursion when
   9117 
   9118            (when (string= web-mode-engine "closure")
   9119              (save-excursion
   9120                (when (and (re-search-backward "{/?switch" nil t)
   9121                           (string= (match-string-no-properties 0) "{switch"))
   9122                  (setq offset (+ (current-indentation) (* 2 web-mode-markup-indent-offset)))
   9123                  )
   9124                ))
   9125            (cond
   9126              ((not (null offset))
   9127               )
   9128              ((get-text-property pos 'tag-beg)
   9129               (setq offset (web-mode-markup-indentation pos))
   9130               )
   9131              ((and web-mode-indentless-elements
   9132                    (not (string= language "jsx"))
   9133                    (null (get-text-property pos 'block-side))
   9134                    (null (get-text-property pos 'part-side))
   9135                    (and (null (get-text-property pos 'tag-beg))
   9136                         (save-excursion
   9137                           (and (web-mode-element-parent)
   9138                                (member (get-text-property (point) 'tag-name) web-mode-indentless-elements))))
   9139                    )
   9140               (setq offset nil))
   9141              ((or (eq (length curr-line) 0)
   9142                   (= web-mode-indent-style 2)
   9143                   (get-text-property pos 'tag-beg)
   9144                   (get-text-property pos 'reg-beg))
   9145               (setq offset (web-mode-markup-indentation pos))
   9146               )
   9147              )
   9148            )
   9149 
   9150           ((string= language "ctemplate")
   9151            (when debug (message "I210(%S) ctemplate" pos))
   9152            (setq offset reg-col))
   9153 
   9154           ((string= language "antlers")
   9155            (when debug (message "I214(%S) antlers" pos))
   9156            (setq offset reg-col))
   9157 
   9158           ((string= language "expressionengine")
   9159            (when debug (message "I220(%S) expressionengine" pos))
   9160            (setq offset (+ reg-col (or web-mode-attr-indent-offset web-mode-code-indent-offset))))
   9161 
   9162           ((string= language "asp")
   9163            (when debug (message "I230(%S) asp" pos))
   9164            (setq offset (web-mode-asp-indentation pos
   9165                                                   curr-line
   9166                                                   reg-col
   9167                                                   curr-indentation
   9168                                                   reg-beg)))
   9169 
   9170           ((member language '("lsp" "cl-emb" "artanis"))
   9171            (when debug (message "I240(%S) lsp" pos))
   9172            (setq offset (web-mode-lisp-indentation pos ctx)))
   9173 
   9174           ((and (member curr-char '(?\}))
   9175                 (string= language "razor")
   9176                 (get-text-property pos 'block-end))
   9177            (when debug (message "I245(%S) razor closing" pos))
   9178            (goto-char reg-beg)
   9179            ;;(message "%S %S" (point) (current-column))
   9180            (setq offset (current-column)
   9181                  reg-col nil)
   9182            )
   9183 
   9184           ((member curr-char '(?\} ?\) ?\]))
   9185            (when debug (message "I250(%S) closing-paren" pos))
   9186            (let (ori pos2)
   9187              (setq pos2 pos)
   9188              ;; #1096
   9189              (when (looking-at-p ".[\]})]+")
   9190                (skip-chars-forward "[\]})]")
   9191                (backward-char)
   9192                (setq pos2 (point))
   9193                ) ;when
   9194              (if (get-text-property pos 'block-side)
   9195                  (setq ori (web-mode-block-opening-paren-position pos2 reg-beg))
   9196                  (setq ori (web-mode-part-opening-paren-position pos2 reg-beg)))
   9197              ;;(message "ori=%S" ori)
   9198              (cond
   9199                ((null ori)
   9200                 (setq offset reg-col))
   9201                ((and (goto-char ori)
   9202                      (looking-back ")[ ]*" (point-min)) ;; peut-on se passer du looking-back ?
   9203                      (re-search-backward ")[ ]*" nil t)
   9204                      (web-mode-block-opening-paren reg-beg))
   9205                 (back-to-indentation)
   9206                 (setq offset (current-indentation))
   9207                 )
   9208                (t
   9209                 (goto-char ori)
   9210                 (back-to-indentation)
   9211                 (setq offset (current-indentation))
   9212                 ;;(message "ori=%S offset=%S" ori offset)
   9213                 (when (get-text-property pos 'jsx-depth)
   9214                   ;;(when (get-text-property pos 'jsx-end)
   9215                   (setq adjust nil))
   9216                 ) ;t
   9217                ) ;cond
   9218              ) ;let
   9219            )
   9220 
   9221           ((member language '("mako" "web2py"))
   9222            (when debug (message "I254(%S) python (mako/web2py)" pos))
   9223            (setq offset (web-mode-python-indentation pos
   9224                                                      curr-line
   9225                                                      reg-col
   9226                                                      curr-indentation
   9227                                                      reg-beg)))
   9228 
   9229           ((member language '("erb" "ruby"))
   9230            (when debug (message "I260(%S) erb" pos))
   9231            (setq offset (web-mode-ruby-indentation pos
   9232                                                    curr-line
   9233                                                    reg-col
   9234                                                    curr-indentation
   9235                                                    reg-beg)))
   9236 
   9237           ((string= language "css")
   9238            (when debug (message "I270(%S) css-indentation" pos))
   9239            ;;(message "prev=%c" prev-char)
   9240            (cond
   9241              ((eq prev-char ?:)
   9242               (setq offset (+ prev-indentation web-mode-css-indent-offset)))
   9243              ((eq prev-char ?,)
   9244               (setq offset prev-indentation))
   9245              (t
   9246               (setq offset (car (web-mode-css-indentation pos
   9247                                                           reg-col
   9248                                                           curr-indentation
   9249                                                           language
   9250                                                           reg-beg))))))
   9251 
   9252           ((string= language "sql")
   9253            (when debug (message "I280(%S) sql" pos))
   9254            (setq offset (car (web-mode-sql-indentation pos
   9255                                                        reg-col
   9256                                                        curr-indentation
   9257                                                        language
   9258                                                        reg-beg))))
   9259 
   9260           ((string= language "markdown")
   9261            (when debug (message "I290(%S) markdown" pos))
   9262            (setq offset (car (web-mode-markdown-indentation pos
   9263                                                             reg-col
   9264                                                             curr-indentation
   9265                                                             language
   9266                                                             reg-beg))))
   9267 
   9268           ((string= language "stylus")
   9269            (when debug (message "I294(%S) stylus" pos))
   9270            (setq offset (car (web-mode-stylus-indentation pos
   9271                                                           reg-col
   9272                                                           curr-indentation
   9273                                                           language
   9274                                                           reg-beg))))
   9275           ((string= language "sass")
   9276            (when debug (message "I296(%S) sass" pos))
   9277            (setq offset (car (web-mode-stylus-indentation pos
   9278                                                           reg-col
   9279                                                           curr-indentation
   9280                                                           language
   9281                                                           reg-beg))))
   9282 
   9283           ((string= language "pug")
   9284            (when debug (message "I298(%S) pug" pos))
   9285            (setq offset (car (web-mode-pug-indentation pos
   9286                                                        reg-col
   9287                                                        curr-indentation
   9288                                                        language
   9289                                                        reg-beg))))
   9290 
   9291           ((and (string= language "razor")
   9292                 (string-match-p "^\\." curr-line)
   9293                 (string-match-p "^\\." prev-line))
   9294            (when debug (message "I300(%S) razor" pos))
   9295            (setq offset prev-indentation))
   9296 
   9297           ((and (string= language "razor")
   9298                 (string-match-p "^case " curr-line)
   9299                 (string-match-p "^case " prev-line))
   9300            (when debug (message "I310(%S) razor case" pos))
   9301            (search-backward "case ")
   9302            (setq offset (current-column)))
   9303 
   9304           ((and is-js
   9305                 (member ?\. chars)
   9306                 (not (string-match-p "^\\.\\.\\." curr-line)))
   9307            (when debug (message "I320(%S) javascript-calls" pos))
   9308            (let (pair)
   9309              (setq pair (web-mode-javascript-calls-beginning-position pos reg-beg))
   9310              ;;(message "%S" pair)
   9311              (when pair
   9312                (goto-char (car pair))
   9313                ;;(message "%S %S" (point) pair)
   9314                (cond
   9315                  ((cdr (assoc "lineup-calls" web-mode-indentation-params))
   9316                   ;;(message "ici")
   9317                   ;;(search-forward ".")
   9318                   (if (cdr pair)
   9319                       (progn
   9320                         (goto-char (cdr pair))
   9321                         (setq offset (current-column))
   9322                         (looking-at "\\.\\([ \t\n]*\\)")
   9323                         (setq offset (- offset (length (match-string-no-properties 1))))
   9324                         (unless (eq curr-char ?\.) (setq offset (1+ offset)))
   9325                         ) ;progn
   9326                       ;; TODO: cela devrait etre fait dans web-mode-javascript-calls-beginning-position
   9327                       (skip-chars-forward " \t\n")
   9328                       (setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9329                       ) ;if
   9330                   )
   9331                  (t
   9332                   (setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9333                   ) ;t
   9334                  ) ;cond
   9335                ) ;when
   9336              ) ;let
   9337            )
   9338 
   9339           ((and is-js
   9340                 (member ?\+ chars))
   9341            (when debug (message "I330(%S) javascript-string" pos))
   9342            ;;(message "js-concat")
   9343            (cond
   9344              ((not (web-mode-javascript-string-beginning pos reg-beg))
   9345               )
   9346              ((null (cdr (assoc "lineup-concats" web-mode-indentation-params)))
   9347               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9348              ((not (eq curr-char ?\+))
   9349               (setq offset (current-column)))
   9350              (t
   9351               (setq offset (current-column))
   9352               (when (not (looking-back "\\(^[ \t]+\\|if[ ]*[(]?\\)" (point-min)))
   9353                 (goto-char pos)
   9354                 (looking-at "\\+[ \t\n]*")
   9355                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9356               )
   9357              )
   9358            )
   9359 
   9360           ;; #579 , #742
   9361           ((and (member language '("javascript" "jsx" "ejs" "php"))
   9362                 (string-match-p "=[>]?$" prev-line))
   9363            (when debug (message "I340(%S)" pos))
   9364            (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9365            ;;(message "ici%S" offset)
   9366            )
   9367 
   9368           ;; #1016
   9369           ((and (member language '("javascript" "jsx" "ejs"))
   9370                 (string-match-p "^[ \t]*|}" curr-line))
   9371            (when debug (message "I346(%S) flow-exact-object-type-end" pos))
   9372            (when (re-search-backward "{|" reg-beg t)
   9373              (setq offset (current-indentation))
   9374              )
   9375            )
   9376 
   9377           ;; #446, #638, #800, #978, #998
   9378           ((and (member language '("javascript" "jsx" "ejs" "php"))
   9379                 (or (string-match-p "[&|?:+-]$" prev-line)
   9380                     (string-match-p "^[&|?:+-]" curr-line))
   9381                 (not (and (string= language "php")
   9382                           (string-match-p "^->" curr-line)))
   9383                 (not (and (string= language "php")
   9384                           (string-match-p "^?[a-zA-z]*" curr-line)))
   9385                 (not (and (string= language "php")
   9386                           (string-match-p "\\(else[ ]?:\\|if[ ]?([^)]*)[ ]?:\\)" prev-line)))
   9387                 (not (string-match-p "^\\(++\\|--\\)" curr-line))
   9388                 (not (and is-js
   9389                           (string-match-p "]:\\|{|$" prev-line)))
   9390                 (not (and (eq prev-char ?\:)
   9391                           (string-match-p "^\\(case\\|default\\)" prev-line)))
   9392                 )
   9393            ;;(message "prev=%S" prev-line)
   9394            (when debug (message "I350(%S) multiline statement" pos))
   9395            (let (is-ternary)
   9396              (setq is-ternary (or (string-match-p "[?:]$" prev-line)
   9397                                   (string-match-p "^[?:]" curr-line)))
   9398              (cond
   9399                ((not (funcall (if is-js
   9400                                   'web-mode-javascript-statement-beginning
   9401                                   'web-mode-block-statement-beginning)
   9402                               pos reg-beg is-ternary))
   9403                 )
   9404                ((null (cdr (assoc "lineup-ternary" web-mode-indentation-params)))
   9405                 (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9406                (t
   9407                 (setq offset (current-column))
   9408                 (when (and (member curr-char '(?\+ ?\- ?\& ?\| ?\? ?\:))
   9409                            (not (looking-back "\\(^[ \t]+\\|if[ ]*[(]?\\)" (point-min)))) ; #743
   9410                   (goto-char pos)
   9411                   (looking-at "\\(||\\|&&\\|[&|?:+-]\\)[ \t\n]*")
   9412                   (setq offset (- offset (length (match-string-no-properties 0)))))
   9413                 )
   9414                ) ;cond
   9415              ) ;let
   9416            )
   9417 
   9418           ((and is-js
   9419                 (eq prev-char ?\()
   9420                 (string-match-p "=>[ ]*([ ]*$" prev-line))
   9421            (when debug (message "I355(%S) => (" pos))
   9422            (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9423            )
   9424 
   9425           ((and is-js
   9426                 (or (member ?\, chars)
   9427                     (member prev-char '(?\( ?\[))))
   9428            (when debug (message "I360(%S) javascript-args(%S)" pos (web-mode-jsx-is-html prev-line-end)))
   9429            (cond
   9430              ((not (web-mode-javascript-args-beginning pos reg-beg))
   9431               (message "no js args beg")
   9432               )
   9433              ((or (not (cdr (assoc "lineup-args" web-mode-indentation-params)))
   9434                   (looking-at-p "|?\n") ;; #1016
   9435                   ;;(eq (char-after) ?\n)
   9436                   )
   9437               (if (and reg-col (> reg-col (current-indentation)))
   9438                   (setq offset (+ reg-col web-mode-code-indent-offset))
   9439                   (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9440               )
   9441              ((not (eq curr-char ?\,))
   9442               (setq offset (current-column)))
   9443              (t
   9444               (setq offset (current-column))
   9445               (goto-char pos)
   9446               (looking-at ",[ \t\n]*")
   9447               (setq offset (- offset (length (match-string-no-properties 0)))))
   9448              ) ;cond
   9449            )
   9450 
   9451           ((and is-js
   9452                 (or (eq prev-char ?\))
   9453                     (string-match-p "\\(^\\|[}[:space:]]+\\)else$" prev-line)))
   9454            (when debug (message "I370(%S)" pos))
   9455            (cond
   9456              ((and (string-match-p "else$" prev-line)
   9457                    (not (string-match-p "^{" curr-line)))
   9458               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9459               )
   9460              ((and (string-match-p "else$" prev-line)
   9461                    (string-match-p "^{" curr-line)
   9462                    web-mode-enable-curly-brace-indentation)
   9463               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9464               )
   9465              ((setq tmp (web-mode-part-is-opener prev-pos reg-beg))
   9466               ;;(message "is-opener")
   9467               (if (or (not (looking-at-p "{")) ;; #1020, #1053, #1160
   9468                       web-mode-enable-curly-brace-indentation)
   9469                   (setq offset (+ tmp web-mode-code-indent-offset))
   9470                   (setq offset tmp))
   9471               )
   9472              (t
   9473               (setq offset
   9474                     (car (web-mode-javascript-indentation pos
   9475                                                           reg-col
   9476                                                           curr-indentation
   9477                                                           language
   9478                                                           reg-beg)))
   9479               ) ;t
   9480              ) ;cond
   9481 
   9482            )
   9483 
   9484           ;; TODO : a retoucher completement car le code js a ete place ci-dessus
   9485           ;;((and (member language '("javascript" "jsx" "ejs" "php"))
   9486           ((and (member language '("php"))
   9487                 (or (and (eq prev-char ?\))
   9488                          (string-match-p "^\\(for\\|foreach\\|if\\|else[ ]*if\\|while\\)[ ]*(" prev-line))
   9489                     (and is-js
   9490                          (web-mode-part-is-opener prev-pos reg-beg))
   9491                     (string-match-p "^else$" prev-line))
   9492                 (not (string-match-p "^\\([{.]\\|->\\)" curr-line)))
   9493            (when debug (message "I380(%S)" pos))
   9494            (cond
   9495              ((and (eq prev-char ?\))
   9496                    (string-match-p "^\\(for\\|if\\|while\\)[ ]*(" prev-line))
   9497               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9498               )
   9499              ((member language '("javascript" "jsx"))
   9500               (setq offset
   9501                     (+ (car (web-mode-javascript-indentation pos
   9502                                                              reg-col
   9503                                                              curr-indentation
   9504                                                              language
   9505                                                              reg-beg))
   9506                        web-mode-code-indent-offset))
   9507               )
   9508              (t
   9509               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9510               )
   9511              )
   9512            )
   9513 
   9514           ((and (member language '("php" "blade")) (string-match-p "^->" curr-line))
   9515            (when debug (message "I390(%S) block-calls" pos))
   9516            (cond
   9517              ((not (web-mode-block-calls-beginning pos reg-beg))
   9518               )
   9519              ((cdr (assoc "lineup-calls" web-mode-indentation-params))
   9520               ;;(message "point=%S" (point))
   9521               (if (looking-back "::[ ]*" (point-min))
   9522                   (progn
   9523                     (re-search-backward "::[ ]*")
   9524                     (setq offset (current-column))
   9525                     ;;(message "ici%S offset=%S" (point) offset)
   9526                     )
   9527                   (search-forward "->")
   9528                   (setq offset (- (current-column) 2)))
   9529               )
   9530              (t
   9531               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9532              ))
   9533 
   9534           ((and is-js (member ?\, chars))
   9535            (when debug (message "I400(%S) part-args" pos))
   9536            (cond
   9537              ((not (web-mode-part-args-beginning pos reg-beg))
   9538               ;;(message "ici")
   9539               )
   9540              ((cdr (assoc "lineup-args" web-mode-indentation-params))
   9541               (setq offset (current-column))
   9542               ;;(message "offset=%S" offset)
   9543               (when (eq curr-char ?\,)
   9544                 (goto-char pos)
   9545                 (looking-at ",[ \t\n]*")
   9546                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9547               )
   9548              (t
   9549               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9550              ))
   9551 
   9552           ((member ?\, chars)
   9553            (when debug (message "I401(%S) block-args" pos))
   9554            (cond
   9555              ((not (web-mode-block-args-beginning pos reg-beg))
   9556               ;;(message "ici")
   9557               )
   9558              ((cdr (assoc "lineup-args" web-mode-indentation-params))
   9559               (setq offset (current-column))
   9560               ;;(message "offset=%S" offset)
   9561               (when (eq curr-char ?\,)
   9562                 (goto-char pos)
   9563                 (looking-at ",[ \t\n]*")
   9564                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9565               )
   9566              (t
   9567               (setq offset (current-column))
   9568               ;;(message "point=%S offset=%S" (point) offset)
   9569               (if (looking-back "[ ]+" (point-min))
   9570                   (progn
   9571                     (setq offset (current-indentation)))
   9572                 (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9573               ;;(when (eq curr-char ?\,)
   9574               ;;  (goto-char pos)
   9575               ;;  (looking-at ",[ \t\n]*")
   9576               ;;  (setq offset (- offset (length (match-string-no-properties 0)))))
   9577               ;;(setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9578               ) ;t
   9579              ))
   9580 
   9581 
   9582           ((and (string= language "php") (member ?\. chars))
   9583            (when debug (message "I410(%S) block-string" pos))
   9584            (cond
   9585              ((not (web-mode-block-string-beginning pos reg-beg))
   9586               )
   9587              ((null (cdr (assoc "lineup-concats" web-mode-indentation-params)))
   9588               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9589              ((not (eq curr-char ?\.))
   9590               (setq offset (current-column)))
   9591              (t
   9592               (setq offset (current-column))
   9593               (goto-char pos)
   9594               (when (cdr (assoc "lineup-quotes" web-mode-indentation-params))
   9595                 (looking-at "\\.[ \t\n]*")
   9596                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9597               )))
   9598 
   9599           ((member language '("javascript" "jsx" "ejs" "underscore"))
   9600            (when debug (message "I420(%S) javascript-indentation" pos))
   9601            (setq offset (car (web-mode-javascript-indentation pos
   9602                                                               reg-col
   9603                                                               curr-indentation
   9604                                                               language
   9605                                                               reg-beg))))
   9606 
   9607           (t
   9608            (when debug (message "I430(%S) bracket-indentation" pos))
   9609            (setq offset (car (web-mode-bracket-indentation pos
   9610                                                            reg-col
   9611                                                            curr-indentation
   9612                                                            language
   9613                                                            reg-beg))))
   9614 
   9615           ) ;cond
   9616 
   9617         (when (and offset reg-col adjust (< offset reg-col)) (setq offset reg-col))
   9618 
   9619         ) ;let
   9620       ) ;save-excursion
   9621 
   9622     (when offset
   9623       ;;(message "offset=%S" offset)
   9624       (let ((diff (- (current-column) (current-indentation))))
   9625         (when (not (= offset (current-indentation)))
   9626           (setq web-mode-change-beg (line-beginning-position)
   9627                 web-mode-change-end (+ web-mode-change-beg offset)))
   9628         (setq offset (max 0 offset))
   9629         (indent-line-to offset)
   9630         (if (> diff 0) (move-to-column (+ (current-column) diff)))
   9631         (when (and (string= web-mode-engine "mason")
   9632                    (= offset 0)
   9633                    (eq char ?\%))
   9634           (save-excursion
   9635             (font-lock-fontify-region (line-beginning-position) (line-end-position)))
   9636           ) ;when
   9637         ) ;let
   9638       ) ;when
   9639 
   9640     ))
   9641 
   9642 (defun web-mode-bracket-level (pos limit)
   9643   (save-excursion
   9644     (let ((continue t)
   9645           (regexp "[\]\[}{)(]")
   9646           (char nil)
   9647           (map nil)
   9648           (key nil)
   9649           (value 0)
   9650           (open '(?\( ?\{ ?\[)))
   9651       (goto-char pos)
   9652       (while (and continue (re-search-backward regexp limit t))
   9653         (setq char (aref (match-string-no-properties 0) 0))
   9654         (setq key (cond ((eq char ?\)) ?\()
   9655                         ((eq char ?\}) ?\{)
   9656                         ((eq char ?\]) ?\[)
   9657                         (t             char)))
   9658         (setq value (or (plist-get map key) 0))
   9659         (setq value (if (member char open) (1+ value) (1- value)))
   9660         (setq map (plist-put map key value))
   9661         (setq continue (< value 1))
   9662         ;;(message "pos=%S char=%c key=%c value=%S" (point) char key value)
   9663         ) ;while
   9664       (if (>= value 1) (current-indentation) nil)
   9665       )))
   9666 
   9667 (defun web-mode-token-html-indentation (pos)
   9668   (save-excursion
   9669     (let (beg (continue t) end level map offset regexp tag val void (css-beg 0))
   9670       (goto-char pos)
   9671       ;;(message "pos=%S" pos)
   9672       (setq beg (web-mode-part-token-beginning-position pos))
   9673       (save-excursion
   9674         (when (and (> (- pos beg) 5)
   9675                    (re-search-backward "</?[a-zA-Z0-9]+" beg t)
   9676                    (string= "<style" (downcase (match-string-no-properties 0))))
   9677           (setq css-beg (point))
   9678           )
   9679         )
   9680       ;;(message "beg=%S" beg)
   9681       (cond
   9682         ((eq (char-after pos) ?\`)
   9683          (setq offset (web-mode-indentation-at-pos beg)))
   9684         ((web-mode-looking-back "`[ \n\t]*" pos)
   9685          (setq offset (+ (web-mode-indentation-at-pos beg) web-mode-markup-indent-offset)))
   9686         ((looking-at "</\\([a-zA-Z0-9]+\\)")
   9687          (setq tag (match-string-no-properties 1)
   9688                regexp (concat "</?" tag)
   9689                level -1)
   9690          (while (and continue (re-search-backward regexp beg t))
   9691            (cond
   9692              ((eq (aref (match-string-no-properties 0) 1) ?\/)
   9693               (setq level (1- level)))
   9694              (t
   9695               (setq level (1+ level)))
   9696              ) ;cond
   9697            (when (= level 0)
   9698              (setq continue nil
   9699                    offset (current-indentation)))
   9700            ) ;while
   9701          )
   9702         ((> css-beg 0)
   9703          ;;(message "CSS")
   9704          (cond
   9705            ((member (char-after) '(?\) ?\} ?\]))
   9706             (web-mode-go (web-mode-token-opening-paren-position pos (+ css-beg 8) ""))
   9707             (setq offset (current-indentation))
   9708             )
   9709            ((setq level (web-mode-bracket-level pos (+ css-beg 8)))
   9710             (setq offset (+ level web-mode-css-indent-offset))
   9711             )
   9712            (t
   9713             (setq offset (+ (web-mode-indentation-at-pos css-beg) web-mode-style-padding))
   9714             ) ;t
   9715            )
   9716          )
   9717         ((looking-at "[a-zA-Z-]+[ ]?=")
   9718          (re-search-backward "<[a-zA-Z]+[ ]*" beg t)
   9719          (setq offset (+ (current-column) (length (match-string-no-properties 0))))
   9720          )
   9721         ((looking-at-p "/>")
   9722          (search-backward "<" beg t)
   9723          (setq offset (current-column))
   9724          )
   9725         (t
   9726          (setq regexp "</?\\([a-zA-Z0-9]+\\)")
   9727          ;;(message "point=%S" (point))
   9728          (while (and continue (re-search-backward regexp beg t))
   9729            (setq tag (downcase (match-string-no-properties 1))
   9730                  end nil
   9731                  void nil)
   9732            (cond
   9733              ((eq (aref (match-string-no-properties 0) 1) ?/)
   9734               (setq end t))
   9735              ((web-mode-element-is-void tag)
   9736               (setq void t))
   9737              (t
   9738               (save-excursion
   9739                 (when (and (search-forward ">" pos t) (eq (char-before (1- (point))) ?\/))
   9740                   (setq void t))
   9741                 ) ;save-excursion
   9742               ) ;t
   9743              ) ;cond
   9744            (unless void
   9745              (setq val (or (lax-plist-get map tag) 0))
   9746              (setq val (if end (1- val) (1+ val)))
   9747              (setq map (lax-plist-put map tag val))
   9748              ;;(message "val=%S tag=%S end=%S | %S" val tag end (plist-get map tag))
   9749              (setq continue (not (> val 0)))
   9750              ) ;unless
   9751                                         ;(message "pos=%S tag=%S val=%S end=%S void=%S" (point) tag val end void)
   9752            ) ;while
   9753          (cond
   9754            ((> val 0)
   9755             ;;(message "point=%S" (point))
   9756             ;;(goto-char (1+ beg))
   9757             ;;(forward-char)
   9758             ;;(re-search-forward "[[:space:]]*")
   9759             (setq offset (+ (current-indentation) web-mode-markup-indent-offset)))
   9760            (t
   9761             (setq offset (current-indentation)))
   9762            )
   9763          ) ;t
   9764         ) ;cond
   9765       offset)))
   9766 
   9767 (defun web-mode-token-css-indentation (pos)
   9768   (save-excursion
   9769     (goto-char pos)
   9770     (web-mode-part-token-beginning)
   9771     (+ web-mode-css-indent-offset (current-indentation))
   9772     ))
   9773 
   9774 (defun web-mode-relayql-indentation (pos &optional prefix)
   9775   (unless prefix (setq prefix "relayql"))
   9776   (let (beg offset level char)
   9777     (setq char (char-after))
   9778     (setq beg (web-mode-part-token-beginning-position pos))
   9779     (goto-char beg)
   9780     (cond
   9781       ((member char '(?\`))
   9782        (setq offset (current-indentation))
   9783        )
   9784       ((member char '(?\) ?\} ?\]))
   9785        (web-mode-go (web-mode-token-opening-paren-position pos beg prefix))
   9786        (setq offset (current-indentation))
   9787        )
   9788       ((setq level (web-mode-bracket-level pos beg))
   9789        (setq offset (+ level web-mode-code-indent-offset))
   9790        )
   9791       (t
   9792        (setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9793        )
   9794       )
   9795     offset))
   9796 
   9797 (defun web-mode-markup-indentation (pos)
   9798   (let (offset beg ret jsx-depth)
   9799     (when (and (setq jsx-depth (get-text-property pos 'jsx-depth))
   9800                (get-text-property pos 'jsx-beg)
   9801                (not (get-text-property pos 'tag-beg)))
   9802       (setq jsx-depth (1- jsx-depth)))
   9803     ;;(when (setq beg (web-mode-markup-indentation-origin pos jsx-depth))
   9804     (cond
   9805       ((not (setq beg (web-mode-markup-indentation-origin pos jsx-depth)))
   9806        (setq offset 0))
   9807       ((null (setq ret (web-mode-element-is-opened beg pos)))
   9808        (setq offset (web-mode-indentation-at-pos beg)))
   9809       ((eq ret t)
   9810        (setq offset (+ (web-mode-indentation-at-pos beg)
   9811                        web-mode-markup-indent-offset)))
   9812       (t
   9813        (setq offset ret))
   9814       ) ;cond
   9815     ;;(message "markup-indentation-origin=%S (jsx-depth=%S)" beg jsx-depth)
   9816     ;;) ;when beg
   9817     offset))
   9818 
   9819 (defun web-mode-css-indentation (pos initial-column language-offset language &optional limit)
   9820   (let ((open-ctx (web-mode-bracket-up pos language limit)) offset)
   9821     (cond
   9822       ((or (null open-ctx) (null (plist-get open-ctx :pos)))
   9823        (setq offset initial-column))
   9824       (t
   9825        (setq offset (+ (plist-get open-ctx :indentation) language-offset)))
   9826       ) ;cond
   9827     (cons (if (< offset initial-column) initial-column offset) open-ctx)
   9828     ))
   9829 
   9830 (defun web-mode-sql-indentation (pos initial-column language-offset language &optional limit)
   9831   (let ((open-ctx (web-mode-bracket-up pos language limit)) offset)
   9832     ;;(message "%S %S %S %S %S" pos (point) initial-column language-offset open-ctx)
   9833     (cond
   9834       ((and (not (null open-ctx)) (not (null (plist-get open-ctx :pos))))
   9835        (setq offset (+ (plist-get open-ctx :column) 1)))
   9836       ((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\\)")
   9837        (setq offset initial-column))
   9838       (t
   9839        (setq offset (+ initial-column language-offset)))
   9840       ) ;cond
   9841     (cons (if (< offset initial-column) initial-column offset) open-ctx)
   9842     ))
   9843 
   9844 (defun web-mode-markdown-indentation (pos initial-column _language-offset _language &optional _limit)
   9845   (let (offset)
   9846     (save-excursion
   9847       (goto-char pos)
   9848       (setq offset (current-column))
   9849       ) ;save-excursion
   9850     ;;(message "%S %S %S %S" pos (point) initial-column language-offset)
   9851     (cons (if (<= offset initial-column) initial-column offset) nil)))
   9852 
   9853 (defun web-mode-stylus-indentation (pos initial-column language-offset _language &optional _limit)
   9854   (let (offset)
   9855     (save-excursion
   9856       (goto-char pos)
   9857       (setq offset (current-column))
   9858       (if (looking-at-p "[[:alnum:]-]+:")
   9859           (setq offset (+ initial-column language-offset))
   9860           (setq offset initial-column))
   9861       ) ;save-excursion
   9862     ;;(message "%S %S %S %S" pos (point) initial-column language-offset)
   9863     (cons (if (<= offset initial-column) initial-column offset) nil)))
   9864 
   9865 (defun web-mode-sass-indentation (pos initial-column language-offset _language &optional _limit)
   9866   (let (offset)
   9867     (save-excursion
   9868       (goto-char pos)
   9869       (setq offset (current-column))
   9870       (if (looking-at-p "[[:alnum:]-]+:")
   9871           (setq offset (+ initial-column language-offset))
   9872           (setq offset initial-column))
   9873       ) ;save-excursion
   9874     ;;(message "%S %S %S %S" pos (point) initial-column language-offset)
   9875     (cons (if (<= offset initial-column) initial-column offset) nil)))
   9876 
   9877 (defun web-mode-pug-indentation (_pos _initial-column _language-offset _language &optional _limit)
   9878   nil
   9879   )
   9880 
   9881 (defun web-mode-javascript-indentation (pos initial-column language-offset language &optional limit)
   9882   (let (open-ctx open-pos indentation offset sub block-pos)
   9883     (setq open-ctx (web-mode-bracket-up pos language limit))
   9884     ;;(message "%S" open-ctx)
   9885     ;;(message "pos(%S) initial-column(%S) language-offset(%S) language(%S) limit(%S)" pos initial-column language-offset language limit)
   9886     ;;(message "javascript-indentation: %S\nchar=%c" open-ctx (plist-get open-ctx :char))
   9887     (setq indentation (plist-get open-ctx :indentation))
   9888     (when (and initial-column (> initial-column indentation))
   9889       (setq indentation initial-column))
   9890     (setq case-fold-search nil) ;#1006
   9891     (when open-ctx
   9892       (setq open-pos (plist-get open-ctx :pos)))
   9893     (setq block-pos (web-mode-inside-block-control pos))
   9894     (when (and block-pos (> limit block-pos)) ;#1275
   9895       (setq block-pos nil))
   9896     ;;(message "bracket-pos=%S block-pos=%S" open-pos block-pos)
   9897     (cond
   9898       ((and block-pos (or (null open-pos) (> block-pos open-pos))) ;#1230
   9899        (setq offset (+ indentation language-offset)))
   9900       ((null open-pos)
   9901        (setq offset initial-column))
   9902       ((and (member language '("javascript" "jsx" "ejs"))
   9903             (eq (plist-get open-ctx :char) ?\{)
   9904             (web-mode-looking-back "switch[ ]*" (plist-get open-ctx :pos)))
   9905        (setq sub (if (cdr (assoc "case-extra-offset" web-mode-indentation-params)) 0 1))
   9906        (cond
   9907          ((looking-at-p "case\\|default")
   9908           (setq offset (+ indentation (* language-offset (- 1 sub)))))
   9909          (t
   9910           (setq offset (+ indentation (* language-offset (- 2 sub)))))
   9911          ) ;cond switch
   9912        )
   9913       (t
   9914        (setq offset (+ indentation language-offset)))
   9915       ) ;cond
   9916     (setq case-fold-search t)
   9917     (cons (if (< offset initial-column) initial-column offset) open-ctx)
   9918     ))
   9919 
   9920 (defun web-mode-bracket-indentation (pos initial-column language-offset language &optional limit)
   9921   (save-excursion
   9922     (let* ((ctx (web-mode-bracket-up pos language limit))
   9923            (char (plist-get ctx :char))
   9924            (pos (plist-get ctx :pos))
   9925            (indentation (plist-get ctx :indentation)))
   9926       ;;(message "pos(%S) initial-column(%S) language-offset(%S) language(%S) limit(%S)" pos initial-column language-offset language limit)
   9927       ;;(message "bracket-up: %S, %c" ctx char)
   9928       (cond
   9929         ((null pos)
   9930          (setq indentation initial-column))
   9931         ((and (member language '("php"))
   9932               (eq char ?\{)
   9933               (web-mode-looking-back "switch[ ]*" pos)
   9934               (not (looking-at-p "case\\|default")))
   9935          (setq indentation (+ indentation (* language-offset 2)))
   9936          )
   9937         ((and (member language '("php"))
   9938               (eq char ?\{)
   9939               (goto-char pos)
   9940               (web-mode-looking-back "[)][ ]*" pos)
   9941               (search-backward ")")
   9942               (web-mode-block-opening-paren limit))
   9943          (setq indentation (+ (current-indentation) language-offset))
   9944          )
   9945         (t
   9946          (setq indentation (+ indentation language-offset))
   9947          )
   9948         ) ;cond
   9949       (cons (if (< indentation initial-column) initial-column indentation) ctx)
   9950       )))
   9951 
   9952 (defun web-mode-ruby-indentation (pos line initial-column language-offset limit)
   9953   (unless limit (setq limit nil))
   9954   (let (h offset prev-line prev-indentation open-ctx)
   9955     (setq open-ctx (web-mode-bracket-up pos "ruby" limit))
   9956     ;;(message "%S" open-ctx)
   9957     (if (plist-get open-ctx :pos)
   9958         (cond
   9959           ((web-mode-looking-at-p ".[ \t\n]+" (plist-get open-ctx :pos))
   9960            (setq offset (+ (plist-get open-ctx :indentation) language-offset)))
   9961           (t
   9962            (setq offset (1+ (plist-get open-ctx :column))))
   9963           )
   9964         (setq h (web-mode-previous-line pos limit))
   9965         (setq offset initial-column)
   9966         (when h
   9967           (setq prev-line (car h))
   9968           (setq prev-indentation (cdr h))
   9969           (cond
   9970             ((string-match-p ",$" prev-line)
   9971              (save-excursion
   9972                (goto-char limit)
   9973                (looking-at "<%=? [a-z_]+ ")
   9974                (setq offset (+ initial-column (length (match-string-no-properties 0))))
   9975                ) ;save-excursion
   9976              )
   9977             ((string-match-p "^[ ]*\\(end\\|else\\|elsif\\|when\\)" line)
   9978              (setq offset (- prev-indentation language-offset))
   9979              )
   9980             ((string-match-p "[ ]+\\(do\\)" prev-line)
   9981              (setq offset (+ prev-indentation language-offset))
   9982              )
   9983             ((string-match-p "^[ ]*\\(when\\|if\\|else\\|elsif\\|unless\\|for\\|while\\|def\\|class\\)" prev-line)
   9984              (setq offset (+ prev-indentation language-offset))
   9985              )
   9986             (t
   9987              (setq offset prev-indentation)
   9988              )
   9989             )
   9990           ) ;when
   9991         ) ;if
   9992     offset))
   9993 
   9994 (defun web-mode-python-indentation (pos line initial-column language-offset limit)
   9995   (unless limit (setq limit nil))
   9996   (let (h offset prev-line prev-indentation ctx)
   9997     (setq ctx (web-mode-bracket-up pos "python" limit))
   9998     ;;(message "point-ctx=%S" ctx)
   9999     (if (plist-get ctx :pos)
  10000         (cond
  10001           ((web-mode-looking-at-p ".[ \t\n]+" (plist-get ctx :pos))
  10002            (setq offset (+ (plist-get ctx :indentation) language-offset)))
  10003           (t
  10004            (setq offset (1+ (plist-get ctx :column))))
  10005           )
  10006         ;; else
  10007         (setq h (web-mode-previous-line pos limit))
  10008         (setq offset initial-column)
  10009         (when h
  10010           (setq prev-line (car h))
  10011           (setq prev-indentation (cdr h))
  10012           (cond
  10013             ((string-match-p "^\\(pass\\|else\\|elif\\|when\\|except\\)" line)
  10014              (setq offset (- prev-indentation language-offset))
  10015              )
  10016             ((string-match-p "\\(if\\|else\\|elif\\|for\\|while\\|try\\|except\\)" prev-line)
  10017              (setq offset (+ prev-indentation language-offset))
  10018              )
  10019             (t
  10020              (setq offset prev-indentation)
  10021              )
  10022             ) ;cond
  10023           ) ;when
  10024         ) ;if
  10025     ;;offset
  10026     (if (< offset initial-column) initial-column offset)
  10027     ))
  10028 
  10029 (defun web-mode-lisp-indentation (pos point-ctx)
  10030   (let (offset open-ctx)
  10031     (setq open-ctx (web-mode-bracket-up pos "lsp" (plist-get point-ctx :reg-beg)))
  10032     ;;(message "point-ctx=%S" point-ctx)
  10033     ;;(message "open-ctx=%S" open-ctx)
  10034     (cond
  10035       ((null (plist-get open-ctx :pos))
  10036        (setq offset (plist-get point-ctx :reg-col)))
  10037       ((member (plist-get point-ctx :curr-char) '(?\( ?\)))
  10038        (if (web-mode-looking-at-p "((" (plist-get open-ctx :pos))
  10039            (setq offset (+ (plist-get open-ctx :column) 1))
  10040            (setq offset (+ (plist-get open-ctx :column) web-mode-code-indent-offset)))
  10041        )
  10042       (t
  10043        (goto-char (plist-get open-ctx :pos))
  10044        (forward-char)
  10045        (web-mode-rsf "[[:alnum:]-:]+ ")
  10046        (setq offset (current-column))
  10047        )
  10048       ) ;cond
  10049     offset))
  10050 
  10051 (defun web-mode-asp-indentation (pos line initial-column language-offset limit)
  10052   (unless limit (setq limit nil))
  10053   (let (h out prev-line prev-indentation)
  10054     (setq h (web-mode-previous-line pos limit))
  10055     (setq out initial-column)
  10056     (when h
  10057       (setq prev-line (car h))
  10058       (setq prev-indentation (cdr h))
  10059       ;;(message "line=%S" line)
  10060       (cond
  10061         ((string-match-p "'" line)
  10062          (setq out prev-indentation))
  10063         ;; ----------------------------------------------------------------------
  10064         ;; unindent
  10065         ((string-match-p "\\_<\\(\\(end \\(if\\|function\\|class\\|sub\\|with\\)\\)\\|else\\|elseif\\|next\\|loop\\)\\_>" line)
  10066          (setq out (- prev-indentation language-offset)))
  10067         ;; ----------------------------------------------------------------------
  10068         ;; select case statement
  10069         ((string-match-p "\\_<\\(select case\\)\\_>" line)
  10070          (setq out (- prev-indentation 0)))
  10071         ((string-match-p "\\_<\\(end select\\)" line)
  10072          (setq out (- prev-indentation (* 2 language-offset))))
  10073         ((and (string-match-p "\\_<\\(case\\)\\_>" line) (not (string-match-p "\\_<\\(select case\\)\\_>" prev-line)))
  10074          (setq out (- prev-indentation language-offset)))
  10075         ;; ----------------------------------------------------------------------
  10076         ;; do nothing
  10077         ((string-match-p "\\_<\\(\\(end \\(if\\|function\\|class\\|sub\\|select\\|with\\)\\)\\|loop\\( until\\| while\\)?\\)\\_>" prev-line)
  10078          (setq out (+ prev-indentation 0)))
  10079         ;; indent
  10080         ((string-match-p "\\_<\\(\\(select \\)?case\\|else\\|elseif\\|unless\\|for\\|class\\|with\\|do\\( until\\| while\\)?\\|while\\|\\(public \\|private \\)?\\(function\\|sub\\|class\\)\\)\\_>" prev-line)
  10081          (setq out (+ prev-indentation language-offset)))
  10082         ;; single line if statement
  10083         ((string-match-p "\\_<if\\_>.*\\_<then\\_>[ \t]*[[:alpha:]]+" prev-line)
  10084          (setq out (+ prev-indentation 0)))
  10085         ;; normal if statement
  10086         ((string-match-p "\\_<\\if\\_>" prev-line)
  10087          (setq out (+ prev-indentation language-offset)))
  10088         (t
  10089          (setq out prev-indentation))
  10090         )
  10091       ) ;when
  10092     out))
  10093 
  10094 (defun web-mode-block-previous-live-line ()
  10095   (save-excursion
  10096     (let ((continue t) (line "") (pos (point)))
  10097       (beginning-of-line)
  10098       (while (and continue (not (bobp)) (forward-line -1))
  10099         (when (not (web-mode-block-is-token-line))
  10100           (setq line (web-mode-trim (buffer-substring (point) (line-end-position)))))
  10101         (when (not (string= line ""))
  10102           (setq continue nil))
  10103         ) ;while
  10104       (if (string= line "")
  10105           (progn (goto-char pos) nil)
  10106           (list line (current-indentation) pos (line-end-position)))
  10107       )))
  10108 
  10109 (defun web-mode-part-is-opener (pos reg-beg)
  10110   (save-excursion
  10111     (save-match-data
  10112       (if (and pos
  10113                (web-mode-go (web-mode-part-opening-paren-position pos))
  10114                (>= (point) reg-beg)
  10115                (looking-back "\\(^\\|[ \t]\\)\\(if\\|for\\|while\\)[ ]*" (point-min)))
  10116           (current-indentation)
  10117           nil)
  10118       )))
  10119 
  10120 (defun web-mode-part-previous-live-line (reg-beg)
  10121   (unless reg-beg (setq reg-beg (point-min)))
  10122   ;;(message "reg-beg=%S" reg-beg)
  10123   (save-excursion
  10124     (let ((continue (> (point) reg-beg))
  10125           (line "")
  10126           bol-pos
  10127           eol-pos
  10128           pos)
  10129       (beginning-of-line)
  10130       (while (and continue (> (point) reg-beg) (forward-line -1))
  10131         (setq bol-pos (point)
  10132               eol-pos (line-end-position))
  10133         (when (> reg-beg bol-pos)
  10134           (setq bol-pos reg-beg))
  10135         (when (not (web-mode-part-is-token-line bol-pos))
  10136           (setq line (web-mode-trim (buffer-substring bol-pos eol-pos)))
  10137           (when (not (string= line "")) (setq continue nil))
  10138           ) ;when
  10139         ) ;while
  10140       (cond
  10141         ((string= line "")
  10142          nil)
  10143         (t
  10144          (setq continue t)
  10145          (setq pos (1- eol-pos))
  10146          (while (and (>= pos bol-pos) continue)
  10147            (cond
  10148              ((eq (char-after pos) ?\s)
  10149               (setq pos (1- pos)))
  10150              ((get-text-property pos 'part-token)
  10151               (setq pos (1- pos)))
  10152              (t
  10153               (setq continue nil))
  10154              ) ;cond
  10155            ) ;while
  10156          ;;(message "%S %S : %S" bol-pos eol-pos pos)
  10157          (setq line (web-mode-clean-part-line line))
  10158          (list line (current-indentation) pos (line-end-position)))
  10159         ) ;cond
  10160       )))
  10161 
  10162 (defun web-mode-in-code-block (open close &optional prop)
  10163   (save-excursion
  10164     (let ((pos (point)) pos-open pos-close start end ret)
  10165       (when prop
  10166         (setq start pos
  10167               end pos)
  10168         (when (eq (get-text-property pos prop) (get-text-property (1- pos) prop))
  10169           (setq start (or (previous-single-property-change pos prop) (point-min))))
  10170         (when (eq (get-text-property pos prop) (get-text-property (1+ pos) prop))
  10171           (setq end (next-single-property-change pos prop)))
  10172         ;;        (message "start(%S) end(%S)" start end)
  10173         )
  10174       (setq ret (and (web-mode-sb open start t)
  10175                      (setq pos-open (point))
  10176                      (web-mode-sf close end t)
  10177                      (setq pos-close (point))
  10178                      (>= pos-close pos)))
  10179       (if ret
  10180           (cons pos-open pos-close)
  10181           ret)
  10182       )))
  10183 
  10184 (defun web-mode-clean-part-line (input)
  10185   (let ((out "")
  10186         (beg 0)
  10187         (keep t)
  10188         (n (length input)))
  10189     (dotimes (i n)
  10190       (if (or (get-text-property i 'block-side input)
  10191               (eq (get-text-property i 'part-token input) 'comment)
  10192               (eq (get-text-property i 'tag-type input) 'comment))
  10193           (when keep
  10194             (setq out (concat out (substring input beg i))
  10195                   beg 0
  10196                   keep nil))
  10197           (when (null keep)
  10198             (setq beg i
  10199                   keep t))
  10200           ) ;if
  10201       ) ;dotimes
  10202     (if (> beg 0) (setq out (concat out (substring input beg n))))
  10203     (setq out (if (= (length out) 0) input out))
  10204     (web-mode-trim out)
  10205     ))
  10206 
  10207 (defun web-mode-clean-block-line (input)
  10208   (let ((out "")
  10209         (beg 0)
  10210         (keep t)
  10211         (n (length input)))
  10212     (dotimes (i n)
  10213       (if (or (not (get-text-property i 'block-side input))
  10214               (member (get-text-property i 'block-token input)
  10215                       '(comment delimiter-beg delimiter-end)))
  10216           (when keep
  10217             (setq out (concat out (substring input beg i))
  10218                   beg 0
  10219                   keep nil))
  10220           (when (null keep)
  10221             (setq beg i
  10222                   keep t))
  10223           ) ;if
  10224       ) ;dotimes
  10225     (if (> beg 0) (setq out (concat out (substring input beg n))))
  10226     (setq out (if (= (length out) 0) input out))
  10227     (web-mode-trim out)
  10228     ;;    (message "%S [%s] > [%s]" beg input out)
  10229     ))
  10230 
  10231 (defun web-mode-language-at-pos (&optional pos)
  10232   (unless pos (setq pos (point)))
  10233   (cond
  10234     ((get-text-property pos 'block-side)
  10235      web-mode-engine)
  10236     ((get-text-property pos 'part-side)
  10237      (symbol-name (get-text-property pos 'part-side)))
  10238     (t
  10239      web-mode-content-type)
  10240     ) ;cond
  10241   )
  10242 
  10243 (defun web-mode-coord-position (line column)
  10244   (save-excursion
  10245     (when (stringp line) (setq line (string-to-number line)))
  10246     (when (stringp column) (setq column (string-to-number column)))
  10247     (goto-char (point-min))
  10248     (forward-line (1- line))
  10249     (move-to-column (1- column))
  10250     (point)))
  10251 
  10252 (defun web-mode-is-single-line-block (pos)
  10253   (= (web-mode-line-number (web-mode-block-beginning-position pos))
  10254      (web-mode-line-number (web-mode-block-end-position pos))))
  10255 
  10256 (defun web-mode-line-number (&optional pos)
  10257   (setq pos (or pos (point)))
  10258   (+ (count-lines 1 pos) (if (= (web-mode-column-at-pos pos) 0) 1 0)))
  10259 
  10260 (defun web-mode-block-is-control (pos)
  10261   (save-excursion
  10262     (let (control state controls pair)
  10263       (goto-char pos)
  10264       (setq controls (web-mode-block-controls-get pos))
  10265       (setq pair (car controls))
  10266       (cond
  10267         ((eq (car pair) 'inside)
  10268          )
  10269         ((eq (car pair) 'open)
  10270          (setq state t
  10271                control (cdr pair)))
  10272         ((eq (car pair) 'close)
  10273          (setq state nil
  10274                control (cdr pair)))
  10275         ) ;cond
  10276       ;;      (message "engine=%S control=%S state=%S" web-mode-engine control state)
  10277       (if control (cons control state) nil)
  10278       )))
  10279 
  10280 (defun web-mode-block-is-opening-control (pos)
  10281   (save-excursion
  10282     (let (controls pair)
  10283       (goto-char pos)
  10284       (if (and (setq controls (web-mode-block-controls-get pos))
  10285                (= (length controls) 1)
  10286                (setq pair (car controls))
  10287                (eq (car pair) 'open))
  10288           (cdr pair)
  10289           nil)
  10290       )))
  10291 
  10292 (defun web-mode-markup-indentation-origin (pos jsx-depth)
  10293   (save-excursion
  10294     (let* ((found (bobp))
  10295            (jsx-beg nil)
  10296            (types '(start end void))
  10297            (type nil))
  10298       (when jsx-depth
  10299         (setq jsx-beg (web-mode-jsx-depth-beginning-position pos jsx-depth)))
  10300       (while (not found)
  10301         (forward-line -1)
  10302         (if (bobp)
  10303             (setq pos (point)
  10304                   found t)
  10305             (back-to-indentation)
  10306             (when (and jsx-beg (< (point) jsx-beg))
  10307               (goto-char jsx-beg))
  10308             (setq pos (point))
  10309             (setq type (get-text-property pos 'tag-type))
  10310             (setq found (or (and (null jsx-depth)
  10311                                  (null (get-text-property pos 'part-side))
  10312                                  (get-text-property pos 'tag-beg)
  10313                                  (member type types)
  10314                                  (null (get-text-property (1- pos) 'invisible)))
  10315                             (and (null jsx-depth)
  10316                                  (null (get-text-property pos 'part-side))
  10317                                  (eq (get-text-property pos 'tag-type) 'comment)
  10318                                  (web-mode-looking-at-p "<!--#\\(endif\\|if\\)" pos)
  10319                                  (null (get-text-property (1- pos) 'invisible)))
  10320                             (and jsx-depth
  10321                                  (get-text-property pos 'tag-beg)
  10322                                  (member type types)
  10323                                  (null (get-text-property (1- pos) 'invisible))
  10324                                  (eq (get-text-property pos 'jsx-depth) jsx-depth))
  10325                             (and (get-text-property pos 'block-beg)
  10326                                  (not type)
  10327                                  (web-mode-block-is-control pos)
  10328                                  (not (looking-at-p "{% commen\\|@break")))))
  10329             ) ;if
  10330         ) ;while
  10331       ;;(message "indent-origin=%S" pos)
  10332       pos)))
  10333 
  10334 ;;TODO : prendre en compte part-token
  10335 ;; state=t <=> start tag
  10336 (defun web-mode-element-is-opened (pos limit)
  10337   (let (tag
  10338         last-end-tag
  10339         tag-pos block-pos
  10340         state
  10341         n
  10342         ret
  10343         (continue t)
  10344         controls
  10345         (h (make-hash-table :test 'equal))
  10346         (h2 (make-hash-table :test 'equal)))
  10347 
  10348     ;;    (message "pos-ori=%S limit=%S" pos limit)
  10349 
  10350     (while continue
  10351       (setq controls nil
  10352             last-end-tag nil
  10353             tag nil)
  10354 
  10355       (cond
  10356         ((and (eq (get-text-property pos 'tag-type) 'comment)
  10357               (web-mode-looking-at "<!--#\\(endif\\|if\\)" pos))
  10358          ;;(message "pos=%S" pos)
  10359          (setq tag "#if")
  10360          (setq n (gethash tag h 0))
  10361          (if (string= (match-string-no-properties 1) "if")
  10362              (puthash tag (1+ n) h)
  10363              (puthash tag (1- n) h))
  10364          ;;(setq tag-pos pos)
  10365          )
  10366         ((get-text-property pos 'tag-beg)
  10367          (when (member (get-text-property pos 'tag-type) '(start end))
  10368            (setq tag (get-text-property pos 'tag-name)
  10369                  state (eq (get-text-property pos 'tag-type) 'start))
  10370            (if (null state) (setq last-end-tag (cons tag pos)))
  10371            (setq n (gethash tag h 0))
  10372            (cond
  10373              ((null state)
  10374               (when (> n 0) (puthash tag (1- n) h))
  10375               (puthash tag (1- n) h2))
  10376              ((member tag web-mode-offsetless-elements)
  10377               )
  10378              (t
  10379               (puthash tag (1+ n) h)
  10380               (puthash tag (1+ n) h2))
  10381              ) ;cond
  10382            ) ;when
  10383          (when (setq pos (web-mode-tag-end-position pos))
  10384            (setq tag-pos nil)
  10385            (when (and block-pos (> pos block-pos))
  10386              (setq block-pos nil))
  10387            ) ;when
  10388          )
  10389         ((and web-mode-enable-control-block-indentation
  10390               (get-text-property pos 'block-beg))
  10391          (when (setq controls (web-mode-block-controls-get pos))
  10392            (dolist (control controls)
  10393              (setq tag (cdr control))
  10394              (setq n (gethash tag h 0))
  10395              (cond
  10396                ((eq (car control) 'inside)
  10397                 )
  10398                ((eq (car control) 'open)
  10399                 (puthash tag (1+ n) h))
  10400                ((> n 0)
  10401                 (puthash tag (1- n) h))
  10402                ) ;cond
  10403              ) ;dolist
  10404            )
  10405          (when (setq pos (web-mode-block-end-position pos))
  10406            (setq block-pos nil)
  10407            (when (and tag-pos (> pos tag-pos))
  10408              (setq tag-pos nil))
  10409            )
  10410          )
  10411         ) ;cond
  10412 
  10413       ;;      (message "tag=%S end-pos=%S" tag pos)
  10414 
  10415       (when (and pos (< pos limit))
  10416         (when (or (null tag-pos) (>= pos tag-pos))
  10417           (setq tag-pos (web-mode-tag-next-position pos limit))
  10418           ;;          (message "from=%S tag-next-pos=%S" pos tag-pos)
  10419           )
  10420         (when (or (null block-pos) (>= pos block-pos))
  10421           (setq block-pos (web-mode-block-next-position pos limit))
  10422           ;;          (message "from=%S block-next-pos=%S" pos block-pos)
  10423           )
  10424         )
  10425 
  10426       (cond
  10427         ((null pos)
  10428          )
  10429         ((and (null tag-pos)
  10430               (null block-pos))
  10431          (setq pos nil))
  10432         ((and tag-pos block-pos)
  10433          (if (< tag-pos block-pos)
  10434              (progn
  10435                (setq pos tag-pos)
  10436                (setq tag-pos nil))
  10437              (setq pos block-pos)
  10438              (setq block-pos nil))
  10439          )
  10440         ((null tag-pos)
  10441          (setq pos block-pos)
  10442          (setq block-pos nil))
  10443         (t
  10444          (setq pos tag-pos)
  10445          (setq tag-pos nil))
  10446         )
  10447 
  10448       (when (or (null pos)
  10449                 (>= pos limit))
  10450         (setq continue nil))
  10451       ) ;while
  10452 
  10453     ;;(message "hashtable=%S" h)
  10454     (maphash (lambda (_k v) (if (> v 0) (setq ret t))) h)
  10455 
  10456     (when (and (null ret)
  10457                last-end-tag
  10458                (> (hash-table-count h2) 1)
  10459                (< (gethash (car last-end-tag) h2) 0))
  10460       ;;      (message "last-end-tag=%S" last-end-tag)
  10461       (save-excursion
  10462         (goto-char (cdr last-end-tag))
  10463         (web-mode-tag-match)
  10464         (when (not (= (point) (cdr last-end-tag)))
  10465           (setq n (point))
  10466           (back-to-indentation)
  10467           (if (= n (point)) (setq ret (current-indentation))))
  10468         ))
  10469 
  10470     ret))
  10471 
  10472 (defun web-mode-previous-line (pos limit)
  10473   (save-excursion
  10474     (let (beg end line (continue t))
  10475       (goto-char pos)
  10476       (while continue
  10477         (forward-line -1)
  10478         (setq end (line-end-position))
  10479         (setq line (buffer-substring-no-properties (point) end))
  10480         (when (or (not (string-match-p "^[ \t]*$" line))
  10481                   (bobp)
  10482                   (<= (point) limit))
  10483           (setq continue nil))
  10484         )
  10485       (if (<= (point) limit)
  10486           ;;todo : affiner (le + 3 n est pas générique cf. <?php <% <%- etc.)
  10487           (setq beg (if (< (+ limit 3) end) (+ limit 3) end))
  10488           (setq beg (line-beginning-position))
  10489           ) ;if
  10490       (setq line (buffer-substring-no-properties beg end))
  10491       (cons line (current-indentation))
  10492       )))
  10493 
  10494 (defun web-mode-bracket-up (pos _language &optional limit)
  10495   (unless limit (setq limit nil))
  10496   ;;(message "pos(%S) language(%S) limit(%S)" pos language limit)
  10497   (save-excursion
  10498     (goto-char pos)
  10499     (let ((continue t)
  10500           (regexp "[\]\[}{)(]")
  10501           (char nil)
  10502           (column nil)
  10503           (indentation nil)
  10504           (map nil)
  10505           (key nil)
  10506           (value 0)
  10507           (open '(?\( ?\{ ?\[))
  10508           (searcher nil)
  10509           (opener nil))
  10510       (cond
  10511         ((get-text-property pos 'block-side)
  10512          (setq searcher 'web-mode-block-rsb
  10513                opener 'web-mode-block-opening-paren-position))
  10514         (t
  10515          (setq searcher 'web-mode-part-rsb
  10516                opener 'web-mode-part-opening-paren-position))
  10517         )
  10518       (while (and continue (funcall searcher regexp limit))
  10519         (setq char (aref (match-string-no-properties 0) 0))
  10520         (setq key (cond ((eq char ?\)) ?\()
  10521                         ((eq char ?\}) ?\{)
  10522                         ((eq char ?\]) ?\[)
  10523                         (t             char)))
  10524         (setq value (or (plist-get map key) 0))
  10525         (setq value (if (member char open) (1+ value) (1- value)))
  10526         (setq map (plist-put map key value))
  10527         (setq continue (< value 1))
  10528         ;;(message "pos=%S char=%c key=%c value=%S map=%S" (point) char key value map)
  10529         ) ;while
  10530       (setq column (current-column)
  10531             indentation (current-indentation))
  10532       (when (and (> value 0)
  10533                  (eq char ?\{)
  10534                  (looking-back ")[ ]*" (point-min)))
  10535         (search-backward ")")
  10536         (when (setq pos (funcall opener (point) limit))
  10537           (goto-char pos)
  10538           ;;(message "pos=%S" pos)
  10539           (setq indentation (current-indentation)))
  10540         ) ;when
  10541       (list :pos (if (> value 0) (point) nil)
  10542             :char char
  10543             :column column
  10544             :indentation indentation)
  10545       ) ;let
  10546     ))
  10547 
  10548 (defun web-mode-count-char-in-string (char string)
  10549   (let ((n 0))
  10550     (dotimes (i (length string))
  10551       (if (eq (elt string i) char)
  10552           (setq n (1+ n))))
  10553     n))
  10554 
  10555 (defun web-mode-mark-and-expand ()
  10556   "Mark and expand."
  10557   (interactive)
  10558   (web-mode-mark (point)))
  10559 
  10560 (defun web-mode-mark (pos)
  10561   (let ((beg pos) (end pos) boundaries)
  10562 
  10563     (if mark-active
  10564         (setq web-mode-expand-initial-pos (point)
  10565               web-mode-expand-initial-scroll (window-start))
  10566         )
  10567 
  10568     ;; (message "regs=%S %S %S %S" (region-beginning) (region-end) (point-min) (point-max))
  10569     ;; (message "before=%S" web-mode-expand-previous-state)
  10570 
  10571     (cond
  10572 
  10573       ((and mark-active
  10574             (= (region-beginning) (point-min))
  10575             (or (= (region-end) (point-max))
  10576                 (= (1+ (region-end)) (point-max))))
  10577        (deactivate-mark)
  10578        (goto-char (or web-mode-expand-initial-pos (point-min)))
  10579        (setq web-mode-expand-previous-state nil)
  10580        (when web-mode-expand-initial-scroll
  10581          (set-window-start (selected-window) web-mode-expand-initial-scroll))
  10582        )
  10583 
  10584       ((string= web-mode-expand-previous-state "elt-content")
  10585        (web-mode-element-parent)
  10586        ;;(message "pos=%S" (point))
  10587        (web-mode-element-select)
  10588        (setq web-mode-expand-previous-state "html-parent"))
  10589 
  10590       ((and (member (get-text-property pos 'block-token) '(comment string))
  10591             (not (member web-mode-expand-previous-state '("block-token" "block-body" "block-side"))))
  10592        (when (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token))
  10593          (setq beg (or (previous-single-property-change pos 'block-token) (point-min))))
  10594        (when (eq (get-text-property pos 'block-token) (get-text-property (1+ pos) 'block-token))
  10595          (setq end (next-single-property-change pos 'block-token)))
  10596        (set-mark beg)
  10597        (goto-char end)
  10598        (exchange-point-and-mark)
  10599        (setq web-mode-expand-previous-state "block-token"))
  10600 
  10601       ((and (get-text-property pos 'block-side)
  10602             (not (member web-mode-expand-previous-state '("block-body" "block-side")))
  10603             (not (member web-mode-engine '(django go)))
  10604             (setq boundaries (web-mode-in-code-block "{" "}" 'block-side)))
  10605        (set-mark (car boundaries))
  10606        (goto-char (cdr boundaries))
  10607        (exchange-point-and-mark)
  10608        (setq web-mode-expand-previous-state "block-body"))
  10609 
  10610       ((and (get-text-property pos 'block-side)
  10611             (not (member web-mode-expand-previous-state '("block-side"))))
  10612        (set-mark (web-mode-block-beginning-position pos))
  10613        (goto-char (1+ (web-mode-block-end-position pos)))
  10614        (exchange-point-and-mark)
  10615        (setq web-mode-expand-previous-state "block-side"))
  10616 
  10617       ((and (get-text-property pos 'part-token)
  10618             (not (string= web-mode-expand-previous-state "part-token")))
  10619        (when (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token))
  10620          (setq beg (previous-single-property-change pos 'part-token)))
  10621        (when (eq (get-text-property pos 'part-token) (get-text-property (1+ pos) 'part-token))
  10622          (setq end (next-single-property-change pos 'part-token)))
  10623        (set-mark beg)
  10624        (goto-char end)
  10625        (exchange-point-and-mark)
  10626        (setq web-mode-expand-previous-state "part-token"))
  10627 
  10628       ((and (get-text-property pos 'part-side)
  10629             (not (string= web-mode-expand-previous-state "client-part"))
  10630             (setq boundaries (web-mode-in-code-block "{" "}" 'part-side)))
  10631        (set-mark (car boundaries))
  10632        (goto-char (cdr boundaries))
  10633        (exchange-point-and-mark)
  10634        (setq web-mode-expand-previous-state "client-part"))
  10635 
  10636       ((and (get-text-property pos 'part-side)
  10637             (not (string= web-mode-expand-previous-state "part-side")))
  10638        (when (eq (get-text-property pos 'part-side) (get-text-property (1- pos) 'part-side))
  10639          (setq beg (previous-single-property-change pos 'part-side)))
  10640        (when (eq (get-text-property pos 'part-side) (get-text-property (1+ pos) 'part-side))
  10641          (setq end (next-single-property-change pos 'part-side)))
  10642        (when (eq (char-after beg) ?\n)
  10643          (setq beg (1+ beg)))
  10644        (set-mark beg)
  10645        (goto-char end)
  10646        (when (looking-back "^[ \t]+" (point-min))
  10647          (beginning-of-line))
  10648        (exchange-point-and-mark)
  10649        (setq web-mode-expand-previous-state "part-side"))
  10650 
  10651       ((and (get-text-property pos 'tag-attr)
  10652             (not (member web-mode-expand-previous-state '("html-attr" "html-tag"))))
  10653        (web-mode-attribute-select pos)
  10654        (setq web-mode-expand-previous-state "html-attr"))
  10655 
  10656       ((and (eq (get-text-property pos 'tag-type) 'comment)
  10657             (not (member web-mode-expand-previous-state '("html-tag" "html-comment" "html-elt" "html-parent"))))
  10658        (web-mode-tag-select)
  10659        (setq web-mode-expand-previous-state "html-comment"))
  10660 
  10661       ((and (get-text-property pos 'tag-name)
  10662             (not (member web-mode-expand-previous-state '("html-tag" "html-elt" "html-parent"))))
  10663        (web-mode-tag-select)
  10664        (setq web-mode-expand-previous-state "html-tag"))
  10665 
  10666       ((and (get-text-property pos 'tag-beg)
  10667             (string= web-mode-expand-previous-state "html-tag"))
  10668        (web-mode-element-select)
  10669        (setq web-mode-expand-previous-state "html-elt"))
  10670 
  10671       (t
  10672        (cond
  10673          ((not (web-mode-element-parent))
  10674           (push-mark (point))
  10675           (push-mark (point-max) nil t)
  10676           (goto-char (point-min))
  10677           (setq web-mode-expand-previous-state "mark-whole"))
  10678          ((not (= (web-mode-tag-end-position (point)) (1- beg)))
  10679           (web-mode-element-content-select)
  10680           (setq web-mode-expand-previous-state "elt-content"))
  10681          (t
  10682           (web-mode-element-select)
  10683           (setq web-mode-expand-previous-state "html-parent"))
  10684          )
  10685        ) ;t
  10686 
  10687       ) ;cond
  10688 
  10689     ;;(message "w=%S" (window-end))
  10690     ;;(message "after=%S" web-mode-expand-previous-state)
  10691 
  10692     ))
  10693 
  10694 (defun web-mode-block-kill ()
  10695   "Kill the current block."
  10696   (interactive)
  10697   (web-mode-block-select)
  10698   (when mark-active
  10699     (kill-region (region-beginning) (region-end))))
  10700 
  10701 (defun web-mode-block-select ()
  10702   "Select the current block."
  10703   (interactive)
  10704   (let (beg)
  10705     (when (setq beg (web-mode-block-beginning-position (point)))
  10706       (goto-char beg)
  10707       (set-mark (point))
  10708       (web-mode-block-end)
  10709       (exchange-point-and-mark))
  10710     beg))
  10711 
  10712 (defun web-mode-tag-select ()
  10713   "Select the current html tag."
  10714   (interactive)
  10715   (let (beg)
  10716     (when (setq beg (web-mode-tag-beginning-position (point)))
  10717       (goto-char beg)
  10718       (set-mark (point))
  10719       (web-mode-tag-end)
  10720       (exchange-point-and-mark))
  10721     beg))
  10722 
  10723 (defun web-mode-element-content-select ()
  10724   "Select the content of a html element."
  10725   (interactive)
  10726   (let (pos end)
  10727     (web-mode-element-select)
  10728     (when mark-active
  10729       (setq pos (point))
  10730       (deactivate-mark)
  10731       (web-mode-tag-match)
  10732       (setq end (point))
  10733       (goto-char pos)
  10734       (web-mode-tag-end)
  10735       (set-mark (point))
  10736       (goto-char end)
  10737       (exchange-point-and-mark)
  10738       )))
  10739 
  10740 (defun web-mode-element-select ()
  10741   "Select the current html element (including opening and closing tags)."
  10742   (interactive)
  10743   (let* ((pos (point))
  10744          (type (get-text-property pos 'tag-type)))
  10745     (cond
  10746       ((not type)
  10747        (web-mode-element-parent)
  10748        (unless (= (point) pos) (web-mode-element-select)))
  10749       ((member type '(start void))
  10750        (web-mode-tag-beginning)
  10751        (set-mark (point))
  10752        (web-mode-tag-match)
  10753        (web-mode-tag-end)
  10754        (exchange-point-and-mark))
  10755       (t
  10756        (web-mode-tag-match)
  10757        (set-mark (point))
  10758        (web-mode-tag-match)
  10759        (web-mode-tag-end)
  10760        (exchange-point-and-mark))
  10761       )))
  10762 
  10763 (defun web-mode-element-is-collapsed (&optional pos)
  10764   (unless pos (setq pos (point)))
  10765   (let (boundaries)
  10766     (and (setq boundaries (web-mode-element-boundaries pos))
  10767          (or (= (car (car boundaries)) (car (cdr boundaries)))
  10768              (= (cdr (car boundaries)) (1- (car (cdr boundaries)))))
  10769          )))
  10770 
  10771 (defun web-mode-element-contract ()
  10772   "Flatten elements."
  10773   (interactive)
  10774   (let (beg end (continue t) replacement boundaries)
  10775     (cond
  10776       ((or (not (get-text-property (point) 'tag-type))
  10777            (not (member (get-text-property (point) 'tag-type) '(start end))))
  10778        (web-mode-element-parent))
  10779       ((eq (get-text-property (point) 'tag-type) 'end)
  10780        (web-mode-tag-match))
  10781       ) ;cond
  10782     (setq boundaries (web-mode-element-boundaries (point)))
  10783     (setq beg (car (car boundaries))
  10784           end (cdr (cdr boundaries)))
  10785     (goto-char beg)
  10786     ;;(message "beg(%S) end(%S)" beg end)
  10787     (while continue
  10788       (if (or (not (re-search-forward ">[ \t\r\n]+\\|[ \t\r\n]+<"))
  10789               (>= (point) end))
  10790           (setq continue nil)
  10791           (setq end (+ (- end (length (match-string-no-properties 0))) 1))
  10792           (setq replacement (if (eq (char-before) ?\<) "<" ">"))
  10793           (replace-match replacement nil nil)
  10794           ;;(message "end(%S)" end))
  10795           )
  10796       ) ;while
  10797     (goto-char beg)
  10798     ))
  10799 
  10800 (defun web-mode-element-extract ()
  10801   "Flatten element."
  10802   (interactive)
  10803   (let (beg end (continue t) save boundaries)
  10804     (cond
  10805       ((or (not (get-text-property (point) 'tag-type))
  10806            (not (member (get-text-property (point) 'tag-type) '(start end))))
  10807        (web-mode-element-parent))
  10808       ((eq (get-text-property (point) 'tag-type) 'end)
  10809        (web-mode-tag-match))
  10810       ) ;cond
  10811     (setq boundaries (web-mode-element-boundaries (point)))
  10812     (setq beg (car (car boundaries))
  10813           end (cdr (cdr boundaries)))
  10814     (goto-char beg)
  10815     (while continue
  10816       (if (or (not (and (or (get-text-property (point) 'tag-type) (web-mode-tag-next))
  10817                         (web-mode-tag-end)))
  10818               (>= (point) end))
  10819           (setq continue nil)
  10820           (setq save (point))
  10821           ;;(message "point(%S)" (point))
  10822           (skip-chars-forward "\n\t ")
  10823           (when (get-text-property (point) 'tag-type)
  10824             (newline)
  10825             (indent-according-to-mode)
  10826             (setq end (+ end (- (point) save))))
  10827           ) ;if
  10828       ) ;while
  10829     (goto-char beg)
  10830     ))
  10831 
  10832 (defun web-mode-element-transpose ()
  10833   "Transpose two html elements."
  10834   (interactive)
  10835   (let (pos start1 end1 start2 end2)
  10836     (save-excursion
  10837       (setq pos (point))
  10838       (cond
  10839         ((get-text-property pos 'tag-type)
  10840          (setq start1 (web-mode-element-beginning-position pos)
  10841                end1 (1+ (web-mode-element-end-position pos)))
  10842          )
  10843         ((setq start1 (web-mode-element-parent-position pos))
  10844          (setq end1 (1+ (web-mode-element-end-position pos)))
  10845          )
  10846         ) ;cond
  10847       (when (and start1 end1 (> end1 0))
  10848         (goto-char end1)
  10849         (unless (get-text-property (point) 'tag-beg)
  10850           (skip-chars-forward "\n\t "))
  10851         (when (get-text-property (point) 'tag-beg)
  10852           (setq start2 (web-mode-element-beginning-position (point))
  10853                 end2 (1+ (web-mode-element-end-position (point))))
  10854           )
  10855         )
  10856       (transpose-regions start1 end1 start2 end2)
  10857       ) ;save-excursion
  10858     start2))
  10859 
  10860 (defun web-mode-element-children-comment (&optional pos)
  10861   "Comment all the children of the current html element."
  10862   (interactive)
  10863   (unless pos (setq pos (point)))
  10864   (save-excursion
  10865     (dolist (child (reverse (web-mode-element-children pos)))
  10866       (goto-char child)
  10867       (web-mode-comment (point)))
  10868     ))
  10869 
  10870 (defun web-mode-element-mute-blanks ()
  10871   "Mute blanks."
  10872   (interactive)
  10873   (let (pos parent children elt)
  10874     (setq pos (point))
  10875     (save-excursion
  10876       (when (and (setq parent (web-mode-element-boundaries pos))
  10877                  (web-mode-element-child-position (point)))
  10878         (setq children (reverse (web-mode-element-children)))
  10879         (goto-char (car (cdr parent)))
  10880         (dolist (child children)
  10881           (setq elt (web-mode-element-boundaries child))
  10882           (when (> (point) (1+ (cddr elt)))
  10883             (when (and (not (eq (get-text-property (point) 'part-token) 'comment))
  10884                        (not (eq (get-text-property (1+ (cddr elt)) 'part-token) 'comment)))
  10885               (web-mode-insert-text-at-pos "-->" (point))
  10886               (web-mode-insert-text-at-pos "<!--" (1+ (cddr elt))))
  10887             )
  10888           (goto-char child)
  10889           )
  10890         (when (and (> (point) (1+ (cdr (car parent))))
  10891                    (not (eq (get-text-property (point) 'part-token) 'comment))
  10892                    (not (eq (get-text-property (1+ (cdr (car parent))) 'part-token) 'comment)))
  10893           (web-mode-insert-text-at-pos "-->" (point))
  10894           (web-mode-insert-text-at-pos "<!--" (1+ (cdr (car parent)))))
  10895         ) ;when
  10896       )))
  10897 
  10898 (defun web-mode-element-children (&optional pos)
  10899   (unless pos (setq pos (point)))
  10900   (let ((continue t) (i 0) child children)
  10901     (save-excursion
  10902       (when (and (member (get-text-property pos 'tag-type) '(start end))
  10903                  (setq child (web-mode-element-child-position pos)))
  10904         (while continue
  10905           (cond
  10906             ((> (setq i (1+ i)) 100)
  10907              (setq continue nil)
  10908              (message "element-children ** warning **"))
  10909             ((= i 1)
  10910              (goto-char child))
  10911             ((web-mode-element-sibling-next)
  10912              )
  10913             (t
  10914              (setq continue nil))
  10915             ) ;cond
  10916           (when continue
  10917             (setq children (append children (list (point)))))
  10918           ) ;while
  10919         ) ;when
  10920       ) ;save-excursion
  10921     ;;(message "%S" children)
  10922     children))
  10923 
  10924 (defun web-mode-property-boundaries (prop &optional pos)
  10925   "property boundaries (cdr is 1+)"
  10926   (unless pos (setq pos (point)))
  10927   (let (beg end val)
  10928     (setq val (get-text-property pos prop))
  10929     (if (null val)
  10930         val
  10931         (if (or (bobp)
  10932                 (not (eq (get-text-property (1- pos) prop) val)))
  10933             (setq beg pos)
  10934             (setq beg (previous-single-property-change pos prop))
  10935             (when (null beg) (setq beg (point-min))))
  10936         (if (or (eobp)
  10937                 (not (eq (get-text-property (1+ pos) prop) val)))
  10938             (setq end pos)
  10939             (setq end (next-single-property-change pos prop))
  10940             (when (null end) (setq end (point-min))))
  10941         (cons beg end))))
  10942 
  10943 (defun web-mode-content-boundaries (&optional pos)
  10944   (unless pos (setq pos (point)))
  10945   (let (beg end)
  10946     (setq beg (or (previous-property-change pos (current-buffer))
  10947                   (point-max)))
  10948     (setq end (or (next-property-change pos (current-buffer))
  10949                   (point-min)))
  10950     (while (and (< beg end) (member (char-after beg) '(?\s ?\n)))
  10951       (setq beg (1+ beg)))
  10952     (while (and (> end beg) (member (char-after (1- end)) '(?\s ?\n)))
  10953       (setq end (1- end)))
  10954     ;;    (message "beg(%S) end(%S)" beg end)
  10955     (cons beg end)
  10956     ))
  10957 
  10958 (defun web-mode-element-boundaries (&optional pos)
  10959   "Return ((start-tag-beg . start-tag-end) . (end-tag-beg . end-tag-end))
  10960 First level car and cdr are the same with void elements.
  10961 Pos should be in a tag."
  10962   (unless pos (setq pos (point)))
  10963   (let (start-tag-beg start-tag-end end-tag-beg end-tag-end)
  10964     (cond
  10965       ((eq (get-text-property pos 'tag-type) 'start)
  10966        (setq start-tag-beg (web-mode-tag-beginning-position pos)
  10967              start-tag-end (web-mode-tag-end-position pos))
  10968        (when (setq pos (web-mode-tag-match-position pos))
  10969          (setq end-tag-beg pos
  10970                end-tag-end (web-mode-tag-end-position pos)))
  10971        )
  10972       ((eq (get-text-property pos 'tag-type) 'end)
  10973        (setq end-tag-beg (web-mode-tag-beginning-position pos)
  10974              end-tag-end (web-mode-tag-end-position pos))
  10975        (when (setq pos (web-mode-tag-match-position pos))
  10976          (setq start-tag-beg pos
  10977                start-tag-end (web-mode-tag-end-position pos)))
  10978        )
  10979       ((eq (get-text-property pos 'tag-type) 'void)
  10980        (setq start-tag-beg (web-mode-tag-beginning-position pos)
  10981              start-tag-end (web-mode-tag-end-position pos))
  10982        (setq end-tag-beg start-tag-beg
  10983              end-tag-end start-tag-end)
  10984        )
  10985       ) ;cond
  10986     (if (and start-tag-beg start-tag-end end-tag-beg end-tag-end)
  10987         (cons (cons start-tag-beg start-tag-end) (cons end-tag-beg end-tag-end))
  10988         nil)
  10989     ))
  10990 
  10991 (defun web-mode-surround ()
  10992   "Surround each line of the current REGION with a start/end tag."
  10993   (interactive)
  10994   (when mark-active
  10995     (let (beg end line-beg line-end tag tag-start tag-end)
  10996       (save-excursion
  10997         (combine-after-change-calls
  10998           (setq tag (web-mode-element-complete)
  10999                 tag-start (concat "<" tag ">")
  11000                 tag-end (concat "</" tag ">")
  11001                 beg (region-beginning)
  11002                 end (region-end)
  11003                 line-beg (web-mode-line-number beg)
  11004                 line-end (web-mode-line-number end))
  11005           (goto-char end)
  11006           (unless (bolp)
  11007             (insert tag-end)
  11008             (back-to-indentation)
  11009             (when (> beg (point))
  11010               (goto-char beg))
  11011             (insert tag-start))
  11012           (while (> line-end line-beg)
  11013             (forward-line -1)
  11014             (setq line-end (1- line-end))
  11015             (unless (looking-at-p "[[:space:]]*$")
  11016               (end-of-line)
  11017               (insert tag-end)
  11018               (back-to-indentation)
  11019               (when (> beg (point))
  11020                 (goto-char beg))
  11021               (insert tag-start))
  11022             ) ;while
  11023           (deactivate-mark)
  11024           ) ;combine-after-change-calls
  11025         ) ;save-excursion
  11026       )))
  11027 
  11028 (defun web-mode-lify-region ()
  11029   "Transform current REGION in an html list (<li>line1</li>...)"
  11030   (interactive)
  11031   (let (beg end lines)
  11032     (save-excursion
  11033       (combine-after-change-calls
  11034         (when  mark-active
  11035           (setq beg (region-beginning)
  11036                 end (region-end))
  11037           (setq lines (buffer-substring beg end))
  11038           (kill-region beg end)
  11039           (setq lines (replace-regexp-in-string "^[ \t]*" "<li>" lines))
  11040           (setq lines (replace-regexp-in-string "$" "</li>" lines))
  11041           (web-mode-insert-and-indent lines)
  11042           ) ;when
  11043         ) ;combine-after-change-calls
  11044       ) ;save-excursion
  11045     ) ;let
  11046   )
  11047 
  11048 (defun web-mode-element-complete (&optional prompt)
  11049   "Completes for an element tag."
  11050   (completing-read
  11051    (or prompt "Tag name: ")
  11052    (append
  11053     web-mode-tag-list
  11054     web-mode-tag-history)
  11055    nil nil nil 'web-mode-tag-history))
  11056 
  11057 (defun web-mode-element-wrap (&optional tag-name)
  11058   "Wrap current REGION with start and end tags.
  11059 Prompt user if TAG-NAME isn't provided."
  11060   (interactive)
  11061   (let (beg end pos tag sep)
  11062     (save-excursion
  11063       (setq tag (or tag-name (web-mode-element-complete)))
  11064       (setq pos (point))
  11065       (cond
  11066         (mark-active
  11067          (setq beg (region-beginning)
  11068                end (region-end)))
  11069         ((get-text-property pos 'tag-type)
  11070          (setq beg (web-mode-element-beginning-position pos)
  11071                end (1+ (web-mode-element-end-position pos))))
  11072         ((setq beg (web-mode-element-parent-position pos))
  11073          (setq end (1+ (web-mode-element-end-position pos))))
  11074         )
  11075       ;;      (message "beg(%S) end(%S)" beg end)
  11076       (when (and beg end (> end 0))
  11077         (setq sep (if (get-text-property beg 'tag-beg) "\n" ""))
  11078         (web-mode-insert-text-at-pos (concat sep "</" tag ">") end)
  11079         (web-mode-insert-text-at-pos (concat "<" tag ">" sep) beg)
  11080         (when (string= sep "\n") (indent-region beg (+ end (* (+ 3 (length tag)) 2))))
  11081         )
  11082       ) ;save-excursion
  11083     (web-mode-go beg)))
  11084 
  11085 (defun web-mode-element-vanish (&optional arg)
  11086   "Vanish the current html element. The content of the element is kept."
  11087   (interactive "p")
  11088   (let (type (pos (point)) start-b start-e end-b end-e)
  11089     (while (>= arg 1)
  11090       (setq type (get-text-property pos 'tag-type))
  11091       (when type
  11092         (cond
  11093           ((member type '(void))
  11094            (web-mode-element-kill)
  11095            (set-mark (point))
  11096            (web-mode-tag-match)
  11097            (web-mode-tag-end)
  11098            (exchange-point-and-mark))
  11099           ((member type '(start))
  11100            (setq start-b (web-mode-tag-beginning-position)
  11101                  start-e (web-mode-tag-end-position))
  11102            (when (web-mode-tag-match)
  11103              (setq end-b (web-mode-tag-beginning-position)
  11104                    end-e (web-mode-tag-end-position)))
  11105            )
  11106           (t
  11107            (setq end-b (web-mode-tag-beginning-position)
  11108                  end-e (web-mode-tag-end-position))
  11109            (when (web-mode-tag-match)
  11110              (setq start-b (web-mode-tag-beginning-position)
  11111                    start-e (web-mode-tag-end-position)))
  11112            ) ;t
  11113           ) ;cond
  11114         (when (and start-b end-b)
  11115           (goto-char end-b)
  11116           (delete-region end-b (1+ end-e))
  11117           (delete-blank-lines)
  11118           (goto-char start-b)
  11119           (delete-region start-b (1+ start-e))
  11120           (delete-blank-lines)
  11121           (web-mode-buffer-indent)
  11122           )
  11123         ;;        (message "start %S %S - end %S %S" start-b start-e end-b end-e))
  11124         ) ;when
  11125       (skip-chars-forward "[:space:]\n")
  11126       (setq arg (1- arg))
  11127       ) ;while
  11128     ) ;let
  11129   )
  11130 
  11131 (defun web-mode-element-kill (&optional arg)
  11132   "Kill the current html element."
  11133   (interactive "p")
  11134   (while (>= arg 1)
  11135     (setq arg (1- arg))
  11136     (web-mode-element-select)
  11137     (when mark-active
  11138       (kill-region (region-beginning) (region-end)))
  11139     ) ;while
  11140   )
  11141 
  11142 (defun web-mode-element-clone (&optional arg)
  11143   "Clone the current html element."
  11144   (interactive "p")
  11145   (let (col pos)
  11146     (while (>= arg 1)
  11147       (setq arg (1- arg)
  11148             col 0)
  11149       (web-mode-element-select)
  11150       (when mark-active
  11151         (save-excursion
  11152           (goto-char (region-beginning))
  11153           (setq col (current-column)))
  11154         (kill-region (region-beginning) (region-end))
  11155         (yank)
  11156         (newline)
  11157         (indent-line-to col)
  11158         (setq pos (point))
  11159         (yank)
  11160         (goto-char pos))
  11161       )
  11162     ) ;let
  11163   )
  11164 
  11165 (defun web-mode-element-insert ()
  11166   "Insert an html element."
  11167   (interactive)
  11168   (let (tag-name)
  11169     (cond
  11170       ((and (get-text-property (point) 'tag-type)
  11171             (not (get-text-property (point) 'tag-beg)))
  11172        (message "element-insert ** invalid context **"))
  11173       ((not (and (setq tag-name (web-mode-element-complete))
  11174                  (> (length tag-name) 0)))
  11175        (message "element-insert ** failure **"))
  11176       ((web-mode-element-is-void tag-name)
  11177        (insert (concat "<" (replace-regexp-in-string "/" "" tag-name) "/>"))
  11178        )
  11179       (mark-active
  11180        (let ((beg (region-beginning)) (end (region-end)))
  11181          (deactivate-mark)
  11182          (goto-char end)
  11183          (insert "</" tag-name ">")
  11184          (goto-char beg)
  11185          (insert "<" tag-name ">")
  11186          )
  11187        )
  11188       (t
  11189        (insert (concat "<" tag-name ">" "</" tag-name ">"))
  11190        (web-mode-sb "</")
  11191        )
  11192       ) ;cond
  11193     ))
  11194 
  11195 (defun web-mode-element-insert-at-point ()
  11196   "Replace the word at point with a html tag of it."
  11197   (interactive)
  11198   (let ((tag-name (thing-at-point 'word)))
  11199     (cond
  11200       ((web-mode-element-is-void tag-name)
  11201        (backward-kill-word 1)
  11202        (insert (concat "<" (replace-regexp-in-string "/" "" tag-name) "/>"))
  11203        )
  11204       (mark-active
  11205        (setq tag-name (buffer-substring (region-beginning) (region-end)))
  11206        (delete-region (region-beginning) (region-end))
  11207        (insert (concat "<" tag-name ">" "</" tag-name ">"))
  11208        (web-mode-sb "</")
  11209        )
  11210       (tag-name ; do nothing is there isn's word at point
  11211        (backward-kill-word 1)
  11212        (insert (concat "<" tag-name ">" "</" tag-name ">"))
  11213        (web-mode-sb "</")
  11214        )
  11215       ) ;cond
  11216     ))
  11217 
  11218 (defun web-mode-element-rename (&optional tag-name)
  11219   "Rename the current html element."
  11220   (interactive)
  11221   (save-excursion
  11222     (let (pos)
  11223       (unless tag-name (setq tag-name (web-mode-element-complete "New tag name: ")))
  11224       (when (and (> (length tag-name) 0)
  11225                  (web-mode-element-beginning)
  11226                  (looking-at "<\\([[:alnum:]]+\\(:?[[:alpha:]_-]+\\)?\\)"))
  11227         (setq pos (point))
  11228         (unless (web-mode-element-is-void)
  11229           (save-match-data
  11230             (web-mode-tag-match)
  11231             (if (looking-at "</[ ]*\\([[:alnum:]]+\\(:?[[:alpha:]_-]+\\)?\\)")
  11232                 (replace-match (concat "</" tag-name))
  11233                 )))
  11234         (goto-char pos)
  11235         (replace-match (concat "<" tag-name))
  11236         ))))
  11237 
  11238 (defun web-mode-current-trimmed-line ()
  11239   (web-mode-trim (buffer-substring-no-properties
  11240                   (line-beginning-position)
  11241                   (line-end-position))))
  11242 
  11243 (defun web-mode-trim (string)
  11244   (replace-regexp-in-string "\\`[ \t\n]*" "" (replace-regexp-in-string "[ \t\n]*\\'" "" string)))
  11245 
  11246 (defun web-mode-is-token-end (pos)
  11247   (let (block-token part-token)
  11248     (setq block-token (get-text-property pos 'block-token))
  11249     (setq part-token (get-text-property pos 'part-token))
  11250     (cond
  11251       ((not (or block-token part-token))
  11252        nil)
  11253       ((>= (1+ pos) (point-max))
  11254        t)
  11255       ((and block-token
  11256             (not (string= (get-text-property (1+ pos) 'block-token) block-token)))
  11257        t)
  11258       ((and part-token
  11259             (not (string= (get-text-property (1+ pos) 'part-token) part-token)))
  11260        t)
  11261       (t
  11262        nil)
  11263       ) ;cond
  11264     ))
  11265 
  11266 (defun web-mode-block-is-token-line ()
  11267   (save-excursion
  11268     (let ((continue t) (counter 0))
  11269       (beginning-of-line)
  11270       (back-to-indentation)
  11271       (while (and continue (not (eolp)))
  11272         (cond
  11273           ((get-text-property (point) 'block-token)
  11274            (setq counter (1+ counter)))
  11275           ((not (member (following-char) '(?\s ?\t)))
  11276            (setq continue nil
  11277                  counter 0))
  11278           ) ;cond
  11279         (forward-char)
  11280         ) ;while
  11281       (> counter 0)
  11282       )))
  11283 
  11284 (defun web-mode-part-is-token-line (pos)
  11285   (save-excursion
  11286     (let ((continue t)
  11287           (counter 0))
  11288       (goto-char pos)
  11289       (setq continue (not (eolp)))
  11290       (while continue
  11291         (forward-char)
  11292         (cond
  11293           ((eolp)
  11294            (setq continue nil))
  11295           ((or (get-text-property (point) 'block-side)
  11296                (member (get-text-property (point) 'part-token) '(comment string)))
  11297            (setq counter (1+ counter)))
  11298           ((not (member (following-char) '(?\s ?\t)))
  11299            (setq continue nil
  11300                  counter 0))
  11301           )
  11302         ) ;while
  11303       (> counter 0))))
  11304 
  11305 (defun web-mode-is-content (&optional pos)
  11306   (unless pos (setq pos (point)))
  11307   (not (or (get-text-property pos 'part-side)
  11308            (get-text-property pos 'tag-type)
  11309            (get-text-property pos 'block-side)
  11310            )))
  11311 
  11312 (defun web-mode-is-comment-or-string (&optional pos)
  11313   (unless pos (setq pos (point)))
  11314   (not (null (or (eq (get-text-property pos 'tag-type) 'comment)
  11315                  (member (get-text-property pos 'block-token) '(comment string))
  11316                  (member (get-text-property pos 'part-token) '(comment string))))))
  11317 
  11318 ;; NOTE: we look at the firt one
  11319 (defun web-mode-block-is-open (&optional pos)
  11320   (unless pos (setq pos (point))))
  11321 
  11322 ;; NOTE: we look at the last one
  11323 (defun web-mode-block-is-close (&optional pos)
  11324   (unless pos (setq pos (point)))
  11325   (and (get-text-property pos 'block-side)
  11326        (eq (caar (web-mode-block-controls-get pos)) 'close)))
  11327 
  11328 ;; NOTE: we look at the first one
  11329 (defun web-mode-block-is-inside (&optional pos)
  11330   (unless pos (setq pos (point)))
  11331   (and (get-text-property pos 'block-side)
  11332        (eq (caar (web-mode-block-controls-get pos)) 'inside)))
  11333 
  11334 (defun web-mode-element-is-void (&optional tag)
  11335   (cond
  11336     ((and (not tag) (eq (get-text-property (point) 'tag-type) 'void))
  11337      t)
  11338     ((and tag (member tag '("div" "li" "a" "p" "h1" "h2" "h3" "ul" "span" "article" "section" "td" "tr")))
  11339      nil)
  11340     ((and tag (string-suffix-p "/" tag))
  11341      t)
  11342     ((and tag (string= web-mode-content-type "jsx"))
  11343      (member (downcase tag) '("img" "br" "hr")))
  11344     (tag
  11345      (car (member (downcase tag) web-mode-void-elements)))
  11346     (t
  11347      nil)
  11348     ))
  11349 
  11350 ;;---- COMMENT ------------------------------------------------------------------
  11351 
  11352 (defun web-mode-toggle-comments ()
  11353   "Toggle comments visbility."
  11354   (interactive)
  11355   (web-mode-with-silent-modifications
  11356    (save-excursion
  11357      (if web-mode-comments-invisible
  11358          (remove-overlays))
  11359      (setq web-mode-comments-invisible (null web-mode-comments-invisible))
  11360      (let ((continue t)
  11361            (pos (point-min))
  11362            (visibility web-mode-comments-invisible)
  11363            end)
  11364        (while continue
  11365          (setq pos (next-single-property-change pos 'font-lock-face))
  11366          (if (null pos)
  11367              (setq continue nil)
  11368              (when (eq (get-text-property pos 'font-lock-face) 'web-mode-comment-face)
  11369                (setq end (next-single-property-change pos 'font-lock-face))
  11370                (put-text-property pos end 'invisible visibility)
  11371                (when visibility
  11372                  (make-overlay pos end))
  11373                (goto-char pos)
  11374                )
  11375              )
  11376          )
  11377        ) ;let
  11378      )))
  11379 
  11380 (defun web-mode-comment-or-uncomment-region (beg end &optional _arg)
  11381   (interactive)
  11382   (save-excursion
  11383     (push-mark end)
  11384     (goto-char beg)
  11385     (setq mark-active t)
  11386     (web-mode-comment-or-uncomment)
  11387     (pop-mark)))
  11388 
  11389 (defun web-mode-comment-or-uncomment ()
  11390   "Comment or uncomment line(s), block or region at POS."
  11391   (interactive)
  11392   ;; TODO : if mark is at eol, mark--
  11393   (if (and (not mark-active) (looking-at-p "[[:space:]]*$"))
  11394       (web-mode-comment-insert)
  11395       (when (and (use-region-p) (eq (point) (region-end)))
  11396         (if (bolp) (backward-char))
  11397         (exchange-point-and-mark))
  11398       (if (eq (get-text-property (point) 'block-token) 'delimiter-beg)
  11399           (web-mode-block-skip-blank-forward (point) '(delimiter-beg))
  11400           (skip-chars-forward "[:space:]" (line-end-position)))
  11401       (cond
  11402         ;; #1147
  11403         ((and (get-text-property (point) 'jsx-beg)
  11404               (eq (get-text-property (1+ (point)) 'part-token) 'comment))
  11405          (web-mode-uncomment (1+ (point))))
  11406         ((or (eq (get-text-property (point) 'tag-type) 'comment)
  11407              (eq (get-text-property (point) 'block-token) 'comment)
  11408              (eq (get-text-property (point) 'part-token) 'comment))
  11409          (web-mode-uncomment (point)))
  11410         (t
  11411          (web-mode-comment (point)))
  11412         )
  11413       ) ;if
  11414   )
  11415 
  11416 (defun web-mode-comment-indent-new-line (&optional _soft)
  11417   (interactive)
  11418   (let (ctx)
  11419     (setq ctx (web-mode-comment-context))
  11420     (cond
  11421       ((null ctx)
  11422        (newline 1))
  11423       (t
  11424        (newline 1)
  11425        (indent-line-to (plist-get ctx :col))
  11426        (let ((prefix (plist-get ctx :prefix)))
  11427          (insert
  11428           (concat prefix
  11429                   ;; Check if the comment ends with a space, and if not, insert one.
  11430                   (if
  11431                    (string-equal (substring prefix -1 (length prefix)) " ")
  11432                    ""
  11433                    " ")))))
  11434       ) ;cond
  11435     ))
  11436 
  11437 (defun web-mode-comment-context (&optional pos)
  11438   (cond
  11439     (pos
  11440      )
  11441     ((and (eolp) (not (bobp)))
  11442      (setq pos (1- (point))))
  11443     (t
  11444      (setq pos (point)))
  11445     ) ;cond
  11446   (let (beg col prefix type format)
  11447     (cond
  11448       ((eq (get-text-property pos 'block-token) 'comment)
  11449        (setq type "block"))
  11450       ((eq (get-text-property pos 'tag-type) 'comment)
  11451        (setq type "tag"))
  11452       ((eq (get-text-property pos 'part-token) 'comment)
  11453        (setq type "part"))
  11454       )
  11455     (if (null type) nil
  11456         (save-excursion
  11457           (goto-char pos)
  11458           (web-mode-comment-beginning)
  11459           (setq beg (point)
  11460                 col (current-column))
  11461           (cond
  11462             ((looking-at-p "/\\*")
  11463              (setq format "/*"
  11464                    prefix " * "))
  11465             ((looking-at-p "//")
  11466              (setq format "//"
  11467                    prefix "//"))
  11468             ((looking-at-p "#")
  11469              (setq format "#"
  11470                    prefix "#"))
  11471             ((looking-at-p ";")
  11472              (setq format ";"
  11473                    prefix ";"))
  11474             ((looking-at-p "''")
  11475              (setq format "''"
  11476                    prefix "''"))
  11477             ) ;cond
  11478           (list :beg beg :col col :prefix prefix :type type :format format)))))
  11479 
  11480 (defun web-mode-comment-insert ()
  11481   (let ((alt nil) (language nil) (pos (point)))
  11482     (setq language (web-mode-language-at-pos pos))
  11483     (setq alt (cdr (assoc language web-mode-comment-formats)))
  11484     ;;(message "language=%S" language)
  11485     (cond
  11486       ((get-text-property pos 'block-side)
  11487        (cond
  11488          ((and alt (string= alt "//"))
  11489           (insert "// "))
  11490          (t
  11491           (insert "/*  */")
  11492           (search-backward " */"))
  11493          ) ;cond
  11494        ) ;case block-side
  11495       ((get-text-property pos 'part-side)
  11496        (cond
  11497          ((and alt (string= alt "//"))
  11498           (insert "// "))
  11499          (t
  11500           (insert "/*  */")
  11501           (search-backward " */"))
  11502          ) ;cond
  11503        ) ;case part-side
  11504       (t
  11505        (insert "<!--  -->")
  11506        (search-backward " -->")
  11507        ) ;case html
  11508       ) ;cond
  11509     ))
  11510 
  11511 (defun web-mode-comment (pos)
  11512   (let (ctx language col sel beg end block-side single-line-block pos-after content)
  11513 
  11514     (setq pos-after pos)
  11515 
  11516     (setq block-side (get-text-property pos 'block-side))
  11517     (setq single-line-block (web-mode-is-single-line-block pos))
  11518 
  11519     (cond
  11520 
  11521       ((and block-side (string= web-mode-engine "erb"))
  11522        (web-mode-comment-erb-block pos)
  11523        )
  11524 
  11525       ((and block-side (string= web-mode-engine "artanis"))
  11526        (web-mode-comment-artanis-block pos)
  11527        )
  11528 
  11529       ((and single-line-block block-side
  11530             (intern-soft (concat "web-mode-comment-" web-mode-engine "-block")))
  11531        (funcall (intern (concat "web-mode-comment-" web-mode-engine "-block")) pos)
  11532        )
  11533 
  11534       (t
  11535        (setq ctx (web-mode-point-context
  11536                   (if mark-active (region-beginning) (line-beginning-position))))
  11537        ;;(message "%S" ctx)
  11538        (setq language (plist-get ctx :language))
  11539        (setq col (current-column))
  11540        (cond
  11541          (mark-active
  11542           ;;(message "%S %S" (point) col)
  11543           )
  11544          ((and (member language '("html" "xml"))
  11545                (get-text-property (progn (back-to-indentation) (point)) 'tag-beg))
  11546           (web-mode-element-select))
  11547          (t
  11548           (end-of-line)
  11549           (set-mark (line-beginning-position)))
  11550          ) ;cond
  11551 
  11552        (setq beg (region-beginning)
  11553              end (region-end))
  11554 
  11555        (when (> (point) (mark))
  11556          (exchange-point-and-mark))
  11557 
  11558        (if (and (eq (char-before end) ?\n)
  11559                 (not (eq (char-after end) ?\n)))
  11560            (setq end (1- end)))
  11561 
  11562        (setq sel (buffer-substring-no-properties beg end))
  11563 
  11564        (cond
  11565 
  11566          ((member language '("html" "xml"))
  11567           (cond
  11568             ((and (= web-mode-comment-style 2) (string= web-mode-engine "django"))
  11569              (setq content (concat "{# " sel " #}")))
  11570             ((and (= web-mode-comment-style 2) (member web-mode-engine '("ejs" "erb")))
  11571              (setq content (concat "<%# " sel " %>")))
  11572             ((and (= web-mode-comment-style 2) (string= web-mode-engine "artanis"))
  11573              (setq content (concat "<%; " sel " %>")))
  11574             ((and (= web-mode-comment-style 2) (string= web-mode-engine "aspx"))
  11575              (setq content (concat "<%-- " sel " --%>")))
  11576             ((and (= web-mode-comment-style 2) (string= web-mode-engine "smarty"))
  11577              (setq content (concat "{* " sel " *}")))
  11578             ((and (= web-mode-comment-style 2) (string= web-mode-engine "expressionengine"))
  11579              (setq content (concat "{!-- " sel " --}")))
  11580             ((and (= web-mode-comment-style 2) (string= web-mode-engine "xoops"))
  11581              (setq content (concat "<{* " sel " *}>")))
  11582             ((and (= web-mode-comment-style 2) (string= web-mode-engine "hero"))
  11583              (setq content (concat "<%# " sel " %>")))
  11584             ((and (= web-mode-comment-style 2) (string= web-mode-engine "blade"))
  11585              (setq content (concat "{{-- " sel " --}}")))
  11586             ((and (= web-mode-comment-style 2) (string= web-mode-engine "ctemplate"))
  11587              (setq content (concat "{{!-- " sel " --}}")))
  11588             ((and (= web-mode-comment-style 2) (string= web-mode-engine "antlers"))
  11589              (setq content (concat "{{# " sel " #}}")))
  11590             ((and (= web-mode-comment-style 2) (string= web-mode-engine "razor"))
  11591              (setq content (concat "@* " sel " *@")))
  11592             (t
  11593              (setq content (concat "<!-- " sel " -->"))
  11594              (when (< (length sel) 1)
  11595                (search-backward " -->")
  11596                (setq pos-after nil))
  11597              ))
  11598           ) ;case html
  11599 
  11600          ((member language '("php" "javascript" "typescript" "java" "jsx"))
  11601           (let (alt)
  11602             (setq alt (cdr (assoc language web-mode-comment-formats)))
  11603             ;;(message "language=%S alt=%S sel=%S col=%S" language alt sel col)
  11604             (cond
  11605               ((and alt (string= alt "//"))
  11606                (setq content (replace-regexp-in-string (concat "\n[ ]\\{" (number-to-string col) "\\}") "\n" sel))
  11607                (setq content (replace-regexp-in-string (concat "\n") "\n// " content))
  11608                (setq content (concat "// " content)))
  11609               ((get-text-property pos 'jsx-depth)
  11610                (setq content (concat "{/* " sel " */}")))
  11611               (web-mode-comment-prefixing
  11612                (setq content (replace-regexp-in-string (concat "\n[ ]\\{" (number-to-string col) "\\}") "\n* " sel))
  11613                (setq content (concat "/* " content " */")))
  11614               (t
  11615                (setq content (concat "/* " sel " */")))
  11616               ) ;cond
  11617             ) ;let
  11618           )
  11619 
  11620          ((member language '("erb"))
  11621           (setq content (replace-regexp-in-string "^[ ]*" "#" sel)))
  11622 
  11623          ((member language '("asp"))
  11624           (setq content (replace-regexp-in-string "^[ ]*" "'" sel)))
  11625 
  11626          (t
  11627           (setq content (concat "/* " sel " */")))
  11628 
  11629          ) ;cond
  11630 
  11631        (when content
  11632          (delete-region beg end)
  11633          (deactivate-mark)
  11634          (let (beg end)
  11635            (setq beg (line-beginning-position))
  11636            (insert content)
  11637            (setq end (line-end-position))
  11638            (indent-region beg end)
  11639            )
  11640          ) ;when
  11641 
  11642        ) ;t
  11643       ) ;cond
  11644 
  11645     (when pos-after (goto-char pos-after))
  11646 
  11647     ))
  11648 
  11649 (defun web-mode-comment-ejs-block (pos)
  11650   (let (beg end)
  11651     (setq beg (web-mode-block-beginning-position pos)
  11652           end (web-mode-block-end-position pos))
  11653     (web-mode-insert-text-at-pos "//" (+ beg 2))))
  11654 
  11655 (defun web-mode-comment-erb-block (pos)
  11656   (let (beg end)
  11657     (setq beg (web-mode-block-beginning-position pos)
  11658           end (web-mode-block-end-position pos))
  11659     (web-mode-insert-text-at-pos "#" (+ beg 2))))
  11660 
  11661 (defun web-mode-comment-artanis-block (pos)
  11662   (let (beg end)
  11663     (setq beg (web-mode-block-beginning-position pos)
  11664           end (web-mode-block-end-position pos))
  11665     (web-mode-insert-text-at-pos ";" (+ beg 2))))
  11666 
  11667 (defun web-mode-comment-django-block (pos)
  11668   (let (beg end)
  11669     (setq beg (web-mode-block-beginning-position pos)
  11670           end (web-mode-block-end-position pos))
  11671     (web-mode-insert-text-at-pos "#" end)
  11672     (web-mode-insert-text-at-pos "#" (1+ beg))))
  11673 
  11674 (defun web-mode-comment-dust-block (pos)
  11675   (let (beg end)
  11676     (setq beg (web-mode-block-beginning-position pos)
  11677           end (web-mode-block-end-position pos))
  11678     (web-mode-insert-text-at-pos "!" end)
  11679     (web-mode-insert-text-at-pos "!" (1+ beg))))
  11680 
  11681 (defun web-mode-comment-aspx-block (pos)
  11682   (let (beg end)
  11683     (setq beg (web-mode-block-beginning-position pos)
  11684           end (web-mode-block-end-position pos))
  11685     (web-mode-insert-text-at-pos "#" end)
  11686     (web-mode-insert-text-at-pos "#" (1+ beg))))
  11687 
  11688 (defun web-mode-comment-jsp-block (pos)
  11689   (let (beg end)
  11690     (setq beg (web-mode-block-beginning-position pos)
  11691           end (web-mode-block-end-position pos))
  11692     (web-mode-insert-text-at-pos "--" (+ beg 2))))
  11693 
  11694 (defun web-mode-comment-go-block (pos)
  11695   (let (beg end)
  11696     (setq beg (web-mode-block-beginning-position pos)
  11697           end (web-mode-block-end-position pos))
  11698     (web-mode-insert-text-at-pos "*/" (1- end))
  11699     (web-mode-insert-text-at-pos "/*" (+ beg (if (web-mode-looking-at "{{" beg) 2 0)))))
  11700 
  11701 (defun web-mode-comment-php-block (pos)
  11702   (let (beg end)
  11703     (setq beg (web-mode-block-beginning-position pos)
  11704           end (web-mode-block-end-position pos))
  11705     (web-mode-insert-text-at-pos "*/" (- end 2))
  11706     (web-mode-insert-text-at-pos "/*" (+ beg 1 (if (web-mode-looking-at "<\\?php" beg) 5 3)))))
  11707 
  11708 (defun web-mode-comment-svelte-block (pos)
  11709   (let (beg end)
  11710     (setq beg (web-mode-block-beginning-position pos)
  11711           end (web-mode-block-end-position pos))
  11712     (web-mode-insert-text-at-pos "!" end)
  11713     (web-mode-insert-text-at-pos "!" (1+ beg))))
  11714 
  11715 (defun web-mode-comment-boundaries (&optional pos)
  11716   (interactive)
  11717   (unless pos (setq pos (point)))
  11718   (let ((beg pos) (end pos) prop)
  11719     (save-excursion
  11720       (goto-char pos)
  11721       (setq prop
  11722             (cond
  11723               ((eq (get-text-property pos 'block-token) 'comment) 'block-token)
  11724               ((eq (get-text-property pos 'tag-type) 'comment) 'tag-type)
  11725               ((eq (get-text-property pos 'part-token) 'comment) 'part-token)
  11726               (t nil)
  11727               ))
  11728       (if (null prop)
  11729           (setq beg nil
  11730                 end nil)
  11731           (when (and (not (bobp))
  11732                      (eq (get-text-property pos prop) (get-text-property (1- pos) prop)))
  11733             (setq beg (or (previous-single-property-change pos prop) (point-min))))
  11734           (when (and (not (eobp))
  11735                      (eq (get-text-property pos prop) (get-text-property (1+ pos) prop)))
  11736             (setq end (or (next-single-property-change pos prop) (point-max)))))
  11737       (message "beg(%S) end(%S) point-max(%S)" beg end (point-max))
  11738       (when (and beg (string= (buffer-substring-no-properties beg (+ beg 2)) "//"))
  11739         (goto-char end)
  11740         (while (and (looking-at-p "\n[ ]*//")
  11741                     (not (eobp)))
  11742           (search-forward "//")
  11743           (backward-char 2)
  11744           ;;(message "%S" (point))
  11745           (setq end (next-single-property-change (point) prop))
  11746           (goto-char end)
  11747           ;;(message "%S" (point))
  11748           ) ;while
  11749         ) ;when
  11750       ;;(when end (setq end (1- end))) ;; #1021
  11751       ) ;save-excursion
  11752     ;;(message "beg=%S end=%S" beg end)
  11753     (if (and beg end) (cons beg end) nil)
  11754     ))
  11755 
  11756 (defun web-mode-uncomment (pos)
  11757   (let ((beg pos) (end pos) (sub2 "") comment boundaries)
  11758     (save-excursion
  11759       (cond
  11760         ((and (get-text-property pos 'block-side)
  11761               (intern-soft (concat "web-mode-uncomment-" web-mode-engine "-block")))
  11762          (funcall (intern (concat "web-mode-uncomment-" web-mode-engine "-block")) pos))
  11763         ((and (setq boundaries (web-mode-comment-boundaries pos))
  11764               (setq beg (car boundaries))
  11765               (setq end (1+ (cdr boundaries)))
  11766               (> (- end beg) 4))
  11767          (when (and (eq (get-text-property beg 'part-token) 'comment)
  11768                     (> beg 1) ;#1158
  11769                     (get-text-property (1- beg) 'jsx-beg))
  11770            (setq beg (1- beg)
  11771                  end (1+ end)))
  11772          (setq comment (buffer-substring-no-properties beg end))
  11773          (setq sub2 (substring comment 0 2))
  11774          (cond
  11775            ((member sub2 '("<!" "<%"))
  11776             (setq comment (replace-regexp-in-string "\\(^<[!%]--[ ]?\\|[ ]?--[%]?>$\\)" "" comment)))
  11777            ((string= sub2 "{#")
  11778             (setq comment (replace-regexp-in-string "\\(^{#[ ]?\\|[ ]?#}$\\)" "" comment)))
  11779            ((string= sub2 "{/") ;jsx comments
  11780             (setq comment (replace-regexp-in-string "\\(^{/\\*[ ]?\\|[ ]?\\*/}$\\)" "" comment)))
  11781            ((string= sub2 "/*")
  11782             ;;(message "%S" comment)
  11783             ;;(setq comment (replace-regexp-in-string "\\(\\*/\\|^/\\*[ ]?\\|^[ \t]*\\*\\)" "" comment))
  11784             (setq comment (replace-regexp-in-string "\\([ ]?\\*/$\\|^/\\*[ ]?\\)" "" comment))
  11785             (setq comment (replace-regexp-in-string "\\(^[ \t]*\\*\\)" "" comment))
  11786             ;;(message "%S" comment)
  11787             )
  11788            ((string= sub2 "''")
  11789             (setq comment (replace-regexp-in-string "''" "" comment)))
  11790            ((string= sub2 "//")
  11791             (setq comment (replace-regexp-in-string "^ *//" "" comment)))
  11792            ) ;cond
  11793          (delete-region beg end)
  11794          (web-mode-insert-and-indent comment)
  11795          (goto-char beg)
  11796          )
  11797         ) ;cond
  11798       (indent-according-to-mode)
  11799       )))
  11800 
  11801 (defun web-mode-uncomment-erb-block (pos)
  11802   (let (beg end)
  11803     (setq beg (web-mode-block-beginning-position pos)
  11804           end (web-mode-block-end-position pos))
  11805     (cond
  11806       ((string= (buffer-substring-no-properties beg (+ beg 4)) "<%#=")
  11807        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11808       ((string-match-p "<[%[:alpha:]]" (buffer-substring-no-properties (+ beg 2) (- end 2)))
  11809        (web-mode-remove-text-at-pos 2 (1- end))
  11810        (web-mode-remove-text-at-pos 3 beg))
  11811       (t
  11812        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11813       ) ;cond
  11814     )
  11815   )
  11816 
  11817 (defun web-mode-uncomment-artanis-block (pos)
  11818   (let (beg end)
  11819     (setq beg (web-mode-block-beginning-position pos)
  11820           end (web-mode-block-end-position pos))
  11821     (cond
  11822       ((string= (buffer-substring-no-properties beg (+ beg 4)) "<%;=")
  11823        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11824       ((string-match-p "<[%[:alpha:]]" (buffer-substring-no-properties (+ beg 2) (- end 2)))
  11825        (web-mode-remove-text-at-pos 2 (1- end))
  11826        (web-mode-remove-text-at-pos 3 beg))
  11827       (t
  11828        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11829       ) ;cond
  11830     )
  11831   )
  11832 
  11833 (defun web-mode-uncomment-ejs-block (pos)
  11834   (let (beg end)
  11835     (setq beg (web-mode-block-beginning-position pos)
  11836           end (web-mode-block-end-position pos))
  11837     (web-mode-remove-text-at-pos 1 (+ beg 2))))
  11838 
  11839 (defun web-mode-uncomment-django-block (pos)
  11840   (let (beg end)
  11841     (setq beg (web-mode-block-beginning-position pos)
  11842           end (web-mode-block-end-position pos))
  11843     (cond
  11844       ((web-mode-looking-at-p "{#[{%]" beg)
  11845        (web-mode-remove-text-at-pos 1 (1- end))
  11846        (web-mode-remove-text-at-pos 1 (1+ beg))
  11847        )
  11848       (t
  11849        (web-mode-remove-text-at-pos 2 (1- end))
  11850        (web-mode-remove-text-at-pos 2 beg))
  11851       ) ;cond
  11852     ))
  11853 
  11854 (defun web-mode-uncomment-ctemplate-block (pos)
  11855   (let (beg end)
  11856     (setq beg (web-mode-block-beginning-position pos)
  11857           end (web-mode-block-end-position pos))
  11858     (web-mode-remove-text-at-pos 5 (- end 4))
  11859     (web-mode-remove-text-at-pos 5 beg)))
  11860 
  11861 (defun web-mode-uncomment-antlers-block (pos)
  11862   (let (beg end)
  11863     (setq beg (web-mode-block-beginning-position pos)
  11864           end (web-mode-block-end-position pos))
  11865     (web-mode-remove-text-at-pos 3 (- end 2))
  11866     (web-mode-remove-text-at-pos 3 beg)))
  11867 
  11868 (defun web-mode-uncomment-dust-block (pos)
  11869   (let (beg end)
  11870     (setq beg (web-mode-block-beginning-position pos)
  11871           end (web-mode-block-end-position pos))
  11872     (web-mode-remove-text-at-pos 1 (1- end))
  11873     (web-mode-remove-text-at-pos 1 (1+ beg))))
  11874 
  11875 (defun web-mode-uncomment-aspx-block (pos)
  11876   (let (beg end)
  11877     (setq beg (web-mode-block-beginning-position pos)
  11878           end (web-mode-block-end-position pos))
  11879     (web-mode-remove-text-at-pos 1 (1- end))
  11880     (web-mode-remove-text-at-pos 1 (1+ beg))))
  11881 
  11882 (defun web-mode-uncomment-jsp-block (pos)
  11883   (let (beg end)
  11884     (setq beg (web-mode-block-beginning-position pos)
  11885           end (web-mode-block-end-position pos))
  11886     (web-mode-remove-text-at-pos 2 (+ beg 2))))
  11887 
  11888 (defun web-mode-uncomment-go-block (pos)
  11889   (let (beg end)
  11890     (setq beg (web-mode-block-beginning-position pos)
  11891           end (web-mode-block-end-position pos))
  11892     (web-mode-remove-text-at-pos 2 (+ beg 2))
  11893     (web-mode-remove-text-at-pos 2 (- end 5))))
  11894 
  11895 (defun web-mode-uncomment-svelte-block (pos)
  11896   (let (beg end)
  11897     (setq beg (web-mode-block-beginning-position pos)
  11898           end (web-mode-block-end-position pos))
  11899     (web-mode-remove-text-at-pos 1 (1- end))
  11900     (web-mode-remove-text-at-pos 1 (1+ beg))))
  11901 
  11902 (defun web-mode-snippet-names ()
  11903   (mapcar #'car web-mode-snippets))
  11904 
  11905 (defun web-mode-snippet-insert (code)
  11906   "Insert a snippet."
  11907   (interactive
  11908    (list (completing-read "Snippet: " (web-mode-snippet-names))))
  11909   (let (beg
  11910         (continue t)
  11911         (counter 0)
  11912         end
  11913         sel
  11914         snippet
  11915         (l (length web-mode-snippets))
  11916         pos)
  11917     (when mark-active
  11918       (setq sel (web-mode-trim (buffer-substring-no-properties
  11919                                 (region-beginning) (region-end))))
  11920       (delete-region (region-beginning) (region-end)))
  11921     (while (and continue (< counter l))
  11922       (setq snippet (nth counter web-mode-snippets))
  11923       (when (string= (car snippet) code)
  11924         (setq continue nil))
  11925       (setq counter (1+ counter)))
  11926     (when snippet
  11927       (setq snippet (cdr snippet))
  11928       (setq beg (line-beginning-position))
  11929       (insert snippet)
  11930       (setq pos (point)
  11931             end (point))
  11932       (cond
  11933         ((string-match-p "¦" snippet)
  11934          (search-backward "¦")
  11935          (delete-char 1)
  11936          (setq pos (point)
  11937                end (1- end)))
  11938         ((string-match-p "|" snippet)
  11939          (search-backward "|")
  11940          (delete-char 1)
  11941          (setq pos (point)
  11942                end (1- end)))
  11943         ) ;cond
  11944       (when sel
  11945         (insert sel)
  11946         (setq pos (point)
  11947               end (+ end (length sel))))
  11948       (goto-char end)
  11949       (setq end (line-end-position))
  11950       (unless sel (goto-char pos))
  11951       (indent-region beg end))
  11952     ))
  11953 
  11954 (defun web-mode-looking-at (regexp pos)
  11955   (save-excursion
  11956     (goto-char pos)
  11957     (looking-at regexp)))
  11958 
  11959 (defun web-mode-looking-at-p (regexp pos)
  11960   (save-excursion
  11961     (goto-char pos)
  11962     (looking-at-p regexp)))
  11963 
  11964 (defun web-mode-looking-back (regexp pos &optional limit greedy)
  11965   (save-excursion
  11966     (goto-char pos)
  11967     (if limit
  11968         (looking-back regexp limit greedy)
  11969         (looking-back regexp (point-min)))))
  11970 
  11971 (defun web-mode-insert-text-at-pos (text pos)
  11972   (let ((mem web-mode-enable-auto-pairing))
  11973     (setq web-mode-enable-auto-pairing nil)
  11974     (save-excursion
  11975       (goto-char pos)
  11976       (insert text)
  11977       (setq web-mode-enable-auto-pairing mem)
  11978       )))
  11979 
  11980 (defun web-mode-remove-text-at-pos (n &optional pos)
  11981   (unless pos (setq pos (point)))
  11982   (delete-region pos (+ pos n)))
  11983 
  11984 (defun web-mode-insert-and-indent (text)
  11985   (let (beg end)
  11986     (setq beg (line-beginning-position))
  11987     (insert text)
  11988     (setq end (line-end-position))
  11989     (indent-region beg end)
  11990     ))
  11991 
  11992 (defun web-mode-column-at-pos (pos)
  11993   (save-excursion
  11994     (goto-char pos)
  11995     (current-column)))
  11996 
  11997 (defun web-mode-indentation-at-pos (pos)
  11998   (save-excursion
  11999     (goto-char pos)
  12000     (current-indentation)))
  12001 
  12002 (defun web-mode-navigate (&optional pos)
  12003   "Move point to the matching opening/closing tag/block."
  12004   (interactive)
  12005   (unless pos (setq pos (point)))
  12006   (let (init)
  12007     (goto-char pos)
  12008     (setq init (point))
  12009     (when (> (current-indentation) (current-column))
  12010       (back-to-indentation))
  12011     (setq pos (point))
  12012     (cond
  12013       ((and (get-text-property pos 'block-side)
  12014             (web-mode-block-beginning)
  12015             (web-mode-block-controls-get (point)))
  12016        (web-mode-block-match))
  12017       ((member (get-text-property pos 'tag-type) '(start end))
  12018        (web-mode-tag-beginning)
  12019        (web-mode-tag-match))
  12020       (t
  12021        (goto-char init))
  12022       )
  12023     ))
  12024 
  12025 (defun web-mode-block-match (&optional pos)
  12026   (unless pos (setq pos (point)))
  12027   (let (pos-ori controls control (counter 1) type (continue t) pair)
  12028     (setq pos-ori pos)
  12029     (goto-char pos)
  12030     (setq controls (web-mode-block-controls-get pos))
  12031     ;;(message "controls=%S" controls)
  12032     (cond
  12033       (controls
  12034        (setq pair (car controls))
  12035        (setq control (cdr pair))
  12036        (setq type (car pair))
  12037        (when (eq type 'inside) (setq type 'close))
  12038        (while continue
  12039          (cond
  12040            ((and (> pos-ori 1) (bobp))
  12041             (setq continue nil))
  12042            ((or (and (eq type 'open) (not (web-mode-block-next)))
  12043                 (and (eq type 'close) (not (web-mode-block-previous))))
  12044             (setq continue nil)
  12045             )
  12046            ((null (setq controls (web-mode-block-controls-get (point))))
  12047             )
  12048            (t
  12049             ;;TODO : est il nécessaire de faire un reverse sur controls si on doit matcher backward
  12050             (dolist (pair controls)
  12051               (cond
  12052                 ((not (string= (cdr pair) control))
  12053                  )
  12054                 ((eq (car pair) 'inside)
  12055                  )
  12056                 ((eq (car pair) type)
  12057                  (setq counter (1+ counter)))
  12058                 (t
  12059                  (setq counter (1- counter)))
  12060                 )
  12061               ) ;dolist
  12062             (when (= counter 0)
  12063               (setq continue nil))
  12064             ) ;t
  12065            ) ;cond
  12066          ) ;while
  12067        (if (= counter 0) (point) nil)
  12068        ) ;controls
  12069       (t
  12070        (goto-char pos-ori)
  12071        nil
  12072        ) ;controls = nul
  12073       ) ;conf
  12074     ))
  12075 
  12076 (defun web-mode-tag-match (&optional pos)
  12077   "Move point to the matching opening/closing tag."
  12078   (interactive)
  12079   (unless pos (setq pos (point)))
  12080   (let (regexp name)
  12081     (cond
  12082       ((eq (get-text-property pos 'tag-type) 'void)
  12083        (web-mode-tag-beginning))
  12084       ((and (eq (get-text-property pos 'tag-type) 'comment)
  12085             (web-mode-looking-at-p "<!--#\\(elif\\|else\\|endif\\|if\\)" pos))
  12086        (setq regexp "<!--#\\(end\\)?if")
  12087        (if (web-mode-looking-at-p "<!--#if" pos)
  12088            (web-mode-tag-fetch-closing regexp pos)
  12089            (web-mode-tag-fetch-opening regexp pos))
  12090        )
  12091       (t
  12092        (setq name (get-text-property pos 'tag-name))
  12093        (when (string= name "_fragment_") (setq name ">"))
  12094        (setq regexp (concat "</?" name))
  12095        (when (member (get-text-property pos 'tag-type) '(start end))
  12096          (web-mode-tag-beginning)
  12097          (setq pos (point)))
  12098        (if (eq (get-text-property pos 'tag-type) 'end)
  12099            (web-mode-tag-fetch-opening regexp pos)
  12100            (web-mode-tag-fetch-closing regexp pos))
  12101        ) ;t
  12102       ) ;cond
  12103     t))
  12104 
  12105 (defun web-mode-tag-fetch-opening (regexp pos)
  12106   (let ((counter 1) (n 0) (is-comment nil) (types '(start end)))
  12107     (when (eq (aref regexp 1) ?\!)
  12108       (setq types '(comment)
  12109             is-comment t))
  12110     (goto-char pos)
  12111     (while (and (> counter 0) (re-search-backward regexp nil t))
  12112       (when (and (get-text-property (point) 'tag-beg)
  12113                  (member (get-text-property (point) 'tag-type) types))
  12114         (setq n (1+ n))
  12115         (cond
  12116           ((and is-comment
  12117                 (eq (aref (match-string-no-properties 0) 5) ?e))
  12118            (setq counter (1+ counter)))
  12119           (is-comment
  12120            (setq counter (1- counter)))
  12121           ((eq (get-text-property (point) 'tag-type) 'end)
  12122            (setq counter (1+ counter)))
  12123           (t
  12124            (setq counter (1- counter))
  12125            )
  12126           )
  12127         )
  12128       )
  12129     (if (= n 0) (goto-char pos))
  12130     ))
  12131 
  12132 (defun web-mode-tag-fetch-closing (regexp pos)
  12133   (let ((counter 1) (is-comment nil) (n 0))
  12134     (when (eq (aref regexp 1) ?\!)
  12135       (setq is-comment t))
  12136     (goto-char pos)
  12137     (web-mode-tag-end)
  12138     (while (and (> counter 0) (re-search-forward regexp nil t))
  12139       (when (get-text-property (match-beginning 0) 'tag-beg)
  12140         (setq n (1+ n))
  12141         (cond
  12142           ((and is-comment
  12143                 (eq (aref (match-string-no-properties 0) 5) ?e))
  12144            (setq counter (1- counter)))
  12145           (is-comment
  12146            (setq counter (1+ counter)))
  12147           ((eq (get-text-property (point) 'tag-type) 'end)
  12148            (setq counter (1- counter)))
  12149           (t
  12150            (setq counter (1+ counter)))
  12151           )
  12152         ) ;when
  12153       ) ;while
  12154     (if (> n 0)
  12155         (web-mode-tag-beginning)
  12156         (goto-char pos))
  12157     ))
  12158 
  12159 (defun web-mode-element-tag-name (&optional pos)
  12160   (unless pos (setq pos (point)))
  12161   (save-excursion
  12162     (goto-char pos)
  12163     (if (and (web-mode-tag-beginning)
  12164              (looking-at web-mode-tag-regexp))
  12165         (match-string-no-properties 1)
  12166         nil)))
  12167 
  12168 (defun web-mode-element-close ()
  12169   "Close html element."
  12170   (interactive)
  12171   (let (jmp epp ins tag)
  12172 
  12173     (if (and (eq (char-before) ?\>)
  12174              (web-mode-element-is-void (get-text-property (1- (point)) 'tag-name)))
  12175         (unless (eq (char-before (1- (point))) ?\/)
  12176           (backward-char)
  12177           (insert "/")
  12178           (forward-char))
  12179         (setq epp (web-mode-element-parent-position)))
  12180 
  12181     ;;(message "epp=%S" epp)
  12182     (when epp
  12183       (setq tag (get-text-property epp 'tag-name))
  12184       (setq tag (web-mode-element-tag-name epp))
  12185       ;;(message "tag=%S %c" tag (char-before))
  12186       (cond
  12187         ((or (null tag) (web-mode-element-is-void tag))
  12188          (setq epp nil))
  12189         ((looking-back "</" (point-min))
  12190          (setq ins tag))
  12191         ((looking-back "<" (point-min))
  12192          (setq ins (concat "/" tag)))
  12193         (t
  12194          ;;auto-close-style = 2
  12195          ;;(message "%S %c" (point) (char-after))
  12196          (when (and (looking-at-p "[[:alpha:]]") (> (length tag) 4))
  12197            (dolist (elt '("div" "span" "strong" "pre" "li"))
  12198              (when (and (string-match-p (concat "^" elt) tag) (not (string= tag elt)))
  12199                (setq tag elt)
  12200                (put-text-property epp (point) 'tag-name tag))
  12201              )
  12202            ) ;when
  12203          (if (web-mode-element-is-void (get-text-property (point) 'tag-name))
  12204              (setq ins nil
  12205                    epp nil)
  12206              (setq ins (concat "</" tag)))
  12207          )
  12208         ) ;cond
  12209       (when ins
  12210         (unless (looking-at-p "[ ]*>")
  12211           (setq ins (concat ins ">")))
  12212         (insert ins)
  12213         (setq tag (downcase tag))
  12214         (save-excursion
  12215           (search-backward "<")
  12216           (setq jmp (and (eq (char-before) ?\>)
  12217                          (string= (get-text-property (1- (point)) 'tag-name) tag)))
  12218           (if jmp (setq jmp (point)))
  12219           ) ;save-excursion
  12220         (if jmp (goto-char jmp))
  12221         ) ;when not ins
  12222       ) ;when epp
  12223     epp))
  12224 
  12225 (defun web-mode-detect-content-type ()
  12226   (cond
  12227     ((and (string= web-mode-engine "none")
  12228           (< (point) 16)
  12229           (eq (char-after 1) ?\#)
  12230           (string-match-p "php" (buffer-substring-no-properties
  12231                                  (line-beginning-position)
  12232                                  (line-end-position))))
  12233      (web-mode-set-engine "php"))
  12234     ((and (string= web-mode-content-type "javascript")
  12235           (< (point) web-mode-chunk-length)
  12236           (eq (char-after (point-min)) ?\/)
  12237           (string-match-p "@jsx" (buffer-substring-no-properties
  12238                                   (line-beginning-position)
  12239                                   (line-end-position))))
  12240      (web-mode-set-content-type "jsx"))
  12241     ))
  12242 
  12243 (defun web-mode-auto-complete ()
  12244   "Autocomple at point."
  12245   (interactive)
  12246   (let ((pos (point))
  12247         (char (char-before))
  12248         (chunk (buffer-substring-no-properties (- (point) 2) (point)))
  12249         (expanders nil) (tag nil)
  12250         (auto-closed   nil)
  12251         (auto-expanded nil)
  12252         (auto-paired   nil)
  12253         (auto-quoted   nil))
  12254 
  12255     ;;-- auto-closing
  12256     (when web-mode-enable-auto-closing
  12257 
  12258       (cond
  12259 
  12260         ((and (= web-mode-auto-close-style 3)
  12261               (eq char ?\<))
  12262          (insert "/>")
  12263          (backward-char 2)
  12264          (setq auto-closed t))
  12265 
  12266         ((and (= web-mode-auto-close-style 3)
  12267               (eq char ?\>)
  12268               (looking-at-p "/>"))
  12269          (save-excursion
  12270            (re-search-backward web-mode-start-tag-regexp)
  12271            (setq tag (match-string-no-properties 1)))
  12272          (insert "<")
  12273          (forward-char)
  12274          (insert tag)
  12275          (setq auto-closed t))
  12276 
  12277         ((and (>= pos 4)
  12278               (or (string= "</" chunk)
  12279                   ;;(progn (message "%c" char) nil)
  12280                   (and (= web-mode-auto-close-style 2)
  12281                        (or (string= web-mode-content-type "jsx")
  12282                            (not (get-text-property pos 'part-side)))
  12283                        (string-match-p "[[:alnum:]'\"]>" chunk)))
  12284               (not (get-text-property (- pos 2) 'block-side))
  12285               (web-mode-element-close))
  12286          (setq auto-closed t))
  12287 
  12288         ) ;cond
  12289       ) ;when
  12290 
  12291     ;;-- auto-pairing
  12292     (when (and web-mode-enable-auto-pairing
  12293                (>= pos 4)
  12294                (not auto-closed))
  12295       (let ((i 0) expr after pos-end (l (length web-mode-auto-pairs)))
  12296         (setq pos-end (if (> (+ pos 32) (line-end-position))
  12297                           (line-end-position)
  12298                           (+ pos 10)))
  12299         (setq chunk (buffer-substring-no-properties (- pos 3) pos)
  12300               after (buffer-substring-no-properties pos pos-end))
  12301         (while (and (< i l) (not auto-paired))
  12302           (setq expr (elt web-mode-auto-pairs i)
  12303                 i (1+ i))
  12304           ;;(message "chunk=%S expr=%S after=%S" chunk expr after)
  12305           (when (and (string= (car expr) chunk)
  12306                      (not (string-match-p (regexp-quote (cdr expr)) after)))
  12307             (setq auto-paired t)
  12308             (insert (cdr expr))
  12309             (if (string-match-p "|" (cdr expr))
  12310                 (progn
  12311                   (search-backward "|")
  12312                   (delete-char 1))
  12313                 (goto-char pos))
  12314             ) ;when
  12315           ) ;while
  12316         ) ;let
  12317       )
  12318 
  12319     ;;-- auto-expanding
  12320     (when (and web-mode-enable-auto-expanding
  12321                (not auto-closed)
  12322                (not auto-paired)
  12323                (eq char ?\/)
  12324                (looking-back "\\(^\\|[[:punct:][:space:]>]\\)./" (point-min))
  12325                (or (web-mode-jsx-is-html (1- pos))
  12326                    (and (not (get-text-property (1- pos) 'tag-type))
  12327                         (not (get-text-property (1- pos) 'part-side))))
  12328                (not (get-text-property (1- pos) 'block-side))
  12329                )
  12330       (setq expanders (append web-mode-extra-expanders web-mode-expanders))
  12331       (let ((i 0) pair (l (length expanders)))
  12332         (setq chunk (buffer-substring-no-properties (- pos 2) pos))
  12333         ;;(message "%S" chunk)
  12334         (while (and (< i l) (not auto-expanded))
  12335           (setq pair (elt expanders i)
  12336                 i (1+ i))
  12337           (when (string= (car pair) chunk)
  12338             (setq auto-expanded t)
  12339             (delete-char -2)
  12340             (insert (cdr pair))
  12341             (when (string-match-p "|" (cdr pair))
  12342               (search-backward "|")
  12343               (delete-char 1))
  12344             ) ;when
  12345           ) ;while
  12346         ) ;let
  12347       )
  12348 
  12349     ;;-- auto-quoting
  12350     (when (and web-mode-enable-auto-quoting
  12351                (>= pos 4)
  12352                (not (get-text-property pos 'block-side))
  12353                (not auto-closed)
  12354                (not auto-paired)
  12355                (not auto-expanded)
  12356                (get-text-property (- pos 2) 'tag-attr))
  12357       (cond
  12358         ((and (eq char ?\=)
  12359               (not (looking-at-p "[ ]*[\"']")))
  12360          (cond ((= web-mode-auto-quote-style 2)
  12361                 (insert "''"))
  12362                ((= web-mode-auto-quote-style 3)
  12363                 (insert "{}"))
  12364                (t
  12365                 (insert "\"\"")))
  12366          (if (looking-at-p "[ \n>]")
  12367              (backward-char)
  12368              (insert " ")
  12369              (backward-char 2)
  12370              )
  12371          (setq auto-quoted t))
  12372         ((and (eq char ?\")
  12373               (looking-back "=[ ]*\"" (point-min))
  12374               (not (looking-at-p "[ ]*[\"]")))
  12375          (insert-and-inherit "\"")
  12376          (backward-char)
  12377          (setq auto-quoted t))
  12378         ((and (eq char ?\')
  12379               (looking-back "=[ ]*'" (point-min))
  12380               (not (looking-at-p "[ ]*[']")))
  12381          (insert-and-inherit "'")
  12382          (backward-char)
  12383          (setq auto-quoted t))
  12384         ((and (eq char ?\{)
  12385               (eq (get-text-property pos 'part-side) 'jsx)
  12386               (looking-back "=[ ]*{" (point-min))
  12387               (not (looking-at-p "[ ]*[}]")))
  12388          (insert-and-inherit "}")
  12389          (backward-char)
  12390          (setq auto-quoted t))
  12391         ((and (eq char ?\")
  12392               (eq (char-after) ?\"))
  12393          (delete-char 1)
  12394          (cond
  12395            ((looking-back "=\"\"" (point-min))
  12396             (backward-char))
  12397            ((eq (char-after) ?\s)
  12398             (forward-char))
  12399            (t
  12400             (insert " "))
  12401            ) ;cond
  12402          )
  12403         ) ;cond
  12404       ) ;when
  12405 
  12406     ;;--
  12407     (cond
  12408       ((or auto-closed auto-paired auto-expanded auto-quoted)
  12409        (when (and web-mode-change-end (>= (line-end-position) web-mode-change-end))
  12410          (setq web-mode-change-end (line-end-position)))
  12411        (list :auto-closed auto-closed
  12412              :auto-paired auto-paired
  12413              :auto-expanded auto-expanded
  12414              :auto-quoted auto-quoted))
  12415       (t
  12416        nil)
  12417       )
  12418 
  12419     ))
  12420 
  12421 (defun web-mode-dom-xpath (&optional pos)
  12422   "Display html path."
  12423   (interactive)
  12424   (unless pos (setq pos (point)))
  12425   (save-excursion
  12426     (goto-char pos)
  12427     (let (path tag)
  12428       (while (web-mode-element-parent)
  12429         (looking-at web-mode-tag-regexp)
  12430         (setq tag (match-string-no-properties 1))
  12431         (setq path (cons tag path))
  12432         )
  12433       (message "/%s" (mapconcat 'identity path "/"))
  12434       )))
  12435 
  12436 (defun web-mode-block-ends-with (regexp &optional pos)
  12437   (unless pos (setq pos (point)))
  12438   (save-excursion
  12439     (goto-char pos)
  12440     (save-match-data
  12441       (if (stringp regexp)
  12442           (and (web-mode-block-end)
  12443                (progn (backward-char) t)
  12444                (web-mode-block-skip-blank-backward)
  12445                (progn (forward-char) t)
  12446                (looking-back regexp (point-min)))
  12447           (let ((pair regexp)
  12448                 (block-beg (web-mode-block-beginning-position pos))
  12449                 (block-end (web-mode-block-end-position pos)))
  12450             (and (web-mode-block-end)
  12451                  (web-mode-block-sb (car pair) block-beg)
  12452                  (not (web-mode-sf (cdr pair) block-end)))
  12453             ) ;let
  12454           ) ;if
  12455       )))
  12456 
  12457 (defun web-mode-block-token-starts-with (regexp &optional pos)
  12458   (unless pos (setq pos (point)))
  12459   (save-excursion
  12460     (and (goto-char pos)
  12461          (web-mode-block-token-beginning)
  12462          (skip-chars-forward "[\"']")
  12463          (looking-at regexp))
  12464     ))
  12465 
  12466 (defun web-mode-block-starts-with (regexp &optional pos)
  12467   (unless pos (setq pos (point)))
  12468   (save-excursion
  12469     (and (web-mode-block-beginning)
  12470          (web-mode-block-skip-blank-forward)
  12471          (looking-at regexp))
  12472     ))
  12473 
  12474 (defun web-mode-block-skip-blank-backward (&optional pos)
  12475   (unless pos (setq pos (point)))
  12476   (let ((continue t))
  12477     (goto-char pos)
  12478     (while continue
  12479       (if (and (get-text-property (point) 'block-side)
  12480                (not (bobp))
  12481                (or (member (char-after) '(?\s ?\n))
  12482                    (member (get-text-property (point) 'block-token)
  12483                            '(delimiter-beg delimiter-end comment))))
  12484           (backward-char)
  12485           (setq continue nil))
  12486       ) ;while
  12487     (point)))
  12488 
  12489 (defun web-mode-block-skip-blank-forward (&optional pos props)
  12490   (unless pos (setq pos (point)))
  12491   (unless props (setq props '(delimiter-beg delimiter-end comment)))
  12492   (let ((continue t))
  12493     (goto-char pos)
  12494     (while continue
  12495       (if (and (get-text-property (point) 'block-side)
  12496                (or (member (char-after) '(?\s ?\n ?\t))
  12497                    (member (get-text-property (point) 'block-token) props)))
  12498           (forward-char)
  12499           (setq continue nil))
  12500       ) ;while
  12501     (point)))
  12502 
  12503 (defun web-mode-tag-attributes-sort (&optional pos)
  12504   "Sort the attributes inside the current html tag."
  12505   (interactive)
  12506   (unless pos (setq pos (point)))
  12507   (save-excursion
  12508     (let (attrs (continue t) min max tag-beg tag-end attr attr-name attr-beg attr-end indent sorter ins)
  12509       (if (not (member (get-text-property pos 'tag-type) '(start void)))
  12510           nil
  12511           (setq tag-beg (web-mode-tag-beginning-position pos)
  12512                 tag-end (web-mode-tag-end-position))
  12513           ;;        (message "%S %S" tag-beg tag-end)
  12514           (goto-char tag-beg)
  12515           (while continue
  12516             (if (or (not (web-mode-attribute-next))
  12517                     (>= (point) tag-end))
  12518                 (setq continue nil)
  12519                 ;;(message "attr=%S" (point))
  12520                 (setq attr-beg (web-mode-attribute-beginning-position)
  12521                       attr-end (1+ (web-mode-attribute-end-position)))
  12522                 (when (null min)
  12523                   (setq min attr-beg))
  12524                 (setq max attr-end)
  12525                 (goto-char attr-beg)
  12526                 (setq attr (buffer-substring-no-properties attr-beg attr-end))
  12527                 (if (string-match "^\\([[:alnum:]-]+\\)=" attr)
  12528                     (setq attr-name (match-string-no-properties 1 attr))
  12529                     (setq attr-name attr))
  12530                 (setq indent (looking-back "^[ \t]*" (point-min)))
  12531                 (setq attrs (append attrs (list (list attr-beg attr-end attr-name attr indent))))
  12532                 ) ;if
  12533             ) ;while
  12534           ) ;if in tag
  12535       (when attrs
  12536         (setq sorter (function
  12537                       (lambda (elt1 elt2)
  12538                        (string< (nth 2 elt1) (nth 2 elt2))
  12539                        )))
  12540         (setq attrs (sort attrs sorter))
  12541         (delete-region (1- min) max)
  12542         (setq ins "")
  12543         (dolist (elt attrs)
  12544           (if (and (nth 4 elt) (> (length ins) 1))
  12545               (setq ins (concat ins "\n"))
  12546               (setq ins (concat ins " ")))
  12547           (setq ins (concat ins (nth 3 elt)))
  12548           )
  12549         (goto-char (1- min))
  12550         (insert ins)
  12551         (web-mode-tag-beginning)
  12552         (setq min (line-beginning-position))
  12553         (web-mode-tag-end)
  12554         (setq max (line-end-position))
  12555         (indent-region min max)
  12556         )
  12557       ;;(message "attrs=%S" attrs)
  12558       )))
  12559 
  12560 (defun web-mode-attribute-insert (&optional _attr-name _attr-value)
  12561   "Insert an attribute inside current tag."
  12562   (interactive)
  12563   (let (attr attr-name attr-value)
  12564     (cond
  12565       ((not (member (get-text-property (point) 'tag-type) '(start void)))
  12566        (message "attribute-insert ** invalid context **"))
  12567       ((not (and (setq attr-name (or attr-name (completing-read
  12568                                                 "Attribute name: "
  12569                                                 (append
  12570                                                  web-mode-attribute-list
  12571                                                  web-mode-attribute-history)
  12572                                                 nil nil nil 'web-mode-attribute-history)))
  12573                  (> (length attr-name) 0)))
  12574        (message "attribute-insert ** failure **"))
  12575       (t
  12576        (setq attr (concat " " attr-name))
  12577        (when (setq attr-value (or attr-value (completing-read
  12578                                               "Attribute value: "
  12579                                               web-mode-attribute-value-history
  12580                                               nil nil nil 'web-mode-attribute-value-history)))
  12581          (setq attr (concat attr "=\"" attr-value "\"")))
  12582        (web-mode-tag-end)
  12583        (if (looking-back "/>" (point-min))
  12584            (backward-char 2)
  12585            (backward-char))
  12586        (insert attr)
  12587        ) ;t
  12588       ) ;cond
  12589     ))
  12590 
  12591 (defun web-mode-attribute-transpose (&optional pos)
  12592   "Transpose the current html attribute."
  12593   (interactive)
  12594   (unless pos (setq pos (point)))
  12595   (let (attr-beg attr-end next-beg next-end tag-end)
  12596     (when (and (get-text-property pos 'tag-attr)
  12597                (setq next-beg (web-mode-attribute-next-position pos))
  12598                (setq next-end (web-mode-attribute-end-position next-beg))
  12599                (setq tag-end (web-mode-tag-end-position pos))
  12600                (> tag-end next-end))
  12601       (setq attr-beg (web-mode-attribute-beginning-position pos)
  12602             attr-end (web-mode-attribute-end-position pos))
  12603       ;;      (message "%S %S - %S %S" attr-beg attr-end next-beg next-end)
  12604       (transpose-regions attr-beg (1+ attr-end) next-beg (1+ next-end))
  12605       )))
  12606 
  12607 (defun web-mode-attribute-select (&optional pos)
  12608   "Select the current html attribute."
  12609   (interactive)
  12610   (unless pos (setq pos (point)))
  12611   (if (null (get-text-property pos 'tag-attr))
  12612       nil
  12613       (goto-char pos)
  12614       (web-mode-attribute-beginning)
  12615       (set-mark (point))
  12616       (web-mode-attribute-end)
  12617       (exchange-point-and-mark)
  12618       (point)
  12619       ))
  12620 
  12621 (defun web-mode-attribute-kill (&optional arg)
  12622   "Kill the current html attribute."
  12623   (interactive "p")
  12624   (unless arg (setq arg 1))
  12625   (while (>= arg 1)
  12626     (setq arg (1- arg))
  12627     (web-mode-attribute-select)
  12628     (when mark-active
  12629       (let ((beg (region-beginning)) (end (region-end)))
  12630         (save-excursion
  12631           (goto-char end)
  12632           (when (looking-at "[ \n\t]*")
  12633             (setq end (+ end (length (match-string-no-properties 0)))))
  12634           ) ;save-excursion
  12635         (kill-region beg end)
  12636         ) ;let
  12637       ) ;when
  12638     ) ;while
  12639   ;; Delete a potential space before the closing ">".
  12640   (when (and (looking-at ">")
  12641              (looking-back " " (point-min)))
  12642     (delete-char -1))
  12643   )
  12644 
  12645 (defun web-mode-block-close (&optional pos)
  12646   "Close the first unclosed control block."
  12647   (interactive)
  12648   (unless pos (setq pos (point)))
  12649   (let ((continue t)
  12650         (h (make-hash-table :test 'equal)) ctx ctrl n closing-block)
  12651     (save-excursion
  12652       (while (and continue (web-mode-block-previous))
  12653         (when (setq ctx (web-mode-block-is-control (point)))
  12654           (setq ctrl (car ctx))
  12655           (setq n (gethash ctrl h 0))
  12656           (if (cdr ctx)
  12657               (puthash ctrl (1+ n) h)
  12658               (puthash ctrl (1- n) h))
  12659           (when (> (gethash ctrl h) 0)
  12660             (setq continue nil))
  12661           )
  12662         ) ;while
  12663       ) ;save-excursion
  12664     (when (and (null continue)
  12665                (setq closing-block (web-mode-closing-block ctrl)))
  12666       (insert closing-block)
  12667       (indent-according-to-mode))
  12668     ))
  12669 
  12670 (defun web-mode-closing-block (type)
  12671   (cond
  12672     ((string= web-mode-engine "php")              (concat "<?php end" type "; ?>"))
  12673     ((string= web-mode-engine "django")           (concat "{% end" type " %}"))
  12674     ((string= web-mode-engine "antlers")          (concat "{{/" type "}}"))
  12675     ((string= web-mode-engine "ctemplate")        (concat "{{/" type "}}"))
  12676     ((string= web-mode-engine "blade")
  12677      (if (string= type "section") (concat "@show") (concat "@end" type)))
  12678     ((string= web-mode-engine "dust")             (concat "{/" type "}"))
  12679     ((string= web-mode-engine "mako")             (concat "% end" type))
  12680     ((string= web-mode-engine "closure")          (concat "{/" type "}"))
  12681     ((string= web-mode-engine "smarty")           (concat "{/" type "}"))
  12682     ((string= web-mode-engine "expressionengine") (concat "{/" type "}"))
  12683     ((string= web-mode-engine "xoops")            (concat "<{/" type "}>"))
  12684     ((string= web-mode-engine "svelte")           (concat "{/" type "}"))
  12685     ((string= web-mode-engine "underscore")        "<% } %>")
  12686     ((string= web-mode-engine "lsp")               "<% ) %>")
  12687     ((string= web-mode-engine "erb")               "<% } %>")
  12688     ((string= web-mode-engine "erb")               "<% end %>")
  12689     ((string= web-mode-engine "artanis")           "<% ) %>")
  12690     ((string= web-mode-engine "hero")              "<% } %>")
  12691     ((string= web-mode-engine "go")                "{{end}}")
  12692     ((string= web-mode-engine "velocity")          "#end")
  12693     ((string= web-mode-engine "velocity")          "#{end}")
  12694     ((string= web-mode-engine "template-toolkit")  "[% end %]")
  12695     ((member web-mode-engine '("asp" "jsp"))
  12696      (if (string-match-p "[:.]" type) (concat "</" type ">") "<% } %>"))
  12697     (t nil)
  12698     ) ;cond
  12699   )
  12700 
  12701 ;;---- POSITION ----------------------------------------------------------------
  12702 
  12703 (defun web-mode-comment-beginning-position (&optional pos)
  12704   (unless pos (setq pos (point)))
  12705   (car (web-mode-comment-boundaries pos)))
  12706 
  12707 (defun web-mode-comment-end-position (&optional pos)
  12708   (unless pos (setq pos (point)))
  12709   (cdr (web-mode-comment-boundaries pos)))
  12710 
  12711 (defun web-mode-part-opening-paren-position (pos &optional limit)
  12712   (save-restriction
  12713     (unless limit (setq limit nil))
  12714     (goto-char pos)
  12715     (let* ((n -1)
  12716            (paren (char-after))
  12717            (pairs '((?\) . "[)(]")
  12718                     (?\] . "[\]\[]")
  12719                     (?\} . "[}{]")
  12720                     (?\> . "[><]")))
  12721            (regexp (cdr (assoc paren pairs)))
  12722            (continue (not (null regexp)))
  12723            (counter 0))
  12724       (while (and continue (re-search-backward regexp limit t))
  12725         (cond
  12726           ((> (setq counter (1+ counter)) 500)
  12727            (message "part-opening-paren-position ** warning **")
  12728            (setq continue nil))
  12729           ((or (web-mode-is-comment-or-string)
  12730                (get-text-property (point) 'block-side))
  12731            )
  12732           ((eq (char-after) paren)
  12733            (setq n (1- n)))
  12734           (t
  12735            (setq n (1+ n))
  12736            (setq continue (not (= n 0))))
  12737           )
  12738         ) ;while
  12739       (if (= n 0) (point) nil)
  12740       )))
  12741 
  12742 (defun web-mode-token-opening-paren-position (pos limit _context)
  12743   (save-restriction
  12744     (unless limit (setq limit nil))
  12745     (goto-char pos)
  12746     (let* ((n -1)
  12747            (paren (char-after))
  12748            (pairs '((?\) . "[)(]")
  12749                     (?\] . "[\]\[]")
  12750                     (?\} . "[}{]")
  12751                     (?\> . "[><]")))
  12752            (regexp (cdr (assoc paren pairs)))
  12753            (continue (not (null regexp)))
  12754            (counter 0))
  12755       (while (and continue (re-search-backward regexp limit t))
  12756         (cond
  12757           ((> (setq counter (1+ counter)) 200)
  12758            (message "token-opening-paren-position ** warning **")
  12759            (setq continue nil))
  12760           ((get-text-property (point) 'block-side)
  12761            )
  12762           ((eq (char-after) paren)
  12763            (setq n (1- n)))
  12764           (t
  12765            (setq n (1+ n))
  12766            (setq continue (not (= n 0))))
  12767           )
  12768         ) ;while
  12769       (if (= n 0) (point) nil)
  12770       )))
  12771 
  12772 (defun web-mode-closing-paren-position (&optional pos limit)
  12773   (save-excursion
  12774     (unless pos (setq pos (point)))
  12775     (unless limit (setq limit nil))
  12776     (goto-char pos)
  12777     (let* ((n 0)
  12778            (block-side (and (get-text-property pos 'block-side)
  12779                             (not (string= web-mode-engine "razor"))))
  12780            (paren (char-after))
  12781            (pairs '((?\( . "[)(]")
  12782                     (?\[ . "[\]\[]")
  12783                     (?\{ . "[}{]")
  12784                     (?\< . "[><]")))
  12785            (regexp (cdr (assoc paren pairs)))
  12786            (continue (not (null regexp))))
  12787       (while (and continue (re-search-forward regexp limit t))
  12788         (cond
  12789           ((or (web-mode-is-comment-or-string (1- (point)))
  12790                (and block-side (not (get-text-property (point) 'block-side))))
  12791            ;;(message "pt=%S" (point))
  12792            )
  12793           ((eq (char-before) paren)
  12794            (setq n (1+ n)))
  12795           (t
  12796            (setq n (1- n))
  12797            (setq continue (not (= n 0)))
  12798            )
  12799           ) ;cond
  12800         ) ;while
  12801       (if (= n 0) (1- (point)) nil)
  12802       )))
  12803 
  12804 (defun web-mode-closing-delimiter-position (delimiter &optional pos limit)
  12805   (unless pos (setq pos (point)))
  12806   (unless limit (setq limit nil))
  12807   (save-excursion
  12808     (goto-char pos)
  12809     (setq pos nil)
  12810     (let ((continue t))
  12811       (while (and continue (re-search-forward delimiter limit t))
  12812         (setq continue nil
  12813               pos (1- (point)))
  12814         ) ;while
  12815       pos)))
  12816 
  12817 (defun web-mode-tag-match-position (&optional pos)
  12818   (unless pos (setq pos (point)))
  12819   (save-excursion
  12820     (web-mode-tag-match pos)
  12821     (if (= pos (point)) nil (point))))
  12822 
  12823 (defun web-mode-tag-beginning-position (&optional pos)
  12824   (unless pos (setq pos (point)))
  12825   (let (beg depth)
  12826     (setq depth (get-text-property pos 'jsx-depth))
  12827     (when (and depth (get-text-property pos 'tag-attr-beg))
  12828       (setq depth (get-text-property (1- pos) 'jsx-depth)))
  12829     (cond
  12830       ((null pos))
  12831       ((get-text-property pos 'tag-beg)
  12832        (setq beg pos))
  12833       ((and (> pos 1) (get-text-property (1- pos) 'tag-beg))
  12834        (setq beg (1- pos)))
  12835       ((get-text-property pos 'tag-type)
  12836        (setq beg (previous-single-property-change pos 'tag-beg))
  12837        (when beg (setq beg (1- beg)))
  12838        (cond
  12839          ((not (get-text-property beg 'tag-beg))
  12840           (setq beg nil))
  12841          ((and depth (not (eq depth (get-text-property beg 'jsx-depth))))
  12842           (let ((continue (> beg (point-min))))
  12843             (while continue
  12844               (setq beg (previous-single-property-change beg 'tag-beg))
  12845               (when beg (setq beg (1- beg)))
  12846               (cond
  12847                 ((null beg)
  12848                  (setq continue nil))
  12849                 ((not (get-text-property beg 'tag-beg))
  12850                  (setq continue nil
  12851                        beg nil))
  12852                 ((eq depth (get-text-property beg 'jsx-depth))
  12853                  (setq continue nil))
  12854                 ) ;cond
  12855               ) ;while
  12856             ) ;let
  12857           )
  12858          ) ;cond
  12859        )
  12860       (t
  12861        (setq beg nil))
  12862       ) ;cond
  12863     beg))
  12864 
  12865 (defun web-mode-tag-end-position (&optional pos)
  12866   (unless pos (setq pos (point)))
  12867   (let (end depth)
  12868     (setq depth (get-text-property pos 'jsx-depth))
  12869     (when (and depth (get-text-property pos 'tag-attr-beg))
  12870       (setq depth (get-text-property (1- pos) 'jsx-depth)))
  12871     (cond
  12872       ((null pos)
  12873        (setq end nil))
  12874       ((get-text-property pos 'tag-end)
  12875        (setq end pos))
  12876       ((get-text-property pos 'tag-type)
  12877        (setq end (next-single-property-change pos 'tag-end))
  12878        (cond
  12879          ((not (get-text-property end 'tag-end))
  12880           (setq end nil))
  12881          ((and depth (not (eq depth (get-text-property end 'jsx-depth))))
  12882           (let ((continue (< end (point-max))))
  12883             (while continue
  12884               (setq end (1+ end))
  12885               (setq end (next-single-property-change end 'tag-end))
  12886               (cond
  12887                 ((null end)
  12888                  (setq continue nil))
  12889                 ((not (get-text-property end 'tag-end))
  12890                  (setq continue nil
  12891                        end nil))
  12892                 ((eq depth (get-text-property end 'jsx-depth))
  12893                  (setq continue nil))
  12894                 ) ;cond
  12895               ) ;while
  12896             ) ;let
  12897           )
  12898          ) ;cond
  12899        )
  12900       (t
  12901        (setq end nil))
  12902       ) ;cond
  12903     end))
  12904 
  12905 ;; TODO: prendre en compte jsx-depth
  12906 (defun web-mode-tag-next-position (&optional pos limit)
  12907   (unless pos (setq pos (point)))
  12908   (unless limit (setq limit (point-max)))
  12909   (cond
  12910     ((or (>= pos (point-max)) (>= pos limit)) nil)
  12911     (t
  12912      (when (get-text-property pos 'tag-beg) (setq pos (1+ pos)))
  12913      (setq pos (next-single-property-change pos 'tag-beg))
  12914      (if (and pos (<= pos limit)) pos nil))
  12915     ))
  12916 
  12917 ;; TODO: prendre en compte jsx-depth
  12918 (defun web-mode-tag-previous-position (&optional pos limit)
  12919   (unless pos (setq pos (point)))
  12920   (unless limit (setq limit (point-min)))
  12921   (cond
  12922     ((or (<= pos (point-min)) (<= pos limit)) nil)
  12923     (t
  12924      (when (get-text-property pos 'tag-beg) (setq pos (1- pos)))
  12925      (web-mode-go (previous-single-property-change pos 'tag-beg) -1))
  12926     ))
  12927 
  12928 ;; TODO: prendre en compte jsx-depth
  12929 (defun web-mode-attribute-beginning-position (&optional pos)
  12930   (unless pos (setq pos (point)))
  12931   (cond
  12932     ((null (get-text-property pos 'tag-attr))
  12933      nil)
  12934     ((get-text-property pos 'tag-attr-beg)
  12935      pos)
  12936     ((and (> pos (point-min)) (get-text-property (1- pos) 'tag-attr-beg))
  12937      (1- pos))
  12938     (t
  12939      (setq pos (previous-single-property-change pos 'tag-attr-beg))
  12940      (setq pos (1- pos)))
  12941     ))
  12942 
  12943 ;; TODO: retoucher en incluant un param limit et en s'inspirant de
  12944 ;;       web-mode-attribute-next-position
  12945 (defun web-mode-attribute-end-position (&optional pos)
  12946   (unless pos (setq pos (point)))
  12947   (let (beg end depth flags)
  12948     ;;(message "pos=%S" pos)
  12949     (setq depth (get-text-property pos 'jsx-depth))
  12950     (cond
  12951       ((null pos)
  12952        (setq end nil))
  12953       ((get-text-property pos 'tag-attr-end)
  12954        (setq end pos))
  12955       ((get-text-property pos 'tag-attr)
  12956        (setq end (next-single-property-change pos 'tag-attr-end))
  12957        (when (and depth
  12958                   end
  12959                   (setq beg (web-mode-attribute-beginning-position end))
  12960                   (setq flags (get-text-property pos 'tag-attr-beg))
  12961                   (eq (logand flags 4) 4))
  12962          (setq depth (1- (get-text-property beg 'jsx-depth)))
  12963          ;;(message "%S %S" beg end)
  12964          )
  12965        (cond
  12966          ((not (get-text-property end 'tag-attr-end))
  12967           (setq end nil))
  12968          ((and depth
  12969                (eq depth (get-text-property end 'jsx-depth))
  12970                (not (eq depth (get-text-property end 'jsx-end))))
  12971           )
  12972          ((and depth (eq (1+ depth) (get-text-property end 'jsx-depth)))
  12973           )
  12974          ((and depth (not (eq (1+ depth) (get-text-property end 'jsx-depth))))
  12975           (let ((continue (< end (point-max))))
  12976             (while continue
  12977               (setq end (1+ end))
  12978               (setq end (next-single-property-change end 'tag-attr-end))
  12979               (cond
  12980                 ((null end)
  12981                  (setq continue nil))
  12982                 ((not (get-text-property end 'tag-attr-end))
  12983                  (setq continue nil
  12984                        end nil))
  12985                 ((eq (1+ depth) (get-text-property end 'jsx-depth))
  12986                  (setq continue nil))
  12987                 ) ;cond
  12988               ) ;while
  12989             ) ;let
  12990           )
  12991          ) ;cond
  12992        )
  12993       (t
  12994        (setq end nil))
  12995       ) ;cond
  12996     end))
  12997 
  12998 ;; attention si pos est au debut d'un spread attributes, cela
  12999 ;; risque de poser pb
  13000 (defun web-mode-attribute-next-position (&optional pos limit)
  13001   (unless pos (setq pos (point)))
  13002   (unless limit (setq limit (point-max)))
  13003   (let (continue depth)
  13004     (when (get-text-property pos 'tag-attr-beg)
  13005       (setq pos (1+ pos)))
  13006     (if (< pos limit)
  13007         (setq continue t
  13008               depth (get-text-property pos 'jsx-depth))
  13009         (setq continue nil
  13010               pos nil))
  13011     (while continue
  13012       (setq pos (next-single-property-change pos 'tag-attr-beg))
  13013       (cond
  13014         ((null pos)
  13015          (setq continue nil))
  13016         ((>= pos limit)
  13017          (setq continue nil
  13018                pos nil))
  13019         ((null depth)
  13020          (setq continue nil))
  13021         ((and (eq (get-text-property pos 'tag-attr-beg) 4)
  13022               (eq (1+ depth) (get-text-property pos 'jsx-depth)))
  13023          (setq continue nil))
  13024         ((eq depth (get-text-property pos 'jsx-depth))
  13025          (setq continue nil))
  13026         (t
  13027          (setq pos (1+ pos)
  13028                continue (< pos limit)))
  13029         )
  13030       ) ;while
  13031     pos))
  13032 
  13033 (defun web-mode-attribute-previous-position (&optional pos limit)
  13034   (unless pos (setq pos (point)))
  13035   (unless limit (setq limit (point-min)))
  13036   (let (continue depth)
  13037     (cond
  13038       ((and (> pos (point-min)) (get-text-property (1- pos) 'tag-attr-beg))
  13039        (setq pos (1- pos)
  13040              continue nil))
  13041       (t
  13042        (when (get-text-property pos 'tag-attr-beg)
  13043          (setq pos (1- pos)))
  13044        (if (> pos limit)
  13045            (setq continue t
  13046                  depth (get-text-property pos 'jsx-depth))
  13047            (setq continue nil
  13048                  pos nil))
  13049        ) ;t
  13050       ) ;cond
  13051     (while continue
  13052       (setq pos (previous-single-property-change pos 'tag-attr-beg))
  13053       (cond
  13054         ((null pos)
  13055          (setq continue nil))
  13056         ((< pos limit)
  13057          (setq continue nil
  13058                pos nil))
  13059         ;;((null depth)
  13060         ;; (setq continue nil))
  13061         ((and depth (eq depth (get-text-property pos 'jsx-depth)))
  13062          (setq  pos (1- pos)
  13063                 continue nil))
  13064         (depth
  13065          (setq pos nil
  13066                continue (> pos limit)))
  13067         (t
  13068          (setq pos (1- pos)
  13069                continue nil))
  13070         ) ;cond
  13071       ) ;while
  13072     pos))
  13073 
  13074 ;; TODO: prendre en compte jsx-depth
  13075 (defun web-mode-element-beginning-position (&optional pos)
  13076   (unless pos (setq pos (point)))
  13077   (cond
  13078     ((null (get-text-property pos 'tag-type))
  13079      (setq pos (web-mode-element-parent-position)))
  13080     ((eq (get-text-property pos 'tag-type) 'end)
  13081      (setq pos (web-mode-tag-match-position pos))
  13082      (setq pos (if (get-text-property pos 'tag-beg) pos nil)))
  13083     ((member (get-text-property pos 'tag-type) '(start void))
  13084      (setq pos (web-mode-tag-beginning-position pos)))
  13085     (t
  13086      (setq pos nil))
  13087     ) ;cond
  13088   pos)
  13089 
  13090 ;; TODO: prendre en compte jsx-depth
  13091 (defun web-mode-element-end-position (&optional pos)
  13092   (unless pos (setq pos (point)))
  13093   (cond
  13094     ((null (get-text-property pos 'tag-type))
  13095      (setq pos (web-mode-element-parent-position pos))
  13096      (when pos
  13097        (setq pos (web-mode-tag-match-position pos))
  13098        (when pos (setq pos (web-mode-tag-end-position pos)))
  13099        )
  13100      )
  13101     ((member (get-text-property pos 'tag-type) '(end void comment))
  13102      (setq pos (web-mode-tag-end-position pos))
  13103      )
  13104     ((member (get-text-property pos 'tag-type) '(start))
  13105      (setq pos (web-mode-tag-match-position pos))
  13106      (when pos (setq pos (web-mode-tag-end-position pos))))
  13107     (t
  13108      (setq pos nil))
  13109     ) ;cond
  13110   pos)
  13111 
  13112 (defun web-mode-element-child-position (&optional pos)
  13113   (save-excursion
  13114     (let (child close)
  13115       (unless pos (setq pos (point)))
  13116       (goto-char pos)
  13117       (cond
  13118         ((eq (get-text-property pos 'tag-type) 'start)
  13119          (web-mode-tag-match)
  13120          (setq close (point))
  13121          (goto-char pos)
  13122          )
  13123         ((eq (get-text-property pos 'tag-type) 'void)
  13124          )
  13125         ((eq (get-text-property pos 'tag-type) 'end)
  13126          (web-mode-tag-beginning)
  13127          (setq close (point))
  13128          (web-mode-tag-match)
  13129          )
  13130         ((web-mode-element-parent-position pos)
  13131          (setq pos (point))
  13132          (web-mode-tag-match)
  13133          (setq close (point))
  13134          (goto-char pos)
  13135          )
  13136         ) ;cond
  13137       (when (and close
  13138                  (web-mode-element-next)
  13139                  (< (point) close))
  13140         (setq child (point))
  13141         )
  13142       child)))
  13143 
  13144 (defun web-mode-element-parent-position (&optional pos)
  13145   (let (n tag-type tag-name (continue t) (tags (make-hash-table :test 'equal)))
  13146     (save-excursion
  13147       (if pos (goto-char pos))
  13148       (while (and continue (web-mode-tag-previous))
  13149         (setq pos (point)
  13150               tag-type (get-text-property pos 'tag-type)
  13151               tag-name (get-text-property pos 'tag-name)
  13152               n (gethash tag-name tags 0))
  13153         (when (member tag-type '(end start))
  13154           (if (eq tag-type 'end)
  13155               (puthash tag-name (1- n) tags)
  13156               (puthash tag-name (1+ n) tags)
  13157               (when (= n 0) (setq continue nil))
  13158               ) ;if
  13159           ) ;when
  13160         ) ;while
  13161       ) ;save-excursion
  13162     (if (null continue) pos nil)))
  13163 
  13164 (defun web-mode-element-previous-position (&optional pos limit)
  13165   (unless pos (setq pos (point)))
  13166   (unless limit (setq limit (point-min)))
  13167   (save-excursion
  13168     (goto-char pos)
  13169     (let ((continue (not (bobp)))
  13170           (props '(start void comment)))
  13171       (while continue
  13172         (setq pos (web-mode-tag-previous))
  13173         (cond
  13174           ((or (null pos) (< (point) limit))
  13175            (setq continue nil
  13176                  pos nil))
  13177           ((member (get-text-property (point) 'tag-type) props)
  13178            (setq continue nil))
  13179           )
  13180         ) ;while
  13181       pos)))
  13182 
  13183 (defun web-mode-element-next-position (&optional pos limit)
  13184   (unless pos (setq pos (point)))
  13185   (unless limit (setq limit (point-max)))
  13186   (save-excursion
  13187     (goto-char pos)
  13188     (let ((continue (not (eobp)))
  13189           (props '(start void comment)))
  13190       (while continue
  13191         (setq pos (web-mode-tag-next))
  13192         (cond
  13193           ((or (null pos) (> (point) limit))
  13194            (setq continue nil
  13195                  pos nil))
  13196           ((member (get-text-property (point) 'tag-type) props)
  13197            (setq continue nil))
  13198           )
  13199         ) ;while
  13200       ;;      (message "pos=%S" pos)
  13201       pos)))
  13202 
  13203 (defun web-mode-part-end-position (&optional pos)
  13204   (unless pos (setq pos (point)))
  13205   (cond
  13206     ((member web-mode-content-type web-mode-part-content-types)
  13207      (setq pos (point-max)))
  13208     ((not (get-text-property pos 'part-side))
  13209      (setq pos nil))
  13210     ((= pos (point-max))
  13211      (setq pos nil))
  13212     ((not (get-text-property (1+ pos) 'part-side))
  13213      pos)
  13214     (t
  13215      (setq pos (next-single-property-change pos 'part-side)))
  13216     ) ;cond
  13217   pos)
  13218 
  13219 (defun web-mode-part-beginning-position (&optional pos)
  13220   (unless pos (setq pos (point)))
  13221   (cond
  13222     (web-mode-part-beg
  13223      (setq pos web-mode-part-beg))
  13224     ((member web-mode-content-type web-mode-part-content-types)
  13225      (setq pos (point-min)
  13226            web-mode-part-beg (point-min)))
  13227     ((not (get-text-property pos 'part-side))
  13228      (setq pos nil))
  13229     ((= pos (point-min))
  13230      (setq pos nil))
  13231     ((not (get-text-property (1- pos) 'part-side))
  13232      pos)
  13233     (t
  13234      (setq pos (previous-single-property-change pos 'part-side)))
  13235     ) ;cond
  13236   pos)
  13237 
  13238 (defun web-mode-part-next-position (&optional pos)
  13239   (unless pos (setq pos (point)))
  13240   (cond
  13241     ((and (= pos (point-min)) (get-text-property pos 'part-side))
  13242      )
  13243     ((not (get-text-property pos 'part-side))
  13244      (setq pos (next-single-property-change pos 'part-side)))
  13245     ((and (setq pos (web-mode-part-end-position pos)) (>= pos (point-max)))
  13246      (setq pos nil))
  13247     ((and (setq pos (1+ pos)) (not (get-text-property pos 'part-side)))
  13248      (setq pos (next-single-property-change pos 'part-side)))
  13249     ) ;cond
  13250   pos)
  13251 
  13252 (defun web-mode-block-match-position (&optional pos)
  13253   (unless pos (setq pos (point)))
  13254   (save-excursion
  13255     (web-mode-block-match pos)
  13256     (if (= pos (point)) nil (point))))
  13257 
  13258 ;; type may be nil
  13259 (defun web-mode-block-control-previous-position (type &optional pos)
  13260   (unless pos (setq pos (point)))
  13261   (let ((continue t) controls)
  13262     (while continue
  13263       (setq pos (web-mode-block-previous-position pos))
  13264       (cond
  13265         ((null pos)
  13266          (setq continue nil
  13267                pos nil))
  13268         ((null type)
  13269          (setq continue nil))
  13270         ((and (setq controls (web-mode-block-controls-get pos))
  13271               (eq (car (car controls)) type))
  13272          (setq continue nil))
  13273         ) ;cond
  13274       ) ;while
  13275     pos))
  13276 
  13277 (defun web-mode-inside-block-control (&optional pos)
  13278   (unless pos (setq pos (point)))
  13279   (setq pos (web-mode-block-control-previous-position nil pos))
  13280   (if (and pos (member (car (car (web-mode-block-controls-get pos))) '(open inside)))
  13281       pos
  13282       nil))
  13283 
  13284 (defun web-mode-block-opening-paren-position (pos limit)
  13285   (save-excursion
  13286     (when (> limit pos)
  13287       (message "block-opening-paren-position: limit(%S) > pos(%S)" limit pos))
  13288     (goto-char pos)
  13289     (let (c
  13290           n
  13291           pt
  13292           (continue (> pos limit))
  13293           (pairs '((?\) . ?\()
  13294                    (?\] . ?\[)
  13295                    (?\} . ?\{)))
  13296           (h (make-hash-table :test 'equal))
  13297           (regexp "[\]\[)(}{]"))
  13298       (while (and continue (re-search-backward regexp limit t))
  13299         (cond
  13300           ((web-mode-is-comment-or-string)
  13301            )
  13302           (t
  13303            (setq c (char-after))
  13304            (cond
  13305              ((member c '(?\( ?\{ ?\[))
  13306               (setq n (gethash c h 0))
  13307               (if (= n 0)
  13308                   (setq continue nil
  13309                         pt (point))
  13310                   (puthash c (1+ n) h)
  13311                   ))
  13312              (t
  13313               (setq c (cdr (assoc c pairs)))
  13314               (setq n (gethash c h 0))
  13315               (puthash c (1- n) h))
  13316              ) ;cond
  13317            ) ;t
  13318           ) ;cond
  13319         ) ;while
  13320       pt)))
  13321 
  13322 (defun web-mode-block-code-beginning-position (&optional pos)
  13323   (unless pos (setq pos (point)))
  13324   (when (and (setq pos (web-mode-block-beginning-position pos))
  13325              (eq (get-text-property pos 'block-token) 'delimiter-beg))
  13326     (setq pos (next-single-property-change pos 'block-token)))
  13327   pos)
  13328 
  13329 (defun web-mode-block-beginning-position (&optional pos)
  13330   (unless pos (setq pos (point)))
  13331   (cond
  13332     ((or (and (get-text-property pos 'block-side) (= pos (point-min)))
  13333          (get-text-property pos 'block-beg))
  13334      )
  13335     ((and (> pos (point-min)) (get-text-property (1- pos) 'block-beg))
  13336      (setq pos (1- pos)))
  13337     ((get-text-property pos 'block-side)
  13338      (setq pos (previous-single-property-change pos 'block-beg))
  13339      (setq pos (if (and pos (> pos (point-min))) (1- pos) (point-min))))
  13340     (t
  13341      (setq pos nil))
  13342     ) ;cond
  13343   pos)
  13344 
  13345 (defun web-mode-block-string-beginning-position (pos &optional block-beg)
  13346   (unless pos (setq pos (point)))
  13347   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13348   (let (char (ori pos) (continue (not (null pos))))
  13349     (while continue
  13350       (setq char (char-after pos))
  13351       (cond
  13352         ((< pos block-beg)
  13353          (setq continue nil
  13354                pos block-beg))
  13355         ((and (member (get-text-property pos 'block-token) '(string comment))
  13356               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13357          (setq pos (web-mode-block-token-beginning-position pos))
  13358          )
  13359         ((member char '(?\) ?\]))
  13360          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13361          (setq pos (1- pos))
  13362          )
  13363         ((and (> ori pos) (member char '(?\( ?\= ?\[ ?\? ?\: ?\; ?\, ?\`)))
  13364          (if (and (eq char ?\:) ; #1024
  13365                   (web-mode-looking-at ":" pos))
  13366              (setq pos (1- pos))
  13367              (web-mode-looking-at ".[ \t\n]*" pos)
  13368              (setq pos (+ pos (length (match-string-no-properties 0)))
  13369                    continue nil)
  13370              )
  13371          )
  13372         ((web-mode-looking-at "\\(return\\|echo\\|include\\|print\\)[ \n]" pos)
  13373          (setq pos (+ pos (length (match-string-no-properties 0)))
  13374                continue nil))
  13375         (t
  13376          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?;,`:]\\|\\(return\\|echo\\|include\\|print\\)" block-beg))
  13377          (when (not pos)
  13378            (message "block-string-beginning-position ** search failure **")
  13379            (setq continue nil
  13380                  pos block-beg)))
  13381         ) ;cond
  13382       ) ;while
  13383     ;;(message "pos=%S" pos)
  13384     pos))
  13385 
  13386 (defun web-mode-block-statement-beginning-position (pos block-beg _is-ternary)
  13387   (unless pos (setq pos (point)))
  13388   (setq pos (1- pos))
  13389   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13390   (let (char (continue (not (null pos))))
  13391     (while continue
  13392       (setq char (char-after pos))
  13393       (cond
  13394         ((< pos block-beg)
  13395          (setq continue nil
  13396                pos block-beg))
  13397         ((and (member (get-text-property pos 'block-token) '(string comment))
  13398               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13399          (setq pos (web-mode-block-token-beginning-position pos)))
  13400         ((member char '(?\) ?\] ?\}))
  13401          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13402          (setq pos (1- pos)))
  13403         ((and (eq char ?\=)
  13404               (web-mode-looking-back "[<>!=]+" pos block-beg t))
  13405          (setq pos (- pos 1 (length (match-string-no-properties 0))))
  13406          ;;(setq pos (1- pos))
  13407          ;;(message "%S pos=%S" (match-string-no-properties 0) pos)
  13408          )
  13409         ((member char '(?\( ?\[ ?\{ ?\=))
  13410          (setq continue nil)
  13411          (web-mode-looking-at ".[ \t\n]*" pos)
  13412          (setq pos (+ pos (length (match-string-no-properties 0)))))
  13413         ((web-mode-looking-at "\\(return\\|echo\\|include\\|print\\)[ \n]" pos)
  13414          (setq pos (+ pos (length (match-string-no-properties 0)))
  13415                continue nil))
  13416         (t
  13417          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=]\\|\\(return\\|echo\\|include\\|print\\)" block-beg))
  13418          (when (not pos)
  13419            (message "block-statement-beginning-position ** search failure **")
  13420            (setq continue nil
  13421                  pos block-beg)))
  13422         ) ;cond
  13423       ) ;while
  13424     pos))
  13425 
  13426 (defun web-mode-block-args-beginning-position (pos &optional block-beg)
  13427   (unless pos (setq pos (point)))
  13428   (setq pos (1- pos)) ;#512
  13429   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13430   (let (char (continue (not (null pos))))
  13431     (while continue
  13432       (setq char (char-after pos))
  13433       (cond
  13434         ((< pos block-beg)
  13435          (message "block-args-beginning-position ** failure **")
  13436          (setq continue nil
  13437                pos block-beg))
  13438         ((and (member (get-text-property pos 'block-token) '(string comment))
  13439               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13440          (setq pos (web-mode-block-token-beginning-position pos)))
  13441         ((member char '(?\) ?\] ?\}))
  13442          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13443          (setq pos (1- pos)))
  13444         ((member char '(?\( ?\[ ?\{))
  13445          (setq continue nil)
  13446          (web-mode-looking-at ".[ \t\n]*" pos)
  13447          (setq pos (+ pos (length (match-string-no-properties 0)))))
  13448         ((and (string= web-mode-engine "php")
  13449               (web-mode-looking-at "\\(extends\\|implements\\)[ \n]" pos))
  13450          (setq pos (+ pos (length (match-string-no-properties 0)))
  13451                continue nil))
  13452         (t
  13453          (setq pos (web-mode-rsb-position pos "[\]\[}{)(]\\|\\(extends\\|implements\\)" block-beg))
  13454          (when (not pos)
  13455            (message "block-args-beginning-position ** search failure **")
  13456            (setq pos block-beg
  13457                  continue nil))
  13458          ) ;t
  13459         ) ;cond
  13460       ) ;while
  13461     pos))
  13462 
  13463 (defun web-mode-block-calls-beginning-position (pos &optional block-beg)
  13464   (unless pos (setq pos (point)))
  13465   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13466   (let (char (continue (not (null pos))))
  13467     (while continue
  13468       (setq char (char-after pos))
  13469       (cond
  13470         ((< pos block-beg)
  13471          (message "block-calls-beginning-position ** failure **")
  13472          (setq continue nil
  13473                pos block-beg))
  13474         ((and (member (get-text-property pos 'block-token) '(string comment))
  13475               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13476          (setq pos (web-mode-block-token-beginning-position pos)))
  13477         ((member char '(?\) ?\]))
  13478          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13479          (setq pos (1- pos)))
  13480         ((member char '(?\( ?\[ ?\{ ?\} ?\= ?\? ?\: ?\; ?\,))
  13481          (web-mode-looking-at ".[ \t\n]*" pos)
  13482          (setq pos (+ pos (length (match-string-no-properties 0)))
  13483                continue nil))
  13484         ((web-mode-looking-at "\\(return\\|else\\)[ \n]" pos)
  13485          (setq pos (+ pos (length (match-string-no-properties 0)))
  13486                continue nil))
  13487         (t
  13488          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,]\\|\\(return\\|else\\)" block-beg))
  13489          (when (not pos)
  13490            (message "block-calls-beginning-position ** search failure **")
  13491            (setq pos block-beg
  13492                  continue nil))
  13493          ) ;t
  13494         ) ;cond
  13495       ) ;while
  13496     pos))
  13497 
  13498 (defun web-mode-javascript-string-beginning-position (pos &optional reg-beg)
  13499   (unless pos (setq pos (point)))
  13500   (let ((char nil)
  13501         (blockside (get-text-property pos 'block-side))
  13502         (i 0)
  13503         (continue (not (null pos))))
  13504     (unless reg-beg
  13505       (if blockside
  13506           (setq reg-beg (web-mode-block-beginning-position pos))
  13507           (setq reg-beg (web-mode-part-beginning-position pos)))
  13508       )
  13509     (while continue
  13510       (setq char (char-after pos))
  13511       (cond
  13512         ((> (setq i (1+ i)) 20000)
  13513          (message "javascript-string-beginning-position ** warning (%S) **" pos)
  13514          (setq continue nil
  13515                pos nil))
  13516         ((null pos)
  13517          (message "javascript-string-beginning-position ** invalid pos **")
  13518          (setq continue nil))
  13519         ((< pos reg-beg)
  13520          (message "javascript-string-beginning-position ** failure **")
  13521          (setq continue nil
  13522                pos reg-beg))
  13523         ((and blockside
  13524               (member (get-text-property pos 'block-token) '(string comment))
  13525               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13526          (setq pos (web-mode-block-token-beginning-position pos)))
  13527         ((and (not blockside)
  13528               (member (get-text-property pos 'part-token) '(string comment))
  13529               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13530          (setq pos (web-mode-part-token-beginning-position pos)))
  13531         ((and (not blockside)
  13532               (get-text-property pos 'block-side))
  13533          (when (setq pos (web-mode-block-beginning-position pos))
  13534            (setq pos (1- pos))))
  13535         ((member char '(?\) ?\] ?\}))
  13536          (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13537          (setq pos (1- pos)))
  13538         ((member char '(?\( ?\{ ?\[ ?\= ?\? ?\: ?\; ?\, ?\& ?\|))
  13539          (setq continue nil)
  13540          (web-mode-looking-at ".[ \t\n]*" pos)
  13541          (setq pos (+ pos (length (match-string-no-properties 0)))))
  13542         ((web-mode-looking-at "\\(return\\)[ \n]" pos)
  13543          (setq pos (+ pos (length (match-string-no-properties 0)))
  13544                continue nil))
  13545         (t
  13546          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,&|]\\|\\(return\\)" reg-beg))
  13547          (when (not pos)
  13548            (message "javascript-string-beginning-position ** search failure **")
  13549            (setq continue nil
  13550                  pos reg-beg)))
  13551         ) ;cond
  13552       ) ;while
  13553     ;;(message "js-statement-beg:%S" pos)
  13554     pos))
  13555 
  13556 ;; TODO: reg-beg : jsx-beg
  13557 ;; TODO: skipper les expr dont la depth est superieure
  13558 
  13559 ;; NOTE: blockside is useful for ejs
  13560 (defun web-mode-javascript-statement-beginning-position (pos reg-beg is-ternary)
  13561   (unless pos (setq pos (point)))
  13562   (setq pos (1- pos))
  13563   (let ((char nil)
  13564         (blockside (get-text-property pos 'block-side))
  13565         (i 0)
  13566         (is-jsx (string= web-mode-content-type "jsx"))
  13567         (depth-o nil) (depth-l nil)
  13568         (continue (not (null pos)))
  13569         (regexp "[\]\[}{)(=:]\\|\\(return\\)"))
  13570     (when is-ternary
  13571       (setq regexp (concat regexp "\\|[><]")))
  13572     (setq depth-o (get-text-property pos 'jsx-depth))
  13573     (unless reg-beg
  13574       (cond
  13575         (blockside
  13576          (setq reg-beg (web-mode-block-beginning-position pos)))
  13577         (is-jsx
  13578          (setq reg-beg (web-mode-jsx-depth-beginning-position pos)))
  13579         (t
  13580          (setq reg-beg (web-mode-part-beginning-position pos)))
  13581         ) ;cond
  13582       ) ;unless
  13583     (while continue
  13584       (setq char (char-after pos))
  13585       (cond
  13586         ((> (setq i (1+ i)) 20000)
  13587          (message "javascript-statement-beginning-position ** warning (%S) **" pos)
  13588          (setq continue nil
  13589                pos nil))
  13590         ((null pos)
  13591          (message "javascript-statement-beginning-position ** invalid pos **")
  13592          (setq continue nil))
  13593         ((< pos reg-beg)
  13594          (when (not is-jsx)
  13595            (message "javascript-statement-beginning-position ** failure **"))
  13596          (setq continue nil
  13597                pos reg-beg))
  13598         ((and is-jsx
  13599               (progn (setq depth-l (get-text-property pos 'jsx-depth)) t)
  13600               (not (eq depth-l depth-o)))
  13601          ;;(message "%S > depth-o(%S) depth-l(%S)" pos depth-o depth-l)
  13602          (setq pos (previous-single-property-change pos 'jsx-depth))
  13603          (setq pos (1- pos))
  13604          ;;(message "--> %S %S" pos (get-text-property pos 'jsx-depth))
  13605          )
  13606         ((and blockside
  13607               (member (get-text-property pos 'block-token) '(string comment))
  13608               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13609          (setq pos (web-mode-block-token-beginning-position pos)))
  13610         ((and (not blockside)
  13611               (member (get-text-property pos 'part-token) '(string comment))
  13612               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13613          (setq pos (web-mode-part-token-beginning-position pos)))
  13614         ((and (not blockside)
  13615               (get-text-property pos 'block-side))
  13616          (when (setq pos (web-mode-block-beginning-position pos))
  13617            (setq pos (1- pos))))
  13618         ((member char '(?\) ?\] ?\}))
  13619          (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13620          (setq pos (1- pos)))
  13621         ((and (eq char ?\=)
  13622               (web-mode-looking-back "[<>!=]+" pos reg-beg t))
  13623          (setq pos (- pos 1 (length (match-string-no-properties 0)))))
  13624         ((member char '(?\( ?\{ ?\[ ?\= ?\< ?\>))
  13625          (web-mode-looking-at ".[ \t\n]*" pos)
  13626          (setq continue nil
  13627                pos (+ pos (length (match-string-no-properties 0)))))
  13628 
  13629         ((web-mode-looking-at "\\(return\\)[ \n]" pos)
  13630          (setq continue nil
  13631                pos (+ pos (length (match-string-no-properties 0)))))
  13632         ((and (eq char ?\:)
  13633               (web-mode-looking-back "[{,][ \t\n]*[[:alnum:]_]+[ ]*" pos))
  13634          (web-mode-looking-at ".[ \t\n]*" pos)
  13635          (setq continue nil
  13636                pos (+ pos (length (match-string-no-properties 0)))))
  13637         (t
  13638          (setq pos (web-mode-rsb-position pos regexp reg-beg))
  13639          (when (not pos)
  13640            (cond
  13641              (is-jsx
  13642               (when (web-mode-looking-at "[ \n]*" reg-beg)
  13643                 (setq pos (+ reg-beg (length (match-string-no-properties 0)))))
  13644               (setq continue nil))
  13645              (t
  13646               (message "javascript-statement-beginning-position ** search failure **")
  13647               (setq continue nil
  13648                     pos reg-beg))
  13649              ) ;cond
  13650            )
  13651          ) ;t
  13652         ) ;cond
  13653       ) ;while
  13654     ;;(message "%S -------" pos)
  13655     pos))
  13656 
  13657 (defun web-mode-javascript-args-beginning-position (pos &optional reg-beg)
  13658   (unless pos (setq pos (point)))
  13659   (setq pos (1- pos))
  13660   (let ((char nil)
  13661         (blockside (get-text-property pos 'block-side))
  13662         (i 0)
  13663         (continue (not (null pos))))
  13664     (unless reg-beg
  13665       (if blockside
  13666           (setq reg-beg (web-mode-block-beginning-position pos))
  13667           (setq reg-beg (web-mode-part-beginning-position pos)))
  13668       )
  13669     (while continue
  13670       (setq char (char-after pos))
  13671       ;;(message "pos(%S) char(%c)" pos char)
  13672       (cond
  13673         ((> (setq i (1+ i)) 20000)
  13674          (message "javascript-args-beginning-position ** warning (%S) **" pos)
  13675          (setq continue nil
  13676                pos nil))
  13677         ((null pos)
  13678          (message "javascript-args-beginning-position ** invalid pos **")
  13679          (setq continue nil))
  13680         ((< pos reg-beg)
  13681          (message "javascript-args-beginning-position ** failure(position) **")
  13682          (setq continue nil
  13683                pos reg-beg))
  13684         ((and blockside
  13685               (member (get-text-property pos 'block-token) '(string comment))
  13686               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13687          (setq pos (web-mode-block-token-beginning-position pos)))
  13688         ((and (not blockside)
  13689               (member (get-text-property pos 'part-token) '(string comment))
  13690               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13691          (setq pos (web-mode-part-token-beginning-position pos)))
  13692         ((and (not blockside)
  13693               (get-text-property pos 'block-side))
  13694          (when (setq pos (web-mode-block-beginning-position pos))
  13695            (setq pos (1- pos)))
  13696          )
  13697         ((member char '(?\) ?\] ?\}))
  13698          (when (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13699            (setq pos (1- pos))))
  13700         ((member char '(?\( ?\[ ?\{))
  13701          (web-mode-looking-at ".[ ]*" pos)
  13702          (setq pos (+ pos (length (match-string-no-properties 0)))
  13703                continue nil)
  13704          )
  13705         ((web-mode-looking-at "\\(var\\|let\\|return\\|const\\)[ \n]" pos)
  13706          (setq pos (+ pos (length (match-string-no-properties 0)))
  13707                continue nil))
  13708         (t
  13709          (setq pos (web-mode-rsb-position pos "[\]\[}{)(]\\|\\(var\\|let\\|return\\|const\\)" reg-beg))
  13710          (when (not pos)
  13711            (message "javascript-args-beginning-position ** search failure **")
  13712            (setq continue nil
  13713                  pos reg-beg)))
  13714         ) ;cond
  13715       ) ;while
  13716     ;;(message "=%S" pos)
  13717     pos))
  13718 
  13719 (defun web-mode-javascript-calls-beginning-position (pos &optional reg-beg)
  13720   (unless pos (setq pos (point)))
  13721   ;;(message "pos=%S" pos)
  13722   (let ((char nil)
  13723         (dot-pos nil)
  13724         (blockside (get-text-property pos 'block-side))
  13725         (i 0)
  13726         (continue (not (null pos))))
  13727     (unless reg-beg
  13728       (setq reg-beg (if blockside
  13729                         (web-mode-block-beginning-position pos)
  13730                         (web-mode-part-beginning-position pos))))
  13731     (while continue
  13732       (setq char (char-after pos))
  13733       ;;(message "%S| %S=%c" reg-beg pos char)
  13734       (cond
  13735         ((> (setq i (1+ i)) 20000)
  13736          (message "javascript-calls-beginning-position ** warning (%S) **" pos)
  13737          (setq continue nil
  13738                pos nil))
  13739         ((null pos)
  13740          (message "javascript-calls-beginning-position ** invalid pos **")
  13741          (setq continue nil))
  13742         ((< pos reg-beg)
  13743          (setq continue nil
  13744                pos reg-beg))
  13745         ((and blockside
  13746               (member (get-text-property pos 'block-token) '(string comment))
  13747               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13748          (setq pos (web-mode-block-token-beginning-position pos)))
  13749         ((and (not blockside)
  13750               (member (get-text-property pos 'part-token) '(string comment))
  13751               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13752          (setq pos (web-mode-part-token-beginning-position pos)))
  13753         ((and (not blockside)
  13754               (get-text-property pos 'block-side))
  13755          (when (setq pos (web-mode-block-beginning-position pos))
  13756            (setq pos (1- pos))))
  13757         ((and (member char '(?\.)) (> i 1))
  13758          (setq dot-pos pos
  13759                pos (1- pos)))
  13760         ((member char '(?\) ?\]))
  13761          (when (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13762            (setq pos (1- pos)))
  13763          )
  13764         ((member char '(?\( ?\{ ?\} ?\[ ?\= ?\? ?\: ?\; ?\, ?\& ?\| ?\>))
  13765          (web-mode-looking-at ".[ \t\n]*" pos)
  13766          (setq pos (+ pos (length (match-string-no-properties 0)))
  13767                continue nil))
  13768         ((web-mode-looking-at "\\(return\\|else\\|const\\)[ \n]" pos)
  13769          (setq pos (+ pos (length (match-string-no-properties 0)))
  13770                continue nil))
  13771         (t
  13772          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,&|>.]\\|\\(return\\|else\\|const\\)" reg-beg))
  13773          (when (not pos)
  13774            (message "javascript-calls-beginning-position ** search failure **")
  13775            (setq pos reg-beg
  13776                  continue nil))
  13777          ) ;t
  13778         ) ;cond
  13779       ) ;while
  13780     ;;(message "pos=%S dot-pos=%S" pos dot-pos)
  13781     (if (null pos) pos (cons pos dot-pos))
  13782     ))
  13783 
  13784 (defun web-mode-part-token-beginning-position (&optional pos)
  13785   (unless pos (setq pos (point)))
  13786   (cond
  13787     ((not (get-text-property pos 'part-token))
  13788      nil)
  13789     ((or (= pos (point-min))
  13790          (and (> pos (point-min))
  13791               (not (get-text-property (1- pos) 'part-token))))
  13792      pos)
  13793     (t
  13794      (setq pos (previous-single-property-change pos 'part-token))
  13795      (if (and pos (> pos (point-min))) pos (point-min)))
  13796     ))
  13797 
  13798 (defun web-mode-part-token-end-position (&optional pos)
  13799   (unless pos (setq pos (point)))
  13800   (cond
  13801     ((not (get-text-property pos 'part-token))
  13802      nil)
  13803     ((or (= pos (point-max))
  13804          (not (get-text-property (1+ pos) 'part-token)))
  13805      pos)
  13806     (t
  13807      (1- (next-single-property-change pos 'part-token)))
  13808     ))
  13809 
  13810 (defun web-mode-block-token-beginning-position (&optional pos)
  13811   (unless pos (setq pos (point)))
  13812   (cond
  13813     ((not (get-text-property pos 'block-token))
  13814      nil)
  13815     ((or (= pos (point-min))
  13816          (and (> pos (point-min))
  13817               (not (get-text-property (1- pos) 'block-token))))
  13818      pos)
  13819     (t
  13820      (setq pos (previous-single-property-change pos 'block-token))
  13821      (if (and pos (> pos (point-min))) pos (point-min)))
  13822     ))
  13823 
  13824 (defun web-mode-block-token-end-position (&optional pos)
  13825   (unless pos (setq pos (point)))
  13826   (cond
  13827     ((not (get-text-property pos 'block-token))
  13828      nil)
  13829     ((or (= pos (point-max))
  13830          (not (get-text-property (1+ pos) 'block-token)))
  13831      pos)
  13832     (t
  13833      (1- (next-single-property-change pos 'block-token)))
  13834     ))
  13835 
  13836 (defun web-mode-block-code-end-position (&optional pos)
  13837   (unless pos (setq pos (point)))
  13838   (setq pos (web-mode-block-end-position pos))
  13839   (cond
  13840     ((not pos)
  13841      nil)
  13842     ((and (eq (get-text-property pos 'block-token) 'delimiter-end)
  13843           (eq (get-text-property (1- pos) 'block-token) 'delimiter-end))
  13844      (previous-single-property-change pos 'block-token))
  13845     ((= pos (1- (point-max))) ;; TODO: comparer plutot avec line-end-position
  13846      (point-max))
  13847     (t
  13848      pos)
  13849     ))
  13850 
  13851 (defun web-mode-block-end-position (&optional pos)
  13852   (unless pos (setq pos (point)))
  13853   (cond
  13854     ((get-text-property pos 'block-end)
  13855      pos)
  13856     ((get-text-property pos 'block-side)
  13857      (or (next-single-property-change pos 'block-end)
  13858          (point-max)))
  13859     (t
  13860      nil)
  13861     ))
  13862 
  13863 (defun web-mode-block-previous-position (&optional pos)
  13864   (unless pos (setq pos (point)))
  13865   (cond
  13866     ((= pos (point-min))
  13867      (setq pos nil))
  13868     ((get-text-property pos 'block-side)
  13869      (setq pos (web-mode-block-beginning-position pos))
  13870      (cond
  13871        ((or (null pos) (= pos (point-min)))
  13872         (setq pos nil)
  13873         )
  13874        ((and (setq pos (previous-single-property-change pos 'block-beg))
  13875              (> pos (point-min)))
  13876         (setq pos (1- pos))
  13877         )
  13878        )
  13879      ) ;block-side
  13880     ((get-text-property (1- pos) 'block-side)
  13881      (setq pos (web-mode-block-beginning-position (1- pos)))
  13882      )
  13883     (t
  13884      (setq pos (previous-single-property-change pos 'block-side))
  13885      (cond
  13886        ((and (null pos) (get-text-property (point-min) 'block-beg))
  13887         (setq pos (point-min)))
  13888        ((and pos (> pos (point-min)))
  13889         (setq pos (web-mode-block-beginning-position (1- pos))))
  13890        )
  13891      )
  13892     ) ;conf
  13893   pos)
  13894 
  13895 (defun web-mode-block-next-position (&optional pos limit)
  13896   (unless pos (setq pos (point)))
  13897   (unless limit (setq limit (point-max)))
  13898   (cond
  13899     ((and (get-text-property pos 'block-side)
  13900           (setq pos (web-mode-block-end-position pos))
  13901           (< pos (point-max))
  13902           (setq pos (1+ pos)))
  13903      (unless (get-text-property pos 'block-beg)
  13904        (setq pos (next-single-property-change pos 'block-side)))
  13905      )
  13906     (t
  13907      (setq pos (next-single-property-change pos 'block-side)))
  13908     ) ;cond
  13909   (if (and pos (<= pos limit)) pos nil))
  13910 
  13911 (defun web-mode-is-css-string (pos)
  13912   (let (beg)
  13913     (cond
  13914       ((and (setq beg (web-mode-part-token-beginning-position pos))
  13915             (web-mode-looking-at-p "`" beg)
  13916             (web-mode-looking-back "\\(styled[[:alnum:].]+\\|css\\)" beg))
  13917        beg)
  13918       (t
  13919        nil)
  13920       ) ;cond
  13921     ))
  13922 
  13923 ;; Relay.QL , gql, graphql
  13924 (defun web-mode-is-ql-string (pos prefix-regexp)
  13925   (let (beg)
  13926     (cond
  13927       ((and (setq beg (web-mode-part-token-beginning-position pos))
  13928             (web-mode-looking-back prefix-regexp beg))
  13929        beg)
  13930       (t
  13931        nil)
  13932       ) ;cond
  13933     ))
  13934 
  13935 (defun web-mode-is-html-string (pos)
  13936   (let (beg)
  13937     (cond
  13938       ((and (setq beg (web-mode-part-token-beginning-position pos))
  13939             (web-mode-looking-at-p "`[ \t\n]*<[a-zA-Z]" beg)
  13940             (web-mode-looking-back "\\(template\\|html\\)\\([ ]*[=:][ ]*\\)?" beg))
  13941        beg)
  13942       (t
  13943        nil)
  13944       ) ;cond
  13945     ))
  13946 
  13947 ;;---- EXCURSION ---------------------------------------------------------------
  13948 
  13949 (defun web-mode-backward-sexp (n)
  13950   (interactive "p")
  13951   (if (< n 0) (web-mode-forward-sexp (- n))
  13952       (let (pos)
  13953         (dotimes (_ n)
  13954           (skip-chars-backward "[:space:]")
  13955           (setq pos (point))
  13956           (cond
  13957             ((bobp) nil)
  13958             ((get-text-property (1- pos) 'block-end)
  13959              (backward-char 1)
  13960              (web-mode-block-beginning))
  13961             ((get-text-property (1- pos) 'block-token)
  13962              (backward-char 1)
  13963              (web-mode-block-token-beginning))
  13964             ((get-text-property (1- pos) 'part-token)
  13965              (backward-char 1)
  13966              (web-mode-part-token-beginning))
  13967             ((get-text-property (1- pos) 'tag-end)
  13968              (backward-char 1)
  13969              (web-mode-element-beginning))
  13970             ((get-text-property (1- pos) 'tag-attr)
  13971              (backward-char 1)
  13972              (web-mode-attribute-beginning))
  13973             ((get-text-property (1- pos) 'tag-type)
  13974              (backward-char 1)
  13975              (web-mode-tag-beginning))
  13976             ((get-text-property (1- pos) 'jsx-end)
  13977              (backward-char 1)
  13978              (web-mode-jsx-beginning))
  13979             (t
  13980              (let ((forward-sexp-function nil))
  13981                (backward-sexp))
  13982              ) ;case t
  13983             ) ;cond
  13984           ) ;dotimes
  13985         ))) ;let if defun
  13986 
  13987 (defun web-mode-forward-sexp (n)
  13988   (interactive "p")
  13989   (if (< n 0) (web-mode-backward-sexp (- n))
  13990       (let (pos)
  13991         (dotimes (_ n)
  13992           (skip-chars-forward "[:space:]")
  13993           (setq pos (point))
  13994           (cond
  13995             ((eobp) nil)
  13996             ((get-text-property pos 'block-beg)
  13997              (web-mode-block-end))
  13998             ((get-text-property pos 'block-token)
  13999              (web-mode-block-token-end))
  14000             ((get-text-property pos 'part-token)
  14001              (web-mode-part-token-end))
  14002             ((get-text-property pos 'tag-beg)
  14003              (web-mode-element-end))
  14004             ((get-text-property pos 'tag-attr)
  14005              (web-mode-attribute-end))
  14006             ((get-text-property pos 'tag-type)
  14007              (web-mode-tag-end))
  14008             ((get-text-property pos 'jsx-beg)
  14009              (web-mode-jsx-end))
  14010             (t
  14011              (let ((forward-sexp-function nil))
  14012                (forward-sexp))
  14013              ) ;case t
  14014             ) ;cond
  14015           ) ;dotimes
  14016         ))) ;let if defun
  14017 
  14018 (defun web-mode-comment-beginning ()
  14019   "Fetch current comment beg."
  14020   (interactive)
  14021   (web-mode-go (web-mode-comment-beginning-position (point))))
  14022 
  14023 (defun web-mode-comment-end ()
  14024   "Fetch current comment end."
  14025   (interactive)
  14026   (web-mode-go (web-mode-comment-end-position (point)) 1))
  14027 
  14028 (defun web-mode-tag-beginning ()
  14029   "Fetch current html tag beg."
  14030   (interactive)
  14031   (web-mode-go (web-mode-tag-beginning-position (point))))
  14032 
  14033 (defun web-mode-tag-end ()
  14034   "Fetch current html tag end."
  14035   (interactive)
  14036   (web-mode-go (web-mode-tag-end-position (point)) 1))
  14037 
  14038 (defun web-mode-tag-previous ()
  14039   "Fetch previous tag."
  14040   (interactive)
  14041   (web-mode-go (web-mode-tag-previous-position (point))))
  14042 
  14043 (defun web-mode-tag-next ()
  14044   "Fetch next tag. Might be html comment or server tag (e.g. jsp)."
  14045   (interactive)
  14046   (web-mode-go (web-mode-tag-next-position (point))))
  14047 
  14048 (defun web-mode-attribute-beginning ()
  14049   "Fetch html attribute beginning."
  14050   (interactive)
  14051   (web-mode-go (web-mode-attribute-beginning-position (point))))
  14052 
  14053 (defun web-mode-attribute-end ()
  14054   "Fetch html attribute end."
  14055   (interactive)
  14056   (web-mode-go (web-mode-attribute-end-position (point)) 1))
  14057 
  14058 (defun web-mode-attribute-next (&optional arg)
  14059   "Fetch next attribute."
  14060   (interactive "p")
  14061   (unless arg (setq arg 1))
  14062   (cond
  14063     ((= arg 1) (web-mode-go (web-mode-attribute-next-position (point))))
  14064     ((< arg 1) (web-mode-element-previous (* arg -1)))
  14065     (t
  14066      (while (>= arg 1)
  14067        (setq arg (1- arg))
  14068        (web-mode-go (web-mode-attribute-next-position (point)))
  14069        )
  14070      )
  14071     )
  14072   )
  14073 
  14074 (defun web-mode-attribute-previous (&optional arg)
  14075   "Fetch previous attribute."
  14076   (interactive "p")
  14077   (unless arg (setq arg 1))
  14078   (unless arg (setq arg 1))
  14079   (cond
  14080     ((= arg 1) (web-mode-go (web-mode-attribute-previous-position (point))))
  14081     ((< arg 1) (web-mode-element-next (* arg -1)))
  14082     (t
  14083      (while (>= arg 1)
  14084        (setq arg (1- arg))
  14085        (web-mode-go (web-mode-attribute-previous-position (point)))
  14086        )
  14087      )
  14088     )
  14089   )
  14090 
  14091 (defun web-mode-element-previous (&optional arg)
  14092   "Fetch previous element."
  14093   (interactive "p")
  14094   (unless arg (setq arg 1))
  14095   (cond
  14096     ((= arg 1) (web-mode-go (web-mode-element-previous-position (point))))
  14097     ((< arg 1) (web-mode-element-next (* arg -1)))
  14098     (t
  14099      (while (>= arg 1)
  14100        (setq arg (1- arg))
  14101        (web-mode-go (web-mode-element-previous-position (point)))
  14102        ) ;while
  14103      ) ;t
  14104     ) ;cond
  14105   )
  14106 
  14107 (defun web-mode-element-next (&optional arg)
  14108   "Fetch next element."
  14109   (interactive "p")
  14110   (unless arg (setq arg 1))
  14111   (cond
  14112     ((= arg 1) (web-mode-go (web-mode-element-next-position (point))))
  14113     ((< arg 1) (web-mode-element-previous (* arg -1)))
  14114     (t
  14115      (while (>= arg 1)
  14116        (setq arg (1- arg))
  14117        (web-mode-go (web-mode-element-next-position (point)))
  14118        ) ;while
  14119      ) ;t
  14120     ) ;cond
  14121   )
  14122 
  14123 (defun web-mode-element-sibling-next ()
  14124   "Fetch next sibling element."
  14125   (interactive)
  14126   (let ((pos (point)))
  14127     (save-excursion
  14128       (cond
  14129         ((not (get-text-property pos 'tag-type))
  14130          (if (and (web-mode-element-parent)
  14131                   (web-mode-tag-match)
  14132                   (web-mode-tag-next)
  14133                   (member (get-text-property (point) 'tag-type) '(start void comment)))
  14134              (setq pos (point))
  14135              (setq pos nil))
  14136          )
  14137         ((member (get-text-property pos 'tag-type) '(start void))
  14138          (if (and (web-mode-tag-match)
  14139                   (web-mode-tag-next)
  14140                   (member (get-text-property (point) 'tag-type) '(start void comment)))
  14141              (setq pos (point))
  14142              (setq pos nil))
  14143          )
  14144         ((and (web-mode-tag-next)
  14145               (member (get-text-property (point) 'tag-type) '(start void comment)))
  14146          (setq pos (point)))
  14147         (t
  14148          (setq pos nil))
  14149         ) ;cond
  14150       ) ;save-excursion
  14151     (web-mode-go pos)))
  14152 
  14153 (defun web-mode-element-sibling-previous ()
  14154   "Fetch previous sibling element."
  14155   (interactive)
  14156   (let ((pos (point)))
  14157     (save-excursion
  14158       (cond
  14159         ((not (get-text-property pos 'tag-type))
  14160          (if (and (web-mode-element-parent)
  14161                   (web-mode-tag-previous)
  14162                   (web-mode-element-beginning))
  14163              (setq pos (point))
  14164              (setq pos nil))
  14165          )
  14166         ((eq (get-text-property pos 'tag-type) 'start)
  14167          (if (and (web-mode-tag-beginning)
  14168                   (web-mode-tag-previous)
  14169                   (web-mode-element-beginning))
  14170              (setq pos (point))
  14171              (setq pos nil))
  14172          )
  14173         ((and (web-mode-element-beginning)
  14174               (web-mode-tag-previous)
  14175               (web-mode-element-beginning))
  14176          (setq pos (point)))
  14177         (t
  14178          (setq pos nil))
  14179         ) ;cond
  14180       ) ;save-excursion
  14181     (web-mode-go pos)))
  14182 
  14183 (defun web-mode-element-beginning ()
  14184   "Move to beginning of element."
  14185   (interactive)
  14186   (web-mode-go (web-mode-element-beginning-position (point))))
  14187 
  14188 (defun web-mode-element-end ()
  14189   "Move to end of element."
  14190   (interactive)
  14191   (web-mode-go (web-mode-element-end-position (point)) 1))
  14192 
  14193 (defun web-mode-element-parent ()
  14194   "Fetch parent element."
  14195   (interactive)
  14196   (web-mode-go (web-mode-element-parent-position (point))))
  14197 
  14198 (defun web-mode-element-child ()
  14199   "Fetch child element."
  14200   (interactive)
  14201   (web-mode-go (web-mode-element-child-position (point))))
  14202 
  14203 (defun web-mode-dom-traverse ()
  14204   "Traverse html dom tree."
  14205   (interactive)
  14206   (cond
  14207     ((web-mode-element-child)
  14208      )
  14209     ((web-mode-element-sibling-next)
  14210      )
  14211     ((and (web-mode-element-parent)
  14212           (not (web-mode-element-sibling-next)))
  14213      (goto-char (point-min)))
  14214     (t
  14215      (goto-char (point-min)))
  14216     ) ;cond
  14217   )
  14218 
  14219 (defun web-mode-closing-paren (limit)
  14220   (let ((pos (web-mode-closing-paren-position (point) limit)))
  14221     (if (or (null pos) (> pos limit))
  14222         nil
  14223         (goto-char pos)
  14224         pos)
  14225     ))
  14226 
  14227 (defun web-mode-part-next ()
  14228   "Move point to the beginning of the next part."
  14229   (interactive)
  14230   (web-mode-go (web-mode-part-next-position (point))))
  14231 
  14232 (defun web-mode-part-beginning ()
  14233   "Move point to the beginning of the current part."
  14234   (interactive)
  14235   (web-mode-go (web-mode-part-beginning-position (point))))
  14236 
  14237 (defun web-mode-part-end ()
  14238   "Move point to the end of the current part."
  14239   (interactive)
  14240   (web-mode-go (web-mode-part-end-position (point)) 1))
  14241 
  14242 (defun web-mode-block-previous ()
  14243   "Move point to the beginning of the previous block."
  14244   (interactive)
  14245   (web-mode-go (web-mode-block-previous-position (point))))
  14246 
  14247 (defun web-mode-block-next ()
  14248   "Move point to the beginning of the next block."
  14249   (interactive)
  14250   (web-mode-go (web-mode-block-next-position (point))))
  14251 
  14252 (defun web-mode-block-beginning ()
  14253   "Move point to the beginning of the current block."
  14254   (interactive)
  14255   (web-mode-go (web-mode-block-beginning-position (point))))
  14256 
  14257 (defun web-mode-block-end ()
  14258   "Move point to the end of the current block."
  14259   (interactive)
  14260   (web-mode-go (web-mode-block-end-position (point)) 1))
  14261 
  14262 (defun web-mode-block-token-beginning ()
  14263   (web-mode-go (web-mode-block-token-beginning-position (point))))
  14264 
  14265 (defun web-mode-block-token-end ()
  14266   (web-mode-go (web-mode-block-token-end-position (point)) 1))
  14267 
  14268 (defun web-mode-part-token-beginning ()
  14269   (web-mode-go (web-mode-part-token-beginning-position (point))))
  14270 
  14271 (defun web-mode-part-token-end ()
  14272   (web-mode-go (web-mode-part-token-end-position (point)) 1))
  14273 
  14274 (defun web-mode-block-opening-paren (limit)
  14275   (web-mode-go (web-mode-block-opening-paren-position (point) limit)))
  14276 
  14277 (defun web-mode-block-string-beginning (&optional pos block-beg)
  14278   (unless pos (setq pos (point)))
  14279   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14280   (web-mode-go (web-mode-block-string-beginning-position pos block-beg)))
  14281 
  14282 (defun web-mode-block-statement-beginning (pos block-beg is-ternary)
  14283   (unless pos (setq pos (point)))
  14284   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14285   (web-mode-go (web-mode-block-statement-beginning-position pos block-beg is-ternary)))
  14286 
  14287 (defun web-mode-block-args-beginning (&optional pos block-beg)
  14288   (unless pos (setq pos (point)))
  14289   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14290   (web-mode-go (web-mode-block-args-beginning-position pos block-beg)))
  14291 
  14292 (defun web-mode-block-calls-beginning (&optional pos block-beg)
  14293   (unless pos (setq pos (point)))
  14294   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14295   (web-mode-go (web-mode-block-calls-beginning-position pos block-beg)))
  14296 
  14297 (defun web-mode-javascript-string-beginning (&optional pos reg-beg)
  14298   (unless pos (setq pos (point)))
  14299   (unless reg-beg
  14300     (if (get-text-property pos 'block-side)
  14301         (setq reg-beg (web-mode-block-beginning-position pos))
  14302         (setq reg-beg (web-mode-part-beginning-position pos))))
  14303   (web-mode-go (web-mode-javascript-string-beginning-position pos reg-beg)))
  14304 
  14305 (defun web-mode-javascript-statement-beginning (pos reg-beg is-ternary)
  14306   (unless pos (setq pos (point)))
  14307   (unless reg-beg
  14308     (if (get-text-property pos 'block-side)
  14309         (setq reg-beg (web-mode-block-beginning-position pos))
  14310         (setq reg-beg (web-mode-part-beginning-position pos))))
  14311   (web-mode-go (web-mode-javascript-statement-beginning-position pos reg-beg is-ternary)))
  14312 
  14313 (defun web-mode-javascript-args-beginning (&optional pos reg-beg)
  14314   (unless pos (setq pos (point)))
  14315   (unless reg-beg
  14316     (setq reg-beg (if (get-text-property pos 'block-side)
  14317                       (web-mode-block-beginning-position pos)
  14318                       (web-mode-part-beginning-position pos))))
  14319   ;;(message "reg-beg%S" reg-beg)
  14320   (web-mode-go (web-mode-javascript-args-beginning-position pos reg-beg)))
  14321 
  14322 (defun web-mode-javascript-calls-beginning (&optional pos reg-beg)
  14323   (unless pos (setq pos (point)))
  14324   (unless reg-beg
  14325     (if (get-text-property pos 'block-side)
  14326         (setq reg-beg (web-mode-block-beginning-position pos))
  14327         (setq reg-beg (web-mode-part-beginning-position pos))))
  14328   (let (pair)
  14329     (setq pair (web-mode-javascript-calls-beginning-position pos reg-beg))
  14330     (when pair (web-mode-go (car pair)))
  14331     ))
  14332 
  14333 (defun web-mode-go (pos &optional offset)
  14334   (unless offset (setq offset 0))
  14335   (when pos
  14336     (cond
  14337       ((and (> offset 0) (<= (+ pos offset) (point-max)))
  14338        (setq pos (+ pos offset)))
  14339       ((and (< offset 0) (>= (+ pos offset) (point-min)))
  14340        (setq pos (+ pos offset)))
  14341       ) ;cond
  14342     (goto-char pos))
  14343   pos)
  14344 
  14345 ;;---- SEARCH ------------------------------------------------------------------
  14346 
  14347 (defun web-mode-rsf-balanced (regexp-open regexp-close &optional limit noerror)
  14348   (unless noerror (setq noerror t))
  14349   (let ((continue t)
  14350         (level 1)
  14351         (pos (point))
  14352         ret
  14353         (regexp (concat regexp-open "\\|" regexp-close)))
  14354     (while continue
  14355       (setq ret (re-search-forward regexp limit noerror))
  14356       (cond
  14357         ((null ret)
  14358          (setq continue nil)
  14359          )
  14360         (t
  14361          (if (string-match-p regexp-open (match-string-no-properties 0))
  14362              (setq level (1+ level))
  14363              (setq level (1- level)))
  14364          (when (< level 1)
  14365            (setq continue nil)
  14366            )
  14367          ) ;t
  14368         ) ;cond
  14369       ) ;while
  14370     (when (not (= level 0)) (goto-char pos))
  14371     ret))
  14372 
  14373 (defun web-mode-block-sb (expr &optional limit noerror)
  14374   (unless limit (setq limit (web-mode-block-beginning-position (point))))
  14375   (unless noerror (setq noerror t))
  14376   (let ((continue t) ret)
  14377     (while continue
  14378       (setq ret (search-backward expr limit noerror))
  14379       (when (or (null ret)
  14380                 (not (get-text-property (point) 'block-token)))
  14381         (setq continue nil)
  14382         ) ;when
  14383       ) ;while
  14384     ret))
  14385 
  14386 (defun web-mode-block-sf (expr &optional limit noerror)
  14387   (unless limit (setq limit (web-mode-block-end-position (point))))
  14388   (unless noerror (setq noerror t))
  14389   (let ((continue t) ret)
  14390     (while continue
  14391       (setq ret (search-forward expr limit noerror))
  14392       (when (or (null ret)
  14393                 (not (get-text-property (point) 'block-token)))
  14394         (setq continue nil)
  14395         ) ;when
  14396       ) ;while
  14397     ret))
  14398 
  14399 (defun web-mode-block-rsb (regexp &optional limit noerror)
  14400   (unless limit (setq limit (web-mode-block-beginning-position (point))))
  14401   (unless noerror (setq noerror t))
  14402   (let ((continue t) ret)
  14403     (while continue
  14404       (setq ret (re-search-backward regexp limit noerror))
  14405       (when (or (null ret)
  14406                 (not (get-text-property (point) 'block-token)))
  14407         (setq continue nil)
  14408         ) ;when
  14409       ) ;while
  14410     ret))
  14411 
  14412 (defun web-mode-block-rsf (regexp &optional limit noerror)
  14413   (unless limit (setq limit (web-mode-block-end-position (point))))
  14414   (unless noerror (setq noerror t))
  14415   (let ((continue t) ret)
  14416     (while continue
  14417       (setq ret (re-search-forward regexp limit noerror))
  14418       (when (or (null ret)
  14419                 (not (get-text-property (point) 'block-token)))
  14420         (setq continue nil)
  14421         ) ;when
  14422       ) ;while
  14423     ret))
  14424 
  14425 (defun web-mode-part-sb (expr &optional limit noerror)
  14426   (unless limit (setq limit (web-mode-part-beginning-position (point))))
  14427   (unless noerror (setq noerror t))
  14428   (let ((continue t) ret)
  14429     (while continue
  14430       (setq ret (search-backward expr limit noerror))
  14431       (when (or (null ret)
  14432                 (and (not (get-text-property (point) 'part-token))
  14433                      (not (get-text-property (point) 'block-side)))
  14434                 )
  14435         (setq continue nil)
  14436         ) ;when
  14437       ) ;while
  14438     ret))
  14439 
  14440 (defun web-mode-part-sf (expr &optional limit noerror)
  14441   (unless limit (setq limit (web-mode-part-end-position (point))))
  14442   (unless noerror (setq noerror t))
  14443   (let ((continue t) ret)
  14444     (while continue
  14445       (setq ret (search-forward expr limit noerror))
  14446       (when (or (null ret)
  14447                 (and (not (get-text-property (point) 'part-token))
  14448                      (not (get-text-property (point) 'block-side)))
  14449                 )
  14450         (setq continue nil)
  14451         ) ;when
  14452       ) ;while
  14453     ret))
  14454 
  14455 (defun web-mode-part-rsb (regexp &optional limit noerror)
  14456   (unless limit (setq limit (web-mode-part-beginning-position (point))))
  14457   (unless noerror (setq noerror t))
  14458   (let ((continue t) ret)
  14459     (while continue
  14460       (setq ret (re-search-backward regexp limit noerror))
  14461       (when (or (null ret)
  14462                 (and (not (get-text-property (point) 'part-token))
  14463                      (not (get-text-property (point) 'block-side)))
  14464                 )
  14465         (setq continue nil)
  14466         ) ;when
  14467       ) ;while
  14468     ret))
  14469 
  14470 (defun web-mode-part-rsf (regexp &optional limit noerror)
  14471   (unless limit (setq limit (web-mode-part-end-position (point))))
  14472   (unless noerror (setq noerror t))
  14473   (let ((continue t) ret)
  14474     (while continue
  14475       (setq ret (re-search-forward regexp limit t))
  14476       (when (or (null ret)
  14477                 (and (not (get-text-property (point) 'part-token))
  14478                      (not (get-text-property (point) 'block-side)))
  14479                 )
  14480         (setq continue nil)
  14481         ) ;when
  14482       ) ;while
  14483     ret))
  14484 
  14485 (defun web-mode-javascript-rsb (regexp &optional limit noerror)
  14486   (unless limit (setq limit (web-mode-part-beginning-position (point))))
  14487   (unless noerror (setq noerror t))
  14488   (let ((continue t) ret)
  14489     (while continue
  14490       (setq ret (re-search-backward regexp limit noerror))
  14491       (when (or (null ret)
  14492                 (and (not (get-text-property (point) 'part-token))
  14493                      (not (get-text-property (point) 'block-side))
  14494                      (not (get-text-property (point) 'jsx-depth)))
  14495                 )
  14496         (setq continue nil)
  14497         ) ;when
  14498       ) ;while
  14499     ret))
  14500 
  14501 (defun web-mode-javascript-rsf (regexp &optional limit noerror)
  14502   (unless limit (setq limit (web-mode-part-end-position (point))))
  14503   (unless noerror (setq noerror t))
  14504   (let ((continue t) ret)
  14505     (while continue
  14506       (setq ret (re-search-forward regexp limit t))
  14507       (when (or (null ret)
  14508                 (and (not (get-text-property (point) 'part-token))
  14509                      (not (get-text-property (point) 'block-side))
  14510                      (not (get-text-property (point) 'jsx-depth)))
  14511                 )
  14512         (setq continue nil)
  14513         ) ;when
  14514       ) ;while
  14515     ret))
  14516 
  14517 (defun web-mode-dom-sf (expr &optional limit noerror)
  14518   (unless noerror (setq noerror t))
  14519   (let ((continue t) ret)
  14520     (while continue
  14521       (setq ret (search-forward expr limit noerror))
  14522       (if (or (null ret)
  14523               (not (get-text-property (- (point) (length expr)) 'block-side)))
  14524           (setq continue nil))
  14525       )
  14526     ret))
  14527 
  14528 (defun web-mode-dom-rsf (regexp &optional limit noerror)
  14529   (unless noerror (setq noerror t))
  14530   (let ((continue t) (ret nil))
  14531     (while continue
  14532       (setq ret (re-search-forward regexp limit noerror))
  14533       ;;      (message "ret=%S point=%S limit=%S i=%S" ret (point) limit 0)
  14534       (cond
  14535         ((null ret)
  14536          (setq continue nil))
  14537         ((or (get-text-property (match-beginning 0) 'block-side)
  14538              (get-text-property (match-beginning 0) 'part-token))
  14539          )
  14540         (t
  14541          (setq continue nil))
  14542         ) ;cond
  14543       ) ;while
  14544     ret))
  14545 
  14546 (defun web-mode-rsb-position (pos regexp &optional limit noerror)
  14547   (unless noerror (setq noerror t))
  14548   (save-excursion
  14549     (goto-char pos)
  14550     (if (re-search-backward regexp limit noerror) (point) nil)
  14551     ))
  14552 
  14553 (defun web-mode-rsb (regexp &optional limit noerror)
  14554   (unless noerror (setq noerror t))
  14555   (let ((continue t) ret)
  14556     (while continue
  14557       (setq ret (re-search-backward regexp limit noerror))
  14558       (if (or (null ret)
  14559               (not (web-mode-is-comment-or-string)))
  14560           (setq continue nil)))
  14561     ret))
  14562 
  14563 (defun web-mode-rsf (regexp &optional limit noerror)
  14564   (unless noerror (setq noerror t))
  14565   (let ((continue t) ret)
  14566     (while continue
  14567       (setq ret (re-search-forward regexp limit noerror))
  14568       (if (or (null ret)
  14569               (not (web-mode-is-comment-or-string)))
  14570           (setq continue nil))
  14571       )
  14572     ret))
  14573 
  14574 (defun web-mode-sb (expr &optional limit noerror)
  14575   (unless noerror (setq noerror t))
  14576   (let ((continue t) ret)
  14577     (while continue
  14578       (setq ret (search-backward expr limit noerror))
  14579       (if (or (null ret)
  14580               (not (web-mode-is-comment-or-string)))
  14581           (setq continue nil)))
  14582     ret))
  14583 
  14584 (defun web-mode-sf (expr &optional limit noerror)
  14585   (unless noerror (setq noerror t))
  14586   (let ((continue t) ret)
  14587     (while continue
  14588       (setq ret (search-forward expr limit noerror))
  14589       (if (or (null ret)
  14590               (not (web-mode-is-comment-or-string)))
  14591           (setq continue nil)))
  14592     ret))
  14593 
  14594 (defun web-mode-content-rsf (regexp &optional limit noerror)
  14595   (unless noerror (setq noerror t))
  14596   (let ((continue t) ret beg end)
  14597     (while continue
  14598       (setq ret (re-search-forward regexp limit noerror)
  14599             beg (if (null ret) (point) (match-beginning 0))
  14600             end (if (null ret) (point) (1- (match-end 0))))
  14601       (if (or (null ret)
  14602               (and (web-mode-is-content beg)
  14603                    (web-mode-is-content end)))
  14604           (setq continue nil)))
  14605     ret))
  14606 
  14607 ;;---- ADVICES -----------------------------------------------------------------
  14608 
  14609 (defadvice ac-start (before web-mode-set-up-ac-sources activate)
  14610   "Set `ac-sources' based on current language before running auto-complete."
  14611   (when (equal major-mode 'web-mode)
  14612     ;; set ignore each time to nil. User has to implement a hook to change it
  14613     ;; for each completion
  14614     (setq web-mode-ignore-ac-start-advice nil)
  14615     (run-hooks 'web-mode-before-auto-complete-hooks)
  14616     (unless web-mode-ignore-ac-start-advice
  14617       (when web-mode-ac-sources-alist
  14618         (let ((new-web-mode-ac-sources
  14619                (assoc (web-mode-language-at-pos)
  14620                       web-mode-ac-sources-alist)))
  14621           (setq ac-sources (cdr new-web-mode-ac-sources)))))))
  14622 
  14623 ;;---- MINOR MODE ADDONS -------------------------------------------------------
  14624 
  14625 (defun web-mode-yasnippet-exit-hook ()
  14626   "Yasnippet exit hook"
  14627   (when (and (boundp 'yas-snippet-beg) (boundp 'yas-snippet-end))
  14628     (indent-region yas-snippet-beg yas-snippet-end)))
  14629 
  14630 (defun web-mode-imenu-index ()
  14631   "Returns imenu items."
  14632   (interactive)
  14633   (let (toc-index
  14634         line)
  14635     (save-excursion
  14636       (goto-char (point-min))
  14637       (while (not (eobp))
  14638         (setq line (buffer-substring-no-properties
  14639                     (line-beginning-position)
  14640                     (line-end-position)))
  14641         (let (found
  14642               (i 0)
  14643               item
  14644               regexp
  14645               type
  14646               type-idx
  14647               content
  14648               content-idx
  14649               content-regexp
  14650               close-tag-regexp
  14651               concat-str
  14652               jumpto
  14653               str)
  14654           (while (and (not found ) (< i (length web-mode-imenu-regexp-list)))
  14655             (setq item (nth i web-mode-imenu-regexp-list))
  14656             (setq regexp (nth 0 item))
  14657             (setq type-idx (nth 1 item))
  14658             (setq content-idx (nth 2 item))
  14659             (setq concat-str (nth 3 item))
  14660             (when (not (numberp content-idx))
  14661               (setq content-regexp (nth 2 item)
  14662                     close-tag-regexp (nth 4 item)
  14663                     content-idx nil))
  14664 
  14665             (when (string-match regexp line)
  14666 
  14667               (cond
  14668                 (content-idx
  14669                  (setq type (match-string type-idx line))
  14670                  (setq content (match-string content-idx line))
  14671                  (setq str (concat type concat-str content))
  14672                  (setq jumpto (line-beginning-position)))
  14673                 (t
  14674                  (let (limit)
  14675                    (setq type (match-string type-idx line))
  14676                    (goto-char (line-beginning-position))
  14677                    (save-excursion
  14678                      (setq limit (re-search-forward close-tag-regexp (point-max) t)))
  14679 
  14680                    (when limit
  14681                      (when (re-search-forward content-regexp limit t)
  14682                        (setq content (match-string 1))
  14683                        (setq str (concat type concat-str content))
  14684                        (setq jumpto (line-beginning-position))
  14685                        )
  14686                      )))
  14687                 )
  14688               (when str (setq toc-index
  14689                               (cons (cons str jumpto)
  14690                                     toc-index)
  14691                               )
  14692                     (setq found t))
  14693               )
  14694             (setq i (1+ i))))
  14695         (forward-line)
  14696         (goto-char (line-end-position)) ;; make sure we are at eobp
  14697         ))
  14698     (nreverse toc-index)))
  14699 
  14700 ;;---- UNIT TESTING ------------------------------------------------------------
  14701 
  14702 (defun web-mode-test ()
  14703   "Executes web-mode unit tests. See `web-mode-tests-directory'."
  14704   (interactive)
  14705   (let (files regexp)
  14706     (setq regexp "^[[:alnum:]][[:alnum:]._]+\\'")
  14707     (setq files (directory-files web-mode-tests-directory t regexp))
  14708     (dolist (file files)
  14709       (cond
  14710         ((eq (string-to-char (file-name-nondirectory file)) ?\_)
  14711          (delete-file file))
  14712         (t
  14713          (web-mode-test-process file))
  14714         ) ;cond
  14715       ) ;dolist
  14716     ))
  14717 
  14718 (defun web-mode-test-process (file)
  14719   (with-temp-buffer
  14720     (let (out sig1 sig2 success err)
  14721       (setq-default indent-tabs-mode nil)
  14722       (if (string-match-p "sql" file)
  14723           (setq web-mode-enable-sql-detection t)
  14724           (setq web-mode-enable-sql-detection nil))
  14725       (insert-file-contents file)
  14726       (set-visited-file-name file)
  14727       (web-mode)
  14728       (setq sig1 (md5 (current-buffer)))
  14729       (delete-horizontal-space)
  14730       (while (not (eobp))
  14731         (forward-line)
  14732         (delete-horizontal-space)
  14733         (end-of-line))
  14734       (web-mode-buffer-indent)
  14735       (setq sig2 (md5 (current-buffer)))
  14736       (setq success (string= sig1 sig2))
  14737       (setq out (concat (if success "ok" "ko") " : " (file-name-nondirectory file) "\n"))
  14738       (princ out)
  14739       (setq err (concat (file-name-directory file) "_err." (file-name-nondirectory file)))
  14740       (if success
  14741           (when (file-readable-p err)
  14742             (delete-file err))
  14743           (write-file err)
  14744           (message "[%s]" (buffer-string))
  14745           ) ;if
  14746       out)))
  14747 
  14748 ;;---- MISC --------------------------------------------------------------------
  14749 
  14750 (defun web-mode-set-engine (engine)
  14751   "Set the engine for the current buffer."
  14752   (interactive
  14753    (list (completing-read
  14754           "Engine: "
  14755           (let (engines)
  14756             (dolist (elt web-mode-engines)
  14757               (setq engines (append engines (list (car elt)))))
  14758             engines))))
  14759   (setq web-mode-content-type "html"
  14760         web-mode-engine (web-mode-engine-canonical-name engine)
  14761         web-mode-minor-engine engine)
  14762   (web-mode-on-engine-setted)
  14763   (web-mode-buffer-fontify))
  14764 
  14765 (defun web-mode-set-content-type (content-type)
  14766   "Set the content-type for the current buffer"
  14767   (interactive (list (completing-read "Content-type: " web-mode-part-content-types)))
  14768   (setq web-mode-content-type content-type)
  14769   (when (called-interactively-p 'any)
  14770     )
  14771   (web-mode-buffer-fontify))
  14772 
  14773 (defun web-mode-on-engine-setted ()
  14774   (let (elt elts)
  14775 
  14776     (when (string= web-mode-engine "razor") (setq web-mode-enable-block-face t))
  14777     ;;(setq web-mode-engine-attr-regexp (cdr (assoc web-mode-engine web-mode-engine-attr-regexps)))
  14778     (setq web-mode-engine-token-regexp (cdr (assoc web-mode-engine web-mode-engine-token-regexps)))
  14779 
  14780     ;;(message "%S %S %S" web-mode-engine web-mode-engine-attr-regexp web-mode-engine-token-regexp)
  14781 
  14782     (when (null web-mode-minor-engine)
  14783       (setq web-mode-minor-engine "none"))
  14784 
  14785     (setq elt (assoc web-mode-engine web-mode-engine-open-delimiter-regexps))
  14786     (cond
  14787       (elt
  14788        (setq web-mode-block-regexp (cdr elt)))
  14789       ((string= web-mode-engine "archibus")
  14790        (setq web-mode-block-regexp nil))
  14791       (t
  14792        (setq web-mode-engine "none"))
  14793       )
  14794 
  14795     (unless (boundp 'web-mode-extra-auto-pairs)
  14796       (setq web-mode-extra-auto-pairs nil))
  14797 
  14798     (setq web-mode-auto-pairs
  14799           (append
  14800            (cdr (assoc web-mode-engine web-mode-engines-auto-pairs))
  14801            (cdr (assoc nil web-mode-engines-auto-pairs))
  14802            (cdr (assoc web-mode-engine web-mode-extra-auto-pairs))
  14803            (cdr (assoc nil web-mode-extra-auto-pairs))))
  14804 
  14805     (unless (boundp 'web-mode-extra-snippets)
  14806       (setq web-mode-extra-snippets nil))
  14807 
  14808     (setq elts
  14809           (append
  14810            (cdr (assoc web-mode-engine web-mode-extra-snippets))
  14811            (cdr (assoc nil             web-mode-extra-snippets))
  14812            (cdr (assoc web-mode-engine web-mode-engines-snippets))
  14813            (cdr (assoc nil             web-mode-engines-snippets))))
  14814 
  14815     ;;(message "%S" elts)
  14816 
  14817     (dolist (elt elts)
  14818       (unless (assoc (car elt) web-mode-snippets)
  14819         (setq web-mode-snippets (cons elt web-mode-snippets)))
  14820       )
  14821 
  14822     (setq web-mode-engine-font-lock-keywords
  14823           (symbol-value (cdr (assoc web-mode-engine web-mode-engines-font-lock-keywords))))
  14824 
  14825     (when (and (string= web-mode-minor-engine "jinja")
  14826                (not (member "endtrans" web-mode-django-control-blocks)))
  14827       (add-to-list 'web-mode-django-control-blocks "endtrans")
  14828       (setq web-mode-django-control-blocks-regexp
  14829             (regexp-opt web-mode-django-control-blocks t))
  14830       )
  14831 
  14832     (when (string= web-mode-engine "spip")
  14833       (modify-syntax-entry ?# "w" (syntax-table)))
  14834 
  14835     ;;(message "%S" (symbol-value (cdr (assoc web-mode-engine web-mode-engines-font-lock-keywords))))
  14836 
  14837     ))
  14838 
  14839 (defun web-mode-detect-engine ()
  14840   (save-excursion
  14841     (goto-char (point-min))
  14842     (when (re-search-forward "-\\*- engine:[ ]*\\([[:alnum:]-]+\\)[ ]*-\\*-" web-mode-chunk-length t)
  14843       (setq web-mode-minor-engine (match-string-no-properties 1))
  14844       (setq web-mode-engine (web-mode-engine-canonical-name web-mode-minor-engine)))
  14845     web-mode-minor-engine))
  14846 
  14847 (defun web-mode-guess-engine-and-content-type ()
  14848   (let (buff-name found)
  14849 
  14850     (setq buff-name (buffer-file-name))
  14851     (unless buff-name (setq buff-name (buffer-name)))
  14852     (setq web-mode-is-scratch (string= buff-name "*scratch*"))
  14853     (setq web-mode-content-type nil)
  14854 
  14855     (when (boundp 'web-mode-content-types-alist)
  14856       (setq found nil)
  14857       (dolist (elt web-mode-content-types-alist)
  14858         (when (and (not found) (string-match-p (cdr elt) buff-name))
  14859           (setq web-mode-content-type (car elt)
  14860                 found t))
  14861         ) ;dolist
  14862       ) ;when
  14863 
  14864     (unless web-mode-content-type
  14865       (setq found nil)
  14866       (dolist (elt web-mode-content-types)
  14867         (when (and (not found) (string-match-p (cdr elt) buff-name))
  14868           (setq web-mode-content-type (car elt)
  14869                 found t)
  14870           ;;(message "%S" web-mode-content-type)
  14871           ) ;when
  14872         ) ;dolist
  14873       ) ;unless
  14874 
  14875     (when (boundp 'web-mode-engines-alist)
  14876       (setq found nil)
  14877       (dolist (elt web-mode-engines-alist)
  14878         (cond
  14879           ((stringp (cdr elt))
  14880            (when (string-match-p (cdr elt) buff-name)
  14881              (setq web-mode-engine (car elt))))
  14882           ((functionp (cdr elt))
  14883            (when (funcall (cdr elt))
  14884              (setq web-mode-engine (car elt))))
  14885           ) ;cond
  14886         ) ;dolist
  14887       ) ;when
  14888 
  14889     (unless web-mode-engine
  14890       (setq found nil)
  14891       (dolist (elt web-mode-engine-file-regexps)
  14892         ;;(message "%S %S %S" (cdr elt) (car elt) buff-name)
  14893         (when (and (not found) (string-match-p (cdr elt) buff-name))
  14894           ;;(message "%S %S %S" (cdr elt) (car elt) buff-name)
  14895           (setq web-mode-engine (car elt)
  14896                 found t)
  14897           ;;(when (and web-mode-engine (string= web-mode-engine "astro"))
  14898           ;;  (setq web-mode-enable-front-matter-block t)
  14899           ;;) ;when
  14900           ) ;when
  14901         )
  14902       )
  14903 
  14904     (when (and (or (null web-mode-engine) (string= web-mode-engine "none"))
  14905                (string-match-p "php" (buffer-substring-no-properties
  14906                                       (line-beginning-position)
  14907                                       (line-end-position))))
  14908       (setq web-mode-engine "php"))
  14909 
  14910     (when (and (string= web-mode-content-type "javascript")
  14911                (string-match-p "@jsx"
  14912                                (buffer-substring-no-properties
  14913                                 (point-min)
  14914                                 (if (< (point-max) web-mode-chunk-length)
  14915                                     (point-max)
  14916                                     web-mode-chunk-length)
  14917                                 )))
  14918       (setq web-mode-content-type "jsx"))
  14919 
  14920     (when web-mode-engine
  14921       (setq web-mode-minor-engine web-mode-engine
  14922             web-mode-engine (web-mode-engine-canonical-name web-mode-engine))
  14923       )
  14924 
  14925     ;;(message "%S %S" web-mode-engine web-mode-enable-engine-detection)
  14926 
  14927     (when (and (or (null web-mode-engine)
  14928                    (string= web-mode-engine "none"))
  14929                web-mode-enable-engine-detection)
  14930       (web-mode-detect-engine))
  14931 
  14932     (web-mode-on-engine-setted)
  14933 
  14934     ))
  14935 
  14936 (defun web-mode-engine-canonical-name (name)
  14937   (let (engine)
  14938     (cond
  14939       ((null name)
  14940        nil)
  14941       ((assoc name web-mode-engines)
  14942        name)
  14943       (t
  14944        (dolist (elt web-mode-engines)
  14945          (when (and (null engine) (member name (cdr elt)))
  14946            (setq engine (car elt)))
  14947          ) ;dolist
  14948        engine)
  14949       )))
  14950 
  14951 (defun web-mode-on-after-save ()
  14952   (when web-mode-is-scratch
  14953     (web-mode-guess-engine-and-content-type)
  14954     (web-mode-buffer-fontify))
  14955   nil)
  14956 
  14957 (defun web-mode-on-exit ()
  14958   (web-mode-with-silent-modifications
  14959    (put-text-property (point-min) (point-max) 'invisible nil)
  14960    (remove-overlays)
  14961    (remove-hook 'change-major-mode-hook 'web-mode-on-exit t)
  14962    ))
  14963 
  14964 (defun web-mode-file-link (file)
  14965   "Insert a link to a file in html document. This function can be
  14966 extended to support more filetypes by customizing
  14967 `web-mode-links'."
  14968   (interactive
  14969    (list (file-relative-name (read-file-name "Link file: "))))
  14970   (let ((matched nil)
  14971         (point-line (line-number-at-pos))
  14972         (point-column (current-column)))
  14973     (dolist (type web-mode-links)
  14974       (when (string-match (car type) file)
  14975         (setq matched t)
  14976         (when (nth 2 type)
  14977           (goto-char (point-min))
  14978           (search-forward "</head>")
  14979           (backward-char 7)
  14980           (open-line 1))
  14981         (insert (format (cadr type) file))
  14982         (indent-for-tab-command)
  14983         (when (nth 2 type)
  14984           ;; return point where it was and fix indentation
  14985           (forward-line)
  14986           (indent-for-tab-command)
  14987           (if (> point-line (- (line-number-at-pos) 2))
  14988               (forward-line (+ (- point-line (line-number-at-pos)) 1))
  14989               (forward-line (- point-line (line-number-at-pos))))
  14990           (move-to-column point-column))
  14991         ;; move point back if needed
  14992         (backward-char (nth 3 type))))
  14993     (when (not matched)
  14994       (user-error "Unknown file type"))))
  14995 
  14996 (defun web-mode-reload ()
  14997   "Reload web-mode."
  14998   (interactive)
  14999   (web-mode-with-silent-modifications
  15000    (put-text-property (point-min) (point-max) 'invisible nil)
  15001    (remove-overlays)
  15002    (setq font-lock-unfontify-region-function 'font-lock-default-unfontify-region)
  15003    (load "web-mode.el")
  15004    (setq web-mode-change-beg nil
  15005          web-mode-change-end nil)
  15006    (web-mode)
  15007    ))
  15008 
  15009 (defun web-mode-measure (msg)
  15010   (let (sub)
  15011     (when (null web-mode-time) (setq web-mode-time (current-time)))
  15012     (setq sub (time-subtract (current-time) web-mode-time))
  15013     (when nil
  15014       (save-excursion
  15015         (let ((n 0))
  15016           (goto-char (point-min))
  15017           (while (web-mode-tag-next)
  15018             (setq n (1+ n))
  15019             )
  15020           (message "%S tags found" n)
  15021           )))
  15022     (message "%18s: time elapsed = %Ss %9Sµs" msg (nth 1 sub) (nth 2 sub))
  15023     ))
  15024 
  15025 (defun web-mode-reveal ()
  15026   "Display text properties at point."
  15027   (interactive)
  15028   (let (symbols out)
  15029     (setq out (format
  15030                "[point=%S engine=%S minor=%S content-type=%S language-at-pos=%S]\n"
  15031                (point)
  15032                web-mode-engine
  15033                web-mode-minor-engine
  15034                web-mode-content-type
  15035                (web-mode-language-at-pos (point))))
  15036     (setq symbols (append web-mode-scan-properties '(font-lock-face face)))
  15037     (dolist (symbol symbols)
  15038       (when symbol
  15039         (setq out (concat out (format "%s(%S) " (symbol-name symbol) (get-text-property (point) symbol)))))
  15040       )
  15041     (message "%s\n" out)
  15042     ;;(message "syntax-class=%S" (syntax-class (syntax-after (point))))
  15043     (message nil)))
  15044 
  15045 (defun web-mode-toggle-tracing ()
  15046   "Toggle tracing."
  15047   (interactive)
  15048   (if web-mode-trace
  15049       (setq web-mode-trace nil)
  15050       (message "** tracing on ** point(%S) web-mode-change-beg(%S) web-mode-change-end(%S) web-mode-skip-fontification(%S)"
  15051                (point) web-mode-change-beg web-mode-change-end web-mode-skip-fontification)
  15052       (setq web-mode-trace t)))
  15053 
  15054 (defun web-mode-debug ()
  15055   "Display informations useful for debugging."
  15056   (interactive)
  15057   (let ((modes nil)
  15058         (customs '(web-mode-enable-current-column-highlight web-mode-enable-current-element-highlight indent-tabs-mode))
  15059         (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)))
  15060     (message "\n")
  15061     (message "--- WEB-MODE DEBUG BEG ---")
  15062     (message "versions: emacs(%S.%S) web-mode(%S)"
  15063              emacs-major-version emacs-minor-version web-mode-version)
  15064     (message "vars: engine(%S) minor(%S) content-type(%S) file(%S)"
  15065              web-mode-engine
  15066              web-mode-minor-engine
  15067              web-mode-content-type
  15068              (or (buffer-file-name) (buffer-name)))
  15069     (message "system: window(%S) config(%S)" window-system system-configuration)
  15070     (message "colors: fg(%S) bg(%S) "
  15071              (cdr (assoc 'foreground-color default-frame-alist))
  15072              (cdr (assoc 'background-color default-frame-alist)))
  15073     (mapc (lambda (mode)
  15074             (condition-case nil
  15075                 (if (and (symbolp mode) (symbol-value mode) (not (member mode ignore)))
  15076                     (push mode modes))
  15077               (error nil))
  15078             ) ;lambda
  15079           minor-mode-list)
  15080     (message "minor modes: %S" modes)
  15081     (message "vars:")
  15082     (dolist (custom customs)
  15083       (message (format "%s=%S " (symbol-name custom) (symbol-value custom))))
  15084     (message "--- WEB-MODE DEBUG END ---")
  15085     (switch-to-buffer "*Messages*")
  15086     (goto-char (point-max))
  15087     (recenter)
  15088     ))
  15089 
  15090 (provide 'web-mode)
  15091 
  15092 ;;; web-mode.el ends here
  15093 
  15094 ;; Local Variables:
  15095 ;; coding: utf-8
  15096 ;; indent-tabs-mode: nil
  15097 ;; sentence-end-double-space: nil
  15098 ;; End: