config

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

web-mode.el (586530B)


      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   :group 'web-mode)
     75 ;;;###autoload
     76 (put 'web-mode-attr-indent-offset
     77      'safe-local-variable #'(lambda (v) (or (integerp v) (booleanp v))))
     78 
     79 (defcustom web-mode-attr-value-indent-offset nil
     80   "Html attribute value indentation level."
     81   :type '(choice (integer :tags "Number of spaces")
     82           (const :tags "Default" nil))
     83   :group 'web-mode)
     84 ;;;###autoload
     85 (put 'web-mode-attr-value-indent-offset
     86      'safe-local-variable #'(lambda (v) (or (integerp v) (booleanp v))))
     87 
     88 (defcustom web-mode-markup-indent-offset
     89   (if (and (boundp 'standard-indent) standard-indent) standard-indent 2)
     90   "Html indentation level."
     91   :type 'integer
     92   :group 'web-mode)
     93 ;;;###autoload
     94 (put 'web-mode-markup-indent-offset 'safe-local-variable #'integerp)
     95 
     96 (defcustom web-mode-markup-comment-indent-offset
     97   5
     98   "Html comment indentation level."
     99   :type 'integer
    100   :group 'web-mode)
    101 ;;;###autoload
    102 (put 'web-mode-markup-comment-indent-offset 'safe-local-variable #'integerp)
    103 
    104 (defcustom web-mode-css-indent-offset
    105   (if (and (boundp 'standard-indent) standard-indent) standard-indent 2)
    106   "CSS indentation level."
    107   :type 'integer
    108   :group 'web-mode)
    109 ;;;###autoload
    110 (put 'web-mode-css-indent-offset 'safe-local-variable #'integerp)
    111 
    112 (defcustom web-mode-code-indent-offset
    113   (if (and (boundp 'standard-indent) standard-indent) standard-indent 2)
    114   "Code (javascript, php, etc.) indentation level."
    115   :type 'integer
    116   :group 'web-mode)
    117 ;;;###autoload
    118 (put 'web-mode-code-indent-offset 'safe-local-variable #'integerp)
    119 
    120 (defcustom web-mode-sql-indent-offset 4
    121   "Sql (inside strings) indentation level."
    122   :type 'integer
    123   :group 'web-mode)
    124 ;;;###autoload
    125 (put 'web-mode-sql-indent-offset 'safe-local-variable #'integerp)
    126 
    127 (defcustom web-mode-enable-css-colorization (display-graphic-p)
    128   "In a CSS part, set background according to the color: #xxx, rgb(x,x,x)."
    129   :type 'boolean
    130   :group 'web-mode)
    131 
    132 (defcustom web-mode-enable-comment-interpolation nil
    133   "Enable highlight of keywords like FIXME, TODO, etc. in comments."
    134   :type 'boolean
    135   :group 'web-mode)
    136 
    137 (defcustom web-mode-enable-comment-annotation nil
    138   "Enable annotation in comments (jsdoc, phpdoc, etc.)."
    139   :type 'boolean
    140   :group 'web-mode)
    141 
    142 (defcustom web-mode-enable-auto-indentation (display-graphic-p)
    143   "Auto-indentation."
    144   :type 'boolean
    145   :group 'web-mode)
    146 
    147 (defcustom web-mode-enable-auto-closing (display-graphic-p)
    148   "Auto-closing."
    149   :type 'boolean
    150   :group 'web-mode)
    151 
    152 (defcustom web-mode-enable-auto-pairing (display-graphic-p)
    153   "Auto-pairing."
    154   :type 'boolean
    155   :group 'web-mode)
    156 
    157 (defcustom web-mode-enable-auto-opening (display-graphic-p)
    158   "Html element auto-opening."
    159   :type 'boolean
    160   :group 'web-mode)
    161 
    162 (defcustom web-mode-enable-auto-quoting (display-graphic-p)
    163   "Add double quotes after the character = in a tag."
    164   :type 'boolean
    165   :group 'web-mode)
    166 
    167 (defcustom web-mode-enable-auto-expanding nil
    168   "e.g. s/ expands to <span>|</span>."
    169   :type 'boolean
    170   :group 'web-mode)
    171 
    172 (defcustom web-mode-enable-curly-brace-indentation nil
    173   "Indent lines beginning with {."
    174   :type 'boolean
    175   :group 'web-mode)
    176 
    177 (defcustom web-mode-enable-control-block-indentation t
    178   "Control blocks increase indentation."
    179   :type 'boolean
    180   :group 'web-mode)
    181 
    182 (defcustom web-mode-enable-current-element-highlight nil
    183   "Enable current element highlight."
    184   :type 'boolean
    185   :group 'web-mode)
    186 
    187 (defcustom web-mode-enable-current-column-highlight nil
    188   "Show column for current element."
    189   :type 'boolean
    190   :group 'web-mode)
    191 
    192 (defcustom web-mode-enable-whitespace-fontification nil
    193   "Enable whitespaces."
    194   :type 'boolean
    195   :group 'web-mode)
    196 
    197 (defcustom web-mode-enable-html-entities-fontification nil
    198   "Enable html entities fontification."
    199   :type 'boolean
    200   :group 'web-mode)
    201 
    202 (defcustom web-mode-enable-block-face nil
    203   "Enable block face (useful for setting a background for example).
    204 See web-mode-block-face."
    205   :type 'boolean
    206   :group 'web-mode)
    207 
    208 (defcustom web-mode-enable-part-face nil
    209   "Enable part face (useful for setting background of <style> or <script>
    210  elements for example). See web-mode-part-face."
    211   :type 'boolean
    212   :group 'web-mode)
    213 
    214 (defcustom web-mode-enable-inlays nil
    215   "Enable inlays (e.g. LaTeX) highlighting."
    216   :type 'boolean
    217   :group 'web-mode)
    218 
    219 (defcustom web-mode-enable-sexp-functions t
    220   "Enable specific sexp functions."
    221   :type 'boolean
    222   :group 'web-mode)
    223 
    224 (defcustom web-mode-enable-string-interpolation t
    225   "Enable string interpolation fontification (php and erb)."
    226   :type 'boolean
    227   :group 'web-mode)
    228 
    229 (defcustom web-mode-enable-literal-interpolation t
    230   "Enable template literal fontification. e.g. css` `."
    231   :type 'boolean
    232   :group 'web-mode)
    233 
    234 (defcustom web-mode-enable-sql-detection nil
    235   "Enable fontification and indentation of sql queries in strings."
    236   :type 'boolean
    237   :group 'web-mode)
    238 
    239 (defcustom web-mode-enable-heredoc-fontification t
    240   "Enable heredoc fontification. The identifier should contain JS, JAVASCRIPT,
    241  CSS or HTML."
    242   :type 'boolean
    243   :group 'web-mode)
    244 
    245 (defcustom web-mode-enable-element-content-fontification nil
    246   "Enable element content fontification. The content of an element can have a
    247 face associated."
    248   :type 'boolean
    249   :group 'web-mode)
    250 
    251 (defcustom web-mode-enable-element-tag-fontification nil
    252   "Enable tag name fontification."
    253   :type 'boolean
    254   :group 'web-mode)
    255 
    256 (defcustom web-mode-enable-front-matter-block nil
    257   "Enable front matter block (data at the beginning the template
    258 between --- and ---)."
    259   :type 'boolean
    260   :group 'web-mode)
    261 
    262 (defcustom web-mode-enable-engine-detection nil
    263   "Detect such directive -*- engine: ENGINE -*- at the top of the file."
    264   :type 'boolean
    265   :group 'web-mode)
    266 
    267 (defcustom web-mode-enable-optional-tags nil
    268   "Enable omission of certain closing tags (e.g. a li open tag followed
    269 by a li open tag is valid)."
    270   :type 'boolean
    271   :group 'web-mode)
    272 
    273 (defcustom web-mode-comment-style 1
    274   "Comment style : 1 = default, 2 = force server comments outside a block."
    275   :group 'web-mode
    276   :type '(choice (const :tag "Default" 1)
    277           (const :tag "Force engine comments" 2)))
    278 
    279 (defcustom web-mode-indent-style 2
    280   "Indentation style."
    281   :group 'web-mode
    282   :type '(choice (const :tag "Default (all lines are indented)" 2)
    283           (const :tag "Text at the beginning of line is not indented" 1)))
    284 
    285 (defcustom web-mode-auto-close-style 1
    286   "Auto-close style."
    287   :group 'web-mode
    288   :type '(choice (const :tag "Auto-close on </" 1)
    289           (const :tag "Auto-close on > and </" 2)
    290           (const :tag "Auto-close on < and >/>" 3)))
    291 
    292 (defcustom web-mode-auto-quote-style 1
    293   "Auto-quoting style."
    294   :group 'web-mode
    295   :type '(choice (const :tag "Auto-quotes with double quote" 1)
    296           (const :tag "Auto-quotes with single quote" 2)
    297           (const :tag "Auto-quotes with paren (for jsx)" 3)))
    298 
    299 (defcustom web-mode-extra-expanders '()
    300   "A list of additional expanders."
    301   :type '(alist :key-type string :value-type string)
    302   :group 'web-mode)
    303 
    304 (defcustom web-mode-extra-auto-pairs '()
    305   "A list of additional auto-pairs."
    306   :type '(alist :key-type string :value-type string)
    307   :group 'web-mode)
    308 
    309 (defcustom web-mode-extra-snippets '()
    310   "A list of additional snippets."
    311   :type '(alist :key-type string :value-type string)
    312   :group 'web-mode)
    313 
    314 (defcustom web-mode-extra-builtins '()
    315   "A list of additional builtins."
    316   :type '(alist :key-type string :value-type string)
    317   :group 'web-mode)
    318 
    319 (defcustom web-mode-extra-constants '()
    320   "A list of additional constants."
    321   :type '(alist :key-type string :value-type string)
    322   :group 'web-mode)
    323 
    324 (defcustom web-mode-extra-keywords '()
    325   "A list of additional keywords."
    326   :type '(alist :key-type string :value-type string)
    327   :group 'web-mode)
    328 
    329 (defcustom web-mode-extra-types '()
    330   "A list of additional types."
    331   :type '(alist :key-type string :value-type string)
    332   :group 'web-mode)
    333 
    334 (defcustom web-mode-extra-control-blocks '()
    335   "A list of additional control blocks."
    336   :type '(alist :key-type string :value-type (repeat string))
    337   :group 'web-mode)
    338 
    339 (defcustom web-mode-tests-directory (concat default-directory "tests/")
    340   "Directory containing all the unit tests."
    341   :type 'directory
    342   :group 'web-mode)
    343 
    344 (defcustom web-mode-jsx-depth-faces
    345   nil
    346   ;;'(web-mode-jsx-depth-1-face web-mode-jsx-depth-2-face web-mode-jsx-depth-3-face web-mode-jsx-depth-4-face web-mode-jsx-depth-5-face)
    347   "Each jsx depth has is own face."
    348   :type '(repeat face)
    349   :group 'web-mode)
    350 
    351 (defcustom web-mode-commands-like-expand-region
    352   '(web-mode-mark-and-expand er/expand-region mc/mark-next-like-this mc/mark-previous-like-this)
    353   "Add commmand here if you have some wrapper function for er/expand-region"
    354   :type '(repeat function)
    355   :group 'web-mode)
    356 
    357 (defcustom web-mode-comment-formats
    358   '(("java"       . "/*")
    359     ("javascript" . "/*")
    360     ("typescript" . "//")
    361     ("php"        . "/*")
    362     ("css"        . "/*"))
    363   "Default comment format for a language"
    364   :type '(alist :key-type string :value-type string)
    365   :group 'web-mode)
    366 
    367 (defcustom web-mode-script-template-types
    368   '("text/x-handlebars"
    369     "text/x-jquery-tmpl"
    370     "text/x-jsrender"
    371     "text/html"
    372     "text/ng-template"
    373     "text/x-template"
    374     "text/mustache"
    375     "text/x-dust-template")
    376   "<script> block types that are interpreted as HTML."
    377   :type '(repeat string)
    378   :group 'web-mode)
    379 
    380 ;; https://developer.mozilla.org/en-US/docs/Web/HTML/Element
    381 (defcustom web-mode-tag-list
    382   '("a" "abbr" "address" "area" "article" "aside" "audio" "b"
    383     "base" "bdi" "bdo" "blockquote" "body" "br" "button" "canvas"
    384     "caption" "cite" "code" "col" "colgroup" "data" "datalist"
    385     "dd" "del" "details" "dfn" "dialog" "div" "dl" "dt" "em"
    386     "embed" "fieldset" "figcaption" "figure" "footer" "form" "h1"
    387     "h2" "h3" "h4" "h5" "h6" "head" "header" "hgroup" "hr" "html"
    388     "i" "iframe" "img" "input" "ins" "kbd" "label" "legend" "li"
    389     "link" "main" "map" "mark" "math" "menu" "meta" "meter" "nav"
    390     "noscript" "object" "ol" "optgroup" "option" "output" "p"
    391     "picture" "pre" "progress" "q" "rp" "rt" "ruby" "s" "samp"
    392     "script" "search" "section" "select" "slot" "small" "source"
    393     "span" "strong" "style" "sub" "summary" "sup" "svg" "table"
    394     "tbody" "td" "template" "textarea" "tfoot" "th" "thead" "time"
    395     "title" "tr" "track" "u" "ul" "var" "video" "wbr")
    396   "HTML tags used for completion."
    397   :type '(repeat string)
    398   :group 'web-mode)
    399 
    400 
    401 ;; https://www.w3schools.com/tags/ref_attributes.asp
    402 ;; Attributes marked as deprecated in HTML 5 are not added.
    403 (defcustom web-mode-attribute-list
    404   '("accept" "accesskey" "action" "alt" "async" "autocomplete" "autofocus"
    405     "autoplay" "charset" "checked" "cite" "class" "cols" "colspan" "content"
    406     "contenteditable" "controls" "coords" "data" "datetime" "default" "defer"
    407     "dir" "dirname" "disabled" "download" "draggable" "enctype" "for" "form"
    408     "formaction" "headers" "height" "hidden" "high" "href" "hreflang" "http"
    409     "id" "ismap" "kind" "label" "lang" "list" "loop" "low" "max" "maxlength"
    410     "media" "method" "min" "multiple" "muted" "name" "novalidate" "onabort"
    411     "onafterprint" "onbeforeprint" "onbeforeunload" "onblur" "oncanplay"
    412     "oncanplaythrough" "onchange" "onclick" "oncontextmenu" "oncopy"
    413     "oncuechange" "oncut" "ondblclick" "ondrag" "ondragend" "ondragenter"
    414     "ondragleave" "ondragover" "ondragstart" "ondrop" "ondurationchange"
    415     "onemptied" "onended" "onerror" "onfocus" "onhashchange" "oninput"
    416     "oninvalid" "onkeydown" "onkeypress" "onkeyup" "onload" "onloadeddata"
    417     "onloadedmetadata" "onloadstart" "onmousedown" "onmousemove" "onmouseout"
    418     "onmouseover" "onmouseup" "onmousewheel" "onoffline" "ononline"
    419     "onpagehide" "onpageshow" "onpaste" "onpause" "onplay" "onplaying"
    420     "onpopstate" "onprogress" "onratechange" "onreset" "onresize" "onscroll"
    421     "onsearch" "onseeked" "onseeking" "onselect" "onstalled" "onstorage"
    422     "onsubmit" "onsuspend" "ontimeupdate" "ontoggle" "onunload"
    423     "onvolumechange" "onwaiting" "onwheel" "open" "optimum" "pattern"
    424     "placeholder" "poster" "preload" "readonly" "rel" "required" "reversed"
    425     "rows" "rowspan" "sandbox" "scope" "selected" "shape" "size" "sizes"
    426     "span" "spellcheck" "src" "srcdoc" "srclang" "srcset" "start" "step"
    427     "style" "tabindex" "target" "title" "translate" "type" "usemap" "value"
    428     "width" "wrap")
    429   "HTML attributes used for completion."
    430   :type '(repeat string)
    431   :group 'web-mode)
    432 
    433 (defcustom web-mode-engines-alist nil
    434   "A list of filename patterns and corresponding `web-mode' engine.
    435 For example,
    436 \(setq web-mode-engines-alist
    437        \\='((\"php\"    . \"\\\\.phtml\\\\\\='\")
    438          (\"blade\"  . \"\\\\.blade\\\\.\")))"
    439   :type '(alist :key-type string :value-type string)
    440   :group 'web-mode)
    441 
    442 ;;---- FACES -------------------------------------------------------------------
    443 
    444 (defface web-mode-error-face
    445     '((t :background "red"))
    446   "Face for warning."
    447   :group 'web-mode-faces)
    448 
    449 (defface web-mode-warning-face
    450     '((t :inherit font-lock-warning-face))
    451   "Face for warning."
    452   :group 'web-mode-faces)
    453 
    454 (defface web-mode-preprocessor-face
    455     '((t :inherit font-lock-preprocessor-face))
    456   "Face for preprocessor commands."
    457   :group 'web-mode-faces)
    458 
    459 (defface web-mode-preprocessor-face
    460     '((t :inherit font-lock-preprocessor-face))
    461   "Face for preprocessor."
    462   :group 'web-mode-faces)
    463 
    464 (defface web-mode-block-delimiter-face
    465     '((t :inherit font-lock-preprocessor-face))
    466   "Face for block delimiters."
    467   :group 'web-mode-faces)
    468 
    469 (defface web-mode-block-control-face
    470     '((t :inherit font-lock-preprocessor-face))
    471   "Face for preprocessor."
    472   :group 'web-mode-faces)
    473 
    474 (defface web-mode-builtin-face
    475     '((t :inherit font-lock-builtin-face))
    476   "Face for builtins."
    477   :group 'web-mode-faces)
    478 
    479 (defface web-mode-symbol-face
    480     '((t :foreground "goldenrod2"))
    481   "Face for symbols."
    482   :group 'web-mode-faces)
    483 
    484 (defface web-mode-doctype-face
    485     '((t :foreground "Grey"))
    486   "Face for html doctype."
    487   :group 'web-mode-faces)
    488 
    489 (defface web-mode-html-tag-face
    490     '((((class color) (min-colors 88) (background dark))  :foreground "Snow4")
    491       (((class color) (min-colors 88) (background light)) :foreground "Snow4")
    492       (((class color) (min-colors 16) (background dark))  :foreground "Snow4")
    493       (((class color) (min-colors 16) (background light)) :foreground "Grey15")
    494       (((class color) (min-colors 8))                     :foreground "Snow4")
    495       (((type tty) (class mono))                          :inverse-video t)
    496       (t                                                  :foreground "Snow4"))
    497   "Face for html tags."
    498   :group 'web-mode-faces)
    499 
    500 (defface web-mode-html-tag-custom-face
    501     '((t :inherit web-mode-html-tag-face))
    502   "Face for html custom tags (e.g. <polymer-element>)."
    503   :group 'web-mode-faces)
    504 
    505 (defface web-mode-html-tag-unclosed-face
    506     '((t :inherit web-mode-html-tag-face :underline t))
    507   "Face for unclosed tags."
    508   :group 'web-mode-faces)
    509 
    510 (defface web-mode-html-tag-namespaced-face
    511     '((t :inherit web-mode-block-control-face))
    512   "Face for html namespaced tags (e.g. <c:forEach>)."
    513   :group 'web-mode-faces)
    514 
    515 (defface web-mode-html-tag-bracket-face
    516     '((((class color) (min-colors 88) (background dark))  :foreground "Snow3")
    517       (((class color) (min-colors 88) (background light)) :foreground "Grey14")
    518       (((class color) (min-colors 16) (background dark))  :foreground "Snow3")
    519       (((class color) (min-colors 16) (background light)) :foreground "Grey14")
    520       (((class color) (min-colors 8))                     :foreground "Snow3")
    521       (((type tty) (class mono))                          :inverse-video t)
    522       (t                                                  :foreground "Snow3"))
    523   "Face for html tags angle brackets (<, > and />)."
    524   :group 'web-mode-faces)
    525 
    526 (defface web-mode-html-attr-name-face
    527     '((((class color) (min-colors 88) (background dark))  :foreground "Snow3")
    528       (((class color) (min-colors 88) (background light)) :foreground "Snow4")
    529       (((class color) (min-colors 16) (background dark))  :foreground "Snow3")
    530       (((class color) (min-colors 16) (background light)) :foreground "Grey13")
    531       (((class color) (min-colors 8))                     :foreground "Snow3")
    532       (((type tty) (class mono))                          :inverse-video t)
    533       (t                                                  :foreground "Snow4"))
    534   "Face for html attribute names."
    535   :group 'web-mode-faces)
    536 
    537 (defface web-mode-html-attr-custom-face
    538     '((t :inherit web-mode-html-attr-name-face))
    539   "Face for custom attribute names (e.g. data-*)."
    540   :group 'web-mode-faces)
    541 
    542 (defface web-mode-html-attr-engine-face
    543     '((t :inherit web-mode-block-delimiter-face))
    544   "Face for custom engine attribute names (e.g. ng-*)."
    545   :group 'web-mode-faces)
    546 
    547 (defface web-mode-html-attr-equal-face
    548     '((t :inherit web-mode-html-attr-name-face))
    549   "Face for the = character between name and value."
    550   :group 'web-mode-faces)
    551 
    552 (defface web-mode-html-attr-value-face
    553     '((t :inherit font-lock-string-face))
    554   "Face for html attribute values."
    555   :group 'web-mode-faces)
    556 
    557 (defface web-mode-block-attr-name-face
    558     '((t :foreground "#8fbc8f"))
    559   "Face for block attribute names."
    560   :group 'web-mode-faces)
    561 
    562 (defface web-mode-block-attr-value-face
    563     '((t :foreground "#5f9ea0"))
    564   "Face for block attribute values."
    565   :group 'web-mode-faces)
    566 
    567 (defface web-mode-variable-name-face
    568     '((t :inherit font-lock-variable-name-face))
    569   "Face for variable names."
    570   :group 'web-mode-faces)
    571 
    572 (defface web-mode-css-selector-face
    573     '((t :inherit font-lock-keyword-face))
    574   "Face for CSS rules."
    575   :group 'web-mode-faces)
    576 
    577 (defface web-mode-css-selector-class-face
    578     '((t :inherit font-lock-keyword-face))
    579   "Face for CSS class rules."
    580   :group 'web-mode-faces)
    581 
    582 (defface web-mode-css-selector-tag-face
    583     '((t :inherit font-lock-keyword-face))
    584   "Face for CSS tag rules."
    585   :group 'web-mode-faces)
    586 
    587 (defface web-mode-css-pseudo-class-face
    588     '((t :inherit font-lock-builtin-face))
    589   "Face for CSS pseudo-classes."
    590   :group 'web-mode-faces)
    591 
    592 (defface web-mode-css-at-rule-face
    593     '((t :inherit font-lock-constant-face))
    594   "Face for CSS at-rules."
    595   :group 'web-mode-faces)
    596 
    597 (defface web-mode-css-property-name-face
    598     '((t :inherit font-lock-variable-name-face))
    599   "Face for CSS props."
    600   :group 'web-mode-faces)
    601 
    602 (defface web-mode-css-color-face
    603     '((t :inherit font-lock-builtin-face))
    604   "Face for CSS colors (#xxx)."
    605   :group 'web-mode-faces)
    606 
    607 (defface web-mode-css-priority-face
    608     '((t :inherit font-lock-builtin-face))
    609   "Face for CSS priority (!important)."
    610   :group 'web-mode-faces)
    611 
    612 (defface web-mode-css-function-face
    613     '((t :inherit font-lock-builtin-face))
    614   "Face for CSS functions."
    615   :group 'web-mode-faces)
    616 
    617 (defface web-mode-css-variable-face
    618     '((t :inherit web-mode-variable-name-face :slant italic))
    619   "Face for CSS vars."
    620   :group 'web-mode-faces)
    621 
    622 (defface web-mode-function-name-face
    623     '((t :inherit font-lock-function-name-face))
    624   "Face for function names."
    625   :group 'web-mode-faces)
    626 
    627 (defface web-mode-filter-face
    628     '((t :inherit font-lock-function-name-face))
    629   "Face for function names."
    630   :group 'web-mode-faces)
    631 
    632 (defface web-mode-function-call-face
    633     '((t :inherit font-lock-function-name-face))
    634   "Face for function calls."
    635   :group 'web-mode-faces)
    636 
    637 (defface web-mode-string-face
    638     '((t :inherit font-lock-string-face))
    639   "Face for strings."
    640   :group 'web-mode-faces)
    641 
    642 (defface web-mode-block-string-face
    643     '((t :inherit web-mode-string-face))
    644   "Face for block strings."
    645   :group 'web-mode-faces)
    646 
    647 (defface web-mode-part-string-face
    648     '((t :inherit web-mode-string-face))
    649   "Face for part strings."
    650   :group 'web-mode-faces)
    651 
    652 (defface web-mode-javascript-string-face
    653     '((t :inherit web-mode-string-face))
    654   "Face for javascript strings."
    655   :group 'web-mode-faces)
    656 
    657 (defface web-mode-interpolate-color1-face
    658     '((t :inherit web-mode-string-face))
    659   "Face for element interpolation strings."
    660   :group 'web-mode-faces)
    661 
    662 (defface web-mode-interpolate-color2-face
    663     '((t :inherit web-mode-string-face))
    664   "Face for element interpolation strings."
    665   :group 'web-mode-faces)
    666 
    667 (defface web-mode-interpolate-color3-face
    668     '((t :inherit web-mode-string-face))
    669   "Face for element interpolation strings."
    670   :group 'web-mode-faces)
    671 
    672 (defface web-mode-interpolate-color4-face
    673     '((t :inherit web-mode-string-face))
    674   "Face for element interpolation strings."
    675   :group 'web-mode-faces)
    676 
    677 (defface web-mode-css-string-face
    678     '((t :inherit web-mode-string-face))
    679   "Face for css strings."
    680   :group 'web-mode-faces)
    681 
    682 (defface web-mode-json-key-face
    683     '((t :foreground "plum"))
    684   "Face for json key strings."
    685   :group 'web-mode-faces)
    686 
    687 (defface web-mode-json-context-face
    688     '((t :foreground "orchid3"))
    689   "Face for json context strings."
    690   :group 'web-mode-faces)
    691 
    692 (defface web-mode-json-string-face
    693     '((t :inherit web-mode-string-face))
    694   "Face for json strings."
    695   :group 'web-mode-faces)
    696 
    697 (defface web-mode-comment-face
    698     '((t :inherit font-lock-comment-face))
    699   "Face for comments."
    700   :group 'web-mode-faces)
    701 
    702 (defface web-mode-block-comment-face
    703     '((t :inherit web-mode-comment-face))
    704   "Face for server comments."
    705   :group 'web-mode-faces)
    706 
    707 (defface web-mode-part-comment-face
    708     '((t :inherit web-mode-comment-face))
    709   "Face for part comments."
    710   :group 'web-mode-faces)
    711 
    712 (defface web-mode-json-comment-face
    713     '((t :inherit web-mode-comment-face))
    714   "Face for json comments."
    715   :group 'web-mode-faces)
    716 
    717 (defface web-mode-javascript-comment-face
    718     '((t :inherit web-mode-comment-face))
    719   "Face for javascript comments."
    720   :group 'web-mode-faces)
    721 
    722 (defface web-mode-css-comment-face
    723     '((t :inherit web-mode-comment-face))
    724   "Face for css comments."
    725   :group 'web-mode-faces)
    726 
    727 (defface web-mode-annotation-face
    728     '((t :inherit web-mode-comment-face))
    729   "Face for code annotations."
    730   :group 'web-mode-faces)
    731 
    732 (defface web-mode-annotation-tag-face
    733     '((t :inherit web-mode-annotation-face :underline t))
    734   "Face for @tags in code annotations."
    735   :group 'web-mode-faces)
    736 
    737 (defface web-mode-annotation-type-face
    738     '((t :inherit web-mode-annotation-face :weight bold))
    739   "Face for types in code annotations."
    740   :group 'web-mode-faces)
    741 
    742 (defface web-mode-annotation-value-face
    743     '((t :inherit web-mode-annotation-face :slant italic))
    744   "Face for values in code annotations."
    745   :group 'web-mode-faces)
    746 
    747 (defface web-mode-annotation-html-face
    748     '((t :inherit web-mode-annotation-face :slant italic))
    749   "Face for HTML tags in code annotations."
    750   :group 'web-mode-faces)
    751 
    752 (defface web-mode-constant-face
    753     '((t :inherit font-lock-constant-face))
    754   "Face for language constants."
    755   :group 'web-mode-faces)
    756 
    757 (defface web-mode-type-face
    758     '((t :inherit font-lock-type-face))
    759   "Face for language types."
    760   :group 'web-mode-faces)
    761 
    762 (defface web-mode-keyword-face
    763     '((t :inherit font-lock-keyword-face))
    764   "Face for language keywords."
    765   :group 'web-mode-faces)
    766 
    767 (defface web-mode-param-name-face
    768     '((t :foreground "Snow3"))
    769   "Face for server attribute names."
    770   :group 'web-mode-faces)
    771 
    772 (defface web-mode-whitespace-face
    773     '((t :background "DarkOrchid4"))
    774   "Face for whitespaces."
    775   :group 'web-mode-faces)
    776 
    777 (defface web-mode-inlay-face
    778     '((((class color) (min-colors 88) (background dark))  :background "Black")
    779       (((class color) (min-colors 88) (background light)) :background "LightYellow1")
    780       (((class color) (min-colors 16) (background dark))  :background "Brey18")
    781       (((class color) (min-colors 16) (background light)) :background "LightYellow1")
    782       (((class color) (min-colors 8))                     :background "Black")
    783       (((type tty) (class mono))                          :inverse-video t)
    784       (t                                                  :background "Grey"))
    785   "Face for inlays. Must be used in conjunction with web-mode-enable-inlays."
    786   :group 'web-mode-faces)
    787 
    788 (defface web-mode-block-face
    789     '((((class color) (min-colors 88) (background dark))  :background "Black")
    790       (((class color) (min-colors 88) (background light)) :background "LightYellow1")
    791       (((class color) (min-colors 16) (background dark))  :background "Grey18")
    792       (((class color) (min-colors 16) (background light)) :background "LightYellow1")
    793       (((class color) (min-colors 8))                     :background "Black")
    794       (((type tty) (class mono))                          :inverse-video t)
    795       (t                                                  :background "Grey"))
    796   "Face for blocks (useful for setting a background for example).
    797 Must be used in conjunction with web-mode-enable-block-face."
    798   :group 'web-mode-faces)
    799 
    800 (defface web-mode-part-face
    801     '((t :inherit web-mode-block-face))
    802   "Face for parts."
    803   :group 'web-mode-faces)
    804 
    805 (defface web-mode-script-face
    806     '((t :inherit web-mode-part-face))
    807   "Face for javascript inside a script element."
    808   :group 'web-mode-faces)
    809 
    810 (defface web-mode-style-face
    811     '((t :inherit web-mode-part-face))
    812   "Face for css inside a style element."
    813   :group 'web-mode-faces)
    814 
    815 (defface web-mode-folded-face
    816     '((t :underline t))
    817   "Overlay face for folded."
    818   :group 'web-mode-faces)
    819 
    820 (defface web-mode-bold-face
    821     '((t :weight bold))
    822   "bold face."
    823   :group 'web-mode-faces)
    824 
    825 (defface web-mode-italic-face
    826     '((t :slant italic))
    827   "bold face."
    828   :group 'web-mode-faces)
    829 
    830 (defface web-mode-underline-face
    831     '((t :underline t))
    832   "bold face."
    833   :group 'web-mode-faces)
    834 
    835 (defface web-mode-current-element-highlight-face
    836     '((t :background "#000000" :foreground "#ffffff"))
    837   "Overlay face for element highlight."
    838   :group 'web-mode-faces)
    839 
    840 (defface web-mode-current-column-highlight-face
    841     '((t :background "#3e3c36"))
    842   "Overlay face for current column."
    843   :group 'web-mode-faces)
    844 
    845 (defface web-mode-comment-keyword-face
    846     '((t :weight bold :box t))
    847   "Comment keywords."
    848   :group 'web-mode-faces)
    849 
    850 (defface web-mode-sql-keyword-face
    851     '((t :weight bold :slant italic))
    852   "Sql keywords."
    853   :group 'web-mode-faces)
    854 
    855 (defface web-mode-html-entity-face
    856     '((t :slant italic))
    857   "Face html entities (e.g. &#8211;, &eacute;)."
    858   :group 'web-mode-faces)
    859 
    860 ;; https://material.io/tools/color/#!/?view.left=0&view.right=0
    861 (defface web-mode-jsx-depth-1-face
    862     '((t :background "#000053"))
    863   "jsx depth 1"
    864   :group 'web-mode-faces)
    865 
    866 (defface web-mode-jsx-depth-2-face
    867     '((t :background "#001970"))
    868   "jsx"
    869   :group 'web-mode-faces)
    870 
    871 (defface web-mode-jsx-depth-3-face
    872     '((t :background "#002984"))
    873   "jsx"
    874   :group 'web-mode-faces)
    875 
    876 (defface web-mode-jsx-depth-4-face
    877     '((t :background "#49599a"))
    878   "jsx"
    879   :group 'web-mode-faces)
    880 
    881 (defface web-mode-jsx-depth-5-face
    882     '((t :background "#9499b7"))
    883   "jsx"
    884   :group 'web-mode-faces)
    885 
    886 ;;---- VARS --------------------------------------------------------------------
    887 
    888 (defvar font-lock-beg)
    889 (defvar font-lock-end)
    890 
    891 (defvar web-mode-auto-pairs nil)
    892 (defvar web-mode-block-regexp nil)
    893 (defvar web-mode-change-beg nil)
    894 (defvar web-mode-change-end nil)
    895 (defvar web-mode-chunk-length 64)
    896 (defvar web-mode-column-overlays nil)
    897 (defvar web-mode-comments-invisible nil)
    898 (defvar web-mode-content-type "")
    899 (defvar web-mode-engine nil)
    900 ;;(defvar web-mode-engine-attr-regexp nil)
    901 (defvar web-mode-engine-font-lock-keywords nil)
    902 (defvar web-mode-engine-token-regexp nil)
    903 (defvar web-mode-expand-initial-pos nil)
    904 (defvar web-mode-expand-initial-scroll nil)
    905 (defvar web-mode-expand-previous-state "")
    906 ;;(defvar web-mode-font-lock-keywords '(web-mode-font-lock-highlight))
    907 (defvar web-mode-skip-fontification nil)
    908 (defvar web-mode-inlay-regexp nil)
    909 (defvar web-mode-is-scratch nil)
    910 (defvar web-mode-jshint-errors 0)
    911 (defvar web-mode-minor-engine nil)
    912 (defvar web-mode-obarray nil)
    913 (defvar web-mode-overlay-tag-start nil)
    914 (defvar web-mode-overlay-tag-end nil)
    915 (defvar web-mode-part-beg nil)
    916 (defvar web-mode-scan-beg nil)
    917 (defvar web-mode-scan-end nil)
    918 (defvar web-mode-snippets nil)
    919 (defvar web-mode-time nil)
    920 
    921 (defvar web-mode-offsetless-elements
    922   '())
    923 
    924 (defvar web-mode-indentless-elements
    925   '("code" "pre" "textarea"))
    926 
    927 (defvar web-mode-indentless-attributes
    928   '("onclick" "onmouseover" "onmouseout" "onsubmit"))
    929 
    930 (defvar web-mode-void-elements
    931   '("area" "base" "br" "col" "command" "embed" "hr" "img" "input" "keygen"
    932     "link" "meta" "param" "source" "track" "wbr" "tmpl_var"))
    933 
    934 (defvar web-mode-part-content-types
    935   '("css" "javascript" "json" "jsx" "markdown" "pug" "ruby"
    936     "sass" "sql" "stylus" "typescript"))
    937 
    938 (defvar web-mode-javascript-languages '("javascript" "jsx" "ejs"))
    939 
    940 ;; NOTE: without 'syntax-table forward-word fails (#377)
    941 (defvar web-mode-scan-properties
    942   (list 'tag-beg 'tag-end 'tag-name 'tag-type
    943         'tag-attr 'tag-attr-beg 'tag-attr-end
    944         'part-side 'part-token
    945         'jsx-beg 'jsx-end 'jsx-depth
    946         'block-side 'block-token 'block-controls 'block-beg 'block-end
    947         'syntax-table)
    948   "Text properties used for code regions/tokens and html nodes.")
    949 
    950 (defvar web-mode-start-tag-regexp "<\\([[:alnum:].:_-]+\\|>\\)"
    951   "Regular expression for HTML/XML start tag.")
    952 
    953 (defvar web-mode-tag-regexp "</?\\([[:alnum:].:_-]+\\)"
    954   "Regular expression for HTML/XML tag.")
    955 
    956 (defvar web-mode-dom-regexp "<\\(/?>\\|/?[[:alnum:].:_-]+\\|!--\\|!\\[CDATA\\[\\|!doctype\\|!DOCTYPE\\|\?xml\\)")
    957 
    958 (defvar web-mode-whitespaces-regexp
    959   "^[ \t]\\{2,\\}$\\| \t\\|\t \\|[ \t]+$\\|^[ \n\t]+\\'\\|^[ \t]?[\n]\\{2,\\}"
    960   "Regular expression for whitespaces.")
    961 
    962 (defvar web-mode-imenu-regexp-list
    963   '(("<\\(h[1-9]\\)\\([^>]*\\)>\\([^<]*\\)" 1 3 ">")
    964     ("^[ \t]*<\\([@a-z]+\\)[^>]*>? *$" 1 "id=\"\\([a-zA-Z0-9_]+\\)\"" "#" ">"))
    965   "Regexps to match imenu items (see https://web-mode.org/doc/imenu.txt)")
    966 
    967 ;; https://www.gnu.org/software/emacs/manual/html_node/ccmode/Syntactic-Symbols.html
    968 (defvar web-mode-indentation-params
    969   '(("lineup-args"       . t)
    970     ("lineup-calls"      . t)
    971     ("lineup-concats"    . t)
    972     ("lineup-quotes"     . t)
    973     ("lineup-ternary"    . t)
    974     ("case-extra-offset" . t)
    975     ))
    976 
    977 (defvar web-mode-tag-history nil)
    978 (defvar web-mode-attribute-history nil)
    979 (defvar web-mode-attribute-value-history nil)
    980 
    981 (defvar web-mode-engines
    982   '(("angular"          . ("angularjs"))
    983     ("anki"             . ())
    984     ("antlers"          . ())
    985     ("archibus"         . ())
    986     ("artanis"          . ())
    987     ("asp"              . ())
    988     ("aspx"             . ())
    989     ("astro"            . ())
    990     ("blade"            . ("laravel"))
    991     ("cl-emb"           . ())
    992     ("clip"             . ())
    993     ("closure"          . ("soy"))
    994     ("ctemplate"        . ("mustache" "handlebars" "hapax" "ngtemplate" "ember"
    995                            "kite" "meteor" "blaze" "ractive" "velvet"))
    996     ("django"           . ("dtl" "twig" "swig" "jinja" "jinja2" "erlydtl" "liquid"
    997                            "clabango" "selmer" "nunjucks"))
    998     ("dust"             . ("dustjs"))
    999     ("ejs"              . ())
   1000     ("elixir"           . ("phoenix"))
   1001     ("erb"              . ("eruby" "erubis" "crystal"))
   1002     ("expressionengine" . ("ee"))
   1003     ("freemarker"       . ())
   1004     ("go"               . ("gtl" "hugo"))
   1005     ("hero"             . ())
   1006     ("json-t"           . ())
   1007     ("jsp"              . ("grails"))
   1008     ("mako"             . ())
   1009     ("marko"            . ())
   1010     ("mason"            . ("poet"))
   1011     ("lsp"              . ("lisp"))
   1012     ("mojolicious"      . ())
   1013     ("php"              . ())
   1014     ("python"           . ())
   1015     ("razor"            . ("play" "play2"))
   1016     ("riot"             . ())
   1017     ("smarty"           . ())
   1018     ("spip"             . ())
   1019     ("svelte"           . ("svelte"))
   1020     ("template-toolkit" . ())
   1021     ("thymeleaf"        . ())
   1022     ("perl"             . ())
   1023     ("underscore"       . ("underscore.js"))
   1024     ("velocity"         . ("vtl" "cheetah" "ssp"))
   1025     ("vue"              . ("vuejs" "vue.js"))
   1026     ("web2py"           . ())
   1027     ("xoops"            . ())
   1028     )
   1029   "Engine name aliases")
   1030 
   1031 (defvar web-mode-content-types
   1032   '(("css"        . "\\.\\(s?css\\|css\\.erb\\)\\'")
   1033     ("javascript" . "\\.\\([mc]?js\\|js\\.erb\\)\\'")
   1034     ("typescript" . "\\.\\([mc]?ts\\|ts\\.erb\\)\\'")
   1035     ("json"       . "\\.\\(api\\|json\\|jsonld\\)\\'")
   1036     ("jsx"        . "\\.[jt]sx\\'")
   1037     ("xml"        . "\\.xml\\'")
   1038     ("html"       . "."))
   1039   "content types")
   1040 
   1041 (defvar web-mode-engine-attr-regexps
   1042   '(("angular"   . "ng-")
   1043     ("thymeleaf" . "th:")
   1044     ("vue"       . "v-"))
   1045   "Engine custom attributes")
   1046 
   1047 (defvar web-mode-engine-attr-regexp
   1048   "^ng[-]\\|^th[:]\\|^v[-]\\|^[@:#(\[*]"
   1049   "Engine custom attributes")
   1050 
   1051 (defvar web-mode-last-enabled-feature nil)
   1052 
   1053 (defvar web-mode-features
   1054   '(("css-colorization"          . web-mode-enable-css-colorization)
   1055     ("element-highlight"         . web-mode-enable-current-element-highlight)
   1056     ("column-highlight"          . web-mode-enable-current-column-highlight)
   1057     ("whitespace-fontification"  . web-mode-enable-whitespace-fontification)
   1058     ("element-tag-fontification" . web-mode-enable-element-tag-fontification)
   1059     ("block-face"                . web-mode-enable-block-face)
   1060     ("part-face"                 . web-mode-enable-part-face)))
   1061 
   1062 (defvar web-mode-comment-prefixing t)
   1063 
   1064 (defvar web-mode-engine-file-regexps
   1065   '(("angular"          . "\\.component\\.html\\'")
   1066     ("anki"             . "\\.anki\\'")
   1067     ("antlers"          . "\\.antlers\\.html\\'")
   1068     ("archibus"         . "\\.axvw\\'")
   1069     ("artanis"          . "\\.html\\.tpl\\'")
   1070     ("asp"              . "\\.asp\\'")
   1071     ("aspx"             . "\\.as[cp]x\\'")
   1072     ("astro"            . "\\.astro\\'")
   1073     ("blade"            . "\\.blade\\.php\\'")
   1074     ("cl-emb"           . "\\.clemb\\'")
   1075     ("clip"             . "\\.ctml\\'")
   1076     ("closure"          . "\\.soy\\'")
   1077     ("ctemplate"        . "\\.\\(chtml\\|mustache\\)\\'")
   1078     ("django"           . "\\.\\(djhtml\\|tmpl\\|dtl\\|liquid\\|j2\\|njk\\)\\'")
   1079     ("dust"             . "\\.dust\\'")
   1080     ("elixir"           . "\\.[hl]?eex\\'")
   1081     ("ejs"              . "\\.ejs\\'")
   1082     ("erb"              . "\\.\\(erb\\|rhtml\\|erb\\.html\\|ecr\\)\\'")
   1083     ("expressionengine" . "\\.ee\\'")
   1084     ("freemarker"       . "\\.ftl\\'")
   1085     ("go"               . "\\.go\\(html\\|tmpl\\)\\'")
   1086     ("handlebars"       . "\\.\\(hb\\.html\\|hbs\\)\\'")
   1087     ("hero"             . "\\.hero\\'")
   1088     ("jinja"            . "\\.\\(jinja\\|nwt\\)\\'")
   1089     ("jsp"              . "\\.[gj]sp\\'")
   1090     ("lsp"              . "\\.lsp\\'")
   1091     ("mako"             . "\\.mako?\\'")
   1092     ("marko"            . "\\.marko\\'")
   1093     ("mason"            . "\\.mas\\'")
   1094     ("mojolicious"      . "\\.epl?\\'")
   1095     ("perl"             . "\\.\\(ptmpl\\|perl\\.html\\)\\'")
   1096     ("php"              . "\\.\\(p[hs]p\\|ctp\\|inc\\)\\'")
   1097     ("python"           . "\\.pml\\'")
   1098     ("razor"            . "\\.\\(cs\\|vb\\)html\\|\\.razor\\'")
   1099     ("riot"             . "\\.tag\\'")
   1100     ("smarty"           . "\\.tpl\\'")
   1101     ("svelte"           . "\\.svelte\\'")
   1102     ("template-toolkit" . "\\.tt.?\\'")
   1103     ("thymeleaf"        . "\\.thtml\\'")
   1104     ("velocity"         . "\\.v\\(sl\\|tl\\|m\\)\\'")
   1105     ("vue"              . "\\.vue\\'")
   1106     ("xoops"            . "\\.xoops'")
   1107     ;; regexp on the path, not just the extension
   1108     ("django"           . "[st]wig")
   1109     ("razor"            . "scala")
   1110     ("spip"             . "spip")
   1111     )
   1112   "Engine file extensions.")
   1113 
   1114 (defvar web-mode-content-types-alist nil
   1115   "A list of filename patterns and corresponding web-mode content types.
   1116 For example,
   1117 (setq web-mode-content-types-alist
   1118   \\='((\"json\" . \"/some/path/.*\\.api\\\\='\")
   1119     (\"jsx\"  . \"/some/react/path/.*\\.js[x]?\\\\='\")))")
   1120 
   1121 (defvar web-mode-smart-quotes
   1122   '("«" . "»")
   1123   "Preferred smart quotes")
   1124 
   1125 (defvar web-mode-xml-chars
   1126   '((?\& . "&amp;")
   1127     (?\< . "&lt;")
   1128     (?\> . "&gt;"))
   1129   "XML chars")
   1130 
   1131 ;; #1254 : https://html.spec.whatwg.org/entities.json
   1132 (defvar web-mode-html-entities
   1133   ;; #985
   1134   ;; remove ("gt" . 62) ("lt" . 60) ("amp" . 38)
   1135   '(("AElig" . 198) ("Aacute" . 193) ("Acirc" . 194) ("Agrave" . 192)
   1136     ("Alpha" . 913) ("Aring" . 197) ("Atilde" . 195) ("Auml" . 196)
   1137     ("Beta" . 914)
   1138     ("Ccedil" . 199) ("Chi" . 935)
   1139     ("Dagger" . 8225) ("Delta" . 916)
   1140     ("ETH" . 208) ("Eacute" . 201) ("Ecirc" . 202) ("Egrave" . 200)
   1141     ("Epsilon" . 917) ("Eta" . 919) ("Euml" . 203)
   1142     ("Gamma" . 915)
   1143     ("Iacute" . 205) ("Icirc" . 206) ("Igrave" . 204) ("Iota" . 921)
   1144     ("Iuml" . 207)
   1145     ("Kappa" . 922)
   1146     ("Lambda" . 923)
   1147     ("Mu" . 924)
   1148     ("Ntilde" . 209) ("Nu" . 925)
   1149     ("OElig" . 338) ("Oacute" . 211) ("Ocirc" . 212) ("Ograve" . 210)
   1150     ("Omega" . 937) ("Omicron" . 927) ("Oslash" . 216) ("Otilde" . 213)
   1151     ("Ouml" . 214)
   1152     ("Phi" . 934) ("Pi" . 928) ("Prime" . 8243) ("Psi" . 936)
   1153     ("Rho" . 929)
   1154     ("Scaron" . 352) ("Sigma" . 931)
   1155     ("THORN" . 222) ("Tau" . 932) ("Theta" . 920)
   1156     ("UArr" . 8657) ("Uacute" . 218) ("Uacute" . 250) ("Ucirc" . 219)
   1157     ("Ugrave" . 217)  ("Upsih" . 978)
   1158     ("Upsilon" . 933) ("Uuml" . 220) ("Uuml" . 252)
   1159     ("Xi" . 926)
   1160     ("Yacute" . 221) ("Yuml" . 376)
   1161     ("Zeta" . 918)
   1162     ("aacute" . 225) ("acirc" . 226) ("acute" . 180) ("aelig" . 230)
   1163     ("agrave" . 224) ("alefsym" . 8501) ("alpha" . 945)
   1164     ("ang" . 8736) ("apos" . 39) ("aring" . 229) ("asymp" . 8776)
   1165     ("atilde" . 227) ("auml" . 228)
   1166     ("bdquo" . 8222) ("beta" . 946) ("brvbar" . 166) ("bull" . 8226)
   1167     ("cap" . 8745) ("ccedil" . 231) ("cedil" . 184) ("cent" . 162)
   1168     ("chi" . 967) ("circ" . 710) ("clubs" . 9827) ("cong" . 8773)
   1169     ("copy" . 169) ("crarr"  . 8629) ("cup" . 8746) ("curren" . 164)
   1170     ("dArr" . 8659) ("dagger" . 8224) ("darr" . 8595) ("deg" . 176)
   1171     ("delta" . 948) ("diams" . 9830) ("divide" . 247)
   1172     ("eacute" . 233) ("ecirc"  . 234) ("egrave" . 232) ("empty" . 8709)
   1173     ("emsp" . 8195) ("ensp" . 8194) ("epsilon" . 949) ("equiv" . 8801)
   1174     ("eta" . 951) ("eth" . 240) ("euml" . 235) ("euro" . 8364) ("exist" . 8707)
   1175     ("fnof" . 402) ("forall" . 8704) ("frac12" . 189) ("frac14" . 188)
   1176     ("frac34" . 190) ("frasl" . 8260)
   1177     ("gamma" . 947) ("ge" . 8805)
   1178     ("hArr" . 8660) ("harr" . 8596) ("hearts" . 9829) ("hellip" . 8230)
   1179     ("iacute" . 237) ("icirc" . 238) ("iexcl" . 161) ("igrave" . 236)
   1180     ("image" . 8465) ("infin" . 8734) ("int" . 8747) ("iota" . 953)
   1181     ("iquest" . 191) ("isin" . 8712) ("iuml" . 239)
   1182     ("kappa" . 954)
   1183     ("lArr" . 8656) ("lambda" . 955) ("lang" . 9001) ("laquo" . 171)
   1184     ("larr" . 8592) ("lceil" . 8968) ("ldquo" . 8220) ("le" . 8804)
   1185     ("lfloor" . 8970) ("lowast" . 8727) ("loz" . 9674) ("lrm" . 8206)
   1186     ("lsaquo" . 8249) ("lsquo" . 8249)
   1187     ("macr" . 175) ("mdash" . 8212) ("micro" . 181) ("middot" . 183)
   1188     ("minus" . 8722) ("mu" . 956)
   1189     ("nabla" . 8711) ("nbsp" . 160) ("ndash" . 8211) ("ne" . 8800)
   1190     ("ni" . 8715) ("not" . 172) ("notin" . 8713) ("nsub" . 8836)
   1191     ("ntilde" . 241) ("nu" . 957) ("oacute" . 243) ("ocirc" . 244)
   1192     ("oelig" . 339) ("ograve" . 242) ("oline" . 8254) ("omega" . 969)
   1193     ("omicron" . 959) ("oplus" . 8853) ("or" . 8744) ("ordf" . 170)
   1194     ("ordm" . 186) ("oslash" . 248) ("otilde" . 245) ("otimes" . 8855)
   1195     ("ouml" . 246)
   1196     ("para" . 182) ("part" . 8706) ("permil" . 8240) ("perp" . 8869)
   1197     ("phi" . 966) ("pi" . 960) ("piv" . 982) ("plusmn" . 177) ("pound" . 163)
   1198     ("prime" . 8242) ("prod" . 8719) ("prop" . 8733) ("psi" . 968)
   1199     ("quot" . 34)
   1200     ("rArr" . 8658) ("radic" . 8730) ("rang" . 9002) ("raquo" . 187)
   1201     ("rarr" . 8594) ("rceil" . 8969) ("rdquo" . 8221) ("real" . 8476)
   1202     ("reg" . 174) ("rfloor" . 8971) ("rho" . 961) ("rlm" . 8207)
   1203     ("rsaquo" . 8250) ("rsquo" . 8250) ("sbquo" . 8218)
   1204     ("scaron" . 353) ("sdot" . 8901) ("sect" . 167) ("shy" . 173)
   1205     ("sigma" . 963) ("sigmaf" . 962) ("sim" . 8764) ("spades" . 9824)
   1206     ("sub" . 8834) ("sube" . 8838) ("sum" . 8721) ("sup" . 8835)
   1207     ("sup1" . 185) ("sup2" . 178) ("sup3" . 179) ("supe" . 8839)
   1208     ("szlig" . 223)
   1209     ("tau" . 964) ("there4" . 8756) ("theta" . 952) ("thetasym" . 977)
   1210     ("thinsp" . 8201) ("thorn" . 254) ("tilde" . 732) ("times" . 215)
   1211     ("trade" . 8482)
   1212     ("uarr" . 8593) ("ucirc" . 251) ("ugrave" . 249) ("uml" . 168)
   1213     ("upsilon" . 965)
   1214     ("weierp" . 8472)
   1215     ("xi" . 958)
   1216     ("yacute" . 253) ("yen" . 165) ("yuml" . 255)
   1217     ("zeta" . 950) ("zwj" . 8205) ("zwnj" . 8204)))
   1218 
   1219 ;; http://webdesign.about.com/od/localization/l/blhtmlcodes-ascii.htm
   1220 (defvar web-mode-display-table
   1221   (let ((table (make-display-table)))
   1222     (aset table 9  (vector ?\xBB ?\t))
   1223     (aset table 10 (vector ?\xB6 ?\n))
   1224     (aset table 32 (vector ?\xB7))
   1225     table)
   1226   "Display table used when switching to the whitespace visualization.")
   1227 
   1228 (defvar web-mode-expanders
   1229   '(("a/" . "<a href=\"|\"></a>")
   1230     ("b/" . "<table><tbody><tr><td>|</td><td></td></tr></tbody></table>")
   1231     ("c/" . "<div class=\"|\"></div>")
   1232     ("d/" . "<div>|</div>")
   1233     ("e/" . "<em>|</em>")
   1234     ("f/" . "<form>|</form>")
   1235     ("g/" . "<strong>|</strong>")
   1236     ("h/" . "<h1>|</h1>")
   1237     ("i/" . "<img src=\"|\" />")
   1238     ("j/" . "<script>|</script>")
   1239     ("l/" . "<li>|</li>")
   1240     ("m/" . "<main>|</main>")
   1241     ("n/" . "<input type=\"|\" />")
   1242     ("p/" . "<p>|</p>")
   1243     ("q/" . "<quote>|</quote>")
   1244     ("s/" . "<span>|</span>")
   1245     ("t/" . "<td>|</td>")
   1246     ("u/" . "<ul><li>|</li><li></li></ul>")
   1247     ("x/" . "<textarea>|</textarea>")
   1248     ("2/" . "<h2>|</h2>")
   1249     ("3/" . "<h3>|</h3>")
   1250     ("?/" . "<?php | ?>")))
   1251 
   1252 (defvar web-mode-engines-auto-pairs
   1253   '(("angular"          . (("{{ " . " }}")))
   1254     ("anki"             . (("{{ " . " }}")))
   1255     ("antlers"          . (("{{ "  . " }}")
   1256                            ("{{$ " . "| $}}")
   1257                            ("{{? " . "| ?}}")
   1258                            ("{{# " . "| #}}")))
   1259     ("artanis"          . (("<% "       . " %>")
   1260                            ("<%="       . " | %>")
   1261                            ("<@css"     . " | %>")
   1262                            ("<@icon"    . " | %>")
   1263                            ("<@include" . " | %>")
   1264                            ("<@js"      . " | %>")))
   1265     ("asp"              . (("<% " . " %>")))
   1266     ("aspx"             . (("<% " . " %>")
   1267                            ("<%=" . "%>")
   1268                            ("<%#" . "%>")
   1269                            ("<%$" . "%>")
   1270                            ("<%@" . "%>")
   1271                            ("<%:" . "%>")
   1272                            ("<%-" . "- | --%>")))
   1273     ("astro"            . (("{ " . " }")))
   1274     ("blade"            . (("{{{" . " | }}}")
   1275                            ("{{ " . " }}")
   1276                            ("{!!" . " | !!}")
   1277                            ("@{{" . " | }}")
   1278                            ("{{-" . "- | --}}")))
   1279     ("cl-emb"           . (("<% " . " %>")
   1280                            ("<%=" . " | %>")
   1281                            ("<%#" . " | %>")))
   1282     ("ctemplate"        . (("{{ " . "| }}")
   1283                            ("{{~ " . "| }}")
   1284                            ("{{{" . " | }}}")
   1285                            ("{~{" . " | }}")
   1286                            ("{{~{" . " | }}}")
   1287                            ("{{!" . "-- | --}}")
   1288                            ("{{^" . "}}")
   1289                            ("{{/" . "}}")
   1290                            ("{{#" . "}}")))
   1291     ("django"           . (("{{ " . " }}")
   1292                            ("{% " . " %}")
   1293                            ("{%-" . " | %}")
   1294                            ("{# " . " #}")))
   1295     ("elixir"           . (("<% " . " %>")
   1296                            ("<%=" . " | %>")
   1297                            ("<%%" . " | %>")
   1298                            ("<%#" . " | %>")))
   1299     ("ejs"              . (("<% " . " %>")
   1300                            ("<%=" . "%>")
   1301                            ("<%#" . "%>")
   1302                            ("<%-" . "%>")))
   1303     ("erb"              . (("<% " . " %>")
   1304                            ("<%=" . " %>")
   1305                            ("<%#" . "%>")
   1306                            ("<%-" . " %>")))
   1307     ("freemarker"       . (("<% " . " %>")
   1308                            ("<#-" . "- | -->")
   1309                            ("${ " . " }")
   1310                            ("[% " . " %]")
   1311                            ("[# " . " #]")
   1312                            ("[#-" . "- | --]")))
   1313     ("go"               . (("{{ " . " }}")
   1314                            ("{{-" . " | -}}")))
   1315     ("hero"             . (("<% " . " %>")
   1316                            ("<%=" . " | %>")
   1317                            ("<%!" . " | %>")
   1318                            ("<%:" . " | %>")
   1319                            ("<%#" . " | %>")
   1320                            ("<%@" . " | %>")
   1321                            ("<%~" . " | %>")
   1322                            ("<%+" . " | %>")))
   1323     ("jsp"              . (("<% " . " %>")
   1324                            ("<%-" . "- | --%>")
   1325                            ("<%=" . "%>")
   1326                            ("<%!" . "%>")
   1327                            ("<%@" . "%>")
   1328                            ("${ " . " }")))
   1329     ("lsp"              . (("<% " . " %>")
   1330                            ("<%%" . " | %>")
   1331                            ("<%#" . " | %>")))
   1332     ("mako"             . (("<% " . " %>")
   1333                            ("<%!" . " | %>")
   1334                            ("${ " . " }")))
   1335     ("marko"            . (("${ " . " }")))
   1336     ("mason"            . (("<% " . " %>")
   1337                            ("<& " . " &>")))
   1338     ("mojolicious"      . (("<% " . " %>")
   1339                            ("<%=" . " | %>")
   1340                            ("<%%" . " | %>")
   1341                            ("<%#" . " | %>")))
   1342     ("php"              . (("<?p" . "hp | ?>")
   1343                            ("<? " . " ?>")
   1344                            ("<?=" . "?>")))
   1345     ("template-toolkit" . (("[% " . " %]")
   1346                            ("[%-" . " | %]")
   1347                            ("[%#" . " | %]")))
   1348     ("riot"             . (("={ " . " }")))
   1349     ("underscore"       . (("<% " . " %>")))
   1350     ("vue"              . (("{{ " . " }}")))
   1351     ("web2py"           . (("{{ " . " }}")
   1352                            ("{{=" . "}}")))
   1353     (nil                . (("<!-" . "- | -->")))
   1354     ))
   1355 
   1356 (defvar web-mode-engines-snippets
   1357   '(("artanis" . (("if"       . "<% (if (|) %>\n\n<% ) %>")
   1358                   ("when"     . "<% (when (|) %>\n\n<% ) %>")
   1359                   ("unless"   . "<% (unless (|) %>\n\n<% ) %>")
   1360                   ("cond"     . "<% (cond %>\n<%  [(|) %>\n\n<%  ] %>\n<%  [else %>\n\n<%  ] %>\n<% ) %>")
   1361                   ("let"      . "<% (let ([|]) %>\n\n<% ) %>")
   1362                   ("let*"     . "<% (let* ([|]) %>\n\n<% ) %>")
   1363                   ("do"       . "<% (do ([|]) %>\n<%     [()] %>\n\n<% ) %>")
   1364                   ("for-each" . "<% (for-each %>\n|\n\n<% ) %>")
   1365                   ("case"     . "<% (case | %>\n<%   [() %>\n\n<%   ] %>\n<%   [() %>\n\n<%   ] %>\n<% ) %>")))
   1366     ("ejs" . (("for"     . "<% for (|) { %>\n\n<% } %>")
   1367               ("if"      . "<% if (|) { %>\n\n<% } %>")))
   1368     ("erb" . (("each"    . "<% |.each do  %>\n\n<% end %>")
   1369               ("if"      . "<% if | %>\n\n<% end %>")
   1370               ("when"    . "<% when | %>\n\n<% end %>")
   1371               ("unless"  . "<% unless | %>\n\n<% end %>")))
   1372     ("php" . (("if"      . "<?php if (|): ?>\n\n<?php endif; ?>")
   1373               ("while"   . "<?php while (|): ?>\n\n<?php endwhile; ?>")
   1374               ("for"     . "<?php for (| ; ; ): ?>\n\n<?php endfor; ?>")
   1375               ("foreach" . "<?php foreach (| as ): ?>\n\n<?php endforeach; ?>")
   1376               ("each"    . "<?php foreach (| as ): ?>\n\n<?php endforeach; ?>")
   1377               ("switch"  . "<?php switch (|): ?>\n<?php case 1: ?>\n\n<?php break ;?>\n<?php case 2: ?>\n\n<?php break ;?>\n<?php endswitch;?>")))
   1378     ("django" . (("block"      . "{% block | %}\n\n{% endblock %}")
   1379                  ("comment"    . "{% comment | %}\n\n{% endcomment %}")
   1380                  ("css"        . "{% stylesheet  %}\n\n{% endstylesheet  %}")
   1381                  ("cycle"      . "{% cycle | as  %}\n\n{% endcycle  %}")
   1382                  ("filter"     . "{% filter | %}\n\n{% endfilter %}")
   1383                  ("for"        . "{% for | in  %}\n\n{% endfor %}")
   1384                  ("if"         . "{% if | %}\n\n{% endif %}")
   1385                  ("ifequal"    . "{% ifequal | %}\n\n{% endifequal %}")
   1386                  ("ifnotequal" . "{% ifnotequal | %}\n\n{% endifnotequal %}")
   1387                  ("js"         . "{% javascript | %}\n\n{% endjavascript %}")
   1388                  ("schema"     . "{% javascript | %}\n\n{% endschema %}")
   1389                  ("safe"       . "{% safe | %}\n\n{% endsafe %}")))
   1390     ("mako" . (("if"        . "% if |:\n% endif")
   1391                ("for"       . "% for | in :\n% endfor")
   1392                ("doc"       . "<%doc>\n|\n</%doc>")
   1393                ("inherit"   . "<%inherit file=\"|\" />")
   1394                ("namespace" . "<%namespace name=\"|\" file=\"\" import=\"\"/>")
   1395                ("block"     . "<%block name=\"|\">\n</%block>")))
   1396     ("template-toolkit" . (("if"      . "[% IF | %]\n\n[% END %]")))
   1397     (nil . (("html5" . "<!doctype html>\n<html>\n<head>\n<title></title>\n<meta charset=\"utf-8\" />\n</head>\n<body>\n|\n</body>\n</html>")
   1398             ("table" . "<table><tbody>\n<tr>\n<td>|</td>\n<td></td>\n</tr>\n</tbody></table>")
   1399             ("ul"    . "<ul>\n<li>|</li>\n<li></li>\n</ul>")))
   1400     ))
   1401 
   1402 (defvar web-mode-engine-token-regexps
   1403   (list
   1404    '("antlers"     . "\"\\|'")
   1405    '("artanis"     . "\"\\|#|\\|;")
   1406    '("asp"         . "//\\|/\\*\\|\"\\|'")
   1407    '("ejs"         . "//\\|/\\*\\|\"\\|'")
   1408    '("erb"         . "\"\\|'\\|#\\|<<[-]?['\"]?\\([[:alnum:]_]+\\)['\"]?")
   1409    '("lsp"         . "\"\\|#|\\|;")
   1410    '("mako"        . "\"\\|'\\|#")
   1411    '("mason"       . "\"\\|'\\|#")
   1412    '("mojolicious" . "\"\\|'")
   1413    '("php"         . "//\\|/\\*\\|#\\|\"\\|'\\|<<<['\"]?\\([[:alnum:]]+\\)['\"]?")
   1414    '("python"      . "\"\\|'\\|#")
   1415    '("web2py"      . "\"\\|'"))
   1416   "Engine regexps used to identify tokens (strings / comments) in blocks.")
   1417 
   1418 (defvar web-mode-engine-open-delimiter-regexps
   1419   (list
   1420    '("angular"          . "{{")
   1421    '("anki"             . "{{")
   1422    '("antlers"          . "{{[@#$]?")
   1423    '("artanis"          . "<%\\|<@\\(css\\|icon\\|include\\|js\\)")
   1424    '("asp"              . "<%\\|</?[[:alpha:]]+:[[:alpha:]]+\\|</?[[:alpha:]]+Template")
   1425    '("aspx"             . "<%.")
   1426    '("astro"            . "---")
   1427    '("blade"            . "{{.\\|{!!\\|@{{\\|@[[:alpha:]]")
   1428    '("cl-emb"           . "<%")
   1429    '("closure"          . "{.\\|/\\*\\| //")
   1430    '("clip"             . "</?c:[[:alpha:]-]+")
   1431    '("ctemplate"        . "[$]?{[{~].")
   1432    '("django"           . "{[#{%]\\|^#")
   1433    '("dust"             . "{.")
   1434    '("elixir"           . "<%\\|</?[.:]")
   1435    '("ejs"              . "<%")
   1436    '("erb"              . "<%\\|^%.")
   1437    '("expressionengine" . "{.")
   1438    '("freemarker"       . "<%\\|${\\|</?[[:alpha:]]+:[[:alpha:]]\\|</?[@#]\\|\\[/?[@#].")
   1439    '("go"               . "{{.")
   1440    '("hero"             . "<%")
   1441    '("jsp"              . "<%\\|${")
   1442    '("lsp"              . "<%")
   1443    '("mako"             . "</?%\\|${\\|^[ \t]*%.\\|^[ \t]*##")
   1444    '("marko"            . "${")
   1445    '("mason"            . "</?[&%]\\|^%.")
   1446    '("mojolicious"      . "<%\\|^[ \t]*%.")
   1447    '("perl"             . "</?TMPL_[[:alpha:]]+")
   1448    '("php"              . "<\\?")
   1449    '("python"           . "<\\?")
   1450    '("razor"            . "@.\\|^[ \t]*}")
   1451    '("riot"             . "{.\\|/// begin script")
   1452    '("smarty"           . "{[[:alpha:]#$/*\"]")
   1453    '("spip"             . "\\[(#REM)\\|(\\|#[A-Z0-9_]\\|{\\|<:")
   1454    '("template-toolkit" . "\\[%\\(.\\|$\\)\\|%%#")
   1455    '("underscore"       . "<%")
   1456    '("velocity"         . "#[[:alpha:]#*]\\|$[[:alpha:]!{]")
   1457    '("vue"              . "{{\\|[:@][-[:alpha:]]+=\"")
   1458    '("web2py"           . "{{")
   1459    '("xoops"            . "<{[[:alpha:]#$/*\"]")
   1460    '("svelte"           . "{.")
   1461    )
   1462   "Engine regexps used to identify blocks.")
   1463 
   1464 (defvar web-mode-normalization-rules
   1465   '(("tag-case"          . "lower-case")
   1466     ("attr-case"         . "lower-case")
   1467     ("special-chars"     . "unicode") ;"unicode" "entities"
   1468     ("css-indentation"   . t)
   1469     ("smart-apostrophes" . t)
   1470     ("smart-quotes"      . t)
   1471     ("whitespaces"       . t)
   1472     ("indentation"       . t))
   1473   "Normalization rules")
   1474 
   1475 (defvar web-mode-element-tag-faces
   1476   (list
   1477    '("h1"     . web-mode-underline-face)
   1478    '("h2"     . web-mode-underline-face)
   1479    '("h3"     . web-mode-underline-face)
   1480    '("h4"     . web-mode-underline-face)
   1481    '("title"  . web-mode-underline-face)
   1482    '("em"     . web-mode-italic-face)
   1483    '("strong" . web-mode-bold-face)
   1484    ))
   1485 
   1486 (defvar web-mode-element-content-faces
   1487   (list
   1488    '("h1"     . web-mode-underline-face)
   1489    '("h2"     . web-mode-underline-face)
   1490    '("h3"     . web-mode-underline-face)
   1491    '("h4"     . web-mode-underline-face)
   1492    '("title"  . web-mode-underline-face)
   1493    '("em"     . web-mode-italic-face)
   1494    '("strong" . web-mode-bold-face)
   1495    ))
   1496 
   1497 (defvar web-mode-comment-keywords
   1498   (regexp-opt
   1499    (append
   1500     (cdr (assoc "comment" web-mode-extra-keywords))
   1501     '("FIXME" "TODO" "BUG" "KLUDGE" "WORKAROUND" "OPTIMIZE" "HACK" "REFACTOR" "REVIEW"))))
   1502 
   1503 (defvar web-mode-links
   1504   '(("\\.\\(png\\|jpe?g\\|gif\\|webp\\)$" "<img src=\"%s\" alt=\"\" />" nil 4)
   1505     ("\\.svg$" "<object data=\"%s\" type=\"image/svg+xml\"></object>" nil 0)
   1506     ("\\.js$" "<script type=\"text/javascript\" src=\"%s\"></script>" t 0)
   1507     ("\\.css$" "<link rel=\"stylesheet\" type=\"text/css\" href=\"%s\" />" t 0)
   1508     ("\\.html?$" "<a href=\"%s\"></a>" nil 4))
   1509   "List of elements and extensions for `web-mode-file-link'. It
   1510 consists of a string that contains the regular expression that
   1511 matches the appropriate files, a format string with element that
   1512 contains the link (%s should be put where the path goes,) a bool
   1513 that tells if the element belongs in the <head> element, and
   1514 number of characters to move back if needed (or 0 if point
   1515 shouldn't be moved back.)")
   1516 
   1517 (defvar web-mode-sql-queries
   1518   (regexp-opt
   1519    '("SELECT" "INSERT" "UPDATE" "DELETE" "select" "insert" "update" "delete")))
   1520 
   1521 (defvar web-mode-sql-keywords
   1522   (regexp-opt
   1523    (append
   1524     (cdr (assoc "sql" web-mode-extra-keywords))
   1525     '("SELECT" "INSERT" "UPDATE" "DELETE"
   1526       "FROM" "WHERE" "GROUP BY" "LIKE" "LIMIT" "HAVING" "JOIN" "LEFT" "INNER"
   1527       "FULL" "OUTER" "VALUES" "ORDER BY" "SEPARATOR" "ASC" "DESC"
   1528       "AND" "OR" "ON" "WHEN" "ELSE" "END" "THEN"))))
   1529 
   1530 (defvar web-mode-python-constants
   1531   (regexp-opt
   1532    (append
   1533     (cdr (assoc "python" web-mode-extra-constants))
   1534     '("True" "False" "None" "__debug__" "NotImplemented" "Ellipsis"))))
   1535 
   1536 (defvar web-mode-elixir-keywords
   1537   (regexp-opt
   1538    (append
   1539     (cdr (assoc "elixir" web-mode-extra-keywords))
   1540     '("after" "and" "bc" "case" "catch" "cond" "defcallback" "defdelegate" "defexception" "defgaurdp" "defguard" "defimpl" "defmodule" "defoverridable" "defprotocol" "defrecord" "defrecordp" "defstruct" "do" "else" "end" "exit" "fn" "for" "form_for" "if" "in" "lc" "not" "or" "quote" "raise" "receive" "rescue" "super" "throw" "try" "unless" "unquote" "when" "with"))))
   1541 
   1542 
   1543 (defvar web-mode-elixir-constants
   1544   (regexp-opt
   1545    (append
   1546     (cdr (assoc "elixir" web-mode-extra-constants))
   1547     '("nil" "true" "false"))))
   1548 
   1549 (defvar web-mode-erlang-constants
   1550   (regexp-opt
   1551    (append
   1552     (cdr (assoc "erlang" web-mode-extra-constants))
   1553     '("true" "false"))))
   1554 
   1555 (defvar web-mode-erlang-keywords
   1556   (regexp-opt
   1557    (append
   1558     (cdr (assoc "erlang" web-mode-extra-keywords))
   1559     '("else" "if" "do" "end"))))
   1560 
   1561 (defvar web-mode-cl-emb-constants
   1562   (regexp-opt
   1563    '("nil" "t" "raw" "escape")))
   1564 
   1565 (defvar web-mode-cl-emb-keywords
   1566   (regexp-opt
   1567    '("if" "else" "endif" "unless" "endunless" "var" "repeat"
   1568      "endrepeat" "loop" "endloop" "include" "call" "with"
   1569      "endwith" "set" "genloop" "endgenloop" "insert")))
   1570 
   1571 (defvar web-mode-artanis-constants
   1572   (regexp-opt
   1573    '("#f" "#t")))
   1574 
   1575 (defvar web-mode-artanis-keywords
   1576   (regexp-opt
   1577    (append
   1578     (cdr (assoc "artanis" web-mode-extra-keywords))
   1579     '("begin" "cut" "cute" "if" "when" "unless" "cond" "case"
   1580       "do" "quote" "syntax" "lambda" "lambda*" "and" "and-let*"
   1581       "or" "else" "delay" "receive" "use-modules" "match"
   1582       "match-lambda" "match-lambda*" "match-let" "match-let*"
   1583       "match-letrec" "let" "let*" "letrec" "letrec*" "and-let*"
   1584       "let-syntax" "letrec-syntax" "syntax-rules" "syntax-case"
   1585       "define" "define-syntax" "define-macro"
   1586       "define-condition-type" "define-immutable-record-type"
   1587       "define-record-type" "define-values" "parameterize" "for-each"
   1588       "require-extension" "set!" "test-approximate" "test-assert"
   1589       "test-begin" "test-end" "test-eq" "test-equal" "test-eqv"
   1590       "test-error" "test-group" "test-group-with-cleanup" "test-with-runner"))))
   1591 
   1592 (defvar web-mode-lsp-constants
   1593   (regexp-opt
   1594    '("nil" "t")))
   1595 
   1596 (defvar web-mode-lsp-keywords
   1597   (regexp-opt
   1598    '("dolist" "let" "while" "cond" "when" "progn" "if"
   1599      "dotimes" "unless" "lambda"
   1600      "loop" "for" "and" "or" "in" "do" "defun")))
   1601 
   1602 (defvar web-mode-php-constants
   1603   (regexp-opt
   1604    (append
   1605     (cdr (assoc "php" web-mode-extra-constants))
   1606     '("TRUE" "FALSE" "NULL" "true" "false" "null"
   1607       "STR_PAD_LEFT" "STR_PAD_RIGHT"
   1608       "ENT_COMPAT" "ENT_QUOTES" "ENT_NOQUOTES" "ENT_IGNORE"
   1609       "ENT_SUBSTITUTE" "ENT_DISALLOWED" "ENT_HTML401" "ENT_XML1"
   1610       "ENT_XHTML" "ENT_HTML5" "JSON_PRETTY_PRINT" "JSON_UNESCAPED_SLASHES"
   1611       "LIBXML_NOBLANKS"))))
   1612 
   1613 (defvar web-mode-php-keywords
   1614   (regexp-opt
   1615    (append
   1616     (cdr (assoc "php" web-mode-extra-keywords))
   1617     '("abstract" "and" "array" "as" "break" "case" "catch" "class" "clone"
   1618       "const" "continue" "declare" "default" "die" "do" "echo" "else" "elseif"
   1619       "empty" "enddeclare" "endfor" "endforeach" "endif" "endswitch" "endwhile"
   1620       "eval" "exit" "extends" "final" "finally" "fn" "for" "foreach" "function"
   1621       "global" "goto" "if" "implements" "include" "include_once" "instanceof"
   1622       "insteadof" "interface" "isset" "list" "namespace" "new" "or" "parent"
   1623       "print" "private" "protected" "public" "require" "require_once" "return"
   1624       "self" "static" "switch" "trait" "try" "throw" "unset" "use" "var"
   1625       "while" "xor" "yield" "yield from"))))
   1626 
   1627 (defvar web-mode-php-types
   1628   (eval-when-compile
   1629     (regexp-opt
   1630      '("array" "bool" "boolean" "callable" "float" "int" "integer"
   1631        "iterable" "mixed" "object" "resource" "string" "void"))))
   1632 
   1633 (defvar web-mode-css-at-rules
   1634   (eval-when-compile
   1635     (regexp-opt
   1636      '("charset" "import" "media" "page" "font-face"
   1637        "namespace" "supports" "document"
   1638        "keyframes" "-moz-keyframes" "-webkit-keyframes"
   1639        "mixin" "viewport"))))
   1640 
   1641 (defvar web-mode-css-pseudo-classes
   1642   (eval-when-compile
   1643     (regexp-opt
   1644      '("active" "after" "before" "checked" "disabled" "empty" "enabled"
   1645        "first" "first-child" "first-letter" "first-line" "first-of-type" "focus"
   1646        "hover" "lang" "last-child" "last-of-type" "left" "link"
   1647        "not" "nth-child" "nth-last-child" "nth-last-of-type" "nth-of-type"
   1648        "only-child" "only-of-type"
   1649        "right" "root" "selection" "target" "visited"))))
   1650 
   1651 (defvar web-mode-python-keywords
   1652   (regexp-opt
   1653    (append
   1654     (cdr (assoc "python" web-mode-extra-keywords))
   1655     '("and" "as" "assert" "break" "class" "continue" "def" "del"
   1656       "elif" "else" "except" "finally" "for" "from" "global"
   1657       "if" "import" "in" "is" "lambda" "nonlocal" "not" "or" "pass"
   1658       "raise" "return" "try" "while" "with" "yield"))))
   1659 
   1660 (defvar web-mode-jsp-keywords
   1661   (regexp-opt
   1662    (append
   1663     (cdr (assoc "jsp" web-mode-extra-keywords))
   1664     '("case" "catch" "do" "else" "end" "false" "for" "function"
   1665       "if" "in" "include"
   1666       "new" "package" "page" "private" "protected" "public"
   1667       "return" "tag" "taglib" "throw" "throws" "true" "try" "void" "while"))))
   1668 
   1669 (defvar web-mode-erb-keywords
   1670   (regexp-opt
   1671    (append
   1672     (cdr (assoc "erb" web-mode-extra-keywords))
   1673     '("alias" "and" "begin" "break" "case" "class" "def" "defined?" "do"
   1674       "elsif" "else" "end" "ensure" "fail" "for" "if" "in"
   1675       "module" "next" "not" "or" "redo" "rescue" "retry" "return"
   1676       "then" "super" "unless" "undef" "until" "when" "while" "yield"
   1677       "__ENCODING__" "__FILE__" "__LINE__"))))
   1678 
   1679 (defvar web-mode-mason-keywords
   1680   (regexp-opt
   1681    (append
   1682     (cdr (assoc "mason" web-mode-extra-keywords))
   1683     '("and" "base" "close" "die" "each" "else" "elsif" "eval" "exists"
   1684       "foreach" "grep" "if" "length" "local" "my" "next" "open" "or"
   1685       "package" "pop" "ref" "return" "stat" "sub" "tie"
   1686       "undef" "unless" "use" "while"))))
   1687 
   1688 (defvar web-mode-erb-builtins
   1689   (regexp-opt
   1690    (append
   1691     (cdr (assoc "erb" web-mode-extra-builtins))
   1692 
   1693     '("__callee__" "__dir__" "__method__"
   1694       "abort" "at_exit" "autoload" "autoload?"
   1695       "binding" "block_given?" "caller" "catch"
   1696       "eval" "exec" "exit" "exit!" "fail" "fork" "format"
   1697       "lambda" "load" "loop" "open"
   1698       "p" "print" "printf" "proc" "putc" "puts"
   1699       "raise" "rand" "readline" "readlines" "require" "require_relative"
   1700       "sleep" "spawn" "sprintf" "srand" "syscall" "system"
   1701       "throw" "trap" "warn"
   1702       "alias_method" "attr" "attr_accessor" "attr_reader" "attr_writer"
   1703       "define_method" "extend" "include" "module_function"
   1704       "prepend" "private" "protected" "public"
   1705       "refine" "using"
   1706 
   1707       "error_message_on" "error_messages_for" "form" "input"
   1708       "auto_discovery_link_tag" "image_tag" "javascript_include_tag"
   1709       "stylesheet_link_tag" "image_path" "path_to_image"" "
   1710       "javascript_path" "path_to_javascript" "register_javascript_expansion"
   1711       "register_javascript_include_default" "register_stylesheet_expansion"
   1712       "stylesheet_path" "path_to_stylesheet" "atom_feed" "entry" "updated"
   1713       "benchmark" "cache" "capture" "content_for" "distance_of_time_in_words"
   1714       "distance_of_time_in_words_to_now" "time_ago_in_words" "date_select"
   1715       "datetime_select" "time_select" "select_date" "select_datetime"
   1716       "select_day" "select_hour" "select_minute" "select_month" "select_second"
   1717       "select_time" "select_year" "debug"
   1718       "check_box" "fields_for" "file_field" "form_for" "hidden_field"
   1719       "label" "password_field" "radio_button" "text_area" "text_field"
   1720       "check_box_tag" "field_set_tag" "file_field_tag" "form_with" "form_tag"
   1721       "hidden_field_tag" "image_submit_tag" "label_tag" "password_field_tag"
   1722       "radio_button_tag" "select_tag" "submit_tag" "text_area_tag"
   1723       "text_field_tag"
   1724       "collection_select" "country_options_for_select" "country_select"
   1725       "option_groups_from_collection_for_select" "options_for_select"
   1726       "options_from_collection_for_select" "select"
   1727       "time_zone_options_for_select"
   1728       "time_zone_select" "button_to_function" "define_javascript_functions"
   1729       "escape_javascript" "javascript_tag" "link_to_function"" "
   1730       "number_to_currency" "number_to_human_size" "number_to_percentage"
   1731       "number_to_phone" "number_with_delimiter" "number_with_precision"
   1732       "evaluate_remote_response" "form_remote_for" "form_remote_tag"
   1733       "link_to_remote" "observe_field" "observe_field"
   1734       "periodically_call_remote"
   1735       "remote_form_for" "remote_function" "submit_to_remote" "update_page"
   1736       "update_page_tag" "dom_class" "dom_id" "partial_path" "sanitize"
   1737       "sanitize_css" "strip_links" "strip_tags"
   1738       "cdata_section" "content_tag" "escape_once" "tag"
   1739       "auto_link" "concat" "cycle" "excerpt" "highlight" "markdown" "pluralize"
   1740       "reset_cycle" "simple_format" "textilize" "textilize_without_paragraph"
   1741       "truncate" "word_wrap" "button_to" "current_page?" "link_to" "link_to_if"
   1742       "link_to_unless" "link_to_unless_current" "mail_to" "url_for"
   1743       "action_name" "atom_feed" "audio_path" "audio_tag"
   1744       "content_tag_for" "controller" "controller_name" "action_name"
   1745       "controller_path" "convert_to_model" "cookies" "csrf_meta_tag"
   1746       "csrf_meta_tags" "headers"
   1747       "current_cycle" "div_for" "email_field" "email_field_tag"
   1748       "favicon_link_tag" "flash" "l" "button_tag"
   1749       "grouped_collection_select" "grouped_options_for_select"
   1750       "image_alt" "j" "javascript_cdata_section"
   1751       "localize" "logger" "number_field"
   1752       "number_field_tag" "number_to_human" "params" "path_to_audio"
   1753       "path_to_video" "phone_field" "phone_field_tag" "provide"
   1754       "range_field" "range_field_tag" "raw" "render" "render_to_string" "request"
   1755       "request_forgery_protection_token" "response" "safe_concat"
   1756       "safe_join" "search_field" "search_field_tag"
   1757       "session" "t" "telephone_field" "telephone_field_tag"
   1758       "time_tag" "translate" "url_field" "url_field_tag"
   1759       "url_options" "video_path" "video_tag" "simple_form_for"
   1760       "javascript_pack_tag" "stylesheet_pack_tag" "csp_meta_tag"
   1761 
   1762       ))))
   1763 
   1764 (defvar web-mode-asp-constants
   1765   (regexp-opt
   1766    (append
   1767     (cdr (assoc "asp" web-mode-extra-constants))
   1768     '("adAsyncExecute" "adAsyncFetch" "adAsyncFetchNonBlocking" "adCmdFile"
   1769       "adCmdStoredProc" "adCmdTable" "adCmdTableDirect" "adCmdText" "adCmdUnknown"
   1770       "adCmdUnspecified" "adExecuteNoRecords" "adExecuteRecord" "adExecuteStream"
   1771       "adLockBatchOptimistic" "adLockOptimistic" "adLockPessimistic"
   1772       "adLockReadOnly" "adLockUnspecified" "adOpenDynamic" "adOpenForwardOnly"
   1773       "adOpenKeyset" "adOpenStatic" "adOpenUnspecified" "adOptionUnspecified"
   1774       "Empty" "Nothing" "Null" "True" "False"
   1775       "vbBack" "vbCr" "vbCrLf" "vbFormFeed" "vbLf" "vbNewLine" "vbNullChar"
   1776       "vbNullString" "vbObjectError" "vbScript" "vbTab" "vbVerticalTab"))))
   1777 
   1778 (defvar web-mode-asp-keywords
   1779   (regexp-opt
   1780    (append
   1781     (cdr (assoc "asp" web-mode-extra-keywords))
   1782     '("Abs" "And" "Array" "Asc" "Atn"
   1783       "CBool" "CByte" "CCur" "CDate" "CDbl" "CInt" "CLng" "CSng" "CStr"
   1784       "Call" "Case" "Chr" "Class" "Const" "Cos" "CreateObject"
   1785       "Date" "DateAdd" "DateDiff" "DatePart" "DateSerial" "DateValue"
   1786       "Day" "Dim" "Do"
   1787       "Each" "Else" "ElseIf" "End" "Erase" "Err" "Eval" "Exit" "Exp"
   1788       "Explicit"
   1789       "Filter" "Fix" "For" "FormatCurrency" "FormatDateTime"
   1790       "FormatNumber" "FormatPercent" "Function"
   1791       "GetLocale" "GetObject" "GetRef" "Hex" "Hour"
   1792       "If" "In" "InStr" "InStrRev" "InputBox" "Int" "IsArray" "IsDate"
   1793       "IsEmpty" "IsNull" "IsNumeric" "IsObject" "Join"
   1794       "LBound" "LCase" "LTrim" "Language" "Left" "Len" "Let"
   1795       "LoadPicture" "Log" "Loop"
   1796       "Mid" "Minute" "Month" "MonthName" "MsgBox"
   1797       "New" "Next" "Not" "Now"
   1798       "Oct" "On" "Option" "Or" "Preserve" "Private" "Public"
   1799       "RGB" "RTrim" "Redim" "Rem" "Replace" "Right" "Rnd" "Round"
   1800       "ScriptEngine" "ScriptEngineBuildVersion"
   1801       "ScriptEngineMajorVersion" "ScriptEngineMinorVersion"
   1802       "Second" "Select" "Set" "SetLocale" "Sgn" "Sin" "Space" "Split"
   1803       "Sqr" "StrComp" "StrReverse" "String" "Sub"
   1804       "Tan" "Then" "Time" "TimeSerial" "TimeValue" "Timer" "To" "Trim"
   1805       "TypeName"
   1806       "UBound" "UCase" "Until" "VarType"
   1807       "Weekday" "WeekdayName" "Wend" "With" "While" "Year"))))
   1808 
   1809 (defvar web-mode-asp-types
   1810   (regexp-opt
   1811    (append
   1812     (cdr (assoc "asp" web-mode-extra-types))
   1813     '("Application" "ASPError" "Request" "Response" "Server" "Session"))))
   1814 
   1815 (defvar web-mode-aspx-keywords
   1816   (regexp-opt
   1817    (append
   1818     (cdr (assoc "aspx" web-mode-extra-keywords))
   1819     '("case" "catch" "do" "else" "end" "for" "foreach" "function"
   1820       "if" "in" "include" "new" "package" "page" "return"
   1821       "tag" "throw" "throws" "try" "while"))))
   1822 
   1823 (defvar web-mode-smarty-keywords
   1824   (regexp-opt '("as")))
   1825 
   1826 (defvar web-mode-velocity-keywords
   1827   (eval-when-compile
   1828     (regexp-opt '("in" "true" "false"))))
   1829 
   1830 (defvar web-mode-freemarker-keywords
   1831   (eval-when-compile
   1832     (regexp-opt '("as" "list"))))
   1833 
   1834 (defvar web-mode-go-keywords
   1835   (eval-when-compile
   1836     (regexp-opt
   1837      '("const" "define" "else" "end"
   1838        "for" "func" "if" "import"
   1839        "pipeline" "range" "return" "struct"
   1840        "template" "type" "var" "with"))))
   1841 
   1842 (defvar web-mode-go-functions
   1843   (eval-when-compile
   1844     (regexp-opt
   1845      '("and" "call" "ge" "html" "index" "js" "len" "not" "or"
   1846        "print" "printf" "println" "urlquery" "where"))))
   1847 
   1848 (defvar web-mode-go-types
   1849   (regexp-opt
   1850    (append
   1851     (cdr (assoc "go" web-mode-extra-types))
   1852     '("int" "string"))))
   1853 
   1854 (defvar web-mode-closure-keywords
   1855   (eval-when-compile
   1856     (regexp-opt '("in" "and" "not" "or"))))
   1857 
   1858 (defvar web-mode-svelte-keywords
   1859   (regexp-opt '("as")))
   1860 
   1861 (defvar web-mode-django-control-blocks
   1862   (append
   1863    (cdr (assoc "django" web-mode-extra-control-blocks))
   1864    '(
   1865 
   1866      "assets" "autoescape"
   1867      "block" "blocktrans" "blocktranslate"
   1868      "cache" "call" "capture" "comment"
   1869      "draw"
   1870      "embed"
   1871      "filter" "for" "foreach" "form"
   1872      "if" "ifchanged" "ifequal" "ifnotequal"
   1873      "macro"
   1874      "random" "raw"
   1875      "safe" "sandbox" "spaceless"
   1876      "tablerow"
   1877      "unless"
   1878      "verbatim"
   1879      "with"
   1880 
   1881      "endassets" "endautoescape"
   1882      "endblock" "endblocktrans" "endblocktranslate"
   1883      "endcache" "endcall" "endcapture" "endcomment"
   1884      "draw"
   1885      "endembed"
   1886      "endfilter" "endfor" "endforeach" "endform"
   1887      "endif" "endifchanged" "endifequal" "endifnotequal"
   1888      "endmacro"
   1889      "endrandom" "endraw"
   1890      "endsafe" "endsandbox" "endspaceless"
   1891      "endtablerow"
   1892      "endunless"
   1893      "endverbatim"
   1894      "endwith"
   1895 
   1896      ;; "set" "endset" ;#504
   1897 
   1898      "csrf_token" "cycle" "debug"
   1899      "elif" "else" "elseif" "elsif" "empty" "extends"
   1900      "firstof" "include" "load" "lorem" "now" "regroup" "ssi"
   1901      "trans" "templatetag" "url" "widthratio"
   1902 
   1903      ;; #805
   1904      "graph" "endgraph"
   1905      "javascript" "endjavascript"
   1906      "schema" "endschema"
   1907      "stylesheet" "endstylesheet"
   1908 
   1909      )))
   1910 
   1911 (defvar web-mode-django-control-blocks-regexp
   1912   (regexp-opt web-mode-django-control-blocks t))
   1913 
   1914 (defvar web-mode-django-keywords
   1915   (eval-when-compile
   1916     (regexp-opt
   1917      '("and" "as" "assign"
   1918        "break"
   1919        "cache" "call" "case" "context" "continue"
   1920        "do"
   1921        "flush" "from"
   1922        "ignore" "import" "in" "is"
   1923        "layout" "load"
   1924        "missing"
   1925        "none" "not"
   1926        "or"
   1927        "pluralize"
   1928        "random"
   1929        "set" ;#504
   1930        "unless" "use"
   1931        "var"
   1932        ))))
   1933 
   1934 (defvar web-mode-django-types
   1935   (eval-when-compile
   1936     (regexp-opt '("null" "false" "true"))))
   1937 
   1938 (defvar web-mode-blade-control-blocks
   1939   (append
   1940    (cdr (assoc "blade" web-mode-extra-control-blocks))
   1941    '("component" "foreach" "forelse" "for" "if" "section" "slot" "switch" "unless" "while")
   1942    ))
   1943 
   1944 (defvar web-mode-blade-control-blocks-regexp
   1945   (regexp-opt web-mode-blade-control-blocks t))
   1946 
   1947 (defvar web-mode-directives
   1948   (eval-when-compile
   1949     (regexp-opt
   1950      '("include" "page" "taglib"
   1951        "Assembly" "Control" "Implements" "Import"
   1952        "Master" "OutputCache" "Page" "Reference" "Register"))))
   1953 
   1954 (defvar web-mode-template-toolkit-keywords
   1955   (regexp-opt
   1956    '("block" "call" "case" "catch" "clear" "default" "do"
   1957      "else" "elsif" "end" "filter" "final" "for"
   1958      "foreach" "get" "if" "in" "include" "insert" "is" "last"
   1959      "macro" "meta" "or" "perl" "process" "rawperl" "return"
   1960      "set" "stop" "switch" "tags" "throw" "try"
   1961      "unless" "use" "while" "wrapper")))
   1962 
   1963 (defvar web-mode-perl-keywords
   1964   (regexp-opt
   1965    '("__DATA__" "__END__" "__FILE__" "__LINE__" "__PACKAGE__"
   1966      "and" "cmp" "continue" "CORE" "do" "else" "elsif" "eq" "exp"
   1967      "for" "foreach" "ge" "gt" "if" "le" "lock" "lt" "m" "ne" "no"
   1968      "or" "package" "q" "qq" "qr" "qw" "qx" "s" "sub"
   1969      "tr" "unless" "until" "while" "xor" "y"
   1970      "my" "use" "print" "say")))
   1971 
   1972 (defvar web-mode-javascript-keywords
   1973   (regexp-opt
   1974    (append
   1975     (cdr (assoc "javascript" web-mode-extra-keywords))
   1976     '("as" "async" "await" "break" "case" "catch" "class" "const" "continue"
   1977       "debugger" "default" "delete" "do" "else" "enum" "eval"
   1978       "export" "extends" "finally" "for" "from" "function" "get" "if"
   1979       "implements" "import" "in" "instanceof" "interface" "let"
   1980       "new" "of" "package" "private" "protected" "public"
   1981       "return" "set" "static" "super" "switch"
   1982       "throw" "try" "type" "typeof" "var" "void" "while" "with" "yield"))))
   1983 
   1984 (defvar web-mode-javascript-constants
   1985   (regexp-opt
   1986    '("false" "null" "undefined" "Infinity" "NaN" "true" "arguments" "this")))
   1987 
   1988 (defvar web-mode-razor-keywords
   1989   (regexp-opt
   1990    (append
   1991     (cdr (assoc "razor" web-mode-extra-keywords))
   1992     '("false" "true" "foreach" "if" "else" "in" "var" "for" "display"
   1993       "match" "case" "to"
   1994       "Html"))))
   1995 
   1996 (defvar web-mode-selector-font-lock-keywords
   1997   (list
   1998    '("$[[:alnum:]-]+" 0 'web-mode-css-variable-face)
   1999    (cons (concat "@\\(" web-mode-css-at-rules "\\)\\_>")
   2000          '(0 'web-mode-css-at-rule-face))
   2001    '("\\_<\\(all\|braille\\|embossed\\|handheld\\|print\\|projection\\|screen\\|speech\\|tty\\|tv\\|and\\|or\\)\\_>"
   2002      1 'web-mode-keyword-face)
   2003    '("\\.[^ ,]+" 0 'web-mode-css-selector-class-face)
   2004    '("[^,]+" 0 'web-mode-css-selector-tag-face)
   2005    (cons (concat ":\\([ ]*[[:alpha:]][^,{]*\\)") '(0 'web-mode-css-pseudo-class-face t t))
   2006    ))
   2007 
   2008 (defvar web-mode-declaration-font-lock-keywords
   2009   (list
   2010    '("--[[:alnum:]-]+" 0 'web-mode-css-variable-face)
   2011    '("$[[:alnum:]-]+" 0 'web-mode-css-variable-face)
   2012    (cons (concat "@\\(" web-mode-css-at-rules "\\)\\_>") '(1 'web-mode-css-at-rule-face))
   2013    '("\\([[:alpha:]-]+\\)[ ]?:" 0 'web-mode-css-property-name-face)
   2014    '("\\([[:alpha:]-]+\\)[ ]?(" 1 'web-mode-css-function-face)
   2015    '("#[[:alnum:]]\\{1,6\\}" 0 'web-mode-css-color-face t t)
   2016    '("![ ]?important" 0 'web-mode-css-priority-face t t)
   2017    '("\\([^,]+\\)[ ]+{" 1 'web-mode-css-selector-face)
   2018    '("'[^']*'\\|\"[^\"]*\"" 0 'web-mode-string-face t t)
   2019    ))
   2020 
   2021 (defvar web-mode-html-font-lock-keywords
   2022   (list
   2023    '("</?[[:alnum:]]+[ >]\\|>" 0 'web-mode-html-tag-face t)
   2024    '(" \\([[:alnum:]-]+=\\)\\(\"[^\"]+\"\\)"
   2025      (1 'web-mode-html-attr-name-face)
   2026      (2 'web-mode-html-attr-value-face))
   2027    ))
   2028 
   2029 ;; voir https://www.gnu.org/software/emacs/manual/html_node/elisp/Search_002dbased-Fontification.html
   2030 (defvar web-mode-javascript-font-lock-keywords
   2031   (list
   2032    '("@\\([[:alnum:]_]+\\)\\_>" 0 'web-mode-keyword-face)
   2033    '("\\([[:alnum:]]+\\)[`]" 0 'web-mode-preprocessor-face)
   2034    (cons (concat "\\_<\\(function\\*\\)\\_>") '(1 'web-mode-keyword-face))
   2035    (cons (concat "\\([ \t}{(]\\|^\\)\\(" web-mode-javascript-keywords "\\)\\_>") '(2 'web-mode-keyword-face))
   2036    (cons (concat "\\_<\\(" web-mode-javascript-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2037    '("\\_<\\([$]\\)(" 1 'web-mode-type-face)
   2038    '("\\_<\\(new\\|instanceof\\|class\\|extends\\|import\\) \\([[:alnum:]_.]+\\)\\_>" 2 'web-mode-type-face)
   2039    '("\\_<\\([[:alnum:]_]+\\):[ ]*function[ ]*(" 1 'web-mode-function-name-face)
   2040    '("\\_<\\(function\\|get\\|set\\)[ ]+\\([[:alnum:]_]+\\)"
   2041      (1 'web-mode-keyword-face)
   2042      (2 'web-mode-function-name-face))
   2043    '("\\([[:alnum:]_]+\\)[ ]*([^)]*)[ \n]*{" 1 'web-mode-function-name-face)
   2044    '("([ ]*\\([[:alnum:]_]+\\)[ ]*=>" 1 'web-mode-function-name-face)
   2045    '("[ ]*\\([[:alnum:]_]+\\)[ ]*=[ ]*([^)]*)[ ]*=>[ ]*{" 1 'web-mode-function-name-face)
   2046    '("\\_<\\(var\\|let\\|const\\)[ ]+\\([[:alnum:]_]+\\)" 2 'web-mode-variable-name-face)
   2047    '("({" "\\([[:alnum:]_]+\\)[, }]+" nil nil (1 'web-mode-variable-name-face)) ;#738
   2048    '("\\([[:alnum:]_]+\\)[ ]*=> [{(]" 1 'web-mode-variable-name-face)
   2049    ;; #989
   2050    ;; '("\\(function\\|[,=]\\|^\\)[ ]*("
   2051    ;;   ("\\([[:alnum:]_]+\\)\\([ ]*=[^,)]*\\)?[,)]" nil nil (1 'web-mode-variable-name-face)))
   2052    '("\\([[:alnum:]_]+\\):" 1 'web-mode-variable-name-face)
   2053    '("\\_<\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2054    '("[a-zA-Z]<\\([a-zA-Z]+\\)[,>]" 1 'web-mode-type-face)
   2055    ))
   2056 
   2057 (defvar web-mode-stylus-font-lock-keywords
   2058   (list
   2059    '("^[ \t]*\\([[:alnum:]().-]+\\)$" 1 'web-mode-css-selector-face)
   2060    '("^[ \t]*\\([[:alnum:]-]+[ ]*:\\)" 1 'web-mode-css-property-name-face)
   2061    ))
   2062 
   2063 (defvar web-mode-sass-font-lock-keywords
   2064   (list
   2065    '("^[ \t]*\\([[:alnum:]().-]+\\|&:\\(before\\|after\\)\\)$" 1 'web-mode-css-selector-face)
   2066    '("^[ \t]*\\([[:alnum:]-]+[ ]*:\\)" 1 'web-mode-css-property-name-face)
   2067    ))
   2068 
   2069 (defvar web-mode-pug-font-lock-keywords
   2070   (list
   2071    '("^[ \t]*\\(#?[[:alnum:].-]+\\)" 1 'web-mode-css-selector-face)
   2072    ;;'("^[ \t]*\\(#[[:alnum:]-]+\\)" 0 'web-mode-css-selector-face)
   2073    '(" \\([@:]?\\sw+[ ]?=\\)" 1 'web-mode-param-name-face)
   2074    ))
   2075 
   2076 (defvar web-mode-sql-font-lock-keywords
   2077   (list
   2078    (cons (concat "\\_<\\(" web-mode-sql-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2079    '("\\_<\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2080    ))
   2081 
   2082 (defvar web-mode-markdown-font-lock-keywords
   2083   (list
   2084    '("^[ ]*[*].*$" 0 'web-mode-variable-name-face)
   2085    '("^[ ]*#.*$" 0 'web-mode-comment-face)
   2086    ))
   2087 
   2088 (defvar web-mode-html-tag-font-lock-keywords
   2089   (list
   2090    '("\\(</?\\)\\([[:alnum:]]+\\)"
   2091      (1 'web-mode-html-tag-bracket-face)
   2092      (2 'web-mode-html-tag-face))
   2093    '("\"[^\"]*\"" 0 'web-mode-html-attr-value-face)
   2094    '("\\([[:alnum:]]+\\)" 1 'web-mode-html-attr-name-face)
   2095    '("/?>" 0 'web-mode-html-tag-bracket-face)
   2096    ))
   2097 
   2098 (defvar web-mode-anki-font-lock-keywords
   2099   (list
   2100    '("{{[#/^]\\([[:alnum:]_.]+\\)" 1 'web-mode-block-control-face)
   2101    ;;'("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_.: ]*\\)"
   2102    ;;  (1 'web-mode-block-attr-name-face)
   2103    ;;  (2 'web-mode-block-attr-value-face))
   2104    '("{{\\(.+\\)}}" 1 'web-mode-variable-name-face)
   2105    ))
   2106 
   2107 (defvar web-mode-dust-font-lock-keywords
   2108   (list
   2109    '("{[#:/?@><+^]\\([[:alpha:]_.]+\\)" 1 'web-mode-block-control-face)
   2110    '(":\\([[:alpha:]]+\\)" 1 'web-mode-keyword-face)
   2111    '("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_]*\\)"
   2112      (1 'web-mode-block-attr-name-face)
   2113      (2 'web-mode-block-attr-value-face))
   2114    '("\\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face)
   2115    ))
   2116 
   2117 (defvar web-mode-expressionengine-font-lock-keywords
   2118   (list
   2119    '("{/?\\([[:alpha:]_]+:[[:alpha:]_:]+\\|if\\)" 1 'web-mode-block-control-face)
   2120    '(":\\([[:alpha:]_]+\\)" 1 'web-mode-keyword-face)
   2121    '(" {\\([[:alpha:]_]+\\)}" 1 'web-mode-keyword-face t)
   2122    '("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_]*\\)"
   2123      (1 'web-mode-block-attr-name-face)
   2124      (2 'web-mode-block-attr-value-face))
   2125    '("\\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face)
   2126    ))
   2127 
   2128 (defvar web-mode-svelte-font-lock-keywords
   2129   (list
   2130    (cons (concat "[ ]\\(" web-mode-svelte-keywords "\\)[ ]") '(1 'web-mode-keyword-face))
   2131    '("{[#:/@]\\([[:alpha:]_.]+\\)" 1 'web-mode-block-control-face)
   2132    '("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_]*\\)"
   2133      (1 'web-mode-block-attr-name-face)
   2134      (2 'web-mode-block-attr-value-face))
   2135    '("\\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face)
   2136    '("\\_<\\([$]\\)\\([[:alnum:]_]+\\)" (1 'web-mode-constant-face) (2 'web-mode-variable-name-face))
   2137    ))
   2138 
   2139 (defvar web-mode-template-toolkit-font-lock-keywords
   2140   (list
   2141    (cons (concat "\\_<\\(" web-mode-template-toolkit-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2142    '("\\\([[:alpha:]][[:alnum:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2143    '("\\\([[:alpha:]][[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2144    ))
   2145 
   2146 (defvar web-mode-smarty-font-lock-keywords
   2147   (list
   2148    (cons (concat "[ ]\\(" web-mode-smarty-keywords "\\)[ ]") '(1 'web-mode-keyword-face))
   2149    '("{/?\\([[:alpha:]_]+\\)" 1 'web-mode-block-control-face)
   2150    '("\\([}{]\\)" 0 'web-mode-block-delimiter-face)
   2151    '("\\_<\\([$]\\)\\([[:alnum:]_]+\\)" (1 nil) (2 'web-mode-variable-name-face))
   2152    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2153    '(" \\(\\sw+[ ]?=\\)" 1 'web-mode-param-name-face)
   2154    '(" \\(\\sw+\\)[ }]" 1 'web-mode-param-name-face)
   2155    '("|\\([[:alnum:]_]+\\)" 1 'web-mode-function-call-face)
   2156    '("\\(->\\)\\(\\sw+\\)" (1 nil) (2 'web-mode-variable-name-face))
   2157    '("[.]\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2158    '("[.]\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2159    '("#\\([[:alnum:]_]+\\)#" 1 'web-mode-variable-name-face)
   2160    ))
   2161 
   2162 (defvar web-mode-velocity-font-lock-keywords
   2163   (list
   2164    '("#{?\\([[:alpha:]_]+\\)\\_>" (1 'web-mode-block-control-face))
   2165    (cons (concat "\\_<\\(" web-mode-velocity-keywords "\\)\\_>") '(1 'web-mode-keyword-face t t))
   2166    '("#macro([ ]*\\([[:alpha:]]+\\)[ ]+" 1 'web-mode-function-name-face)
   2167    '("\\(def\\|define\\) \\([[:alnum:]_-]+\\)(" 2 'web-mode-function-name-face)
   2168    '("[.]\\([[:alnum:]_-]+\\)" 1 'web-mode-variable-name-face)
   2169    '("\\_<\\($[!]?[{]?\\)\\([[:alnum:]_-]+\\)[}]?" (1 nil) (2 'web-mode-variable-name-face))
   2170    ))
   2171 
   2172 (defvar web-mode-mako-tag-font-lock-keywords
   2173   (list
   2174    '("</?%\\([[:alpha:]:]+\\)" 1 'web-mode-block-control-face)
   2175    '("\\_<\\([[:alpha:]]+=\\)\\(\"[^\"]*\"\\)"
   2176      (1 'web-mode-block-attr-name-face t t)
   2177      (2 'web-mode-block-attr-value-face t t))
   2178    ))
   2179 
   2180 (defvar web-mode-mako-block-font-lock-keywords
   2181   (list
   2182    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2183    (cons (concat "\\_<\\(" web-mode-python-constants "\\)\\_>") '(1 'web-mode-constant-face))
   2184    (cons (concat "\\_<\\(" web-mode-python-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2185    (cons (concat "\\_<\\(endfor\\|endif\\|endwhile\\)\\_>") '(1 'web-mode-keyword-face))
   2186    ))
   2187 
   2188 (defvar web-mode-web2py-font-lock-keywords
   2189   (list
   2190    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2191    (cons (concat "\\_<\\(" web-mode-python-constants "\\)\\_>") '(1 'web-mode-constant-face))
   2192    (cons (concat "\\_<\\(" web-mode-python-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2193    (cons (concat "\\_<\\(block\\|extend\\|super\\|end\\|include\\)\\_>") '(1 'web-mode-keyword-face))
   2194    ))
   2195 
   2196 (defvar web-mode-django-expr-font-lock-keywords
   2197   (list
   2198    '("|[ ]?\\([[:alpha:]_]+\\)\\_>" 1 'web-mode-filter-face)
   2199    (cons (concat "\\_<\\(" web-mode-django-types "\\)\\_>") '(1 'web-mode-type-face))
   2200    '("\\_<\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2201    '("[[:alnum:]_]+" 0 'web-mode-variable-name-face)
   2202    ))
   2203 
   2204 (defvar web-mode-django-code-font-lock-keywords
   2205   (list
   2206    '("{%[ ]*\\(set\\)[ ]+\\([[:alpha:]]+\\)[ ]*%}"
   2207      (1 'web-mode-block-control-face)
   2208      (2 'web-mode-variable-name-face))
   2209    (cons (concat "\\({%\\|#\\)[ ]*\\(" web-mode-django-control-blocks-regexp "\\)[ %]") '(2 'web-mode-block-control-face))
   2210    '("\\({%\\|#\\)[ ]*\\(end[[:alpha:]]+\\)\\_>" 2 'web-mode-block-control-face) ;#504
   2211    (cons (concat "\\_<\\(" web-mode-django-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2212    (cons (concat "\\_<\\(" web-mode-django-types "\\)\\_>") '(1 'web-mode-type-face))
   2213    '("|[ ]?\\([[:alpha:]_]+\\)\\_>" 1 'web-mode-function-call-face)
   2214    '("\\_<\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2215    '("[[:alnum:]_.]+" 0 'web-mode-variable-name-face)
   2216    '("[[:alnum:]_]+\\([.][[:alnum:]_]+\\)+" 0 'web-mode-variable-name-face t t)
   2217    ))
   2218 
   2219 (defvar web-mode-ctemplate-font-lock-keywords
   2220   (list
   2221    '("{[~]?{[#/>^]?[ ]*\\([[:alnum:]_.-]+\\)" 1 'web-mode-block-control-face)
   2222    '("[ \t]+\\([[:alnum:]_-]+\\)="
   2223      (1 'web-mode-block-attr-name-face))
   2224    '("\"[^\"]+\"" 0 'web-mode-block-string-face)
   2225    ))
   2226 
   2227 (defvar web-mode-astro-font-lock-keywords
   2228   (append
   2229    (list
   2230     '("\\({\\)\\([[:alpha:]]+\\)\\(}\\)"
   2231       (1 'web-mode-block-control-face)
   2232       (2 'web-mode-variable-name-face)
   2233       (3 'web-mode-block-control-face)))
   2234     web-mode-javascript-font-lock-keywords
   2235     ))
   2236 
   2237 (defvar web-mode-antlers-font-lock-keywords
   2238   (list
   2239    '("{{[ ]*\\(/?\\(if\\|elseif\\|else\\|unless\\|switch\\)\\)" 1 'web-mode-block-control-face)
   2240    '("[ \t]+\\(:?[[:alnum:]_-]+\\)=" (1 'web-mode-block-attr-name-face))
   2241    '("[[:alnum:]_.]+" 0 'web-mode-variable-name-face)
   2242    '("\"[^\"]+\"" 0 'web-mode-block-string-face)
   2243    '("'[^']+'" 0 'web-mode-block-string-face)
   2244    ))
   2245 
   2246 (defvar web-mode-razor-font-lock-keywords
   2247   (list
   2248    '("@\\([[:alnum:]_.]+\\)[ ]*[({]" 1 'web-mode-block-control-face)
   2249    (cons (concat "\\_<\\(" web-mode-razor-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2250    '("\\_<\\(String\\)\\_>" 1 'web-mode-type-face)
   2251    '("\\([[:alnum:]]+:\\)" 1 'web-mode-symbol-face)
   2252    '("\\(@[[:alnum:]_.]+\\)" 1 'web-mode-variable-name-face)
   2253    ))
   2254 
   2255 (defvar web-mode-riot-font-lock-keywords
   2256   (list
   2257    '("\\(parent\\|opts\\|tags\\|this\\)\\.\\([[:alnum:]_.]+\\)"
   2258      (1 'web-mode-constant-face)
   2259      (2 'web-mode-variable-name-face))
   2260    '("\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face)
   2261    ))
   2262 
   2263 (defvar web-mode-closure-font-lock-keywords
   2264   (list
   2265    '("{\\([@/]?[[:alpha:]]+[?]?\\)" 1 'web-mode-block-control-face)
   2266    '("{[@]?param[?]?[ ]+\\([[:alnum:]]+[:]?\\)" 1 'web-mode-symbol-face)
   2267    '("\\_<\\(true\\|false\\|null\\)\\_>" 1 'web-mode-type-face)
   2268    '("\\\_<[[:alpha:]]+:[ ]+\\([[:alpha:]]+\\)" 1 'web-mode-type-face)
   2269    (cons (concat "\\_<\\(" web-mode-closure-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2270    '("{\\(alias\\|call\\|delcall\\|delpackage\\|deltemplate\\|namespace\\|template\\)[ ]+\\([[:alnum:].]+\\)" 2 'web-mode-constant-face)
   2271    '("\\(allowemptydefault\\|data\\|desc\\|meaning\\|autoescape\\|private\\|variant\\)=" 0 'web-mode-block-attr-name-face)
   2272    '("|\\([[:alpha:]]+\\)" 1 'web-mode-function-call-face)
   2273    '("\\_<\\([[:alnum:]]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2274    '("$\\([[:alnum:]._]+\\)" 1 'web-mode-variable-name-face)
   2275    ))
   2276 
   2277 (defvar web-mode-go-font-lock-keywords
   2278   (list
   2279    '("{{[-]?[ ]*\\([[:alpha:]]+\\)" 1 'web-mode-block-control-face)
   2280    '("\\_<func \\([[:alnum:]]+\\)" 1 'web-mode-function-name-face)
   2281    '("\\_<type \\([[:alnum:]]+\\)" 1 'web-mode-type-face)
   2282    (cons (concat "\\_<\\(" web-mode-go-types "\\)\\_>") '(0 'web-mode-type-face))
   2283    (cons (concat "\\_<\\(" web-mode-go-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2284    (cons (concat "\\_<\\(" web-mode-go-functions "\\)\\_>") '(1 'web-mode-function-call-face))
   2285    '("[$.]\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face t t)
   2286    '("|[ ]?\\([[:alpha:]_]+\\)\\_>" 1 'web-mode-filter-face)
   2287    ))
   2288 
   2289 (defvar web-mode-expression-font-lock-keywords
   2290   (list
   2291    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2292    ))
   2293 
   2294 (defvar web-mode-angular-font-lock-keywords
   2295   (list
   2296    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2297    ))
   2298 
   2299 (defvar web-mode-underscore-font-lock-keywords
   2300   (list
   2301    (cons (concat "\\_<\\(" web-mode-javascript-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2302    '("\\_<\\(_\.[[:alpha:]]+\\)(" 1 'web-mode-function-call-face)
   2303    '("\\_<new \\([[:alnum:]_.]+\\)\\_>" 1 'web-mode-type-face)
   2304    '("\\_<\\([[:alnum:]_]+\\):[ ]*function[ ]*(" 1 'web-mode-function-name-face)
   2305    '("\\_<\\(var\\)\\_>[ ]+\\([[:alnum:]_]+\\)"
   2306      (1 'web-mode-keyword-face)
   2307      (2 'web-mode-variable-name-face))
   2308    ))
   2309 
   2310 (defvar web-mode-vue-font-lock-keywords
   2311   (list
   2312    '("\\_<\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2313    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2314    ))
   2315 
   2316 (defvar web-mode-engine-tag-font-lock-keywords
   2317   (list
   2318    '("</?\\([[:alpha:]]+\\(?:Template\\|[:.][[:alpha:]-]+\\)\\|TMPL_[[:alpha:]]+\\)" 1 'web-mode-block-control-face)
   2319    '("\\_<\\([[:alpha:]-]+=\\)\\(\"[^\"]*\"\\)"
   2320      (1 'web-mode-block-attr-name-face t t)
   2321      (2 'web-mode-block-attr-value-face t t))
   2322    '("\\_<\\([[:alpha:]-]+=\\)\\('[^']*\'\\)"
   2323      (1 'web-mode-block-attr-name-face t t)
   2324      (2 'web-mode-block-attr-value-face t t))
   2325    ))
   2326 
   2327 (defvar web-mode-jsp-font-lock-keywords
   2328   (list
   2329    '("\\(throws\\|new\\|extends\\)[ ]+\\([[:alnum:].]+\\)" 2 'web-mode-type-face)
   2330    (cons (concat "\\_<\\(" web-mode-jsp-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2331    '("\\(public\\|private\\)[ ]+\\([[:alpha:]]+\\)[ ]+\\([[:alnum:]._]+\\)[ ]?("
   2332      (2 'web-mode-type-face)
   2333      (3 'web-mode-function-name-face))
   2334    '("\\_<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2335    '("@\\(\\sw*\\)" 1 'web-mode-variable-name-face)
   2336    '("\\_<\\([[:alnum:].]+\\)[ ]+[{[:alpha:]]+" 1 'web-mode-type-face)
   2337    ))
   2338 
   2339 (defvar web-mode-asp-font-lock-keywords
   2340   (list
   2341    (cons (concat "\\_<\\(" web-mode-asp-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2342    (cons (concat "\\_<\\(" web-mode-asp-types "\\)\\_>") '(0 'web-mode-type-face))
   2343    (cons (concat "\\_<\\(" web-mode-asp-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2344    '("\\(Class\\|new\\) \\([[:alnum:]_]+\\)" 2 'web-mode-type-face)
   2345    '("Const \\([[:alnum:]_]+\\)" 1 'web-mode-constant-face)
   2346    '("\\_<dim\\_>"
   2347      (0 'web-mode-keyword-face)
   2348      ("[[:alnum:]_]+" nil nil (0 'web-mode-variable-name-face)))
   2349    '("\\_<\\(public\\|private\\|sub\\|function\\)\\_> \\([[:alnum:]_]+\\)[ ]*(" 2 'web-mode-function-name-face)
   2350    '("\\_<\\(public\\|private\\|dim\\)\\_> \\([[:alnum:]_]+\\)" 2 'web-mode-variable-name-face)
   2351    ))
   2352 
   2353 (defvar web-mode-aspx-font-lock-keywords
   2354   (list
   2355    (cons (concat "\\_<\\(" web-mode-aspx-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2356    '("\\_<\\([[:alnum:].]+\\)[ ]+[[:alpha:]]+" 1 'web-mode-type-face)
   2357    ))
   2358 
   2359 (defvar web-mode-uel-font-lock-keywords
   2360   (list
   2361    '("[$#{]{\\|}" 0 'web-mode-preprocessor-face)
   2362    '("\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2363    '("|[ ]*\\(trim\\|x\\|u\\)" 1 'web-mode-function-call-face)
   2364    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2365    ))
   2366 
   2367 (defvar web-mode-php-var-interpolation-font-lock-keywords
   2368   (list
   2369    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2370    '("\".+\"\\|'.*'" 0 'web-mode-string-face)
   2371    ))
   2372 
   2373 (defvar web-mode-marko-font-lock-keywords
   2374   (list
   2375    '("[[:alnum:]_]+" 0 'web-mode-variable-name-face)
   2376    ))
   2377 
   2378 (defvar web-mode-freemarker-square-font-lock-keywords
   2379   (list
   2380    '("\\[/?[#@]\\([[:alpha:]_.]*\\)" 1 'web-mode-block-control-face)
   2381    '("#\\(macro\\|function\\) \\([[:alpha:]]+\\)" 2 'web-mode-function-name-face)
   2382    (cons (concat "\\_<\\(" web-mode-freemarker-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2383    '("\\_<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2384    '("[[:alpha:]]\\([[:alnum:]_]+\\)?" 0 'web-mode-variable-name-face)
   2385    ))
   2386 
   2387 (defvar web-mode-freemarker-font-lock-keywords
   2388   (list
   2389    '("</?[#@]\\([[:alpha:]_.]*\\)" 1 'web-mode-block-control-face)
   2390    '("#\\(macro\\|function\\) \\([[:alpha:]]+\\)" 2 'web-mode-function-name-face)
   2391    (cons (concat "\\_<\\(" web-mode-freemarker-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2392    '("\\_<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2393    '("[[:alpha:]]\\([[:alnum:]_]+\\)?" 0 'web-mode-variable-name-face)
   2394    ))
   2395 
   2396 (defvar web-mode-directive-font-lock-keywords
   2397   (list
   2398    '("<%@[ ]*\\([[:alpha:]]+\\)[ ]+" 1 'web-mode-block-control-face)
   2399    '("\\_<\\([[:alpha:]]+=\\)\\(\"[^\"]*\"\\)"
   2400      (1 'web-mode-block-attr-name-face t t)
   2401      (2 'web-mode-block-attr-value-face t t))
   2402    ))
   2403 
   2404 (defvar web-mode-erb-font-lock-keywords
   2405   (list
   2406    '("[^:]\\(:[[:alnum:]_]+\\)" 1 'web-mode-symbol-face)
   2407    '("\\([[:alnum:]_]+:\\)[ ]+" 1 'web-mode-symbol-face)
   2408    (cons (concat "\\_<\\(" web-mode-erb-builtins "\\)\\_>") '(0 'web-mode-builtin-face))
   2409    (cons (concat "\\_<\\(" web-mode-erb-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2410    '("\\_<\\(self\\|true\\|false\\|nil\\)\\_>" 0 'web-mode-variable-name-face)
   2411    '("[@$]@?\\([[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2412    '("class[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-type-face)
   2413    '("def[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2414    '("\\(?:\\_<\\|::\\)\\([A-Z]+[[:alnum:]_]+\\)" 1 (unless (eq (char-after) ?\() 'web-mode-type-face))
   2415    '("/[^/]+/" 0 'web-mode-string-face)
   2416    ))
   2417 
   2418 (defvar web-mode-ejs-font-lock-keywords
   2419   web-mode-javascript-font-lock-keywords)
   2420 
   2421 (defvar web-mode-python-font-lock-keywords
   2422   (list
   2423    (cons (concat "\\_<\\(" web-mode-python-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2424    ))
   2425 
   2426 (defvar web-mode-elixir-font-lock-keywords
   2427   (list
   2428    '("@\\([[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2429    '("[ ]\\(:[[:alnum:]-_]+\\)" 1 'web-mode-symbol-face)
   2430    '("def[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2431    (cons (concat "\\_<\\(" web-mode-elixir-keywords "\\)\\_>") '(0 'web-mode-builtin-face))
   2432    (cons (concat "\\_<\\(" web-mode-elixir-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2433    ))
   2434 
   2435 (defvar web-mode-erlang-font-lock-keywords
   2436   (list
   2437    (cons (concat "\\_<\\(" web-mode-erlang-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2438    (cons (concat "\\_<\\(" web-mode-erlang-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2439    '("@\\([[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2440    '("[ ]\\(:[[:alnum:]-_]+\\)" 1 'web-mode-symbol-face)
   2441    ))
   2442 
   2443 (defvar web-mode-mason-code-font-lock-keywords
   2444   (list
   2445    (cons (concat "\\_<\\(" web-mode-mason-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2446    '("sub[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2447    '("\\_<\\([[:alnum:]_]+\\)[ ]?::" 1 'web-mode-type-face)
   2448    '("\\([@]\\)\\([[:alnum:]#_]*\\)" (1 nil) (2 'web-mode-variable-name-face))
   2449    '("\\_<\\([$%]\\)\\([[:alnum:]@#_]*\\)" (1 nil) (2 'web-mode-variable-name-face))
   2450    '("{\\([[:alnum:]_]+\\)}" 1 'web-mode-variable-name-face)
   2451    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2452    '("[[:alnum:]_][ ]?::[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2453    '("->[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2454    '("\\(?:method\\|def\\) \\([[:alnum:]._]+\\)" 1 'web-mode-function-name-face)
   2455    '("|[ ]*\\([[:alnum:],]+\\)[ ]*%>" 1 'web-mode-filter-face)
   2456    ))
   2457 
   2458 (defvar web-mode-mason-block-font-lock-keywords
   2459   (list
   2460    '("<[/]?%\\([[:alpha:]]+\\)" 1 'web-mode-block-control-face)
   2461    '("[[:alpha:]]" 0 'web-mode-block-attr-value-face)
   2462    ))
   2463 
   2464 (defvar web-mode-mojolicious-font-lock-keywords
   2465   (list
   2466    (cons (concat "\\_<\\(" web-mode-perl-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2467    '("\\_<\\(begin\\|end\\)\\_>" 1 'web-mode-constant-face)
   2468    '("\\_<\\([$]\\)\\([[:alnum:]_]*\\)" (1 nil) (2 'web-mode-variable-name-face))
   2469    ))
   2470 
   2471 (defvar web-mode-lsp-font-lock-keywords
   2472   (list
   2473    (cons (concat "\\_<\\(" web-mode-lsp-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2474    (cons (concat "\\_<\\(" web-mode-lsp-constants "\\)\\_>") '(1 'web-mode-constant-face))
   2475    '("[ ]\\(:[[:alnum:]-_]+\\)" 1 'web-mode-symbol-face)
   2476    '("(defun \\([[:alnum:]-:]+\\)" 1 'web-mode-function-name-face)
   2477    '("(defvar \\([[:alnum:]-:]+\\)" 1 'web-mode-variable-name-face)
   2478    ))
   2479 
   2480 (defvar web-mode-cl-emb-font-lock-keywords
   2481   (list
   2482    (cons (concat "\\_<\\(" web-mode-cl-emb-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2483    (cons (concat "\\_<\\(" web-mode-cl-emb-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2484    '("\\(@\\)" 1 'web-mode-function-call-face)
   2485    (list (concat "\\(@" web-mode-cl-emb-keywords "\\)[ ]+\\([[:alnum:]_]+\\)")
   2486          '(1 'web-mode-keyword-face)
   2487          '(2 'web-mode-variable-name-face))
   2488    ))
   2489 
   2490 (defvar web-mode-artanis-font-lock-keywords
   2491   (list
   2492    (cons (concat "\\_<\\(" web-mode-artanis-keywords  "\\)\\_>") '(0 'web-mode-keyword-face))
   2493    (cons (concat "\\_<\\(" web-mode-artanis-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2494    '("(define[*]? (\\([[:alnum:]-:_!#$%^&*=+/?<>.]+\\)" 1 'web-mode-function-name-face)
   2495    '("\\(#:[[:alnum:]-:_!#$%^&*=+/?<>.]+\\)"            1 'web-mode-builtin-face)
   2496    ))
   2497 
   2498 (defvar web-mode-php-font-lock-keywords
   2499   (list
   2500    (cons (concat "\\_<\\(" web-mode-php-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2501    (cons (concat "\\_<\\(" web-mode-php-types "\\)\\_>") '(1 'web-mode-type-face))
   2502    (cons (concat "\\(" web-mode-php-constants "\\)") '(0 'web-mode-constant-face))
   2503    '("function[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2504    '("\\_<\\([[:alnum:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2505    '("[[:alnum:]_][ ]?::[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-constant-face)
   2506    '("->[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2507    '("\\_<\\([[:alnum:]_]+\\)[ ]?::" 1 'web-mode-type-face)
   2508    '("\\_<\\(instanceof\\|class\\|extends\\|new\\)[ ]+\\([[:alnum:]_]+\\)" 2 'web-mode-type-face)
   2509    '("\\(\\_<\\|[+-]\\)\\([$]\\)\\([[:alnum:]_]*\\)" (2 nil) (3 'web-mode-variable-name-face))
   2510    ))
   2511 
   2512 (defvar web-mode-spip-font-lock-keywords
   2513   (list
   2514    '("<:.+:>" 0 'web-mode-block-string-face)
   2515    '("#[A-Z0-9_]+" 0 'web-mode-variable-name-face)
   2516    '("|[a-z0-9_=!?<>]+" 0 'web-mode-function-call-face)
   2517    '("(\\([[:alnum:]_ ]+\\))" 1 'web-mode-constant-face)
   2518    ))
   2519 
   2520 (defvar web-mode-latex-font-lock-keywords
   2521   (list
   2522    '("[[:alnum:]_]+" 0 'web-mode-function-name-face t t)
   2523    ))
   2524 
   2525 (defvar web-mode-blade-font-lock-keywords
   2526   (append
   2527    (list
   2528     '("@\\([[:alpha:]_]+\\)" (1 'web-mode-block-control-face)))
   2529    web-mode-php-font-lock-keywords))
   2530 
   2531 (defvar web-mode-engines-font-lock-keywords
   2532   '(("angular"          . web-mode-angular-font-lock-keywords)
   2533     ("anki"             . web-mode-anki-font-lock-keywords)
   2534     ("antlers"          . web-mode-antlers-font-lock-keywords)
   2535     ("artanis"          . web-mode-artanis-font-lock-keywords)
   2536     ("astro"            . web-mode-astro-font-lock-keywords)
   2537     ("blade"            . web-mode-blade-font-lock-keywords)
   2538     ("cl-emb"           . web-mode-cl-emb-font-lock-keywords)
   2539     ("closure"          . web-mode-closure-font-lock-keywords)
   2540     ("ctemplate"        . web-mode-ctemplate-font-lock-keywords)
   2541     ("dust"             . web-mode-dust-font-lock-keywords)
   2542     ("elixir"           . web-mode-elixir-font-lock-keywords)
   2543     ("ejs"              . web-mode-ejs-font-lock-keywords)
   2544     ("erb"              . web-mode-erb-font-lock-keywords)
   2545     ("expressionengine" . web-mode-expressionengine-font-lock-keywords)
   2546     ("go"               . web-mode-go-font-lock-keywords)
   2547     ("hero"             . web-mode-go-font-lock-keywords)
   2548     ("lsp"              . web-mode-lsp-font-lock-keywords)
   2549     ("marko"            . web-mode-marko-font-lock-keywords)
   2550     ("mojolicious"      . web-mode-mojolicious-font-lock-keywords)
   2551     ("php"              . web-mode-php-font-lock-keywords)
   2552     ("python"           . web-mode-python-font-lock-keywords)
   2553     ("razor"            . web-mode-razor-font-lock-keywords)
   2554     ("riot"             . web-mode-riot-font-lock-keywords)
   2555     ("smarty"           . web-mode-smarty-font-lock-keywords)
   2556     ("spip"             . web-mode-spip-font-lock-keywords)
   2557     ("template-toolkit" . web-mode-template-toolkit-font-lock-keywords)
   2558     ("underscore"       . web-mode-underscore-font-lock-keywords)
   2559     ("web2py"           . web-mode-web2py-font-lock-keywords)
   2560     ("velocity"         . web-mode-velocity-font-lock-keywords)
   2561     ("vue"              . web-mode-vue-font-lock-keywords)
   2562     ("xoops"            . web-mode-smarty-font-lock-keywords)
   2563     ("svelte"           . web-mode-svelte-font-lock-keywords)
   2564     )
   2565   "Engines font-lock keywords")
   2566 
   2567 (defvar web-mode-prettify-symbols-alist
   2568   '(("=>" . 8658)
   2569     (">=" . 8805)
   2570     ("<=" . 8804)))
   2571 
   2572 (defvar web-mode-before-auto-complete-hooks nil
   2573   "List of functions to run before triggering the auto-complete library.
   2574 
   2575 Auto-complete sources will sometimes need some tweaking to work
   2576 nicely with web-mode. This hook gives users the chance to adjust
   2577 the environment as needed for ac-sources, right before they're used.")
   2578 
   2579 (defvar web-mode-ignore-ac-start-advice nil
   2580   "If not nil `defadvice' for `ac-start' will be ignored.
   2581 
   2582 Can be set inside a hook in `web-mode-before-auto-complete-hooks' to
   2583 non nil to ignore the defadvice which sets ac-sources according to current
   2584 language. This is needed if the corresponding auto-completion triggers
   2585 another auto-completion with different ac-sources (e.g. ac-php)")
   2586 
   2587 (defvar web-mode-ac-sources-alist nil
   2588   "alist mapping language names to ac-sources for that language.")
   2589 
   2590 (defvar web-mode-trace nil
   2591   "Activate debug tracing.")
   2592 
   2593 (defvar web-mode-syntax-table
   2594   (let ((table (make-syntax-table)))
   2595     (modify-syntax-entry ?- "_" table)
   2596     (modify-syntax-entry ?_ "_" table) ;#563
   2597     (modify-syntax-entry ?< "." table)
   2598     (modify-syntax-entry ?> "." table)
   2599     (modify-syntax-entry ?& "." table)
   2600     (modify-syntax-entry ?/ "." table)
   2601     (modify-syntax-entry ?= "." table)
   2602     (modify-syntax-entry ?% "." table)
   2603     table)
   2604   "Syntax table used to reveal whitespaces.")
   2605 
   2606 (defvar web-mode-map
   2607   (let ((map (make-sparse-keymap)))
   2608 
   2609     (define-key map [menu-bar wm]             (cons "Web-Mode" (make-sparse-keymap)))
   2610     (define-key map [menu-bar wm dom]         (cons "Dom" (make-sparse-keymap)))
   2611     (define-key map [menu-bar wm blk]         (cons "Block" (make-sparse-keymap)))
   2612     (define-key map [menu-bar wm attr]        (cons "Html Attr" (make-sparse-keymap)))
   2613     (define-key map [menu-bar wm tag]         (cons "Html Tag" (make-sparse-keymap)))
   2614     (define-key map [menu-bar wm elt]         (cons "Html Element" (make-sparse-keymap)))
   2615 
   2616     (define-key map [menu-bar wm sep-1]       '(menu-item "--"))
   2617 
   2618     (define-key map [menu-bar wm dom dom-xpa] '(menu-item "XPath" web-mode-dom-xpath))
   2619     (define-key map [menu-bar wm dom dom-tra] '(menu-item "Traverse" web-mode-dom-traverse))
   2620     (define-key map [menu-bar wm dom dom-err] '(menu-item "Show error(s)" web-mode-dom-errors-show))
   2621     (define-key map [menu-bar wm dom dom-ent] '(menu-item "Replace html entities" web-mode-dom-entities-replace))
   2622     (define-key map [menu-bar wm dom dom-quo] '(menu-item "Replace dumb quotes" web-mode-dom-quotes-replace))
   2623     (define-key map [menu-bar wm dom dom-apo] '(menu-item "Replace apostrophes" web-mode-dom-apostrophes-replace))
   2624     (define-key map [menu-bar wm dom dom-nor] '(menu-item "Normalize" web-mode-dom-normalize))
   2625 
   2626     (define-key map [menu-bar wm blk blk-sel] '(menu-item "Select" web-mode-block-select))
   2627     (define-key map [menu-bar wm blk blk-pre] '(menu-item "Previous" web-mode-block-previous))
   2628     (define-key map [menu-bar wm blk blk-nex] '(menu-item "Next" web-mode-block-next))
   2629     (define-key map [menu-bar wm blk blk-kil] '(menu-item "Kill" web-mode-block-kill))
   2630     (define-key map [menu-bar wm blk blk-end] '(menu-item "End" web-mode-block-end))
   2631     (define-key map [menu-bar wm blk blk-clo] '(menu-item "Close" web-mode-block-close))
   2632     (define-key map [menu-bar wm blk blk-beg] '(menu-item "Beginning" web-mode-block-beginning))
   2633 
   2634     (define-key map [menu-bar wm attr attr-ins] '(menu-item "Insert" web-mode-attribute-insert))
   2635     (define-key map [menu-bar wm attr attr-end] '(menu-item "End" web-mode-attribute-end))
   2636     (define-key map [menu-bar wm attr attr-beg] '(menu-item "Beginning" web-mode-attribute-beginning))
   2637     (define-key map [menu-bar wm attr attr-sel] '(menu-item "Select" web-mode-attribute-select))
   2638     (define-key map [menu-bar wm attr attr-kil] '(menu-item "Kill" web-mode-attribute-kill))
   2639     (define-key map [menu-bar wm attr attr-nex] '(menu-item "Next" web-mode-attribute-next))
   2640     (define-key map [menu-bar wm attr attr-pre] '(menu-item "Previous" web-mode-attribute-previous))
   2641     (define-key map [menu-bar wm attr attr-tra] '(menu-item "Transpose" web-mode-attribute-transpose))
   2642 
   2643     (define-key map [menu-bar wm tag tag-beg] '(menu-item "Sort Attributes" web-mode-tag-attributes-sort))
   2644     (define-key map [menu-bar wm tag tag-sel] '(menu-item "Select" web-mode-tag-select))
   2645     (define-key map [menu-bar wm tag tag-pre] '(menu-item "Previous" web-mode-tag-previous))
   2646     (define-key map [menu-bar wm tag tag-nex] '(menu-item "Next" web-mode-tag-next))
   2647     (define-key map [menu-bar wm tag tag-end] '(menu-item "End" web-mode-tag-end))
   2648     (define-key map [menu-bar wm tag tag-beg] '(menu-item "Beginning" web-mode-tag-beginning))
   2649 
   2650     (define-key map [menu-bar wm elt elt-con] '(menu-item "Contract" web-mode-element-contract))
   2651     (define-key map [menu-bar wm elt elt-ext] '(menu-item "Extract" web-mode-element-extract))
   2652     (define-key map [menu-bar wm elt elt-van] '(menu-item "Vanish" web-mode-element-vanish))
   2653     (define-key map [menu-bar wm elt elt-exc] '(menu-item "Transpose" web-mode-element-transpose))
   2654     (define-key map [menu-bar wm elt elt-sel] '(menu-item "Select" web-mode-element-select))
   2655     (define-key map [menu-bar wm elt elt-ren] '(menu-item "Rename" web-mode-element-rename))
   2656     (define-key map [menu-bar wm elt elt-pre] '(menu-item "Previous" web-mode-element-previous))
   2657     (define-key map [menu-bar wm elt elt-par] '(menu-item "Parent" web-mode-element-parent))
   2658     (define-key map [menu-bar wm elt elt-nex] '(menu-item "Next" web-mode-element-next))
   2659     (define-key map [menu-bar wm elt elt-mut] '(menu-item "Mute blanks" web-mode-element-mute-blanks))
   2660     (define-key map [menu-bar wm elt elt-del] '(menu-item "Kill" web-mode-element-kill))
   2661     (define-key map [menu-bar wm elt elt-end] '(menu-item "End" web-mode-element-end))
   2662     (define-key map [menu-bar wm elt elt-inn] '(menu-item "Content (select)" web-mode-element-content-select))
   2663     (define-key map [menu-bar wm elt elt-clo] '(menu-item "Close" web-mode-element-close))
   2664     (define-key map [menu-bar wm elt elt-ins] '(menu-item "Insert" web-mode-element-insert))
   2665     (define-key map [menu-bar wm elt elt-ins] '(menu-item "Word to tag" web-mode-element-insert-at-point))
   2666     (define-key map [menu-bar wm elt elt-dup] '(menu-item "Clone" web-mode-element-clone))
   2667     (define-key map [menu-bar wm elt elt-cfo] '(menu-item "Children fold" web-mode-element-children-fold-or-unfold))
   2668     (define-key map [menu-bar wm elt elt-chi] '(menu-item "Child" web-mode-element-child))
   2669     (define-key map [menu-bar wm elt elt-beg] '(menu-item "Beginning" web-mode-element-beginning))
   2670 
   2671     (define-key map [menu-bar wm fol]         '(menu-item "Fold/Unfold" web-mode-fold-or-unfold))
   2672     (define-key map [menu-bar wm hig]         '(menu-item "Fontify buffer" web-mode-buffer-fontify))
   2673     (define-key map [menu-bar wm ind]         '(menu-item "Indent buffer" web-mode-buffer-indent))
   2674     (define-key map [menu-bar wm nav]         '(menu-item "Tag/Block navigation" web-mode-navigate))
   2675     (define-key map [menu-bar wm exp]         '(menu-item "Mark and Expand" web-mode-mark-and-expand))
   2676     (define-key map [menu-bar wm spa]         '(menu-item "Toggle whitespaces" web-mode-whitespaces-show))
   2677     (define-key map [menu-bar wm sni]         '(menu-item "Insert snippet" web-mode-snippet-insert))
   2678 
   2679     ;;--------------------------------------------------------------------------
   2680     ;; "C-c <LETTER>" are reserved for users
   2681 
   2682     (define-key map (kbd "C-c C-a b") 'web-mode-attribute-beginning)
   2683     (define-key map (kbd "C-c C-a e") 'web-mode-attribute-end)
   2684     (define-key map (kbd "C-c C-a i") 'web-mode-attribute-insert)
   2685     (define-key map (kbd "C-c C-a n") 'web-mode-attribute-next)
   2686     (define-key map (kbd "C-c C-a s") 'web-mode-attribute-select)
   2687     (define-key map (kbd "C-c C-a k") 'web-mode-attribute-kill)
   2688     (define-key map (kbd "C-c C-a p") 'web-mode-attribute-previous)
   2689     (define-key map (kbd "C-c C-a t") 'web-mode-attribute-transpose)
   2690 
   2691     (define-key map (kbd "C-c C-b b") 'web-mode-block-beginning)
   2692     (define-key map (kbd "C-c C-b c") 'web-mode-block-close)
   2693     (define-key map (kbd "C-c C-b e") 'web-mode-block-end)
   2694     (define-key map (kbd "C-c C-b k") 'web-mode-block-kill)
   2695     (define-key map (kbd "C-c C-b n") 'web-mode-block-next)
   2696     (define-key map (kbd "C-c C-b p") 'web-mode-block-previous)
   2697     (define-key map (kbd "C-c C-b s") 'web-mode-block-select)
   2698 
   2699     (define-key map (kbd "C-c C-d a") 'web-mode-dom-apostrophes-replace)
   2700     (define-key map (kbd "C-c C-d d") 'web-mode-dom-errors-show)
   2701     (define-key map (kbd "C-c C-d e") 'web-mode-dom-entities-replace)
   2702     (define-key map (kbd "C-c C-d n") 'web-mode-dom-normalize)
   2703     (define-key map (kbd "C-c C-d q") 'web-mode-dom-quotes-replace)
   2704     (define-key map (kbd "C-c C-d t") 'web-mode-dom-traverse)
   2705     (define-key map (kbd "C-c C-d x") 'web-mode-dom-xpath)
   2706 
   2707     (define-key map (kbd "C-c C-e /") 'web-mode-element-close)
   2708     (define-key map (kbd "C-c C-e a") 'web-mode-element-content-select)
   2709     (define-key map (kbd "C-c C-e b") 'web-mode-element-beginning)
   2710     (define-key map (kbd "C-c C-e c") 'web-mode-element-clone)
   2711     (define-key map (kbd "C-c C-e d") 'web-mode-element-child)
   2712     (define-key map (kbd "C-c C-e e") 'web-mode-element-end)
   2713     (define-key map (kbd "C-c C-e f") 'web-mode-element-children-fold-or-unfold)
   2714     (define-key map (kbd "C-c C-e i") 'web-mode-element-insert)
   2715     (define-key map (kbd "C-c C-e I") 'web-mode-element-insert-at-point)
   2716     (define-key map (kbd "C-c C-e k") 'web-mode-element-kill)
   2717     (define-key map (kbd "C-c C-e m") 'web-mode-element-mute-blanks)
   2718     (define-key map (kbd "C-c C-e n") 'web-mode-element-next)
   2719     (define-key map (kbd "C-c C-e p") 'web-mode-element-previous)
   2720     (define-key map (kbd "C-c C-e r") 'web-mode-element-rename)
   2721     (define-key map (kbd "C-c C-e s") 'web-mode-element-select)
   2722     (define-key map (kbd "C-c C-e t") 'web-mode-element-transpose)
   2723     (define-key map (kbd "C-c C-e u") 'web-mode-element-parent)
   2724     (define-key map (kbd "C-c C-e v") 'web-mode-element-vanish)
   2725     (define-key map (kbd "C-c C-e w") 'web-mode-element-wrap)
   2726     (define-key map (kbd "C-c C-e +") 'web-mode-element-extract)
   2727     (define-key map (kbd "C-c C-e -") 'web-mode-element-contract)
   2728 
   2729     (define-key map (kbd "C-c C-t a") 'web-mode-tag-attributes-sort)
   2730     (define-key map (kbd "C-c C-t b") 'web-mode-tag-beginning)
   2731     (define-key map (kbd "C-c C-t e") 'web-mode-tag-end)
   2732     (define-key map (kbd "C-c C-t m") 'web-mode-tag-match)
   2733     (define-key map (kbd "C-c C-t n") 'web-mode-tag-next)
   2734     (define-key map (kbd "C-c C-t p") 'web-mode-tag-previous)
   2735     (define-key map (kbd "C-c C-t s") 'web-mode-tag-select)
   2736 
   2737     ;;--------------------------------------------------------------------------
   2738 
   2739     ;;(define-key map (kbd "M-q")       'fill-paragraph)
   2740     (define-key map (kbd "M-;")       'web-mode-comment-or-uncomment)
   2741 
   2742     ;;C-c C-a : attribute
   2743     ;;C-c C-b : block
   2744     ;;C-c C-d : dom
   2745     ;;C-c C-e : element
   2746     (define-key map (kbd "C-c C-f")   'web-mode-fold-or-unfold)
   2747     (define-key map (kbd "C-c C-h")   'web-mode-buffer-fontify)
   2748     (define-key map (kbd "C-c C-i")   'web-mode-buffer-indent)
   2749     (define-key map (kbd "C-c C-j")   'web-mode-jshint)
   2750     (define-key map (kbd "C-c C-l")   'web-mode-file-link)
   2751     (define-key map (kbd "C-c C-m")   'web-mode-mark-and-expand)
   2752     (define-key map (kbd "C-c C-n")   'web-mode-navigate)
   2753     (define-key map (kbd "C-c C-r")   'web-mode-reload)
   2754     (define-key map (kbd "C-c C-s")   'web-mode-snippet-insert)
   2755     ;;C-c C-t : tag
   2756     (define-key map (kbd "C-c C-w")   'web-mode-whitespaces-show)
   2757 
   2758     map)
   2759   "Keymap for `web-mode'.")
   2760 
   2761 ;;---- COMPATIBILITY -----------------------------------------------------------
   2762 
   2763 (eval-and-compile
   2764 
   2765   ;; compatibility with emacs < 23
   2766   (defun web-mode-string-match-p (regexp string &optional start)
   2767     "Same as `string-match' except it does not change the match data."
   2768     (save-match-data
   2769       (string-match regexp string start)))
   2770 
   2771   (unless (fboundp 'string-match-p)
   2772     (fset 'string-match-p (symbol-function 'web-mode-string-match-p)))
   2773 
   2774   ;; compatibility with emacs < 23.3
   2775   (if (fboundp 'with-silent-modifications)
   2776       (defalias 'web-mode-with-silent-modifications 'with-silent-modifications)
   2777       (defmacro web-mode-with-silent-modifications (&rest body)
   2778         `(let ((old-modified-p (buffer-modified-p))
   2779                (inhibit-modification-hooks t)
   2780                (buffer-undo-list t))
   2781            (unwind-protect
   2782                 ,@body
   2783              (restore-buffer-modified-p old-modified-p)))))
   2784 
   2785   ;; compatibility with emacs < 24.3
   2786   (defun web-mode-buffer-narrowed-p ()
   2787     (if (fboundp 'buffer-narrowed-p)
   2788         (buffer-narrowed-p)
   2789         (/= (- (point-max) (point-min)) (buffer-size))))
   2790 
   2791   ;; compatibility with emacs < 24
   2792   (defalias 'web-mode-prog-mode
   2793       (if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode))
   2794 
   2795   ;; compatibility with emacs < 24.3
   2796   (unless (fboundp 'setq-local)
   2797     (defmacro setq-local (var val)
   2798       `(set (make-local-variable ',var) ,val)))
   2799 
   2800   ;; compatability with emacs < 24.4
   2801   (defun web-mode-string-suffix-p (suffix string)
   2802     "Return t if STRING ends with SUFFIX."
   2803     (and (string-match (rx-to-string `(: ,suffix eos) t)
   2804                        string)
   2805          t))
   2806 
   2807   (unless (fboundp 'string-suffix-p)
   2808     (fset 'string-suffix-p (symbol-function 'web-mode-string-suffix-p)))
   2809 
   2810   (unless (fboundp 'seq-some)
   2811     (defun seq-some (pred seq)
   2812       (unless (null seq)
   2813         (or (funcall pred (car seq))
   2814             (seq-some pred (cdr seq))))))
   2815   ) ;eval-and-compile
   2816 
   2817 ;;---- MAJOR MODE --------------------------------------------------------------
   2818 
   2819 ;;;###autoload
   2820 (define-derived-mode
   2821     web-mode web-mode-prog-mode "Web"
   2822     "Major mode for editing web templates."
   2823 
   2824     (make-local-variable 'web-mode-attr-indent-offset)
   2825     (make-local-variable 'web-mode-attr-value-indent-offset)
   2826     (make-local-variable 'web-mode-auto-pairs)
   2827     (make-local-variable 'web-mode-block-regexp)
   2828     (make-local-variable 'web-mode-change-beg)
   2829     (make-local-variable 'web-mode-change-end)
   2830     (make-local-variable 'web-mode-code-indent-offset)
   2831     (make-local-variable 'web-mode-column-overlays)
   2832     (make-local-variable 'web-mode-comment-formats)
   2833     (make-local-variable 'web-mode-comment-style)
   2834     (make-local-variable 'web-mode-content-type)
   2835     (make-local-variable 'web-mode-css-indent-offset)
   2836     (make-local-variable 'web-mode-display-table)
   2837     (make-local-variable 'web-mode-django-control-blocks)
   2838     (make-local-variable 'web-mode-django-control-blocks-regexp)
   2839     (make-local-variable 'web-mode-enable-block-face)
   2840     (make-local-variable 'web-mode-enable-inlays)
   2841     (make-local-variable 'web-mode-enable-part-face)
   2842     (make-local-variable 'web-mode-enable-sexp-functions)
   2843     (make-local-variable 'web-mode-engine)
   2844     (make-local-variable 'web-mode-engine-attr-regexp)
   2845     (make-local-variable 'web-mode-engine-file-regexps)
   2846     (make-local-variable 'web-mode-engine-open-delimiter-regexps)
   2847     (make-local-variable 'web-mode-engine-token-regexp)
   2848     (make-local-variable 'web-mode-expand-initial-pos)
   2849     (make-local-variable 'web-mode-expand-initial-scroll)
   2850     (make-local-variable 'web-mode-expand-previous-state)
   2851     (make-local-variable 'web-mode-indent-style)
   2852     (make-local-variable 'web-mode-indentless-attributes)
   2853     (make-local-variable 'web-mode-indentless-elements)
   2854     (make-local-variable 'web-mode-is-scratch)
   2855     (make-local-variable 'web-mode-skip-fontification)
   2856     (make-local-variable 'web-mode-jshint-errors)
   2857     (make-local-variable 'web-mode-last-enabled-feature)
   2858     (make-local-variable 'web-mode-markup-indent-offset)
   2859     (make-local-variable 'web-mode-minor-engine)
   2860     (make-local-variable 'web-mode-overlay-tag-end)
   2861     (make-local-variable 'web-mode-overlay-tag-start)
   2862     (make-local-variable 'web-mode-part-beg)
   2863     (make-local-variable 'web-mode-scan-beg)
   2864     (make-local-variable 'web-mode-scan-end)
   2865     (make-local-variable 'web-mode-sql-indent-offset)
   2866     (make-local-variable 'web-mode-time)
   2867     (make-local-variable 'web-mode-trace)
   2868 
   2869     (make-local-variable 'font-lock-beg)
   2870     (make-local-variable 'font-lock-end)
   2871 
   2872     (make-local-variable 'comment-end)
   2873     (make-local-variable 'comment-region-function)
   2874     (make-local-variable 'comment-start)
   2875     (make-local-variable 'fill-paragraph-function)
   2876     (make-local-variable 'font-lock-defaults)
   2877     (make-local-variable 'font-lock-extend-region-functions)
   2878     (make-local-variable 'font-lock-support-mode)
   2879     (make-local-variable 'font-lock-unfontify-region-function)
   2880     (make-local-variable 'imenu-case-fold-search)
   2881     (make-local-variable 'imenu-create-index-function)
   2882     (make-local-variable 'imenu-generic-expression)
   2883     (make-local-variable 'indent-line-function)
   2884     (make-local-variable 'parse-sexp-lookup-properties)
   2885     (make-local-variable 'uncomment-region-function)
   2886     (make-local-variable 'yank-excluded-properties)
   2887 
   2888     (setq web-mode-time (current-time))
   2889 
   2890     (setq comment-end "-->"
   2891           comment-region-function 'web-mode-comment-or-uncomment-region
   2892           comment-start "<!--"
   2893           fill-paragraph-function 'web-mode-fill-paragraph
   2894           ;;font-lock-defaults '(web-mode-font-lock-keywords t)
   2895           font-lock-defaults '('(web-mode-fontify) t)
   2896           font-lock-extend-region-functions '(web-mode-extend-region)
   2897           font-lock-support-mode nil
   2898           font-lock-unfontify-region-function 'web-mode-unfontify-region
   2899           imenu-case-fold-search t
   2900           imenu-create-index-function 'web-mode-imenu-index
   2901           indent-line-function 'web-mode-indent-line
   2902           parse-sexp-lookup-properties t
   2903           yank-excluded-properties t
   2904           uncomment-region-function 'web-mode-comment-or-uncomment-region
   2905           prettify-symbols-alist web-mode-prettify-symbols-alist)
   2906 
   2907     (substitute-key-definition #'indent-new-comment-line
   2908                                #'web-mode-comment-indent-new-line
   2909                                web-mode-map global-map)
   2910 
   2911     (add-hook 'after-change-functions #'web-mode-on-after-change nil t)
   2912     (add-hook 'after-save-hook        #'web-mode-on-after-save t t)
   2913     (add-hook 'change-major-mode-hook #'web-mode-on-exit nil t)
   2914     (add-hook 'post-command-hook      #'web-mode-on-post-command nil t)
   2915     (add-hook 'hack-local-variables-hook #'web-mode-guess-engine-and-content-type t t)
   2916 
   2917     (cond
   2918       ((boundp 'yas-after-exit-snippet-hook)
   2919        (add-hook 'yas-after-exit-snippet-hook
   2920                  'web-mode-yasnippet-exit-hook
   2921                  t t))
   2922       ((boundp 'yas/after-exit-snippet-hook)
   2923        (add-hook 'yas/after-exit-snippet-hook
   2924                  'web-mode-yasnippet-exit-hook
   2925                  t t))
   2926       )
   2927 
   2928     (when web-mode-enable-whitespace-fontification
   2929       (web-mode-whitespaces-on))
   2930 
   2931     (when web-mode-enable-sexp-functions
   2932       (setq-local forward-sexp-function #'web-mode-forward-sexp))
   2933 
   2934     (setq web-mode-change-beg (point-min)
   2935           web-mode-change-end (point-max))
   2936     (when (> (point-max) 256000)
   2937       (web-mode-buffer-fontify))
   2938 
   2939     (when (and (boundp 'hs-special-modes-alist)
   2940                (not (assoc major-mode hs-special-modes-alist)))
   2941       (add-to-list 'hs-special-modes-alist '(web-mode "{" "}" "/[*/]" web-mode-forward-sexp nil))
   2942       ) ;when
   2943 
   2944     ;; compatibility with emacs < 24
   2945     (if (fboundp 'prog-mode)
   2946         (put 'web-mode 'derived-mode-parent 'prog-mode))
   2947 
   2948     (cond
   2949       ((not (buffer-file-name))
   2950        )
   2951       ((string-match-p "web-mode-benchmark.html" (buffer-file-name))
   2952        (web-mode-measure "end"))
   2953       ) ;cond
   2954 
   2955     )
   2956 
   2957 ;;---- INVALIDATION ------------------------------------------------------------
   2958 
   2959 ;; 1/ after-change
   2960 ;; 2/ extend-region
   2961 ;; 3/ scan
   2962 ;; 4/ fontify
   2963 ;; 5/ post-command
   2964 
   2965 (defun web-mode-on-after-change (beg end len)
   2966   (when web-mode-trace
   2967     (message "after-change: pos(%d) beg(%d) end(%d) len(%d) this-command(%S)"
   2968              (point) beg end len this-command))
   2969   (when (or (null web-mode-change-beg) (< beg web-mode-change-beg))
   2970     (setq web-mode-change-beg beg))
   2971   (when (or (null web-mode-change-end) (> end web-mode-change-end))
   2972     (setq web-mode-change-end end)))
   2973 
   2974 (defun web-mode-extend-region ()
   2975   (when web-mode-trace
   2976     (message "extend-region: font-lock-beg(%S) font-lock-end(%S) web-mode-change-beg(%S) web-mode-change-end(%S) web-mode-skip-fontification(%S)"
   2977              font-lock-beg font-lock-end web-mode-change-beg web-mode-change-end web-mode-skip-fontification))
   2978   (when (and (string= web-mode-engine "php")
   2979              (and (>= font-lock-beg 6) (<= font-lock-beg 9))
   2980              (or (message (buffer-substring-no-properties 1 6)) t)
   2981              (string= (buffer-substring-no-properties 1 6) "<?php"))
   2982     (setq font-lock-beg (point-min)
   2983           font-lock-end (point-max))
   2984     )
   2985   (when (or (null web-mode-change-beg) (< font-lock-beg web-mode-change-beg))
   2986     (when web-mode-trace (message "extend-region: font-lock-beg(%S) < web-mode-change-beg(%S)" font-lock-beg web-mode-change-beg))
   2987     (setq web-mode-change-beg font-lock-beg))
   2988   (when (or (null web-mode-change-end) (> font-lock-end web-mode-change-end))
   2989     (when web-mode-trace (message "extend-region: font-lock-end(%S) > web-mode-change-end(%S)" font-lock-end web-mode-change-end))
   2990     (setq web-mode-change-end font-lock-end))
   2991   (when font-lock-dont-widen
   2992     (setq web-mode-change-beg (max web-mode-change-beg (point-min))
   2993           web-mode-change-end (min web-mode-change-end (point-max))))
   2994   (let ((region (web-mode-scan web-mode-change-beg web-mode-change-end)))
   2995     (when region
   2996       ;;(message "region: %S" region)
   2997       (setq font-lock-beg (car region)
   2998             font-lock-end (cdr region))
   2999       ) ;when
   3000     ) ;let
   3001   nil)
   3002 
   3003 (defun web-mode-scan (&optional beg end)
   3004   (when web-mode-trace
   3005     (message "scan: beg(%S) end(%S) web-mode-change-beg(%S) web-mode-change-end(%S)"
   3006              beg end web-mode-change-beg web-mode-change-end))
   3007   (unless beg (setq beg web-mode-change-beg))
   3008   (unless end (setq end web-mode-change-end))
   3009   ;;(message "%S %S %S" web-mode-content-type (get-text-property beg 'part-side) (get-text-property end 'part-side))
   3010   (when (and end (> end (point-max)))
   3011     (setq end (point-max)))
   3012   (setq web-mode-change-beg nil
   3013         web-mode-change-end nil)
   3014   (cond
   3015     ((or (null beg) (null end))
   3016      nil)
   3017     ((and (member web-mode-engine '("php" "asp"))
   3018           (get-text-property beg 'block-side)
   3019           (get-text-property end 'block-side)
   3020           (> beg (point-min))
   3021           (not (eq (get-text-property (1- beg) 'block-token) 'delimiter-beg))
   3022           (not (eq (get-text-property end 'block-token) 'delimiter-end)))
   3023      ;;(message "invalidate block (%S > %S)" beg end)
   3024      (web-mode-invalidate-block-region beg end))
   3025     ((and (or (member web-mode-content-type
   3026                       '("css" "javascript" "json" "jsx" "sass" "stylus" "typescript"))
   3027               (and (get-text-property beg 'part-side)
   3028                    (get-text-property end 'part-side)
   3029                    (> beg (point-min))
   3030                    (get-text-property (1- beg) 'part-side))
   3031               ))
   3032      ;;(message "invalidate part (%S > %S)" beg end)
   3033      (web-mode-invalidate-part-region beg end))
   3034     (t
   3035      ;;(message "invalidate default (%S > %S)" beg end)
   3036      (web-mode-invalidate-region beg end))
   3037     ) ;cond
   3038   )
   3039 
   3040 (defun web-mode-invalidate-region (reg-beg reg-end)
   3041   (when web-mode-trace
   3042     (message "invalidate-region: point(%S) reg-beg(%S) reg-end(%S)" (point) reg-beg reg-end))
   3043   (setq reg-beg (web-mode-invalidate-region-beginning-position reg-beg)
   3044         reg-end (web-mode-invalidate-region-end-position reg-end))
   3045   ;;(message "invalidate-region: reg-beg(%S) reg-end(%S)" reg-beg reg-end)
   3046   (web-mode-scan-region reg-beg reg-end))
   3047 
   3048 (defun web-mode--command-is-self-insert-p ()
   3049   "Return non-nil if `this-command' is `self-insert-command'.
   3050 Also return non-nil if it is the command `self-insert-command' is remapped to."
   3051   (memq this-command (list 'self-insert-command
   3052                            (key-binding [remap self-insert-command]))))
   3053 
   3054 (defun web-mode-on-post-command ()
   3055   (when (and web-mode-trace
   3056              (not (member this-command
   3057                           '(left-char right-char previous-line next-line save-buffer mwheel-scroll end-of-line beginning-of-line))))
   3058     (message "post-command: this-command(%S) web-mode-change-beg(%S) web-mode-change-end(%S) previous-state(%S)"
   3059              this-command web-mode-change-beg web-mode-change-end web-mode-expand-previous-state))
   3060   (let (ctx n char)
   3061     (when (and web-mode-expand-previous-state
   3062                (not (member this-command web-mode-commands-like-expand-region)))
   3063       (when (eq this-command 'keyboard-quit)
   3064         (goto-char web-mode-expand-initial-pos))
   3065       (deactivate-mark)
   3066       (when web-mode-expand-initial-scroll
   3067         (set-window-start (selected-window) web-mode-expand-initial-scroll)
   3068         )
   3069       (setq web-mode-expand-previous-state nil
   3070             web-mode-expand-initial-pos nil
   3071             web-mode-expand-initial-scroll nil))
   3072 
   3073     (when (member this-command '(yank))
   3074       ;;(setq web-mode-skip-fontification nil)
   3075       (when (and web-mode-scan-beg web-mode-scan-end global-font-lock-mode)
   3076         (save-excursion
   3077           (font-lock-fontify-region web-mode-scan-beg web-mode-scan-end))
   3078         (when web-mode-enable-auto-indentation
   3079           (indent-region web-mode-scan-beg web-mode-scan-end))
   3080         ) ;and
   3081       )
   3082 
   3083     (when (and (< (point) 16) web-mode-change-beg web-mode-change-end)
   3084       (web-mode-detect-content-type))
   3085 
   3086     (when (and web-mode-change-beg web-mode-change-end
   3087                web-mode-enable-engine-detection
   3088                (or (null web-mode-engine) (string= web-mode-engine "none"))
   3089                (< (point) web-mode-chunk-length)
   3090                (web-mode-detect-engine))
   3091       (web-mode-on-engine-setted)
   3092       (web-mode-buffer-fontify))
   3093 
   3094     (when (> (point) 1)
   3095       (setq char (char-before)))
   3096 
   3097     (cond
   3098       ((null char)
   3099        )
   3100       ((and (>= (point) 3)
   3101             (web-mode--command-is-self-insert-p)
   3102             (not (member (get-text-property (point) 'part-token) '(comment string)))
   3103             (not (eq (get-text-property (point) 'tag-type) 'comment))
   3104             )
   3105        (setq ctx (web-mode-auto-complete)))
   3106       ((and web-mode-enable-auto-opening
   3107             (member this-command '(newline electric-newline-and-maybe-indent newline-and-indent))
   3108             (or (and (not (eobp))
   3109                      (eq (char-after) ?\<)
   3110                      (eq (get-text-property (point) 'tag-type) 'end)
   3111                      (looking-back ">\n[ \t]*" (point-min))
   3112                      (setq n (length (match-string-no-properties 0)))
   3113                      (eq (get-text-property (- (point) n) 'tag-type) 'start)
   3114                      (string= (get-text-property (- (point) n) 'tag-name)
   3115                               (get-text-property (point) 'tag-name))
   3116                      )
   3117                 (and (get-text-property (1- (point)) 'block-side)
   3118                      (string= web-mode-engine "php")
   3119                      (looking-back "<\\?php[ ]*\n" (point-min))
   3120                      (looking-at-p "[ ]*\\?>"))))
   3121        (newline-and-indent)
   3122        (forward-line -1)
   3123        (indent-according-to-mode)
   3124        )
   3125       ) ;cond
   3126 
   3127     (cond
   3128 
   3129       ((not web-mode-enable-auto-opening)
   3130        )
   3131       ((and (member this-command '(newline electric-newline-and-maybe-indent newline-and-indent))
   3132             (get-text-property (point) 'part-side)
   3133             (eq (get-text-property (point) 'part-token) 'string))
   3134        (indent-according-to-mode)
   3135        (when (and web-mode-change-end (> web-mode-change-end (point-max)))
   3136          (message "post-command: enlarge web-mode-change-end")
   3137          (setq web-mode-change-end (point-max))
   3138          )
   3139        )
   3140       ((and (web-mode--command-is-self-insert-p)
   3141             (or (and ctx
   3142                      (or (plist-get ctx :auto-closed)
   3143                          (plist-get ctx :auto-expanded)))
   3144                 (and (> (point) (point-min))
   3145                      (get-text-property (1- (point)) 'tag-end)
   3146                      (get-text-property (line-beginning-position) 'tag-beg))))
   3147        (indent-according-to-mode)
   3148        (when (and web-mode-change-end (> web-mode-change-end (point-max)))
   3149          (message "post-command: enlarge web-mode-change-end")
   3150          (setq web-mode-change-end (point-max))
   3151          )
   3152        )
   3153       ((and (web-mode--command-is-self-insert-p)
   3154             (member (get-text-property (point) 'part-side) '(javascript jsx css))
   3155             (looking-back "^[ \t]+[]})]" (point-min)))
   3156        (indent-according-to-mode)
   3157        (when (and web-mode-change-end (> web-mode-change-end (point-max)))
   3158          (message "post-command: enlarge web-mode-change-end")
   3159          (setq web-mode-change-end (point-max))
   3160          )
   3161        )
   3162       ) ; cond web-mode-enable-auto-opening
   3163 
   3164     (when web-mode-enable-current-element-highlight
   3165       (web-mode-highlight-current-element))
   3166 
   3167     (when (and web-mode-enable-current-column-highlight
   3168                (not (web-mode-buffer-narrowed-p)))
   3169       (web-mode-column-show))
   3170 
   3171     (when (and web-mode-trace (not (member this-command
   3172                                            '(left-char right-char previous-line next-line save-buffer mwheel-scroll end-of-line beginning-of-line))))
   3173       (when (or web-mode-change-beg web-mode-change-end)
   3174         (message "post-command: web-mode-change-beg(%S) web-mode-change-end(%S)"
   3175                  web-mode-change-end web-mode-change-end))
   3176       (message "-------------------------------------------------------------------")
   3177       )
   3178 
   3179     ))
   3180 
   3181 ;; NOTE: il est important d'identifier des caractères en fin de ligne
   3182 ;; web-mode-block-tokenize travaille en effet sur les fins de lignes pour
   3183 ;; les commentaires de type //
   3184 (defun web-mode-invalidate-block-region (pos-beg pos-end)
   3185   ;;  (message "pos-beg(%S) pos-end(%S)" pos-beg pos-end)
   3186   (save-excursion
   3187     (let (beg end code-beg code-end)
   3188       ;;(message "invalidate-block-region: pos-beg(%S)=%S" pos-beg (get-text-property pos 'block-side))
   3189       ;;(message "code-beg(%S) code-end(%S) pos-beg(%S) pos-end(%S)" code-beg code-end pos-beg pos-end)
   3190       (cond
   3191         ((not (and (setq code-beg (web-mode-block-code-beginning-position pos-beg))
   3192                    (setq code-end (web-mode-block-code-end-position pos-beg))
   3193                    (>= pos-beg code-beg)
   3194                    (<= pos-end code-end)
   3195                    (> code-end code-beg)))
   3196          (web-mode-invalidate-region pos-beg pos-end))
   3197         ((member web-mode-engine '("asp"))
   3198          (goto-char pos-beg)
   3199          (forward-line -1)
   3200          (setq beg (line-beginning-position))
   3201          (when (> code-beg beg)
   3202            (setq beg code-beg))
   3203          (goto-char pos-beg)
   3204          (forward-line)
   3205          (setq end (line-end-position))
   3206          (when (< code-end end)
   3207            (setq end code-end))
   3208          ;; ?? pas de (web-mode-block-tokenize beg end) ?
   3209          (web-mode-block-tokenize beg end)
   3210          (cons beg end)
   3211          ) ;asp
   3212         (t
   3213          (goto-char pos-beg)
   3214          ;;(message "pos-beg=%S" pos-beg)
   3215          (when (string= web-mode-engine "php")
   3216            (cond
   3217              ((and (looking-back "\*" (point-min))
   3218                    (looking-at-p "/"))
   3219               (search-backward "/*" code-beg))
   3220              ) ;cond
   3221            ) ;when
   3222          (if (web-mode-block-rsb "[;{}(][ ]*\n" code-beg)
   3223              (setq beg (match-end 0))
   3224              (setq beg code-beg))
   3225          (goto-char pos-end)
   3226          (if (web-mode-block-rsf "[;{})][ ]*\n" code-end)
   3227              (setq end (1- (match-end 0)))
   3228              (setq end code-end))
   3229          (web-mode-block-tokenize beg end)
   3230          ;;(message "beg(%S) end(%S)" beg end)
   3231          (cons beg end)
   3232          )
   3233         ) ;cond
   3234       )))
   3235 
   3236 (defun web-mode-invalidate-part-region (pos-beg pos-end)
   3237   (save-excursion
   3238     (let (beg end part-beg part-end language)
   3239       (if (member web-mode-content-type web-mode-part-content-types)
   3240           (setq language web-mode-content-type)
   3241           (setq language (symbol-name (get-text-property pos-beg 'part-side))))
   3242       (setq part-beg (web-mode-part-beginning-position pos-beg)
   3243             part-end (web-mode-part-end-position pos-beg))
   3244       ;;(message "language(%S) pos-beg(%S) pos-end(%S) part-beg(%S) part-end(%S)"
   3245       ;;         language pos-beg pos-end part-beg part-end)
   3246       (goto-char pos-beg)
   3247       (cond
   3248         ((not (and part-beg part-end
   3249                    (>= pos-beg part-beg)
   3250                    (<= pos-end part-end)
   3251                    (> part-end part-beg)))
   3252          (web-mode-invalidate-region pos-beg pos-end))
   3253         ((member language '("javascript" "json" "jsx" "typescript"))
   3254          (if (web-mode-javascript-rsb "[;{}(][ ]*\n" part-beg)
   3255              (setq beg (match-end 0))
   3256              (setq beg part-beg))
   3257          (goto-char pos-end)
   3258          (if (web-mode-javascript-rsf "[;{})][ ]*\n" part-end)
   3259              (setq end (match-end 0))
   3260              (setq end part-end))
   3261          (web-mode-scan-region beg end language))
   3262         ((member language '("css" "sass"))
   3263          (let (rule1 rule2)
   3264            (setq rule1 (web-mode-css-rule-current pos-beg))
   3265            (setq rule2 rule1)
   3266            (when (> pos-end (cdr rule1))
   3267              (setq rule2 (web-mode-css-rule-current pos-end)))
   3268            (setq beg (car rule1)
   3269                  end (cdr rule2))
   3270            )
   3271          (web-mode-scan-region beg end language))
   3272         (t
   3273          (setq beg part-beg
   3274                end part-end)
   3275          (web-mode-scan-region beg end language))
   3276         ) ;cond
   3277       )))
   3278 
   3279 (defun web-mode-invalidate-region-beginning-position (pos)
   3280   (save-excursion
   3281     (goto-char pos)
   3282 
   3283     (cond
   3284       ((and (looking-at-p ">") ;#1151
   3285             (looking-back "--" (point-min)))
   3286        (search-backward "<!--" nil t))
   3287       ((and (bolp) (not (bobp)))
   3288        (backward-char))
   3289       )
   3290 
   3291     (beginning-of-line)
   3292     ;;(message "pos=%S point=%S %S" pos (point) (text-properties-at (point)))
   3293     (setq pos (point-min))
   3294     (let ((continue (not (bobp))))
   3295       (while continue
   3296         (cond
   3297           ((bobp)
   3298            (setq continue nil))
   3299           ;; NOTE: Going back to the previous start tag is necessary
   3300           ;; when inserting a part endtag (e.g. </script>).
   3301           ;; Indeed, parts must be identified asap.
   3302           ((and (progn (back-to-indentation) t)
   3303                 (get-text-property (point) 'tag-beg)
   3304                 (eq (get-text-property (point) 'tag-type) 'start))
   3305            (setq pos (point)
   3306                  continue nil))
   3307           (t
   3308            (forward-line -1))
   3309           ) ;cond
   3310         ) ;while
   3311       ;;(message "pos=%S" pos)
   3312       pos)))
   3313 
   3314 (defun web-mode-invalidate-region-end-position (pos)
   3315   (save-excursion
   3316     (goto-char pos)
   3317     ;;(message "pos=%S %S" pos (get-text-property pos 'block-token))
   3318     (when (string= web-mode-engine "jsp")
   3319       (cond
   3320         ((and (looking-back "<%" (point-min))
   3321               (looking-at-p "--"))
   3322          (search-forward "--%>"))
   3323         ((and (looking-back "-- %" (point-min))
   3324               (looking-at-p ">"))
   3325          (search-forward "--%>"))
   3326         ) ;cond
   3327       ) ;when
   3328     (setq pos (point-max))
   3329     (let ((continue (not (eobp))))
   3330       (while continue
   3331         (end-of-line)
   3332         ;;(message "%S %S" (point) (get-text-property (point) 'block-token))
   3333         (cond
   3334           ((eobp)
   3335            (setq continue nil))
   3336           ((and (not (get-text-property (point) 'tag-type))
   3337                 (not (get-text-property (point) 'part-side))
   3338                 (not (get-text-property (point) 'block-side)))
   3339            (setq pos (point)
   3340                  continue nil))
   3341           (t
   3342            (forward-line))
   3343           ) ;cond
   3344         ) ;while
   3345       pos)))
   3346 
   3347 (defun web-mode-buffer-scan ()
   3348   "Scan entine buffer."
   3349   (interactive)
   3350   (web-mode-scan-region (point-min) (point-max)))
   3351 
   3352 (defun web-mode-scan-region (beg end &optional content-type)
   3353   "Identify nodes/parts/blocks and syntactic symbols (strings/comments/etc.)."
   3354   ;;(message "scan-region: beg(%d) end(%d) content-type(%S)" beg end content-type)
   3355   (setq web-mode-scan-beg beg
   3356         web-mode-scan-end end)
   3357   (web-mode-with-silent-modifications
   3358    (save-excursion
   3359      (save-restriction
   3360        (save-match-data
   3361          (let ((inhibit-point-motion-hooks t)
   3362                (inhibit-quit t))
   3363            (remove-list-of-text-properties beg end web-mode-scan-properties)
   3364            (cond
   3365              ((and content-type (string= content-type "php"))
   3366               )
   3367              ((and content-type (member content-type web-mode-part-content-types))
   3368               (put-text-property beg end 'part-side
   3369                                  (cond
   3370                                    ((string= content-type "javascript") 'javascript)
   3371                                    ((string= content-type "json") 'json)
   3372                                    ((string= content-type "jsx") 'jsx)
   3373                                    ((string= content-type "css") 'css)
   3374                                    ((string= content-type "sql") 'sql)
   3375                                    ((string= content-type "pug") 'pug)
   3376                                    ((string= content-type "sass") 'sass)
   3377                                    ((string= content-type "stylus") 'stylus)
   3378                                    ((string= content-type "markdown") 'markdown)
   3379                                    ((string= content-type "ruby") 'ruby)
   3380                                    ((string= content-type "typescript") 'typescript)
   3381                                    ))
   3382               (web-mode-scan-blocks beg end)
   3383               (web-mode-part-scan beg end content-type))
   3384              ((member web-mode-content-type web-mode-part-content-types)
   3385               (web-mode-scan-blocks beg end)
   3386               (web-mode-part-scan beg end))
   3387              ((string= web-mode-engine "riot")
   3388               (web-mode-scan-elements beg end)
   3389               (web-mode-scan-blocks beg end)
   3390               (web-mode-part-foreach beg end 'web-mode-part-scan))
   3391              (t
   3392               (web-mode-scan-blocks beg end)
   3393               (web-mode-scan-elements beg end)
   3394               (web-mode-part-foreach beg end 'web-mode-part-scan))
   3395              ) ;cond
   3396            (cons beg end)
   3397            ))))))
   3398 
   3399 ;;---- LEXER BLOCKS ------------------------------------------------------------
   3400 
   3401 (defun web-mode-scan-blocks (reg-beg reg-end)
   3402   "Identifies blocks (with block-side, block-beg, block-end text properties)."
   3403   (save-excursion
   3404 
   3405     (let ((i 0) open close closing-string sub1 sub2 pos tagopen tmp delim-open delim-close part-beg part-end tagclose)
   3406 
   3407       (goto-char reg-beg)
   3408 
   3409       ;;(message "%S: %Sx%S" (point) reg-beg reg-end)
   3410       ;;(message "regexp=%S" web-mode-block-regexp)
   3411       (while (and (< i 2000)
   3412                   (> reg-end (point))
   3413                   web-mode-block-regexp
   3414                   (re-search-forward web-mode-block-regexp reg-end t)
   3415                   (not (eobp)))
   3416 
   3417         (setq i (1+ i)
   3418               closing-string nil
   3419               close nil
   3420               tagopen (match-string 0)
   3421               open (match-beginning 0)
   3422               delim-open nil
   3423               delim-close nil
   3424               pos nil)
   3425 
   3426         (let ((l (length tagopen)))
   3427           (when (member (string-to-char tagopen) '(?\s ?\t))
   3428             (setq tagopen (replace-regexp-in-string "\\`[ \t]*" "" tagopen))
   3429             (setq open (+ open (- l (length tagopen))))
   3430             (setq l (length tagopen))
   3431             )
   3432           (setq sub1 (substring tagopen 0 1)
   3433                 sub2 (substring tagopen 0 (if (>= l 2) 2 1)))
   3434           )
   3435         ;;(message " found block #(%S) at pos=(%S), part-type=(%S)" i open (get-text-property open 'part-side))
   3436         (cond
   3437 
   3438           ((string= web-mode-engine "php")
   3439            (unless (member (char-after) '(?x ?X))
   3440              (setq closing-string '("<\\?". "\\?>")))
   3441            (cond
   3442              ((looking-at-p "<?php")
   3443               (setq delim-open "<?php")
   3444               (setq delim-close "?>"))
   3445              ((eq (char-after) ?\=)
   3446               (setq delim-open "<?=")
   3447               (setq delim-close "?>"))
   3448              (t
   3449               (setq delim-open "<?")
   3450               (setq delim-close "?>"))
   3451              ) ;cond
   3452            ) ;php
   3453 
   3454           ((string= web-mode-engine "erb")
   3455            (cond
   3456              ((string= sub2 "<%")
   3457               (setq closing-string '("<%". "%>")
   3458                     delim-open "<%\\(==\\|[=-]\\)?"
   3459                     delim-close "[-]?%>"))
   3460              (t
   3461               (setq closing-string "EOL"
   3462                     delim-open "%"))
   3463              )
   3464            ) ;erb
   3465 
   3466           ((string= web-mode-engine "django")
   3467            (cond
   3468              ((string= sub2 "{{")
   3469               (setq closing-string "EODQ"
   3470                     ;;(setq closing-string '("{{" . "}}")
   3471                     delim-open "{{"
   3472                     delim-close "}}"))
   3473              ((string= sub2 "{%")
   3474               (setq closing-string "%}"
   3475                     delim-open "{%[+-]?"
   3476                     delim-close "[-]?%}"))
   3477              ((string= sub2 "{#")
   3478               (setq closing-string "#}"))
   3479              (t
   3480               (setq closing-string "EOL"
   3481                     delim-open "#[#]?"))
   3482              )
   3483            ) ;django
   3484 
   3485           ((string= web-mode-engine "anki")
   3486            (setq closing-string "}}"
   3487                  delim-open "{{[#/^]?"
   3488                  delim-close "}}")
   3489            ) ;anki
   3490 
   3491           ((string= web-mode-engine "ejs")
   3492            (setq closing-string "%>"
   3493                  delim-open "<%[=-]?"
   3494                  delim-close "[-]?%>")
   3495            ) ;ejs
   3496 
   3497           ((string= web-mode-engine "lsp")
   3498            (setq closing-string "%>"
   3499                  delim-open "<%[%#]?"
   3500                  delim-close "%>")
   3501            ) ;lsp
   3502 
   3503           ((string= web-mode-engine "mako")
   3504            (cond
   3505              ((and (string= tagopen "<%")
   3506                    (member (char-after) '(?\s ?\n ?\!)))
   3507               (setq closing-string "%>"
   3508                     delim-open "<%[!]?"
   3509                     delim-close "%>"))
   3510              ((member sub2 '("<%" "</"))
   3511               (setq closing-string ">"
   3512                     delim-open "</?%"
   3513                     delim-close "/?>"))
   3514              ((string= sub2 "${")
   3515               (setq closing-string "}"
   3516                     delim-open "${"
   3517                     delim-close "}"))
   3518              (t
   3519               (setq closing-string "EOL"
   3520                     delim-open "%"))
   3521              )
   3522            ) ;mako
   3523 
   3524           ((string= web-mode-engine "cl-emb")
   3525            (cond
   3526              ((string= tagopen "<%#")
   3527               (setq closing-string "#%>"))
   3528              ((string= sub2 "<%")
   3529               (setq closing-string "%>"
   3530                     delim-open "<%[=%]?"
   3531                     delim-close "%>"))
   3532              )
   3533            ) ;cl-emb
   3534 
   3535           ((string= web-mode-engine "artanis")
   3536            (cond
   3537              ((string= tagopen "<%;")
   3538               (setq closing-string "%>"))
   3539              ((string= tagopen "<%#|")
   3540               (setq closing-string "|#%>"))
   3541              ((string= sub2 "<@")
   3542               (setq closing-string "%>"
   3543                     delim-open "<@\\(css\\|icon\\|include\\|js\\)"
   3544                     delim-close "%>"))
   3545              ((string= sub2 "<%")
   3546               (setq closing-string "%>"
   3547                     delim-open "<%[=]?"
   3548                     delim-close "%>"))
   3549              )
   3550            ) ;artanis
   3551 
   3552           ((string= web-mode-engine "elixir")
   3553            (cond
   3554              ((member (char-after) '(?\#))
   3555               (setq closing-string "%>"))
   3556              (t
   3557               (setq closing-string "%>"
   3558                     delim-open "<%[=%]?"
   3559                     delim-close "%>"))
   3560              )
   3561            ) ;elixir
   3562 
   3563           ((string= web-mode-engine "mojolicious")
   3564            (cond
   3565              ((string= tagopen "<%#")
   3566               (setq closing-string "%>"))
   3567              ((string= sub2 "<%")
   3568               (setq closing-string "%>"
   3569                     delim-open "<%\\(==\\|[=%]\\)?"
   3570                     delim-close "%>"))
   3571              ((string= sub2 "%#")
   3572               (setq closing-string "EOL"))
   3573              (t
   3574               (setq closing-string "EOL"
   3575                     delim-open "%\\(==\\|[=%]\\)?"))
   3576              )
   3577            ) ;mojolicious
   3578 
   3579           ((string= web-mode-engine "ctemplate")
   3580            (cond
   3581              ((member tagopen '("{{{" "{{~"))
   3582               (setq closing-string "}~?}}"
   3583                     delim-open "{{~?{"
   3584                     delim-close "}~?}}")
   3585               )
   3586              ((string= tagopen "{~{")
   3587               (setq closing-string "}~?}"
   3588                     delim-open "{~{"
   3589                     delim-close "}~?}")
   3590               )
   3591              ((string= tagopen "{{!")
   3592               (setq closing-string (if (looking-at-p "--") "--}}" "}}"))
   3593               )
   3594              ((string= sub2 "{{")
   3595               (setq closing-string "}~?}"
   3596                     delim-open "{{[>#/%^&]?"
   3597                     delim-close "}~?}"))
   3598              (t
   3599               (setq closing-string "}}"
   3600                     delim-open "${{"
   3601                     delim-close "}}"))
   3602              )
   3603            ) ;ctemplate
   3604 
   3605           ((string= web-mode-engine "antlers")
   3606            (cond
   3607              ((string= tagopen "{{$")
   3608               (setq closing-string "$}}"
   3609                     delim-open "{{$"
   3610                     delim-close "$}}")
   3611               )
   3612              ((string= tagopen "{{?")
   3613               (setq closing-string "?}}"
   3614                     delim-open "{{?"
   3615                     delim-close "?}}")
   3616               )
   3617              ((string= tagopen "{{$")
   3618               (setq closing-string "$}}"
   3619                     delim-open "{{$"
   3620                     delim-close "$}}")
   3621               )
   3622              ((string= sub2 "{{")
   3623               (setq closing-string "}}"
   3624                     delim-open "{{"
   3625                     delim-close "}}"))
   3626              )
   3627            ) ;antlers
   3628 
   3629           ((string= web-mode-engine "astro")
   3630            (cond
   3631              ((string= tagopen "---")
   3632               (setq closing-string "---"
   3633                     delim-open "---"
   3634                     delim-close "---")
   3635               )
   3636              )
   3637            ) ;astro
   3638 
   3639           ((string= web-mode-engine "aspx")
   3640            (setq closing-string "%>"
   3641                  delim-open "<%[:=#@$]?"
   3642                  delim-close "%>")
   3643            ) ;aspx
   3644 
   3645           ((string= web-mode-engine "asp")
   3646            (cond
   3647              ((string= sub2 "<%")
   3648               (setq closing-string "%>"
   3649                     delim-open "<%[:=#@$]?"
   3650                     delim-close "%>"))
   3651              (t
   3652               (setq closing-string ">"
   3653                     delim-open "</?"
   3654                     delim-close "/?>"))
   3655              )
   3656            ) ;asp
   3657 
   3658           ((string= web-mode-engine "jsp")
   3659            (cond
   3660              ((looking-at-p "--")
   3661               (setq closing-string "--%>"))
   3662              ((string= sub2 "<%")
   3663               (setq closing-string "%>"
   3664                     delim-open "<%\\([!=@]\\|#=\\)?"
   3665                     delim-close "[-]?%>"))
   3666              ((string= sub2 "${")
   3667               (setq closing-string "}"
   3668                     delim-open "${"
   3669                     delim-close "}"))
   3670              )
   3671            ) ;jsp
   3672 
   3673           ((string= web-mode-engine "clip")
   3674            (setq closing-string ">"
   3675                  delim-open "</?"
   3676                  delim-close "/?>")
   3677            ) ;clip
   3678 
   3679           ((string= web-mode-engine "perl")
   3680            (setq closing-string ">"
   3681                  delim-open "</?"
   3682                  delim-close "/?>")
   3683            ) ;perl
   3684 
   3685           ((string= web-mode-engine "blade")
   3686            (cond
   3687              ((string= tagopen "{{-")
   3688               (setq closing-string "--}}"))
   3689              ((string= tagopen "{!!")
   3690               (setq closing-string "!!}"
   3691                     delim-open "{!!"
   3692                     delim-close "!!}"))
   3693              ((string= tagopen "@{{")
   3694               (setq closing-string nil))
   3695              ((string= tagopen "{{{")
   3696               (setq closing-string "}}}"
   3697                     delim-open "{{{"
   3698                     delim-close "}}}"))
   3699              ((string= sub2 "{{")
   3700               (setq closing-string "}}"
   3701                     delim-open "{{"
   3702                     delim-close "}}"))
   3703              ((looking-at-p "[[:alnum:]]+\\.[[:alpha:]]+")
   3704               )
   3705              ((string= sub1 "@")
   3706               (setq closing-string "EOB"
   3707                     delim-open "@"))
   3708              ((looking-at-p "[[:alnum:]]+(")
   3709               (setq closing-string ")"
   3710                     delim-open "@"))
   3711              )
   3712            ;;(message "closing-string=%S delim-open=%S delim-close=%S" closing-string delim-open delim-close)
   3713            ) ;blade
   3714 
   3715           ((string= web-mode-engine "smarty")
   3716            (cond
   3717              ((string= tagopen "{*")
   3718               (setq closing-string "*}")
   3719               )
   3720              ((string= tagopen "{#")
   3721               (setq closing-string "#}"
   3722                     delim-open "{#"
   3723                     delim-close "#}")
   3724               )
   3725              (t
   3726               (setq closing-string (cons "{" "}")
   3727                     delim-open "{/?"
   3728                     delim-close "}")
   3729               ) ;t
   3730              ) ;cond
   3731            ) ;smarty
   3732 
   3733           ((string= web-mode-engine "hero")
   3734            (setq closing-string "%>"
   3735                  delim-open "<%==?\\([biufsv]\\|bs\\)?\\|<%[:~@+!]?"
   3736                  delim-close "%>")
   3737            ) ;hero
   3738 
   3739           ((string= web-mode-engine "xoops")
   3740            (cond
   3741              ((string= tagopen "<{*")
   3742               (setq closing-string "*}>")
   3743               )
   3744              ((string= tagopen "<{#")
   3745               (setq closing-string "#}>"
   3746                     delim-open "<{#"
   3747                     delim-close "#}>")
   3748               )
   3749              (t
   3750               (setq closing-string (cons "<{" "}>")
   3751                     delim-open "<{/?"
   3752                     delim-close "}>")
   3753               ) ;t
   3754              ) ;cond
   3755            ) ;xoops
   3756 
   3757           ((string= web-mode-engine "web2py")
   3758            (setq closing-string "}}"
   3759                  delim-open "{{[=]?"
   3760                  delim-close "}}")
   3761            ) ;web2py
   3762 
   3763           ((string= web-mode-engine "expressionengine")
   3764            (cond
   3765              ((string= sub2 "{!--")
   3766               (setq closing-string "--}"))
   3767              (t
   3768               (setq closing-string '("{". "}")
   3769                     delim-open "{/?"
   3770                     delim-close "}")
   3771               )
   3772              )
   3773            ) ;expressionengine
   3774 
   3775           ((string= web-mode-engine "dust")
   3776            (cond
   3777              ((string= sub2 "{!")
   3778               (setq closing-string "!}"))
   3779              (t
   3780               (setq closing-string '("{". "}")
   3781                     delim-open "{[#/:?@><+^]?"
   3782                     delim-close "/?}")
   3783               )
   3784              )
   3785            ) ;dust
   3786 
   3787           ((string= web-mode-engine "svelte")
   3788            (cond
   3789              ((string= sub2 "{!")
   3790               (setq closing-string "!}"))
   3791              ((string= sub2 "{}")
   3792               (setq closing-string nil
   3793                     delim-open nil
   3794                     delim-close nil))
   3795              (t
   3796               (setq closing-string '("{". "}")
   3797                     delim-open "{[#/:?@><+^]?"
   3798                     delim-close "/?}")
   3799               )
   3800              )
   3801            ) ;svelte
   3802 
   3803           ((string= web-mode-engine "closure")
   3804            (cond
   3805              ((string= sub2 "//")
   3806               (setq closing-string "EOL")
   3807               )
   3808              ((string= sub2 "/*")
   3809               (setq closing-string "*/")
   3810               )
   3811              (t
   3812               (setq closing-string "}"
   3813                     delim-open "{/?"
   3814                     delim-close "/?}")
   3815               )
   3816              )
   3817            ) ;closure
   3818 
   3819           ((string= web-mode-engine "go")
   3820            (setq closing-string "}}"
   3821                  delim-open "{{-?"
   3822                  delim-close "-?}}")
   3823            ) ;go
   3824 
   3825           ((string= web-mode-engine "angular")
   3826            (setq closing-string "}}"
   3827                  delim-open "{{"
   3828                  delim-close "}}")
   3829            ) ;angular
   3830 
   3831           ((string= web-mode-engine "vue")
   3832            (cond
   3833              ((string-match-p "[:@][-[:alpha:]]+=\"" tagopen)
   3834               (setq closing-string "\""
   3835                     delim-open tagopen
   3836                     delim-close "\""))
   3837              ((string= tagopen "{{")
   3838               (setq closing-string "}}"
   3839                     delim-open "{{"
   3840                     delim-close "}}")))
   3841            ) ;vue
   3842 
   3843           ((string= web-mode-engine "mason")
   3844            (cond
   3845              ((and (member sub2 '("<%" "</"))
   3846                    (looking-at "[[:alpha:]]+"))
   3847               (if (member (match-string-no-properties 0) '("after" "around" "augment" "before" "def" "filter" "method" "override"))
   3848                   (setq closing-string ">"
   3849                         delim-open "<[/]?%"
   3850                         delim-close ">")
   3851                   (setq closing-string (concat "</%" (match-string-no-properties 0) ">")
   3852                         delim-open "<[^>]+>"
   3853                         delim-close "<[^>]+>")
   3854                   ) ;if
   3855               )
   3856              ((and (string= sub2 "<%")
   3857                    (eq (char-after) ?\s))
   3858               (setq closing-string "%>"
   3859                     delim-open "<%"
   3860                     delim-close "%>"))
   3861              ((string= tagopen "</&")
   3862               (setq closing-string ">"
   3863                     delim-open "</&"
   3864                     delim-close ">")
   3865               )
   3866              ((string= sub2 "<&")
   3867               (setq closing-string "&>"
   3868                     delim-open "<&[|]?"
   3869                     delim-close "&>"))
   3870              (t
   3871               (setq closing-string "EOL"
   3872                     delim-open "%"))
   3873              )
   3874            ) ;mason
   3875 
   3876           ((string= web-mode-engine "underscore")
   3877            (setq closing-string "%>"
   3878                  delim-open "<%"
   3879                  delim-close "%>")
   3880            ) ;underscore
   3881 
   3882           ((string= web-mode-engine "template-toolkit")
   3883            (cond
   3884              ((string= tagopen "%%#")
   3885               (setq closing-string "EOL"))
   3886              ((string= tagopen "[%#")
   3887               (setq closing-string "%]"))
   3888              (t
   3889               (setq closing-string "%]"
   3890                     delim-open "\\[%[-+]?"
   3891                     delim-close "[-=+]?%\\]"))
   3892              )
   3893            ) ;template-toolkit
   3894 
   3895           ((string= web-mode-engine "freemarker")
   3896            (cond
   3897              ((and (string= sub2 "<#") (eq (char-after) ?\-))
   3898               (setq closing-string "-->"))
   3899              ((string= sub1 "<")
   3900               (setq closing-string ">"
   3901                     delim-open "</?[#@]"
   3902                     delim-close "/?>"))
   3903              ((string= sub1 "[")
   3904               (setq closing-string "]"
   3905                     delim-open "\\[/?[#@]"
   3906                     delim-close "/?\\]"))
   3907              (t
   3908               (setq closing-string "}"
   3909                     delim-open "${"
   3910                     delim-close "}"))
   3911              )
   3912            ) ;freemarker
   3913 
   3914           ((string= web-mode-engine "velocity")
   3915            (cond
   3916              ((string= sub2 "##")
   3917               (setq closing-string "EOL"))
   3918              ((string= sub2 "#*")
   3919               (setq closing-string "*#"))
   3920              (t
   3921               (setq closing-string "EOV"
   3922                     delim-open "#"))
   3923              )
   3924            ) ;velocity
   3925 
   3926           ((string= web-mode-engine "razor")
   3927            (cond
   3928              ((string= sub2 "@@")
   3929               (forward-char 2)
   3930               (setq closing-string nil))
   3931              ((string= sub2 "@*")
   3932               (setq closing-string "*@"))
   3933              ((string= sub1 "@")
   3934               (setq closing-string "EOR"
   3935                     delim-open "@"))
   3936              ((and (string= sub1 "}")
   3937                    (looking-at-p "[ ]*\n"))
   3938               ;;(setq closing-string "EOC")
   3939               (save-excursion
   3940                 (let (paren-pos)
   3941                   (setq paren-pos (web-mode-part-opening-paren-position (1- (point))))
   3942                   (if (and paren-pos (get-text-property paren-pos 'block-side))
   3943                       (setq closing-string "EOC")
   3944                       (setq closing-string nil)
   3945                       ) ;if
   3946                   ) ;let
   3947                 ) ;save-excursion
   3948               ;;(message "%s %S %S" sub2 (point) (get-text-property (point) 'part-side))
   3949               )
   3950              ((string= sub1 "}")
   3951               ;;(message "%s: %s" (point) sub1)
   3952               (save-excursion
   3953                 (let (paren-pos)
   3954                   (setq paren-pos (web-mode-part-opening-paren-position (1- (point))))
   3955                   (if (and paren-pos (get-text-property paren-pos 'block-side))
   3956                       (setq closing-string "EOR")
   3957                       (setq closing-string nil)
   3958                       ) ;if
   3959                   ) ;let
   3960                 ) ;save-excursion
   3961               ) ;case }
   3962              ) ;cond
   3963            ) ;razor
   3964 
   3965           ((and (string= web-mode-engine "riot")
   3966                 (not (get-text-property open 'part-side)))
   3967            (setq closing-string (if (string= tagopen "{") "}" "/// end script")
   3968                  delim-open "{"
   3969                  delim-close "}")
   3970            ) ;riot
   3971 
   3972           ((string= web-mode-engine "spip")
   3973            (cond
   3974              ((and (string= sub1 "#")
   3975                    (looking-at "[A-Z0-9_]+"))
   3976               (setq closing-string (match-string-no-properties 0)))
   3977              ((string= sub1 "(")
   3978               (setq closing-string '("(" . ")")))
   3979              ((string= sub1 "{")
   3980               (setq closing-string '("{" . "}")))
   3981              ((string= sub2 "<:")
   3982               (setq closing-string ":>"))
   3983              (t
   3984               (setq closing-string "]"))
   3985              ))
   3986 
   3987           ((string= web-mode-engine "marko")
   3988            (setq closing-string "}"
   3989                  delim-open "${"
   3990                  delim-close "}")
   3991            ) ;marko
   3992 
   3993           ) ;cond
   3994 
   3995         (when closing-string
   3996           (cond
   3997 
   3998             ((listp closing-string)
   3999              (cond
   4000                ((web-mode-rsf-balanced (car closing-string) (cdr closing-string) reg-end t)
   4001                 (setq close (match-end 0)
   4002                       pos (point))
   4003                 )
   4004                ((and (string= web-mode-engine "php")
   4005                      (string= "<?" sub2))
   4006 
   4007                 (if (or (text-property-not-all (1+ open) (point-max) 'tag-beg nil)
   4008                         (text-property-not-all (1+ open) (point-max) 'block-beg nil)
   4009                         (looking-at-p "[ \t\n]*<"))
   4010                     (setq close nil
   4011                           delim-close nil
   4012                           pos (point))
   4013                     (setq close (point-max)
   4014                           delim-close nil
   4015                           pos (point-max))
   4016                     ) ;if
   4017                 ) ;case
   4018                ) ;cond
   4019              ) ;case listp
   4020 
   4021             ((and (string= web-mode-engine "smarty")
   4022                   (string= closing-string "}"))
   4023              (goto-char open)
   4024              (setq tmp (web-mode-closing-delimiter-position
   4025                         "}"
   4026                         (point)
   4027                         (line-end-position)))
   4028              (if tmp
   4029                  (setq tmp (1+ tmp))
   4030                  (setq tmp (line-end-position)))
   4031              (goto-char tmp)
   4032              (setq close (point)
   4033                    pos (point))
   4034              )
   4035 
   4036             ((and (member web-mode-engine '("closure"))
   4037                   (string= closing-string "}"))
   4038              (when (web-mode-closure-skip reg-beg reg-end)
   4039                (setq close (point)
   4040                      pos (point))
   4041                ;;(message "close=%S pos=%S" close pos)
   4042                ) ;when
   4043              )
   4044 
   4045             ((string= closing-string "EOB")
   4046              (web-mode-blade-skip open)
   4047              (setq close (point)
   4048                    pos (point)))
   4049 
   4050             ((string= closing-string "EOL")
   4051              (end-of-line)
   4052              (setq close (point)
   4053                    pos (point)))
   4054 
   4055             ((string= closing-string "EOC")
   4056              (setq close (point)
   4057                    pos (point)))
   4058 
   4059             ((string= closing-string "EODQ")
   4060              (when (web-mode-django-skip reg-beg reg-end)
   4061                (setq close (point)
   4062                      pos (point))
   4063                ))
   4064 
   4065             ((string= closing-string "EOR")
   4066              (web-mode-razor-skip open)
   4067              (setq close (if (> (point) reg-end) reg-end (point))
   4068                    pos (if (> (point) reg-end) reg-end (point)))
   4069              (goto-char pos))
   4070 
   4071             ((string= closing-string "EOV")
   4072              (web-mode-velocity-skip open)
   4073              (setq close (point)
   4074                    pos (point)))
   4075 
   4076             ((and (member web-mode-engine '("ctemplate"))
   4077                   (re-search-forward closing-string reg-end t))
   4078              (setq close (match-end 0)
   4079                    pos (point)))
   4080 
   4081             ((and (member web-mode-engine '("antlers"))
   4082                   (re-search-forward closing-string reg-end t))
   4083              (setq close (match-end 0)
   4084                    pos (point)))
   4085 
   4086             ((and (member web-mode-engine '("astro"))
   4087                   (re-search-forward closing-string reg-end t))
   4088              (setq close (match-end 0)
   4089                    pos (point)))
   4090 
   4091             ((search-forward closing-string reg-end t)
   4092              (setq close (match-end 0)
   4093                    pos (point)))
   4094             ) ;cond
   4095 
   4096           (when (and close (>= reg-end pos))
   4097             ;;(message "pos(%S) : open(%S) close(%S)" pos open close)
   4098             (put-text-property open (1+ open) 'block-beg 0)
   4099             (put-text-property open (1+ open) 'block-controls 0)
   4100             (put-text-property open close 'block-side t)
   4101             (put-text-property (1- close) close 'block-end t)
   4102             (when delim-open
   4103               (web-mode-block-delimiters-set open close delim-open delim-close))
   4104             (web-mode-block-scan open close)
   4105             (cond
   4106               ((and (string= web-mode-engine "erb")
   4107                     (looking-at-p "<%= javascript_tag do %>"))
   4108                (setq tagopen "<%= javascript_tag do %>"))
   4109               ((and (string= web-mode-engine "mojolicious")
   4110                     (looking-at-p "%= javascript begin"))
   4111                (setq tagopen "%= javascript begin"))
   4112               ((and (string= web-mode-engine "mako")
   4113                     (looking-at-p "<%block filter=\"collect_js\">"))
   4114                (setq tagopen "<%block filter=\"collect_js\">"))
   4115               ((and (string= web-mode-engine "mako")
   4116                     (looking-at-p "<%block filter=\"collect_css\">"))
   4117                (setq tagopen "<%block filter=\"collect_css\">"))
   4118               ((and (string= web-mode-engine "django")
   4119                     (looking-at-p "{% javascript %}"))
   4120                (setq tagopen "{% javascript %}"))
   4121               ((and (string= web-mode-engine "django")
   4122                     (looking-at-p "{% schema %}"))
   4123                (setq tagopen "{% schema %}"))
   4124               ((and (string= web-mode-engine "django")
   4125                     (looking-at-p "{% stylesheet %}"))
   4126                (setq tagopen "{% stylesheet %}"))
   4127               )
   4128             ;;(message "%S %s" (point) tagopen)
   4129             (when (and (member tagopen '("<r:script" "<r:style"
   4130                                          "<c:js" "<c:css"
   4131                                          "<%= javascript_tag do %>"
   4132                                          "<%block filter=\"collect_js\">"
   4133                                          "<%block filter=\"collect_css\">"
   4134                                          "{% javascript %}"
   4135                                          "{% schema %}"
   4136                                          "{% stylesheet %}"
   4137                                          "%= javascript begin"
   4138                                          "---"))
   4139                        (setq part-beg close)
   4140                        (setq tagclose
   4141                              (cond
   4142                                ((string= tagopen "<r:script") "</r:script")
   4143                                ((string= tagopen "<r:style") "</r:style")
   4144                                ((string= tagopen "<c:js") "</c:js")
   4145                                ((string= tagopen "<c:css") "</c:css")
   4146                                ((string= tagopen "{% javascript %}") "{% endjavascript %}")
   4147                                ((string= tagopen "{% schema %}") "{% endschema %}")
   4148                                ((string= tagopen "{% stylesheet %}") "{% endstylesheet %}")
   4149                                ((string= tagopen "%= javascript begin") "% end")
   4150                                ((string= tagopen "---") "---")
   4151                                ((string= tagopen "<%= javascript_tag do %>") "<% end %>")
   4152                                ((member tagopen '("<%block filter=\"collect_js\">"
   4153                                                   "<%block filter=\"collect_css\">")) "</%block")
   4154                                ))
   4155                        (web-mode-sf tagclose)
   4156                        (setq part-end (match-beginning 0))
   4157                        (> part-end part-beg))
   4158               ;;(message "tagopen=%S tagclose=%S end=%S" tagopen tagclose (point))
   4159               (put-text-property part-beg part-end
   4160                                  'part-side
   4161                                  (cond
   4162                                    ((member tagopen '("<r:style" "<c:css" "<%block filter=\"collect_css\">" "{% stylesheet %}")) 'css)
   4163                                    (t 'javascript)))
   4164               (setq pos part-beg
   4165                     part-beg nil
   4166                     part-end nil)
   4167               ) ;when
   4168             ) ;when close
   4169 
   4170           (if pos (goto-char pos))
   4171 
   4172           ) ;when closing-string
   4173 
   4174         ) ;while
   4175 
   4176       (cond
   4177         ((>= i 2000)
   4178          (message "scan-blocks ** warning (%S) **" i))
   4179         ((string= web-mode-engine "razor")
   4180          (web-mode-block-foreach reg-beg reg-end 'web-mode-block-scan))
   4181         ((string= web-mode-engine "django")
   4182          (web-mode-scan-engine-comments reg-beg reg-end
   4183                                         "{% comment %}" "{% endcomment %}"))
   4184         ((string= web-mode-engine "mako")
   4185          (web-mode-scan-engine-comments reg-beg reg-end
   4186                                         "<%doc>" "</%doc>"))
   4187         ((string= web-mode-engine "mason")
   4188          (web-mode-scan-engine-comments reg-beg reg-end
   4189                                         "<%doc>" "</%doc>"))
   4190         ) ;cond
   4191 
   4192       )))
   4193 
   4194 (defun web-mode-scan-engine-comments (reg-beg reg-end tag-start tag-end)
   4195   "Scan engine comments (mako, django)."
   4196   (save-excursion
   4197     (let (beg end (continue t))
   4198       (goto-char reg-beg)
   4199       (while (and continue
   4200                   (< (point) reg-end)
   4201                   (re-search-forward tag-start reg-end t))
   4202         (goto-char (match-beginning 0))
   4203         (setq beg (point))
   4204         (if (not (re-search-forward tag-end reg-end t))
   4205             (setq continue nil)
   4206             (setq end (point))
   4207             (remove-list-of-text-properties beg end web-mode-scan-properties)
   4208             (add-text-properties beg end '(block-side t block-token comment))
   4209             (put-text-property beg (1+ beg) 'block-beg 0)
   4210             (put-text-property (1- end) end 'block-end t)
   4211             ) ;if
   4212         ) ;while
   4213       )))
   4214 
   4215 (defun web-mode-closure-skip (reg-beg reg-end)
   4216   (let (regexp char pos inc continue found)
   4217     (setq regexp "[\"'{}]"
   4218           inc 0)
   4219     (while (and (not found) (re-search-forward regexp reg-end t))
   4220       (setq char (char-before))
   4221       (cond
   4222         ((get-text-property (point) 'block-side)
   4223          (setq found t))
   4224         ((eq char ?\{)
   4225          (setq inc (1+ inc)))
   4226         ((eq char ?\})
   4227          (cond
   4228            ((and (not (eobp))
   4229                  (< inc 1))
   4230             (setq found t
   4231                   pos (point)))
   4232            ((> inc 0)
   4233             (setq inc (1- inc)))
   4234            )
   4235          )
   4236         ((eq char ?\')
   4237          (setq continue t)
   4238          (while (and continue (search-forward "'" reg-end t))
   4239            (setq continue (web-mode-string-continue-p reg-beg))
   4240            )
   4241          )
   4242         ((eq char ?\")
   4243          (setq continue t)
   4244          (while (and continue (search-forward "\"" reg-end t))
   4245            (setq continue (web-mode-string-continue-p reg-beg))
   4246            )
   4247          )
   4248         ) ;cond
   4249       ) ;while
   4250     pos))
   4251 
   4252 (defun web-mode-django-skip (reg-beg reg-end)
   4253   (let (regexp char pos inc continue found)
   4254     (setq regexp "[\"'{}]"
   4255           inc 0)
   4256     (while (and (not found) (re-search-forward regexp reg-end t))
   4257       (setq char (char-before))
   4258       (cond
   4259         ((get-text-property (point) 'block-side)
   4260          (setq found t))
   4261         ((eq char ?\{)
   4262          (setq inc (1+ inc)))
   4263         ((eq char ?\})
   4264          (cond
   4265            ((and (not (eobp))
   4266                  (eq (char-after) ?\})
   4267                  (< inc 2))
   4268             (forward-char)
   4269             (setq found t
   4270                   pos (1+ (point))))
   4271            ((> inc 0)
   4272             (setq inc (1- inc)))
   4273            )
   4274          )
   4275         ((eq char ?\')
   4276          (setq continue t)
   4277          (while (and continue (search-forward "'" reg-end t))
   4278            (setq continue (web-mode-string-continue-p reg-beg))
   4279            )
   4280          )
   4281         ((eq char ?\")
   4282          (setq continue t)
   4283          (while (and continue (search-forward "\"" reg-end t))
   4284            (setq continue (web-mode-string-continue-p reg-beg))
   4285            )
   4286          )
   4287         ) ;cond
   4288       ) ;while
   4289     pos))
   4290 
   4291 (defun web-mode-blade-skip (pos)
   4292   (let (regexp char inc continue found (reg-beg pos) (reg-end (point-max)))
   4293     ;;(message "pos=%S" pos)
   4294     (goto-char pos)
   4295     (forward-char)
   4296     (skip-chars-forward "a-zA-Z0-9_-")
   4297     (when (eq (char-after) ?\()
   4298       (setq regexp "[\"'()]"
   4299             inc 0)
   4300       (while (and (not found) (re-search-forward regexp reg-end t))
   4301         (setq char (char-before))
   4302         ;;(message "point=%S char=%c inc=%S" (point) char inc)
   4303         (cond
   4304          ((eq char ?\()
   4305           (setq inc (1+ inc)))
   4306          ((eq char ?\))
   4307           (cond
   4308            ((and (not (eobp))
   4309                  (< inc 2))
   4310             (forward-char)
   4311             (setq inc (1- inc))
   4312             (setq found t)
   4313             )
   4314            ((> inc 0)
   4315             (setq inc (1- inc)))
   4316            )
   4317           )
   4318          ((eq char ?\')
   4319           (setq continue t)
   4320           (while (and continue (search-forward "'" reg-end t))
   4321             (setq continue (web-mode-string-continue-p reg-beg))
   4322             )
   4323           )
   4324          ((eq char ?\")
   4325           (setq continue t)
   4326           (while (and continue (search-forward "\"" reg-end t))
   4327             (setq continue (web-mode-string-continue-p reg-beg))
   4328             )
   4329           )
   4330          ) ;cond
   4331         ;;(message "inc=%S found=%S" inc found)
   4332         ) ;while
   4333       ) ; when
   4334     ;;(message "point=%S inc=%S" (point) inc)
   4335     (when found (backward-char))
   4336   ))
   4337 
   4338 (defun web-mode-velocity-skip (pos)
   4339   (goto-char pos)
   4340   (let ((continue t) (i 0))
   4341     (when (eq ?\# (char-after))
   4342       (forward-char))
   4343     (when (member (char-after) '(?\$ ?\@))
   4344       (forward-char))
   4345     (when (member (char-after) '(?\!))
   4346       (forward-char))
   4347     (cond
   4348       ((member (char-after) '(?\{))
   4349        (search-forward "}" nil t))
   4350       ((looking-at-p "def \\|define ")
   4351        (search-forward ")" (line-end-position) t))
   4352       (t
   4353        (setq continue t)
   4354        (while continue
   4355          (skip-chars-forward "a-zA-Z0-9_-")
   4356          (when (> (setq i (1+ i)) 500)
   4357            (message "velocity-skip ** warning (%S) **" pos)
   4358            (setq continue nil))
   4359          (when (member (char-after) '(?\())
   4360            (search-forward ")" nil t))
   4361          (if (member (char-after) '(?\.))
   4362              (forward-char)
   4363              (setq continue nil))
   4364          ) ;while
   4365        ) ;t
   4366       ) ;cond
   4367     ))
   4368 
   4369 (defun web-mode-razor-skip (pos)
   4370   (goto-char pos)
   4371   (let ((continue t) (i 0))
   4372     (while continue
   4373       (skip-chars-forward " =@a-zA-Z0-9_-")
   4374       (cond
   4375         ((> (setq i (1+ i)) 500)
   4376          (message "razor-skip ** warning **")
   4377          (setq continue nil))
   4378         ((and (eq (char-after) ?\*)
   4379               (eq (char-before) ?@))
   4380          (when (not (search-forward "*@" nil t))
   4381            (setq continue nil))
   4382          )
   4383         ((looking-at-p "@[({]")
   4384          (forward-char)
   4385          (when (setq pos (web-mode-closing-paren-position (point)))
   4386            (goto-char pos))
   4387          (forward-char)
   4388          )
   4389         ((and (not (eobp)) (eq ?\( (char-after)))
   4390          (cond
   4391            ((looking-at-p "[ \n]*[<@]")
   4392             (setq continue nil))
   4393            ((setq pos (web-mode-closing-paren-position))
   4394             (goto-char pos)
   4395             (forward-char))
   4396            (t
   4397             (forward-char))
   4398            ) ;cond
   4399          )
   4400         ((and (not (eobp)) (eq ?\< (char-after)) (looking-back "[a-z]" (point-min)))
   4401          (setq pos (point))
   4402          (cond
   4403            ;; #988
   4404            ((search-forward ">" (line-end-position) t)
   4405             (goto-char pos)
   4406             (setq continue nil)
   4407             )
   4408            (t
   4409             (setq continue nil))
   4410            ) ;cond
   4411          )
   4412         ((and (not (eobp)) (eq ?\. (char-after)))
   4413          (forward-char))
   4414         ((and (not (eobp)) (looking-at-p "[ \n]*else"))
   4415          (re-search-forward "[ \t]*else")
   4416          )
   4417         ((looking-at-p "[ \n]*{")
   4418          (search-forward "{")
   4419          (search-forward "=>" (line-end-position) 't)
   4420          (if (looking-at-p "[ \n]*[<@]")
   4421              (setq continue nil)
   4422              (backward-char)
   4423              (when (setq pos (web-mode-closing-paren-position))
   4424                (goto-char pos))
   4425              (forward-char)
   4426              ) ;if
   4427          )
   4428         ((looking-at-p "}")
   4429          (forward-char))
   4430         (t
   4431          (setq continue nil))
   4432         ) ;cond
   4433       ) ;while
   4434     ))
   4435 
   4436 (defun web-mode-block-delimiters-set (reg-beg reg-end delim-open delim-close)
   4437   "Set text-property `block-token' to `delimiter-(beg|end)' on block delimiters
   4438 (e.g. <?php and ?>)"
   4439   ;;(message "reg-beg(%S) reg-end(%S) delim-open(%S) delim-close(%S)" reg-beg reg-end delim-open delim-close)
   4440   (when (member web-mode-engine
   4441                 '("artanis" "anki" "antlers" "asp" "aspx"
   4442                   "cl-emb" "clip" "closure" "ctemplate" "django" "dust"
   4443                   "elixir" "ejs" "erb" "expressionengine" "freemarker" "go" "hero" "jsp" "lsp"
   4444                   "mako" "mason" "mojolicious"
   4445                   "perl"
   4446                   "smarty" "template-toolkit" "web2py" "xoops" "svelte"))
   4447     (save-excursion
   4448       (when delim-open
   4449         (goto-char reg-beg)
   4450         (looking-at delim-open)
   4451         (setq delim-open (match-string-no-properties 0)))
   4452       (when delim-close
   4453         (goto-char reg-end)
   4454         (looking-back delim-close reg-beg t)
   4455         (setq delim-close (match-string-no-properties 0)))
   4456       ))
   4457   (when delim-open
   4458     (put-text-property reg-beg (+ reg-beg (length delim-open))
   4459                        'block-token 'delimiter-beg))
   4460   (when delim-close
   4461     (put-text-property (- reg-end (length delim-close)) reg-end
   4462                        'block-token 'delimiter-end))
   4463   )
   4464 
   4465 (defun web-mode-block-foreach (reg-beg reg-end func)
   4466   (let ((i 0) (continue t) (block-beg reg-beg) (block-end nil))
   4467     (while continue
   4468       (setq block-end nil)
   4469       (unless (get-text-property block-beg 'block-beg)
   4470         (setq block-beg (web-mode-block-next-position block-beg)))
   4471       (when (and block-beg (< block-beg reg-end))
   4472         (setq block-end (web-mode-block-end-position block-beg)))
   4473       (cond
   4474         ((> (setq i (1+ i)) 2000)
   4475          (message "process-blocks ** warning (%S) **" (point))
   4476          (setq continue nil))
   4477         ((or (null block-end) (> block-end reg-end))
   4478          (setq continue nil))
   4479         (t
   4480          (setq block-end (1+ block-end))
   4481          (funcall func block-beg block-end)
   4482          (setq block-beg block-end)
   4483          ) ;t
   4484         ) ;cond
   4485       ) ;while
   4486     ))
   4487 
   4488 (defun web-mode-block-scan (block-beg block-end)
   4489   (let (sub1 sub2 sub3 regexp token-type)
   4490 
   4491     ;;(message "block-beg=%S block-end=%S" block-beg block-end)
   4492     ;;(remove-text-properties block-beg block-end web-mode-scan-properties)
   4493 
   4494     (goto-char block-beg)
   4495 
   4496     (cond
   4497       ((>= (point-max) (+ block-beg 3))
   4498        (setq sub3 (buffer-substring-no-properties block-beg (+ block-beg 3))
   4499              sub2 (buffer-substring-no-properties block-beg (+ block-beg 2))
   4500              sub1 (buffer-substring-no-properties block-beg (+ block-beg 1)))
   4501        )
   4502       ((>= (point-max) (+ block-beg 2))
   4503        (setq sub3 (buffer-substring-no-properties block-beg (+ block-beg 2))
   4504              sub2 (buffer-substring-no-properties block-beg (+ block-beg 2))
   4505              sub1 (buffer-substring-no-properties block-beg (+ block-beg 1)))
   4506        )
   4507       (t
   4508        (setq sub1 (buffer-substring-no-properties block-beg (+ block-beg 1)))
   4509        (setq sub2 sub1
   4510              sub3 sub1)
   4511        )
   4512       )
   4513 
   4514     (cond
   4515 
   4516       ((member web-mode-engine '("php" "lsp" "python" "web2py" "mason"))
   4517        (setq regexp web-mode-engine-token-regexp))
   4518 
   4519       ((string= web-mode-engine "mako")
   4520        (cond
   4521          ((string= sub2 "##")
   4522           (setq token-type 'comment)
   4523           )
   4524          (t
   4525           (setq regexp web-mode-engine-token-regexp))
   4526          )
   4527        ) ;mako
   4528 
   4529       ((string= web-mode-engine "django")
   4530        (cond
   4531          ((member sub2 '("{{" "{%"))
   4532           (setq regexp "\"\\|'"))
   4533          ((string= sub2 "{#")
   4534           (setq token-type 'comment))
   4535          )
   4536        ) ;django
   4537 
   4538       ((string= web-mode-engine "ctemplate")
   4539        (cond
   4540          ((string= sub3 "{{!")
   4541           (setq token-type 'comment))
   4542          ((member sub2 '("{{"))
   4543           )
   4544          )
   4545        ) ;ctemplate
   4546 
   4547       ((string= web-mode-engine "antlers")
   4548        (cond
   4549          ((string= sub3 "{{#")
   4550           (setq token-type 'comment))
   4551          ((member sub2 '("{{"))
   4552           )
   4553          )
   4554        ) ;antlers
   4555 
   4556       ((string= web-mode-engine "astro")
   4557        (setq regexp "\"\\|'")
   4558        ) ;astro
   4559 
   4560       ((string= web-mode-engine "go")
   4561        (cond
   4562          ((string= sub3 "{{/")
   4563           (setq token-type 'comment))
   4564          ((string= sub2 "{{")
   4565           (setq regexp "\"\\|'"))
   4566          )
   4567        ) ;go
   4568 
   4569       ((string= web-mode-engine "hero")
   4570        (cond
   4571          ((string= sub3 "<%#")
   4572           (setq token-type 'comment))
   4573          (t
   4574           (setq regexp "\"\\|'"))
   4575          )
   4576        ) ;hero
   4577 
   4578       ((string= web-mode-engine "razor")
   4579        (cond
   4580          ((string= sub2 "@*")
   4581           (setq token-type 'comment))
   4582          (t
   4583           (setq regexp "//\\|@\\*\\|\"\\|'"))
   4584          )
   4585        ) ;razor
   4586 
   4587       ((string= web-mode-engine "blade")
   4588        (cond
   4589          ((string= sub3 "{{-")
   4590           (setq token-type 'comment))
   4591          (t
   4592           (setq regexp "\"\\|'"))
   4593          )
   4594        ) ;blade
   4595 
   4596       ((string= web-mode-engine "cl-emb")
   4597        (cond
   4598          ((string= sub3 "<%#")
   4599           (setq token-type 'comment))
   4600          (t
   4601           (setq regexp "\"\\|'"))
   4602          )
   4603        ) ;cl-emb
   4604 
   4605       ((string= web-mode-engine "artanis")
   4606        (cond
   4607          ((string= sub3 "<%;")
   4608           (setq token-type 'comment))
   4609          ((string= sub3 "<%#|")
   4610           (setq token-type 'comment))
   4611          (t
   4612           (setq regexp "\""))
   4613          )
   4614        ) ;artanis
   4615 
   4616       ((string= web-mode-engine "elixir")
   4617        (cond
   4618          ((string= sub3 "<%#")
   4619           (setq token-type 'comment))
   4620          (t
   4621           (setq regexp "\"\\|'"))
   4622          )
   4623        ) ;elixir
   4624 
   4625       ((string= web-mode-engine "mojolicious")
   4626        (cond
   4627          ((or (string= sub2 "%#") (string= sub3 "<%#"))
   4628           (setq token-type 'comment))
   4629          (t
   4630           (setq regexp "\"\\|'"))
   4631          )
   4632        ) ;mojolicious
   4633 
   4634       ((string= web-mode-engine "velocity")
   4635        (cond
   4636          ((member sub2 '("##" "#*"))
   4637           (setq token-type 'comment))
   4638          ((member sub1 '("$" "#"))
   4639           (setq regexp "\"\\|'"))
   4640          )
   4641        ) ;velocity
   4642 
   4643       ((string= web-mode-engine "jsp")
   4644        (cond
   4645          ((string= sub3 "<%-")
   4646           (setq token-type 'comment))
   4647          ((string= sub3 "<%@")
   4648           (setq regexp "/\\*"))
   4649          ((member sub2 '("${" "#{"))
   4650           (setq regexp "\"\\|'"))
   4651          ((string= sub2 "<%")
   4652           (setq regexp "//\\|/\\*\\|\"\\|'"))
   4653          )
   4654        ) ;jsp
   4655 
   4656       ((string= web-mode-engine "clip")
   4657        (setq regexp nil)
   4658        ) ;clip
   4659 
   4660       ((string= web-mode-engine "perl")
   4661        (setq regexp nil)
   4662        ) ;perl
   4663 
   4664       ((and (string= web-mode-engine "asp")
   4665             (string= sub2 "<%"))
   4666        (setq regexp "//\\|/\\*\\|\"\\|'")
   4667        ) ;asp
   4668 
   4669       ((string= web-mode-engine "aspx")
   4670        (cond
   4671          ((string= sub3 "<%-")
   4672           (setq token-type 'comment))
   4673          ((string= sub3 "<%@")
   4674           (setq regexp "/\\*"))
   4675          ((string= sub3 "<%$")
   4676           (setq regexp "\"\\|'"))
   4677          (t
   4678           (setq regexp "//\\|/\\*\\|\"\\|'"))
   4679          )
   4680        ) ;aspx
   4681 
   4682       ((string= web-mode-engine "freemarker")
   4683        (cond
   4684          ((member sub3 '("<#-" "[#-"))
   4685           (setq token-type 'comment))
   4686          ((member sub2 '("${" "#{"))
   4687           (setq regexp "\"\\|'"))
   4688          ((or (member sub2 '("<@" "[@" "<#" "[#"))
   4689               (member sub3 '("</@" "[/@" "</#" "[/#")))
   4690           (setq regexp "\"\\|'"))
   4691          )
   4692        ) ;freemarker
   4693 
   4694       ((member web-mode-engine '("ejs" "erb"))
   4695        (cond
   4696          ((string= sub3 "<%#")
   4697           (setq token-type 'comment))
   4698          (t
   4699           (setq regexp web-mode-engine-token-regexp))
   4700          )
   4701        ) ;erb
   4702 
   4703       ((string= web-mode-engine "template-toolkit")
   4704        (cond
   4705          ((member sub3 '("[%#" "%%#"))
   4706           (setq token-type 'comment))
   4707          (t
   4708           (setq regexp "#\\|\"\\|'"))
   4709          )
   4710        ) ;template-toolkit
   4711 
   4712       ((string= web-mode-engine "underscore")
   4713        (setq regexp "/\\*\\|\"\\|'")
   4714        ) ;underscore
   4715 
   4716       ((string= web-mode-engine "angular")
   4717        (setq regexp "#\\|\"\\|'")) ;angular
   4718 
   4719       ((string= web-mode-engine "vue")
   4720        ) ;vue
   4721 
   4722       ((string= web-mode-engine "smarty")
   4723        (cond
   4724          ((string= sub2 "{*")
   4725           (setq token-type 'comment))
   4726          (t
   4727           (setq regexp "\"\\|'")))
   4728        ) ;smarty
   4729 
   4730       ((string= web-mode-engine "xoops")
   4731        (cond
   4732          ((string= sub3 "<{*")
   4733           (setq token-type 'comment))
   4734          (t
   4735           (setq regexp "\"\\|'")))
   4736        ) ;xoops
   4737 
   4738       ((string= web-mode-engine "spip")
   4739        (if (string= (buffer-substring-no-properties
   4740                      block-beg (+ block-beg 7))
   4741                     "[(#REM)")
   4742            (setq token-type 'comment
   4743                  regexp "\\]")))
   4744 
   4745       ((string= web-mode-engine "dust")
   4746        (cond
   4747          ((string= sub2 "{!")
   4748           (setq token-type 'comment))
   4749          (t
   4750           (setq regexp "\"\\|'"))
   4751          )
   4752        ) ;dust
   4753 
   4754       ((string= web-mode-engine "expressionengine")
   4755        (cond
   4756          ((string= sub2 "{!")
   4757           (setq token-type 'comment))
   4758          (t
   4759           (setq regexp "\"\\|'")))
   4760        ) ;expressionengine
   4761 
   4762       ((string= web-mode-engine "closure")
   4763        (cond
   4764          ((member sub2 '("/*" "//"))
   4765           (setq token-type 'comment))
   4766          (t
   4767           (setq regexp "\"\\|'"))
   4768          )
   4769        ) ;closure
   4770 
   4771       ((string= web-mode-engine "svelte")
   4772        ) ;svelte
   4773 
   4774       ) ;cond
   4775 
   4776     (cond
   4777       (token-type
   4778        (put-text-property block-beg block-end 'block-token token-type))
   4779       ((and regexp
   4780             (> (- block-end block-beg) 6))
   4781        (web-mode-block-tokenize
   4782         (web-mode-block-code-beginning-position block-beg)
   4783         (web-mode-block-code-end-position block-beg)
   4784         regexp)
   4785        )
   4786       ) ;cond
   4787 
   4788     ))
   4789 
   4790 (defun web-mode-block-tokenize (reg-beg reg-end &optional regexp)
   4791   (unless regexp (setq regexp web-mode-engine-token-regexp))
   4792   ;;(message "tokenize: reg-beg(%S) reg-end(%S) regexp(%S)" reg-beg reg-end regexp)
   4793   ;;(message "tokenize: reg-beg(%S) reg-end(%S) command(%S)" reg-beg reg-end this-command)
   4794   ;;(message "%S>%S : %S" reg-beg reg-end (buffer-substring-no-properties reg-beg reg-end))
   4795   (save-excursion
   4796     (let ((pos reg-beg) beg char match continue token-type token-end)
   4797 
   4798       (remove-list-of-text-properties reg-beg reg-end '(block-token))
   4799 
   4800       ;; TODO : vérifier la cohérence
   4801       (put-text-property reg-beg reg-end 'block-side t)
   4802 
   4803       (goto-char reg-beg)
   4804 
   4805       (when (> (point) reg-end)
   4806         (message "block-tokenize ** reg-beg(%S) > reg-end(%S) **" reg-beg reg-end))
   4807 
   4808       (while (and (< (point) reg-end) (re-search-forward regexp reg-end t))
   4809         (setq beg (match-beginning 0)
   4810               match (match-string 0)
   4811               continue t
   4812               token-type 'comment
   4813               token-end (if (< reg-end (line-end-position)) reg-end (line-end-position))
   4814               char (aref match 0))
   4815         (cond
   4816 
   4817           ((and (string= web-mode-engine "asp") (string= match "'"))
   4818            (goto-char token-end))
   4819 
   4820           ((and (string= web-mode-engine "razor") (eq char ?\'))
   4821            (cond
   4822              ((looking-at-p "\\(.\\|[\\][bfntr]\\|[\\]u....\\)'")
   4823               (search-forward "'" reg-end t)
   4824               (setq token-type 'string)
   4825               )
   4826              (t
   4827               (re-search-forward "[[:alnum:]_-]+")
   4828               (setq token-type 'symbol)
   4829               )))
   4830 
   4831           ((eq char ?\')
   4832            (setq token-type 'string)
   4833            (while (and continue (search-forward "'" reg-end t))
   4834              (setq continue (web-mode-string-continue-p reg-beg))
   4835              ))
   4836 
   4837           ((eq char ?\")
   4838            (setq token-type 'string)
   4839            (while (and continue (search-forward "\"" reg-end t))
   4840              (setq continue (web-mode-string-continue-p reg-beg))
   4841              ))
   4842 
   4843           ((string= match "//")
   4844            (goto-char token-end))
   4845 
   4846           ((eq char ?\;)
   4847            (goto-char token-end))
   4848 
   4849           ((string= match "#|")
   4850            (unless (search-forward "|#" reg-end t)
   4851              (goto-char token-end)))
   4852 
   4853           ((eq char ?\#)
   4854            (goto-char token-end))
   4855 
   4856           ((string= match "/*")
   4857            (unless (search-forward "*/" reg-end t)
   4858              (goto-char token-end))
   4859            )
   4860 
   4861           ((string= match "@*")
   4862            (unless (search-forward "*@" reg-end t)
   4863              (goto-char token-end)))
   4864 
   4865           ((eq char ?\<)
   4866            (setq token-type 'string)
   4867            (re-search-forward (concat "^[ ]*" (match-string 1)) reg-end t))
   4868 
   4869           (t
   4870            (message "block-tokenize ** token end (%S) **" beg)
   4871            (setq token-type nil))
   4872 
   4873           ) ;cond
   4874 
   4875         (put-text-property beg (point) 'block-token token-type)
   4876 
   4877         (when (eq token-type 'comment)
   4878           (put-text-property beg (1+ beg) 'syntax-table (string-to-syntax "<"))
   4879           (if (or (< (point) (line-end-position)) (= (point) (point-max)))
   4880               (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax ">")) ;#445 #480
   4881               (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax ">")) ;#377
   4882               )
   4883           )
   4884 
   4885         ) ;while
   4886 
   4887       (web-mode-block-controls-unset pos)
   4888 
   4889       )))
   4890 
   4891 (defun web-mode-set-php-controls (reg-beg reg-end)
   4892   (goto-char reg-beg)
   4893   (let (match controls
   4894               (continue t)
   4895               (regexp "endif\\|endforeach\\|endfor\\|endwhile\\|elseif\\|else\\|if\\|foreach\\|for\\|while"))
   4896     (while continue
   4897       (if (not (web-mode-block-rsf regexp reg-end))
   4898           (setq continue nil)
   4899           (setq match (match-string-no-properties 0))
   4900           ;;        (message "%S %S" match (point))
   4901           (cond
   4902             ((and (member match '("else" "elseif"))
   4903                   (looking-at-p "[ ]*[:(]"))
   4904              (setq controls (append controls (list (cons 'inside "if"))))
   4905              )
   4906             ((and (>= (length match) 3)
   4907                   (string= (substring match 0 3) "end"))
   4908              (setq controls (append controls (list (cons 'close (substring match 3)))))
   4909              )
   4910             ((and (progn (skip-chars-forward "[ ]") t)
   4911                   (eq (char-after) ?\()
   4912                   (web-mode-closing-paren reg-end)
   4913                   ;;(progn (message "ixi%S" (point)))
   4914                   (looking-at-p ")[ ]*:"))
   4915              (setq controls (append controls (list (cons 'open match))))
   4916              )
   4917             ) ;cond
   4918           ) ;if
   4919       ) ;while
   4920     ;;(message "%S-%S %S" reg-beg reg-end controls)
   4921     (when (and controls (> (length controls) 1))
   4922       (setq controls (web-mode-block-controls-reduce controls)))
   4923     controls))
   4924 
   4925 (defun web-mode-block-controls-reduce (controls)
   4926   (when (and (eq (car (car controls)) 'open)
   4927              (member (cons 'close (cdr (car controls))) controls))
   4928     (setq controls nil))
   4929   controls)
   4930 
   4931 (defun web-mode-block-controls-unset (pos)
   4932   (cond
   4933     ((null (get-text-property pos 'block-side))
   4934      (message "block-controls-unset ** invalid value (%S) **" pos))
   4935     ((or (get-text-property pos 'block-beg)
   4936          (setq pos (web-mode-block-beginning-position pos)))
   4937      (put-text-property pos (1+ pos) 'block-controls 0))
   4938     (t
   4939      (message "block-controls-unset ** failure (%S) **" (point)))
   4940     ))
   4941 
   4942 (defun web-mode-block-controls-get (pos)
   4943   (web-mode-with-silent-modifications
   4944    (let ((controls nil))
   4945      (cond
   4946        ((null (get-text-property pos 'block-side))
   4947         (message "block-controls-get ** invalid value (%S) **" pos))
   4948        ((or (get-text-property pos 'block-beg)
   4949             (setq pos (web-mode-block-beginning-position pos)))
   4950         (setq controls (get-text-property pos 'block-controls))
   4951         (when (integerp controls)
   4952           (web-mode-block-controls-set pos (web-mode-block-end-position pos))
   4953           (setq controls (get-text-property pos 'block-controls))
   4954           )
   4955         )
   4956        (t
   4957         (message "block-controls-get ** failure (%S) **" (point)))
   4958        ) ;cond
   4959      controls)))
   4960 
   4961 (defun web-mode-block-controls-set (reg-beg reg-end)
   4962   (save-excursion
   4963     (goto-char reg-beg)
   4964     (let (controls pos type control)
   4965 
   4966       (cond
   4967 
   4968         ((null web-mode-engine)
   4969          (message "block-controls-set ** unknown engine (%S) **" web-mode-engine)
   4970          )
   4971 
   4972         ((string= web-mode-engine "php")
   4973          (setq controls (web-mode-set-php-controls reg-beg reg-end))
   4974          (when (web-mode-block-starts-with "}" reg-beg)
   4975            (setq controls (append controls (list (cons 'close "{")))))
   4976          (when (web-mode-block-ends-with (cons "{" "}") reg-beg)
   4977            (setq controls (append controls (list (cons 'open "{")))))
   4978          ) ;php
   4979 
   4980         ((string= web-mode-engine "ejs")
   4981          (cond
   4982            ((web-mode-block-ends-with "}[ ]*else[ ]*{" reg-beg)
   4983             (setq controls (append controls (list (cons 'inside "{")))))
   4984            ((web-mode-block-starts-with "}" reg-beg)
   4985             (setq controls (append controls (list (cons 'close "{")))))
   4986            ((web-mode-block-ends-with "{" reg-beg)
   4987             (setq controls (append controls (list (cons 'open "{")))))
   4988            )
   4989          ) ;ejs
   4990 
   4991         ((string= web-mode-engine "erb")
   4992          (cond
   4993            ((web-mode-block-starts-with "else\\|elsif\\|when" reg-beg)
   4994             (setq controls (append controls (list (cons 'inside "ctrl")))))
   4995            ((web-mode-block-starts-with "end" reg-beg)
   4996             (setq controls (append controls (list (cons 'close "ctrl")))))
   4997            ((web-mode-block-ends-with " do\\( |.*|\\)?" reg-beg)
   4998             (setq controls (append controls (list (cons 'open "ctrl")))))
   4999            ((and (web-mode-block-starts-with "\\(for\\|if\\|unless\\|case\\)\\_>" reg-beg)
   5000                  (not (web-mode-block-ends-with "end" reg-end)))
   5001             (setq controls (append controls (list (cons 'open "ctrl")))))
   5002            )
   5003          ) ;erb
   5004 
   5005         ((string= web-mode-engine "django")
   5006          (cond
   5007            ((and (string= web-mode-minor-engine "jinja") ;#504
   5008                  (web-mode-block-starts-with "else\\_>" reg-beg))
   5009             (let ((continue t)
   5010                   (pos reg-beg)
   5011                   (ctrl nil))
   5012               (while continue
   5013                 (cond
   5014                   ((null (setq pos (web-mode-block-control-previous-position 'open pos)))
   5015                    (setq continue nil))
   5016                   ((member (setq ctrl (cdr (car (get-text-property pos 'block-controls)))) '("if" "ifequal" "ifnotequal" "for"))
   5017                    (setq continue nil)
   5018                    )
   5019                   ) ;cond
   5020                 )
   5021               (setq controls (append controls (list (cons 'inside (or ctrl "if")))))
   5022               )
   5023             )
   5024            ((web-mode-block-starts-with "form_start[ ]*(" reg-beg)
   5025             (setq controls (append controls (list (cons 'open "form_start")))))
   5026            ((web-mode-block-starts-with "form_end[ ]*(" reg-beg)
   5027             (setq controls (append controls (list (cons 'close "form_start")))))
   5028            ((not (eq (char-after (1+ reg-beg)) ?\%))
   5029             )
   5030            ((web-mode-block-starts-with "\\(else\\|els?if\\)" reg-beg)
   5031             (let ((continue t)
   5032                   (pos reg-beg)
   5033                   (ctrl nil))
   5034               (while continue
   5035                 (cond
   5036                   ((null (setq pos (web-mode-block-control-previous-position 'open pos)))
   5037                    (setq continue nil))
   5038                   ((member (setq ctrl (cdr (car (get-text-property pos 'block-controls)))) '("if" "ifequal" "ifnotequal"))
   5039                    (setq continue nil)
   5040                    )
   5041                   ) ;cond
   5042                 ) ;while
   5043               (setq controls (append controls (list (cons 'inside (or ctrl "if")))))
   5044               ) ;let
   5045             ) ;case else
   5046            ((web-mode-block-starts-with "\\(empty\\)" reg-beg)
   5047             (setq controls (append controls (list (cons 'inside "for")))))
   5048            ((web-mode-block-starts-with "end\\([[:alpha:]]+\\)" reg-beg)
   5049             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5050            ((web-mode-block-starts-with "set [[:alpha:]]+[ ]*%}" reg-beg)
   5051             (setq controls (append controls (list (cons 'open "set")))))
   5052            ((web-mode-block-starts-with (concat web-mode-django-control-blocks-regexp "[ %]") reg-beg)
   5053             (let (control)
   5054               (setq control (match-string-no-properties 1))
   5055               ;;(message "%S %S %S" control (concat "end" control) web-mode-django-control-blocks)
   5056               (when (member (concat "end" control) web-mode-django-control-blocks)
   5057                 (setq controls (append controls (list (cons 'open control))))
   5058                 ) ;when
   5059               ) ;let
   5060             ) ;case
   5061            ) ;cond
   5062          ) ;django
   5063 
   5064         ((string= web-mode-engine "smarty")
   5065          (cond
   5066            ((and (eq (char-after (1+ reg-beg)) ?\/)
   5067                  (web-mode-block-starts-with "\\([[:alpha:]]+\\)" reg-beg))
   5068             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5069            ((web-mode-block-starts-with "\\(else\\|elseif\\)" reg-beg)
   5070             (setq controls (append controls (list (cons 'inside "if")))))
   5071            ((web-mode-block-starts-with "\\(block\\|foreach\\|for\\|if\\|section\\|while\\)")
   5072             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5073            )
   5074          ) ;smarty
   5075 
   5076         ((string= web-mode-engine "expressionengine")
   5077          (cond
   5078            ((and (eq (char-after (1+ reg-beg)) ?\/)
   5079                  (web-mode-block-starts-with "\\(if\\)" reg-beg))
   5080             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5081            ((web-mode-block-starts-with "\\(if:else\\|if:ifelse\\)" reg-beg)
   5082             (setq controls (append controls (list (cons 'inside "if")))))
   5083            ((web-mode-block-starts-with "\\(if\\)")
   5084             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5085            )
   5086          ) ;expressionengine
   5087 
   5088         ((string= web-mode-engine "xoops")
   5089          (cond
   5090            ((and (eq (char-after (+ reg-beg 2)) ?\/)
   5091                  (web-mode-block-starts-with "\\([[:alpha:]]+\\)" reg-beg))
   5092             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5093            ((web-mode-block-starts-with "\\(else\\|elseif\\)" reg-beg)
   5094             (setq controls (append controls (list (cons 'inside "if")))))
   5095            ((web-mode-block-starts-with "\\(block\\|foreach\\|for\\|if\\|section\\|while\\)")
   5096             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5097            )
   5098          ) ;xoops
   5099 
   5100         ((string= web-mode-engine "web2py")
   5101          (cond
   5102            ((web-mode-block-starts-with "def" reg-beg)
   5103             (setq controls (append controls (list (cons 'open "def")))))
   5104            ((web-mode-block-starts-with "return" reg-beg)
   5105             (setq controls (append controls (list (cons 'close "def")))))
   5106            ((web-mode-block-starts-with "block" reg-beg)
   5107             (setq controls (append controls (list (cons 'open "block")))))
   5108            ((web-mode-block-starts-with "end" reg-beg)
   5109             (setq controls (append controls (list (cons 'close "block")))))
   5110            ((web-mode-block-starts-with "pass" reg-beg)
   5111             (setq controls (append controls (list (cons 'close "ctrl")))))
   5112            ((web-mode-block-starts-with "\\(except\\|finally\\|els\\)" reg-beg)
   5113             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5114            ((web-mode-block-starts-with "\\(if\\|for\\|try\\|while\\)")
   5115             (setq controls (append controls (list (cons 'open "ctrl")))))
   5116            )
   5117          ) ;web2py
   5118 
   5119         ((string= web-mode-engine "dust")
   5120          (cond
   5121            ((eq (char-after (1- reg-end)) ?\/)
   5122             )
   5123            ((eq (char-after (1+ reg-beg)) ?\:)
   5124             (setq pos (web-mode-block-control-previous-position 'open reg-beg))
   5125             (when pos
   5126               (setq controls (append controls
   5127                                      (list
   5128                                       (cons 'inside
   5129                                             (cdr (car (web-mode-block-controls-get pos))))))))
   5130             )
   5131            ((looking-at "{/\\([[:alpha:].]+\\)")
   5132             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5133            ((looking-at "{[#?@><+^]\\([[:alpha:].]+\\)")
   5134             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5135            )
   5136          ) ;dust
   5137 
   5138         ((string= web-mode-engine "anki")
   5139          (cond
   5140            ((looking-at "{{[#^]\\([[:alpha:].]+\\)")
   5141             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5142            ((looking-at "{{/\\([[:alpha:].]+\\)")
   5143             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5144            )
   5145          ) ;anki
   5146 
   5147         ((member web-mode-engine '("mojolicious"))
   5148          (cond
   5149            ((web-mode-block-ends-with "begin" reg-beg)
   5150             (setq controls (append controls (list (cons 'open "begin")))))
   5151            ((web-mode-block-starts-with "end" reg-beg)
   5152             (setq controls (append controls (list (cons 'close "begin")))))
   5153            ((web-mode-block-starts-with "}[ ]*else[ ]*{" reg-beg)
   5154             (setq controls (append controls (list (cons 'inside "{")))))
   5155            ((web-mode-block-starts-with "}" reg-beg)
   5156             (setq controls (append controls (list (cons 'close "{")))))
   5157            ((web-mode-block-ends-with "{" reg-beg)
   5158             (setq controls (append controls (list (cons 'open "{")))))
   5159            )
   5160          ) ;mojolicious
   5161 
   5162         ((member web-mode-engine '("aspx" "underscore"))
   5163          (cond
   5164            ((and (web-mode-block-starts-with "}" reg-beg)
   5165                  (web-mode-block-ends-with "{" reg-beg))
   5166             (setq controls (append controls (list (cons 'inside "{")))))
   5167            ((web-mode-block-starts-with "}" reg-beg)
   5168             (setq controls (append controls (list (cons 'close "{")))))
   5169            ((web-mode-block-ends-with "{" reg-beg)
   5170             (setq controls (append controls (list (cons 'open "{")))))
   5171            )
   5172          ) ;aspx underscore
   5173 
   5174         ((member web-mode-engine '("jsp" "asp" "clip" "perl"))
   5175          (cond
   5176            ((eq (char-after (1- reg-end)) ?\/)
   5177             )
   5178            ((looking-at "<TMPL_ELSE")
   5179             (setq controls (append controls (list (cons 'inside "TMPL_IF")))))
   5180            ((looking-at "</?\\([[:alpha:]]+\\(?:[:.][[:alpha:]]+\\)\\|[[:alpha:]]+Template\\|TMPL_[[:alpha:]]+\\)")
   5181             (setq control (match-string-no-properties 1)
   5182                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5183             (when (not (member control '("h:inputtext" "jsp:usebean" "jsp:forward" "struts:property")))
   5184               (setq controls (append controls (list (cons type control)))))
   5185             )
   5186            (t
   5187             (when (web-mode-block-starts-with "}" reg-beg)
   5188               (setq controls (append controls (list (cons 'close "{")))))
   5189             (when (web-mode-block-ends-with "{" reg-beg)
   5190               (setq controls (append controls (list (cons 'open "{")))))
   5191             )
   5192            )
   5193          ) ;jsp asp
   5194 
   5195         ((string= web-mode-engine "mako")
   5196          (cond
   5197            ((looking-at "</?%\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)")
   5198             (cond
   5199               ((eq (char-after (- (web-mode-block-end-position reg-beg) 1)) ?\/)
   5200                )
   5201               (t
   5202                (setq control (match-string-no-properties 1)
   5203                      type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5204                (setq controls (append controls (list (cons type control)))))
   5205               )
   5206             )
   5207            ((web-mode-block-starts-with "\\(else\\|elif\\)" reg-beg)
   5208             (setq controls (append controls (list (cons 'inside "if")))))
   5209            ((web-mode-block-starts-with "end\\(if\\|for\\)" reg-beg)
   5210             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5211            ((and (web-mode-block-starts-with "if\\|for" reg-beg)
   5212                  (web-mode-block-ends-with ":" reg-beg))
   5213             (setq controls (append controls (list (cons 'open (match-string-no-properties 0))))))
   5214            )
   5215          ) ;mako
   5216 
   5217         ((string= web-mode-engine "mason")
   5218          (cond
   5219            ((looking-at "</?%\\(after\\|around\\|augment\\|before\\|def\\|filter\\|method\\|override\\)")
   5220             (setq control (match-string-no-properties 1)
   5221                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5222             (setq controls (append controls (list (cons type control))))
   5223             )
   5224            )
   5225          ) ;mason
   5226 
   5227         ((string= web-mode-engine "ctemplate")
   5228          (cond
   5229            ((looking-at-p "{{else") ;#721
   5230             (let ((continue t)
   5231                   (pos reg-beg)
   5232                   (ctrl nil))
   5233               (while continue
   5234                 (cond
   5235                   ((null (setq pos (web-mode-block-control-previous-position 'open pos)))
   5236                    (setq continue nil))
   5237                   ((member (setq ctrl (cdr (car (get-text-property pos 'block-controls)))) '("if" "each"))
   5238                    (setq continue nil)
   5239                    )
   5240                   ) ;cond
   5241                 ) ;while
   5242               (setq controls (append controls (list (cons 'inside (or ctrl "if")))))
   5243               )
   5244             )
   5245 
   5246            ((looking-at "{{[#^/][ ]*\\([[:alpha:]_.-]+\\)")
   5247             (setq control (match-string-no-properties 1)
   5248                   type (if (eq (aref (match-string-no-properties 0) 2) ?\/) 'close 'open))
   5249             (setq controls (append controls (list (cons type control))))
   5250             )
   5251            )
   5252          ) ;ctemplate
   5253 
   5254         ((string= web-mode-engine "antlers")
   5255          (cond
   5256            ((web-mode-block-starts-with "\\(else\\|elseif\\)" reg-beg)
   5257             (setq controls (append controls (list (cons 'inside "if")))))
   5258            ((looking-at  "{{[ ]*/?\\(if\\|unless\\)")
   5259             (setq control (match-string-no-properties 1)
   5260                   type (if (eq (aref (match-string-no-properties 0) 3) ?\/) 'close 'open))
   5261             (setq controls (append controls (list (cons type control))))
   5262             )
   5263            )
   5264          ) ;antlers
   5265 
   5266         ((string= web-mode-engine "blade")
   5267          (cond
   5268            ((not (eq (char-after) ?\@))
   5269             )
   5270            ((web-mode-block-starts-with
   5271              "section\(\s*\\(['\"]\\).*\\1\s*,\s*\\(['\"]\\).*\\2\s*\)" reg-beg)
   5272             )
   5273            ((web-mode-block-starts-with "case\\|break" reg-beg)
   5274             (setq type (if (eq (aref (match-string-no-properties 0) 0) ?b) 'close 'open))
   5275             (setq controls (append controls (list (cons type "case"))))
   5276             )
   5277            ((web-mode-block-starts-with
   5278              (concat "\\(?:end\\)?\\(" web-mode-blade-control-blocks-regexp "\\)")
   5279              reg-beg)
   5280             (setq control (match-string-no-properties 1)
   5281                   type (if (eq (aref (match-string-no-properties 0) 0) ?e) 'close 'open))
   5282             (setq controls (append controls (list (cons type control))))
   5283             )
   5284            ((web-mode-block-starts-with "stop\\|show\\|overwrite" reg-beg)
   5285             (setq controls (append controls (list (cons 'close "section")))))
   5286            ((web-mode-block-starts-with "else\\|elseif" reg-beg)
   5287             (setq controls (append controls (list (cons 'inside "if")))))
   5288            ((web-mode-block-starts-with "empty" reg-beg)
   5289             (setq controls (append controls (list (cons 'inside "forelse")))))
   5290            )
   5291          ) ;blade
   5292 
   5293         ((string= web-mode-engine "closure")
   5294          (cond
   5295            ((eq (char-after (1- reg-end)) ?\/)
   5296             )
   5297            ((looking-at "alias\\|namespace")
   5298             )
   5299            ((web-mode-block-starts-with "ifempty" reg-beg)
   5300             (setq controls (append controls (list (cons 'inside "foreach")))))
   5301            ((web-mode-block-starts-with "else\\|elseif" reg-beg)
   5302             (setq controls (append controls (list (cons 'inside "if")))))
   5303            ((web-mode-block-starts-with "case\\|default" reg-beg)
   5304             (setq controls (append controls (list (cons 'inside "switch")))))
   5305            ((looking-at
   5306              "{/?\\(call\\|deltemplate\\|for\\|foreach\\|if\\|let\\|literal\\|msg\\|param\\|switch\\|template\\)")
   5307             (setq control (match-string-no-properties 1)
   5308                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5309             (setq controls (append controls (list (cons type control))))
   5310             )
   5311            )
   5312          ) ;closure
   5313 
   5314         ((string= web-mode-engine "go")
   5315          (cond
   5316            ((web-mode-block-starts-with "end\\_>" reg-beg)
   5317             (setq controls (append controls (list (cons 'close "ctrl")))))
   5318            ((web-mode-block-starts-with "else\\_>" reg-beg)
   5319             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5320            ((web-mode-block-starts-with "\\(range\\|with\\|if\\|define\\|block\\)\\_>" reg-beg)
   5321             (setq controls (append controls (list (cons 'open "ctrl")))))
   5322            )
   5323          ) ;go
   5324 
   5325         ((string= web-mode-engine "template-toolkit")
   5326          (cond
   5327            ((web-mode-block-starts-with "end" reg-beg)
   5328             (setq controls (append controls (list (cons 'close "ctrl")))))
   5329            ((web-mode-block-starts-with "els\\|catch\\|final" reg-beg)
   5330             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5331            ((web-mode-block-starts-with "filter\\|foreach\\|if\\|last\\|next\\|perl\\|rawperl\\|try\\|unless\\|while" reg-beg)
   5332             (setq controls (append controls (list (cons 'open "ctrl")))))
   5333            )
   5334          ) ;template-toolkit
   5335 
   5336         ((string= web-mode-engine "cl-emb")
   5337          (cond
   5338            ((web-mode-block-starts-with "@else" reg-beg)
   5339             (setq controls (append controls (list (cons 'inside "if")))))
   5340            ((web-mode-block-starts-with "@\\(?:end\\)?\\(if\\|unless\\|repeat\\|loop\\|with\\|genloop\\)" reg-beg)
   5341             (setq control (match-string-no-properties 1)
   5342                   type (if (eq (aref (match-string-no-properties 0) 1) ?e) 'close 'open))
   5343             (setq controls (append controls (list (cons type control)))))
   5344            )
   5345          ) ;cl-emb
   5346 
   5347         ((string= web-mode-engine "elixir")
   5348          (cond
   5349            ((web-mode-block-starts-with "end" reg-beg)
   5350             (setq controls (append controls (list (cons 'close "ctrl")))))
   5351            ((web-mode-block-starts-with "else" reg-beg)
   5352             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5353            ((web-mode-block-ends-with " do" reg-beg)
   5354             (setq controls (append controls (list (cons 'open "ctrl")))))
   5355            ((web-mode-block-ends-with " ->" reg-beg)
   5356             (setq controls (append controls (list (cons 'open "ctrl")))))
   5357            )
   5358          ) ;elixir
   5359 
   5360         ((string= web-mode-engine "velocity")
   5361          (cond
   5362            ((web-mode-block-starts-with "{?end" reg-beg)
   5363             (setq controls (append controls (list (cons 'close "ctrl")))))
   5364            ((web-mode-block-starts-with "{?els" reg-beg)
   5365             (setq controls (append controls (list (cons 'inside "ctrl")))))
   5366            ((web-mode-block-starts-with "{?\\(def\\|if\\|for\\|foreach\\|macro\\)" reg-beg)
   5367             ;;((web-mode-block-starts-with "{?\\(define\\|\\|if\\|for\\|foreach\\|macro\\)" reg-beg)
   5368             (setq controls (append controls (list (cons 'open "ctrl")))))
   5369            )
   5370          ) ;velocity
   5371 
   5372         ((string= web-mode-engine "freemarker")
   5373          (cond
   5374            ((looking-at "[<[]#\\(import\\|include\\|assign\\|return\\|local\\)")
   5375             )
   5376            ((eq (char-after (1- reg-end)) ?\/)
   5377             )
   5378            ((looking-at "[<[]#\\(break\\|case\\|default\\)")
   5379             (setq controls (append controls (list (cons 'inside "switch"))))
   5380             )
   5381            ((looking-at "[<[]#els")
   5382             (setq controls (append controls (list (cons 'inside "if"))))
   5383             )
   5384            ((looking-at "</?\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)")
   5385             (setq control (match-string-no-properties 1)
   5386                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5387             (setq controls (append controls (list (cons type control))))
   5388             )
   5389            ((looking-at "[<[]/?\\(@\\)")
   5390             (setq control (match-string-no-properties 1)
   5391                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5392             (setq controls (append controls (list (cons type control))))
   5393             )
   5394            ((looking-at "[<[]/?#\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)")
   5395             (setq control (match-string-no-properties 1)
   5396                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5397             (setq controls (append controls (list (cons type control))))
   5398             )
   5399            (t
   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             )
   5405            )
   5406          ) ;freemarker
   5407 
   5408         ((string= web-mode-engine "razor")
   5409          (when (web-mode-block-starts-with "}" reg-beg)
   5410            (setq controls (append controls (list (cons 'close "{")))))
   5411          (when (web-mode-block-ends-with "{" reg-beg)
   5412            (setq controls (append controls (list (cons 'open "{")))))
   5413          ) ;razor
   5414 
   5415         ((string= web-mode-engine "lsp")
   5416          (when (web-mode-block-starts-with ")" reg-beg)
   5417            (setq controls (append controls (list (cons 'close "(")))))
   5418          (when (web-mode-block-is-opened-sexp reg-beg reg-end)
   5419            (setq controls (append controls (list (cons 'open "(")))))
   5420          ) ;lsp
   5421 
   5422         ((string= web-mode-engine "hero")
   5423          (cond
   5424            ((web-mode-block-ends-with "}[ ]*else[ ]*{" reg-beg)
   5425             (setq controls (append controls (list (cons 'inside "{")))))
   5426            ((web-mode-block-starts-with "}" reg-beg)
   5427             (setq controls (append controls (list (cons 'close "{")))))
   5428            ((web-mode-block-ends-with "{" reg-beg)
   5429             (setq controls (append controls (list (cons 'open "{")))))
   5430            )
   5431          ) ;hero
   5432 
   5433         ((string= web-mode-engine "svelte")
   5434          (cond
   5435            ((eq (char-after (1- reg-end)) ?\/)
   5436             )
   5437            ((eq (char-after (1+ reg-beg)) ?\:)
   5438             (setq pos (web-mode-block-control-previous-position 'open reg-beg))
   5439             (when pos
   5440               (setq controls (append controls
   5441                                      (list
   5442                                       (cons 'inside
   5443                                             (cdr (car (web-mode-block-controls-get pos))))))))
   5444             )
   5445            ((looking-at "{/\\([[:alpha:].]+\\)")
   5446             (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5447            ((looking-at "{[#?><+^]\\([[:alpha:].]+\\)")
   5448             (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5449            )
   5450          ) ;svelte
   5451 
   5452         ) ;cond engine
   5453 
   5454       (put-text-property reg-beg (1+ reg-beg) 'block-controls controls)
   5455       ;;(message "(%S) controls=%S" reg-beg controls)
   5456 
   5457       )))
   5458 
   5459 (defun web-mode-block-is-opened-sexp (reg-beg reg-end)
   5460   (let ((n 0))
   5461     (save-excursion
   5462       (goto-char reg-beg)
   5463       (while (web-mode-block-rsf "[()]" reg-end)
   5464         (if (eq (char-before) ?\() (setq n (1+ n)) (setq n (1- n)))))
   5465     (> n 0)))
   5466 
   5467 ;;---- LEXER PARTS -------------------------------------------------------------
   5468 
   5469 (defun web-mode-scan-elements (reg-beg reg-end)
   5470   (save-excursion
   5471     (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)
   5472       ;;(message "scan-elements: reg-beg(%S) reg-end(%S)" reg-beg reg-end)
   5473       (goto-char reg-beg)
   5474 
   5475       (while (web-mode-dom-rsf regexp reg-end)
   5476 
   5477         ;;(message "%S: %S (%S %S)" (point) (match-string-no-properties 0) reg-beg reg-end)
   5478 
   5479         (setq flags 0
   5480               tname (downcase (match-string-no-properties 1))
   5481               char (aref tname 0)
   5482               tbeg (match-beginning 0)
   5483               tend nil
   5484               element-content-type nil
   5485               limit reg-end
   5486               part-beg nil
   5487               part-end nil
   5488               props nil
   5489               close-expr nil
   5490               part-close-tag nil)
   5491 
   5492         ;;(message "tname[%S] tbeg(%S) point(%S)" tname tbeg (point))
   5493 
   5494         (cond
   5495 
   5496           ((member tname '("/>" ">")) ;;jsx fragment #952
   5497            (setq tname "_fragment_"
   5498                  tend (point))
   5499            (if (eq char ?\/)
   5500                (setq props (list 'tag-name tname 'tag-type 'end)
   5501                      flags (logior flags 20)) ;; 16 + 4
   5502                (setq props (list 'tag-name tname 'tag-type 'start)
   5503                      flags (logior flags 16))
   5504                ) ;if
   5505            )
   5506 
   5507           ((not (member char '(?\! ?\?)))
   5508            (cond
   5509              ((string-match-p "-" tname)
   5510               (setq flags (logior flags 2)))
   5511              ;;((string-match-p ":" tname)
   5512              ;; (setq flags (logior flags 32)))
   5513              ((string-match-p "[._:]" tname)
   5514               (setq flags (logior flags 32)))
   5515              )
   5516            (cond
   5517              ((eq char ?\/)
   5518               (setq props (list 'tag-name (substring tname 1) 'tag-type 'end)
   5519                     flags (logior flags 4)
   5520                     limit (if (> reg-end (line-end-position)) (line-end-position) reg-end))
   5521               )
   5522              ((web-mode-element-is-void tname)
   5523               ;;(message "void: tag=%S" tname)
   5524               (setq props (list 'tag-name tname 'tag-type 'void)))
   5525              (t
   5526               (setq props (list 'tag-name tname 'tag-type 'start)))
   5527              ) ;cond
   5528            ) ; not <! <?
   5529           ((and (eq char ?\!) (eq (aref tname 1) ?\-))
   5530            (setq close-expr "-->"
   5531                  props '(tag-type comment)))
   5532           ((string= tname "?xml")
   5533            (setq ;;regexp web-mode-tag-regexp2
   5534             close-expr "?>"
   5535             props '(tag-type declaration)))
   5536           ((string= tname "![cdata[")
   5537            (setq close-expr "]]>"
   5538                  props '(tag-type cdata)))
   5539           ((string= tname "!doctype")
   5540            (setq ;;regexp web-mode-tag-regexp2
   5541             props '(tag-type doctype)))
   5542           ) ;cond - special tags
   5543 
   5544         (cond
   5545 
   5546           (tend
   5547            )
   5548 
   5549           ((and (null close-expr) (eq (char-after) ?\>))
   5550            (setq flags (logior flags 16)
   5551                  tend (1+ (point)))
   5552            ;;(message "end=%S" tend)
   5553            )
   5554 
   5555           ((and (null close-expr)
   5556                 (looking-at "[ ]\\(class\\|id\\|href\\|style\\)=\"[[:alnum:]_=:/?;#. -]*\">"))
   5557            (let ((beg (1+ (point)))
   5558                  (end (+ (point) (length (match-string-no-properties 0)))))
   5559              (setq flags (logior flags 17)
   5560                    tend end)
   5561              (put-text-property beg (1+ beg) 'tag-attr-beg 0)
   5562              (put-text-property beg (1- end) 'tag-attr t)
   5563              (put-text-property (- end 2) (1- end) 'tag-attr-end (length (match-string-no-properties 1)))
   5564              ) ;let
   5565            )
   5566 
   5567           ((null close-expr)
   5568            (setq flags (logior flags (web-mode-attr-skip reg-end)))
   5569            (when (> (logand flags 8) 0)
   5570              (setq props (plist-put props 'tag-type 'void)))
   5571            (setq tend (point)))
   5572 
   5573           ((web-mode-dom-sf close-expr limit t)
   5574            (setq tend (point)))
   5575 
   5576           (t
   5577            (setq tend (line-end-position)))
   5578 
   5579           ) ;cond
   5580 
   5581         (cond
   5582           ((string= tname "style")
   5583            (let (style)
   5584              (setq style (buffer-substring-no-properties tbeg tend)
   5585                    part-close-tag "</style>")
   5586              (cond
   5587                ((string-match-p " lang[ ]*=[ ]*[\"']stylus" style)
   5588                 (setq element-content-type "stylus"))
   5589                ((string-match-p " lang[ ]*=[ ]*[\"']sass" style)
   5590                 (setq element-content-type "sass"))
   5591                (t
   5592                 (setq element-content-type "css"))
   5593                ) ;cond
   5594              ) ;let
   5595            ) ;style
   5596           ((string= tname "script")
   5597            (let (script)
   5598              (setq script (buffer-substring-no-properties tbeg tend)
   5599                    part-close-tag "</script>")
   5600              (cond
   5601                ((string-match-p " type[ ]*=[ ]*[\"']text/\\(jsx\\|babel\\)" script)
   5602                 (setq element-content-type "jsx"))
   5603                ((string-match-p " type[ ]*=[ ]*[\"']text/\\(markdown\\|template\\)" script)
   5604                 (setq element-content-type "markdown"))
   5605                ((string-match-p " type[ ]*=[ ]*[\"']text/ruby" script)
   5606                 (setq element-content-type "ruby"))
   5607                ((seq-some (lambda (x)
   5608                             (string-match-p (concat "type[ ]*=[ ]*[\"']" x) script))
   5609                           web-mode-script-template-types)
   5610                 (setq element-content-type "html"
   5611                       part-close-tag nil))
   5612                ((string-match-p " type[ ]*=[ ]*[\"']application/\\(ld\\+json\\|json\\)" script)
   5613                 (setq element-content-type "json"))
   5614                ((string-match-p " lang[ ]*=[ ]*[\"']\\(typescript\\|ts\\)" script)
   5615                 (setq element-content-type "typescript"))
   5616                (t
   5617                 (setq element-content-type "javascript"))
   5618                ) ;cond
   5619              ) ;let
   5620            ) ;script
   5621           ((string= tname "i18n")
   5622            (setq element-content-type "javascript"
   5623                  part-close-tag "</i18n>"))
   5624           ((and (string= tname "template") (string-match-p " lang" (buffer-substring-no-properties tbeg tend)))
   5625            (let (template)
   5626              (setq template (buffer-substring-no-properties tbeg tend)
   5627                    part-close-tag "</template>")
   5628              (cond
   5629                ((string-match-p " lang[ ]*=[ ]*[\"']pug" template)
   5630                 (setq element-content-type "pug"))
   5631                (t
   5632                 (setq element-content-type "html"))
   5633                ) ;cond
   5634              ) ;let
   5635            ) ;style
   5636           ((and (string= web-mode-engine "archibus")
   5637                 (string= tname "sql"))
   5638            (setq element-content-type "sql"
   5639                  part-close-tag "</sql>"))
   5640           )
   5641 
   5642         (add-text-properties tbeg tend props)
   5643         (put-text-property tbeg (1+ tbeg) 'tag-beg flags)
   5644         (put-text-property (1- tend) tend 'tag-end t)
   5645 
   5646         (when (and part-close-tag
   5647                    (web-mode-dom-sf part-close-tag reg-end t)
   5648                    (setq part-beg tend)
   5649                    (setq part-end (match-beginning 0))
   5650                    (> part-end part-beg))
   5651           (put-text-property part-beg part-end 'part-side
   5652                              (intern element-content-type web-mode-obarray))
   5653           (setq tend part-end)
   5654           ) ;when
   5655 
   5656         (goto-char tend)
   5657 
   5658         ) ;while
   5659 
   5660       )))
   5661 
   5662 ;; FLAGS: tag
   5663 ;; (1)attrs (2)custom (4)slash-beg (8)slash-end (16)bracket-end (32)namespaced
   5664 
   5665 ;; FLAGS: attr
   5666 ;; (1)custom-attr (2)engine-attr (4)spread-attr[jsx] (8)code-value
   5667 ;; https://www.w3.org/TR/2012/WD-html-markup-20120329/syntax.html#attr-value-unquoted
   5668 
   5669 ;; STATES: attr
   5670 ;; (0)nil (1)space (2)name (3)space-before (4)equal (5)space-after
   5671 ;; (6)value-uq (7)value-sq (8)value-dq (9)value-bq : jsx attr={}
   5672 ;; (10)value-block
   5673 
   5674 (defun web-mode-attr-skip (limit)
   5675 
   5676   (let ((tag-flags 0) (attr-flags 0) (continue t) (attrs 0) (brace-depth 0)
   5677         (state 0) (equal-offset 0) (go-back nil)
   5678         (is-jsx (or (string= web-mode-content-type "jsx") (eq (get-text-property (point) 'part-type) 'jsx)))
   5679         attr name-beg name-end val-beg char pos mem step escaped spaced quoted)
   5680 
   5681     (while continue
   5682 
   5683       (setq pos (point)
   5684             char (char-after)
   5685             mem state
   5686             ;;spaced (eq char ?\s)
   5687             spaced (member char '(?\s ?\n))
   5688             step nil)
   5689 
   5690       (ignore mem step) ;; Only used in debug print
   5691       (when quoted (setq quoted (1+ quoted)))
   5692 
   5693       (cond
   5694 
   5695         ((>= pos limit)
   5696          (setq continue nil)
   5697          (setq go-back t)
   5698          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5699          )
   5700 
   5701         ((and (or (= state 0) (= state 1)) (get-text-property pos 'block-side))
   5702          )
   5703 
   5704         ((or (and (= state 8) (not (member char '(?\" ?\\))))
   5705              (and (= state 7) (not (member char '(?\' ?\\))))
   5706              (and (= state 9) (not (member char '(?} ?\\))))
   5707              )
   5708          (when (and (= state 9) (eq char ?\{))
   5709            (setq brace-depth (1+ brace-depth)))
   5710          )
   5711 
   5712         ((and (= state 9) (eq char ?\}) (> brace-depth 1))
   5713          (setq brace-depth (1- brace-depth)))
   5714 
   5715         ;; #1233
   5716         ;;((get-text-property pos 'block-side)
   5717         ;; (when (= state 2)
   5718         ;;   (setq name-end pos))
   5719         ;; )
   5720 
   5721         ((and (= state 2) is-jsx (eq char ?\}) (eq attr-flags 4))
   5722          (setq name-end pos)
   5723          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5724          (setq state 0
   5725                attr-flags 0
   5726                equal-offset 0
   5727                name-beg nil
   5728                name-end nil
   5729                val-beg nil)
   5730          )
   5731 
   5732         ((or (and (= state 8) (eq ?\" char) (not escaped))
   5733              (and (= state 7) (eq ?\' char) (not escaped))
   5734              (and (= state 9) (eq ?\} char) (= brace-depth 1))
   5735              (and (= state 10) (get-text-property pos 'block-end))
   5736              )
   5737          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5738          (setq state 0
   5739                attr-flags 0
   5740                equal-offset 0
   5741                name-beg nil
   5742                name-end nil
   5743                val-beg nil)
   5744          )
   5745 
   5746         ((and (member state '(4 5)) (get-text-property pos 'block-beg))
   5747          (setq val-beg pos)
   5748          (setq state 10))
   5749 
   5750         ((and (member state '(4 5)) (member char '(?\' ?\" ?\{)))
   5751          (setq val-beg pos)
   5752          (setq quoted 1)
   5753          (setq state (cond ((eq ?\' char) 7)
   5754                            ((eq ?\" char) 8)
   5755                            (t             9)))
   5756          (setq step 100)
   5757          (when (= state 9) (setq brace-depth 1))
   5758          )
   5759 
   5760         ((and (eq ?\= char) (member state '(2 3)))
   5761          (setq equal-offset (- pos name-beg)
   5762                name-end (1- pos))
   5763          (setq state 4)
   5764          (setq attr (buffer-substring-no-properties name-beg (1+ name-end)))
   5765          (when (and web-mode-indentless-attributes (member (downcase attr) web-mode-indentless-attributes))
   5766            (setq attr-flags (logior attr-flags 8)))
   5767          )
   5768 
   5769         ((and spaced (= state 0))
   5770          (setq state 1)
   5771          )
   5772 
   5773         ((and (eq char ?\<) (not (member state '(7 8 9))))
   5774          (setq continue nil)
   5775          (setq go-back t)
   5776          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5777          )
   5778 
   5779         ((and (eq char ?\>) (not (member state '(7 8 9))))
   5780          (setq tag-flags (logior tag-flags 16))
   5781          (when (eq (char-before) ?\/)
   5782            (setq tag-flags (logior tag-flags 8))
   5783            )
   5784          (setq continue nil)
   5785          (when name-beg
   5786            (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags))))
   5787          )
   5788 
   5789         ((and spaced (member state '(1 3 5)))
   5790          )
   5791 
   5792         ((and spaced (= state 2))
   5793          (setq state 3)
   5794          )
   5795 
   5796         ((and (eq char ?\/) (member state '(4 5)))
   5797          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5798          (setq state 1
   5799                attr-flags 0
   5800                equal-offset 0
   5801                name-beg nil
   5802                name-end nil
   5803                val-beg nil)
   5804          )
   5805 
   5806         ((and (eq char ?\/) (member state '(0 1)))
   5807          )
   5808 
   5809         ((and spaced (= state 4))
   5810          (setq state 5)
   5811          )
   5812 
   5813         ((and (= state 3)
   5814               (or (and (>= char 97) (<= char 122)) ;a - z
   5815                   (and (>= char 65) (<= char 90)) ;A - Z
   5816                   (eq char ?\-)))
   5817          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5818          (setq state 2
   5819                attr-flags 0
   5820                equal-offset 0
   5821                name-beg pos
   5822                name-end pos
   5823                val-beg nil)
   5824          )
   5825 
   5826         ((and (eq char ?\n) (not (member state '(7 8 9))))
   5827          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5828          (setq state 1
   5829                attr-flags 0
   5830                equal-offset 0
   5831                name-beg nil
   5832                name-end nil
   5833                val-beg nil)
   5834          )
   5835 
   5836         ((and (= state 6) (member char '(?\s ?\n))) ;#1150
   5837          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5838          (setq state 1
   5839                attr-flags 0
   5840                equal-offset 0
   5841                name-beg nil
   5842                name-end nil
   5843                val-beg nil)
   5844          )
   5845 
   5846         ((and quoted (= quoted 2) (member char '(?\s ?\n ?\>)))
   5847          (when (eq char ?\>)
   5848            (setq tag-flags (logior tag-flags 16))
   5849            (setq continue nil))
   5850          (setq state 6)
   5851          (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5852          (setq state 1
   5853                attr-flags 0
   5854                equal-offset 0
   5855                name-beg nil
   5856                name-end nil
   5857                val-beg nil)
   5858          )
   5859 
   5860         ((and (not spaced) (= state 1))
   5861          (when (and is-jsx (eq char ?\{))
   5862            (setq attr-flags 4))
   5863          (setq state 2)
   5864          (setq name-beg pos
   5865                name-end pos)
   5866          )
   5867 
   5868         ((member state '(4 5))
   5869          (setq val-beg pos)
   5870          (setq state 6)
   5871          )
   5872 
   5873         ((= state 1)
   5874          (setq state 2)
   5875          )
   5876 
   5877         ((= state 2)
   5878          (setq name-end pos)
   5879          (when (and nil (= attr-flags 0) (member char '(?\- ?\:)))
   5880            (let (attr)
   5881              (setq attr (buffer-substring-no-properties name-beg (1+ name-end)))
   5882              (cond
   5883                ((member attr '("http-equiv"))
   5884                 (setq attr-flags (1- attr-flags))
   5885                 )
   5886                ((and (eq char ?\-) (not (string= attr "http-")))
   5887                 (setq attr-flags (logior attr-flags 1)))
   5888                ) ;cond
   5889              ) ;let
   5890            ) ;when attr-flags = 1
   5891          ) ;state=2
   5892 
   5893         ) ;cond
   5894 
   5895       ;;(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)
   5896 
   5897       (when (and quoted (>= quoted 2))
   5898         (setq quoted nil))
   5899 
   5900       (setq escaped (eq ?\\ char))
   5901       (when (null go-back)
   5902         (forward-char))
   5903 
   5904       ;;(when (not (= mem state)) (message "pos=%S before=%S after=%S step=%S" pos mem state step))
   5905 
   5906       ) ;while
   5907 
   5908     (when (> attrs 0) (setq tag-flags (logior tag-flags 1)))
   5909 
   5910     tag-flags))
   5911 
   5912 (defun web-mode-attr-scan (pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)
   5913   ;;(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)
   5914   (when (null attr-flags) (setq attr-flags 0))
   5915   (when (and name-beg name-end web-mode-engine-attr-regexp)
   5916     (let (name)
   5917       (setq name (buffer-substring-no-properties name-beg (1+ name-end)))
   5918       (cond
   5919         ((string-match-p "^data[-]" name)
   5920          (setq attr-flags (logior attr-flags 1))
   5921          )
   5922         ((string-match-p web-mode-engine-attr-regexp name)
   5923          (setq attr-flags (logior attr-flags 2))
   5924          )
   5925         )
   5926       ) ;name
   5927     )
   5928   ;;(message "%S" name)
   5929   (cond
   5930     ((null name-beg)
   5931      0)
   5932     ((or (and (= state 8) (not (eq ?\" char)))
   5933          (and (= state 7) (not (eq ?\' char))))
   5934      (put-text-property name-beg (1+ name-beg) 'tag-attr-beg attr-flags)
   5935      (put-text-property name-beg val-beg 'tag-attr t)
   5936      (put-text-property (1- val-beg) val-beg 'tag-attr-end equal-offset)
   5937      1)
   5938     ((and (member state '(4 5)) (null val-beg))
   5939      (put-text-property name-beg (1+ name-beg) 'tag-attr-beg attr-flags)
   5940      (put-text-property name-beg (+ name-beg equal-offset 1) 'tag-attr t)
   5941      (put-text-property (+ name-beg equal-offset) (+ name-beg equal-offset 1) 'tag-attr-end equal-offset)
   5942      1)
   5943     (t
   5944      (let (val-end)
   5945        (if (null val-beg)
   5946            (setq val-end name-end)
   5947            (setq val-end pos)
   5948            (cond
   5949              ((null char)
   5950               (setq val-end (1- val-end)))
   5951              ((member char '(?\s ?\n ?\/))
   5952               (setq val-end (1- val-end)))
   5953              ((eq char ?\>)
   5954               (if (= (logand tag-flags 8) 8)
   5955                   (progn
   5956                     ;;(message "tag-flags=%S %S" tag-flags (logand tag-flags 8))
   5957                     (setq val-end (- val-end 2)))
   5958                   (setq val-end (- val-end 1)))
   5959               ;; (message "val-end=%S" val-end)
   5960               )
   5961              )
   5962            )
   5963        (put-text-property name-beg (1+ name-beg) 'tag-attr-beg attr-flags)
   5964        (put-text-property name-beg (1+ val-end) 'tag-attr t)
   5965        (put-text-property val-end (1+ val-end) 'tag-attr-end equal-offset)
   5966        ) ;let
   5967      1) ;t
   5968     ) ;cond
   5969   )
   5970 
   5971 (defun web-mode-part-foreach (reg-beg reg-end func)
   5972   (let ((i 0) (continue t) (part-beg reg-beg) (part-end nil))
   5973     (while continue
   5974       (setq part-end nil)
   5975       (unless (get-text-property part-beg 'part-side)
   5976         (setq part-beg (web-mode-part-next-position part-beg)))
   5977       (when (and part-beg (< part-beg reg-end))
   5978         (setq part-end (web-mode-part-end-position part-beg)))
   5979       (cond
   5980         ((> (setq i (1+ i)) 100)
   5981          (message "process-parts ** warning (%S) **" (point))
   5982          (setq continue nil))
   5983         ((or (null part-end) (> part-end reg-end))
   5984          (setq continue nil))
   5985         (t
   5986          (setq part-end (1+ part-end))
   5987          (funcall func part-beg part-end)
   5988          (setq part-beg part-end))
   5989         ) ;cond
   5990       ) ;while
   5991     ))
   5992 
   5993 (defun web-mode-part-scan (reg-beg reg-end &optional content-type depth)
   5994   (save-excursion
   5995     (let (token-re ch-before ch-at ch-next token-type beg continue)
   5996       ;;(message "%S %S" reg-beg reg-end)
   5997       (cond
   5998         (content-type
   5999          )
   6000         ((member web-mode-content-type web-mode-part-content-types)
   6001          (setq content-type web-mode-content-type))
   6002         (t
   6003          (setq content-type (symbol-name (get-text-property reg-beg 'part-side))))
   6004         ) ;cond
   6005 
   6006       (goto-char reg-beg)
   6007 
   6008       (cond
   6009         ((member content-type '("javascript" "json"))
   6010          (setq token-re "/\\|\"\\|'\\|`"))
   6011         ((member content-type '("typescript"))
   6012          (setq token-re "/\\|\"\\|'\\|`\\|//\\|/\\*"))
   6013         ((member content-type '("jsx"))
   6014          (setq token-re "/\\|\"\\|'\\|`\\|</?[[:alpha:]>]"))
   6015         ((string= web-mode-content-type "css")
   6016          (setq token-re "\"\\|'\\|/\\*\\|//"))
   6017         ((string= content-type "css")
   6018          (setq token-re "\"\\|'\\|/\\*"))
   6019         (t
   6020          (setq token-re "/\\*\\|\"\\|'"))
   6021         )
   6022 
   6023       (while (and token-re (< (point) reg-end) (web-mode-dom-rsf token-re reg-end t))
   6024 
   6025         (setq beg (match-beginning 0)
   6026               token-type nil
   6027               continue t
   6028               ch-at (char-after beg)
   6029               ch-next (or (char-after (1+ beg)) ?\d)
   6030               ch-before (or (char-before beg) ?\d))
   6031 
   6032         ;;(message "[%S>%S|%S] %S %c %c %c" reg-beg reg-end depth beg ch-before ch-at ch-next)
   6033 
   6034         (cond
   6035 
   6036           ((eq ?\' ch-at)
   6037            (while (and continue (search-forward "'" reg-end t))
   6038              (cond
   6039                ((get-text-property (1- (point)) 'block-side)
   6040                 (setq continue t))
   6041                (t
   6042                 (setq continue (web-mode-string-continue-p reg-beg)))
   6043                )
   6044              ) ;while
   6045            (setq token-type 'string))
   6046 
   6047           ((eq ?\` ch-at)
   6048            (while (and continue (search-forward "`" reg-end t))
   6049              (cond
   6050                ((get-text-property (1- (point)) 'block-side)
   6051                 (setq continue t))
   6052                (t
   6053                 (setq continue (web-mode-string-continue-p reg-beg)))
   6054                )
   6055              ) ;while
   6056            (setq token-type 'string))
   6057 
   6058           ((eq ?\" ch-at)
   6059            (while (and continue (search-forward "\"" reg-end t))
   6060              (cond
   6061                ((get-text-property (1- (point)) 'block-side)
   6062                 (setq continue t))
   6063                (t
   6064                 (setq continue (web-mode-string-continue-p reg-beg)))
   6065                ) ;cond
   6066              ) ;while
   6067            (cond
   6068              ((string= content-type "json")
   6069               (if (looking-at-p "[ ]*:")
   6070                   (cond
   6071                     ((eq ?\@ (char-after (1+ beg)))
   6072                      (setq token-type 'context))
   6073                     (t
   6074                      (setq token-type 'key))
   6075                     )
   6076                   (setq token-type 'string))
   6077               ) ;json
   6078              (t
   6079               (setq token-type 'string))
   6080              ) ;cond
   6081            )
   6082 
   6083           ((and (eq ?\< ch-at)
   6084                 (not (or (and (>= ch-before 97) (<= ch-before 122)) ;; a-z
   6085                          (and (>= ch-before 65) (<= ch-before 90))))) ;; A-Z
   6086            ;;(message "before [%S>%S|%S] pt=%S" reg-beg reg-end depth (point))
   6087            (search-backward "<")
   6088            (if (web-mode-jsx-skip reg-end)
   6089                (web-mode-jsx-scan-element beg (point) depth)
   6090                (forward-char))
   6091            ;;(message "after [%S>%S|%S] pt=%S" reg-beg reg-end depth (point))
   6092            )
   6093 
   6094           ((and (eq ?\/ ch-at) (member content-type '("javascript" "jsx" "typescript")))
   6095            (cond
   6096              ((eq ?\\ ch-before)
   6097               )
   6098              ((eq ?\* ch-next)
   6099               ;;(message "--> %S %S" (point) reg-end)
   6100               (when (search-forward "*/" reg-end t)
   6101                 (setq token-type 'comment))
   6102               )
   6103              ((eq ?\/ ch-next)
   6104               (setq token-type 'comment)
   6105               (goto-char (if (< reg-end (line-end-position)) reg-end (line-end-position)))
   6106               )
   6107              ((and (looking-at-p ".*/")
   6108                    (looking-back "\\(^\\|case\\|[[(,=:!&|?{};]\\)[ ]*/" (point-min)))
   6109               ;;(re-search-forward "/[gimyu]*" reg-end t))
   6110               (let ((eol (line-end-position)))
   6111                 (while (and continue (search-forward "/" eol t))
   6112                   (cond
   6113                     ((get-text-property (1- (point)) 'block-side)
   6114                      (setq continue t))
   6115                     ((looking-back "\\\\+/" reg-beg t)
   6116                      (setq continue (= (mod (- (point) (match-beginning 0)) 2) 0)))
   6117                     (t
   6118                      (re-search-forward "[gimyu]*" eol t)
   6119                      (setq token-type 'string)
   6120                      (setq continue nil))
   6121                     )
   6122                   ) ;while
   6123                 ) ;let
   6124               )
   6125              ) ;cond
   6126            )
   6127 
   6128           ((eq ?\/ ch-next)
   6129            ;;(message "%S" (point))
   6130            (cond
   6131              ((and (string= content-type "css")
   6132                    (eq ?/ ch-at)
   6133                    (eq ?: ch-before))
   6134               )
   6135              (t
   6136               (unless (eq ?\\ ch-before)
   6137                 (setq token-type 'comment)
   6138                 (goto-char (if (< reg-end (line-end-position)) reg-end (line-end-position)))
   6139                 )
   6140               )
   6141              )
   6142 
   6143            )
   6144 
   6145           ((eq ?\* ch-next)
   6146            (cond
   6147              ((search-forward "*/" reg-end t)
   6148               (setq token-type 'comment))
   6149              ((not (eobp))
   6150               (forward-char))
   6151              ) ;cond
   6152            )
   6153 
   6154           ) ;cond
   6155 
   6156         (when (and beg (>= reg-end (point)) token-type)
   6157           (put-text-property beg (point) 'part-token token-type)
   6158           (cond
   6159             ((eq token-type 'comment)
   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 ">")) ;#445
   6164                    (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax ">")) ;#377
   6165                    )
   6166                ) ;when
   6167              ) ;comment
   6168             ((eq token-type 'string)
   6169              (put-text-property beg (1+ beg) 'syntax-table (string-to-syntax "|"))
   6170              (when (< (point) (point-max))
   6171                (if (< (point) (line-end-position))
   6172                    (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax "|"))
   6173                    (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax "|"))
   6174                    )
   6175                ) ;when
   6176              ) ;string
   6177             ) ;cond
   6178           ) ;when
   6179 
   6180         (when (> (point) reg-end)
   6181           (message "reg-beg(%S) reg-end(%S) token-type(%S) point(%S)" reg-beg reg-end token-type (point)))
   6182 
   6183         ;;(message "#[%S>%S|%S] %S %c %c %c | (%S)" reg-beg reg-end depth beg ch-before ch-at ch-next (point))
   6184 
   6185         ) ;while
   6186 
   6187       )))
   6188 
   6189 (defun web-mode-string-continue-p (reg-beg)
   6190   "Is `point' preceeded by an odd number of backslashes?"
   6191   (let ((p (1- (point))))
   6192     (while (and (< reg-beg p) (eq ?\\ (char-before p)))
   6193       (setq p (1- p)))
   6194     (= (mod (- (point) p) 2) 0)))
   6195 
   6196 ;; css rule = selector(s) + declaration (properties)
   6197 (defun web-mode-css-rule-next (limit)
   6198   (let (at-rule var-rule sel-beg sel-end dec-beg dec-end chunk)
   6199     (skip-chars-forward "\n\t ")
   6200     (setq sel-beg (point))
   6201     (when (and (< (point) limit)
   6202                (web-mode-part-rsf "[{;]" limit))
   6203       (setq sel-end (1- (point)))
   6204       (cond
   6205         ((eq (char-before) ?\{)
   6206          (setq dec-beg (point))
   6207          (setq dec-end (web-mode-closing-paren-position (1- dec-beg) limit))
   6208          (if dec-end
   6209              (progn
   6210                (goto-char dec-end)
   6211                (forward-char))
   6212              (setq dec-end limit)
   6213              (goto-char limit))
   6214          )
   6215         (t
   6216          )
   6217         ) ;cond
   6218       (setq chunk (buffer-substring-no-properties sel-beg sel-end))
   6219       (cond
   6220         ((string-match "@\\([[:alpha:]-]+\\)" chunk)
   6221          (setq at-rule (match-string-no-properties 1 chunk)))
   6222         ((string-match "\\$\\([[:alpha:]-]+\\)" chunk)
   6223          (setq var-rule (match-string-no-properties 1 chunk)))
   6224         ) ;cond
   6225       ) ;when
   6226     (if (not sel-end)
   6227         (progn (goto-char limit) nil)
   6228         (list :at-rule at-rule
   6229               :var-rule var-rule
   6230               :sel-beg sel-beg
   6231               :sel-end sel-end
   6232               :dec-beg dec-beg
   6233               :dec-end dec-end)
   6234         ) ;if
   6235     ))
   6236 
   6237 (defun web-mode-css-rule-current (&optional pos part-beg part-end)
   6238   "Current CSS rule boundaries."
   6239   (unless pos (setq pos (point)))
   6240   (unless part-beg (setq part-beg (web-mode-part-beginning-position pos)))
   6241   (unless part-end (setq part-end (web-mode-part-end-position pos)))
   6242   (save-excursion
   6243     (let (beg end)
   6244       (goto-char pos)
   6245       (if (not (web-mode-part-sb "{" part-beg))
   6246           (progn
   6247             (setq beg part-beg)
   6248             (if (web-mode-part-sf ";" part-end)
   6249                 (setq end (1+ (point)))
   6250                 (setq end part-end))
   6251             ) ;progn
   6252           (setq beg (point))
   6253           (setq end (web-mode-closing-paren-position beg part-end))
   6254           (if end
   6255               (setq end (1+ end))
   6256               (setq end (line-end-position)))
   6257           ;;        (message "%S >>beg%S >>end%S" pos beg end)
   6258           (if (> pos end)
   6259 
   6260               ;;selectors
   6261               (progn
   6262                 (goto-char pos)
   6263                 (if (web-mode-part-rsb "[};]" part-beg)
   6264                     (setq beg (1+ (point)))
   6265                     (setq beg part-beg)
   6266                     ) ;if
   6267                 (goto-char pos)
   6268                 (if (web-mode-part-rsf "[{;]" part-end)
   6269                     (cond
   6270                       ((eq (char-before) ?\;)
   6271                        (setq end (point))
   6272                        )
   6273                       (t
   6274                        (setq end (web-mode-closing-paren-position (1- (point)) part-end))
   6275                        (if end
   6276                            (setq end (1+ end))
   6277                            (setq end part-end))
   6278                        )
   6279                       ) ;cond
   6280                     (setq end part-end)
   6281                     )
   6282                 ) ;progn selectors
   6283 
   6284               ;; declaration
   6285               (goto-char beg)
   6286               (if (web-mode-part-rsb "[}{;]" part-beg)
   6287                   (setq beg (1+ (point)))
   6288                   (setq beg part-beg)
   6289                   ) ;if
   6290               ) ;if > pos end
   6291           )
   6292       ;;      (message "beg(%S) end(%S)" beg end)
   6293       (when (eq (char-after beg) ?\n)
   6294         (setq beg (1+ beg)))
   6295       (cons beg end)
   6296       )))
   6297 
   6298 (defun web-mode-jsx-skip2 (reg-end)
   6299   (let ((continue t) (pos nil) (i 0))
   6300     (looking-at "<\\([[:alpha:]][[:alnum:]:-]*\\)")
   6301     ;; (let ((tag (match-string-no-properties 1)))
   6302     ;;   (message "point=%S tag=%S" (point) tag))
   6303     (save-excursion
   6304       (while continue
   6305         (cond
   6306           ((> (setq i (1+ i)) 1000)
   6307            (message "jsx-skip ** warning **")
   6308            (setq continue nil))
   6309           ((looking-at "<[[:alpha:]][[:alnum:]:-]*[ ]*/>")
   6310            (goto-char (match-end 0))
   6311            (setq pos (point))
   6312            (setq continue nil))
   6313           ((not (web-mode-dom-rsf ">\\([ \t\n]*[\];,)':}|&]\\)\\|{" reg-end))
   6314            (setq continue nil)
   6315            )
   6316           ((eq (char-before) ?\{)
   6317            (backward-char)
   6318            (web-mode-closing-paren reg-end)
   6319            (forward-char)
   6320            )
   6321           (t
   6322            (setq continue nil)
   6323            (setq pos (match-beginning 1))
   6324            ) ;t
   6325           ) ;cond
   6326         ) ;while
   6327       ) ;save-excursion
   6328     (when pos (goto-char pos))
   6329     ;;(message "jsx-skip: %S" pos)
   6330     pos))
   6331 
   6332  (defun web-mode-jsx-skip (reg-end) ;; #1299
   6333    (let ((continue t) (pos nil) (i 0) (tag nil) (regexp nil) (counter 0) (ret nil) (match nil) (inside t))
   6334      (looking-at "<\\([[:alpha:]][[:alnum:]:-]*\\)")
   6335      (setq tag (match-string-no-properties 1))
   6336      (setq regexp (concat "<" tag "[[:space:]/>]"))
   6337      ;;(message "-----\npoint=%S tag=%S reg-end=%S" (point) tag reg-end)
   6338      (save-excursion
   6339        (while continue
   6340          (setq ret (web-mode-dom-rsf regexp reg-end))
   6341          (if ret
   6342              (progn
   6343                (setq match (match-string-no-properties 0))
   6344                (when (and (eq (aref match 0) ?\<)
   6345                           (eq (char-before) ?\>))
   6346                  (backward-char)
   6347                  (when (eq (char-before) ?\/) (backward-char)))
   6348                )
   6349            (setq match nil)
   6350            ) ;if
   6351          ;;(message "point=%S regexp=%S match=%S" (point) regexp match)
   6352          (cond
   6353           ((> (setq i (1+ i)) 100)
   6354            (message "jsx-skip ** warning **")
   6355            (setq continue nil))
   6356           ((not ret)
   6357            (setq continue nil)
   6358            )
   6359           ((eq (aref match 0) ?\{)
   6360            (backward-char)
   6361            (web-mode-closing-paren reg-end)
   6362            (forward-char)
   6363            (if inside
   6364                (setq regexp (concat "[{]\\|/?>"))
   6365              (setq regexp (concat "[{]\\|</?" tag "[[:space:]/>]"))
   6366              )
   6367            )
   6368           ((and (eq (char-before) ?\>) (eq (char-before (1- (point))) ?\/)) ;; />
   6369            (setq inside nil)
   6370            (if (eq counter 1)
   6371                (progn
   6372                  (setq counter 0)
   6373                  (setq continue nil)
   6374                  (setq pos (point)))
   6375              (setq regexp (concat "[{]\\|<" tag "[[:space:]/>]"))
   6376              )
   6377            )
   6378           ((eq (char-before) ?\>) ;; >
   6379            (setq inside nil)
   6380            (if (= counter 0)
   6381                (progn
   6382                  (setq continue nil)
   6383                  (setq pos (point)))
   6384              (setq regexp (concat "[{]\\|</?" tag "[[:space:]/>]"))
   6385              )
   6386            )
   6387           ((and (> (length match) 1) (string= (substring match 0 2) "</"))
   6388            (setq inside t)
   6389            (setq counter (1- counter))
   6390            (setq regexp (concat "[{]\\|>"))
   6391            )
   6392           (t ;; <tag
   6393            (setq inside t)
   6394            (setq counter (1+ counter))
   6395            (setq regexp (concat "[{]\\|>"))
   6396            ) ;t
   6397           ) ;cond
   6398          ;;(message "point=%S counter=%S inside=%S" (point) counter inside)
   6399          ) ;while
   6400        ) ;save-excursion
   6401      (when pos (goto-char pos))
   6402      ;;(message "jsx-skip: %S" pos)
   6403      pos))
   6404 
   6405 ;; http://facebook.github.io/jsx/
   6406 ;; https://github.com/facebook/jsx/blob/master/AST.md
   6407 (defun web-mode-jsx-scan-element (reg-beg reg-end depth)
   6408   (unless depth (setq depth 1))
   6409   (save-excursion
   6410     (goto-char reg-beg)
   6411     (put-text-property reg-beg (1+ reg-beg) 'jsx-beg depth)
   6412     (put-text-property (1- reg-end) reg-end 'jsx-end depth)
   6413     (put-text-property reg-beg reg-end 'jsx-depth depth)
   6414     (goto-char reg-beg)
   6415     (web-mode-scan-elements reg-beg reg-end)
   6416     (web-mode-jsx-scan-expression reg-beg reg-end (1+ depth))
   6417     ))
   6418 
   6419 (defun web-mode-jsx-scan-expression (reg-beg reg-end depth)
   6420   (let ((continue t) beg end)
   6421     (save-excursion
   6422       (goto-char reg-beg)
   6423       ;;(message "reg-beg=%S reg-end=%S" reg-beg reg-end)
   6424       (while (and continue (search-forward "{" reg-end t))
   6425         (backward-char)
   6426         (setq beg (point)
   6427               end (web-mode-closing-paren reg-end))
   6428         (cond
   6429           ((eq (get-text-property beg 'part-token) 'comment)
   6430            (forward-char))
   6431           ((not end)
   6432            (setq continue nil))
   6433           (t
   6434            (setq end (1+ end))
   6435            (put-text-property beg end 'jsx-depth depth)
   6436            (put-text-property beg (1+ beg) 'jsx-beg depth)
   6437            (put-text-property (1- end) end 'jsx-end depth)
   6438            (web-mode-part-scan beg end "jsx" (1+ depth))
   6439            ) ;t
   6440           ) ;cond
   6441         ) ;while
   6442       ) ;save-excursion
   6443     ))
   6444 
   6445 (defun web-mode-jsx-is-html (&optional pos)
   6446   (interactive)
   6447   (unless pos (setq pos (point)))
   6448   (let ((depth (get-text-property pos 'jsx-depth)))
   6449     (cond
   6450       ((or (null depth) (<= pos 2))
   6451        (setq pos nil))
   6452       ((and (= depth 1) (get-text-property pos 'jsx-beg))
   6453        (setq pos nil))
   6454       ((get-text-property pos 'tag-end)
   6455        (setq pos nil))
   6456       ((get-text-property pos 'tag-attr-beg)
   6457        (setq pos nil))
   6458       ((get-text-property pos 'jsx-beg)
   6459        (setq pos (null (get-text-property pos 'tag-beg))))
   6460       ((setq pos (web-mode-jsx-depth-beginning-position pos))
   6461        (setq pos (not (null (get-text-property pos 'tag-beg)))))
   6462       (t
   6463        (setq pos nil))
   6464       ) ;cond
   6465     ;;(message "is-html: %S (depth=%S)" pos depth)
   6466     pos))
   6467 
   6468 (defun web-mode-jsx-is-expr (&optional pos)
   6469   (cond
   6470     ((and (get-text-property pos 'jsx-beg)
   6471           (not (get-text-property pos 'tag-beg)))
   6472      nil)
   6473     (t
   6474      (setq pos (web-mode-jsx-depth-beginning-position pos))
   6475      (null (get-text-property pos 'tag-beg)))
   6476     ) ;cond
   6477   )
   6478 
   6479 (defun web-mode-jsx-depth-beginning-position (&optional pos target-depth)
   6480   (interactive)
   6481   (unless pos (setq pos (point)))
   6482   (unless target-depth (setq target-depth (get-text-property pos 'jsx-depth)))
   6483   (cond
   6484     ((or (null target-depth) (bobp))
   6485      (setq pos nil))
   6486     ((and (get-text-property pos 'jsx-beg) (= target-depth (get-text-property pos 'jsx-depth)))
   6487      )
   6488     (t
   6489      (let ((continue t) depth)
   6490        (while continue
   6491          (setq pos (previous-single-property-change pos 'jsx-depth))
   6492          (cond
   6493            ((or (null pos)
   6494                 (null (setq depth (get-text-property pos 'jsx-depth))))
   6495             (setq continue nil
   6496                   pos nil))
   6497            ((and (get-text-property pos 'jsx-beg) (= target-depth depth))
   6498             (setq continue nil))
   6499            ) ;cond
   6500          ) ;while
   6501        ) ;let
   6502      ) ;t
   6503     ) ;cond
   6504   ;;(message "beg: %S" pos)
   6505   pos)
   6506 
   6507 (defun web-mode-jsx-element-next (reg-end)
   6508   (let (continue beg end)
   6509     (setq beg (point))
   6510     (unless (get-text-property beg 'jsx-depth)
   6511       (setq beg (next-single-property-change beg 'jsx-beg)))
   6512     (setq continue (and beg (< beg reg-end))
   6513           end beg)
   6514     (while continue
   6515       (setq end (next-single-property-change end 'jsx-end))
   6516       (cond
   6517         ((or (null end) (> end reg-end))
   6518          (setq continue nil
   6519                end nil))
   6520         ((eq (get-text-property end 'jsx-depth) 1)
   6521          (setq continue nil))
   6522         (t
   6523          (setq end (1+ end)))
   6524         ) ;cond
   6525       ) ;while
   6526     ;;(message "beg=%S end=%S" beg end)
   6527     (if (and beg end (< beg end)) (cons beg end) nil)))
   6528 
   6529 (defun web-mode-jsx-expression-next (reg-end)
   6530   (let (beg end depth continue pos)
   6531     (setq beg (point))
   6532     ;;(message "pt=%S" beg)
   6533     (unless (and (get-text-property beg 'jsx-beg) (null (get-text-property beg 'tag-beg)))
   6534       ;;(setq beg (next-single-property-change beg 'jsx-beg))
   6535       (setq continue t
   6536             pos (1+ beg))
   6537       (while continue
   6538         (setq pos (next-single-property-change pos 'jsx-beg))
   6539         (cond
   6540           ((null pos)
   6541            (setq continue nil
   6542                  beg nil))
   6543           ((> pos reg-end)
   6544            (setq continue nil
   6545                  beg nil))
   6546           ((null (get-text-property pos 'jsx-beg))
   6547            )
   6548           ((null (get-text-property pos 'tag-beg))
   6549            (setq continue nil
   6550                  beg pos))
   6551           ;;(t
   6552           ;; (setq pos (1+ pos)))
   6553           ) ;cond
   6554         ) ;while
   6555       ) ;unless
   6556     ;;(message "beg=%S" beg)
   6557     (when (and beg (< beg reg-end))
   6558       (setq depth (get-text-property beg 'jsx-beg)
   6559             continue (not (null depth))
   6560             pos beg)
   6561       ;;(message "beg=%S" beg)
   6562       (while continue
   6563         (setq pos (next-single-property-change pos 'jsx-end))
   6564         ;;(message "pos=%S" pos)
   6565         (cond
   6566           ((null pos)
   6567            (setq continue nil))
   6568           ((> pos reg-end)
   6569            (setq continue nil))
   6570           ((eq depth (get-text-property pos 'jsx-end))
   6571            (setq continue nil
   6572                  end pos))
   6573           (t
   6574            ;;(setq pos (1+ pos))
   6575            )
   6576           ) ;cond
   6577         ) ;while
   6578       ) ;when
   6579     ;;(message "%S > %S" beg end)
   6580     (if (and beg end) (cons beg end) nil)))
   6581 
   6582 (defun web-mode-jsx-depth-next (reg-end)
   6583   (let (beg end depth continue pos)
   6584     (setq beg (point))
   6585     ;;(message "pt=%S" beg)
   6586     (unless (get-text-property beg 'jsx-beg)
   6587       ;;(setq beg (next-single-property-change beg 'jsx-beg))
   6588       ;;(setq pos (1+ beg))
   6589       (setq pos (next-single-property-change (1+ beg) 'jsx-beg))
   6590       (cond
   6591         ((null pos)
   6592          (setq beg nil))
   6593         ((>= pos reg-end)
   6594          (setq beg nil))
   6595         (t
   6596          (setq beg pos))
   6597         ) ;cond
   6598       ) ;unless
   6599     ;;(message "beg=%S" beg)
   6600     (when beg
   6601       (setq depth (get-text-property beg 'jsx-beg)
   6602             continue (not (null depth))
   6603             pos beg)
   6604       ;;(message "beg=%S" beg)
   6605       (while continue
   6606         (setq pos (next-single-property-change pos 'jsx-end))
   6607         ;;(message "pos=%S" pos)
   6608         (cond
   6609           ((null pos)
   6610            (setq continue nil))
   6611           ((> pos reg-end)
   6612            (setq continue nil))
   6613           ((eq depth (get-text-property pos 'jsx-end))
   6614            (setq continue nil
   6615                  end pos))
   6616           (t
   6617            ;;(setq pos (1+ pos))
   6618            )
   6619           ) ;cond
   6620         ) ;while
   6621       ) ;when
   6622     ;;(message "%S > %S" beg end)
   6623     (if (and beg end) (cons beg end) nil)))
   6624 
   6625 (defun web-mode-jsx-beginning ()
   6626   (interactive)
   6627   (let (depth (continue t) (reg-beg (point-min)) (pos (point)))
   6628     (setq depth (get-text-property pos 'jsx-depth))
   6629     (cond
   6630       ((not depth)
   6631        )
   6632       ((get-text-property (1- pos) 'jsx-beg)
   6633        (goto-char (1- pos)))
   6634       (t
   6635        (while continue
   6636          (setq pos (previous-single-property-change pos 'jsx-beg))
   6637          ;;(message "pos=%S" pos)
   6638          (cond
   6639            ((null pos)
   6640             (setq continue nil))
   6641            ((<= pos reg-beg)
   6642             (setq continue nil))
   6643            ((eq depth (get-text-property pos 'jsx-beg))
   6644             (setq continue nil))
   6645            ) ;cond
   6646          ) ;while
   6647        (web-mode-go pos)
   6648        ) ;t
   6649       ) ;cond
   6650     ))
   6651 
   6652 (defun web-mode-jsx-end ()
   6653   (interactive)
   6654   (let (depth (continue t) (reg-end (point-max)) (pos (point)))
   6655     (setq depth (get-text-property pos 'jsx-depth))
   6656     (cond
   6657       ((not depth)
   6658        )
   6659       ((get-text-property pos 'jsx-end)
   6660        (goto-char (+ pos 1)))
   6661       (t
   6662        (while continue
   6663          (setq pos (next-single-property-change pos 'jsx-end))
   6664          ;;(message "pos=%S" pos)
   6665          (cond
   6666            ((null pos)
   6667             (setq continue nil))
   6668            ((> pos reg-end)
   6669             (setq continue nil))
   6670            ((eq depth (get-text-property pos 'jsx-end))
   6671             (setq continue nil))
   6672            ) ;cond
   6673          ) ;while
   6674        (web-mode-go pos 1)
   6675        ) ;t
   6676       ) ;cond
   6677     ))
   6678 
   6679 ;;---- FONTIFICATION -----------------------------------------------------------
   6680 
   6681 (defun web-mode-fontify (limit)
   6682   (when web-mode-trace
   6683     (message "fontify: point(%S) limit(%S)" (point) limit))
   6684   (cond
   6685     ;;(web-mode-skip-fontification
   6686     ;; nil)
   6687     (t
   6688      (web-mode-with-silent-modifications
   6689       (save-excursion
   6690         (save-restriction
   6691           (save-match-data
   6692             (let ((beg (point))
   6693                   (buffer-undo-list t)
   6694                   (end limit)
   6695                   (inhibit-point-motion-hooks t)
   6696                   (inhibit-quit t))
   6697               (remove-list-of-text-properties beg end '(font-lock-face face))
   6698               (cond
   6699                 ((and (get-text-property beg 'block-side)
   6700                       (not (get-text-property beg 'block-beg)))
   6701                  (web-mode-fontify-block beg end))
   6702                 ((or (member web-mode-content-type web-mode-part-content-types)
   6703                      (get-text-property beg 'part-side))
   6704                  (web-mode-fontify-part beg end)
   6705                  (web-mode-block-foreach beg end 'web-mode-fontify-block))
   6706                 ((string= web-mode-engine "none")
   6707                  (web-mode-fontify-tags beg end)
   6708                  (web-mode-part-foreach beg end 'web-mode-fontify-part))
   6709                 (t
   6710                  (web-mode-fontify-tags beg end)
   6711                  (web-mode-part-foreach beg end 'web-mode-fontify-part)
   6712                  (web-mode-block-foreach beg end 'web-mode-fontify-block))
   6713                 ) ;cond
   6714               (when web-mode-enable-element-content-fontification
   6715                 (web-mode-fontify-elements beg end))
   6716               (when web-mode-enable-whitespace-fontification
   6717                 (web-mode-fontify-whitespaces beg end))
   6718               ) ;let
   6719             ))))
   6720      nil) ;t
   6721     ))
   6722 
   6723 (defun web-mode-buffer-fontify ()
   6724   (interactive)
   6725   (cond
   6726     ((and (fboundp 'font-lock-flush) global-font-lock-mode)
   6727      (font-lock-flush)
   6728      (font-lock-ensure))
   6729     (t  ;emacs 24
   6730      ;;(font-lock-fontify-buffer)
   6731      (and global-font-lock-mode
   6732           (font-lock-fontify-region (point-min) (point-max))))
   6733     ))
   6734 
   6735 (defun web-mode-unfontify-region (beg end)
   6736   (ignore beg end)
   6737   ;;(message "unfontify: %S %S" beg end)
   6738   )
   6739 
   6740 (defun web-mode-fontify-region (beg end keywords)
   6741   ;;  (message "beg=%S end=%S keywords=%S" beg end (symbol-name keywords))
   6742   (save-excursion
   6743     (let ((font-lock-keywords keywords)
   6744           (font-lock-multiline nil)
   6745           (font-lock-keywords-case-fold-search
   6746            (member web-mode-engine '("archibus" "asp" "template-toolkit")))
   6747           (font-lock-keywords-only t)
   6748           (font-lock-extend-region-functions nil))
   6749       (when (and (listp font-lock-keywords) global-font-lock-mode)
   6750         (font-lock-fontify-region beg end)
   6751         )
   6752       )))
   6753 
   6754 (defun web-mode-fontify-tags (reg-beg reg-end &optional depth)
   6755   (let ((continue t))
   6756     (goto-char reg-beg)
   6757     (when (and (not (get-text-property (point) 'tag-beg))
   6758                (not (web-mode-tag-next)))
   6759       (setq continue nil))
   6760     (when (and continue (>= (point) reg-end))
   6761       (setq continue nil))
   6762     (while continue
   6763       (cond
   6764         (depth
   6765          (when (eq depth (get-text-property (point) 'jsx-depth))
   6766            (web-mode-fontify-tag))
   6767          )
   6768         (t
   6769          (web-mode-fontify-tag))
   6770         ) ;cond
   6771       (when (or (not (web-mode-tag-next))
   6772                 (>= (point) reg-end))
   6773         (setq continue nil))
   6774       ) ;while
   6775     (when web-mode-enable-inlays
   6776       (when (null web-mode-inlay-regexp)
   6777         (setq web-mode-inlay-regexp (regexp-opt '("\\[" "\\(" "\\begin{align}"))))
   6778       (let (beg end expr)
   6779         (goto-char reg-beg)
   6780         (while (web-mode-dom-rsf web-mode-inlay-regexp reg-end)
   6781           (setq beg (match-beginning 0)
   6782                 end nil
   6783                 expr (substring (match-string-no-properties 0) 0 2))
   6784           (setq expr (cond
   6785                        ((string= expr "\\[") "\\]")
   6786                        ((string= expr "\\(") "\\)")
   6787                        (t "\\end{align}")))
   6788           (when (and (web-mode-dom-sf expr reg-end)
   6789                      (setq end (match-end 0))
   6790                      (not (text-property-any beg end 'tag-end t)))
   6791             (font-lock-append-text-property beg end 'font-lock-face 'web-mode-inlay-face)
   6792             ) ;when
   6793           ) ;while
   6794         ) ;let
   6795       ) ;when
   6796     (when web-mode-enable-html-entities-fontification
   6797       (let (beg end)
   6798         (goto-char reg-beg)
   6799         (while (web-mode-dom-rsf "&\\([#]?[[:alnum:]]\\{2,8\\}\\);" reg-end)
   6800           (setq beg (match-beginning 0)
   6801                 end (match-end 0))
   6802           (when (not (text-property-any beg end 'tag-end t))
   6803             (font-lock-append-text-property beg end 'font-lock-face 'web-mode-html-entity-face)
   6804             ) ;when
   6805           ) ;while
   6806         ) ;let
   6807       ) ;when
   6808     ))
   6809 
   6810 (defun web-mode-fontify-tag (&optional beg end)
   6811   (unless beg (setq beg (point)))
   6812   (unless end (setq end (1+ (web-mode-tag-end-position beg))))
   6813   (let (name type face flags slash-beg slash-end bracket-end)
   6814     (setq flags (get-text-property beg 'tag-beg)
   6815           type (get-text-property beg 'tag-type)
   6816           name (get-text-property beg 'tag-name))
   6817     (setq bracket-end (> (logand flags 16) 0))
   6818     (cond
   6819       ((eq type 'comment)
   6820        (put-text-property beg end 'font-lock-face 'web-mode-comment-face)
   6821        (when (and web-mode-enable-comment-interpolation (> (- end beg) 5))
   6822          (web-mode-interpolate-comment beg end nil)))
   6823       ((eq type 'cdata)
   6824        (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
   6825       ((eq type 'doctype)
   6826        (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
   6827       ((eq type 'declaration)
   6828        (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
   6829       (name
   6830        (setq slash-beg (> (logand flags 4) 0)
   6831              slash-end (> (logand flags 8) 0)
   6832              bracket-end (> (logand flags 16) 0))
   6833        (setq face (cond
   6834                     ((not bracket-end)       'web-mode-html-tag-unclosed-face)
   6835                     ((and web-mode-enable-element-tag-fontification
   6836                           (setq face (cdr (assoc name web-mode-element-tag-faces))))
   6837                      face)
   6838                     ((> (logand flags 32) 0) 'web-mode-html-tag-namespaced-face)
   6839                     ((> (logand flags 2) 0)  'web-mode-html-tag-custom-face)
   6840                     (t                       'web-mode-html-tag-face)))
   6841        (put-text-property beg (+ beg (if slash-beg 2 1))
   6842                           'font-lock-face 'web-mode-html-tag-bracket-face)
   6843        (unless (string= name "_fragment_")
   6844          (put-text-property (+ beg (if slash-beg 2 1))
   6845                             (+ beg (if slash-beg 2 1) (length name))
   6846                             'font-lock-face face))
   6847        (when (or slash-end bracket-end)
   6848          (put-text-property (- end (if slash-end 2 1)) end 'font-lock-face 'web-mode-html-tag-bracket-face)
   6849          ) ;when
   6850        (when (> (logand flags 1) 0)
   6851          ;;(message "%S>%S" beg end)
   6852          (web-mode-fontify-attrs beg end))
   6853        ) ;case name
   6854       ) ;cond
   6855     ))
   6856 
   6857 (defun web-mode-fontify-attrs (reg-beg reg-end)
   6858   (let ((continue t) (pos reg-beg) beg end flags offset face)
   6859     ;;(message "fontify-attrs %S>%S" reg-beg reg-end)
   6860     (while continue
   6861       (setq beg (web-mode-attribute-next-position pos reg-end))
   6862       (cond
   6863         ((or (null beg) (>= beg reg-end))
   6864          (setq continue nil))
   6865         (t
   6866          (setq flags (or (get-text-property beg 'tag-attr-beg) 0))
   6867          (setq face (cond
   6868                       ((= (logand flags 1) 1) 'web-mode-html-attr-custom-face)
   6869                       ((= (logand flags 2) 2) 'web-mode-html-attr-engine-face)
   6870                       ((= (logand flags 4) 4) nil)
   6871                       (t                      'web-mode-html-attr-name-face)))
   6872          ;;(setq end (if (get-text-property beg 'tag-attr-end) beg (web-mode-attribute-end-position beg)))
   6873          (setq end (web-mode-attribute-end-position beg))
   6874          ;;(message "beg=%S end=%S" beg end)
   6875          (cond
   6876            ((or (null end) (>= end reg-end))
   6877             (setq continue nil))
   6878            (t
   6879             (setq offset (get-text-property end 'tag-attr-end))
   6880             (if (= offset 0)
   6881                 (put-text-property beg (1+ end) 'font-lock-face face)
   6882                 (put-text-property beg (+ beg offset) 'font-lock-face face)
   6883                 (put-text-property (+ beg offset) (+ beg offset 1)
   6884                                    'font-lock-face
   6885                                    'web-mode-html-attr-equal-face)
   6886                 (when (not (get-text-property (+ beg offset 1) 'jsx-beg))
   6887                   (put-text-property (+ beg offset 1) (1+ end)
   6888                                      'font-lock-face
   6889                                      'web-mode-html-attr-value-face)
   6890                   )
   6891                 ) ;if offset
   6892             (setq pos (1+ end))
   6893             ) ;t
   6894            ) ;cond
   6895          ) ;t
   6896         );cond
   6897       ) ;while
   6898     ))
   6899 
   6900 (defun web-mode-fontify-block (reg-beg reg-end)
   6901   (when web-mode-trace
   6902     (message "fontify-block: reg-beg(%S) reg-end(%S) engine(%S) keywords(%S)"
   6903              reg-beg reg-end web-mode-engine (not (null web-mode-engine-font-lock-keywords))))
   6904 
   6905   (let (sub1 sub2 sub3 continue char keywords token-type face beg end (buffer (current-buffer)))
   6906 
   6907     ;; NOTE: required for blocks inside tag attrs
   6908     ;; NOTE: ajout de face dans la liste pour sucharger la couleur définie par
   6909     ;;       un prealable web-mode-fontity-part (2022-12-25 #1230)
   6910     (remove-list-of-text-properties reg-beg reg-end '(font-lock-face face))
   6911     ;;(message "reg-beg=%S reg-end=%S" reg-beg reg-end)
   6912 
   6913     (goto-char reg-beg)
   6914 
   6915     (when (null web-mode-engine-font-lock-keywords)
   6916       (setq sub1 (buffer-substring-no-properties
   6917                   reg-beg (+ reg-beg 1))
   6918             sub2 (buffer-substring-no-properties
   6919                   reg-beg (+ reg-beg 2))
   6920             sub3 (buffer-substring-no-properties
   6921                   reg-beg (+ reg-beg (if (>= (point-max) (+ reg-beg 3)) 3 2))))
   6922       )
   6923 
   6924     (cond
   6925 
   6926       ((and (get-text-property reg-beg 'block-beg)
   6927             (eq (get-text-property reg-beg 'block-token) 'comment))
   6928        (put-text-property reg-beg reg-end 'font-lock-face 'web-mode-comment-face)
   6929        ) ;comment block
   6930 
   6931       (web-mode-engine-font-lock-keywords
   6932        (setq keywords web-mode-engine-font-lock-keywords))
   6933 
   6934       ((string= web-mode-engine "django")
   6935        (cond
   6936          ((string= sub2 "{{")
   6937           (setq keywords web-mode-django-expr-font-lock-keywords))
   6938          ((string= sub2 "{%")
   6939           (setq keywords web-mode-django-code-font-lock-keywords))
   6940          ((string= sub1 "#")
   6941           (setq keywords web-mode-django-code-font-lock-keywords))
   6942          )) ;django
   6943 
   6944       ((string= web-mode-engine "mako")
   6945        (cond
   6946          ((member sub3 '("<% " "<%\n" "<%!"))
   6947           (setq keywords web-mode-mako-block-font-lock-keywords))
   6948          ((eq (aref sub2 0) ?\%)
   6949           (setq keywords web-mode-mako-block-font-lock-keywords))
   6950          ((member sub2 '("<%" "</"))
   6951           (setq keywords web-mode-mako-tag-font-lock-keywords))
   6952          ((member sub2 '("${"))
   6953           (setq keywords web-mode-uel-font-lock-keywords))
   6954          )) ;mako
   6955 
   6956       ((string= web-mode-engine "mason")
   6957        ;;(message "%S %S" sub2 sub3)
   6958        (cond
   6959          ((member sub3 '("<% " "<%\n" "<&|"))
   6960           (setq keywords web-mode-mason-code-font-lock-keywords))
   6961          ((eq (aref sub2 0) ?\%)
   6962           (setq keywords web-mode-mason-code-font-lock-keywords))
   6963          ((and (or (string= sub2 "<%") (string= sub3 "</%"))
   6964                (not (member sub3 '("<%c" "<%i" "<%p"))))
   6965           (setq keywords web-mode-mason-block-font-lock-keywords))
   6966          (t
   6967           (setq keywords web-mode-mason-code-font-lock-keywords))
   6968          )) ;mason
   6969 
   6970       ((string= web-mode-engine "jsp")
   6971        (cond
   6972          ((string= sub3 "<%@")
   6973           (setq keywords web-mode-directive-font-lock-keywords))
   6974          ((member sub2 '("${" "#{"))
   6975           (setq keywords web-mode-uel-font-lock-keywords))
   6976          ((string= sub2 "<%")
   6977           (setq keywords web-mode-jsp-font-lock-keywords))
   6978          )) ;jsp
   6979 
   6980       ((string= web-mode-engine "asp")
   6981        (cond
   6982          ((or (string= sub2 "<%")
   6983               (not (string= sub1 "<")))
   6984           (setq keywords web-mode-asp-font-lock-keywords))
   6985          (t
   6986           (setq keywords web-mode-engine-tag-font-lock-keywords))
   6987          )) ;asp
   6988 
   6989       ((string= web-mode-engine "clip")
   6990        (setq keywords web-mode-engine-tag-font-lock-keywords)
   6991        ) ;clip
   6992 
   6993       ((string= web-mode-engine "perl")
   6994        (setq keywords web-mode-engine-tag-font-lock-keywords)
   6995        ) ;perl
   6996 
   6997       ((string= web-mode-engine "aspx")
   6998        (cond
   6999          ((string= sub3 "<%@")
   7000           (setq keywords web-mode-directive-font-lock-keywords))
   7001          ((string= sub3 "<%$")
   7002           (setq keywords web-mode-expression-font-lock-keywords))
   7003          (t
   7004           (setq keywords web-mode-aspx-font-lock-keywords))
   7005          )) ;aspx
   7006 
   7007       ((string= web-mode-engine "freemarker")
   7008        (cond
   7009          ((member sub2 '("${" "#{"))
   7010           (setq keywords web-mode-uel-font-lock-keywords))
   7011          ((or (member sub2 '("<@" "[@" "<#" "[#"))
   7012               (member sub3 '("</@" "[/@" "</#" "[/#")))
   7013           (setq keywords (if (eq ?\[ (aref sub2 0))
   7014                              web-mode-freemarker-square-font-lock-keywords
   7015                              web-mode-freemarker-font-lock-keywords)))
   7016          (t
   7017           (setq keywords web-mode-engine-tag-font-lock-keywords))
   7018          )) ;freemarker
   7019 
   7020       ) ;cond
   7021 
   7022     (when keywords
   7023       (web-mode-fontify-region reg-beg reg-end keywords)
   7024       (setq continue t)
   7025       (setq end reg-beg)
   7026       (while continue
   7027         (if (get-text-property end 'block-token)
   7028             (setq beg end)
   7029             (setq beg (next-single-property-change end 'block-token buffer reg-end)))
   7030         (setq end nil)
   7031         (when beg (setq char (char-after beg)))
   7032         (if (and beg (< beg reg-end))
   7033             (progn
   7034               (setq token-type (get-text-property beg 'block-token))
   7035               (setq face (cond
   7036                            ((eq token-type 'string)  'web-mode-block-string-face)
   7037                            ((eq token-type 'comment) 'web-mode-block-comment-face)
   7038                            ((eq token-type 'symbol)  'web-mode-symbol-face)
   7039                            (t                        'web-mode-block-delimiter-face)))
   7040               (setq end (next-single-property-change beg 'block-token buffer reg-end))
   7041               ;;              (message "end=%S" end)
   7042               (if (and end (<= end reg-end))
   7043                   (progn
   7044                     ;;(message "%S > %S face(%S)" beg end face)
   7045                     (remove-list-of-text-properties beg end '(face))
   7046                     (put-text-property beg end 'font-lock-face face)
   7047                     )
   7048                   (setq continue nil
   7049                         end nil)
   7050                   ) ;if end
   7051               ) ;progn beg
   7052             (setq continue nil
   7053                   end nil)
   7054             ) ;if beg
   7055         (when (and beg end)
   7056           (save-match-data
   7057             (when (and web-mode-enable-heredoc-fontification
   7058                        (eq char ?\<)
   7059                        (> (- end beg) 8)
   7060                        (string-match-p "JS\\|JAVASCRIPT\\|HTM\\|CSS" (buffer-substring-no-properties beg end)))
   7061               (setq keywords
   7062                     (cond
   7063                       ((string-match-p "H" (buffer-substring-no-properties beg (+ beg 8)))
   7064                        web-mode-html-font-lock-keywords)
   7065                       (t
   7066                        web-mode-javascript-font-lock-keywords)
   7067                       ))
   7068               (web-mode-fontify-region beg end keywords)
   7069               )
   7070             ) ;save-match-data
   7071           (when (and web-mode-enable-string-interpolation
   7072                      (member char '(?\" ?\<))
   7073                      (member web-mode-engine '("php" "erb"))
   7074                      (> (- end beg) 4))
   7075             (web-mode-interpolate-block-string beg end)
   7076             ) ;when
   7077           (when (and web-mode-enable-comment-interpolation
   7078                      (eq token-type 'comment)
   7079                      (> (- end beg) 3))
   7080             (web-mode-interpolate-comment beg end t)
   7081             ) ;when
   7082           (when (and web-mode-enable-comment-annotation
   7083                      (eq token-type 'comment)
   7084                      (> (- end beg) 3))
   7085             (web-mode-annotate-comment beg end)
   7086             ) ;when
   7087           (when (and web-mode-enable-sql-detection
   7088                      (eq token-type 'string)
   7089                      (> (- end beg) 6)
   7090                      (web-mode-looking-at-p (concat "\\(.\\|<<<[[:alnum:]]+\\)[ \n]*" web-mode-sql-queries) beg)
   7091                      )
   7092             (web-mode-interpolate-sql-string beg end)
   7093             ) ;when
   7094           ) ;when beg end
   7095         ) ;while continue
   7096       ) ;when keywords
   7097 
   7098     (when (and (member web-mode-engine '("mako"))
   7099                (> (- reg-end reg-beg) 12)
   7100                (eq ?\< (char-after reg-beg)))
   7101       (web-mode-interpolate-block-tag reg-beg reg-end))
   7102 
   7103     (when web-mode-enable-block-face
   7104       (font-lock-append-text-property reg-beg reg-end 'face 'web-mode-block-face))
   7105 
   7106     ))
   7107 
   7108 (defun web-mode-fontify-part (reg-beg reg-end &optional depth)
   7109   (save-excursion
   7110     (let (continue token-type face pos beg end string-face comment-face content-type)
   7111       ;;(message "fontify-part: reg-beg(%S) reg-end(%S)" reg-beg reg-end)
   7112       (if (member web-mode-content-type web-mode-part-content-types)
   7113           (setq content-type web-mode-content-type)
   7114           (setq content-type (symbol-name (get-text-property reg-beg 'part-side))))
   7115       ;;(message "content-type=%S" content-type)
   7116       (unless depth
   7117         (when (string= content-type "jsx") (setq depth 0))
   7118         )
   7119       (setq string-face 'web-mode-part-string-face
   7120             comment-face 'web-mode-part-comment-face)
   7121       (cond
   7122         ((member content-type '("javascript" "jsx"))
   7123          (setq string-face 'web-mode-javascript-string-face
   7124                comment-face 'web-mode-javascript-comment-face)
   7125          (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
   7126         ((string= content-type "json")
   7127          (setq string-face 'web-mode-json-string-face
   7128                comment-face 'web-mode-json-comment-face)
   7129          (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
   7130         ((string= content-type "css")
   7131          (setq string-face 'web-mode-css-string-face
   7132                comment-face 'web-mode-css-comment-face)
   7133          (web-mode-fontify-css-rules reg-beg reg-end))
   7134         ((string= content-type "sql")
   7135          (web-mode-fontify-region reg-beg reg-end web-mode-sql-font-lock-keywords))
   7136         ((string= content-type "stylus")
   7137          (web-mode-fontify-region reg-beg reg-end web-mode-stylus-font-lock-keywords))
   7138         ((string= content-type "sass")
   7139          (web-mode-fontify-region reg-beg reg-end web-mode-sass-font-lock-keywords))
   7140         ((string= content-type "pug")
   7141          (web-mode-fontify-region reg-beg reg-end web-mode-pug-font-lock-keywords))
   7142         ((string= content-type "markdown")
   7143          (web-mode-fontify-region reg-beg reg-end web-mode-markdown-font-lock-keywords))
   7144         ((string= content-type "ruby")
   7145          (web-mode-fontify-region reg-beg reg-end web-mode-erb-font-lock-keywords))
   7146         ((string= content-type "typescript")
   7147          (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
   7148         ) ;cond
   7149 
   7150       (goto-char reg-beg)
   7151 
   7152       ;;(when (string= content-type "jsx") (web-mode-fontify-tags reg-beg reg-end))
   7153       ;;(setq continue (and pos (< pos reg-end)))
   7154       (setq continue t
   7155             pos reg-beg)
   7156       (while continue
   7157         (if (get-text-property pos 'part-token)
   7158             (setq beg pos)
   7159             (setq beg (next-single-property-change pos 'part-token)))
   7160         (cond
   7161           ((or (null beg) (>= beg reg-end))
   7162            (setq continue nil
   7163                  end nil))
   7164           ((and (eq depth 0) (get-text-property beg 'jsx-depth))
   7165            (setq pos (or (next-single-property-change beg 'jsx-depth) (point-max))))
   7166           (t
   7167            ;;(message "%c" (char-after beg))
   7168            (setq token-type (get-text-property beg 'part-token))
   7169            (setq face (cond
   7170                         ((eq token-type 'string)  string-face)
   7171                         ((eq token-type 'comment) comment-face)
   7172                         ((eq token-type 'context) 'web-mode-json-context-face)
   7173                         ((eq token-type 'key)     'web-mode-json-key-face)
   7174                         (t                        nil)))
   7175            (setq end (or (next-single-property-change beg 'part-token) (point-max))
   7176                  pos end)
   7177            (cond
   7178              ((or (null end) (> end reg-end))
   7179               (setq continue nil
   7180                     end nil))
   7181              (t
   7182               (when face
   7183                 (remove-list-of-text-properties beg end '(face))
   7184                 (put-text-property beg end 'font-lock-face face))
   7185               (cond
   7186                 ((< (- end beg) 6)
   7187                  )
   7188                 ((eq token-type 'string)
   7189                  (cond
   7190                    ((and (eq (char-after beg) ?\`)
   7191                          web-mode-enable-literal-interpolation
   7192                          (member content-type '("javascript" "jsx" "typescript")))
   7193                     (web-mode-interpolate-javascript-literal beg end)
   7194                     )
   7195                    ((and (eq (char-after beg) ?\")
   7196                          web-mode-enable-string-interpolation
   7197                          (member content-type '("javascript" "jsx" "typescript")))
   7198                     (web-mode-interpolate-javascript-string beg end))
   7199                    ) ;cond
   7200                  ) ;case string
   7201                 ((eq token-type 'comment)
   7202                  (when web-mode-enable-comment-interpolation
   7203                    (web-mode-interpolate-comment beg end t))
   7204                  (when web-mode-enable-comment-annotation
   7205                    (web-mode-annotate-comment beg end))
   7206                  )
   7207                 ) ;cond
   7208               ) ;t
   7209              ) ;cond
   7210            ) ;t
   7211           ) ;cond
   7212         ) ;while
   7213 
   7214       (when (and (string= web-mode-content-type "html") web-mode-enable-part-face)
   7215         (font-lock-append-text-property reg-beg reg-end 'face
   7216                                         (cond
   7217                                           ((string= content-type "javascript")
   7218                                            'web-mode-script-face)
   7219                                           ((string= content-type "css")
   7220                                            'web-mode-style-face)
   7221                                           (t
   7222                                            'web-mode-part-face)))
   7223         )
   7224 
   7225       (when (and web-mode-enable-css-colorization (string= content-type "stylus"))
   7226         (goto-char reg-beg)
   7227         (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)
   7228                     (<= (point) reg-end))
   7229           (web-mode-colorize (match-beginning 0) (match-end 0))
   7230           )
   7231         )
   7232 
   7233       (when (and (eq depth 0) (string= content-type "jsx"))
   7234         (let (pair elt-beg elt-end exp-beg exp-end exp-depth)
   7235           (goto-char reg-beg)
   7236           (while (setq pair (web-mode-jsx-element-next reg-end))
   7237             ;;(message "elt-pair=%S" pair)
   7238             (setq elt-beg (car pair)
   7239                   elt-end (cdr pair))
   7240             (remove-list-of-text-properties elt-beg (1+ elt-end) '(face))
   7241             (web-mode-fontify-tags elt-beg elt-end 1)
   7242             (goto-char elt-beg)
   7243             (while (setq pair (web-mode-jsx-expression-next elt-end))
   7244               ;;(message "exp-pair=%S elt-end=%S" pair elt-end)
   7245               (setq exp-beg (car pair)
   7246                     exp-end (cdr pair))
   7247               (when (eq (char-after exp-beg) ?\{)
   7248                 ;;(message "%S : %c %c" exp-beg (char-after (+ exp-beg 1)) (char-after (+ exp-beg 2)))
   7249                 (cond
   7250                   ;;((and (eq (char-after (+ exp-beg 1)) ?\/) (eq (char-after (+ exp-beg 2)) ?\*))
   7251                   ;; (put-text-property exp-beg (1+ exp-end) 'font-lock-face 'web-mode-part-comment-face)
   7252                   ;; )
   7253                   (t
   7254                    (setq exp-depth (get-text-property exp-beg 'jsx-depth))
   7255                    (remove-list-of-text-properties exp-beg exp-end '(font-lock-face))
   7256                    (put-text-property exp-beg (1+ exp-beg) 'font-lock-face 'web-mode-block-delimiter-face)
   7257                    (when (and (eq (get-text-property exp-beg 'tag-attr-beg) 4) (web-mode-looking-at-p "\.\.\." (1+ exp-beg)))
   7258                      (put-text-property exp-beg (+ exp-beg 4) 'font-lock-face 'web-mode-block-delimiter-face))
   7259                    (put-text-property exp-end (1+ exp-end) 'font-lock-face 'web-mode-block-delimiter-face)
   7260                    (web-mode-fontify-tags (1+ exp-beg) exp-end (1+ exp-depth))
   7261                    (web-mode-fontify-part (1+ exp-beg) exp-end exp-depth)
   7262                    (web-mode-fontify-region (1+ exp-beg) exp-end web-mode-javascript-font-lock-keywords)
   7263                    ) ;t
   7264                   ) ;cond
   7265                 ) ;when
   7266               (goto-char (1+ exp-beg))
   7267               ) ;while exp
   7268 
   7269             (when (and elt-beg web-mode-jsx-depth-faces)
   7270               (let (depth-beg depth-end jsx-face)
   7271                 (goto-char elt-beg)
   7272                 (while (setq pair (web-mode-jsx-depth-next reg-end))
   7273                   ;;(message "depth-pair=%S" pair)
   7274                   (setq depth-beg (car pair)
   7275                         depth-end (cdr pair)
   7276                         depth (get-text-property depth-beg 'jsx-depth)
   7277                         jsx-face (elt web-mode-jsx-depth-faces (1- depth)))
   7278                   ;;(message "%S" jsx-face)
   7279                   (font-lock-prepend-text-property depth-beg (1+ depth-end) 'face jsx-face)
   7280                   (goto-char (+ depth-beg 2))
   7281                   )
   7282                 ) ;let
   7283               )
   7284 
   7285             (goto-char (1+ elt-end))
   7286             ) ;while elt
   7287           ) ;let
   7288         ) ;when
   7289 
   7290       ) ;let
   7291     ) ;save-excursion
   7292   )
   7293 
   7294 (defun web-mode-fontify-css-rules (part-beg part-end)
   7295   (save-excursion
   7296     (goto-char part-beg)
   7297     (let (rule (continue t) (i 0) (at-rule nil))
   7298       (while continue
   7299         (setq rule (web-mode-css-rule-next part-end))
   7300         ;;(message "rule=%S" rule)
   7301         (cond
   7302           ((> (setq i (1+ i)) 1000)
   7303            (message "fontify-css-rules ** too much rules **")
   7304            (setq continue nil))
   7305           ((null rule)
   7306            (setq continue nil))
   7307           ((and (setq at-rule (plist-get rule :at-rule))
   7308                 (not (member at-rule '("charset" "font-face" "import" "viewport")))
   7309                 (plist-get rule :dec-end))
   7310            (web-mode-fontify-css-rule (plist-get rule :sel-beg)
   7311                                       (plist-get rule :sel-end)
   7312                                       nil nil)
   7313            (web-mode-fontify-css-rules (plist-get rule :dec-beg)
   7314                                        (plist-get rule :dec-end)))
   7315           (t
   7316            (web-mode-fontify-css-rule (plist-get rule :sel-beg)
   7317                                       (plist-get rule :sel-end)
   7318                                       (plist-get rule :dec-beg)
   7319                                       (plist-get rule :dec-end)))
   7320           ) ;cond
   7321         ) ;while
   7322       ) ;let
   7323     ))
   7324 
   7325 (defun web-mode-fontify-css-rule (sel-beg sel-end dec-beg dec-end)
   7326   (save-excursion
   7327     ;;(let ((end sel-end))
   7328     ;;(message "sel-beg=%S sel-end=%S dec-beg=%S dec-end=%S" sel-beg sel-end dec-beg dec-end)
   7329     (web-mode-fontify-region sel-beg sel-end web-mode-selector-font-lock-keywords)
   7330     (when (and dec-beg dec-end)
   7331       ;;(setq end dec-end)
   7332       (web-mode-fontify-region dec-beg dec-end web-mode-declaration-font-lock-keywords)
   7333       ) ;when
   7334     (when (and dec-beg dec-end)
   7335       (goto-char dec-beg)
   7336       (while (and web-mode-enable-css-colorization
   7337                   (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)
   7338                   ;;(progn (message "%S %S" end (point)) t)
   7339                   (<= (point) dec-end))
   7340         ;;(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)))
   7341         (web-mode-colorize (match-beginning 1) (match-end 1))
   7342         ) ;while
   7343       ) ;when
   7344     ;;) ;let
   7345     ))
   7346 
   7347 (defun web-mode-colorize-foreground (color)
   7348   (let* ((values (x-color-values color))
   7349          (r (car values))
   7350          (g (cadr values))
   7351          (b (car (cdr (cdr values)))))
   7352     (if (> 128.0 (floor (+ (* .3 r) (* .59 g) (* .11 b)) 256))
   7353         "white" "black")))
   7354 
   7355 (defun web-mode-colorize (beg end)
   7356   (let (str plist)
   7357     (setq str (buffer-substring-no-properties beg end))
   7358     ;;(setq str1 (match-string-no-properties 1))
   7359     ;;(message "str=%S" str str1)
   7360     (cond
   7361       ;;(t
   7362       ;; (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))
   7363       ;; )
   7364       ((string= (substring str 0 1) "#")
   7365        (setq plist (list :background str
   7366                          :foreground (web-mode-colorize-foreground str))))
   7367       ((and (>= (length str) 3) (string= (substring str 0 3) "rgb"))
   7368        (setq str (format "#%02X%02X%02X"
   7369                          (string-to-number (match-string-no-properties 2))
   7370                          (string-to-number (match-string-no-properties 3))
   7371                          (string-to-number (match-string-no-properties 4))))
   7372        (setq plist (list :background str
   7373                          :foreground (web-mode-colorize-foreground str))))
   7374       ((string= str "black") (setq plist (list :background "#000000" :foreground (web-mode-colorize-foreground "#000000"))))
   7375       ((string= str "silver") (setq plist (list :background "#c0c0c0" :foreground (web-mode-colorize-foreground "#c0c0c0"))))
   7376       ((string= str "gray") (setq plist (list :background "#808080" :foreground (web-mode-colorize-foreground "#808080"))))
   7377       ((string= str "white") (setq plist (list :background "#ffffff" :foreground (web-mode-colorize-foreground "#ffffff"))))
   7378       ((string= str "maroon") (setq plist (list :background "#800000" :foreground (web-mode-colorize-foreground "#800000"))))
   7379       ((string= str "red") (setq plist (list :background "#ff0000" :foreground (web-mode-colorize-foreground "#ff0000"))))
   7380       ((string= str "purple") (setq plist (list :background "#800080" :foreground (web-mode-colorize-foreground "#800080"))))
   7381       ((string= str "fuchsia") (setq plist (list :background "#ff00ff" :foreground (web-mode-colorize-foreground "#ff00ff"))))
   7382       ((string= str "green") (setq plist (list :background "#008000" :foreground (web-mode-colorize-foreground "#008000"))))
   7383       ((string= str "lime") (setq plist (list :background "#00ff00" :foreground (web-mode-colorize-foreground "#00ff00"))))
   7384       ((string= str "olive") (setq plist (list :background "#808000" :foreground (web-mode-colorize-foreground "#808000"))))
   7385       ((string= str "yellow") (setq plist (list :background "#ffff00" :foreground (web-mode-colorize-foreground "#ffff00"))))
   7386       ((string= str "navy") (setq plist (list :background "#000080" :foreground (web-mode-colorize-foreground "#000080"))))
   7387       ((string= str "blue") (setq plist (list :background "#0000ff" :foreground (web-mode-colorize-foreground "#0000ff"))))
   7388       ((string= str "teal") (setq plist (list :background "#008080" :foreground (web-mode-colorize-foreground "#008080"))))
   7389       ((string= str "aqua") (setq plist (list :background "#00ffff" :foreground (web-mode-colorize-foreground "#00ffff"))))
   7390       ((string= str "orange") (setq plist (list :background "#ffa500" :foreground (web-mode-colorize-foreground "#ffa500"))))
   7391       ((string= str "aliceblue") (setq plist (list :background "#f0f8ff" :foreground (web-mode-colorize-foreground "#f0f8ff"))))
   7392       ((string= str "antiquewhite") (setq plist (list :background "#faebd7" :foreground (web-mode-colorize-foreground "#faebd7"))))
   7393       ((string= str "aquamarine") (setq plist (list :background "#7fffd4" :foreground (web-mode-colorize-foreground "#7fffd4"))))
   7394       ((string= str "azure") (setq plist (list :background "#f0ffff" :foreground (web-mode-colorize-foreground "#f0ffff"))))
   7395       ((string= str "beige") (setq plist (list :background "#f5f5dc" :foreground (web-mode-colorize-foreground "#f5f5dc"))))
   7396       ((string= str "bisque") (setq plist (list :background "#ffe4c4" :foreground (web-mode-colorize-foreground "#ffe4c4"))))
   7397       ((string= str "blanchedalmond") (setq plist (list :background "#ffebcd" :foreground (web-mode-colorize-foreground "#ffebcd"))))
   7398       ((string= str "blueviolet") (setq plist (list :background "#8a2be2" :foreground (web-mode-colorize-foreground "#8a2be2"))))
   7399       ((string= str "brown") (setq plist (list :background "#a52a2a" :foreground (web-mode-colorize-foreground "#a52a2a"))))
   7400       ((string= str "burlywood") (setq plist (list :background "#deb887" :foreground (web-mode-colorize-foreground "#deb887"))))
   7401       ((string= str "cadetblue") (setq plist (list :background "#5f9ea0" :foreground (web-mode-colorize-foreground "#5f9ea0"))))
   7402       ((string= str "chartreuse") (setq plist (list :background "#7fff00" :foreground (web-mode-colorize-foreground "#7fff00"))))
   7403       ((string= str "chocolate") (setq plist (list :background "#d2691e" :foreground (web-mode-colorize-foreground "#d2691e"))))
   7404       ((string= str "coral") (setq plist (list :background "#ff7f50" :foreground (web-mode-colorize-foreground "#ff7f50"))))
   7405       ((string= str "cornflowerblue") (setq plist (list :background "#6495ed" :foreground (web-mode-colorize-foreground "#6495ed"))))
   7406       ((string= str "cornsilk") (setq plist (list :background "#fff8dc" :foreground (web-mode-colorize-foreground "#fff8dc"))))
   7407       ((string= str "crimson") (setq plist (list :background "#dc143c" :foreground (web-mode-colorize-foreground "#dc143c"))))
   7408       ((string= str "cyan") (setq plist (list :background "#00ffff" :foreground (web-mode-colorize-foreground "#00ffff"))))
   7409       ((string= str "darkblue") (setq plist (list :background "#00008b" :foreground (web-mode-colorize-foreground "#00008b"))))
   7410       ((string= str "darkcyan") (setq plist (list :background "#008b8b" :foreground (web-mode-colorize-foreground "#008b8b"))))
   7411       ((string= str "darkgoldenrod") (setq plist (list :background "#b8860b" :foreground (web-mode-colorize-foreground "#b8860b"))))
   7412       ((string= str "darkgray") (setq plist (list :background "#a9a9a9" :foreground (web-mode-colorize-foreground "#a9a9a9"))))
   7413       ((string= str "darkgreen") (setq plist (list :background "#006400" :foreground (web-mode-colorize-foreground "#006400"))))
   7414       ((string= str "darkgrey") (setq plist (list :background "#a9a9a9" :foreground (web-mode-colorize-foreground "#a9a9a9"))))
   7415       ((string= str "darkkhaki") (setq plist (list :background "#bdb76b" :foreground (web-mode-colorize-foreground "#bdb76b"))))
   7416       ((string= str "darkmagenta") (setq plist (list :background "#8b008b" :foreground (web-mode-colorize-foreground "#8b008b"))))
   7417       ((string= str "darkolivegreen") (setq plist (list :background "#556b2f" :foreground (web-mode-colorize-foreground "#556b2f"))))
   7418       ((string= str "darkorange") (setq plist (list :background "#ff8c00" :foreground (web-mode-colorize-foreground "#ff8c00"))))
   7419       ((string= str "darkorchid") (setq plist (list :background "#9932cc" :foreground (web-mode-colorize-foreground "#9932cc"))))
   7420       ((string= str "darkred") (setq plist (list :background "#8b0000" :foreground (web-mode-colorize-foreground "#8b0000"))))
   7421       ((string= str "darksalmon") (setq plist (list :background "#e9967a" :foreground (web-mode-colorize-foreground "#e9967a"))))
   7422       ((string= str "darkseagreen") (setq plist (list :background "#8fbc8f" :foreground (web-mode-colorize-foreground "#8fbc8f"))))
   7423       ((string= str "darkslateblue") (setq plist (list :background "#483d8b" :foreground (web-mode-colorize-foreground "#483d8b"))))
   7424       ((string= str "darkslategray") (setq plist (list :background "#2f4f4f" :foreground (web-mode-colorize-foreground "#2f4f4f"))))
   7425       ((string= str "darkslategrey") (setq plist (list :background "#2f4f4f" :foreground (web-mode-colorize-foreground "#2f4f4f"))))
   7426       ((string= str "darkturquoise") (setq plist (list :background "#00ced1" :foreground (web-mode-colorize-foreground "#00ced1"))))
   7427       ((string= str "darkviolet") (setq plist (list :background "#9400d3" :foreground (web-mode-colorize-foreground "#9400d3"))))
   7428       ((string= str "deeppink") (setq plist (list :background "#ff1493" :foreground (web-mode-colorize-foreground "#ff1493"))))
   7429       ((string= str "deepskyblue") (setq plist (list :background "#00bfff" :foreground (web-mode-colorize-foreground "#00bfff"))))
   7430       ((string= str "dimgray") (setq plist (list :background "#696969" :foreground (web-mode-colorize-foreground "#696969"))))
   7431       ((string= str "dimgrey") (setq plist (list :background "#696969" :foreground (web-mode-colorize-foreground "#696969"))))
   7432       ((string= str "dodgerblue") (setq plist (list :background "#1e90ff" :foreground (web-mode-colorize-foreground "#1e90ff"))))
   7433       ((string= str "firebrick") (setq plist (list :background "#b22222" :foreground (web-mode-colorize-foreground "#b22222"))))
   7434       ((string= str "floralwhite") (setq plist (list :background "#fffaf0" :foreground (web-mode-colorize-foreground "#fffaf0"))))
   7435       ((string= str "forestgreen") (setq plist (list :background "#228b22" :foreground (web-mode-colorize-foreground "#228b22"))))
   7436       ((string= str "gainsboro") (setq plist (list :background "#dcdcdc" :foreground (web-mode-colorize-foreground "#dcdcdc"))))
   7437       ((string= str "ghostwhite") (setq plist (list :background "#f8f8ff" :foreground (web-mode-colorize-foreground "#f8f8ff"))))
   7438       ((string= str "gold") (setq plist (list :background "#ffd700" :foreground (web-mode-colorize-foreground "#ffd700"))))
   7439       ((string= str "goldenrod") (setq plist (list :background "#daa520" :foreground (web-mode-colorize-foreground "#daa520"))))
   7440       ((string= str "greenyellow") (setq plist (list :background "#adff2f" :foreground (web-mode-colorize-foreground "#adff2f"))))
   7441       ((string= str "grey") (setq plist (list :background "#808080" :foreground (web-mode-colorize-foreground "#808080"))))
   7442       ((string= str "honeydew") (setq plist (list :background "#f0fff0" :foreground (web-mode-colorize-foreground "#f0fff0"))))
   7443       ((string= str "hotpink") (setq plist (list :background "#ff69b4" :foreground (web-mode-colorize-foreground "#ff69b4"))))
   7444       ((string= str "indianred") (setq plist (list :background "#cd5c5c" :foreground (web-mode-colorize-foreground "#cd5c5c"))))
   7445       ((string= str "indigo") (setq plist (list :background "#4b0082" :foreground (web-mode-colorize-foreground "#4b0082"))))
   7446       ((string= str "ivory") (setq plist (list :background "#fffff0" :foreground (web-mode-colorize-foreground "#fffff0"))))
   7447       ((string= str "khaki") (setq plist (list :background "#f0e68c" :foreground (web-mode-colorize-foreground "#f0e68c"))))
   7448       ((string= str "lavender") (setq plist (list :background "#e6e6fa" :foreground (web-mode-colorize-foreground "#e6e6fa"))))
   7449       ((string= str "lavenderblush") (setq plist (list :background "#fff0f5" :foreground (web-mode-colorize-foreground "#fff0f5"))))
   7450       ((string= str "lawngreen") (setq plist (list :background "#7cfc00" :foreground (web-mode-colorize-foreground "#7cfc00"))))
   7451       ((string= str "lemonchiffon") (setq plist (list :background "#fffacd" :foreground (web-mode-colorize-foreground "#fffacd"))))
   7452       ((string= str "lightblue") (setq plist (list :background "#add8e6" :foreground (web-mode-colorize-foreground "#add8e6"))))
   7453       ((string= str "lightcoral") (setq plist (list :background "#f08080" :foreground (web-mode-colorize-foreground "#f08080"))))
   7454       ((string= str "lightcyan") (setq plist (list :background "#e0ffff" :foreground (web-mode-colorize-foreground "#e0ffff"))))
   7455       ((string= str "lightgoldenrodyellow") (setq plist (list :background "#fafad2" :foreground (web-mode-colorize-foreground "#fafad2"))))
   7456       ((string= str "lightgray") (setq plist (list :background "#d3d3d3" :foreground (web-mode-colorize-foreground "#d3d3d3"))))
   7457       ((string= str "lightgreen") (setq plist (list :background "#90ee90" :foreground (web-mode-colorize-foreground "#90ee90"))))
   7458       ((string= str "lightgrey") (setq plist (list :background "#d3d3d3" :foreground (web-mode-colorize-foreground "#d3d3d3"))))
   7459       ((string= str "lightpink") (setq plist (list :background "#ffb6c1" :foreground (web-mode-colorize-foreground "#ffb6c1"))))
   7460       ((string= str "lightsalmon") (setq plist (list :background "#ffa07a" :foreground (web-mode-colorize-foreground "#ffa07a"))))
   7461       ((string= str "lightseagreen") (setq plist (list :background "#20b2aa" :foreground (web-mode-colorize-foreground "#20b2aa"))))
   7462       ((string= str "lightskyblue") (setq plist (list :background "#87cefa" :foreground (web-mode-colorize-foreground "#87cefa"))))
   7463       ((string= str "lightslategray") (setq plist (list :background "#778899" :foreground (web-mode-colorize-foreground "#778899"))))
   7464       ((string= str "lightslategrey") (setq plist (list :background "#778899" :foreground (web-mode-colorize-foreground "#778899"))))
   7465       ((string= str "lightsteelblue") (setq plist (list :background "#b0c4de" :foreground (web-mode-colorize-foreground "#b0c4de"))))
   7466       ((string= str "lightyellow") (setq plist (list :background "#ffffe0" :foreground (web-mode-colorize-foreground "#ffffe0"))))
   7467       ((string= str "limegreen") (setq plist (list :background "#32cd32" :foreground (web-mode-colorize-foreground "#32cd32"))))
   7468       ((string= str "linen") (setq plist (list :background "#faf0e6" :foreground (web-mode-colorize-foreground "#faf0e6"))))
   7469       ((string= str "magenta") (setq plist (list :background "#ff00ff" :foreground (web-mode-colorize-foreground "#ff00ff"))))
   7470       ((string= str "mediumaquamarine") (setq plist (list :background "#66cdaa" :foreground (web-mode-colorize-foreground "#66cdaa"))))
   7471       ((string= str "mediumblue") (setq plist (list :background "#0000cd" :foreground (web-mode-colorize-foreground "#0000cd"))))
   7472       ((string= str "mediumorchid") (setq plist (list :background "#ba55d3" :foreground (web-mode-colorize-foreground "#ba55d3"))))
   7473       ((string= str "mediumpurple") (setq plist (list :background "#9370db" :foreground (web-mode-colorize-foreground "#9370db"))))
   7474       ((string= str "mediumseagreen") (setq plist (list :background "#3cb371" :foreground (web-mode-colorize-foreground "#3cb371"))))
   7475       ((string= str "mediumslateblue") (setq plist (list :background "#7b68ee" :foreground (web-mode-colorize-foreground "#7b68ee"))))
   7476       ((string= str "mediumspringgreen") (setq plist (list :background "#00fa9a" :foreground (web-mode-colorize-foreground "#00fa9a"))))
   7477       ((string= str "mediumturquoise") (setq plist (list :background "#48d1cc" :foreground (web-mode-colorize-foreground "#48d1cc"))))
   7478       ((string= str "mediumvioletred") (setq plist (list :background "#c71585" :foreground (web-mode-colorize-foreground "#c71585"))))
   7479       ((string= str "midnightblue") (setq plist (list :background "#191970" :foreground (web-mode-colorize-foreground "#191970"))))
   7480       ((string= str "mintcream") (setq plist (list :background "#f5fffa" :foreground (web-mode-colorize-foreground "#f5fffa"))))
   7481       ((string= str "mistyrose") (setq plist (list :background "#ffe4e1" :foreground (web-mode-colorize-foreground "#ffe4e1"))))
   7482       ((string= str "moccasin") (setq plist (list :background "#ffe4b5" :foreground (web-mode-colorize-foreground "#ffe4b5"))))
   7483       ((string= str "navajowhite") (setq plist (list :background "#ffdead" :foreground (web-mode-colorize-foreground "#ffdead"))))
   7484       ((string= str "oldlace") (setq plist (list :background "#fdf5e6" :foreground (web-mode-colorize-foreground "#fdf5e6"))))
   7485       ((string= str "olivedrab") (setq plist (list :background "#6b8e23" :foreground (web-mode-colorize-foreground "#6b8e23"))))
   7486       ((string= str "orangered") (setq plist (list :background "#ff4500" :foreground (web-mode-colorize-foreground "#ff4500"))))
   7487       ((string= str "orchid") (setq plist (list :background "#da70d6" :foreground (web-mode-colorize-foreground "#da70d6"))))
   7488       ((string= str "palegoldenrod") (setq plist (list :background "#eee8aa" :foreground (web-mode-colorize-foreground "#eee8aa"))))
   7489       ((string= str "palegreen") (setq plist (list :background "#98fb98" :foreground (web-mode-colorize-foreground "#98fb98"))))
   7490       ((string= str "paleturquoise") (setq plist (list :background "#afeeee" :foreground (web-mode-colorize-foreground "#afeeee"))))
   7491       ((string= str "palevioletred") (setq plist (list :background "#db7093" :foreground (web-mode-colorize-foreground "#db7093"))))
   7492       ((string= str "papayawhip") (setq plist (list :background "#ffefd5" :foreground (web-mode-colorize-foreground "#ffefd5"))))
   7493       ((string= str "peachpuff") (setq plist (list :background "#ffdab9" :foreground (web-mode-colorize-foreground "#ffdab9"))))
   7494       ((string= str "peru") (setq plist (list :background "#cd853f" :foreground (web-mode-colorize-foreground "#cd853f"))))
   7495       ((string= str "pink") (setq plist (list :background "#ffc0cb" :foreground (web-mode-colorize-foreground "#ffc0cb"))))
   7496       ((string= str "plum") (setq plist (list :background "#dda0dd" :foreground (web-mode-colorize-foreground "#dda0dd"))))
   7497       ((string= str "powderblue") (setq plist (list :background "#b0e0e6" :foreground (web-mode-colorize-foreground "#b0e0e6"))))
   7498       ((string= str "rosybrown") (setq plist (list :background "#bc8f8f" :foreground (web-mode-colorize-foreground "#bc8f8f"))))
   7499       ((string= str "royalblue") (setq plist (list :background "#4169e1" :foreground (web-mode-colorize-foreground "#4169e1"))))
   7500       ((string= str "saddlebrown") (setq plist (list :background "#8b4513" :foreground (web-mode-colorize-foreground "#8b4513"))))
   7501       ((string= str "salmon") (setq plist (list :background "#fa8072" :foreground (web-mode-colorize-foreground "#fa8072"))))
   7502       ((string= str "sandybrown") (setq plist (list :background "#f4a460" :foreground (web-mode-colorize-foreground "#f4a460"))))
   7503       ((string= str "seagreen") (setq plist (list :background "#2e8b57" :foreground (web-mode-colorize-foreground "#2e8b57"))))
   7504       ((string= str "seashell") (setq plist (list :background "#fff5ee" :foreground (web-mode-colorize-foreground "#fff5ee"))))
   7505       ((string= str "sienna") (setq plist (list :background "#a0522d" :foreground (web-mode-colorize-foreground "#a0522d"))))
   7506       ((string= str "skyblue") (setq plist (list :background "#87ceeb" :foreground (web-mode-colorize-foreground "#87ceeb"))))
   7507       ((string= str "slateblue") (setq plist (list :background "#6a5acd" :foreground (web-mode-colorize-foreground "#6a5acd"))))
   7508       ((string= str "slategray") (setq plist (list :background "#708090" :foreground (web-mode-colorize-foreground "#708090"))))
   7509       ((string= str "slategrey") (setq plist (list :background "#708090" :foreground (web-mode-colorize-foreground "#708090"))))
   7510       ((string= str "snow") (setq plist (list :background "#fffafa" :foreground (web-mode-colorize-foreground "#fffafa"))))
   7511       ((string= str "springgreen") (setq plist (list :background "#00ff7f" :foreground (web-mode-colorize-foreground "#00ff7f"))))
   7512       ((string= str "steelblue") (setq plist (list :background "#4682b4" :foreground (web-mode-colorize-foreground "#4682b4"))))
   7513       ((string= str "tan") (setq plist (list :background "#d2b48c" :foreground (web-mode-colorize-foreground "#d2b48c"))))
   7514       ((string= str "thistle") (setq plist (list :background "#d8bfd8" :foreground (web-mode-colorize-foreground "#d8bfd8"))))
   7515       ((string= str "tomato") (setq plist (list :background "#ff6347" :foreground (web-mode-colorize-foreground "#ff6347"))))
   7516       ((string= str "turquoise") (setq plist (list :background "#40e0d0" :foreground (web-mode-colorize-foreground "#40e0d0"))))
   7517       ((string= str "violet") (setq plist (list :background "#ee82ee" :foreground (web-mode-colorize-foreground "#ee82ee"))))
   7518       ((string= str "wheat") (setq plist (list :background "#f5deb3" :foreground (web-mode-colorize-foreground "#f5deb3"))))
   7519       ((string= str "whitesmoke") (setq plist (list :background "#f5f5f5" :foreground (web-mode-colorize-foreground "#f5f5f5"))))
   7520       ((string= str "yellowgreen") (setq plist (list :background "#9acd32" :foreground (web-mode-colorize-foreground "#9acd32"))))
   7521       ) ;cond
   7522     (put-text-property beg end 'face plist)
   7523     ))
   7524 
   7525 (defun web-mode-interpolate-block-tag (beg end)
   7526   (save-excursion
   7527     (goto-char (+ 4 beg))
   7528     (setq end (1- end))
   7529     (while (re-search-forward "${.*?}" end t)
   7530       (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(face))
   7531       (web-mode-fontify-region (match-beginning 0) (match-end 0)
   7532                                web-mode-uel-font-lock-keywords))
   7533     ))
   7534 
   7535 (defun web-mode-interpolate-javascript-string (beg end)
   7536   (save-excursion
   7537     (goto-char (1+ beg))
   7538     (setq end (1- end))
   7539     (while (re-search-forward "${.*?}" end t)
   7540       (put-text-property (match-beginning 0) (match-end 0)
   7541                          'font-lock-face
   7542                          'web-mode-variable-name-face)
   7543       )
   7544     ))
   7545 
   7546 (defun web-mode-interpolate-javascript-literal (beg end)
   7547   (save-excursion
   7548     (setq end (1- end))
   7549     (goto-char (1+ beg))
   7550     (cond
   7551       ((web-mode-looking-back "\\(css\\|styled[[:alnum:].]+\\|css = \\)" beg)
   7552        (goto-char (1+ beg))
   7553        (while (re-search-forward ".*?:" end t)
   7554          (put-text-property (match-beginning 0) (match-end 0)
   7555                             'font-lock-face
   7556                             'web-mode-interpolate-color1-face)
   7557          )
   7558        ) ;case css
   7559       ((web-mode-looking-back "\\(template\\|html\\|html = \\)" beg)
   7560        (goto-char (1+ beg))
   7561        (while (re-search-forward web-mode-tag-regexp end t)
   7562          (put-text-property (match-beginning 1) (match-end 1)
   7563                             'font-lock-face
   7564                             'web-mode-interpolate-color1-face)
   7565          )
   7566        (goto-char (1+ beg))
   7567        (while (re-search-forward "</?\\|/?>\\| [.@?]?[[:alnum:]]+=" end t)
   7568          (cond
   7569            ((member (char-after (match-beginning 0)) '(?\< ?\/ ?\>))
   7570             (put-text-property (match-beginning 0) (match-end 0)
   7571                                'font-lock-face
   7572                                'web-mode-interpolate-color2-face)
   7573             )
   7574            (t
   7575             (put-text-property (1+ (match-beginning 0)) (1- (match-end 0))
   7576                                'font-lock-face
   7577                                'web-mode-interpolate-color3-face)
   7578             ) ;t
   7579            ) ;cond
   7580          ) ;while
   7581        (goto-char (1+ beg))
   7582        (while (re-search-forward "<\\(script\\|style\\)>\\(.*\\)</\\(script\\|style\\)>" end t)
   7583          (put-text-property (match-beginning 2) (match-end 2)
   7584                             'font-lock-face
   7585                             'web-mode-interpolate-color4-face)
   7586          )
   7587        ) ;case html
   7588       ) ;cond type of literal
   7589     (goto-char (1+ beg))
   7590     (while (re-search-forward "${.*?}" end t)
   7591       (put-text-property (match-beginning 0) (match-end 0)
   7592                          'font-lock-face
   7593                          'web-mode-variable-name-face)
   7594       ) ;while
   7595     ))
   7596 
   7597 ;; todo : parsing plus compliqué: {$obj->values[3]->name}
   7598 (defun web-mode-interpolate-block-string (beg end)
   7599   (save-excursion
   7600     (goto-char (1+ beg))
   7601     (setq end (1- end))
   7602     (cond
   7603       ((string= web-mode-engine "php")
   7604        (while (re-search-forward "$[[:alnum:]_]+\\(->[[:alnum:]_]+\\)*\\|{[ ]*$.+?}" end t)
   7605          ;;        (message "%S > %S" (match-beginning 0) (match-end 0))
   7606          (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(font-lock-face))
   7607          (web-mode-fontify-region (match-beginning 0) (match-end 0)
   7608                                   web-mode-php-var-interpolation-font-lock-keywords)
   7609          ))
   7610       ((string= web-mode-engine "erb")
   7611        (while (re-search-forward "#{.*?}" end t)
   7612          (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(font-lock-face))
   7613          (put-text-property (match-beginning 0) (match-end 0)
   7614                             'font-lock-face 'web-mode-variable-name-face)
   7615          ))
   7616       ) ;cond
   7617     ))
   7618 
   7619 (defun web-mode-interpolate-comment (beg end _block-side)
   7620   (save-excursion
   7621     (let ((regexp (concat "\\_<\\(" web-mode-comment-keywords "\\)\\_>")))
   7622       (goto-char beg)
   7623       (while (re-search-forward regexp end t)
   7624         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7625                                          'font-lock-face
   7626                                          'web-mode-comment-keyword-face)
   7627         ) ;while
   7628       )))
   7629 
   7630 (defun web-mode-annotate-comment (beg end)
   7631   (save-excursion
   7632     ;;(message "beg=%S end=%S" beg end)
   7633     (goto-char beg)
   7634     (when (looking-at-p "/\\*\\*")
   7635       (while (re-search-forward "\\(.+\\)" end t)
   7636         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7637                                          'font-lock-face
   7638                                          'web-mode-annotation-face))
   7639       (goto-char beg)
   7640       (while (re-search-forward "[ ]+\\({[^}]+}\\)" end t)
   7641         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7642                                          'font-lock-face
   7643                                          'web-mode-annotation-type-face))
   7644       (goto-char beg)
   7645       (while (re-search-forward "\\(@[[:alnum:]]+\\)" end t)
   7646         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7647                                          'font-lock-face
   7648                                          'web-mode-annotation-tag-face))
   7649       (goto-char beg)
   7650       (while (re-search-forward "}[[:blank:]]+\\([[:graph:]]+\\)" end t)
   7651         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7652                                          'font-lock-face
   7653                                          'web-mode-annotation-value-face))
   7654       (goto-char beg)
   7655       (while (re-search-forward "@see[[:blank:]]+\\([[:graph:]]+\\)" end t)
   7656         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7657                                          'font-lock-face
   7658                                          'web-mode-annotation-value-face))
   7659       (goto-char beg)
   7660       (while (re-search-forward "{\\(@\\(?:link\\|code\\)\\)\\s-+\\([^}\n]+\\)\\(#.+\\)?}" end t)
   7661         (font-lock-prepend-text-property (match-beginning 2) (match-end 2)
   7662                                          'font-lock-face
   7663                                          'web-mode-annotation-value-face))
   7664       (goto-char beg)
   7665       (while (re-search-forward "\\(</?\\)\\([[:alnum:]]+\\)\\s-*\\(/?>\\)" end t)
   7666         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7667                                          'font-lock-face
   7668                                          'web-mode-annotation-html-face)
   7669         (font-lock-prepend-text-property (match-beginning 2) (match-end 2)
   7670                                          'font-lock-face
   7671                                          'web-mode-annotation-html-face)
   7672         (font-lock-prepend-text-property (match-beginning 3) (match-end 3)
   7673                                          'font-lock-face
   7674                                          'web-mode-annotation-html-face))
   7675       ) ;when
   7676     ))
   7677 
   7678 (defun web-mode-interpolate-sql-string (beg end)
   7679   (save-excursion
   7680     (let ((case-fold-search t)
   7681           (regexp (concat "\\_<\\(" web-mode-sql-keywords "\\)\\_>")))
   7682       (goto-char beg)
   7683       (while (re-search-forward regexp end t)
   7684         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7685                                          'font-lock-face
   7686                                          'web-mode-sql-keyword-face)
   7687         ) ;while
   7688       )))
   7689 
   7690 ;;---- EFFECTS -----------------------------------------------------------------
   7691 
   7692 (defun web-mode-fill-paragraph (&optional _justify)
   7693   (save-excursion
   7694     (let ((pos (point))
   7695           prop pair beg end delim-beg delim-end chunk fill-coll)
   7696       (ignore delim-beg delim-end fill-coll)
   7697       (cond
   7698         ((or (eq (get-text-property pos 'part-token) 'comment)
   7699              (eq (get-text-property pos 'block-token) 'comment))
   7700          (setq prop
   7701                (if (get-text-property pos 'part-token) 'part-token 'block-token))
   7702          (setq pair (web-mode-property-boundaries prop pos))
   7703          (when (and pair (> (- (cdr pair) (car pair)) 6))
   7704            (setq fill-coll (if (< fill-column 10) 70 fill-column))
   7705            (setq beg (car pair)
   7706                  end (cdr pair))
   7707            (goto-char beg)
   7708            (setq chunk (buffer-substring-no-properties beg (+ beg 2)))
   7709            (cond
   7710              ((string= chunk "//")
   7711               (setq delim-beg "//"
   7712                     delim-end "EOL"))
   7713              ((string= chunk "/*")
   7714               (setq delim-beg "/*"
   7715                     delim-end "*/"))
   7716              ((string= chunk "{#")
   7717               (setq delim-beg "{#"
   7718                     delim-end "#}"))
   7719              ((string= chunk "<!")
   7720               (setq delim-beg "<!--"
   7721                     delim-end "-->"))
   7722              )
   7723            )
   7724          ) ;comment - case
   7725         ((web-mode-is-content)
   7726          (setq pair (web-mode-content-boundaries pos))
   7727          (setq beg (car pair)
   7728                end (cdr pair))
   7729          )
   7730         ) ;cond
   7731       ;;(message "beg(%S) end(%S)" beg end)
   7732       (when (and beg end)
   7733         (fill-region beg end))
   7734       t)))
   7735 
   7736 (defun web-mode-engine-syntax-check ()
   7737   (interactive)
   7738   (let ((proc nil) (errors nil)
   7739         (file (concat temporary-file-directory "emacs-web-mode-tmp")))
   7740     (write-region (point-min) (point-max) file)
   7741     (cond
   7742       ;; ((null (buffer-file-name))
   7743       ;; )
   7744       ((string= web-mode-engine "php")
   7745        (setq proc (start-process "php-proc" nil "php" "-l" file))
   7746        (set-process-filter
   7747         proc
   7748         (lambda (_proc output)
   7749           (cond
   7750             ((string-match-p "No syntax errors" output)
   7751              (message "No syntax errors")
   7752              )
   7753             (t
   7754              ;; (setq output (replace-regexp-in-string temporary-file-directory "" output))
   7755              ;; (message output)
   7756              (message "Syntax error")
   7757              (setq errors t))
   7758             ) ;cond
   7759           ;; (delete-file file)
   7760           ) ;lambda
   7761         )
   7762        ) ;php
   7763       (t
   7764        (message "no syntax checker found")
   7765        ) ;t
   7766       ) ;cond
   7767     errors))
   7768 
   7769 (defun web-mode-jshint ()
   7770   "Run JSHint on all the JavaScript parts."
   7771   (interactive)
   7772   (let (proc)
   7773     (when (buffer-file-name)
   7774       (setq proc (start-process
   7775                   "jshint-proc"
   7776                   nil
   7777                   (or (executable-find "jshint") "/usr/local/bin/jshint")
   7778                   "--extract=auto"
   7779                   (buffer-file-name)))
   7780       (setq web-mode-jshint-errors 0)
   7781       (set-process-filter proc
   7782                           (lambda (_proc output)
   7783                             (let ((offset 0) overlay pos (old 0) msg)
   7784                               (remove-overlays (point-min) (point-max) 'font-lock-face 'web-mode-error-face)
   7785                               (while (string-match
   7786                                       "line \\([[:digit:]]+\\), col \\([[:digit:]]+\\), \\(.+\\)\\.$"
   7787                                       output offset)
   7788                                 (setq web-mode-jshint-errors (1+ web-mode-jshint-errors))
   7789                                 (setq offset (match-end 0))
   7790                                 (setq pos (web-mode-coord-position
   7791                                            (match-string-no-properties 1 output)
   7792                                            (match-string-no-properties 2 output)))
   7793                                 (when (get-text-property pos 'tag-beg)
   7794                                   (setq pos (1- pos)))
   7795                                 (when (not (= pos old))
   7796                                   (setq old pos)
   7797                                   (setq overlay (make-overlay pos (1+ pos)))
   7798                                   (overlay-put overlay 'font-lock-face 'web-mode-error-face)
   7799                                   )
   7800                                 (setq msg (or (overlay-get overlay 'help-echo)
   7801                                               (concat "line="
   7802                                                       (match-string-no-properties 1 output)
   7803                                                       " column="
   7804                                                       (match-string-no-properties 2 output)
   7805                                                       )))
   7806                                 (overlay-put overlay 'help-echo
   7807                                              (concat msg " ## " (match-string-no-properties 3 output)))
   7808                                 ) ;while
   7809                               ))
   7810                           )
   7811       ) ;when
   7812     ))
   7813 
   7814 (defun web-mode-dom-errors-show ()
   7815   "Show unclosed tags."
   7816   (interactive)
   7817   (let (beg end tag pos l tags i cont cell overlay overlays first
   7818             (ori (point))
   7819             (errors 0)
   7820             (continue t)
   7821             )
   7822     (setq overlays (overlays-in (point-min) (point-max)))
   7823     (when overlays
   7824       (dolist (overlay overlays)
   7825         (when (eq (overlay-get overlay 'face) 'web-mode-warning-face)
   7826           (delete-overlay overlay)
   7827           )
   7828         )
   7829       )
   7830     (goto-char (point-min))
   7831     (when (not (or (get-text-property (point) 'tag-beg)
   7832                    (web-mode-tag-next)))
   7833       (setq continue nil))
   7834     (while continue
   7835       (setq pos (point))
   7836       (setq tag (get-text-property pos 'tag-name))
   7837       (cond
   7838         ((eq (get-text-property (point) 'tag-type) 'start)
   7839          (setq tags (push (list tag pos) tags))
   7840          ;;        (message "(%S) opening %S" pos tag)
   7841          )
   7842         ((eq (get-text-property (point) 'tag-type) 'end)
   7843          (setq i 0
   7844                l (length tags)
   7845                cont t)
   7846          (while (and (< i l) cont)
   7847            (setq cell (nth i tags))
   7848            ;;          (message "cell=%S" cell)
   7849            (setq i (1+ i))
   7850            (cond
   7851              ((string= tag (nth 0 cell))
   7852               (setq cont nil)
   7853               )
   7854              (t
   7855               (setq errors (1+ errors))
   7856               (setq beg (nth 1 cell))
   7857               (setq end (web-mode-tag-end-position beg))
   7858               (unless first
   7859                 (setq first beg))
   7860               (setq overlay (make-overlay beg (1+ end)))
   7861               (overlay-put overlay 'font-lock-face 'web-mode-warning-face)
   7862               ;;            (message "invalid <%S> at %S" (nth 0 cell) (nth 1 cell))
   7863               )
   7864              ) ;cond
   7865            ) ;while
   7866 
   7867          (dotimes (_i i)
   7868            (setq tags (cdr tags)))
   7869 
   7870          )
   7871         ) ;cond
   7872       (when (not (web-mode-tag-next))
   7873         (setq continue nil))
   7874       ) ;while
   7875     (message "%S error(s) detected" errors)
   7876     (if (< errors 1)
   7877         (goto-char ori)
   7878         (goto-char first)
   7879         (recenter))
   7880     ;;    (message "%S" tags)
   7881     ))
   7882 
   7883 (defun web-mode-fontify-elements (beg end)
   7884   (save-excursion
   7885     (goto-char beg)
   7886     (let ((continue (or (get-text-property (point) 'tag-beg) (web-mode-tag-next)))
   7887           (i 0) (ctx nil) (face nil))
   7888       (while continue
   7889         (cond
   7890           ((> (setq i (1+ i)) 1000)
   7891            (message "fontify-elements ** too much tags **")
   7892            (setq continue nil))
   7893           ((> (point) end)
   7894            (setq continue nil))
   7895           ((not (get-text-property (point) 'tag-beg))
   7896            (setq continue nil))
   7897           ((eq (get-text-property (point) 'tag-type) 'start)
   7898            (when (and (setq ctx (web-mode-element-boundaries (point)))
   7899                       (<= (car (cdr ctx)) end)
   7900                       (setq face (cdr (assoc (get-text-property (point) 'tag-name) web-mode-element-content-faces))))
   7901              (font-lock-prepend-text-property (1+ (cdr (car ctx))) (car (cdr ctx))
   7902                                               'font-lock-face face))
   7903            )
   7904           ) ;cond
   7905         (when (not (web-mode-tag-next))
   7906           (setq continue nil))
   7907         ) ;while
   7908       )))
   7909 
   7910 (defun web-mode-enable (feature)
   7911   "Enable one feature."
   7912   (interactive
   7913    (list (completing-read
   7914           "Feature: "
   7915           (let (features)
   7916             (dolist (elt web-mode-features)
   7917               (setq features (append features (list (car elt)))))
   7918             features))))
   7919   (when (and (or (not feature) (< (length feature) 1)) web-mode-last-enabled-feature)
   7920     (setq feature web-mode-last-enabled-feature))
   7921   (when feature
   7922     (setq web-mode-last-enabled-feature feature)
   7923     (setq feature (cdr (assoc feature web-mode-features)))
   7924     (cond
   7925       ((eq feature 'web-mode-enable-current-column-highlight)
   7926        (web-mode-column-show))
   7927       ((eq feature 'web-mode-enable-current-element-highlight)
   7928        (when (not web-mode-enable-current-element-highlight)
   7929          (web-mode-toggle-current-element-highlight))
   7930        )
   7931       ((eq feature 'web-mode-enable-whitespace-fontification)
   7932        (web-mode-whitespaces-on))
   7933       (t
   7934        (set feature t)
   7935        (web-mode-buffer-fontify))
   7936       )
   7937     ) ;when
   7938   )
   7939 
   7940 (defun web-mode-disable (feature)
   7941   "Disable one feature."
   7942   (interactive
   7943    (list (completing-read
   7944           "Feature: "
   7945           (let (features)
   7946             (dolist (elt web-mode-features)
   7947               (setq features (append features (list (car elt)))))
   7948             features))))
   7949   (when (and (or (not feature) (< (length feature) 1)) web-mode-last-enabled-feature)
   7950     (setq feature web-mode-last-enabled-feature))
   7951   (when feature
   7952     (setq feature (cdr (assoc feature web-mode-features)))
   7953     (cond
   7954       ((eq feature 'web-mode-enable-current-column-highlight)
   7955        (web-mode-column-hide))
   7956       ((eq feature 'web-mode-enable-current-element-highlight)
   7957        (when web-mode-enable-current-element-highlight
   7958          (web-mode-toggle-current-element-highlight))
   7959        )
   7960       ((eq feature 'web-mode-enable-whitespace-fontification)
   7961        (web-mode-whitespaces-off))
   7962       (t
   7963        (set feature nil)
   7964        (web-mode-buffer-fontify))
   7965       )
   7966     ) ;when
   7967   )
   7968 
   7969 (defun web-mode-toggle-current-element-highlight ()
   7970   "Toggle highlighting of the current html element."
   7971   (interactive)
   7972   (if web-mode-enable-current-element-highlight
   7973       (progn
   7974         (web-mode-delete-tag-overlays)
   7975         (setq web-mode-enable-current-element-highlight nil))
   7976       (setq web-mode-enable-current-element-highlight t)
   7977       ))
   7978 
   7979 (defun web-mode-make-tag-overlays ()
   7980   (unless web-mode-overlay-tag-start
   7981     (setq web-mode-overlay-tag-start (make-overlay 1 1)
   7982           web-mode-overlay-tag-end (make-overlay 1 1))
   7983     (overlay-put web-mode-overlay-tag-start
   7984                  'font-lock-face
   7985                  'web-mode-current-element-highlight-face)
   7986     (overlay-put web-mode-overlay-tag-end
   7987                  'font-lock-face
   7988                  'web-mode-current-element-highlight-face)))
   7989 
   7990 (defun web-mode-delete-tag-overlays ()
   7991   (when web-mode-overlay-tag-start
   7992     (delete-overlay web-mode-overlay-tag-start)
   7993     (delete-overlay web-mode-overlay-tag-end)))
   7994 
   7995 (defun web-mode-column-overlay-factory (index)
   7996   (let (overlay)
   7997     (when (null web-mode-column-overlays)
   7998       (dotimes (_i 100)
   7999         (setq overlay (make-overlay 1 1))
   8000         (overlay-put overlay 'font-lock-face 'web-mode-current-column-highlight-face)
   8001         (setq web-mode-column-overlays (append web-mode-column-overlays (list overlay)))
   8002         )
   8003       ) ;when
   8004     (setq overlay (nth index web-mode-column-overlays))
   8005     (when (null overlay)
   8006       (setq overlay (make-overlay 1 1))
   8007       (overlay-put overlay 'font-lock-face 'web-mode-current-column-highlight-face)
   8008       (setq web-mode-column-overlays (append web-mode-column-overlays (list overlay)))
   8009       ) ;when
   8010     overlay))
   8011 
   8012 (defun web-mode-column-hide ()
   8013   (setq web-mode-enable-current-column-highlight nil)
   8014   (remove-overlays (point-min) (point-max)
   8015                    'font-lock-face
   8016                    'web-mode-current-column-highlight-face))
   8017 
   8018 (defun web-mode-count-invisible-character-ranges (min max)
   8019   (interactive "r")
   8020   (let ((count 0) (current-pos min))
   8021     (save-excursion
   8022       (while (<= current-pos max)
   8023         (goto-char current-pos)
   8024         (if (get-text-property current-pos 'invisible)
   8025             (progn
   8026               (setq count (1+ count))
   8027               (setq current-pos (1+ current-pos))
   8028               (while (and (<= current-pos max)
   8029                           (get-text-property current-pos 'invisible))
   8030                 (setq current-pos (1+ current-pos))))
   8031           (setq current-pos (1+ current-pos)))))
   8032     count))
   8033 
   8034 (defun web-mode-column-show ()
   8035   (let ((index 0) overlay diff column line-to line-from line-delta regions (overlay-skip nil) last-line-no)
   8036     (web-mode-column-hide)
   8037     (setq web-mode-enable-current-column-highlight t)
   8038     (save-excursion ;;save-mark-and-excursion
   8039       (back-to-indentation)
   8040       (setq column (current-column)
   8041             line-to (web-mode-line-number))
   8042       (when (and (get-text-property (point) 'tag-beg)
   8043                  (member (get-text-property (point) 'tag-type) '(start end))
   8044                  (web-mode-tag-match)
   8045                  (setq line-from (web-mode-line-number))
   8046                  (not (= line-from line-to)))
   8047         (when (> line-from line-to)
   8048           (let (tmp)
   8049             (setq tmp line-from)
   8050             (setq line-from line-to)
   8051             (setq line-to tmp))
   8052           ) ;when
   8053         ;;(message "column(%S) line-from(%S) line-to(%S)" column line-from line-to)
   8054         (goto-char (point-min))
   8055         (when (> line-from 1)
   8056           (forward-line (1- line-from)))
   8057         ;; Added by JMA
   8058         (save-excursion ;;save-mark-and-excursion
   8059           (let (start-point end-point)
   8060             (goto-line line-from)
   8061             (move-to-column column)
   8062             (setq start-point (point))
   8063             (goto-line line-to)
   8064             (move-to-column column)
   8065             (setq end-point (point))
   8066             (setq line-delta (count-lines start-point end-point t))
   8067             (setq line-delta (+ line-delta (web-mode-count-invisible-character-ranges start-point end-point))))
   8068           (setq line-to (+ line-from (1- line-delta))))
   8069         ;(message (format "Currently at line: %d" (line-number-at-pos)))
   8070         (setq last-line-no (line-number-at-pos))
   8071         ;; end JMA add
   8072         (while (<= line-from line-to)
   8073           (setq overlay (web-mode-column-overlay-factory index))
   8074           (setq diff (- (line-end-position) (point)))
   8075           (cond
   8076             ((or (and (= column 0) (= diff 0))
   8077                  (> column diff))
   8078              (end-of-line)
   8079              (move-overlay overlay (point) (point))
   8080              (overlay-put overlay
   8081                           'after-string
   8082                           (concat
   8083                            (if (> column diff) (make-string (- column diff) ?\s) "")
   8084                            (propertize " "
   8085                                        'font-lock-face
   8086                                        'web-mode-current-column-highlight-face)
   8087                            ) ;concat
   8088                           )
   8089              )
   8090             (t
   8091              (move-to-column column)
   8092              (overlay-put overlay 'after-string nil)
   8093              (move-overlay overlay (point) (1+ (point)))
   8094              )
   8095             ) ;cond
   8096           (setq line-from (1+ line-from))
   8097           (forward-line)
   8098           ;; JMA ADD
   8099           ;(message (format "Currently at line: %d" (line-number-at-pos)))
   8100           (if (not (= (1+ last-line-no) (line-number-at-pos)))
   8101               (delete-overlay overlay))
   8102           (setq last-line-no (line-number-at-pos))
   8103           ;; END JMA ADD
   8104           (setq index (1+ index))
   8105           ) ;while
   8106         ) ;when
   8107       ) ;save-excursion
   8108     ) ;let
   8109   )
   8110 
   8111 (defun web-mode-column-show2 ()
   8112   (let ((index 0) overlay diff column line-to line-from
   8113         line-delta regions (overlay-skip nil) last-line-no)
   8114     (web-mode-column-hide)
   8115     (setq web-mode-enable-current-column-highlight t)
   8116     (save-excursion
   8117       (back-to-indentation)
   8118       (setq column (current-column)
   8119             line-to (web-mode-line-number))
   8120       (when (and (get-text-property (point) 'tag-beg)
   8121                  (member (get-text-property (point) 'tag-type) '(start end))
   8122                  (web-mode-tag-match)
   8123                  (setq line-from (web-mode-line-number))
   8124                  (not (= line-from line-to)))
   8125         (when (> line-from line-to)
   8126           (let (tmp)
   8127             (setq tmp line-from)
   8128             (setq line-from line-to)
   8129             (setq line-to tmp))
   8130           ) ;when
   8131         ;;(message "column(%S) line-from(%S) line-to(%S)" column line-from line-to)
   8132         (goto-char (point-min))
   8133         (when (> line-from 1)
   8134           (forward-line (1- line-from)))
   8135         (while (<= line-from line-to)
   8136           (setq overlay (web-mode-column-overlay-factory index))
   8137           (setq diff (- (line-end-position) (point)))
   8138           (cond
   8139             ((or (and (= column 0) (= diff 0))
   8140                  (> column diff))
   8141              (end-of-line)
   8142              (move-overlay overlay (point) (point))
   8143              (overlay-put overlay
   8144                           'after-string
   8145                           (concat
   8146                            (if (> column diff) (make-string (- column diff) ?\s) "")
   8147                            (propertize " "
   8148                                        'font-lock-face
   8149                                        'web-mode-current-column-highlight-face)
   8150                            ) ;concat
   8151                           )
   8152              )
   8153             (t
   8154              (move-to-column column)
   8155              (overlay-put overlay 'after-string nil)
   8156              (move-overlay overlay (point) (1+ (point)))
   8157              )
   8158             ) ;cond
   8159           (setq line-from (1+ line-from))
   8160           (forward-line)
   8161           (setq index (1+ index))
   8162           ) ;while
   8163         ) ;when
   8164       ) ;save-excursion
   8165     ) ;let
   8166   )
   8167 
   8168 (defun web-mode-highlight-current-element ()
   8169   (let ((ctx (web-mode-element-boundaries)) len)
   8170     (cond
   8171       ((null ctx)
   8172        (web-mode-delete-tag-overlays))
   8173       ((eq (get-text-property (caar ctx) 'tag-type) 'void) ;; #1046
   8174        (web-mode-make-tag-overlays)
   8175        (setq len (length (get-text-property (caar ctx) 'tag-name)))
   8176        (move-overlay web-mode-overlay-tag-start (+ (caar ctx) 1) (+ (caar ctx) 1 len))
   8177        (move-overlay web-mode-overlay-tag-end (+ (cadr ctx) 1) (+ (cadr ctx) 1 len)) ;; #1257
   8178        )
   8179       (t
   8180        (web-mode-make-tag-overlays)
   8181        (setq len (length (get-text-property (caar ctx) 'tag-name)))
   8182        (move-overlay web-mode-overlay-tag-start (+ (caar ctx) 1) (+ (caar ctx) 1 len))
   8183        (move-overlay web-mode-overlay-tag-end (+ (cadr ctx) 2) (+ (cadr ctx) 2 len))
   8184        ) ;t
   8185       ) ;cond
   8186     ))
   8187 
   8188 (defun web-mode-fontify-whitespaces (beg end)
   8189   (save-excursion
   8190     (goto-char beg)
   8191     (while (re-search-forward web-mode-whitespaces-regexp end t)
   8192       (add-text-properties (match-beginning 0) (match-end 0)
   8193                            '(face web-mode-whitespace-face))
   8194       ) ;while
   8195     ))
   8196 
   8197 (defun web-mode-whitespaces-show ()
   8198   "Toggle whitespaces."
   8199   (interactive)
   8200   (if web-mode-enable-whitespace-fontification
   8201       (web-mode-whitespaces-off)
   8202       (web-mode-whitespaces-on)))
   8203 
   8204 (defun web-mode-whitespaces-on ()
   8205   "Show whitespaces."
   8206   (interactive)
   8207   (when web-mode-display-table
   8208     (setq buffer-display-table web-mode-display-table))
   8209   (setq web-mode-enable-whitespace-fontification t))
   8210 
   8211 (defun web-mode-whitespaces-off ()
   8212   (setq buffer-display-table nil)
   8213   (setq web-mode-enable-whitespace-fontification nil))
   8214 
   8215 (defun web-mode-use-tabs ()
   8216   "Tweaks vars to be compatible with TAB indentation."
   8217   (let (offset)
   8218     (setq web-mode-block-padding 0)
   8219     (setq web-mode-script-padding 0)
   8220     (setq web-mode-style-padding 0)
   8221     (setq offset
   8222           (cond
   8223             ((and (boundp 'tab-width) tab-width) tab-width)
   8224             ((and (boundp 'standard-indent) standard-indent) standard-indent)
   8225             (t 4)))
   8226     ;;    (message "offset(%S)" offset)
   8227     (setq web-mode-attr-indent-offset offset)
   8228     (setq web-mode-code-indent-offset offset)
   8229     (setq web-mode-css-indent-offset offset)
   8230     (setq web-mode-markup-indent-offset offset)
   8231     (setq web-mode-sql-indent-offset offset)
   8232     (add-to-list 'web-mode-indentation-params '("lineup-args" . nil))
   8233     (add-to-list 'web-mode-indentation-params '("lineup-calls" . nil))
   8234     (add-to-list 'web-mode-indentation-params '("lineup-concats" . nil))
   8235     (add-to-list 'web-mode-indentation-params '("lineup-ternary" . nil))
   8236     ))
   8237 
   8238 (defun web-mode-element-children-fold-or-unfold (&optional pos)
   8239   "Fold/Unfold all the children of the current html element."
   8240   (interactive)
   8241   (unless pos (setq pos (point)))
   8242   (save-excursion
   8243     (dolist (child (reverse (web-mode-element-children pos)))
   8244       (goto-char child)
   8245       (web-mode-fold-or-unfold))
   8246     ))
   8247 
   8248 (defun web-mode-fold-or-unfold (&optional pos)
   8249   "Toggle folding on an html element or a control block."
   8250   (interactive)
   8251   (web-mode-scan)
   8252   (web-mode-with-silent-modifications
   8253    (save-excursion
   8254      (if pos (goto-char pos))
   8255      (let (beg-inside beg-outside end-inside end-outside overlay overlays)
   8256        (when (looking-back "^[\t ]*" (point-min))
   8257          (back-to-indentation))
   8258        (setq overlays (overlays-at (point)))
   8259        (dolist (elt overlays)
   8260          (when (and (not overlay)
   8261                     (eq (overlay-get elt 'font-lock-face) 'web-mode-folded-face))
   8262            (setq overlay elt)))
   8263        (cond
   8264          ;; *** unfolding
   8265          (overlay
   8266           (setq beg-inside (overlay-start overlay)
   8267                 end-inside (overlay-end overlay))
   8268           (remove-overlays beg-inside end-inside)
   8269           (put-text-property beg-inside end-inside 'invisible nil)
   8270           )
   8271          ;; *** block folding
   8272          ((and (get-text-property (point) 'block-side)
   8273                (cdr (web-mode-block-is-control (point))))
   8274           (setq beg-outside (web-mode-block-beginning-position (point)))
   8275           (setq beg-inside (1+ (web-mode-block-end-position (point))))
   8276           (when (web-mode-block-match)
   8277             (setq end-inside (point))
   8278             (setq end-outside (1+ (web-mode-block-end-position (point)))))
   8279           )
   8280          ;; *** html comment folding
   8281          ((eq (get-text-property (point) 'tag-type) 'comment)
   8282           (setq beg-outside (web-mode-tag-beginning-position))
   8283           (setq beg-inside (+ beg-outside 4))
   8284           (setq end-outside (web-mode-tag-end-position))
   8285           (setq end-inside (- end-outside 3))
   8286           )
   8287          ;; *** tag folding
   8288          ((or (member (get-text-property (point) 'tag-type) '(start end))
   8289               (web-mode-element-parent))
   8290           (when (not (web-mode-element-is-collapsed (point)))
   8291             (web-mode-tag-beginning)
   8292             (when (eq (get-text-property (point) 'tag-type) 'end)
   8293               (web-mode-tag-match))
   8294             (setq beg-outside (point))
   8295             (web-mode-tag-end)
   8296             (setq beg-inside (point))
   8297             (goto-char beg-outside)
   8298             (when (web-mode-tag-match)
   8299               (setq end-inside (point))
   8300               (web-mode-tag-end)
   8301               (setq end-outside (point)))
   8302             )
   8303           )
   8304          ) ;cond
   8305        (when (and beg-inside beg-outside end-inside end-outside)
   8306          (setq overlay (make-overlay beg-outside end-outside))
   8307          (overlay-put overlay 'font-lock-face 'web-mode-folded-face)
   8308          (put-text-property beg-inside end-inside 'invisible t))
   8309        ))))
   8310 
   8311 ;;---- TRANSFORMATION ----------------------------------------------------------
   8312 
   8313 (defun web-mode-buffer-change-tag-case (&optional type)
   8314   "Change html tag case."
   8315   (interactive)
   8316   (save-excursion
   8317     (goto-char (point-min))
   8318     (let ((continue t) f)
   8319       (setq f (if (member type '("upper" "uppercase" "upper-case")) 'uppercase 'downcase))
   8320       (when (and (not (get-text-property (point) 'tag-beg))
   8321                  (not (web-mode-tag-next)))
   8322         (setq continue nil))
   8323       (while continue
   8324         (skip-chars-forward "<!/")
   8325         (if (looking-at "\\([[:alnum:]:-]+\\)")
   8326             (replace-match (funcall f (match-string 0)) t))
   8327         ;;        (message "tag: %S (%S)"
   8328         ;;                 (get-text-property (point) 'tag-name)
   8329         ;;                 (point))
   8330         (unless (web-mode-tag-next)
   8331           (setq continue nil))
   8332         ) ;while
   8333       )))
   8334 
   8335 (defun web-mode-buffer-change-attr-case (&optional type)
   8336   "Change case of html attribute names."
   8337   (interactive)
   8338   (unless type (setq type "downcase"))
   8339   (save-excursion
   8340     (goto-char (point-min))
   8341     (let ((continue t)
   8342           (fun (if (eq (aref (downcase type) 0) ?u) 'uppercase 'downcase)))
   8343       (while continue
   8344         (cond
   8345           ((not (web-mode-attribute-next))
   8346            (setq continue nil))
   8347           ((looking-at "\\([[:alnum:]-]+\\)")
   8348            (replace-match (funcall fun (match-string 0)) t)
   8349            )
   8350           ) ;cond
   8351         ) ;while
   8352       )))
   8353 
   8354 ;; tag-case=lower|upper-case , attr-case=lower|upper-case
   8355 ;; special-chars=unicode|html-entities
   8356 ;; smart-apostrophes=bool , smart-quotes=bool , indentation=bool
   8357 (defun web-mode-dom-normalize ()
   8358   "Normalize buffer"
   8359   (interactive)
   8360   (save-excursion
   8361     (let ((rules web-mode-normalization-rules) elt)
   8362       (when (setq elt (cdr (assoc "tag-case" rules)))
   8363         (web-mode-buffer-change-tag-case elt))
   8364       (when (setq elt (cdr (assoc "attr-case" rules)))
   8365         (web-mode-buffer-change-attr-case elt))
   8366       (when (setq elt (cdr (assoc "css-indentation" rules)))
   8367         (web-mode-css-indent))
   8368       (when (setq elt (cdr (assoc "smart-apostrophes" rules)))
   8369         (web-mode-dom-apostrophes-replace))
   8370       (when (setq elt (cdr (assoc "smart-quotes" rules)))
   8371         (web-mode-dom-quotes-replace))
   8372       (when (setq elt (cdr (assoc "special-chars" rules)))
   8373         (if (string= elt "entities")
   8374             (web-mode-dom-entities-encode)
   8375             (web-mode-dom-entities-replace)))
   8376       (when (setq elt (cdr (assoc "whitespaces" rules)))
   8377         (goto-char (point-min))
   8378         (while (not (eobp))
   8379           (forward-line)
   8380           (delete-blank-lines))
   8381         (delete-trailing-whitespace)
   8382         (untabify (point-min) (point-max)))
   8383       (when (setq elt (cdr (assoc "indentation" rules)))
   8384         (web-mode-buffer-indent))
   8385       )))
   8386 
   8387 (defun web-mode-dom-apostrophes-replace ()
   8388   "Replace char(') with char(’) in the innerText of html elements."
   8389   (interactive)
   8390   (save-excursion
   8391     (let ((min (point-min)) (max (point-max)))
   8392       (when mark-active
   8393         (setq min (region-beginning)
   8394               max (region-end))
   8395         (deactivate-mark))
   8396       (goto-char min)
   8397       (while (web-mode-content-rsf "\\([[:alpha:]]\\)'\\([[:alpha:]]\\)" max)
   8398         (replace-match "\\1’\\2"))
   8399       )))
   8400 
   8401 (defun web-mode-dom-entities-encode ()
   8402   (save-excursion
   8403     (let (regexp elt (min (point-min)) (max (point-max)))
   8404       (when mark-active
   8405         (setq min (region-beginning)
   8406               max (region-end))
   8407         (deactivate-mark))
   8408       (goto-char min)
   8409       (setq regexp "[")
   8410       (dolist (pair web-mode-html-entities)
   8411         (setq regexp (concat regexp (char-to-string (cdr pair))))
   8412         )
   8413       (setq regexp (concat regexp "]"))
   8414       (while (web-mode-content-rsf regexp max)
   8415         (setq elt (match-string-no-properties 0))
   8416         (setq elt (aref elt 0))
   8417         (setq elt (car (rassoc elt web-mode-html-entities)))
   8418         (replace-match (concat "&" elt ";"))
   8419         (setq max (+ max (length elt) 1))
   8420         ) ;while
   8421       )))
   8422 
   8423 (defun web-mode-dom-entities-replace ()
   8424   "Replace html entities (e.g. &eacute; &#233; or &#x00E9; become é)"
   8425   (interactive)
   8426   (save-excursion
   8427     (let (ms pair elt (min (point-min)) (max (point-max)))
   8428       (when mark-active
   8429         (setq min (region-beginning)
   8430               max (region-end))
   8431         (deactivate-mark))
   8432       (goto-char min)
   8433       (while (web-mode-content-rsf "&\\([#]?[[:alnum:]]\\{2,8\\}\\);" max)
   8434         (setq elt nil)
   8435         (setq ms (match-string-no-properties 1))
   8436         (cond
   8437           ((not (eq (aref ms 0) ?\#))
   8438            (and (setq pair (assoc ms web-mode-html-entities))
   8439                 (setq elt (cdr pair))
   8440                 (setq elt (char-to-string elt))))
   8441           ((eq (aref ms 1) ?x)
   8442            (setq elt (substring ms 2))
   8443            (setq elt (downcase elt))
   8444            (setq elt (string-to-number elt 16))
   8445            (setq elt (char-to-string elt)))
   8446           (t
   8447            (setq elt (substring ms 1))
   8448            (setq elt (char-to-string (string-to-number elt))))
   8449           ) ;cond
   8450         (when elt (replace-match elt))
   8451         ) ;while
   8452       )))
   8453 
   8454 (defun web-mode-dom-xml-replace ()
   8455   "Replace &, > and < in html content."
   8456   (interactive)
   8457   (save-excursion
   8458     (let ((min (point-min)) (max (point-max)))
   8459       (when mark-active
   8460         (setq min (region-beginning)
   8461               max (region-end))
   8462         (deactivate-mark))
   8463       (goto-char min)
   8464       (while (web-mode-content-rsf "[&<>]" max)
   8465         (replace-match (cdr (assq (char-before) web-mode-xml-chars)) t t))
   8466       )))
   8467 
   8468 (defun web-mode-dom-quotes-replace ()
   8469   "Replace dumb quotes."
   8470   (interactive)
   8471   (save-excursion
   8472     (let (expr (min (point-min)) (max (point-max)))
   8473       (when mark-active
   8474         (setq min (region-beginning)
   8475               max (region-end))
   8476         (deactivate-mark))
   8477       (goto-char min)
   8478       (setq expr (concat (car web-mode-smart-quotes) "\\2" (cdr web-mode-smart-quotes)))
   8479       (while (web-mode-content-rsf "\\(\"\\)\\(.\\{1,200\\}\\)\\(\"\\)" max)
   8480         (replace-match expr)
   8481         ) ;while
   8482       )))
   8483 
   8484 ;;---- INDENTATION -------------------------------------------------------------
   8485 
   8486 ;; todo : passer de règle en règle et mettre un \n à la fin
   8487 (defun web-mode-css-indent ()
   8488   (save-excursion
   8489     (goto-char (point-min))
   8490     (let ((continue t) part-end)
   8491       (while continue
   8492         (cond
   8493           ((not (web-mode-part-next))
   8494            (setq continue nil))
   8495           ((eq (get-text-property (point) 'part-side) 'css)
   8496            (setq part-end (web-mode-part-end-position))
   8497            (while (web-mode-css-rule-next part-end)
   8498              (when (not (looking-at-p "[[:space:]]*\\($\\|<\\)"))
   8499                (newline)
   8500                (indent-according-to-mode)
   8501                (setq part-end (web-mode-part-end-position)))
   8502              )
   8503            )
   8504           ) ;cond
   8505         )
   8506       )))
   8507 
   8508 (defun web-mode-buffer-indent ()
   8509   "Indent all buffer."
   8510   (interactive)
   8511   (let ((debug t) (ts (current-time)) (sub nil))
   8512     (indent-region (point-min) (point-max))
   8513     (when debug
   8514       (setq sub (time-subtract (current-time) ts))
   8515       (message "buffer-indent: time elapsed = %Ss %9Sµs" (nth 1 sub) (nth 2 sub)))
   8516     (delete-trailing-whitespace)))
   8517 
   8518 (defun web-mode-point-context (pos)
   8519   "POS should be at the beginning of the indentation."
   8520   (save-excursion
   8521     (let (curr-char curr-indentation curr-line
   8522                     language
   8523                     options
   8524                     reg-beg reg-col
   8525                     prev-char prev-indentation prev-line prev-pos
   8526                     token
   8527                     part-language
   8528                     depth)
   8529 
   8530       (setq reg-beg (point-min)
   8531             reg-col 0
   8532             token "live"
   8533             options ""
   8534             language ""
   8535             prev-line ""
   8536             prev-char 0
   8537             prev-pos nil
   8538             prev-line-end nil)
   8539 
   8540       (when (get-text-property pos 'part-side)
   8541         (setq part-language (symbol-name (get-text-property pos 'part-side))))
   8542 
   8543       ;;(message "part-language=%S" part-language)
   8544 
   8545       (cond
   8546 
   8547         ((and (bobp) (member web-mode-content-type '("html" "xml")))
   8548          (setq language web-mode-content-type)
   8549          )
   8550 
   8551         ((string= web-mode-content-type "css")
   8552          (setq language "css"
   8553                curr-indentation web-mode-css-indent-offset))
   8554 
   8555         ((member web-mode-content-type '("javascript" "json" "typescript"))
   8556          (setq language web-mode-content-type
   8557                curr-indentation web-mode-code-indent-offset))
   8558 
   8559         ((or (string= web-mode-content-type "jsx")
   8560              (and part-language (string= part-language "jsx")))
   8561          (setq language "jsx"
   8562                curr-indentation web-mode-code-indent-offset)
   8563          (cond
   8564            ((web-mode-jsx-is-html pos)
   8565             (setq curr-indentation web-mode-markup-indent-offset
   8566                   options "is-html"))
   8567            ((and (setq depth (get-text-property pos 'jsx-depth)) (> depth 1))
   8568             (when (get-text-property pos 'jsx-beg)
   8569               (setq depth (1- depth)))
   8570             (setq reg-beg (web-mode-jsx-depth-beginning-position pos depth))
   8571             (setq reg-beg (1+ reg-beg))
   8572             ;;(message "%S" (point))
   8573             (save-excursion
   8574               (goto-char reg-beg)
   8575               ;;(message "pt=%S" reg-beg)
   8576               (cond
   8577                 ((and (not (looking-at-p "[ ]*$"))
   8578                       (looking-back "^[[:space:]]*{" (point-min)))
   8579                  (setq reg-col (+ (current-indentation) ;; #1027
   8580                                   (cond
   8581                                     ((looking-at "[ ]+") (1+ (length (match-string-no-properties 0))))
   8582                                     (t 0))
   8583                                   ))
   8584                  )
   8585                 ((looking-at-p "[ ]*\\[[ ]*$") ;; #0659
   8586                  (setq reg-col (current-indentation))
   8587                  )
   8588                 ((and (looking-back "=[ ]*{" (point-min)) ;; #0739 #1022
   8589                       (not (looking-at-p "[[:space:]]*<")))
   8590                  (setq reg-col (current-indentation))
   8591                  )
   8592                 ;;((and (looking-back "=[ ]*{" (point-min)) ;; #0739
   8593                 ;;      (looking-at-p "{[ ]*"))
   8594                 ;; (setq reg-col (current-indentation))
   8595                 ;; )
   8596                 ((get-text-property (1- (point)) 'tag-beg)
   8597                  ;;(message "point=%S" (point))
   8598                  (setq reg-col (current-indentation))
   8599                  )
   8600                 (t
   8601                  (message "%S : %S %S" (point) (current-indentation) web-mode-code-indent-offset)
   8602                  ;;(setq reg-col (+ (current-indentation) web-mode-code-indent-offset web-mode-jsx-expression-padding)))
   8603                  (setq reg-col (+ (current-indentation) web-mode-code-indent-offset)))
   8604                 )
   8605 
   8606               ;;(message "%S %S %S" (point) (current-indentation) reg-col)
   8607               ) ;save-excursion
   8608             )
   8609            ((string= web-mode-content-type "jsx")
   8610             (setq reg-beg (point-min)))
   8611            (t
   8612             (setq reg-beg (or (web-mode-part-beginning-position pos) (point-min)))
   8613             (save-excursion
   8614               (goto-char reg-beg)
   8615               (search-backward "<" nil t)
   8616               (setq reg-col (current-column))
   8617               ) ;save-excursion
   8618             )
   8619            ) ;cond
   8620          ;;(message "jsx reg-beg=%S" reg-beg)
   8621          ) ;jsx
   8622 
   8623         ((string= web-mode-content-type "php")
   8624          (setq language "php"
   8625                curr-indentation web-mode-code-indent-offset))
   8626 
   8627         ((or (string= web-mode-content-type "xml"))
   8628          (setq language "xml"
   8629                curr-indentation web-mode-markup-indent-offset))
   8630 
   8631         ;; TODO: est ce util ?
   8632         ((and (get-text-property pos 'tag-beg)
   8633               (get-text-property pos 'tag-name)
   8634               ;;(not (get-text-property pos 'part-side))
   8635               )
   8636          (setq language "html"
   8637                curr-indentation web-mode-markup-indent-offset))
   8638 
   8639         ((and (get-text-property pos 'block-side)
   8640               (not (get-text-property pos 'block-beg)))
   8641 
   8642          (setq reg-beg (or (web-mode-block-beginning-position pos) (point-min)))
   8643          (goto-char reg-beg)
   8644          (setq reg-col (current-column))
   8645          ;;(message "%S %S" reg-beg reg-col)
   8646          (setq language web-mode-engine)
   8647          (setq curr-indentation web-mode-code-indent-offset)
   8648 
   8649          (cond
   8650            ((string= web-mode-engine "blade")
   8651             (save-excursion
   8652               (when (web-mode-rsf "{[{!]+[ ]*")
   8653                 (setq reg-col (current-column))))
   8654             (setq reg-beg (+ reg-beg 2))
   8655             )
   8656            ((string= web-mode-engine "razor")
   8657             ;;(setq reg-beg (+ reg-beg 2))
   8658             ;;(setq reg-col (current-column))
   8659             )
   8660            ;; tests/demo.chtml
   8661            ((string= web-mode-engine "ctemplate")
   8662             (save-excursion
   8663               (when (web-mode-rsf "{{#?")
   8664                 (setq reg-col (current-column))))
   8665             )
   8666            ((string= web-mode-engine "dust")
   8667             (save-excursion
   8668               (when (web-mode-rsf "{@")
   8669                 (setq reg-col (current-column))))
   8670             )
   8671            ((string= web-mode-engine "svelte")
   8672             (save-excursion
   8673               (when (web-mode-rsf "{@")
   8674                 (setq reg-col (current-column))))
   8675             )
   8676            ((string= web-mode-engine "template-toolkit")
   8677             (setq reg-beg (+ reg-beg 3)
   8678                   reg-col (+ reg-col 3))
   8679             )
   8680            ((and (string= web-mode-engine "jsp")
   8681                  (web-mode-looking-at "<%@" reg-beg))
   8682             (save-excursion
   8683               (goto-char reg-beg)
   8684               (looking-at "<%@[ ]*[[:alpha:]]+[ ]+\\|</?[[:alpha:]]+[:.][[:alpha:]]+[ ]+")
   8685               (goto-char (match-end 0))
   8686               (setq reg-col (current-column))
   8687               )
   8688             )
   8689            ((and (string= web-mode-engine "freemarker")
   8690                  (web-mode-looking-at "<@\\|<%@\\|<[[:alpha:]]" reg-beg))
   8691             (save-excursion
   8692               (goto-char reg-beg)
   8693               (looking-at "<@[[:alpha:].]+[ ]+\\|<%@[ ]*[[:alpha:]]+[ ]+\\|<[[:alpha:]]+:[[:alpha:]]+[ ]+")
   8694               (goto-char (match-end 0))
   8695               (setq reg-col (current-column))
   8696               )
   8697             )
   8698            ) ;cond
   8699          ) ;block-side
   8700 
   8701         ((and part-language (member part-language
   8702                                     '("css" "javascript" "json" "sql" "markdown"
   8703                                       "pug" "ruby" "sass" "stylus" "typescript")))
   8704          (setq reg-beg (or (web-mode-part-beginning-position pos) (point-min)))
   8705          (goto-char reg-beg)
   8706          (if (and (string= web-mode-engine "mojolicious")
   8707                   (looking-back "javascript begin" (point-min)))
   8708              (search-backward "%" nil t)
   8709              (search-backward "<" nil t))
   8710          (setq reg-col (current-column))
   8711          (setq language part-language)
   8712          (cond
   8713            ((string= language "css")
   8714             (setq curr-indentation web-mode-css-indent-offset))
   8715            ((string= language "sql")
   8716             (setq curr-indentation web-mode-sql-indent-offset))
   8717            ((string= language "markdown")
   8718             (setq curr-indentation web-mode-code-indent-offset))
   8719            ((string= language "pug")
   8720             (setq curr-indentation web-mode-code-indent-offset))
   8721            ((string= language "sass")
   8722             (setq curr-indentation web-mode-code-indent-offset))
   8723            ((string= language "stylus")
   8724             (setq curr-indentation web-mode-code-indent-offset))
   8725            ((string= language "ruby")
   8726             (setq curr-indentation web-mode-code-indent-offset))
   8727            ((string= language "typescript")
   8728             (setq curr-indentation web-mode-code-indent-offset))
   8729            (t
   8730             (setq language "javascript"
   8731                   curr-indentation web-mode-code-indent-offset))
   8732            )
   8733          ) ;part-side
   8734 
   8735         (t
   8736          (setq language "html"
   8737                curr-indentation web-mode-markup-indent-offset)
   8738          )
   8739 
   8740         ) ;cond
   8741 
   8742       (cond
   8743         ((or (and (> pos (point-min))
   8744                   (eq (get-text-property pos 'part-token) 'comment)
   8745                   (eq (get-text-property (1- pos) 'part-token) 'comment)
   8746                   (progn
   8747                     (setq reg-beg (previous-single-property-change pos 'part-token))
   8748                     t))
   8749              (and (> pos (point-min))
   8750                   (eq (get-text-property pos 'block-token) 'comment)
   8751                   (eq (get-text-property (1- pos) 'block-token) 'comment)
   8752                   (progn
   8753                     (setq reg-beg (previous-single-property-change pos 'block-token))
   8754                     t))
   8755              (and (> pos (point-min))
   8756                   (eq (get-text-property pos 'tag-type) 'comment)
   8757                   (not (get-text-property pos 'tag-beg))
   8758                   (progn
   8759                     (setq reg-beg (web-mode-tag-beginning-position pos))
   8760                     t))
   8761              )
   8762          (setq token "comment"))
   8763         ((or (and (> pos (point-min))
   8764                   (member (get-text-property pos 'part-token)
   8765                           '(string context key))
   8766                   (member (get-text-property (1- pos) 'part-token)
   8767                           '(string context key)))
   8768              (and (eq (get-text-property pos 'block-token) 'string)
   8769                   (eq (get-text-property (1- pos) 'block-token) 'string)))
   8770          (setq token "string"))
   8771         )
   8772 
   8773       (goto-char pos)
   8774       (setq curr-line (web-mode-trim
   8775                        (buffer-substring-no-properties
   8776                         (line-beginning-position)
   8777                         (line-end-position))))
   8778       (setq curr-char (if (string= curr-line "") 0 (aref curr-line 0)))
   8779 
   8780       (when (or (member language '("php" "blade" "javascript" "typescript" "jsx" "razor" "css"))
   8781                 (and (member language '("html" "xml"))
   8782                      (not (eq ?\< curr-char))))
   8783         (let (prev)
   8784           (cond
   8785             ((member language '("html" "xml" "javascript" "typescript" "jsx" "css"))
   8786              (when (setq prev (web-mode-part-previous-live-line reg-beg))
   8787                (setq prev-line (nth 0 prev)
   8788                      prev-indentation (nth 1 prev)
   8789                      prev-pos (nth 2 prev)
   8790                      prev-line-end (nth 3 prev))
   8791                )
   8792              )
   8793             ((setq prev (web-mode-block-previous-live-line))
   8794              (setq prev-line (nth 0 prev)
   8795                    prev-indentation (nth 1 prev)
   8796                    prev-pos (nth 2 prev)
   8797                    prev-line-end (nth 3 prev))
   8798              (setq prev-line (web-mode-clean-block-line prev-line)))
   8799             ) ;cond
   8800           ) ;let
   8801         (when (>= (length prev-line) 1)
   8802           (setq prev-char (aref prev-line (1- (length prev-line))))
   8803           (setq prev-line (substring-no-properties prev-line))
   8804           )
   8805         )
   8806 
   8807       (cond
   8808         ((not (member web-mode-content-type '("html" "xml")))
   8809          )
   8810         ((member language '("javascript" "typescript" "jsx" "ruby"))
   8811          (setq reg-col (if web-mode-script-padding (+ reg-col web-mode-script-padding) 0)))
   8812         ((member language '("css" "sql" "markdown" "pug" "sass" "stylus"))
   8813          (setq reg-col (if web-mode-style-padding (+ reg-col web-mode-style-padding) 0)))
   8814         ((not (member language '("html" "xml")))
   8815          (setq reg-col
   8816                (cond
   8817                  ((not web-mode-block-padding) reg-col)
   8818                  ((eq web-mode-block-padding -1) 0)
   8819                  (t (+ reg-col web-mode-block-padding))
   8820                  ) ;cond
   8821                ) ;setq
   8822          )
   8823         )
   8824 
   8825       (list :curr-char curr-char
   8826             :curr-indentation curr-indentation
   8827             :curr-line curr-line
   8828             :language language
   8829             :options options
   8830             :prev-char prev-char
   8831             :prev-indentation prev-indentation
   8832             :prev-line prev-line
   8833             :prev-line-end prev-line-end
   8834             :prev-pos prev-pos
   8835             :reg-beg reg-beg
   8836             :reg-col reg-col
   8837             :token token)
   8838       )))
   8839 
   8840 (defun web-mode-indent-line ()
   8841 
   8842   (web-mode-scan)
   8843 
   8844   (let ((offset nil)
   8845         (char nil)
   8846         (debug nil)
   8847         (inhibit-modification-hooks nil)
   8848         (adjust t))
   8849 
   8850     (save-excursion
   8851       (back-to-indentation)
   8852       (setq char (char-after))
   8853       (let* ((pos (point))
   8854              (ctx (web-mode-point-context pos))
   8855              (curr-char (plist-get ctx :curr-char))
   8856              (curr-indentation (plist-get ctx :curr-indentation))
   8857              (curr-line (plist-get ctx :curr-line))
   8858              (language (plist-get ctx :language))
   8859              (prev-char (plist-get ctx :prev-char))
   8860              (prev-indentation (plist-get ctx :prev-indentation))
   8861              (prev-line (plist-get ctx :prev-line))
   8862              (prev-line-end (plist-get ctx :prev-line-end))
   8863              (prev-pos (plist-get ctx :prev-pos))
   8864              (reg-beg (plist-get ctx :reg-beg))
   8865              (reg-col (plist-get ctx :reg-col))
   8866              (token (plist-get ctx :token))
   8867              (options (plist-get ctx :options))
   8868              (chars (list curr-char prev-char))
   8869              (tmp nil)
   8870              (is-js (member language '("javascript" "jsx" "ejs" "typescript"))))
   8871 
   8872         (when (member language '("json" "typescript"))
   8873           (setq language "javascript"))
   8874 
   8875         ;;(message "%S %S" (plist-get ctx :language) language)
   8876         ;;(message "curr-char=[%c] prev-char=[%c]\n%S" curr-char prev-char ctx)
   8877         ;;(message "options=%S" ctx)
   8878 
   8879         (cond
   8880 
   8881           ((or (bobp) (= (line-number-at-pos pos) 1))
   8882            (when debug (message "I100(%S) first line" pos))
   8883            (setq offset 0))
   8884 
   8885           ;; #123 #1145
   8886           ((and web-mode-enable-front-matter-block
   8887                 (eq (char-after (point-min)) ?\-)
   8888                 (or (looking-at-p "---")
   8889                     (search-forward "---" (point-max) t)))
   8890            (when debug (message "I108(%S) front-matter-block" pos))
   8891            (setq offset nil))
   8892 
   8893           ;; #1073
   8894           ((get-text-property pos 'invisible)
   8895            (when debug (message "I110(%S) invible" pos))
   8896            (setq offset nil))
   8897 
   8898           ((string= token "string")
   8899            (when debug (message "I120(%S) string" pos))
   8900            (cond
   8901              ((web-mode-is-token-end pos)
   8902               (if (get-text-property pos 'block-side)
   8903                   (web-mode-block-token-beginning)
   8904                   (web-mode-part-token-beginning))
   8905               (setq offset (current-indentation))
   8906               )
   8907              ((and web-mode-enable-sql-detection
   8908                    (web-mode-block-token-starts-with (concat "[ \n]*" web-mode-sql-queries)))
   8909               (save-excursion
   8910                 (let (col)
   8911                   (web-mode-block-string-beginning)
   8912                   (skip-chars-forward "[ \"'\n]")
   8913                   (setq col (current-column))
   8914                   (goto-char pos)
   8915                   (if (looking-at-p "\\(SELECT\\|INSERT\\|DELETE\\|UPDATE\\|FROM\\|LEFT\\|JOIN\\|WHERE\\|GROUP BY\\|LIMIT\\|HAVING\\|\)\\)")
   8916                       (setq offset col)
   8917                       (setq offset (+ col web-mode-sql-indent-offset)))
   8918                   )
   8919                 ) ;save-excursion
   8920               )
   8921              ((and is-js
   8922                    (web-mode-is-ql-string pos "Relay\.QL"))
   8923               (setq offset (web-mode-relayql-indentation pos))
   8924               )
   8925              ((and is-js
   8926                    (web-mode-is-ql-string pos "gql"))
   8927               (setq offset (web-mode-relayql-indentation pos "gql"))
   8928               )
   8929              ((and is-js
   8930                    (web-mode-is-ql-string pos "graphql"))
   8931               (setq offset (web-mode-relayql-indentation pos "graphql"))
   8932               )
   8933              ((and is-js
   8934                    (web-mode-is-css-string pos))
   8935               (when debug (message "I127(%S) css string" pos))
   8936               (setq offset (web-mode-token-css-indentation pos))
   8937               )
   8938              ((and is-js
   8939                    (web-mode-is-html-string pos))
   8940               (when debug (message "I128(%S) html string" pos))
   8941               (setq offset (web-mode-token-html-indentation pos))
   8942               )
   8943              (t
   8944               (setq offset nil))
   8945              ) ;cond
   8946            ) ;case string
   8947 
   8948           ((string= token "comment")
   8949            (when debug (message "I130(%S) comment" pos))
   8950            (if (eq (get-text-property pos 'tag-type) 'comment)
   8951                (web-mode-tag-beginning)
   8952                (goto-char (car
   8953                            (web-mode-property-boundaries
   8954                             (if (eq (get-text-property pos 'part-token) 'comment)
   8955                                 'part-token
   8956                                 'block-token)
   8957                             pos))))
   8958            (setq offset (current-column))
   8959            (cond
   8960              ((string= web-mode-engine "freemarker")
   8961               (setq offset (+ (current-indentation) 2)))
   8962              ((member (buffer-substring-no-properties (point) (+ (point) 2)) '("/*" "{*" "@*"))
   8963               (cond
   8964                 ((eq ?\* curr-char)
   8965                  (setq offset (+ offset 1)))
   8966                 (t
   8967                  (setq offset (+ offset 3)))
   8968                 ) ;cond
   8969               )
   8970              ((string= (buffer-substring-no-properties (point) (+ (point) 4)) "<!--")
   8971               (cond
   8972                 ((string-match-p "^<!\\[endif" curr-line)
   8973                  )
   8974                 ((looking-at-p "<!--\\[if")
   8975                  (setq offset (+ offset web-mode-markup-indent-offset)))
   8976                 ((string-match-p "^-->" curr-line)
   8977                  (setq offset offset))
   8978                 ((string-match-p "^-" curr-line)
   8979                  (setq offset (+ offset 3)))
   8980                 (t
   8981                  (setq offset (+ offset web-mode-markup-comment-indent-offset)))
   8982                 ) ;cond
   8983               )
   8984              ((and (string= web-mode-engine "django") (looking-back "{% comment %}" (point-min)))
   8985               (setq offset (- offset 12)))
   8986              ((and (string= web-mode-engine "mako") (looking-back "<%doc%>" (point-min)))
   8987               (setq offset (- offset 6)))
   8988              ((and (string= web-mode-engine "mason") (looking-back "<%doc%>" (point-min)))
   8989               (setq offset (- offset 6)))
   8990              ) ;cond
   8991            ) ;case comment
   8992 
   8993           ((and (string= web-mode-engine "mason")
   8994                 (string-match-p "^%" curr-line))
   8995            (when debug (message "I140(%S) mason" pos))
   8996            (setq offset 0))
   8997 
   8998           ((and (string= web-mode-engine "razor")
   8999                 (string-match-p "^\\([{}]\\|else\\)" curr-line))
   9000            (when debug (message "I142(%S) razor" pos))
   9001            (save-excursion
   9002              (web-mode-block-previous)
   9003              (setq offset (current-indentation))
   9004              ))
   9005 
   9006           ((and (string= web-mode-engine "django")
   9007                 (string-match-p "^#" curr-line))
   9008            (when debug (message "I144(%S) django line statements" pos))
   9009            (setq offset 0))
   9010 
   9011           ((and (get-text-property pos 'block-beg)
   9012                 (or (web-mode-block-is-close pos)
   9013                     (web-mode-block-is-inside pos)))
   9014            (when debug (message "I150(%S) block-match" pos))
   9015            (cond
   9016              ((not (web-mode-block-match))
   9017               )
   9018              ((and (string= web-mode-engine "closure")
   9019                    (string-match-p "{\\(case\\|default\\)" curr-line))
   9020               (setq offset (+ (current-indentation) web-mode-markup-indent-offset)))
   9021              (t
   9022               (setq offset (current-indentation))
   9023               (if (and (string= web-mode-engine "blade")
   9024                        (string-match-p "@break" curr-line))
   9025                   (setq offset (+ (current-indentation) offset)))
   9026               )
   9027              ) ;cond
   9028            )
   9029 
   9030           ((eq (get-text-property pos 'block-token) 'delimiter-end)
   9031            (when debug (message "I160(%S) block-beginning" pos))
   9032            (when (web-mode-block-beginning)
   9033              (setq reg-col (current-indentation))
   9034              (setq offset (current-column))))
   9035 
   9036           ((or (and (get-text-property pos 'tag-beg)
   9037                     (eq (get-text-property pos 'tag-type) 'end))
   9038                (and (eq (get-text-property pos 'tag-type) 'comment)
   9039                     (string-match-p "<!--#\\(else\\|elif\\|endif\\)" curr-line)))
   9040            (when debug (message "I170(%S) tag-match" pos))
   9041            (when (web-mode-tag-match)
   9042              (setq offset (current-indentation))))
   9043 
   9044           ((and (member language '("jsx"))
   9045                 (eq curr-char ?\})
   9046                 (get-text-property pos 'jsx-end))
   9047            (when debug (message "I180(%S) jsx-expr-end" pos))
   9048            (web-mode-go (1- reg-beg))
   9049            (setq reg-col nil)
   9050            ;;(setq offset (current-column)))
   9051            (setq offset (current-indentation)))
   9052 
   9053           ((and (member language '("html" "xml" "javascript" "jsx"))
   9054                 (get-text-property pos 'tag-type)
   9055                 (not (get-text-property pos 'tag-beg))
   9056                 ;;(or (not (string= language "jsx"))
   9057                 ;;    (string= options "is-html"))
   9058                 (not (and (string= language "jsx")
   9059                           (web-mode-jsx-is-expr pos)))
   9060                 )
   9061            (when debug (message "I190(%S) attr-indent" pos))
   9062            (cond
   9063              ((and (not (get-text-property pos 'tag-attr-beg))
   9064                    (get-text-property pos 'tag-attr)
   9065                    (get-text-property (1- pos) 'tag-attr)
   9066                    (web-mode-attribute-beginning)
   9067                    (not (string-match-p "^/?>" curr-line))
   9068                    ;;(progn (message "pos=%S point=%S" pos (point)) t)
   9069                    )
   9070 
   9071               (cond
   9072                 ((eq (logand (get-text-property (point) 'tag-attr-beg) 8) 8)
   9073                  (setq offset nil))
   9074                 ((not (web-mode-tag-beginning))
   9075                  (message "** tag-beginning ** failure")
   9076                  (setq offset nil))
   9077                 (web-mode-attr-value-indent-offset
   9078                  (setq offset (+ (current-column) web-mode-attr-value-indent-offset)))
   9079                 ((web-mode-dom-rsf "=[ ]*[\"']?" pos)
   9080                  ;;(message "%S" (point))
   9081                  (setq offset (current-column)))
   9082                 (t
   9083                  (setq offset (+ (current-column) web-mode-markup-indent-offset)))
   9084                 ) ;cond
   9085               ) ;and
   9086              ((not (web-mode-tag-beginning))
   9087               (message "** error ** unable to jump to tag beg"))
   9088              ((string-match-p "^/?>" curr-line)
   9089               (setq offset (web-mode-column-at-pos (web-mode-tag-beginning-position pos)))
   9090               )
   9091              (web-mode-attr-indent-offset
   9092               (setq offset (+ (current-column) web-mode-attr-indent-offset)))
   9093              ((looking-at-p (concat web-mode-start-tag-regexp "[ ]*\n"))
   9094               ;;(message "%S: %S" (point) (web-mode-inside-block-control pos))
   9095               (setq offset (+ (current-column) (or web-mode-attr-indent-offset web-mode-code-indent-offset)))
   9096               ;; #1109
   9097               (setq tmp (web-mode-inside-block-control pos))
   9098               (when (and tmp (> tmp (point)))
   9099                 (setq offset (+ offset (or web-mode-attr-indent-offset web-mode-code-indent-offset))))
   9100               )
   9101              ((web-mode-attribute-next)
   9102               (setq offset (current-column)))
   9103              ) ;cond
   9104            ) ;attr-indent
   9105 
   9106           ((or (member language '("html" "xml"))
   9107                (and (member language '("jsx"))
   9108                     (string= options "is-html")))
   9109            (when debug (message "I200(%S) web-mode-markup-indentation" pos))
   9110            ;; https://www.w3.org/TR/html5/syntax.html#optional-tags
   9111            (when web-mode-enable-optional-tags
   9112              (save-excursion
   9113                (let (tag-name parent-tag-name parent-tag-pos)
   9114                  (when (and (setq tag-name (get-text-property pos 'tag-name))
   9115                             (setq parent-tag-pos (web-mode-element-parent-position pos))
   9116                             (setq parent-tag-name (get-text-property parent-tag-pos 'tag-name))
   9117                             (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")))
   9118                                 (and (string= parent-tag-name "li") (member tag-name '("li")))
   9119                                 (and (string= parent-tag-name "dt") (member tag-name '("dt" "dd")))
   9120                                 (and (string= parent-tag-name "td") (member tag-name '("td" "th")))
   9121                                 (and (string= parent-tag-name "th") (member tag-name '("td" "th")))
   9122                                 ))
   9123                    (when debug (message "I205(%S) %S(%S) auto-closing" pos parent-tag-name parent-tag-pos))
   9124                    (setq offset (web-mode-indentation-at-pos parent-tag-pos))
   9125                    )))) ; when let save-excursion when
   9126 
   9127            (when (string= web-mode-engine "closure")
   9128              (save-excursion
   9129                (when (and (re-search-backward "{/?switch" nil t)
   9130                           (string= (match-string-no-properties 0) "{switch"))
   9131                  (setq offset (+ (current-indentation) (* 2 web-mode-markup-indent-offset)))
   9132                  )
   9133                ))
   9134            (cond
   9135              ((not (null offset))
   9136               )
   9137              ((get-text-property pos 'tag-beg)
   9138               (setq offset (web-mode-markup-indentation pos))
   9139               )
   9140              ((and web-mode-indentless-elements
   9141                    (not (string= language "jsx"))
   9142                    (null (get-text-property pos 'block-side))
   9143                    (null (get-text-property pos 'part-side))
   9144                    (and (null (get-text-property pos 'tag-beg))
   9145                         (save-excursion
   9146                           (and (web-mode-element-parent)
   9147                                (member (get-text-property (point) 'tag-name) web-mode-indentless-elements))))
   9148                    )
   9149               (setq offset nil))
   9150              ((or (eq (length curr-line) 0)
   9151                   (= web-mode-indent-style 2)
   9152                   (get-text-property pos 'tag-beg)
   9153                   (get-text-property pos 'reg-beg))
   9154               (setq offset (web-mode-markup-indentation pos))
   9155               )
   9156              )
   9157            )
   9158 
   9159           ((string= language "ctemplate")
   9160            (when debug (message "I210(%S) ctemplate" pos))
   9161            (setq offset reg-col))
   9162 
   9163           ((string= language "antlers")
   9164            (when debug (message "I214(%S) antlers" pos))
   9165            (setq offset reg-col))
   9166 
   9167           ((string= language "expressionengine")
   9168            (when debug (message "I220(%S) expressionengine" pos))
   9169            (setq offset (+ reg-col (or web-mode-attr-indent-offset web-mode-code-indent-offset))))
   9170 
   9171           ((string= language "asp")
   9172            (when debug (message "I230(%S) asp" pos))
   9173            (setq offset (web-mode-asp-indentation pos
   9174                                                   curr-line
   9175                                                   reg-col
   9176                                                   curr-indentation
   9177                                                   reg-beg)))
   9178 
   9179           ((member language '("lsp" "cl-emb" "artanis"))
   9180            (when debug (message "I240(%S) lsp" pos))
   9181            (setq offset (web-mode-lisp-indentation pos ctx)))
   9182 
   9183           ((and (member curr-char '(?\}))
   9184                 (string= language "razor")
   9185                 (get-text-property pos 'block-end))
   9186            (when debug (message "I245(%S) razor closing" pos))
   9187            (goto-char reg-beg)
   9188            ;;(message "%S %S" (point) (current-column))
   9189            (setq offset (current-column)
   9190                  reg-col nil)
   9191            )
   9192 
   9193           ((member curr-char '(?\} ?\) ?\]))
   9194            (when debug (message "I250(%S) closing-paren" pos))
   9195            (let (ori pos2)
   9196              (setq pos2 pos)
   9197              ;; #1096
   9198              (when (looking-at-p ".[\]})]+")
   9199                (skip-chars-forward "[\]})]")
   9200                (backward-char)
   9201                (setq pos2 (point))
   9202                ) ;when
   9203              (if (get-text-property pos 'block-side)
   9204                  (setq ori (web-mode-block-opening-paren-position pos2 reg-beg))
   9205                  (setq ori (web-mode-part-opening-paren-position pos2 reg-beg)))
   9206              ;;(message "ori=%S" ori)
   9207              (cond
   9208                ((null ori)
   9209                 (setq offset reg-col))
   9210                ((and (goto-char ori)
   9211                      (looking-back ")[ ]*" (point-min)) ;; peut-on se passer du looking-back ?
   9212                      (re-search-backward ")[ ]*" nil t)
   9213                      (web-mode-block-opening-paren reg-beg))
   9214                 (back-to-indentation)
   9215                 (setq offset (current-indentation))
   9216                 )
   9217                (t
   9218                 (goto-char ori)
   9219                 (back-to-indentation)
   9220                 (setq offset (current-indentation))
   9221                 ;;(message "ori=%S offset=%S" ori offset)
   9222                 (when (get-text-property pos 'jsx-depth)
   9223                   ;;(when (get-text-property pos 'jsx-end)
   9224                   (setq adjust nil))
   9225                 ) ;t
   9226                ) ;cond
   9227              ) ;let
   9228            )
   9229 
   9230           ((member language '("mako" "web2py"))
   9231            (when debug (message "I254(%S) python (mako/web2py)" pos))
   9232            (setq offset (web-mode-python-indentation pos
   9233                                                      curr-line
   9234                                                      reg-col
   9235                                                      curr-indentation
   9236                                                      reg-beg)))
   9237 
   9238           ((member language '("erb" "ruby"))
   9239            (when debug (message "I260(%S) erb" pos))
   9240            (setq offset (web-mode-ruby-indentation pos
   9241                                                    curr-line
   9242                                                    reg-col
   9243                                                    curr-indentation
   9244                                                    reg-beg)))
   9245 
   9246           ((string= language "css")
   9247            (when debug (message "I270(%S) css-indentation" pos))
   9248            ;;(message "prev=%c" prev-char)
   9249            (cond
   9250              ((eq prev-char ?:)
   9251               (setq offset (+ prev-indentation web-mode-css-indent-offset)))
   9252              ((eq prev-char ?,)
   9253               (setq offset prev-indentation))
   9254              (t
   9255               (setq offset (car (web-mode-css-indentation pos
   9256                                                           reg-col
   9257                                                           curr-indentation
   9258                                                           language
   9259                                                           reg-beg))))))
   9260 
   9261           ((string= language "sql")
   9262            (when debug (message "I280(%S) sql" pos))
   9263            (setq offset (car (web-mode-sql-indentation pos
   9264                                                        reg-col
   9265                                                        curr-indentation
   9266                                                        language
   9267                                                        reg-beg))))
   9268 
   9269           ((string= language "markdown")
   9270            (when debug (message "I290(%S) markdown" pos))
   9271            (setq offset (car (web-mode-markdown-indentation pos
   9272                                                             reg-col
   9273                                                             curr-indentation
   9274                                                             language
   9275                                                             reg-beg))))
   9276 
   9277           ((string= language "stylus")
   9278            (when debug (message "I294(%S) stylus" pos))
   9279            (setq offset (car (web-mode-stylus-indentation pos
   9280                                                           reg-col
   9281                                                           curr-indentation
   9282                                                           language
   9283                                                           reg-beg))))
   9284           ((string= language "sass")
   9285            (when debug (message "I296(%S) sass" pos))
   9286            (setq offset (car (web-mode-stylus-indentation pos
   9287                                                           reg-col
   9288                                                           curr-indentation
   9289                                                           language
   9290                                                           reg-beg))))
   9291 
   9292           ((string= language "pug")
   9293            (when debug (message "I298(%S) pug" pos))
   9294            (setq offset (car (web-mode-pug-indentation pos
   9295                                                        reg-col
   9296                                                        curr-indentation
   9297                                                        language
   9298                                                        reg-beg))))
   9299 
   9300           ((and (string= language "razor")
   9301                 (string-match-p "^\\." curr-line)
   9302                 (string-match-p "^\\." prev-line))
   9303            (when debug (message "I300(%S) razor" pos))
   9304            (setq offset prev-indentation))
   9305 
   9306           ((and (string= language "razor")
   9307                 (string-match-p "^case " curr-line)
   9308                 (string-match-p "^case " prev-line))
   9309            (when debug (message "I310(%S) razor case" pos))
   9310            (search-backward "case ")
   9311            (setq offset (current-column)))
   9312 
   9313           ((and is-js
   9314                 (member ?\. chars)
   9315                 (not (string-match-p "^\\.\\.\\." curr-line)))
   9316            (when debug (message "I320(%S) javascript-calls" pos))
   9317            (let (pair)
   9318              (setq pair (web-mode-javascript-calls-beginning-position pos reg-beg))
   9319              ;;(message "%S" pair)
   9320              (when pair
   9321                (goto-char (car pair))
   9322                ;;(message "%S %S" (point) pair)
   9323                (cond
   9324                  ((cdr (assoc "lineup-calls" web-mode-indentation-params))
   9325                   ;;(message "ici")
   9326                   ;;(search-forward ".")
   9327                   (if (cdr pair)
   9328                       (progn
   9329                         (goto-char (cdr pair))
   9330                         (setq offset (current-column))
   9331                         (looking-at "\\.\\([ \t\n]*\\)")
   9332                         (setq offset (- offset (length (match-string-no-properties 1))))
   9333                         (unless (eq curr-char ?\.) (setq offset (1+ offset)))
   9334                         ) ;progn
   9335                       ;; TODO: cela devrait etre fait dans web-mode-javascript-calls-beginning-position
   9336                       (skip-chars-forward " \t\n")
   9337                       (setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9338                       ) ;if
   9339                   )
   9340                  (t
   9341                   (setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9342                   ) ;t
   9343                  ) ;cond
   9344                ) ;when
   9345              ) ;let
   9346            )
   9347 
   9348           ((and is-js
   9349                 (member ?\+ chars))
   9350            (when debug (message "I330(%S) javascript-string" pos))
   9351            ;;(message "js-concat")
   9352            (cond
   9353              ((not (web-mode-javascript-string-beginning pos reg-beg))
   9354               )
   9355              ((null (cdr (assoc "lineup-concats" web-mode-indentation-params)))
   9356               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9357              ((not (eq curr-char ?\+))
   9358               (setq offset (current-column)))
   9359              (t
   9360               (setq offset (current-column))
   9361               (when (not (looking-back "\\(^[ \t]+\\|if[ ]*[(]?\\)" (point-min)))
   9362                 (goto-char pos)
   9363                 (looking-at "\\+[ \t\n]*")
   9364                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9365               )
   9366              )
   9367            )
   9368 
   9369           ;; #579 , #742
   9370           ((and (member language '("javascript" "jsx" "ejs" "php"))
   9371                 (string-match-p "=[>]?$" prev-line))
   9372            (when debug (message "I340(%S)" pos))
   9373            (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9374            ;;(message "ici%S" offset)
   9375            )
   9376 
   9377           ;; #1016
   9378           ((and (member language '("javascript" "jsx" "ejs"))
   9379                 (string-match-p "^[ \t]*|}" curr-line))
   9380            (when debug (message "I346(%S) flow-exact-object-type-end" pos))
   9381            (when (re-search-backward "{|" reg-beg t)
   9382              (setq offset (current-indentation))
   9383              )
   9384            )
   9385 
   9386           ;; #446, #638, #800, #978, #998
   9387           ((and (member language '("javascript" "jsx" "ejs" "php"))
   9388                 (or (string-match-p "[&|?:+-]$" prev-line)
   9389                     (string-match-p "^[&|?:+-]" curr-line))
   9390                 (not (and (string= language "php")
   9391                           (string-match-p "^->" curr-line)))
   9392                 (not (and (string= language "php")
   9393                           (string-match-p "^?[a-zA-z]*" curr-line)))
   9394                 (not (and (string= language "php")
   9395                           (string-match-p "\\(else[ ]?:\\|if[ ]?([^)]*)[ ]?:\\)" prev-line)))
   9396                 (not (string-match-p "^\\(++\\|--\\)" curr-line))
   9397                 (not (and is-js
   9398                           (string-match-p "]:\\|{|$" prev-line)))
   9399                 (not (and (eq prev-char ?\:)
   9400                           (string-match-p "^\\(case\\|default\\)" prev-line)))
   9401                 )
   9402            ;;(message "prev=%S" prev-line)
   9403            (when debug (message "I350(%S) multiline statement" pos))
   9404            (let (is-ternary)
   9405              (setq is-ternary (or (string-match-p "[?:]$" prev-line)
   9406                                   (string-match-p "^[?:]" curr-line)))
   9407              (cond
   9408                ((not (funcall (if is-js
   9409                                   'web-mode-javascript-statement-beginning
   9410                                   'web-mode-block-statement-beginning)
   9411                               pos reg-beg is-ternary))
   9412                 )
   9413                ((null (cdr (assoc "lineup-ternary" web-mode-indentation-params)))
   9414                 (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9415                (t
   9416                 (setq offset (current-column))
   9417                 (when (and (member curr-char '(?\+ ?\- ?\& ?\| ?\? ?\:))
   9418                            (not (looking-back "\\(^[ \t]+\\|if[ ]*[(]?\\)" (point-min)))) ; #743
   9419                   (goto-char pos)
   9420                   (looking-at "\\(||\\|&&\\|[&|?:+-]\\)[ \t\n]*")
   9421                   (setq offset (- offset (length (match-string-no-properties 0)))))
   9422                 )
   9423                ) ;cond
   9424              ) ;let
   9425            )
   9426 
   9427           ((and is-js
   9428                 (eq prev-char ?\()
   9429                 (string-match-p "=>[ ]*([ ]*$" prev-line))
   9430            (when debug (message "I355(%S) => (" pos))
   9431            (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9432            )
   9433 
   9434           ((and is-js
   9435                 (or (member ?\, chars)
   9436                     (member prev-char '(?\( ?\[))))
   9437            (when debug (message "I360(%S) javascript-args(%S)" pos (web-mode-jsx-is-html prev-line-end)))
   9438            (cond
   9439              ((not (web-mode-javascript-args-beginning pos reg-beg))
   9440               (message "no js args beg")
   9441               )
   9442              ((or (not (cdr (assoc "lineup-args" web-mode-indentation-params)))
   9443                   (looking-at-p "|?\n") ;; #1016
   9444                   ;;(eq (char-after) ?\n)
   9445                   )
   9446               (if (and reg-col (> reg-col (current-indentation)))
   9447                   (setq offset (+ reg-col web-mode-code-indent-offset))
   9448                   (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9449               )
   9450              ((not (eq curr-char ?\,))
   9451               (setq offset (current-column)))
   9452              (t
   9453               (setq offset (current-column))
   9454               (goto-char pos)
   9455               (looking-at ",[ \t\n]*")
   9456               (setq offset (- offset (length (match-string-no-properties 0)))))
   9457              ) ;cond
   9458            )
   9459 
   9460           ((and is-js
   9461                 (or (eq prev-char ?\))
   9462                     (string-match-p "\\(^\\|[}[:space:]]+\\)else$" prev-line)))
   9463            (when debug (message "I370(%S)" pos))
   9464            (cond
   9465              ((and (string-match-p "else$" prev-line)
   9466                    (not (string-match-p "^{" curr-line)))
   9467               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9468               )
   9469              ((and (string-match-p "else$" prev-line)
   9470                    (string-match-p "^{" curr-line)
   9471                    web-mode-enable-curly-brace-indentation)
   9472               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9473               )
   9474              ((setq tmp (web-mode-part-is-opener prev-pos reg-beg))
   9475               ;;(message "is-opener")
   9476               (if (or (not (looking-at-p "{")) ;; #1020, #1053, #1160
   9477                       web-mode-enable-curly-brace-indentation)
   9478                   (setq offset (+ tmp web-mode-code-indent-offset))
   9479                   (setq offset tmp))
   9480               )
   9481              (t
   9482               (setq offset
   9483                     (car (web-mode-javascript-indentation pos
   9484                                                           reg-col
   9485                                                           curr-indentation
   9486                                                           language
   9487                                                           reg-beg)))
   9488               ) ;t
   9489              ) ;cond
   9490 
   9491            )
   9492 
   9493           ;; TODO : a retoucher completement car le code js a ete place ci-dessus
   9494           ;;((and (member language '("javascript" "jsx" "ejs" "php"))
   9495           ((and (member language '("php"))
   9496                 (or (and (eq prev-char ?\))
   9497                          (string-match-p "^\\(for\\|foreach\\|if\\|else[ ]*if\\|while\\)[ ]*(" prev-line))
   9498                     (and is-js
   9499                          (web-mode-part-is-opener prev-pos reg-beg))
   9500                     (string-match-p "^else$" prev-line))
   9501                 (not (string-match-p "^\\([{.]\\|->\\)" curr-line)))
   9502            (when debug (message "I380(%S)" pos))
   9503            (cond
   9504              ((and (eq prev-char ?\))
   9505                    (string-match-p "^\\(for\\|if\\|while\\)[ ]*(" prev-line))
   9506               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9507               )
   9508              ((member language '("javascript" "jsx"))
   9509               (setq offset
   9510                     (+ (car (web-mode-javascript-indentation pos
   9511                                                              reg-col
   9512                                                              curr-indentation
   9513                                                              language
   9514                                                              reg-beg))
   9515                        web-mode-code-indent-offset))
   9516               )
   9517              (t
   9518               (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9519               )
   9520              )
   9521            )
   9522 
   9523           ((and (member language '("php" "blade")) (string-match-p "^->" curr-line))
   9524            (when debug (message "I390(%S) block-calls" pos))
   9525            (cond
   9526              ((not (web-mode-block-calls-beginning pos reg-beg))
   9527               )
   9528              ((cdr (assoc "lineup-calls" web-mode-indentation-params))
   9529               ;;(message "point=%S" (point))
   9530               (if (looking-back "::[ ]*" (point-min))
   9531                   (progn
   9532                     (re-search-backward "::[ ]*")
   9533                     (setq offset (current-column))
   9534                     ;;(message "ici%S offset=%S" (point) offset)
   9535                     )
   9536                   (search-forward "->")
   9537                   (setq offset (- (current-column) 2)))
   9538               )
   9539              (t
   9540               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9541              ))
   9542 
   9543           ((and is-js (member ?\, chars))
   9544            (when debug (message "I400(%S) part-args" pos))
   9545            (cond
   9546              ((not (web-mode-part-args-beginning pos reg-beg))
   9547               ;;(message "ici")
   9548               )
   9549              ((cdr (assoc "lineup-args" web-mode-indentation-params))
   9550               (setq offset (current-column))
   9551               ;;(message "offset=%S" offset)
   9552               (when (eq curr-char ?\,)
   9553                 (goto-char pos)
   9554                 (looking-at ",[ \t\n]*")
   9555                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9556               )
   9557              (t
   9558               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9559              ))
   9560 
   9561           ((member ?\, chars)
   9562            (when debug (message "I401(%S) block-args" pos))
   9563            (cond
   9564              ((not (web-mode-block-args-beginning pos reg-beg))
   9565               ;;(message "ici")
   9566               )
   9567              ((cdr (assoc "lineup-args" web-mode-indentation-params))
   9568               (setq offset (current-column))
   9569               ;;(message "offset=%S" offset)
   9570               (when (eq curr-char ?\,)
   9571                 (goto-char pos)
   9572                 (looking-at ",[ \t\n]*")
   9573                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9574               )
   9575              (t
   9576               (setq offset (current-column))
   9577               ;;(message "point=%S offset=%S" (point) offset)
   9578               (if (looking-back "[ ]+" (point-min))
   9579                   (progn
   9580                     (setq offset (current-indentation)))
   9581                 (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9582               ;;(when (eq curr-char ?\,)
   9583               ;;  (goto-char pos)
   9584               ;;  (looking-at ",[ \t\n]*")
   9585               ;;  (setq offset (- offset (length (match-string-no-properties 0)))))
   9586               ;;(setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9587               ) ;t
   9588              ))
   9589 
   9590 
   9591           ((and (string= language "php") (member ?\. chars))
   9592            (when debug (message "I410(%S) block-string" pos))
   9593            (cond
   9594              ((not (web-mode-block-string-beginning pos reg-beg))
   9595               )
   9596              ((null (cdr (assoc "lineup-concats" web-mode-indentation-params)))
   9597               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9598              ((not (eq curr-char ?\.))
   9599               (setq offset (current-column)))
   9600              (t
   9601               (setq offset (current-column))
   9602               (goto-char pos)
   9603               (when (cdr (assoc "lineup-quotes" web-mode-indentation-params))
   9604                 (looking-at "\\.[ \t\n]*")
   9605                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9606               )))
   9607 
   9608           ((member language '("javascript" "jsx" "ejs" "underscore"))
   9609            (when debug (message "I420(%S) javascript-indentation" pos))
   9610            (setq offset (car (web-mode-javascript-indentation pos
   9611                                                               reg-col
   9612                                                               curr-indentation
   9613                                                               language
   9614                                                               reg-beg))))
   9615 
   9616           (t
   9617            (when debug (message "I430(%S) bracket-indentation" pos))
   9618            (setq offset (car (web-mode-bracket-indentation pos
   9619                                                            reg-col
   9620                                                            curr-indentation
   9621                                                            language
   9622                                                            reg-beg))))
   9623 
   9624           ) ;cond
   9625 
   9626         (when (and offset reg-col adjust (< offset reg-col)) (setq offset reg-col))
   9627 
   9628         ) ;let
   9629       ) ;save-excursion
   9630 
   9631     (when offset
   9632       ;;(message "offset=%S" offset)
   9633       (let ((diff (- (current-column) (current-indentation))))
   9634         (when (not (= offset (current-indentation)))
   9635           (setq web-mode-change-beg (line-beginning-position)
   9636                 web-mode-change-end (+ web-mode-change-beg offset)))
   9637         (setq offset (max 0 offset))
   9638         (indent-line-to offset)
   9639         (if (> diff 0) (move-to-column (+ (current-column) diff)))
   9640         (when (and (string= web-mode-engine "mason")
   9641                    (= offset 0)
   9642                    (eq char ?\%))
   9643           (save-excursion
   9644             (font-lock-fontify-region (line-beginning-position) (line-end-position)))
   9645           ) ;when
   9646         ) ;let
   9647       ) ;when
   9648 
   9649     ))
   9650 
   9651 (defun web-mode-bracket-level (pos limit)
   9652   (save-excursion
   9653     (let ((continue t)
   9654           (regexp "[\]\[}{)(]")
   9655           (char nil)
   9656           (map nil)
   9657           (key nil)
   9658           (value 0)
   9659           (open '(?\( ?\{ ?\[)))
   9660       (goto-char pos)
   9661       (while (and continue (re-search-backward regexp limit t))
   9662         (setq char (aref (match-string-no-properties 0) 0))
   9663         (setq key (cond ((eq char ?\)) ?\()
   9664                         ((eq char ?\}) ?\{)
   9665                         ((eq char ?\]) ?\[)
   9666                         (t             char)))
   9667         (setq value (or (plist-get map key) 0))
   9668         (setq value (if (member char open) (1+ value) (1- value)))
   9669         (setq map (plist-put map key value))
   9670         (setq continue (< value 1))
   9671         ;;(message "pos=%S char=%c key=%c value=%S" (point) char key value)
   9672         ) ;while
   9673       (if (>= value 1) (current-indentation) nil)
   9674       )))
   9675 
   9676 (defun web-mode-token-html-indentation (pos)
   9677   (save-excursion
   9678     (let (beg (continue t) end level map offset regexp tag val void (css-beg 0))
   9679       (goto-char pos)
   9680       ;;(message "pos=%S" pos)
   9681       (setq beg (web-mode-part-token-beginning-position pos))
   9682       (save-excursion
   9683         (when (and (> (- pos beg) 5)
   9684                    (re-search-backward "</?[a-zA-Z0-9]+" beg t)
   9685                    (string= "<style" (downcase (match-string-no-properties 0))))
   9686           (setq css-beg (point))
   9687           )
   9688         )
   9689       ;;(message "beg=%S" beg)
   9690       (cond
   9691         ((eq (char-after pos) ?\`)
   9692          (setq offset (web-mode-indentation-at-pos beg)))
   9693         ((web-mode-looking-back "`[ \n\t]*" pos)
   9694          (setq offset (+ (web-mode-indentation-at-pos beg) web-mode-markup-indent-offset)))
   9695         ((looking-at "</\\([a-zA-Z0-9]+\\)")
   9696          (setq tag (match-string-no-properties 1)
   9697                regexp (concat "</?" tag)
   9698                level -1)
   9699          (while (and continue (re-search-backward regexp beg t))
   9700            (cond
   9701              ((eq (aref (match-string-no-properties 0) 1) ?\/)
   9702               (setq level (1- level)))
   9703              (t
   9704               (setq level (1+ level)))
   9705              ) ;cond
   9706            (when (= level 0)
   9707              (setq continue nil
   9708                    offset (current-indentation)))
   9709            ) ;while
   9710          )
   9711         ((> css-beg 0)
   9712          ;;(message "CSS")
   9713          (cond
   9714            ((member (char-after) '(?\) ?\} ?\]))
   9715             (web-mode-go (web-mode-token-opening-paren-position pos (+ css-beg 8) ""))
   9716             (setq offset (current-indentation))
   9717             )
   9718            ((setq level (web-mode-bracket-level pos (+ css-beg 8)))
   9719             (setq offset (+ level web-mode-css-indent-offset))
   9720             )
   9721            (t
   9722             (setq offset (+ (web-mode-indentation-at-pos css-beg) web-mode-style-padding))
   9723             ) ;t
   9724            )
   9725          )
   9726         ((looking-at "[a-zA-Z-]+[ ]?=")
   9727          (re-search-backward "<[a-zA-Z]+[ ]*" beg t)
   9728          (setq offset (+ (current-column) (length (match-string-no-properties 0))))
   9729          )
   9730         ((looking-at-p "/>")
   9731          (search-backward "<" beg t)
   9732          (setq offset (current-column))
   9733          )
   9734         (t
   9735          (setq regexp "</?\\([a-zA-Z0-9]+\\)")
   9736          ;;(message "point=%S" (point))
   9737          (while (and continue (re-search-backward regexp beg t))
   9738            (setq tag (downcase (match-string-no-properties 1))
   9739                  end nil
   9740                  void nil)
   9741            (cond
   9742              ((eq (aref (match-string-no-properties 0) 1) ?/)
   9743               (setq end t))
   9744              ((web-mode-element-is-void tag)
   9745               (setq void t))
   9746              (t
   9747               (save-excursion
   9748                 (when (and (search-forward ">" pos t) (eq (char-before (1- (point))) ?\/))
   9749                   (setq void t))
   9750                 ) ;save-excursion
   9751               ) ;t
   9752              ) ;cond
   9753            (unless void
   9754              (setq val (or (lax-plist-get map tag) 0))
   9755              (setq val (if end (1- val) (1+ val)))
   9756              (setq map (lax-plist-put map tag val))
   9757              ;;(message "val=%S tag=%S end=%S | %S" val tag end (plist-get map tag))
   9758              (setq continue (not (> val 0)))
   9759              ) ;unless
   9760                                         ;(message "pos=%S tag=%S val=%S end=%S void=%S" (point) tag val end void)
   9761            ) ;while
   9762          (cond
   9763            ((> val 0)
   9764             ;;(message "point=%S" (point))
   9765             ;;(goto-char (1+ beg))
   9766             ;;(forward-char)
   9767             ;;(re-search-forward "[[:space:]]*")
   9768             (setq offset (+ (current-indentation) web-mode-markup-indent-offset)))
   9769            (t
   9770             (setq offset (current-indentation)))
   9771            )
   9772          ) ;t
   9773         ) ;cond
   9774       offset)))
   9775 
   9776 (defun web-mode-token-css-indentation (pos)
   9777   (save-excursion
   9778     (goto-char pos)
   9779     (web-mode-part-token-beginning)
   9780     (+ web-mode-css-indent-offset (current-indentation))
   9781     ))
   9782 
   9783 (defun web-mode-relayql-indentation (pos &optional prefix)
   9784   (unless prefix (setq prefix "relayql"))
   9785   (let (beg offset level char)
   9786     (setq char (char-after))
   9787     (setq beg (web-mode-part-token-beginning-position pos))
   9788     (goto-char beg)
   9789     (cond
   9790       ((member char '(?\`))
   9791        (setq offset (current-indentation))
   9792        )
   9793       ((member char '(?\) ?\} ?\]))
   9794        (web-mode-go (web-mode-token-opening-paren-position pos beg prefix))
   9795        (setq offset (current-indentation))
   9796        )
   9797       ((setq level (web-mode-bracket-level pos beg))
   9798        (setq offset (+ level web-mode-code-indent-offset))
   9799        )
   9800       (t
   9801        (setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9802        )
   9803       )
   9804     offset))
   9805 
   9806 (defun web-mode-markup-indentation (pos)
   9807   (let (offset beg ret jsx-depth)
   9808     (when (and (setq jsx-depth (get-text-property pos 'jsx-depth))
   9809                (get-text-property pos 'jsx-beg)
   9810                (not (get-text-property pos 'tag-beg)))
   9811       (setq jsx-depth (1- jsx-depth)))
   9812     ;;(when (setq beg (web-mode-markup-indentation-origin pos jsx-depth))
   9813     (cond
   9814       ((not (setq beg (web-mode-markup-indentation-origin pos jsx-depth)))
   9815        (setq offset 0))
   9816       ((null (setq ret (web-mode-element-is-opened beg pos)))
   9817        (setq offset (web-mode-indentation-at-pos beg)))
   9818       ((eq ret t)
   9819        (setq offset (+ (web-mode-indentation-at-pos beg)
   9820                        web-mode-markup-indent-offset)))
   9821       (t
   9822        (setq offset ret))
   9823       ) ;cond
   9824     ;;(message "markup-indentation-origin=%S (jsx-depth=%S)" beg jsx-depth)
   9825     ;;) ;when beg
   9826     offset))
   9827 
   9828 (defun web-mode-css-indentation (pos initial-column language-offset language &optional limit)
   9829   (let ((open-ctx (web-mode-bracket-up pos language limit)) offset)
   9830     (cond
   9831       ((or (null open-ctx) (null (plist-get open-ctx :pos)))
   9832        (setq offset initial-column))
   9833       (t
   9834        (setq offset (+ (plist-get open-ctx :indentation) language-offset)))
   9835       ) ;cond
   9836     (cons (if (< offset initial-column) initial-column offset) open-ctx)
   9837     ))
   9838 
   9839 (defun web-mode-sql-indentation (pos initial-column language-offset language &optional limit)
   9840   (let ((open-ctx (web-mode-bracket-up pos language limit)) offset)
   9841     ;;(message "%S %S %S %S %S" pos (point) initial-column language-offset open-ctx)
   9842     (cond
   9843       ((and (not (null open-ctx)) (not (null (plist-get open-ctx :pos))))
   9844        (setq offset (+ (plist-get open-ctx :column) 1)))
   9845       ((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\\)")
   9846        (setq offset initial-column))
   9847       (t
   9848        (setq offset (+ initial-column language-offset)))
   9849       ) ;cond
   9850     (cons (if (< offset initial-column) initial-column offset) open-ctx)
   9851     ))
   9852 
   9853 (defun web-mode-markdown-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       ) ;save-excursion
   9859     ;;(message "%S %S %S %S" pos (point) initial-column language-offset)
   9860     (cons (if (<= offset initial-column) initial-column offset) nil)))
   9861 
   9862 (defun web-mode-stylus-indentation (pos initial-column language-offset _language &optional _limit)
   9863   (let (offset)
   9864     (save-excursion
   9865       (goto-char pos)
   9866       (setq offset (current-column))
   9867       (if (looking-at-p "[[:alnum:]-]+:")
   9868           (setq offset (+ initial-column language-offset))
   9869           (setq offset initial-column))
   9870       ) ;save-excursion
   9871     ;;(message "%S %S %S %S" pos (point) initial-column language-offset)
   9872     (cons (if (<= offset initial-column) initial-column offset) nil)))
   9873 
   9874 (defun web-mode-sass-indentation (pos initial-column language-offset _language &optional _limit)
   9875   (let (offset)
   9876     (save-excursion
   9877       (goto-char pos)
   9878       (setq offset (current-column))
   9879       (if (looking-at-p "[[:alnum:]-]+:")
   9880           (setq offset (+ initial-column language-offset))
   9881           (setq offset initial-column))
   9882       ) ;save-excursion
   9883     ;;(message "%S %S %S %S" pos (point) initial-column language-offset)
   9884     (cons (if (<= offset initial-column) initial-column offset) nil)))
   9885 
   9886 (defun web-mode-pug-indentation (_pos _initial-column _language-offset _language &optional _limit)
   9887   nil
   9888   )
   9889 
   9890 (defun web-mode-javascript-indentation (pos initial-column language-offset language &optional limit)
   9891   (let (open-ctx open-pos indentation offset sub block-pos)
   9892     (setq open-ctx (web-mode-bracket-up pos language limit))
   9893     ;;(message "%S" open-ctx)
   9894     ;;(message "pos(%S) initial-column(%S) language-offset(%S) language(%S) limit(%S)" pos initial-column language-offset language limit)
   9895     ;;(message "javascript-indentation: %S\nchar=%c" open-ctx (plist-get open-ctx :char))
   9896     (setq indentation (plist-get open-ctx :indentation))
   9897     (when (and initial-column (> initial-column indentation))
   9898       (setq indentation initial-column))
   9899     (setq case-fold-search nil) ;#1006
   9900     (when open-ctx
   9901       (setq open-pos (plist-get open-ctx :pos)))
   9902     (setq block-pos (web-mode-inside-block-control pos))
   9903     (when (and block-pos (> limit block-pos)) ;#1275
   9904       (setq block-pos nil))
   9905     ;;(message "bracket-pos=%S block-pos=%S" open-pos block-pos)
   9906     (cond
   9907       ((and block-pos (or (null open-pos) (> block-pos open-pos))) ;#1230
   9908        (setq offset (+ indentation language-offset)))
   9909       ((null open-pos)
   9910        (setq offset initial-column))
   9911       ((and (member language '("javascript" "jsx" "ejs"))
   9912             (eq (plist-get open-ctx :char) ?\{)
   9913             (web-mode-looking-back "switch[ ]*" (plist-get open-ctx :pos)))
   9914        (setq sub (if (cdr (assoc "case-extra-offset" web-mode-indentation-params)) 0 1))
   9915        (cond
   9916          ((looking-at-p "case\\|default")
   9917           (setq offset (+ indentation (* language-offset (- 1 sub)))))
   9918          (t
   9919           (setq offset (+ indentation (* language-offset (- 2 sub)))))
   9920          ) ;cond switch
   9921        )
   9922       (t
   9923        (setq offset (+ indentation language-offset)))
   9924       ) ;cond
   9925     (setq case-fold-search t)
   9926     (cons (if (< offset initial-column) initial-column offset) open-ctx)
   9927     ))
   9928 
   9929 (defun web-mode-bracket-indentation (pos initial-column language-offset language &optional limit)
   9930   (save-excursion
   9931     (let* ((ctx (web-mode-bracket-up pos language limit))
   9932            (char (plist-get ctx :char))
   9933            (pos (plist-get ctx :pos))
   9934            (indentation (plist-get ctx :indentation)))
   9935       ;;(message "pos(%S) initial-column(%S) language-offset(%S) language(%S) limit(%S)" pos initial-column language-offset language limit)
   9936       ;;(message "bracket-up: %S, %c" ctx char)
   9937       (cond
   9938         ((null pos)
   9939          (setq indentation initial-column))
   9940         ((and (member language '("php"))
   9941               (eq char ?\{)
   9942               (web-mode-looking-back "switch[ ]*" pos)
   9943               (not (looking-at-p "case\\|default")))
   9944          (setq indentation (+ indentation (* language-offset 2)))
   9945          )
   9946         ((and (member language '("php"))
   9947               (eq char ?\{)
   9948               (goto-char pos)
   9949               (web-mode-looking-back "[)][ ]*" pos)
   9950               (search-backward ")")
   9951               (web-mode-block-opening-paren limit))
   9952          (setq indentation (+ (current-indentation) language-offset))
   9953          )
   9954         (t
   9955          (setq indentation (+ indentation language-offset))
   9956          )
   9957         ) ;cond
   9958       (cons (if (< indentation initial-column) initial-column indentation) ctx)
   9959       )))
   9960 
   9961 (defun web-mode-ruby-indentation (pos line initial-column language-offset limit)
   9962   (unless limit (setq limit nil))
   9963   (let (h offset prev-line prev-indentation open-ctx)
   9964     (setq open-ctx (web-mode-bracket-up pos "ruby" limit))
   9965     ;;(message "%S" open-ctx)
   9966     (if (plist-get open-ctx :pos)
   9967         (cond
   9968           ((web-mode-looking-at-p ".[ \t\n]+" (plist-get open-ctx :pos))
   9969            (setq offset (+ (plist-get open-ctx :indentation) language-offset)))
   9970           (t
   9971            (setq offset (1+ (plist-get open-ctx :column))))
   9972           )
   9973         (setq h (web-mode-previous-line pos limit))
   9974         (setq offset initial-column)
   9975         (when h
   9976           (setq prev-line (car h))
   9977           (setq prev-indentation (cdr h))
   9978           (cond
   9979             ((string-match-p ",$" prev-line)
   9980              (save-excursion
   9981                (goto-char limit)
   9982                (looking-at "<%=? [a-z_]+ ")
   9983                (setq offset (+ initial-column (length (match-string-no-properties 0))))
   9984                ) ;save-excursion
   9985              )
   9986             ((string-match-p "^[ ]*\\(end\\|else\\|elsif\\|when\\)" line)
   9987              (setq offset (- prev-indentation language-offset))
   9988              )
   9989             ((string-match-p "[ ]+\\(do\\)" prev-line)
   9990              (setq offset (+ prev-indentation language-offset))
   9991              )
   9992             ((string-match-p "^[ ]*\\(when\\|if\\|else\\|elsif\\|unless\\|for\\|while\\|def\\|class\\)" prev-line)
   9993              (setq offset (+ prev-indentation language-offset))
   9994              )
   9995             (t
   9996              (setq offset prev-indentation)
   9997              )
   9998             )
   9999           ) ;when
  10000         ) ;if
  10001     offset))
  10002 
  10003 (defun web-mode-python-indentation (pos line initial-column language-offset limit)
  10004   (unless limit (setq limit nil))
  10005   (let (h offset prev-line prev-indentation ctx)
  10006     (setq ctx (web-mode-bracket-up pos "python" limit))
  10007     ;;(message "point-ctx=%S" ctx)
  10008     (if (plist-get ctx :pos)
  10009         (cond
  10010           ((web-mode-looking-at-p ".[ \t\n]+" (plist-get ctx :pos))
  10011            (setq offset (+ (plist-get ctx :indentation) language-offset)))
  10012           (t
  10013            (setq offset (1+ (plist-get ctx :column))))
  10014           )
  10015         ;; else
  10016         (setq h (web-mode-previous-line pos limit))
  10017         (setq offset initial-column)
  10018         (when h
  10019           (setq prev-line (car h))
  10020           (setq prev-indentation (cdr h))
  10021           (cond
  10022             ((string-match-p "^\\(pass\\|else\\|elif\\|when\\|except\\)" line)
  10023              (setq offset (- prev-indentation language-offset))
  10024              )
  10025             ((string-match-p "\\(if\\|else\\|elif\\|for\\|while\\|try\\|except\\)" prev-line)
  10026              (setq offset (+ prev-indentation language-offset))
  10027              )
  10028             (t
  10029              (setq offset prev-indentation)
  10030              )
  10031             ) ;cond
  10032           ) ;when
  10033         ) ;if
  10034     ;;offset
  10035     (if (< offset initial-column) initial-column offset)
  10036     ))
  10037 
  10038 (defun web-mode-lisp-indentation (pos point-ctx)
  10039   (let (offset open-ctx)
  10040     (setq open-ctx (web-mode-bracket-up pos "lsp" (plist-get point-ctx :reg-beg)))
  10041     ;;(message "point-ctx=%S" point-ctx)
  10042     ;;(message "open-ctx=%S" open-ctx)
  10043     (cond
  10044       ((null (plist-get open-ctx :pos))
  10045        (setq offset (plist-get point-ctx :reg-col)))
  10046       ((member (plist-get point-ctx :curr-char) '(?\( ?\)))
  10047        (if (web-mode-looking-at-p "((" (plist-get open-ctx :pos))
  10048            (setq offset (+ (plist-get open-ctx :column) 1))
  10049            (setq offset (+ (plist-get open-ctx :column) web-mode-code-indent-offset)))
  10050        )
  10051       (t
  10052        (goto-char (plist-get open-ctx :pos))
  10053        (forward-char)
  10054        (web-mode-rsf "[[:alnum:]-:]+ ")
  10055        (setq offset (current-column))
  10056        )
  10057       ) ;cond
  10058     offset))
  10059 
  10060 (defun web-mode-asp-indentation (pos line initial-column language-offset limit)
  10061   (unless limit (setq limit nil))
  10062   (let (h out prev-line prev-indentation)
  10063     (setq h (web-mode-previous-line pos limit))
  10064     (setq out initial-column)
  10065     (when h
  10066       (setq prev-line (car h))
  10067       (setq prev-indentation (cdr h))
  10068       ;;(message "line=%S" line)
  10069       (cond
  10070         ((string-match-p "'" line)
  10071          (setq out prev-indentation))
  10072         ;; ----------------------------------------------------------------------
  10073         ;; unindent
  10074         ((string-match-p "\\_<\\(\\(end \\(if\\|function\\|class\\|sub\\|with\\)\\)\\|else\\|elseif\\|next\\|loop\\)\\_>" line)
  10075          (setq out (- prev-indentation language-offset)))
  10076         ;; ----------------------------------------------------------------------
  10077         ;; select case statement
  10078         ((string-match-p "\\_<\\(select case\\)\\_>" line)
  10079          (setq out (- prev-indentation 0)))
  10080         ((string-match-p "\\_<\\(end select\\)" line)
  10081          (setq out (- prev-indentation (* 2 language-offset))))
  10082         ((and (string-match-p "\\_<\\(case\\)\\_>" line) (not (string-match-p "\\_<\\(select case\\)\\_>" prev-line)))
  10083          (setq out (- prev-indentation language-offset)))
  10084         ;; ----------------------------------------------------------------------
  10085         ;; do nothing
  10086         ((string-match-p "\\_<\\(\\(end \\(if\\|function\\|class\\|sub\\|select\\|with\\)\\)\\|loop\\( until\\| while\\)?\\)\\_>" prev-line)
  10087          (setq out (+ prev-indentation 0)))
  10088         ;; indent
  10089         ((string-match-p "\\_<\\(\\(select \\)?case\\|else\\|elseif\\|unless\\|for\\|class\\|with\\|do\\( until\\| while\\)?\\|while\\|\\(public \\|private \\)?\\(function\\|sub\\|class\\)\\)\\_>" prev-line)
  10090          (setq out (+ prev-indentation language-offset)))
  10091         ;; single line if statement
  10092         ((string-match-p "\\_<if\\_>.*\\_<then\\_>[ \t]*[[:alpha:]]+" prev-line)
  10093          (setq out (+ prev-indentation 0)))
  10094         ;; normal if statement
  10095         ((string-match-p "\\_<\\if\\_>" prev-line)
  10096          (setq out (+ prev-indentation language-offset)))
  10097         (t
  10098          (setq out prev-indentation))
  10099         )
  10100       ) ;when
  10101     out))
  10102 
  10103 (defun web-mode-block-previous-live-line ()
  10104   (save-excursion
  10105     (let ((continue t) (line "") (pos (point)))
  10106       (beginning-of-line)
  10107       (while (and continue (not (bobp)) (forward-line -1))
  10108         (when (not (web-mode-block-is-token-line))
  10109           (setq line (web-mode-trim (buffer-substring (point) (line-end-position)))))
  10110         (when (not (string= line ""))
  10111           (setq continue nil))
  10112         ) ;while
  10113       (if (string= line "")
  10114           (progn (goto-char pos) nil)
  10115           (list line (current-indentation) pos (line-end-position)))
  10116       )))
  10117 
  10118 (defun web-mode-part-is-opener (pos reg-beg)
  10119   (save-excursion
  10120     (save-match-data
  10121       (if (and pos
  10122                (web-mode-go (web-mode-part-opening-paren-position pos))
  10123                (>= (point) reg-beg)
  10124                (looking-back "\\(^\\|[ \t]\\)\\(if\\|for\\|while\\)[ ]*" (point-min)))
  10125           (current-indentation)
  10126           nil)
  10127       )))
  10128 
  10129 (defun web-mode-part-previous-live-line (reg-beg)
  10130   (unless reg-beg (setq reg-beg (point-min)))
  10131   ;;(message "reg-beg=%S" reg-beg)
  10132   (save-excursion
  10133     (let ((continue (> (point) reg-beg))
  10134           (line "")
  10135           bol-pos
  10136           eol-pos
  10137           pos)
  10138       (beginning-of-line)
  10139       (while (and continue (> (point) reg-beg) (forward-line -1))
  10140         (setq bol-pos (point)
  10141               eol-pos (line-end-position))
  10142         (when (> reg-beg bol-pos)
  10143           (setq bol-pos reg-beg))
  10144         (when (not (web-mode-part-is-token-line bol-pos))
  10145           (setq line (web-mode-trim (buffer-substring bol-pos eol-pos)))
  10146           (when (not (string= line "")) (setq continue nil))
  10147           ) ;when
  10148         ) ;while
  10149       (cond
  10150         ((string= line "")
  10151          nil)
  10152         (t
  10153          (setq continue t)
  10154          (setq pos (1- eol-pos))
  10155          (while (and (>= pos bol-pos) continue)
  10156            (cond
  10157              ((eq (char-after pos) ?\s)
  10158               (setq pos (1- pos)))
  10159              ((get-text-property pos 'part-token)
  10160               (setq pos (1- pos)))
  10161              (t
  10162               (setq continue nil))
  10163              ) ;cond
  10164            ) ;while
  10165          ;;(message "%S %S : %S" bol-pos eol-pos pos)
  10166          (setq line (web-mode-clean-part-line line))
  10167          (list line (current-indentation) pos (line-end-position)))
  10168         ) ;cond
  10169       )))
  10170 
  10171 (defun web-mode-in-code-block (open close &optional prop)
  10172   (save-excursion
  10173     (let ((pos (point)) pos-open pos-close start end ret)
  10174       (when prop
  10175         (setq start pos
  10176               end pos)
  10177         (when (eq (get-text-property pos prop) (get-text-property (1- pos) prop))
  10178           (setq start (or (previous-single-property-change pos prop) (point-min))))
  10179         (when (eq (get-text-property pos prop) (get-text-property (1+ pos) prop))
  10180           (setq end (next-single-property-change pos prop)))
  10181         ;;        (message "start(%S) end(%S)" start end)
  10182         )
  10183       (setq ret (and (web-mode-sb open start t)
  10184                      (setq pos-open (point))
  10185                      (web-mode-sf close end t)
  10186                      (setq pos-close (point))
  10187                      (>= pos-close pos)))
  10188       (if ret
  10189           (cons pos-open pos-close)
  10190           ret)
  10191       )))
  10192 
  10193 (defun web-mode-clean-part-line (input)
  10194   (let ((out "")
  10195         (beg 0)
  10196         (keep t)
  10197         (n (length input)))
  10198     (dotimes (i n)
  10199       (if (or (get-text-property i 'block-side input)
  10200               (eq (get-text-property i 'part-token input) 'comment)
  10201               (eq (get-text-property i 'tag-type input) 'comment))
  10202           (when keep
  10203             (setq out (concat out (substring input beg i))
  10204                   beg 0
  10205                   keep nil))
  10206           (when (null keep)
  10207             (setq beg i
  10208                   keep t))
  10209           ) ;if
  10210       ) ;dotimes
  10211     (if (> beg 0) (setq out (concat out (substring input beg n))))
  10212     (setq out (if (= (length out) 0) input out))
  10213     (web-mode-trim out)
  10214     ))
  10215 
  10216 (defun web-mode-clean-block-line (input)
  10217   (let ((out "")
  10218         (beg 0)
  10219         (keep t)
  10220         (n (length input)))
  10221     (dotimes (i n)
  10222       (if (or (not (get-text-property i 'block-side input))
  10223               (member (get-text-property i 'block-token input)
  10224                       '(comment delimiter-beg delimiter-end)))
  10225           (when keep
  10226             (setq out (concat out (substring input beg i))
  10227                   beg 0
  10228                   keep nil))
  10229           (when (null keep)
  10230             (setq beg i
  10231                   keep t))
  10232           ) ;if
  10233       ) ;dotimes
  10234     (if (> beg 0) (setq out (concat out (substring input beg n))))
  10235     (setq out (if (= (length out) 0) input out))
  10236     (web-mode-trim out)
  10237     ;;    (message "%S [%s] > [%s]" beg input out)
  10238     ))
  10239 
  10240 (defun web-mode-language-at-pos (&optional pos)
  10241   (unless pos (setq pos (point)))
  10242   (cond
  10243     ((get-text-property pos 'block-side)
  10244      web-mode-engine)
  10245     ((get-text-property pos 'part-side)
  10246      (symbol-name (get-text-property pos 'part-side)))
  10247     (t
  10248      web-mode-content-type)
  10249     ) ;cond
  10250   )
  10251 
  10252 (defun web-mode-coord-position (line column)
  10253   (save-excursion
  10254     (when (stringp line) (setq line (string-to-number line)))
  10255     (when (stringp column) (setq column (string-to-number column)))
  10256     (goto-char (point-min))
  10257     (forward-line (1- line))
  10258     (move-to-column (1- column))
  10259     (point)))
  10260 
  10261 (defun web-mode-is-single-line-block (pos)
  10262   (= (web-mode-line-number (web-mode-block-beginning-position pos))
  10263      (web-mode-line-number (web-mode-block-end-position pos))))
  10264 
  10265 (defun web-mode-line-number (&optional pos)
  10266   (setq pos (or pos (point)))
  10267   (+ (count-lines 1 pos) (if (= (web-mode-column-at-pos pos) 0) 1 0)))
  10268 
  10269 (defun web-mode-block-is-control (pos)
  10270   (save-excursion
  10271     (let (control state controls pair)
  10272       (goto-char pos)
  10273       (setq controls (web-mode-block-controls-get pos))
  10274       (setq pair (car controls))
  10275       (cond
  10276         ((eq (car pair) 'inside)
  10277          )
  10278         ((eq (car pair) 'open)
  10279          (setq state t
  10280                control (cdr pair)))
  10281         ((eq (car pair) 'close)
  10282          (setq state nil
  10283                control (cdr pair)))
  10284         ) ;cond
  10285       ;;      (message "engine=%S control=%S state=%S" web-mode-engine control state)
  10286       (if control (cons control state) nil)
  10287       )))
  10288 
  10289 (defun web-mode-block-is-opening-control (pos)
  10290   (save-excursion
  10291     (let (controls pair)
  10292       (goto-char pos)
  10293       (if (and (setq controls (web-mode-block-controls-get pos))
  10294                (= (length controls) 1)
  10295                (setq pair (car controls))
  10296                (eq (car pair) 'open))
  10297           (cdr pair)
  10298           nil)
  10299       )))
  10300 
  10301 (defun web-mode-markup-indentation-origin (pos jsx-depth)
  10302   (save-excursion
  10303     (let* ((found (bobp))
  10304            (jsx-beg nil)
  10305            (types '(start end void))
  10306            (type nil))
  10307       (when jsx-depth
  10308         (setq jsx-beg (web-mode-jsx-depth-beginning-position pos jsx-depth)))
  10309       (while (not found)
  10310         (forward-line -1)
  10311         (if (bobp)
  10312             (setq pos (point)
  10313                   found t)
  10314             (back-to-indentation)
  10315             (when (and jsx-beg (< (point) jsx-beg))
  10316               (goto-char jsx-beg))
  10317             (setq pos (point))
  10318             (setq type (get-text-property pos 'tag-type))
  10319             (setq found (or (and (null jsx-depth)
  10320                                  (null (get-text-property pos 'part-side))
  10321                                  (get-text-property pos 'tag-beg)
  10322                                  (member type types)
  10323                                  (null (get-text-property (1- pos) 'invisible)))
  10324                             (and (null jsx-depth)
  10325                                  (null (get-text-property pos 'part-side))
  10326                                  (eq (get-text-property pos 'tag-type) 'comment)
  10327                                  (web-mode-looking-at-p "<!--#\\(endif\\|if\\)" pos)
  10328                                  (null (get-text-property (1- pos) 'invisible)))
  10329                             (and jsx-depth
  10330                                  (get-text-property pos 'tag-beg)
  10331                                  (member type types)
  10332                                  (null (get-text-property (1- pos) 'invisible))
  10333                                  (eq (get-text-property pos 'jsx-depth) jsx-depth))
  10334                             (and (get-text-property pos 'block-beg)
  10335                                  (not type)
  10336                                  (web-mode-block-is-control pos)
  10337                                  (not (looking-at-p "{% commen\\|@break")))))
  10338             ) ;if
  10339         ) ;while
  10340       ;;(message "indent-origin=%S" pos)
  10341       pos)))
  10342 
  10343 ;;TODO : prendre en compte part-token
  10344 ;; state=t <=> start tag
  10345 (defun web-mode-element-is-opened (pos limit)
  10346   (let (tag
  10347         last-end-tag
  10348         tag-pos block-pos
  10349         state
  10350         n
  10351         ret
  10352         (continue t)
  10353         controls
  10354         (h (make-hash-table :test 'equal))
  10355         (h2 (make-hash-table :test 'equal)))
  10356 
  10357     ;;    (message "pos-ori=%S limit=%S" pos limit)
  10358 
  10359     (while continue
  10360       (setq controls nil
  10361             last-end-tag nil
  10362             tag nil)
  10363 
  10364       (cond
  10365         ((and (eq (get-text-property pos 'tag-type) 'comment)
  10366               (web-mode-looking-at "<!--#\\(endif\\|if\\)" pos))
  10367          ;;(message "pos=%S" pos)
  10368          (setq tag "#if")
  10369          (setq n (gethash tag h 0))
  10370          (if (string= (match-string-no-properties 1) "if")
  10371              (puthash tag (1+ n) h)
  10372              (puthash tag (1- n) h))
  10373          ;;(setq tag-pos pos)
  10374          )
  10375         ((get-text-property pos 'tag-beg)
  10376          (when (member (get-text-property pos 'tag-type) '(start end))
  10377            (setq tag (get-text-property pos 'tag-name)
  10378                  state (eq (get-text-property pos 'tag-type) 'start))
  10379            (if (null state) (setq last-end-tag (cons tag pos)))
  10380            (setq n (gethash tag h 0))
  10381            (cond
  10382              ((null state)
  10383               (when (> n 0) (puthash tag (1- n) h))
  10384               (puthash tag (1- n) h2))
  10385              ((member tag web-mode-offsetless-elements)
  10386               )
  10387              (t
  10388               (puthash tag (1+ n) h)
  10389               (puthash tag (1+ n) h2))
  10390              ) ;cond
  10391            ) ;when
  10392          (when (setq pos (web-mode-tag-end-position pos))
  10393            (setq tag-pos nil)
  10394            (when (and block-pos (> pos block-pos))
  10395              (setq block-pos nil))
  10396            ) ;when
  10397          )
  10398         ((and web-mode-enable-control-block-indentation
  10399               (get-text-property pos 'block-beg))
  10400          (when (setq controls (web-mode-block-controls-get pos))
  10401            (dolist (control controls)
  10402              (setq tag (cdr control))
  10403              (setq n (gethash tag h 0))
  10404              (cond
  10405                ((eq (car control) 'inside)
  10406                 )
  10407                ((eq (car control) 'open)
  10408                 (puthash tag (1+ n) h))
  10409                ((> n 0)
  10410                 (puthash tag (1- n) h))
  10411                ) ;cond
  10412              ) ;dolist
  10413            )
  10414          (when (setq pos (web-mode-block-end-position pos))
  10415            (setq block-pos nil)
  10416            (when (and tag-pos (> pos tag-pos))
  10417              (setq tag-pos nil))
  10418            )
  10419          )
  10420         ) ;cond
  10421 
  10422       ;;      (message "tag=%S end-pos=%S" tag pos)
  10423 
  10424       (when (and pos (< pos limit))
  10425         (when (or (null tag-pos) (>= pos tag-pos))
  10426           (setq tag-pos (web-mode-tag-next-position pos limit))
  10427           ;;          (message "from=%S tag-next-pos=%S" pos tag-pos)
  10428           )
  10429         (when (or (null block-pos) (>= pos block-pos))
  10430           (setq block-pos (web-mode-block-next-position pos limit))
  10431           ;;          (message "from=%S block-next-pos=%S" pos block-pos)
  10432           )
  10433         )
  10434 
  10435       (cond
  10436         ((null pos)
  10437          )
  10438         ((and (null tag-pos)
  10439               (null block-pos))
  10440          (setq pos nil))
  10441         ((and tag-pos block-pos)
  10442          (if (< tag-pos block-pos)
  10443              (progn
  10444                (setq pos tag-pos)
  10445                (setq tag-pos nil))
  10446              (setq pos block-pos)
  10447              (setq block-pos nil))
  10448          )
  10449         ((null tag-pos)
  10450          (setq pos block-pos)
  10451          (setq block-pos nil))
  10452         (t
  10453          (setq pos tag-pos)
  10454          (setq tag-pos nil))
  10455         )
  10456 
  10457       (when (or (null pos)
  10458                 (>= pos limit))
  10459         (setq continue nil))
  10460       ) ;while
  10461 
  10462     ;;(message "hashtable=%S" h)
  10463     (maphash (lambda (_k v) (if (> v 0) (setq ret t))) h)
  10464 
  10465     (when (and (null ret)
  10466                last-end-tag
  10467                (> (hash-table-count h2) 1)
  10468                (< (gethash (car last-end-tag) h2) 0))
  10469       ;;      (message "last-end-tag=%S" last-end-tag)
  10470       (save-excursion
  10471         (goto-char (cdr last-end-tag))
  10472         (web-mode-tag-match)
  10473         (when (not (= (point) (cdr last-end-tag)))
  10474           (setq n (point))
  10475           (back-to-indentation)
  10476           (if (= n (point)) (setq ret (current-indentation))))
  10477         ))
  10478 
  10479     ret))
  10480 
  10481 (defun web-mode-previous-line (pos limit)
  10482   (save-excursion
  10483     (let (beg end line (continue t))
  10484       (goto-char pos)
  10485       (while continue
  10486         (forward-line -1)
  10487         (setq end (line-end-position))
  10488         (setq line (buffer-substring-no-properties (point) end))
  10489         (when (or (not (string-match-p "^[ \t]*$" line))
  10490                   (bobp)
  10491                   (<= (point) limit))
  10492           (setq continue nil))
  10493         )
  10494       (if (<= (point) limit)
  10495           ;;todo : affiner (le + 3 n est pas générique cf. <?php <% <%- etc.)
  10496           (setq beg (if (< (+ limit 3) end) (+ limit 3) end))
  10497           (setq beg (line-beginning-position))
  10498           ) ;if
  10499       (setq line (buffer-substring-no-properties beg end))
  10500       (cons line (current-indentation))
  10501       )))
  10502 
  10503 (defun web-mode-bracket-up (pos _language &optional limit)
  10504   (unless limit (setq limit nil))
  10505   ;;(message "pos(%S) language(%S) limit(%S)" pos language limit)
  10506   (save-excursion
  10507     (goto-char pos)
  10508     (let ((continue t)
  10509           (regexp "[\]\[}{)(]")
  10510           (char nil)
  10511           (column nil)
  10512           (indentation nil)
  10513           (map nil)
  10514           (key nil)
  10515           (value 0)
  10516           (open '(?\( ?\{ ?\[))
  10517           (searcher nil)
  10518           (opener nil))
  10519       (cond
  10520         ((get-text-property pos 'block-side)
  10521          (setq searcher 'web-mode-block-rsb
  10522                opener 'web-mode-block-opening-paren-position))
  10523         (t
  10524          (setq searcher 'web-mode-part-rsb
  10525                opener 'web-mode-part-opening-paren-position))
  10526         )
  10527       (while (and continue (funcall searcher regexp limit))
  10528         (setq char (aref (match-string-no-properties 0) 0))
  10529         (setq key (cond ((eq char ?\)) ?\()
  10530                         ((eq char ?\}) ?\{)
  10531                         ((eq char ?\]) ?\[)
  10532                         (t             char)))
  10533         (setq value (or (plist-get map key) 0))
  10534         (setq value (if (member char open) (1+ value) (1- value)))
  10535         (setq map (plist-put map key value))
  10536         (setq continue (< value 1))
  10537         ;;(message "pos=%S char=%c key=%c value=%S map=%S" (point) char key value map)
  10538         ) ;while
  10539       (setq column (current-column)
  10540             indentation (current-indentation))
  10541       (when (and (> value 0)
  10542                  (eq char ?\{)
  10543                  (looking-back ")[ ]*" (point-min)))
  10544         (search-backward ")")
  10545         (when (setq pos (funcall opener (point) limit))
  10546           (goto-char pos)
  10547           ;;(message "pos=%S" pos)
  10548           (setq indentation (current-indentation)))
  10549         ) ;when
  10550       (list :pos (if (> value 0) (point) nil)
  10551             :char char
  10552             :column column
  10553             :indentation indentation)
  10554       ) ;let
  10555     ))
  10556 
  10557 (defun web-mode-count-char-in-string (char string)
  10558   (let ((n 0))
  10559     (dotimes (i (length string))
  10560       (if (eq (elt string i) char)
  10561           (setq n (1+ n))))
  10562     n))
  10563 
  10564 (defun web-mode-mark-and-expand ()
  10565   "Mark and expand."
  10566   (interactive)
  10567   (web-mode-mark (point)))
  10568 
  10569 (defun web-mode-mark (pos)
  10570   (let ((beg pos) (end pos) boundaries)
  10571 
  10572     (if mark-active
  10573         (setq web-mode-expand-initial-pos (point)
  10574               web-mode-expand-initial-scroll (window-start))
  10575         )
  10576 
  10577     ;; (message "regs=%S %S %S %S" (region-beginning) (region-end) (point-min) (point-max))
  10578     ;; (message "before=%S" web-mode-expand-previous-state)
  10579 
  10580     (cond
  10581 
  10582       ((and mark-active
  10583             (= (region-beginning) (point-min))
  10584             (or (= (region-end) (point-max))
  10585                 (= (1+ (region-end)) (point-max))))
  10586        (deactivate-mark)
  10587        (goto-char (or web-mode-expand-initial-pos (point-min)))
  10588        (setq web-mode-expand-previous-state nil)
  10589        (when web-mode-expand-initial-scroll
  10590          (set-window-start (selected-window) web-mode-expand-initial-scroll))
  10591        )
  10592 
  10593       ((string= web-mode-expand-previous-state "elt-content")
  10594        (web-mode-element-parent)
  10595        ;;(message "pos=%S" (point))
  10596        (web-mode-element-select)
  10597        (setq web-mode-expand-previous-state "html-parent"))
  10598 
  10599       ((and (member (get-text-property pos 'block-token) '(comment string))
  10600             (not (member web-mode-expand-previous-state '("block-token" "block-body" "block-side"))))
  10601        (when (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token))
  10602          (setq beg (or (previous-single-property-change pos 'block-token) (point-min))))
  10603        (when (eq (get-text-property pos 'block-token) (get-text-property (1+ pos) 'block-token))
  10604          (setq end (next-single-property-change pos 'block-token)))
  10605        (set-mark beg)
  10606        (goto-char end)
  10607        (exchange-point-and-mark)
  10608        (setq web-mode-expand-previous-state "block-token"))
  10609 
  10610       ((and (get-text-property pos 'block-side)
  10611             (not (member web-mode-expand-previous-state '("block-body" "block-side")))
  10612             (not (member web-mode-engine '(django go)))
  10613             (setq boundaries (web-mode-in-code-block "{" "}" 'block-side)))
  10614        (set-mark (car boundaries))
  10615        (goto-char (cdr boundaries))
  10616        (exchange-point-and-mark)
  10617        (setq web-mode-expand-previous-state "block-body"))
  10618 
  10619       ((and (get-text-property pos 'block-side)
  10620             (not (member web-mode-expand-previous-state '("block-side"))))
  10621        (set-mark (web-mode-block-beginning-position pos))
  10622        (goto-char (1+ (web-mode-block-end-position pos)))
  10623        (exchange-point-and-mark)
  10624        (setq web-mode-expand-previous-state "block-side"))
  10625 
  10626       ((and (get-text-property pos 'part-token)
  10627             (not (string= web-mode-expand-previous-state "part-token")))
  10628        (when (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token))
  10629          (setq beg (previous-single-property-change pos 'part-token)))
  10630        (when (eq (get-text-property pos 'part-token) (get-text-property (1+ pos) 'part-token))
  10631          (setq end (next-single-property-change pos 'part-token)))
  10632        (set-mark beg)
  10633        (goto-char end)
  10634        (exchange-point-and-mark)
  10635        (setq web-mode-expand-previous-state "part-token"))
  10636 
  10637       ((and (get-text-property pos 'part-side)
  10638             (not (string= web-mode-expand-previous-state "client-part"))
  10639             (setq boundaries (web-mode-in-code-block "{" "}" 'part-side)))
  10640        (set-mark (car boundaries))
  10641        (goto-char (cdr boundaries))
  10642        (exchange-point-and-mark)
  10643        (setq web-mode-expand-previous-state "client-part"))
  10644 
  10645       ((and (get-text-property pos 'part-side)
  10646             (not (string= web-mode-expand-previous-state "part-side")))
  10647        (when (eq (get-text-property pos 'part-side) (get-text-property (1- pos) 'part-side))
  10648          (setq beg (previous-single-property-change pos 'part-side)))
  10649        (when (eq (get-text-property pos 'part-side) (get-text-property (1+ pos) 'part-side))
  10650          (setq end (next-single-property-change pos 'part-side)))
  10651        (when (eq (char-after beg) ?\n)
  10652          (setq beg (1+ beg)))
  10653        (set-mark beg)
  10654        (goto-char end)
  10655        (when (looking-back "^[ \t]+" (point-min))
  10656          (beginning-of-line))
  10657        (exchange-point-and-mark)
  10658        (setq web-mode-expand-previous-state "part-side"))
  10659 
  10660       ((and (get-text-property pos 'tag-attr)
  10661             (not (member web-mode-expand-previous-state '("html-attr" "html-tag"))))
  10662        (web-mode-attribute-select pos)
  10663        (setq web-mode-expand-previous-state "html-attr"))
  10664 
  10665       ((and (eq (get-text-property pos 'tag-type) 'comment)
  10666             (not (member web-mode-expand-previous-state '("html-tag" "html-comment" "html-elt" "html-parent"))))
  10667        (web-mode-tag-select)
  10668        (setq web-mode-expand-previous-state "html-comment"))
  10669 
  10670       ((and (get-text-property pos 'tag-name)
  10671             (not (member web-mode-expand-previous-state '("html-tag" "html-elt" "html-parent"))))
  10672        (web-mode-tag-select)
  10673        (setq web-mode-expand-previous-state "html-tag"))
  10674 
  10675       ((and (get-text-property pos 'tag-beg)
  10676             (string= web-mode-expand-previous-state "html-tag"))
  10677        (web-mode-element-select)
  10678        (setq web-mode-expand-previous-state "html-elt"))
  10679 
  10680       (t
  10681        (cond
  10682          ((not (web-mode-element-parent))
  10683           (push-mark (point))
  10684           (push-mark (point-max) nil t)
  10685           (goto-char (point-min))
  10686           (setq web-mode-expand-previous-state "mark-whole"))
  10687          ((not (= (web-mode-tag-end-position (point)) (1- beg)))
  10688           (web-mode-element-content-select)
  10689           (setq web-mode-expand-previous-state "elt-content"))
  10690          (t
  10691           (web-mode-element-select)
  10692           (setq web-mode-expand-previous-state "html-parent"))
  10693          )
  10694        ) ;t
  10695 
  10696       ) ;cond
  10697 
  10698     ;;(message "w=%S" (window-end))
  10699     ;;(message "after=%S" web-mode-expand-previous-state)
  10700 
  10701     ))
  10702 
  10703 (defun web-mode-block-kill ()
  10704   "Kill the current block."
  10705   (interactive)
  10706   (web-mode-block-select)
  10707   (when mark-active
  10708     (kill-region (region-beginning) (region-end))))
  10709 
  10710 (defun web-mode-block-select ()
  10711   "Select the current block."
  10712   (interactive)
  10713   (let (beg)
  10714     (when (setq beg (web-mode-block-beginning-position (point)))
  10715       (goto-char beg)
  10716       (set-mark (point))
  10717       (web-mode-block-end)
  10718       (exchange-point-and-mark))
  10719     beg))
  10720 
  10721 (defun web-mode-tag-select ()
  10722   "Select the current html tag."
  10723   (interactive)
  10724   (let (beg)
  10725     (when (setq beg (web-mode-tag-beginning-position (point)))
  10726       (goto-char beg)
  10727       (set-mark (point))
  10728       (web-mode-tag-end)
  10729       (exchange-point-and-mark))
  10730     beg))
  10731 
  10732 (defun web-mode-element-content-select ()
  10733   "Select the content of a html element."
  10734   (interactive)
  10735   (let (pos end)
  10736     (web-mode-element-select)
  10737     (when mark-active
  10738       (setq pos (point))
  10739       (deactivate-mark)
  10740       (web-mode-tag-match)
  10741       (setq end (point))
  10742       (goto-char pos)
  10743       (web-mode-tag-end)
  10744       (set-mark (point))
  10745       (goto-char end)
  10746       (exchange-point-and-mark)
  10747       )))
  10748 
  10749 (defun web-mode-element-select ()
  10750   "Select the current html element (including opening and closing tags)."
  10751   (interactive)
  10752   (let* ((pos (point))
  10753          (type (get-text-property pos 'tag-type)))
  10754     (cond
  10755       ((not type)
  10756        (web-mode-element-parent)
  10757        (unless (= (point) pos) (web-mode-element-select)))
  10758       ((member type '(start void))
  10759        (web-mode-tag-beginning)
  10760        (set-mark (point))
  10761        (web-mode-tag-match)
  10762        (web-mode-tag-end)
  10763        (exchange-point-and-mark))
  10764       (t
  10765        (web-mode-tag-match)
  10766        (set-mark (point))
  10767        (web-mode-tag-match)
  10768        (web-mode-tag-end)
  10769        (exchange-point-and-mark))
  10770       )))
  10771 
  10772 (defun web-mode-element-is-collapsed (&optional pos)
  10773   (unless pos (setq pos (point)))
  10774   (let (boundaries)
  10775     (and (setq boundaries (web-mode-element-boundaries pos))
  10776          (or (= (car (car boundaries)) (car (cdr boundaries)))
  10777              (= (cdr (car boundaries)) (1- (car (cdr boundaries)))))
  10778          )))
  10779 
  10780 (defun web-mode-element-contract ()
  10781   "Flatten elements."
  10782   (interactive)
  10783   (let (beg end (continue t) replacement boundaries)
  10784     (cond
  10785       ((or (not (get-text-property (point) 'tag-type))
  10786            (not (member (get-text-property (point) 'tag-type) '(start end))))
  10787        (web-mode-element-parent))
  10788       ((eq (get-text-property (point) 'tag-type) 'end)
  10789        (web-mode-tag-match))
  10790       ) ;cond
  10791     (setq boundaries (web-mode-element-boundaries (point)))
  10792     (setq beg (car (car boundaries))
  10793           end (cdr (cdr boundaries)))
  10794     (goto-char beg)
  10795     ;;(message "beg(%S) end(%S)" beg end)
  10796     (while continue
  10797       (if (or (not (re-search-forward ">[ \t\r\n]+\\|[ \t\r\n]+<"))
  10798               (>= (point) end))
  10799           (setq continue nil)
  10800           (setq end (+ (- end (length (match-string-no-properties 0))) 1))
  10801           (setq replacement (if (eq (char-before) ?\<) "<" ">"))
  10802           (replace-match replacement nil nil)
  10803           ;;(message "end(%S)" end))
  10804           )
  10805       ) ;while
  10806     (goto-char beg)
  10807     ))
  10808 
  10809 (defun web-mode-element-extract ()
  10810   "Flatten element."
  10811   (interactive)
  10812   (let (beg end (continue t) save boundaries)
  10813     (cond
  10814       ((or (not (get-text-property (point) 'tag-type))
  10815            (not (member (get-text-property (point) 'tag-type) '(start end))))
  10816        (web-mode-element-parent))
  10817       ((eq (get-text-property (point) 'tag-type) 'end)
  10818        (web-mode-tag-match))
  10819       ) ;cond
  10820     (setq boundaries (web-mode-element-boundaries (point)))
  10821     (setq beg (car (car boundaries))
  10822           end (cdr (cdr boundaries)))
  10823     (goto-char beg)
  10824     (while continue
  10825       (if (or (not (and (or (get-text-property (point) 'tag-type) (web-mode-tag-next))
  10826                         (web-mode-tag-end)))
  10827               (>= (point) end))
  10828           (setq continue nil)
  10829           (setq save (point))
  10830           ;;(message "point(%S)" (point))
  10831           (skip-chars-forward "\n\t ")
  10832           (when (get-text-property (point) 'tag-type)
  10833             (newline)
  10834             (indent-according-to-mode)
  10835             (setq end (+ end (- (point) save))))
  10836           ) ;if
  10837       ) ;while
  10838     (goto-char beg)
  10839     ))
  10840 
  10841 (defun web-mode-element-transpose ()
  10842   "Transpose two html elements."
  10843   (interactive)
  10844   (let (pos start1 end1 start2 end2)
  10845     (save-excursion
  10846       (setq pos (point))
  10847       (cond
  10848         ((get-text-property pos 'tag-type)
  10849          (setq start1 (web-mode-element-beginning-position pos)
  10850                end1 (1+ (web-mode-element-end-position pos)))
  10851          )
  10852         ((setq start1 (web-mode-element-parent-position pos))
  10853          (setq end1 (1+ (web-mode-element-end-position pos)))
  10854          )
  10855         ) ;cond
  10856       (when (and start1 end1 (> end1 0))
  10857         (goto-char end1)
  10858         (unless (get-text-property (point) 'tag-beg)
  10859           (skip-chars-forward "\n\t "))
  10860         (when (get-text-property (point) 'tag-beg)
  10861           (setq start2 (web-mode-element-beginning-position (point))
  10862                 end2 (1+ (web-mode-element-end-position (point))))
  10863           )
  10864         )
  10865       (transpose-regions start1 end1 start2 end2)
  10866       ) ;save-excursion
  10867     start2))
  10868 
  10869 (defun web-mode-element-children-comment (&optional pos)
  10870   "Comment all the children of the current html element."
  10871   (interactive)
  10872   (unless pos (setq pos (point)))
  10873   (save-excursion
  10874     (dolist (child (reverse (web-mode-element-children pos)))
  10875       (goto-char child)
  10876       (web-mode-comment (point)))
  10877     ))
  10878 
  10879 (defun web-mode-element-mute-blanks ()
  10880   "Mute blanks."
  10881   (interactive)
  10882   (let (pos parent children elt)
  10883     (setq pos (point))
  10884     (save-excursion
  10885       (when (and (setq parent (web-mode-element-boundaries pos))
  10886                  (web-mode-element-child-position (point)))
  10887         (setq children (reverse (web-mode-element-children)))
  10888         (goto-char (car (cdr parent)))
  10889         (dolist (child children)
  10890           (setq elt (web-mode-element-boundaries child))
  10891           (when (> (point) (1+ (cddr elt)))
  10892             (when (and (not (eq (get-text-property (point) 'part-token) 'comment))
  10893                        (not (eq (get-text-property (1+ (cddr elt)) 'part-token) 'comment)))
  10894               (web-mode-insert-text-at-pos "-->" (point))
  10895               (web-mode-insert-text-at-pos "<!--" (1+ (cddr elt))))
  10896             )
  10897           (goto-char child)
  10898           )
  10899         (when (and (> (point) (1+ (cdr (car parent))))
  10900                    (not (eq (get-text-property (point) 'part-token) 'comment))
  10901                    (not (eq (get-text-property (1+ (cdr (car parent))) 'part-token) 'comment)))
  10902           (web-mode-insert-text-at-pos "-->" (point))
  10903           (web-mode-insert-text-at-pos "<!--" (1+ (cdr (car parent)))))
  10904         ) ;when
  10905       )))
  10906 
  10907 (defun web-mode-element-children (&optional pos)
  10908   (unless pos (setq pos (point)))
  10909   (let ((continue t) (i 0) child children)
  10910     (save-excursion
  10911       (when (and (member (get-text-property pos 'tag-type) '(start end))
  10912                  (setq child (web-mode-element-child-position pos)))
  10913         (while continue
  10914           (cond
  10915             ((> (setq i (1+ i)) 100)
  10916              (setq continue nil)
  10917              (message "element-children ** warning **"))
  10918             ((= i 1)
  10919              (goto-char child))
  10920             ((web-mode-element-sibling-next)
  10921              )
  10922             (t
  10923              (setq continue nil))
  10924             ) ;cond
  10925           (when continue
  10926             (setq children (append children (list (point)))))
  10927           ) ;while
  10928         ) ;when
  10929       ) ;save-excursion
  10930     ;;(message "%S" children)
  10931     children))
  10932 
  10933 (defun web-mode-property-boundaries (prop &optional pos)
  10934   "property boundaries (cdr is 1+)"
  10935   (unless pos (setq pos (point)))
  10936   (let (beg end val)
  10937     (setq val (get-text-property pos prop))
  10938     (if (null val)
  10939         val
  10940         (if (or (bobp)
  10941                 (not (eq (get-text-property (1- pos) prop) val)))
  10942             (setq beg pos)
  10943             (setq beg (previous-single-property-change pos prop))
  10944             (when (null beg) (setq beg (point-min))))
  10945         (if (or (eobp)
  10946                 (not (eq (get-text-property (1+ pos) prop) val)))
  10947             (setq end pos)
  10948             (setq end (next-single-property-change pos prop))
  10949             (when (null end) (setq end (point-min))))
  10950         (cons beg end))))
  10951 
  10952 (defun web-mode-content-boundaries (&optional pos)
  10953   (unless pos (setq pos (point)))
  10954   (let (beg end)
  10955     (setq beg (or (previous-property-change pos (current-buffer))
  10956                   (point-max)))
  10957     (setq end (or (next-property-change pos (current-buffer))
  10958                   (point-min)))
  10959     (while (and (< beg end) (member (char-after beg) '(?\s ?\n)))
  10960       (setq beg (1+ beg)))
  10961     (while (and (> end beg) (member (char-after (1- end)) '(?\s ?\n)))
  10962       (setq end (1- end)))
  10963     ;;    (message "beg(%S) end(%S)" beg end)
  10964     (cons beg end)
  10965     ))
  10966 
  10967 (defun web-mode-element-boundaries (&optional pos)
  10968   "Return ((start-tag-beg . start-tag-end) . (end-tag-beg . end-tag-end))
  10969 First level car and cdr are the same with void elements.
  10970 Pos should be in a tag."
  10971   (unless pos (setq pos (point)))
  10972   (let (start-tag-beg start-tag-end end-tag-beg end-tag-end)
  10973     (cond
  10974       ((eq (get-text-property pos 'tag-type) 'start)
  10975        (setq start-tag-beg (web-mode-tag-beginning-position pos)
  10976              start-tag-end (web-mode-tag-end-position pos))
  10977        (when (setq pos (web-mode-tag-match-position pos))
  10978          (setq end-tag-beg pos
  10979                end-tag-end (web-mode-tag-end-position pos)))
  10980        )
  10981       ((eq (get-text-property pos 'tag-type) 'end)
  10982        (setq end-tag-beg (web-mode-tag-beginning-position pos)
  10983              end-tag-end (web-mode-tag-end-position pos))
  10984        (when (setq pos (web-mode-tag-match-position pos))
  10985          (setq start-tag-beg pos
  10986                start-tag-end (web-mode-tag-end-position pos)))
  10987        )
  10988       ((eq (get-text-property pos 'tag-type) 'void)
  10989        (setq start-tag-beg (web-mode-tag-beginning-position pos)
  10990              start-tag-end (web-mode-tag-end-position pos))
  10991        (setq end-tag-beg start-tag-beg
  10992              end-tag-end start-tag-end)
  10993        )
  10994       ) ;cond
  10995     (if (and start-tag-beg start-tag-end end-tag-beg end-tag-end)
  10996         (cons (cons start-tag-beg start-tag-end) (cons end-tag-beg end-tag-end))
  10997         nil)
  10998     ))
  10999 
  11000 (defun web-mode-surround ()
  11001   "Surround each line of the current REGION with a start/end tag."
  11002   (interactive)
  11003   (when mark-active
  11004     (let (beg end line-beg line-end tag tag-start tag-end)
  11005       (save-excursion
  11006         (combine-after-change-calls
  11007           (setq tag (web-mode-element-complete)
  11008                 tag-start (concat "<" tag ">")
  11009                 tag-end (concat "</" tag ">")
  11010                 beg (region-beginning)
  11011                 end (region-end)
  11012                 line-beg (web-mode-line-number beg)
  11013                 line-end (web-mode-line-number end))
  11014           (goto-char end)
  11015           (unless (bolp)
  11016             (insert tag-end)
  11017             (back-to-indentation)
  11018             (when (> beg (point))
  11019               (goto-char beg))
  11020             (insert tag-start))
  11021           (while (> line-end line-beg)
  11022             (forward-line -1)
  11023             (setq line-end (1- line-end))
  11024             (unless (looking-at-p "[[:space:]]*$")
  11025               (end-of-line)
  11026               (insert tag-end)
  11027               (back-to-indentation)
  11028               (when (> beg (point))
  11029                 (goto-char beg))
  11030               (insert tag-start))
  11031             ) ;while
  11032           (deactivate-mark)
  11033           ) ;combine-after-change-calls
  11034         ) ;save-excursion
  11035       )))
  11036 
  11037 (defun web-mode-lify-region ()
  11038   "Transform current REGION in an html list (<li>line1</li>...)"
  11039   (interactive)
  11040   (let (beg end lines)
  11041     (save-excursion
  11042       (combine-after-change-calls
  11043         (when  mark-active
  11044           (setq beg (region-beginning)
  11045                 end (region-end))
  11046           (setq lines (buffer-substring beg end))
  11047           (kill-region beg end)
  11048           (setq lines (replace-regexp-in-string "^[ \t]*" "<li>" lines))
  11049           (setq lines (replace-regexp-in-string "$" "</li>" lines))
  11050           (web-mode-insert-and-indent lines)
  11051           ) ;when
  11052         ) ;combine-after-change-calls
  11053       ) ;save-excursion
  11054     ) ;let
  11055   )
  11056 
  11057 (defun web-mode-element-complete (&optional prompt)
  11058   "Completes for an element tag."
  11059   (completing-read
  11060    (or prompt "Tag name: ")
  11061    (append
  11062     web-mode-tag-list
  11063     web-mode-tag-history)
  11064    nil nil nil 'web-mode-tag-history))
  11065 
  11066 (defun web-mode-element-wrap (&optional tag-name)
  11067   "Wrap current REGION with start and end tags.
  11068 Prompt user if TAG-NAME isn't provided."
  11069   (interactive)
  11070   (let (beg end pos tag sep)
  11071     (save-excursion
  11072       (setq tag (or tag-name (web-mode-element-complete)))
  11073       (setq pos (point))
  11074       (cond
  11075         (mark-active
  11076          (setq beg (region-beginning)
  11077                end (region-end)))
  11078         ((get-text-property pos 'tag-type)
  11079          (setq beg (web-mode-element-beginning-position pos)
  11080                end (1+ (web-mode-element-end-position pos))))
  11081         ((setq beg (web-mode-element-parent-position pos))
  11082          (setq end (1+ (web-mode-element-end-position pos))))
  11083         )
  11084       ;;      (message "beg(%S) end(%S)" beg end)
  11085       (when (and beg end (> end 0))
  11086         (setq sep (if (get-text-property beg 'tag-beg) "\n" ""))
  11087         (web-mode-insert-text-at-pos (concat sep "</" tag ">") end)
  11088         (web-mode-insert-text-at-pos (concat "<" tag ">" sep) beg)
  11089         (when (string= sep "\n") (indent-region beg (+ end (* (+ 3 (length tag)) 2))))
  11090         )
  11091       ) ;save-excursion
  11092     (web-mode-go beg)))
  11093 
  11094 (defun web-mode-element-vanish (&optional arg)
  11095   "Vanish the current html element. The content of the element is kept."
  11096   (interactive "p")
  11097   (let (type (pos (point)) start-b start-e end-b end-e)
  11098     (while (>= arg 1)
  11099       (setq type (get-text-property pos 'tag-type))
  11100       (when type
  11101         (cond
  11102           ((member type '(void))
  11103            (web-mode-element-kill)
  11104            (set-mark (point))
  11105            (web-mode-tag-match)
  11106            (web-mode-tag-end)
  11107            (exchange-point-and-mark))
  11108           ((member type '(start))
  11109            (setq start-b (web-mode-tag-beginning-position)
  11110                  start-e (web-mode-tag-end-position))
  11111            (when (web-mode-tag-match)
  11112              (setq end-b (web-mode-tag-beginning-position)
  11113                    end-e (web-mode-tag-end-position)))
  11114            )
  11115           (t
  11116            (setq end-b (web-mode-tag-beginning-position)
  11117                  end-e (web-mode-tag-end-position))
  11118            (when (web-mode-tag-match)
  11119              (setq start-b (web-mode-tag-beginning-position)
  11120                    start-e (web-mode-tag-end-position)))
  11121            ) ;t
  11122           ) ;cond
  11123         (when (and start-b end-b)
  11124           (goto-char end-b)
  11125           (delete-region end-b (1+ end-e))
  11126           (delete-blank-lines)
  11127           (goto-char start-b)
  11128           (delete-region start-b (1+ start-e))
  11129           (delete-blank-lines)
  11130           (web-mode-buffer-indent)
  11131           )
  11132         ;;        (message "start %S %S - end %S %S" start-b start-e end-b end-e))
  11133         ) ;when
  11134       (skip-chars-forward "[:space:]\n")
  11135       (setq arg (1- arg))
  11136       ) ;while
  11137     ) ;let
  11138   )
  11139 
  11140 (defun web-mode-element-kill (&optional arg)
  11141   "Kill the current html element."
  11142   (interactive "p")
  11143   (while (>= arg 1)
  11144     (setq arg (1- arg))
  11145     (web-mode-element-select)
  11146     (when mark-active
  11147       (kill-region (region-beginning) (region-end)))
  11148     ) ;while
  11149   )
  11150 
  11151 (defun web-mode-element-clone (&optional arg)
  11152   "Clone the current html element."
  11153   (interactive "p")
  11154   (let (col pos)
  11155     (while (>= arg 1)
  11156       (setq arg (1- arg)
  11157             col 0)
  11158       (web-mode-element-select)
  11159       (when mark-active
  11160         (save-excursion
  11161           (goto-char (region-beginning))
  11162           (setq col (current-column)))
  11163         (kill-region (region-beginning) (region-end))
  11164         (yank)
  11165         (newline)
  11166         (indent-line-to col)
  11167         (setq pos (point))
  11168         (yank)
  11169         (goto-char pos))
  11170       )
  11171     ) ;let
  11172   )
  11173 
  11174 (defun web-mode-element-insert ()
  11175   "Insert an html element."
  11176   (interactive)
  11177   (let (tag-name)
  11178     (cond
  11179       ((and (get-text-property (point) 'tag-type)
  11180             (not (get-text-property (point) 'tag-beg)))
  11181        (message "element-insert ** invalid context **"))
  11182       ((not (and (setq tag-name (web-mode-element-complete))
  11183                  (> (length tag-name) 0)))
  11184        (message "element-insert ** failure **"))
  11185       ((web-mode-element-is-void tag-name)
  11186        (insert (concat "<" (replace-regexp-in-string "/" "" tag-name) "/>"))
  11187        )
  11188       (mark-active
  11189        (let ((beg (region-beginning)) (end (region-end)))
  11190          (deactivate-mark)
  11191          (goto-char end)
  11192          (insert "</" tag-name ">")
  11193          (goto-char beg)
  11194          (insert "<" tag-name ">")
  11195          )
  11196        )
  11197       (t
  11198        (insert (concat "<" tag-name ">" "</" tag-name ">"))
  11199        (web-mode-sb "</")
  11200        )
  11201       ) ;cond
  11202     ))
  11203 
  11204 (defun web-mode-element-insert-at-point ()
  11205   "Replace the word at point with a html tag of it."
  11206   (interactive)
  11207   (let ((tag-name (thing-at-point 'word)))
  11208     (cond
  11209       ((web-mode-element-is-void tag-name)
  11210        (backward-kill-word 1)
  11211        (insert (concat "<" (replace-regexp-in-string "/" "" tag-name) "/>"))
  11212        )
  11213       (mark-active
  11214        (setq tag-name (buffer-substring (region-beginning) (region-end)))
  11215        (delete-region (region-beginning) (region-end))
  11216        (insert (concat "<" tag-name ">" "</" tag-name ">"))
  11217        (web-mode-sb "</")
  11218        )
  11219       (tag-name ; do nothing is there isn's word at point
  11220        (backward-kill-word 1)
  11221        (insert (concat "<" tag-name ">" "</" tag-name ">"))
  11222        (web-mode-sb "</")
  11223        )
  11224       ) ;cond
  11225     ))
  11226 
  11227 (defun web-mode-element-rename (&optional tag-name)
  11228   "Rename the current html element."
  11229   (interactive)
  11230   (save-excursion
  11231     (let (pos)
  11232       (unless tag-name (setq tag-name (web-mode-element-complete "New tag name: ")))
  11233       (when (and (> (length tag-name) 0)
  11234                  (web-mode-element-beginning)
  11235                  (looking-at "<\\([[:alnum:]]+\\(:?[[:alpha:]_-]+\\)?\\)"))
  11236         (setq pos (point))
  11237         (unless (web-mode-element-is-void)
  11238           (save-match-data
  11239             (web-mode-tag-match)
  11240             (if (looking-at "</[ ]*\\([[:alnum:]]+\\(:?[[:alpha:]_-]+\\)?\\)")
  11241                 (replace-match (concat "</" tag-name))
  11242                 )))
  11243         (goto-char pos)
  11244         (replace-match (concat "<" tag-name))
  11245         ))))
  11246 
  11247 (defun web-mode-current-trimmed-line ()
  11248   (web-mode-trim (buffer-substring-no-properties
  11249                   (line-beginning-position)
  11250                   (line-end-position))))
  11251 
  11252 (defun web-mode-trim (string)
  11253   (replace-regexp-in-string "\\`[ \t\n]*" "" (replace-regexp-in-string "[ \t\n]*\\'" "" string)))
  11254 
  11255 (defun web-mode-is-token-end (pos)
  11256   (let (block-token part-token)
  11257     (setq block-token (get-text-property pos 'block-token))
  11258     (setq part-token (get-text-property pos 'part-token))
  11259     (cond
  11260       ((not (or block-token part-token))
  11261        nil)
  11262       ((>= (1+ pos) (point-max))
  11263        t)
  11264       ((and block-token
  11265             (not (string= (get-text-property (1+ pos) 'block-token) block-token)))
  11266        t)
  11267       ((and part-token
  11268             (not (string= (get-text-property (1+ pos) 'part-token) part-token)))
  11269        t)
  11270       (t
  11271        nil)
  11272       ) ;cond
  11273     ))
  11274 
  11275 (defun web-mode-block-is-token-line ()
  11276   (save-excursion
  11277     (let ((continue t) (counter 0))
  11278       (beginning-of-line)
  11279       (back-to-indentation)
  11280       (while (and continue (not (eolp)))
  11281         (cond
  11282           ((get-text-property (point) 'block-token)
  11283            (setq counter (1+ counter)))
  11284           ((not (member (following-char) '(?\s ?\t)))
  11285            (setq continue nil
  11286                  counter 0))
  11287           ) ;cond
  11288         (forward-char)
  11289         ) ;while
  11290       (> counter 0)
  11291       )))
  11292 
  11293 (defun web-mode-part-is-token-line (pos)
  11294   (save-excursion
  11295     (let ((continue t)
  11296           (counter 0))
  11297       (goto-char pos)
  11298       (setq continue (not (eolp)))
  11299       (while continue
  11300         (forward-char)
  11301         (cond
  11302           ((eolp)
  11303            (setq continue nil))
  11304           ((or (get-text-property (point) 'block-side)
  11305                (member (get-text-property (point) 'part-token) '(comment string)))
  11306            (setq counter (1+ counter)))
  11307           ((not (member (following-char) '(?\s ?\t)))
  11308            (setq continue nil
  11309                  counter 0))
  11310           )
  11311         ) ;while
  11312       (> counter 0))))
  11313 
  11314 (defun web-mode-is-content (&optional pos)
  11315   (unless pos (setq pos (point)))
  11316   (not (or (get-text-property pos 'part-side)
  11317            (get-text-property pos 'tag-type)
  11318            (get-text-property pos 'block-side)
  11319            )))
  11320 
  11321 (defun web-mode-is-comment-or-string (&optional pos)
  11322   (unless pos (setq pos (point)))
  11323   (not (null (or (eq (get-text-property pos 'tag-type) 'comment)
  11324                  (member (get-text-property pos 'block-token) '(comment string))
  11325                  (member (get-text-property pos 'part-token) '(comment string))))))
  11326 
  11327 ;; NOTE: we look at the firt one
  11328 (defun web-mode-block-is-open (&optional pos)
  11329   (unless pos (setq pos (point))))
  11330 
  11331 ;; NOTE: we look at the last one
  11332 (defun web-mode-block-is-close (&optional pos)
  11333   (unless pos (setq pos (point)))
  11334   (and (get-text-property pos 'block-side)
  11335        (eq (caar (web-mode-block-controls-get pos)) 'close)))
  11336 
  11337 ;; NOTE: we look at the first one
  11338 (defun web-mode-block-is-inside (&optional pos)
  11339   (unless pos (setq pos (point)))
  11340   (and (get-text-property pos 'block-side)
  11341        (eq (caar (web-mode-block-controls-get pos)) 'inside)))
  11342 
  11343 (defun web-mode-element-is-void (&optional tag)
  11344   (cond
  11345     ((and (not tag) (eq (get-text-property (point) 'tag-type) 'void))
  11346      t)
  11347     ((and tag (member tag '("div" "li" "a" "p" "h1" "h2" "h3" "ul" "span" "article" "section" "td" "tr")))
  11348      nil)
  11349     ((and tag (string-suffix-p "/" tag))
  11350      t)
  11351     ((and tag (string= web-mode-content-type "jsx"))
  11352      (member (downcase tag) '("img" "br" "hr")))
  11353     (tag
  11354      (car (member (downcase tag) web-mode-void-elements)))
  11355     (t
  11356      nil)
  11357     ))
  11358 
  11359 ;;---- COMMENT ------------------------------------------------------------------
  11360 
  11361 (defun web-mode-toggle-comments ()
  11362   "Toggle comments visbility."
  11363   (interactive)
  11364   (web-mode-with-silent-modifications
  11365    (save-excursion
  11366      (if web-mode-comments-invisible
  11367          (remove-overlays))
  11368      (setq web-mode-comments-invisible (null web-mode-comments-invisible))
  11369      (let ((continue t)
  11370            (pos (point-min))
  11371            (visibility web-mode-comments-invisible)
  11372            end)
  11373        (while continue
  11374          (setq pos (next-single-property-change pos 'font-lock-face))
  11375          (if (null pos)
  11376              (setq continue nil)
  11377              (when (eq (get-text-property pos 'font-lock-face) 'web-mode-comment-face)
  11378                (setq end (next-single-property-change pos 'font-lock-face))
  11379                (put-text-property pos end 'invisible visibility)
  11380                (when visibility
  11381                  (make-overlay pos end))
  11382                (goto-char pos)
  11383                )
  11384              )
  11385          )
  11386        ) ;let
  11387      )))
  11388 
  11389 (defun web-mode-comment-or-uncomment-region (beg end &optional _arg)
  11390   (interactive)
  11391   (save-excursion
  11392     (push-mark end)
  11393     (goto-char beg)
  11394     (setq mark-active t)
  11395     (web-mode-comment-or-uncomment)
  11396     (pop-mark)))
  11397 
  11398 (defun web-mode-comment-or-uncomment ()
  11399   "Comment or uncomment line(s), block or region at POS."
  11400   (interactive)
  11401   ;; TODO : if mark is at eol, mark--
  11402   (if (and (not mark-active) (looking-at-p "[[:space:]]*$"))
  11403       (web-mode-comment-insert)
  11404       (when (and (use-region-p) (eq (point) (region-end)))
  11405         (if (bolp) (backward-char))
  11406         (exchange-point-and-mark))
  11407       (if (eq (get-text-property (point) 'block-token) 'delimiter-beg)
  11408           (web-mode-block-skip-blank-forward (point) '(delimiter-beg))
  11409           (skip-chars-forward "[:space:]" (line-end-position)))
  11410       (cond
  11411         ;; #1147
  11412         ((and (get-text-property (point) 'jsx-beg)
  11413               (eq (get-text-property (1+ (point)) 'part-token) 'comment))
  11414          (web-mode-uncomment (1+ (point))))
  11415         ((or (eq (get-text-property (point) 'tag-type) 'comment)
  11416              (eq (get-text-property (point) 'block-token) 'comment)
  11417              (eq (get-text-property (point) 'part-token) 'comment))
  11418          (web-mode-uncomment (point)))
  11419         (t
  11420          (web-mode-comment (point)))
  11421         )
  11422       ) ;if
  11423   )
  11424 
  11425 (defun web-mode-comment-indent-new-line (&optional _soft)
  11426   (interactive)
  11427   (let (ctx)
  11428     (setq ctx (web-mode-comment-context))
  11429     (cond
  11430       ((null ctx)
  11431        (newline 1))
  11432       (t
  11433        (newline 1)
  11434        (indent-line-to (plist-get ctx :col))
  11435        (let ((prefix (plist-get ctx :prefix)))
  11436          (insert
  11437           (concat prefix
  11438                   ;; Check if the comment ends with a space, and if not, insert one.
  11439                   (if
  11440                    (string-equal (substring prefix -1 (length prefix)) " ")
  11441                    ""
  11442                    " ")))))
  11443       ) ;cond
  11444     ))
  11445 
  11446 (defun web-mode-comment-context (&optional pos)
  11447   (cond
  11448     (pos
  11449      )
  11450     ((and (eolp) (not (bobp)))
  11451      (setq pos (1- (point))))
  11452     (t
  11453      (setq pos (point)))
  11454     ) ;cond
  11455   (let (beg col prefix type format)
  11456     (cond
  11457       ((eq (get-text-property pos 'block-token) 'comment)
  11458        (setq type "block"))
  11459       ((eq (get-text-property pos 'tag-type) 'comment)
  11460        (setq type "tag"))
  11461       ((eq (get-text-property pos 'part-token) 'comment)
  11462        (setq type "part"))
  11463       )
  11464     (if (null type) nil
  11465         (save-excursion
  11466           (goto-char pos)
  11467           (web-mode-comment-beginning)
  11468           (setq beg (point)
  11469                 col (current-column))
  11470           (cond
  11471             ((looking-at-p "/\\*")
  11472              (setq format "/*"
  11473                    prefix " * "))
  11474             ((looking-at-p "//")
  11475              (setq format "//"
  11476                    prefix "//"))
  11477             ((looking-at-p "#")
  11478              (setq format "#"
  11479                    prefix "#"))
  11480             ((looking-at-p ";")
  11481              (setq format ";"
  11482                    prefix ";"))
  11483             ((looking-at-p "''")
  11484              (setq format "''"
  11485                    prefix "''"))
  11486             ) ;cond
  11487           (list :beg beg :col col :prefix prefix :type type :format format)))))
  11488 
  11489 (defun web-mode-comment-insert ()
  11490   (let ((alt nil) (language nil) (pos (point)))
  11491     (setq language (web-mode-language-at-pos pos))
  11492     (setq alt (cdr (assoc language web-mode-comment-formats)))
  11493     ;;(message "language=%S" language)
  11494     (cond
  11495       ((get-text-property pos 'block-side)
  11496        (cond
  11497          ((and alt (string= alt "//"))
  11498           (insert "// "))
  11499          (t
  11500           (insert "/*  */")
  11501           (search-backward " */"))
  11502          ) ;cond
  11503        ) ;case block-side
  11504       ((get-text-property pos 'part-side)
  11505        (cond
  11506          ((and alt (string= alt "//"))
  11507           (insert "// "))
  11508          (t
  11509           (insert "/*  */")
  11510           (search-backward " */"))
  11511          ) ;cond
  11512        ) ;case part-side
  11513       (t
  11514        (insert "<!--  -->")
  11515        (search-backward " -->")
  11516        ) ;case html
  11517       ) ;cond
  11518     ))
  11519 
  11520 (defun web-mode-comment (pos)
  11521   (let (ctx language col sel beg end block-side single-line-block pos-after content)
  11522 
  11523     (setq pos-after pos)
  11524 
  11525     (setq block-side (get-text-property pos 'block-side))
  11526     (setq single-line-block (web-mode-is-single-line-block pos))
  11527 
  11528     (cond
  11529 
  11530       ((and block-side (string= web-mode-engine "erb"))
  11531        (web-mode-comment-erb-block pos)
  11532        )
  11533 
  11534       ((and block-side (string= web-mode-engine "artanis"))
  11535        (web-mode-comment-artanis-block pos)
  11536        )
  11537 
  11538       ((and single-line-block block-side
  11539             (intern-soft (concat "web-mode-comment-" web-mode-engine "-block")))
  11540        (funcall (intern (concat "web-mode-comment-" web-mode-engine "-block")) pos)
  11541        )
  11542 
  11543       (t
  11544        (setq ctx (web-mode-point-context
  11545                   (if mark-active (region-beginning) (line-beginning-position))))
  11546        ;;(message "%S" ctx)
  11547        (setq language (plist-get ctx :language))
  11548        (setq col (current-column))
  11549        (cond
  11550          (mark-active
  11551           ;;(message "%S %S" (point) col)
  11552           )
  11553          ((and (member language '("html" "xml"))
  11554                (get-text-property (progn (back-to-indentation) (point)) 'tag-beg))
  11555           (web-mode-element-select))
  11556          (t
  11557           (end-of-line)
  11558           (set-mark (line-beginning-position)))
  11559          ) ;cond
  11560 
  11561        (setq beg (region-beginning)
  11562              end (region-end))
  11563 
  11564        (when (> (point) (mark))
  11565          (exchange-point-and-mark))
  11566 
  11567        (if (and (eq (char-before end) ?\n)
  11568                 (not (eq (char-after end) ?\n)))
  11569            (setq end (1- end)))
  11570 
  11571        (setq sel (buffer-substring-no-properties beg end))
  11572 
  11573        (cond
  11574 
  11575          ((member language '("html" "xml"))
  11576           (cond
  11577             ((and (= web-mode-comment-style 2) (string= web-mode-engine "django"))
  11578              (setq content (concat "{# " sel " #}")))
  11579             ((and (= web-mode-comment-style 2) (member web-mode-engine '("ejs" "erb")))
  11580              (setq content (concat "<%# " sel " %>")))
  11581             ((and (= web-mode-comment-style 2) (string= web-mode-engine "artanis"))
  11582              (setq content (concat "<%; " sel " %>")))
  11583             ((and (= web-mode-comment-style 2) (string= web-mode-engine "aspx"))
  11584              (setq content (concat "<%-- " sel " --%>")))
  11585             ((and (= web-mode-comment-style 2) (string= web-mode-engine "smarty"))
  11586              (setq content (concat "{* " sel " *}")))
  11587             ((and (= web-mode-comment-style 2) (string= web-mode-engine "expressionengine"))
  11588              (setq content (concat "{!-- " sel " --}")))
  11589             ((and (= web-mode-comment-style 2) (string= web-mode-engine "xoops"))
  11590              (setq content (concat "<{* " sel " *}>")))
  11591             ((and (= web-mode-comment-style 2) (string= web-mode-engine "hero"))
  11592              (setq content (concat "<%# " sel " %>")))
  11593             ((and (= web-mode-comment-style 2) (string= web-mode-engine "blade"))
  11594              (setq content (concat "{{-- " sel " --}}")))
  11595             ((and (= web-mode-comment-style 2) (string= web-mode-engine "ctemplate"))
  11596              (setq content (concat "{{!-- " sel " --}}")))
  11597             ((and (= web-mode-comment-style 2) (string= web-mode-engine "antlers"))
  11598              (setq content (concat "{{# " sel " #}}")))
  11599             ((and (= web-mode-comment-style 2) (string= web-mode-engine "razor"))
  11600              (setq content (concat "@* " sel " *@")))
  11601             (t
  11602              (setq content (concat "<!-- " sel " -->"))
  11603              (when (< (length sel) 1)
  11604                (search-backward " -->")
  11605                (setq pos-after nil))
  11606              ))
  11607           ) ;case html
  11608 
  11609          ((member language '("php" "javascript" "typescript" "java" "jsx"))
  11610           (let (alt)
  11611             (setq alt (cdr (assoc language web-mode-comment-formats)))
  11612             ;;(message "language=%S alt=%S sel=%S col=%S" language alt sel col)
  11613             (cond
  11614               ((and alt (string= alt "//"))
  11615                (setq content (replace-regexp-in-string (concat "\n[ ]\\{" (number-to-string col) "\\}") "\n" sel))
  11616                (setq content (replace-regexp-in-string (concat "\n") "\n// " content))
  11617                (setq content (concat "// " content)))
  11618               ((get-text-property pos 'jsx-depth)
  11619                (setq content (concat "{/* " sel " */}")))
  11620               (web-mode-comment-prefixing
  11621                (setq content (replace-regexp-in-string (concat "\n[ ]\\{" (number-to-string col) "\\}") "\n* " sel))
  11622                (setq content (concat "/* " content " */")))
  11623               (t
  11624                (setq content (concat "/* " sel " */")))
  11625               ) ;cond
  11626             ) ;let
  11627           )
  11628 
  11629          ((member language '("erb"))
  11630           (setq content (replace-regexp-in-string "^[ ]*" "#" sel)))
  11631 
  11632          ((member language '("asp"))
  11633           (setq content (replace-regexp-in-string "^[ ]*" "'" sel)))
  11634 
  11635          (t
  11636           (setq content (concat "/* " sel " */")))
  11637 
  11638          ) ;cond
  11639 
  11640        (when content
  11641          (delete-region beg end)
  11642          (deactivate-mark)
  11643          (let (beg end)
  11644            (setq beg (line-beginning-position))
  11645            (insert content)
  11646            (setq end (line-end-position))
  11647            (indent-region beg end)
  11648            )
  11649          ) ;when
  11650 
  11651        ) ;t
  11652       ) ;cond
  11653 
  11654     (when pos-after (goto-char pos-after))
  11655 
  11656     ))
  11657 
  11658 (defun web-mode-comment-ejs-block (pos)
  11659   (let (beg end)
  11660     (setq beg (web-mode-block-beginning-position pos)
  11661           end (web-mode-block-end-position pos))
  11662     (web-mode-insert-text-at-pos "//" (+ beg 2))))
  11663 
  11664 (defun web-mode-comment-erb-block (pos)
  11665   (let (beg end)
  11666     (setq beg (web-mode-block-beginning-position pos)
  11667           end (web-mode-block-end-position pos))
  11668     (web-mode-insert-text-at-pos "#" (+ beg 2))))
  11669 
  11670 (defun web-mode-comment-artanis-block (pos)
  11671   (let (beg end)
  11672     (setq beg (web-mode-block-beginning-position pos)
  11673           end (web-mode-block-end-position pos))
  11674     (web-mode-insert-text-at-pos ";" (+ beg 2))))
  11675 
  11676 (defun web-mode-comment-django-block (pos)
  11677   (let (beg end)
  11678     (setq beg (web-mode-block-beginning-position pos)
  11679           end (web-mode-block-end-position pos))
  11680     (web-mode-insert-text-at-pos "#" end)
  11681     (web-mode-insert-text-at-pos "#" (1+ beg))))
  11682 
  11683 (defun web-mode-comment-dust-block (pos)
  11684   (let (beg end)
  11685     (setq beg (web-mode-block-beginning-position pos)
  11686           end (web-mode-block-end-position pos))
  11687     (web-mode-insert-text-at-pos "!" end)
  11688     (web-mode-insert-text-at-pos "!" (1+ beg))))
  11689 
  11690 (defun web-mode-comment-aspx-block (pos)
  11691   (let (beg end)
  11692     (setq beg (web-mode-block-beginning-position pos)
  11693           end (web-mode-block-end-position pos))
  11694     (web-mode-insert-text-at-pos "#" end)
  11695     (web-mode-insert-text-at-pos "#" (1+ beg))))
  11696 
  11697 (defun web-mode-comment-jsp-block (pos)
  11698   (let (beg end)
  11699     (setq beg (web-mode-block-beginning-position pos)
  11700           end (web-mode-block-end-position pos))
  11701     (web-mode-insert-text-at-pos "--" (+ beg 2))))
  11702 
  11703 (defun web-mode-comment-go-block (pos)
  11704   (let (beg end)
  11705     (setq beg (web-mode-block-beginning-position pos)
  11706           end (web-mode-block-end-position pos))
  11707     (web-mode-insert-text-at-pos "*/" (1- end))
  11708     (web-mode-insert-text-at-pos "/*" (+ beg (if (web-mode-looking-at "{{" beg) 2 0)))))
  11709 
  11710 (defun web-mode-comment-php-block (pos)
  11711   (let (beg end)
  11712     (setq beg (web-mode-block-beginning-position pos)
  11713           end (web-mode-block-end-position pos))
  11714     (web-mode-insert-text-at-pos "*/" (- end 2))
  11715     (web-mode-insert-text-at-pos "/*" (+ beg 1 (if (web-mode-looking-at "<\\?php" beg) 5 3)))))
  11716 
  11717 (defun web-mode-comment-svelte-block (pos)
  11718   (let (beg end)
  11719     (setq beg (web-mode-block-beginning-position pos)
  11720           end (web-mode-block-end-position pos))
  11721     (web-mode-insert-text-at-pos "!" end)
  11722     (web-mode-insert-text-at-pos "!" (1+ beg))))
  11723 
  11724 (defun web-mode-comment-boundaries (&optional pos)
  11725   (interactive)
  11726   (unless pos (setq pos (point)))
  11727   (let ((beg pos) (end pos) prop)
  11728     (save-excursion
  11729       (goto-char pos)
  11730       (setq prop
  11731             (cond
  11732               ((eq (get-text-property pos 'block-token) 'comment) 'block-token)
  11733               ((eq (get-text-property pos 'tag-type) 'comment) 'tag-type)
  11734               ((eq (get-text-property pos 'part-token) 'comment) 'part-token)
  11735               (t nil)
  11736               ))
  11737       (if (null prop)
  11738           (setq beg nil
  11739                 end nil)
  11740           (when (and (not (bobp))
  11741                      (eq (get-text-property pos prop) (get-text-property (1- pos) prop)))
  11742             (setq beg (or (previous-single-property-change pos prop) (point-min))))
  11743           (when (and (not (eobp))
  11744                      (eq (get-text-property pos prop) (get-text-property (1+ pos) prop)))
  11745             (setq end (or (next-single-property-change pos prop) (point-max)))))
  11746       (message "beg(%S) end(%S) point-max(%S)" beg end (point-max))
  11747       (when (and beg (string= (buffer-substring-no-properties beg (+ beg 2)) "//"))
  11748         (goto-char end)
  11749         (while (and (looking-at-p "\n[ ]*//")
  11750                     (not (eobp)))
  11751           (search-forward "//")
  11752           (backward-char 2)
  11753           ;;(message "%S" (point))
  11754           (setq end (next-single-property-change (point) prop))
  11755           (goto-char end)
  11756           ;;(message "%S" (point))
  11757           ) ;while
  11758         ) ;when
  11759       ;;(when end (setq end (1- end))) ;; #1021
  11760       ) ;save-excursion
  11761     ;;(message "beg=%S end=%S" beg end)
  11762     (if (and beg end) (cons beg end) nil)
  11763     ))
  11764 
  11765 (defun web-mode-uncomment (pos)
  11766   (let ((beg pos) (end pos) (sub2 "") comment boundaries)
  11767     (save-excursion
  11768       (cond
  11769         ((and (get-text-property pos 'block-side)
  11770               (intern-soft (concat "web-mode-uncomment-" web-mode-engine "-block")))
  11771          (funcall (intern (concat "web-mode-uncomment-" web-mode-engine "-block")) pos))
  11772         ((and (setq boundaries (web-mode-comment-boundaries pos))
  11773               (setq beg (car boundaries))
  11774               (setq end (1+ (cdr boundaries)))
  11775               (> (- end beg) 4))
  11776          (when (and (eq (get-text-property beg 'part-token) 'comment)
  11777                     (> beg 1) ;#1158
  11778                     (get-text-property (1- beg) 'jsx-beg))
  11779            (setq beg (1- beg)
  11780                  end (1+ end)))
  11781          (setq comment (buffer-substring-no-properties beg end))
  11782          (setq sub2 (substring comment 0 2))
  11783          (cond
  11784            ((member sub2 '("<!" "<%"))
  11785             (setq comment (replace-regexp-in-string "\\(^<[!%]--[ ]?\\|[ ]?--[%]?>$\\)" "" comment)))
  11786            ((string= sub2 "{#")
  11787             (setq comment (replace-regexp-in-string "\\(^{#[ ]?\\|[ ]?#}$\\)" "" comment)))
  11788            ((string= sub2 "{/") ;jsx comments
  11789             (setq comment (replace-regexp-in-string "\\(^{/\\*[ ]?\\|[ ]?\\*/}$\\)" "" comment)))
  11790            ((string= sub2 "/*")
  11791             ;;(message "%S" comment)
  11792             ;;(setq comment (replace-regexp-in-string "\\(\\*/\\|^/\\*[ ]?\\|^[ \t]*\\*\\)" "" comment))
  11793             (setq comment (replace-regexp-in-string "\\([ ]?\\*/$\\|^/\\*[ ]?\\)" "" comment))
  11794             (setq comment (replace-regexp-in-string "\\(^[ \t]*\\*\\)" "" comment))
  11795             ;;(message "%S" comment)
  11796             )
  11797            ((string= sub2 "''")
  11798             (setq comment (replace-regexp-in-string "''" "" comment)))
  11799            ((string= sub2 "//")
  11800             (setq comment (replace-regexp-in-string "^ *//" "" comment)))
  11801            ) ;cond
  11802          (delete-region beg end)
  11803          (web-mode-insert-and-indent comment)
  11804          (goto-char beg)
  11805          )
  11806         ) ;cond
  11807       (indent-according-to-mode)
  11808       )))
  11809 
  11810 (defun web-mode-uncomment-erb-block (pos)
  11811   (let (beg end)
  11812     (setq beg (web-mode-block-beginning-position pos)
  11813           end (web-mode-block-end-position pos))
  11814     (cond
  11815       ((string= (buffer-substring-no-properties beg (+ beg 4)) "<%#=")
  11816        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11817       ((string-match-p "<[%[:alpha:]]" (buffer-substring-no-properties (+ beg 2) (- end 2)))
  11818        (web-mode-remove-text-at-pos 2 (1- end))
  11819        (web-mode-remove-text-at-pos 3 beg))
  11820       (t
  11821        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11822       ) ;cond
  11823     )
  11824   )
  11825 
  11826 (defun web-mode-uncomment-artanis-block (pos)
  11827   (let (beg end)
  11828     (setq beg (web-mode-block-beginning-position pos)
  11829           end (web-mode-block-end-position pos))
  11830     (cond
  11831       ((string= (buffer-substring-no-properties beg (+ beg 4)) "<%;=")
  11832        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11833       ((string-match-p "<[%[:alpha:]]" (buffer-substring-no-properties (+ beg 2) (- end 2)))
  11834        (web-mode-remove-text-at-pos 2 (1- end))
  11835        (web-mode-remove-text-at-pos 3 beg))
  11836       (t
  11837        (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11838       ) ;cond
  11839     )
  11840   )
  11841 
  11842 (defun web-mode-uncomment-ejs-block (pos)
  11843   (let (beg end)
  11844     (setq beg (web-mode-block-beginning-position pos)
  11845           end (web-mode-block-end-position pos))
  11846     (web-mode-remove-text-at-pos 1 (+ beg 2))))
  11847 
  11848 (defun web-mode-uncomment-django-block (pos)
  11849   (let (beg end)
  11850     (setq beg (web-mode-block-beginning-position pos)
  11851           end (web-mode-block-end-position pos))
  11852     (cond
  11853       ((web-mode-looking-at-p "{#[{%]" beg)
  11854        (web-mode-remove-text-at-pos 1 (1- end))
  11855        (web-mode-remove-text-at-pos 1 (1+ beg))
  11856        )
  11857       (t
  11858        (web-mode-remove-text-at-pos 2 (1- end))
  11859        (web-mode-remove-text-at-pos 2 beg))
  11860       ) ;cond
  11861     ))
  11862 
  11863 (defun web-mode-uncomment-ctemplate-block (pos)
  11864   (let (beg end)
  11865     (setq beg (web-mode-block-beginning-position pos)
  11866           end (web-mode-block-end-position pos))
  11867     (web-mode-remove-text-at-pos 5 (- end 4))
  11868     (web-mode-remove-text-at-pos 5 beg)))
  11869 
  11870 (defun web-mode-uncomment-antlers-block (pos)
  11871   (let (beg end)
  11872     (setq beg (web-mode-block-beginning-position pos)
  11873           end (web-mode-block-end-position pos))
  11874     (web-mode-remove-text-at-pos 3 (- end 2))
  11875     (web-mode-remove-text-at-pos 3 beg)))
  11876 
  11877 (defun web-mode-uncomment-dust-block (pos)
  11878   (let (beg end)
  11879     (setq beg (web-mode-block-beginning-position pos)
  11880           end (web-mode-block-end-position pos))
  11881     (web-mode-remove-text-at-pos 1 (1- end))
  11882     (web-mode-remove-text-at-pos 1 (1+ beg))))
  11883 
  11884 (defun web-mode-uncomment-aspx-block (pos)
  11885   (let (beg end)
  11886     (setq beg (web-mode-block-beginning-position pos)
  11887           end (web-mode-block-end-position pos))
  11888     (web-mode-remove-text-at-pos 1 (1- end))
  11889     (web-mode-remove-text-at-pos 1 (1+ beg))))
  11890 
  11891 (defun web-mode-uncomment-jsp-block (pos)
  11892   (let (beg end)
  11893     (setq beg (web-mode-block-beginning-position pos)
  11894           end (web-mode-block-end-position pos))
  11895     (web-mode-remove-text-at-pos 2 (+ beg 2))))
  11896 
  11897 (defun web-mode-uncomment-go-block (pos)
  11898   (let (beg end)
  11899     (setq beg (web-mode-block-beginning-position pos)
  11900           end (web-mode-block-end-position pos))
  11901     (web-mode-remove-text-at-pos 2 (+ beg 2))
  11902     (web-mode-remove-text-at-pos 2 (- end 5))))
  11903 
  11904 (defun web-mode-uncomment-svelte-block (pos)
  11905   (let (beg end)
  11906     (setq beg (web-mode-block-beginning-position pos)
  11907           end (web-mode-block-end-position pos))
  11908     (web-mode-remove-text-at-pos 1 (1- end))
  11909     (web-mode-remove-text-at-pos 1 (1+ beg))))
  11910 
  11911 (defun web-mode-snippet-names ()
  11912   (mapcar #'car web-mode-snippets))
  11913 
  11914 (defun web-mode-snippet-insert (code)
  11915   "Insert a snippet."
  11916   (interactive
  11917    (list (completing-read "Snippet: " (web-mode-snippet-names))))
  11918   (let (beg
  11919         (continue t)
  11920         (counter 0)
  11921         end
  11922         sel
  11923         snippet
  11924         (l (length web-mode-snippets))
  11925         pos)
  11926     (when mark-active
  11927       (setq sel (web-mode-trim (buffer-substring-no-properties
  11928                                 (region-beginning) (region-end))))
  11929       (delete-region (region-beginning) (region-end)))
  11930     (while (and continue (< counter l))
  11931       (setq snippet (nth counter web-mode-snippets))
  11932       (when (string= (car snippet) code)
  11933         (setq continue nil))
  11934       (setq counter (1+ counter)))
  11935     (when snippet
  11936       (setq snippet (cdr snippet))
  11937       (setq beg (line-beginning-position))
  11938       (insert snippet)
  11939       (setq pos (point)
  11940             end (point))
  11941       (cond
  11942         ((string-match-p "¦" snippet)
  11943          (search-backward "¦")
  11944          (delete-char 1)
  11945          (setq pos (point)
  11946                end (1- end)))
  11947         ((string-match-p "|" snippet)
  11948          (search-backward "|")
  11949          (delete-char 1)
  11950          (setq pos (point)
  11951                end (1- end)))
  11952         ) ;cond
  11953       (when sel
  11954         (insert sel)
  11955         (setq pos (point)
  11956               end (+ end (length sel))))
  11957       (goto-char end)
  11958       (setq end (line-end-position))
  11959       (unless sel (goto-char pos))
  11960       (indent-region beg end))
  11961     ))
  11962 
  11963 (defun web-mode-looking-at (regexp pos)
  11964   (save-excursion
  11965     (goto-char pos)
  11966     (looking-at regexp)))
  11967 
  11968 (defun web-mode-looking-at-p (regexp pos)
  11969   (save-excursion
  11970     (goto-char pos)
  11971     (looking-at-p regexp)))
  11972 
  11973 (defun web-mode-looking-back (regexp pos &optional limit greedy)
  11974   (save-excursion
  11975     (goto-char pos)
  11976     (if limit
  11977         (looking-back regexp limit greedy)
  11978         (looking-back regexp (point-min)))))
  11979 
  11980 (defun web-mode-insert-text-at-pos (text pos)
  11981   (let ((mem web-mode-enable-auto-pairing))
  11982     (setq web-mode-enable-auto-pairing nil)
  11983     (save-excursion
  11984       (goto-char pos)
  11985       (insert text)
  11986       (setq web-mode-enable-auto-pairing mem)
  11987       )))
  11988 
  11989 (defun web-mode-remove-text-at-pos (n &optional pos)
  11990   (unless pos (setq pos (point)))
  11991   (delete-region pos (+ pos n)))
  11992 
  11993 (defun web-mode-insert-and-indent (text)
  11994   (let (beg end)
  11995     (setq beg (line-beginning-position))
  11996     (insert text)
  11997     (setq end (line-end-position))
  11998     (indent-region beg end)
  11999     ))
  12000 
  12001 (defun web-mode-column-at-pos (pos)
  12002   (save-excursion
  12003     (goto-char pos)
  12004     (current-column)))
  12005 
  12006 (defun web-mode-indentation-at-pos (pos)
  12007   (save-excursion
  12008     (goto-char pos)
  12009     (current-indentation)))
  12010 
  12011 (defun web-mode-navigate (&optional pos)
  12012   "Move point to the matching opening/closing tag/block."
  12013   (interactive)
  12014   (unless pos (setq pos (point)))
  12015   (let (init)
  12016     (goto-char pos)
  12017     (setq init (point))
  12018     (when (> (current-indentation) (current-column))
  12019       (back-to-indentation))
  12020     (setq pos (point))
  12021     (cond
  12022       ((and (get-text-property pos 'block-side)
  12023             (web-mode-block-beginning)
  12024             (web-mode-block-controls-get (point)))
  12025        (web-mode-block-match))
  12026       ((member (get-text-property pos 'tag-type) '(start end))
  12027        (web-mode-tag-beginning)
  12028        (web-mode-tag-match))
  12029       (t
  12030        (goto-char init))
  12031       )
  12032     ))
  12033 
  12034 (defun web-mode-block-match (&optional pos)
  12035   (unless pos (setq pos (point)))
  12036   (let (pos-ori controls control (counter 1) type (continue t) pair)
  12037     (setq pos-ori pos)
  12038     (goto-char pos)
  12039     (setq controls (web-mode-block-controls-get pos))
  12040     ;;(message "controls=%S" controls)
  12041     (cond
  12042       (controls
  12043        (setq pair (car controls))
  12044        (setq control (cdr pair))
  12045        (setq type (car pair))
  12046        (when (eq type 'inside) (setq type 'close))
  12047        (while continue
  12048          (cond
  12049            ((and (> pos-ori 1) (bobp))
  12050             (setq continue nil))
  12051            ((or (and (eq type 'open) (not (web-mode-block-next)))
  12052                 (and (eq type 'close) (not (web-mode-block-previous))))
  12053             (setq continue nil)
  12054             )
  12055            ((null (setq controls (web-mode-block-controls-get (point))))
  12056             )
  12057            (t
  12058             ;;TODO : est il nécessaire de faire un reverse sur controls si on doit matcher backward
  12059             (dolist (pair controls)
  12060               (cond
  12061                 ((not (string= (cdr pair) control))
  12062                  )
  12063                 ((eq (car pair) 'inside)
  12064                  )
  12065                 ((eq (car pair) type)
  12066                  (setq counter (1+ counter)))
  12067                 (t
  12068                  (setq counter (1- counter)))
  12069                 )
  12070               ) ;dolist
  12071             (when (= counter 0)
  12072               (setq continue nil))
  12073             ) ;t
  12074            ) ;cond
  12075          ) ;while
  12076        (if (= counter 0) (point) nil)
  12077        ) ;controls
  12078       (t
  12079        (goto-char pos-ori)
  12080        nil
  12081        ) ;controls = nul
  12082       ) ;conf
  12083     ))
  12084 
  12085 (defun web-mode-tag-match (&optional pos)
  12086   "Move point to the matching opening/closing tag."
  12087   (interactive)
  12088   (unless pos (setq pos (point)))
  12089   (let (regexp name)
  12090     (cond
  12091       ((eq (get-text-property pos 'tag-type) 'void)
  12092        (web-mode-tag-beginning))
  12093       ((and (eq (get-text-property pos 'tag-type) 'comment)
  12094             (web-mode-looking-at-p "<!--#\\(elif\\|else\\|endif\\|if\\)" pos))
  12095        (setq regexp "<!--#\\(end\\)?if")
  12096        (if (web-mode-looking-at-p "<!--#if" pos)
  12097            (web-mode-tag-fetch-closing regexp pos)
  12098            (web-mode-tag-fetch-opening regexp pos))
  12099        )
  12100       (t
  12101        (setq name (get-text-property pos 'tag-name))
  12102        (when (string= name "_fragment_") (setq name ">"))
  12103        (setq regexp (concat "</?" name))
  12104        (when (member (get-text-property pos 'tag-type) '(start end))
  12105          (web-mode-tag-beginning)
  12106          (setq pos (point)))
  12107        (if (eq (get-text-property pos 'tag-type) 'end)
  12108            (web-mode-tag-fetch-opening regexp pos)
  12109            (web-mode-tag-fetch-closing regexp pos))
  12110        ) ;t
  12111       ) ;cond
  12112     t))
  12113 
  12114 (defun web-mode-tag-fetch-opening (regexp pos)
  12115   (let ((counter 1) (n 0) (is-comment nil) (types '(start end)))
  12116     (when (eq (aref regexp 1) ?\!)
  12117       (setq types '(comment)
  12118             is-comment t))
  12119     (goto-char pos)
  12120     (while (and (> counter 0) (re-search-backward regexp nil t))
  12121       (when (and (get-text-property (point) 'tag-beg)
  12122                  (member (get-text-property (point) 'tag-type) types))
  12123         (setq n (1+ n))
  12124         (cond
  12125           ((and is-comment
  12126                 (eq (aref (match-string-no-properties 0) 5) ?e))
  12127            (setq counter (1+ counter)))
  12128           (is-comment
  12129            (setq counter (1- counter)))
  12130           ((eq (get-text-property (point) 'tag-type) 'end)
  12131            (setq counter (1+ counter)))
  12132           (t
  12133            (setq counter (1- counter))
  12134            )
  12135           )
  12136         )
  12137       )
  12138     (if (= n 0) (goto-char pos))
  12139     ))
  12140 
  12141 (defun web-mode-tag-fetch-closing (regexp pos)
  12142   (let ((counter 1) (is-comment nil) (n 0))
  12143     (when (eq (aref regexp 1) ?\!)
  12144       (setq is-comment t))
  12145     (goto-char pos)
  12146     (web-mode-tag-end)
  12147     (while (and (> counter 0) (re-search-forward regexp nil t))
  12148       (when (get-text-property (match-beginning 0) 'tag-beg)
  12149         (setq n (1+ n))
  12150         (cond
  12151           ((and is-comment
  12152                 (eq (aref (match-string-no-properties 0) 5) ?e))
  12153            (setq counter (1- counter)))
  12154           (is-comment
  12155            (setq counter (1+ counter)))
  12156           ((eq (get-text-property (point) 'tag-type) 'end)
  12157            (setq counter (1- counter)))
  12158           (t
  12159            (setq counter (1+ counter)))
  12160           )
  12161         ) ;when
  12162       ) ;while
  12163     (if (> n 0)
  12164         (web-mode-tag-beginning)
  12165         (goto-char pos))
  12166     ))
  12167 
  12168 (defun web-mode-element-tag-name (&optional pos)
  12169   (unless pos (setq pos (point)))
  12170   (save-excursion
  12171     (goto-char pos)
  12172     (if (and (web-mode-tag-beginning)
  12173              (looking-at web-mode-tag-regexp))
  12174         (match-string-no-properties 1)
  12175         nil)))
  12176 
  12177 (defun web-mode-element-close ()
  12178   "Close html element."
  12179   (interactive)
  12180   (let (jmp epp ins tag)
  12181 
  12182     (if (and (eq (char-before) ?\>)
  12183              (web-mode-element-is-void (get-text-property (1- (point)) 'tag-name)))
  12184         (unless (eq (char-before (1- (point))) ?\/)
  12185           (backward-char)
  12186           (insert "/")
  12187           (forward-char))
  12188         (setq epp (web-mode-element-parent-position)))
  12189 
  12190     ;;(message "epp=%S" epp)
  12191     (when epp
  12192       (setq tag (get-text-property epp 'tag-name))
  12193       (setq tag (web-mode-element-tag-name epp))
  12194       ;;(message "tag=%S %c" tag (char-before))
  12195       (cond
  12196         ((or (null tag) (web-mode-element-is-void tag))
  12197          (setq epp nil))
  12198         ((looking-back "</" (point-min))
  12199          (setq ins tag))
  12200         ((looking-back "<" (point-min))
  12201          (setq ins (concat "/" tag)))
  12202         (t
  12203          ;;auto-close-style = 2
  12204          ;;(message "%S %c" (point) (char-after))
  12205          (when (and (looking-at-p "[[:alpha:]]") (> (length tag) 4))
  12206            (dolist (elt '("div" "span" "strong" "pre" "li"))
  12207              (when (and (string-match-p (concat "^" elt) tag) (not (string= tag elt)))
  12208                (setq tag elt)
  12209                (put-text-property epp (point) 'tag-name tag))
  12210              )
  12211            ) ;when
  12212          (if (web-mode-element-is-void (get-text-property (point) 'tag-name))
  12213              (setq ins nil
  12214                    epp nil)
  12215              (setq ins (concat "</" tag)))
  12216          )
  12217         ) ;cond
  12218       (when ins
  12219         (unless (looking-at-p "[ ]*>")
  12220           (setq ins (concat ins ">")))
  12221         (insert ins)
  12222         (setq tag (downcase tag))
  12223         (save-excursion
  12224           (search-backward "<")
  12225           (setq jmp (and (eq (char-before) ?\>)
  12226                          (string= (get-text-property (1- (point)) 'tag-name) tag)))
  12227           (if jmp (setq jmp (point)))
  12228           ) ;save-excursion
  12229         (if jmp (goto-char jmp))
  12230         ) ;when not ins
  12231       ) ;when epp
  12232     epp))
  12233 
  12234 (defun web-mode-detect-content-type ()
  12235   (cond
  12236     ((and (string= web-mode-engine "none")
  12237           (< (point) 16)
  12238           (eq (char-after 1) ?\#)
  12239           (string-match-p "php" (buffer-substring-no-properties
  12240                                  (line-beginning-position)
  12241                                  (line-end-position))))
  12242      (web-mode-set-engine "php"))
  12243     ((and (string= web-mode-content-type "javascript")
  12244           (< (point) web-mode-chunk-length)
  12245           (eq (char-after (point-min)) ?\/)
  12246           (string-match-p "@jsx" (buffer-substring-no-properties
  12247                                   (line-beginning-position)
  12248                                   (line-end-position))))
  12249      (web-mode-set-content-type "jsx"))
  12250     ))
  12251 
  12252 (defun web-mode-auto-complete ()
  12253   "Autocomple at point."
  12254   (interactive)
  12255   (let ((pos (point))
  12256         (char (char-before))
  12257         (chunk (buffer-substring-no-properties (- (point) 2) (point)))
  12258         (expanders nil) (tag nil)
  12259         (auto-closed   nil)
  12260         (auto-expanded nil)
  12261         (auto-paired   nil)
  12262         (auto-quoted   nil))
  12263 
  12264     ;;-- auto-closing
  12265     (when web-mode-enable-auto-closing
  12266 
  12267       (cond
  12268 
  12269         ((and (= web-mode-auto-close-style 3)
  12270               (eq char ?\<))
  12271          (insert "/>")
  12272          (backward-char 2)
  12273          (setq auto-closed t))
  12274 
  12275         ((and (= web-mode-auto-close-style 3)
  12276               (eq char ?\>)
  12277               (looking-at-p "/>"))
  12278          (save-excursion
  12279            (re-search-backward web-mode-start-tag-regexp)
  12280            (setq tag (match-string-no-properties 1)))
  12281          (insert "<")
  12282          (forward-char)
  12283          (insert tag)
  12284          (setq auto-closed t))
  12285 
  12286         ((and (>= pos 4)
  12287               (or (string= "</" chunk)
  12288                   ;;(progn (message "%c" char) nil)
  12289                   (and (= web-mode-auto-close-style 2)
  12290                        (or (string= web-mode-content-type "jsx")
  12291                            (not (get-text-property pos 'part-side)))
  12292                        (string-match-p "[[:alnum:]'\"]>" chunk)))
  12293               (not (get-text-property (- pos 2) 'block-side))
  12294               (web-mode-element-close))
  12295          (setq auto-closed t))
  12296 
  12297         ) ;cond
  12298       ) ;when
  12299 
  12300     ;;-- auto-pairing
  12301     (when (and web-mode-enable-auto-pairing
  12302                (>= pos 4)
  12303                (not auto-closed))
  12304       (let ((i 0) expr after pos-end (l (length web-mode-auto-pairs)))
  12305         (setq pos-end (if (> (+ pos 32) (line-end-position))
  12306                           (line-end-position)
  12307                           (+ pos 10)))
  12308         (setq chunk (buffer-substring-no-properties (- pos 3) pos)
  12309               after (buffer-substring-no-properties pos pos-end))
  12310         (while (and (< i l) (not auto-paired))
  12311           (setq expr (elt web-mode-auto-pairs i)
  12312                 i (1+ i))
  12313           ;;(message "chunk=%S expr=%S after=%S" chunk expr after)
  12314           (when (and (string= (car expr) chunk)
  12315                      (not (string-match-p (regexp-quote (cdr expr)) after)))
  12316             (setq auto-paired t)
  12317             (insert (cdr expr))
  12318             (if (string-match-p "|" (cdr expr))
  12319                 (progn
  12320                   (search-backward "|")
  12321                   (delete-char 1))
  12322                 (goto-char pos))
  12323             ) ;when
  12324           ) ;while
  12325         ) ;let
  12326       )
  12327 
  12328     ;;-- auto-expanding
  12329     (when (and web-mode-enable-auto-expanding
  12330                (not auto-closed)
  12331                (not auto-paired)
  12332                (eq char ?\/)
  12333                (looking-back "\\(^\\|[[:punct:][:space:]>]\\)./" (point-min))
  12334                (or (web-mode-jsx-is-html (1- pos))
  12335                    (and (not (get-text-property (1- pos) 'tag-type))
  12336                         (not (get-text-property (1- pos) 'part-side))))
  12337                (not (get-text-property (1- pos) 'block-side))
  12338                )
  12339       (setq expanders (append web-mode-extra-expanders web-mode-expanders))
  12340       (let ((i 0) pair (l (length expanders)))
  12341         (setq chunk (buffer-substring-no-properties (- pos 2) pos))
  12342         ;;(message "%S" chunk)
  12343         (while (and (< i l) (not auto-expanded))
  12344           (setq pair (elt expanders i)
  12345                 i (1+ i))
  12346           (when (string= (car pair) chunk)
  12347             (setq auto-expanded t)
  12348             (delete-char -2)
  12349             (insert (cdr pair))
  12350             (when (string-match-p "|" (cdr pair))
  12351               (search-backward "|")
  12352               (delete-char 1))
  12353             ) ;when
  12354           ) ;while
  12355         ) ;let
  12356       )
  12357 
  12358     ;;-- auto-quoting
  12359     (when (and web-mode-enable-auto-quoting
  12360                (>= pos 4)
  12361                (not (get-text-property pos 'block-side))
  12362                (not auto-closed)
  12363                (not auto-paired)
  12364                (not auto-expanded)
  12365                (get-text-property (- pos 2) 'tag-attr))
  12366       (cond
  12367         ((and (eq char ?\=)
  12368               (not (looking-at-p "[ ]*[\"']")))
  12369          (cond ((= web-mode-auto-quote-style 2)
  12370                 (insert "''"))
  12371                ((= web-mode-auto-quote-style 3)
  12372                 (insert "{}"))
  12373                (t
  12374                 (insert "\"\"")))
  12375          (if (looking-at-p "[ \n>]")
  12376              (backward-char)
  12377              (insert " ")
  12378              (backward-char 2)
  12379              )
  12380          (setq auto-quoted t))
  12381         ((and (eq char ?\")
  12382               (looking-back "=[ ]*\"" (point-min))
  12383               (not (looking-at-p "[ ]*[\"]")))
  12384          (insert-and-inherit "\"")
  12385          (backward-char)
  12386          (setq auto-quoted t))
  12387         ((and (eq char ?\')
  12388               (looking-back "=[ ]*'" (point-min))
  12389               (not (looking-at-p "[ ]*[']")))
  12390          (insert-and-inherit "'")
  12391          (backward-char)
  12392          (setq auto-quoted t))
  12393         ((and (eq char ?\{)
  12394               (eq (get-text-property pos 'part-side) 'jsx)
  12395               (looking-back "=[ ]*{" (point-min))
  12396               (not (looking-at-p "[ ]*[}]")))
  12397          (insert-and-inherit "}")
  12398          (backward-char)
  12399          (setq auto-quoted t))
  12400         ((and (eq char ?\")
  12401               (eq (char-after) ?\"))
  12402          (delete-char 1)
  12403          (cond
  12404            ((looking-back "=\"\"" (point-min))
  12405             (backward-char))
  12406            ((eq (char-after) ?\s)
  12407             (forward-char))
  12408            (t
  12409             (insert " "))
  12410            ) ;cond
  12411          )
  12412         ) ;cond
  12413       ) ;when
  12414 
  12415     ;;--
  12416     (cond
  12417       ((or auto-closed auto-paired auto-expanded auto-quoted)
  12418        (when (and web-mode-change-end (>= (line-end-position) web-mode-change-end))
  12419          (setq web-mode-change-end (line-end-position)))
  12420        (list :auto-closed auto-closed
  12421              :auto-paired auto-paired
  12422              :auto-expanded auto-expanded
  12423              :auto-quoted auto-quoted))
  12424       (t
  12425        nil)
  12426       )
  12427 
  12428     ))
  12429 
  12430 (defun web-mode-dom-xpath (&optional pos)
  12431   "Display html path."
  12432   (interactive)
  12433   (unless pos (setq pos (point)))
  12434   (save-excursion
  12435     (goto-char pos)
  12436     (let (path tag)
  12437       (while (web-mode-element-parent)
  12438         (looking-at web-mode-tag-regexp)
  12439         (setq tag (match-string-no-properties 1))
  12440         (setq path (cons tag path))
  12441         )
  12442       (message "/%s" (mapconcat 'identity path "/"))
  12443       )))
  12444 
  12445 (defun web-mode-block-ends-with (regexp &optional pos)
  12446   (unless pos (setq pos (point)))
  12447   (save-excursion
  12448     (goto-char pos)
  12449     (save-match-data
  12450       (if (stringp regexp)
  12451           (and (web-mode-block-end)
  12452                (progn (backward-char) t)
  12453                (web-mode-block-skip-blank-backward)
  12454                (progn (forward-char) t)
  12455                (looking-back regexp (point-min)))
  12456           (let ((pair regexp)
  12457                 (block-beg (web-mode-block-beginning-position pos))
  12458                 (block-end (web-mode-block-end-position pos)))
  12459             (and (web-mode-block-end)
  12460                  (web-mode-block-sb (car pair) block-beg)
  12461                  (not (web-mode-sf (cdr pair) block-end)))
  12462             ) ;let
  12463           ) ;if
  12464       )))
  12465 
  12466 (defun web-mode-block-token-starts-with (regexp &optional pos)
  12467   (unless pos (setq pos (point)))
  12468   (save-excursion
  12469     (and (goto-char pos)
  12470          (web-mode-block-token-beginning)
  12471          (skip-chars-forward "[\"']")
  12472          (looking-at regexp))
  12473     ))
  12474 
  12475 (defun web-mode-block-starts-with (regexp &optional pos)
  12476   (unless pos (setq pos (point)))
  12477   (save-excursion
  12478     (and (web-mode-block-beginning)
  12479          (web-mode-block-skip-blank-forward)
  12480          (looking-at regexp))
  12481     ))
  12482 
  12483 (defun web-mode-block-skip-blank-backward (&optional pos)
  12484   (unless pos (setq pos (point)))
  12485   (let ((continue t))
  12486     (goto-char pos)
  12487     (while continue
  12488       (if (and (get-text-property (point) 'block-side)
  12489                (not (bobp))
  12490                (or (member (char-after) '(?\s ?\n))
  12491                    (member (get-text-property (point) 'block-token)
  12492                            '(delimiter-beg delimiter-end comment))))
  12493           (backward-char)
  12494           (setq continue nil))
  12495       ) ;while
  12496     (point)))
  12497 
  12498 (defun web-mode-block-skip-blank-forward (&optional pos props)
  12499   (unless pos (setq pos (point)))
  12500   (unless props (setq props '(delimiter-beg delimiter-end comment)))
  12501   (let ((continue t))
  12502     (goto-char pos)
  12503     (while continue
  12504       (if (and (get-text-property (point) 'block-side)
  12505                (or (member (char-after) '(?\s ?\n ?\t))
  12506                    (member (get-text-property (point) 'block-token) props)))
  12507           (forward-char)
  12508           (setq continue nil))
  12509       ) ;while
  12510     (point)))
  12511 
  12512 (defun web-mode-tag-attributes-sort (&optional pos)
  12513   "Sort the attributes inside the current html tag."
  12514   (interactive)
  12515   (unless pos (setq pos (point)))
  12516   (save-excursion
  12517     (let (attrs (continue t) min max tag-beg tag-end attr attr-name attr-beg attr-end indent sorter ins)
  12518       (if (not (member (get-text-property pos 'tag-type) '(start void)))
  12519           nil
  12520           (setq tag-beg (web-mode-tag-beginning-position pos)
  12521                 tag-end (web-mode-tag-end-position))
  12522           ;;        (message "%S %S" tag-beg tag-end)
  12523           (goto-char tag-beg)
  12524           (while continue
  12525             (if (or (not (web-mode-attribute-next))
  12526                     (>= (point) tag-end))
  12527                 (setq continue nil)
  12528                 ;;(message "attr=%S" (point))
  12529                 (setq attr-beg (web-mode-attribute-beginning-position)
  12530                       attr-end (1+ (web-mode-attribute-end-position)))
  12531                 (when (null min)
  12532                   (setq min attr-beg))
  12533                 (setq max attr-end)
  12534                 (goto-char attr-beg)
  12535                 (setq attr (buffer-substring-no-properties attr-beg attr-end))
  12536                 (if (string-match "^\\([[:alnum:]-]+\\)=" attr)
  12537                     (setq attr-name (match-string-no-properties 1 attr))
  12538                     (setq attr-name attr))
  12539                 (setq indent (looking-back "^[ \t]*" (point-min)))
  12540                 (setq attrs (append attrs (list (list attr-beg attr-end attr-name attr indent))))
  12541                 ) ;if
  12542             ) ;while
  12543           ) ;if in tag
  12544       (when attrs
  12545         (setq sorter (function
  12546                       (lambda (elt1 elt2)
  12547                        (string< (nth 2 elt1) (nth 2 elt2))
  12548                        )))
  12549         (setq attrs (sort attrs sorter))
  12550         (delete-region (1- min) max)
  12551         (setq ins "")
  12552         (dolist (elt attrs)
  12553           (if (and (nth 4 elt) (> (length ins) 1))
  12554               (setq ins (concat ins "\n"))
  12555               (setq ins (concat ins " ")))
  12556           (setq ins (concat ins (nth 3 elt)))
  12557           )
  12558         (goto-char (1- min))
  12559         (insert ins)
  12560         (web-mode-tag-beginning)
  12561         (setq min (line-beginning-position))
  12562         (web-mode-tag-end)
  12563         (setq max (line-end-position))
  12564         (indent-region min max)
  12565         )
  12566       ;;(message "attrs=%S" attrs)
  12567       )))
  12568 
  12569 (defun web-mode-attribute-insert (&optional _attr-name _attr-value)
  12570   "Insert an attribute inside current tag."
  12571   (interactive)
  12572   (let (attr attr-name attr-value)
  12573     (cond
  12574       ((not (member (get-text-property (point) 'tag-type) '(start void)))
  12575        (message "attribute-insert ** invalid context **"))
  12576       ((not (and (setq attr-name (or attr-name (completing-read
  12577                                                 "Attribute name: "
  12578                                                 (append
  12579                                                  web-mode-attribute-list
  12580                                                  web-mode-attribute-history)
  12581                                                 nil nil nil 'web-mode-attribute-history)))
  12582                  (> (length attr-name) 0)))
  12583        (message "attribute-insert ** failure **"))
  12584       (t
  12585        (setq attr (concat " " attr-name))
  12586        (when (setq attr-value (or attr-value (completing-read
  12587                                               "Attribute value: "
  12588                                               web-mode-attribute-value-history
  12589                                               nil nil nil 'web-mode-attribute-value-history)))
  12590          (setq attr (concat attr "=\"" attr-value "\"")))
  12591        (web-mode-tag-end)
  12592        (if (looking-back "/>" (point-min))
  12593            (backward-char 2)
  12594            (backward-char))
  12595        (insert attr)
  12596        ) ;t
  12597       ) ;cond
  12598     ))
  12599 
  12600 (defun web-mode-attribute-transpose (&optional pos)
  12601   "Transpose the current html attribute."
  12602   (interactive)
  12603   (unless pos (setq pos (point)))
  12604   (let (attr-beg attr-end next-beg next-end tag-end)
  12605     (when (and (get-text-property pos 'tag-attr)
  12606                (setq next-beg (web-mode-attribute-next-position pos))
  12607                (setq next-end (web-mode-attribute-end-position next-beg))
  12608                (setq tag-end (web-mode-tag-end-position pos))
  12609                (> tag-end next-end))
  12610       (setq attr-beg (web-mode-attribute-beginning-position pos)
  12611             attr-end (web-mode-attribute-end-position pos))
  12612       ;;      (message "%S %S - %S %S" attr-beg attr-end next-beg next-end)
  12613       (transpose-regions attr-beg (1+ attr-end) next-beg (1+ next-end))
  12614       )))
  12615 
  12616 (defun web-mode-attribute-select (&optional pos)
  12617   "Select the current html attribute."
  12618   (interactive)
  12619   (unless pos (setq pos (point)))
  12620   (if (null (get-text-property pos 'tag-attr))
  12621       nil
  12622       (goto-char pos)
  12623       (web-mode-attribute-beginning)
  12624       (set-mark (point))
  12625       (web-mode-attribute-end)
  12626       (exchange-point-and-mark)
  12627       (point)
  12628       ))
  12629 
  12630 (defun web-mode-attribute-kill (&optional arg)
  12631   "Kill the current html attribute."
  12632   (interactive "p")
  12633   (unless arg (setq arg 1))
  12634   (while (>= arg 1)
  12635     (setq arg (1- arg))
  12636     (web-mode-attribute-select)
  12637     (when mark-active
  12638       (let ((beg (region-beginning)) (end (region-end)))
  12639         (save-excursion
  12640           (goto-char end)
  12641           (when (looking-at "[ \n\t]*")
  12642             (setq end (+ end (length (match-string-no-properties 0)))))
  12643           ) ;save-excursion
  12644         (kill-region beg end)
  12645         ) ;let
  12646       ) ;when
  12647     ) ;while
  12648   ;; Delete a potential space before the closing ">".
  12649   (when (and (looking-at ">")
  12650              (looking-back " " (point-min)))
  12651     (delete-char -1))
  12652   )
  12653 
  12654 (defun web-mode-block-close (&optional pos)
  12655   "Close the first unclosed control block."
  12656   (interactive)
  12657   (unless pos (setq pos (point)))
  12658   (let ((continue t)
  12659         (h (make-hash-table :test 'equal)) ctx ctrl n closing-block)
  12660     (save-excursion
  12661       (while (and continue (web-mode-block-previous))
  12662         (when (setq ctx (web-mode-block-is-control (point)))
  12663           (setq ctrl (car ctx))
  12664           (setq n (gethash ctrl h 0))
  12665           (if (cdr ctx)
  12666               (puthash ctrl (1+ n) h)
  12667               (puthash ctrl (1- n) h))
  12668           (when (> (gethash ctrl h) 0)
  12669             (setq continue nil))
  12670           )
  12671         ) ;while
  12672       ) ;save-excursion
  12673     (when (and (null continue)
  12674                (setq closing-block (web-mode-closing-block ctrl)))
  12675       (insert closing-block)
  12676       (indent-according-to-mode))
  12677     ))
  12678 
  12679 (defun web-mode-closing-block (type)
  12680   (cond
  12681     ((string= web-mode-engine "php")              (concat "<?php end" type "; ?>"))
  12682     ((string= web-mode-engine "django")           (concat "{% end" type " %}"))
  12683     ((string= web-mode-engine "antlers")          (concat "{{/" type "}}"))
  12684     ((string= web-mode-engine "ctemplate")        (concat "{{/" type "}}"))
  12685     ((string= web-mode-engine "blade")
  12686      (if (string= type "section") (concat "@show") (concat "@end" type)))
  12687     ((string= web-mode-engine "dust")             (concat "{/" type "}"))
  12688     ((string= web-mode-engine "mako")             (concat "% end" type))
  12689     ((string= web-mode-engine "closure")          (concat "{/" type "}"))
  12690     ((string= web-mode-engine "smarty")           (concat "{/" type "}"))
  12691     ((string= web-mode-engine "expressionengine") (concat "{/" type "}"))
  12692     ((string= web-mode-engine "xoops")            (concat "<{/" type "}>"))
  12693     ((string= web-mode-engine "svelte")           (concat "{/" type "}"))
  12694     ((string= web-mode-engine "underscore")        "<% } %>")
  12695     ((string= web-mode-engine "lsp")               "<% ) %>")
  12696     ((string= web-mode-engine "erb")               "<% } %>")
  12697     ((string= web-mode-engine "erb")               "<% end %>")
  12698     ((string= web-mode-engine "artanis")           "<% ) %>")
  12699     ((string= web-mode-engine "hero")              "<% } %>")
  12700     ((string= web-mode-engine "go")                "{{end}}")
  12701     ((string= web-mode-engine "velocity")          "#end")
  12702     ((string= web-mode-engine "velocity")          "#{end}")
  12703     ((string= web-mode-engine "template-toolkit")  "[% end %]")
  12704     ((member web-mode-engine '("asp" "jsp"))
  12705      (if (string-match-p "[:.]" type) (concat "</" type ">") "<% } %>"))
  12706     (t nil)
  12707     ) ;cond
  12708   )
  12709 
  12710 ;;---- POSITION ----------------------------------------------------------------
  12711 
  12712 (defun web-mode-comment-beginning-position (&optional pos)
  12713   (unless pos (setq pos (point)))
  12714   (car (web-mode-comment-boundaries pos)))
  12715 
  12716 (defun web-mode-comment-end-position (&optional pos)
  12717   (unless pos (setq pos (point)))
  12718   (cdr (web-mode-comment-boundaries pos)))
  12719 
  12720 (defun web-mode-part-opening-paren-position (pos &optional limit)
  12721   (save-restriction
  12722     (unless limit (setq limit nil))
  12723     (goto-char pos)
  12724     (let* ((n -1)
  12725            (paren (char-after))
  12726            (pairs '((?\) . "[)(]")
  12727                     (?\] . "[\]\[]")
  12728                     (?\} . "[}{]")
  12729                     (?\> . "[><]")))
  12730            (regexp (cdr (assoc paren pairs)))
  12731            (continue (not (null regexp)))
  12732            (counter 0))
  12733       (while (and continue (re-search-backward regexp limit t))
  12734         (cond
  12735           ((> (setq counter (1+ counter)) 500)
  12736            (message "part-opening-paren-position ** warning **")
  12737            (setq continue nil))
  12738           ((or (web-mode-is-comment-or-string)
  12739                (get-text-property (point) 'block-side))
  12740            )
  12741           ((eq (char-after) paren)
  12742            (setq n (1- n)))
  12743           (t
  12744            (setq n (1+ n))
  12745            (setq continue (not (= n 0))))
  12746           )
  12747         ) ;while
  12748       (if (= n 0) (point) nil)
  12749       )))
  12750 
  12751 (defun web-mode-token-opening-paren-position (pos limit _context)
  12752   (save-restriction
  12753     (unless limit (setq limit nil))
  12754     (goto-char pos)
  12755     (let* ((n -1)
  12756            (paren (char-after))
  12757            (pairs '((?\) . "[)(]")
  12758                     (?\] . "[\]\[]")
  12759                     (?\} . "[}{]")
  12760                     (?\> . "[><]")))
  12761            (regexp (cdr (assoc paren pairs)))
  12762            (continue (not (null regexp)))
  12763            (counter 0))
  12764       (while (and continue (re-search-backward regexp limit t))
  12765         (cond
  12766           ((> (setq counter (1+ counter)) 200)
  12767            (message "token-opening-paren-position ** warning **")
  12768            (setq continue nil))
  12769           ((get-text-property (point) 'block-side)
  12770            )
  12771           ((eq (char-after) paren)
  12772            (setq n (1- n)))
  12773           (t
  12774            (setq n (1+ n))
  12775            (setq continue (not (= n 0))))
  12776           )
  12777         ) ;while
  12778       (if (= n 0) (point) nil)
  12779       )))
  12780 
  12781 (defun web-mode-closing-paren-position (&optional pos limit)
  12782   (save-excursion
  12783     (unless pos (setq pos (point)))
  12784     (unless limit (setq limit nil))
  12785     (goto-char pos)
  12786     (let* ((n 0)
  12787            (block-side (and (get-text-property pos 'block-side)
  12788                             (not (string= web-mode-engine "razor"))))
  12789            (paren (char-after))
  12790            (pairs '((?\( . "[)(]")
  12791                     (?\[ . "[\]\[]")
  12792                     (?\{ . "[}{]")
  12793                     (?\< . "[><]")))
  12794            (regexp (cdr (assoc paren pairs)))
  12795            (continue (not (null regexp))))
  12796       (while (and continue (re-search-forward regexp limit t))
  12797         (cond
  12798           ((or (web-mode-is-comment-or-string (1- (point)))
  12799                (and block-side (not (get-text-property (point) 'block-side))))
  12800            ;;(message "pt=%S" (point))
  12801            )
  12802           ((eq (char-before) paren)
  12803            (setq n (1+ n)))
  12804           (t
  12805            (setq n (1- n))
  12806            (setq continue (not (= n 0)))
  12807            )
  12808           ) ;cond
  12809         ) ;while
  12810       (if (= n 0) (1- (point)) nil)
  12811       )))
  12812 
  12813 (defun web-mode-closing-delimiter-position (delimiter &optional pos limit)
  12814   (unless pos (setq pos (point)))
  12815   (unless limit (setq limit nil))
  12816   (save-excursion
  12817     (goto-char pos)
  12818     (setq pos nil)
  12819     (let ((continue t))
  12820       (while (and continue (re-search-forward delimiter limit t))
  12821         (setq continue nil
  12822               pos (1- (point)))
  12823         ) ;while
  12824       pos)))
  12825 
  12826 (defun web-mode-tag-match-position (&optional pos)
  12827   (unless pos (setq pos (point)))
  12828   (save-excursion
  12829     (web-mode-tag-match pos)
  12830     (if (= pos (point)) nil (point))))
  12831 
  12832 (defun web-mode-tag-beginning-position (&optional pos)
  12833   (unless pos (setq pos (point)))
  12834   (let (beg depth)
  12835     (setq depth (get-text-property pos 'jsx-depth))
  12836     (when (and depth (get-text-property pos 'tag-attr-beg))
  12837       (setq depth (get-text-property (1- pos) 'jsx-depth)))
  12838     (cond
  12839       ((null pos))
  12840       ((get-text-property pos 'tag-beg)
  12841        (setq beg pos))
  12842       ((and (> pos 1) (get-text-property (1- pos) 'tag-beg))
  12843        (setq beg (1- pos)))
  12844       ((get-text-property pos 'tag-type)
  12845        (setq beg (previous-single-property-change pos 'tag-beg))
  12846        (when beg (setq beg (1- beg)))
  12847        (cond
  12848          ((not (get-text-property beg 'tag-beg))
  12849           (setq beg nil))
  12850          ((and depth (not (eq depth (get-text-property beg 'jsx-depth))))
  12851           (let ((continue (> beg (point-min))))
  12852             (while continue
  12853               (setq beg (previous-single-property-change beg 'tag-beg))
  12854               (when beg (setq beg (1- beg)))
  12855               (cond
  12856                 ((null beg)
  12857                  (setq continue nil))
  12858                 ((not (get-text-property beg 'tag-beg))
  12859                  (setq continue nil
  12860                        beg nil))
  12861                 ((eq depth (get-text-property beg 'jsx-depth))
  12862                  (setq continue nil))
  12863                 ) ;cond
  12864               ) ;while
  12865             ) ;let
  12866           )
  12867          ) ;cond
  12868        )
  12869       (t
  12870        (setq beg nil))
  12871       ) ;cond
  12872     beg))
  12873 
  12874 (defun web-mode-tag-end-position (&optional pos)
  12875   (unless pos (setq pos (point)))
  12876   (let (end depth)
  12877     (setq depth (get-text-property pos 'jsx-depth))
  12878     (when (and depth (get-text-property pos 'tag-attr-beg))
  12879       (setq depth (get-text-property (1- pos) 'jsx-depth)))
  12880     (cond
  12881       ((null pos)
  12882        (setq end nil))
  12883       ((get-text-property pos 'tag-end)
  12884        (setq end pos))
  12885       ((get-text-property pos 'tag-type)
  12886        (setq end (next-single-property-change pos 'tag-end))
  12887        (cond
  12888          ((not (get-text-property end 'tag-end))
  12889           (setq end nil))
  12890          ((and depth (not (eq depth (get-text-property end 'jsx-depth))))
  12891           (let ((continue (< end (point-max))))
  12892             (while continue
  12893               (setq end (1+ end))
  12894               (setq end (next-single-property-change end 'tag-end))
  12895               (cond
  12896                 ((null end)
  12897                  (setq continue nil))
  12898                 ((not (get-text-property end 'tag-end))
  12899                  (setq continue nil
  12900                        end nil))
  12901                 ((eq depth (get-text-property end 'jsx-depth))
  12902                  (setq continue nil))
  12903                 ) ;cond
  12904               ) ;while
  12905             ) ;let
  12906           )
  12907          ) ;cond
  12908        )
  12909       (t
  12910        (setq end nil))
  12911       ) ;cond
  12912     end))
  12913 
  12914 ;; TODO: prendre en compte jsx-depth
  12915 (defun web-mode-tag-next-position (&optional pos limit)
  12916   (unless pos (setq pos (point)))
  12917   (unless limit (setq limit (point-max)))
  12918   (cond
  12919     ((or (>= pos (point-max)) (>= pos limit)) nil)
  12920     (t
  12921      (when (get-text-property pos 'tag-beg) (setq pos (1+ pos)))
  12922      (setq pos (next-single-property-change pos 'tag-beg))
  12923      (if (and pos (<= pos limit)) pos nil))
  12924     ))
  12925 
  12926 ;; TODO: prendre en compte jsx-depth
  12927 (defun web-mode-tag-previous-position (&optional pos limit)
  12928   (unless pos (setq pos (point)))
  12929   (unless limit (setq limit (point-min)))
  12930   (cond
  12931     ((or (<= pos (point-min)) (<= pos limit)) nil)
  12932     (t
  12933      (when (get-text-property pos 'tag-beg) (setq pos (1- pos)))
  12934      (web-mode-go (previous-single-property-change pos 'tag-beg) -1))
  12935     ))
  12936 
  12937 ;; TODO: prendre en compte jsx-depth
  12938 (defun web-mode-attribute-beginning-position (&optional pos)
  12939   (unless pos (setq pos (point)))
  12940   (cond
  12941     ((null (get-text-property pos 'tag-attr))
  12942      nil)
  12943     ((get-text-property pos 'tag-attr-beg)
  12944      pos)
  12945     ((and (> pos (point-min)) (get-text-property (1- pos) 'tag-attr-beg))
  12946      (1- pos))
  12947     (t
  12948      (setq pos (previous-single-property-change pos 'tag-attr-beg))
  12949      (setq pos (1- pos)))
  12950     ))
  12951 
  12952 ;; TODO: retoucher en incluant un param limit et en s'inspirant de
  12953 ;;       web-mode-attribute-next-position
  12954 (defun web-mode-attribute-end-position (&optional pos)
  12955   (unless pos (setq pos (point)))
  12956   (let (beg end depth flags)
  12957     ;;(message "pos=%S" pos)
  12958     (setq depth (get-text-property pos 'jsx-depth))
  12959     (cond
  12960       ((null pos)
  12961        (setq end nil))
  12962       ((get-text-property pos 'tag-attr-end)
  12963        (setq end pos))
  12964       ((get-text-property pos 'tag-attr)
  12965        (setq end (next-single-property-change pos 'tag-attr-end))
  12966        (when (and depth
  12967                   end
  12968                   (setq beg (web-mode-attribute-beginning-position end))
  12969                   (setq flags (get-text-property pos 'tag-attr-beg))
  12970                   (eq (logand flags 4) 4))
  12971          (setq depth (1- (get-text-property beg 'jsx-depth)))
  12972          ;;(message "%S %S" beg end)
  12973          )
  12974        (cond
  12975          ((not (get-text-property end 'tag-attr-end))
  12976           (setq end nil))
  12977          ((and depth
  12978                (eq depth (get-text-property end 'jsx-depth))
  12979                (not (eq depth (get-text-property end 'jsx-end))))
  12980           )
  12981          ((and depth (eq (1+ depth) (get-text-property end 'jsx-depth)))
  12982           )
  12983          ((and depth (not (eq (1+ depth) (get-text-property end 'jsx-depth))))
  12984           (let ((continue (< end (point-max))))
  12985             (while continue
  12986               (setq end (1+ end))
  12987               (setq end (next-single-property-change end 'tag-attr-end))
  12988               (cond
  12989                 ((null end)
  12990                  (setq continue nil))
  12991                 ((not (get-text-property end 'tag-attr-end))
  12992                  (setq continue nil
  12993                        end nil))
  12994                 ((eq (1+ depth) (get-text-property end 'jsx-depth))
  12995                  (setq continue nil))
  12996                 ) ;cond
  12997               ) ;while
  12998             ) ;let
  12999           )
  13000          ) ;cond
  13001        )
  13002       (t
  13003        (setq end nil))
  13004       ) ;cond
  13005     end))
  13006 
  13007 ;; attention si pos est au debut d'un spread attributes, cela
  13008 ;; risque de poser pb
  13009 (defun web-mode-attribute-next-position (&optional pos limit)
  13010   (unless pos (setq pos (point)))
  13011   (unless limit (setq limit (point-max)))
  13012   (let (continue depth)
  13013     (when (get-text-property pos 'tag-attr-beg)
  13014       (setq pos (1+ pos)))
  13015     (if (< pos limit)
  13016         (setq continue t
  13017               depth (get-text-property pos 'jsx-depth))
  13018         (setq continue nil
  13019               pos nil))
  13020     (while continue
  13021       (setq pos (next-single-property-change pos 'tag-attr-beg))
  13022       (cond
  13023         ((null pos)
  13024          (setq continue nil))
  13025         ((>= pos limit)
  13026          (setq continue nil
  13027                pos nil))
  13028         ((null depth)
  13029          (setq continue nil))
  13030         ((and (eq (get-text-property pos 'tag-attr-beg) 4)
  13031               (eq (1+ depth) (get-text-property pos 'jsx-depth)))
  13032          (setq continue nil))
  13033         ((eq depth (get-text-property pos 'jsx-depth))
  13034          (setq continue nil))
  13035         (t
  13036          (setq pos (1+ pos)
  13037                continue (< pos limit)))
  13038         )
  13039       ) ;while
  13040     pos))
  13041 
  13042 (defun web-mode-attribute-previous-position (&optional pos limit)
  13043   (unless pos (setq pos (point)))
  13044   (unless limit (setq limit (point-min)))
  13045   (let (continue depth)
  13046     (cond
  13047       ((and (> pos (point-min)) (get-text-property (1- pos) 'tag-attr-beg))
  13048        (setq pos (1- pos)
  13049              continue nil))
  13050       (t
  13051        (when (get-text-property pos 'tag-attr-beg)
  13052          (setq pos (1- pos)))
  13053        (if (> pos limit)
  13054            (setq continue t
  13055                  depth (get-text-property pos 'jsx-depth))
  13056            (setq continue nil
  13057                  pos nil))
  13058        ) ;t
  13059       ) ;cond
  13060     (while continue
  13061       (setq pos (previous-single-property-change pos 'tag-attr-beg))
  13062       (cond
  13063         ((null pos)
  13064          (setq continue nil))
  13065         ((< pos limit)
  13066          (setq continue nil
  13067                pos nil))
  13068         ;;((null depth)
  13069         ;; (setq continue nil))
  13070         ((and depth (eq depth (get-text-property pos 'jsx-depth)))
  13071          (setq  pos (1- pos)
  13072                 continue nil))
  13073         (depth
  13074          (setq pos nil
  13075                continue (> pos limit)))
  13076         (t
  13077          (setq pos (1- pos)
  13078                continue nil))
  13079         ) ;cond
  13080       ) ;while
  13081     pos))
  13082 
  13083 ;; TODO: prendre en compte jsx-depth
  13084 (defun web-mode-element-beginning-position (&optional pos)
  13085   (unless pos (setq pos (point)))
  13086   (cond
  13087     ((null (get-text-property pos 'tag-type))
  13088      (setq pos (web-mode-element-parent-position)))
  13089     ((eq (get-text-property pos 'tag-type) 'end)
  13090      (setq pos (web-mode-tag-match-position pos))
  13091      (setq pos (if (get-text-property pos 'tag-beg) pos nil)))
  13092     ((member (get-text-property pos 'tag-type) '(start void))
  13093      (setq pos (web-mode-tag-beginning-position pos)))
  13094     (t
  13095      (setq pos nil))
  13096     ) ;cond
  13097   pos)
  13098 
  13099 ;; TODO: prendre en compte jsx-depth
  13100 (defun web-mode-element-end-position (&optional pos)
  13101   (unless pos (setq pos (point)))
  13102   (cond
  13103     ((null (get-text-property pos 'tag-type))
  13104      (setq pos (web-mode-element-parent-position pos))
  13105      (when pos
  13106        (setq pos (web-mode-tag-match-position pos))
  13107        (when pos (setq pos (web-mode-tag-end-position pos)))
  13108        )
  13109      )
  13110     ((member (get-text-property pos 'tag-type) '(end void comment))
  13111      (setq pos (web-mode-tag-end-position pos))
  13112      )
  13113     ((member (get-text-property pos 'tag-type) '(start))
  13114      (setq pos (web-mode-tag-match-position pos))
  13115      (when pos (setq pos (web-mode-tag-end-position pos))))
  13116     (t
  13117      (setq pos nil))
  13118     ) ;cond
  13119   pos)
  13120 
  13121 (defun web-mode-element-child-position (&optional pos)
  13122   (save-excursion
  13123     (let (child close)
  13124       (unless pos (setq pos (point)))
  13125       (goto-char pos)
  13126       (cond
  13127         ((eq (get-text-property pos 'tag-type) 'start)
  13128          (web-mode-tag-match)
  13129          (setq close (point))
  13130          (goto-char pos)
  13131          )
  13132         ((eq (get-text-property pos 'tag-type) 'void)
  13133          )
  13134         ((eq (get-text-property pos 'tag-type) 'end)
  13135          (web-mode-tag-beginning)
  13136          (setq close (point))
  13137          (web-mode-tag-match)
  13138          )
  13139         ((web-mode-element-parent-position pos)
  13140          (setq pos (point))
  13141          (web-mode-tag-match)
  13142          (setq close (point))
  13143          (goto-char pos)
  13144          )
  13145         ) ;cond
  13146       (when (and close
  13147                  (web-mode-element-next)
  13148                  (< (point) close))
  13149         (setq child (point))
  13150         )
  13151       child)))
  13152 
  13153 (defun web-mode-element-parent-position (&optional pos)
  13154   (let (n tag-type tag-name (continue t) (tags (make-hash-table :test 'equal)))
  13155     (save-excursion
  13156       (if pos (goto-char pos))
  13157       (while (and continue (web-mode-tag-previous))
  13158         (setq pos (point)
  13159               tag-type (get-text-property pos 'tag-type)
  13160               tag-name (get-text-property pos 'tag-name)
  13161               n (gethash tag-name tags 0))
  13162         (when (member tag-type '(end start))
  13163           (if (eq tag-type 'end)
  13164               (puthash tag-name (1- n) tags)
  13165               (puthash tag-name (1+ n) tags)
  13166               (when (= n 0) (setq continue nil))
  13167               ) ;if
  13168           ) ;when
  13169         ) ;while
  13170       ) ;save-excursion
  13171     (if (null continue) pos nil)))
  13172 
  13173 (defun web-mode-element-previous-position (&optional pos limit)
  13174   (unless pos (setq pos (point)))
  13175   (unless limit (setq limit (point-min)))
  13176   (save-excursion
  13177     (goto-char pos)
  13178     (let ((continue (not (bobp)))
  13179           (props '(start void comment)))
  13180       (while continue
  13181         (setq pos (web-mode-tag-previous))
  13182         (cond
  13183           ((or (null pos) (< (point) limit))
  13184            (setq continue nil
  13185                  pos nil))
  13186           ((member (get-text-property (point) 'tag-type) props)
  13187            (setq continue nil))
  13188           )
  13189         ) ;while
  13190       pos)))
  13191 
  13192 (defun web-mode-element-next-position (&optional pos limit)
  13193   (unless pos (setq pos (point)))
  13194   (unless limit (setq limit (point-max)))
  13195   (save-excursion
  13196     (goto-char pos)
  13197     (let ((continue (not (eobp)))
  13198           (props '(start void comment)))
  13199       (while continue
  13200         (setq pos (web-mode-tag-next))
  13201         (cond
  13202           ((or (null pos) (> (point) limit))
  13203            (setq continue nil
  13204                  pos nil))
  13205           ((member (get-text-property (point) 'tag-type) props)
  13206            (setq continue nil))
  13207           )
  13208         ) ;while
  13209       ;;      (message "pos=%S" pos)
  13210       pos)))
  13211 
  13212 (defun web-mode-part-end-position (&optional pos)
  13213   (unless pos (setq pos (point)))
  13214   (cond
  13215     ((member web-mode-content-type web-mode-part-content-types)
  13216      (setq pos (point-max)))
  13217     ((not (get-text-property pos 'part-side))
  13218      (setq pos nil))
  13219     ((= pos (point-max))
  13220      (setq pos nil))
  13221     ((not (get-text-property (1+ pos) 'part-side))
  13222      pos)
  13223     (t
  13224      (setq pos (next-single-property-change pos 'part-side)))
  13225     ) ;cond
  13226   pos)
  13227 
  13228 (defun web-mode-part-beginning-position (&optional pos)
  13229   (unless pos (setq pos (point)))
  13230   (cond
  13231     (web-mode-part-beg
  13232      (setq pos web-mode-part-beg))
  13233     ((member web-mode-content-type web-mode-part-content-types)
  13234      (setq pos (point-min)
  13235            web-mode-part-beg (point-min)))
  13236     ((not (get-text-property pos 'part-side))
  13237      (setq pos nil))
  13238     ((= pos (point-min))
  13239      (setq pos nil))
  13240     ((not (get-text-property (1- pos) 'part-side))
  13241      pos)
  13242     (t
  13243      (setq pos (previous-single-property-change pos 'part-side)))
  13244     ) ;cond
  13245   pos)
  13246 
  13247 (defun web-mode-part-next-position (&optional pos)
  13248   (unless pos (setq pos (point)))
  13249   (cond
  13250     ((and (= pos (point-min)) (get-text-property pos 'part-side))
  13251      )
  13252     ((not (get-text-property pos 'part-side))
  13253      (setq pos (next-single-property-change pos 'part-side)))
  13254     ((and (setq pos (web-mode-part-end-position pos)) (>= pos (point-max)))
  13255      (setq pos nil))
  13256     ((and (setq pos (1+ pos)) (not (get-text-property pos 'part-side)))
  13257      (setq pos (next-single-property-change pos 'part-side)))
  13258     ) ;cond
  13259   pos)
  13260 
  13261 (defun web-mode-block-match-position (&optional pos)
  13262   (unless pos (setq pos (point)))
  13263   (save-excursion
  13264     (web-mode-block-match pos)
  13265     (if (= pos (point)) nil (point))))
  13266 
  13267 ;; type may be nil
  13268 (defun web-mode-block-control-previous-position (type &optional pos)
  13269   (unless pos (setq pos (point)))
  13270   (let ((continue t) controls)
  13271     (while continue
  13272       (setq pos (web-mode-block-previous-position pos))
  13273       (cond
  13274         ((null pos)
  13275          (setq continue nil
  13276                pos nil))
  13277         ((null type)
  13278          (setq continue nil))
  13279         ((and (setq controls (web-mode-block-controls-get pos))
  13280               (eq (car (car controls)) type))
  13281          (setq continue nil))
  13282         ) ;cond
  13283       ) ;while
  13284     pos))
  13285 
  13286 (defun web-mode-inside-block-control (&optional pos)
  13287   (unless pos (setq pos (point)))
  13288   (setq pos (web-mode-block-control-previous-position nil pos))
  13289   (if (and pos (member (car (car (web-mode-block-controls-get pos))) '(open inside)))
  13290       pos
  13291       nil))
  13292 
  13293 (defun web-mode-block-opening-paren-position (pos limit)
  13294   (save-excursion
  13295     (when (> limit pos)
  13296       (message "block-opening-paren-position: limit(%S) > pos(%S)" limit pos))
  13297     (goto-char pos)
  13298     (let (c
  13299           n
  13300           pt
  13301           (continue (> pos limit))
  13302           (pairs '((?\) . ?\()
  13303                    (?\] . ?\[)
  13304                    (?\} . ?\{)))
  13305           (h (make-hash-table :test 'equal))
  13306           (regexp "[\]\[)(}{]"))
  13307       (while (and continue (re-search-backward regexp limit t))
  13308         (cond
  13309           ((web-mode-is-comment-or-string)
  13310            )
  13311           (t
  13312            (setq c (char-after))
  13313            (cond
  13314              ((member c '(?\( ?\{ ?\[))
  13315               (setq n (gethash c h 0))
  13316               (if (= n 0)
  13317                   (setq continue nil
  13318                         pt (point))
  13319                   (puthash c (1+ n) h)
  13320                   ))
  13321              (t
  13322               (setq c (cdr (assoc c pairs)))
  13323               (setq n (gethash c h 0))
  13324               (puthash c (1- n) h))
  13325              ) ;cond
  13326            ) ;t
  13327           ) ;cond
  13328         ) ;while
  13329       pt)))
  13330 
  13331 (defun web-mode-block-code-beginning-position (&optional pos)
  13332   (unless pos (setq pos (point)))
  13333   (when (and (setq pos (web-mode-block-beginning-position pos))
  13334              (eq (get-text-property pos 'block-token) 'delimiter-beg))
  13335     (setq pos (next-single-property-change pos 'block-token)))
  13336   pos)
  13337 
  13338 (defun web-mode-block-beginning-position (&optional pos)
  13339   (unless pos (setq pos (point)))
  13340   (cond
  13341     ((or (and (get-text-property pos 'block-side) (= pos (point-min)))
  13342          (get-text-property pos 'block-beg))
  13343      )
  13344     ((and (> pos (point-min)) (get-text-property (1- pos) 'block-beg))
  13345      (setq pos (1- pos)))
  13346     ((get-text-property pos 'block-side)
  13347      (setq pos (previous-single-property-change pos 'block-beg))
  13348      (setq pos (if (and pos (> pos (point-min))) (1- pos) (point-min))))
  13349     (t
  13350      (setq pos nil))
  13351     ) ;cond
  13352   pos)
  13353 
  13354 (defun web-mode-block-string-beginning-position (pos &optional block-beg)
  13355   (unless pos (setq pos (point)))
  13356   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13357   (let (char (ori pos) (continue (not (null pos))))
  13358     (while continue
  13359       (setq char (char-after pos))
  13360       (cond
  13361         ((< pos block-beg)
  13362          (setq continue nil
  13363                pos block-beg))
  13364         ((and (member (get-text-property pos 'block-token) '(string comment))
  13365               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13366          (setq pos (web-mode-block-token-beginning-position pos))
  13367          )
  13368         ((member char '(?\) ?\]))
  13369          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13370          (setq pos (1- pos))
  13371          )
  13372         ((and (> ori pos) (member char '(?\( ?\= ?\[ ?\? ?\: ?\; ?\, ?\`)))
  13373          (if (and (eq char ?\:) ; #1024
  13374                   (web-mode-looking-at ":" pos))
  13375              (setq pos (1- pos))
  13376              (web-mode-looking-at ".[ \t\n]*" pos)
  13377              (setq pos (+ pos (length (match-string-no-properties 0)))
  13378                    continue nil)
  13379              )
  13380          )
  13381         ((web-mode-looking-at "\\(return\\|echo\\|include\\|print\\)[ \n]" pos)
  13382          (setq pos (+ pos (length (match-string-no-properties 0)))
  13383                continue nil))
  13384         (t
  13385          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?;,`:]\\|\\(return\\|echo\\|include\\|print\\)" block-beg))
  13386          (when (not pos)
  13387            (message "block-string-beginning-position ** search failure **")
  13388            (setq continue nil
  13389                  pos block-beg)))
  13390         ) ;cond
  13391       ) ;while
  13392     ;;(message "pos=%S" pos)
  13393     pos))
  13394 
  13395 (defun web-mode-block-statement-beginning-position (pos block-beg _is-ternary)
  13396   (unless pos (setq pos (point)))
  13397   (setq pos (1- pos))
  13398   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13399   (let (char (continue (not (null pos))))
  13400     (while continue
  13401       (setq char (char-after pos))
  13402       (cond
  13403         ((< pos block-beg)
  13404          (setq continue nil
  13405                pos block-beg))
  13406         ((and (member (get-text-property pos 'block-token) '(string comment))
  13407               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13408          (setq pos (web-mode-block-token-beginning-position pos)))
  13409         ((member char '(?\) ?\] ?\}))
  13410          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13411          (setq pos (1- pos)))
  13412         ((and (eq char ?\=)
  13413               (web-mode-looking-back "[<>!=]+" pos block-beg t))
  13414          (setq pos (- pos 1 (length (match-string-no-properties 0))))
  13415          ;;(setq pos (1- pos))
  13416          ;;(message "%S pos=%S" (match-string-no-properties 0) pos)
  13417          )
  13418         ((member char '(?\( ?\[ ?\{ ?\=))
  13419          (setq continue nil)
  13420          (web-mode-looking-at ".[ \t\n]*" pos)
  13421          (setq pos (+ pos (length (match-string-no-properties 0)))))
  13422         ((web-mode-looking-at "\\(return\\|echo\\|include\\|print\\)[ \n]" pos)
  13423          (setq pos (+ pos (length (match-string-no-properties 0)))
  13424                continue nil))
  13425         (t
  13426          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=]\\|\\(return\\|echo\\|include\\|print\\)" block-beg))
  13427          (when (not pos)
  13428            (message "block-statement-beginning-position ** search failure **")
  13429            (setq continue nil
  13430                  pos block-beg)))
  13431         ) ;cond
  13432       ) ;while
  13433     pos))
  13434 
  13435 (defun web-mode-block-args-beginning-position (pos &optional block-beg)
  13436   (unless pos (setq pos (point)))
  13437   (setq pos (1- pos)) ;#512
  13438   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13439   (let (char (continue (not (null pos))))
  13440     (while continue
  13441       (setq char (char-after pos))
  13442       (cond
  13443         ((< pos block-beg)
  13444          (message "block-args-beginning-position ** failure **")
  13445          (setq continue nil
  13446                pos block-beg))
  13447         ((and (member (get-text-property pos 'block-token) '(string comment))
  13448               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13449          (setq pos (web-mode-block-token-beginning-position pos)))
  13450         ((member char '(?\) ?\] ?\}))
  13451          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13452          (setq pos (1- pos)))
  13453         ((member char '(?\( ?\[ ?\{))
  13454          (setq continue nil)
  13455          (web-mode-looking-at ".[ \t\n]*" pos)
  13456          (setq pos (+ pos (length (match-string-no-properties 0)))))
  13457         ((and (string= web-mode-engine "php")
  13458               (web-mode-looking-at "\\(extends\\|implements\\)[ \n]" pos))
  13459          (setq pos (+ pos (length (match-string-no-properties 0)))
  13460                continue nil))
  13461         (t
  13462          (setq pos (web-mode-rsb-position pos "[\]\[}{)(]\\|\\(extends\\|implements\\)" block-beg))
  13463          (when (not pos)
  13464            (message "block-args-beginning-position ** search failure **")
  13465            (setq pos block-beg
  13466                  continue nil))
  13467          ) ;t
  13468         ) ;cond
  13469       ) ;while
  13470     pos))
  13471 
  13472 (defun web-mode-block-calls-beginning-position (pos &optional block-beg)
  13473   (unless pos (setq pos (point)))
  13474   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13475   (let (char (continue (not (null pos))))
  13476     (while continue
  13477       (setq char (char-after pos))
  13478       (cond
  13479         ((< pos block-beg)
  13480          (message "block-calls-beginning-position ** failure **")
  13481          (setq continue nil
  13482                pos block-beg))
  13483         ((and (member (get-text-property pos 'block-token) '(string comment))
  13484               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13485          (setq pos (web-mode-block-token-beginning-position pos)))
  13486         ((member char '(?\) ?\]))
  13487          (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13488          (setq pos (1- pos)))
  13489         ((member char '(?\( ?\[ ?\{ ?\} ?\= ?\? ?\: ?\; ?\,))
  13490          (web-mode-looking-at ".[ \t\n]*" pos)
  13491          (setq pos (+ pos (length (match-string-no-properties 0)))
  13492                continue nil))
  13493         ((web-mode-looking-at "\\(return\\|else\\)[ \n]" pos)
  13494          (setq pos (+ pos (length (match-string-no-properties 0)))
  13495                continue nil))
  13496         (t
  13497          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,]\\|\\(return\\|else\\)" block-beg))
  13498          (when (not pos)
  13499            (message "block-calls-beginning-position ** search failure **")
  13500            (setq pos block-beg
  13501                  continue nil))
  13502          ) ;t
  13503         ) ;cond
  13504       ) ;while
  13505     pos))
  13506 
  13507 (defun web-mode-javascript-string-beginning-position (pos &optional reg-beg)
  13508   (unless pos (setq pos (point)))
  13509   (let ((char nil)
  13510         (blockside (get-text-property pos 'block-side))
  13511         (i 0)
  13512         (continue (not (null pos))))
  13513     (unless reg-beg
  13514       (if blockside
  13515           (setq reg-beg (web-mode-block-beginning-position pos))
  13516           (setq reg-beg (web-mode-part-beginning-position pos)))
  13517       )
  13518     (while continue
  13519       (setq char (char-after pos))
  13520       (cond
  13521         ((> (setq i (1+ i)) 20000)
  13522          (message "javascript-string-beginning-position ** warning (%S) **" pos)
  13523          (setq continue nil
  13524                pos nil))
  13525         ((null pos)
  13526          (message "javascript-string-beginning-position ** invalid pos **")
  13527          (setq continue nil))
  13528         ((< pos reg-beg)
  13529          (message "javascript-string-beginning-position ** failure **")
  13530          (setq continue nil
  13531                pos reg-beg))
  13532         ((and blockside
  13533               (member (get-text-property pos 'block-token) '(string comment))
  13534               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13535          (setq pos (web-mode-block-token-beginning-position pos)))
  13536         ((and (not blockside)
  13537               (member (get-text-property pos 'part-token) '(string comment))
  13538               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13539          (setq pos (web-mode-part-token-beginning-position pos)))
  13540         ((and (not blockside)
  13541               (get-text-property pos 'block-side))
  13542          (when (setq pos (web-mode-block-beginning-position pos))
  13543            (setq pos (1- pos))))
  13544         ((member char '(?\) ?\] ?\}))
  13545          (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13546          (setq pos (1- pos)))
  13547         ((member char '(?\( ?\{ ?\[ ?\= ?\? ?\: ?\; ?\, ?\& ?\|))
  13548          (setq continue nil)
  13549          (web-mode-looking-at ".[ \t\n]*" pos)
  13550          (setq pos (+ pos (length (match-string-no-properties 0)))))
  13551         ((web-mode-looking-at "\\(return\\)[ \n]" pos)
  13552          (setq pos (+ pos (length (match-string-no-properties 0)))
  13553                continue nil))
  13554         (t
  13555          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,&|]\\|\\(return\\)" reg-beg))
  13556          (when (not pos)
  13557            (message "javascript-string-beginning-position ** search failure **")
  13558            (setq continue nil
  13559                  pos reg-beg)))
  13560         ) ;cond
  13561       ) ;while
  13562     ;;(message "js-statement-beg:%S" pos)
  13563     pos))
  13564 
  13565 ;; TODO: reg-beg : jsx-beg
  13566 ;; TODO: skipper les expr dont la depth est superieure
  13567 
  13568 ;; NOTE: blockside is useful for ejs
  13569 (defun web-mode-javascript-statement-beginning-position (pos reg-beg is-ternary)
  13570   (unless pos (setq pos (point)))
  13571   (setq pos (1- pos))
  13572   (let ((char nil)
  13573         (blockside (get-text-property pos 'block-side))
  13574         (i 0)
  13575         (is-jsx (string= web-mode-content-type "jsx"))
  13576         (depth-o nil) (depth-l nil)
  13577         (continue (not (null pos)))
  13578         (regexp "[\]\[}{)(=:]\\|\\(return\\)"))
  13579     (when is-ternary
  13580       (setq regexp (concat regexp "\\|[><]")))
  13581     (setq depth-o (get-text-property pos 'jsx-depth))
  13582     (unless reg-beg
  13583       (cond
  13584         (blockside
  13585          (setq reg-beg (web-mode-block-beginning-position pos)))
  13586         (is-jsx
  13587          (setq reg-beg (web-mode-jsx-depth-beginning-position pos)))
  13588         (t
  13589          (setq reg-beg (web-mode-part-beginning-position pos)))
  13590         ) ;cond
  13591       ) ;unless
  13592     (while continue
  13593       (setq char (char-after pos))
  13594       (cond
  13595         ((> (setq i (1+ i)) 20000)
  13596          (message "javascript-statement-beginning-position ** warning (%S) **" pos)
  13597          (setq continue nil
  13598                pos nil))
  13599         ((null pos)
  13600          (message "javascript-statement-beginning-position ** invalid pos **")
  13601          (setq continue nil))
  13602         ((< pos reg-beg)
  13603          (when (not is-jsx)
  13604            (message "javascript-statement-beginning-position ** failure **"))
  13605          (setq continue nil
  13606                pos reg-beg))
  13607         ((and is-jsx
  13608               (progn (setq depth-l (get-text-property pos 'jsx-depth)) t)
  13609               (not (eq depth-l depth-o)))
  13610          ;;(message "%S > depth-o(%S) depth-l(%S)" pos depth-o depth-l)
  13611          (setq pos (previous-single-property-change pos 'jsx-depth))
  13612          (setq pos (1- pos))
  13613          ;;(message "--> %S %S" pos (get-text-property pos 'jsx-depth))
  13614          )
  13615         ((and blockside
  13616               (member (get-text-property pos 'block-token) '(string comment))
  13617               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13618          (setq pos (web-mode-block-token-beginning-position pos)))
  13619         ((and (not blockside)
  13620               (member (get-text-property pos 'part-token) '(string comment))
  13621               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13622          (setq pos (web-mode-part-token-beginning-position pos)))
  13623         ((and (not blockside)
  13624               (get-text-property pos 'block-side))
  13625          (when (setq pos (web-mode-block-beginning-position pos))
  13626            (setq pos (1- pos))))
  13627         ((member char '(?\) ?\] ?\}))
  13628          (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13629          (setq pos (1- pos)))
  13630         ((and (eq char ?\=)
  13631               (web-mode-looking-back "[<>!=]+" pos reg-beg t))
  13632          (setq pos (- pos 1 (length (match-string-no-properties 0)))))
  13633         ((member char '(?\( ?\{ ?\[ ?\= ?\< ?\>))
  13634          (web-mode-looking-at ".[ \t\n]*" pos)
  13635          (setq continue nil
  13636                pos (+ pos (length (match-string-no-properties 0)))))
  13637 
  13638         ((web-mode-looking-at "\\(return\\)[ \n]" pos)
  13639          (setq continue nil
  13640                pos (+ pos (length (match-string-no-properties 0)))))
  13641         ((and (eq char ?\:)
  13642               (web-mode-looking-back "[{,][ \t\n]*[[:alnum:]_]+[ ]*" pos))
  13643          (web-mode-looking-at ".[ \t\n]*" pos)
  13644          (setq continue nil
  13645                pos (+ pos (length (match-string-no-properties 0)))))
  13646         (t
  13647          (setq pos (web-mode-rsb-position pos regexp reg-beg))
  13648          (when (not pos)
  13649            (cond
  13650              (is-jsx
  13651               (when (web-mode-looking-at "[ \n]*" reg-beg)
  13652                 (setq pos (+ reg-beg (length (match-string-no-properties 0)))))
  13653               (setq continue nil))
  13654              (t
  13655               (message "javascript-statement-beginning-position ** search failure **")
  13656               (setq continue nil
  13657                     pos reg-beg))
  13658              ) ;cond
  13659            )
  13660          ) ;t
  13661         ) ;cond
  13662       ) ;while
  13663     ;;(message "%S -------" pos)
  13664     pos))
  13665 
  13666 (defun web-mode-javascript-args-beginning-position (pos &optional reg-beg)
  13667   (unless pos (setq pos (point)))
  13668   (setq pos (1- pos))
  13669   (let ((char nil)
  13670         (blockside (get-text-property pos 'block-side))
  13671         (i 0)
  13672         (continue (not (null pos))))
  13673     (unless reg-beg
  13674       (if blockside
  13675           (setq reg-beg (web-mode-block-beginning-position pos))
  13676           (setq reg-beg (web-mode-part-beginning-position pos)))
  13677       )
  13678     (while continue
  13679       (setq char (char-after pos))
  13680       ;;(message "pos(%S) char(%c)" pos char)
  13681       (cond
  13682         ((> (setq i (1+ i)) 20000)
  13683          (message "javascript-args-beginning-position ** warning (%S) **" pos)
  13684          (setq continue nil
  13685                pos nil))
  13686         ((null pos)
  13687          (message "javascript-args-beginning-position ** invalid pos **")
  13688          (setq continue nil))
  13689         ((< pos reg-beg)
  13690          (message "javascript-args-beginning-position ** failure(position) **")
  13691          (setq continue nil
  13692                pos reg-beg))
  13693         ((and blockside
  13694               (member (get-text-property pos 'block-token) '(string comment))
  13695               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13696          (setq pos (web-mode-block-token-beginning-position pos)))
  13697         ((and (not blockside)
  13698               (member (get-text-property pos 'part-token) '(string comment))
  13699               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13700          (setq pos (web-mode-part-token-beginning-position pos)))
  13701         ((and (not blockside)
  13702               (get-text-property pos 'block-side))
  13703          (when (setq pos (web-mode-block-beginning-position pos))
  13704            (setq pos (1- pos)))
  13705          )
  13706         ((member char '(?\) ?\] ?\}))
  13707          (when (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13708            (setq pos (1- pos))))
  13709         ((member char '(?\( ?\[ ?\{))
  13710          (web-mode-looking-at ".[ ]*" pos)
  13711          (setq pos (+ pos (length (match-string-no-properties 0)))
  13712                continue nil)
  13713          )
  13714         ((web-mode-looking-at "\\(var\\|let\\|return\\|const\\)[ \n]" pos)
  13715          (setq pos (+ pos (length (match-string-no-properties 0)))
  13716                continue nil))
  13717         (t
  13718          (setq pos (web-mode-rsb-position pos "[\]\[}{)(]\\|\\(var\\|let\\|return\\|const\\)" reg-beg))
  13719          (when (not pos)
  13720            (message "javascript-args-beginning-position ** search failure **")
  13721            (setq continue nil
  13722                  pos reg-beg)))
  13723         ) ;cond
  13724       ) ;while
  13725     ;;(message "=%S" pos)
  13726     pos))
  13727 
  13728 (defun web-mode-javascript-calls-beginning-position (pos &optional reg-beg)
  13729   (unless pos (setq pos (point)))
  13730   ;;(message "pos=%S" pos)
  13731   (let ((char nil)
  13732         (dot-pos nil)
  13733         (blockside (get-text-property pos 'block-side))
  13734         (i 0)
  13735         (continue (not (null pos))))
  13736     (unless reg-beg
  13737       (setq reg-beg (if blockside
  13738                         (web-mode-block-beginning-position pos)
  13739                         (web-mode-part-beginning-position pos))))
  13740     (while continue
  13741       (setq char (char-after pos))
  13742       ;;(message "%S| %S=%c" reg-beg pos char)
  13743       (cond
  13744         ((> (setq i (1+ i)) 20000)
  13745          (message "javascript-calls-beginning-position ** warning (%S) **" pos)
  13746          (setq continue nil
  13747                pos nil))
  13748         ((null pos)
  13749          (message "javascript-calls-beginning-position ** invalid pos **")
  13750          (setq continue nil))
  13751         ((< pos reg-beg)
  13752          (setq continue nil
  13753                pos reg-beg))
  13754         ((and blockside
  13755               (member (get-text-property pos 'block-token) '(string comment))
  13756               (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13757          (setq pos (web-mode-block-token-beginning-position pos)))
  13758         ((and (not blockside)
  13759               (member (get-text-property pos 'part-token) '(string comment))
  13760               (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13761          (setq pos (web-mode-part-token-beginning-position pos)))
  13762         ((and (not blockside)
  13763               (get-text-property pos 'block-side))
  13764          (when (setq pos (web-mode-block-beginning-position pos))
  13765            (setq pos (1- pos))))
  13766         ((and (member char '(?\.)) (> i 1))
  13767          (setq dot-pos pos
  13768                pos (1- pos)))
  13769         ((member char '(?\) ?\]))
  13770          (when (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13771            (setq pos (1- pos)))
  13772          )
  13773         ((member char '(?\( ?\{ ?\} ?\[ ?\= ?\? ?\: ?\; ?\, ?\& ?\| ?\>))
  13774          (web-mode-looking-at ".[ \t\n]*" pos)
  13775          (setq pos (+ pos (length (match-string-no-properties 0)))
  13776                continue nil))
  13777         ((web-mode-looking-at "\\(return\\|else\\|const\\)[ \n]" pos)
  13778          (setq pos (+ pos (length (match-string-no-properties 0)))
  13779                continue nil))
  13780         (t
  13781          (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,&|>.]\\|\\(return\\|else\\|const\\)" reg-beg))
  13782          (when (not pos)
  13783            (message "javascript-calls-beginning-position ** search failure **")
  13784            (setq pos reg-beg
  13785                  continue nil))
  13786          ) ;t
  13787         ) ;cond
  13788       ) ;while
  13789     ;;(message "pos=%S dot-pos=%S" pos dot-pos)
  13790     (if (null pos) pos (cons pos dot-pos))
  13791     ))
  13792 
  13793 (defun web-mode-part-token-beginning-position (&optional pos)
  13794   (unless pos (setq pos (point)))
  13795   (cond
  13796     ((not (get-text-property pos 'part-token))
  13797      nil)
  13798     ((or (= pos (point-min))
  13799          (and (> pos (point-min))
  13800               (not (get-text-property (1- pos) 'part-token))))
  13801      pos)
  13802     (t
  13803      (setq pos (previous-single-property-change pos 'part-token))
  13804      (if (and pos (> pos (point-min))) pos (point-min)))
  13805     ))
  13806 
  13807 (defun web-mode-part-token-end-position (&optional pos)
  13808   (unless pos (setq pos (point)))
  13809   (cond
  13810     ((not (get-text-property pos 'part-token))
  13811      nil)
  13812     ((or (= pos (point-max))
  13813          (not (get-text-property (1+ pos) 'part-token)))
  13814      pos)
  13815     (t
  13816      (1- (next-single-property-change pos 'part-token)))
  13817     ))
  13818 
  13819 (defun web-mode-block-token-beginning-position (&optional pos)
  13820   (unless pos (setq pos (point)))
  13821   (cond
  13822     ((not (get-text-property pos 'block-token))
  13823      nil)
  13824     ((or (= pos (point-min))
  13825          (and (> pos (point-min))
  13826               (not (get-text-property (1- pos) 'block-token))))
  13827      pos)
  13828     (t
  13829      (setq pos (previous-single-property-change pos 'block-token))
  13830      (if (and pos (> pos (point-min))) pos (point-min)))
  13831     ))
  13832 
  13833 (defun web-mode-block-token-end-position (&optional pos)
  13834   (unless pos (setq pos (point)))
  13835   (cond
  13836     ((not (get-text-property pos 'block-token))
  13837      nil)
  13838     ((or (= pos (point-max))
  13839          (not (get-text-property (1+ pos) 'block-token)))
  13840      pos)
  13841     (t
  13842      (1- (next-single-property-change pos 'block-token)))
  13843     ))
  13844 
  13845 (defun web-mode-block-code-end-position (&optional pos)
  13846   (unless pos (setq pos (point)))
  13847   (setq pos (web-mode-block-end-position pos))
  13848   (cond
  13849     ((not pos)
  13850      nil)
  13851     ((and (eq (get-text-property pos 'block-token) 'delimiter-end)
  13852           (eq (get-text-property (1- pos) 'block-token) 'delimiter-end))
  13853      (previous-single-property-change pos 'block-token))
  13854     ((= pos (1- (point-max))) ;; TODO: comparer plutot avec line-end-position
  13855      (point-max))
  13856     (t
  13857      pos)
  13858     ))
  13859 
  13860 (defun web-mode-block-end-position (&optional pos)
  13861   (unless pos (setq pos (point)))
  13862   (cond
  13863     ((get-text-property pos 'block-end)
  13864      pos)
  13865     ((get-text-property pos 'block-side)
  13866      (or (next-single-property-change pos 'block-end)
  13867          (point-max)))
  13868     (t
  13869      nil)
  13870     ))
  13871 
  13872 (defun web-mode-block-previous-position (&optional pos)
  13873   (unless pos (setq pos (point)))
  13874   (cond
  13875     ((= pos (point-min))
  13876      (setq pos nil))
  13877     ((get-text-property pos 'block-side)
  13878      (setq pos (web-mode-block-beginning-position pos))
  13879      (cond
  13880        ((or (null pos) (= pos (point-min)))
  13881         (setq pos nil)
  13882         )
  13883        ((and (setq pos (previous-single-property-change pos 'block-beg))
  13884              (> pos (point-min)))
  13885         (setq pos (1- pos))
  13886         )
  13887        )
  13888      ) ;block-side
  13889     ((get-text-property (1- pos) 'block-side)
  13890      (setq pos (web-mode-block-beginning-position (1- pos)))
  13891      )
  13892     (t
  13893      (setq pos (previous-single-property-change pos 'block-side))
  13894      (cond
  13895        ((and (null pos) (get-text-property (point-min) 'block-beg))
  13896         (setq pos (point-min)))
  13897        ((and pos (> pos (point-min)))
  13898         (setq pos (web-mode-block-beginning-position (1- pos))))
  13899        )
  13900      )
  13901     ) ;conf
  13902   pos)
  13903 
  13904 (defun web-mode-block-next-position (&optional pos limit)
  13905   (unless pos (setq pos (point)))
  13906   (unless limit (setq limit (point-max)))
  13907   (cond
  13908     ((and (get-text-property pos 'block-side)
  13909           (setq pos (web-mode-block-end-position pos))
  13910           (< pos (point-max))
  13911           (setq pos (1+ pos)))
  13912      (unless (get-text-property pos 'block-beg)
  13913        (setq pos (next-single-property-change pos 'block-side)))
  13914      )
  13915     (t
  13916      (setq pos (next-single-property-change pos 'block-side)))
  13917     ) ;cond
  13918   (if (and pos (<= pos limit)) pos nil))
  13919 
  13920 (defun web-mode-is-css-string (pos)
  13921   (let (beg)
  13922     (cond
  13923       ((and (setq beg (web-mode-part-token-beginning-position pos))
  13924             (web-mode-looking-at-p "`" beg)
  13925             (web-mode-looking-back "\\(styled[[:alnum:].]+\\|css\\)" beg))
  13926        beg)
  13927       (t
  13928        nil)
  13929       ) ;cond
  13930     ))
  13931 
  13932 ;; Relay.QL , gql, graphql
  13933 (defun web-mode-is-ql-string (pos prefix-regexp)
  13934   (let (beg)
  13935     (cond
  13936       ((and (setq beg (web-mode-part-token-beginning-position pos))
  13937             (web-mode-looking-back prefix-regexp beg))
  13938        beg)
  13939       (t
  13940        nil)
  13941       ) ;cond
  13942     ))
  13943 
  13944 (defun web-mode-is-html-string (pos)
  13945   (let (beg)
  13946     (cond
  13947       ((and (setq beg (web-mode-part-token-beginning-position pos))
  13948             (web-mode-looking-at-p "`[ \t\n]*<[a-zA-Z]" beg)
  13949             (web-mode-looking-back "\\(template\\|html\\)\\([ ]*[=:][ ]*\\)?" beg))
  13950        beg)
  13951       (t
  13952        nil)
  13953       ) ;cond
  13954     ))
  13955 
  13956 ;;---- EXCURSION ---------------------------------------------------------------
  13957 
  13958 (defun web-mode-backward-sexp (n)
  13959   (interactive "p")
  13960   (if (< n 0) (web-mode-forward-sexp (- n))
  13961       (let (pos)
  13962         (dotimes (_ n)
  13963           (skip-chars-backward "[:space:]")
  13964           (setq pos (point))
  13965           (cond
  13966             ((bobp) nil)
  13967             ((get-text-property (1- pos) 'block-end)
  13968              (backward-char 1)
  13969              (web-mode-block-beginning))
  13970             ((get-text-property (1- pos) 'block-token)
  13971              (backward-char 1)
  13972              (web-mode-block-token-beginning))
  13973             ((get-text-property (1- pos) 'part-token)
  13974              (backward-char 1)
  13975              (web-mode-part-token-beginning))
  13976             ((get-text-property (1- pos) 'tag-end)
  13977              (backward-char 1)
  13978              (web-mode-element-beginning))
  13979             ((get-text-property (1- pos) 'tag-attr)
  13980              (backward-char 1)
  13981              (web-mode-attribute-beginning))
  13982             ((get-text-property (1- pos) 'tag-type)
  13983              (backward-char 1)
  13984              (web-mode-tag-beginning))
  13985             ((get-text-property (1- pos) 'jsx-end)
  13986              (backward-char 1)
  13987              (web-mode-jsx-beginning))
  13988             (t
  13989              (let ((forward-sexp-function nil))
  13990                (backward-sexp))
  13991              ) ;case t
  13992             ) ;cond
  13993           ) ;dotimes
  13994         ))) ;let if defun
  13995 
  13996 (defun web-mode-forward-sexp (n)
  13997   (interactive "p")
  13998   (if (< n 0) (web-mode-backward-sexp (- n))
  13999       (let (pos)
  14000         (dotimes (_ n)
  14001           (skip-chars-forward "[:space:]")
  14002           (setq pos (point))
  14003           (cond
  14004             ((eobp) nil)
  14005             ((get-text-property pos 'block-beg)
  14006              (web-mode-block-end))
  14007             ((get-text-property pos 'block-token)
  14008              (web-mode-block-token-end))
  14009             ((get-text-property pos 'part-token)
  14010              (web-mode-part-token-end))
  14011             ((get-text-property pos 'tag-beg)
  14012              (web-mode-element-end))
  14013             ((get-text-property pos 'tag-attr)
  14014              (web-mode-attribute-end))
  14015             ((get-text-property pos 'tag-type)
  14016              (web-mode-tag-end))
  14017             ((get-text-property pos 'jsx-beg)
  14018              (web-mode-jsx-end))
  14019             (t
  14020              (let ((forward-sexp-function nil))
  14021                (forward-sexp))
  14022              ) ;case t
  14023             ) ;cond
  14024           ) ;dotimes
  14025         ))) ;let if defun
  14026 
  14027 (defun web-mode-comment-beginning ()
  14028   "Fetch current comment beg."
  14029   (interactive)
  14030   (web-mode-go (web-mode-comment-beginning-position (point))))
  14031 
  14032 (defun web-mode-comment-end ()
  14033   "Fetch current comment end."
  14034   (interactive)
  14035   (web-mode-go (web-mode-comment-end-position (point)) 1))
  14036 
  14037 (defun web-mode-tag-beginning ()
  14038   "Fetch current html tag beg."
  14039   (interactive)
  14040   (web-mode-go (web-mode-tag-beginning-position (point))))
  14041 
  14042 (defun web-mode-tag-end ()
  14043   "Fetch current html tag end."
  14044   (interactive)
  14045   (web-mode-go (web-mode-tag-end-position (point)) 1))
  14046 
  14047 (defun web-mode-tag-previous ()
  14048   "Fetch previous tag."
  14049   (interactive)
  14050   (web-mode-go (web-mode-tag-previous-position (point))))
  14051 
  14052 (defun web-mode-tag-next ()
  14053   "Fetch next tag. Might be html comment or server tag (e.g. jsp)."
  14054   (interactive)
  14055   (web-mode-go (web-mode-tag-next-position (point))))
  14056 
  14057 (defun web-mode-attribute-beginning ()
  14058   "Fetch html attribute beginning."
  14059   (interactive)
  14060   (web-mode-go (web-mode-attribute-beginning-position (point))))
  14061 
  14062 (defun web-mode-attribute-end ()
  14063   "Fetch html attribute end."
  14064   (interactive)
  14065   (web-mode-go (web-mode-attribute-end-position (point)) 1))
  14066 
  14067 (defun web-mode-attribute-next (&optional arg)
  14068   "Fetch next attribute."
  14069   (interactive "p")
  14070   (unless arg (setq arg 1))
  14071   (cond
  14072     ((= arg 1) (web-mode-go (web-mode-attribute-next-position (point))))
  14073     ((< arg 1) (web-mode-element-previous (* arg -1)))
  14074     (t
  14075      (while (>= arg 1)
  14076        (setq arg (1- arg))
  14077        (web-mode-go (web-mode-attribute-next-position (point)))
  14078        )
  14079      )
  14080     )
  14081   )
  14082 
  14083 (defun web-mode-attribute-previous (&optional arg)
  14084   "Fetch previous attribute."
  14085   (interactive "p")
  14086   (unless arg (setq arg 1))
  14087   (unless arg (setq arg 1))
  14088   (cond
  14089     ((= arg 1) (web-mode-go (web-mode-attribute-previous-position (point))))
  14090     ((< arg 1) (web-mode-element-next (* arg -1)))
  14091     (t
  14092      (while (>= arg 1)
  14093        (setq arg (1- arg))
  14094        (web-mode-go (web-mode-attribute-previous-position (point)))
  14095        )
  14096      )
  14097     )
  14098   )
  14099 
  14100 (defun web-mode-element-previous (&optional arg)
  14101   "Fetch previous element."
  14102   (interactive "p")
  14103   (unless arg (setq arg 1))
  14104   (cond
  14105     ((= arg 1) (web-mode-go (web-mode-element-previous-position (point))))
  14106     ((< arg 1) (web-mode-element-next (* arg -1)))
  14107     (t
  14108      (while (>= arg 1)
  14109        (setq arg (1- arg))
  14110        (web-mode-go (web-mode-element-previous-position (point)))
  14111        ) ;while
  14112      ) ;t
  14113     ) ;cond
  14114   )
  14115 
  14116 (defun web-mode-element-next (&optional arg)
  14117   "Fetch next element."
  14118   (interactive "p")
  14119   (unless arg (setq arg 1))
  14120   (cond
  14121     ((= arg 1) (web-mode-go (web-mode-element-next-position (point))))
  14122     ((< arg 1) (web-mode-element-previous (* arg -1)))
  14123     (t
  14124      (while (>= arg 1)
  14125        (setq arg (1- arg))
  14126        (web-mode-go (web-mode-element-next-position (point)))
  14127        ) ;while
  14128      ) ;t
  14129     ) ;cond
  14130   )
  14131 
  14132 (defun web-mode-element-sibling-next ()
  14133   "Fetch next sibling element."
  14134   (interactive)
  14135   (let ((pos (point)))
  14136     (save-excursion
  14137       (cond
  14138         ((not (get-text-property pos 'tag-type))
  14139          (if (and (web-mode-element-parent)
  14140                   (web-mode-tag-match)
  14141                   (web-mode-tag-next)
  14142                   (member (get-text-property (point) 'tag-type) '(start void comment)))
  14143              (setq pos (point))
  14144              (setq pos nil))
  14145          )
  14146         ((member (get-text-property pos 'tag-type) '(start void))
  14147          (if (and (web-mode-tag-match)
  14148                   (web-mode-tag-next)
  14149                   (member (get-text-property (point) 'tag-type) '(start void comment)))
  14150              (setq pos (point))
  14151              (setq pos nil))
  14152          )
  14153         ((and (web-mode-tag-next)
  14154               (member (get-text-property (point) 'tag-type) '(start void comment)))
  14155          (setq pos (point)))
  14156         (t
  14157          (setq pos nil))
  14158         ) ;cond
  14159       ) ;save-excursion
  14160     (web-mode-go pos)))
  14161 
  14162 (defun web-mode-element-sibling-previous ()
  14163   "Fetch previous sibling element."
  14164   (interactive)
  14165   (let ((pos (point)))
  14166     (save-excursion
  14167       (cond
  14168         ((not (get-text-property pos 'tag-type))
  14169          (if (and (web-mode-element-parent)
  14170                   (web-mode-tag-previous)
  14171                   (web-mode-element-beginning))
  14172              (setq pos (point))
  14173              (setq pos nil))
  14174          )
  14175         ((eq (get-text-property pos 'tag-type) 'start)
  14176          (if (and (web-mode-tag-beginning)
  14177                   (web-mode-tag-previous)
  14178                   (web-mode-element-beginning))
  14179              (setq pos (point))
  14180              (setq pos nil))
  14181          )
  14182         ((and (web-mode-element-beginning)
  14183               (web-mode-tag-previous)
  14184               (web-mode-element-beginning))
  14185          (setq pos (point)))
  14186         (t
  14187          (setq pos nil))
  14188         ) ;cond
  14189       ) ;save-excursion
  14190     (web-mode-go pos)))
  14191 
  14192 (defun web-mode-element-beginning ()
  14193   "Move to beginning of element."
  14194   (interactive)
  14195   (web-mode-go (web-mode-element-beginning-position (point))))
  14196 
  14197 (defun web-mode-element-end ()
  14198   "Move to end of element."
  14199   (interactive)
  14200   (web-mode-go (web-mode-element-end-position (point)) 1))
  14201 
  14202 (defun web-mode-element-parent ()
  14203   "Fetch parent element."
  14204   (interactive)
  14205   (web-mode-go (web-mode-element-parent-position (point))))
  14206 
  14207 (defun web-mode-element-child ()
  14208   "Fetch child element."
  14209   (interactive)
  14210   (web-mode-go (web-mode-element-child-position (point))))
  14211 
  14212 (defun web-mode-dom-traverse ()
  14213   "Traverse html dom tree."
  14214   (interactive)
  14215   (cond
  14216     ((web-mode-element-child)
  14217      )
  14218     ((web-mode-element-sibling-next)
  14219      )
  14220     ((and (web-mode-element-parent)
  14221           (not (web-mode-element-sibling-next)))
  14222      (goto-char (point-min)))
  14223     (t
  14224      (goto-char (point-min)))
  14225     ) ;cond
  14226   )
  14227 
  14228 (defun web-mode-closing-paren (limit)
  14229   (let ((pos (web-mode-closing-paren-position (point) limit)))
  14230     (if (or (null pos) (> pos limit))
  14231         nil
  14232         (goto-char pos)
  14233         pos)
  14234     ))
  14235 
  14236 (defun web-mode-part-next ()
  14237   "Move point to the beginning of the next part."
  14238   (interactive)
  14239   (web-mode-go (web-mode-part-next-position (point))))
  14240 
  14241 (defun web-mode-part-beginning ()
  14242   "Move point to the beginning of the current part."
  14243   (interactive)
  14244   (web-mode-go (web-mode-part-beginning-position (point))))
  14245 
  14246 (defun web-mode-part-end ()
  14247   "Move point to the end of the current part."
  14248   (interactive)
  14249   (web-mode-go (web-mode-part-end-position (point)) 1))
  14250 
  14251 (defun web-mode-block-previous ()
  14252   "Move point to the beginning of the previous block."
  14253   (interactive)
  14254   (web-mode-go (web-mode-block-previous-position (point))))
  14255 
  14256 (defun web-mode-block-next ()
  14257   "Move point to the beginning of the next block."
  14258   (interactive)
  14259   (web-mode-go (web-mode-block-next-position (point))))
  14260 
  14261 (defun web-mode-block-beginning ()
  14262   "Move point to the beginning of the current block."
  14263   (interactive)
  14264   (web-mode-go (web-mode-block-beginning-position (point))))
  14265 
  14266 (defun web-mode-block-end ()
  14267   "Move point to the end of the current block."
  14268   (interactive)
  14269   (web-mode-go (web-mode-block-end-position (point)) 1))
  14270 
  14271 (defun web-mode-block-token-beginning ()
  14272   (web-mode-go (web-mode-block-token-beginning-position (point))))
  14273 
  14274 (defun web-mode-block-token-end ()
  14275   (web-mode-go (web-mode-block-token-end-position (point)) 1))
  14276 
  14277 (defun web-mode-part-token-beginning ()
  14278   (web-mode-go (web-mode-part-token-beginning-position (point))))
  14279 
  14280 (defun web-mode-part-token-end ()
  14281   (web-mode-go (web-mode-part-token-end-position (point)) 1))
  14282 
  14283 (defun web-mode-block-opening-paren (limit)
  14284   (web-mode-go (web-mode-block-opening-paren-position (point) limit)))
  14285 
  14286 (defun web-mode-block-string-beginning (&optional pos block-beg)
  14287   (unless pos (setq pos (point)))
  14288   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14289   (web-mode-go (web-mode-block-string-beginning-position pos block-beg)))
  14290 
  14291 (defun web-mode-block-statement-beginning (pos block-beg is-ternary)
  14292   (unless pos (setq pos (point)))
  14293   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14294   (web-mode-go (web-mode-block-statement-beginning-position pos block-beg is-ternary)))
  14295 
  14296 (defun web-mode-block-args-beginning (&optional pos block-beg)
  14297   (unless pos (setq pos (point)))
  14298   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14299   (web-mode-go (web-mode-block-args-beginning-position pos block-beg)))
  14300 
  14301 (defun web-mode-block-calls-beginning (&optional pos block-beg)
  14302   (unless pos (setq pos (point)))
  14303   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  14304   (web-mode-go (web-mode-block-calls-beginning-position pos block-beg)))
  14305 
  14306 (defun web-mode-javascript-string-beginning (&optional pos reg-beg)
  14307   (unless pos (setq pos (point)))
  14308   (unless reg-beg
  14309     (if (get-text-property pos 'block-side)
  14310         (setq reg-beg (web-mode-block-beginning-position pos))
  14311         (setq reg-beg (web-mode-part-beginning-position pos))))
  14312   (web-mode-go (web-mode-javascript-string-beginning-position pos reg-beg)))
  14313 
  14314 (defun web-mode-javascript-statement-beginning (pos reg-beg is-ternary)
  14315   (unless pos (setq pos (point)))
  14316   (unless reg-beg
  14317     (if (get-text-property pos 'block-side)
  14318         (setq reg-beg (web-mode-block-beginning-position pos))
  14319         (setq reg-beg (web-mode-part-beginning-position pos))))
  14320   (web-mode-go (web-mode-javascript-statement-beginning-position pos reg-beg is-ternary)))
  14321 
  14322 (defun web-mode-javascript-args-beginning (&optional pos reg-beg)
  14323   (unless pos (setq pos (point)))
  14324   (unless reg-beg
  14325     (setq reg-beg (if (get-text-property pos 'block-side)
  14326                       (web-mode-block-beginning-position pos)
  14327                       (web-mode-part-beginning-position pos))))
  14328   ;;(message "reg-beg%S" reg-beg)
  14329   (web-mode-go (web-mode-javascript-args-beginning-position pos reg-beg)))
  14330 
  14331 (defun web-mode-javascript-calls-beginning (&optional pos reg-beg)
  14332   (unless pos (setq pos (point)))
  14333   (unless reg-beg
  14334     (if (get-text-property pos 'block-side)
  14335         (setq reg-beg (web-mode-block-beginning-position pos))
  14336         (setq reg-beg (web-mode-part-beginning-position pos))))
  14337   (let (pair)
  14338     (setq pair (web-mode-javascript-calls-beginning-position pos reg-beg))
  14339     (when pair (web-mode-go (car pair)))
  14340     ))
  14341 
  14342 (defun web-mode-go (pos &optional offset)
  14343   (unless offset (setq offset 0))
  14344   (when pos
  14345     (cond
  14346       ((and (> offset 0) (<= (+ pos offset) (point-max)))
  14347        (setq pos (+ pos offset)))
  14348       ((and (< offset 0) (>= (+ pos offset) (point-min)))
  14349        (setq pos (+ pos offset)))
  14350       ) ;cond
  14351     (goto-char pos))
  14352   pos)
  14353 
  14354 ;;---- SEARCH ------------------------------------------------------------------
  14355 
  14356 (defun web-mode-rsf-balanced (regexp-open regexp-close &optional limit noerror)
  14357   (unless noerror (setq noerror t))
  14358   (let ((continue t)
  14359         (level 1)
  14360         (pos (point))
  14361         ret
  14362         (regexp (concat regexp-open "\\|" regexp-close)))
  14363     (while continue
  14364       (setq ret (re-search-forward regexp limit noerror))
  14365       (cond
  14366         ((null ret)
  14367          (setq continue nil)
  14368          )
  14369         (t
  14370          (if (string-match-p regexp-open (match-string-no-properties 0))
  14371              (setq level (1+ level))
  14372              (setq level (1- level)))
  14373          (when (< level 1)
  14374            (setq continue nil)
  14375            )
  14376          ) ;t
  14377         ) ;cond
  14378       ) ;while
  14379     (when (not (= level 0)) (goto-char pos))
  14380     ret))
  14381 
  14382 (defun web-mode-block-sb (expr &optional limit noerror)
  14383   (unless limit (setq limit (web-mode-block-beginning-position (point))))
  14384   (unless noerror (setq noerror t))
  14385   (let ((continue t) ret)
  14386     (while continue
  14387       (setq ret (search-backward expr limit noerror))
  14388       (when (or (null ret)
  14389                 (not (get-text-property (point) 'block-token)))
  14390         (setq continue nil)
  14391         ) ;when
  14392       ) ;while
  14393     ret))
  14394 
  14395 (defun web-mode-block-sf (expr &optional limit noerror)
  14396   (unless limit (setq limit (web-mode-block-end-position (point))))
  14397   (unless noerror (setq noerror t))
  14398   (let ((continue t) ret)
  14399     (while continue
  14400       (setq ret (search-forward expr limit noerror))
  14401       (when (or (null ret)
  14402                 (not (get-text-property (point) 'block-token)))
  14403         (setq continue nil)
  14404         ) ;when
  14405       ) ;while
  14406     ret))
  14407 
  14408 (defun web-mode-block-rsb (regexp &optional limit noerror)
  14409   (unless limit (setq limit (web-mode-block-beginning-position (point))))
  14410   (unless noerror (setq noerror t))
  14411   (let ((continue t) ret)
  14412     (while continue
  14413       (setq ret (re-search-backward regexp limit noerror))
  14414       (when (or (null ret)
  14415                 (not (get-text-property (point) 'block-token)))
  14416         (setq continue nil)
  14417         ) ;when
  14418       ) ;while
  14419     ret))
  14420 
  14421 (defun web-mode-block-rsf (regexp &optional limit noerror)
  14422   (unless limit (setq limit (web-mode-block-end-position (point))))
  14423   (unless noerror (setq noerror t))
  14424   (let ((continue t) ret)
  14425     (while continue
  14426       (setq ret (re-search-forward regexp limit noerror))
  14427       (when (or (null ret)
  14428                 (not (get-text-property (point) 'block-token)))
  14429         (setq continue nil)
  14430         ) ;when
  14431       ) ;while
  14432     ret))
  14433 
  14434 (defun web-mode-part-sb (expr &optional limit noerror)
  14435   (unless limit (setq limit (web-mode-part-beginning-position (point))))
  14436   (unless noerror (setq noerror t))
  14437   (let ((continue t) ret)
  14438     (while continue
  14439       (setq ret (search-backward expr limit noerror))
  14440       (when (or (null ret)
  14441                 (and (not (get-text-property (point) 'part-token))
  14442                      (not (get-text-property (point) 'block-side)))
  14443                 )
  14444         (setq continue nil)
  14445         ) ;when
  14446       ) ;while
  14447     ret))
  14448 
  14449 (defun web-mode-part-sf (expr &optional limit noerror)
  14450   (unless limit (setq limit (web-mode-part-end-position (point))))
  14451   (unless noerror (setq noerror t))
  14452   (let ((continue t) ret)
  14453     (while continue
  14454       (setq ret (search-forward expr limit noerror))
  14455       (when (or (null ret)
  14456                 (and (not (get-text-property (point) 'part-token))
  14457                      (not (get-text-property (point) 'block-side)))
  14458                 )
  14459         (setq continue nil)
  14460         ) ;when
  14461       ) ;while
  14462     ret))
  14463 
  14464 (defun web-mode-part-rsb (regexp &optional limit noerror)
  14465   (unless limit (setq limit (web-mode-part-beginning-position (point))))
  14466   (unless noerror (setq noerror t))
  14467   (let ((continue t) ret)
  14468     (while continue
  14469       (setq ret (re-search-backward regexp limit noerror))
  14470       (when (or (null ret)
  14471                 (and (not (get-text-property (point) 'part-token))
  14472                      (not (get-text-property (point) 'block-side)))
  14473                 )
  14474         (setq continue nil)
  14475         ) ;when
  14476       ) ;while
  14477     ret))
  14478 
  14479 (defun web-mode-part-rsf (regexp &optional limit noerror)
  14480   (unless limit (setq limit (web-mode-part-end-position (point))))
  14481   (unless noerror (setq noerror t))
  14482   (let ((continue t) ret)
  14483     (while continue
  14484       (setq ret (re-search-forward regexp limit t))
  14485       (when (or (null ret)
  14486                 (and (not (get-text-property (point) 'part-token))
  14487                      (not (get-text-property (point) 'block-side)))
  14488                 )
  14489         (setq continue nil)
  14490         ) ;when
  14491       ) ;while
  14492     ret))
  14493 
  14494 (defun web-mode-javascript-rsb (regexp &optional limit noerror)
  14495   (unless limit (setq limit (web-mode-part-beginning-position (point))))
  14496   (unless noerror (setq noerror t))
  14497   (let ((continue t) ret)
  14498     (while continue
  14499       (setq ret (re-search-backward regexp limit noerror))
  14500       (when (or (null ret)
  14501                 (and (not (get-text-property (point) 'part-token))
  14502                      (not (get-text-property (point) 'block-side))
  14503                      (not (get-text-property (point) 'jsx-depth)))
  14504                 )
  14505         (setq continue nil)
  14506         ) ;when
  14507       ) ;while
  14508     ret))
  14509 
  14510 (defun web-mode-javascript-rsf (regexp &optional limit noerror)
  14511   (unless limit (setq limit (web-mode-part-end-position (point))))
  14512   (unless noerror (setq noerror t))
  14513   (let ((continue t) ret)
  14514     (while continue
  14515       (setq ret (re-search-forward regexp limit t))
  14516       (when (or (null ret)
  14517                 (and (not (get-text-property (point) 'part-token))
  14518                      (not (get-text-property (point) 'block-side))
  14519                      (not (get-text-property (point) 'jsx-depth)))
  14520                 )
  14521         (setq continue nil)
  14522         ) ;when
  14523       ) ;while
  14524     ret))
  14525 
  14526 (defun web-mode-dom-sf (expr &optional limit noerror)
  14527   (unless noerror (setq noerror t))
  14528   (let ((continue t) ret)
  14529     (while continue
  14530       (setq ret (search-forward expr limit noerror))
  14531       (if (or (null ret)
  14532               (not (get-text-property (- (point) (length expr)) 'block-side)))
  14533           (setq continue nil))
  14534       )
  14535     ret))
  14536 
  14537 (defun web-mode-dom-rsf (regexp &optional limit noerror)
  14538   (unless noerror (setq noerror t))
  14539   (let ((continue t) (ret nil))
  14540     (while continue
  14541       (setq ret (re-search-forward regexp limit noerror))
  14542       ;;      (message "ret=%S point=%S limit=%S i=%S" ret (point) limit 0)
  14543       (cond
  14544         ((null ret)
  14545          (setq continue nil))
  14546         ((or (get-text-property (match-beginning 0) 'block-side)
  14547              (get-text-property (match-beginning 0) 'part-token))
  14548          )
  14549         (t
  14550          (setq continue nil))
  14551         ) ;cond
  14552       ) ;while
  14553     ret))
  14554 
  14555 (defun web-mode-rsb-position (pos regexp &optional limit noerror)
  14556   (unless noerror (setq noerror t))
  14557   (save-excursion
  14558     (goto-char pos)
  14559     (if (re-search-backward regexp limit noerror) (point) nil)
  14560     ))
  14561 
  14562 (defun web-mode-rsb (regexp &optional limit noerror)
  14563   (unless noerror (setq noerror t))
  14564   (let ((continue t) ret)
  14565     (while continue
  14566       (setq ret (re-search-backward regexp limit noerror))
  14567       (if (or (null ret)
  14568               (not (web-mode-is-comment-or-string)))
  14569           (setq continue nil)))
  14570     ret))
  14571 
  14572 (defun web-mode-rsf (regexp &optional limit noerror)
  14573   (unless noerror (setq noerror t))
  14574   (let ((continue t) ret)
  14575     (while continue
  14576       (setq ret (re-search-forward regexp limit noerror))
  14577       (if (or (null ret)
  14578               (not (web-mode-is-comment-or-string)))
  14579           (setq continue nil))
  14580       )
  14581     ret))
  14582 
  14583 (defun web-mode-sb (expr &optional limit noerror)
  14584   (unless noerror (setq noerror t))
  14585   (let ((continue t) ret)
  14586     (while continue
  14587       (setq ret (search-backward expr limit noerror))
  14588       (if (or (null ret)
  14589               (not (web-mode-is-comment-or-string)))
  14590           (setq continue nil)))
  14591     ret))
  14592 
  14593 (defun web-mode-sf (expr &optional limit noerror)
  14594   (unless noerror (setq noerror t))
  14595   (let ((continue t) ret)
  14596     (while continue
  14597       (setq ret (search-forward expr limit noerror))
  14598       (if (or (null ret)
  14599               (not (web-mode-is-comment-or-string)))
  14600           (setq continue nil)))
  14601     ret))
  14602 
  14603 (defun web-mode-content-rsf (regexp &optional limit noerror)
  14604   (unless noerror (setq noerror t))
  14605   (let ((continue t) ret beg end)
  14606     (while continue
  14607       (setq ret (re-search-forward regexp limit noerror)
  14608             beg (if (null ret) (point) (match-beginning 0))
  14609             end (if (null ret) (point) (1- (match-end 0))))
  14610       (if (or (null ret)
  14611               (and (web-mode-is-content beg)
  14612                    (web-mode-is-content end)))
  14613           (setq continue nil)))
  14614     ret))
  14615 
  14616 ;;---- ADVICES -----------------------------------------------------------------
  14617 
  14618 (defadvice ac-start (before web-mode-set-up-ac-sources activate)
  14619   "Set `ac-sources' based on current language before running auto-complete."
  14620   (when (equal major-mode 'web-mode)
  14621     ;; set ignore each time to nil. User has to implement a hook to change it
  14622     ;; for each completion
  14623     (setq web-mode-ignore-ac-start-advice nil)
  14624     (run-hooks 'web-mode-before-auto-complete-hooks)
  14625     (unless web-mode-ignore-ac-start-advice
  14626       (when web-mode-ac-sources-alist
  14627         (let ((new-web-mode-ac-sources
  14628                (assoc (web-mode-language-at-pos)
  14629                       web-mode-ac-sources-alist)))
  14630           (setq ac-sources (cdr new-web-mode-ac-sources)))))))
  14631 
  14632 ;;---- MINOR MODE ADDONS -------------------------------------------------------
  14633 
  14634 (defun web-mode-yasnippet-exit-hook ()
  14635   "Yasnippet exit hook"
  14636   (when (and (boundp 'yas-snippet-beg) (boundp 'yas-snippet-end))
  14637     (indent-region yas-snippet-beg yas-snippet-end)))
  14638 
  14639 (defun web-mode-imenu-index ()
  14640   "Returns imenu items."
  14641   (interactive)
  14642   (let (toc-index
  14643         line)
  14644     (save-excursion
  14645       (goto-char (point-min))
  14646       (while (not (eobp))
  14647         (setq line (buffer-substring-no-properties
  14648                     (line-beginning-position)
  14649                     (line-end-position)))
  14650         (let (found
  14651               (i 0)
  14652               item
  14653               regexp
  14654               type
  14655               type-idx
  14656               content
  14657               content-idx
  14658               content-regexp
  14659               close-tag-regexp
  14660               concat-str
  14661               jumpto
  14662               str)
  14663           (while (and (not found ) (< i (length web-mode-imenu-regexp-list)))
  14664             (setq item (nth i web-mode-imenu-regexp-list))
  14665             (setq regexp (nth 0 item))
  14666             (setq type-idx (nth 1 item))
  14667             (setq content-idx (nth 2 item))
  14668             (setq concat-str (nth 3 item))
  14669             (when (not (numberp content-idx))
  14670               (setq content-regexp (nth 2 item)
  14671                     close-tag-regexp (nth 4 item)
  14672                     content-idx nil))
  14673 
  14674             (when (string-match regexp line)
  14675 
  14676               (cond
  14677                 (content-idx
  14678                  (setq type (match-string type-idx line))
  14679                  (setq content (match-string content-idx line))
  14680                  (setq str (concat type concat-str content))
  14681                  (setq jumpto (line-beginning-position)))
  14682                 (t
  14683                  (let (limit)
  14684                    (setq type (match-string type-idx line))
  14685                    (goto-char (line-beginning-position))
  14686                    (save-excursion
  14687                      (setq limit (re-search-forward close-tag-regexp (point-max) t)))
  14688 
  14689                    (when limit
  14690                      (when (re-search-forward content-regexp limit t)
  14691                        (setq content (match-string 1))
  14692                        (setq str (concat type concat-str content))
  14693                        (setq jumpto (line-beginning-position))
  14694                        )
  14695                      )))
  14696                 )
  14697               (when str (setq toc-index
  14698                               (cons (cons str jumpto)
  14699                                     toc-index)
  14700                               )
  14701                     (setq found t))
  14702               )
  14703             (setq i (1+ i))))
  14704         (forward-line)
  14705         (goto-char (line-end-position)) ;; make sure we are at eobp
  14706         ))
  14707     (nreverse toc-index)))
  14708 
  14709 ;;---- UNIT TESTING ------------------------------------------------------------
  14710 
  14711 (defun web-mode-test ()
  14712   "Executes web-mode unit tests. See `web-mode-tests-directory'."
  14713   (interactive)
  14714   (let (files regexp)
  14715     (setq regexp "^[[:alnum:]][[:alnum:]._]+\\'")
  14716     (setq files (directory-files web-mode-tests-directory t regexp))
  14717     (dolist (file files)
  14718       (cond
  14719         ((eq (string-to-char (file-name-nondirectory file)) ?\_)
  14720          (delete-file file))
  14721         (t
  14722          (web-mode-test-process file))
  14723         ) ;cond
  14724       ) ;dolist
  14725     ))
  14726 
  14727 (defun web-mode-test-process (file)
  14728   (with-temp-buffer
  14729     (let (out sig1 sig2 success err)
  14730       (setq-default indent-tabs-mode nil)
  14731       (if (string-match-p "sql" file)
  14732           (setq web-mode-enable-sql-detection t)
  14733           (setq web-mode-enable-sql-detection nil))
  14734       (insert-file-contents file)
  14735       (set-visited-file-name file)
  14736       (web-mode)
  14737       (setq sig1 (md5 (current-buffer)))
  14738       (delete-horizontal-space)
  14739       (while (not (eobp))
  14740         (forward-line)
  14741         (delete-horizontal-space)
  14742         (end-of-line))
  14743       (web-mode-buffer-indent)
  14744       (setq sig2 (md5 (current-buffer)))
  14745       (setq success (string= sig1 sig2))
  14746       (setq out (concat (if success "ok" "ko") " : " (file-name-nondirectory file) "\n"))
  14747       (princ out)
  14748       (setq err (concat (file-name-directory file) "_err." (file-name-nondirectory file)))
  14749       (if success
  14750           (when (file-readable-p err)
  14751             (delete-file err))
  14752           (write-file err)
  14753           (message "[%s]" (buffer-string))
  14754           ) ;if
  14755       out)))
  14756 
  14757 ;;---- MISC --------------------------------------------------------------------
  14758 
  14759 (defun web-mode-set-engine (engine)
  14760   "Set the engine for the current buffer."
  14761   (interactive
  14762    (list (completing-read
  14763           "Engine: "
  14764           (let (engines)
  14765             (dolist (elt web-mode-engines)
  14766               (setq engines (append engines (list (car elt)))))
  14767             engines))))
  14768   (setq web-mode-content-type "html"
  14769         web-mode-engine (web-mode-engine-canonical-name engine)
  14770         web-mode-minor-engine engine)
  14771   (web-mode-on-engine-setted)
  14772   (web-mode-buffer-fontify))
  14773 
  14774 (defun web-mode-set-content-type (content-type)
  14775   "Set the content-type for the current buffer"
  14776   (interactive (list (completing-read "Content-type: " web-mode-part-content-types)))
  14777   (setq web-mode-content-type content-type)
  14778   (when (called-interactively-p 'any)
  14779     )
  14780   (web-mode-buffer-fontify))
  14781 
  14782 (defun web-mode-on-engine-setted ()
  14783   (let (elt elts)
  14784 
  14785     (when (string= web-mode-engine "razor") (setq web-mode-enable-block-face t))
  14786     ;;(setq web-mode-engine-attr-regexp (cdr (assoc web-mode-engine web-mode-engine-attr-regexps)))
  14787     (setq web-mode-engine-token-regexp (cdr (assoc web-mode-engine web-mode-engine-token-regexps)))
  14788 
  14789     ;;(message "%S %S %S" web-mode-engine web-mode-engine-attr-regexp web-mode-engine-token-regexp)
  14790 
  14791     (when (null web-mode-minor-engine)
  14792       (setq web-mode-minor-engine "none"))
  14793 
  14794     (setq elt (assoc web-mode-engine web-mode-engine-open-delimiter-regexps))
  14795     (cond
  14796       (elt
  14797        (setq web-mode-block-regexp (cdr elt)))
  14798       ((string= web-mode-engine "archibus")
  14799        (setq web-mode-block-regexp nil))
  14800       (t
  14801        (setq web-mode-engine "none"))
  14802       )
  14803 
  14804     (unless (boundp 'web-mode-extra-auto-pairs)
  14805       (setq web-mode-extra-auto-pairs nil))
  14806 
  14807     (setq web-mode-auto-pairs
  14808           (append
  14809            (cdr (assoc web-mode-engine web-mode-engines-auto-pairs))
  14810            (cdr (assoc nil web-mode-engines-auto-pairs))
  14811            (cdr (assoc web-mode-engine web-mode-extra-auto-pairs))
  14812            (cdr (assoc nil web-mode-extra-auto-pairs))))
  14813 
  14814     (unless (boundp 'web-mode-extra-snippets)
  14815       (setq web-mode-extra-snippets nil))
  14816 
  14817     (setq elts
  14818           (append
  14819            (cdr (assoc web-mode-engine web-mode-extra-snippets))
  14820            (cdr (assoc nil             web-mode-extra-snippets))
  14821            (cdr (assoc web-mode-engine web-mode-engines-snippets))
  14822            (cdr (assoc nil             web-mode-engines-snippets))))
  14823 
  14824     ;;(message "%S" elts)
  14825 
  14826     (dolist (elt elts)
  14827       (unless (assoc (car elt) web-mode-snippets)
  14828         (setq web-mode-snippets (cons elt web-mode-snippets)))
  14829       )
  14830 
  14831     (setq web-mode-engine-font-lock-keywords
  14832           (symbol-value (cdr (assoc web-mode-engine web-mode-engines-font-lock-keywords))))
  14833 
  14834     (when (and (string= web-mode-minor-engine "jinja")
  14835                (not (member "endtrans" web-mode-django-control-blocks)))
  14836       (add-to-list 'web-mode-django-control-blocks "endtrans")
  14837       (setq web-mode-django-control-blocks-regexp
  14838             (regexp-opt web-mode-django-control-blocks t))
  14839       )
  14840 
  14841     (when (string= web-mode-engine "spip")
  14842       (modify-syntax-entry ?# "w" (syntax-table)))
  14843 
  14844     ;;(message "%S" (symbol-value (cdr (assoc web-mode-engine web-mode-engines-font-lock-keywords))))
  14845 
  14846     ))
  14847 
  14848 (defun web-mode-detect-engine ()
  14849   (save-excursion
  14850     (goto-char (point-min))
  14851     (when (re-search-forward "-\\*- engine:[ ]*\\([[:alnum:]-]+\\)[ ]*-\\*-" web-mode-chunk-length t)
  14852       (setq web-mode-minor-engine (match-string-no-properties 1))
  14853       (setq web-mode-engine (web-mode-engine-canonical-name web-mode-minor-engine)))
  14854     web-mode-minor-engine))
  14855 
  14856 (defun web-mode-guess-engine-and-content-type ()
  14857   (let (buff-name found)
  14858 
  14859     (setq buff-name (buffer-file-name))
  14860     (unless buff-name (setq buff-name (buffer-name)))
  14861     (setq web-mode-is-scratch (string= buff-name "*scratch*"))
  14862     (setq web-mode-content-type nil)
  14863 
  14864     (when (boundp 'web-mode-content-types-alist)
  14865       (setq found nil)
  14866       (dolist (elt web-mode-content-types-alist)
  14867         (when (and (not found) (string-match-p (cdr elt) buff-name))
  14868           (setq web-mode-content-type (car elt)
  14869                 found t))
  14870         ) ;dolist
  14871       ) ;when
  14872 
  14873     (unless web-mode-content-type
  14874       (setq found nil)
  14875       (dolist (elt web-mode-content-types)
  14876         (when (and (not found) (string-match-p (cdr elt) buff-name))
  14877           (setq web-mode-content-type (car elt)
  14878                 found t)
  14879           ;;(message "%S" web-mode-content-type)
  14880           ) ;when
  14881         ) ;dolist
  14882       ) ;unless
  14883 
  14884     (when (boundp 'web-mode-engines-alist)
  14885       (setq found nil)
  14886       (dolist (elt web-mode-engines-alist)
  14887         (cond
  14888           ((stringp (cdr elt))
  14889            (when (string-match-p (cdr elt) buff-name)
  14890              (setq web-mode-engine (car elt))))
  14891           ((functionp (cdr elt))
  14892            (when (funcall (cdr elt))
  14893              (setq web-mode-engine (car elt))))
  14894           ) ;cond
  14895         ) ;dolist
  14896       ) ;when
  14897 
  14898     (unless web-mode-engine
  14899       (setq found nil)
  14900       (dolist (elt web-mode-engine-file-regexps)
  14901         ;;(message "%S %S %S" (cdr elt) (car elt) buff-name)
  14902         (when (and (not found) (string-match-p (cdr elt) buff-name))
  14903           ;;(message "%S %S %S" (cdr elt) (car elt) buff-name)
  14904           (setq web-mode-engine (car elt)
  14905                 found t)
  14906           ;;(when (and web-mode-engine (string= web-mode-engine "astro"))
  14907           ;;  (setq web-mode-enable-front-matter-block t)
  14908           ;;) ;when
  14909           ) ;when
  14910         )
  14911       )
  14912 
  14913     (when (and (or (null web-mode-engine) (string= web-mode-engine "none"))
  14914                (string-match-p "php" (buffer-substring-no-properties
  14915                                       (line-beginning-position)
  14916                                       (line-end-position))))
  14917       (setq web-mode-engine "php"))
  14918 
  14919     (when (and (string= web-mode-content-type "javascript")
  14920                (string-match-p "@jsx"
  14921                                (buffer-substring-no-properties
  14922                                 (point-min)
  14923                                 (if (< (point-max) web-mode-chunk-length)
  14924                                     (point-max)
  14925                                     web-mode-chunk-length)
  14926                                 )))
  14927       (setq web-mode-content-type "jsx"))
  14928 
  14929     (when web-mode-engine
  14930       (setq web-mode-minor-engine web-mode-engine
  14931             web-mode-engine (web-mode-engine-canonical-name web-mode-engine))
  14932       )
  14933 
  14934     ;;(message "%S %S" web-mode-engine web-mode-enable-engine-detection)
  14935 
  14936     (when (and (or (null web-mode-engine)
  14937                    (string= web-mode-engine "none"))
  14938                web-mode-enable-engine-detection)
  14939       (web-mode-detect-engine))
  14940 
  14941     (web-mode-on-engine-setted)
  14942 
  14943     ))
  14944 
  14945 (defun web-mode-engine-canonical-name (name)
  14946   (let (engine)
  14947     (cond
  14948       ((null name)
  14949        nil)
  14950       ((assoc name web-mode-engines)
  14951        name)
  14952       (t
  14953        (dolist (elt web-mode-engines)
  14954          (when (and (null engine) (member name (cdr elt)))
  14955            (setq engine (car elt)))
  14956          ) ;dolist
  14957        engine)
  14958       )))
  14959 
  14960 (defun web-mode-on-after-save ()
  14961   (when web-mode-is-scratch
  14962     (web-mode-guess-engine-and-content-type)
  14963     (web-mode-buffer-fontify))
  14964   nil)
  14965 
  14966 (defun web-mode-on-exit ()
  14967   (web-mode-with-silent-modifications
  14968    (put-text-property (point-min) (point-max) 'invisible nil)
  14969    (remove-overlays)
  14970    (remove-hook 'change-major-mode-hook 'web-mode-on-exit t)
  14971    ))
  14972 
  14973 (defun web-mode-file-link (file)
  14974   "Insert a link to a file in html document. This function can be
  14975 extended to support more filetypes by customizing
  14976 `web-mode-links'."
  14977   (interactive
  14978    (list (file-relative-name (read-file-name "Link file: "))))
  14979   (let ((matched nil)
  14980         (point-line (line-number-at-pos))
  14981         (point-column (current-column)))
  14982     (dolist (type web-mode-links)
  14983       (when (string-match (car type) file)
  14984         (setq matched t)
  14985         (when (nth 2 type)
  14986           (goto-char (point-min))
  14987           (search-forward "</head>")
  14988           (backward-char 7)
  14989           (open-line 1))
  14990         (insert (format (cadr type) file))
  14991         (indent-for-tab-command)
  14992         (when (nth 2 type)
  14993           ;; return point where it was and fix indentation
  14994           (forward-line)
  14995           (indent-for-tab-command)
  14996           (if (> point-line (- (line-number-at-pos) 2))
  14997               (forward-line (+ (- point-line (line-number-at-pos)) 1))
  14998               (forward-line (- point-line (line-number-at-pos))))
  14999           (move-to-column point-column))
  15000         ;; move point back if needed
  15001         (backward-char (nth 3 type))))
  15002     (when (not matched)
  15003       (user-error "Unknown file type"))))
  15004 
  15005 (defun web-mode-reload ()
  15006   "Reload web-mode."
  15007   (interactive)
  15008   (web-mode-with-silent-modifications
  15009    (put-text-property (point-min) (point-max) 'invisible nil)
  15010    (remove-overlays)
  15011    (setq font-lock-unfontify-region-function 'font-lock-default-unfontify-region)
  15012    (load "web-mode.el")
  15013    (setq web-mode-change-beg nil
  15014          web-mode-change-end nil)
  15015    (web-mode)
  15016    ))
  15017 
  15018 (defun web-mode-measure (msg)
  15019   (let (sub)
  15020     (when (null web-mode-time) (setq web-mode-time (current-time)))
  15021     (setq sub (time-subtract (current-time) web-mode-time))
  15022     (when nil
  15023       (save-excursion
  15024         (let ((n 0))
  15025           (goto-char (point-min))
  15026           (while (web-mode-tag-next)
  15027             (setq n (1+ n))
  15028             )
  15029           (message "%S tags found" n)
  15030           )))
  15031     (message "%18s: time elapsed = %Ss %9Sµs" msg (nth 1 sub) (nth 2 sub))
  15032     ))
  15033 
  15034 (defun web-mode-reveal ()
  15035   "Display text properties at point."
  15036   (interactive)
  15037   (let (symbols out)
  15038     (setq out (format
  15039                "[point=%S engine=%S minor=%S content-type=%S language-at-pos=%S]\n"
  15040                (point)
  15041                web-mode-engine
  15042                web-mode-minor-engine
  15043                web-mode-content-type
  15044                (web-mode-language-at-pos (point))))
  15045     (setq symbols (append web-mode-scan-properties '(font-lock-face face)))
  15046     (dolist (symbol symbols)
  15047       (when symbol
  15048         (setq out (concat out (format "%s(%S) " (symbol-name symbol) (get-text-property (point) symbol)))))
  15049       )
  15050     (message "%s\n" out)
  15051     ;;(message "syntax-class=%S" (syntax-class (syntax-after (point))))
  15052     (message nil)))
  15053 
  15054 (defun web-mode-toggle-tracing ()
  15055   "Toggle tracing."
  15056   (interactive)
  15057   (if web-mode-trace
  15058       (setq web-mode-trace nil)
  15059       (message "** tracing on ** point(%S) web-mode-change-beg(%S) web-mode-change-end(%S) web-mode-skip-fontification(%S)"
  15060                (point) web-mode-change-beg web-mode-change-end web-mode-skip-fontification)
  15061       (setq web-mode-trace t)))
  15062 
  15063 (defun web-mode-debug ()
  15064   "Display informations useful for debugging."
  15065   (interactive)
  15066   (let ((modes nil)
  15067         (customs '(web-mode-enable-current-column-highlight web-mode-enable-current-element-highlight indent-tabs-mode))
  15068         (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)))
  15069     (message "\n")
  15070     (message "--- WEB-MODE DEBUG BEG ---")
  15071     (message "versions: emacs(%S.%S) web-mode(%S)"
  15072              emacs-major-version emacs-minor-version web-mode-version)
  15073     (message "vars: engine(%S) minor(%S) content-type(%S) file(%S)"
  15074              web-mode-engine
  15075              web-mode-minor-engine
  15076              web-mode-content-type
  15077              (or (buffer-file-name) (buffer-name)))
  15078     (message "system: window(%S) config(%S)" window-system system-configuration)
  15079     (message "colors: fg(%S) bg(%S) "
  15080              (cdr (assoc 'foreground-color default-frame-alist))
  15081              (cdr (assoc 'background-color default-frame-alist)))
  15082     (mapc (lambda (mode)
  15083             (condition-case nil
  15084                 (if (and (symbolp mode) (symbol-value mode) (not (member mode ignore)))
  15085                     (push mode modes))
  15086               (error nil))
  15087             ) ;lambda
  15088           minor-mode-list)
  15089     (message "minor modes: %S" modes)
  15090     (message "vars:")
  15091     (dolist (custom customs)
  15092       (message (format "%s=%S " (symbol-name custom) (symbol-value custom))))
  15093     (message "--- WEB-MODE DEBUG END ---")
  15094     (switch-to-buffer "*Messages*")
  15095     (goto-char (point-max))
  15096     (recenter)
  15097     ))
  15098 
  15099 (provide 'web-mode)
  15100 
  15101 ;;; web-mode.el ends here
  15102 
  15103 ;; Local Variables:
  15104 ;; coding: utf-8
  15105 ;; indent-tabs-mode: nil
  15106 ;; sentence-end-double-space: nil
  15107 ;; End: