dotemacs

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

web-mode.el (561693B)


      1 ;;; web-mode.el --- major mode for editing web templates -*- coding: utf-8; lexical-binding: t; -*-
      2 
      3 ;; Copyright 2011-2022 François-Xavier Bois
      4 
      5 ;; Version: 17.3.1
      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.1"
     27   "Web Mode version.")
     28 
     29 ;;---- GROUPS ------------------------------------------------------------------
     30 
     31 (defgroup web-mode nil
     32   "Major mode for editing web templates"
     33   :group 'languages
     34   :prefix "web-"
     35   :link '(url-link :tag "Site" "https://web-mode.org")
     36   :link '(url-link :tag "Repository" "https://github.com/fxbois/web-mode"))
     37 
     38 (defgroup web-mode-faces nil
     39   "Faces for syntax highlighting."
     40   :group 'web-mode
     41   :group 'faces)
     42 
     43 ;;---- CUSTOMS -----------------------------------------------------------------
     44 
     45 (defcustom web-mode-block-padding 0
     46   "Multi-line block (php, ruby, java, python, asp, etc.) left padding.
     47    -1 to have to code aligned on the column 0."
     48   :type '(choice (integer :tags "Number of spaces")
     49                  (const :tags "No indent" nil))
     50   :group 'web-mode)
     51 
     52 (defcustom web-mode-part-padding 1
     53   "Part elements (script, style) left padding."
     54   :type '(choice (integer :tags "Number of spaces")
     55                  (const :tags "No indent" nil))
     56   :group 'web-mode)
     57 
     58 (defcustom web-mode-script-padding web-mode-part-padding
     59   "Script element left padding."
     60   :type '(choice (integer :tags "Number of spaces")
     61                  (const :tags "No indent" nil))
     62   :group 'web-mode)
     63 
     64 (defcustom web-mode-style-padding web-mode-part-padding
     65   "Style element left padding."
     66   :type '(choice (integer :tags "Number of spaces")
     67                  (const :tags "No indent" nil))
     68   :group 'web-mode)
     69 
     70 (defcustom web-mode-attr-indent-offset nil
     71   "Html attribute indentation level."
     72   :type '(choice (integer :tags "Number of spaces")
     73                  (const :tags "Default" nil))
     74   :safe #'(lambda (v) (or (integerp v) (booleanp v)))
     75   :group 'web-mode)
     76 
     77 (defcustom web-mode-attr-value-indent-offset nil
     78   "Html attribute value indentation level."
     79   :type '(choice (integer :tags "Number of spaces")
     80                  (const :tags "Default" nil))
     81   :safe #'(lambda (v) (or (integerp v) (booleanp v)))
     82   :group 'web-mode)
     83 
     84 (defcustom web-mode-markup-indent-offset
     85   (if (and (boundp 'standard-indent) standard-indent) standard-indent 2)
     86   "Html indentation level."
     87   :type 'integer
     88   :safe #'integerp
     89   :group 'web-mode)
     90 
     91 (defcustom web-mode-css-indent-offset
     92   (if (and (boundp 'standard-indent) standard-indent) standard-indent 2)
     93   "CSS indentation level."
     94   :type 'integer
     95   :safe #'integerp
     96   :group 'web-mode)
     97 
     98 (defcustom web-mode-code-indent-offset
     99   (if (and (boundp 'standard-indent) standard-indent) standard-indent 2)
    100   "Code (javascript, php, etc.) indentation level."
    101   :type 'integer
    102   :safe #'integerp
    103   :group 'web-mode)
    104 
    105 (defcustom web-mode-sql-indent-offset 4
    106   "Sql (inside strings) indentation level."
    107   :type 'integer
    108   :safe #'integerp
    109   :group 'web-mode)
    110 
    111 (defcustom web-mode-enable-css-colorization (display-graphic-p)
    112   "In a CSS part, set background according to the color: #xxx, rgb(x,x,x)."
    113   :type 'boolean
    114   :group 'web-mode)
    115 
    116 (defcustom web-mode-enable-comment-interpolation nil
    117   "Enable highlight of keywords like FIXME, TODO, etc. in comments."
    118   :type 'boolean
    119   :group 'web-mode)
    120 
    121 (defcustom web-mode-enable-comment-annotation nil
    122   "Enable annotation in comments (jsdoc, phpdoc, etc.)."
    123   :type 'boolean
    124   :group 'web-mode)
    125 
    126 (defcustom web-mode-enable-auto-indentation (display-graphic-p)
    127   "Auto-indentation."
    128   :type 'boolean
    129   :group 'web-mode)
    130 
    131 (defcustom web-mode-enable-auto-closing (display-graphic-p)
    132   "Auto-closing."
    133   :type 'boolean
    134   :group 'web-mode)
    135 
    136 (defcustom web-mode-enable-auto-pairing (display-graphic-p)
    137   "Auto-pairing."
    138   :type 'boolean
    139   :group 'web-mode)
    140 
    141 (defcustom web-mode-enable-auto-opening (display-graphic-p)
    142   "Html element auto-opening."
    143   :type 'boolean
    144   :group 'web-mode)
    145 
    146 (defcustom web-mode-enable-auto-quoting (display-graphic-p)
    147   "Add double quotes after the character = in a tag."
    148   :type 'boolean
    149   :group 'web-mode)
    150 
    151 (defcustom web-mode-enable-auto-expanding nil
    152   "e.g. s/ expands to <span>|</span>."
    153   :type 'boolean
    154   :group 'web-mode)
    155 
    156 (defcustom web-mode-enable-curly-brace-indentation nil
    157   "Indent lines beginning with {."
    158   :type 'boolean
    159   :group 'web-mode)
    160 
    161 (defcustom web-mode-enable-control-block-indentation t
    162   "Control blocks increase indentation."
    163   :type 'boolean
    164   :group 'web-mode)
    165 
    166 (defcustom web-mode-enable-current-element-highlight nil
    167   "Enable current element highlight."
    168   :type 'boolean
    169   :group 'web-mode)
    170 
    171 (defcustom web-mode-enable-current-column-highlight nil
    172   "Show column for current element."
    173   :type 'boolean
    174   :group 'web-mode)
    175 
    176 (defcustom web-mode-enable-whitespace-fontification nil
    177   "Enable whitespaces."
    178   :type 'boolean
    179   :group 'web-mode)
    180 
    181 (defcustom web-mode-enable-html-entities-fontification nil
    182   "Enable html entities fontification."
    183   :type 'boolean
    184   :group 'web-mode)
    185 
    186 (defcustom web-mode-enable-block-face nil
    187   "Enable block face (useful for setting a background for example).
    188 See web-mode-block-face."
    189   :type 'boolean
    190   :group 'web-mode)
    191 
    192 (defcustom web-mode-enable-part-face nil
    193   "Enable part face (useful for setting background of <style> or <script>
    194  elements for example). See web-mode-part-face."
    195   :type 'boolean
    196   :group 'web-mode)
    197 
    198 (defcustom web-mode-enable-inlays nil
    199   "Enable inlays (e.g. LaTeX) highlighting."
    200   :type 'boolean
    201   :group 'web-mode)
    202 
    203 (defcustom web-mode-enable-sexp-functions t
    204   "Enable specific sexp functions."
    205   :type 'boolean
    206   :group 'web-mode)
    207 
    208 (defcustom web-mode-enable-string-interpolation t
    209   "Enable string interpolation fontification (php and erb)."
    210   :type 'boolean
    211   :group 'web-mode)
    212 
    213 (defcustom web-mode-enable-literal-interpolation t
    214   "Enable template literal fontification. e.g. css` `."
    215   :type 'boolean
    216   :group 'web-mode)
    217 
    218 (defcustom web-mode-enable-sql-detection nil
    219   "Enable fontification and indentation of sql queries in strings."
    220   :type 'boolean
    221   :group 'web-mode)
    222 
    223 (defcustom web-mode-enable-heredoc-fontification t
    224   "Enable heredoc fontification. The identifier should contain JS, JAVASCRIPT, CSS or HTML."
    225   :type 'boolean
    226   :group 'web-mode)
    227 
    228 (defcustom web-mode-enable-element-content-fontification nil
    229   "Enable element content fontification. The content of an element can have a face associated."
    230   :type 'boolean
    231   :group 'web-mode)
    232 
    233 (defcustom web-mode-enable-element-tag-fontification nil
    234   "Enable tag name fontification."
    235   :type 'boolean
    236   :group 'web-mode)
    237 
    238 (defcustom web-mode-enable-front-matter-block nil
    239   "Enable front matter block (data at the beginning the template between --- and ---)."
    240   :type 'boolean
    241   :group 'web-mode)
    242 
    243 (defcustom web-mode-enable-engine-detection nil
    244   "Detect such directive -*- engine: ENGINE -*- at the top of the file."
    245   :type 'boolean
    246   :group 'web-mode)
    247 
    248 (defcustom web-mode-enable-optional-tags nil
    249   "Enable omission of certain closing tags (e.g. a li open tag followed by a li open tag is valid)."
    250   :type 'boolean
    251   :group 'web-mode)
    252 
    253 (defcustom web-mode-comment-style 1
    254   "Comment style : 1 = default, 2 = force server comments outside a block."
    255   :group 'web-mode
    256   :type '(choice (const :tag "Default" 1)
    257                  (const :tag "Force engine comments" 2)))
    258 
    259 (defcustom web-mode-indent-style 2
    260   "Indentation style."
    261   :group 'web-mode
    262   :type '(choice (const :tag "Default (all lines are indented)" 2)
    263                  (const :tag "Text at the beginning of line is not indented" 1)))
    264 
    265 (defcustom web-mode-auto-close-style 1
    266   "Auto-close style."
    267   :group 'web-mode
    268   :type '(choice (const :tag "Auto-close on </" 1)
    269                  (const :tag "Auto-close on > and </" 2)
    270                  (const :tag "Auto-close on < and >/>" 3)))
    271 
    272 (defcustom web-mode-auto-quote-style 1
    273   "Auto-quoting style."
    274   :group 'web-mode
    275   :type '(choice (const :tag "Auto-quotes with double quote" 1)
    276                  (const :tag "Auto-quotes with single quote" 2)
    277                  (const :tag "Auto-quotes with paren (for jsx)" 3)))
    278 
    279 (defcustom web-mode-extra-expanders '()
    280   "A list of additional expanders."
    281   :type '(alist :key-type string :value-type string)
    282   :group 'web-mode)
    283 
    284 (defcustom web-mode-extra-auto-pairs '()
    285   "A list of additional auto-pairs."
    286   :type '(alist :key-type string :value-type string)
    287   :group 'web-mode)
    288 
    289 (defcustom web-mode-extra-snippets '()
    290   "A list of additional snippets."
    291   :type '(alist :key-type string :value-type string)
    292   :group 'web-mode)
    293 
    294 (defcustom web-mode-extra-builtins '()
    295   "A list of additional builtins."
    296   :type '(alist :key-type string :value-type string)
    297   :group 'web-mode)
    298 
    299 (defcustom web-mode-extra-constants '()
    300   "A list of additional constants."
    301   :type '(alist :key-type string :value-type string)
    302   :group 'web-mode)
    303 
    304 (defcustom web-mode-extra-keywords '()
    305   "A list of additional keywords."
    306   :type '(alist :key-type string :value-type string)
    307   :group 'web-mode)
    308 
    309 (defcustom web-mode-extra-types '()
    310   "A list of additional types."
    311   :type '(alist :key-type string :value-type string)
    312   :group 'web-mode)
    313 
    314 (defcustom web-mode-extra-control-blocks '()
    315   "A list of additional control blocks."
    316   :type '(alist :key-type string :value-type (repeat string))
    317   :group 'web-mode)
    318 
    319 (defcustom web-mode-tests-directory (concat default-directory "tests/")
    320   "Directory containing all the unit tests."
    321   :type 'directory
    322   :group 'web-mode)
    323 
    324 (defcustom web-mode-jsx-depth-faces
    325   nil
    326   ;;'(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)
    327   "Each jsx depth has is own face."
    328   :type '(repeat face)
    329   :group 'web-mode)
    330 
    331 (defcustom web-mode-commands-like-expand-region
    332   '(web-mode-mark-and-expand er/expand-region mc/mark-next-like-this mc/mark-previous-like-this)
    333   "Add commmand here if you have some wrapper function for er/expand-region"
    334   :type '(repeat function)
    335   :group 'web-mode)
    336 
    337 (defcustom web-mode-comment-formats
    338   '(("java"       . "/*")
    339     ("javascript" . "/*")
    340     ("typescript" . "//")
    341     ("php"        . "/*")
    342     ("css"        . "/*"))
    343   "Default comment format for a language"
    344   :type '(alist :key-type string :value-type string)
    345   :group 'web-mode)
    346 
    347 (defcustom web-mode-script-template-types
    348   '("text/x-handlebars"
    349     "text/x-jquery-tmpl"
    350     "text/x-jsrender"
    351     "text/html"
    352     "text/ng-template"
    353     "text/x-template"
    354     "text/mustache"
    355     "text/x-dust-template")
    356   "<script> block types that are interpreted as HTML."
    357   :type '(repeat string)
    358   :group 'web-mode)
    359 
    360 ;; https://developer.mozilla.org/en-US/docs/Web/HTML/Element
    361 (defcustom web-mode-tag-list
    362   '("html" "base" "head" "link" "meta" "style" "title" "body" "address"
    363     "article" "aside" "footer" "header" "h1" "h2" "h3" "h4" "h5" "h6" "main"
    364     "nav" "section" "blockquote" "dd" "div" "dl" "dt" "figcaption" "figure"
    365     "hr" "li" "menu" "ol" "p" "pre" "ula" "a" "abbr" "b" "bdi" "bdo" "br"
    366     "cite" "code" "data" "dfn" "em" "i" "kbdmark" "q" "rp" "rt" "ruby" "s"
    367     "samp" "small" "span" "strong" "sub" "sup" "time" "u" "var" "wbr" "area"
    368     "audio" "img" "map" "track" "video" "embed" "iframe" "object" "picture"
    369     "portal" "source" "svg" "math" "canvas" "noscript" "script" "del" "ins"
    370     "caption" "col" "colgroup" "table" "tbody" "td" "tfoot" "th" "thead" "tr"
    371     "button" "datalist" "fieldset" "form" "input" "label" "legend" "meter"
    372     "optgroup" "option" "output" "progress" "select" "textarea" "details"
    373     "dialog" "summary" "slot" "template")
    374   "HTML tags used for completion."
    375   :type '(repeat string)
    376   :group 'web-mode)
    377 
    378 
    379 ;; https://www.w3schools.com/tags/ref_attributes.asp
    380 ;; Attributes marked as deprecated in HTML 5 are not added.
    381 (defcustom web-mode-attribute-list
    382   '("accept" "accesskey" "action" "alt" "async" "autocomplete" "autofocus"
    383     "autoplay" "charset" "checked" "cite" "class" "cols" "colspan" "content"
    384     "contenteditable" "controls" "coords" "data" "datetime" "default" "defer"
    385     "dir" "dirname" "disabled" "download" "draggable" "enctype" "for" "form"
    386     "formaction" "headers" "height" "hidden" "high" "href" "hreflang" "http"
    387     "id" "ismap" "kind" "label" "lang" "list" "loop" "low" "max" "maxlength"
    388     "media" "method" "min" "multiple" "muted" "name" "novalidate" "onabort"
    389     "onafterprint" "onbeforeprint" "onbeforeunload" "onblur" "oncanplay"
    390     "oncanplaythrough" "onchange" "onclick" "oncontextmenu" "oncopy"
    391     "oncuechange" "oncut" "ondblclick" "ondrag" "ondragend" "ondragenter"
    392     "ondragleave" "ondragover" "ondragstart" "ondrop" "ondurationchange"
    393     "onemptied" "onended" "onerror" "onfocus" "onhashchange" "oninput"
    394     "oninvalid" "onkeydown" "onkeypress" "onkeyup" "onload" "onloadeddata"
    395     "onloadedmetadata" "onloadstart" "onmousedown" "onmousemove" "onmouseout"
    396     "onmouseover" "onmouseup" "onmousewheel" "onoffline" "ononline"
    397     "onpagehide" "onpageshow" "onpaste" "onpause" "onplay" "onplaying"
    398     "onpopstate" "onprogress" "onratechange" "onreset" "onresize" "onscroll"
    399     "onsearch" "onseeked" "onseeking" "onselect" "onstalled" "onstorage"
    400     "onsubmit" "onsuspend" "ontimeupdate" "ontoggle" "onunload"
    401     "onvolumechange" "onwaiting" "onwheel" "open" "optimum" "pattern"
    402     "placeholder" "poster" "preload" "readonly" "rel" "required" "reversed"
    403     "rows" "rowspan" "sandbox" "scope" "selected" "shape" "size" "sizes"
    404     "span" "spellcheck" "src" "srcdoc" "srclang" "srcset" "start" "step"
    405     "style" "tabindex" "target" "title" "translate" "type" "usemap" "value"
    406     "width" "wrap")
    407   "HTML attributes used for completion."
    408   :type '(repeat string)
    409   :group 'web-mode)
    410 
    411 ;;---- FACES -------------------------------------------------------------------
    412 
    413 (defface web-mode-error-face
    414   '((t :background "red"))
    415   "Face for warning."
    416   :group 'web-mode-faces)
    417 
    418 (defface web-mode-warning-face
    419   '((t :inherit font-lock-warning-face))
    420   "Face for warning."
    421   :group 'web-mode-faces)
    422 
    423 (defface web-mode-preprocessor-face
    424   '((t :inherit font-lock-preprocessor-face))
    425   "Face for preprocessor commands."
    426   :group 'web-mode-faces)
    427 
    428 (defface web-mode-preprocessor-face
    429   '((t :inherit font-lock-preprocessor-face))
    430   "Face for preprocessor."
    431   :group 'web-mode-faces)
    432 
    433 (defface web-mode-block-delimiter-face
    434   '((t :inherit font-lock-preprocessor-face))
    435   "Face for block delimiters."
    436   :group 'web-mode-faces)
    437 
    438 (defface web-mode-block-control-face
    439   '((t :inherit font-lock-preprocessor-face))
    440   "Face for preprocessor."
    441   :group 'web-mode-faces)
    442 
    443 (defface web-mode-builtin-face
    444   '((t :inherit font-lock-builtin-face))
    445   "Face for builtins."
    446   :group 'web-mode-faces)
    447 
    448 (defface web-mode-symbol-face
    449   '((t :foreground "goldenrod2"))
    450   "Face for symbols."
    451   :group 'web-mode-faces)
    452 
    453 (defface web-mode-doctype-face
    454   '((t :foreground "Grey"))
    455   "Face for html doctype."
    456   :group 'web-mode-faces)
    457 
    458 (defface web-mode-html-tag-face
    459   '((((class color) (min-colors 88) (background dark))  :foreground "Snow4")
    460     (((class color) (min-colors 88) (background light)) :foreground "Snow4")
    461     (((class color) (min-colors 16) (background dark))  :foreground "Snow4")
    462     (((class color) (min-colors 16) (background light)) :foreground "Grey15")
    463     (((class color) (min-colors 8))                     :foreground "Snow4")
    464     (((type tty) (class mono))                          :inverse-video t)
    465     (t                                                  :foreground "Snow4"))
    466   "Face for html tags."
    467   :group 'web-mode-faces)
    468 
    469 (defface web-mode-html-tag-custom-face
    470   '((t :inherit web-mode-html-tag-face))
    471   "Face for html custom tags (e.g. <polymer-element>)."
    472   :group 'web-mode-faces)
    473 
    474 (defface web-mode-html-tag-unclosed-face
    475   '((t :inherit web-mode-html-tag-face :underline t))
    476   "Face for unclosed tags."
    477   :group 'web-mode-faces)
    478 
    479 (defface web-mode-html-tag-namespaced-face
    480   '((t :inherit web-mode-block-control-face))
    481   "Face for html namespaced tags (e.g. <c:forEach>)."
    482   :group 'web-mode-faces)
    483 
    484 (defface web-mode-html-tag-bracket-face
    485   '((((class color) (min-colors 88) (background dark))  :foreground "Snow3")
    486     (((class color) (min-colors 88) (background light)) :foreground "Grey14")
    487     (((class color) (min-colors 16) (background dark))  :foreground "Snow3")
    488     (((class color) (min-colors 16) (background light)) :foreground "Grey14")
    489     (((class color) (min-colors 8))                     :foreground "Snow3")
    490     (((type tty) (class mono))                          :inverse-video t)
    491     (t                                                  :foreground "Snow3"))
    492   "Face for html tags angle brackets (<, > and />)."
    493   :group 'web-mode-faces)
    494 
    495 (defface web-mode-html-attr-name-face
    496   '((((class color) (min-colors 88) (background dark))  :foreground "Snow3")
    497     (((class color) (min-colors 88) (background light)) :foreground "Snow4")
    498     (((class color) (min-colors 16) (background dark))  :foreground "Snow3")
    499     (((class color) (min-colors 16) (background light)) :foreground "Grey13")
    500     (((class color) (min-colors 8))                     :foreground "Snow3")
    501     (((type tty) (class mono))                          :inverse-video t)
    502     (t                                                  :foreground "Snow4"))
    503   "Face for html attribute names."
    504   :group 'web-mode-faces)
    505 
    506 (defface web-mode-html-attr-custom-face
    507   '((t :inherit web-mode-html-attr-name-face))
    508   "Face for custom attribute names (e.g. data-*)."
    509   :group 'web-mode-faces)
    510 
    511 (defface web-mode-html-attr-engine-face
    512   '((t :inherit web-mode-block-delimiter-face))
    513   "Face for custom engine attribute names (e.g. ng-*)."
    514   :group 'web-mode-faces)
    515 
    516 (defface web-mode-html-attr-equal-face
    517   '((t :inherit web-mode-html-attr-name-face))
    518   "Face for the = character between name and value."
    519   :group 'web-mode-faces)
    520 
    521 (defface web-mode-html-attr-value-face
    522   '((t :inherit font-lock-string-face))
    523   "Face for html attribute values."
    524   :group 'web-mode-faces)
    525 
    526 (defface web-mode-block-attr-name-face
    527   '((t :foreground "#8fbc8f"))
    528   "Face for block attribute names."
    529   :group 'web-mode-faces)
    530 
    531 (defface web-mode-block-attr-value-face
    532   '((t :foreground "#5f9ea0"))
    533   "Face for block attribute values."
    534   :group 'web-mode-faces)
    535 
    536 (defface web-mode-variable-name-face
    537   '((t :inherit font-lock-variable-name-face))
    538   "Face for variable names."
    539   :group 'web-mode-faces)
    540 
    541 (defface web-mode-css-selector-face
    542   '((t :inherit font-lock-keyword-face))
    543   "Face for CSS rules."
    544   :group 'web-mode-faces)
    545 
    546 (defface web-mode-css-selector-class-face
    547   '((t :inherit font-lock-keyword-face))
    548   "Face for CSS class rules."
    549   :group 'web-mode-faces)
    550 
    551 (defface web-mode-css-selector-tag-face
    552   '((t :inherit font-lock-keyword-face))
    553   "Face for CSS tag rules."
    554   :group 'web-mode-faces)
    555 
    556 (defface web-mode-css-pseudo-class-face
    557   '((t :inherit font-lock-builtin-face))
    558   "Face for CSS pseudo-classes."
    559   :group 'web-mode-faces)
    560 
    561 (defface web-mode-css-at-rule-face
    562   '((t :inherit font-lock-constant-face))
    563   "Face for CSS at-rules."
    564   :group 'web-mode-faces)
    565 
    566 (defface web-mode-css-property-name-face
    567   '((t :inherit font-lock-variable-name-face))
    568   "Face for CSS props."
    569   :group 'web-mode-faces)
    570 
    571 (defface web-mode-css-color-face
    572   '((t :inherit font-lock-builtin-face))
    573   "Face for CSS colors (#xxx)."
    574   :group 'web-mode-faces)
    575 
    576 (defface web-mode-css-priority-face
    577   '((t :inherit font-lock-builtin-face))
    578   "Face for CSS priority (!important)."
    579   :group 'web-mode-faces)
    580 
    581 (defface web-mode-css-function-face
    582   '((t :inherit font-lock-builtin-face))
    583   "Face for CSS functions."
    584   :group 'web-mode-faces)
    585 
    586 (defface web-mode-css-variable-face
    587   '((t :inherit web-mode-variable-name-face :slant italic))
    588   "Face for CSS vars."
    589   :group 'web-mode-faces)
    590 
    591 (defface web-mode-function-name-face
    592   '((t :inherit font-lock-function-name-face))
    593   "Face for function names."
    594   :group 'web-mode-faces)
    595 
    596 (defface web-mode-filter-face
    597   '((t :inherit font-lock-function-name-face))
    598   "Face for function names."
    599   :group 'web-mode-faces)
    600 
    601 (defface web-mode-function-call-face
    602   '((t :inherit font-lock-function-name-face))
    603   "Face for function calls."
    604   :group 'web-mode-faces)
    605 
    606 (defface web-mode-string-face
    607   '((t :inherit font-lock-string-face))
    608   "Face for strings."
    609   :group 'web-mode-faces)
    610 
    611 (defface web-mode-block-string-face
    612   '((t :inherit web-mode-string-face))
    613   "Face for block strings."
    614   :group 'web-mode-faces)
    615 
    616 (defface web-mode-part-string-face
    617   '((t :inherit web-mode-string-face))
    618   "Face for part strings."
    619   :group 'web-mode-faces)
    620 
    621 (defface web-mode-javascript-string-face
    622   '((t :inherit web-mode-string-face))
    623   "Face for javascript strings."
    624   :group 'web-mode-faces)
    625 
    626 (defface web-mode-interpolate-color1-face
    627   '((t :inherit web-mode-string-face))
    628   "Face for element interpolation strings."
    629   :group 'web-mode-faces)
    630 
    631 (defface web-mode-interpolate-color2-face
    632   '((t :inherit web-mode-string-face))
    633   "Face for element interpolation strings."
    634   :group 'web-mode-faces)
    635 
    636 (defface web-mode-interpolate-color3-face
    637   '((t :inherit web-mode-string-face))
    638   "Face for element interpolation strings."
    639   :group 'web-mode-faces)
    640 
    641 (defface web-mode-css-string-face
    642   '((t :inherit web-mode-string-face))
    643   "Face for css strings."
    644   :group 'web-mode-faces)
    645 
    646 (defface web-mode-json-key-face
    647   '((t :foreground "plum"))
    648   "Face for json key strings."
    649   :group 'web-mode-faces)
    650 
    651 (defface web-mode-json-context-face
    652   '((t :foreground "orchid3"))
    653   "Face for json context strings."
    654   :group 'web-mode-faces)
    655 
    656 (defface web-mode-json-string-face
    657   '((t :inherit web-mode-string-face))
    658   "Face for json strings."
    659   :group 'web-mode-faces)
    660 
    661 (defface web-mode-comment-face
    662   '((t :inherit font-lock-comment-face))
    663   "Face for comments."
    664   :group 'web-mode-faces)
    665 
    666 (defface web-mode-block-comment-face
    667   '((t :inherit web-mode-comment-face))
    668   "Face for server comments."
    669   :group 'web-mode-faces)
    670 
    671 (defface web-mode-part-comment-face
    672   '((t :inherit web-mode-comment-face))
    673   "Face for part comments."
    674   :group 'web-mode-faces)
    675 
    676 (defface web-mode-json-comment-face
    677   '((t :inherit web-mode-comment-face))
    678   "Face for json comments."
    679   :group 'web-mode-faces)
    680 
    681 (defface web-mode-javascript-comment-face
    682   '((t :inherit web-mode-comment-face))
    683   "Face for javascript comments."
    684   :group 'web-mode-faces)
    685 
    686 (defface web-mode-css-comment-face
    687   '((t :inherit web-mode-comment-face))
    688   "Face for css comments."
    689   :group 'web-mode-faces)
    690 
    691 (defface web-mode-annotation-face
    692   '((t :inherit web-mode-comment-face))
    693   "Face for code annotations."
    694   :group 'web-mode-faces)
    695 
    696 (defface web-mode-annotation-tag-face
    697   '((t :inherit web-mode-annotation-face :underline t))
    698   "Face for @tags in code annotations."
    699   :group 'web-mode-faces)
    700 
    701 (defface web-mode-annotation-type-face
    702   '((t :inherit web-mode-annotation-face :weight bold))
    703   "Face for types in code annotations."
    704   :group 'web-mode-faces)
    705 
    706 (defface web-mode-annotation-value-face
    707   '((t :inherit web-mode-annotation-face :slant italic))
    708   "Face for values in code annotations."
    709   :group 'web-mode-faces)
    710 
    711 (defface web-mode-annotation-html-face
    712   '((t :inherit web-mode-annotation-face :slant italic))
    713   "Face for HTML tags in code annotations."
    714   :group 'web-mode-faces)
    715 
    716 (defface web-mode-constant-face
    717   '((t :inherit font-lock-constant-face))
    718   "Face for language constants."
    719   :group 'web-mode-faces)
    720 
    721 (defface web-mode-type-face
    722   '((t :inherit font-lock-type-face))
    723   "Face for language types."
    724   :group 'web-mode-faces)
    725 
    726 (defface web-mode-keyword-face
    727   '((t :inherit font-lock-keyword-face))
    728   "Face for language keywords."
    729   :group 'web-mode-faces)
    730 
    731 (defface web-mode-param-name-face
    732   '((t :foreground "Snow3"))
    733   "Face for server attribute names."
    734   :group 'web-mode-faces)
    735 
    736 (defface web-mode-whitespace-face
    737   '((t :background "DarkOrchid4"))
    738   "Face for whitespaces."
    739   :group 'web-mode-faces)
    740 
    741 (defface web-mode-inlay-face
    742   '((((class color) (min-colors 88) (background dark))  :background "Black")
    743     (((class color) (min-colors 88) (background light)) :background "LightYellow1")
    744     (((class color) (min-colors 16) (background dark))  :background "Brey18")
    745     (((class color) (min-colors 16) (background light)) :background "LightYellow1")
    746     (((class color) (min-colors 8))                     :background "Black")
    747     (((type tty) (class mono))                          :inverse-video t)
    748     (t                                                  :background "Grey"))
    749   "Face for inlays. Must be used in conjunction with web-mode-enable-inlays."
    750   :group 'web-mode-faces)
    751 
    752 (defface web-mode-block-face
    753   '((((class color) (min-colors 88) (background dark))  :background "Black")
    754     (((class color) (min-colors 88) (background light)) :background "LightYellow1")
    755     (((class color) (min-colors 16) (background dark))  :background "Grey18")
    756     (((class color) (min-colors 16) (background light)) :background "LightYellow1")
    757     (((class color) (min-colors 8))                     :background "Black")
    758     (((type tty) (class mono))                          :inverse-video t)
    759     (t                                                  :background "Grey"))
    760   "Face for blocks (useful for setting a background for example).
    761 Must be used in conjunction with web-mode-enable-block-face."
    762   :group 'web-mode-faces)
    763 
    764 (defface web-mode-part-face
    765   '((t :inherit web-mode-block-face))
    766   "Face for parts."
    767   :group 'web-mode-faces)
    768 
    769 (defface web-mode-script-face
    770   '((t :inherit web-mode-part-face))
    771   "Face for javascript inside a script element."
    772   :group 'web-mode-faces)
    773 
    774 (defface web-mode-style-face
    775   '((t :inherit web-mode-part-face))
    776   "Face for css inside a style element."
    777   :group 'web-mode-faces)
    778 
    779 (defface web-mode-folded-face
    780   '((t :underline t))
    781   "Overlay face for folded."
    782   :group 'web-mode-faces)
    783 
    784 (defface web-mode-bold-face
    785   '((t :weight bold))
    786   "bold face."
    787   :group 'web-mode-faces)
    788 
    789 (defface web-mode-italic-face
    790   '((t :slant italic))
    791   "bold face."
    792   :group 'web-mode-faces)
    793 
    794 (defface web-mode-underline-face
    795   '((t :underline t))
    796   "bold face."
    797   :group 'web-mode-faces)
    798 
    799 (defface web-mode-current-element-highlight-face
    800   '((t :background "#000000" :foreground "#ffffff"))
    801   "Overlay face for element highlight."
    802   :group 'web-mode-faces)
    803 
    804 (defface web-mode-current-column-highlight-face
    805   '((t :background "#3e3c36"))
    806   "Overlay face for current column."
    807   :group 'web-mode-faces)
    808 
    809 (defface web-mode-comment-keyword-face
    810   '((t :weight bold :box t))
    811   "Comment keywords."
    812   :group 'web-mode-faces)
    813 
    814 (defface web-mode-sql-keyword-face
    815   '((t :weight bold :slant italic))
    816   "Sql keywords."
    817   :group 'web-mode-faces)
    818 
    819 (defface web-mode-html-entity-face
    820   '((t :slant italic))
    821   "Face html entities (e.g. &#8211;, &eacute;)."
    822   :group 'web-mode-faces)
    823 
    824 ;; https://material.io/tools/color/#!/?view.left=0&view.right=0
    825 (defface web-mode-jsx-depth-1-face
    826   '((t :background "#000053"))
    827   "jsx depth 1"
    828   :group 'web-mode-faces)
    829 
    830 (defface web-mode-jsx-depth-2-face
    831   '((t :background "#001970"))
    832   "jsx"
    833   :group 'web-mode-faces)
    834 
    835 (defface web-mode-jsx-depth-3-face
    836   '((t :background "#002984"))
    837   "jsx"
    838   :group 'web-mode-faces)
    839 
    840 (defface web-mode-jsx-depth-4-face
    841   '((t :background "#49599a"))
    842   "jsx"
    843   :group 'web-mode-faces)
    844 
    845 (defface web-mode-jsx-depth-5-face
    846   '((t :background "#9499b7"))
    847   "jsx"
    848   :group 'web-mode-faces)
    849 
    850 ;;---- VARS --------------------------------------------------------------------
    851 
    852 (defvar font-lock-beg)
    853 (defvar font-lock-end)
    854 
    855 (defvar web-mode-auto-pairs nil)
    856 (defvar web-mode-block-regexp nil)
    857 (defvar web-mode-change-beg nil)
    858 (defvar web-mode-change-end nil)
    859 (defvar web-mode-chunk-length 64)
    860 (defvar web-mode-column-overlays nil)
    861 (defvar web-mode-comments-invisible nil)
    862 (defvar web-mode-content-type "")
    863 (defvar web-mode-engine nil)
    864 ;;(defvar web-mode-engine-attr-regexp nil)
    865 (defvar web-mode-engine-font-lock-keywords nil)
    866 (defvar web-mode-engine-token-regexp nil)
    867 (defvar web-mode-expand-initial-pos nil)
    868 (defvar web-mode-expand-initial-scroll nil)
    869 (defvar web-mode-expand-previous-state "")
    870 ;;(defvar web-mode-font-lock-keywords '(web-mode-font-lock-highlight))
    871 (defvar web-mode-skip-fontification nil)
    872 (defvar web-mode-inlay-regexp nil)
    873 (defvar web-mode-is-scratch nil)
    874 (defvar web-mode-jshint-errors 0)
    875 (defvar web-mode-minor-engine nil)
    876 (defvar web-mode-obarray nil)
    877 (defvar web-mode-overlay-tag-start nil)
    878 (defvar web-mode-overlay-tag-end nil)
    879 (defvar web-mode-part-beg nil)
    880 (defvar web-mode-scan-beg nil)
    881 (defvar web-mode-scan-end nil)
    882 (defvar web-mode-snippets nil)
    883 (defvar web-mode-time nil)
    884 
    885 (defvar web-mode-offsetless-elements
    886   '())
    887 
    888 (defvar web-mode-indentless-elements
    889   '("code" "pre" "textarea"))
    890 
    891 (defvar web-mode-indentless-attributes
    892   '("onclick" "onmouseover" "onmouseout" "onsubmit"))
    893 
    894 (defvar web-mode-void-elements
    895   '("area" "base" "br" "col" "command" "embed" "hr" "img" "input" "keygen"
    896     "link" "meta" "param" "source" "track" "wbr" "tmpl_var"))
    897 
    898 (defvar web-mode-part-content-types
    899   '("css" "javascript" "json" "jsx" "markdown" "pug" "ruby"
    900     "sass" "sql" "stylus" "typescript"))
    901 
    902 (defvar web-mode-javascript-languages '("javascript" "jsx" "ejs"))
    903 
    904 ;; NOTE: without 'syntax-table forward-word fails (#377)
    905 (defvar web-mode-scan-properties
    906   (list 'tag-beg 'tag-end 'tag-name 'tag-type
    907         'tag-attr 'tag-attr-beg 'tag-attr-end
    908         'part-side 'part-token
    909         'jsx-beg 'jsx-end 'jsx-depth
    910         'block-side 'block-token 'block-controls 'block-beg 'block-end
    911         'syntax-table)
    912   "Text properties used for code regions/tokens and html nodes.")
    913 
    914 (defvar web-mode-start-tag-regexp "<\\([[:alpha:]][[:alnum:].:_-]*\\|>\\)"
    915   "Regular expression for HTML/XML start tag.")
    916 
    917 (defvar web-mode-tag-regexp "</?\\([[:alpha:]][[:alnum:].:_-]*\\)"
    918   "Regular expression for HTML/XML tag.")
    919 
    920 (defvar web-mode-dom-regexp "<\\(/?>\\|/?[[:alpha:]][[:alnum:].:_-]*\\|!--\\|!\\[CDATA\\[\\|!doctype\\|!DOCTYPE\\|\?xml\\)")
    921 
    922 (defvar web-mode-whitespaces-regexp
    923   "^[ \t]\\{2,\\}$\\| \t\\|\t \\|[ \t]+$\\|^[ \n\t]+\\'\\|^[ \t]?[\n]\\{2,\\}"
    924   "Regular expression for whitespaces.")
    925 
    926 (defvar web-mode-imenu-regexp-list
    927   '(("<\\(h[1-9]\\)\\([^>]*\\)>\\([^<]*\\)" 1 3 ">")
    928     ("^[ \t]*<\\([@a-z]+\\)[^>]*>? *$" 1 "id=\"\\([a-zA-Z0-9_]+\\)\"" "#" ">"))
    929   "Regexps to match imenu items (see https://web-mode.org/doc/imenu.txt)")
    930 
    931 ;; https://www.gnu.org/software/emacs/manual/html_node/ccmode/Syntactic-Symbols.html
    932 (defvar web-mode-indentation-params
    933   '(("lineup-args"       . t)
    934     ("lineup-calls"      . t)
    935     ("lineup-concats"    . t)
    936     ("lineup-quotes"     . t)
    937     ("lineup-ternary"    . t)
    938     ("case-extra-offset" . t)
    939     ))
    940 
    941 (defvar web-mode-tag-history nil)
    942 (defvar web-mode-attribute-history nil)
    943 (defvar web-mode-attribute-value-history nil)
    944 
    945 (defvar web-mode-engines
    946   '(("angular"          . ("angularjs"))
    947     ("anki"             . ())
    948     ("archibus"         . ())
    949     ("artanis"          . ())
    950     ("asp"              . ())
    951     ("aspx"             . ())
    952     ("blade"            . ("laravel"))
    953     ("cl-emb"           . ())
    954     ("clip"             . ())
    955     ("closure"          . ("soy"))
    956     ("ctemplate"        . ("mustache" "handlebars" "hapax" "ngtemplate" "ember"
    957                            "kite" "meteor" "blaze" "ractive" "velvet"))
    958     ("django"           . ("dtl" "twig" "swig" "jinja" "jinja2" "erlydtl" "liquid"
    959                            "clabango" "selmer" "nunjucks"))
    960     ("dust"             . ("dustjs"))
    961     ("ejs"              . ())
    962     ("elixir"           . ("phoenix"))
    963     ("erb"              . ("eruby" "erubis" "crystal"))
    964     ("expressionengine" . ("ee"))
    965     ("freemarker"       . ())
    966     ("go"               . ("gtl" "hugo"))
    967     ("hero"             . ())
    968     ("json-t"           . ())
    969     ("jsp"              . ("grails"))
    970     ("mako"             . ())
    971     ("marko"            . ())
    972     ("mason"            . ("poet"))
    973     ("lsp"              . ("lisp"))
    974     ("mojolicious"      . ())
    975     ("php"              . ())
    976     ("python"           . ())
    977     ("razor"            . ("play" "play2"))
    978     ("riot"             . ())
    979     ("smarty"           . ())
    980     ("spip"             . ())
    981     ("svelte"           . ("svelte"))
    982     ("template-toolkit" . ())
    983     ("thymeleaf"        . ())
    984     ("perl"             . ())
    985     ("underscore"       . ("underscore.js"))
    986     ("velocity"         . ("vtl" "cheetah" "ssp"))
    987     ("vue"              . ("vuejs" "vue.js"))
    988     ("web2py"           . ())
    989     ("xoops"            . ())
    990     )
    991   "Engine name aliases")
    992 
    993 (defvar web-mode-content-types
    994   '(("css"        . "\\.\\(s?css\\|css\\.erb\\)\\'")
    995     ("javascript" . "\\.\\([mc]?js\\|js\\.erb\\)\\'")
    996     ("typescript" . "\\.\\(ts\\|ts\\.erb\\)\\'")
    997     ("json"       . "\\.\\(api\\|json\\|jsonld\\)\\'")
    998     ("jsx"        . "\\.[jt]sx\\'")
    999     ("xml"        . "\\.xml\\'")
   1000     ("html"       . "."))
   1001   "content types")
   1002 
   1003 (defvar web-mode-engine-attr-regexps
   1004   '(("angular"   . "ng-")
   1005     ("thymeleaf" . "th:")
   1006     ("vue"       . "v-"))
   1007   "Engine custom attributes")
   1008 
   1009 (defvar web-mode-engine-attr-regexp
   1010   "^ng[-]\\|^th[:]\\|^v[-]\\|^[@:#(\[*]"
   1011   "Engine custom attributes")
   1012 
   1013 (defvar web-mode-last-enabled-feature nil)
   1014 
   1015 (defvar web-mode-features
   1016   '(("css-colorization"          . web-mode-enable-css-colorization)
   1017     ("element-highlight"         . web-mode-enable-current-element-highlight)
   1018     ("column-highlight"          . web-mode-enable-current-column-highlight)
   1019     ("whitespace-fontification"  . web-mode-enable-whitespace-fontification)
   1020     ("element-tag-fontification" . web-mode-enable-element-tag-fontification)
   1021     ("block-face"                . web-mode-enable-block-face)
   1022     ("part-face"                 . web-mode-enable-part-face)))
   1023 
   1024 (defvar web-mode-comment-prefixing t)
   1025 
   1026 (defvar web-mode-engine-file-regexps
   1027   '(("angular"          . "\\.component.html\\'")
   1028     ("anki"             . "\\.anki\\'")
   1029     ("archibus"         . "\\.axvw\\'")
   1030     ("artanis"          . "\\.html\\.tpl\\'")
   1031     ("asp"              . "\\.asp\\'")
   1032     ("aspx"             . "\\.as[cp]x\\'")
   1033     ("blade"            . "\\.blade\\.php\\'")
   1034     ("cl-emb"           . "\\.clemb\\'")
   1035     ("clip"             . "\\.ctml\\'")
   1036     ("closure"          . "\\.soy\\'")
   1037     ("ctemplate"        . "\\.\\(chtml\\|mustache\\)\\'")
   1038     ("django"           . "\\.\\(djhtml\\|tmpl\\|dtl\\|liquid\\|j2\\|njk\\)\\'")
   1039     ("dust"             . "\\.dust\\'")
   1040     ("elixir"           . "\\.[hl]?eex\\'")
   1041     ("ejs"              . "\\.ejs\\'")
   1042     ("erb"              . "\\.\\(erb\\|rhtml\\|erb\\.html\\|ecr\\)\\'")
   1043     ("expressionengine" . "\\.ee\\'")
   1044     ("freemarker"       . "\\.ftl\\'")
   1045     ("go"               . "\\.go\\(html\\|tmpl\\)\\'")
   1046     ("handlebars"       . "\\.\\(hb\\.html\\|hbs\\)\\'")
   1047     ("hero"             . "\\.hero\\'")
   1048     ("jinja"            . "\\.jinja\\'")
   1049     ("jsp"              . "\\.[gj]sp\\'")
   1050     ("lsp"              . "\\.lsp\\'")
   1051     ("mako"             . "\\.mako?\\'")
   1052     ("marko"            . "\\.marko\\'")
   1053     ("mason"            . "\\.mas\\'")
   1054     ("mojolicious"      . "\\.epl?\\'")
   1055     ("perl"             . "\\.\\(ptmpl\\|perl\\.html\\)\\'")
   1056     ("php"              . "\\.\\(p[hs]p\\|ctp\\|inc\\)\\'")
   1057     ("python"           . "\\.pml\\'")
   1058     ("razor"            . "\\.\\(cs\\|vb\\)html\\|\\.razor\\'")
   1059     ("riot"             . "\\.tag\\'")
   1060     ("smarty"           . "\\.tpl\\'")
   1061     ("svelte"           . "\\.svelte\\'")
   1062     ("template-toolkit" . "\\.tt.?\\'")
   1063     ("thymeleaf"        . "\\.thtml\\'")
   1064     ("velocity"         . "\\.v\\(sl\\|tl\\|m\\)\\'")
   1065     ("vue"              . "\\.vue\\'")
   1066     ("xoops"            . "\\.xoops'")
   1067     ;; regexp on the path, not just the extension
   1068     ("django"           . "[st]wig")
   1069     ("razor"            . "scala")
   1070     ("spip"             . "spip")
   1071     )
   1072   "Engine file extensions.")
   1073 
   1074 (defvar web-mode-content-types-alist nil
   1075   "A list of filename patterns and corresponding web-mode content types. For example,
   1076 (setq web-mode-content-types-alist
   1077   '((\"json\" . \"/some/path/.*\\.api\\'\")
   1078     (\"jsx\"  . \"/some/react/path/.*\\.js[x]?\\'\")))")
   1079 
   1080 (defvar web-mode-engines-alist nil
   1081   "A list of filename patterns and corresponding web-mode engine. For example,
   1082 (setq web-mode-engines-alist
   1083       '((\"php\"    . \"\\\\.phtml\\\\'\")
   1084         (\"blade\"  . \"\\\\.blade\\\\.\")))")
   1085 
   1086 (defvar web-mode-smart-quotes
   1087   '("«" . "»")
   1088   "Preferred smart quotes")
   1089 
   1090 (defvar web-mode-xml-chars
   1091   '((?\& . "&amp;")
   1092     (?\< . "&lt;")
   1093     (?\> . "&gt;"))
   1094   "XML chars")
   1095 
   1096 (defvar web-mode-html-entities
   1097   ;; #985
   1098   ;; remove ("gt" . 62) ("lt" . 60) ("amp" . 38)
   1099   '(("AElig" . 198) ("Aacute" . 193) ("Acirc" . 194) ("Agrave" . 192)
   1100     ("Alpha" . 913) ("Aring" . 197) ("Atilde" . 195) ("Auml" . 196)
   1101     ("Beta" . 914)
   1102     ("Ccedil" . 199) ("Chi" . 935)
   1103     ("Dagger" . 8225) ("Delta" . 916)
   1104     ("ETH" . 208) ("Eacute" . 201) ("Ecirc" . 202) ("Egrave" . 200)
   1105     ("Epsilon" . 917) ("Eta" . 919) ("Euml" . 203)
   1106     ("Gamma" . 915)
   1107     ("Iacute" . 205) ("Icirc" . 206) ("Igrave" . 204) ("Iota" . 921)
   1108     ("Iuml" . 207)
   1109     ("Kappa" . 922)
   1110     ("Lambda" . 923)
   1111     ("Mu" . 924)
   1112     ("Ntilde" . 209) ("Nu" . 925)
   1113     ("OElig" . 338) ("Oacute" . 211) ("Ocirc" . 212) ("Ograve" . 210)
   1114     ("Omega" . 937) ("Omicron" . 927) ("Oslash" . 216) ("Otilde" . 213)
   1115     ("Ouml" . 214)
   1116     ("Phi" . 934) ("Pi" . 928) ("Prime" . 8243) ("Psi" . 936)
   1117     ("Rho" . 929)
   1118     ("Scaron" . 352) ("Sigma" . 931)
   1119     ("THORN" . 222) ("Tau" . 932) ("Theta" . 920)
   1120     ("UArr" . 8657) ("Uacute" . 218) ("Uacute" . 250) ("Ucirc" . 219)
   1121     ("Ugrave" . 217)  ("Upsih" . 978)
   1122     ("Upsilon" . 933) ("Uuml" . 220) ("Uuml" . 252)
   1123     ("Xi" . 926)
   1124     ("Yacute" . 221) ("Yuml" . 376)
   1125     ("Zeta" . 918)
   1126     ("aacute" . 225) ("acirc" . 226) ("acute" . 180) ("aelig" . 230)
   1127     ("agrave" . 224) ("alefsym" . 8501) ("alpha" . 945)
   1128     ("ang" . 8736) ("apos" . 39) ("aring" . 229) ("asymp" . 8776)
   1129     ("atilde" . 227) ("auml" . 228)
   1130     ("bdquo" . 8222) ("beta" . 946) ("brvbar" . 166) ("bull" . 8226)
   1131     ("cap" . 8745) ("ccedil" . 231) ("cedil" . 184) ("cent" . 162)
   1132     ("chi" . 967) ("circ" . 710) ("clubs" . 9827) ("cong" . 8773)
   1133     ("copy" . 169) ("crarr"  . 8629) ("cup" . 8746) ("curren" . 164)
   1134     ("dArr" . 8659) ("dagger" . 8224) ("darr" . 8595) ("deg" . 176)
   1135     ("delta" . 948) ("diams" . 9830) ("divide" . 247)
   1136     ("eacute" . 233) ("ecirc"  . 234) ("egrave" . 232) ("empty" . 8709)
   1137     ("emsp" . 8195) ("ensp" . 8194) ("epsilon" . 949) ("equiv" . 8801)
   1138     ("eta" . 951) ("eth" . 240) ("euml" . 235) ("euro" . 8364) ("exist" . 8707)
   1139     ("fnof" . 402) ("forall" . 8704) ("frac12" . 189) ("frac14" . 188)
   1140     ("frac34" . 190) ("frasl" . 8260)
   1141     ("gamma" . 947) ("ge" . 8805)
   1142     ("hArr" . 8660) ("harr" . 8596) ("hearts" . 9829) ("hellip" . 8230)
   1143     ("iacute" . 237) ("icirc" . 238) ("iexcl" . 161) ("igrave" . 236)
   1144     ("image" . 8465) ("infin" . 8734) ("int" . 8747) ("iota" . 953)
   1145     ("iquest" . 191) ("isin" . 8712) ("iuml" . 239)
   1146     ("kappa" . 954)
   1147     ("lArr" . 8656) ("lambda" . 955) ("lang" . 9001) ("laquo" . 171)
   1148     ("larr" . 8592) ("lceil" . 8968) ("ldquo" . 8220) ("le" . 8804)
   1149     ("lfloor" . 8970) ("lowast" . 8727) ("loz" . 9674) ("lrm" . 8206)
   1150     ("lsaquo" . 8249) ("lsquo" . 8249)
   1151     ("macr" . 175) ("mdash" . 8212) ("micro" . 181) ("middot" . 183)
   1152     ("minus" . 8722) ("mu" . 956)
   1153     ("nabla" . 8711) ("nbsp" . 160) ("ndash" . 8211) ("ne" . 8800)
   1154     ("ni" . 8715) ("not" . 172) ("notin" . 8713) ("nsub" . 8836)
   1155     ("ntilde" . 241) ("nu" . 957) ("oacute" . 243) ("ocirc" . 244)
   1156     ("oelig" . 339) ("ograve" . 242) ("oline" . 8254) ("omega" . 969)
   1157     ("omicron" . 959) ("oplus" . 8853) ("or" . 8744) ("ordf" . 170)
   1158     ("ordm" . 186) ("oslash" . 248) ("otilde" . 245) ("otimes" . 8855)
   1159     ("ouml" . 246)
   1160     ("para" . 182) ("part" . 8706) ("permil" . 8240) ("perp" . 8869)
   1161     ("phi" . 966) ("pi" . 960) ("piv" . 982) ("plusmn" . 177) ("pound" . 163)
   1162     ("prime" . 8242) ("prod" . 8719) ("prop" . 8733) ("psi" . 968)
   1163     ("quot" . 34)
   1164     ("rArr" . 8658) ("radic" . 8730) ("rang" . 9002) ("raquo" . 187)
   1165     ("rarr" . 8594) ("rceil" . 8969) ("rdquo" . 8221) ("real" . 8476)
   1166     ("reg" . 174) ("rfloor" . 8971) ("rho" . 961) ("rlm" . 8207)
   1167     ("rsaquo" . 8250) ("rsquo" . 8250) ("sbquo" . 8218)
   1168     ("scaron" . 353) ("sdot" . 8901) ("sect" . 167) ("shy" . 173)
   1169     ("sigma" . 963) ("sigmaf" . 962) ("sim" . 8764) ("spades" . 9824)
   1170     ("sub" . 8834) ("sube" . 8838) ("sum" . 8721) ("sup" . 8835)
   1171     ("sup1" . 185) ("sup2" . 178) ("sup3" . 179) ("supe" . 8839)
   1172     ("szlig" . 223)
   1173     ("tau" . 964) ("there4" . 8756) ("theta" . 952) ("thetasym" . 977)
   1174     ("thinsp" . 8201) ("thorn" . 254) ("tilde" . 732) ("times" . 215)
   1175     ("trade" . 8482)
   1176     ("uarr" . 8593) ("ucirc" . 251) ("ugrave" . 249) ("uml" . 168)
   1177     ("upsilon" . 965)
   1178     ("weierp" . 8472)
   1179     ("xi" . 958)
   1180     ("yacute" . 253) ("yen" . 165) ("yuml" . 255)
   1181     ("zeta" . 950) ("zwj" . 8205) ("zwnj" . 8204)))
   1182 
   1183 ;; http://webdesign.about.com/od/localization/l/blhtmlcodes-ascii.htm
   1184 (defvar web-mode-display-table
   1185   (let ((table (make-display-table)))
   1186     (aset table 9  (vector ?\xBB ?\t))
   1187     (aset table 10 (vector ?\xB6 ?\n))
   1188     (aset table 32 (vector ?\xB7))
   1189     table)
   1190   "Display table used when switching to the whitespace visualization.")
   1191 
   1192 (defvar web-mode-expanders
   1193   '(("a/" . "<a href=\"|\"></a>")
   1194     ("b/" . "<table><tbody><tr><td>|</td><td></td></tr></tbody></table>")
   1195     ("c/" . "<div class=\"|\"></div>")
   1196     ("d/" . "<div>|</div>")
   1197     ("e/" . "<em>|</em>")
   1198     ("f/" . "<form>|</form>")
   1199     ("g/" . "<strong>|</strong>")
   1200     ("h/" . "<h1>|</h1>")
   1201     ("i/" . "<img src=\"|\" />")
   1202     ("j/" . "<script>|</script>")
   1203     ("l/" . "<li>|</li>")
   1204     ("m/" . "<main>|</main>")
   1205     ("n/" . "<input type=\"|\" />")
   1206     ("p/" . "<p>|</p>")
   1207     ("q/" . "<quote>|</quote>")
   1208     ("s/" . "<span>|</span>")
   1209     ("t/" . "<td>|</td>")
   1210     ("u/" . "<ul><li>|</li><li></li></ul>")
   1211     ("x/" . "<textarea>|</textarea>")
   1212     ("2/" . "<h2>|</h2>")
   1213     ("3/" . "<h3>|</h3>")
   1214     ("?/" . "<?php | ?>")))
   1215 
   1216 (defvar web-mode-engines-auto-pairs
   1217   '(("angular"          . (("{{ " . " }}")))
   1218     ("anki"             . (("{{ " . " }}")))
   1219     ("artanis"          . (("<% "       . " %>")
   1220                            ("<%="       . " | %>")
   1221                            ("<@css"     . " | %>")
   1222                            ("<@icon"    . " | %>")
   1223                            ("<@include" . " | %>")
   1224                            ("<@js"      . " | %>")))
   1225     ("asp"              . (("<% " . " %>")))
   1226     ("aspx"             . (("<% " . " %>")
   1227                            ("<%=" . "%>")
   1228                            ("<%#" . "%>")
   1229                            ("<%$" . "%>")
   1230                            ("<%@" . "%>")
   1231                            ("<%:" . "%>")
   1232                            ("<%-" . "- | --%>")))
   1233     ("blade"            . (("{{{" . " | }}}")
   1234                            ("{{ " . " }}")
   1235                            ("{!!" . " | !!}")
   1236                            ("@{{" . " | }}")
   1237                            ("{{-" . "- | --}}")))
   1238     ("cl-emb"           . (("<% " . " %>")
   1239                            ("<%=" . " | %>")
   1240                            ("<%#" . " | %>")))
   1241     ("ctemplate"        . (("{{ " . "| }}")
   1242                            ("{{~ " . "| }}")
   1243                            ("{{{" . " | }}}")
   1244                            ("{~{" . " | }}")
   1245                            ("{{~{" . " | }}}")
   1246                            ("{{!" . "-- | --}}")
   1247                            ("{{^" . "}}")
   1248                            ("{{/" . "}}")
   1249                            ("{{#" . "}}")))
   1250     ("django"           . (("{{ " . " }}")
   1251                            ("{% " . " %}")
   1252                            ("{%-" . " | %}")
   1253                            ("{# " . " #}")))
   1254     ("elixir"           . (("<% " . " %>")
   1255                            ("<%=" . " | %>")
   1256                            ("<%%" . " | %>")
   1257                            ("<%#" . " | %>")))
   1258     ("ejs"              . (("<% " . " %>")
   1259                            ("<%=" . "%>")
   1260                            ("<%#" . "%>")
   1261                            ("<%-" . "%>")))
   1262     ("erb"              . (("<% " . " %>")
   1263                            ("<%=" . " %>")
   1264                            ("<%#" . "%>")
   1265                            ("<%-" . " %>")))
   1266     ("freemarker"       . (("<% " . " %>")
   1267                            ("<#-" . "- | -->")
   1268                            ("${ " . " }")
   1269                            ("[% " . " %]")
   1270                            ("[# " . " #]")
   1271                            ("[#-" . "- | --]")))
   1272     ("go"               . (("{{ " . " }}")
   1273                            ("{{-" . " | -}}")))
   1274     ("hero"             . (("<% " . " %>")
   1275                            ("<%=" . " | %>")
   1276                            ("<%!" . " | %>")
   1277                            ("<%:" . " | %>")
   1278                            ("<%#" . " | %>")
   1279                            ("<%@" . " | %>")
   1280                            ("<%~" . " | %>")
   1281                            ("<%+" . " | %>")))
   1282     ("jsp"              . (("<% " . " %>")
   1283                            ("<%-" . "- | --%>")
   1284                            ("<%=" . "%>")
   1285                            ("<%!" . "%>")
   1286                            ("<%@" . "%>")
   1287                            ("${ " . " }")))
   1288     ("lsp"              . (("<% " . " %>")
   1289                            ("<%%" . " | %>")
   1290                            ("<%#" . " | %>")))
   1291     ("mako"             . (("<% " . " %>")
   1292                            ("<%!" . " | %>")
   1293                            ("${ " . " }")))
   1294     ("marko"            . (("${ " . " }")))
   1295     ("mason"            . (("<% " . " %>")
   1296                            ("<& " . " &>")))
   1297     ("mojolicious"      . (("<% " . " %>")
   1298                            ("<%=" . " | %>")
   1299                            ("<%%" . " | %>")
   1300                            ("<%#" . " | %>")))
   1301     ("php"              . (("<?p" . "hp | ?>")
   1302                            ("<? " . " ?>")
   1303                            ("<?=" . "?>")))
   1304     ("template-toolkit" . (("[% " . " %]")
   1305                            ("[%-" . " | %]")
   1306                            ("[%#" . " | %]")))
   1307     ("riot"             . (("={ " . " }")))
   1308     ("underscore"       . (("<% " . " %>")))
   1309     ("vue"              . (("{{ " . " }}")))
   1310     ("web2py"           . (("{{ " . " }}")
   1311                            ("{{=" . "}}")))
   1312     (nil                . (("<!-" . "- | -->")))
   1313     ))
   1314 
   1315 (defvar web-mode-engines-snippets
   1316   '(("artanis" . (("if"       . "<% (if (|) %>\n\n<% ) %>")
   1317                   ("when"     . "<% (when (|) %>\n\n<% ) %>")
   1318                   ("unless"   . "<% (unless (|) %>\n\n<% ) %>")
   1319                   ("cond"     . "<% (cond %>\n<%  [(|) %>\n\n<%  ] %>\n<%  [else %>\n\n<%  ] %>\n<% ) %>")
   1320                   ("let"      . "<% (let ([|]) %>\n\n<% ) %>")
   1321                   ("let*"     . "<% (let* ([|]) %>\n\n<% ) %>")
   1322                   ("do"       . "<% (do ([|]) %>\n<%     [()] %>\n\n<% ) %>")
   1323                   ("for-each" . "<% (for-each %>\n|\n\n<% ) %>")
   1324                   ("case"     . "<% (case | %>\n<%   [() %>\n\n<%   ] %>\n<%   [() %>\n\n<%   ] %>\n<% ) %>")))
   1325     ("ejs" . (("for"     . "<% for (|) { %>\n\n<% } %>")
   1326               ("if"      . "<% if (|) { %>\n\n<% } %>")))
   1327     ("erb" . (("each"    . "<% |.each do  %>\n\n<% end %>")
   1328               ("if"      . "<% if | %>\n\n<% end %>")
   1329               ("when"    . "<% when | %>\n\n<% end %>")
   1330               ("unless"  . "<% unless | %>\n\n<% end %>")))
   1331     ("php" . (("if"      . "<?php if (|): ?>\n\n<?php endif; ?>")
   1332               ("while"   . "<?php while (|): ?>\n\n<?php endwhile; ?>")
   1333               ("for"     . "<?php for (| ; ; ): ?>\n\n<?php endfor; ?>")
   1334               ("foreach" . "<?php foreach (| as ): ?>\n\n<?php endforeach; ?>")
   1335               ("each"    . "<?php foreach (| as ): ?>\n\n<?php endforeach; ?>")
   1336               ("switch"  . "<?php switch (|): ?>\n<?php case 1: ?>\n\n<?php break ;?>\n<?php case 2: ?>\n\n<?php break ;?>\n<?php endswitch;?>")))
   1337     ("django" . (("block"      . "{% block | %}\n\n{% endblock %}")
   1338                  ("comment"    . "{% comment | %}\n\n{% endcomment %}")
   1339                  ("css"        . "{% stylesheet  %}\n\n{% endstylesheet  %}")
   1340                  ("cycle"      . "{% cycle | as  %}\n\n{% endcycle  %}")
   1341                  ("filter"     . "{% filter | %}\n\n{% endfilter %}")
   1342                  ("for"        . "{% for | in  %}\n\n{% endfor %}")
   1343                  ("if"         . "{% if | %}\n\n{% endif %}")
   1344                  ("ifequal"    . "{% ifequal | %}\n\n{% endifequal %}")
   1345                  ("ifnotequal" . "{% ifnotequal | %}\n\n{% endifnotequal %}")
   1346                  ("js"         . "{% javascript | %}\n\n{% endjavascript %}")
   1347                  ("schema"     . "{% javascript | %}\n\n{% endschema %}")
   1348                  ("safe"       . "{% safe | %}\n\n{% endsafe %}")))
   1349     ("mako" . (("if"        . "% if |:\n% endif")
   1350                ("for"       . "% for | in :\n% endfor")
   1351                ("doc"       . "<%doc>\n|\n</%doc>")
   1352                ("inherit"   . "<%inherit file=\"|\" />")
   1353                ("namespace" . "<%namespace name=\"|\" file=\"\" import=\"\"/>")
   1354                ("block"     . "<%block name=\"|\">\n</%block>")))
   1355     ("template-toolkit" . (("if"      . "[% IF | %]\n\n[% END %]")))
   1356     (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>")
   1357             ("table" . "<table><tbody>\n<tr>\n<td>|</td>\n<td></td>\n</tr>\n</tbody></table>")
   1358             ("ul"    . "<ul>\n<li>|</li>\n<li></li>\n</ul>")))
   1359     ))
   1360 
   1361 (defvar web-mode-engine-token-regexps
   1362   (list
   1363    '("artanis"     . "\"\\|#|\\|;")
   1364    '("asp"         . "//\\|/\\*\\|\"\\|''")
   1365    '("ejs"         . "//\\|/\\*\\|\"\\|'")
   1366    '("erb"         . "\"\\|'\\|#\\|<<[-]?['\"]?\\([[:alnum:]_]+\\)['\"]?")
   1367    '("lsp"         . "\"\\|#|\\|;")
   1368    '("mako"        . "\"\\|'\\|#")
   1369    '("mason"       . "\"\\|'\\|#")
   1370    '("mojolicious" . "\"\\|'")
   1371    '("php"         . "//\\|/\\*\\|#\\|\"\\|'\\|<<<['\"]?\\([[:alnum:]]+\\)['\"]?")
   1372    '("python"      . "\"\\|'\\|#")
   1373    '("web2py"      . "\"\\|'"))
   1374   "Engine regexps used to identify tokens (strings / comments) in blocks.")
   1375 
   1376 (defvar web-mode-engine-open-delimiter-regexps
   1377   (list
   1378    '("angular"          . "{{")
   1379    '("anki"             . "{{")
   1380    '("artanis"          . "<%\\|<@\\(css\\|icon\\|include\\|js\\)")
   1381    '("asp"              . "<%\\|</?[[:alpha:]]+:[[:alpha:]]+\\|</?[[:alpha:]]+Template")
   1382    '("aspx"             . "<%.")
   1383    '("blade"            . "{{.\\|{!!\\|@{{\\|@[[:alpha:]]")
   1384    '("cl-emb"           . "<%")
   1385    '("closure"          . "{.\\|/\\*\\| //")
   1386    '("clip"             . "</?c:[[:alpha:]-]+")
   1387    '("ctemplate"        . "[$]?{[{~].")
   1388    '("django"           . "{[#{%]\\|^#")
   1389    '("dust"             . "{.")
   1390    '("elixir"           . "<%\\|</?[.:]")
   1391    '("ejs"              . "<%")
   1392    '("erb"              . "<%\\|^%.")
   1393    '("expressionengine" . "{.")
   1394    '("freemarker"       . "<%\\|${\\|</?[[:alpha:]]+:[[:alpha:]]\\|</?[@#]\\|\\[/?[@#].")
   1395    '("go"               . "{{.")
   1396    '("hero"             . "<%")
   1397    '("jsp"              . "<%\\|${")
   1398    '("lsp"              . "<%")
   1399    '("mako"             . "</?%\\|${\\|^[ \t]*%.\\|^[ \t]*##")
   1400    '("marko"            . "${")
   1401    '("mason"            . "</?[&%]\\|^%.")
   1402    '("mojolicious"      . "<%\\|^[ \t]*%.")
   1403    '("perl"             . "</?TMPL_[[:alpha:]]+")
   1404    '("php"              . "<\\?")
   1405    '("python"           . "<\\?")
   1406    '("razor"            . "@.\\|^[ \t]*}")
   1407    '("riot"             . "{.\\|/// begin script")
   1408    '("smarty"           . "{[[:alpha:]#$/*\"]")
   1409    '("spip"             . "\\[(#REM)\\|(\\|#[A-Z0-9_]\\|{\\|<:")
   1410    '("template-toolkit" . "\\[%\\(.\\|$\\)\\|%%#")
   1411    '("underscore"       . "<%")
   1412    '("velocity"         . "#[[:alpha:]#*]\\|$[[:alpha:]!{]")
   1413    '("vue"              . "{{\\|[:@][-[:alpha:]]+=\"")
   1414    '("web2py"           . "{{")
   1415    '("xoops"            . "<{[[:alpha:]#$/*\"]")
   1416    '("svelte"           . "{.")
   1417    )
   1418   "Engine regexps used to identify blocks.")
   1419 
   1420 (defvar web-mode-normalization-rules
   1421   '(("tag-case"          . "lower-case")
   1422     ("attr-case"         . "lower-case")
   1423     ("special-chars"     . "unicode") ;"unicode" "entities"
   1424     ("css-indentation"   . t)
   1425     ("smart-apostrophes" . t)
   1426     ("smart-quotes"      . t)
   1427     ("whitespaces"       . t)
   1428     ("indentation"       . t))
   1429   "Normalization rules")
   1430 
   1431 (defvar web-mode-element-tag-faces
   1432   (list
   1433    '("h1"     . web-mode-underline-face)
   1434    '("h2"     . web-mode-underline-face)
   1435    '("h3"     . web-mode-underline-face)
   1436    '("h4"     . web-mode-underline-face)
   1437    '("title"  . web-mode-underline-face)
   1438    '("em"     . web-mode-italic-face)
   1439    '("strong" . web-mode-bold-face)
   1440    ))
   1441 
   1442 (defvar web-mode-element-content-faces
   1443   (list
   1444    '("h1"     . web-mode-underline-face)
   1445    '("h2"     . web-mode-underline-face)
   1446    '("h3"     . web-mode-underline-face)
   1447    '("h4"     . web-mode-underline-face)
   1448    '("title"  . web-mode-underline-face)
   1449    '("em"     . web-mode-italic-face)
   1450    '("strong" . web-mode-bold-face)
   1451    ))
   1452 
   1453 (defvar web-mode-comment-keywords
   1454   (regexp-opt
   1455    (append
   1456     (cdr (assoc "comment" web-mode-extra-keywords))
   1457     '("FIXME" "TODO" "BUG" "KLUDGE" "WORKAROUND" "OPTIMIZE" "HACK" "REFACTOR" "REVIEW"))))
   1458 
   1459 (defvar web-mode-links
   1460   '(("\\.\\(png\\|jpe?g\\|gif\\|webp\\)$" "<img src=\"%s\" alt=\"\" />" nil 4)
   1461     ("\\.svg$" "<object data=\"%s\" type=\"image/svg+xml\"></object>" nil 0)
   1462     ("\\.js$" "<script type=\"text/javascript\" src=\"%s\"></script>" t 0)
   1463     ("\\.css$" "<link rel=\"stylesheet\" type=\"text/css\" href=\"%s\" />" t 0)
   1464     ("\\.html?$" "<a href=\"%s\"></a>" nil 4))
   1465   "List of elements and extensions for `web-mode-file-link'. It
   1466 consists of a string that contains the regular expression that
   1467 matches the appropriate files, a format string with element that
   1468 contains the link (%s should be put where the path goes,) a bool
   1469 that tells if the element belongs in the <head> element, and
   1470 number of characters to move back if needed (or 0 if point
   1471 shouldn't be moved back.)")
   1472 
   1473 (defvar web-mode-sql-queries
   1474   (regexp-opt
   1475    '("SELECT" "INSERT" "UPDATE" "DELETE" "select" "insert" "update" "delete")))
   1476 
   1477 (defvar web-mode-sql-keywords
   1478   (regexp-opt
   1479    (append
   1480     (cdr (assoc "sql" web-mode-extra-keywords))
   1481     '("SELECT" "INSERT" "UPDATE" "DELETE"
   1482       "FROM" "WHERE" "GROUP BY" "LIKE" "LIMIT" "HAVING" "JOIN" "LEFT" "INNER"
   1483       "FULL" "OUTER" "VALUES" "ORDER BY" "SEPARATOR" "ASC" "DESC"
   1484       "AND" "OR" "ON" "WHEN" "ELSE" "END" "THEN"))))
   1485 
   1486 (defvar web-mode-python-constants
   1487   (regexp-opt
   1488    (append
   1489     (cdr (assoc "python" web-mode-extra-constants))
   1490     '("True" "False" "None" "__debug__" "NotImplemented" "Ellipsis"))))
   1491 
   1492 (defvar web-mode-elixir-keywords
   1493   (regexp-opt
   1494    (append
   1495     (cdr (assoc "elixir" web-mode-extra-keywords))
   1496     '("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"))))
   1497 
   1498 
   1499 (defvar web-mode-elixir-constants
   1500   (regexp-opt
   1501    (append
   1502     (cdr (assoc "elixir" web-mode-extra-constants))
   1503     '("nil" "true" "false"))))
   1504 
   1505 (defvar web-mode-erlang-constants
   1506   (regexp-opt
   1507    (append
   1508     (cdr (assoc "erlang" web-mode-extra-constants))
   1509     '("true" "false"))))
   1510 
   1511 (defvar web-mode-erlang-keywords
   1512   (regexp-opt
   1513    (append
   1514     (cdr (assoc "erlang" web-mode-extra-keywords))
   1515     '("else" "if" "do" "end"))))
   1516 
   1517 (defvar web-mode-cl-emb-constants
   1518   (regexp-opt
   1519    '("nil" "t" "raw" "escape")))
   1520 
   1521 (defvar web-mode-cl-emb-keywords
   1522   (regexp-opt
   1523    '("if" "else" "endif" "unless" "endunless" "var" "repeat"
   1524      "endrepeat" "loop" "endloop" "include" "call" "with"
   1525      "endwith" "set" "genloop" "endgenloop" "insert")))
   1526 
   1527 (defvar web-mode-artanis-constants
   1528   (regexp-opt
   1529    '("#f" "#t")))
   1530 
   1531 (defvar web-mode-artanis-keywords
   1532   (regexp-opt
   1533    (append
   1534     (cdr (assoc "artanis" web-mode-extra-keywords))
   1535     '("begin" "cut" "cute" "if" "when" "unless" "cond" "case"
   1536       "do" "quote" "syntax" "lambda" "lambda*" "and" "and-let*"
   1537       "or" "else" "delay" "receive" "use-modules" "match"
   1538       "match-lambda" "match-lambda*" "match-let" "match-let*"
   1539       "match-letrec" "let" "let*" "letrec" "letrec*" "and-let*"
   1540       "let-syntax" "letrec-syntax" "syntax-rules" "syntax-case"
   1541       "define" "define-syntax" "define-macro"
   1542       "define-condition-type" "define-immutable-record-type"
   1543       "define-record-type" "define-values" "parameterize" "for-each"
   1544       "require-extension" "set!" "test-approximate" "test-assert"
   1545       "test-begin" "test-end" "test-eq" "test-equal" "test-eqv"
   1546       "test-error" "test-group" "test-group-with-cleanup" "test-with-runner"))))
   1547 
   1548 (defvar web-mode-lsp-constants
   1549   (regexp-opt
   1550    '("nil" "t")))
   1551 
   1552 (defvar web-mode-lsp-keywords
   1553   (regexp-opt
   1554    '("dolist" "let" "while" "cond" "when" "progn" "if"
   1555      "dotimes" "unless" "lambda"
   1556      "loop" "for" "and" "or" "in" "do" "defun")))
   1557 
   1558 (defvar web-mode-php-constants
   1559   (regexp-opt
   1560    (append
   1561     (cdr (assoc "php" web-mode-extra-constants))
   1562     '("TRUE" "FALSE" "NULL" "true" "false" "null"
   1563       "STR_PAD_LEFT" "STR_PAD_RIGHT"
   1564       "ENT_COMPAT" "ENT_QUOTES" "ENT_NOQUOTES" "ENT_IGNORE"
   1565       "ENT_SUBSTITUTE" "ENT_DISALLOWED" "ENT_HTML401" "ENT_XML1"
   1566       "ENT_XHTML" "ENT_HTML5" "JSON_PRETTY_PRINT"
   1567       "LIBXML_NOBLANKS"))))
   1568 
   1569 (defvar web-mode-php-keywords
   1570   (regexp-opt
   1571    (append
   1572     (cdr (assoc "php" web-mode-extra-keywords))
   1573     '("abstract" "and" "array" "as" "break" "case" "catch" "class" "clone"
   1574       "const" "continue" "declare" "default" "die" "do" "echo" "else" "elseif"
   1575       "empty" "enddeclare" "endfor" "endforeach" "endif" "endswitch" "endwhile"
   1576       "eval" "exit" "extends" "final" "finally" "fn" "for" "foreach" "function"
   1577       "global" "goto" "if" "implements" "include" "include_once" "instanceof"
   1578       "insteadof" "interface" "isset" "list" "namespace" "new" "or" "parent"
   1579       "print" "private" "protected" "public" "require" "require_once" "return"
   1580       "self" "static" "switch" "trait" "try" "throw" "unset" "use" "var"
   1581       "while" "xor" "yield" "yield from"))))
   1582 
   1583 (defvar web-mode-php-types
   1584   (eval-when-compile
   1585     (regexp-opt
   1586      '("array" "bool" "boolean" "callable" "float" "int" "integer"
   1587        "iterable" "mixed" "object" "resource" "string" "void"))))
   1588 
   1589 (defvar web-mode-css-at-rules
   1590   (eval-when-compile
   1591     (regexp-opt
   1592      '("charset" "import" "media" "page" "font-face"
   1593        "namespace" "supports" "document"
   1594        "keyframes" "-moz-keyframes" "-webkit-keyframes"
   1595        "mixin" "viewport"))))
   1596 
   1597 (defvar web-mode-css-pseudo-classes
   1598   (eval-when-compile
   1599     (regexp-opt
   1600      '("active" "after" "before" "checked" "disabled" "empty" "enabled"
   1601        "first" "first-child" "first-letter" "first-line" "first-of-type" "focus"
   1602        "hover" "lang" "last-child" "last-of-type" "left" "link"
   1603        "not" "nth-child" "nth-last-child" "nth-last-of-type" "nth-of-type"
   1604        "only-child" "only-of-type"
   1605        "right" "root" "selection" "target" "visited"))))
   1606 
   1607 (defvar web-mode-python-keywords
   1608   (regexp-opt
   1609    (append
   1610     (cdr (assoc "python" web-mode-extra-keywords))
   1611     '("and" "as" "assert" "break" "class" "continue" "def" "del"
   1612       "elif" "else" "except" "finally" "for" "from" "global"
   1613       "if" "import" "in" "is" "lambda" "nonlocal" "not" "or" "pass"
   1614       "raise" "return" "try" "while" "with" "yield"))))
   1615 
   1616 (defvar web-mode-jsp-keywords
   1617   (regexp-opt
   1618    (append
   1619     (cdr (assoc "jsp" web-mode-extra-keywords))
   1620     '("case" "catch" "do" "else" "end" "false" "for" "function"
   1621       "if" "in" "include"
   1622       "new" "package" "page" "private" "protected" "public"
   1623       "return" "tag" "taglib" "throw" "throws" "true" "try" "void" "while"))))
   1624 
   1625 (defvar web-mode-erb-keywords
   1626   (regexp-opt
   1627    (append
   1628     (cdr (assoc "erb" web-mode-extra-keywords))
   1629     '("alias" "and" "begin" "break" "case" "class" "def" "defined?" "do"
   1630       "elsif" "else" "end" "ensure" "fail" "for" "if" "in"
   1631       "module" "next" "not" "or" "redo" "rescue" "retry" "return"
   1632       "then" "super" "unless" "undef" "until" "when" "while" "yield"
   1633       "__ENCODING__" "__FILE__" "__LINE__"))))
   1634 
   1635 (defvar web-mode-mason-keywords
   1636   (regexp-opt
   1637    (append
   1638     (cdr (assoc "mason" web-mode-extra-keywords))
   1639     '("and" "base" "close" "die" "each" "else" "elsif" "eval" "exists"
   1640       "foreach" "grep" "if" "length" "local" "my" "next" "open" "or"
   1641       "package" "pop" "ref" "return" "stat" "sub" "tie"
   1642       "undef" "unless" "use" "while"))))
   1643 
   1644 (defvar web-mode-erb-builtins
   1645   (regexp-opt
   1646    (append
   1647     (cdr (assoc "erb" web-mode-extra-builtins))
   1648 
   1649     '("__callee__" "__dir__" "__method__"
   1650       "abort" "at_exit" "autoload" "autoload?"
   1651       "binding" "block_given?" "caller" "catch"
   1652       "eval" "exec" "exit" "exit!" "fail" "fork" "format"
   1653       "lambda" "load" "loop" "open"
   1654       "p" "print" "printf" "proc" "putc" "puts"
   1655       "raise" "rand" "readline" "readlines" "require" "require_relative"
   1656       "sleep" "spawn" "sprintf" "srand" "syscall" "system"
   1657       "throw" "trap" "warn"
   1658       "alias_method" "attr" "attr_accessor" "attr_reader" "attr_writer"
   1659       "define_method" "extend" "include" "module_function"
   1660       "prepend" "private" "protected" "public"
   1661       "refine" "using"
   1662 
   1663       "error_message_on" "error_messages_for" "form" "input"
   1664       "auto_discovery_link_tag" "image_tag" "javascript_include_tag"
   1665       "stylesheet_link_tag" "image_path" "path_to_image"" "
   1666       "javascript_path" "path_to_javascript" "register_javascript_expansion"
   1667       "register_javascript_include_default" "register_stylesheet_expansion"
   1668       "stylesheet_path" "path_to_stylesheet" "atom_feed" "entry" "updated"
   1669       "benchmark" "cache" "capture" "content_for" "distance_of_time_in_words"
   1670       "distance_of_time_in_words_to_now" "time_ago_in_words" "date_select"
   1671       "datetime_select" "time_select" "select_date" "select_datetime"
   1672       "select_day" "select_hour" "select_minute" "select_month" "select_second"
   1673       "select_time" "select_year" "debug"
   1674       "check_box" "fields_for" "file_field" "form_for" "hidden_field"
   1675       "label" "password_field" "radio_button" "text_area" "text_field"
   1676       "check_box_tag" "field_set_tag" "file_field_tag" "form_with" "form_tag"
   1677       "hidden_field_tag" "image_submit_tag" "label_tag" "password_field_tag"
   1678       "radio_button_tag" "select_tag" "submit_tag" "text_area_tag"
   1679       "text_field_tag"
   1680       "collection_select" "country_options_for_select" "country_select"
   1681       "option_groups_from_collection_for_select" "options_for_select"
   1682       "options_from_collection_for_select" "select"
   1683       "time_zone_options_for_select"
   1684       "time_zone_select" "button_to_function" "define_javascript_functions"
   1685       "escape_javascript" "javascript_tag" "link_to_function"" "
   1686       "number_to_currency" "number_to_human_size" "number_to_percentage"
   1687       "number_to_phone" "number_with_delimiter" "number_with_precision"
   1688       "evaluate_remote_response" "form_remote_for" "form_remote_tag"
   1689       "link_to_remote" "observe_field" "observe_field"
   1690       "periodically_call_remote"
   1691       "remote_form_for" "remote_function" "submit_to_remote" "update_page"
   1692       "update_page_tag" "dom_class" "dom_id" "partial_path" "sanitize"
   1693       "sanitize_css" "strip_links" "strip_tags"
   1694       "cdata_section" "content_tag" "escape_once" "tag"
   1695       "auto_link" "concat" "cycle" "excerpt" "highlight" "markdown" "pluralize"
   1696       "reset_cycle" "simple_format" "textilize" "textilize_without_paragraph"
   1697       "truncate" "word_wrap" "button_to" "current_page?" "link_to" "link_to_if"
   1698       "link_to_unless" "link_to_unless_current" "mail_to" "url_for"
   1699       "action_name" "atom_feed" "audio_path" "audio_tag"
   1700       "content_tag_for" "controller" "controller_name" "action_name"
   1701       "controller_path" "convert_to_model" "cookies" "csrf_meta_tag"
   1702       "csrf_meta_tags" "headers"
   1703       "current_cycle" "div_for" "email_field" "email_field_tag"
   1704       "favicon_link_tag" "flash" "l" "button_tag"
   1705       "grouped_collection_select" "grouped_options_for_select"
   1706       "image_alt" "j" "javascript_cdata_section"
   1707       "localize" "logger" "number_field"
   1708       "number_field_tag" "number_to_human" "params" "path_to_audio"
   1709       "path_to_video" "phone_field" "phone_field_tag" "provide"
   1710       "range_field" "range_field_tag" "raw" "render" "request"
   1711       "request_forgery_protection_token" "response" "safe_concat"
   1712       "safe_join" "search_field" "search_field_tag"
   1713       "session" "t" "telephone_field" "telephone_field_tag"
   1714       "time_tag" "translate" "url_field" "url_field_tag"
   1715       "url_options" "video_path" "video_tag" "simple_form_for"
   1716       "javascript_pack_tag" "stylesheet_pack_tag" "csp_meta_tag"
   1717 
   1718       ))))
   1719 
   1720 (defvar web-mode-asp-constants
   1721   (regexp-opt
   1722    (append
   1723     (cdr (assoc "asp" web-mode-extra-constants))
   1724     '("adAsyncExecute" "adAsyncFetch" "adAsyncFetchNonBlocking" "adCmdFile"
   1725       "adCmdStoredProc" "adCmdTable" "adCmdTableDirect" "adCmdText" "adCmdUnknown"
   1726       "adCmdUnspecified" "adExecuteNoRecords" "adExecuteRecord" "adExecuteStream"
   1727       "adLockBatchOptimistic" "adLockOptimistic" "adLockPessimistic"
   1728       "adLockReadOnly" "adLockUnspecified" "adOpenDynamic" "adOpenForwardOnly"
   1729       "adOpenKeyset" "adOpenStatic" "adOpenUnspecified" "adOptionUnspecified"
   1730       "Empty" "Nothing" "Null" "True" "False"
   1731       "vbBack" "vbCr" "vbCrLf" "vbFormFeed" "vbLf" "vbNewLine" "vbNullChar"
   1732       "vbNullString" "vbObjectError" "vbScript" "vbTab" "vbVerticalTab"))))
   1733 
   1734 (defvar web-mode-asp-keywords
   1735   (regexp-opt
   1736    (append
   1737     (cdr (assoc "asp" web-mode-extra-keywords))
   1738     '("Abs" "And" "Array" "Asc" "Atn"
   1739       "CBool" "CByte" "CCur" "CDate" "CDbl" "CInt" "CLng" "CSng" "CStr"
   1740       "Call" "Case" "Chr" "Class" "Const" "Cos" "CreateObject"
   1741       "Date" "DateAdd" "DateDiff" "DatePart" "DateSerial" "DateValue"
   1742       "Day" "Dim" "Do"
   1743       "Each" "Else" "ElseIf" "End" "Erase" "Err" "Eval" "Exit" "Exp"
   1744       "Explicit"
   1745       "Filter" "Fix" "For" "FormatCurrency" "FormatDateTime"
   1746       "FormatNumber" "FormatPercent" "Function"
   1747       "GetLocale" "GetObject" "GetRef" "Hex" "Hour"
   1748       "If" "In" "InStr" "InStrRev" "InputBox" "Int" "IsArray" "IsDate"
   1749       "IsEmpty" "IsNull" "IsNumeric" "IsObject" "Join"
   1750       "LBound" "LCase" "LTrim" "Language" "Left" "Len" "Let"
   1751       "LoadPicture" "Log" "Loop"
   1752       "Mid" "Minute" "Month" "MonthName" "MsgBox"
   1753       "New" "Next" "Not" "Now"
   1754       "Oct" "On" "Option" "Or" "Preserve" "Private" "Public"
   1755       "RGB" "RTrim" "Redim" "Rem" "Replace" "Right" "Rnd" "Round"
   1756       "ScriptEngine" "ScriptEngineBuildVersion"
   1757       "ScriptEngineMajorVersion" "ScriptEngineMinorVersion"
   1758       "Second" "Select" "Set" "SetLocale" "Sgn" "Sin" "Space" "Split"
   1759       "Sqr" "StrComp" "StrReverse" "String" "Sub"
   1760       "Tan" "Then" "Time" "TimeSerial" "TimeValue" "Timer" "To" "Trim"
   1761       "TypeName"
   1762       "UBound" "UCase" "Until" "VarType"
   1763       "Weekday" "WeekdayName" "Wend" "With" "While" "Year"))))
   1764 
   1765 (defvar web-mode-asp-types
   1766   (regexp-opt
   1767    (append
   1768     (cdr (assoc "asp" web-mode-extra-types))
   1769     '("Application" "ASPError" "Request" "Response" "Server" "Session"))))
   1770 
   1771 (defvar web-mode-aspx-keywords
   1772   (regexp-opt
   1773    (append
   1774     (cdr (assoc "aspx" web-mode-extra-keywords))
   1775     '("case" "catch" "do" "else" "end" "for" "foreach" "function"
   1776       "if" "in" "include" "new" "package" "page" "return"
   1777       "tag" "throw" "throws" "try" "while"))))
   1778 
   1779 (defvar web-mode-smarty-keywords
   1780   (regexp-opt '("as")))
   1781 
   1782 (defvar web-mode-velocity-keywords
   1783   (eval-when-compile
   1784     (regexp-opt '("in" "true" "false"))))
   1785 
   1786 (defvar web-mode-freemarker-keywords
   1787   (eval-when-compile
   1788     (regexp-opt '("as" "list"))))
   1789 
   1790 (defvar web-mode-go-keywords
   1791   (eval-when-compile
   1792     (regexp-opt
   1793      '("const" "define" "else" "end"
   1794        "for" "func" "if" "import"
   1795        "pipeline" "range" "return" "struct"
   1796        "template" "type" "var" "with"))))
   1797 
   1798 (defvar web-mode-go-functions
   1799   (eval-when-compile
   1800     (regexp-opt
   1801      '("and" "call" "ge" "html" "index" "js" "len" "not" "or"
   1802        "print" "printf" "println" "urlquery" "where"))))
   1803 
   1804 (defvar web-mode-go-types
   1805   (regexp-opt
   1806    (append
   1807     (cdr (assoc "go" web-mode-extra-types))
   1808     '("int" "string"))))
   1809 
   1810 (defvar web-mode-closure-keywords
   1811   (eval-when-compile
   1812     (regexp-opt '("in" "and" "not" "or"))))
   1813 
   1814 (defvar web-mode-svelte-keywords
   1815   (regexp-opt '("as")))
   1816 
   1817 (defvar web-mode-django-control-blocks
   1818   (append
   1819    (cdr (assoc "django" web-mode-extra-control-blocks))
   1820    '(
   1821 
   1822      "assets" "autoescape"
   1823      "block" "blocktrans"
   1824      "cache" "call" "capture" "comment"
   1825      "draw"
   1826      "embed"
   1827      "filter" "for" "foreach" "form"
   1828      "if" "ifchanged" "ifequal" "ifnotequal"
   1829      "macro"
   1830      "random" "raw"
   1831      "safe" "sandbox" "spaceless"
   1832      "tablerow"
   1833      "unless"
   1834      "verbatim"
   1835      "with"
   1836 
   1837      "endassets" "endautoescape"
   1838      "endblock" "endblocktrans"
   1839      "endcache" "endcall" "endcapture" "endcomment"
   1840      "draw"
   1841      "endembed"
   1842      "endfilter" "endfor" "endforeach" "endform"
   1843      "endif" "endifchanged" "endifequal" "endifnotequal"
   1844      "endmacro"
   1845      "endrandom" "endraw"
   1846      "endsafe" "endsandbox" "endspaceless"
   1847      "endtablerow"
   1848      "endunless"
   1849      "endverbatim"
   1850      "endwith"
   1851 
   1852      ;; "set" "endset" ;#504
   1853 
   1854      "csrf_token" "cycle" "debug"
   1855      "elif" "else" "elseif" "elsif" "empty" "extends"
   1856      "firstof" "include" "load" "lorem" "now" "regroup" "ssi"
   1857      "trans" "templatetag" "url" "widthratio"
   1858 
   1859      ;; #805
   1860      "graph" "endgraph"
   1861      "javascript" "endjavascript"
   1862      "schema" "endschema"
   1863      "stylesheet" "endstylesheet"
   1864 
   1865      )))
   1866 
   1867 (defvar web-mode-django-control-blocks-regexp
   1868   (regexp-opt web-mode-django-control-blocks t))
   1869 
   1870 (defvar web-mode-django-keywords
   1871   (eval-when-compile
   1872     (regexp-opt
   1873      '("and" "as" "assign"
   1874        "break"
   1875        "cache" "call" "case" "context" "continue"
   1876        "do"
   1877        "flush" "from"
   1878        "ignore" "import" "in" "is"
   1879        "layout" "load"
   1880        "missing"
   1881        "none" "not"
   1882        "or"
   1883        "pluralize"
   1884        "random"
   1885        "set" ;#504
   1886        "unless" "use"
   1887        "var"
   1888        ))))
   1889 
   1890 (defvar web-mode-django-types
   1891   (eval-when-compile
   1892     (regexp-opt '("null" "false" "true"))))
   1893 
   1894 (defvar web-mode-blade-control-blocks
   1895   (append
   1896    (cdr (assoc "blade" web-mode-extra-control-blocks))
   1897    '("component" "foreach" "forelse" "for" "if" "section" "slot" "switch" "unless" "while")
   1898    ))
   1899 
   1900 (defvar web-mode-blade-control-blocks-regexp
   1901   (regexp-opt web-mode-blade-control-blocks t))
   1902 
   1903 (defvar web-mode-directives
   1904   (eval-when-compile
   1905     (regexp-opt
   1906      '("include" "page" "taglib"
   1907        "Assembly" "Control" "Implements" "Import"
   1908        "Master" "OutputCache" "Page" "Reference" "Register"))))
   1909 
   1910 (defvar web-mode-template-toolkit-keywords
   1911   (regexp-opt
   1912    '("block" "call" "case" "catch" "clear" "default" "do"
   1913      "else" "elsif" "end" "filter" "final" "for"
   1914      "foreach" "get" "if" "in" "include" "insert" "is" "last"
   1915      "macro" "meta" "or" "perl" "process" "rawperl" "return"
   1916      "set" "stop" "switch" "tags" "throw" "try"
   1917      "unless" "use" "while" "wrapper")))
   1918 
   1919 (defvar web-mode-perl-keywords
   1920   (regexp-opt
   1921    '("__DATA__" "__END__" "__FILE__" "__LINE__" "__PACKAGE__"
   1922      "and" "cmp" "continue" "CORE" "do" "else" "elsif" "eq" "exp"
   1923      "for" "foreach" "ge" "gt" "if" "le" "lock" "lt" "m" "ne" "no"
   1924      "or" "package" "q" "qq" "qr" "qw" "qx" "s" "sub"
   1925      "tr" "unless" "until" "while" "xor" "y"
   1926      "my" "use" "print" "say")))
   1927 
   1928 (defvar web-mode-javascript-keywords
   1929   (regexp-opt
   1930    (append
   1931     (cdr (assoc "javascript" web-mode-extra-keywords))
   1932     '("as" "async" "await" "break" "case" "catch" "class" "const" "continue"
   1933       "debugger" "default" "delete" "do" "else" "enum" "eval"
   1934       "export" "extends" "finally" "for" "from" "function" "get" "if"
   1935       "implements" "import" "in" "instanceof" "interface" "let"
   1936       "new" "of" "package" "private" "protected" "public"
   1937       "return" "set" "static" "super" "switch"
   1938       "throw" "try" "type" "typeof" "var" "void" "while" "with" "yield"))))
   1939 
   1940 (defvar web-mode-javascript-constants
   1941   (regexp-opt
   1942    '("false" "null" "undefined" "Infinity" "NaN" "true" "arguments" "this")))
   1943 
   1944 (defvar web-mode-razor-keywords
   1945   (regexp-opt
   1946    (append
   1947     (cdr (assoc "razor" web-mode-extra-keywords))
   1948     '("false" "true" "foreach" "if" "else" "in" "var" "for" "display"
   1949       "match" "case" "to"
   1950       "Html"))))
   1951 
   1952 (defvar web-mode-selector-font-lock-keywords
   1953   (list
   1954    '("$[[:alnum:]-]+" 0 'web-mode-css-variable-face)
   1955    (cons (concat "@\\(" web-mode-css-at-rules "\\)\\_>")
   1956          '(0 'web-mode-css-at-rule-face))
   1957    '("\\_<\\(all\|braille\\|embossed\\|handheld\\|print\\|projection\\|screen\\|speech\\|tty\\|tv\\|and\\|or\\)\\_>"
   1958      1 'web-mode-keyword-face)
   1959    '("\\.[^ ,]+" 0 'web-mode-css-selector-class-face)
   1960    '("[^,]+" 0 'web-mode-css-selector-tag-face)
   1961    (cons (concat ":\\([ ]*[[:alpha:]][^,{]*\\)") '(0 'web-mode-css-pseudo-class-face t t))
   1962    ))
   1963 
   1964 (defvar web-mode-declaration-font-lock-keywords
   1965   (list
   1966    '("--[[:alnum:]-]+" 0 'web-mode-css-variable-face)
   1967    '("$[[:alnum:]-]+" 0 'web-mode-css-variable-face)
   1968    (cons (concat "@\\(" web-mode-css-at-rules "\\)\\_>") '(1 'web-mode-css-at-rule-face))
   1969    '("\\([[:alpha:]-]+\\)[ ]?:" 0 'web-mode-css-property-name-face)
   1970    '("\\([[:alpha:]-]+\\)[ ]?(" 1 'web-mode-css-function-face)
   1971    '("#[[:alnum:]]\\{1,6\\}" 0 'web-mode-css-color-face t t)
   1972    '("![ ]?important" 0 'web-mode-css-priority-face t t)
   1973    '("\\([^,]+\\)[ ]+{" 1 'web-mode-css-selector-face)
   1974    '("'[^']*'\\|\"[^\"]*\"" 0 'web-mode-string-face t t)
   1975    ))
   1976 
   1977 (defvar web-mode-html-font-lock-keywords
   1978   (list
   1979    '("</?[[:alnum:]]+[ >]\\|>" 0 'web-mode-html-tag-face t)
   1980    '(" \\([[:alnum:]-]+=\\)\\(\"[^\"]+\"\\)"
   1981      (1 'web-mode-html-attr-name-face)
   1982      (2 'web-mode-html-attr-value-face))
   1983    ))
   1984 
   1985 ;; voir https://www.gnu.org/software/emacs/manual/html_node/elisp/Search_002dbased-Fontification.html
   1986 (defvar web-mode-javascript-font-lock-keywords
   1987   (list
   1988    '("@\\([[:alnum:]_]+\\)\\_>" 0 'web-mode-keyword-face)
   1989    '("\\([[:alnum:]]+\\)[`]" 0 'web-mode-preprocessor-face)
   1990    (cons (concat "\\_<\\(function\\*\\)\\_>") '(1 'web-mode-keyword-face))
   1991    (cons (concat "\\([ \t}{(]\\|^\\)\\(" web-mode-javascript-keywords "\\)\\_>") '(2 'web-mode-keyword-face))
   1992    (cons (concat "\\_<\\(" web-mode-javascript-constants "\\)\\_>") '(0 'web-mode-constant-face))
   1993    '("\\_<\\([$]\\)(" 1 'web-mode-type-face)
   1994    '("\\_<\\(new\\|instanceof\\|class\\|extends\\) \\([[:alnum:]_.]+\\)\\_>" 2 'web-mode-type-face)
   1995    '("\\_<\\([[:alnum:]_]+\\):[ ]*function[ ]*(" 1 'web-mode-function-name-face)
   1996    '("\\_<\\(function\\|get\\|set\\)[ ]+\\([[:alnum:]_]+\\)"
   1997      (1 'web-mode-keyword-face)
   1998      (2 'web-mode-function-name-face))
   1999    '("\\([[:alnum:]_]+\\)[ ]*([^)]*)[ \n]*{" 1 'web-mode-function-name-face)
   2000    '("([ ]*\\([[:alnum:]_]+\\)[ ]*=>" 1 'web-mode-function-name-face)
   2001    '("[ ]*\\([[:alnum:]_]+\\)[ ]*=[ ]*([^)]*)[ ]*=>[ ]*{" 1 'web-mode-function-name-face)
   2002    '("\\_<\\(var\\|let\\|const\\)[ ]+\\([[:alnum:]_]+\\)" 2 'web-mode-variable-name-face)
   2003    '("({" "\\([[:alnum:]_]+\\)[, }]+" nil nil (1 'web-mode-variable-name-face)) ;#738
   2004    '("\\([[:alnum:]_]+\\)[ ]*=> [{(]" 1 'web-mode-variable-name-face)
   2005    ;; #989
   2006    ;; '("\\(function\\|[,=]\\|^\\)[ ]*("
   2007    ;;   ("\\([[:alnum:]_]+\\)\\([ ]*=[^,)]*\\)?[,)]" nil nil (1 'web-mode-variable-name-face)))
   2008    '("\\([[:alnum:]_]+\\):" 1 'web-mode-variable-name-face)
   2009    '("\\_<\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2010    '("[a-zA-Z]<\\([a-zA-Z]+\\)[,>]" 1 'web-mode-type-face)
   2011    ))
   2012 
   2013 (defvar web-mode-stylus-font-lock-keywords
   2014   (list
   2015    '("^[ \t]*\\([[:alnum:]().-]+\\)$" 1 'web-mode-css-selector-face)
   2016    '("^[ \t]*\\([[:alnum:]-]+[ ]*:\\)" 1 'web-mode-css-property-name-face)
   2017    ))
   2018 
   2019 (defvar web-mode-sass-font-lock-keywords
   2020   (list
   2021    '("^[ \t]*\\([[:alnum:]().-]+\\|&:\\(before\\|after\\)\\)$" 1 'web-mode-css-selector-face)
   2022    '("^[ \t]*\\([[:alnum:]-]+[ ]*:\\)" 1 'web-mode-css-property-name-face)
   2023    ))
   2024 
   2025 (defvar web-mode-pug-font-lock-keywords
   2026   (list
   2027    '("^[ \t]*\\(#?[[:alnum:].-]+\\)" 1 'web-mode-css-selector-face)
   2028    ;;'("^[ \t]*\\(#[[:alnum:]-]+\\)" 0 'web-mode-css-selector-face)
   2029    '(" \\([@:]?\\sw+[ ]?=\\)" 1 'web-mode-param-name-face)
   2030    ))
   2031 
   2032 (defvar web-mode-sql-font-lock-keywords
   2033   (list
   2034    (cons (concat "\\_<\\(" web-mode-sql-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2035    '("\\_<\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2036    ))
   2037 
   2038 (defvar web-mode-markdown-font-lock-keywords
   2039   (list
   2040    '("^[ ]*[*].*$" 0 'web-mode-variable-name-face)
   2041    '("^[ ]*#.*$" 0 'web-mode-comment-face)
   2042    ))
   2043 
   2044 (defvar web-mode-html-tag-font-lock-keywords
   2045   (list
   2046    '("\\(</?\\)\\([[:alnum:]]+\\)"
   2047      (1 'web-mode-html-tag-bracket-face)
   2048      (2 'web-mode-html-tag-face))
   2049    '("\"[^\"]*\"" 0 'web-mode-html-attr-value-face)
   2050    '("\\([[:alnum:]]+\\)" 1 'web-mode-html-attr-name-face)
   2051    '("/?>" 0 'web-mode-html-tag-bracket-face)
   2052   ))
   2053 
   2054 (defvar web-mode-anki-font-lock-keywords
   2055   (list
   2056    '("{{[#/^]\\([[:alnum:]_.]+\\)" 1 'web-mode-block-control-face)
   2057    ;;'("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_.: ]*\\)"
   2058    ;;  (1 'web-mode-block-attr-name-face)
   2059    ;;  (2 'web-mode-block-attr-value-face))
   2060    '("{{\\(.+\\)}}" 1 'web-mode-variable-name-face)
   2061    ))
   2062 
   2063 (defvar web-mode-dust-font-lock-keywords
   2064   (list
   2065    '("{[#:/?@><+^]\\([[:alpha:]_.]+\\)" 1 'web-mode-block-control-face)
   2066    '(":\\([[:alpha:]]+\\)" 1 'web-mode-keyword-face)
   2067    '("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_]*\\)"
   2068      (1 'web-mode-block-attr-name-face)
   2069      (2 'web-mode-block-attr-value-face))
   2070    '("\\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face)
   2071    ))
   2072 
   2073 (defvar web-mode-expressionengine-font-lock-keywords
   2074   (list
   2075    '("{/?\\([[:alpha:]_]+:[[:alpha:]_:]+\\|if\\)" 1 'web-mode-block-control-face)
   2076    '(":\\([[:alpha:]_]+\\)" 1 'web-mode-keyword-face)
   2077    '(" {\\([[:alpha:]_]+\\)}" 1 'web-mode-keyword-face t)
   2078    '("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_]*\\)"
   2079      (1 'web-mode-block-attr-name-face)
   2080      (2 'web-mode-block-attr-value-face))
   2081    '("\\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face)
   2082    ))
   2083 
   2084 (defvar web-mode-svelte-font-lock-keywords
   2085   (list
   2086    (cons (concat "[ ]\\(" web-mode-svelte-keywords "\\)[ ]") '(1 'web-mode-keyword-face))
   2087    '("{[#:/@]\\([[:alpha:]_.]+\\)" 1 'web-mode-block-control-face)
   2088    '("\\_<\\([[:alnum:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_]*\\)"
   2089       (1 'web-mode-block-attr-name-face)
   2090       (2 'web-mode-block-attr-value-face))
   2091    '("\\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face)
   2092    '("\\_<\\([$]\\)\\([[:alnum:]_]+\\)" (1 'web-mode-constant-face) (2 'web-mode-variable-name-face))
   2093    ))
   2094 
   2095 (defvar web-mode-template-toolkit-font-lock-keywords
   2096   (list
   2097    (cons (concat "\\_<\\(" web-mode-template-toolkit-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2098    '("\\\([[:alpha:]][[:alnum:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2099    '("\\\([[:alpha:]][[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2100    ))
   2101 
   2102 (defvar web-mode-smarty-font-lock-keywords
   2103   (list
   2104    (cons (concat "[ ]\\(" web-mode-smarty-keywords "\\)[ ]") '(1 'web-mode-keyword-face))
   2105    '("{/?\\([[:alpha:]_]+\\)" 1 'web-mode-block-control-face)
   2106    '("\\([}{]\\)" 0 'web-mode-block-delimiter-face)
   2107    '("\\_<\\([$]\\)\\([[:alnum:]_]+\\)" (1 nil) (2 'web-mode-variable-name-face))
   2108    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2109    '(" \\(\\sw+[ ]?=\\)" 1 'web-mode-param-name-face)
   2110    '(" \\(\\sw+\\)[ }]" 1 'web-mode-param-name-face)
   2111    '("|\\([[:alnum:]_]+\\)" 1 'web-mode-function-call-face)
   2112    '("\\(->\\)\\(\\sw+\\)" (1 nil) (2 'web-mode-variable-name-face))
   2113    '("[.]\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2114    '("[.]\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2115    '("#\\([[:alnum:]_]+\\)#" 1 'web-mode-variable-name-face)
   2116    ))
   2117 
   2118 (defvar web-mode-velocity-font-lock-keywords
   2119   (list
   2120    '("#{?\\([[:alpha:]_]+\\)\\_>" (1 'web-mode-block-control-face))
   2121    (cons (concat "\\_<\\(" web-mode-velocity-keywords "\\)\\_>") '(1 'web-mode-keyword-face t t))
   2122    '("#macro([ ]*\\([[:alpha:]]+\\)[ ]+" 1 'web-mode-function-name-face)
   2123    '("\\(def\\|define\\) \\([[:alnum:]_-]+\\)(" 2 'web-mode-function-name-face)
   2124    '("[.]\\([[:alnum:]_-]+\\)" 1 'web-mode-variable-name-face)
   2125    '("\\_<\\($[!]?[{]?\\)\\([[:alnum:]_-]+\\)[}]?" (1 nil) (2 'web-mode-variable-name-face))
   2126    ))
   2127 
   2128 (defvar web-mode-mako-tag-font-lock-keywords
   2129   (list
   2130    '("</?%\\([[:alpha:]:]+\\)" 1 'web-mode-block-control-face)
   2131    '("\\_<\\([[:alpha:]]+=\\)\\(\"[^\"]*\"\\)"
   2132      (1 'web-mode-block-attr-name-face t t)
   2133      (2 'web-mode-block-attr-value-face t t))
   2134    ))
   2135 
   2136 (defvar web-mode-mako-block-font-lock-keywords
   2137   (list
   2138    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2139    (cons (concat "\\_<\\(" web-mode-python-constants "\\)\\_>") '(1 'web-mode-constant-face))
   2140    (cons (concat "\\_<\\(" web-mode-python-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2141    (cons (concat "\\_<\\(endfor\\|endif\\|endwhile\\)\\_>") '(1 'web-mode-keyword-face))
   2142    ))
   2143 
   2144 (defvar web-mode-web2py-font-lock-keywords
   2145   (list
   2146    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2147    (cons (concat "\\_<\\(" web-mode-python-constants "\\)\\_>") '(1 'web-mode-constant-face))
   2148    (cons (concat "\\_<\\(" web-mode-python-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2149    (cons (concat "\\_<\\(block\\|extend\\|super\\|end\\|include\\)\\_>") '(1 'web-mode-keyword-face))
   2150    ))
   2151 
   2152 (defvar web-mode-django-expr-font-lock-keywords
   2153   (list
   2154    '("|[ ]?\\([[:alpha:]_]+\\)\\_>" 1 'web-mode-filter-face)
   2155    (cons (concat "\\_<\\(" web-mode-django-types "\\)\\_>") '(1 'web-mode-type-face))
   2156    '("\\_<\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2157    '("[[:alnum:]_]+" 0 'web-mode-variable-name-face)
   2158    ))
   2159 
   2160 (defvar web-mode-django-code-font-lock-keywords
   2161   (list
   2162    '("{%[ ]*\\(set\\)[ ]+\\([[:alpha:]]+\\)[ ]*%}"
   2163      (1 'web-mode-block-control-face)
   2164      (2 'web-mode-variable-name-face))
   2165    (cons (concat "\\({%\\|#\\)[ ]*\\(" web-mode-django-control-blocks-regexp "\\)[ %]") '(2 'web-mode-block-control-face))
   2166    '("\\({%\\|#\\)[ ]*\\(end[[:alpha:]]+\\)\\_>" 2 'web-mode-block-control-face) ;#504
   2167    (cons (concat "\\_<\\(" web-mode-django-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2168    (cons (concat "\\_<\\(" web-mode-django-types "\\)\\_>") '(1 'web-mode-type-face))
   2169    '("|[ ]?\\([[:alpha:]_]+\\)\\_>" 1 'web-mode-function-call-face)
   2170    '("\\_<\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2171    '("[[:alnum:]_.]+" 0 'web-mode-variable-name-face)
   2172    '("[[:alnum:]_]+\\([.][[:alnum:]_]+\\)+" 0 'web-mode-variable-name-face t t)
   2173    ))
   2174 
   2175 (defvar web-mode-ctemplate-font-lock-keywords
   2176   (list
   2177    '("{[~]?{[#/>^]?[ ]*\\([[:alnum:]_.-]+\\)" 1 'web-mode-block-control-face)
   2178    '("[ \t]+\\([[:alnum:]_-]+\\)="
   2179      (1 'web-mode-block-attr-name-face))
   2180    '("\"[^\"]+\"" 0 'web-mode-block-string-face)
   2181    ))
   2182 
   2183 (defvar web-mode-razor-font-lock-keywords
   2184   (list
   2185    '("@\\([[:alnum:]_.]+\\)[ ]*[({]" 1 'web-mode-block-control-face)
   2186    (cons (concat "\\_<\\(" web-mode-razor-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2187    '("\\_<\\(String\\)\\_>" 1 'web-mode-type-face)
   2188    '("\\([[:alnum:]]+:\\)" 1 'web-mode-symbol-face)
   2189    '("\\(@[[:alnum:]_.]+\\)" 1 'web-mode-variable-name-face)
   2190    ))
   2191 
   2192 (defvar web-mode-riot-font-lock-keywords
   2193   (list
   2194    '("\\(parent\\|opts\\|tags\\|this\\)\\.\\([[:alnum:]_.]+\\)"
   2195      (1 'web-mode-constant-face)
   2196      (2 'web-mode-variable-name-face))
   2197    '("\\([[:alnum:]_.]+\\)" 0 'web-mode-variable-name-face)
   2198    ))
   2199 
   2200 (defvar web-mode-closure-font-lock-keywords
   2201   (list
   2202    '("{\\([@/]?[[:alpha:]]+[?]?\\)" 1 'web-mode-block-control-face)
   2203    '("{[@]?param[?]?[ ]+\\([[:alnum:]]+[:]?\\)" 1 'web-mode-symbol-face)
   2204    '("\\_<\\(true\\|false\\|null\\)\\_>" 1 'web-mode-type-face)
   2205    '("\\\_<[[:alpha:]]+:[ ]+\\([[:alpha:]]+\\)" 1 'web-mode-type-face)
   2206    (cons (concat "\\_<\\(" web-mode-closure-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2207    '("{\\(alias\\|call\\|delcall\\|delpackage\\|deltemplate\\|namespace\\|template\\)[ ]+\\([[:alnum:].]+\\)" 2 'web-mode-constant-face)
   2208    '("\\(allowemptydefault\\|data\\|desc\\|meaning\\|autoescape\\|private\\|variant\\)=" 0 'web-mode-block-attr-name-face)
   2209    '("|\\([[:alpha:]]+\\)" 1 'web-mode-function-call-face)
   2210    '("\\_<\\([[:alnum:]]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2211    '("$\\([[:alnum:]._]+\\)" 1 'web-mode-variable-name-face)
   2212    ))
   2213 
   2214 (defvar web-mode-go-font-lock-keywords
   2215   (list
   2216    '("{{[-]?[ ]*\\([[:alpha:]]+\\)" 1 'web-mode-block-control-face)
   2217    '("\\_<func \\([[:alnum:]]+\\)" 1 'web-mode-function-name-face)
   2218    '("\\_<type \\([[:alnum:]]+\\)" 1 'web-mode-type-face)
   2219    (cons (concat "\\_<\\(" web-mode-go-types "\\)\\_>") '(0 'web-mode-type-face))
   2220    (cons (concat "\\_<\\(" web-mode-go-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2221    (cons (concat "\\_<\\(" web-mode-go-functions "\\)\\_>") '(1 'web-mode-function-call-face))
   2222    '("[$.]\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face t t)
   2223    '("|[ ]?\\([[:alpha:]_]+\\)\\_>" 1 'web-mode-filter-face)
   2224    ))
   2225 
   2226 (defvar web-mode-expression-font-lock-keywords
   2227   (list
   2228    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2229    ))
   2230 
   2231 (defvar web-mode-angular-font-lock-keywords
   2232   (list
   2233    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2234    ))
   2235 
   2236 (defvar web-mode-underscore-font-lock-keywords
   2237   (list
   2238    (cons (concat "\\_<\\(" web-mode-javascript-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2239    '("\\_<\\(_\.[[:alpha:]]+\\)(" 1 'web-mode-function-call-face)
   2240    '("\\_<new \\([[:alnum:]_.]+\\)\\_>" 1 'web-mode-type-face)
   2241    '("\\_<\\([[:alnum:]_]+\\):[ ]*function[ ]*(" 1 'web-mode-function-name-face)
   2242    '("\\_<\\(var\\)\\_>[ ]+\\([[:alnum:]_]+\\)"
   2243      (1 'web-mode-keyword-face)
   2244      (2 'web-mode-variable-name-face))
   2245    ))
   2246 
   2247 (defvar web-mode-vue-font-lock-keywords
   2248   (list
   2249    '("\\_<\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2250    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2251    ))
   2252 
   2253 (defvar web-mode-engine-tag-font-lock-keywords
   2254   (list
   2255    '("</?\\([[:alpha:]]+\\(?:Template\\|[:.][[:alpha:]-]+\\)\\|TMPL_[[:alpha:]]+\\)" 1 'web-mode-block-control-face)
   2256    '("\\_<\\([[:alpha:]-]+=\\)\\(\"[^\"]*\"\\)"
   2257      (1 'web-mode-block-attr-name-face t t)
   2258      (2 'web-mode-block-attr-value-face t t))
   2259    '("\\_<\\([[:alpha:]-]+=\\)\\('[^']*\'\\)"
   2260      (1 'web-mode-block-attr-name-face t t)
   2261      (2 'web-mode-block-attr-value-face t t))
   2262    ))
   2263 
   2264 (defvar web-mode-jsp-font-lock-keywords
   2265   (list
   2266    '("\\(throws\\|new\\|extends\\)[ ]+\\([[:alnum:].]+\\)" 2 'web-mode-type-face)
   2267    (cons (concat "\\_<\\(" web-mode-jsp-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2268    '("\\(public\\|private\\)[ ]+\\([[:alpha:]]+\\)[ ]+\\([[:alnum:]._]+\\)[ ]?("
   2269      (2 'web-mode-type-face)
   2270      (3 'web-mode-function-name-face))
   2271    '("\\_<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2272    '("@\\(\\sw*\\)" 1 'web-mode-variable-name-face)
   2273    '("\\_<\\([[:alnum:].]+\\)[ ]+[{[:alpha:]]+" 1 'web-mode-type-face)
   2274    ))
   2275 
   2276 (defvar web-mode-asp-font-lock-keywords
   2277   (list
   2278    (cons (concat "\\_<\\(" web-mode-asp-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2279    (cons (concat "\\_<\\(" web-mode-asp-types "\\)\\_>") '(0 'web-mode-type-face))
   2280    (cons (concat "\\_<\\(" web-mode-asp-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2281    '("\\(Class\\|new\\) \\([[:alnum:]_]+\\)" 2 'web-mode-type-face)
   2282    '("Const \\([[:alnum:]_]+\\)" 1 'web-mode-constant-face)
   2283    '("\\_<dim\\_>"
   2284      (0 'web-mode-keyword-face)
   2285      ("[[:alnum:]_]+" nil nil (0 'web-mode-variable-name-face)))
   2286    '("\\_<\\(public\\|private\\|sub\\|function\\)\\_> \\([[:alnum:]_]+\\)[ ]*(" 2 'web-mode-function-name-face)
   2287    '("\\_<\\(public\\|private\\|dim\\)\\_> \\([[:alnum:]_]+\\)" 2 'web-mode-variable-name-face)
   2288    ))
   2289 
   2290 (defvar web-mode-aspx-font-lock-keywords
   2291   (list
   2292    (cons (concat "\\_<\\(" web-mode-aspx-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2293    '("\\_<\\([[:alnum:].]+\\)[ ]+[[:alpha:]]+" 1 'web-mode-type-face)
   2294    ))
   2295 
   2296 (defvar web-mode-uel-font-lock-keywords
   2297   (list
   2298    '("[$#{]{\\|}" 0 'web-mode-preprocessor-face)
   2299    '("\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2300    '("|[ ]*\\(trim\\|x\\|u\\)" 1 'web-mode-function-call-face)
   2301    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2302    ))
   2303 
   2304 (defvar web-mode-php-var-interpolation-font-lock-keywords
   2305   (list
   2306    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
   2307    '("\".+\"\\|'.*'" 0 'web-mode-string-face)
   2308    ))
   2309 
   2310 (defvar web-mode-marko-font-lock-keywords
   2311   (list
   2312    '("[[:alnum:]_]+" 0 'web-mode-variable-name-face)
   2313    ))
   2314 
   2315 (defvar web-mode-freemarker-square-font-lock-keywords
   2316   (list
   2317    '("\\[/?[#@]\\([[:alpha:]_.]*\\)" 1 'web-mode-block-control-face)
   2318    '("#\\(macro\\|function\\) \\([[:alpha:]]+\\)" 2 'web-mode-function-name-face)
   2319    (cons (concat "\\_<\\(" web-mode-freemarker-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2320    '("\\_<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2321    '("[[:alpha:]]\\([[:alnum:]_]+\\)?" 0 'web-mode-variable-name-face)
   2322    ))
   2323 
   2324 (defvar web-mode-freemarker-font-lock-keywords
   2325   (list
   2326    '("</?[#@]\\([[:alpha:]_.]*\\)" 1 'web-mode-block-control-face)
   2327    '("#\\(macro\\|function\\) \\([[:alpha:]]+\\)" 2 'web-mode-function-name-face)
   2328    (cons (concat "\\_<\\(" web-mode-freemarker-keywords "\\)\\_>") '(1 'web-mode-keyword-face))
   2329    '("\\_<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2330    '("[[:alpha:]]\\([[:alnum:]_]+\\)?" 0 'web-mode-variable-name-face)
   2331    ))
   2332 
   2333 (defvar web-mode-directive-font-lock-keywords
   2334   (list
   2335    '("<%@[ ]*\\([[:alpha:]]+\\)[ ]+" 1 'web-mode-block-control-face)
   2336    '("\\_<\\([[:alpha:]]+=\\)\\(\"[^\"]*\"\\)"
   2337      (1 'web-mode-block-attr-name-face t t)
   2338      (2 'web-mode-block-attr-value-face t t))
   2339    ))
   2340 
   2341 (defvar web-mode-erb-font-lock-keywords
   2342   (list
   2343    '("[^:]\\(:[[:alnum:]_]+\\)" 1 'web-mode-symbol-face)
   2344    '("\\([[:alnum:]_]+:\\)[ ]+" 1 'web-mode-symbol-face)
   2345    (cons (concat "\\_<\\(" web-mode-erb-builtins "\\)\\_>") '(0 'web-mode-builtin-face))
   2346    (cons (concat "\\_<\\(" web-mode-erb-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2347    '("\\_<\\(self\\|true\\|false\\|nil\\)\\_>" 0 'web-mode-variable-name-face)
   2348    '("[@$]@?\\([[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2349    '("class[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-type-face)
   2350    '("def[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2351    '("\\(?:\\_<\\|::\\)\\([A-Z]+[[:alnum:]_]+\\)" 1 (unless (eq (char-after) ?\() 'web-mode-type-face))
   2352    '("/[^/]+/" 0 'web-mode-string-face)
   2353    ))
   2354 
   2355 (defvar web-mode-ejs-font-lock-keywords
   2356   web-mode-javascript-font-lock-keywords)
   2357 
   2358 (defvar web-mode-python-font-lock-keywords
   2359   (list
   2360    (cons (concat "\\_<\\(" web-mode-python-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2361    ))
   2362 
   2363 (defvar web-mode-elixir-font-lock-keywords
   2364   (list
   2365    '("@\\([[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2366    '("[ ]\\(:[[:alnum:]-_]+\\)" 1 'web-mode-symbol-face)
   2367    '("def[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2368    (cons (concat "\\_<\\(" web-mode-elixir-keywords "\\)\\_>") '(0 'web-mode-builtin-face))
   2369    (cons (concat "\\_<\\(" web-mode-elixir-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2370    ))
   2371 
   2372 (defvar web-mode-erlang-font-lock-keywords
   2373   (list
   2374    (cons (concat "\\_<\\(" web-mode-erlang-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2375    (cons (concat "\\_<\\(" web-mode-erlang-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2376    '("@\\([[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
   2377    '("[ ]\\(:[[:alnum:]-_]+\\)" 1 'web-mode-symbol-face)
   2378    ))
   2379 
   2380 (defvar web-mode-mason-code-font-lock-keywords
   2381   (list
   2382    (cons (concat "\\_<\\(" web-mode-mason-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2383    '("sub[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2384    '("\\_<\\([[:alnum:]_]+\\)[ ]?::" 1 'web-mode-type-face)
   2385    '("\\([@]\\)\\([[:alnum:]#_]*\\)" (1 nil) (2 'web-mode-variable-name-face))
   2386    '("\\_<\\([$%]\\)\\([[:alnum:]@#_]*\\)" (1 nil) (2 'web-mode-variable-name-face))
   2387    '("{\\([[:alnum:]_]+\\)}" 1 'web-mode-variable-name-face)
   2388    '("\\_<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
   2389    '("[[:alnum:]_][ ]?::[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2390    '("->[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2391    '("\\(?:method\\|def\\) \\([[:alnum:]._]+\\)" 1 'web-mode-function-name-face)
   2392    '("|[ ]*\\([[:alnum:],]+\\)[ ]*%>" 1 'web-mode-filter-face)
   2393    ))
   2394 
   2395 (defvar web-mode-mason-block-font-lock-keywords
   2396   (list
   2397    '("<[/]?%\\([[:alpha:]]+\\)" 1 'web-mode-block-control-face)
   2398    '("[[:alpha:]]" 0 'web-mode-block-attr-value-face)
   2399    ))
   2400 
   2401 (defvar web-mode-mojolicious-font-lock-keywords
   2402   (list
   2403    (cons (concat "\\_<\\(" web-mode-perl-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2404    '("\\_<\\(begin\\|end\\)\\_>" 1 'web-mode-constant-face)
   2405    '("\\_<\\([$]\\)\\([[:alnum:]_]*\\)" (1 nil) (2 'web-mode-variable-name-face))
   2406    ))
   2407 
   2408 (defvar web-mode-lsp-font-lock-keywords
   2409   (list
   2410    (cons (concat "\\_<\\(" web-mode-lsp-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2411    (cons (concat "\\_<\\(" web-mode-lsp-constants "\\)\\_>") '(1 'web-mode-constant-face))
   2412    '("[ ]\\(:[[:alnum:]-_]+\\)" 1 'web-mode-symbol-face)
   2413    '("(defun \\([[:alnum:]-:]+\\)" 1 'web-mode-function-name-face)
   2414    '("(defvar \\([[:alnum:]-:]+\\)" 1 'web-mode-variable-name-face)
   2415    ))
   2416 
   2417 (defvar web-mode-cl-emb-font-lock-keywords
   2418   (list
   2419    (cons (concat "\\_<\\(" web-mode-cl-emb-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2420    (cons (concat "\\_<\\(" web-mode-cl-emb-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2421    '("\\(@\\)" 1 'web-mode-function-call-face)
   2422    (list (concat "\\(@" web-mode-cl-emb-keywords "\\)[ ]+\\([[:alnum:]_]+\\)")
   2423          '(1 'web-mode-keyword-face)
   2424          '(2 'web-mode-variable-name-face))
   2425    ))
   2426 
   2427 (defvar web-mode-artanis-font-lock-keywords
   2428   (list
   2429    (cons (concat "\\_<\\(" web-mode-artanis-keywords  "\\)\\_>") '(0 'web-mode-keyword-face))
   2430    (cons (concat "\\_<\\(" web-mode-artanis-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2431    '("(define[*]? (\\([[:alnum:]-:_!#$%^&*=+/?<>.]+\\)" 1 'web-mode-function-name-face)
   2432    '("\\(#:[[:alnum:]-:_!#$%^&*=+/?<>.]+\\)"            1 'web-mode-builtin-face)
   2433    ))
   2434 
   2435 (defvar web-mode-php-font-lock-keywords
   2436   (list
   2437    (cons (concat "\\_<\\(" web-mode-php-keywords "\\)\\_>") '(0 'web-mode-keyword-face))
   2438    (cons (concat "\\_<\\(" web-mode-php-types "\\)\\_>") '(1 'web-mode-type-face))
   2439    (cons (concat "\\_<\\(" web-mode-php-constants "\\)\\_>") '(0 'web-mode-constant-face))
   2440    '("function[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
   2441    '("\\_<\\([[:alnum:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
   2442    '("[[:alnum:]_][ ]?::[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-constant-face)
   2443    '("->[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
   2444    '("\\_<\\([[:alnum:]_]+\\)[ ]?::" 1 'web-mode-type-face)
   2445    '("\\_<\\(instanceof\\|class\\|extends\\|new\\)[ ]+\\([[:alnum:]_]+\\)" 2 'web-mode-type-face)
   2446    '("\\(\\_<\\|[+-]\\)\\([$]\\)\\([[:alnum:]_]*\\)" (2 nil) (3 'web-mode-variable-name-face))
   2447    ))
   2448 
   2449 (defvar web-mode-spip-font-lock-keywords
   2450   (list
   2451    '("<:.+:>" 0 'web-mode-block-string-face)
   2452    '("#[A-Z0-9_]+" 0 'web-mode-variable-name-face)
   2453    '("|[a-z0-9_=!?<>]+" 0 'web-mode-function-call-face)
   2454    '("(\\([[:alnum:]_ ]+\\))" 1 'web-mode-constant-face)
   2455    ))
   2456 
   2457 (defvar web-mode-latex-font-lock-keywords
   2458   (list
   2459    '("[[:alnum:]_]+" 0 'web-mode-function-name-face t t)
   2460    ))
   2461 
   2462 (defvar web-mode-blade-font-lock-keywords
   2463   (append
   2464    (list
   2465     '("@\\([[:alpha:]_]+\\)" (1 'web-mode-block-control-face)))
   2466    web-mode-php-font-lock-keywords))
   2467 
   2468 (defvar web-mode-engines-font-lock-keywords
   2469   '(("angular"          . web-mode-angular-font-lock-keywords)
   2470     ("anki"             . web-mode-anki-font-lock-keywords)
   2471     ("artanis"          . web-mode-artanis-font-lock-keywords)
   2472     ("blade"            . web-mode-blade-font-lock-keywords)
   2473     ("cl-emb"           . web-mode-cl-emb-font-lock-keywords)
   2474     ("closure"          . web-mode-closure-font-lock-keywords)
   2475     ("ctemplate"        . web-mode-ctemplate-font-lock-keywords)
   2476     ("dust"             . web-mode-dust-font-lock-keywords)
   2477     ("elixir"           . web-mode-elixir-font-lock-keywords)
   2478     ("ejs"              . web-mode-ejs-font-lock-keywords)
   2479     ("erb"              . web-mode-erb-font-lock-keywords)
   2480     ("expressionengine" . web-mode-expressionengine-font-lock-keywords)
   2481     ("go"               . web-mode-go-font-lock-keywords)
   2482     ("hero"             . web-mode-go-font-lock-keywords)
   2483     ("lsp"              . web-mode-lsp-font-lock-keywords)
   2484     ("marko"            . web-mode-marko-font-lock-keywords)
   2485     ("mojolicious"      . web-mode-mojolicious-font-lock-keywords)
   2486     ("php"              . web-mode-php-font-lock-keywords)
   2487     ("python"           . web-mode-python-font-lock-keywords)
   2488     ("razor"            . web-mode-razor-font-lock-keywords)
   2489     ("riot"             . web-mode-riot-font-lock-keywords)
   2490     ("smarty"           . web-mode-smarty-font-lock-keywords)
   2491     ("spip"             . web-mode-spip-font-lock-keywords)
   2492     ("template-toolkit" . web-mode-template-toolkit-font-lock-keywords)
   2493     ("underscore"       . web-mode-underscore-font-lock-keywords)
   2494     ("web2py"           . web-mode-web2py-font-lock-keywords)
   2495     ("velocity"         . web-mode-velocity-font-lock-keywords)
   2496     ("vue"              . web-mode-vue-font-lock-keywords)
   2497     ("xoops"            . web-mode-smarty-font-lock-keywords)
   2498     ("svelte"           . web-mode-svelte-font-lock-keywords)
   2499     )
   2500   "Engines font-lock keywords")
   2501 
   2502 (defvar web-mode-prettify-symbols-alist
   2503   '(("=>" . 8658)
   2504     (">=" . 8805)
   2505     ("<=" . 8804)))
   2506 
   2507 (defvar web-mode-before-auto-complete-hooks nil
   2508   "List of functions to run before triggering the auto-complete library.
   2509 
   2510 Auto-complete sources will sometimes need some tweaking to work
   2511 nicely with web-mode. This hook gives users the chance to adjust
   2512 the environment as needed for ac-sources, right before they're used.")
   2513 
   2514 (defvar web-mode-ignore-ac-start-advice nil
   2515   "If not nil 'defadvice' for 'ac-start' will be ignored.
   2516 
   2517 Can be set inside a hook in 'web-mode-before-auto-complete-hooks' to
   2518 non nil to ignore the defadvice which sets ac-sources according to current
   2519 language. This is needed if the corresponding auto-completion triggers
   2520 another auto-completion with different ac-sources (e.g. ac-php)")
   2521 
   2522 (defvar web-mode-ac-sources-alist nil
   2523   "alist mapping language names to ac-sources for that language.")
   2524 
   2525 (defvar web-mode-trace nil
   2526   "Activate debug tracing.")
   2527 
   2528 (defvar web-mode-syntax-table
   2529   (let ((table (make-syntax-table)))
   2530     (modify-syntax-entry ?- "_" table)
   2531     (modify-syntax-entry ?_ "_" table) ;#563
   2532     (modify-syntax-entry ?< "." table)
   2533     (modify-syntax-entry ?> "." table)
   2534     (modify-syntax-entry ?& "." table)
   2535     (modify-syntax-entry ?/ "." table)
   2536     (modify-syntax-entry ?= "." table)
   2537     (modify-syntax-entry ?% "." table)
   2538     table)
   2539   "Syntax table used to reveal whitespaces.")
   2540 
   2541 (defvar web-mode-map
   2542   (let ((map (make-sparse-keymap)))
   2543 
   2544     (define-key map [menu-bar wm]             (cons "Web-Mode" (make-sparse-keymap)))
   2545     (define-key map [menu-bar wm dom]         (cons "Dom" (make-sparse-keymap)))
   2546     (define-key map [menu-bar wm blk]         (cons "Block" (make-sparse-keymap)))
   2547     (define-key map [menu-bar wm attr]        (cons "Html Attr" (make-sparse-keymap)))
   2548     (define-key map [menu-bar wm tag]         (cons "Html Tag" (make-sparse-keymap)))
   2549     (define-key map [menu-bar wm elt]         (cons "Html Element" (make-sparse-keymap)))
   2550 
   2551     (define-key map [menu-bar wm sep-1]       '(menu-item "--"))
   2552 
   2553     (define-key map [menu-bar wm dom dom-xpa] '(menu-item "XPath" web-mode-dom-xpath))
   2554     (define-key map [menu-bar wm dom dom-tra] '(menu-item "Traverse" web-mode-dom-traverse))
   2555     (define-key map [menu-bar wm dom dom-err] '(menu-item "Show error(s)" web-mode-dom-errors-show))
   2556     (define-key map [menu-bar wm dom dom-ent] '(menu-item "Replace html entities" web-mode-dom-entities-replace))
   2557     (define-key map [menu-bar wm dom dom-quo] '(menu-item "Replace dumb quotes" web-mode-dom-quotes-replace))
   2558     (define-key map [menu-bar wm dom dom-apo] '(menu-item "Replace apostrophes" web-mode-dom-apostrophes-replace))
   2559     (define-key map [menu-bar wm dom dom-nor] '(menu-item "Normalize" web-mode-dom-normalize))
   2560 
   2561     (define-key map [menu-bar wm blk blk-sel] '(menu-item "Select" web-mode-block-select))
   2562     (define-key map [menu-bar wm blk blk-pre] '(menu-item "Previous" web-mode-block-previous))
   2563     (define-key map [menu-bar wm blk blk-nex] '(menu-item "Next" web-mode-block-next))
   2564     (define-key map [menu-bar wm blk blk-kil] '(menu-item "Kill" web-mode-block-kill))
   2565     (define-key map [menu-bar wm blk blk-end] '(menu-item "End" web-mode-block-end))
   2566     (define-key map [menu-bar wm blk blk-clo] '(menu-item "Close" web-mode-block-close))
   2567     (define-key map [menu-bar wm blk blk-beg] '(menu-item "Beginning" web-mode-block-beginning))
   2568 
   2569     (define-key map [menu-bar wm attr attr-ins] '(menu-item "Insert" web-mode-attribute-insert))
   2570     (define-key map [menu-bar wm attr attr-end] '(menu-item "End" web-mode-attribute-end))
   2571     (define-key map [menu-bar wm attr attr-beg] '(menu-item "Beginning" web-mode-attribute-beginning))
   2572     (define-key map [menu-bar wm attr attr-sel] '(menu-item "Select" web-mode-attribute-select))
   2573     (define-key map [menu-bar wm attr attr-kil] '(menu-item "Kill" web-mode-attribute-kill))
   2574     (define-key map [menu-bar wm attr attr-nex] '(menu-item "Next" web-mode-attribute-next))
   2575     (define-key map [menu-bar wm attr attr-pre] '(menu-item "Previous" web-mode-attribute-previous))
   2576     (define-key map [menu-bar wm attr attr-tra] '(menu-item "Transpose" web-mode-attribute-transpose))
   2577 
   2578     (define-key map [menu-bar wm tag tag-beg] '(menu-item "Sort Attributes" web-mode-tag-attributes-sort))
   2579     (define-key map [menu-bar wm tag tag-sel] '(menu-item "Select" web-mode-tag-select))
   2580     (define-key map [menu-bar wm tag tag-pre] '(menu-item "Previous" web-mode-tag-previous))
   2581     (define-key map [menu-bar wm tag tag-nex] '(menu-item "Next" web-mode-tag-next))
   2582     (define-key map [menu-bar wm tag tag-end] '(menu-item "End" web-mode-tag-end))
   2583     (define-key map [menu-bar wm tag tag-beg] '(menu-item "Beginning" web-mode-tag-beginning))
   2584 
   2585     (define-key map [menu-bar wm elt elt-con] '(menu-item "Contract" web-mode-element-contract))
   2586     (define-key map [menu-bar wm elt elt-ext] '(menu-item "Extract" web-mode-element-extract))
   2587     (define-key map [menu-bar wm elt elt-van] '(menu-item "Vanish" web-mode-element-vanish))
   2588     (define-key map [menu-bar wm elt elt-exc] '(menu-item "Transpose" web-mode-element-transpose))
   2589     (define-key map [menu-bar wm elt elt-sel] '(menu-item "Select" web-mode-element-select))
   2590     (define-key map [menu-bar wm elt elt-ren] '(menu-item "Rename" web-mode-element-rename))
   2591     (define-key map [menu-bar wm elt elt-pre] '(menu-item "Previous" web-mode-element-previous))
   2592     (define-key map [menu-bar wm elt elt-par] '(menu-item "Parent" web-mode-element-parent))
   2593     (define-key map [menu-bar wm elt elt-nex] '(menu-item "Next" web-mode-element-next))
   2594     (define-key map [menu-bar wm elt elt-mut] '(menu-item "Mute blanks" web-mode-element-mute-blanks))
   2595     (define-key map [menu-bar wm elt elt-del] '(menu-item "Kill" web-mode-element-kill))
   2596     (define-key map [menu-bar wm elt elt-end] '(menu-item "End" web-mode-element-end))
   2597     (define-key map [menu-bar wm elt elt-inn] '(menu-item "Content (select)" web-mode-element-content-select))
   2598     (define-key map [menu-bar wm elt elt-clo] '(menu-item "Close" web-mode-element-close))
   2599     (define-key map [menu-bar wm elt elt-ins] '(menu-item "Insert" web-mode-element-insert))
   2600     (define-key map [menu-bar wm elt elt-ins] '(menu-item "Word to tag" web-mode-element-insert-at-point))
   2601     (define-key map [menu-bar wm elt elt-dup] '(menu-item "Clone" web-mode-element-clone))
   2602     (define-key map [menu-bar wm elt elt-cfo] '(menu-item "Children fold" web-mode-element-children-fold-or-unfold))
   2603     (define-key map [menu-bar wm elt elt-chi] '(menu-item "Child" web-mode-element-child))
   2604     (define-key map [menu-bar wm elt elt-beg] '(menu-item "Beginning" web-mode-element-beginning))
   2605 
   2606     (define-key map [menu-bar wm fol]         '(menu-item "Fold/Unfold" web-mode-fold-or-unfold))
   2607     (define-key map [menu-bar wm hig]         '(menu-item "Fontify buffer" web-mode-buffer-fontify))
   2608     (define-key map [menu-bar wm ind]         '(menu-item "Indent buffer" web-mode-buffer-indent))
   2609     (define-key map [menu-bar wm nav]         '(menu-item "Tag/Block navigation" web-mode-navigate))
   2610     (define-key map [menu-bar wm exp]         '(menu-item "Mark and Expand" web-mode-mark-and-expand))
   2611     (define-key map [menu-bar wm spa]         '(menu-item "Toggle whitespaces" web-mode-whitespaces-show))
   2612     (define-key map [menu-bar wm sni]         '(menu-item "Insert snippet" web-mode-snippet-insert))
   2613 
   2614     ;;--------------------------------------------------------------------------
   2615     ;; "C-c <LETTER>" are reserved for users
   2616 
   2617     (define-key map (kbd "C-c C-a b") 'web-mode-attribute-beginning)
   2618     (define-key map (kbd "C-c C-a e") 'web-mode-attribute-end)
   2619     (define-key map (kbd "C-c C-a i") 'web-mode-attribute-insert)
   2620     (define-key map (kbd "C-c C-a n") 'web-mode-attribute-next)
   2621     (define-key map (kbd "C-c C-a s") 'web-mode-attribute-select)
   2622     (define-key map (kbd "C-c C-a k") 'web-mode-attribute-kill)
   2623     (define-key map (kbd "C-c C-a p") 'web-mode-attribute-previous)
   2624     (define-key map (kbd "C-c C-a t") 'web-mode-attribute-transpose)
   2625 
   2626     (define-key map (kbd "C-c C-b b") 'web-mode-block-beginning)
   2627     (define-key map (kbd "C-c C-b c") 'web-mode-block-close)
   2628     (define-key map (kbd "C-c C-b e") 'web-mode-block-end)
   2629     (define-key map (kbd "C-c C-b k") 'web-mode-block-kill)
   2630     (define-key map (kbd "C-c C-b n") 'web-mode-block-next)
   2631     (define-key map (kbd "C-c C-b p") 'web-mode-block-previous)
   2632     (define-key map (kbd "C-c C-b s") 'web-mode-block-select)
   2633 
   2634     (define-key map (kbd "C-c C-d a") 'web-mode-dom-apostrophes-replace)
   2635     (define-key map (kbd "C-c C-d d") 'web-mode-dom-errors-show)
   2636     (define-key map (kbd "C-c C-d e") 'web-mode-dom-entities-replace)
   2637     (define-key map (kbd "C-c C-d n") 'web-mode-dom-normalize)
   2638     (define-key map (kbd "C-c C-d q") 'web-mode-dom-quotes-replace)
   2639     (define-key map (kbd "C-c C-d t") 'web-mode-dom-traverse)
   2640     (define-key map (kbd "C-c C-d x") 'web-mode-dom-xpath)
   2641 
   2642     (define-key map (kbd "C-c C-e /") 'web-mode-element-close)
   2643     (define-key map (kbd "C-c C-e a") 'web-mode-element-content-select)
   2644     (define-key map (kbd "C-c C-e b") 'web-mode-element-beginning)
   2645     (define-key map (kbd "C-c C-e c") 'web-mode-element-clone)
   2646     (define-key map (kbd "C-c C-e d") 'web-mode-element-child)
   2647     (define-key map (kbd "C-c C-e e") 'web-mode-element-end)
   2648     (define-key map (kbd "C-c C-e f") 'web-mode-element-children-fold-or-unfold)
   2649     (define-key map (kbd "C-c C-e i") 'web-mode-element-insert)
   2650     (define-key map (kbd "C-c C-e I") 'web-mode-element-insert-at-point)
   2651     (define-key map (kbd "C-c C-e k") 'web-mode-element-kill)
   2652     (define-key map (kbd "C-c C-e m") 'web-mode-element-mute-blanks)
   2653     (define-key map (kbd "C-c C-e n") 'web-mode-element-next)
   2654     (define-key map (kbd "C-c C-e p") 'web-mode-element-previous)
   2655     (define-key map (kbd "C-c C-e r") 'web-mode-element-rename)
   2656     (define-key map (kbd "C-c C-e s") 'web-mode-element-select)
   2657     (define-key map (kbd "C-c C-e t") 'web-mode-element-transpose)
   2658     (define-key map (kbd "C-c C-e u") 'web-mode-element-parent)
   2659     (define-key map (kbd "C-c C-e v") 'web-mode-element-vanish)
   2660     (define-key map (kbd "C-c C-e w") 'web-mode-element-wrap)
   2661     (define-key map (kbd "C-c C-e +") 'web-mode-element-extract)
   2662     (define-key map (kbd "C-c C-e -") 'web-mode-element-contract)
   2663 
   2664     (define-key map (kbd "C-c C-t a") 'web-mode-tag-attributes-sort)
   2665     (define-key map (kbd "C-c C-t b") 'web-mode-tag-beginning)
   2666     (define-key map (kbd "C-c C-t e") 'web-mode-tag-end)
   2667     (define-key map (kbd "C-c C-t m") 'web-mode-tag-match)
   2668     (define-key map (kbd "C-c C-t n") 'web-mode-tag-next)
   2669     (define-key map (kbd "C-c C-t p") 'web-mode-tag-previous)
   2670     (define-key map (kbd "C-c C-t s") 'web-mode-tag-select)
   2671 
   2672     ;;--------------------------------------------------------------------------
   2673 
   2674     ;;(define-key map (kbd "M-q")       'fill-paragraph)
   2675     (define-key map (kbd "M-;")       'web-mode-comment-or-uncomment)
   2676 
   2677     ;;C-c C-a : attribute
   2678     ;;C-c C-b : block
   2679     ;;C-c C-d : dom
   2680     ;;C-c C-e : element
   2681     (define-key map (kbd "C-c C-f")   'web-mode-fold-or-unfold)
   2682     (define-key map (kbd "C-c C-h")   'web-mode-buffer-fontify)
   2683     (define-key map (kbd "C-c C-i")   'web-mode-buffer-indent)
   2684     (define-key map (kbd "C-c C-j")   'web-mode-jshint)
   2685     (define-key map (kbd "C-c C-l")   'web-mode-file-link)
   2686     (define-key map (kbd "C-c C-m")   'web-mode-mark-and-expand)
   2687     (define-key map (kbd "C-c C-n")   'web-mode-navigate)
   2688     (define-key map (kbd "C-c C-r")   'web-mode-reload)
   2689     (define-key map (kbd "C-c C-s")   'web-mode-snippet-insert)
   2690     ;;C-c C-t : tag
   2691     (define-key map (kbd "C-c C-w")   'web-mode-whitespaces-show)
   2692 
   2693     map)
   2694   "Keymap for `web-mode'.")
   2695 
   2696 ;;---- COMPATIBILITY -----------------------------------------------------------
   2697 
   2698 (eval-and-compile
   2699 
   2700   ;; compatibility with emacs < 23
   2701   (defun web-mode-string-match-p (regexp string &optional start)
   2702     "Same as `string-match' except it does not change the match data."
   2703     (let ((inhibit-changing-match-data t))
   2704       (string-match regexp string start)))
   2705 
   2706   (unless (fboundp 'string-match-p)
   2707     (fset 'string-match-p (symbol-function 'web-mode-string-match-p)))
   2708 
   2709   ;; compatibility with emacs < 23.3
   2710   (if (fboundp 'with-silent-modifications)
   2711       (defalias 'web-mode-with-silent-modifications 'with-silent-modifications)
   2712     (defmacro web-mode-with-silent-modifications (&rest body)
   2713       `(let ((old-modified-p (buffer-modified-p))
   2714              (inhibit-modification-hooks t)
   2715              (buffer-undo-list t))
   2716          (unwind-protect
   2717              ,@body
   2718            (restore-buffer-modified-p old-modified-p)))))
   2719 
   2720   ;; compatibility with emacs < 24.3
   2721   (defun web-mode-buffer-narrowed-p ()
   2722     (if (fboundp 'buffer-narrowed-p)
   2723         (buffer-narrowed-p)
   2724       (/= (- (point-max) (point-min)) (buffer-size))))
   2725 
   2726   ;; compatibility with emacs < 24
   2727   (defalias 'web-mode-prog-mode
   2728     (if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode))
   2729 
   2730   ;; compatibility with emacs < 24.3
   2731   (unless (fboundp 'setq-local)
   2732     (defmacro setq-local (var val)
   2733     `(set (make-local-variable ',var) ,val)))
   2734 
   2735   ;; compatability with emacs < 24.4
   2736   (defun web-mode-string-suffix-p (suffix string)
   2737     "Return t if STRING ends with SUFFIX."
   2738       (and (string-match (rx-to-string `(: ,suffix eos) t)
   2739                          string)
   2740            t))
   2741 
   2742   (unless (fboundp 'string-suffix-p)
   2743     (fset 'string-suffix-p (symbol-function 'web-mode-string-suffix-p)))
   2744 
   2745   (unless (fboundp 'seq-some)
   2746     (defun seq-some (pred seq)
   2747       (unless (null seq)
   2748         (or (funcall pred (car seq))
   2749             (seq-some pred (cdr seq))))))
   2750   ) ;eval-and-compile
   2751 
   2752 ;;---- MAJOR MODE --------------------------------------------------------------
   2753 
   2754 ;;;###autoload
   2755 (define-derived-mode web-mode web-mode-prog-mode "Web"
   2756   "Major mode for editing web templates."
   2757 
   2758   (make-local-variable 'web-mode-attr-indent-offset)
   2759   (make-local-variable 'web-mode-attr-value-indent-offset)
   2760   (make-local-variable 'web-mode-auto-pairs)
   2761   (make-local-variable 'web-mode-block-regexp)
   2762   (make-local-variable 'web-mode-change-beg)
   2763   (make-local-variable 'web-mode-change-end)
   2764   (make-local-variable 'web-mode-code-indent-offset)
   2765   (make-local-variable 'web-mode-column-overlays)
   2766   (make-local-variable 'web-mode-comment-formats)
   2767   (make-local-variable 'web-mode-comment-style)
   2768   (make-local-variable 'web-mode-content-type)
   2769   (make-local-variable 'web-mode-css-indent-offset)
   2770   (make-local-variable 'web-mode-display-table)
   2771   (make-local-variable 'web-mode-django-control-blocks)
   2772   (make-local-variable 'web-mode-django-control-blocks-regexp)
   2773   (make-local-variable 'web-mode-enable-block-face)
   2774   (make-local-variable 'web-mode-enable-inlays)
   2775   (make-local-variable 'web-mode-enable-part-face)
   2776   (make-local-variable 'web-mode-enable-sexp-functions)
   2777   (make-local-variable 'web-mode-engine)
   2778   (make-local-variable 'web-mode-engine-attr-regexp)
   2779   (make-local-variable 'web-mode-engine-file-regexps)
   2780   (make-local-variable 'web-mode-engine-open-delimiter-regexps)
   2781   (make-local-variable 'web-mode-engine-token-regexp)
   2782   (make-local-variable 'web-mode-expand-initial-pos)
   2783   (make-local-variable 'web-mode-expand-initial-scroll)
   2784   (make-local-variable 'web-mode-expand-previous-state)
   2785   (make-local-variable 'web-mode-indent-style)
   2786   (make-local-variable 'web-mode-indentless-attributes)
   2787   (make-local-variable 'web-mode-indentless-elements)
   2788   (make-local-variable 'web-mode-is-scratch)
   2789   (make-local-variable 'web-mode-skip-fontification)
   2790   (make-local-variable 'web-mode-jshint-errors)
   2791   (make-local-variable 'web-mode-last-enabled-feature)
   2792   (make-local-variable 'web-mode-markup-indent-offset)
   2793   (make-local-variable 'web-mode-minor-engine)
   2794   (make-local-variable 'web-mode-overlay-tag-end)
   2795   (make-local-variable 'web-mode-overlay-tag-start)
   2796   (make-local-variable 'web-mode-part-beg)
   2797   (make-local-variable 'web-mode-scan-beg)
   2798   (make-local-variable 'web-mode-scan-end)
   2799   (make-local-variable 'web-mode-sql-indent-offset)
   2800   (make-local-variable 'web-mode-time)
   2801   (make-local-variable 'web-mode-trace)
   2802 
   2803   (make-local-variable 'font-lock-beg)
   2804   (make-local-variable 'font-lock-end)
   2805 
   2806   (make-local-variable 'comment-end)
   2807   (make-local-variable 'comment-region-function)
   2808   (make-local-variable 'comment-start)
   2809   (make-local-variable 'fill-paragraph-function)
   2810   (make-local-variable 'font-lock-defaults)
   2811   (make-local-variable 'font-lock-extend-region-functions)
   2812   (make-local-variable 'font-lock-support-mode)
   2813   (make-local-variable 'font-lock-unfontify-region-function)
   2814   (make-local-variable 'imenu-case-fold-search)
   2815   (make-local-variable 'imenu-create-index-function)
   2816   (make-local-variable 'imenu-generic-expression)
   2817   (make-local-variable 'indent-line-function)
   2818   (make-local-variable 'parse-sexp-lookup-properties)
   2819   (make-local-variable 'uncomment-region-function)
   2820   (make-local-variable 'yank-excluded-properties)
   2821 
   2822   (setq web-mode-time (current-time))
   2823 
   2824   (setq comment-end "-->"
   2825         comment-region-function 'web-mode-comment-or-uncomment-region
   2826         comment-start "<!--"
   2827         fill-paragraph-function 'web-mode-fill-paragraph
   2828         ;;font-lock-defaults '(web-mode-font-lock-keywords t)
   2829         font-lock-defaults '('(web-mode-fontify) t)
   2830         font-lock-extend-region-functions '(web-mode-extend-region)
   2831         font-lock-support-mode nil
   2832         font-lock-unfontify-region-function 'web-mode-unfontify-region
   2833         imenu-case-fold-search t
   2834         imenu-create-index-function 'web-mode-imenu-index
   2835         indent-line-function 'web-mode-indent-line
   2836         parse-sexp-lookup-properties t
   2837         yank-excluded-properties t
   2838         uncomment-region-function 'web-mode-comment-or-uncomment-region
   2839         prettify-symbols-alist web-mode-prettify-symbols-alist)
   2840 
   2841   (substitute-key-definition #'indent-new-comment-line
   2842                              #'web-mode-comment-indent-new-line
   2843                              web-mode-map global-map)
   2844 
   2845   (add-hook 'after-change-functions #'web-mode-on-after-change nil t)
   2846   (add-hook 'after-save-hook        #'web-mode-on-after-save t t)
   2847   (add-hook 'change-major-mode-hook #'web-mode-on-exit nil t)
   2848   (add-hook 'post-command-hook      #'web-mode-on-post-command nil t)
   2849 
   2850   (cond
   2851    ((boundp 'yas-after-exit-snippet-hook)
   2852     (add-hook 'yas-after-exit-snippet-hook
   2853               'web-mode-yasnippet-exit-hook
   2854               t t))
   2855    ((boundp 'yas/after-exit-snippet-hook)
   2856     (add-hook 'yas/after-exit-snippet-hook
   2857               'web-mode-yasnippet-exit-hook
   2858               t t))
   2859    )
   2860 
   2861   (when web-mode-enable-whitespace-fontification
   2862     (web-mode-whitespaces-on))
   2863 
   2864   (when web-mode-enable-sexp-functions
   2865     (setq-local forward-sexp-function #'web-mode-forward-sexp))
   2866 
   2867   (web-mode-guess-engine-and-content-type)
   2868   (setq web-mode-change-beg (point-min)
   2869         web-mode-change-end (point-max))
   2870   (when (> (point-max) 256000)
   2871     (web-mode-buffer-fontify))
   2872 
   2873   (when (and (boundp 'hs-special-modes-alist)
   2874              (not (assoc major-mode hs-special-modes-alist)))
   2875     (add-to-list 'hs-special-modes-alist '(web-mode "{" "}" "/[*/]" web-mode-forward-sexp nil))
   2876     ) ;when
   2877 
   2878   ;; compatibility with emacs < 24
   2879   (if (fboundp 'prog-mode)
   2880       (put 'web-mode 'derived-mode-parent 'prog-mode))
   2881 
   2882   (cond
   2883    ((not (buffer-file-name))
   2884     )
   2885    ((string-match-p "web-mode-benchmark.html" (buffer-file-name))
   2886     (web-mode-measure "end"))
   2887    ) ;cond
   2888 
   2889   )
   2890 
   2891 ;;---- INVALIDATION ------------------------------------------------------------
   2892 
   2893 ;; 1/ after-change
   2894 ;; 2/ extend-region
   2895 ;; 3/ scan
   2896 ;; 4/ fontify
   2897 ;; 5/ post-command
   2898 
   2899 (defun web-mode-on-after-change (beg end len)
   2900   (when web-mode-trace
   2901     (message "after-change: pos(%d) beg(%d) end(%d) len(%d) this-command(%S)"
   2902              (point) beg end len this-command))
   2903   (when (or (null web-mode-change-beg) (< beg web-mode-change-beg))
   2904     (setq web-mode-change-beg beg))
   2905   (when (or (null web-mode-change-end) (> end web-mode-change-end))
   2906     (setq web-mode-change-end end)))
   2907 
   2908 (defun web-mode-extend-region ()
   2909   (when web-mode-trace
   2910     (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)"
   2911              font-lock-beg font-lock-end web-mode-change-beg web-mode-change-end web-mode-skip-fontification))
   2912   (when (and (string= web-mode-engine "php")
   2913              (and (>= font-lock-beg 6) (<= font-lock-beg 9))
   2914              (or (message (buffer-substring-no-properties 1 6)) t)
   2915              (string= (buffer-substring-no-properties 1 6) "<?php"))
   2916     (setq font-lock-beg (point-min)
   2917           font-lock-end (point-max))
   2918     )
   2919   (when (or (null web-mode-change-beg) (< font-lock-beg web-mode-change-beg))
   2920     (when web-mode-trace (message "extend-region: font-lock-beg(%S) < web-mode-change-beg(%S)" font-lock-beg web-mode-change-beg))
   2921     (setq web-mode-change-beg font-lock-beg))
   2922   (when (or (null web-mode-change-end) (> font-lock-end web-mode-change-end))
   2923     (when web-mode-trace (message "extend-region: font-lock-end(%S) > web-mode-change-end(%S)" font-lock-end web-mode-change-end))
   2924     (setq web-mode-change-end font-lock-end))
   2925   (when font-lock-dont-widen
   2926     (setq web-mode-change-beg (max web-mode-change-beg (point-min))
   2927           web-mode-change-end (min web-mode-change-end (point-max))))
   2928   (let ((region (web-mode-scan web-mode-change-beg web-mode-change-end)))
   2929     (when region
   2930       ;;(message "region: %S" region)
   2931       (setq font-lock-beg (car region)
   2932             font-lock-end (cdr region))
   2933       ) ;when
   2934     ) ;let
   2935   nil)
   2936 
   2937 (defun web-mode-scan (&optional beg end)
   2938   (when web-mode-trace
   2939     (message "scan: beg(%S) end(%S) web-mode-change-beg(%S) web-mode-change-end(%S)"
   2940              beg end web-mode-change-beg web-mode-change-end))
   2941   (unless beg (setq beg web-mode-change-beg))
   2942   (unless end (setq end web-mode-change-end))
   2943   ;;(message "%S %S %S" web-mode-content-type (get-text-property beg 'part-side) (get-text-property end 'part-side))
   2944   (when (and end (> end (point-max)))
   2945     (setq end (point-max)))
   2946   (setq web-mode-change-beg nil
   2947         web-mode-change-end nil)
   2948   (cond
   2949    ((or (null beg) (null end))
   2950     nil)
   2951    ((and (member web-mode-engine '("php" "asp"))
   2952          (get-text-property beg 'block-side)
   2953          (get-text-property end 'block-side)
   2954          (> beg (point-min))
   2955          (not (eq (get-text-property (1- beg) 'block-token) 'delimiter-beg))
   2956          (not (eq (get-text-property end 'block-token) 'delimiter-end)))
   2957     ;;(message "invalidate block (%S > %S)" beg end)
   2958     (web-mode-invalidate-block-region beg end))
   2959    ((and (or (member web-mode-content-type
   2960                      '("css" "javascript" "json" "jsx" "sass" "stylus" "typescript"))
   2961              (and (get-text-property beg 'part-side)
   2962                   (get-text-property end 'part-side)
   2963                   (> beg (point-min))
   2964                   (get-text-property (1- beg) 'part-side))
   2965              ))
   2966     ;;(message "invalidate part (%S > %S)" beg end)
   2967     (web-mode-invalidate-part-region beg end))
   2968    (t
   2969     ;;(message "invalidate default (%S > %S)" beg end)
   2970     (web-mode-invalidate-region beg end))
   2971    ) ;cond
   2972   )
   2973 
   2974 (defun web-mode-invalidate-region (reg-beg reg-end)
   2975   (when web-mode-trace
   2976     (message "invalidate-region: point(%S) reg-beg(%S) reg-end(%S)" (point) reg-beg reg-end))
   2977   (setq reg-beg (web-mode-invalidate-region-beginning-position reg-beg)
   2978         reg-end (web-mode-invalidate-region-end-position reg-end))
   2979   ;;(message "invalidate-region: reg-beg(%S) reg-end(%S)" reg-beg reg-end)
   2980   (web-mode-scan-region reg-beg reg-end))
   2981 
   2982 (defun web-mode--command-is-self-insert-p ()
   2983   "Return non-nil if `this-command' is `self-insert-command'.
   2984 Also return non-nil if it is the command `self-insert-command' is remapped to."
   2985   (memq this-command (list 'self-insert-command
   2986                            (key-binding [remap self-insert-command]))))
   2987 
   2988 (defun web-mode-on-post-command ()
   2989   (when (and web-mode-trace
   2990              (not (member this-command
   2991                           '(left-char right-char previous-line next-line save-buffer mwheel-scroll end-of-line beginning-of-line))))
   2992     (message "post-command: this-command(%S) web-mode-change-beg(%S) web-mode-change-end(%S) previous-state(%S)"
   2993              this-command web-mode-change-beg web-mode-change-end web-mode-expand-previous-state))
   2994   (let (ctx n char)
   2995     (when (and web-mode-expand-previous-state
   2996                (not (member this-command web-mode-commands-like-expand-region)))
   2997       (when (eq this-command 'keyboard-quit)
   2998         (goto-char web-mode-expand-initial-pos))
   2999       (deactivate-mark)
   3000       (when web-mode-expand-initial-scroll
   3001         (set-window-start (selected-window) web-mode-expand-initial-scroll)
   3002         )
   3003       (setq web-mode-expand-previous-state nil
   3004             web-mode-expand-initial-pos nil
   3005             web-mode-expand-initial-scroll nil))
   3006 
   3007     (when (member this-command '(yank))
   3008       ;;(setq web-mode-skip-fontification nil)
   3009       (when (and web-mode-scan-beg web-mode-scan-end global-font-lock-mode)
   3010         (save-excursion
   3011           (font-lock-fontify-region web-mode-scan-beg web-mode-scan-end))
   3012         (when web-mode-enable-auto-indentation
   3013           (indent-region web-mode-scan-beg web-mode-scan-end))
   3014         ) ;and
   3015       )
   3016 
   3017     (when (and (< (point) 16) web-mode-change-beg web-mode-change-end)
   3018       (web-mode-detect-content-type))
   3019 
   3020     (when (and web-mode-change-beg web-mode-change-end
   3021                web-mode-enable-engine-detection
   3022                (or (null web-mode-engine) (string= web-mode-engine "none"))
   3023                (< (point) web-mode-chunk-length)
   3024                (web-mode-detect-engine))
   3025       (web-mode-on-engine-setted)
   3026       (web-mode-buffer-fontify))
   3027 
   3028     (when (> (point) 1)
   3029       (setq char (char-before)))
   3030 
   3031     (cond
   3032      ((null char)
   3033       )
   3034      ((and (>= (point) 3)
   3035            (web-mode--command-is-self-insert-p)
   3036            (not (member (get-text-property (point) 'part-token) '(comment string)))
   3037            (not (eq (get-text-property (point) 'tag-type) 'comment))
   3038            )
   3039       (setq ctx (web-mode-auto-complete)))
   3040      ((and web-mode-enable-auto-opening
   3041            (member this-command '(newline electric-newline-and-maybe-indent newline-and-indent))
   3042            (or (and (not (eobp))
   3043                     (eq (char-after) ?\<)
   3044                     (eq (get-text-property (point) 'tag-type) 'end)
   3045                     (looking-back ">\n[ \t]*" (point-min))
   3046                     (setq n (length (match-string-no-properties 0)))
   3047                     (eq (get-text-property (- (point) n) 'tag-type) 'start)
   3048                     (string= (get-text-property (- (point) n) 'tag-name)
   3049                              (get-text-property (point) 'tag-name))
   3050                     )
   3051                (and (get-text-property (1- (point)) 'block-side)
   3052                     (string= web-mode-engine "php")
   3053                     (looking-back "<\\?php[ ]*\n" (point-min))
   3054                     (looking-at-p "[ ]*\\?>"))))
   3055       (newline-and-indent)
   3056       (forward-line -1)
   3057       (indent-according-to-mode)
   3058       )
   3059      ) ;cond
   3060 
   3061     (cond
   3062 
   3063      ((not web-mode-enable-auto-opening)
   3064       )
   3065      ((and (member this-command '(newline electric-newline-and-maybe-indent newline-and-indent))
   3066            (get-text-property (point) 'part-side)
   3067            (eq (get-text-property (point) 'part-token) 'string))
   3068       (indent-according-to-mode)
   3069       (when (and web-mode-change-end (> web-mode-change-end (point-max)))
   3070         (message "post-command: enlarge web-mode-change-end")
   3071         (setq web-mode-change-end (point-max))
   3072         )
   3073       )
   3074      ((and (web-mode--command-is-self-insert-p)
   3075            (or (and ctx
   3076                     (or (plist-get ctx :auto-closed)
   3077                         (plist-get ctx :auto-expanded)))
   3078                (and (> (point) (point-min))
   3079                     (get-text-property (1- (point)) 'tag-end)
   3080                     (get-text-property (line-beginning-position) 'tag-beg))))
   3081       (indent-according-to-mode)
   3082       (when (and web-mode-change-end (> web-mode-change-end (point-max)))
   3083         (message "post-command: enlarge web-mode-change-end")
   3084         (setq web-mode-change-end (point-max))
   3085         )
   3086       )
   3087      ((and (web-mode--command-is-self-insert-p)
   3088            (member (get-text-property (point) 'part-side) '(javascript jsx css))
   3089            (looking-back "^[ \t]+[]})]" (point-min)))
   3090       (indent-according-to-mode)
   3091       (when (and web-mode-change-end (> web-mode-change-end (point-max)))
   3092         (message "post-command: enlarge web-mode-change-end")
   3093         (setq web-mode-change-end (point-max))
   3094         )
   3095       )
   3096      ) ; cond web-mode-enable-auto-opening
   3097 
   3098     (when web-mode-enable-current-element-highlight
   3099       (web-mode-highlight-current-element))
   3100 
   3101     (when (and web-mode-enable-current-column-highlight
   3102                (not (web-mode-buffer-narrowed-p)))
   3103       (web-mode-column-show))
   3104 
   3105     (when (and web-mode-trace (not (member this-command
   3106                                            '(left-char right-char previous-line next-line save-buffer mwheel-scroll end-of-line beginning-of-line))))
   3107       (when (or web-mode-change-beg web-mode-change-end)
   3108         (message "post-command: web-mode-change-beg(%S) web-mode-change-end(%S)"
   3109                  web-mode-change-end web-mode-change-end))
   3110       (message "-------------------------------------------------------------------")
   3111       )
   3112 
   3113     ))
   3114 
   3115 ;; NOTE: il est important d'identifier des caractères en fin de ligne
   3116 ;; web-mode-block-tokenize travaille en effet sur les fins de lignes pour
   3117 ;; les commentaires de type //
   3118 (defun web-mode-invalidate-block-region (pos-beg pos-end)
   3119   ;;  (message "pos-beg(%S) pos-end(%S)" pos-beg pos-end)
   3120   (save-excursion
   3121     (let (beg end code-beg code-end)
   3122       ;;(message "invalidate-block-region: pos-beg(%S)=%S" pos-beg (get-text-property pos 'block-side))
   3123       ;;(message "code-beg(%S) code-end(%S) pos-beg(%S) pos-end(%S)" code-beg code-end pos-beg pos-end)
   3124       (cond
   3125        ((not (and (setq code-beg (web-mode-block-code-beginning-position pos-beg))
   3126                   (setq code-end (web-mode-block-code-end-position pos-beg))
   3127                   (>= pos-beg code-beg)
   3128                   (<= pos-end code-end)
   3129                   (> code-end code-beg)))
   3130         (web-mode-invalidate-region pos-beg pos-end))
   3131        ((member web-mode-engine '("asp"))
   3132         (goto-char pos-beg)
   3133         (forward-line -1)
   3134         (setq beg (line-beginning-position))
   3135         (when (> code-beg beg)
   3136           (setq beg code-beg))
   3137         (goto-char pos-beg)
   3138         (forward-line)
   3139         (setq end (line-end-position))
   3140         (when (< code-end end)
   3141           (setq end code-end))
   3142         ;; ?? pas de (web-mode-block-tokenize beg end) ?
   3143         (web-mode-block-tokenize beg end)
   3144         (cons beg end)
   3145         ) ;asp
   3146        (t
   3147         (goto-char pos-beg)
   3148         ;;(message "pos-beg=%S" pos-beg)
   3149         (when (string= web-mode-engine "php")
   3150           (cond
   3151            ((and (looking-back "\*" (point-min))
   3152                  (looking-at-p "/"))
   3153             (search-backward "/*" code-beg))
   3154            ) ;cond
   3155           ) ;when
   3156         (if (web-mode-block-rsb "[;{}(][ ]*\n" code-beg)
   3157             (setq beg (match-end 0))
   3158           (setq beg code-beg))
   3159         (goto-char pos-end)
   3160         (if (web-mode-block-rsf "[;{})][ ]*\n" code-end)
   3161             (setq end (1- (match-end 0)))
   3162           (setq end code-end))
   3163         (web-mode-block-tokenize beg end)
   3164         ;;(message "beg(%S) end(%S)" beg end)
   3165         (cons beg end)
   3166         )
   3167        ) ;cond
   3168       )))
   3169 
   3170 (defun web-mode-invalidate-part-region (pos-beg pos-end)
   3171   (save-excursion
   3172     (let (beg end part-beg part-end language)
   3173       (if (member web-mode-content-type web-mode-part-content-types)
   3174           (setq language web-mode-content-type)
   3175         (setq language (symbol-name (get-text-property pos-beg 'part-side))))
   3176       (setq part-beg (web-mode-part-beginning-position pos-beg)
   3177             part-end (web-mode-part-end-position pos-beg))
   3178       ;;(message "language(%S) pos-beg(%S) pos-end(%S) part-beg(%S) part-end(%S)"
   3179       ;;         language pos-beg pos-end part-beg part-end)
   3180       (goto-char pos-beg)
   3181       (cond
   3182        ((not (and part-beg part-end
   3183                   (>= pos-beg part-beg)
   3184                   (<= pos-end part-end)
   3185                   (> part-end part-beg)))
   3186         (web-mode-invalidate-region pos-beg pos-end))
   3187        ((member language '("javascript" "json" "jsx" "typescript"))
   3188         (if (web-mode-javascript-rsb "[;{}(][ ]*\n" part-beg)
   3189             (setq beg (match-end 0))
   3190           (setq beg part-beg))
   3191         (goto-char pos-end)
   3192         (if (web-mode-javascript-rsf "[;{})][ ]*\n" part-end)
   3193             (setq end (match-end 0))
   3194           (setq end part-end))
   3195         (web-mode-scan-region beg end language))
   3196        ((member language '("css" "sass"))
   3197         (let (rule1 rule2)
   3198           (setq rule1 (web-mode-css-rule-current pos-beg))
   3199           (setq rule2 rule1)
   3200           (when (> pos-end (cdr rule1))
   3201             (setq rule2 (web-mode-css-rule-current pos-end)))
   3202           (setq beg (car rule1)
   3203                 end (cdr rule2))
   3204           )
   3205         (web-mode-scan-region beg end language))
   3206        (t
   3207         (setq beg part-beg
   3208               end part-end)
   3209         (web-mode-scan-region beg end language))
   3210        ) ;cond
   3211       )))
   3212 
   3213 (defun web-mode-invalidate-region-beginning-position (pos)
   3214   (save-excursion
   3215     (goto-char pos)
   3216 
   3217     (cond
   3218      ((and (looking-at-p ">") ;#1151
   3219            (looking-back "--" (point-min)))
   3220       (search-backward "<!--" nil t))
   3221      ((and (bolp) (not (bobp)))
   3222       (backward-char))
   3223      )
   3224 
   3225     (beginning-of-line)
   3226     ;;(message "pos=%S point=%S %S" pos (point) (text-properties-at (point)))
   3227     (setq pos (point-min))
   3228     (let ((continue (not (bobp))))
   3229       (while continue
   3230         (cond
   3231          ((bobp)
   3232           (setq continue nil))
   3233          ;; NOTE: Going back to the previous start tag is necessary
   3234          ;; when inserting a part endtag (e.g. </script>).
   3235          ;; Indeed, parts must be identified asap.
   3236          ((and (progn (back-to-indentation) t)
   3237                (get-text-property (point) 'tag-beg)
   3238                (eq (get-text-property (point) 'tag-type) 'start))
   3239           (setq pos (point)
   3240                 continue nil))
   3241          (t
   3242           (forward-line -1))
   3243          ) ;cond
   3244         ) ;while
   3245       ;;(message "pos=%S" pos)
   3246       pos)))
   3247 
   3248 (defun web-mode-invalidate-region-end-position (pos)
   3249   (save-excursion
   3250     (goto-char pos)
   3251     ;;(message "pos=%S %S" pos (get-text-property pos 'block-token))
   3252     (when (string= web-mode-engine "jsp")
   3253       (cond
   3254        ((and (looking-back "<%" (point-min))
   3255              (looking-at-p "--"))
   3256         (search-forward "--%>"))
   3257        ((and (looking-back "-- %" (point-min))
   3258              (looking-at-p ">"))
   3259         (search-forward "--%>"))
   3260        ) ;cond
   3261       ) ;when
   3262     (setq pos (point-max))
   3263     (let ((continue (not (eobp))))
   3264       (while continue
   3265         (end-of-line)
   3266         ;;(message "%S %S" (point) (get-text-property (point) 'block-token))
   3267         (cond
   3268          ((eobp)
   3269           (setq continue nil))
   3270          ((and (not (get-text-property (point) 'tag-type))
   3271                (not (get-text-property (point) 'part-side))
   3272                (not (get-text-property (point) 'block-side)))
   3273           (setq pos (point)
   3274                 continue nil))
   3275          (t
   3276           (forward-line))
   3277          ) ;cond
   3278         ) ;while
   3279       pos)))
   3280 
   3281 (defun web-mode-buffer-scan ()
   3282   "Scan entine buffer."
   3283   (interactive)
   3284   (web-mode-scan-region (point-min) (point-max)))
   3285 
   3286 (defun web-mode-scan-region (beg end &optional content-type)
   3287   "Identify nodes/parts/blocks and syntactic symbols (strings/comments/etc.)."
   3288   ;;(message "scan-region: beg(%d) end(%d) content-type(%S)" beg end content-type)
   3289   (setq web-mode-scan-beg beg
   3290         web-mode-scan-end end)
   3291   (web-mode-with-silent-modifications
   3292    (save-excursion
   3293      (save-restriction
   3294        (save-match-data
   3295          (let ((inhibit-point-motion-hooks t)
   3296                (inhibit-quit t))
   3297            (remove-list-of-text-properties beg end web-mode-scan-properties)
   3298            (cond
   3299             ((and content-type (string= content-type "php"))
   3300              )
   3301             ((and content-type (member content-type web-mode-part-content-types))
   3302              (put-text-property beg end 'part-side
   3303                                 (cond
   3304                                  ((string= content-type "javascript") 'javascript)
   3305                                  ((string= content-type "json") 'json)
   3306                                  ((string= content-type "jsx") 'jsx)
   3307                                  ((string= content-type "css") 'css)
   3308                                  ((string= content-type "sql") 'sql)
   3309                                  ((string= content-type "pug") 'pug)
   3310                                  ((string= content-type "sass") 'sass)
   3311                                  ((string= content-type "stylus") 'stylus)
   3312                                  ((string= content-type "markdown") 'markdown)
   3313                                  ((string= content-type "ruby") 'ruby)
   3314                                  ((string= content-type "typescript") 'typescript)
   3315                                  ))
   3316              (web-mode-scan-blocks beg end)
   3317              (web-mode-part-scan beg end content-type))
   3318             ((member web-mode-content-type web-mode-part-content-types)
   3319              (web-mode-scan-blocks beg end)
   3320              (web-mode-part-scan beg end))
   3321             ((string= web-mode-engine "riot")
   3322              (web-mode-scan-elements beg end)
   3323              (web-mode-scan-blocks beg end)
   3324              (web-mode-part-foreach beg end 'web-mode-part-scan))
   3325             (t
   3326              (web-mode-scan-blocks beg end)
   3327              (web-mode-scan-elements beg end)
   3328              (web-mode-part-foreach beg end 'web-mode-part-scan))
   3329             ) ;cond
   3330            (cons beg end)
   3331            ))))))
   3332 
   3333 ;;---- LEXER BLOCKS ------------------------------------------------------------
   3334 
   3335 (defun web-mode-scan-blocks (reg-beg reg-end)
   3336   "Identifies blocks (with block-side, block-beg, block-end text properties)."
   3337   (save-excursion
   3338 
   3339     (let ((i 0) open close closing-string sub1 sub2 pos tagopen tmp delim-open delim-close part-beg part-end tagclose)
   3340 
   3341       (goto-char reg-beg)
   3342 
   3343       ;;(message "%S: %Sx%S" (point) reg-beg reg-end)
   3344       ;;(message "regexp=%S" web-mode-block-regexp)
   3345       (while (and (< i 2000)
   3346                   (> reg-end (point))
   3347                   web-mode-block-regexp
   3348                   (re-search-forward web-mode-block-regexp reg-end t)
   3349                   (not (eobp)))
   3350 
   3351         (setq i (1+ i)
   3352               closing-string nil
   3353               close nil
   3354               tagopen (match-string 0)
   3355               open (match-beginning 0)
   3356               delim-open nil
   3357               delim-close nil
   3358               pos nil)
   3359 
   3360         (let ((l (length tagopen)))
   3361           (when (member (string-to-char tagopen) '(?\s ?\t))
   3362             (setq tagopen (replace-regexp-in-string "\\`[ \t]*" "" tagopen))
   3363             (setq open (+ open (- l (length tagopen))))
   3364             (setq l (length tagopen))
   3365             )
   3366           (setq sub1 (substring tagopen 0 1)
   3367                 sub2 (substring tagopen 0 (if (>= l 2) 2 1)))
   3368           )
   3369         ;;(message " found block #(%S) at pos=(%S), part-type=(%S)" i open (get-text-property open 'part-side))
   3370         (cond
   3371 
   3372          ((string= web-mode-engine "php")
   3373           (unless (member (char-after) '(?x ?X))
   3374             (setq closing-string '("<\\?". "\\?>")))
   3375           (cond
   3376            ((looking-at-p "<?php")
   3377             (setq delim-open "<?php"))
   3378            ((eq (char-after) ?\=)
   3379             (setq delim-open "<?="))
   3380            (t
   3381             (setq delim-open "<?"))
   3382            ) ;cond
   3383           (setq delim-close "?>")
   3384           ) ;php
   3385 
   3386          ((string= web-mode-engine "erb")
   3387           (cond
   3388            ((string= sub2 "<%")
   3389             (setq closing-string '("<%". "%>")
   3390                   delim-open "<%\\(==\\|[=-]\\)?"
   3391                   delim-close "[-]?%>"))
   3392            (t
   3393             (setq closing-string "EOL"
   3394                   delim-open "%"))
   3395            )
   3396           ) ;erb
   3397 
   3398          ((string= web-mode-engine "django")
   3399           (cond
   3400            ((string= sub2 "{{")
   3401             (setq closing-string "EODQ"
   3402             ;;(setq closing-string '("{{" . "}}")
   3403                   delim-open "{{"
   3404                   delim-close "}}"))
   3405            ((string= sub2 "{%")
   3406             (setq closing-string "%}"
   3407                   delim-open "{%[+-]?"
   3408                   delim-close "[-]?%}"))
   3409            ((string= sub2 "{#")
   3410             (setq closing-string "#}"))
   3411            (t
   3412             (setq closing-string "EOL"
   3413                   delim-open "#[#]?"))
   3414            )
   3415           ) ;django
   3416 
   3417          ((string= web-mode-engine "anki")
   3418           (setq closing-string "}}"
   3419                 delim-open "{{[#/^]?"
   3420                 delim-close "}}")
   3421           ) ;anki
   3422 
   3423          ((string= web-mode-engine "ejs")
   3424           (setq closing-string "%>"
   3425                 delim-open "<%[=-]?"
   3426                 delim-close "[-]?%>")
   3427           ) ;ejs
   3428 
   3429          ((string= web-mode-engine "lsp")
   3430           (setq closing-string "%>"
   3431                 delim-open "<%[%#]?"
   3432                 delim-close "%>")
   3433           ) ;lsp
   3434 
   3435          ((string= web-mode-engine "mako")
   3436           (cond
   3437            ((and (string= tagopen "<%")
   3438                  (member (char-after) '(?\s ?\n ?\!)))
   3439             (setq closing-string "%>"
   3440                   delim-open "<%[!]?"
   3441                   delim-close "%>"))
   3442            ((member sub2 '("<%" "</"))
   3443             (setq closing-string ">"
   3444                   delim-open "</?%"
   3445                   delim-close "/?>"))
   3446            ((string= sub2 "${")
   3447             (setq closing-string "}"
   3448                   delim-open "${"
   3449                   delim-close "}"))
   3450            (t
   3451             (setq closing-string "EOL"
   3452                   delim-open "%"))
   3453            )
   3454           ) ;mako
   3455 
   3456          ((string= web-mode-engine "cl-emb")
   3457           (cond
   3458            ((string= tagopen "<%#")
   3459             (setq closing-string "#%>"))
   3460            ((string= sub2 "<%")
   3461             (setq closing-string "%>"
   3462                   delim-open "<%[=%]?"
   3463                   delim-close "%>"))
   3464            )
   3465           ) ;cl-emb
   3466 
   3467          ((string= web-mode-engine "artanis")
   3468           (cond
   3469            ((string= tagopen "<%;")
   3470             (setq closing-string "%>"))
   3471            ((string= tagopen "<%#|")
   3472             (setq closing-string "|#%>"))
   3473            ((string= sub2 "<@")
   3474             (setq closing-string "%>"
   3475                   delim-open "<@\\(css\\|icon\\|include\\|js\\)"
   3476                   delim-close "%>"))
   3477            ((string= sub2 "<%")
   3478             (setq closing-string "%>"
   3479                   delim-open "<%[=]?"
   3480                   delim-close "%>"))
   3481            )
   3482           ) ;artanis
   3483 
   3484          ((string= web-mode-engine "elixir")
   3485           (cond
   3486            ((member (char-after) '(?\#))
   3487             (setq closing-string "%>"))
   3488            (t
   3489             (setq closing-string "%>"
   3490                   delim-open "<%[=%]?"
   3491                   delim-close "%>"))
   3492            )
   3493           ) ;elixir
   3494 
   3495          ((string= web-mode-engine "mojolicious")
   3496           (cond
   3497            ((string= tagopen "<%#")
   3498             (setq closing-string "%>"))
   3499            ((string= sub2 "<%")
   3500             (setq closing-string "%>"
   3501                   delim-open "<%\\(==\\|[=%]\\)?"
   3502                   delim-close "%>"))
   3503            ((string= sub2 "%#")
   3504             (setq closing-string "EOL"))
   3505            (t
   3506             (setq closing-string "EOL"
   3507                   delim-open "%\\(==\\|[=%]\\)?"))
   3508            )
   3509           ) ;mojolicious
   3510 
   3511          ((string= web-mode-engine "ctemplate")
   3512           (cond
   3513            ((member tagopen '("{{{" "{{~"))
   3514             (setq closing-string "}~?}}"
   3515                   delim-open "{{~?{"
   3516                   delim-close "}~?}}")
   3517             )
   3518            ((string= tagopen "{~{")
   3519             (setq closing-string "}~?}"
   3520                   delim-open "{~{"
   3521                   delim-close "}~?}")
   3522             )
   3523            ((string= tagopen "{{!")
   3524             (setq closing-string (if (looking-at-p "--") "--}}" "}}"))
   3525             )
   3526            ((string= sub2 "{{")
   3527             (setq closing-string "}~?}"
   3528                   delim-open "{{[>#/%^&]?"
   3529                   delim-close "}~?}"))
   3530            (t
   3531             (setq closing-string "}}"
   3532                   delim-open "${{"
   3533                   delim-close "}}"))
   3534            )
   3535           ) ;ctemplate
   3536 
   3537          ((string= web-mode-engine "aspx")
   3538           (setq closing-string "%>"
   3539                 delim-open "<%[:=#@$]?"
   3540                 delim-close "%>")
   3541           ) ;aspx
   3542 
   3543          ((string= web-mode-engine "asp")
   3544           (cond
   3545            ((string= sub2 "<%")
   3546             (setq closing-string "%>"
   3547                   delim-open "<%[:=#@$]?"
   3548                   delim-close "%>"))
   3549            (t
   3550             (setq closing-string ">"
   3551                   delim-open "</?"
   3552                   delim-close "/?>"))
   3553            )
   3554           ) ;asp
   3555 
   3556          ((string= web-mode-engine "jsp")
   3557           (cond
   3558            ((looking-at-p "--")
   3559             (setq closing-string "--%>"))
   3560            ((string= sub2 "<%")
   3561             (setq closing-string "%>"
   3562                   delim-open "<%\\([!=@]\\|#=\\)?"
   3563                   delim-close "[-]?%>"))
   3564            ((string= sub2 "${")
   3565             (setq closing-string "}"
   3566                   delim-open "${"
   3567                   delim-close "}"))
   3568            )
   3569           ) ;jsp
   3570 
   3571          ((string= web-mode-engine "clip")
   3572           (setq closing-string ">"
   3573                 delim-open "</?"
   3574                 delim-close "/?>")
   3575           ) ;clip
   3576 
   3577          ((string= web-mode-engine "perl")
   3578           (setq closing-string ">"
   3579                 delim-open "</?"
   3580                 delim-close "/?>")
   3581           ) ;perl
   3582 
   3583          ((string= web-mode-engine "blade")
   3584           (cond
   3585            ((string= tagopen "{{-")
   3586             (setq closing-string "--}}"))
   3587            ((string= tagopen "{!!")
   3588             (setq closing-string "!!}"
   3589                   delim-open "{!!"
   3590                   delim-close "!!}"))
   3591            ((string= tagopen "@{{")
   3592             (setq closing-string nil))
   3593            ((string= tagopen "{{{")
   3594             (setq closing-string "}}}"
   3595                   delim-open "{{{"
   3596                   delim-close "}}}"))
   3597            ((string= sub2 "{{")
   3598             (setq closing-string "}}"
   3599                   delim-open "{{"
   3600                   delim-close "}}"))
   3601            ((looking-at-p "[[:alnum:]]+\\.[[:alpha:]]+")
   3602             )
   3603            ((looking-at-p "[[:alnum:]]+(")
   3604             (setq closing-string ")"
   3605                   delim-open "@"))
   3606            ((string= sub1 "@")
   3607             (setq closing-string "EOB"
   3608                   delim-open "@"))
   3609            )
   3610           ) ;blade
   3611 
   3612          ((string= web-mode-engine "smarty")
   3613           (cond
   3614            ((string= tagopen "{*")
   3615             (setq closing-string "*}")
   3616             )
   3617            ((string= tagopen "{#")
   3618             (setq closing-string "#}"
   3619                   delim-open "{#"
   3620                   delim-close "#}")
   3621             )
   3622            (t
   3623             (setq closing-string (cons "{" "}")
   3624                   delim-open "{/?"
   3625                   delim-close "}")
   3626             ) ;t
   3627            ) ;cond
   3628           ) ;smarty
   3629 
   3630          ((string= web-mode-engine "hero")
   3631           (setq closing-string "%>"
   3632                 delim-open "<%==?\\([biufsv]\\|bs\\)?\\|<%[:~@+!]?"
   3633                 delim-close "%>")
   3634           ) ;hero
   3635 
   3636          ((string= web-mode-engine "xoops")
   3637           (cond
   3638            ((string= tagopen "<{*")
   3639             (setq closing-string "*}>")
   3640             )
   3641            ((string= tagopen "<{#")
   3642             (setq closing-string "#}>"
   3643                   delim-open "<{#"
   3644                   delim-close "#}>")
   3645             )
   3646            (t
   3647             (setq closing-string (cons "<{" "}>")
   3648                   delim-open "<{/?"
   3649                   delim-close "}>")
   3650             ) ;t
   3651            ) ;cond
   3652           ) ;xoops
   3653 
   3654          ((string= web-mode-engine "web2py")
   3655           (setq closing-string "}}"
   3656                 delim-open "{{[=]?"
   3657                 delim-close "}}")
   3658           ) ;web2py
   3659 
   3660          ((string= web-mode-engine "expressionengine")
   3661           (cond
   3662            ((string= sub2 "{!--")
   3663             (setq closing-string "--}"))
   3664            (t
   3665             (setq closing-string '("{". "}")
   3666                   delim-open "{/?"
   3667                   delim-close "}")
   3668             )
   3669            )
   3670           ) ;expressionengine
   3671 
   3672          ((string= web-mode-engine "dust")
   3673           (cond
   3674            ((string= sub2 "{!")
   3675             (setq closing-string "!}"))
   3676            (t
   3677             (setq closing-string '("{". "}")
   3678                   delim-open "{[#/:?@><+^]?"
   3679                   delim-close "/?}")
   3680             )
   3681            )
   3682           ) ;dust
   3683 
   3684          ((string= web-mode-engine "svelte")
   3685           (cond
   3686            ((string= sub2 "{!")
   3687             (setq closing-string "!}"))
   3688            ((string= sub2 "{}")
   3689             (setq closing-string nil
   3690                   delim-open nil
   3691                   delim-close nil))
   3692            (t
   3693             (setq closing-string '("{". "}")
   3694                   delim-open "{[#/:?@><+^]?"
   3695                   delim-close "/?}")
   3696             )
   3697            )
   3698           ) ;svelte
   3699 
   3700          ((string= web-mode-engine "closure")
   3701           (cond
   3702            ((string= sub2 "//")
   3703             (setq closing-string "EOL")
   3704             )
   3705            ((string= sub2 "/*")
   3706             (setq closing-string "*/")
   3707             )
   3708            (t
   3709             (setq closing-string "}"
   3710                   delim-open "{/?"
   3711                   delim-close "/?}")
   3712             )
   3713            )
   3714           ) ;closure
   3715 
   3716          ((string= web-mode-engine "go")
   3717           (setq closing-string "}}"
   3718                 delim-open "{{-?"
   3719                 delim-close "-?}}")
   3720           ) ;go
   3721 
   3722          ((string= web-mode-engine "angular")
   3723           (setq closing-string "}}"
   3724                 delim-open "{{"
   3725                 delim-close "}}")
   3726           ) ;angular
   3727 
   3728          ((string= web-mode-engine "vue")
   3729           (cond
   3730            ((string-match-p "[:@][-[:alpha:]]+=\"" tagopen)
   3731             (setq closing-string "\""
   3732                   delim-open tagopen
   3733                   delim-close "\""))
   3734            ((string= tagopen "{{")
   3735             (setq closing-string "}}"
   3736                   delim-open "{{"
   3737                   delim-close "}}")))
   3738           ) ;vue
   3739 
   3740          ((string= web-mode-engine "mason")
   3741           (cond
   3742            ((and (member sub2 '("<%" "</"))
   3743                  (looking-at "[[:alpha:]]+"))
   3744             (if (member (match-string-no-properties 0) '("after" "around" "augment" "before" "def" "filter" "method" "override"))
   3745                 (setq closing-string ">"
   3746                       delim-open "<[/]?%"
   3747                       delim-close ">")
   3748               (setq closing-string (concat "</%" (match-string-no-properties 0) ">")
   3749                     delim-open "<[^>]+>"
   3750                     delim-close "<[^>]+>")
   3751               ) ;if
   3752             )
   3753            ((and (string= sub2 "<%")
   3754                  (eq (char-after) ?\s))
   3755             (setq closing-string "%>"
   3756                   delim-open "<%"
   3757                   delim-close "%>"))
   3758            ((string= tagopen "</&")
   3759             (setq closing-string ">"
   3760                   delim-open "</&"
   3761                   delim-close ">")
   3762             )
   3763            ((string= sub2 "<&")
   3764             (setq closing-string "&>"
   3765                   delim-open "<&[|]?"
   3766                   delim-close "&>"))
   3767            (t
   3768             (setq closing-string "EOL"
   3769                   delim-open "%"))
   3770            )
   3771           ) ;mason
   3772 
   3773          ((string= web-mode-engine "underscore")
   3774           (setq closing-string "%>"
   3775                 delim-open "<%"
   3776                 delim-close "%>")
   3777           ) ;underscore
   3778 
   3779          ((string= web-mode-engine "template-toolkit")
   3780           (cond
   3781            ((string= tagopen "%%#")
   3782             (setq closing-string "EOL"))
   3783            ((string= tagopen "[%#")
   3784             (setq closing-string "%]"))
   3785            (t
   3786             (setq closing-string "%]"
   3787                   delim-open "\\[%[-+]?"
   3788                   delim-close "[-=+]?%\\]"))
   3789            )
   3790           ) ;template-toolkit
   3791 
   3792          ((string= web-mode-engine "freemarker")
   3793           (cond
   3794            ((and (string= sub2 "<#") (eq (char-after) ?\-))
   3795             (setq closing-string "-->"))
   3796            ((string= sub1 "<")
   3797             (setq closing-string ">"
   3798                   delim-open "</?[#@]"
   3799                   delim-close "/?>"))
   3800            ((string= sub1 "[")
   3801             (setq closing-string "]"
   3802                   delim-open "\\[/?[#@]"
   3803                   delim-close "/?\\]"))
   3804            (t
   3805             (setq closing-string "}"
   3806                   delim-open "${"
   3807                   delim-close "}"))
   3808            )
   3809           ) ;freemarker
   3810 
   3811          ((string= web-mode-engine "velocity")
   3812           (cond
   3813            ((string= sub2 "##")
   3814             (setq closing-string "EOL"))
   3815            ((string= sub2 "#*")
   3816             (setq closing-string "*#"))
   3817            (t
   3818             (setq closing-string "EOV"
   3819                   delim-open "#"))
   3820            )
   3821           ) ;velocity
   3822 
   3823          ((string= web-mode-engine "razor")
   3824           (cond
   3825            ((string= sub2 "@@")
   3826             (forward-char 2)
   3827             (setq closing-string nil))
   3828            ((string= sub2 "@*")
   3829             (setq closing-string "*@"))
   3830            ((string= sub1 "@")
   3831             (setq closing-string "EOR"
   3832                   delim-open "@"))
   3833            ((and (string= sub1 "}")
   3834                  (looking-at-p "[ ]*\n"))
   3835             ;;(setq closing-string "EOC")
   3836             (save-excursion
   3837               (let (paren-pos)
   3838                 (setq paren-pos (web-mode-part-opening-paren-position (1- (point))))
   3839                 (if (and paren-pos (get-text-property paren-pos 'block-side))
   3840                     (setq closing-string "EOC")
   3841                   (setq closing-string nil)
   3842                   ) ;if
   3843                 ) ;let
   3844               ) ;save-excursion
   3845             ;;(message "%s %S %S" sub2 (point) (get-text-property (point) 'part-side))
   3846             )
   3847            ((string= sub1 "}")
   3848             ;;(message "%s: %s" (point) sub1)
   3849             (save-excursion
   3850               (let (paren-pos)
   3851                 (setq paren-pos (web-mode-part-opening-paren-position (1- (point))))
   3852                 (if (and paren-pos (get-text-property paren-pos 'block-side))
   3853                     (setq closing-string "EOR")
   3854                   (setq closing-string nil)
   3855                   ) ;if
   3856                 ) ;let
   3857               ) ;save-excursion
   3858             ) ;case }
   3859            ) ;cond
   3860           ) ;razor
   3861 
   3862          ((and (string= web-mode-engine "riot")
   3863                (not (get-text-property open 'part-side)))
   3864           (setq closing-string (if (string= tagopen "{") "}" "/// end script")
   3865                 delim-open "{"
   3866                 delim-close "}")
   3867           ) ;riot
   3868 
   3869          ((string= web-mode-engine "spip")
   3870           (cond
   3871            ((and (string= sub1 "#")
   3872                  (looking-at "[A-Z0-9_]+"))
   3873             (setq closing-string (match-string-no-properties 0)))
   3874            ((string= sub1 "(")
   3875             (setq closing-string '("(" . ")")))
   3876            ((string= sub1 "{")
   3877             (setq closing-string '("{" . "}")))
   3878            ((string= sub2 "<:")
   3879             (setq closing-string ":>"))
   3880            (t
   3881             (setq closing-string "]"))
   3882             ))
   3883 
   3884          ((string= web-mode-engine "marko")
   3885           (setq closing-string "}"
   3886                 delim-open "${"
   3887                 delim-close "}")
   3888           ) ;marko
   3889 
   3890          ) ;cond
   3891 
   3892         (when closing-string
   3893           (cond
   3894 
   3895            ((listp closing-string)
   3896             (cond
   3897              ((web-mode-rsf-balanced (car closing-string) (cdr closing-string) reg-end t)
   3898               (setq close (match-end 0)
   3899                     pos (point))
   3900               )
   3901              ((and (string= web-mode-engine "php")
   3902                    (string= "<?" sub2))
   3903 
   3904               (if (or (text-property-not-all (1+ open) (point-max) 'tag-beg nil)
   3905                       (text-property-not-all (1+ open) (point-max) 'block-beg nil)
   3906                       (looking-at-p "[ \t\n]*<"))
   3907                   (setq close nil
   3908                         delim-close nil
   3909                         pos (point))
   3910                 (setq close (point-max)
   3911                       delim-close nil
   3912                       pos (point-max))
   3913                 ) ;if
   3914               ) ;case
   3915              ) ;cond
   3916             ) ;case listp
   3917 
   3918            ((and (string= web-mode-engine "smarty")
   3919                  (string= closing-string "}"))
   3920             (goto-char open)
   3921             (setq tmp (web-mode-closing-delimiter-position
   3922                        "}"
   3923                        (point)
   3924                        (line-end-position)))
   3925             (if tmp
   3926                 (setq tmp (1+ tmp))
   3927               (setq tmp (line-end-position)))
   3928             (goto-char tmp)
   3929             (setq close (point)
   3930                   pos (point))
   3931             )
   3932 
   3933            ((and (member web-mode-engine '("closure"))
   3934                  (string= closing-string "}"))
   3935             (when (web-mode-closure-skip reg-beg reg-end)
   3936               (setq close (point)
   3937                     pos (point))
   3938               ;;(message "close=%S pos=%S" close pos)
   3939               ) ;when
   3940             )
   3941 
   3942            ((string= closing-string "EOB")
   3943             (web-mode-blade-skip open)
   3944             (setq close (point)
   3945                   pos (point)))
   3946 
   3947            ((string= closing-string "EOL")
   3948             (end-of-line)
   3949             (setq close (point)
   3950                   pos (point)))
   3951 
   3952            ((string= closing-string "EOC")
   3953             (setq close (point)
   3954                   pos (point)))
   3955 
   3956            ((string= closing-string "EODQ")
   3957             (when (web-mode-django-skip reg-beg reg-end)
   3958               (setq close (point)
   3959                     pos (point))
   3960               ))
   3961 
   3962            ((string= closing-string "EOR")
   3963             (web-mode-razor-skip open)
   3964             (setq close (if (> (point) reg-end) reg-end (point))
   3965                   pos (if (> (point) reg-end) reg-end (point)))
   3966             (goto-char pos))
   3967 
   3968            ((string= closing-string "EOV")
   3969             (web-mode-velocity-skip open)
   3970             (setq close (point)
   3971                   pos (point)))
   3972 
   3973            ((and (member web-mode-engine '("ctemplate"))
   3974                  (re-search-forward closing-string reg-end t))
   3975             (setq close (match-end 0)
   3976                   pos (point)))
   3977 
   3978            ((search-forward closing-string reg-end t)
   3979             (setq close (match-end 0)
   3980                   pos (point)))
   3981            ) ;cond
   3982 
   3983           (when (and close (>= reg-end pos))
   3984             ;;(message "pos(%S) : open(%S) close(%S)" pos open close)
   3985             (put-text-property open (1+ open) 'block-beg 0)
   3986             (put-text-property open (1+ open) 'block-controls 0)
   3987             (put-text-property open close 'block-side t)
   3988             (put-text-property (1- close) close 'block-end t)
   3989             (when delim-open
   3990               (web-mode-block-delimiters-set open close delim-open delim-close))
   3991             (web-mode-block-scan open close)
   3992             (cond
   3993              ((and (string= web-mode-engine "erb")
   3994                    (looking-at-p "<%= javascript_tag do %>"))
   3995               (setq tagopen "<%= javascript_tag do %>"))
   3996              ((and (string= web-mode-engine "mojolicious")
   3997                    (looking-at-p "%= javascript begin"))
   3998               (setq tagopen "%= javascript begin"))
   3999              ((and (string= web-mode-engine "mako")
   4000                    (looking-at-p "<%block filter=\"collect_js\">"))
   4001               (setq tagopen "<%block filter=\"collect_js\">"))
   4002              ((and (string= web-mode-engine "mako")
   4003                    (looking-at-p "<%block filter=\"collect_css\">"))
   4004               (setq tagopen "<%block filter=\"collect_css\">"))
   4005              ((and (string= web-mode-engine "django")
   4006                    (looking-at-p "{% javascript %}"))
   4007               (setq tagopen "{% javascript %}"))
   4008              ((and (string= web-mode-engine "django")
   4009                    (looking-at-p "{% schema %}"))
   4010               (setq tagopen "{% schema %}"))
   4011              ((and (string= web-mode-engine "django")
   4012                    (looking-at-p "{% stylesheet %}"))
   4013               (setq tagopen "{% stylesheet %}"))
   4014              )
   4015             ;;(message "%S %s" (point) tagopen)
   4016             (when (and (member tagopen '("<r:script" "<r:style"
   4017                                          "<c:js" "<c:css"
   4018                                          "<%= javascript_tag do %>"
   4019                                          "<%block filter=\"collect_js\">"
   4020                                          "<%block filter=\"collect_css\">"
   4021                                          "{% javascript %}"
   4022                                          "{% schema %}"
   4023                                          "{% stylesheet %}"
   4024                                          "%= javascript begin"))
   4025                        (setq part-beg close)
   4026                        (setq tagclose
   4027                              (cond
   4028                               ((string= tagopen "<r:script") "</r:script")
   4029                               ((string= tagopen "<r:style") "</r:style")
   4030                               ((string= tagopen "<c:js") "</c:js")
   4031                               ((string= tagopen "<c:css") "</c:css")
   4032                               ((string= tagopen "{% javascript %}") "{% endjavascript %}")
   4033                               ((string= tagopen "{% schema %}") "{% endschema %}")
   4034                               ((string= tagopen "{% stylesheet %}") "{% endstylesheet %}")
   4035                               ((string= tagopen "%= javascript begin") "% end")
   4036                               ((string= tagopen "<%= javascript_tag do %>") "<% end %>")
   4037                               ((member tagopen '("<%block filter=\"collect_js\">"
   4038                                                  "<%block filter=\"collect_css\">")) "</%block")
   4039                               ))
   4040                        (web-mode-sf tagclose)
   4041                        (setq part-end (match-beginning 0))
   4042                        (> part-end part-beg))
   4043               ;;(message "end=%S" (point))
   4044               (put-text-property part-beg part-end
   4045                                  'part-side
   4046                                  (cond
   4047                                   ((member tagopen '("<r:style" "<c:css" "<%block filter=\"collect_css\">" "{% stylesheet %}")) 'css)
   4048                                   (t 'javascript)))
   4049               (setq pos part-beg
   4050                     part-beg nil
   4051                     part-end nil)
   4052               ) ;when
   4053             ) ;when close
   4054 
   4055           (if pos (goto-char pos))
   4056 
   4057           ) ;when closing-string
   4058 
   4059         ) ;while
   4060 
   4061       (cond
   4062        ((>= i 2000)
   4063         (message "scan-blocks ** warning (%S) **" i))
   4064        ((string= web-mode-engine "razor")
   4065         (web-mode-block-foreach reg-beg reg-end 'web-mode-block-scan))
   4066        ((string= web-mode-engine "django")
   4067         (web-mode-scan-engine-comments reg-beg reg-end
   4068                                        "{% comment %}" "{% endcomment %}"))
   4069        ((string= web-mode-engine "mako")
   4070         (web-mode-scan-engine-comments reg-beg reg-end
   4071                                        "<%doc>" "</%doc>"))
   4072        ((string= web-mode-engine "mason")
   4073         (web-mode-scan-engine-comments reg-beg reg-end
   4074                                        "<%doc>" "</%doc>"))
   4075        ) ;cond
   4076 
   4077       )))
   4078 
   4079 (defun web-mode-scan-engine-comments (reg-beg reg-end tag-start tag-end)
   4080   "Scan engine comments (mako, django)."
   4081   (save-excursion
   4082     (let (beg end (continue t))
   4083       (goto-char reg-beg)
   4084       (while (and continue
   4085                   (< (point) reg-end)
   4086                   (re-search-forward tag-start reg-end t))
   4087         (goto-char (match-beginning 0))
   4088         (setq beg (point))
   4089         (if (not (re-search-forward tag-end reg-end t))
   4090             (setq continue nil)
   4091           (setq end (point))
   4092           (remove-list-of-text-properties beg end web-mode-scan-properties)
   4093           (add-text-properties beg end '(block-side t block-token comment))
   4094           (put-text-property beg (1+ beg) 'block-beg 0)
   4095           (put-text-property (1- end) end 'block-end t)
   4096           ) ;if
   4097         ) ;while
   4098       )))
   4099 
   4100 (defun web-mode-closure-skip (reg-beg reg-end)
   4101   (let (regexp char pos inc continue found)
   4102     (setq regexp "[\"'{}]"
   4103           inc 0)
   4104     (while (and (not found) (re-search-forward regexp reg-end t))
   4105       (setq char (char-before))
   4106       (cond
   4107        ((get-text-property (point) 'block-side)
   4108         (setq found t))
   4109        ((eq char ?\{)
   4110         (setq inc (1+ inc)))
   4111        ((eq char ?\})
   4112         (cond
   4113          ((and (not (eobp))
   4114                (< inc 1))
   4115           (setq found t
   4116                 pos (point)))
   4117          ((> inc 0)
   4118           (setq inc (1- inc)))
   4119          )
   4120         )
   4121        ((eq char ?\')
   4122         (setq continue t)
   4123         (while (and continue (search-forward "'" reg-end t))
   4124           (setq continue (web-mode-string-continue-p reg-beg))
   4125           )
   4126         )
   4127        ((eq char ?\")
   4128         (setq continue t)
   4129         (while (and continue (search-forward "\"" reg-end t))
   4130           (setq continue (web-mode-string-continue-p reg-beg))
   4131           )
   4132         )
   4133        ) ;cond
   4134       ) ;while
   4135     pos))
   4136 
   4137 (defun web-mode-django-skip (reg-beg reg-end)
   4138   (let (regexp char pos inc continue found)
   4139     (setq regexp "[\"'{}]"
   4140           inc 0)
   4141     (while (and (not found) (re-search-forward regexp reg-end t))
   4142       (setq char (char-before))
   4143       (cond
   4144        ((get-text-property (point) 'block-side)
   4145         (setq found t))
   4146        ((eq char ?\{)
   4147         (setq inc (1+ inc)))
   4148        ((eq char ?\})
   4149         (cond
   4150          ((and (not (eobp))
   4151                (eq (char-after) ?\})
   4152                (< inc 2))
   4153           (forward-char)
   4154           (setq found t
   4155                 pos (1+ (point))))
   4156          ((> inc 0)
   4157           (setq inc (1- inc)))
   4158          )
   4159         )
   4160        ((eq char ?\')
   4161         (setq continue t)
   4162         (while (and continue (search-forward "'" reg-end t))
   4163           (setq continue (web-mode-string-continue-p reg-beg))
   4164           )
   4165         )
   4166        ((eq char ?\")
   4167         (setq continue t)
   4168         (while (and continue (search-forward "\"" reg-end t))
   4169           (setq continue (web-mode-string-continue-p reg-beg))
   4170           )
   4171         )
   4172        ) ;cond
   4173       ) ;while
   4174     pos))
   4175 
   4176 (defun web-mode-blade-skip (pos)
   4177   (goto-char pos)
   4178   (forward-char)
   4179   (skip-chars-forward "a-zA-Z0-9_-"))
   4180 
   4181 (defun web-mode-velocity-skip (pos)
   4182   (goto-char pos)
   4183   (let ((continue t) (i 0))
   4184     (when (eq ?\# (char-after))
   4185       (forward-char))
   4186     (when (member (char-after) '(?\$ ?\@))
   4187       (forward-char))
   4188     (when (member (char-after) '(?\!))
   4189       (forward-char))
   4190     (cond
   4191      ((member (char-after) '(?\{))
   4192       (search-forward "}" nil t))
   4193      ((looking-at-p "def \\|define ")
   4194       (search-forward ")" (line-end-position) t))
   4195      (t
   4196       (setq continue t)
   4197       (while continue
   4198         (skip-chars-forward "a-zA-Z0-9_-")
   4199         (when (> (setq i (1+ i)) 500)
   4200           (message "velocity-skip ** warning (%S) **" pos)
   4201           (setq continue nil))
   4202         (when (member (char-after) '(?\())
   4203           (search-forward ")" nil t))
   4204         (if (member (char-after) '(?\.))
   4205             (forward-char)
   4206           (setq continue nil))
   4207         ) ;while
   4208       ) ;t
   4209      ) ;cond
   4210     ))
   4211 
   4212 (defun web-mode-razor-skip (pos)
   4213   (goto-char pos)
   4214   (let ((continue t) (i 0))
   4215     (while continue
   4216       (skip-chars-forward " =@a-zA-Z0-9_-")
   4217       (cond
   4218        ((> (setq i (1+ i)) 500)
   4219         (message "razor-skip ** warning **")
   4220         (setq continue nil))
   4221        ((and (eq (char-after) ?\*)
   4222              (eq (char-before) ?@))
   4223         (when (not (search-forward "*@" nil t))
   4224           (setq continue nil))
   4225         )
   4226        ((looking-at-p "@[({]")
   4227         (forward-char)
   4228         (when (setq pos (web-mode-closing-paren-position (point)))
   4229           (goto-char pos))
   4230         (forward-char)
   4231         )
   4232        ((and (not (eobp)) (eq ?\( (char-after)))
   4233         (cond
   4234          ((looking-at-p "[ \n]*[<@]")
   4235           (setq continue nil))
   4236          ((setq pos (web-mode-closing-paren-position))
   4237           (goto-char pos)
   4238           (forward-char))
   4239          (t
   4240           (forward-char))
   4241          ) ;cond
   4242         )
   4243        ((and (not (eobp)) (eq ?\< (char-after)) (looking-back "[a-z]" (point-min)))
   4244         (setq pos (point))
   4245         (cond
   4246          ;; #988
   4247          ((search-forward ">" (line-end-position) t)
   4248           (goto-char pos)
   4249           (setq continue nil)
   4250           )
   4251          (t
   4252           (setq continue nil))
   4253          ) ;cond
   4254         )
   4255        ((and (not (eobp)) (eq ?\. (char-after)))
   4256         (forward-char))
   4257        ((and (not (eobp)) (looking-at-p "[ \n]*else"))
   4258         (re-search-forward "[ \t]*else")
   4259         )
   4260        ((looking-at-p "[ \n]*{")
   4261         (search-forward "{")
   4262         (search-forward "=>" (point-at-eol) 't)
   4263         (if (looking-at-p "[ \n]*[<@]")
   4264             (setq continue nil)
   4265           (backward-char)
   4266           (when (setq pos (web-mode-closing-paren-position))
   4267             (goto-char pos))
   4268           (forward-char)
   4269           ) ;if
   4270         )
   4271        ((looking-at-p "}")
   4272         (forward-char))
   4273        (t
   4274         (setq continue nil))
   4275        ) ;cond
   4276       ) ;while
   4277     ))
   4278 
   4279 (defun web-mode-block-delimiters-set (reg-beg reg-end delim-open delim-close)
   4280   "Set text-property 'block-token to 'delimiter-(beg|end) on block delimiters (e.g. <?php and ?>)"
   4281   ;;(message "reg-beg(%S) reg-end(%S) delim-open(%S) delim-close(%S)" reg-beg reg-end delim-open delim-close)
   4282   (when (member web-mode-engine
   4283                 '("artanis" "anki" "asp" "aspx" "cl-emb" "clip" "closure" "ctemplate" "django" "dust"
   4284                   "elixir" "ejs" "erb" "expressionengine" "freemarker" "go" "hero" "jsp" "lsp"
   4285                   "mako" "mason" "mojolicious"
   4286                   "perl"
   4287                   "smarty" "template-toolkit" "web2py" "xoops" "svelte"))
   4288     (save-excursion
   4289       (when delim-open
   4290         (goto-char reg-beg)
   4291         (looking-at delim-open)
   4292         (setq delim-open (match-string-no-properties 0)))
   4293       (when delim-close
   4294         (goto-char reg-end)
   4295         (looking-back delim-close reg-beg t)
   4296         (setq delim-close (match-string-no-properties 0)))
   4297       ))
   4298   (when delim-open
   4299     (put-text-property reg-beg (+ reg-beg (length delim-open))
   4300                        'block-token 'delimiter-beg))
   4301   (when delim-close
   4302     (put-text-property (- reg-end (length delim-close)) reg-end
   4303                        'block-token 'delimiter-end))
   4304   )
   4305 
   4306 (defun web-mode-block-foreach (reg-beg reg-end func)
   4307   (let ((i 0) (continue t) (block-beg reg-beg) (block-end nil))
   4308     (while continue
   4309       (setq block-end nil)
   4310       (unless (get-text-property block-beg 'block-beg)
   4311         (setq block-beg (web-mode-block-next-position block-beg)))
   4312       (when (and block-beg (< block-beg reg-end))
   4313         (setq block-end (web-mode-block-end-position block-beg)))
   4314       (cond
   4315        ((> (setq i (1+ i)) 2000)
   4316         (message "process-blocks ** warning (%S) **" (point))
   4317         (setq continue nil))
   4318        ((or (null block-end) (> block-end reg-end))
   4319         (setq continue nil))
   4320        (t
   4321         (setq block-end (1+ block-end))
   4322         (funcall func block-beg block-end)
   4323         (setq block-beg block-end)
   4324         ) ;t
   4325        ) ;cond
   4326       ) ;while
   4327     ))
   4328 
   4329 (defun web-mode-block-scan (block-beg block-end)
   4330   (let (sub1 sub2 sub3 regexp token-type)
   4331 
   4332     ;;(message "block-beg=%S block-end=%S" block-beg block-end)
   4333     ;;(remove-text-properties block-beg block-end web-mode-scan-properties)
   4334 
   4335     (goto-char block-beg)
   4336 
   4337     (cond
   4338      ((>= (point-max) (+ block-beg 3))
   4339       (setq sub3 (buffer-substring-no-properties block-beg (+ block-beg 3))
   4340             sub2 (buffer-substring-no-properties block-beg (+ block-beg 2))
   4341             sub1 (buffer-substring-no-properties block-beg (+ block-beg 1)))
   4342       )
   4343      ((>= (point-max) (+ block-beg 2))
   4344       (setq sub3 (buffer-substring-no-properties block-beg (+ block-beg 2))
   4345             sub2 (buffer-substring-no-properties block-beg (+ block-beg 2))
   4346             sub1 (buffer-substring-no-properties block-beg (+ block-beg 1)))
   4347       )
   4348      (t
   4349       (setq sub1 (buffer-substring-no-properties block-beg (+ block-beg 1)))
   4350       (setq sub2 sub1
   4351             sub3 sub1)
   4352       )
   4353      )
   4354 
   4355     (cond
   4356 
   4357      ((member web-mode-engine '("php" "lsp" "python" "web2py" "mason"))
   4358       (setq regexp web-mode-engine-token-regexp))
   4359 
   4360      ((string= web-mode-engine "mako")
   4361       (cond
   4362        ((string= sub2 "##")
   4363         (setq token-type 'comment)
   4364         )
   4365        (t
   4366         (setq regexp web-mode-engine-token-regexp))
   4367        )
   4368       ) ;mako
   4369 
   4370      ((string= web-mode-engine "django")
   4371       (cond
   4372        ((member sub2 '("{{" "{%"))
   4373         (setq regexp "\"\\|'"))
   4374        ((string= sub2 "{#")
   4375         (setq token-type 'comment))
   4376        )
   4377       ) ;django
   4378 
   4379      ((string= web-mode-engine "ctemplate")
   4380       (cond
   4381        ((string= sub3 "{{!")
   4382         (setq token-type 'comment))
   4383        ((member sub2 '("{{"))
   4384         )
   4385        )
   4386       ) ;ctemplate
   4387 
   4388      ((string= web-mode-engine "go")
   4389       (cond
   4390        ((string= sub3 "{{/")
   4391         (setq token-type 'comment))
   4392        ((string= sub2 "{{")
   4393         (setq regexp "\"\\|'"))
   4394        )
   4395       ) ;go
   4396 
   4397      ((string= web-mode-engine "hero")
   4398       (cond
   4399        ((string= sub3 "<%#")
   4400         (setq token-type 'comment))
   4401        (t
   4402         (setq regexp "\"\\|'"))
   4403        )
   4404       ) ;hero
   4405 
   4406      ((string= web-mode-engine "razor")
   4407       (cond
   4408        ((string= sub2 "@*")
   4409         (setq token-type 'comment))
   4410        (t
   4411         (setq regexp "//\\|@\\*\\|\"\\|'"))
   4412        )
   4413       ) ;razor
   4414 
   4415      ((string= web-mode-engine "blade")
   4416       (cond
   4417        ((string= sub3 "{{-")
   4418         (setq token-type 'comment))
   4419        (t
   4420         (setq regexp "\"\\|'"))
   4421        )
   4422       ) ;blade
   4423 
   4424      ((string= web-mode-engine "cl-emb")
   4425       (cond
   4426        ((string= sub3 "<%#")
   4427         (setq token-type 'comment))
   4428        (t
   4429         (setq regexp "\"\\|'"))
   4430        )
   4431       ) ;cl-emb
   4432 
   4433      ((string= web-mode-engine "artanis")
   4434       (cond
   4435        ((string= sub3 "<%;")
   4436         (setq token-type 'comment))
   4437        ((string= sub3 "<%#|")
   4438         (setq token-type 'comment))
   4439        (t
   4440         (setq regexp "\""))
   4441        )
   4442       ) ;artanis
   4443 
   4444      ((string= web-mode-engine "elixir")
   4445       (cond
   4446        ((string= sub3 "<%#")
   4447         (setq token-type 'comment))
   4448        (t
   4449         (setq regexp "\"\\|'"))
   4450        )
   4451       ) ;elixir
   4452 
   4453      ((string= web-mode-engine "mojolicious")
   4454       (cond
   4455        ((or (string= sub2 "%#") (string= sub3 "<%#"))
   4456         (setq token-type 'comment))
   4457        (t
   4458         (setq regexp "\"\\|'"))
   4459        )
   4460       ) ;mojolicious
   4461 
   4462      ((string= web-mode-engine "velocity")
   4463       (cond
   4464        ((member sub2 '("##" "#*"))
   4465         (setq token-type 'comment))
   4466        ((member sub1 '("$" "#"))
   4467         (setq regexp "\"\\|'"))
   4468        )
   4469       ) ;velocity
   4470 
   4471      ((string= web-mode-engine "jsp")
   4472       (cond
   4473        ((string= sub3 "<%-")
   4474         (setq token-type 'comment))
   4475        ((string= sub3 "<%@")
   4476         (setq regexp "/\\*"))
   4477        ((member sub2 '("${" "#{"))
   4478         (setq regexp "\"\\|'"))
   4479        ((string= sub2 "<%")
   4480         (setq regexp "//\\|/\\*\\|\"\\|'"))
   4481        )
   4482       ) ;jsp
   4483 
   4484      ((string= web-mode-engine "clip")
   4485       (setq regexp nil)
   4486       ) ;clip
   4487 
   4488      ((string= web-mode-engine "perl")
   4489       (setq regexp nil)
   4490       ) ;perl
   4491 
   4492      ((and (string= web-mode-engine "asp")
   4493            (string= sub2 "<%"))
   4494       (setq regexp "//\\|/\\*\\|\"\\|''")
   4495       ) ;asp
   4496 
   4497      ((string= web-mode-engine "aspx")
   4498       (cond
   4499        ((string= sub3 "<%-")
   4500         (setq token-type 'comment))
   4501        ((string= sub3 "<%@")
   4502         (setq regexp "/\\*"))
   4503        ((string= sub3 "<%$")
   4504         (setq regexp "\"\\|'"))
   4505        (t
   4506         (setq regexp "//\\|/\\*\\|\"\\|'"))
   4507        )
   4508       ) ;aspx
   4509 
   4510      ((string= web-mode-engine "freemarker")
   4511       (cond
   4512        ((member sub3 '("<#-" "[#-"))
   4513         (setq token-type 'comment))
   4514        ((member sub2 '("${" "#{"))
   4515         (setq regexp "\"\\|'"))
   4516        ((or (member sub2 '("<@" "[@" "<#" "[#"))
   4517             (member sub3 '("</@" "[/@" "</#" "[/#")))
   4518         (setq regexp "\"\\|'"))
   4519        )
   4520       ) ;freemarker
   4521 
   4522      ((member web-mode-engine '("ejs" "erb"))
   4523       (cond
   4524        ((string= sub3 "<%#")
   4525         (setq token-type 'comment))
   4526        (t
   4527         (setq regexp web-mode-engine-token-regexp))
   4528        )
   4529       ) ;erb
   4530 
   4531      ((string= web-mode-engine "template-toolkit")
   4532       (cond
   4533        ((member sub3 '("[%#" "%%#"))
   4534         (setq token-type 'comment))
   4535        (t
   4536         (setq regexp "#\\|\"\\|'"))
   4537        )
   4538       ) ;template-toolkit
   4539 
   4540      ((string= web-mode-engine "underscore")
   4541       (setq regexp "/\\*\\|\"\\|'")
   4542       ) ;underscore
   4543 
   4544      ((string= web-mode-engine "angular")
   4545       (setq regexp "#\\|\"\\|'")) ;angular
   4546 
   4547      ((string= web-mode-engine "vue")
   4548       ) ;vue
   4549 
   4550      ((string= web-mode-engine "smarty")
   4551       (cond
   4552        ((string= sub2 "{*")
   4553         (setq token-type 'comment))
   4554        (t
   4555         (setq regexp "\"\\|'")))
   4556       ) ;smarty
   4557 
   4558      ((string= web-mode-engine "xoops")
   4559       (cond
   4560        ((string= sub3 "<{*")
   4561         (setq token-type 'comment))
   4562        (t
   4563         (setq regexp "\"\\|'")))
   4564       ) ;xoops
   4565 
   4566      ((string= web-mode-engine "spip")
   4567       (if (string= (buffer-substring-no-properties
   4568                     block-beg (+ block-beg 7))
   4569                    "[(#REM)")
   4570           (setq token-type 'comment
   4571                 regexp "\\]")))
   4572 
   4573      ((string= web-mode-engine "dust")
   4574       (cond
   4575        ((string= sub2 "{!")
   4576         (setq token-type 'comment))
   4577        (t
   4578         (setq regexp "\"\\|'"))
   4579        )
   4580       ) ;dust
   4581 
   4582      ((string= web-mode-engine "expressionengine")
   4583       (cond
   4584        ((string= sub2 "{!")
   4585         (setq token-type 'comment))
   4586        (t
   4587         (setq regexp "\"\\|'")))
   4588       ) ;expressionengine
   4589 
   4590      ((string= web-mode-engine "closure")
   4591       (cond
   4592        ((member sub2 '("/*" "//"))
   4593         (setq token-type 'comment))
   4594        (t
   4595         (setq regexp "\"\\|'"))
   4596        )
   4597       ) ;closure
   4598 
   4599      ((string= web-mode-engine "svelte")
   4600       ) ;svelte
   4601 
   4602      ) ;cond
   4603 
   4604     (cond
   4605      (token-type
   4606       (put-text-property block-beg block-end 'block-token token-type))
   4607      ((and regexp
   4608            (> (- block-end block-beg) 6))
   4609       (web-mode-block-tokenize
   4610        (web-mode-block-code-beginning-position block-beg)
   4611        (web-mode-block-code-end-position block-beg)
   4612        regexp)
   4613       )
   4614      ) ;cond
   4615 
   4616     ))
   4617 
   4618 (defun web-mode-block-tokenize (reg-beg reg-end &optional regexp)
   4619   (unless regexp (setq regexp web-mode-engine-token-regexp))
   4620   ;;(message "tokenize: reg-beg(%S) reg-end(%S) regexp(%S)" reg-beg reg-end regexp)
   4621   ;;(message "tokenize: reg-beg(%S) reg-end(%S) command(%S)" reg-beg reg-end this-command)
   4622   ;;(message "%S>%S : %S" reg-beg reg-end (buffer-substring-no-properties reg-beg reg-end))
   4623   (save-excursion
   4624     (let ((pos reg-beg) beg char match continue (flags 0) token-type token-end)
   4625 
   4626       (remove-list-of-text-properties reg-beg reg-end '(block-token))
   4627 
   4628       ;; TODO : vérifier la cohérence
   4629       (put-text-property reg-beg reg-end 'block-side t)
   4630 
   4631       (goto-char reg-beg)
   4632 
   4633       (when (> (point) reg-end)
   4634         (message "block-tokenize ** reg-beg(%S) > reg-end(%S) **" reg-beg reg-end))
   4635 
   4636       (while (and (< (point) reg-end) (re-search-forward regexp reg-end t))
   4637         (setq beg (match-beginning 0)
   4638               match (match-string 0)
   4639               continue t
   4640               token-type 'comment
   4641               token-end (if (< reg-end (line-end-position)) reg-end (line-end-position))
   4642               char (aref match 0))
   4643         (cond
   4644 
   4645          ((and (string= web-mode-engine "asp") (string= match "''"))
   4646           (goto-char token-end))
   4647 
   4648          ((and (string= web-mode-engine "razor") (eq char ?\'))
   4649           (cond
   4650            ((looking-at-p "\\(.\\|[\\][bfntr]\\|[\\]u....\\)'")
   4651             (search-forward "'" reg-end t)
   4652             (setq token-type 'string)
   4653             )
   4654            (t
   4655             (re-search-forward "[[:alnum:]_-]+")
   4656             (setq token-type 'symbol)
   4657             )))
   4658 
   4659          ((eq char ?\')
   4660           (setq token-type 'string)
   4661           (while (and continue (search-forward "'" reg-end t))
   4662             (setq continue (web-mode-string-continue-p reg-beg))
   4663             ))
   4664 
   4665          ((eq char ?\")
   4666           (setq token-type 'string)
   4667           (while (and continue (search-forward "\"" reg-end t))
   4668             (setq continue (web-mode-string-continue-p reg-beg))
   4669             ))
   4670 
   4671          ((string= match "//")
   4672           (goto-char token-end))
   4673 
   4674          ((eq char ?\;)
   4675           (goto-char token-end))
   4676 
   4677          ((string= match "#|")
   4678           (unless (search-forward "|#" reg-end t)
   4679             (goto-char token-end)))
   4680 
   4681          ((eq char ?\#)
   4682           (goto-char token-end))
   4683 
   4684          ((string= match "/*")
   4685           (unless (search-forward "*/" reg-end t)
   4686             (goto-char token-end))
   4687           )
   4688 
   4689          ((string= match "@*")
   4690           (unless (search-forward "*@" reg-end t)
   4691             (goto-char token-end)))
   4692 
   4693          ((eq char ?\<)
   4694           (setq token-type 'string)
   4695           (re-search-forward (concat "^[ ]*" (match-string 1)) reg-end t))
   4696 
   4697          (t
   4698           (message "block-tokenize ** token end (%S) **" beg)
   4699           (setq token-type nil))
   4700 
   4701          ) ;cond
   4702 
   4703         (put-text-property beg (point) 'block-token token-type)
   4704 
   4705         (when (eq token-type 'comment)
   4706           (put-text-property beg (1+ beg) 'syntax-table (string-to-syntax "<"))
   4707           (if (or (< (point) (line-end-position)) (= (point) (point-max)))
   4708               (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax ">")) ;#445 #480
   4709             (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax ">")) ;#377
   4710             )
   4711           )
   4712 
   4713         ) ;while
   4714 
   4715       (web-mode-block-controls-unset pos)
   4716 
   4717       )))
   4718 
   4719 (defun web-mode-set-php-controls (reg-beg reg-end)
   4720   (goto-char reg-beg)
   4721   (let (match controls
   4722         (continue t)
   4723         (regexp "endif\\|endforeach\\|endfor\\|endwhile\\|elseif\\|else\\|if\\|foreach\\|for\\|while"))
   4724     (while continue
   4725       (if (not (web-mode-block-rsf regexp reg-end))
   4726           (setq continue nil)
   4727         (setq match (match-string-no-properties 0))
   4728 ;;        (message "%S %S" match (point))
   4729         (cond
   4730          ((and (member match '("else" "elseif"))
   4731                (looking-at-p "[ ]*[:(]"))
   4732           (setq controls (append controls (list (cons 'inside "if"))))
   4733           )
   4734          ((and (>= (length match) 3)
   4735                (string= (substring match 0 3) "end"))
   4736           (setq controls (append controls (list (cons 'close (substring match 3)))))
   4737           )
   4738          ((and (progn (skip-chars-forward "[ ]") t)
   4739                (eq (char-after) ?\()
   4740                (web-mode-closing-paren reg-end)
   4741                ;;(progn (message "ixi%S" (point)))
   4742                (looking-at-p ")[ ]*:"))
   4743           (setq controls (append controls (list (cons 'open match))))
   4744           )
   4745          ) ;cond
   4746         ) ;if
   4747       ) ;while
   4748     ;;(message "%S-%S %S" reg-beg reg-end controls)
   4749     (when (and controls (> (length controls) 1))
   4750       (setq controls (web-mode-block-controls-reduce controls)))
   4751     controls))
   4752 
   4753 (defun web-mode-block-controls-reduce (controls)
   4754   (when (and (eq (car (car controls)) 'open)
   4755              (member (cons 'close (cdr (car controls))) controls))
   4756     (setq controls nil))
   4757   controls)
   4758 
   4759 (defun web-mode-block-controls-unset (pos)
   4760   (cond
   4761    ((null (get-text-property pos 'block-side))
   4762     (message "block-controls-unset ** invalid value (%S) **" pos))
   4763    ((or (get-text-property pos 'block-beg)
   4764         (setq pos (web-mode-block-beginning-position pos)))
   4765     (put-text-property pos (1+ pos) 'block-controls 0))
   4766    (t
   4767     (message "block-controls-unset ** failure (%S) **" (point)))
   4768    ))
   4769 
   4770 (defun web-mode-block-controls-get (pos)
   4771   (web-mode-with-silent-modifications
   4772    (let ((controls nil))
   4773      (cond
   4774       ((null (get-text-property pos 'block-side))
   4775        (message "block-controls-get ** invalid value (%S) **" pos))
   4776       ((or (get-text-property pos 'block-beg)
   4777            (setq pos (web-mode-block-beginning-position pos)))
   4778        (setq controls (get-text-property pos 'block-controls))
   4779        (when (integerp controls)
   4780          (web-mode-block-controls-set pos (web-mode-block-end-position pos))
   4781          (setq controls (get-text-property pos 'block-controls))
   4782          )
   4783        )
   4784       (t
   4785        (message "block-controls-get ** failure (%S) **" (point)))
   4786       ) ;cond
   4787      controls)))
   4788 
   4789 (defun web-mode-block-controls-set (reg-beg reg-end)
   4790   (save-excursion
   4791     (goto-char reg-beg)
   4792     (let (controls pos type control)
   4793 
   4794       (cond
   4795 
   4796        ((null web-mode-engine)
   4797         (message "block-controls-set ** unknown engine (%S) **" web-mode-engine)
   4798         )
   4799 
   4800        ((string= web-mode-engine "php")
   4801         (setq controls (web-mode-set-php-controls reg-beg reg-end))
   4802         (when (web-mode-block-starts-with "}" reg-beg)
   4803           (setq controls (append controls (list (cons 'close "{")))))
   4804         (when (web-mode-block-ends-with (cons "{" "}") reg-beg)
   4805           (setq controls (append controls (list (cons 'open "{")))))
   4806         ) ;php
   4807 
   4808        ((string= web-mode-engine "ejs")
   4809         (cond
   4810          ((web-mode-block-ends-with "}[ ]*else[ ]*{" reg-beg)
   4811           (setq controls (append controls (list (cons 'inside "{")))))
   4812          ((web-mode-block-starts-with "}" reg-beg)
   4813           (setq controls (append controls (list (cons 'close "{")))))
   4814          ((web-mode-block-ends-with "{" reg-beg)
   4815           (setq controls (append controls (list (cons 'open "{")))))
   4816          )
   4817         ) ;ejs
   4818 
   4819        ((string= web-mode-engine "erb")
   4820         (cond
   4821          ((web-mode-block-starts-with "else\\|elsif\\|when" reg-beg)
   4822           (setq controls (append controls (list (cons 'inside "ctrl")))))
   4823          ((web-mode-block-starts-with "end" reg-beg)
   4824           (setq controls (append controls (list (cons 'close "ctrl")))))
   4825          ((web-mode-block-ends-with " do\\( |.*|\\)?" reg-beg)
   4826           (setq controls (append controls (list (cons 'open "ctrl")))))
   4827          ((and (web-mode-block-starts-with "\\(for\\|if\\|unless\\|case\\)\\_>" reg-beg)
   4828                (not (web-mode-block-ends-with "end" reg-end)))
   4829           (setq controls (append controls (list (cons 'open "ctrl")))))
   4830          )
   4831         ) ;erb
   4832 
   4833        ((string= web-mode-engine "django")
   4834         (cond
   4835          ((and (string= web-mode-minor-engine "jinja") ;#504
   4836                (web-mode-block-starts-with "else\\_>" reg-beg))
   4837           (let ((continue t)
   4838                 (pos reg-beg)
   4839                 (ctrl nil))
   4840             (while continue
   4841               (cond
   4842                ((null (setq pos (web-mode-block-control-previous-position 'open pos)))
   4843                 (setq continue nil))
   4844                ((member (setq ctrl (cdr (car (get-text-property pos 'block-controls)))) '("if" "ifequal" "ifnotequal" "for"))
   4845                 (setq continue nil)
   4846                 )
   4847                ) ;cond
   4848               )
   4849             (setq controls (append controls (list (cons 'inside (or ctrl "if")))))
   4850             )
   4851           )
   4852          ((web-mode-block-starts-with "form_start[ ]*(" reg-beg)
   4853           (setq controls (append controls (list (cons 'open "form_start")))))
   4854          ((web-mode-block-starts-with "form_end[ ]*(" reg-beg)
   4855           (setq controls (append controls (list (cons 'close "form_start")))))
   4856          ((not (eq (char-after (1+ reg-beg)) ?\%))
   4857           )
   4858          ((web-mode-block-starts-with "\\(else\\|els?if\\)" reg-beg)
   4859           (let ((continue t)
   4860                 (pos reg-beg)
   4861                 (ctrl nil))
   4862             (while continue
   4863               (cond
   4864                ((null (setq pos (web-mode-block-control-previous-position 'open pos)))
   4865                 (setq continue nil))
   4866                ((member (setq ctrl (cdr (car (get-text-property pos 'block-controls)))) '("if" "ifequal" "ifnotequal"))
   4867                 (setq continue nil)
   4868                 )
   4869                ) ;cond
   4870               ) ;while
   4871             (setq controls (append controls (list (cons 'inside (or ctrl "if")))))
   4872             ) ;let
   4873           ) ;case else
   4874          ((web-mode-block-starts-with "\\(empty\\)" reg-beg)
   4875           (setq controls (append controls (list (cons 'inside "for")))))
   4876          ((web-mode-block-starts-with "end\\([[:alpha:]]+\\)" reg-beg)
   4877           (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   4878          ((web-mode-block-starts-with "set [[:alpha:]]+[ ]*%}" reg-beg)
   4879           (setq controls (append controls (list (cons 'open "set")))))
   4880          ((web-mode-block-starts-with (concat web-mode-django-control-blocks-regexp "[ %]") reg-beg)
   4881           (let (control)
   4882             (setq control (match-string-no-properties 1))
   4883             ;;(message "%S %S %S" control (concat "end" control) web-mode-django-control-blocks)
   4884             (when (member (concat "end" control) web-mode-django-control-blocks)
   4885               (setq controls (append controls (list (cons 'open control))))
   4886               ) ;when
   4887             ) ;let
   4888           ) ;case
   4889          ) ;cond
   4890         ) ;django
   4891 
   4892        ((string= web-mode-engine "smarty")
   4893         (cond
   4894          ((and (eq (char-after (1+ reg-beg)) ?\/)
   4895                (web-mode-block-starts-with "\\([[:alpha:]]+\\)" reg-beg))
   4896           (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   4897          ((web-mode-block-starts-with "\\(else\\|elseif\\)" reg-beg)
   4898           (setq controls (append controls (list (cons 'inside "if")))))
   4899          ((web-mode-block-starts-with "\\(block\\|foreach\\|for\\|if\\|section\\|while\\)")
   4900           (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   4901          )
   4902         ) ;smarty
   4903 
   4904        ((string= web-mode-engine "expressionengine")
   4905         (cond
   4906          ((and (eq (char-after (1+ reg-beg)) ?\/)
   4907                (web-mode-block-starts-with "\\(if\\)" reg-beg))
   4908           (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   4909          ((web-mode-block-starts-with "\\(if:else\\|if:ifelse\\)" reg-beg)
   4910           (setq controls (append controls (list (cons 'inside "if")))))
   4911          ((web-mode-block-starts-with "\\(if\\)")
   4912           (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   4913          )
   4914         ) ;expressionengine
   4915 
   4916        ((string= web-mode-engine "xoops")
   4917         (cond
   4918          ((and (eq (char-after (+ reg-beg 2)) ?\/)
   4919                (web-mode-block-starts-with "\\([[:alpha:]]+\\)" reg-beg))
   4920           (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   4921          ((web-mode-block-starts-with "\\(else\\|elseif\\)" reg-beg)
   4922           (setq controls (append controls (list (cons 'inside "if")))))
   4923          ((web-mode-block-starts-with "\\(block\\|foreach\\|for\\|if\\|section\\|while\\)")
   4924           (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   4925          )
   4926         ) ;xoops
   4927 
   4928        ((string= web-mode-engine "web2py")
   4929         (cond
   4930          ((web-mode-block-starts-with "def" reg-beg)
   4931           (setq controls (append controls (list (cons 'open "def")))))
   4932          ((web-mode-block-starts-with "return" reg-beg)
   4933           (setq controls (append controls (list (cons 'close "def")))))
   4934          ((web-mode-block-starts-with "block" reg-beg)
   4935           (setq controls (append controls (list (cons 'open "block")))))
   4936          ((web-mode-block-starts-with "end" reg-beg)
   4937           (setq controls (append controls (list (cons 'close "block")))))
   4938          ((web-mode-block-starts-with "pass" reg-beg)
   4939           (setq controls (append controls (list (cons 'close "ctrl")))))
   4940          ((web-mode-block-starts-with "\\(except\\|finally\\|els\\)" reg-beg)
   4941           (setq controls (append controls (list (cons 'inside "ctrl")))))
   4942          ((web-mode-block-starts-with "\\(if\\|for\\|try\\|while\\)")
   4943           (setq controls (append controls (list (cons 'open "ctrl")))))
   4944          )
   4945         ) ;web2py
   4946 
   4947        ((string= web-mode-engine "dust")
   4948         (cond
   4949          ((eq (char-after (1- reg-end)) ?\/)
   4950           )
   4951          ((eq (char-after (1+ reg-beg)) ?\:)
   4952           (setq pos (web-mode-block-control-previous-position 'open reg-beg))
   4953           (when pos
   4954             (setq controls (append controls
   4955                                    (list
   4956                                     (cons 'inside
   4957                                           (cdr (car (web-mode-block-controls-get pos))))))))
   4958           )
   4959          ((looking-at "{/\\([[:alpha:].]+\\)")
   4960           (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   4961          ((looking-at "{[#?@><+^]\\([[:alpha:].]+\\)")
   4962           (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   4963          )
   4964         ) ;dust
   4965 
   4966        ((string= web-mode-engine "anki")
   4967         (cond
   4968          ((looking-at "{{[#^]\\([[:alpha:].]+\\)")
   4969           (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   4970          ((looking-at "{{/\\([[:alpha:].]+\\)")
   4971           (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   4972          )
   4973         ) ;anki
   4974 
   4975        ((member web-mode-engine '("mojolicious"))
   4976         (cond
   4977          ((web-mode-block-ends-with "begin" reg-beg)
   4978           (setq controls (append controls (list (cons 'open "begin")))))
   4979          ((web-mode-block-starts-with "end" reg-beg)
   4980           (setq controls (append controls (list (cons 'close "begin")))))
   4981          ((web-mode-block-starts-with "}[ ]*else[ ]*{" reg-beg)
   4982           (setq controls (append controls (list (cons 'inside "{")))))
   4983          ((web-mode-block-starts-with "}" reg-beg)
   4984           (setq controls (append controls (list (cons 'close "{")))))
   4985          ((web-mode-block-ends-with "{" reg-beg)
   4986           (setq controls (append controls (list (cons 'open "{")))))
   4987          )
   4988         ) ;mojolicious
   4989 
   4990        ((member web-mode-engine '("aspx" "underscore"))
   4991         (cond
   4992          ((and (web-mode-block-starts-with "}" reg-beg)
   4993                (web-mode-block-ends-with "{" reg-beg))
   4994           (setq controls (append controls (list (cons 'inside "{")))))
   4995          ((web-mode-block-starts-with "}" reg-beg)
   4996           (setq controls (append controls (list (cons 'close "{")))))
   4997          ((web-mode-block-ends-with "{" reg-beg)
   4998           (setq controls (append controls (list (cons 'open "{")))))
   4999          )
   5000         ) ;aspx underscore
   5001 
   5002        ((member web-mode-engine '("jsp" "asp" "clip" "perl"))
   5003         (cond
   5004           ((eq (char-after (1- reg-end)) ?\/)
   5005            )
   5006           ((looking-at "<TMPL_ELSE")
   5007            (setq controls (append controls (list (cons 'inside "TMPL_IF")))))
   5008           ((looking-at "</?\\([[:alpha:]]+\\(?:[:.][[:alpha:]]+\\)\\|[[:alpha:]]+Template\\|TMPL_[[:alpha:]]+\\)")
   5009            (setq control (match-string-no-properties 1)
   5010                  type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5011            (when (not (member control '("h:inputtext" "jsp:usebean" "jsp:forward" "struts:property")))
   5012              (setq controls (append controls (list (cons type control)))))
   5013            )
   5014           (t
   5015            (when (web-mode-block-starts-with "}" reg-beg)
   5016              (setq controls (append controls (list (cons 'close "{")))))
   5017            (when (web-mode-block-ends-with "{" reg-beg)
   5018              (setq controls (append controls (list (cons 'open "{")))))
   5019            )
   5020           )
   5021         ) ;jsp asp
   5022 
   5023        ((string= web-mode-engine "mako")
   5024         (cond
   5025          ((looking-at "</?%\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)")
   5026           (cond
   5027            ((eq (char-after (- (web-mode-block-end-position reg-beg) 1)) ?\/)
   5028             )
   5029            (t
   5030             (setq control (match-string-no-properties 1)
   5031                   type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5032             (setq controls (append controls (list (cons type control)))))
   5033            )
   5034           )
   5035          ((web-mode-block-starts-with "\\(else\\|elif\\)" reg-beg)
   5036           (setq controls (append controls (list (cons 'inside "if")))))
   5037          ((web-mode-block-starts-with "end\\(if\\|for\\)" reg-beg)
   5038           (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5039          ((and (web-mode-block-starts-with "if\\|for" reg-beg)
   5040                (web-mode-block-ends-with ":" reg-beg))
   5041           (setq controls (append controls (list (cons 'open (match-string-no-properties 0))))))
   5042          )
   5043         ) ;mako
   5044 
   5045        ((string= web-mode-engine "mason")
   5046         (cond
   5047          ((looking-at "</?%\\(after\\|around\\|augment\\|before\\|def\\|filter\\|method\\|override\\)")
   5048           (setq control (match-string-no-properties 1)
   5049                 type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5050           (setq controls (append controls (list (cons type control))))
   5051           )
   5052          )
   5053         ) ;mason
   5054 
   5055        ((string= web-mode-engine "ctemplate")
   5056         (cond
   5057          ((looking-at-p "{{else") ;#721
   5058           (let ((continue t)
   5059                 (pos reg-beg)
   5060                 (ctrl nil))
   5061             (while continue
   5062               (cond
   5063                ((null (setq pos (web-mode-block-control-previous-position 'open pos)))
   5064                 (setq continue nil))
   5065                ((member (setq ctrl (cdr (car (get-text-property pos 'block-controls)))) '("if" "each"))
   5066                 (setq continue nil)
   5067                 )
   5068                ) ;cond
   5069               ) ;while
   5070             (setq controls (append controls (list (cons 'inside (or ctrl "if")))))
   5071             )
   5072           )
   5073 
   5074          ((looking-at "{{[#^/][ ]*\\([[:alpha:]_.-]+\\)")
   5075           (setq control (match-string-no-properties 1)
   5076                 type (if (eq (aref (match-string-no-properties 0) 2) ?\/) 'close 'open))
   5077           (setq controls (append controls (list (cons type control))))
   5078           )
   5079          )
   5080         ) ;ctemplate
   5081 
   5082        ((string= web-mode-engine "blade")
   5083         (cond
   5084          ((not (eq (char-after) ?\@))
   5085           )
   5086          ((web-mode-block-starts-with
   5087            "section\(\s*\\(['\"]\\).*\\1\s*,\s*\\(['\"]\\).*\\2\s*\)" reg-beg)
   5088           )
   5089          ((web-mode-block-starts-with "case\\|break" reg-beg)
   5090           (setq type (if (eq (aref (match-string-no-properties 0) 0) ?b) 'close 'open))
   5091           (setq controls (append controls (list (cons type "case"))))
   5092           )
   5093          ((web-mode-block-starts-with
   5094            (concat "\\(?:end\\)?\\(" web-mode-blade-control-blocks-regexp "\\)")
   5095            reg-beg)
   5096           (setq control (match-string-no-properties 1)
   5097                 type (if (eq (aref (match-string-no-properties 0) 0) ?e) 'close 'open))
   5098           (setq controls (append controls (list (cons type control))))
   5099           )
   5100          ((web-mode-block-starts-with "stop\\|show\\|overwrite" reg-beg)
   5101           (setq controls (append controls (list (cons 'close "section")))))
   5102          ((web-mode-block-starts-with "else\\|elseif" reg-beg)
   5103           (setq controls (append controls (list (cons 'inside "if")))))
   5104          ((web-mode-block-starts-with "empty" reg-beg)
   5105           (setq controls (append controls (list (cons 'inside "forelse")))))
   5106          )
   5107         ) ;blade
   5108 
   5109        ((string= web-mode-engine "closure")
   5110         (cond
   5111          ((eq (char-after (1- reg-end)) ?\/)
   5112           )
   5113          ((looking-at "alias\\|namespace")
   5114           )
   5115          ((web-mode-block-starts-with "ifempty" reg-beg)
   5116           (setq controls (append controls (list (cons 'inside "foreach")))))
   5117          ((web-mode-block-starts-with "else\\|elseif" reg-beg)
   5118           (setq controls (append controls (list (cons 'inside "if")))))
   5119          ((web-mode-block-starts-with "case\\|default" reg-beg)
   5120           (setq controls (append controls (list (cons 'inside "switch")))))
   5121          ((looking-at
   5122            "{/?\\(call\\|deltemplate\\|for\\|foreach\\|if\\|let\\|literal\\|msg\\|param\\|switch\\|template\\)")
   5123           (setq control (match-string-no-properties 1)
   5124                 type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5125           (setq controls (append controls (list (cons type control))))
   5126           )
   5127          )
   5128         ) ;closure
   5129 
   5130        ((string= web-mode-engine "go")
   5131         (cond
   5132          ((web-mode-block-starts-with "end\\_>" reg-beg)
   5133           (setq controls (append controls (list (cons 'close "ctrl")))))
   5134          ((web-mode-block-starts-with "else\\_>" reg-beg)
   5135           (setq controls (append controls (list (cons 'inside "ctrl")))))
   5136          ((web-mode-block-starts-with "\\(range\\|with\\|if\\|define\\|block\\)\\_>" reg-beg)
   5137           (setq controls (append controls (list (cons 'open "ctrl")))))
   5138          )
   5139         ) ;go
   5140 
   5141        ((string= web-mode-engine "template-toolkit")
   5142         (cond
   5143          ((web-mode-block-starts-with "end" reg-beg)
   5144           (setq controls (append controls (list (cons 'close "ctrl")))))
   5145          ((web-mode-block-starts-with "els\\|catch\\|final" reg-beg)
   5146           (setq controls (append controls (list (cons 'inside "ctrl")))))
   5147          ((web-mode-block-starts-with "filter\\|foreach\\|if\\|last\\|next\\|perl\\|rawperl\\|try\\|unless\\|while" reg-beg)
   5148           (setq controls (append controls (list (cons 'open "ctrl")))))
   5149          )
   5150         ) ;template-toolkit
   5151 
   5152        ((string= web-mode-engine "cl-emb")
   5153         (cond
   5154          ((web-mode-block-starts-with "@else" reg-beg)
   5155           (setq controls (append controls (list (cons 'inside "if")))))
   5156          ((web-mode-block-starts-with "@\\(?:end\\)?\\(if\\|unless\\|repeat\\|loop\\|with\\|genloop\\)" reg-beg)
   5157           (setq control (match-string-no-properties 1)
   5158                 type (if (eq (aref (match-string-no-properties 0) 1) ?e) 'close 'open))
   5159           (setq controls (append controls (list (cons type control)))))
   5160          )
   5161         ) ;cl-emb
   5162 
   5163        ((string= web-mode-engine "elixir")
   5164         (cond
   5165          ((web-mode-block-starts-with "end" reg-beg)
   5166           (setq controls (append controls (list (cons 'close "ctrl")))))
   5167          ((web-mode-block-starts-with "else" reg-beg)
   5168           (setq controls (append controls (list (cons 'inside "ctrl")))))
   5169          ((web-mode-block-ends-with " do" reg-beg)
   5170           (setq controls (append controls (list (cons 'open "ctrl")))))
   5171          ((web-mode-block-ends-with " ->" reg-beg)
   5172           (setq controls (append controls (list (cons 'open "ctrl")))))
   5173          )
   5174         ) ;elixir
   5175 
   5176        ((string= web-mode-engine "velocity")
   5177         (cond
   5178          ((web-mode-block-starts-with "{?end" reg-beg)
   5179           (setq controls (append controls (list (cons 'close "ctrl")))))
   5180          ((web-mode-block-starts-with "{?els" reg-beg)
   5181           (setq controls (append controls (list (cons 'inside "ctrl")))))
   5182          ((web-mode-block-starts-with "{?\\(def\\|if\\|for\\|foreach\\|macro\\)" reg-beg)
   5183           ;;((web-mode-block-starts-with "{?\\(define\\|\\|if\\|for\\|foreach\\|macro\\)" reg-beg)
   5184           (setq controls (append controls (list (cons 'open "ctrl")))))
   5185          )
   5186         ) ;velocity
   5187 
   5188        ((string= web-mode-engine "freemarker")
   5189         (cond
   5190          ((looking-at "[<[]#\\(import\\|include\\|assign\\|return\\|local\\)")
   5191           )
   5192          ((eq (char-after (1- reg-end)) ?\/)
   5193           )
   5194          ((looking-at "[<[]#\\(break\\|case\\|default\\)")
   5195           (setq controls (append controls (list (cons 'inside "switch"))))
   5196           )
   5197          ((looking-at "[<[]#els")
   5198           (setq controls (append controls (list (cons 'inside "if"))))
   5199           )
   5200          ((looking-at "</?\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)")
   5201           (setq control (match-string-no-properties 1)
   5202                 type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5203           (setq controls (append controls (list (cons type control))))
   5204           )
   5205          ((looking-at "[<[]/?\\(@\\)")
   5206           (setq control (match-string-no-properties 1)
   5207                 type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5208           (setq controls (append controls (list (cons type control))))
   5209           )
   5210          ((looking-at "[<[]/?#\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)")
   5211           (setq control (match-string-no-properties 1)
   5212                 type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
   5213           (setq controls (append controls (list (cons type control))))
   5214           )
   5215          (t
   5216           (when (web-mode-block-starts-with "}" reg-beg)
   5217             (setq controls (append controls (list (cons 'close "{")))))
   5218           (when (web-mode-block-ends-with "{" reg-beg)
   5219             (setq controls (append controls (list (cons 'open "{")))))
   5220           )
   5221          )
   5222         ) ;freemarker
   5223 
   5224        ((string= web-mode-engine "razor")
   5225         (when (web-mode-block-starts-with "}" reg-beg)
   5226           (setq controls (append controls (list (cons 'close "{")))))
   5227         (when (web-mode-block-ends-with "{" reg-beg)
   5228           (setq controls (append controls (list (cons 'open "{")))))
   5229         ) ;razor
   5230 
   5231        ((string= web-mode-engine "lsp")
   5232         (when (web-mode-block-starts-with ")" reg-beg)
   5233           (setq controls (append controls (list (cons 'close "(")))))
   5234         (when (web-mode-block-is-opened-sexp reg-beg reg-end)
   5235           (setq controls (append controls (list (cons 'open "(")))))
   5236         ) ;lsp
   5237 
   5238        ((string= web-mode-engine "hero")
   5239         (cond
   5240          ((web-mode-block-ends-with "}[ ]*else[ ]*{" reg-beg)
   5241           (setq controls (append controls (list (cons 'inside "{")))))
   5242          ((web-mode-block-starts-with "}" reg-beg)
   5243           (setq controls (append controls (list (cons 'close "{")))))
   5244          ((web-mode-block-ends-with "{" reg-beg)
   5245           (setq controls (append controls (list (cons 'open "{")))))
   5246          )
   5247         ) ;hero
   5248 
   5249        ((string= web-mode-engine "svelte")
   5250         (cond
   5251          ((eq (char-after (1- reg-end)) ?\/)
   5252           )
   5253          ((eq (char-after (1+ reg-beg)) ?\:)
   5254           (setq pos (web-mode-block-control-previous-position 'open reg-beg))
   5255           (when pos
   5256             (setq controls (append controls
   5257                                    (list
   5258                                     (cons 'inside
   5259                                           (cdr (car (web-mode-block-controls-get pos))))))))
   5260           )
   5261          ((looking-at "{/\\([[:alpha:].]+\\)")
   5262           (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
   5263          ((looking-at "{[#?><+^]\\([[:alpha:].]+\\)")
   5264           (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
   5265          )
   5266         ) ;svelte
   5267 
   5268        ) ;cond engine
   5269 
   5270       (put-text-property reg-beg (1+ reg-beg) 'block-controls controls)
   5271       ;;(message "(%S) controls=%S" reg-beg controls)
   5272 
   5273       )))
   5274 
   5275 (defun web-mode-block-is-opened-sexp (reg-beg reg-end)
   5276   (let ((n 0))
   5277     (save-excursion
   5278       (goto-char reg-beg)
   5279       (while (web-mode-block-rsf "[()]" reg-end)
   5280         (if (eq (char-before) ?\() (setq n (1+ n)) (setq n (1- n)))))
   5281     (> n 0)))
   5282 
   5283 ;;---- LEXER PARTS -------------------------------------------------------------
   5284 
   5285 (defun web-mode-scan-elements (reg-beg reg-end)
   5286   (save-excursion
   5287     (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)
   5288       ;;(message "scan-elements: reg-beg(%S) reg-end(%S)" reg-beg reg-end)
   5289       (goto-char reg-beg)
   5290 
   5291       (while (web-mode-dom-rsf regexp reg-end)
   5292 
   5293         ;;(message "%S: %S (%S %S)" (point) (match-string-no-properties 0) reg-beg reg-end)
   5294 
   5295         (setq flags 0
   5296               tname (downcase (match-string-no-properties 1))
   5297               char (aref tname 0)
   5298               tbeg (match-beginning 0)
   5299               tend nil
   5300               element-content-type nil
   5301               limit reg-end
   5302               part-beg nil
   5303               part-end nil
   5304               props nil
   5305               close-expr nil
   5306               part-close-tag nil)
   5307 
   5308         ;;(message "tname[%S] tbeg(%S) point(%S)" tname tbeg (point))
   5309 
   5310         (cond
   5311 
   5312          ((member tname '("/>" ">")) ;;jsx fragment #952
   5313           (setq tname "_fragment_"
   5314                 tend (point))
   5315           (if (eq char ?\/)
   5316               (setq props (list 'tag-name tname 'tag-type 'end)
   5317                     flags (logior flags 20)) ;; 16 + 4
   5318             (setq props (list 'tag-name tname 'tag-type 'start)
   5319                   flags (logior flags 16))
   5320             ) ;if
   5321           )
   5322 
   5323          ((not (member char '(?\! ?\?)))
   5324           (cond
   5325            ((string-match-p "-" tname)
   5326             (setq flags (logior flags 2)))
   5327            ((string-match-p ":" tname)
   5328             (setq flags (logior flags 32)))
   5329            )
   5330           (cond
   5331            ((eq char ?\/)
   5332             (setq props (list 'tag-name (substring tname 1) 'tag-type 'end)
   5333                   flags (logior flags 4)
   5334                   limit (if (> reg-end (line-end-position)) (line-end-position) reg-end))
   5335             )
   5336            ((web-mode-element-is-void tname)
   5337             ;;(message "void: tag=%S" tname)
   5338             (setq props (list 'tag-name tname 'tag-type 'void)))
   5339            (t
   5340             (setq props (list 'tag-name tname 'tag-type 'start)))
   5341            ) ;cond
   5342           ) ; not <! <?
   5343          ((and (eq char ?\!) (eq (aref tname 1) ?\-))
   5344           (setq close-expr "-->"
   5345                 props '(tag-type comment)))
   5346          ((string= tname "?xml")
   5347           (setq ;;regexp web-mode-tag-regexp2
   5348                 close-expr "?>"
   5349                 props '(tag-type declaration)))
   5350          ((string= tname "![cdata[")
   5351           (setq close-expr "]]>"
   5352                 props '(tag-type cdata)))
   5353          ((string= tname "!doctype")
   5354           (setq ;;regexp web-mode-tag-regexp2
   5355                 props '(tag-type doctype)))
   5356          ) ;cond - special tags
   5357 
   5358         (cond
   5359 
   5360          (tend
   5361           )
   5362 
   5363          ((and (null close-expr) (eq (char-after) ?\>))
   5364           (setq flags (logior flags 16)
   5365                 tend (1+ (point)))
   5366           ;;(message "end=%S" tend)
   5367           )
   5368 
   5369          ((and (null close-expr)
   5370                (looking-at "[ ]\\(class\\|id\\|href\\|style\\)=\"[[:alnum:]_=:/?;#. -]*\">"))
   5371           (let ((beg (1+ (point)))
   5372                 (end (+ (point) (length (match-string-no-properties 0)))))
   5373             (setq flags (logior flags 17)
   5374                   tend end)
   5375             (put-text-property beg (1+ beg) 'tag-attr-beg 0)
   5376             (put-text-property beg (1- end) 'tag-attr t)
   5377             (put-text-property (- end 2) (1- end) 'tag-attr-end (length (match-string-no-properties 1)))
   5378             ) ;let
   5379           )
   5380 
   5381          ((null close-expr)
   5382           (setq flags (logior flags (web-mode-attr-skip reg-end)))
   5383           (when (> (logand flags 8) 0)
   5384             (setq props (plist-put props 'tag-type 'void)))
   5385           (setq tend (point)))
   5386 
   5387          ((web-mode-dom-sf close-expr limit t)
   5388           (setq tend (point)))
   5389 
   5390          (t
   5391           (setq tend (line-end-position)))
   5392 
   5393          ) ;cond
   5394 
   5395         (cond
   5396          ((string= tname "style")
   5397           (let (style)
   5398             (setq style (buffer-substring-no-properties tbeg tend)
   5399                   part-close-tag "</style>")
   5400             (cond
   5401              ((string-match-p " lang[ ]*=[ ]*[\"']stylus" style)
   5402               (setq element-content-type "stylus"))
   5403              ((string-match-p " lang[ ]*=[ ]*[\"']sass" style)
   5404               (setq element-content-type "sass"))
   5405              (t
   5406               (setq element-content-type "css"))
   5407              ) ;cond
   5408             ) ;let
   5409           ) ;style
   5410          ((string= tname "script")
   5411           (let (script)
   5412             (setq script (buffer-substring-no-properties tbeg tend)
   5413                   part-close-tag "</script>")
   5414             (cond
   5415              ((string-match-p " type[ ]*=[ ]*[\"']text/\\(jsx\\|babel\\)" script)
   5416               (setq element-content-type "jsx"))
   5417              ((string-match-p " type[ ]*=[ ]*[\"']text/\\(markdown\\|template\\)" script)
   5418               (setq element-content-type "markdown"))
   5419              ((string-match-p " type[ ]*=[ ]*[\"']text/ruby" script)
   5420               (setq element-content-type "ruby"))
   5421              ((seq-some (lambda (x)
   5422                           (string-match-p (concat "type[ ]*=[ ]*[\"']" x) script))
   5423                         web-mode-script-template-types)
   5424               (setq element-content-type "html"
   5425                     part-close-tag nil))
   5426              ((string-match-p " type[ ]*=[ ]*[\"']application/\\(ld\\+json\\|json\\)" script)
   5427               (setq element-content-type "json"))
   5428              ((string-match-p " lang[ ]*=[ ]*[\"']\\(typescript\\|ts\\)" script)
   5429               (setq element-content-type "typescript"))
   5430              (t
   5431               (setq element-content-type "javascript"))
   5432              ) ;cond
   5433             ) ;let
   5434           ) ;script
   5435          ((and (string= tname "template") (string-match-p " lang" (buffer-substring-no-properties tbeg tend)))
   5436           (let (template)
   5437             (setq template (buffer-substring-no-properties tbeg tend)
   5438                   part-close-tag "</template>")
   5439             (cond
   5440              ((string-match-p " lang[ ]*=[ ]*[\"']pug" template)
   5441               (setq element-content-type "pug"))
   5442              (t
   5443               (setq element-content-type "html"))
   5444              ) ;cond
   5445             ) ;let
   5446           ) ;style
   5447          ((and (string= web-mode-engine "archibus")
   5448                (string= tname "sql"))
   5449           (setq element-content-type "sql"
   5450                 part-close-tag "</sql>"))
   5451          )
   5452 
   5453         (add-text-properties tbeg tend props)
   5454         (put-text-property tbeg (1+ tbeg) 'tag-beg flags)
   5455         (put-text-property (1- tend) tend 'tag-end t)
   5456 
   5457         (when (and part-close-tag
   5458                    (web-mode-dom-sf part-close-tag reg-end t)
   5459                    (setq part-beg tend)
   5460                    (setq part-end (match-beginning 0))
   5461                    (> part-end part-beg))
   5462           (put-text-property part-beg part-end 'part-side
   5463                              (intern element-content-type web-mode-obarray))
   5464           (setq tend part-end)
   5465           ) ;when
   5466 
   5467         (goto-char tend)
   5468 
   5469         ) ;while
   5470 
   5471       )))
   5472 
   5473 ;; FLAGS: tag
   5474 ;; (1)attrs (2)custom (4)slash-beg (8)slash-end (16)bracket-end (32)namespaced
   5475 
   5476 ;; FLAGS: attr
   5477 ;; (1)custom-attr (2)engine-attr (4)spread-attr[jsx] (8)code-value
   5478 ;; SPECS: https://www.w3.org/TR/2012/WD-html-markup-20120329/syntax.html#attr-value-unquoted
   5479 
   5480 ;; STATES: attr
   5481 ;; (0)nil (1)space (2)name (3)space-before (4)equal (5)space-after
   5482 ;; (6)value-uq (7)value-sq (8)value-dq (9)value-bq : jsx attr={}
   5483 
   5484 (defun web-mode-attr-skip (limit)
   5485 
   5486   (let ((tag-flags 0) (attr-flags 0) (continue t) (attrs 0) (counter 0) (brace-depth 0)
   5487         (pos-ori (point)) (state 0) (equal-offset 0) (go-back nil)
   5488         (is-jsx (or (string= web-mode-content-type "jsx") (eq (get-text-property (point) 'part-type) 'jsx)))
   5489         attr name-beg name-end val-beg char pos escaped spaced quoted)
   5490 
   5491     (while continue
   5492 
   5493       (setq pos (point)
   5494             char (char-after)
   5495             ;;spaced (eq char ?\s)
   5496             spaced (member char '(?\s ?\n))
   5497             )
   5498 
   5499       (when quoted (setq quoted (1+ quoted)))
   5500 
   5501       (cond
   5502 
   5503        ((>= pos limit)
   5504         (setq continue nil)
   5505         (setq go-back t)
   5506         (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5507         )
   5508 
   5509        ((or (and (= state 8) (not (member char '(?\" ?\\))))
   5510             (and (= state 7) (not (member char '(?\' ?\\))))
   5511             (and (= state 9) (not (member char '(?} ?\\))))
   5512             )
   5513         (when (and (= state 9) (eq char ?\{))
   5514           (setq brace-depth (1+ brace-depth)))
   5515         )
   5516 
   5517        ((and (= state 9) (eq char ?\}) (> brace-depth 1))
   5518         (setq brace-depth (1- brace-depth)))
   5519 
   5520        ((get-text-property pos 'block-side)
   5521         (when (= state 2)
   5522           (setq name-end pos))
   5523         )
   5524 
   5525        ((and (= state 2) is-jsx (eq char ?\}) (eq attr-flags 4))
   5526         (setq name-end pos)
   5527         (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5528         (setq state 0
   5529               attr-flags 0
   5530               equal-offset 0
   5531               name-beg nil
   5532               name-end nil
   5533               val-beg nil)
   5534         )
   5535 
   5536        ((or (and (= state 8) (eq ?\" char) (not escaped))
   5537             (and (= state 7) (eq ?\' char) (not escaped))
   5538             (and (= state 9) (eq ?\} char) (= brace-depth 1))
   5539             )
   5540 
   5541         ;;(message "%S %S" (point) attr-flags)
   5542         (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5543         (setq state 0
   5544               attr-flags 0
   5545               equal-offset 0
   5546               name-beg nil
   5547               name-end nil
   5548               val-beg nil)
   5549         )
   5550 
   5551        ((and (member state '(4 5)) (member char '(?\' ?\" ?\{)))
   5552         (setq val-beg pos)
   5553         (setq quoted 1)
   5554         (setq state (cond ((eq ?\' char) 7)
   5555                           ((eq ?\" char) 8)
   5556                           (t             9)))
   5557         (when (= state 9)
   5558           (setq brace-depth 1))
   5559         )
   5560 
   5561        ((and (eq ?\= char) (member state '(2 3)))
   5562         (setq equal-offset (- pos name-beg)
   5563               name-end (1- pos))
   5564         (setq state 4)
   5565         (setq attr (buffer-substring-no-properties name-beg (1+ name-end)))
   5566         (when (and web-mode-indentless-attributes (member (downcase attr) web-mode-indentless-attributes))
   5567           ;;(message "onclick")
   5568           (setq attr-flags (logior attr-flags 8)))
   5569         )
   5570 
   5571        ((and spaced (= state 0))
   5572         (setq state 1)
   5573         )
   5574 
   5575        ((and (eq char ?\<) (not (member state '(7 8 9))))
   5576         (setq continue nil)
   5577         (setq go-back t)
   5578         (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5579         )
   5580 
   5581        ((and (eq char ?\>) (not (member state '(7 8 9))))
   5582         (setq tag-flags (logior tag-flags 16))
   5583         (when (eq (char-before) ?\/)
   5584           (setq tag-flags (logior tag-flags 8))
   5585           )
   5586         (setq continue nil)
   5587         (when name-beg
   5588           (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags))))
   5589         )
   5590 
   5591        ((and spaced (member state '(1 3 5)))
   5592         )
   5593 
   5594        ((and spaced (= state 2))
   5595         (setq state 3)
   5596         )
   5597 
   5598        ((and (eq char ?\/) (member state '(4 5)))
   5599         (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5600         (setq state 1
   5601               attr-flags 0
   5602               equal-offset 0
   5603               name-beg nil
   5604               name-end nil
   5605               val-beg nil)
   5606         )
   5607 
   5608        ((and (eq char ?\/) (member state '(0 1)))
   5609         )
   5610 
   5611        ((and spaced (= state 4))
   5612         (setq state 5)
   5613         )
   5614 
   5615        ((and (= state 3)
   5616              (or (and (>= char 97) (<= char 122)) ;a - z
   5617                  (and (>= char 65) (<= char 90)) ;A - Z
   5618                  (eq char ?\-)))
   5619         (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5620         (setq state 2
   5621               attr-flags 0
   5622               equal-offset 0
   5623               name-beg pos
   5624               name-end pos
   5625               val-beg nil)
   5626         )
   5627 
   5628        ((and (eq char ?\n) (not (member state '(7 8 9))))
   5629         (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5630         (setq state 1
   5631               attr-flags 0
   5632               equal-offset 0
   5633               name-beg nil
   5634               name-end nil
   5635               val-beg nil)
   5636         )
   5637 
   5638        ((and (= state 6) (member char '(?\s ?\n))) ;#1150
   5639         (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5640         (setq state 1
   5641               attr-flags 0
   5642               equal-offset 0
   5643               name-beg nil
   5644               name-end nil
   5645               val-beg nil)
   5646         )
   5647 
   5648        ((and quoted (= quoted 2) (member char '(?\s ?\n ?\>)))
   5649         (when (eq char ?\>)
   5650           (setq tag-flags (logior tag-flags 16))
   5651           (setq continue nil))
   5652         (setq state 6)
   5653         (setq attrs (+ attrs (web-mode-attr-scan pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)))
   5654         (setq state 1
   5655               attr-flags 0
   5656               equal-offset 0
   5657               name-beg nil
   5658               name-end nil
   5659               val-beg nil)
   5660         )
   5661 
   5662        ((and (not spaced) (= state 1))
   5663         (when (and is-jsx (eq char ?\{))
   5664           (setq attr-flags 4))
   5665         (setq state 2)
   5666         (setq name-beg pos
   5667               name-end pos)
   5668         )
   5669 
   5670        ((member state '(4 5))
   5671         (setq val-beg pos)
   5672         (setq state 6)
   5673         )
   5674 
   5675        ((= state 1)
   5676         (setq state 2)
   5677         )
   5678 
   5679        ((= state 2)
   5680         (setq name-end pos)
   5681         (when (and nil (= attr-flags 0) (member char '(?\- ?\:)))
   5682           (let (attr)
   5683             (setq attr (buffer-substring-no-properties name-beg (1+ name-end)))
   5684             (cond
   5685              ((member attr '("http-equiv"))
   5686               (setq attr-flags (1- attr-flags))
   5687               )
   5688              ;;((and web-mode-engine-attr-regexp
   5689              ;;      (string-match-p web-mode-engine-attr-regexp attr))
   5690              ;; (setq attr-flags (logior attr-flags 2))
   5691              ;; )
   5692              ((and (eq char ?\-) (not (string= attr "http-")))
   5693               (setq attr-flags (logior attr-flags 1)))
   5694              ) ;cond
   5695             ) ;let
   5696           ) ;when attr-flags = 1
   5697         ) ;state=2
   5698 
   5699        ) ;cond
   5700 
   5701       ;;(message "point(%S) end(%S) state(%S) c(%S) name-beg(%S) name-end(%S) val-beg(%S) attr-flags(%S) equal-offset(%S)" pos end state char name-beg name-end val-beg attr-flags equal-offset tag-flags)
   5702 
   5703       (when (and quoted (>= quoted 2))
   5704         (setq quoted nil))
   5705 
   5706       (setq escaped (eq ?\\ char))
   5707       (when (null go-back)
   5708         (forward-char))
   5709 
   5710       ) ;while
   5711 
   5712     (when (> attrs 0) (setq tag-flags (logior tag-flags 1)))
   5713 
   5714     tag-flags))
   5715 
   5716 (defun web-mode-attr-scan (pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)
   5717   ;;(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)"
   5718   ;;         pos state char name-beg name-end val-beg attr-flags equal-offset tag-flags)
   5719   (when (null attr-flags) (setq attr-flags 0))
   5720   (when (and name-beg name-end web-mode-engine-attr-regexp)
   5721     (let (name)
   5722       (setq name (buffer-substring-no-properties name-beg (1+ name-end)))
   5723       ;;(message "%S" name)
   5724       (cond
   5725        ((string-match-p "^data[-]" name)
   5726         (setq attr-flags (logior attr-flags 1))
   5727         )
   5728        ((string-match-p web-mode-engine-attr-regexp name)
   5729         (setq attr-flags (logior attr-flags 2))
   5730         )
   5731        )
   5732       ) ;name
   5733     )
   5734   ;;(message "%S" name)
   5735   (cond
   5736    ((null name-beg)
   5737     0)
   5738    ((or (and (= state 8) (not (eq ?\" char)))
   5739         (and (= state 7) (not (eq ?\' char))))
   5740     (put-text-property name-beg (1+ name-beg) 'tag-attr-beg attr-flags)
   5741     (put-text-property name-beg val-beg 'tag-attr t)
   5742     (put-text-property (1- val-beg) val-beg 'tag-attr-end equal-offset)
   5743     1)
   5744    ((and (member state '(4 5)) (null val-beg))
   5745     (put-text-property name-beg (1+ name-beg) 'tag-attr-beg attr-flags)
   5746     (put-text-property name-beg (+ name-beg equal-offset 1) 'tag-attr t)
   5747     (put-text-property (+ name-beg equal-offset) (+ name-beg equal-offset 1) 'tag-attr-end equal-offset)
   5748     1)
   5749    (t
   5750     (let (val-end)
   5751       (if (null val-beg)
   5752           (setq val-end name-end)
   5753         (setq val-end pos)
   5754         (cond
   5755          ((null char)
   5756           (setq val-end (1- val-end)))
   5757          ((member char '(?\s ?\n ?\/))
   5758           (setq val-end (1- val-end)))
   5759          ((eq char ?\>)
   5760           (if (= (logand tag-flags 8) 8)
   5761               (progn
   5762                 ;;(message "tag-flags=%S %S" tag-flags (logand tag-flags 8))
   5763                 (setq val-end (- val-end 2)))
   5764             (setq val-end (- val-end 1)))
   5765           ;; (message "val-end=%S" val-end)
   5766           )
   5767          )
   5768         )
   5769       (put-text-property name-beg (1+ name-beg) 'tag-attr-beg attr-flags)
   5770       (put-text-property name-beg (1+ val-end) 'tag-attr t)
   5771       (put-text-property val-end (1+ val-end) 'tag-attr-end equal-offset)
   5772       ) ;let
   5773     1) ;t
   5774    ) ;cond
   5775   )
   5776 
   5777 (defun web-mode-part-foreach (reg-beg reg-end func)
   5778   (let ((i 0) (continue t) (part-beg reg-beg) (part-end nil))
   5779     (while continue
   5780       (setq part-end nil)
   5781       (unless (get-text-property part-beg 'part-side)
   5782         (setq part-beg (web-mode-part-next-position part-beg)))
   5783       (when (and part-beg (< part-beg reg-end))
   5784         (setq part-end (web-mode-part-end-position part-beg)))
   5785       (cond
   5786        ((> (setq i (1+ i)) 100)
   5787         (message "process-parts ** warning (%S) **" (point))
   5788         (setq continue nil))
   5789        ((or (null part-end) (> part-end reg-end))
   5790         (setq continue nil))
   5791        (t
   5792         (setq part-end (1+ part-end))
   5793         (funcall func part-beg part-end)
   5794         (setq part-beg part-end))
   5795        ) ;cond
   5796       ) ;while
   5797     ))
   5798 
   5799 (defun web-mode-part-scan (reg-beg reg-end &optional content-type depth)
   5800   (save-excursion
   5801     (let (token-re ch-before ch-at ch-next token-type beg continue)
   5802       ;;(message "%S %S" reg-beg reg-end)
   5803       (cond
   5804        (content-type
   5805         )
   5806        ((member web-mode-content-type web-mode-part-content-types)
   5807         (setq content-type web-mode-content-type))
   5808        (t
   5809         (setq content-type (symbol-name (get-text-property reg-beg 'part-side))))
   5810        ) ;cond
   5811 
   5812       (goto-char reg-beg)
   5813 
   5814       (cond
   5815        ((member content-type '("javascript" "json"))
   5816         (setq token-re "/\\|\"\\|'\\|`"))
   5817        ((member content-type '("typescript"))
   5818         (setq token-re "\"\\|'\\|`\\|//\\|/\\*"))
   5819        ((member content-type '("jsx"))
   5820         (setq token-re "/\\|\"\\|'\\|`\\|</?[[:alpha:]>]"))
   5821        ((string= web-mode-content-type "css")
   5822         (setq token-re "\"\\|'\\|/\\*\\|//"))
   5823        ((string= content-type "css")
   5824         (setq token-re "\"\\|'\\|/\\*"))
   5825        (t
   5826         (setq token-re "/\\*\\|\"\\|'"))
   5827        )
   5828 
   5829       (while (and token-re (< (point) reg-end) (web-mode-dom-rsf token-re reg-end t))
   5830 
   5831         (setq beg (match-beginning 0)
   5832               token-type nil
   5833               continue t
   5834               ch-at (char-after beg)
   5835               ch-next (or (char-after (1+ beg)) ?\d)
   5836               ch-before (or (char-before beg) ?\d))
   5837 
   5838         ;;(message "[%S>%S|%S] %S %c %c %c" reg-beg reg-end depth beg ch-before ch-at ch-next)
   5839 
   5840         (cond
   5841 
   5842          ((eq ?\' ch-at)
   5843           (while (and continue (search-forward "'" reg-end t))
   5844             (cond
   5845              ((get-text-property (1- (point)) 'block-side)
   5846               (setq continue t))
   5847              (t
   5848               (setq continue (web-mode-string-continue-p reg-beg)))
   5849              )
   5850             ) ;while
   5851           (setq token-type 'string))
   5852 
   5853          ((eq ?\` ch-at)
   5854           (while (and continue (search-forward "`" reg-end t))
   5855             (cond
   5856              ((get-text-property (1- (point)) 'block-side)
   5857               (setq continue t))
   5858              (t
   5859               (setq continue (web-mode-string-continue-p reg-beg)))
   5860              )
   5861             ) ;while
   5862           (setq token-type 'string))
   5863 
   5864          ((eq ?\" ch-at)
   5865           (while (and continue (search-forward "\"" reg-end t))
   5866             (cond
   5867              ((get-text-property (1- (point)) 'block-side)
   5868               (setq continue t))
   5869              (t
   5870               (setq continue (web-mode-string-continue-p reg-beg)))
   5871              ) ;cond
   5872             ) ;while
   5873           (cond
   5874            ((string= content-type "json")
   5875             (if (looking-at-p "[ ]*:")
   5876                 (cond
   5877                  ((eq ?\@ (char-after (1+ beg)))
   5878                   (setq token-type 'context))
   5879                  (t
   5880                   (setq token-type 'key))
   5881                  )
   5882               (setq token-type 'string))
   5883             ) ;json
   5884            (t
   5885             (setq token-type 'string))
   5886            ) ;cond
   5887           )
   5888 
   5889          ((and (eq ?\< ch-at)
   5890                (not (or (and (>= ch-before 97) (<= ch-before 122))
   5891                         (and (>= ch-before 65) (<= ch-before 90)))))
   5892           ;;(message "before [%S>%S|%S] pt=%S" reg-beg reg-end depth (point))
   5893           (search-backward "<")
   5894           (if (web-mode-jsx-skip reg-end)
   5895               (web-mode-jsx-scan-element beg (point) depth)
   5896             (forward-char))
   5897           ;;(message "after [%S>%S|%S] pt=%S" reg-beg reg-end depth (point))
   5898           )
   5899 
   5900          ((and (eq ?\/ ch-at) (member content-type '("javascript" "jsx")))
   5901           (cond
   5902            ((eq ?\\ ch-before)
   5903             )
   5904            ((eq ?\* ch-next)
   5905             ;;(message "--> %S %S" (point) reg-end)
   5906             (when (search-forward "*/" reg-end t)
   5907               (setq token-type 'comment))
   5908             )
   5909            ((eq ?\/ ch-next)
   5910             (setq token-type 'comment)
   5911             (goto-char (if (< reg-end (line-end-position)) reg-end (line-end-position)))
   5912             )
   5913            ((and (looking-at-p ".*/")
   5914                  (looking-back "\\(^\\|case\\|[[(,=:!&|?{};]\\)[ ]*/" (point-min)))
   5915                  ;;(re-search-forward "/[gimyu]*" reg-end t))
   5916             (let ((eol (line-end-position)))
   5917               (while (and continue (search-forward "/" eol t))
   5918                 (cond
   5919                  ((get-text-property (1- (point)) 'block-side)
   5920                   (setq continue t))
   5921                  ((looking-back "\\\\+/" reg-beg t)
   5922                   (setq continue (= (mod (- (point) (match-beginning 0)) 2) 0)))
   5923                  (t
   5924                   (re-search-forward "[gimyu]*" eol t)
   5925                   (setq token-type 'string)
   5926                   (setq continue nil))
   5927                  )
   5928                 ) ;while
   5929               ) ;let
   5930             )
   5931            ) ;cond
   5932           )
   5933 
   5934          ((eq ?\/ ch-next)
   5935           ;;(message "%S" (point))
   5936           (cond
   5937            ((and (string= content-type "css")
   5938                  (eq ?/ ch-at)
   5939                  (eq ?: ch-before))
   5940             )
   5941            (t
   5942             (unless (eq ?\\ ch-before)
   5943              (setq token-type 'comment)
   5944              (goto-char (if (< reg-end (line-end-position)) reg-end (line-end-position)))
   5945              )
   5946             )
   5947            )
   5948 
   5949           )
   5950 
   5951          ((eq ?\* ch-next)
   5952           (cond
   5953            ((search-forward "*/" reg-end t)
   5954             (setq token-type 'comment))
   5955            ((not (eobp))
   5956             (forward-char))
   5957            ) ;cond
   5958           )
   5959 
   5960          ) ;cond
   5961 
   5962         (when (and beg (>= reg-end (point)) token-type)
   5963           (put-text-property beg (point) 'part-token token-type)
   5964           (cond
   5965            ((eq token-type 'comment)
   5966             (put-text-property beg (1+ beg) 'syntax-table (string-to-syntax "<"))
   5967             (when (< (point) (point-max))
   5968               (if (< (point) (line-end-position))
   5969                   (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax ">")) ;#445
   5970                 (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax ">")) ;#377
   5971                 )
   5972               ) ;when
   5973             ) ;comment
   5974            ((eq token-type 'string)
   5975             (put-text-property beg (1+ beg) 'syntax-table (string-to-syntax "|"))
   5976             (when (< (point) (point-max))
   5977               (if (< (point) (line-end-position))
   5978                   (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax "|"))
   5979                 (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax "|"))
   5980                 )
   5981               ) ;when
   5982             ) ;string
   5983            ) ;cond
   5984           ) ;when
   5985 
   5986         (when (> (point) reg-end)
   5987           (message "reg-beg(%S) reg-end(%S) token-type(%S) point(%S)" reg-beg reg-end token-type (point)))
   5988 
   5989         ;;(message "#[%S>%S|%S] %S %c %c %c | (%S)" reg-beg reg-end depth beg ch-before ch-at ch-next (point))
   5990 
   5991         ) ;while
   5992 
   5993       )))
   5994 
   5995 (defun web-mode-string-continue-p (reg-beg)
   5996   "Is `point' preceeded by an odd number of backslashes?"
   5997   (let ((p (1- (point))))
   5998     (while (and (< reg-beg p) (eq ?\\ (char-before p)))
   5999       (setq p (1- p)))
   6000     (= (mod (- (point) p) 2) 0)))
   6001 
   6002 ;; css rule = selector(s) + declaration (properties)
   6003 (defun web-mode-css-rule-next (limit)
   6004   (let (at-rule var-rule sel-beg sel-end dec-beg dec-end chunk)
   6005     (skip-chars-forward "\n\t ")
   6006     (setq sel-beg (point))
   6007     (when (and (< (point) limit)
   6008                (web-mode-part-rsf "[{;]" limit))
   6009       (setq sel-end (1- (point)))
   6010       (cond
   6011        ((eq (char-before) ?\{)
   6012         (setq dec-beg (point))
   6013         (setq dec-end (web-mode-closing-paren-position (1- dec-beg) limit))
   6014         (if dec-end
   6015             (progn
   6016               (goto-char dec-end)
   6017               (forward-char))
   6018           (setq dec-end limit)
   6019           (goto-char limit))
   6020         )
   6021        (t
   6022         )
   6023        ) ;cond
   6024       (setq chunk (buffer-substring-no-properties sel-beg sel-end))
   6025       (cond
   6026        ((string-match "@\\([[:alpha:]-]+\\)" chunk)
   6027         (setq at-rule (match-string-no-properties 1 chunk)))
   6028        ((string-match "\\$\\([[:alpha:]-]+\\)" chunk)
   6029         (setq var-rule (match-string-no-properties 1 chunk)))
   6030        ) ;cond
   6031       ) ;when
   6032     (if (not sel-end)
   6033         (progn (goto-char limit) nil)
   6034       (list :at-rule at-rule
   6035             :var-rule var-rule
   6036             :sel-beg sel-beg
   6037             :sel-end sel-end
   6038             :dec-beg dec-beg
   6039             :dec-end dec-end)
   6040       ) ;if
   6041     ))
   6042 
   6043 (defun web-mode-css-rule-current (&optional pos part-beg part-end)
   6044   "Current CSS rule boundaries."
   6045   (unless pos (setq pos (point)))
   6046   (unless part-beg (setq part-beg (web-mode-part-beginning-position pos)))
   6047   (unless part-end (setq part-end (web-mode-part-end-position pos)))
   6048   (save-excursion
   6049     (let (beg end)
   6050       (goto-char pos)
   6051       (if (not (web-mode-part-sb "{" part-beg))
   6052           (progn
   6053             (setq beg part-beg)
   6054             (if (web-mode-part-sf ";" part-end)
   6055                 (setq end (1+ (point)))
   6056               (setq end part-end))
   6057             ) ;progn
   6058         (setq beg (point))
   6059         (setq end (web-mode-closing-paren-position beg part-end))
   6060         (if end
   6061             (setq end (1+ end))
   6062           (setq end (line-end-position)))
   6063 ;;        (message "%S >>beg%S >>end%S" pos beg end)
   6064         (if (> pos end)
   6065 
   6066             ;;selectors
   6067             (progn
   6068               (goto-char pos)
   6069               (if (web-mode-part-rsb "[};]" part-beg)
   6070                   (setq beg (1+ (point)))
   6071                 (setq beg part-beg)
   6072                 ) ;if
   6073               (goto-char pos)
   6074               (if (web-mode-part-rsf "[{;]" part-end)
   6075                   (cond
   6076                    ((eq (char-before) ?\;)
   6077                     (setq end (point))
   6078                     )
   6079                    (t
   6080                     (setq end (web-mode-closing-paren-position (1- (point)) part-end))
   6081                     (if end
   6082                         (setq end (1+ end))
   6083                       (setq end part-end))
   6084                     )
   6085                    ) ;cond
   6086                 (setq end part-end)
   6087                 )
   6088               ) ;progn selectors
   6089 
   6090           ;; declaration
   6091           (goto-char beg)
   6092           (if (web-mode-part-rsb "[}{;]" part-beg)
   6093               (setq beg (1+ (point)))
   6094             (setq beg part-beg)
   6095             ) ;if
   6096           ) ;if > pos end
   6097         )
   6098 ;;      (message "beg(%S) end(%S)" beg end)
   6099       (when (eq (char-after beg) ?\n)
   6100         (setq beg (1+ beg)))
   6101       (cons beg end)
   6102       )))
   6103 
   6104 (defun web-mode-jsx-skip (reg-end)
   6105   (let ((continue t) (pos nil) (i 0) tag)
   6106     (looking-at "<\\([[:alpha:]][[:alnum:]:-]*\\)")
   6107     (setq tag (match-string-no-properties 1))
   6108     ;;(message "point=%S tag=%S" (point) tag)
   6109     (save-excursion
   6110       (while continue
   6111         (cond
   6112          ((> (setq i (1+ i)) 1000)
   6113           (message "jsx-skip ** warning **")
   6114           (setq continue nil))
   6115          ((looking-at "<[[:alpha:]][[:alnum:]:-]*[ ]*/>")
   6116           (goto-char (match-end 0))
   6117           (setq pos (point))
   6118           (setq continue nil))
   6119          ((not (web-mode-dom-rsf ">\\([ \t\n]*[\];,)':}|&]\\)\\|{" reg-end))
   6120           (setq continue nil)
   6121           )
   6122          ((eq (char-before) ?\{)
   6123           (backward-char)
   6124           (web-mode-closing-paren reg-end)
   6125           (forward-char)
   6126           )
   6127          (t
   6128           (setq continue nil)
   6129           (setq pos (match-beginning 1))
   6130           ) ;t
   6131          ) ;cond
   6132         ) ;while
   6133       ) ;save-excursion
   6134     (when pos (goto-char pos))
   6135     ;;(message "jsx-skip: %S" pos)
   6136     pos))
   6137 
   6138 ;; (defun web-mode-jsx-skip2 (reg-end)
   6139 ;;   (let ((continue t) (pos nil) (i 0) (tag nil) (regexp nil) (counter 1))
   6140 ;;     (looking-at "<\\([[:alpha:]][[:alnum:]:-]*\\)")
   6141 ;;     (setq tag (match-string-no-properties 1))
   6142 ;;     (setq regexp (concat "</?" tag))
   6143 ;;     ;;(message "point=%S tag=%S" (point) tag)
   6144 ;;     (save-excursion
   6145 ;;       (while continue
   6146 ;;         (cond
   6147 ;;          ((> (setq i (1+ i)) 100)
   6148 ;;           (message "jsx-skip ** warning **")
   6149 ;;           (setq continue nil))
   6150 ;;          ((looking-at "<[[:alpha:]][[:alnum:]:-]*[ ]*/>")
   6151 ;;           (goto-char (match-end 0))
   6152 ;;           (setq pos (point))
   6153 ;;           (setq continue nil))
   6154 ;;          ((not (web-mode-dom-rsf ">\\([ \t\n]*[\];,)':}]\\)\\|{" reg-end))
   6155 ;;           (setq continue nil)
   6156 ;;           )
   6157 ;;          ((eq (char-before) ?\{)
   6158 ;;           (backward-char)
   6159 ;;           (web-mode-closing-paren reg-end)
   6160 ;;           (forward-char)
   6161 ;;           )
   6162 ;;          (t
   6163 ;;           (setq continue nil)
   6164 ;;           (setq pos (match-beginning 1))
   6165 ;;           ) ;t
   6166 ;;          ) ;cond
   6167 ;;         ) ;while
   6168 ;;       ) ;save-excursion
   6169 ;;     (when pos (goto-char pos))
   6170 ;;     ;;(message "jsx-skip: %S" pos)
   6171 ;;     pos))
   6172 
   6173 ;; http://facebook.github.io/jsx/
   6174 ;; https://github.com/facebook/jsx/blob/master/AST.md
   6175 (defun web-mode-jsx-scan-element (reg-beg reg-end depth)
   6176   (unless depth (setq depth 1))
   6177   (save-excursion
   6178     (let (token-beg token-end regexp)
   6179       (goto-char reg-beg)
   6180       (put-text-property reg-beg (1+ reg-beg) 'jsx-beg depth)
   6181       (put-text-property (1- reg-end) reg-end 'jsx-end depth)
   6182       (put-text-property reg-beg reg-end 'jsx-depth depth)
   6183       (goto-char reg-beg)
   6184       (web-mode-scan-elements reg-beg reg-end)
   6185       (web-mode-jsx-scan-expression reg-beg reg-end (1+ depth))
   6186       )))
   6187 
   6188 (defun web-mode-jsx-scan-expression (reg-beg reg-end depth)
   6189   (let ((continue t) beg end)
   6190     (save-excursion
   6191       (goto-char reg-beg)
   6192       ;;(message "reg-beg=%S reg-end=%S" reg-beg reg-end)
   6193       (while (and continue (search-forward "{" reg-end t))
   6194         (backward-char)
   6195         (setq beg (point)
   6196               end (web-mode-closing-paren reg-end))
   6197         (cond
   6198          ((eq (get-text-property beg 'part-token) 'comment)
   6199           (forward-char))
   6200          ((not end)
   6201           (setq continue nil))
   6202          (t
   6203           (setq end (1+ end))
   6204           (put-text-property beg end 'jsx-depth depth)
   6205           (put-text-property beg (1+ beg) 'jsx-beg depth)
   6206           (put-text-property (1- end) end 'jsx-end depth)
   6207           (web-mode-part-scan beg end "jsx" (1+ depth))
   6208           ) ;t
   6209          ) ;cond
   6210         ) ;while
   6211       ) ;save-excursion
   6212     ))
   6213 
   6214 (defun web-mode-jsx-is-html (&optional pos)
   6215   (interactive)
   6216   (unless pos (setq pos (point)))
   6217   (let (ret (depth (get-text-property pos 'jsx-depth)))
   6218     (cond
   6219      ((or (null depth) (<= pos 2))
   6220       (setq pos nil))
   6221      ((and (= depth 1) (get-text-property pos 'jsx-beg))
   6222       (setq pos nil))
   6223      ((get-text-property pos 'tag-end)
   6224       (setq pos nil))
   6225      ((get-text-property pos 'tag-attr-beg)
   6226       (setq pos nil))
   6227      ((get-text-property pos 'jsx-beg)
   6228       (setq pos (null (get-text-property pos 'tag-beg))))
   6229      ((setq pos (web-mode-jsx-depth-beginning-position pos))
   6230       (setq pos (not (null (get-text-property pos 'tag-beg)))))
   6231      (t
   6232       (setq pos nil))
   6233      ) ;cond
   6234     ;;(message "is-html: %S (depth=%S)" pos depth)
   6235     pos))
   6236 
   6237 (defun web-mode-jsx-is-expr (&optional pos)
   6238   (cond
   6239    ((and (get-text-property pos 'jsx-beg)
   6240          (not (get-text-property pos 'tag-beg)))
   6241     nil)
   6242    (t
   6243     (setq pos (web-mode-jsx-depth-beginning-position pos))
   6244     (null (get-text-property pos 'tag-beg)))
   6245    ) ;cond
   6246   )
   6247 
   6248 (defun web-mode-jsx-depth-beginning-position (&optional pos target-depth)
   6249   (interactive)
   6250   (unless pos (setq pos (point)))
   6251   (unless target-depth (setq target-depth (get-text-property pos 'jsx-depth)))
   6252   (cond
   6253    ((or (null target-depth) (bobp))
   6254     (setq pos nil))
   6255    ((and (get-text-property pos 'jsx-beg) (= target-depth (get-text-property pos 'jsx-depth)))
   6256     )
   6257    (t
   6258     (let ((continue t) depth)
   6259       (while continue
   6260         (setq pos (previous-single-property-change pos 'jsx-depth))
   6261         (cond
   6262          ((or (null pos)
   6263               (null (setq depth (get-text-property pos 'jsx-depth))))
   6264           (setq continue nil
   6265                 pos nil))
   6266          ((and (get-text-property pos 'jsx-beg) (= target-depth depth))
   6267           (setq continue nil))
   6268          ) ;cond
   6269         ) ;while
   6270       ) ;let
   6271     ) ;t
   6272    ) ;cond
   6273   ;;(message "beg: %S" pos)
   6274   pos)
   6275 
   6276 (defun web-mode-jsx-element-next (reg-end)
   6277   (let (continue beg end)
   6278     (setq beg (point))
   6279     (unless (get-text-property beg 'jsx-depth)
   6280       (setq beg (next-single-property-change beg 'jsx-beg)))
   6281     (setq continue (and beg (< beg reg-end))
   6282           end beg)
   6283     (while continue
   6284       (setq end (next-single-property-change end 'jsx-end))
   6285       (cond
   6286        ((or (null end) (> end reg-end))
   6287         (setq continue nil
   6288               end nil))
   6289        ((eq (get-text-property end 'jsx-depth) 1)
   6290         (setq continue nil))
   6291        (t
   6292         (setq end (1+ end)))
   6293        ) ;cond
   6294       ) ;while
   6295     ;;(message "beg=%S end=%S" beg end)
   6296     (if (and beg end (< beg end)) (cons beg end) nil)))
   6297 
   6298 (defun web-mode-jsx-expression-next (reg-end)
   6299   (let (beg end depth continue pos)
   6300     (setq beg (point))
   6301     ;;(message "pt=%S" beg)
   6302     (unless (and (get-text-property beg 'jsx-beg) (null (get-text-property beg 'tag-beg)))
   6303       ;;(setq beg (next-single-property-change beg 'jsx-beg))
   6304       (setq continue t
   6305             pos (1+ beg))
   6306       (while continue
   6307         (setq pos (next-single-property-change pos 'jsx-beg))
   6308         (cond
   6309          ((null pos)
   6310           (setq continue nil
   6311                 beg nil))
   6312          ((> pos reg-end)
   6313           (setq continue nil
   6314                 beg nil))
   6315          ((null (get-text-property pos 'jsx-beg))
   6316           )
   6317          ((null (get-text-property pos 'tag-beg))
   6318           (setq continue nil
   6319                 beg pos))
   6320          ;;(t
   6321          ;; (setq pos (1+ pos)))
   6322          ) ;cond
   6323         ) ;while
   6324       ) ;unless
   6325     ;;(message "beg=%S" beg)
   6326     (when (and beg (< beg reg-end))
   6327       (setq depth (get-text-property beg 'jsx-beg)
   6328             continue (not (null depth))
   6329             pos beg)
   6330       ;;(message "beg=%S" beg)
   6331       (while continue
   6332         (setq pos (next-single-property-change pos 'jsx-end))
   6333         ;;(message "pos=%S" pos)
   6334         (cond
   6335          ((null pos)
   6336           (setq continue nil))
   6337          ((> pos reg-end)
   6338           (setq continue nil))
   6339          ((eq depth (get-text-property pos 'jsx-end))
   6340           (setq continue nil
   6341                 end pos))
   6342          (t
   6343           ;;(setq pos (1+ pos))
   6344           )
   6345          ) ;cond
   6346         ) ;while
   6347       ) ;when
   6348     ;;(message "%S > %S" beg end)
   6349     (if (and beg end) (cons beg end) nil)))
   6350 
   6351 (defun web-mode-jsx-depth-next (reg-end)
   6352   (let (beg end depth continue pos)
   6353     (setq beg (point))
   6354     ;;(message "pt=%S" beg)
   6355     (unless (get-text-property beg 'jsx-beg)
   6356       ;;(setq beg (next-single-property-change beg 'jsx-beg))
   6357       ;;(setq pos (1+ beg))
   6358       (setq pos (next-single-property-change (1+ beg) 'jsx-beg))
   6359       (cond
   6360        ((null pos)
   6361         (setq beg nil))
   6362        ((>= pos reg-end)
   6363         (setq beg nil))
   6364        (t
   6365         (setq beg pos))
   6366        ) ;cond
   6367       ) ;unless
   6368     ;;(message "beg=%S" beg)
   6369     (when beg
   6370       (setq depth (get-text-property beg 'jsx-beg)
   6371             continue (not (null depth))
   6372             pos beg)
   6373       ;;(message "beg=%S" beg)
   6374       (while continue
   6375         (setq pos (next-single-property-change pos 'jsx-end))
   6376         ;;(message "pos=%S" pos)
   6377         (cond
   6378          ((null pos)
   6379           (setq continue nil))
   6380          ((> pos reg-end)
   6381           (setq continue nil))
   6382          ((eq depth (get-text-property pos 'jsx-end))
   6383           (setq continue nil
   6384                 end pos))
   6385          (t
   6386           ;;(setq pos (1+ pos))
   6387           )
   6388          ) ;cond
   6389         ) ;while
   6390       ) ;when
   6391     ;;(message "%S > %S" beg end)
   6392     (if (and beg end) (cons beg end) nil)))
   6393 
   6394 (defun web-mode-jsx-beginning ()
   6395   (interactive)
   6396   (let (depth (continue t) (reg-beg (point-min)) (pos (point)))
   6397     (setq depth (get-text-property pos 'jsx-depth))
   6398     (cond
   6399      ((not depth)
   6400       )
   6401      ((get-text-property (1- pos) 'jsx-beg)
   6402       (goto-char (1- pos)))
   6403      (t
   6404       (while continue
   6405         (setq pos (previous-single-property-change pos 'jsx-beg))
   6406         ;;(message "pos=%S" pos)
   6407         (cond
   6408          ((null pos)
   6409           (setq continue nil))
   6410          ((<= pos reg-beg)
   6411           (setq continue nil))
   6412          ((eq depth (get-text-property pos 'jsx-beg))
   6413           (setq continue nil))
   6414          ) ;cond
   6415         ) ;while
   6416       (web-mode-go pos)
   6417       ) ;t
   6418      ) ;cond
   6419     ))
   6420 
   6421 (defun web-mode-jsx-end ()
   6422   (interactive)
   6423   (let (depth (continue t) (reg-end (point-max)) (pos (point)))
   6424     (setq depth (get-text-property pos 'jsx-depth))
   6425     (cond
   6426      ((not depth)
   6427       )
   6428      ((get-text-property pos 'jsx-end)
   6429       (goto-char (+ pos 1)))
   6430      (t
   6431       (while continue
   6432         (setq pos (next-single-property-change pos 'jsx-end))
   6433         ;;(message "pos=%S" pos)
   6434         (cond
   6435          ((null pos)
   6436           (setq continue nil))
   6437          ((> pos reg-end)
   6438           (setq continue nil))
   6439          ((eq depth (get-text-property pos 'jsx-end))
   6440           (setq continue nil))
   6441          ) ;cond
   6442         ) ;while
   6443       (web-mode-go pos 1)
   6444       ) ;t
   6445      ) ;cond
   6446     ))
   6447 
   6448 ;;---- FONTIFICATION -----------------------------------------------------------
   6449 
   6450 (defun web-mode-fontify (limit)
   6451   (when web-mode-trace
   6452     (message "fontify: point(%S) limit(%S)" (point) limit))
   6453   (cond
   6454    ;;(web-mode-skip-fontification
   6455    ;; nil)
   6456    (t
   6457     (web-mode-with-silent-modifications
   6458       (save-excursion
   6459         (save-restriction
   6460           (save-match-data
   6461             (let ((beg (point))
   6462                   (buffer-undo-list t)
   6463                   (end limit)
   6464                   (inhibit-point-motion-hooks t)
   6465                   (inhibit-quit t))
   6466               (remove-list-of-text-properties beg end '(font-lock-face face))
   6467               (cond
   6468                ((and (get-text-property beg 'block-side)
   6469                      (not (get-text-property beg 'block-beg)))
   6470                 (web-mode-fontify-block beg end))
   6471                ((or (member web-mode-content-type web-mode-part-content-types)
   6472                     (get-text-property beg 'part-side))
   6473                 (web-mode-fontify-part beg end)
   6474                 (web-mode-block-foreach beg end 'web-mode-fontify-block))
   6475                ((string= web-mode-engine "none")
   6476                 (web-mode-fontify-tags beg end)
   6477                 (web-mode-part-foreach beg end 'web-mode-fontify-part))
   6478                (t
   6479                 (web-mode-fontify-tags beg end)
   6480                 (web-mode-part-foreach beg end 'web-mode-fontify-part)
   6481                 (web-mode-block-foreach beg end 'web-mode-fontify-block))
   6482                ) ;cond
   6483               (when web-mode-enable-element-content-fontification
   6484                 (web-mode-fontify-elements beg end))
   6485               (when web-mode-enable-whitespace-fontification
   6486                 (web-mode-fontify-whitespaces beg end))
   6487               ) ;let
   6488             ))))
   6489     nil) ;t
   6490    ))
   6491 
   6492 (defun web-mode-buffer-fontify ()
   6493   (interactive)
   6494   (cond
   6495    ((and (fboundp 'font-lock-flush) global-font-lock-mode)
   6496     (font-lock-flush)
   6497     (font-lock-ensure))
   6498    (t  ;emacs 24
   6499     ;;(font-lock-fontify-buffer)
   6500     (and global-font-lock-mode
   6501          (font-lock-fontify-region (point-min) (point-max))))
   6502    ))
   6503 
   6504 (defun web-mode-unfontify-region (beg end)
   6505   ;;(message "unfontify: %S %S" beg end)
   6506   )
   6507 
   6508 (defun web-mode-fontify-region (beg end keywords)
   6509 ;;  (message "beg=%S end=%S keywords=%S" beg end (symbol-name keywords))
   6510   (save-excursion
   6511     (let ((font-lock-keywords keywords)
   6512           (font-lock-multiline nil)
   6513           (font-lock-keywords-case-fold-search
   6514            (member web-mode-engine '("archibus" "asp" "template-toolkit")))
   6515           (font-lock-keywords-only t)
   6516           (font-lock-extend-region-functions nil))
   6517       (when (and (listp font-lock-keywords) global-font-lock-mode)
   6518         (font-lock-fontify-region beg end)
   6519         )
   6520       )))
   6521 
   6522 (defun web-mode-fontify-tags (reg-beg reg-end &optional depth)
   6523   (let ((continue t))
   6524     (goto-char reg-beg)
   6525     (when (and (not (get-text-property (point) 'tag-beg))
   6526                (not (web-mode-tag-next)))
   6527       (setq continue nil))
   6528     (when (and continue (>= (point) reg-end))
   6529       (setq continue nil))
   6530     (while continue
   6531       (cond
   6532        (depth
   6533         (when (eq depth (get-text-property (point) 'jsx-depth))
   6534           (web-mode-fontify-tag))
   6535         )
   6536        (t
   6537         (web-mode-fontify-tag))
   6538        ) ;cond
   6539       (when (or (not (web-mode-tag-next))
   6540                 (>= (point) reg-end))
   6541         (setq continue nil))
   6542       ) ;while
   6543     (when web-mode-enable-inlays
   6544       (when (null web-mode-inlay-regexp)
   6545         (setq web-mode-inlay-regexp (regexp-opt '("\\[" "\\(" "\\begin{align}"))))
   6546       (let (beg end expr)
   6547         (goto-char reg-beg)
   6548         (while (web-mode-dom-rsf web-mode-inlay-regexp reg-end)
   6549           (setq beg (match-beginning 0)
   6550                 end nil
   6551                 expr (substring (match-string-no-properties 0) 0 2))
   6552           (setq expr (cond
   6553                       ((string= expr "\\[") "\\]")
   6554                       ((string= expr "\\(") "\\)")
   6555                       (t "\\end{align}")))
   6556           (when (and (web-mode-dom-sf expr reg-end)
   6557                      (setq end (match-end 0))
   6558                      (not (text-property-any beg end 'tag-end t)))
   6559             (font-lock-append-text-property beg end 'font-lock-face 'web-mode-inlay-face)
   6560             ) ;when
   6561           ) ;while
   6562         ) ;let
   6563       ) ;when
   6564     (when web-mode-enable-html-entities-fontification
   6565       (let (beg end)
   6566         (goto-char reg-beg)
   6567         (while (web-mode-dom-rsf "&\\([#]?[[:alnum:]]\\{2,8\\}\\);" reg-end)
   6568           (setq beg (match-beginning 0)
   6569                 end (match-end 0))
   6570           (when (not (text-property-any beg end 'tag-end t))
   6571             (font-lock-append-text-property beg end 'font-lock-face 'web-mode-html-entity-face)
   6572             ) ;when
   6573           ) ;while
   6574         ) ;let
   6575       ) ;when
   6576     ))
   6577 
   6578 (defun web-mode-fontify-tag (&optional beg end)
   6579   (unless beg (setq beg (point)))
   6580   (unless end (setq end (1+ (web-mode-tag-end-position beg))))
   6581   (let (name type face flags slash-beg slash-end bracket-end)
   6582     (setq flags (get-text-property beg 'tag-beg)
   6583           type (get-text-property beg 'tag-type)
   6584           name (get-text-property beg 'tag-name))
   6585     (setq bracket-end (> (logand flags 16) 0))
   6586     (cond
   6587      ((eq type 'comment)
   6588       (put-text-property beg end 'font-lock-face 'web-mode-comment-face)
   6589       (when (and web-mode-enable-comment-interpolation (> (- end beg) 5))
   6590         (web-mode-interpolate-comment beg end nil)))
   6591      ((eq type 'cdata)
   6592       (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
   6593      ((eq type 'doctype)
   6594       (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
   6595      ((eq type 'declaration)
   6596       (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
   6597      (name
   6598       (setq slash-beg (> (logand flags 4) 0)
   6599             slash-end (> (logand flags 8) 0)
   6600             bracket-end (> (logand flags 16) 0))
   6601       (setq face (cond
   6602                   ((not bracket-end)       'web-mode-html-tag-unclosed-face)
   6603                   ((and web-mode-enable-element-tag-fontification
   6604                         (setq face (cdr (assoc name web-mode-element-tag-faces))))
   6605                    face)
   6606                   ((> (logand flags 32) 0) 'web-mode-html-tag-namespaced-face)
   6607                   ((> (logand flags 2) 0)  'web-mode-html-tag-custom-face)
   6608                   (t                       'web-mode-html-tag-face)))
   6609       (put-text-property beg (+ beg (if slash-beg 2 1))
   6610                          'font-lock-face 'web-mode-html-tag-bracket-face)
   6611       (unless (string= name "_fragment_")
   6612         (put-text-property (+ beg (if slash-beg 2 1))
   6613                            (+ beg (if slash-beg 2 1) (length name))
   6614                            'font-lock-face face))
   6615       (when (or slash-end bracket-end)
   6616         (put-text-property (- end (if slash-end 2 1)) end 'font-lock-face 'web-mode-html-tag-bracket-face)
   6617         ) ;when
   6618       (when (> (logand flags 1) 0)
   6619         ;;(message "%S>%S" beg end)
   6620         (web-mode-fontify-attrs beg end))
   6621       ) ;case name
   6622      ) ;cond
   6623     ))
   6624 
   6625 (defun web-mode-fontify-attrs (reg-beg reg-end)
   6626   (let ((continue t) (pos reg-beg) beg end flags offset face)
   6627     ;;(message "fontify-attrs %S>%S" reg-beg reg-end)
   6628     (while continue
   6629       (setq beg (web-mode-attribute-next-position pos reg-end))
   6630       (cond
   6631        ((or (null beg) (>= beg reg-end))
   6632         (setq continue nil))
   6633        (t
   6634         (setq flags (or (get-text-property beg 'tag-attr-beg) 0))
   6635         (setq face (cond
   6636                     ((= (logand flags 1) 1) 'web-mode-html-attr-custom-face)
   6637                     ((= (logand flags 2) 2) 'web-mode-html-attr-engine-face)
   6638                     ((= (logand flags 4) 4) nil)
   6639                     (t                      'web-mode-html-attr-name-face)))
   6640         ;;(setq end (if (get-text-property beg 'tag-attr-end) beg (web-mode-attribute-end-position beg)))
   6641         (setq end (web-mode-attribute-end-position beg))
   6642         ;;(message "beg=%S end=%S" beg end)
   6643         (cond
   6644          ((or (null end) (>= end reg-end))
   6645           (setq continue nil))
   6646          (t
   6647           (setq offset (get-text-property end 'tag-attr-end))
   6648           (if (= offset 0)
   6649               (put-text-property beg (1+ end) 'font-lock-face face)
   6650             (put-text-property beg (+ beg offset) 'font-lock-face face)
   6651             (put-text-property (+ beg offset) (+ beg offset 1)
   6652                                'font-lock-face
   6653                                'web-mode-html-attr-equal-face)
   6654             (when (not (get-text-property (+ beg offset 1) 'jsx-beg))
   6655               (put-text-property (+ beg offset 1) (1+ end)
   6656                                  'font-lock-face
   6657                                  'web-mode-html-attr-value-face)
   6658               )
   6659             ) ;if offset
   6660           (setq pos (1+ end))
   6661           ) ;t
   6662          ) ;cond
   6663         ) ;t
   6664        );cond
   6665       ) ;while
   6666     ))
   6667 
   6668 (defun web-mode-fontify-block (reg-beg reg-end)
   6669   (when web-mode-trace
   6670     (message "fontify-block: reg-beg(%S) reg-end(%S) engine(%S) keywords(%S)"
   6671              reg-beg reg-end web-mode-engine (not (null web-mode-engine-font-lock-keywords))))
   6672 
   6673   (let (sub1 sub2 sub3 continue char keywords token-type face beg end (buffer (current-buffer)))
   6674 
   6675     ;; NOTE: required for blocks inside tag attrs
   6676     (remove-list-of-text-properties reg-beg reg-end '(font-lock-face))
   6677 
   6678     (goto-char reg-beg)
   6679 
   6680     (when (null web-mode-engine-font-lock-keywords)
   6681       (setq sub1 (buffer-substring-no-properties
   6682                   reg-beg (+ reg-beg 1))
   6683             sub2 (buffer-substring-no-properties
   6684                   reg-beg (+ reg-beg 2))
   6685             sub3 (buffer-substring-no-properties
   6686                   reg-beg (+ reg-beg (if (>= (point-max) (+ reg-beg 3)) 3 2))))
   6687       )
   6688 
   6689     (cond
   6690 
   6691      ((and (get-text-property reg-beg 'block-beg)
   6692            (eq (get-text-property reg-beg 'block-token) 'comment))
   6693       (put-text-property reg-beg reg-end 'font-lock-face 'web-mode-comment-face)
   6694       ) ;comment block
   6695 
   6696      (web-mode-engine-font-lock-keywords
   6697       (setq keywords web-mode-engine-font-lock-keywords))
   6698 
   6699      ((string= web-mode-engine "django")
   6700       (cond
   6701        ((string= sub2 "{{")
   6702         (setq keywords web-mode-django-expr-font-lock-keywords))
   6703        ((string= sub2 "{%")
   6704         (setq keywords web-mode-django-code-font-lock-keywords))
   6705        ((string= sub1 "#")
   6706         (setq keywords web-mode-django-code-font-lock-keywords))
   6707        )) ;django
   6708 
   6709      ((string= web-mode-engine "mako")
   6710       (cond
   6711        ((member sub3 '("<% " "<%\n" "<%!"))
   6712         (setq keywords web-mode-mako-block-font-lock-keywords))
   6713        ((eq (aref sub2 0) ?\%)
   6714         (setq keywords web-mode-mako-block-font-lock-keywords))
   6715        ((member sub2 '("<%" "</"))
   6716         (setq keywords web-mode-mako-tag-font-lock-keywords))
   6717        ((member sub2 '("${"))
   6718         (setq keywords web-mode-uel-font-lock-keywords))
   6719        )) ;mako
   6720 
   6721      ((string= web-mode-engine "mason")
   6722       ;;(message "%S %S" sub2 sub3)
   6723       (cond
   6724        ((member sub3 '("<% " "<%\n" "<&|"))
   6725         (setq keywords web-mode-mason-code-font-lock-keywords))
   6726        ((eq (aref sub2 0) ?\%)
   6727         (setq keywords web-mode-mason-code-font-lock-keywords))
   6728        ((and (or (string= sub2 "<%") (string= sub3 "</%"))
   6729              (not (member sub3 '("<%c" "<%i" "<%p"))))
   6730         (setq keywords web-mode-mason-block-font-lock-keywords))
   6731        (t
   6732         (setq keywords web-mode-mason-code-font-lock-keywords))
   6733        )) ;mason
   6734 
   6735      ((string= web-mode-engine "jsp")
   6736       (cond
   6737        ((string= sub3 "<%@")
   6738         (setq keywords web-mode-directive-font-lock-keywords))
   6739        ((member sub2 '("${" "#{"))
   6740         (setq keywords web-mode-uel-font-lock-keywords))
   6741        ((string= sub2 "<%")
   6742         (setq keywords web-mode-jsp-font-lock-keywords))
   6743        )) ;jsp
   6744 
   6745      ((string= web-mode-engine "asp")
   6746       (cond
   6747        ((or (string= sub2 "<%")
   6748             (not (string= sub1 "<")))
   6749         (setq keywords web-mode-asp-font-lock-keywords))
   6750        (t
   6751         (setq keywords web-mode-engine-tag-font-lock-keywords))
   6752        )) ;asp
   6753 
   6754      ((string= web-mode-engine "clip")
   6755       (setq keywords web-mode-engine-tag-font-lock-keywords)
   6756       ) ;clip
   6757 
   6758      ((string= web-mode-engine "perl")
   6759       (setq keywords web-mode-engine-tag-font-lock-keywords)
   6760       ) ;perl
   6761 
   6762      ((string= web-mode-engine "aspx")
   6763       (cond
   6764        ((string= sub3 "<%@")
   6765         (setq keywords web-mode-directive-font-lock-keywords))
   6766        ((string= sub3 "<%$")
   6767         (setq keywords web-mode-expression-font-lock-keywords))
   6768        (t
   6769         (setq keywords web-mode-aspx-font-lock-keywords))
   6770        )) ;aspx
   6771 
   6772      ((string= web-mode-engine "freemarker")
   6773       (cond
   6774        ((member sub2 '("${" "#{"))
   6775         (setq keywords web-mode-uel-font-lock-keywords))
   6776        ((or (member sub2 '("<@" "[@" "<#" "[#"))
   6777             (member sub3 '("</@" "[/@" "</#" "[/#")))
   6778         (setq keywords (if (eq ?\[ (aref sub2 0))
   6779                            web-mode-freemarker-square-font-lock-keywords
   6780                          web-mode-freemarker-font-lock-keywords)))
   6781        (t
   6782         (setq keywords web-mode-engine-tag-font-lock-keywords))
   6783        )) ;freemarker
   6784 
   6785      ) ;cond
   6786 
   6787     (when keywords
   6788       (web-mode-fontify-region reg-beg reg-end keywords)
   6789       (setq continue t)
   6790       (setq end reg-beg)
   6791       (while continue
   6792         (if (get-text-property end 'block-token)
   6793             (setq beg end)
   6794           (setq beg (next-single-property-change end 'block-token buffer reg-end)))
   6795         (setq end nil)
   6796         (when beg (setq char (char-after beg)))
   6797         (if (and beg (< beg reg-end))
   6798             (progn
   6799               (setq token-type (get-text-property beg 'block-token))
   6800               (setq face (cond
   6801                           ((eq token-type 'string)  'web-mode-block-string-face)
   6802                           ((eq token-type 'comment) 'web-mode-block-comment-face)
   6803                           ((eq token-type 'symbol)  'web-mode-symbol-face)
   6804                           (t                        'web-mode-block-delimiter-face)))
   6805               (setq end (next-single-property-change beg 'block-token buffer reg-end))
   6806 ;;              (message "end=%S" end)
   6807               (if (and end (<= end reg-end))
   6808                   (progn
   6809                     ;;(message "%S > %S face(%S)" beg end face)
   6810                     (remove-list-of-text-properties beg end '(face))
   6811                     (put-text-property beg end 'font-lock-face face)
   6812                     )
   6813                 (setq continue nil
   6814                       end nil)
   6815                 ) ;if end
   6816               ) ;progn beg
   6817           (setq continue nil
   6818                 end nil)
   6819           ) ;if beg
   6820         (when (and beg end)
   6821           (save-match-data
   6822             (when (and web-mode-enable-heredoc-fontification
   6823                        (eq char ?\<)
   6824                        (> (- end beg) 8)
   6825                        (string-match-p "JS\\|JAVASCRIPT\\|HTM\\|CSS" (buffer-substring-no-properties beg end)))
   6826               (setq keywords
   6827                     (cond
   6828                      ((string-match-p "H" (buffer-substring-no-properties beg (+ beg 8)))
   6829                       web-mode-html-font-lock-keywords)
   6830                      (t
   6831                       web-mode-javascript-font-lock-keywords)
   6832                      ))
   6833               (web-mode-fontify-region beg end keywords)
   6834               )
   6835             ) ;save-match-data
   6836           (when (and web-mode-enable-string-interpolation
   6837                      (member char '(?\" ?\<))
   6838                      (member web-mode-engine '("php" "erb"))
   6839                      (> (- end beg) 4))
   6840             (web-mode-interpolate-block-string beg end)
   6841             ) ;when
   6842           (when (and web-mode-enable-comment-interpolation
   6843                      (eq token-type 'comment)
   6844                      (> (- end beg) 3))
   6845             (web-mode-interpolate-comment beg end t)
   6846             ) ;when
   6847           (when (and web-mode-enable-comment-annotation
   6848                      (eq token-type 'comment)
   6849                      (> (- end beg) 3))
   6850             (web-mode-annotate-comment beg end)
   6851             ) ;when
   6852           (when (and web-mode-enable-sql-detection
   6853                      (eq token-type 'string)
   6854                      (> (- end beg) 6)
   6855                      (web-mode-looking-at-p (concat "\\(.\\|<<<[[:alnum:]]+\\)[ \n]*" web-mode-sql-queries) beg)
   6856                      )
   6857             (web-mode-interpolate-sql-string beg end)
   6858             ) ;when
   6859           ) ;when beg end
   6860         ) ;while continue
   6861       ) ;when keywords
   6862 
   6863     (when (and (member web-mode-engine '("mako"))
   6864                (> (- reg-end reg-beg) 12)
   6865                (eq ?\< (char-after reg-beg)))
   6866       (web-mode-interpolate-block-tag reg-beg reg-end))
   6867 
   6868     (when web-mode-enable-block-face
   6869       (font-lock-append-text-property reg-beg reg-end 'face 'web-mode-block-face))
   6870 
   6871     ))
   6872 
   6873 (defun web-mode-fontify-part (reg-beg reg-end &optional depth)
   6874   (save-excursion
   6875     (let (start continue token-type face pos beg end string-face comment-face content-type)
   6876       ;;(message "fontify-part: reg-beg(%S) reg-end(%S)" reg-beg reg-end)
   6877       (if (member web-mode-content-type web-mode-part-content-types)
   6878           (setq content-type web-mode-content-type)
   6879         (setq content-type (symbol-name (get-text-property reg-beg 'part-side))))
   6880       ;;(message "content-type=%S" content-type)
   6881       (unless depth
   6882         (when (string= content-type "jsx") (setq depth 0))
   6883         )
   6884       (setq string-face 'web-mode-part-string-face
   6885             comment-face 'web-mode-part-comment-face)
   6886       (cond
   6887        ((member content-type '("javascript" "jsx"))
   6888         (setq string-face 'web-mode-javascript-string-face
   6889               comment-face 'web-mode-javascript-comment-face)
   6890         (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
   6891        ((string= content-type "json")
   6892         (setq string-face 'web-mode-json-string-face
   6893               comment-face 'web-mode-json-comment-face)
   6894         (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
   6895        ((string= content-type "css")
   6896         (setq string-face 'web-mode-css-string-face
   6897               comment-face 'web-mode-css-comment-face)
   6898         (web-mode-fontify-css-rules reg-beg reg-end))
   6899        ((string= content-type "sql")
   6900         (web-mode-fontify-region reg-beg reg-end web-mode-sql-font-lock-keywords))
   6901        ((string= content-type "stylus")
   6902         (web-mode-fontify-region reg-beg reg-end web-mode-stylus-font-lock-keywords))
   6903        ((string= content-type "sass")
   6904         (web-mode-fontify-region reg-beg reg-end web-mode-sass-font-lock-keywords))
   6905        ((string= content-type "pug")
   6906         (web-mode-fontify-region reg-beg reg-end web-mode-pug-font-lock-keywords))
   6907        ((string= content-type "markdown")
   6908         (web-mode-fontify-region reg-beg reg-end web-mode-markdown-font-lock-keywords))
   6909        ((string= content-type "ruby")
   6910         (web-mode-fontify-region reg-beg reg-end web-mode-erb-font-lock-keywords))
   6911        ((string= content-type "typescript")
   6912         (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
   6913        ) ;cond
   6914 
   6915       (goto-char reg-beg)
   6916 
   6917       ;;(when (string= content-type "jsx") (web-mode-fontify-tags reg-beg reg-end))
   6918       ;;(setq continue (and pos (< pos reg-end)))
   6919       (setq continue t
   6920             pos reg-beg)
   6921       (while continue
   6922         (if (get-text-property pos 'part-token)
   6923             (setq beg pos)
   6924           (setq beg (next-single-property-change pos 'part-token)))
   6925         (cond
   6926          ((or (null beg) (>= beg reg-end))
   6927           (setq continue nil
   6928                 end nil))
   6929          ((and (eq depth 0) (get-text-property beg 'jsx-depth))
   6930           (setq pos (or (next-single-property-change beg 'jsx-depth) (point-max))))
   6931          (t
   6932           ;;(message "%c" (char-after beg))
   6933           (setq token-type (get-text-property beg 'part-token))
   6934           (setq face (cond
   6935                       ((eq token-type 'string)  string-face)
   6936                       ((eq token-type 'comment) comment-face)
   6937                       ((eq token-type 'context) 'web-mode-json-context-face)
   6938                       ((eq token-type 'key)     'web-mode-json-key-face)
   6939                       (t                        nil)))
   6940           (setq end (or (next-single-property-change beg 'part-token) (point-max))
   6941                 pos end)
   6942           (cond
   6943            ((or (null end) (> end reg-end))
   6944             (setq continue nil
   6945                   end nil))
   6946            (t
   6947             (when face
   6948               (remove-list-of-text-properties beg end '(face))
   6949               (put-text-property beg end 'font-lock-face face))
   6950             (cond
   6951              ((< (- end beg) 6)
   6952               )
   6953              ((eq token-type 'string)
   6954               (cond
   6955                ((and (eq (char-after beg) ?\`)
   6956                      web-mode-enable-literal-interpolation
   6957                      (member content-type '("javascript" "jsx" "typescript")))
   6958                 (web-mode-interpolate-javascript-literal beg end)
   6959                 )
   6960                ((and (eq (char-after beg) ?\")
   6961                      web-mode-enable-string-interpolation
   6962                      (member content-type '("javascript" "jsx" "typescript")))
   6963                 (web-mode-interpolate-javascript-string beg end))
   6964                ) ;cond
   6965               ) ;case string
   6966              ((eq token-type 'comment)
   6967               (when web-mode-enable-comment-interpolation
   6968                 (web-mode-interpolate-comment beg end t))
   6969               (when web-mode-enable-comment-annotation
   6970                 (web-mode-annotate-comment beg end))
   6971               )
   6972              ) ;cond
   6973             ) ;t
   6974            ) ;cond
   6975           ) ;t
   6976          ) ;cond
   6977         ) ;while
   6978 
   6979       (when (and (string= web-mode-content-type "html") web-mode-enable-part-face)
   6980         (font-lock-append-text-property reg-beg reg-end 'face
   6981                                         (cond
   6982                                          ((string= content-type "javascript")
   6983                                           'web-mode-script-face)
   6984                                          ((string= content-type "css")
   6985                                           'web-mode-style-face)
   6986                                          (t
   6987                                           'web-mode-part-face)))
   6988         )
   6989 
   6990       (when (and web-mode-enable-css-colorization (string= content-type "stylus"))
   6991         (goto-char reg-beg)
   6992         (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)
   6993                     (<= (point) reg-end))
   6994           (web-mode-colorize (match-beginning 0) (match-end 0))
   6995           )
   6996         )
   6997 
   6998       (when (and (eq depth 0) (string= content-type "jsx"))
   6999         (let (pair elt-beg elt-end exp-beg exp-end exp-depth)
   7000           (goto-char reg-beg)
   7001           (while (setq pair (web-mode-jsx-element-next reg-end))
   7002             ;;(message "elt-pair=%S" pair)
   7003             (setq elt-beg (car pair)
   7004                   elt-end (cdr pair))
   7005             (remove-list-of-text-properties elt-beg (1+ elt-end) '(face))
   7006             (web-mode-fontify-tags elt-beg elt-end 1)
   7007             (goto-char elt-beg)
   7008             (while (setq pair (web-mode-jsx-expression-next elt-end))
   7009               ;;(message "exp-pair=%S elt-end=%S" pair elt-end)
   7010               (setq exp-beg (car pair)
   7011                     exp-end (cdr pair))
   7012               (when (eq (char-after exp-beg) ?\{)
   7013                 ;;(message "%S : %c %c" exp-beg (char-after (+ exp-beg 1)) (char-after (+ exp-beg 2)))
   7014                 (cond
   7015                  ;;((and (eq (char-after (+ exp-beg 1)) ?\/) (eq (char-after (+ exp-beg 2)) ?\*))
   7016                  ;; (put-text-property exp-beg (1+ exp-end) 'font-lock-face 'web-mode-part-comment-face)
   7017                  ;; )
   7018                  (t
   7019                   (setq exp-depth (get-text-property exp-beg 'jsx-depth))
   7020                   (remove-list-of-text-properties exp-beg exp-end '(font-lock-face))
   7021                   (put-text-property exp-beg (1+ exp-beg) 'font-lock-face 'web-mode-block-delimiter-face)
   7022                   (when (and (eq (get-text-property exp-beg 'tag-attr-beg) 4) (web-mode-looking-at-p "\.\.\." (1+ exp-beg)))
   7023                   (put-text-property exp-beg (+ exp-beg 4) 'font-lock-face 'web-mode-block-delimiter-face))
   7024                   (put-text-property exp-end (1+ exp-end) 'font-lock-face 'web-mode-block-delimiter-face)
   7025                   (web-mode-fontify-tags (1+ exp-beg) exp-end (1+ exp-depth))
   7026                   (web-mode-fontify-part (1+ exp-beg) exp-end exp-depth)
   7027                   (web-mode-fontify-region (1+ exp-beg) exp-end web-mode-javascript-font-lock-keywords)
   7028                   ) ;t
   7029                  ) ;cond
   7030                 ) ;when
   7031               (goto-char (1+ exp-beg))
   7032               ) ;while exp
   7033 
   7034             (when (and elt-beg web-mode-jsx-depth-faces)
   7035               (let (depth-beg depth-end jsx-face)
   7036                 (goto-char elt-beg)
   7037                 (while (setq pair (web-mode-jsx-depth-next reg-end))
   7038                   ;;(message "depth-pair=%S" pair)
   7039                   (setq depth-beg (car pair)
   7040                         depth-end (cdr pair)
   7041                         depth (get-text-property depth-beg 'jsx-depth)
   7042                         jsx-face (elt web-mode-jsx-depth-faces (1- depth)))
   7043                   ;;(message "%S" jsx-face)
   7044                   (font-lock-prepend-text-property depth-beg (1+ depth-end) 'face jsx-face)
   7045                   (goto-char (+ depth-beg 2))
   7046                   )
   7047                 ) ;let
   7048               )
   7049 
   7050             (goto-char (1+ elt-end))
   7051             ) ;while elt
   7052           ) ;let
   7053         ) ;when
   7054 
   7055       ) ;let
   7056     ) ;save-excursion
   7057   )
   7058 
   7059 (defun web-mode-fontify-css-rules (part-beg part-end)
   7060   (save-excursion
   7061     (goto-char part-beg)
   7062     (let (rule (continue t) (i 0) (at-rule nil) (var-rule nil))
   7063       (while continue
   7064         (setq rule (web-mode-css-rule-next part-end))
   7065         ;;(message "rule=%S" rule)
   7066         (cond
   7067          ((> (setq i (1+ i)) 1000)
   7068           (message "fontify-css-rules ** too much rules **")
   7069           (setq continue nil))
   7070          ((null rule)
   7071           (setq continue nil))
   7072          ((and (setq at-rule (plist-get rule :at-rule))
   7073                (not (member at-rule '("charset" "font-face" "import" "viewport")))
   7074                (plist-get rule :dec-end))
   7075           (web-mode-fontify-css-rule (plist-get rule :sel-beg)
   7076                                      (plist-get rule :sel-end)
   7077                                      nil nil)
   7078           (web-mode-fontify-css-rules (plist-get rule :dec-beg)
   7079                                       (plist-get rule :dec-end)))
   7080          (t
   7081           (web-mode-fontify-css-rule (plist-get rule :sel-beg)
   7082                                      (plist-get rule :sel-end)
   7083                                      (plist-get rule :dec-beg)
   7084                                      (plist-get rule :dec-end)))
   7085          ) ;cond
   7086         ) ;while
   7087       ) ;let
   7088     ))
   7089 
   7090 (defun web-mode-fontify-css-rule (sel-beg sel-end dec-beg dec-end)
   7091   (save-excursion
   7092     ;;(let ((end sel-end))
   7093     ;;(message "sel-beg=%S sel-end=%S dec-beg=%S dec-end=%S" sel-beg sel-end dec-beg dec-end)
   7094     (web-mode-fontify-region sel-beg sel-end web-mode-selector-font-lock-keywords)
   7095     (when (and dec-beg dec-end)
   7096       ;;(setq end dec-end)
   7097       (web-mode-fontify-region dec-beg dec-end web-mode-declaration-font-lock-keywords)
   7098       ) ;when
   7099     (when (and dec-beg dec-end)
   7100       (goto-char dec-beg)
   7101       (while (and web-mode-enable-css-colorization
   7102                   (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)
   7103                   ;;(progn (message "%S %S" end (point)) t)
   7104                   (<= (point) dec-end))
   7105         ;;(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)))
   7106         (web-mode-colorize (match-beginning 1) (match-end 1))
   7107         ) ;while
   7108       ) ;when
   7109     ;;) ;let
   7110     ))
   7111 
   7112 (defun web-mode-colorize-foreground (color)
   7113   (let* ((values (x-color-values color))
   7114          (r (car values))
   7115          (g (cadr values))
   7116          (b (car (cdr (cdr values)))))
   7117     (if (> 128.0 (floor (+ (* .3 r) (* .59 g) (* .11 b)) 256))
   7118         "white" "black")))
   7119 
   7120 (defun web-mode-colorize (beg end)
   7121   (let (str str1 plist)
   7122     (setq str (buffer-substring-no-properties beg end))
   7123     ;;(setq str1 (match-string-no-properties 1))
   7124     ;;(message "str=%S" str str1)
   7125     (cond
   7126      ;;(t
   7127      ;; (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))
   7128      ;; )
   7129      ((string= (substring str 0 1) "#")
   7130       (setq plist (list :background str
   7131                         :foreground (web-mode-colorize-foreground str))))
   7132      ((and (>= (length str) 3) (string= (substring str 0 3) "rgb"))
   7133       (setq str (format "#%02X%02X%02X"
   7134                         (string-to-number (match-string-no-properties 2))
   7135                         (string-to-number (match-string-no-properties 3))
   7136                         (string-to-number (match-string-no-properties 4))))
   7137       (setq plist (list :background str
   7138                         :foreground (web-mode-colorize-foreground str))))
   7139      ((string= str "black") (setq plist (list :background "#000000" :foreground (web-mode-colorize-foreground "#000000"))))
   7140      ((string= str "silver") (setq plist (list :background "#c0c0c0" :foreground (web-mode-colorize-foreground "#c0c0c0"))))
   7141      ((string= str "gray") (setq plist (list :background "#808080" :foreground (web-mode-colorize-foreground "#808080"))))
   7142      ((string= str "white") (setq plist (list :background "#ffffff" :foreground (web-mode-colorize-foreground "#ffffff"))))
   7143      ((string= str "maroon") (setq plist (list :background "#800000" :foreground (web-mode-colorize-foreground "#800000"))))
   7144      ((string= str "red") (setq plist (list :background "#ff0000" :foreground (web-mode-colorize-foreground "#ff0000"))))
   7145      ((string= str "purple") (setq plist (list :background "#800080" :foreground (web-mode-colorize-foreground "#800080"))))
   7146      ((string= str "fuchsia") (setq plist (list :background "#ff00ff" :foreground (web-mode-colorize-foreground "#ff00ff"))))
   7147      ((string= str "green") (setq plist (list :background "#008000" :foreground (web-mode-colorize-foreground "#008000"))))
   7148      ((string= str "lime") (setq plist (list :background "#00ff00" :foreground (web-mode-colorize-foreground "#00ff00"))))
   7149      ((string= str "olive") (setq plist (list :background "#808000" :foreground (web-mode-colorize-foreground "#808000"))))
   7150      ((string= str "yellow") (setq plist (list :background "#ffff00" :foreground (web-mode-colorize-foreground "#ffff00"))))
   7151      ((string= str "navy") (setq plist (list :background "#000080" :foreground (web-mode-colorize-foreground "#000080"))))
   7152      ((string= str "blue") (setq plist (list :background "#0000ff" :foreground (web-mode-colorize-foreground "#0000ff"))))
   7153      ((string= str "teal") (setq plist (list :background "#008080" :foreground (web-mode-colorize-foreground "#008080"))))
   7154      ((string= str "aqua") (setq plist (list :background "#00ffff" :foreground (web-mode-colorize-foreground "#00ffff"))))
   7155      ((string= str "orange") (setq plist (list :background "#ffa500" :foreground (web-mode-colorize-foreground "#ffa500"))))
   7156      ((string= str "aliceblue") (setq plist (list :background "#f0f8ff" :foreground (web-mode-colorize-foreground "#f0f8ff"))))
   7157      ((string= str "antiquewhite") (setq plist (list :background "#faebd7" :foreground (web-mode-colorize-foreground "#faebd7"))))
   7158      ((string= str "aquamarine") (setq plist (list :background "#7fffd4" :foreground (web-mode-colorize-foreground "#7fffd4"))))
   7159      ((string= str "azure") (setq plist (list :background "#f0ffff" :foreground (web-mode-colorize-foreground "#f0ffff"))))
   7160      ((string= str "beige") (setq plist (list :background "#f5f5dc" :foreground (web-mode-colorize-foreground "#f5f5dc"))))
   7161      ((string= str "bisque") (setq plist (list :background "#ffe4c4" :foreground (web-mode-colorize-foreground "#ffe4c4"))))
   7162      ((string= str "blanchedalmond") (setq plist (list :background "#ffebcd" :foreground (web-mode-colorize-foreground "#ffebcd"))))
   7163      ((string= str "blueviolet") (setq plist (list :background "#8a2be2" :foreground (web-mode-colorize-foreground "#8a2be2"))))
   7164      ((string= str "brown") (setq plist (list :background "#a52a2a" :foreground (web-mode-colorize-foreground "#a52a2a"))))
   7165      ((string= str "burlywood") (setq plist (list :background "#deb887" :foreground (web-mode-colorize-foreground "#deb887"))))
   7166      ((string= str "cadetblue") (setq plist (list :background "#5f9ea0" :foreground (web-mode-colorize-foreground "#5f9ea0"))))
   7167      ((string= str "chartreuse") (setq plist (list :background "#7fff00" :foreground (web-mode-colorize-foreground "#7fff00"))))
   7168      ((string= str "chocolate") (setq plist (list :background "#d2691e" :foreground (web-mode-colorize-foreground "#d2691e"))))
   7169      ((string= str "coral") (setq plist (list :background "#ff7f50" :foreground (web-mode-colorize-foreground "#ff7f50"))))
   7170      ((string= str "cornflowerblue") (setq plist (list :background "#6495ed" :foreground (web-mode-colorize-foreground "#6495ed"))))
   7171      ((string= str "cornsilk") (setq plist (list :background "#fff8dc" :foreground (web-mode-colorize-foreground "#fff8dc"))))
   7172      ((string= str "crimson") (setq plist (list :background "#dc143c" :foreground (web-mode-colorize-foreground "#dc143c"))))
   7173      ((string= str "cyan") (setq plist (list :background "#00ffff" :foreground (web-mode-colorize-foreground "#00ffff"))))
   7174      ((string= str "darkblue") (setq plist (list :background "#00008b" :foreground (web-mode-colorize-foreground "#00008b"))))
   7175      ((string= str "darkcyan") (setq plist (list :background "#008b8b" :foreground (web-mode-colorize-foreground "#008b8b"))))
   7176      ((string= str "darkgoldenrod") (setq plist (list :background "#b8860b" :foreground (web-mode-colorize-foreground "#b8860b"))))
   7177      ((string= str "darkgray") (setq plist (list :background "#a9a9a9" :foreground (web-mode-colorize-foreground "#a9a9a9"))))
   7178      ((string= str "darkgreen") (setq plist (list :background "#006400" :foreground (web-mode-colorize-foreground "#006400"))))
   7179      ((string= str "darkgrey") (setq plist (list :background "#a9a9a9" :foreground (web-mode-colorize-foreground "#a9a9a9"))))
   7180      ((string= str "darkkhaki") (setq plist (list :background "#bdb76b" :foreground (web-mode-colorize-foreground "#bdb76b"))))
   7181      ((string= str "darkmagenta") (setq plist (list :background "#8b008b" :foreground (web-mode-colorize-foreground "#8b008b"))))
   7182      ((string= str "darkolivegreen") (setq plist (list :background "#556b2f" :foreground (web-mode-colorize-foreground "#556b2f"))))
   7183      ((string= str "darkorange") (setq plist (list :background "#ff8c00" :foreground (web-mode-colorize-foreground "#ff8c00"))))
   7184      ((string= str "darkorchid") (setq plist (list :background "#9932cc" :foreground (web-mode-colorize-foreground "#9932cc"))))
   7185      ((string= str "darkred") (setq plist (list :background "#8b0000" :foreground (web-mode-colorize-foreground "#8b0000"))))
   7186      ((string= str "darksalmon") (setq plist (list :background "#e9967a" :foreground (web-mode-colorize-foreground "#e9967a"))))
   7187      ((string= str "darkseagreen") (setq plist (list :background "#8fbc8f" :foreground (web-mode-colorize-foreground "#8fbc8f"))))
   7188      ((string= str "darkslateblue") (setq plist (list :background "#483d8b" :foreground (web-mode-colorize-foreground "#483d8b"))))
   7189      ((string= str "darkslategray") (setq plist (list :background "#2f4f4f" :foreground (web-mode-colorize-foreground "#2f4f4f"))))
   7190      ((string= str "darkslategrey") (setq plist (list :background "#2f4f4f" :foreground (web-mode-colorize-foreground "#2f4f4f"))))
   7191      ((string= str "darkturquoise") (setq plist (list :background "#00ced1" :foreground (web-mode-colorize-foreground "#00ced1"))))
   7192      ((string= str "darkviolet") (setq plist (list :background "#9400d3" :foreground (web-mode-colorize-foreground "#9400d3"))))
   7193      ((string= str "deeppink") (setq plist (list :background "#ff1493" :foreground (web-mode-colorize-foreground "#ff1493"))))
   7194      ((string= str "deepskyblue") (setq plist (list :background "#00bfff" :foreground (web-mode-colorize-foreground "#00bfff"))))
   7195      ((string= str "dimgray") (setq plist (list :background "#696969" :foreground (web-mode-colorize-foreground "#696969"))))
   7196      ((string= str "dimgrey") (setq plist (list :background "#696969" :foreground (web-mode-colorize-foreground "#696969"))))
   7197      ((string= str "dodgerblue") (setq plist (list :background "#1e90ff" :foreground (web-mode-colorize-foreground "#1e90ff"))))
   7198      ((string= str "firebrick") (setq plist (list :background "#b22222" :foreground (web-mode-colorize-foreground "#b22222"))))
   7199      ((string= str "floralwhite") (setq plist (list :background "#fffaf0" :foreground (web-mode-colorize-foreground "#fffaf0"))))
   7200      ((string= str "forestgreen") (setq plist (list :background "#228b22" :foreground (web-mode-colorize-foreground "#228b22"))))
   7201      ((string= str "gainsboro") (setq plist (list :background "#dcdcdc" :foreground (web-mode-colorize-foreground "#dcdcdc"))))
   7202      ((string= str "ghostwhite") (setq plist (list :background "#f8f8ff" :foreground (web-mode-colorize-foreground "#f8f8ff"))))
   7203      ((string= str "gold") (setq plist (list :background "#ffd700" :foreground (web-mode-colorize-foreground "#ffd700"))))
   7204      ((string= str "goldenrod") (setq plist (list :background "#daa520" :foreground (web-mode-colorize-foreground "#daa520"))))
   7205      ((string= str "greenyellow") (setq plist (list :background "#adff2f" :foreground (web-mode-colorize-foreground "#adff2f"))))
   7206      ((string= str "grey") (setq plist (list :background "#808080" :foreground (web-mode-colorize-foreground "#808080"))))
   7207      ((string= str "honeydew") (setq plist (list :background "#f0fff0" :foreground (web-mode-colorize-foreground "#f0fff0"))))
   7208      ((string= str "hotpink") (setq plist (list :background "#ff69b4" :foreground (web-mode-colorize-foreground "#ff69b4"))))
   7209      ((string= str "indianred") (setq plist (list :background "#cd5c5c" :foreground (web-mode-colorize-foreground "#cd5c5c"))))
   7210      ((string= str "indigo") (setq plist (list :background "#4b0082" :foreground (web-mode-colorize-foreground "#4b0082"))))
   7211      ((string= str "ivory") (setq plist (list :background "#fffff0" :foreground (web-mode-colorize-foreground "#fffff0"))))
   7212      ((string= str "khaki") (setq plist (list :background "#f0e68c" :foreground (web-mode-colorize-foreground "#f0e68c"))))
   7213      ((string= str "lavender") (setq plist (list :background "#e6e6fa" :foreground (web-mode-colorize-foreground "#e6e6fa"))))
   7214      ((string= str "lavenderblush") (setq plist (list :background "#fff0f5" :foreground (web-mode-colorize-foreground "#fff0f5"))))
   7215      ((string= str "lawngreen") (setq plist (list :background "#7cfc00" :foreground (web-mode-colorize-foreground "#7cfc00"))))
   7216      ((string= str "lemonchiffon") (setq plist (list :background "#fffacd" :foreground (web-mode-colorize-foreground "#fffacd"))))
   7217      ((string= str "lightblue") (setq plist (list :background "#add8e6" :foreground (web-mode-colorize-foreground "#add8e6"))))
   7218      ((string= str "lightcoral") (setq plist (list :background "#f08080" :foreground (web-mode-colorize-foreground "#f08080"))))
   7219      ((string= str "lightcyan") (setq plist (list :background "#e0ffff" :foreground (web-mode-colorize-foreground "#e0ffff"))))
   7220      ((string= str "lightgoldenrodyellow") (setq plist (list :background "#fafad2" :foreground (web-mode-colorize-foreground "#fafad2"))))
   7221      ((string= str "lightgray") (setq plist (list :background "#d3d3d3" :foreground (web-mode-colorize-foreground "#d3d3d3"))))
   7222      ((string= str "lightgreen") (setq plist (list :background "#90ee90" :foreground (web-mode-colorize-foreground "#90ee90"))))
   7223      ((string= str "lightgrey") (setq plist (list :background "#d3d3d3" :foreground (web-mode-colorize-foreground "#d3d3d3"))))
   7224      ((string= str "lightpink") (setq plist (list :background "#ffb6c1" :foreground (web-mode-colorize-foreground "#ffb6c1"))))
   7225      ((string= str "lightsalmon") (setq plist (list :background "#ffa07a" :foreground (web-mode-colorize-foreground "#ffa07a"))))
   7226      ((string= str "lightseagreen") (setq plist (list :background "#20b2aa" :foreground (web-mode-colorize-foreground "#20b2aa"))))
   7227      ((string= str "lightskyblue") (setq plist (list :background "#87cefa" :foreground (web-mode-colorize-foreground "#87cefa"))))
   7228      ((string= str "lightslategray") (setq plist (list :background "#778899" :foreground (web-mode-colorize-foreground "#778899"))))
   7229      ((string= str "lightslategrey") (setq plist (list :background "#778899" :foreground (web-mode-colorize-foreground "#778899"))))
   7230      ((string= str "lightsteelblue") (setq plist (list :background "#b0c4de" :foreground (web-mode-colorize-foreground "#b0c4de"))))
   7231      ((string= str "lightyellow") (setq plist (list :background "#ffffe0" :foreground (web-mode-colorize-foreground "#ffffe0"))))
   7232      ((string= str "limegreen") (setq plist (list :background "#32cd32" :foreground (web-mode-colorize-foreground "#32cd32"))))
   7233      ((string= str "linen") (setq plist (list :background "#faf0e6" :foreground (web-mode-colorize-foreground "#faf0e6"))))
   7234      ((string= str "magenta") (setq plist (list :background "#ff00ff" :foreground (web-mode-colorize-foreground "#ff00ff"))))
   7235      ((string= str "mediumaquamarine") (setq plist (list :background "#66cdaa" :foreground (web-mode-colorize-foreground "#66cdaa"))))
   7236      ((string= str "mediumblue") (setq plist (list :background "#0000cd" :foreground (web-mode-colorize-foreground "#0000cd"))))
   7237      ((string= str "mediumorchid") (setq plist (list :background "#ba55d3" :foreground (web-mode-colorize-foreground "#ba55d3"))))
   7238      ((string= str "mediumpurple") (setq plist (list :background "#9370db" :foreground (web-mode-colorize-foreground "#9370db"))))
   7239      ((string= str "mediumseagreen") (setq plist (list :background "#3cb371" :foreground (web-mode-colorize-foreground "#3cb371"))))
   7240      ((string= str "mediumslateblue") (setq plist (list :background "#7b68ee" :foreground (web-mode-colorize-foreground "#7b68ee"))))
   7241      ((string= str "mediumspringgreen") (setq plist (list :background "#00fa9a" :foreground (web-mode-colorize-foreground "#00fa9a"))))
   7242      ((string= str "mediumturquoise") (setq plist (list :background "#48d1cc" :foreground (web-mode-colorize-foreground "#48d1cc"))))
   7243      ((string= str "mediumvioletred") (setq plist (list :background "#c71585" :foreground (web-mode-colorize-foreground "#c71585"))))
   7244      ((string= str "midnightblue") (setq plist (list :background "#191970" :foreground (web-mode-colorize-foreground "#191970"))))
   7245      ((string= str "mintcream") (setq plist (list :background "#f5fffa" :foreground (web-mode-colorize-foreground "#f5fffa"))))
   7246      ((string= str "mistyrose") (setq plist (list :background "#ffe4e1" :foreground (web-mode-colorize-foreground "#ffe4e1"))))
   7247      ((string= str "moccasin") (setq plist (list :background "#ffe4b5" :foreground (web-mode-colorize-foreground "#ffe4b5"))))
   7248      ((string= str "navajowhite") (setq plist (list :background "#ffdead" :foreground (web-mode-colorize-foreground "#ffdead"))))
   7249      ((string= str "oldlace") (setq plist (list :background "#fdf5e6" :foreground (web-mode-colorize-foreground "#fdf5e6"))))
   7250      ((string= str "olivedrab") (setq plist (list :background "#6b8e23" :foreground (web-mode-colorize-foreground "#6b8e23"))))
   7251      ((string= str "orangered") (setq plist (list :background "#ff4500" :foreground (web-mode-colorize-foreground "#ff4500"))))
   7252      ((string= str "orchid") (setq plist (list :background "#da70d6" :foreground (web-mode-colorize-foreground "#da70d6"))))
   7253      ((string= str "palegoldenrod") (setq plist (list :background "#eee8aa" :foreground (web-mode-colorize-foreground "#eee8aa"))))
   7254      ((string= str "palegreen") (setq plist (list :background "#98fb98" :foreground (web-mode-colorize-foreground "#98fb98"))))
   7255      ((string= str "paleturquoise") (setq plist (list :background "#afeeee" :foreground (web-mode-colorize-foreground "#afeeee"))))
   7256      ((string= str "palevioletred") (setq plist (list :background "#db7093" :foreground (web-mode-colorize-foreground "#db7093"))))
   7257      ((string= str "papayawhip") (setq plist (list :background "#ffefd5" :foreground (web-mode-colorize-foreground "#ffefd5"))))
   7258      ((string= str "peachpuff") (setq plist (list :background "#ffdab9" :foreground (web-mode-colorize-foreground "#ffdab9"))))
   7259      ((string= str "peru") (setq plist (list :background "#cd853f" :foreground (web-mode-colorize-foreground "#cd853f"))))
   7260      ((string= str "pink") (setq plist (list :background "#ffc0cb" :foreground (web-mode-colorize-foreground "#ffc0cb"))))
   7261      ((string= str "plum") (setq plist (list :background "#dda0dd" :foreground (web-mode-colorize-foreground "#dda0dd"))))
   7262      ((string= str "powderblue") (setq plist (list :background "#b0e0e6" :foreground (web-mode-colorize-foreground "#b0e0e6"))))
   7263      ((string= str "rosybrown") (setq plist (list :background "#bc8f8f" :foreground (web-mode-colorize-foreground "#bc8f8f"))))
   7264      ((string= str "royalblue") (setq plist (list :background "#4169e1" :foreground (web-mode-colorize-foreground "#4169e1"))))
   7265      ((string= str "saddlebrown") (setq plist (list :background "#8b4513" :foreground (web-mode-colorize-foreground "#8b4513"))))
   7266      ((string= str "salmon") (setq plist (list :background "#fa8072" :foreground (web-mode-colorize-foreground "#fa8072"))))
   7267      ((string= str "sandybrown") (setq plist (list :background "#f4a460" :foreground (web-mode-colorize-foreground "#f4a460"))))
   7268      ((string= str "seagreen") (setq plist (list :background "#2e8b57" :foreground (web-mode-colorize-foreground "#2e8b57"))))
   7269      ((string= str "seashell") (setq plist (list :background "#fff5ee" :foreground (web-mode-colorize-foreground "#fff5ee"))))
   7270      ((string= str "sienna") (setq plist (list :background "#a0522d" :foreground (web-mode-colorize-foreground "#a0522d"))))
   7271      ((string= str "skyblue") (setq plist (list :background "#87ceeb" :foreground (web-mode-colorize-foreground "#87ceeb"))))
   7272      ((string= str "slateblue") (setq plist (list :background "#6a5acd" :foreground (web-mode-colorize-foreground "#6a5acd"))))
   7273      ((string= str "slategray") (setq plist (list :background "#708090" :foreground (web-mode-colorize-foreground "#708090"))))
   7274      ((string= str "slategrey") (setq plist (list :background "#708090" :foreground (web-mode-colorize-foreground "#708090"))))
   7275      ((string= str "snow") (setq plist (list :background "#fffafa" :foreground (web-mode-colorize-foreground "#fffafa"))))
   7276      ((string= str "springgreen") (setq plist (list :background "#00ff7f" :foreground (web-mode-colorize-foreground "#00ff7f"))))
   7277      ((string= str "steelblue") (setq plist (list :background "#4682b4" :foreground (web-mode-colorize-foreground "#4682b4"))))
   7278      ((string= str "tan") (setq plist (list :background "#d2b48c" :foreground (web-mode-colorize-foreground "#d2b48c"))))
   7279      ((string= str "thistle") (setq plist (list :background "#d8bfd8" :foreground (web-mode-colorize-foreground "#d8bfd8"))))
   7280      ((string= str "tomato") (setq plist (list :background "#ff6347" :foreground (web-mode-colorize-foreground "#ff6347"))))
   7281      ((string= str "turquoise") (setq plist (list :background "#40e0d0" :foreground (web-mode-colorize-foreground "#40e0d0"))))
   7282      ((string= str "violet") (setq plist (list :background "#ee82ee" :foreground (web-mode-colorize-foreground "#ee82ee"))))
   7283      ((string= str "wheat") (setq plist (list :background "#f5deb3" :foreground (web-mode-colorize-foreground "#f5deb3"))))
   7284      ((string= str "whitesmoke") (setq plist (list :background "#f5f5f5" :foreground (web-mode-colorize-foreground "#f5f5f5"))))
   7285      ((string= str "yellowgreen") (setq plist (list :background "#9acd32" :foreground (web-mode-colorize-foreground "#9acd32"))))
   7286      ) ;cond
   7287     (put-text-property beg end 'face plist)
   7288     ))
   7289 
   7290 (defun web-mode-interpolate-block-tag (beg end)
   7291   (save-excursion
   7292     (goto-char (+ 4 beg))
   7293     (setq end (1- end))
   7294     (while (re-search-forward "${.*?}" end t)
   7295       (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(face))
   7296       (web-mode-fontify-region (match-beginning 0) (match-end 0)
   7297                                web-mode-uel-font-lock-keywords))
   7298     ))
   7299 
   7300 (defun web-mode-interpolate-javascript-string (beg end)
   7301   (save-excursion
   7302     (goto-char (1+ beg))
   7303     (setq end (1- end))
   7304     (while (re-search-forward "${.*?}" end t)
   7305       (put-text-property (match-beginning 0) (match-end 0)
   7306                          'font-lock-face
   7307                          'web-mode-variable-name-face)
   7308       )
   7309     ))
   7310 
   7311 (defun web-mode-interpolate-javascript-literal (beg end)
   7312   (save-excursion
   7313     (goto-char (1+ beg))
   7314     (setq end (1- end))
   7315     (while (re-search-forward "${.*?}" end t)
   7316       (put-text-property (match-beginning 0) (match-end 0)
   7317                            'font-lock-face
   7318                            'web-mode-variable-name-face)
   7319       )
   7320     (cond
   7321      ((web-mode-looking-back "\\(css\\|styled[[:alnum:].]+\\)" beg)
   7322       (goto-char (1+ beg))
   7323       (while (re-search-forward ".*?:" end t)
   7324         (put-text-property (match-beginning 0) (match-end 0)
   7325                            'font-lock-face
   7326                            'web-mode-interpolate-color1-face)
   7327         )
   7328       ) ;case css
   7329      ((web-mode-looking-back "\\(template\\|html\\)" beg)
   7330       (goto-char (1+ beg))
   7331       (while (re-search-forward web-mode-tag-regexp end t)
   7332         (put-text-property (match-beginning 1) (match-end 1)
   7333                            'font-lock-face
   7334                            'web-mode-interpolate-color1-face)
   7335         )
   7336       (goto-char (1+ beg))
   7337       (while (re-search-forward "</?\\|/?>\\| [.@?]?[[:alnum:]]+=" end t)
   7338         (cond
   7339          ((member (char-after (match-beginning 0)) '(?\< ?\/ ?\>))
   7340           (put-text-property (match-beginning 0) (match-end 0)
   7341                              'font-lock-face
   7342                              'web-mode-interpolate-color2-face)
   7343           )
   7344          (t
   7345           (put-text-property (1+ (match-beginning 0)) (1- (match-end 0))
   7346                              'font-lock-face
   7347                              'web-mode-interpolate-color3-face)
   7348           ) ;t
   7349          ) ;cond
   7350         ) ;while
   7351       ) ;case html
   7352      ) ;cond type of literal
   7353     ))
   7354 
   7355 ;; todo : parsing plus compliqué: {$obj->values[3]->name}
   7356 (defun web-mode-interpolate-block-string (beg end)
   7357   (save-excursion
   7358     (goto-char (1+ beg))
   7359     (setq end (1- end))
   7360     (cond
   7361      ((string= web-mode-engine "php")
   7362       (while (re-search-forward "$[[:alnum:]_]+\\(->[[:alnum:]_]+\\)*\\|{[ ]*$.+?}" end t)
   7363 ;;        (message "%S > %S" (match-beginning 0) (match-end 0))
   7364         (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(font-lock-face))
   7365         (web-mode-fontify-region (match-beginning 0) (match-end 0)
   7366                                  web-mode-php-var-interpolation-font-lock-keywords)
   7367         ))
   7368      ((string= web-mode-engine "erb")
   7369       (while (re-search-forward "#{.*?}" end t)
   7370         (remove-list-of-text-properties (match-beginning 0) (match-end 0) '(font-lock-face))
   7371         (put-text-property (match-beginning 0) (match-end 0)
   7372                            'font-lock-face 'web-mode-variable-name-face)
   7373         ))
   7374      ) ;cond
   7375     ))
   7376 
   7377 (defun web-mode-interpolate-comment (beg end block-side)
   7378   (save-excursion
   7379     (let ((regexp (concat "\\_<\\(" web-mode-comment-keywords "\\)\\_>")))
   7380       (goto-char beg)
   7381       (while (re-search-forward regexp end t)
   7382         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7383                                          'font-lock-face
   7384                                          'web-mode-comment-keyword-face)
   7385         ) ;while
   7386       )))
   7387 
   7388 (defun web-mode-annotate-comment (beg end)
   7389   (save-excursion
   7390     ;;(message "beg=%S end=%S" beg end)
   7391     (goto-char beg)
   7392     (when (looking-at-p "/\\*\\*")
   7393       (while (re-search-forward "\\(.+\\)" end t)
   7394         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7395                                          'font-lock-face
   7396                                          'web-mode-annotation-face))
   7397       (goto-char beg)
   7398       (while (re-search-forward "[ ]+\\({[^}]+}\\)" end t)
   7399         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7400                                          'font-lock-face
   7401                                          'web-mode-annotation-type-face))
   7402       (goto-char beg)
   7403       (while (re-search-forward "\\(@[[:alnum:]]+\\)" end t)
   7404         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7405                                          'font-lock-face
   7406                                          'web-mode-annotation-tag-face))
   7407       (goto-char beg)
   7408       (while (re-search-forward "}[[:blank:]]+\\([[:graph:]]+\\)" end t)
   7409         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7410                                          'font-lock-face
   7411                                          'web-mode-annotation-value-face))
   7412       (goto-char beg)
   7413       (while (re-search-forward "@see[[:blank:]]+\\([[:graph:]]+\\)" end t)
   7414         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7415                                          'font-lock-face
   7416                                          'web-mode-annotation-value-face))
   7417       (goto-char beg)
   7418       (while (re-search-forward "{\\(@\\(?:link\\|code\\)\\)\\s-+\\([^}\n]+\\)\\(#.+\\)?}" end t)
   7419         (font-lock-prepend-text-property (match-beginning 2) (match-end 2)
   7420                                          'font-lock-face
   7421                                          'web-mode-annotation-value-face))
   7422       (goto-char beg)
   7423       (while (re-search-forward "\\(</?\\)\\([[:alnum:]]+\\)\\s-*\\(/?>\\)" end t)
   7424         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7425                                          'font-lock-face
   7426                                          'web-mode-annotation-html-face)
   7427         (font-lock-prepend-text-property (match-beginning 2) (match-end 2)
   7428                                          'font-lock-face
   7429                                          'web-mode-annotation-html-face)
   7430         (font-lock-prepend-text-property (match-beginning 3) (match-end 3)
   7431                                          'font-lock-face
   7432                                          'web-mode-annotation-html-face))
   7433       ) ;when
   7434     ))
   7435 
   7436 (defun web-mode-interpolate-sql-string (beg end)
   7437   (save-excursion
   7438     (let ((case-fold-search t)
   7439           (regexp (concat "\\_<\\(" web-mode-sql-keywords "\\)\\_>")))
   7440       (goto-char beg)
   7441       (while (re-search-forward regexp end t)
   7442         (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
   7443                                          'font-lock-face
   7444                                          'web-mode-sql-keyword-face)
   7445         ) ;while
   7446       )))
   7447 
   7448 ;;---- EFFECTS -----------------------------------------------------------------
   7449 
   7450 (defun web-mode-fill-paragraph (&optional justify)
   7451   (save-excursion
   7452     (let ((pos (point)) fill-coll
   7453           prop pair beg end delim-beg delim-end chunk fill-col)
   7454       (cond
   7455        ((or (eq (get-text-property pos 'part-token) 'comment)
   7456             (eq (get-text-property pos 'block-token) 'comment))
   7457         (setq prop
   7458               (if (get-text-property pos 'part-token) 'part-token 'block-token))
   7459         (setq pair (web-mode-property-boundaries prop pos))
   7460         (when (and pair (> (- (cdr pair) (car pair)) 6))
   7461           (setq fill-coll (if (< fill-column 10) 70 fill-column))
   7462           (setq beg (car pair)
   7463                 end (cdr pair))
   7464           (goto-char beg)
   7465           (setq chunk (buffer-substring-no-properties beg (+ beg 2)))
   7466           (cond
   7467            ((string= chunk "//")
   7468             (setq delim-beg "//"
   7469                   delim-end "EOL"))
   7470            ((string= chunk "/*")
   7471             (setq delim-beg "/*"
   7472                   delim-end "*/"))
   7473            ((string= chunk "{#")
   7474             (setq delim-beg "{#"
   7475                   delim-end "#}"))
   7476            ((string= chunk "<!")
   7477             (setq delim-beg "<!--"
   7478                   delim-end "-->"))
   7479            )
   7480           )
   7481         ) ;comment - case
   7482        ((web-mode-is-content)
   7483         (setq pair (web-mode-content-boundaries pos))
   7484         (setq beg (car pair)
   7485               end (cdr pair))
   7486         )
   7487        ) ;cond
   7488       ;;(message "beg(%S) end(%S)" beg end)
   7489       (when (and beg end)
   7490         (fill-region beg end))
   7491       t)))
   7492 
   7493 (defun web-mode-engine-syntax-check ()
   7494   (interactive)
   7495   (let ((proc nil) (errors nil)
   7496         (file (concat temporary-file-directory "emacs-web-mode-tmp")))
   7497     (write-region (point-min) (point-max) file)
   7498     (cond
   7499      ;; ((null (buffer-file-name))
   7500      ;; )
   7501      ((string= web-mode-engine "php")
   7502       (setq proc (start-process "php-proc" nil "php" "-l" file))
   7503       (set-process-filter
   7504        proc
   7505        (lambda (proc output)
   7506          (cond
   7507           ((string-match-p "No syntax errors" output)
   7508            (message "No syntax errors")
   7509            )
   7510           (t
   7511            ;; (setq output (replace-regexp-in-string temporary-file-directory "" output))
   7512            ;; (message output)
   7513            (message "Syntax error")
   7514            (setq errors t))
   7515           ) ;cond
   7516          ;; (delete-file file)
   7517          ) ;lambda
   7518        )
   7519       ) ;php
   7520      (t
   7521       (message "no syntax checker found")
   7522       ) ;t
   7523      ) ;cond
   7524     errors))
   7525 
   7526 (defun web-mode-jshint ()
   7527   "Run JSHint on all the JavaScript parts."
   7528   (interactive)
   7529   (let (proc lines)
   7530     (when (buffer-file-name)
   7531       (setq proc (start-process
   7532                   "jshint-proc"
   7533                   nil
   7534                   (or (executable-find "jshint") "/usr/local/bin/jshint")
   7535                   "--extract=auto"
   7536                   (buffer-file-name)))
   7537       (setq web-mode-jshint-errors 0)
   7538       (set-process-filter proc
   7539                           (lambda (proc output)
   7540                             (let ((offset 0) overlay pos (old 0) msg)
   7541                               (remove-overlays (point-min) (point-max) 'font-lock-face 'web-mode-error-face)
   7542                               (while (string-match
   7543                                       "line \\([[:digit:]]+\\), col \\([[:digit:]]+\\), \\(.+\\)\\.$"
   7544                                       output offset)
   7545                                 (setq web-mode-jshint-errors (1+ web-mode-jshint-errors))
   7546                                 (setq offset (match-end 0))
   7547                                 (setq pos (web-mode-coord-position
   7548                                            (match-string-no-properties 1 output)
   7549                                            (match-string-no-properties 2 output)))
   7550                                 (when (get-text-property pos 'tag-beg)
   7551                                   (setq pos (1- pos)))
   7552                                 (when (not (= pos old))
   7553                                   (setq old pos)
   7554                                   (setq overlay (make-overlay pos (1+ pos)))
   7555                                   (overlay-put overlay 'font-lock-face 'web-mode-error-face)
   7556                                   )
   7557                                 (setq msg (or (overlay-get overlay 'help-echo)
   7558                                                (concat "line="
   7559                                                        (match-string-no-properties 1 output)
   7560                                                        " column="
   7561                                                        (match-string-no-properties 2 output)
   7562                                                        )))
   7563                                 (overlay-put overlay 'help-echo
   7564                                              (concat msg " ## " (match-string-no-properties 3 output)))
   7565                                 ) ;while
   7566                               ))
   7567                           )
   7568       ) ;when
   7569     ))
   7570 
   7571 (defun web-mode-dom-errors-show ()
   7572   "Show unclosed tags."
   7573   (interactive)
   7574   (let (beg end tag pos l n tags i cont cell overlay overlays first
   7575             (ori (point))
   7576             (errors 0)
   7577             (continue t)
   7578         )
   7579     (setq overlays (overlays-in (point-min) (point-max)))
   7580     (when overlays
   7581       (dolist (overlay overlays)
   7582         (when (eq (overlay-get overlay 'face) 'web-mode-warning-face)
   7583           (delete-overlay overlay)
   7584           )
   7585         )
   7586       )
   7587     (goto-char (point-min))
   7588     (when (not (or (get-text-property (point) 'tag-beg)
   7589                    (web-mode-tag-next)))
   7590       (setq continue nil))
   7591     (while continue
   7592       (setq pos (point))
   7593       (setq tag (get-text-property pos 'tag-name))
   7594       (cond
   7595        ((eq (get-text-property (point) 'tag-type) 'start)
   7596         (setq tags (push (list tag pos) tags))
   7597 ;;        (message "(%S) opening %S" pos tag)
   7598         )
   7599        ((eq (get-text-property (point) 'tag-type) 'end)
   7600         (setq i 0
   7601               l (length tags)
   7602               cont t)
   7603         (while (and (< i l) cont)
   7604           (setq cell (nth i tags))
   7605 ;;          (message "cell=%S" cell)
   7606           (setq i (1+ i))
   7607           (cond
   7608            ((string= tag (nth 0 cell))
   7609             (setq cont nil)
   7610             )
   7611            (t
   7612             (setq errors (1+ errors))
   7613             (setq beg (nth 1 cell))
   7614             (setq end (web-mode-tag-end-position beg))
   7615             (unless first
   7616               (setq first beg))
   7617             (setq overlay (make-overlay beg (1+ end)))
   7618             (overlay-put overlay 'font-lock-face 'web-mode-warning-face)
   7619 ;;            (message "invalid <%S> at %S" (nth 0 cell) (nth 1 cell))
   7620             )
   7621            ) ;cond
   7622           ) ;while
   7623 
   7624         (dotimes (i i)
   7625           (setq tags (cdr tags)))
   7626 
   7627         )
   7628        ) ;cond
   7629       (when (not (web-mode-tag-next))
   7630         (setq continue nil))
   7631       ) ;while
   7632     (message "%S error(s) detected" errors)
   7633     (if (< errors 1)
   7634         (goto-char ori)
   7635       (goto-char first)
   7636       (recenter))
   7637     ;;    (message "%S" tags)
   7638     ))
   7639 
   7640 (defun web-mode-fontify-elements (beg end)
   7641   (save-excursion
   7642     (goto-char beg)
   7643     (let ((continue (or (get-text-property (point) 'tag-beg) (web-mode-tag-next)))
   7644           (i 0) (ctx nil) (face nil))
   7645       (while continue
   7646         (cond
   7647          ((> (setq i (1+ i)) 1000)
   7648           (message "fontify-elements ** too much tags **")
   7649           (setq continue nil))
   7650          ((> (point) end)
   7651           (setq continue nil))
   7652          ((not (get-text-property (point) 'tag-beg))
   7653           (setq continue nil))
   7654          ((eq (get-text-property (point) 'tag-type) 'start)
   7655           (when (and (setq ctx (web-mode-element-boundaries (point)))
   7656                      (<= (car (cdr ctx)) end)
   7657                      (setq face (cdr (assoc (get-text-property (point) 'tag-name) web-mode-element-content-faces))))
   7658             (font-lock-prepend-text-property (1+ (cdr (car ctx))) (car (cdr ctx))
   7659                                              'font-lock-face face))
   7660           )
   7661          ) ;cond
   7662         (when (not (web-mode-tag-next))
   7663           (setq continue nil))
   7664         ) ;while
   7665       )))
   7666 
   7667 (defun web-mode-enable (feature)
   7668   "Enable one feature."
   7669   (interactive
   7670    (list (completing-read
   7671           "Feature: "
   7672           (let (features)
   7673             (dolist (elt web-mode-features)
   7674               (setq features (append features (list (car elt)))))
   7675             features))))
   7676   (when (and (or (not feature) (< (length feature) 1)) web-mode-last-enabled-feature)
   7677     (setq feature web-mode-last-enabled-feature))
   7678   (when feature
   7679     (setq web-mode-last-enabled-feature feature)
   7680     (setq feature (cdr (assoc feature web-mode-features)))
   7681     (cond
   7682      ((eq feature 'web-mode-enable-current-column-highlight)
   7683       (web-mode-column-show))
   7684      ((eq feature 'web-mode-enable-current-element-highlight)
   7685       (when (not web-mode-enable-current-element-highlight)
   7686         (web-mode-toggle-current-element-highlight))
   7687       )
   7688      ((eq feature 'web-mode-enable-whitespace-fontification)
   7689       (web-mode-whitespaces-on))
   7690      (t
   7691       (set feature t)
   7692       (web-mode-buffer-fontify))
   7693      )
   7694     ) ;when
   7695   )
   7696 
   7697 (defun web-mode-disable (feature)
   7698   "Disable one feature."
   7699   (interactive
   7700    (list (completing-read
   7701           "Feature: "
   7702           (let (features)
   7703             (dolist (elt web-mode-features)
   7704               (setq features (append features (list (car elt)))))
   7705             features))))
   7706   (when (and (or (not feature) (< (length feature) 1)) web-mode-last-enabled-feature)
   7707     (setq feature web-mode-last-enabled-feature))
   7708   (when feature
   7709     (setq feature (cdr (assoc feature web-mode-features)))
   7710     (cond
   7711      ((eq feature 'web-mode-enable-current-column-highlight)
   7712       (web-mode-column-hide))
   7713      ((eq feature 'web-mode-enable-current-element-highlight)
   7714       (when web-mode-enable-current-element-highlight
   7715         (web-mode-toggle-current-element-highlight))
   7716       )
   7717      ((eq feature 'web-mode-enable-whitespace-fontification)
   7718       (web-mode-whitespaces-off))
   7719      (t
   7720       (set feature nil)
   7721       (web-mode-buffer-fontify))
   7722      )
   7723     ) ;when
   7724   )
   7725 
   7726 (defun web-mode-toggle-current-element-highlight ()
   7727   "Toggle highlighting of the current html element."
   7728   (interactive)
   7729   (if web-mode-enable-current-element-highlight
   7730       (progn
   7731         (web-mode-delete-tag-overlays)
   7732         (setq web-mode-enable-current-element-highlight nil))
   7733     (setq web-mode-enable-current-element-highlight t)
   7734     ))
   7735 
   7736 (defun web-mode-make-tag-overlays ()
   7737   (unless web-mode-overlay-tag-start
   7738     (setq web-mode-overlay-tag-start (make-overlay 1 1)
   7739           web-mode-overlay-tag-end (make-overlay 1 1))
   7740     (overlay-put web-mode-overlay-tag-start
   7741                  'font-lock-face
   7742                  'web-mode-current-element-highlight-face)
   7743     (overlay-put web-mode-overlay-tag-end
   7744                  'font-lock-face
   7745                  'web-mode-current-element-highlight-face)))
   7746 
   7747 (defun web-mode-delete-tag-overlays ()
   7748   (when web-mode-overlay-tag-start
   7749     (delete-overlay web-mode-overlay-tag-start)
   7750     (delete-overlay web-mode-overlay-tag-end)))
   7751 
   7752 (defun web-mode-column-overlay-factory (index)
   7753   (let (overlay)
   7754     (when (null web-mode-column-overlays)
   7755       (dotimes (i 100)
   7756         (setq overlay (make-overlay 1 1))
   7757         (overlay-put overlay 'font-lock-face 'web-mode-current-column-highlight-face)
   7758         (setq web-mode-column-overlays (append web-mode-column-overlays (list overlay)))
   7759         )
   7760       ) ;when
   7761     (setq overlay (nth index web-mode-column-overlays))
   7762     (when (null overlay)
   7763       (setq overlay (make-overlay 1 1))
   7764       (overlay-put overlay 'font-lock-face 'web-mode-current-column-highlight-face)
   7765       (setq web-mode-column-overlays (append web-mode-column-overlays (list overlay)))
   7766       ) ;when
   7767     overlay))
   7768 
   7769 (defun web-mode-column-hide ()
   7770   (setq web-mode-enable-current-column-highlight nil)
   7771   (remove-overlays (point-min) (point-max)
   7772                    'font-lock-face
   7773                    'web-mode-current-column-highlight-face))
   7774 
   7775 (defun web-mode-column-show ()
   7776   (let ((index 0) overlay diff column line-to line-from)
   7777     (web-mode-column-hide)
   7778     (setq web-mode-enable-current-column-highlight t)
   7779     (save-excursion
   7780       (back-to-indentation)
   7781       (setq column (current-column)
   7782             line-to (web-mode-line-number))
   7783       (when (and (get-text-property (point) 'tag-beg)
   7784                  (member (get-text-property (point) 'tag-type) '(start end))
   7785                  (web-mode-tag-match)
   7786                  (setq line-from (web-mode-line-number))
   7787                  (not (= line-from line-to)))
   7788         (when (> line-from line-to)
   7789           (let (tmp)
   7790             (setq tmp line-from)
   7791             (setq line-from line-to)
   7792             (setq line-to tmp))
   7793           ) ;when
   7794         ;;(message "column(%S) line-from(%S) line-to(%S)" column line-from line-to)
   7795         (goto-char (point-min))
   7796         (when (> line-from 1)
   7797           (forward-line (1- line-from)))
   7798         (while (<= line-from line-to)
   7799           (setq overlay (web-mode-column-overlay-factory index))
   7800           (setq diff (- (line-end-position) (point)))
   7801           (cond
   7802            ((or (and (= column 0) (= diff 0))
   7803                 (> column diff))
   7804             (end-of-line)
   7805             (move-overlay overlay (point) (point))
   7806             (overlay-put overlay
   7807                          'after-string
   7808                          (concat
   7809                           (if (> column diff) (make-string (- column diff) ?\s) "")
   7810                           (propertize " "
   7811                                       'font-lock-face
   7812                                       'web-mode-current-column-highlight-face)
   7813                           ) ;concat
   7814                          )
   7815             )
   7816            (t
   7817             (move-to-column column)
   7818             (overlay-put overlay 'after-string nil)
   7819             (move-overlay overlay (point) (1+ (point)))
   7820             )
   7821            ) ;cond
   7822           (setq line-from (1+ line-from))
   7823           (forward-line)
   7824           (setq index (1+ index))
   7825           ) ;while
   7826         ) ;when
   7827       ) ;save-excursion
   7828     ) ;let
   7829   )
   7830 
   7831 (defun web-mode-highlight-current-element ()
   7832   (let ((ctx (web-mode-element-boundaries)) len)
   7833     (cond
   7834      ((null ctx)
   7835       (web-mode-delete-tag-overlays))
   7836      ((eq (get-text-property (caar ctx) 'tag-type) 'void) ;; #1046
   7837       (web-mode-make-tag-overlays)
   7838       (setq len (length (get-text-property (caar ctx) 'tag-name)))
   7839       (move-overlay web-mode-overlay-tag-start (+ (caar ctx) 1) (+ (caar ctx) 1 len))
   7840       )
   7841      (t
   7842       (web-mode-make-tag-overlays)
   7843       (setq len (length (get-text-property (caar ctx) 'tag-name)))
   7844       (move-overlay web-mode-overlay-tag-start (+ (caar ctx) 1) (+ (caar ctx) 1 len))
   7845       (move-overlay web-mode-overlay-tag-end (+ (cadr ctx) 2) (+ (cadr ctx) 2 len))
   7846       ) ;t
   7847      ) ;cond
   7848     ))
   7849 
   7850 (defun web-mode-fontify-whitespaces (beg end)
   7851   (save-excursion
   7852     (goto-char beg)
   7853     (while (re-search-forward web-mode-whitespaces-regexp end t)
   7854       (add-text-properties (match-beginning 0) (match-end 0)
   7855                            '(face web-mode-whitespace-face))
   7856       ) ;while
   7857     ))
   7858 
   7859 (defun web-mode-whitespaces-show ()
   7860   "Toggle whitespaces."
   7861   (interactive)
   7862   (if web-mode-enable-whitespace-fontification
   7863       (web-mode-whitespaces-off)
   7864     (web-mode-whitespaces-on)))
   7865 
   7866 (defun web-mode-whitespaces-on ()
   7867   "Show whitespaces."
   7868   (interactive)
   7869   (when web-mode-display-table
   7870     (setq buffer-display-table web-mode-display-table))
   7871   (setq web-mode-enable-whitespace-fontification t))
   7872 
   7873 (defun web-mode-whitespaces-off ()
   7874   (setq buffer-display-table nil)
   7875   (setq web-mode-enable-whitespace-fontification nil))
   7876 
   7877 (defun web-mode-use-tabs ()
   7878   "Tweaks vars to be compatible with TAB indentation."
   7879   (let (offset)
   7880     (setq web-mode-block-padding 0)
   7881     (setq web-mode-script-padding 0)
   7882     (setq web-mode-style-padding 0)
   7883     (setq offset
   7884           (cond
   7885            ((and (boundp 'tab-width) tab-width) tab-width)
   7886            ((and (boundp 'standard-indent) standard-indent) standard-indent)
   7887            (t 4)))
   7888     ;;    (message "offset(%S)" offset)
   7889     (setq web-mode-attr-indent-offset offset)
   7890     (setq web-mode-code-indent-offset offset)
   7891     (setq web-mode-css-indent-offset offset)
   7892     (setq web-mode-markup-indent-offset offset)
   7893     (setq web-mode-sql-indent-offset offset)
   7894     (add-to-list 'web-mode-indentation-params '("lineup-args" . nil))
   7895     (add-to-list 'web-mode-indentation-params '("lineup-calls" . nil))
   7896     (add-to-list 'web-mode-indentation-params '("lineup-concats" . nil))
   7897     (add-to-list 'web-mode-indentation-params '("lineup-ternary" . nil))
   7898     ))
   7899 
   7900 (defun web-mode-element-children-fold-or-unfold (&optional pos)
   7901   "Fold/Unfold all the children of the current html element."
   7902   (interactive)
   7903   (unless pos (setq pos (point)))
   7904   (save-excursion
   7905     (dolist (child (reverse (web-mode-element-children pos)))
   7906       (goto-char child)
   7907       (web-mode-fold-or-unfold))
   7908     ))
   7909 
   7910 (defun web-mode-fold-or-unfold (&optional pos)
   7911   "Toggle folding on an html element or a control block."
   7912   (interactive)
   7913   (web-mode-scan)
   7914   (web-mode-with-silent-modifications
   7915    (save-excursion
   7916      (if pos (goto-char pos))
   7917      (let (beg-inside beg-outside end-inside end-outside overlay overlays regexp)
   7918        (when (looking-back "^[\t ]*" (point-min))
   7919          (back-to-indentation))
   7920        (setq overlays (overlays-at (point)))
   7921        (dolist (elt overlays)
   7922          (when (and (not overlay)
   7923                     (eq (overlay-get elt 'font-lock-face) 'web-mode-folded-face))
   7924            (setq overlay elt)))
   7925        (cond
   7926         ;; *** unfolding
   7927         (overlay
   7928          (setq beg-inside (overlay-start overlay)
   7929                end-inside (overlay-end overlay))
   7930          (remove-overlays beg-inside end-inside)
   7931          (put-text-property beg-inside end-inside 'invisible nil)
   7932          )
   7933         ;; *** block folding
   7934         ((and (get-text-property (point) 'block-side)
   7935               (cdr (web-mode-block-is-control (point))))
   7936          (setq beg-outside (web-mode-block-beginning-position (point)))
   7937          (setq beg-inside (1+ (web-mode-block-end-position (point))))
   7938          (when (web-mode-block-match)
   7939            (setq end-inside (point))
   7940            (setq end-outside (1+ (web-mode-block-end-position (point)))))
   7941          )
   7942         ;; *** html comment folding
   7943         ((eq (get-text-property (point) 'tag-type) 'comment)
   7944          (setq beg-outside (web-mode-tag-beginning-position))
   7945          (setq beg-inside (+ beg-outside 4))
   7946          (setq end-outside (web-mode-tag-end-position))
   7947          (setq end-inside (- end-outside 3))
   7948          )
   7949         ;; *** tag folding
   7950         ((or (member (get-text-property (point) 'tag-type) '(start end))
   7951              (web-mode-element-parent))
   7952          (when (not (web-mode-element-is-collapsed (point)))
   7953            (web-mode-tag-beginning)
   7954            (when (eq (get-text-property (point) 'tag-type) 'end)
   7955              (web-mode-tag-match))
   7956            (setq beg-outside (point))
   7957            (web-mode-tag-end)
   7958            (setq beg-inside (point))
   7959            (goto-char beg-outside)
   7960            (when (web-mode-tag-match)
   7961              (setq end-inside (point))
   7962              (web-mode-tag-end)
   7963              (setq end-outside (point)))
   7964            )
   7965          )
   7966         ) ;cond
   7967        (when (and beg-inside beg-outside end-inside end-outside)
   7968          (setq overlay (make-overlay beg-outside end-outside))
   7969          (overlay-put overlay 'font-lock-face 'web-mode-folded-face)
   7970          (put-text-property beg-inside end-inside 'invisible t))
   7971        ))))
   7972 
   7973 ;;---- TRANSFORMATION ----------------------------------------------------------
   7974 
   7975 (defun web-mode-buffer-change-tag-case (&optional type)
   7976   "Change html tag case."
   7977   (interactive)
   7978   (save-excursion
   7979     (goto-char (point-min))
   7980     (let ((continue t) f)
   7981       (setq f (if (member type '("upper" "uppercase" "upper-case")) 'uppercase 'downcase))
   7982       (when (and (not (get-text-property (point) 'tag-beg))
   7983                  (not (web-mode-tag-next)))
   7984         (setq continue nil))
   7985       (while continue
   7986         (skip-chars-forward "<!/")
   7987         (if (looking-at "\\([[:alnum:]:-]+\\)")
   7988             (replace-match (funcall f (match-string 0)) t))
   7989 ;;        (message "tag: %S (%S)"
   7990 ;;                 (get-text-property (point) 'tag-name)
   7991 ;;                 (point))
   7992         (unless (web-mode-tag-next)
   7993           (setq continue nil))
   7994         ) ;while
   7995       )))
   7996 
   7997 (defun web-mode-buffer-change-attr-case (&optional type)
   7998   "Change case of html attribute names."
   7999   (interactive)
   8000   (unless type (setq type "downcase"))
   8001   (save-excursion
   8002     (goto-char (point-min))
   8003     (let ((continue t)
   8004           (fun (if (eq (aref (downcase type) 0) ?u) 'uppercase 'downcase)))
   8005       (while continue
   8006         (cond
   8007          ((not (web-mode-attribute-next))
   8008           (setq continue nil))
   8009          ((looking-at "\\([[:alnum:]-]+\\)")
   8010           (replace-match (funcall fun (match-string 0)) t)
   8011           )
   8012          ) ;cond
   8013         ) ;while
   8014       )))
   8015 
   8016 ;; tag-case=lower|upper-case , attr-case=lower|upper-case
   8017 ;; special-chars=unicode|html-entities
   8018 ;; smart-apostrophes=bool , smart-quotes=bool , indentation=bool
   8019 (defun web-mode-dom-normalize ()
   8020   "Normalize buffer"
   8021   (interactive)
   8022   (save-excursion
   8023     (let ((rules web-mode-normalization-rules) elt)
   8024       (when (setq elt (cdr (assoc "tag-case" rules)))
   8025         (web-mode-buffer-change-tag-case elt))
   8026       (when (setq elt (cdr (assoc "attr-case" rules)))
   8027         (web-mode-buffer-change-attr-case elt))
   8028       (when (setq elt (cdr (assoc "css-indentation" rules)))
   8029         (web-mode-css-indent))
   8030       (when (setq elt (cdr (assoc "smart-apostrophes" rules)))
   8031         (web-mode-dom-apostrophes-replace))
   8032       (when (setq elt (cdr (assoc "smart-quotes" rules)))
   8033         (web-mode-dom-quotes-replace))
   8034       (when (setq elt (cdr (assoc "special-chars" rules)))
   8035         (if (string= elt "entities")
   8036             (web-mode-dom-entities-encode)
   8037           (web-mode-dom-entities-replace)))
   8038       (when (setq elt (cdr (assoc "whitespaces" rules)))
   8039         (goto-char (point-min))
   8040         (while (not (eobp))
   8041           (forward-line)
   8042           (delete-blank-lines))
   8043         (delete-trailing-whitespace)
   8044         (untabify (point-min) (point-max)))
   8045       (when (setq elt (cdr (assoc "indentation" rules)))
   8046         (web-mode-buffer-indent))
   8047       )))
   8048 
   8049 (defun web-mode-dom-apostrophes-replace ()
   8050   "Replace char(') with char(’) in the innerText of html elements."
   8051   (interactive)
   8052   (save-excursion
   8053     (let ((min (point-min)) (max (point-max)))
   8054       (when mark-active
   8055         (setq min (region-beginning)
   8056               max (region-end))
   8057         (deactivate-mark))
   8058       (goto-char min)
   8059       (while (web-mode-content-rsf "\\([[:alpha:]]\\)'\\([[:alpha:]]\\)" max)
   8060         (replace-match "\\1’\\2"))
   8061       )))
   8062 
   8063 (defun web-mode-dom-entities-encode ()
   8064   (save-excursion
   8065     (let (regexp ms elt (min (point-min)) (max (point-max)))
   8066       (when mark-active
   8067         (setq min (region-beginning)
   8068               max (region-end))
   8069         (deactivate-mark))
   8070       (goto-char min)
   8071       (setq regexp "[")
   8072       (dolist (pair web-mode-html-entities)
   8073         (setq regexp (concat regexp (char-to-string (cdr pair))))
   8074         )
   8075       (setq regexp (concat regexp "]"))
   8076       (while (web-mode-content-rsf regexp max)
   8077         (setq elt (match-string-no-properties 0))
   8078         (setq elt (aref elt 0))
   8079         (setq elt (car (rassoc elt web-mode-html-entities)))
   8080         (replace-match (concat "&" elt ";"))
   8081         (setq max (+ max (length elt) 1))
   8082         ) ;while
   8083       )))
   8084 
   8085 (defun web-mode-dom-entities-replace ()
   8086   "Replace html entities (e.g. &eacute; &#233; or &#x00E9; become é)"
   8087   (interactive)
   8088   (save-excursion
   8089     (let (ms pair elt (min (point-min)) (max (point-max)))
   8090       (when mark-active
   8091         (setq min (region-beginning)
   8092               max (region-end))
   8093         (deactivate-mark))
   8094       (goto-char min)
   8095       (while (web-mode-content-rsf "&\\([#]?[[:alnum:]]\\{2,8\\}\\);" max)
   8096         (setq elt nil)
   8097         (setq ms (match-string-no-properties 1))
   8098         (cond
   8099          ((not (eq (aref ms 0) ?\#))
   8100           (and (setq pair (assoc ms web-mode-html-entities))
   8101                (setq elt (cdr pair))
   8102                (setq elt (char-to-string elt))))
   8103          ((eq (aref ms 1) ?x)
   8104           (setq elt (substring ms 2))
   8105           (setq elt (downcase elt))
   8106           (setq elt (string-to-number elt 16))
   8107           (setq elt (char-to-string elt)))
   8108          (t
   8109           (setq elt (substring ms 1))
   8110           (setq elt (char-to-string (string-to-number elt))))
   8111          ) ;cond
   8112         (when elt (replace-match elt))
   8113         ) ;while
   8114       )))
   8115 
   8116 (defun web-mode-dom-xml-replace ()
   8117   "Replace &, > and < in html content."
   8118   (interactive)
   8119   (save-excursion
   8120     (let (expr (min (point-min)) (max (point-max)))
   8121       (when mark-active
   8122         (setq min (region-beginning)
   8123               max (region-end))
   8124         (deactivate-mark))
   8125       (goto-char min)
   8126       (while (web-mode-content-rsf "[&<>]" max)
   8127         (replace-match (cdr (assq (char-before) web-mode-xml-chars)) t t))
   8128       )))
   8129 
   8130 (defun web-mode-dom-quotes-replace ()
   8131   "Replace dumb quotes."
   8132   (interactive)
   8133   (save-excursion
   8134     (let (expr (min (point-min)) (max (point-max)))
   8135       (when mark-active
   8136         (setq min (region-beginning)
   8137               max (region-end))
   8138         (deactivate-mark))
   8139       (goto-char min)
   8140       (setq expr (concat (car web-mode-smart-quotes) "\\2" (cdr web-mode-smart-quotes)))
   8141       (while (web-mode-content-rsf "\\(\"\\)\\(.\\{1,200\\}\\)\\(\"\\)" max)
   8142         (replace-match expr)
   8143         ) ;while
   8144       )))
   8145 
   8146 ;;---- INDENTATION -------------------------------------------------------------
   8147 
   8148 ;; todo : passer de règle en règle et mettre un \n à la fin
   8149 (defun web-mode-css-indent ()
   8150   (save-excursion
   8151     (goto-char (point-min))
   8152     (let ((continue t) rule part-end)
   8153       (while continue
   8154         (cond
   8155          ((not (web-mode-part-next))
   8156           (setq continue nil))
   8157          ((eq (get-text-property (point) 'part-side) 'css)
   8158           (setq part-end (web-mode-part-end-position))
   8159           (while (setq rule (web-mode-css-rule-next part-end))
   8160             (when (not (looking-at-p "[[:space:]]*\\($\\|<\\)"))
   8161               (newline)
   8162               (indent-according-to-mode)
   8163               (setq part-end (web-mode-part-end-position)))
   8164             )
   8165           )
   8166          ) ;cond
   8167         )
   8168       )))
   8169 
   8170 (defun web-mode-buffer-indent ()
   8171   "Indent all buffer."
   8172   (interactive)
   8173   (let ((debug t) (ts (current-time)) (sub nil))
   8174     (indent-region (point-min) (point-max))
   8175     (when debug
   8176       (setq sub (time-subtract (current-time) ts))
   8177       (message "buffer-indent: time elapsed = %Ss %9Sµs" (nth 1 sub) (nth 2 sub)))
   8178     (delete-trailing-whitespace)))
   8179 
   8180 (defun web-mode-point-context (pos)
   8181   "POS should be at the beginning of the indentation."
   8182   (save-excursion
   8183     (let (curr-char curr-indentation curr-line
   8184           language
   8185           options
   8186           reg-beg reg-col
   8187           prev-char prev-indentation prev-line prev-pos
   8188           token
   8189           part-language
   8190           depth)
   8191 
   8192       (setq reg-beg (point-min)
   8193             reg-col 0
   8194             token "live"
   8195             options ""
   8196             language ""
   8197             prev-line ""
   8198             prev-char 0
   8199             prev-pos nil)
   8200 
   8201       (when (get-text-property pos 'part-side)
   8202         (setq part-language (symbol-name (get-text-property pos 'part-side))))
   8203 
   8204       ;;(message "part-language=%S" part-language)
   8205 
   8206       (cond
   8207 
   8208        ((and (bobp) (member web-mode-content-type '("html" "xml")))
   8209         (setq language web-mode-content-type)
   8210         )
   8211 
   8212        ((string= web-mode-content-type "css")
   8213         (setq language "css"
   8214               curr-indentation web-mode-css-indent-offset))
   8215 
   8216        ((member web-mode-content-type '("javascript" "json" "typescript"))
   8217         (setq language web-mode-content-type
   8218               curr-indentation web-mode-code-indent-offset))
   8219 
   8220        ((or (string= web-mode-content-type "jsx")
   8221             (and part-language (string= part-language "jsx")))
   8222         (setq language "jsx"
   8223               curr-indentation web-mode-code-indent-offset)
   8224         (cond
   8225          ((web-mode-jsx-is-html pos)
   8226           (setq curr-indentation web-mode-markup-indent-offset
   8227                 options "is-html"))
   8228          ((and (setq depth (get-text-property pos 'jsx-depth)) (> depth 1))
   8229           (when (get-text-property pos 'jsx-beg)
   8230             (setq depth (1- depth)))
   8231           (setq reg-beg (web-mode-jsx-depth-beginning-position pos depth))
   8232           (setq reg-beg (1+ reg-beg))
   8233           ;;(message "%S" (point))
   8234           (save-excursion
   8235             (goto-char reg-beg)
   8236             ;;(message "pt=%S" reg-beg)
   8237             (cond
   8238              ((and (not (looking-at-p "[ ]*$"))
   8239                    (looking-back "^[[:space:]]*{" (point-min)))
   8240               (setq reg-col (+ (current-indentation) ;; #1027
   8241                                (cond
   8242                                 ((looking-at "[ ]+") (1+ (length (match-string-no-properties 0))))
   8243                                 (t 0))
   8244                                ))
   8245               )
   8246              ((looking-at-p "[ ]*\\[[ ]*$") ;; #0659
   8247               (setq reg-col (current-indentation))
   8248               )
   8249              ((and (looking-back "=[ ]*{" (point-min)) ;; #0739 #1022
   8250                    (not (looking-at-p "[[:space:]]*<")))
   8251               (setq reg-col (current-indentation))
   8252               )
   8253              ;;((and (looking-back "=[ ]*{" (point-min)) ;; #0739
   8254              ;;      (looking-at-p "{[ ]*"))
   8255              ;; (setq reg-col (current-indentation))
   8256              ;; )
   8257              ((get-text-property (1- (point)) 'tag-beg)
   8258               ;;(message "point=%S" (point))
   8259               (setq reg-col (current-indentation))
   8260               )
   8261              (t
   8262               (message "%S : %S %S" (point) (current-indentation) web-mode-code-indent-offset)
   8263               ;;(setq reg-col (+ (current-indentation) web-mode-code-indent-offset web-mode-jsx-expression-padding)))
   8264               (setq reg-col (+ (current-indentation) web-mode-code-indent-offset)))
   8265              )
   8266 
   8267             ;;(message "%S %S %S" (point) (current-indentation) reg-col)
   8268             ) ;save-excursion
   8269           )
   8270          ((string= web-mode-content-type "jsx")
   8271           (setq reg-beg (point-min)))
   8272          (t
   8273           (setq reg-beg (or (web-mode-part-beginning-position pos) (point-min)))
   8274           (save-excursion
   8275             (goto-char reg-beg)
   8276             (search-backward "<" nil t)
   8277             (setq reg-col (current-column))
   8278             ) ;save-excursion
   8279           )
   8280          ) ;cond
   8281         ;;(message "jsx reg-beg=%S" reg-beg)
   8282         ) ;jsx
   8283 
   8284        ((string= web-mode-content-type "php")
   8285         (setq language "php"
   8286               curr-indentation web-mode-code-indent-offset))
   8287 
   8288        ((or (string= web-mode-content-type "xml"))
   8289         (setq language "xml"
   8290               curr-indentation web-mode-markup-indent-offset))
   8291 
   8292        ;; TODO: est ce util ?
   8293        ((and (get-text-property pos 'tag-beg)
   8294              (get-text-property pos 'tag-name)
   8295              ;;(not (get-text-property pos 'part-side))
   8296              )
   8297         (setq language "html"
   8298               curr-indentation web-mode-markup-indent-offset))
   8299 
   8300        ((and (get-text-property pos 'block-side)
   8301              (not (get-text-property pos 'block-beg)))
   8302 
   8303         (setq reg-beg (or (web-mode-block-beginning-position pos) (point-min)))
   8304         (goto-char reg-beg)
   8305         (setq reg-col (current-column))
   8306         ;;(message "%S %S" reg-beg reg-col)
   8307         (setq language web-mode-engine)
   8308         (setq curr-indentation web-mode-code-indent-offset)
   8309 
   8310         (cond
   8311          ((string= web-mode-engine "blade")
   8312           (save-excursion
   8313             (when (web-mode-rsf "{[{!]+[ ]*")
   8314               (setq reg-col (current-column))))
   8315           (setq reg-beg (+ reg-beg 2))
   8316           )
   8317          ((string= web-mode-engine "razor")
   8318           ;;(setq reg-beg (+ reg-beg 2))
   8319           ;;(setq reg-col (current-column))
   8320           )
   8321          ;; tests/demo.chtml
   8322          ((string= web-mode-engine "ctemplate")
   8323           (save-excursion
   8324             (when (web-mode-rsf "{{#?")
   8325               (setq reg-col (current-column))))
   8326           )
   8327          ((string= web-mode-engine "dust")
   8328           (save-excursion
   8329             (when (web-mode-rsf "{@")
   8330               (setq reg-col (current-column))))
   8331           )
   8332          ((string= web-mode-engine "svelte")
   8333           (save-excursion
   8334             (when (web-mode-rsf "{@")
   8335               (setq reg-col (current-column))))
   8336           )
   8337          ((string= web-mode-engine "template-toolkit")
   8338           (setq reg-beg (+ reg-beg 3)
   8339                 reg-col (+ reg-col 3))
   8340           )
   8341          ((and (string= web-mode-engine "jsp")
   8342                (web-mode-looking-at "<%@" reg-beg))
   8343           (save-excursion
   8344             (goto-char reg-beg)
   8345             (looking-at "<%@[ ]*[[:alpha:]]+[ ]+\\|</?[[:alpha:]]+[:.][[:alpha:]]+[ ]+")
   8346             (goto-char (match-end 0))
   8347             (setq reg-col (current-column))
   8348             )
   8349           )
   8350          ((and (string= web-mode-engine "freemarker")
   8351                (web-mode-looking-at "<@\\|<%@\\|<[[:alpha:]]" reg-beg))
   8352           (save-excursion
   8353             (goto-char reg-beg)
   8354             (looking-at "<@[[:alpha:].]+[ ]+\\|<%@[ ]*[[:alpha:]]+[ ]+\\|<[[:alpha:]]+:[[:alpha:]]+[ ]+")
   8355             (goto-char (match-end 0))
   8356             (setq reg-col (current-column))
   8357             )
   8358           )
   8359          ) ;cond
   8360         ) ;block-side
   8361 
   8362        ((and part-language (member part-language
   8363                                    '("css" "javascript" "json" "sql" "markdown"
   8364                                      "pug" "ruby" "sass" "stylus" "typescript")))
   8365         (setq reg-beg (or (web-mode-part-beginning-position pos) (point-min)))
   8366         (goto-char reg-beg)
   8367         (if (and (string= web-mode-engine "mojolicious")
   8368                  (looking-back "javascript begin" (point-min)))
   8369             (search-backward "%" nil t)
   8370           (search-backward "<" nil t))
   8371         (setq reg-col (current-column))
   8372         (setq language part-language)
   8373         (cond
   8374          ((string= language "css")
   8375           (setq curr-indentation web-mode-css-indent-offset))
   8376          ((string= language "sql")
   8377           (setq curr-indentation web-mode-sql-indent-offset))
   8378          ((string= language "markdown")
   8379           (setq curr-indentation web-mode-code-indent-offset))
   8380          ((string= language "pug")
   8381           (setq curr-indentation web-mode-code-indent-offset))
   8382          ((string= language "sass")
   8383           (setq curr-indentation web-mode-code-indent-offset))
   8384          ((string= language "stylus")
   8385           (setq curr-indentation web-mode-code-indent-offset))
   8386          ((string= language "ruby")
   8387           (setq curr-indentation web-mode-code-indent-offset))
   8388          ((string= language "typescript")
   8389           (setq curr-indentation web-mode-code-indent-offset))
   8390          (t
   8391           (setq language "javascript"
   8392                 curr-indentation web-mode-code-indent-offset))
   8393          )
   8394         ) ;part-side
   8395 
   8396        (t
   8397         (setq language "html"
   8398               curr-indentation web-mode-markup-indent-offset)
   8399         )
   8400 
   8401        ) ;cond
   8402 
   8403       (cond
   8404        ((or (and (> pos (point-min))
   8405                  (eq (get-text-property pos 'part-token) 'comment)
   8406                  (eq (get-text-property (1- pos) 'part-token) 'comment)
   8407                  (progn
   8408                    (setq reg-beg (previous-single-property-change pos 'part-token))
   8409                    t))
   8410             (and (> pos (point-min))
   8411                  (eq (get-text-property pos 'block-token) 'comment)
   8412                  (eq (get-text-property (1- pos) 'block-token) 'comment)
   8413                  (progn
   8414                    (setq reg-beg (previous-single-property-change pos 'block-token))
   8415                    t))
   8416             (and (> pos (point-min))
   8417                  (eq (get-text-property pos 'tag-type) 'comment)
   8418                  (not (get-text-property pos 'tag-beg))
   8419                  (progn
   8420                    (setq reg-beg (web-mode-tag-beginning-position pos))
   8421                    t))
   8422             )
   8423         (setq token "comment"))
   8424        ((or (and (> pos (point-min))
   8425                  (member (get-text-property pos 'part-token)
   8426                          '(string context key))
   8427                  (member (get-text-property (1- pos) 'part-token)
   8428                          '(string context key)))
   8429             (and (eq (get-text-property pos 'block-token) 'string)
   8430                  (eq (get-text-property (1- pos) 'block-token) 'string)))
   8431         (setq token "string"))
   8432        )
   8433 
   8434       (goto-char pos)
   8435       (setq curr-line (web-mode-trim
   8436                        (buffer-substring-no-properties
   8437                         (line-beginning-position)
   8438                         (line-end-position))))
   8439       (setq curr-char (if (string= curr-line "") 0 (aref curr-line 0)))
   8440 
   8441       (when (or (member language '("php" "blade" "javascript" "typescript" "jsx" "razor" "css"))
   8442                 (and (member language '("html" "xml"))
   8443                      (not (eq ?\< curr-char))))
   8444         (let (prev)
   8445           (cond
   8446            ((member language '("html" "xml" "javascript" "jsx" "css"))
   8447             (when (setq prev (web-mode-part-previous-live-line reg-beg))
   8448               (setq prev-line (nth 0 prev)
   8449                     prev-indentation (nth 1 prev)
   8450                     prev-pos (nth 2 prev))
   8451               )
   8452             )
   8453            ((setq prev (web-mode-block-previous-live-line))
   8454             (setq prev-line (car prev)
   8455                   prev-indentation (cdr prev))
   8456             (setq prev-line (web-mode-clean-block-line prev-line)))
   8457            ) ;cond
   8458           ) ;let
   8459         (when (>= (length prev-line) 1)
   8460           (setq prev-char (aref prev-line (1- (length prev-line))))
   8461           (setq prev-line (substring-no-properties prev-line))
   8462           )
   8463         )
   8464 
   8465       (cond
   8466        ((not (member web-mode-content-type '("html" "xml")))
   8467         )
   8468        ((member language '("javascript" "typescript" "jsx" "ruby"))
   8469         (setq reg-col (if web-mode-script-padding (+ reg-col web-mode-script-padding) 0)))
   8470        ((member language '("css" "sql" "markdown" "pug" "sass" "stylus"))
   8471         (setq reg-col (if web-mode-style-padding (+ reg-col web-mode-style-padding) 0)))
   8472        ((not (member language '("html" "xml")))
   8473         (setq reg-col
   8474               (cond
   8475                ((not web-mode-block-padding) reg-col)
   8476                ((eq web-mode-block-padding -1) 0)
   8477                (t (+ reg-col web-mode-block-padding))
   8478                ) ;cond
   8479               ) ;setq
   8480         )
   8481        )
   8482 
   8483       (list :curr-char curr-char
   8484             :curr-indentation curr-indentation
   8485             :curr-line curr-line
   8486             :language language
   8487             :options options
   8488             :prev-char prev-char
   8489             :prev-indentation prev-indentation
   8490             :prev-line prev-line
   8491             :prev-pos prev-pos
   8492             :reg-beg reg-beg
   8493             :reg-col reg-col
   8494             :token token)
   8495       )))
   8496 
   8497 (defun web-mode-indent-line ()
   8498 
   8499   (web-mode-scan)
   8500 
   8501   (let ((offset nil)
   8502         (char nil)
   8503         (debug nil)
   8504         (inhibit-modification-hooks nil)
   8505         (adjust t))
   8506 
   8507     (save-excursion
   8508       (back-to-indentation)
   8509       (setq char (char-after))
   8510       (let* ((pos (point))
   8511              (ctx (web-mode-point-context pos))
   8512              (curr-char (plist-get ctx :curr-char))
   8513              (curr-indentation (plist-get ctx :curr-indentation))
   8514              (curr-line (plist-get ctx :curr-line))
   8515              (language (plist-get ctx :language))
   8516              (prev-char (plist-get ctx :prev-char))
   8517              (prev-indentation (plist-get ctx :prev-indentation))
   8518              (prev-line (plist-get ctx :prev-line))
   8519              (prev-pos (plist-get ctx :prev-pos))
   8520              (reg-beg (plist-get ctx :reg-beg))
   8521              (reg-col (plist-get ctx :reg-col))
   8522              (token (plist-get ctx :token))
   8523              (options (plist-get ctx :options))
   8524              (chars (list curr-char prev-char))
   8525              (tmp nil)
   8526              (is-js (member language '("javascript" "jsx" "ejs" "typescript"))))
   8527 
   8528         (when (member language '("json" "typescript"))
   8529           (setq language "javascript"))
   8530 
   8531         ;;(message "%S %S" (plist-get ctx :language) language)
   8532         ;;(message "curr-char=[%c] prev-char=[%c]\n%S" curr-char prev-char ctx)
   8533         ;;(message "options=%S" ctx)
   8534 
   8535         (cond
   8536 
   8537          ((or (bobp) (= (line-number-at-pos pos) 1))
   8538           (when debug (message "I100(%S) first line" pos))
   8539           (setq offset 0))
   8540 
   8541          ;; #123 #1145
   8542          ((and web-mode-enable-front-matter-block
   8543                (eq (char-after (point-min)) ?\-)
   8544                (or (looking-at-p "---")
   8545                    (search-forward "---" (point-max) t)))
   8546           (when debug (message "I108(%S) front-matter-block" pos))
   8547           (setq offset nil))
   8548 
   8549          ;; #1073
   8550          ((get-text-property pos 'invisible)
   8551           (when debug (message "I110(%S) invible" pos))
   8552           (setq offset nil))
   8553 
   8554          ((string= token "string")
   8555           (when debug (message "I120(%S) string" pos))
   8556           (cond
   8557            ((web-mode-is-token-end pos)
   8558             (if (get-text-property pos 'block-side)
   8559                 (web-mode-block-token-beginning)
   8560               (web-mode-part-token-beginning))
   8561             (setq offset (current-indentation))
   8562             )
   8563            ((and web-mode-enable-sql-detection
   8564                  (web-mode-block-token-starts-with (concat "[ \n]*" web-mode-sql-queries)))
   8565             (save-excursion
   8566               (let (col)
   8567                 (web-mode-block-string-beginning)
   8568                 (skip-chars-forward "[ \"'\n]")
   8569                 (setq col (current-column))
   8570                 (goto-char pos)
   8571                 (if (looking-at-p "\\(SELECT\\|INSERT\\|DELETE\\|UPDATE\\|FROM\\|LEFT\\|JOIN\\|WHERE\\|GROUP BY\\|LIMIT\\|HAVING\\|\)\\)")
   8572                     (setq offset col)
   8573                   (setq offset (+ col web-mode-sql-indent-offset)))
   8574                 )
   8575               ) ;save-excursion
   8576             )
   8577            ((and is-js
   8578                  (web-mode-is-ql-string pos "Relay\.QL"))
   8579             (setq offset (web-mode-relayql-indentation pos))
   8580             )
   8581            ((and is-js
   8582                  (web-mode-is-ql-string pos "gql"))
   8583             (setq offset (web-mode-relayql-indentation pos "gql"))
   8584             )
   8585            ((and is-js
   8586                  (web-mode-is-ql-string pos "graphql"))
   8587             (setq offset (web-mode-relayql-indentation pos "graphql"))
   8588             )
   8589            ((and is-js
   8590                  (web-mode-is-css-string pos))
   8591             (when debug (message "I127(%S) css string" pos))
   8592             (setq offset (web-mode-token-css-indentation pos))
   8593             )
   8594            ((and is-js
   8595                  (web-mode-is-html-string pos))
   8596             (when debug (message "I128(%S) html string" pos))
   8597             (setq offset (web-mode-token-html-indentation pos))
   8598             )
   8599            (t
   8600             (setq offset nil))
   8601            ) ;cond
   8602           ) ;case string
   8603 
   8604          ((string= token "comment")
   8605           (when debug (message "I130(%S) comment" pos))
   8606           (if (eq (get-text-property pos 'tag-type) 'comment)
   8607               (web-mode-tag-beginning)
   8608             (goto-char (car
   8609                         (web-mode-property-boundaries
   8610                          (if (eq (get-text-property pos 'part-token) 'comment)
   8611                              'part-token
   8612                            'block-token)
   8613                          pos))))
   8614           (setq offset (current-column))
   8615           (cond
   8616            ((string= web-mode-engine "freemarker")
   8617             (setq offset (+ (current-indentation) 2)))
   8618            ((member (buffer-substring-no-properties (point) (+ (point) 2)) '("/*" "{*" "@*"))
   8619             (cond
   8620              ((eq ?\* curr-char)
   8621               (setq offset (+ offset 1)))
   8622              (t
   8623               (setq offset (+ offset 3)))
   8624              ) ;cond
   8625             )
   8626            ((string= (buffer-substring-no-properties (point) (+ (point) 4)) "<!--")
   8627             (cond
   8628              ((string-match-p "^<!\\[endif" curr-line)
   8629               )
   8630              ((looking-at-p "<!--\\[if")
   8631               (setq offset (+ offset web-mode-markup-indent-offset)))
   8632              ((string-match-p "^-->" curr-line)
   8633               (setq offset offset))
   8634              ((string-match-p "^-" curr-line)
   8635               (setq offset (+ offset 3)))
   8636              (t
   8637               (setq offset (+ offset 5)))
   8638              ) ;cond
   8639             )
   8640            ((and (string= web-mode-engine "django") (looking-back "{% comment %}" (point-min)))
   8641             (setq offset (- offset 12)))
   8642            ((and (string= web-mode-engine "mako") (looking-back "<%doc%>" (point-min)))
   8643             (setq offset (- offset 6)))
   8644            ((and (string= web-mode-engine "mason") (looking-back "<%doc%>" (point-min)))
   8645             (setq offset (- offset 6)))
   8646            ) ;cond
   8647           ) ;case comment
   8648 
   8649          ((and (string= web-mode-engine "mason")
   8650                (string-match-p "^%" curr-line))
   8651           (when debug (message "I140(%S) mason" pos))
   8652           (setq offset 0))
   8653 
   8654          ((and (string= web-mode-engine "django")
   8655                (string-match-p "^#" curr-line))
   8656           (when debug (message "I144(%S) django line statements" pos))
   8657           (setq offset 0))
   8658 
   8659          ((and (get-text-property pos 'block-beg)
   8660                (or (web-mode-block-is-close pos)
   8661                    (web-mode-block-is-inside pos)))
   8662           (when debug (message "I150(%S) block-match" pos))
   8663           (cond
   8664            ((not (web-mode-block-match))
   8665             )
   8666            ((and (string= web-mode-engine "closure")
   8667                  (string-match-p "{\\(case\\|default\\)" curr-line))
   8668             (setq offset (+ (current-indentation) web-mode-markup-indent-offset)))
   8669            (t
   8670             (setq offset (current-indentation))
   8671             (if (and (string= web-mode-engine "blade")
   8672                      (string-match-p "@break" curr-line))
   8673                 (setq offset (+ (current-indentation) offset)))
   8674             )
   8675            ) ;cond
   8676           )
   8677 
   8678          ((eq (get-text-property pos 'block-token) 'delimiter-end)
   8679           (when debug (message "I160(%S) block-beginning" pos))
   8680           (when (web-mode-block-beginning)
   8681             (setq reg-col (current-indentation))
   8682             (setq offset (current-column))))
   8683 
   8684          ((or (and (get-text-property pos 'tag-beg)
   8685                    (eq (get-text-property pos 'tag-type) 'end))
   8686               (and (eq (get-text-property pos 'tag-type) 'comment)
   8687                    (string-match-p "<!--#\\(else\\|elif\\|endif\\)" curr-line)))
   8688           (when debug (message "I170(%S) tag-match" pos))
   8689           (when (web-mode-tag-match)
   8690             (setq offset (current-indentation))))
   8691 
   8692          ((and (member language '("jsx"))
   8693                (eq curr-char ?\})
   8694                (get-text-property pos 'jsx-end))
   8695           (when debug (message "I180(%S) jsx-expr-end" pos))
   8696           (web-mode-go (1- reg-beg))
   8697           (setq reg-col nil)
   8698           ;;(setq offset (current-column)))
   8699           (setq offset (current-indentation)))
   8700 
   8701          ((and (member language '("html" "xml" "javascript" "jsx"))
   8702                (get-text-property pos 'tag-type)
   8703                (not (get-text-property pos 'tag-beg))
   8704                ;;(or (not (string= language "jsx"))
   8705                ;;    (string= options "is-html"))
   8706                (not (and (string= language "jsx")
   8707                          (or (string= options "is-html")
   8708                              (web-mode-jsx-is-expr pos))))
   8709                )
   8710           (when debug (message "I190(%S) attr-indent" pos))
   8711           (cond
   8712            ((and (not (get-text-property pos 'tag-attr-beg))
   8713                  (get-text-property pos 'tag-attr)
   8714                  (get-text-property (1- pos) 'tag-attr)
   8715                  (web-mode-attribute-beginning)
   8716                  (not (string-match-p "^/?>" curr-line))
   8717                  ;;(progn (message "pos=%S point=%S" pos (point)) t)
   8718                  )
   8719 
   8720             (cond
   8721              ((eq (logand (get-text-property (point) 'tag-attr-beg) 8) 8)
   8722               (setq offset nil))
   8723              ((not (web-mode-tag-beginning))
   8724               (message "** tag-beginning ** failure")
   8725               (setq offset nil))
   8726              (web-mode-attr-value-indent-offset
   8727               (setq offset (+ (current-column) web-mode-attr-value-indent-offset)))
   8728              ((web-mode-dom-rsf "=[ ]*[\"']?" pos)
   8729               ;;(message "%S" (point))
   8730               (setq offset (current-column)))
   8731              (t
   8732               (setq offset (+ (current-column) web-mode-markup-indent-offset)))
   8733              ) ;cond
   8734             ) ;and
   8735            ((not (web-mode-tag-beginning))
   8736             (message "** error ** unable to jump to tag beg"))
   8737            ((string-match-p "^/?>" curr-line)
   8738             (setq offset (web-mode-column-at-pos (web-mode-tag-beginning-position pos)))
   8739             )
   8740            (web-mode-attr-indent-offset
   8741             (setq offset (+ (current-column) web-mode-attr-indent-offset)))
   8742            ((looking-at-p (concat web-mode-start-tag-regexp "[ ]*\n"))
   8743             ;;(message "%S: %S" (point) (web-mode-inside-block-control pos))
   8744             (setq offset (+ (current-column) (or web-mode-attr-indent-offset web-mode-code-indent-offset)))
   8745             ;; #1109
   8746             (setq tmp (web-mode-inside-block-control pos))
   8747             (when (and tmp (> tmp (point)))
   8748               (setq offset (+ offset (or web-mode-attr-indent-offset web-mode-code-indent-offset))))
   8749             )
   8750            ((web-mode-attribute-next)
   8751             (setq offset (current-column)))
   8752            ) ;cond
   8753           ) ;attr-indent
   8754 
   8755          ((or (member language '("html" "xml"))
   8756               (and (member language '("jsx"))
   8757                    (string= options "is-html")))
   8758           (when debug (message "I200(%S) web-mode-markup-indentation" pos))
   8759           ;; https://www.w3.org/TR/html5/syntax.html#optional-tags
   8760           (when web-mode-enable-optional-tags
   8761             (save-excursion
   8762               (let (tag-name parent-tag-name parent-tag-pos)
   8763                 (when (and (setq tag-name (get-text-property pos 'tag-name))
   8764                            (setq parent-tag-pos (web-mode-element-parent-position pos))
   8765                            (setq parent-tag-name (get-text-property parent-tag-pos 'tag-name))
   8766                            (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")))
   8767                                (and (string= parent-tag-name "li") (member tag-name '("li")))
   8768                                (and (string= parent-tag-name "dt") (member tag-name '("dt" "dd")))
   8769                                (and (string= parent-tag-name "td") (member tag-name '("td" "th")))
   8770                                (and (string= parent-tag-name "th") (member tag-name '("td" "th")))
   8771                                ))
   8772                   (when debug (message "I205(%S) %S(%S) auto-closing" pos parent-tag-name parent-tag-pos))
   8773                   (setq offset (web-mode-indentation-at-pos parent-tag-pos))
   8774                   )))) ; when let save-excursion when
   8775 
   8776           (when (string= web-mode-engine "closure")
   8777             (save-excursion
   8778               (when (and (re-search-backward "{/?switch" nil t)
   8779                          (string= (match-string-no-properties 0) "{switch"))
   8780                 (setq offset (+ (current-indentation) (* 2 web-mode-markup-indent-offset)))
   8781                 )
   8782               ))
   8783           (cond
   8784            ((not (null offset))
   8785             )
   8786            ((get-text-property pos 'tag-beg)
   8787             (setq offset (web-mode-markup-indentation pos))
   8788             )
   8789            ((and web-mode-indentless-elements
   8790                  (not (string= language "jsx"))
   8791                  (null (get-text-property pos 'block-side))
   8792                  (null (get-text-property pos 'part-side))
   8793                  (and (null (get-text-property pos 'tag-beg))
   8794                       (save-excursion
   8795                         (and (web-mode-element-parent)
   8796                              (member (get-text-property (point) 'tag-name) web-mode-indentless-elements))))
   8797                  )
   8798             (setq offset nil))
   8799            ((or (eq (length curr-line) 0)
   8800                 (= web-mode-indent-style 2)
   8801                 (get-text-property pos 'tag-beg)
   8802                 (get-text-property pos 'reg-beg))
   8803             (setq offset (web-mode-markup-indentation pos))
   8804             )
   8805            )
   8806           )
   8807 
   8808          ((string= language "ctemplate")
   8809           (when debug (message "I210(%S) ctemplate" pos))
   8810           (setq offset reg-col))
   8811 
   8812          ((string= language "expressionengine")
   8813           (when debug (message "I212(%S) expressionengine" pos))
   8814           (setq offset (+ reg-col (or web-mode-attr-indent-offset web-mode-code-indent-offset))))
   8815 
   8816          ((string= language "asp")
   8817           (when debug (message "I230(%S) asp" pos))
   8818           (setq offset (web-mode-asp-indentation pos
   8819                                                  curr-line
   8820                                                  reg-col
   8821                                                  curr-indentation
   8822                                                  reg-beg)))
   8823 
   8824          ((member language '("lsp" "cl-emb" "artanis"))
   8825           (when debug (message "I240(%S) lsp" pos))
   8826           (setq offset (web-mode-lisp-indentation pos ctx)))
   8827 
   8828          ((and (member curr-char '(?\}))
   8829                (string= language "razor")
   8830                (get-text-property pos 'block-end))
   8831           (when debug (message "I245(%S) razor closing" pos))
   8832           (goto-char reg-beg)
   8833           ;;(message "%S %S" (point) (current-column))
   8834           (setq offset (current-column)
   8835                 reg-col nil)
   8836           )
   8837 
   8838          ((member curr-char '(?\} ?\) ?\]))
   8839           (when debug (message "I250(%S) closing-paren" pos))
   8840           (let (ori pos2)
   8841             (setq pos2 pos)
   8842             ;; #1096
   8843             (when (looking-at-p ".[\]})]+")
   8844               (skip-chars-forward "[\]})]")
   8845               (backward-char)
   8846               (setq pos2 (point))
   8847               ) ;when
   8848             (if (get-text-property pos 'block-side)
   8849                 (setq ori (web-mode-block-opening-paren-position pos2 reg-beg))
   8850               (setq ori (web-mode-part-opening-paren-position pos2 reg-beg)))
   8851             ;;(message "ori=%S" ori)
   8852             (cond
   8853              ((null ori)
   8854               (setq offset reg-col))
   8855              ((and (goto-char ori)
   8856                    (looking-back ")[ ]*" (point-min)) ;; peut-on se passer du looking-back ?
   8857                    (re-search-backward ")[ ]*" nil t)
   8858                    (web-mode-block-opening-paren reg-beg))
   8859               (back-to-indentation)
   8860               (setq offset (current-indentation))
   8861               )
   8862              (t
   8863               (goto-char ori)
   8864               (back-to-indentation)
   8865               (setq offset (current-indentation))
   8866               ;;(message "ori=%S offset=%S" ori offset)
   8867               (when (get-text-property pos 'jsx-depth)
   8868                 ;;(when (get-text-property pos 'jsx-end)
   8869                 (setq adjust nil))
   8870               ) ;t
   8871              ) ;cond
   8872             ) ;let
   8873           )
   8874 
   8875          ((member language '("mako" "web2py"))
   8876           (when debug (message "I254(%S) python (mako/web2py)" pos))
   8877           (setq offset (web-mode-python-indentation pos
   8878                                                     curr-line
   8879                                                     reg-col
   8880                                                     curr-indentation
   8881                                                     reg-beg)))
   8882 
   8883          ((member language '("erb" "ruby"))
   8884           (when debug (message "I260(%S) erb" pos))
   8885           (setq offset (web-mode-ruby-indentation pos
   8886                                                   curr-line
   8887                                                   reg-col
   8888                                                   curr-indentation
   8889                                                   reg-beg)))
   8890 
   8891          ((string= language "css")
   8892           (when debug (message "I270(%S) css-indentation" pos))
   8893           ;;(message "prev=%c" prev-char)
   8894           (cond
   8895            ((eq prev-char ?:)
   8896             (setq offset (+ prev-indentation web-mode-css-indent-offset)))
   8897            ((eq prev-char ?,)
   8898             (setq offset prev-indentation))
   8899            (t
   8900             (setq offset (car (web-mode-css-indentation pos
   8901                                                         reg-col
   8902                                                         curr-indentation
   8903                                                         language
   8904                                                         reg-beg))))))
   8905 
   8906          ((string= language "sql")
   8907           (when debug (message "I280(%S) sql" pos))
   8908           (setq offset (car (web-mode-sql-indentation pos
   8909                                                       reg-col
   8910                                                       curr-indentation
   8911                                                       language
   8912                                                       reg-beg))))
   8913 
   8914          ((string= language "markdown")
   8915           (when debug (message "I290(%S) markdown" pos))
   8916           (setq offset (car (web-mode-markdown-indentation pos
   8917                                                            reg-col
   8918                                                            curr-indentation
   8919                                                            language
   8920                                                            reg-beg))))
   8921 
   8922          ((string= language "stylus")
   8923           (when debug (message "I294(%S) stylus" pos))
   8924           (setq offset (car (web-mode-stylus-indentation pos
   8925                                                          reg-col
   8926                                                          curr-indentation
   8927                                                          language
   8928                                                          reg-beg))))
   8929          ((string= language "sass")
   8930           (when debug (message "I296(%S) sass" pos))
   8931           (setq offset (car (web-mode-stylus-indentation pos
   8932                                                          reg-col
   8933                                                          curr-indentation
   8934                                                          language
   8935                                                          reg-beg))))
   8936 
   8937          ((string= language "pug")
   8938           (when debug (message "I298(%S) pug" pos))
   8939           (setq offset (car (web-mode-pug-indentation pos
   8940                                                       reg-col
   8941                                                       curr-indentation
   8942                                                       language
   8943                                                       reg-beg))))
   8944 
   8945          ((and (string= language "razor")
   8946                (string-match-p "^\\." curr-line)
   8947                (string-match-p "^\\." prev-line))
   8948           (when debug (message "I300(%S) razor" pos))
   8949           (setq offset prev-indentation))
   8950 
   8951          ((and (string= language "razor")
   8952                (string-match-p "^case " curr-line)
   8953                (string-match-p "^case " prev-line))
   8954           (when debug (message "I310(%S) razor case" pos))
   8955           (search-backward "case ")
   8956           (setq offset (current-column)))
   8957 
   8958          ((and is-js
   8959                (member ?\. chars)
   8960                (not (string-match-p "^\\.\\.\\." curr-line)))
   8961           (when debug (message "I320(%S) javascript-calls" pos))
   8962           (let (pair)
   8963             (setq pair (web-mode-javascript-calls-beginning-position pos reg-beg))
   8964             ;;(message "%S" pair)
   8965             (when pair
   8966               (goto-char (car pair))
   8967               ;;(message "%S %S" (point) pair)
   8968               (cond
   8969                ((cdr (assoc "lineup-calls" web-mode-indentation-params))
   8970                 ;;(message "ici")
   8971                 ;;(search-forward ".")
   8972                 (if (cdr pair)
   8973                     (progn
   8974                       (goto-char (cdr pair))
   8975                       (setq offset (current-column))
   8976                       (looking-at "\\.\\([ \t\n]*\\)")
   8977                       (setq offset (- offset (length (match-string-no-properties 1))))
   8978                       (unless (eq curr-char ?\.) (setq offset (1+ offset)))
   8979                       ) ;progn
   8980                   ;; TODO: cela devrait etre fait dans web-mode-javascript-calls-beginning-position
   8981                   (skip-chars-forward " \t\n")
   8982                   (setq offset (+ (current-indentation) web-mode-code-indent-offset))
   8983                   ) ;if
   8984                 )
   8985                (t
   8986                 (setq offset (+ (current-indentation) web-mode-code-indent-offset))
   8987                 ) ;t
   8988                ) ;cond
   8989               ) ;when
   8990             ) ;let
   8991           )
   8992 
   8993          ((and is-js
   8994                (member ?\+ chars))
   8995           (when debug (message "I330(%S) javascript-string" pos))
   8996           ;;(message "js-concat")
   8997           (cond
   8998            ((not (web-mode-javascript-string-beginning pos reg-beg))
   8999             )
   9000            ((null (cdr (assoc "lineup-concats" web-mode-indentation-params)))
   9001             (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9002            ((not (eq curr-char ?\+))
   9003             (setq offset (current-column)))
   9004            (t
   9005             (setq offset (current-column))
   9006             (when (not (looking-back "\\(^[ \t]+\\|if[ ]*[(]?\\)" (point-min)))
   9007               (goto-char pos)
   9008               (looking-at "\\+[ \t\n]*")
   9009               (setq offset (- offset (length (match-string-no-properties 0)))))
   9010             )
   9011            )
   9012           )
   9013 
   9014          ;; #579 , #742
   9015          ((and (member language '("javascript" "jsx" "ejs" "php"))
   9016                (string-match-p "=[>]?$" prev-line))
   9017           (when debug (message "I340(%S)" pos))
   9018           (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9019           ;;(message "ici%S" offset)
   9020           )
   9021 
   9022          ;; #1016
   9023          ((and (member language '("javascript" "jsx" "ejs"))
   9024                (string-match-p "^[ \t]*|}" curr-line))
   9025           (when debug (message "I346(%S) flow-exact-object-type-end" pos))
   9026           (when (re-search-backward "{|" reg-beg t)
   9027             (setq offset (current-indentation))
   9028             )
   9029           )
   9030 
   9031          ;; #446, #638, #800, #978, #998
   9032          ((and (member language '("javascript" "jsx" "ejs" "php"))
   9033                (or (string-match-p "[&|?:+-]$" prev-line)
   9034                    (string-match-p "^[&|?:+-]" curr-line))
   9035                (not (and (string= language "php")
   9036                          (string-match-p "^->" curr-line)))
   9037                (not (and (string= language "php")
   9038                          (string-match-p "^?[a-zA-z]*" curr-line)))
   9039                (not (and (string= language "php")
   9040                          (string-match-p "\\(else[ ]?:\\|if[ ]?([^)]*)[ ]?:\\)" prev-line)))
   9041                (not (string-match-p "^\\(++\\|--\\)" curr-line))
   9042                (not (and is-js
   9043                          (string-match-p "]:\\|{|$" prev-line)))
   9044                (not (and (eq prev-char ?\:)
   9045                          (string-match-p "^\\(case\\|default\\)" prev-line)))
   9046                )
   9047           ;;(message "prev=%S" prev-line)
   9048           (when debug (message "I350(%S) multiline statement" pos))
   9049           (let (is-ternary)
   9050             (setq is-ternary (or (string-match-p "[?:]$" prev-line)
   9051                                  (string-match-p "^[?:]" curr-line)))
   9052             (cond
   9053              ((not (funcall (if is-js
   9054                                 'web-mode-javascript-statement-beginning
   9055                               'web-mode-block-statement-beginning)
   9056                             pos reg-beg is-ternary))
   9057               )
   9058              ((null (cdr (assoc "lineup-ternary" web-mode-indentation-params)))
   9059               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9060              (t
   9061               (setq offset (current-column))
   9062               (when (and (member curr-char '(?\+ ?\- ?\& ?\| ?\? ?\:))
   9063                          (not (looking-back "\\(^[ \t]+\\|if[ ]*[(]?\\)" (point-min)))) ; #743
   9064                 (goto-char pos)
   9065                 (looking-at "\\(||\\|&&\\|[&|?:+-]\\)[ \t\n]*")
   9066                 (setq offset (- offset (length (match-string-no-properties 0)))))
   9067               )
   9068              ) ;cond
   9069             ) ;let
   9070           )
   9071 
   9072          ((and is-js
   9073                (eq prev-char ?\()
   9074                (string-match-p "=>[ ]*([ ]*$" prev-line))
   9075           (when debug (message "I355(%S) => (" pos))
   9076           (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9077           )
   9078 
   9079          ((and is-js
   9080                (or (member ?\, chars)
   9081                    (member prev-char '(?\( ?\[))))
   9082           (when debug (message "I360(%S) javascript-args" pos))
   9083           (cond
   9084            ((not (web-mode-javascript-args-beginning pos reg-beg))
   9085             (message "no js args beg")
   9086             )
   9087            ((or (not (cdr (assoc "lineup-args" web-mode-indentation-params)))
   9088                 (looking-at-p "|?\n") ;; #1016
   9089                 ;;(eq (char-after) ?\n)
   9090                 )
   9091             (if (and reg-col (> reg-col (current-indentation)))
   9092                 (setq offset (+ reg-col web-mode-code-indent-offset))
   9093               (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9094             )
   9095            ((not (eq curr-char ?\,))
   9096             (setq offset (current-column)))
   9097            (t
   9098             (setq offset (current-column))
   9099             (goto-char pos)
   9100             (looking-at ",[ \t\n]*")
   9101             (setq offset (- offset (length (match-string-no-properties 0)))))
   9102            ) ;cond
   9103           )
   9104 
   9105          ((and is-js
   9106                (or (eq prev-char ?\))
   9107                    (string-match-p "\\(^\\|[}[:space:]]+\\)else$" prev-line)))
   9108           (when debug (message "I370(%S)" pos))
   9109           (cond
   9110            ((and (string-match-p "else$" prev-line)
   9111                  (not (string-match-p "^{" curr-line)))
   9112             (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9113             )
   9114            ((and (string-match-p "else$" prev-line)
   9115                  (string-match-p "^{" curr-line)
   9116                  web-mode-enable-curly-brace-indentation)
   9117             (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9118             )
   9119            ((setq tmp (web-mode-part-is-opener prev-pos reg-beg))
   9120             ;;(message "is-opener")
   9121             (if (or (not (looking-at-p "{")) ;; #1020, #1053, #1160
   9122                     web-mode-enable-curly-brace-indentation)
   9123                 (setq offset (+ tmp web-mode-code-indent-offset))
   9124               (setq offset tmp))
   9125             )
   9126            (t
   9127             (setq offset
   9128                   (car (web-mode-javascript-indentation pos
   9129                                                         reg-col
   9130                                                         curr-indentation
   9131                                                         language
   9132                                                         reg-beg)))
   9133             ) ;t
   9134            ) ;cond
   9135 
   9136           )
   9137 
   9138          ;; TODO : a retoucher completement car le code js a ete place ci-dessus
   9139          ;;((and (member language '("javascript" "jsx" "ejs" "php"))
   9140          ((and (member language '("php"))
   9141                (or (and (eq prev-char ?\))
   9142                         (string-match-p "^\\(for\\|foreach\\|if\\|else[ ]*if\\|while\\)[ ]*(" prev-line))
   9143                    (and is-js
   9144                         (web-mode-part-is-opener prev-pos reg-beg))
   9145                    (string-match-p "^else$" prev-line))
   9146                (not (string-match-p "^\\([{.]\\|->\\)" curr-line)))
   9147           (when debug (message "I380(%S)" pos))
   9148           (cond
   9149            ((and (eq prev-char ?\))
   9150                  (string-match-p "^\\(for\\|if\\|while\\)[ ]*(" prev-line))
   9151             (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9152             )
   9153            ((member language '("javascript" "jsx"))
   9154             (setq offset
   9155                   (+ (car (web-mode-javascript-indentation pos
   9156                                                            reg-col
   9157                                                            curr-indentation
   9158                                                            language
   9159                                                            reg-beg))
   9160                      web-mode-code-indent-offset))
   9161             )
   9162            (t
   9163             (setq offset (+ prev-indentation web-mode-code-indent-offset))
   9164             )
   9165            )
   9166           )
   9167 
   9168          ((and (member language '("php" "blade")) (string-match-p "^->" curr-line))
   9169           (when debug (message "I390(%S) block-calls" pos))
   9170           (cond
   9171            ((not (web-mode-block-calls-beginning pos reg-beg))
   9172             )
   9173            ((cdr (assoc "lineup-calls" web-mode-indentation-params))
   9174             ;;(message "point=%S" (point))
   9175             (if (looking-back "::[ ]*" (point-min))
   9176                 (progn
   9177                   (re-search-backward "::[ ]*")
   9178                   (setq offset (current-column))
   9179                   ;;(message "ici%S offset=%S" (point) offset)
   9180                   )
   9181               (search-forward "->")
   9182               (setq offset (- (current-column) 2)))
   9183             )
   9184            (t
   9185             (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9186            ))
   9187 
   9188          ((and is-js (member ?\, chars))
   9189           (when debug (message "I400(%S) part-args" pos))
   9190           (cond
   9191            ((not (web-mode-part-args-beginning pos reg-beg))
   9192             ;;(message "ici")
   9193             )
   9194            ((cdr (assoc "lineup-args" web-mode-indentation-params))
   9195             (setq offset (current-column))
   9196             ;;(message "offset=%S" offset)
   9197             (when (eq curr-char ?\,)
   9198               (goto-char pos)
   9199               (looking-at ",[ \t\n]*")
   9200               (setq offset (- offset (length (match-string-no-properties 0)))))
   9201             )
   9202            (t
   9203             (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9204            ))
   9205 
   9206          ((member ?\, chars)
   9207           (when debug (message "I401(%S) block-args" pos))
   9208           (cond
   9209            ((not (web-mode-block-args-beginning pos reg-beg))
   9210             ;;(message "ici")
   9211             )
   9212            ((cdr (assoc "lineup-args" web-mode-indentation-params))
   9213             (setq offset (current-column))
   9214             ;;(message "offset=%S" offset)
   9215             (when (eq curr-char ?\,)
   9216               (goto-char pos)
   9217               (looking-at ",[ \t\n]*")
   9218               (setq offset (- offset (length (match-string-no-properties 0)))))
   9219             )
   9220            (t
   9221             (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9222            ))
   9223 
   9224 
   9225          ((and (string= language "php") (member ?\. chars))
   9226           (when debug (message "I410(%S) block-string" pos))
   9227           (cond
   9228            ((not (web-mode-block-string-beginning pos reg-beg))
   9229             )
   9230            ((null (cdr (assoc "lineup-concats" web-mode-indentation-params)))
   9231             (setq offset (+ (current-indentation) web-mode-code-indent-offset)))
   9232            ((not (eq curr-char ?\.))
   9233             (setq offset (current-column)))
   9234            (t
   9235             (setq offset (current-column))
   9236             (goto-char pos)
   9237             (when (cdr (assoc "lineup-quotes" web-mode-indentation-params))
   9238               (looking-at "\\.[ \t\n]*")
   9239               (setq offset (- offset (length (match-string-no-properties 0)))))
   9240             )))
   9241 
   9242          ((member language '("javascript" "jsx" "ejs" "underscore"))
   9243           (when debug (message "I420(%S) javascript-indentation" pos))
   9244           (setq offset (car (web-mode-javascript-indentation pos
   9245                                                              reg-col
   9246                                                              curr-indentation
   9247                                                              language
   9248                                                              reg-beg))))
   9249 
   9250          (t
   9251           (when debug (message "I430(%S) bracket-indentation" pos))
   9252           (setq offset (car (web-mode-bracket-indentation pos
   9253                                                           reg-col
   9254                                                           curr-indentation
   9255                                                           language
   9256                                                           reg-beg))))
   9257 
   9258          ) ;cond
   9259 
   9260         (when (and offset reg-col adjust (< offset reg-col)) (setq offset reg-col))
   9261 
   9262         ) ;let
   9263       ) ;save-excursion
   9264 
   9265     (when offset
   9266       ;;(message "offset=%S" offset)
   9267       (let ((diff (- (current-column) (current-indentation))))
   9268         (when (not (= offset (current-indentation)))
   9269           (setq web-mode-change-beg (line-beginning-position)
   9270                 web-mode-change-end (+ web-mode-change-beg offset)))
   9271         (setq offset (max 0 offset))
   9272         (indent-line-to offset)
   9273         (if (> diff 0) (move-to-column (+ (current-column) diff)))
   9274         (when (and (string= web-mode-engine "mason")
   9275                    (= offset 0)
   9276                    (eq char ?\%))
   9277           (save-excursion
   9278             (font-lock-fontify-region (line-beginning-position) (line-end-position)))
   9279           ) ;when
   9280         ) ;let
   9281       ) ;when
   9282 
   9283     ))
   9284 
   9285 (defun web-mode-bracket-level (pos limit)
   9286   (save-excursion
   9287     (let ((continue t)
   9288           (regexp "[\]\[}{)(]")
   9289           (char nil)
   9290           (map nil)
   9291           (key nil)
   9292           (value 0)
   9293           (open '(?\( ?\{ ?\[)))
   9294       (goto-char pos)
   9295       (while (and continue (re-search-backward regexp limit t))
   9296         (setq char (aref (match-string-no-properties 0) 0))
   9297         (setq key (cond ((eq char ?\)) ?\()
   9298                         ((eq char ?\}) ?\{)
   9299                         ((eq char ?\]) ?\[)
   9300                         (t             char)))
   9301         (setq value (or (plist-get map key) 0))
   9302         (setq value (if (member char open) (1+ value) (1- value)))
   9303         (setq map (plist-put map key value))
   9304         (setq continue (< value 1))
   9305         ;;(message "pos=%S char=%c key=%c value=%S" (point) char key value)
   9306         ) ;while
   9307       (if (>= value 1) (current-indentation) nil)
   9308       )))
   9309 
   9310 (defun web-mode-token-html-indentation (pos)
   9311   (save-excursion
   9312     (let (beg (continue t) end level map offset regexp tag val void (css-beg 0))
   9313       (goto-char pos)
   9314       ;;(message "pos=%S" pos)
   9315       (setq beg (web-mode-part-token-beginning-position pos))
   9316       (save-excursion
   9317         (when (and (> (- pos beg) 5)
   9318                    (re-search-backward "</?[a-zA-Z0-9]+" beg t)
   9319                    (string= "<style" (downcase (match-string-no-properties 0))))
   9320           (setq css-beg (point))
   9321           )
   9322         )
   9323       ;;(message "beg=%S" beg)
   9324       (cond
   9325        ((eq (char-after pos) ?\`)
   9326         (setq offset (web-mode-indentation-at-pos beg)))
   9327        ((web-mode-looking-back "`[ \n\t]*" pos)
   9328         (setq offset (+ (web-mode-indentation-at-pos beg) web-mode-markup-indent-offset)))
   9329        ((looking-at "</\\([a-zA-Z0-9]+\\)")
   9330         (setq tag (match-string-no-properties 1)
   9331               regexp (concat "</?" tag)
   9332               level -1)
   9333         (while (and continue (re-search-backward regexp beg t))
   9334           (cond
   9335            ((eq (aref (match-string-no-properties 0) 1) ?\/)
   9336             (setq level (1- level)))
   9337            (t
   9338             (setq level (1+ level)))
   9339            ) ;cond
   9340           (when (= level 0)
   9341             (setq continue nil
   9342                   offset (current-indentation)))
   9343           ) ;while
   9344         )
   9345        ((> css-beg 0)
   9346         ;;(message "CSS")
   9347         (cond
   9348          ((member (char-after) '(?\) ?\} ?\]))
   9349           (web-mode-go (web-mode-token-opening-paren-position pos (+ css-beg 8) ""))
   9350           (setq offset (current-indentation))
   9351           )
   9352          ((setq level (web-mode-bracket-level pos (+ css-beg 8)))
   9353           (setq offset (+ level web-mode-css-indent-offset))
   9354           )
   9355          (t
   9356           (setq offset (+ (web-mode-indentation-at-pos css-beg) web-mode-style-padding))
   9357           ) ;t
   9358          )
   9359         )
   9360        ((looking-at "[a-zA-Z-]+[ ]?=")
   9361         (re-search-backward "<[a-zA-Z]+[ ]*" beg t)
   9362         (setq offset (+ (current-column) (length (match-string-no-properties 0))))
   9363         )
   9364        ((looking-at-p "/>")
   9365         (search-backward "<" beg t)
   9366         (setq offset (current-column))
   9367         )
   9368        (t
   9369         (setq regexp "</?\\([a-zA-Z0-9]+\\)")
   9370         ;;(message "point=%S" (point))
   9371         (while (and continue (re-search-backward regexp beg t))
   9372           (setq tag (downcase (match-string-no-properties 1))
   9373                 end nil
   9374                 void nil)
   9375           (cond
   9376            ((eq (aref (match-string-no-properties 0) 1) ?/)
   9377             (setq end t))
   9378            ((web-mode-element-is-void tag)
   9379             (setq void t))
   9380            (t
   9381             (save-excursion
   9382               (when (and (search-forward ">" pos t) (eq (char-before (1- (point))) ?\/))
   9383                 (setq void t))
   9384               ) ;save-excursion
   9385             ) ;t
   9386            ) ;cond
   9387           (unless void
   9388             (setq val (or (lax-plist-get map tag) 0))
   9389             (setq val (if end (1- val) (1+ val)))
   9390             (setq map (lax-plist-put map tag val))
   9391             ;;(message "val=%S tag=%S end=%S | %S" val tag end (plist-get map tag))
   9392             (setq continue (not (> val 0)))
   9393             ) ;unless
   9394           ;(message "pos=%S tag=%S val=%S end=%S void=%S" (point) tag val end void)
   9395           ) ;while
   9396         (cond
   9397          ((> val 0)
   9398           ;;(message "point=%S" (point))
   9399           ;;(goto-char (1+ beg))
   9400           ;;(forward-char)
   9401           ;;(re-search-forward "[[:space:]]*")
   9402           (setq offset (+ (current-indentation) web-mode-markup-indent-offset)))
   9403          (t
   9404           (setq offset (current-indentation)))
   9405          )
   9406         ) ;t
   9407        ) ;cond
   9408       offset)))
   9409 
   9410 (defun web-mode-token-css-indentation (pos)
   9411   (save-excursion
   9412     (let (offset)
   9413       (goto-char pos)
   9414       (web-mode-part-token-beginning)
   9415       (setq offset (+ web-mode-css-indent-offset (current-indentation)))
   9416       ) ;let
   9417   ))
   9418 
   9419 (defun web-mode-relayql-indentation (pos &optional prefix)
   9420   (unless prefix (setq prefix "relayql"))
   9421   (let (beg offset level char)
   9422     (setq char (char-after))
   9423     (setq beg (web-mode-part-token-beginning-position pos))
   9424     (goto-char beg)
   9425     (cond
   9426      ((member char '(?\`))
   9427       (setq offset (current-indentation))
   9428       )
   9429      ((member char '(?\) ?\} ?\]))
   9430       (web-mode-go (web-mode-token-opening-paren-position pos beg prefix))
   9431       (setq offset (current-indentation))
   9432       )
   9433      ((setq level (web-mode-bracket-level pos beg))
   9434       (setq offset (+ level web-mode-code-indent-offset))
   9435       )
   9436      (t
   9437       (setq offset (+ (current-indentation) web-mode-code-indent-offset))
   9438       )
   9439      )
   9440     offset))
   9441 
   9442 (defun web-mode-markup-indentation (pos)
   9443   (let (offset beg ret jsx-depth)
   9444     (when (and (setq jsx-depth (get-text-property pos 'jsx-depth))
   9445                (get-text-property pos 'jsx-beg)
   9446                (not (get-text-property pos 'tag-beg)))
   9447       (setq jsx-depth (1- jsx-depth)))
   9448     ;;(when (setq beg (web-mode-markup-indentation-origin pos jsx-depth))
   9449     (cond
   9450      ((not (setq beg (web-mode-markup-indentation-origin pos jsx-depth)))
   9451       (setq offset 0))
   9452      ((null (setq ret (web-mode-element-is-opened beg pos)))
   9453       (setq offset (web-mode-indentation-at-pos beg)))
   9454      ((eq ret t)
   9455       (setq offset (+ (web-mode-indentation-at-pos beg)
   9456                       web-mode-markup-indent-offset)))
   9457      (t
   9458       (setq offset ret))
   9459      ) ;cond
   9460     ;;(message "markup-indentation-origin=%S (jsx-depth=%S)" beg jsx-depth)
   9461     ;;) ;when beg
   9462     offset))
   9463 
   9464 (defun web-mode-css-indentation (pos initial-column language-offset language &optional limit)
   9465   (let ((open-ctx (web-mode-bracket-up pos language limit)) offset)
   9466     (cond
   9467      ((or (null open-ctx) (null (plist-get open-ctx :pos)))
   9468       (setq offset initial-column))
   9469      (t
   9470       (setq offset (+ (plist-get open-ctx :indentation) language-offset)))
   9471      ) ;cond
   9472     (cons (if (< offset initial-column) initial-column offset) open-ctx)
   9473     ))
   9474 
   9475 (defun web-mode-sql-indentation (pos initial-column language-offset language &optional limit)
   9476   (let ((open-ctx (web-mode-bracket-up pos language limit)) offset)
   9477     ;;(message "%S %S %S %S %S" pos (point) initial-column language-offset open-ctx)
   9478     (cond
   9479      ((and (not (null open-ctx)) (not (null (plist-get open-ctx :pos))))
   9480       (setq offset (+ (plist-get open-ctx :column) 1)))
   9481      ((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\\)")
   9482       (setq offset initial-column))
   9483      (t
   9484       (setq offset (+ initial-column language-offset)))
   9485      ) ;cond
   9486     (cons (if (< offset initial-column) initial-column offset) open-ctx)
   9487     ))
   9488 
   9489 (defun web-mode-markdown-indentation (pos initial-column language-offset language &optional limit)
   9490   (let (offset)
   9491     (save-excursion
   9492       (goto-char pos)
   9493       (setq offset (current-column))
   9494       ) ;save-excursion
   9495     ;;(message "%S %S %S %S" pos (point) initial-column language-offset)
   9496     (cons (if (<= offset initial-column) initial-column offset) nil)))
   9497 
   9498 (defun web-mode-stylus-indentation (pos initial-column language-offset language &optional limit)
   9499   (let (offset)
   9500     (save-excursion
   9501       (goto-char pos)
   9502       (setq offset (current-column))
   9503       (if (looking-at-p "[[:alnum:]-]+:")
   9504           (setq offset (+ initial-column language-offset))
   9505         (setq offset initial-column))
   9506       ) ;save-excursion
   9507     ;;(message "%S %S %S %S" pos (point) initial-column language-offset)
   9508     (cons (if (<= offset initial-column) initial-column offset) nil)))
   9509 
   9510 (defun web-mode-sass-indentation (pos initial-column language-offset language &optional limit)
   9511   (let (offset)
   9512     (save-excursion
   9513       (goto-char pos)
   9514       (setq offset (current-column))
   9515       (if (looking-at-p "[[:alnum:]-]+:")
   9516           (setq offset (+ initial-column language-offset))
   9517         (setq offset initial-column))
   9518       ) ;save-excursion
   9519     ;;(message "%S %S %S %S" pos (point) initial-column language-offset)
   9520     (cons (if (<= offset initial-column) initial-column offset) nil)))
   9521 
   9522 (defun web-mode-pug-indentation (pos initial-column language-offset language &optional limit)
   9523   nil
   9524   )
   9525 
   9526 (defun web-mode-javascript-indentation (pos initial-column language-offset language &optional limit)
   9527   (let (open-ctx indentation offset sub)
   9528     (setq open-ctx (web-mode-bracket-up pos language limit))
   9529     ;;(message "pos(%S) initial-column(%S) language-offset(%S) language(%S) limit(%S)" pos initial-column language-offset language limit)
   9530     ;;(message "javascript-indentation: %S\nchar=%c" open-ctx (plist-get open-ctx :char))
   9531     (setq indentation (plist-get open-ctx :indentation))
   9532     (when (and initial-column (> initial-column indentation))
   9533       (setq indentation initial-column)
   9534       )
   9535     (setq case-fold-search nil) ; #1006
   9536     (cond
   9537      ((or (null open-ctx) (null (plist-get open-ctx :pos)))
   9538       (setq offset initial-column))
   9539      ((and (member language '("javascript" "jsx" "ejs"))
   9540            (eq (plist-get open-ctx :char) ?\{)
   9541            (web-mode-looking-back "switch[ ]*" (plist-get open-ctx :pos)))
   9542       (setq sub (if (cdr (assoc "case-extra-offset" web-mode-indentation-params)) 0 1))
   9543       (cond
   9544        ((looking-at-p "case\\|default")
   9545         (setq offset (+ indentation (* language-offset (- 1 sub)))))
   9546        (t
   9547         (setq offset (+ indentation (* language-offset (- 2 sub)))))
   9548        ) ;cond switch
   9549       )
   9550      (t
   9551       (setq offset (+ indentation language-offset)))
   9552      ) ;cond
   9553     (setq case-fold-search t)
   9554     (cons (if (< offset initial-column) initial-column offset) open-ctx)
   9555     ))
   9556 
   9557 (defun web-mode-bracket-indentation (pos initial-column language-offset language &optional limit)
   9558   (save-excursion
   9559     (let* ((ctx (web-mode-bracket-up pos language limit))
   9560            (char (plist-get ctx :char))
   9561            (pos (plist-get ctx :pos))
   9562            (indentation (plist-get ctx :indentation)))
   9563       ;;(message "pos(%S) initial-column(%S) language-offset(%S) language(%S) limit(%S)" pos initial-column language-offset language limit)
   9564       ;;(message "bracket-up: %S, %c" ctx char)
   9565       (cond
   9566        ((null pos)
   9567         (setq indentation initial-column))
   9568        ((and (member language '("php"))
   9569              (eq char ?\{)
   9570              (web-mode-looking-back "switch[ ]*" pos)
   9571              (not (looking-at-p "case\\|default")))
   9572         (setq indentation (+ indentation (* language-offset 2)))
   9573         )
   9574        ((and (member language '("php"))
   9575              (eq char ?\{)
   9576              (goto-char pos)
   9577              (web-mode-looking-back "[)][ ]*" pos)
   9578              (search-backward ")")
   9579              (web-mode-block-opening-paren limit))
   9580         (setq indentation (+ (current-indentation) language-offset))
   9581         )
   9582        (t
   9583         (setq indentation (+ indentation language-offset))
   9584         )
   9585        ) ;cond
   9586       (cons (if (< indentation initial-column) initial-column indentation) ctx)
   9587       )))
   9588 
   9589 (defun web-mode-ruby-indentation (pos line initial-column language-offset limit)
   9590   (unless limit (setq limit nil))
   9591   (let (h offset prev-line prev-indentation open-ctx)
   9592     (setq open-ctx (web-mode-bracket-up pos "ruby" limit))
   9593     ;;(message "%S" open-ctx)
   9594     (if (plist-get open-ctx :pos)
   9595         (cond
   9596          ((web-mode-looking-at-p ".[ \t\n]+" (plist-get open-ctx :pos))
   9597           (setq offset (+ (plist-get open-ctx :indentation) language-offset)))
   9598          (t
   9599           (setq offset (1+ (plist-get open-ctx :column))))
   9600          )
   9601       (setq h (web-mode-previous-line pos limit))
   9602       (setq offset initial-column)
   9603       (when h
   9604         (setq prev-line (car h))
   9605         (setq prev-indentation (cdr h))
   9606         (cond
   9607          ((string-match-p ",$" prev-line)
   9608           (save-excursion
   9609             (goto-char limit)
   9610             (looking-at "<%=? [a-z]+ ")
   9611             (setq offset (+ initial-column (length (match-string-no-properties 0))))
   9612             ) ;save-excursion
   9613           )
   9614          ((string-match-p "^[ ]*\\(end\\|else\\|elsif\\|when\\)" line)
   9615           (setq offset (- prev-indentation language-offset))
   9616           )
   9617          ((string-match-p "[ ]+\\(do\\)" prev-line)
   9618           (setq offset (+ prev-indentation language-offset))
   9619           )
   9620          ((string-match-p "^[ ]*\\(when\\|if\\|else\\|elsif\\|unless\\|for\\|while\\|def\\|class\\)" prev-line)
   9621           (setq offset (+ prev-indentation language-offset))
   9622           )
   9623          (t
   9624           (setq offset prev-indentation)
   9625           )
   9626          )
   9627         ) ;when
   9628       ) ;if
   9629     offset))
   9630 
   9631 (defun web-mode-python-indentation (pos line initial-column language-offset limit)
   9632   (unless limit (setq limit nil))
   9633   (let (h offset prev-line prev-indentation ctx)
   9634     (setq ctx (web-mode-bracket-up pos "python" limit))
   9635     ;;(message "point-ctx=%S" ctx)
   9636     (if (plist-get ctx :pos)
   9637         (cond
   9638          ((web-mode-looking-at-p ".[ \t\n]+" (plist-get ctx :pos))
   9639           (setq offset (+ (plist-get ctx :indentation) language-offset)))
   9640          (t
   9641           (setq offset (1+ (plist-get ctx :column))))
   9642          )
   9643       ;; else
   9644       (setq h (web-mode-previous-line pos limit))
   9645       (setq offset initial-column)
   9646       (when h
   9647         (setq prev-line (car h))
   9648         (setq prev-indentation (cdr h))
   9649         (cond
   9650          ((string-match-p "^\\(pass\\|else\\|elif\\|when\\|except\\)" line)
   9651           (setq offset (- prev-indentation language-offset))
   9652           )
   9653          ((string-match-p "\\(if\\|else\\|elif\\|for\\|while\\|try\\|except\\)" prev-line)
   9654           (setq offset (+ prev-indentation language-offset))
   9655           )
   9656          (t
   9657           (setq offset prev-indentation)
   9658           )
   9659          ) ;cond
   9660         ) ;when
   9661       ) ;if
   9662     ;;offset
   9663     (if (< offset initial-column) initial-column offset)
   9664     ))
   9665 
   9666 (defun web-mode-lisp-indentation (pos point-ctx)
   9667   (let (offset open-ctx)
   9668     (setq open-ctx (web-mode-bracket-up pos "lsp" (plist-get point-ctx :reg-beg)))
   9669     ;;(message "point-ctx=%S" point-ctx)
   9670     ;;(message "open-ctx=%S" open-ctx)
   9671     (cond
   9672      ((null (plist-get open-ctx :pos))
   9673       (setq offset (plist-get point-ctx :reg-col)))
   9674      ((member (plist-get point-ctx :curr-char) '(?\( ?\)))
   9675       (if (web-mode-looking-at-p "((" (plist-get open-ctx :pos))
   9676           (setq offset (+ (plist-get open-ctx :column) 1))
   9677         (setq offset (+ (plist-get open-ctx :column) web-mode-code-indent-offset)))
   9678       )
   9679      (t
   9680       (goto-char (plist-get open-ctx :pos))
   9681       (forward-char)
   9682       (web-mode-rsf "[[:alnum:]-:]+ ")
   9683       (setq offset (current-column))
   9684       )
   9685      ) ;cond
   9686     offset))
   9687 
   9688 (defun web-mode-asp-indentation (pos line initial-column language-offset limit)
   9689   (unless limit (setq limit nil))
   9690   (let (h out prev-line prev-indentation)
   9691     (setq h (web-mode-previous-line pos limit))
   9692     (setq out initial-column)
   9693     (when h
   9694       (setq prev-line (car h))
   9695       (setq prev-indentation (cdr h))
   9696       ;;(message "line=%S" line)
   9697       (cond
   9698        ((string-match-p "''" line)
   9699         (setq out prev-indentation))
   9700        ;; ----------------------------------------------------------------------
   9701        ;; unindent
   9702        ((string-match-p "\\_<\\(\\(end \\(if\\|function\\|class\\|sub\\|with\\)\\)\\|else\\|elseif\\|next\\|loop\\)\\_>" line)
   9703         (setq out (- prev-indentation language-offset)))
   9704        ;; ----------------------------------------------------------------------
   9705        ;; select case statement
   9706        ((string-match-p "\\_<\\(select case\\)\\_>" line)
   9707         (setq out (- prev-indentation 0)))
   9708        ((string-match-p "\\_<\\(end select\\)" line)
   9709         (setq out (- prev-indentation (* 2 language-offset))))
   9710        ((and (string-match-p "\\_<\\(case\\)\\_>" line) (not (string-match-p "\\_<\\(select case\\)\\_>" prev-line)))
   9711         (setq out (- prev-indentation language-offset)))
   9712        ;; ----------------------------------------------------------------------
   9713        ;; do nothing
   9714        ((string-match-p "\\_<\\(\\(end \\(if\\|function\\|class\\|sub\\|select\\|with\\)\\)\\|loop\\( until\\| while\\)?\\)\\_>" prev-line)
   9715         (setq out (+ prev-indentation 0)))
   9716        ;; indent
   9717        ((string-match-p "\\_<\\(\\(select \\)?case\\|else\\|elseif\\|unless\\|for\\|class\\|with\\|do\\( until\\| while\\)?\\|while\\|\\(public \\|private \\)?\\(function\\|sub\\|class\\)\\)\\_>" prev-line)
   9718         (setq out (+ prev-indentation language-offset)))
   9719        ;; single line if statement
   9720        ((string-match-p "\\_<if\\_>.*\\_<then\\_>[ \t]*[[:alpha:]]+" prev-line)
   9721         (setq out (+ prev-indentation 0)))
   9722        ;; normal if statement
   9723        ((string-match-p "\\_<\\if\\_>" prev-line)
   9724         (setq out (+ prev-indentation language-offset)))
   9725        (t
   9726         (setq out prev-indentation))
   9727        )
   9728       ) ;when
   9729     out))
   9730 
   9731 (defun web-mode-block-previous-live-line ()
   9732   (save-excursion
   9733     (let ((continue t) (line "") (pos (point)))
   9734       (beginning-of-line)
   9735       (while (and continue (not (bobp)) (forward-line -1))
   9736         (when (not (web-mode-block-is-token-line))
   9737           (setq line (web-mode-trim (buffer-substring (point) (line-end-position)))))
   9738         (when (not (string= line ""))
   9739           (setq continue nil))
   9740         ) ;while
   9741       (if (string= line "")
   9742           (progn (goto-char pos) nil)
   9743         (cons line (current-indentation)))
   9744       )))
   9745 
   9746 (defun web-mode-part-is-opener (pos reg-beg)
   9747   (save-excursion
   9748     (save-match-data
   9749       (if (and pos
   9750                (web-mode-go (web-mode-part-opening-paren-position pos))
   9751                (>= (point) reg-beg)
   9752                (looking-back "\\(^\\|[ \t]\\)\\(if\\|for\\|while\\)[ ]*" (point-min)))
   9753           (current-indentation)
   9754         nil)
   9755       )))
   9756 
   9757 (defun web-mode-part-previous-live-line (reg-beg)
   9758   (unless reg-beg (setq reg-beg (point-min)))
   9759   ;;(message "reg-beg=%S" reg-beg)
   9760   (save-excursion
   9761     (let ((continue (> (point) reg-beg))
   9762           (line "")
   9763           bol-pos
   9764           eol-pos
   9765           pos)
   9766       (beginning-of-line)
   9767       (while (and continue (> (point) reg-beg) (forward-line -1))
   9768         (setq bol-pos (point)
   9769               eol-pos (line-end-position))
   9770         (when (> reg-beg bol-pos)
   9771           (setq bol-pos reg-beg))
   9772         (when (not (web-mode-part-is-token-line bol-pos))
   9773           (setq line (web-mode-trim (buffer-substring bol-pos eol-pos)))
   9774           (when (not (string= line "")) (setq continue nil))
   9775           ) ;when
   9776         ) ;while
   9777       (cond
   9778        ((string= line "")
   9779         nil)
   9780        (t
   9781         (setq continue t)
   9782         (setq pos (1- eol-pos))
   9783         (while (and (>= pos bol-pos) continue)
   9784           (cond
   9785            ((eq (char-after pos) ?\s)
   9786             (setq pos (1- pos)))
   9787            ((get-text-property pos 'part-token)
   9788             (setq pos (1- pos)))
   9789            (t
   9790             (setq continue nil))
   9791            ) ;cond
   9792           ) ;while
   9793         ;;(message "%S %S : %S" bol-pos eol-pos pos)
   9794         (setq line (web-mode-clean-part-line line))
   9795         (list line (current-indentation) pos))
   9796        ) ;cond
   9797       )))
   9798 
   9799 (defun web-mode-in-code-block (open close &optional prop)
   9800   (save-excursion
   9801     (let ((pos (point)) pos-open pos-close start end ret)
   9802       (when prop
   9803         (setq start pos
   9804               end pos)
   9805         (when (eq (get-text-property pos prop) (get-text-property (1- pos) prop))
   9806           (setq start (or (previous-single-property-change pos prop) (point-min))))
   9807         (when (eq (get-text-property pos prop) (get-text-property (1+ pos) prop))
   9808           (setq end (next-single-property-change pos prop)))
   9809         ;;        (message "start(%S) end(%S)" start end)
   9810         )
   9811       (setq ret (and (web-mode-sb open start t)
   9812                      (setq pos-open (point))
   9813                      (web-mode-sf close end t)
   9814                      (setq pos-close (point))
   9815                      (>= pos-close pos)))
   9816       (if ret
   9817           (cons pos-open pos-close)
   9818         ret)
   9819       )))
   9820 
   9821 (defun web-mode-clean-part-line (input)
   9822   (let ((out "")
   9823         (beg 0)
   9824         (keep t)
   9825         (n (length input)))
   9826     (dotimes (i n)
   9827       (if (or (get-text-property i 'block-side input)
   9828               (eq (get-text-property i 'part-token input) 'comment)
   9829               (eq (get-text-property i 'tag-type input) 'comment))
   9830           (when keep
   9831             (setq out (concat out (substring input beg i))
   9832                   beg 0
   9833                   keep nil))
   9834         (when (null keep)
   9835           (setq beg i
   9836                 keep t))
   9837         ) ;if
   9838       ) ;dotimes
   9839     (if (> beg 0) (setq out (concat out (substring input beg n))))
   9840     (setq out (if (= (length out) 0) input out))
   9841     (web-mode-trim out)
   9842     ))
   9843 
   9844 (defun web-mode-clean-block-line (input)
   9845   (let ((out "")
   9846         (beg 0)
   9847         (keep t)
   9848         (n (length input)))
   9849     (dotimes (i n)
   9850       (if (or (not (get-text-property i 'block-side input))
   9851               (member (get-text-property i 'block-token input)
   9852                       '(comment delimiter-beg delimiter-end)))
   9853           (when keep
   9854             (setq out (concat out (substring input beg i))
   9855                   beg 0
   9856                   keep nil))
   9857         (when (null keep)
   9858           (setq beg i
   9859                 keep t))
   9860         ) ;if
   9861       ) ;dotimes
   9862     (if (> beg 0) (setq out (concat out (substring input beg n))))
   9863     (setq out (if (= (length out) 0) input out))
   9864     (web-mode-trim out)
   9865     ;;    (message "%S [%s] > [%s]" beg input out)
   9866     ))
   9867 
   9868 (defun web-mode-language-at-pos (&optional pos)
   9869   (unless pos (setq pos (point)))
   9870   (cond
   9871    ((get-text-property pos 'block-side)
   9872     web-mode-engine)
   9873    ((get-text-property pos 'part-side)
   9874     (symbol-name (get-text-property pos 'part-side)))
   9875    (t
   9876     web-mode-content-type)
   9877    ) ;cond
   9878   )
   9879 
   9880 (defun web-mode-coord-position (line column)
   9881   (save-excursion
   9882     (when (stringp line) (setq line (string-to-number line)))
   9883     (when (stringp column) (setq column (string-to-number column)))
   9884     (goto-char (point-min))
   9885     (forward-line (1- line))
   9886     (move-to-column (1- column))
   9887     (point)))
   9888 
   9889 (defun web-mode-is-single-line-block (pos)
   9890   (= (web-mode-line-number (web-mode-block-beginning-position pos))
   9891      (web-mode-line-number (web-mode-block-end-position pos))))
   9892 
   9893 (defun web-mode-line-number (&optional pos)
   9894   (setq pos (or pos (point)))
   9895   (+ (count-lines 1 pos) (if (= (web-mode-column-at-pos pos) 0) 1 0)))
   9896 
   9897 (defun web-mode-block-is-control (pos)
   9898   (save-excursion
   9899     (let (control state controls pair)
   9900       (goto-char pos)
   9901       (setq controls (web-mode-block-controls-get pos))
   9902       (setq pair (car controls))
   9903       (cond
   9904        ((eq (car pair) 'inside)
   9905         )
   9906        ((eq (car pair) 'open)
   9907         (setq state t
   9908               control (cdr pair)))
   9909        ((eq (car pair) 'close)
   9910         (setq state nil
   9911               control (cdr pair)))
   9912        ) ;cond
   9913       ;;      (message "engine=%S control=%S state=%S" web-mode-engine control state)
   9914       (if control (cons control state) nil)
   9915       )))
   9916 
   9917 (defun web-mode-block-is-opening-control (pos)
   9918   (save-excursion
   9919     (let (controls pair)
   9920       (goto-char pos)
   9921       (if (and (setq controls (web-mode-block-controls-get pos))
   9922                (= (length controls) 1)
   9923                (setq pair (car controls))
   9924                (eq (car pair) 'open))
   9925           (cdr pair)
   9926         nil)
   9927       )))
   9928 
   9929 (defun web-mode-markup-indentation-origin (pos jsx-depth)
   9930   (save-excursion
   9931     (let* ((found (bobp))
   9932            (jsx-beg nil)
   9933            (types '(start end void))
   9934            (type nil))
   9935       (when jsx-depth
   9936         (setq jsx-beg (web-mode-jsx-depth-beginning-position pos jsx-depth)))
   9937       (while (not found)
   9938         (forward-line -1)
   9939         (if (bobp)
   9940             (setq pos (point)
   9941                   found t)
   9942           (back-to-indentation)
   9943           (when (and jsx-beg (< (point) jsx-beg))
   9944             (goto-char jsx-beg))
   9945           (setq pos (point))
   9946           (setq type (get-text-property pos 'tag-type))
   9947           (setq found (or (and (null jsx-depth)
   9948                                (null (get-text-property pos 'part-side))
   9949                                (get-text-property pos 'tag-beg)
   9950                                (member type types)
   9951                                (null (get-text-property (1- pos) 'invisible)))
   9952                           (and (null jsx-depth)
   9953                                (null (get-text-property pos 'part-side))
   9954                                (eq (get-text-property pos 'tag-type) 'comment)
   9955                                (web-mode-looking-at-p "<!--#\\(endif\\|if\\)" pos)
   9956                                (null (get-text-property (1- pos) 'invisible)))
   9957                           (and jsx-depth
   9958                                (get-text-property pos 'tag-beg)
   9959                                (member type types)
   9960                                (null (get-text-property (1- pos) 'invisible))
   9961                                (eq (get-text-property pos 'jsx-depth) jsx-depth))
   9962                           (and (get-text-property pos 'block-beg)
   9963                                (not type)
   9964                                (web-mode-block-is-control pos)
   9965                                (not (looking-at-p "{% commen\\|@break")))))
   9966           ) ;if
   9967         ) ;while
   9968       ;;(message "indent-origin=%S" pos)
   9969       pos)))
   9970 
   9971 ;;TODO : prendre en compte part-token
   9972 ;; state=t <=> start tag
   9973 (defun web-mode-element-is-opened (pos limit)
   9974   (let (tag
   9975         last-end-tag
   9976         tag-pos block-pos
   9977         state
   9978         n
   9979         ret
   9980         (continue t)
   9981         controls
   9982         control
   9983         (buffer (current-buffer))
   9984         (h (make-hash-table :test 'equal))
   9985         (h2 (make-hash-table :test 'equal)))
   9986 
   9987 ;;    (message "pos-ori=%S limit=%S" pos limit)
   9988 
   9989     (while continue
   9990       (setq control nil
   9991             controls nil
   9992             last-end-tag nil
   9993             tag nil)
   9994 
   9995       (cond
   9996        ((and (eq (get-text-property pos 'tag-type) 'comment)
   9997              (web-mode-looking-at "<!--#\\(endif\\|if\\)" pos))
   9998         ;;(message "pos=%S" pos)
   9999         (setq tag "#if")
  10000         (setq n (gethash tag h 0))
  10001         (if (string= (match-string-no-properties 1) "if")
  10002             (puthash tag (1+ n) h)
  10003           (puthash tag (1- n) h))
  10004         ;;(setq tag-pos pos)
  10005         )
  10006        ((get-text-property pos 'tag-beg)
  10007         (when (member (get-text-property pos 'tag-type) '(start end))
  10008           (setq tag (get-text-property pos 'tag-name)
  10009                 state (eq (get-text-property pos 'tag-type) 'start))
  10010           (if (null state) (setq last-end-tag (cons tag pos)))
  10011           (setq n (gethash tag h 0))
  10012           (cond
  10013            ((null state)
  10014             (when (> n 0) (puthash tag (1- n) h))
  10015             (puthash tag (1- n) h2))
  10016            ((member tag web-mode-offsetless-elements)
  10017             )
  10018            (t
  10019             (puthash tag (1+ n) h)
  10020             (puthash tag (1+ n) h2))
  10021            ) ;cond
  10022           ) ;when
  10023         (when (setq pos (web-mode-tag-end-position pos))
  10024           (setq tag-pos nil)
  10025           (when (and block-pos (> pos block-pos))
  10026             (setq block-pos nil))
  10027           ) ;when
  10028         )
  10029        ((and web-mode-enable-control-block-indentation
  10030              (get-text-property pos 'block-beg))
  10031         (when (setq controls (web-mode-block-controls-get pos))
  10032           (dolist (control controls)
  10033             (setq tag (cdr control))
  10034             (setq n (gethash tag h 0))
  10035             (cond
  10036              ((eq (car control) 'inside)
  10037               )
  10038              ((eq (car control) 'open)
  10039               (puthash tag (1+ n) h))
  10040              ((> n 0)
  10041               (puthash tag (1- n) h))
  10042              ) ;cond
  10043             ) ;dolist
  10044           )
  10045         (when (setq pos (web-mode-block-end-position pos))
  10046           (setq block-pos nil)
  10047           (when (and tag-pos (> pos tag-pos))
  10048             (setq tag-pos nil))
  10049           )
  10050         )
  10051        ) ;cond
  10052 
  10053 ;;      (message "tag=%S end-pos=%S" tag pos)
  10054 
  10055       (when (and pos (< pos limit))
  10056         (when (or (null tag-pos) (>= pos tag-pos))
  10057           (setq tag-pos (web-mode-tag-next-position pos limit))
  10058 ;;          (message "from=%S tag-next-pos=%S" pos tag-pos)
  10059           )
  10060         (when (or (null block-pos) (>= pos block-pos))
  10061           (setq block-pos (web-mode-block-next-position pos limit))
  10062 ;;          (message "from=%S block-next-pos=%S" pos block-pos)
  10063           )
  10064         )
  10065 
  10066       (cond
  10067        ((null pos)
  10068         )
  10069        ((and (null tag-pos)
  10070              (null block-pos))
  10071         (setq pos nil))
  10072        ((and tag-pos block-pos)
  10073         (if (< tag-pos block-pos)
  10074             (progn
  10075               (setq pos tag-pos)
  10076               (setq tag-pos nil))
  10077           (setq pos block-pos)
  10078           (setq block-pos nil))
  10079         )
  10080        ((null tag-pos)
  10081         (setq pos block-pos)
  10082         (setq block-pos nil))
  10083        (t
  10084         (setq pos tag-pos)
  10085         (setq tag-pos nil))
  10086        )
  10087 
  10088       (when (or (null pos)
  10089                 (>= pos limit))
  10090         (setq continue nil))
  10091       ) ;while
  10092 
  10093     ;;(message "hashtable=%S" h)
  10094     (maphash (lambda (k v) (if (> v 0) (setq ret t))) h)
  10095 
  10096     (when (and (null ret)
  10097                last-end-tag
  10098                (> (hash-table-count h2) 1)
  10099                (< (gethash (car last-end-tag) h2) 0))
  10100 ;;      (message "last-end-tag=%S" last-end-tag)
  10101       (save-excursion
  10102         (goto-char (cdr last-end-tag))
  10103         (web-mode-tag-match)
  10104         (when (not (= (point) (cdr last-end-tag)))
  10105           (setq n (point))
  10106           (back-to-indentation)
  10107           (if (= n (point)) (setq ret (current-indentation))))
  10108         ))
  10109 
  10110     ret))
  10111 
  10112 (defun web-mode-previous-line (pos limit)
  10113   (save-excursion
  10114     (let (beg end line (continue t))
  10115       (goto-char pos)
  10116       (while continue
  10117         (forward-line -1)
  10118         (setq end (line-end-position))
  10119         (setq line (buffer-substring-no-properties (point) end))
  10120         (when (or (not (string-match-p "^[ \t]*$" line))
  10121                   (bobp)
  10122                   (<= (point) limit))
  10123           (setq continue nil))
  10124         )
  10125       (if (<= (point) limit)
  10126           ;;todo : affiner (le + 3 n est pas générique cf. <?php <% <%- etc.)
  10127           (setq beg (if (< (+ limit 3) end) (+ limit 3) end))
  10128         (setq beg (line-beginning-position))
  10129         ) ;if
  10130       (setq line (buffer-substring-no-properties beg end))
  10131       (cons line (current-indentation))
  10132       )))
  10133 
  10134 (defun web-mode-bracket-up (pos language &optional limit)
  10135   (unless limit (setq limit nil))
  10136   ;;(message "pos(%S) language(%S) limit(%S)" pos language limit)
  10137   (save-excursion
  10138     (goto-char pos)
  10139     (let ((continue t)
  10140           (regexp "[\]\[}{)(]")
  10141           (char nil)
  10142           (column nil)
  10143           (indentation nil)
  10144           (map nil)
  10145           (key nil)
  10146           (value 0)
  10147           (open '(?\( ?\{ ?\[))
  10148           (searcher nil)
  10149           (opener nil))
  10150       (cond
  10151        ((get-text-property pos 'block-side)
  10152         (setq searcher 'web-mode-block-rsb
  10153               opener 'web-mode-block-opening-paren-position))
  10154        (t
  10155         (setq searcher 'web-mode-part-rsb
  10156               opener 'web-mode-part-opening-paren-position))
  10157        )
  10158       (while (and continue (funcall searcher regexp limit))
  10159         (setq char (aref (match-string-no-properties 0) 0))
  10160         (setq key (cond ((eq char ?\)) ?\()
  10161                         ((eq char ?\}) ?\{)
  10162                         ((eq char ?\]) ?\[)
  10163                         (t             char)))
  10164         (setq value (or (plist-get map key) 0))
  10165         (setq value (if (member char open) (1+ value) (1- value)))
  10166         (setq map (plist-put map key value))
  10167         (setq continue (< value 1))
  10168         ;;(message "pos=%S char=%c key=%c value=%S map=%S" (point) char key value map)
  10169         ) ;while
  10170       (setq column (current-column)
  10171             indentation (current-indentation))
  10172       (when (and (> value 0)
  10173                  (eq char ?\{)
  10174                  (looking-back ")[ ]*" (point-min)))
  10175         (search-backward ")")
  10176         (when (setq pos (funcall opener (point) limit))
  10177           (goto-char pos)
  10178           ;;(message "pos=%S" pos)
  10179           (setq indentation (current-indentation)))
  10180         ) ;when
  10181       (list :pos (if (> value 0) (point) nil)
  10182             :char char
  10183             :column column
  10184             :indentation indentation)
  10185       ) ;let
  10186     ))
  10187 
  10188 (defun web-mode-count-char-in-string (char string)
  10189   (let ((n 0))
  10190     (dotimes (i (length string))
  10191       (if (eq (elt string i) char)
  10192           (setq n (1+ n))))
  10193     n))
  10194 
  10195 (defun web-mode-mark-and-expand ()
  10196   "Mark and expand."
  10197   (interactive)
  10198   (web-mode-mark (point)))
  10199 
  10200 (defun web-mode-mark (pos)
  10201   (let ((beg pos) (end pos) prop reg-beg boundaries)
  10202 
  10203     (if mark-active
  10204         (setq reg-beg (region-beginning))
  10205       (setq web-mode-expand-initial-pos (point)
  10206             web-mode-expand-initial-scroll (window-start))
  10207       )
  10208 
  10209     ;; (message "regs=%S %S %S %S" (region-beginning) (region-end) (point-min) (point-max))
  10210     ;; (message "before=%S" web-mode-expand-previous-state)
  10211 
  10212     (cond
  10213 
  10214      ((and mark-active
  10215            (= (region-beginning) (point-min))
  10216            (or (= (region-end) (point-max))
  10217                (= (1+ (region-end)) (point-max))))
  10218       (deactivate-mark)
  10219       (goto-char (or web-mode-expand-initial-pos (point-min)))
  10220       (setq web-mode-expand-previous-state nil)
  10221       (when web-mode-expand-initial-scroll
  10222         (set-window-start (selected-window) web-mode-expand-initial-scroll))
  10223       )
  10224 
  10225      ((string= web-mode-expand-previous-state "elt-content")
  10226       (web-mode-element-parent)
  10227       ;;(message "pos=%S" (point))
  10228       (web-mode-element-select)
  10229       (setq web-mode-expand-previous-state "html-parent"))
  10230 
  10231      ((and (member (get-text-property pos 'block-token) '(comment string))
  10232            (not (member web-mode-expand-previous-state '("block-token" "block-body" "block-side"))))
  10233       (when (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token))
  10234         (setq beg (or (previous-single-property-change pos 'block-token) (point-min))))
  10235       (when (eq (get-text-property pos 'block-token) (get-text-property (1+ pos) 'block-token))
  10236         (setq end (next-single-property-change pos 'block-token)))
  10237       (set-mark beg)
  10238       (goto-char end)
  10239       (exchange-point-and-mark)
  10240       (setq web-mode-expand-previous-state "block-token"))
  10241 
  10242      ((and (get-text-property pos 'block-side)
  10243            (not (member web-mode-expand-previous-state '("block-body" "block-side")))
  10244            (not (member web-mode-engine '(django go)))
  10245            (setq boundaries (web-mode-in-code-block "{" "}" 'block-side)))
  10246       (set-mark (car boundaries))
  10247       (goto-char (cdr boundaries))
  10248       (exchange-point-and-mark)
  10249       (setq web-mode-expand-previous-state "block-body"))
  10250 
  10251      ((and (get-text-property pos 'block-side)
  10252            (not (member web-mode-expand-previous-state '("block-side"))))
  10253       (set-mark (web-mode-block-beginning-position pos))
  10254       (goto-char (1+ (web-mode-block-end-position pos)))
  10255       (exchange-point-and-mark)
  10256       (setq web-mode-expand-previous-state "block-side"))
  10257 
  10258      ((and (get-text-property pos 'part-token)
  10259            (not (string= web-mode-expand-previous-state "part-token")))
  10260       (when (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token))
  10261         (setq beg (previous-single-property-change pos 'part-token)))
  10262       (when (eq (get-text-property pos 'part-token) (get-text-property (1+ pos) 'part-token))
  10263         (setq end (next-single-property-change pos 'part-token)))
  10264       (set-mark beg)
  10265       (goto-char end)
  10266       (exchange-point-and-mark)
  10267       (setq web-mode-expand-previous-state "part-token"))
  10268 
  10269      ((and (get-text-property pos 'part-side)
  10270            (not (string= web-mode-expand-previous-state "client-part"))
  10271            (setq boundaries (web-mode-in-code-block "{" "}" 'part-side)))
  10272       (set-mark (car boundaries))
  10273       (goto-char (cdr boundaries))
  10274       (exchange-point-and-mark)
  10275       (setq web-mode-expand-previous-state "client-part"))
  10276 
  10277      ((and (get-text-property pos 'part-side)
  10278            (not (string= web-mode-expand-previous-state "part-side")))
  10279       (when (eq (get-text-property pos 'part-side) (get-text-property (1- pos) 'part-side))
  10280         (setq beg (previous-single-property-change pos 'part-side)))
  10281       (when (eq (get-text-property pos 'part-side) (get-text-property (1+ pos) 'part-side))
  10282         (setq end (next-single-property-change pos 'part-side)))
  10283       (when (eq (char-after beg) ?\n)
  10284         (setq beg (1+ beg)))
  10285       (set-mark beg)
  10286       (goto-char end)
  10287       (when (looking-back "^[ \t]+" (point-min))
  10288         (beginning-of-line))
  10289       (exchange-point-and-mark)
  10290       (setq web-mode-expand-previous-state "part-side"))
  10291 
  10292      ((and (get-text-property pos 'tag-attr)
  10293            (not (member web-mode-expand-previous-state '("html-attr" "html-tag"))))
  10294       (web-mode-attribute-select pos)
  10295       (setq web-mode-expand-previous-state "html-attr"))
  10296 
  10297      ((and (eq (get-text-property pos 'tag-type) 'comment)
  10298            (not (member web-mode-expand-previous-state '("html-tag" "html-comment" "html-elt" "html-parent"))))
  10299       (web-mode-tag-select)
  10300       (setq web-mode-expand-previous-state "html-comment"))
  10301 
  10302      ((and (get-text-property pos 'tag-name)
  10303            (not (member web-mode-expand-previous-state '("html-tag" "html-elt" "html-parent"))))
  10304       (web-mode-tag-select)
  10305       (setq web-mode-expand-previous-state "html-tag"))
  10306 
  10307      ((and (get-text-property pos 'tag-beg)
  10308            (string= web-mode-expand-previous-state "html-tag"))
  10309       (web-mode-element-select)
  10310       (setq web-mode-expand-previous-state "html-elt"))
  10311 
  10312      (t
  10313       (cond
  10314        ((not (web-mode-element-parent))
  10315         (push-mark (point))
  10316         (push-mark (point-max) nil t)
  10317         (goto-char (point-min))
  10318         (setq web-mode-expand-previous-state "mark-whole"))
  10319        ((not (= (web-mode-tag-end-position (point)) (1- beg)))
  10320         (web-mode-element-content-select)
  10321         (setq web-mode-expand-previous-state "elt-content"))
  10322        (t
  10323         (web-mode-element-select)
  10324         (setq web-mode-expand-previous-state "html-parent"))
  10325        )
  10326       ) ;t
  10327 
  10328      ) ;cond
  10329 
  10330     ;;(message "w=%S" (window-end))
  10331     ;;(message "after=%S" web-mode-expand-previous-state)
  10332 
  10333     ))
  10334 
  10335 (defun web-mode-block-kill ()
  10336   "Kill the current block."
  10337   (interactive)
  10338   (web-mode-block-select)
  10339   (when mark-active
  10340     (kill-region (region-beginning) (region-end))))
  10341 
  10342 (defun web-mode-block-select ()
  10343   "Select the current block."
  10344   (interactive)
  10345   (let (beg)
  10346     (when (setq beg (web-mode-block-beginning-position (point)))
  10347       (goto-char beg)
  10348       (set-mark (point))
  10349       (web-mode-block-end)
  10350       (exchange-point-and-mark))
  10351     beg))
  10352 
  10353 (defun web-mode-tag-select ()
  10354   "Select the current html tag."
  10355   (interactive)
  10356   (let (beg)
  10357     (when (setq beg (web-mode-tag-beginning-position (point)))
  10358       (goto-char beg)
  10359       (set-mark (point))
  10360       (web-mode-tag-end)
  10361       (exchange-point-and-mark))
  10362     beg))
  10363 
  10364 (defun web-mode-element-content-select ()
  10365   "Select the content of a html element."
  10366   (interactive)
  10367   (let (pos beg end)
  10368     (web-mode-element-select)
  10369     (when mark-active
  10370       (setq pos (point))
  10371       (deactivate-mark)
  10372       (web-mode-tag-match)
  10373       (setq end (point))
  10374       (goto-char pos)
  10375       (web-mode-tag-end)
  10376       (set-mark (point))
  10377       (goto-char end)
  10378       (exchange-point-and-mark)
  10379       )))
  10380 
  10381 (defun web-mode-element-select ()
  10382   "Select the current html element (including opening and closing tags)."
  10383   (interactive)
  10384   (let* ((pos (point))
  10385          (type (get-text-property pos 'tag-type)))
  10386     (cond
  10387      ((not type)
  10388       (web-mode-element-parent)
  10389       (unless (= (point) pos) (web-mode-element-select)))
  10390      ((member type '(start void))
  10391       (web-mode-tag-beginning)
  10392       (set-mark (point))
  10393       (web-mode-tag-match)
  10394       (web-mode-tag-end)
  10395       (exchange-point-and-mark))
  10396      (t
  10397       (web-mode-tag-match)
  10398       (set-mark (point))
  10399       (web-mode-tag-match)
  10400       (web-mode-tag-end)
  10401       (exchange-point-and-mark))
  10402      )))
  10403 
  10404 (defun web-mode-element-is-collapsed (&optional pos)
  10405   (unless pos (setq pos (point)))
  10406   (let (boundaries)
  10407     (and (setq boundaries (web-mode-element-boundaries pos))
  10408          (or (= (car (car boundaries)) (car (cdr boundaries)))
  10409              (= (cdr (car boundaries)) (1- (car (cdr boundaries)))))
  10410          )))
  10411 
  10412 (defun web-mode-element-contract ()
  10413   "Flatten elements."
  10414   (interactive)
  10415   (let (beg end (continue t) replacement boundaries)
  10416     (cond
  10417      ((or (not (get-text-property (point) 'tag-type))
  10418           (not (member (get-text-property (point) 'tag-type) '(start end))))
  10419       (web-mode-element-parent))
  10420      ((eq (get-text-property (point) 'tag-type) 'end)
  10421       (web-mode-tag-match))
  10422      ) ;cond
  10423     (setq boundaries (web-mode-element-boundaries (point)))
  10424     (setq beg (car (car boundaries))
  10425           end (cdr (cdr boundaries)))
  10426     (goto-char beg)
  10427     ;;(message "beg(%S) end(%S)" beg end)
  10428     (while continue
  10429       (if (or (not (re-search-forward ">[ \t\r\n]+\\|[ \t\r\n]+<"))
  10430               (>= (point) end))
  10431           (setq continue nil)
  10432         (setq end (+ (- end (length (match-string-no-properties 0))) 1))
  10433         (setq replacement (if (eq (char-before) ?\<) "<" ">"))
  10434         (replace-match replacement nil nil)
  10435         ;;(message "end(%S)" end))
  10436         )
  10437       ) ;while
  10438     (goto-char beg)
  10439     ))
  10440 
  10441 (defun web-mode-element-extract ()
  10442   "Flatten element."
  10443   (interactive)
  10444   (let (beg end (continue t) save boundaries)
  10445     (cond
  10446      ((or (not (get-text-property (point) 'tag-type))
  10447           (not (member (get-text-property (point) 'tag-type) '(start end))))
  10448       (web-mode-element-parent))
  10449      ((eq (get-text-property (point) 'tag-type) 'end)
  10450       (web-mode-tag-match))
  10451      ) ;cond
  10452     (setq boundaries (web-mode-element-boundaries (point)))
  10453     (setq beg (car (car boundaries))
  10454           end (cdr (cdr boundaries)))
  10455     (goto-char beg)
  10456     (while continue
  10457       (if (or (not (and (or (get-text-property (point) 'tag-type) (web-mode-tag-next))
  10458                         (web-mode-tag-end)))
  10459               (>= (point) end))
  10460           (setq continue nil)
  10461         (setq save (point))
  10462         ;;(message "point(%S)" (point))
  10463         (skip-chars-forward "\n\t ")
  10464         (when (get-text-property (point) 'tag-type)
  10465           (newline)
  10466           (indent-according-to-mode)
  10467           (setq end (+ end (- (point) save))))
  10468         ) ;if
  10469       ) ;while
  10470     (goto-char beg)
  10471     ))
  10472 
  10473 (defun web-mode-element-transpose ()
  10474   "Transpose two html elements."
  10475   (interactive)
  10476   (let (pos start1 end1 start2 end2)
  10477     (save-excursion
  10478       (setq pos (point))
  10479       (cond
  10480        ((get-text-property pos 'tag-type)
  10481         (setq start1 (web-mode-element-beginning-position pos)
  10482               end1 (1+ (web-mode-element-end-position pos)))
  10483         )
  10484        ((setq start1 (web-mode-element-parent-position pos))
  10485         (setq end1 (1+ (web-mode-element-end-position pos)))
  10486         )
  10487        ) ;cond
  10488       (when (and start1 end1 (> end1 0))
  10489         (goto-char end1)
  10490         (unless (get-text-property (point) 'tag-beg)
  10491           (skip-chars-forward "\n\t "))
  10492         (when (get-text-property (point) 'tag-beg)
  10493           (setq start2 (web-mode-element-beginning-position (point))
  10494                 end2 (1+ (web-mode-element-end-position (point))))
  10495           )
  10496         )
  10497       (transpose-regions start1 end1 start2 end2)
  10498       ) ;save-excursion
  10499     start2))
  10500 
  10501 (defun web-mode-element-children-comment (&optional pos)
  10502   "Comment all the children of the current html element."
  10503   (interactive)
  10504   (unless pos (setq pos (point)))
  10505   (save-excursion
  10506     (dolist (child (reverse (web-mode-element-children pos)))
  10507       (goto-char child)
  10508       (web-mode-comment (point)))
  10509     ))
  10510 
  10511 (defun web-mode-element-mute-blanks ()
  10512   "Mute blanks."
  10513   (interactive)
  10514   (let (pos parent beg end children elt)
  10515     (setq pos (point))
  10516     (save-excursion
  10517       (when (and (setq parent (web-mode-element-boundaries pos))
  10518                  (web-mode-element-child-position (point)))
  10519         (setq children (reverse (web-mode-element-children)))
  10520         (goto-char (car (cdr parent)))
  10521         (dolist (child children)
  10522           (setq elt (web-mode-element-boundaries child))
  10523           (when (> (point) (1+ (cddr elt)))
  10524             (when (and (not (eq (get-text-property (point) 'part-token) 'comment))
  10525                        (not (eq (get-text-property (1+ (cddr elt)) 'part-token) 'comment)))
  10526               (web-mode-insert-text-at-pos "-->" (point))
  10527               (web-mode-insert-text-at-pos "<!--" (1+ (cddr elt))))
  10528             )
  10529           (goto-char child)
  10530           )
  10531         (when (and (> (point) (1+ (cdr (car parent))))
  10532                    (not (eq (get-text-property (point) 'part-token) 'comment))
  10533                    (not (eq (get-text-property (1+ (cdr (car parent))) 'part-token) 'comment)))
  10534           (web-mode-insert-text-at-pos "-->" (point))
  10535           (web-mode-insert-text-at-pos "<!--" (1+ (cdr (car parent)))))
  10536         ) ;when
  10537       )))
  10538 
  10539 (defun web-mode-element-children (&optional pos)
  10540   (unless pos (setq pos (point)))
  10541   (let ((continue t) (i 0) child children)
  10542     (save-excursion
  10543       (when (and (member (get-text-property pos 'tag-type) '(start end))
  10544                  (setq child (web-mode-element-child-position pos)))
  10545         (while continue
  10546           (cond
  10547            ((> (setq i (1+ i)) 100)
  10548             (setq continue nil)
  10549             (message "element-children ** warning **"))
  10550            ((= i 1)
  10551             (goto-char child))
  10552            ((web-mode-element-sibling-next)
  10553             )
  10554            (t
  10555             (setq continue nil))
  10556            ) ;cond
  10557           (when continue
  10558             (setq children (append children (list (point)))))
  10559           ) ;while
  10560         ) ;when
  10561       ) ;save-excursion
  10562     ;;(message "%S" children)
  10563     children))
  10564 
  10565 (defun web-mode-property-boundaries (prop &optional pos)
  10566   "property boundaries (cdr is 1+)"
  10567   (unless pos (setq pos (point)))
  10568   (let (beg end val)
  10569     (setq val (get-text-property pos prop))
  10570     (if (null val)
  10571         val
  10572       (if (or (bobp)
  10573               (not (eq (get-text-property (1- pos) prop) val)))
  10574           (setq beg pos)
  10575         (setq beg (previous-single-property-change pos prop))
  10576         (when (null beg) (setq beg (point-min))))
  10577       (if (or (eobp)
  10578               (not (eq (get-text-property (1+ pos) prop) val)))
  10579           (setq end pos)
  10580         (setq end (next-single-property-change pos prop))
  10581         (when (null end) (setq end (point-min))))
  10582       (cons beg end))))
  10583 
  10584 (defun web-mode-content-boundaries (&optional pos)
  10585   (unless pos (setq pos (point)))
  10586   (let (beg end)
  10587     (setq beg (or (previous-property-change pos (current-buffer))
  10588                   (point-max)))
  10589     (setq end (or (next-property-change pos (current-buffer))
  10590                   (point-min)))
  10591     (while (and (< beg end) (member (char-after beg) '(?\s ?\n)))
  10592       (setq beg (1+ beg)))
  10593     (while (and (> end beg) (member (char-after (1- end)) '(?\s ?\n)))
  10594       (setq end (1- end)))
  10595 ;;    (message "beg(%S) end(%S)" beg end)
  10596     (cons beg end)
  10597     ))
  10598 
  10599 (defun web-mode-element-boundaries (&optional pos)
  10600   "Return ((start-tag-beg . start-tag-end) . (end-tag-beg . end-tag-end))
  10601 First level car and cdr are the same with void elements.
  10602 Pos should be in a tag."
  10603   (unless pos (setq pos (point)))
  10604   (let (start-tag-beg start-tag-end end-tag-beg end-tag-end)
  10605     (cond
  10606      ((eq (get-text-property pos 'tag-type) 'start)
  10607       (setq start-tag-beg (web-mode-tag-beginning-position pos)
  10608             start-tag-end (web-mode-tag-end-position pos))
  10609       (when (setq pos (web-mode-tag-match-position pos))
  10610         (setq end-tag-beg pos
  10611               end-tag-end (web-mode-tag-end-position pos)))
  10612       )
  10613      ((eq (get-text-property pos 'tag-type) 'end)
  10614       (setq end-tag-beg (web-mode-tag-beginning-position pos)
  10615             end-tag-end (web-mode-tag-end-position pos))
  10616       (when (setq pos (web-mode-tag-match-position pos))
  10617         (setq start-tag-beg pos
  10618               start-tag-end (web-mode-tag-end-position pos)))
  10619       )
  10620      ((eq (get-text-property pos 'tag-type) 'void)
  10621       (setq start-tag-beg (web-mode-tag-beginning-position pos)
  10622             start-tag-end (web-mode-tag-end-position pos))
  10623       (setq end-tag-beg start-tag-beg
  10624             end-tag-end start-tag-end)
  10625       )
  10626      ) ;cond
  10627     (if (and start-tag-beg start-tag-end end-tag-beg end-tag-end)
  10628         (cons (cons start-tag-beg start-tag-end) (cons end-tag-beg end-tag-end))
  10629       nil)
  10630     ))
  10631 
  10632 (defun web-mode-surround ()
  10633   "Surround each line of the current REGION with a start/end tag."
  10634   (interactive)
  10635   (when mark-active
  10636     (let (beg end line-beg line-end pos tag tag-start tag-end)
  10637       (save-excursion
  10638         (combine-after-change-calls
  10639           (setq tag (web-mode-element-complete)
  10640                 tag-start (concat "<" tag ">")
  10641                 tag-end (concat "</" tag ">")
  10642                 pos (point)
  10643                 beg (region-beginning)
  10644                 end (region-end)
  10645                 line-beg (web-mode-line-number beg)
  10646                 line-end (web-mode-line-number end))
  10647           (goto-char end)
  10648           (unless (bolp)
  10649             (insert tag-end)
  10650             (back-to-indentation)
  10651             (when (> beg (point))
  10652               (goto-char beg))
  10653             (insert tag-start))
  10654           (while (> line-end line-beg)
  10655             (forward-line -1)
  10656             (setq line-end (1- line-end))
  10657             (unless (looking-at-p "[[:space:]]*$")
  10658               (end-of-line)
  10659               (insert tag-end)
  10660               (back-to-indentation)
  10661               (when (> beg (point))
  10662                 (goto-char beg))
  10663               (insert tag-start))
  10664             ) ;while
  10665           (deactivate-mark)
  10666           ) ;combine-after-change-calls
  10667         ) ;save-excursion
  10668       )))
  10669 
  10670 (defun web-mode-lify-region ()
  10671   "Transform current REGION in an html list (<li>line1</li>...)"
  10672   (interactive)
  10673   (let (beg end lines)
  10674     (save-excursion
  10675       (combine-after-change-calls
  10676         (when  mark-active
  10677           (setq beg (region-beginning)
  10678                 end (region-end))
  10679           (setq lines (buffer-substring beg end))
  10680           (kill-region beg end)
  10681           (setq lines (replace-regexp-in-string "^[ \t]*" "<li>" lines))
  10682           (setq lines (replace-regexp-in-string "$" "</li>" lines))
  10683           (web-mode-insert-and-indent lines)
  10684           ) ;when
  10685         ) ;combine-after-change-calls
  10686       ) ;save-excursion
  10687     ) ;let
  10688   )
  10689 
  10690 (defun web-mode-element-complete (&optional prompt)
  10691   "Completes for an element tag."
  10692   (completing-read
  10693    (or prompt "Tag name: ")
  10694    (append
  10695     web-mode-tag-list
  10696     web-mode-tag-history)
  10697    nil nil nil 'web-mode-tag-history))
  10698 
  10699 (defun web-mode-element-wrap (&optional tag-name)
  10700   "Wrap current REGION with start and end tags.
  10701 Prompt user if TAG-NAME isn't provided."
  10702   (interactive)
  10703   (let (beg end pos tag sep)
  10704     (save-excursion
  10705       (setq tag (or tag-name (web-mode-element-complete)))
  10706       (setq pos (point))
  10707       (cond
  10708        (mark-active
  10709         (setq beg (region-beginning)
  10710               end (region-end)))
  10711        ((get-text-property pos 'tag-type)
  10712         (setq beg (web-mode-element-beginning-position pos)
  10713               end (1+ (web-mode-element-end-position pos))))
  10714        ((setq beg (web-mode-element-parent-position pos))
  10715         (setq end (1+ (web-mode-element-end-position pos))))
  10716        )
  10717       ;;      (message "beg(%S) end(%S)" beg end)
  10718       (when (and beg end (> end 0))
  10719         (setq sep (if (get-text-property beg 'tag-beg) "\n" ""))
  10720         (web-mode-insert-text-at-pos (concat sep "</" tag ">") end)
  10721         (web-mode-insert-text-at-pos (concat "<" tag ">" sep) beg)
  10722         (when (string= sep "\n") (indent-region beg (+ end (* (+ 3 (length tag)) 2))))
  10723         )
  10724       ) ;save-excursion
  10725     (web-mode-go beg)))
  10726 
  10727 (defun web-mode-element-vanish (&optional arg)
  10728   "Vanish the current html element. The content of the element is kept."
  10729   (interactive "p")
  10730   (let (type (pos (point)) start-b start-e end-b end-e)
  10731     (while (>= arg 1)
  10732       (setq type (get-text-property pos 'tag-type))
  10733       (when type
  10734         (cond
  10735          ((member type '(void))
  10736           (web-mode-element-kill)
  10737           (set-mark (point))
  10738           (web-mode-tag-match)
  10739           (web-mode-tag-end)
  10740           (exchange-point-and-mark))
  10741          ((member type '(start))
  10742           (setq start-b (web-mode-tag-beginning-position)
  10743                 start-e (web-mode-tag-end-position))
  10744           (when (web-mode-tag-match)
  10745             (setq end-b (web-mode-tag-beginning-position)
  10746                   end-e (web-mode-tag-end-position)))
  10747           )
  10748          (t
  10749           (setq end-b (web-mode-tag-beginning-position)
  10750                 end-e (web-mode-tag-end-position))
  10751           (when (web-mode-tag-match)
  10752             (setq start-b (web-mode-tag-beginning-position)
  10753                   start-e (web-mode-tag-end-position)))
  10754           ) ;t
  10755          ) ;cond
  10756         (when (and start-b end-b)
  10757           (goto-char end-b)
  10758           (delete-region end-b (1+ end-e))
  10759           (delete-blank-lines)
  10760           (goto-char start-b)
  10761           (delete-region start-b (1+ start-e))
  10762           (delete-blank-lines)
  10763           (web-mode-buffer-indent)
  10764           )
  10765         ;;        (message "start %S %S - end %S %S" start-b start-e end-b end-e))
  10766         ) ;when
  10767       (skip-chars-forward "[:space:]\n")
  10768       (setq arg (1- arg))
  10769       ) ;while
  10770     ) ;let
  10771   )
  10772 
  10773 (defun web-mode-element-kill (&optional arg)
  10774   "Kill the current html element."
  10775   (interactive "p")
  10776   (while (>= arg 1)
  10777     (setq arg (1- arg))
  10778     (web-mode-element-select)
  10779     (when mark-active
  10780       (kill-region (region-beginning) (region-end)))
  10781     ) ;while
  10782   )
  10783 
  10784 (defun web-mode-element-clone (&optional arg)
  10785   "Clone the current html element."
  10786   (interactive "p")
  10787   (let (col pos)
  10788     (while (>= arg 1)
  10789       (setq arg (1- arg)
  10790             col 0)
  10791       (web-mode-element-select)
  10792       (when mark-active
  10793         (save-excursion
  10794           (goto-char (region-beginning))
  10795           (setq col (current-column)))
  10796         (kill-region (region-beginning) (region-end))
  10797         (yank)
  10798         (newline)
  10799         (indent-line-to col)
  10800         (setq pos (point))
  10801         (yank)
  10802         (goto-char pos))
  10803       )
  10804     ) ;let
  10805   )
  10806 
  10807 (defun web-mode-element-insert ()
  10808   "Insert an html element."
  10809   (interactive)
  10810   (let (tag-name)
  10811     (cond
  10812      ((and (get-text-property (point) 'tag-type)
  10813            (not (get-text-property (point) 'tag-beg)))
  10814       (message "element-insert ** invalid context **"))
  10815      ((not (and (setq tag-name (web-mode-element-complete))
  10816                 (> (length tag-name) 0)))
  10817       (message "element-insert ** failure **"))
  10818      ((web-mode-element-is-void tag-name)
  10819       (insert (concat "<" (replace-regexp-in-string "/" "" tag-name) "/>"))
  10820       )
  10821      (mark-active
  10822       (let ((beg (region-beginning)) (end (region-end)))
  10823         (deactivate-mark)
  10824         (goto-char end)
  10825         (insert "</" tag-name ">")
  10826         (goto-char beg)
  10827         (insert "<" tag-name ">")
  10828         )
  10829       )
  10830      (t
  10831       (insert (concat "<" tag-name ">" "</" tag-name ">"))
  10832       (web-mode-sb "</")
  10833       )
  10834      ) ;cond
  10835     ))
  10836 
  10837 (defun web-mode-element-insert-at-point ()
  10838   "Replace the word at point with a html tag of it."
  10839   (interactive)
  10840   (let ((tag-name (thing-at-point 'word)))
  10841     (cond
  10842      ((web-mode-element-is-void tag-name)
  10843       (backward-kill-word 1)
  10844       (insert (concat "<" (replace-regexp-in-string "/" "" tag-name) "/>"))
  10845       )
  10846      (mark-active
  10847       (setq tag-name (buffer-substring (region-beginning) (region-end)))
  10848       (delete-region (region-beginning) (region-end))
  10849       (insert (concat "<" tag-name ">" "</" tag-name ">"))
  10850       (web-mode-sb "</")
  10851       )
  10852      (tag-name ; do nothing is there isn's word at point
  10853       (backward-kill-word 1)
  10854       (insert (concat "<" tag-name ">" "</" tag-name ">"))
  10855       (web-mode-sb "</")
  10856       )
  10857      ) ;cond
  10858     ))
  10859 
  10860 (defun web-mode-element-rename (&optional tag-name)
  10861   "Rename the current html element."
  10862   (interactive)
  10863   (save-excursion
  10864     (let (pos)
  10865       (unless tag-name (setq tag-name (web-mode-element-complete "New tag name: ")))
  10866       (when (and (> (length tag-name) 0)
  10867                  (web-mode-element-beginning)
  10868                  (looking-at "<\\([[:alnum:]]+\\(:?[[:alpha:]_-]+\\)?\\)"))
  10869         (setq pos (point))
  10870         (unless (web-mode-element-is-void)
  10871             (save-match-data
  10872               (web-mode-tag-match)
  10873               (if (looking-at "</[ ]*\\([[:alnum:]]+\\(:?[[:alpha:]_-]+\\)?\\)")
  10874                   (replace-match (concat "</" tag-name))
  10875                 )))
  10876         (goto-char pos)
  10877         (replace-match (concat "<" tag-name))
  10878         ))))
  10879 
  10880 (defun web-mode-current-trimmed-line ()
  10881   (web-mode-trim (buffer-substring-no-properties
  10882                   (line-beginning-position)
  10883                   (line-end-position))))
  10884 
  10885 (defun web-mode-trim (string)
  10886   (replace-regexp-in-string "\\`[ \t\n]*" "" (replace-regexp-in-string "[ \t\n]*\\'" "" string)))
  10887 
  10888 (defun web-mode-is-token-end (pos)
  10889   (let (block-token part-token)
  10890     (setq block-token (get-text-property pos 'block-token))
  10891     (setq part-token (get-text-property pos 'part-token))
  10892     (cond
  10893      ((not (or block-token part-token))
  10894       nil)
  10895      ((>= (1+ pos) (point-max))
  10896       t)
  10897      ((and block-token
  10898            (not (string= (get-text-property (1+ pos) 'block-token) block-token)))
  10899       t)
  10900      ((and part-token
  10901            (not (string= (get-text-property (1+ pos) 'part-token) part-token)))
  10902       t)
  10903      (t
  10904       nil)
  10905      ) ;cond
  10906    ))
  10907 
  10908 (defun web-mode-block-is-token-line ()
  10909   (save-excursion
  10910     (let ((continue t) (counter 0))
  10911       (beginning-of-line)
  10912       (back-to-indentation)
  10913       (while (and continue (not (eolp)))
  10914         (cond
  10915          ((get-text-property (point) 'block-token)
  10916           (setq counter (1+ counter)))
  10917          ((not (member (following-char) '(?\s ?\t)))
  10918           (setq continue nil
  10919                 counter 0))
  10920          ) ;cond
  10921         (forward-char)
  10922         ) ;while
  10923       (> counter 0)
  10924       )))
  10925 
  10926 (defun web-mode-part-is-token-line (pos)
  10927   (save-excursion
  10928     (let ((continue t)
  10929           (counter 0))
  10930       (goto-char pos)
  10931       (setq continue (not (eolp)))
  10932       (while continue
  10933         (forward-char)
  10934         (cond
  10935          ((eolp)
  10936           (setq continue nil))
  10937          ((or (get-text-property (point) 'block-side)
  10938               (member (get-text-property (point) 'part-token) '(comment string)))
  10939           (setq counter (1+ counter)))
  10940          ((not (member (following-char) '(?\s ?\t)))
  10941           (setq continue nil
  10942                 counter 0))
  10943          )
  10944         ) ;while
  10945       (> counter 0))))
  10946 
  10947 (defun web-mode-is-content (&optional pos)
  10948   (unless pos (setq pos (point)))
  10949   (not (or (get-text-property pos 'part-side)
  10950            (get-text-property pos 'tag-type)
  10951            (get-text-property pos 'block-side)
  10952            )))
  10953 
  10954 (defun web-mode-is-comment-or-string (&optional pos)
  10955   (unless pos (setq pos (point)))
  10956   (not (null (or (eq (get-text-property pos 'tag-type) 'comment)
  10957                  (member (get-text-property pos 'block-token) '(comment string))
  10958                  (member (get-text-property pos 'part-token) '(comment string))))))
  10959 
  10960 ;; NOTE: we look at the firt one
  10961 (defun web-mode-block-is-open (&optional pos)
  10962   (unless pos (setq pos (point))))
  10963 
  10964 ;; NOTE: we look at the last one
  10965 (defun web-mode-block-is-close (&optional pos)
  10966   (unless pos (setq pos (point)))
  10967   (and (get-text-property pos 'block-side)
  10968        (eq (caar (web-mode-block-controls-get pos)) 'close)))
  10969 
  10970 ;; NOTE: we look at the first one
  10971 (defun web-mode-block-is-inside (&optional pos)
  10972   (unless pos (setq pos (point)))
  10973   (and (get-text-property pos 'block-side)
  10974        (eq (caar (web-mode-block-controls-get pos)) 'inside)))
  10975 
  10976 (defun web-mode-element-is-void (&optional tag)
  10977   (cond
  10978    ((and (not tag) (eq (get-text-property (point) 'tag-type) 'void))
  10979     t)
  10980    ((and tag (member tag '("div" "li" "a" "p" "h1" "h2" "h3" "ul" "span" "article" "section" "td" "tr")))
  10981     nil)
  10982    ((and tag (string-suffix-p "/" tag))
  10983     t)
  10984    ((and tag (string= web-mode-content-type "jsx"))
  10985     (member (downcase tag) '("img" "br" "hr")))
  10986    (tag
  10987     (car (member (downcase tag) web-mode-void-elements)))
  10988    (t
  10989     nil)
  10990    ))
  10991 
  10992 ;;---- COMMENT ------------------------------------------------------------------
  10993 
  10994 (defun web-mode-toggle-comments ()
  10995   "Toggle comments visbility."
  10996   (interactive)
  10997   (web-mode-with-silent-modifications
  10998    (save-excursion
  10999      (if web-mode-comments-invisible
  11000          (remove-overlays))
  11001      (setq web-mode-comments-invisible (null web-mode-comments-invisible))
  11002      (let ((continue t)
  11003            (pos (point-min))
  11004            (visibility web-mode-comments-invisible)
  11005            overlay end)
  11006        (while continue
  11007          (setq pos (next-single-property-change pos 'font-lock-face))
  11008          (if (null pos)
  11009              (setq continue nil)
  11010            (when (eq (get-text-property pos 'font-lock-face) 'web-mode-comment-face)
  11011              (setq end (next-single-property-change pos 'font-lock-face))
  11012              (put-text-property pos end 'invisible visibility)
  11013              (when visibility
  11014                (setq overlay (make-overlay pos end)))
  11015              (goto-char pos)
  11016              )
  11017            )
  11018          )
  11019        ) ;let
  11020      )))
  11021 
  11022 (defun web-mode-comment-or-uncomment-region (beg end &optional arg)
  11023   (interactive)
  11024   (save-excursion
  11025     (push-mark end)
  11026     (goto-char beg)
  11027     (setq mark-active t)
  11028     (web-mode-comment-or-uncomment)
  11029     (pop-mark)))
  11030 
  11031 (defun web-mode-comment-or-uncomment ()
  11032   "Comment or uncomment line(s), block or region at POS."
  11033   (interactive)
  11034   ;; TODO : if mark is at eol, mark--
  11035   (if (and (not mark-active) (looking-at-p "[[:space:]]*$"))
  11036       (web-mode-comment-insert)
  11037     (when (and (use-region-p) (eq (point) (region-end)))
  11038       (if (bolp) (backward-char))
  11039       (exchange-point-and-mark))
  11040     (if (eq (get-text-property (point) 'block-token) 'delimiter-beg)
  11041         (web-mode-block-skip-blank-forward (point) '(delimiter-beg))
  11042       (skip-chars-forward "[:space:]" (line-end-position)))
  11043     (cond
  11044      ;; #1147
  11045      ((and (get-text-property (point) 'jsx-beg)
  11046            (eq (get-text-property (1+ (point)) 'part-token) 'comment))
  11047       (web-mode-uncomment (1+ (point))))
  11048      ((or (eq (get-text-property (point) 'tag-type) 'comment)
  11049           (eq (get-text-property (point) 'block-token) 'comment)
  11050           (eq (get-text-property (point) 'part-token) 'comment))
  11051       (web-mode-uncomment (point)))
  11052      (t
  11053       (web-mode-comment (point)))
  11054      )
  11055     ) ;if
  11056   )
  11057 
  11058 (defun web-mode-comment-indent-new-line (&optional soft)
  11059   (interactive)
  11060   (let (ctx)
  11061     (setq ctx (web-mode-comment-context))
  11062     (cond
  11063      ((null ctx)
  11064       (newline 1))
  11065      (t
  11066       (newline 1)
  11067       (indent-line-to (plist-get ctx :col))
  11068       (let ((prefix (plist-get ctx :prefix)))
  11069         (insert
  11070          (concat prefix
  11071                  ;; Check if the comment ends with a space, and if not, insert one.
  11072                  (if
  11073                      (string-equal (substring prefix -1 (length prefix)) " ")
  11074                      ""
  11075                    " ")))))
  11076      ) ;cond
  11077     ))
  11078 
  11079 (defun web-mode-comment-context (&optional pos)
  11080   (cond
  11081    (pos
  11082     )
  11083    ((and (eolp) (not (bobp)))
  11084     (setq pos (1- (point))))
  11085    (t
  11086     (setq pos (point)))
  11087    ) ;cond
  11088   (let (beg col prefix type format)
  11089     (cond
  11090      ((eq (get-text-property pos 'block-token) 'comment)
  11091       (setq type "block"))
  11092      ((eq (get-text-property pos 'tag-type) 'comment)
  11093       (setq type "tag"))
  11094      ((eq (get-text-property pos 'part-token) 'comment)
  11095       (setq type "part"))
  11096      )
  11097     (if (null type) nil
  11098       (save-excursion
  11099         (goto-char pos)
  11100         (web-mode-comment-beginning)
  11101         (setq beg (point)
  11102               col (current-column))
  11103         (cond
  11104          ((looking-at-p "/\\*")
  11105           (setq format "/*"
  11106                 prefix " * "))
  11107          ((looking-at-p "//")
  11108           (setq format "//"
  11109                 prefix "//"))
  11110          ((looking-at-p "#")
  11111           (setq format "#"
  11112                 prefix "#"))
  11113          ((looking-at-p ";")
  11114           (setq format ";"
  11115                 prefix ";"))
  11116          ((looking-at-p "''")
  11117           (setq format "''"
  11118                 prefix "''"))
  11119          ) ;cond
  11120         (list :beg beg :col col :prefix prefix :type type :format format)))))
  11121 
  11122 (defun web-mode-comment-insert ()
  11123   (let ((alt nil) (language nil) (pos (point)))
  11124     (setq language (web-mode-language-at-pos pos))
  11125     (setq alt (cdr (assoc language web-mode-comment-formats)))
  11126     ;;(message "language=%S" language)
  11127     (cond
  11128      ((get-text-property pos 'block-side)
  11129       (cond
  11130        ((and alt (string= alt "//"))
  11131         (insert "// "))
  11132        (t
  11133         (insert "/*  */")
  11134         (search-backward " */"))
  11135        ) ;cond
  11136       ) ;case block-side
  11137      ((get-text-property pos 'part-side)
  11138       (cond
  11139        ((and alt (string= alt "//"))
  11140         (insert "// "))
  11141        (t
  11142         (insert "/*  */")
  11143         (search-backward " */"))
  11144        ) ;cond
  11145       ) ;case part-side
  11146      (t
  11147       (insert "<!--  -->")
  11148       (search-backward " -->")
  11149       ) ;case html
  11150      ) ;cond
  11151     ))
  11152 
  11153 (defun web-mode-comment (pos)
  11154   (let (ctx language col sel beg end tmp block-side single-line-block pos-after content)
  11155 
  11156     (setq pos-after pos)
  11157 
  11158     (setq block-side (get-text-property pos 'block-side))
  11159     (setq single-line-block (web-mode-is-single-line-block pos))
  11160 
  11161     (cond
  11162 
  11163      ((and block-side (string= web-mode-engine "erb"))
  11164       (web-mode-comment-erb-block pos)
  11165       )
  11166 
  11167      ((and block-side (string= web-mode-engine "artanis"))
  11168       (web-mode-comment-artanis-block pos)
  11169       )
  11170 
  11171      ((and single-line-block block-side
  11172            (intern-soft (concat "web-mode-comment-" web-mode-engine "-block")))
  11173         (funcall (intern (concat "web-mode-comment-" web-mode-engine "-block")) pos)
  11174         )
  11175 
  11176      (t
  11177       (setq ctx (web-mode-point-context
  11178                  (if mark-active (region-beginning) (line-beginning-position))))
  11179       ;;(message "%S" ctx)
  11180       (setq language (plist-get ctx :language))
  11181       (setq col (current-column))
  11182       (cond
  11183        (mark-active
  11184         ;;(message "%S %S" (point) col)
  11185         )
  11186        ((and (member language '("html" "xml"))
  11187              (get-text-property (progn (back-to-indentation) (point)) 'tag-beg))
  11188         (web-mode-element-select))
  11189        (t
  11190         (end-of-line)
  11191         (set-mark (line-beginning-position)))
  11192        ) ;cond
  11193 
  11194       (setq beg (region-beginning)
  11195             end (region-end))
  11196 
  11197       (when (> (point) (mark))
  11198         (exchange-point-and-mark))
  11199 
  11200       (if (and (eq (char-before end) ?\n)
  11201                (not (eq (char-after end) ?\n)))
  11202           (setq end (1- end)))
  11203 
  11204       (setq sel (buffer-substring-no-properties beg end))
  11205 
  11206       (cond
  11207 
  11208        ((member language '("html" "xml"))
  11209         (cond
  11210          ((and (= web-mode-comment-style 2) (string= web-mode-engine "django"))
  11211           (setq content (concat "{# " sel " #}")))
  11212          ((and (= web-mode-comment-style 2) (member web-mode-engine '("ejs" "erb")))
  11213           (setq content (concat "<%# " sel " %>")))
  11214          ((and (= web-mode-comment-style 2) (string= web-mode-engine "artanis"))
  11215           (setq content (concat "<%; " sel " %>")))
  11216          ((and (= web-mode-comment-style 2) (string= web-mode-engine "aspx"))
  11217           (setq content (concat "<%-- " sel " --%>")))
  11218          ((and (= web-mode-comment-style 2) (string= web-mode-engine "smarty"))
  11219           (setq content (concat "{* " sel " *}")))
  11220          ((and (= web-mode-comment-style 2) (string= web-mode-engine "expressionengine"))
  11221           (setq content (concat "{!-- " sel " --}")))
  11222          ((and (= web-mode-comment-style 2) (string= web-mode-engine "xoops"))
  11223           (setq content (concat "<{* " sel " *}>")))
  11224          ((and (= web-mode-comment-style 2) (string= web-mode-engine "hero"))
  11225           (setq content (concat "<%# " sel " %>")))
  11226          ((and (= web-mode-comment-style 2) (string= web-mode-engine "blade"))
  11227           (setq content (concat "{{-- " sel " --}}")))
  11228          ((and (= web-mode-comment-style 2) (string= web-mode-engine "ctemplate"))
  11229           (setq content (concat "{{!-- " sel " --}}")))
  11230          ((and (= web-mode-comment-style 2) (string= web-mode-engine "razor"))
  11231           (setq content (concat "@* " sel " *@")))
  11232          (t
  11233           (setq content (concat "<!-- " sel " -->"))
  11234           (when (< (length sel) 1)
  11235             (search-backward " -->")
  11236             (setq pos-after nil))
  11237           ))
  11238         ) ;case html
  11239 
  11240        ((member language '("php" "javascript" "typescript" "java" "jsx"))
  11241         (let (alt)
  11242           (setq alt (cdr (assoc language web-mode-comment-formats)))
  11243           ;;(message "language=%S alt=%S sel=%S col=%S" language alt sel col)
  11244           (cond
  11245            ((and alt (string= alt "//"))
  11246             (setq content (replace-regexp-in-string (concat "\n[ ]\\{" (number-to-string col) "\\}") "\n" sel))
  11247             (setq content (replace-regexp-in-string (concat "\n") "\n// " content))
  11248             (setq content (concat "// " content)))
  11249            ((get-text-property pos 'jsx-depth)
  11250             (setq content (concat "{/* " sel " */}")))
  11251            (web-mode-comment-prefixing
  11252             (setq content (replace-regexp-in-string (concat "\n[ ]\\{" (number-to-string col) "\\}") "\n* " sel))
  11253             (setq content (concat "/* " content " */")))
  11254            (t
  11255             (setq content (concat "/* " sel " */")))
  11256            ) ;cond
  11257           ) ;let
  11258         )
  11259 
  11260        ((member language '("erb"))
  11261         (setq content (replace-regexp-in-string "^[ ]*" "#" sel)))
  11262 
  11263        ((member language '("asp"))
  11264         (setq content (replace-regexp-in-string "^[ ]*" "''" sel)))
  11265 
  11266        (t
  11267         (setq content (concat "/* " sel " */")))
  11268 
  11269        ) ;cond
  11270 
  11271       (when content
  11272         (delete-region beg end)
  11273         (deactivate-mark)
  11274         (let (beg end)
  11275           (setq beg (point-at-bol))
  11276           (insert content)
  11277           (setq end (point-at-eol))
  11278           (indent-region beg end)
  11279           )
  11280         ) ;when
  11281 
  11282       ) ;t
  11283      ) ;cond
  11284 
  11285     (when pos-after (goto-char pos-after))
  11286 
  11287     ))
  11288 
  11289 (defun web-mode-comment-ejs-block (pos)
  11290   (let (beg end)
  11291     (setq beg (web-mode-block-beginning-position pos)
  11292           end (web-mode-block-end-position pos))
  11293     (web-mode-insert-text-at-pos "//" (+ beg 2))))
  11294 
  11295 (defun web-mode-comment-erb-block (pos)
  11296   (let (beg end)
  11297     (setq beg (web-mode-block-beginning-position pos)
  11298           end (web-mode-block-end-position pos))
  11299     (web-mode-insert-text-at-pos "#" (+ beg 2))))
  11300 
  11301 (defun web-mode-comment-artanis-block (pos)
  11302   (let (beg end)
  11303     (setq beg (web-mode-block-beginning-position pos)
  11304           end (web-mode-block-end-position pos))
  11305     (web-mode-insert-text-at-pos ";" (+ beg 2))))
  11306 
  11307 (defun web-mode-comment-django-block (pos)
  11308   (let (beg end)
  11309     (setq beg (web-mode-block-beginning-position pos)
  11310           end (web-mode-block-end-position pos))
  11311     (web-mode-insert-text-at-pos "#" end)
  11312     (web-mode-insert-text-at-pos "#" (1+ beg))))
  11313 
  11314 (defun web-mode-comment-dust-block (pos)
  11315   (let (beg end)
  11316     (setq beg (web-mode-block-beginning-position pos)
  11317           end (web-mode-block-end-position pos))
  11318     (web-mode-insert-text-at-pos "!" end)
  11319     (web-mode-insert-text-at-pos "!" (1+ beg))))
  11320 
  11321 (defun web-mode-comment-aspx-block (pos)
  11322   (let (beg end)
  11323     (setq beg (web-mode-block-beginning-position pos)
  11324           end (web-mode-block-end-position pos))
  11325     (web-mode-insert-text-at-pos "#" end)
  11326     (web-mode-insert-text-at-pos "#" (1+ beg))))
  11327 
  11328 (defun web-mode-comment-jsp-block (pos)
  11329   (let (beg end)
  11330     (setq beg (web-mode-block-beginning-position pos)
  11331           end (web-mode-block-end-position pos))
  11332     (web-mode-insert-text-at-pos "--" (+ beg 2))))
  11333 
  11334 (defun web-mode-comment-go-block (pos)
  11335   (let (beg end)
  11336     (setq beg (web-mode-block-beginning-position pos)
  11337           end (web-mode-block-end-position pos))
  11338     (web-mode-insert-text-at-pos "*/" (1- end))
  11339     (web-mode-insert-text-at-pos "/*" (+ beg (if (web-mode-looking-at "{{" beg) 2 0)))))
  11340 
  11341 (defun web-mode-comment-php-block (pos)
  11342   (let (beg end)
  11343     (setq beg (web-mode-block-beginning-position pos)
  11344           end (web-mode-block-end-position pos))
  11345     (web-mode-insert-text-at-pos "*/" (- end 2))
  11346     (web-mode-insert-text-at-pos "/*" (+ beg 1 (if (web-mode-looking-at "<\\?php" beg) 5 3)))))
  11347 
  11348 (defun web-mode-comment-svelte-block (pos)
  11349   (let (beg end)
  11350     (setq beg (web-mode-block-beginning-position pos)
  11351           end (web-mode-block-end-position pos))
  11352     (web-mode-insert-text-at-pos "!" end)
  11353     (web-mode-insert-text-at-pos "!" (1+ beg))))
  11354 
  11355 (defun web-mode-comment-boundaries (&optional pos)
  11356   (interactive)
  11357   (unless pos (setq pos (point)))
  11358   (let ((beg pos) (end pos) prop)
  11359     (save-excursion
  11360       (goto-char pos)
  11361       (setq prop
  11362             (cond
  11363              ((eq (get-text-property pos 'block-token) 'comment) 'block-token)
  11364              ((eq (get-text-property pos 'tag-type) 'comment) 'tag-type)
  11365              ((eq (get-text-property pos 'part-token) 'comment) 'part-token)
  11366              (t nil)
  11367              ))
  11368       (if (null prop)
  11369           (setq beg nil
  11370                 end nil)
  11371         (when (and (not (bobp))
  11372                    (eq (get-text-property pos prop) (get-text-property (1- pos) prop)))
  11373           (setq beg (or (previous-single-property-change pos prop) (point-min))))
  11374         (when (and (not (eobp))
  11375                    (eq (get-text-property pos prop) (get-text-property (1+ pos) prop)))
  11376           (setq end (or (next-single-property-change pos prop) (point-max)))))
  11377       (message "beg(%S) end(%S) point-max(%S)" beg end (point-max))
  11378       (when (and beg (string= (buffer-substring-no-properties beg (+ beg 2)) "//"))
  11379         (goto-char end)
  11380         (while (and (looking-at-p "\n[ ]*//")
  11381                     (not (eobp)))
  11382           (search-forward "//")
  11383           (backward-char 2)
  11384           ;;(message "%S" (point))
  11385           (setq end (next-single-property-change (point) prop))
  11386           (goto-char end)
  11387           ;;(message "%S" (point))
  11388           ) ;while
  11389         ) ;when
  11390       ;;(when end (setq end (1- end))) ;; #1021
  11391       ) ;save-excursion
  11392     ;;(message "beg=%S end=%S" beg end)
  11393     (if (and beg end) (cons beg end) nil)
  11394     ))
  11395 
  11396 (defun web-mode-uncomment (pos)
  11397   (let ((beg pos) (end pos) (sub2 "") comment boundaries)
  11398     (save-excursion
  11399       (cond
  11400        ((and (get-text-property pos 'block-side)
  11401              (intern-soft (concat "web-mode-uncomment-" web-mode-engine "-block")))
  11402         (funcall (intern (concat "web-mode-uncomment-" web-mode-engine "-block")) pos))
  11403        ((and (setq boundaries (web-mode-comment-boundaries pos))
  11404              (setq beg (car boundaries))
  11405              (setq end (1+ (cdr boundaries)))
  11406              (> (- end beg) 4))
  11407         (when (and (eq (get-text-property beg 'part-token) 'comment)
  11408                    (> beg 1) ;#1158
  11409                    (get-text-property (1- beg) 'jsx-beg))
  11410           (setq beg (1- beg)
  11411                 end (1+ end)))
  11412         (setq comment (buffer-substring-no-properties beg end))
  11413         (setq sub2 (substring comment 0 2))
  11414         (cond
  11415          ((member sub2 '("<!" "<%"))
  11416           (setq comment (replace-regexp-in-string "\\(^<[!%]--[ ]?\\|[ ]?--[%]?>$\\)" "" comment)))
  11417          ((string= sub2 "{#")
  11418           (setq comment (replace-regexp-in-string "\\(^{#[ ]?\\|[ ]?#}$\\)" "" comment)))
  11419          ((string= sub2 "{/") ;jsx comments
  11420           (setq comment (replace-regexp-in-string "\\(^{/\\*[ ]?\\|[ ]?\\*/}$\\)" "" comment)))
  11421          ((string= sub2 "/*")
  11422           ;;(message "%S" comment)
  11423           ;;(setq comment (replace-regexp-in-string "\\(\\*/\\|^/\\*[ ]?\\|^[ \t]*\\*\\)" "" comment))
  11424           (setq comment (replace-regexp-in-string "\\([ ]?\\*/$\\|^/\\*[ ]?\\)" "" comment))
  11425           (setq comment (replace-regexp-in-string "\\(^[ \t]*\\*\\)" "" comment))
  11426           ;;(message "%S" comment)
  11427           )
  11428          ((string= sub2 "''")
  11429           (setq comment (replace-regexp-in-string "''" "" comment)))
  11430          ((string= sub2 "//")
  11431           (setq comment (replace-regexp-in-string "^ *//" "" comment)))
  11432          ) ;cond
  11433         (delete-region beg end)
  11434         (web-mode-insert-and-indent comment)
  11435         (goto-char beg)
  11436         )
  11437        ) ;cond
  11438       (indent-according-to-mode)
  11439       )))
  11440 
  11441 (defun web-mode-uncomment-erb-block (pos)
  11442   (let (beg end)
  11443     (setq beg (web-mode-block-beginning-position pos)
  11444           end (web-mode-block-end-position pos))
  11445     (cond
  11446      ((string= (buffer-substring-no-properties beg (+ beg 4)) "<%#=")
  11447       (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11448      ((string-match-p "<[%[:alpha:]]" (buffer-substring-no-properties (+ beg 2) (- end 2)))
  11449       (web-mode-remove-text-at-pos 2 (1- end))
  11450       (web-mode-remove-text-at-pos 3 beg))
  11451      (t
  11452       (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11453       ) ;cond
  11454     )
  11455   )
  11456 
  11457 (defun web-mode-uncomment-artanis-block (pos)
  11458   (let (beg end)
  11459     (setq beg (web-mode-block-beginning-position pos)
  11460           end (web-mode-block-end-position pos))
  11461     (cond
  11462      ((string= (buffer-substring-no-properties beg (+ beg 4)) "<%;=")
  11463       (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11464      ((string-match-p "<[%[:alpha:]]" (buffer-substring-no-properties (+ beg 2) (- end 2)))
  11465       (web-mode-remove-text-at-pos 2 (1- end))
  11466       (web-mode-remove-text-at-pos 3 beg))
  11467      (t
  11468       (web-mode-remove-text-at-pos 1 (+ beg 2)))
  11469       ) ;cond
  11470     )
  11471   )
  11472 
  11473 (defun web-mode-uncomment-ejs-block (pos)
  11474   (let (beg end)
  11475     (setq beg (web-mode-block-beginning-position pos)
  11476           end (web-mode-block-end-position pos))
  11477     (web-mode-remove-text-at-pos 1 (+ beg 2))))
  11478 
  11479 (defun web-mode-uncomment-django-block (pos)
  11480   (let (beg end)
  11481     (setq beg (web-mode-block-beginning-position pos)
  11482           end (web-mode-block-end-position pos))
  11483     (cond
  11484      ((web-mode-looking-at-p "{#[{%]" beg)
  11485       (web-mode-remove-text-at-pos 1 (1- end))
  11486       (web-mode-remove-text-at-pos 1 (1+ beg))
  11487       )
  11488      (t
  11489       (web-mode-remove-text-at-pos 2 (1- end))
  11490       (web-mode-remove-text-at-pos 2 beg))
  11491      ) ;cond
  11492     ))
  11493 
  11494 (defun web-mode-uncomment-ctemplate-block (pos)
  11495   (let (beg end)
  11496     (setq beg (web-mode-block-beginning-position pos)
  11497           end (web-mode-block-end-position pos))
  11498     (web-mode-remove-text-at-pos 5 (- end 4))
  11499     (web-mode-remove-text-at-pos 5 beg)))
  11500 
  11501 (defun web-mode-uncomment-dust-block (pos)
  11502   (let (beg end)
  11503     (setq beg (web-mode-block-beginning-position pos)
  11504           end (web-mode-block-end-position pos))
  11505     (web-mode-remove-text-at-pos 1 (1- end))
  11506     (web-mode-remove-text-at-pos 1 (1+ beg))))
  11507 
  11508 (defun web-mode-uncomment-aspx-block (pos)
  11509   (let (beg end)
  11510     (setq beg (web-mode-block-beginning-position pos)
  11511           end (web-mode-block-end-position pos))
  11512     (web-mode-remove-text-at-pos 1 (1- end))
  11513     (web-mode-remove-text-at-pos 1 (1+ beg))))
  11514 
  11515 (defun web-mode-uncomment-jsp-block (pos)
  11516   (let (beg end)
  11517     (setq beg (web-mode-block-beginning-position pos)
  11518           end (web-mode-block-end-position pos))
  11519     (web-mode-remove-text-at-pos 2 (+ beg 2))))
  11520 
  11521 (defun web-mode-uncomment-go-block (pos)
  11522   (let (beg end)
  11523     (setq beg (web-mode-block-beginning-position pos)
  11524           end (web-mode-block-end-position pos))
  11525     (web-mode-remove-text-at-pos 2 (+ beg 2))
  11526     (web-mode-remove-text-at-pos 2 (- end 5))))
  11527 
  11528 (defun web-mode-uncomment-svelte-block (pos)
  11529   (let (beg end)
  11530     (setq beg (web-mode-block-beginning-position pos)
  11531           end (web-mode-block-end-position pos))
  11532     (web-mode-remove-text-at-pos 1 (1- end))
  11533     (web-mode-remove-text-at-pos 1 (1+ beg))))
  11534 
  11535 (defun web-mode-snippet-names ()
  11536   (mapcar #'car web-mode-snippets))
  11537 
  11538 (defun web-mode-snippet-insert (code)
  11539   "Insert a snippet."
  11540   (interactive
  11541    (list (completing-read "Snippet: " (web-mode-snippet-names))))
  11542   (let (beg
  11543         (continue t)
  11544         (counter 0)
  11545         end
  11546         sel
  11547         snippet
  11548         (l (length web-mode-snippets))
  11549         pos)
  11550     (when mark-active
  11551       (setq sel (web-mode-trim (buffer-substring-no-properties
  11552                                 (region-beginning) (region-end))))
  11553       (delete-region (region-beginning) (region-end)))
  11554     (while (and continue (< counter l))
  11555       (setq snippet (nth counter web-mode-snippets))
  11556       (when (string= (car snippet) code)
  11557         (setq continue nil))
  11558       (setq counter (1+ counter)))
  11559     (when snippet
  11560       (setq snippet (cdr snippet))
  11561       (setq beg (point-at-bol))
  11562       (insert snippet)
  11563       (setq pos (point)
  11564             end (point))
  11565       (cond
  11566        ((string-match-p "¦" snippet)
  11567         (search-backward "¦")
  11568         (delete-char 1)
  11569         (setq pos (point)
  11570               end (1- end)))
  11571        ((string-match-p "|" snippet)
  11572         (search-backward "|")
  11573         (delete-char 1)
  11574         (setq pos (point)
  11575               end (1- end)))
  11576        ) ;cond
  11577       (when sel
  11578         (insert sel)
  11579         (setq pos (point)
  11580               end (+ end (length sel))))
  11581       (goto-char end)
  11582       (setq end (point-at-eol))
  11583       (unless sel (goto-char pos))
  11584       (indent-region beg end))
  11585     ))
  11586 
  11587 (defun web-mode-looking-at (regexp pos)
  11588   (save-excursion
  11589     (goto-char pos)
  11590     (looking-at regexp)))
  11591 
  11592 (defun web-mode-looking-at-p (regexp pos)
  11593   (save-excursion
  11594     (goto-char pos)
  11595     (looking-at-p regexp)))
  11596 
  11597 (defun web-mode-looking-back (regexp pos &optional limit greedy)
  11598   (save-excursion
  11599     (goto-char pos)
  11600     (if limit
  11601         (looking-back regexp limit greedy)
  11602       (looking-back regexp (point-min)))))
  11603 
  11604 (defun web-mode-insert-text-at-pos (text pos)
  11605   (let ((mem web-mode-enable-auto-pairing))
  11606     (setq web-mode-enable-auto-pairing nil)
  11607     (save-excursion
  11608       (goto-char pos)
  11609       (insert text)
  11610       (setq web-mode-enable-auto-pairing mem)
  11611       )))
  11612 
  11613 (defun web-mode-remove-text-at-pos (n &optional pos)
  11614   (unless pos (setq pos (point)))
  11615   (delete-region pos (+ pos n)))
  11616 
  11617 (defun web-mode-insert-and-indent (text)
  11618   (let (beg end)
  11619     (setq beg (point-at-bol))
  11620     (insert text)
  11621     (setq end (point-at-eol))
  11622     (indent-region beg end)
  11623     ))
  11624 
  11625 (defun web-mode-column-at-pos (pos)
  11626   (save-excursion
  11627     (goto-char pos)
  11628     (current-column)))
  11629 
  11630 (defun web-mode-indentation-at-pos (pos)
  11631   (save-excursion
  11632     (goto-char pos)
  11633     (current-indentation)))
  11634 
  11635 (defun web-mode-navigate (&optional pos)
  11636   "Move point to the matching opening/closing tag/block."
  11637   (interactive)
  11638   (unless pos (setq pos (point)))
  11639   (let (init)
  11640     (goto-char pos)
  11641     (setq init (point))
  11642     (when (> (current-indentation) (current-column))
  11643       (back-to-indentation))
  11644     (setq pos (point))
  11645     (cond
  11646      ((and (get-text-property pos 'block-side)
  11647            (web-mode-block-beginning)
  11648            (web-mode-block-controls-get (point)))
  11649       (web-mode-block-match))
  11650      ((member (get-text-property pos 'tag-type) '(start end))
  11651       (web-mode-tag-beginning)
  11652       (web-mode-tag-match))
  11653      (t
  11654       (goto-char init))
  11655      )
  11656     ))
  11657 
  11658 (defun web-mode-block-match (&optional pos)
  11659   (unless pos (setq pos (point)))
  11660   (let (pos-ori controls control (counter 1) type (continue t) pair)
  11661     (setq pos-ori pos)
  11662     (goto-char pos)
  11663     (setq controls (web-mode-block-controls-get pos))
  11664     ;;(message "controls=%S" controls)
  11665     (cond
  11666      (controls
  11667       (setq pair (car controls))
  11668       (setq control (cdr pair))
  11669       (setq type (car pair))
  11670       (when (eq type 'inside) (setq type 'close))
  11671       (while continue
  11672         (cond
  11673          ((and (> pos-ori 1) (bobp))
  11674           (setq continue nil))
  11675          ((or (and (eq type 'open) (not (web-mode-block-next)))
  11676               (and (eq type 'close) (not (web-mode-block-previous))))
  11677           (setq continue nil)
  11678           )
  11679          ((null (setq controls (web-mode-block-controls-get (point))))
  11680           )
  11681          (t
  11682           ;;TODO : est il nécessaire de faire un reverse sur controls si on doit matcher backward
  11683           (dolist (pair controls)
  11684             (cond
  11685              ((not (string= (cdr pair) control))
  11686               )
  11687              ((eq (car pair) 'inside)
  11688               )
  11689              ((eq (car pair) type)
  11690               (setq counter (1+ counter)))
  11691              (t
  11692               (setq counter (1- counter)))
  11693              )
  11694             ) ;dolist
  11695           (when (= counter 0)
  11696             (setq continue nil))
  11697           ) ;t
  11698          ) ;cond
  11699         ) ;while
  11700       (if (= counter 0) (point) nil)
  11701       ) ;controls
  11702      (t
  11703       (goto-char pos-ori)
  11704       nil
  11705       ) ;controls = nul
  11706      ) ;conf
  11707     ))
  11708 
  11709 (defun web-mode-tag-match (&optional pos)
  11710   "Move point to the matching opening/closing tag."
  11711   (interactive)
  11712   (unless pos (setq pos (point)))
  11713   (let (regexp name)
  11714     (cond
  11715      ((eq (get-text-property pos 'tag-type) 'void)
  11716       (web-mode-tag-beginning))
  11717      ((and (eq (get-text-property pos 'tag-type) 'comment)
  11718            (web-mode-looking-at-p "<!--#\\(elif\\|else\\|endif\\|if\\)" pos))
  11719       (setq regexp "<!--#\\(end\\)?if")
  11720       (if (web-mode-looking-at-p "<!--#if" pos)
  11721           (web-mode-tag-fetch-closing regexp pos)
  11722         (web-mode-tag-fetch-opening regexp pos))
  11723       )
  11724      (t
  11725       (setq name (get-text-property pos 'tag-name))
  11726       (when (string= name "_fragment_") (setq name ">"))
  11727       (setq regexp (concat "</?" name))
  11728       (when (member (get-text-property pos 'tag-type) '(start end))
  11729         (web-mode-tag-beginning)
  11730         (setq pos (point)))
  11731       (if (eq (get-text-property pos 'tag-type) 'end)
  11732           (web-mode-tag-fetch-opening regexp pos)
  11733         (web-mode-tag-fetch-closing regexp pos))
  11734       ) ;t
  11735      ) ;cond
  11736     t))
  11737 
  11738 (defun web-mode-tag-fetch-opening (regexp pos)
  11739   (let ((counter 1) (n 0) (is-comment nil) (types '(start end)))
  11740     (when (eq (aref regexp 1) ?\!)
  11741       (setq types '(comment)
  11742             is-comment t))
  11743     (goto-char pos)
  11744     (while (and (> counter 0) (re-search-backward regexp nil t))
  11745       (when (and (get-text-property (point) 'tag-beg)
  11746                  (member (get-text-property (point) 'tag-type) types))
  11747         (setq n (1+ n))
  11748         (cond
  11749          ((and is-comment
  11750                (eq (aref (match-string-no-properties 0) 5) ?e))
  11751           (setq counter (1+ counter)))
  11752          (is-comment
  11753           (setq counter (1- counter)))
  11754          ((eq (get-text-property (point) 'tag-type) 'end)
  11755           (setq counter (1+ counter)))
  11756          (t
  11757           (setq counter (1- counter))
  11758           )
  11759          )
  11760         )
  11761       )
  11762     (if (= n 0) (goto-char pos))
  11763     ))
  11764 
  11765 (defun web-mode-tag-fetch-closing (regexp pos)
  11766   (let ((counter 1) (is-comment nil) (n 0))
  11767     (when (eq (aref regexp 1) ?\!)
  11768       (setq is-comment t))
  11769     (goto-char pos)
  11770     (web-mode-tag-end)
  11771     (while (and (> counter 0) (re-search-forward regexp nil t))
  11772       (when (get-text-property (match-beginning 0) 'tag-beg)
  11773         (setq n (1+ n))
  11774         (cond
  11775          ((and is-comment
  11776                (eq (aref (match-string-no-properties 0) 5) ?e))
  11777           (setq counter (1- counter)))
  11778          (is-comment
  11779           (setq counter (1+ counter)))
  11780          ((eq (get-text-property (point) 'tag-type) 'end)
  11781           (setq counter (1- counter)))
  11782          (t
  11783           (setq counter (1+ counter)))
  11784          )
  11785         ) ;when
  11786       ) ;while
  11787     (if (> n 0)
  11788         (web-mode-tag-beginning)
  11789       (goto-char pos))
  11790     ))
  11791 
  11792 (defun web-mode-element-tag-name (&optional pos)
  11793   (unless pos (setq pos (point)))
  11794   (save-excursion
  11795     (goto-char pos)
  11796     (if (and (web-mode-tag-beginning)
  11797              (looking-at web-mode-tag-regexp))
  11798         (match-string-no-properties 1)
  11799       nil)))
  11800 
  11801 (defun web-mode-element-close ()
  11802   "Close html element."
  11803   (interactive)
  11804   (let (jmp epp ins tag)
  11805 
  11806     (if (and (eq (char-before) ?\>)
  11807              (web-mode-element-is-void (get-text-property (1- (point)) 'tag-name)))
  11808         (unless (eq (char-before (1- (point))) ?\/)
  11809           (backward-char)
  11810           (insert "/")
  11811           (forward-char))
  11812       (setq epp (web-mode-element-parent-position)))
  11813 
  11814     ;;(message "epp=%S" epp)
  11815     (when epp
  11816       (setq tag (get-text-property epp 'tag-name))
  11817       (setq tag (web-mode-element-tag-name epp))
  11818       ;;(message "tag=%S %c" tag (char-before))
  11819       (cond
  11820        ((or (null tag) (web-mode-element-is-void tag))
  11821         (setq epp nil))
  11822        ((looking-back "</" (point-min))
  11823         (setq ins tag))
  11824        ((looking-back "<" (point-min))
  11825         (setq ins (concat "/" tag)))
  11826        (t
  11827         ;;auto-close-style = 2
  11828         ;;(message "%S %c" (point) (char-after))
  11829         (when (and (looking-at-p "[[:alpha:]]") (> (length tag) 4))
  11830           (dolist (elt '("div" "span" "strong" "pre" "li"))
  11831             (when (and (string-match-p (concat "^" elt) tag) (not (string= tag elt)))
  11832               (setq tag elt)
  11833               (put-text-property epp (point) 'tag-name tag))
  11834             )
  11835           ) ;when
  11836         (if (web-mode-element-is-void (get-text-property (point) 'tag-name))
  11837             (setq ins nil
  11838                   epp nil)
  11839           (setq ins (concat "</" tag)))
  11840         )
  11841        ) ;cond
  11842       (when ins
  11843         (unless (looking-at-p "[ ]*>")
  11844           (setq ins (concat ins ">")))
  11845         (insert ins)
  11846         (setq tag (downcase tag))
  11847         (save-excursion
  11848           (search-backward "<")
  11849           (setq jmp (and (eq (char-before) ?\>)
  11850                           (string= (get-text-property (1- (point)) 'tag-name) tag)))
  11851           (if jmp (setq jmp (point)))
  11852           ) ;save-excursion
  11853         (if jmp (goto-char jmp))
  11854         ) ;when not ins
  11855       ) ;when epp
  11856     epp))
  11857 
  11858 (defun web-mode-detect-content-type ()
  11859   (cond
  11860    ((and (string= web-mode-engine "none")
  11861          (< (point) 16)
  11862          (eq (char-after 1) ?\#)
  11863          (string-match-p "php" (buffer-substring-no-properties
  11864                                 (line-beginning-position)
  11865                                 (line-end-position))))
  11866     (web-mode-set-engine "php"))
  11867    ((and (string= web-mode-content-type "javascript")
  11868          (< (point) web-mode-chunk-length)
  11869          (eq (char-after (point-min)) ?\/)
  11870          (string-match-p "@jsx" (buffer-substring-no-properties
  11871                                  (line-beginning-position)
  11872                                  (line-end-position))))
  11873     (web-mode-set-content-type "jsx"))
  11874    ))
  11875 
  11876 (defun web-mode-auto-complete ()
  11877   "Autocomple at point."
  11878   (interactive)
  11879   (let ((pos (point))
  11880         (char (char-before))
  11881         (chunk (buffer-substring-no-properties (- (point) 2) (point)))
  11882         (expanders nil) (tag nil)
  11883         (auto-closed   nil)
  11884         (auto-expanded nil)
  11885         (auto-paired   nil)
  11886         (auto-quoted   nil))
  11887 
  11888     ;;-- auto-closing
  11889     (when web-mode-enable-auto-closing
  11890 
  11891       (cond
  11892 
  11893        ((and (= web-mode-auto-close-style 3)
  11894              (eq char ?\<))
  11895         (insert "/>")
  11896         (backward-char 2)
  11897         (setq auto-closed t))
  11898 
  11899        ((and (= web-mode-auto-close-style 3)
  11900              (eq char ?\>)
  11901              (looking-at-p "/>"))
  11902         (save-excursion
  11903           (re-search-backward web-mode-start-tag-regexp)
  11904           (setq tag (match-string-no-properties 1)))
  11905         (insert "<")
  11906         (forward-char)
  11907         (insert tag)
  11908         (setq auto-closed t))
  11909 
  11910        ((and (>= pos 4)
  11911              (or (string= "</" chunk)
  11912                  ;;(progn (message "%c" char) nil)
  11913                  (and (= web-mode-auto-close-style 2)
  11914                       (or (string= web-mode-content-type "jsx")
  11915                           (not (get-text-property pos 'part-side)))
  11916                       (string-match-p "[[:alnum:]'\"]>" chunk)))
  11917              (not (get-text-property (- pos 2) 'block-side))
  11918              (web-mode-element-close))
  11919         (setq auto-closed t))
  11920 
  11921        ) ;cond
  11922       ) ;when
  11923 
  11924     ;;-- auto-pairing
  11925     (when (and web-mode-enable-auto-pairing
  11926                (>= pos 4)
  11927                (not auto-closed))
  11928       (let ((i 0) expr after pos-end (l (length web-mode-auto-pairs)))
  11929         (setq pos-end (if (> (+ pos 32) (line-end-position))
  11930                           (line-end-position)
  11931                         (+ pos 10)))
  11932         (setq chunk (buffer-substring-no-properties (- pos 3) pos)
  11933               after (buffer-substring-no-properties pos pos-end))
  11934         (while (and (< i l) (not auto-paired))
  11935           (setq expr (elt web-mode-auto-pairs i)
  11936                 i (1+ i))
  11937           ;;(message "chunk=%S expr=%S after=%S" chunk expr after)
  11938           (when (and (string= (car expr) chunk)
  11939                      (not (string-match-p (regexp-quote (cdr expr)) after)))
  11940             (setq auto-paired t)
  11941             (insert (cdr expr))
  11942             (if (string-match-p "|" (cdr expr))
  11943                 (progn
  11944                   (search-backward "|")
  11945                   (delete-char 1))
  11946               (goto-char pos))
  11947             ) ;when
  11948           ) ;while
  11949         ) ;let
  11950       )
  11951 
  11952     ;;-- auto-expanding
  11953     (when (and web-mode-enable-auto-expanding
  11954                (not auto-closed)
  11955                (not auto-paired)
  11956                (eq char ?\/)
  11957                (looking-back "\\(^\\|[[:punct:][:space:]>]\\)./" (point-min))
  11958                (or (web-mode-jsx-is-html (1- pos))
  11959                    (and (not (get-text-property (1- pos) 'tag-type))
  11960                         (not (get-text-property (1- pos) 'part-side))))
  11961                (not (get-text-property (1- pos) 'block-side))
  11962                )
  11963       (setq expanders (append web-mode-extra-expanders web-mode-expanders))
  11964       (let ((i 0) pair (l (length expanders)))
  11965         (setq chunk (buffer-substring-no-properties (- pos 2) pos))
  11966         ;;(message "%S" chunk)
  11967         (while (and (< i l) (not auto-expanded))
  11968           (setq pair (elt expanders i)
  11969                 i (1+ i))
  11970           (when (string= (car pair) chunk)
  11971             (setq auto-expanded t)
  11972             (delete-char -2)
  11973             (insert (cdr pair))
  11974             (when (string-match-p "|" (cdr pair))
  11975               (search-backward "|")
  11976               (delete-char 1))
  11977             ) ;when
  11978           ) ;while
  11979         ) ;let
  11980       )
  11981 
  11982     ;;-- auto-quoting
  11983     (when (and web-mode-enable-auto-quoting
  11984                (>= pos 4)
  11985                (not (get-text-property pos 'block-side))
  11986                (not auto-closed)
  11987                (not auto-paired)
  11988                (not auto-expanded)
  11989                (get-text-property (- pos 2) 'tag-attr))
  11990       (cond
  11991        ((and (eq char ?\=)
  11992              (not (looking-at-p "[ ]*[\"']")))
  11993         (cond ((= web-mode-auto-quote-style 2)
  11994                (insert "''"))
  11995               ((= web-mode-auto-quote-style 3)
  11996                (insert "{}"))
  11997               (t
  11998                (insert "\"\"")))
  11999         (if (looking-at-p "[ \n>]")
  12000             (backward-char)
  12001           (insert " ")
  12002           (backward-char 2)
  12003           )
  12004         (setq auto-quoted t))
  12005        ((and (eq char ?\")
  12006              (looking-back "=[ ]*\"" (point-min))
  12007              (not (looking-at-p "[ ]*[\"]")))
  12008         (insert-and-inherit "\"")
  12009         (backward-char)
  12010         (setq auto-quoted t))
  12011        ((and (eq char ?\')
  12012              (looking-back "=[ ]*'" (point-min))
  12013              (not (looking-at-p "[ ]*[']")))
  12014         (insert-and-inherit "'")
  12015         (backward-char)
  12016         (setq auto-quoted t))
  12017        ((and (eq char ?\{)
  12018              (eq (get-text-property pos 'part-side) 'jsx)
  12019              (looking-back "=[ ]*{" (point-min))
  12020              (not (looking-at-p "[ ]*[}]")))
  12021         (insert-and-inherit "}")
  12022         (backward-char)
  12023         (setq auto-quoted t))
  12024        ((and (eq char ?\")
  12025              (eq (char-after) ?\"))
  12026         (delete-char 1)
  12027         (cond
  12028          ((looking-back "=\"\"" (point-min))
  12029           (backward-char))
  12030          ((eq (char-after) ?\s)
  12031           (forward-char))
  12032          (t
  12033           (insert " "))
  12034          ) ;cond
  12035         )
  12036        ) ;cond
  12037       ) ;when
  12038 
  12039     ;;--
  12040     (cond
  12041      ((or auto-closed auto-paired auto-expanded auto-quoted)
  12042       (when (and web-mode-change-end (>= (line-end-position) web-mode-change-end))
  12043         (setq web-mode-change-end (line-end-position)))
  12044       (list :auto-closed auto-closed
  12045             :auto-paired auto-paired
  12046             :auto-expanded auto-expanded
  12047             :auto-quoted auto-quoted))
  12048      (t
  12049       nil)
  12050      )
  12051 
  12052     ))
  12053 
  12054 (defun web-mode-dom-xpath (&optional pos)
  12055   "Display html path."
  12056   (interactive)
  12057   (unless pos (setq pos (point)))
  12058   (save-excursion
  12059     (goto-char pos)
  12060     (let (path tag)
  12061       (while (web-mode-element-parent)
  12062         (looking-at web-mode-tag-regexp)
  12063         (setq tag (match-string-no-properties 1))
  12064         (setq path (cons tag path))
  12065         )
  12066       (message "/%s" (mapconcat 'identity path "/"))
  12067       )))
  12068 
  12069 (defun web-mode-block-ends-with (regexp &optional pos)
  12070   (unless pos (setq pos (point)))
  12071   (save-excursion
  12072     (goto-char pos)
  12073     (save-match-data
  12074       (if (stringp regexp)
  12075           (and (web-mode-block-end)
  12076                (progn (backward-char) t)
  12077                (web-mode-block-skip-blank-backward)
  12078                (progn (forward-char) t)
  12079                (looking-back regexp (point-min)))
  12080         (let ((pair regexp)
  12081               (block-beg (web-mode-block-beginning-position pos))
  12082               (block-end (web-mode-block-end-position pos)))
  12083           (and (web-mode-block-end)
  12084                (web-mode-block-sb (car pair) block-beg)
  12085                (not (web-mode-sf (cdr pair) block-end)))
  12086           ) ;let
  12087         ) ;if
  12088       )))
  12089 
  12090 (defun web-mode-block-token-starts-with (regexp &optional pos)
  12091   (unless pos (setq pos (point)))
  12092   (save-excursion
  12093     (and (goto-char pos)
  12094          (web-mode-block-token-beginning)
  12095          (skip-chars-forward "[\"']")
  12096          (looking-at regexp))
  12097     ))
  12098 
  12099 (defun web-mode-block-starts-with (regexp &optional pos)
  12100   (unless pos (setq pos (point)))
  12101   (save-excursion
  12102     (and (web-mode-block-beginning)
  12103          (web-mode-block-skip-blank-forward)
  12104          (looking-at regexp))
  12105     ))
  12106 
  12107 (defun web-mode-block-skip-blank-backward (&optional pos)
  12108   (unless pos (setq pos (point)))
  12109   (let ((continue t))
  12110     (goto-char pos)
  12111     (while continue
  12112       (if (and (get-text-property (point) 'block-side)
  12113                (not (bobp))
  12114                (or (member (char-after) '(?\s ?\n))
  12115                    (member (get-text-property (point) 'block-token)
  12116                            '(delimiter-beg delimiter-end comment))))
  12117           (backward-char)
  12118         (setq continue nil))
  12119       ) ;while
  12120     (point)))
  12121 
  12122 (defun web-mode-block-skip-blank-forward (&optional pos props)
  12123   (unless pos (setq pos (point)))
  12124   (unless props (setq props '(delimiter-beg delimiter-end comment)))
  12125   (let ((continue t))
  12126     (goto-char pos)
  12127     (while continue
  12128       (if (and (get-text-property (point) 'block-side)
  12129                (or (member (char-after) '(?\s ?\n ?\t))
  12130                    (member (get-text-property (point) 'block-token) props)))
  12131           (forward-char)
  12132         (setq continue nil))
  12133       ) ;while
  12134     (point)))
  12135 
  12136 (defun web-mode-tag-attributes-sort (&optional pos)
  12137   "Sort the attributes inside the current html tag."
  12138   (interactive)
  12139   (unless pos (setq pos (point)))
  12140   (save-excursion
  12141     (let (attrs (continue t) min max tag-beg tag-end attr attr-name attr-beg attr-end indent indentation sorter ins)
  12142       (if (not (member (get-text-property pos 'tag-type) '(start void)))
  12143           nil
  12144         (setq tag-beg (web-mode-tag-beginning-position pos)
  12145               tag-end (web-mode-tag-end-position))
  12146 ;;        (message "%S %S" tag-beg tag-end)
  12147         (goto-char tag-beg)
  12148         (while continue
  12149           (if (or (not (web-mode-attribute-next))
  12150                   (>= (point) tag-end))
  12151               (setq continue nil)
  12152             ;;(message "attr=%S" (point))
  12153             (setq attr-beg (web-mode-attribute-beginning-position)
  12154                   attr-end (1+ (web-mode-attribute-end-position)))
  12155             (when (null min)
  12156               (setq min attr-beg))
  12157             (setq max attr-end)
  12158             (goto-char attr-beg)
  12159             (setq attr (buffer-substring-no-properties attr-beg attr-end))
  12160             (if (string-match "^\\([[:alnum:]-]+\\)=" attr)
  12161                 (setq attr-name (match-string-no-properties 1 attr))
  12162               (setq attr-name attr))
  12163             (setq indent (looking-back "^[ \t]*" (point-min)))
  12164             (setq attrs (append attrs (list (list attr-beg attr-end attr-name attr indent))))
  12165             ) ;if
  12166           ) ;while
  12167         ) ;if in tag
  12168       (when attrs
  12169         (setq sorter (function
  12170                       (lambda (elt1 elt2)
  12171                         (string< (nth 2 elt1) (nth 2 elt2))
  12172                         )))
  12173         (setq attrs (sort attrs sorter))
  12174         (delete-region (1- min) max)
  12175         (setq ins "")
  12176         (dolist (elt attrs)
  12177           (if (and (nth 4 elt) (> (length ins) 1))
  12178               (setq ins (concat ins "\n"))
  12179             (setq ins (concat ins " ")))
  12180           (setq ins (concat ins (nth 3 elt)))
  12181           )
  12182         (goto-char (1- min))
  12183         (insert ins)
  12184         (web-mode-tag-beginning)
  12185         (setq min (line-beginning-position))
  12186         (web-mode-tag-end)
  12187         (setq max (line-end-position))
  12188         (indent-region min max)
  12189         )
  12190       ;;(message "attrs=%S" attrs)
  12191       )))
  12192 
  12193 (defun web-mode-attribute-insert (&optional attr-name attr-value)
  12194   "Insert an attribute inside current tag."
  12195   (interactive)
  12196   (let (attr attr-name attr-value)
  12197     (cond
  12198      ((not (member (get-text-property (point) 'tag-type) '(start void)))
  12199       (message "attribute-insert ** invalid context **"))
  12200      ((not (and (setq attr-name (or attr-name (completing-read
  12201                                                "Attribute name: "
  12202                                                (append
  12203                                                 web-mode-attribute-list
  12204                                                 web-mode-attribute-history)
  12205                                                nil nil nil 'web-mode-attribute-history)))
  12206                 (> (length attr-name) 0)))
  12207       (message "attribute-insert ** failure **"))
  12208      (t
  12209       (setq attr (concat " " attr-name))
  12210       (when (setq attr-value (or attr-value (completing-read
  12211                                              "Attribute value: "
  12212                                              web-mode-attribute-value-history
  12213                                              nil nil nil 'web-mode-attribute-value-history)))
  12214         (setq attr (concat attr "=\"" attr-value "\"")))
  12215       (web-mode-tag-end)
  12216       (if (looking-back "/>" (point-min))
  12217           (backward-char 2)
  12218         (backward-char))
  12219       (insert attr)
  12220       ) ;t
  12221      ) ;cond
  12222     ))
  12223 
  12224 (defun web-mode-attribute-transpose (&optional pos)
  12225   "Transpose the current html attribute."
  12226   (interactive)
  12227   (unless pos (setq pos (point)))
  12228   (let (ret attr-beg attr-end next-beg next-end tag-end)
  12229     (when (and (get-text-property pos 'tag-attr)
  12230                (setq next-beg (web-mode-attribute-next-position pos))
  12231                (setq next-end (web-mode-attribute-end-position next-beg))
  12232                (setq tag-end (web-mode-tag-end-position pos))
  12233                (> tag-end next-end))
  12234       (setq attr-beg (web-mode-attribute-beginning-position pos)
  12235             attr-end (web-mode-attribute-end-position pos))
  12236       ;;      (message "%S %S - %S %S" attr-beg attr-end next-beg next-end)
  12237       (transpose-regions attr-beg (1+ attr-end) next-beg (1+ next-end))
  12238       )))
  12239 
  12240 (defun web-mode-attribute-select (&optional pos)
  12241   "Select the current html attribute."
  12242   (interactive)
  12243   (unless pos (setq pos (point)))
  12244   (if (null (get-text-property pos 'tag-attr))
  12245       nil
  12246     (goto-char pos)
  12247     (web-mode-attribute-beginning)
  12248     (set-mark (point))
  12249     (web-mode-attribute-end)
  12250     (exchange-point-and-mark)
  12251     (point)
  12252     ))
  12253 
  12254 (defun web-mode-attribute-kill (&optional arg)
  12255   "Kill the current html attribute."
  12256   (interactive "p")
  12257   (unless arg (setq arg 1))
  12258   (while (>= arg 1)
  12259     (setq arg (1- arg))
  12260     (web-mode-attribute-select)
  12261     (when mark-active
  12262       (let ((beg (region-beginning)) (end (region-end)))
  12263         (save-excursion
  12264           (goto-char end)
  12265           (when (looking-at "[ \n\t]*")
  12266             (setq end (+ end (length (match-string-no-properties 0)))))
  12267           ) ;save-excursion
  12268         (kill-region beg end)
  12269         ) ;let
  12270       ) ;when
  12271     ) ;while
  12272   ;; Delete a potential space before the closing ">".
  12273   (when (and (looking-at ">")
  12274              (looking-back " " (point-min)))
  12275     (delete-char -1))
  12276   )
  12277 
  12278 (defun web-mode-block-close (&optional pos)
  12279   "Close the first unclosed control block."
  12280   (interactive)
  12281   (unless pos (setq pos (point)))
  12282   (let ((continue t)
  12283         (h (make-hash-table :test 'equal)) ctx ctrl n closing-block)
  12284     (save-excursion
  12285       (while (and continue (web-mode-block-previous))
  12286         (when (setq ctx (web-mode-block-is-control (point)))
  12287           (setq ctrl (car ctx))
  12288           (setq n (gethash ctrl h 0))
  12289           (if (cdr ctx)
  12290               (puthash ctrl (1+ n) h)
  12291             (puthash ctrl (1- n) h))
  12292           (when (> (gethash ctrl h) 0)
  12293             (setq continue nil))
  12294           )
  12295         ) ;while
  12296       ) ;save-excursion
  12297     (when (and (null continue)
  12298                (setq closing-block (web-mode-closing-block ctrl)))
  12299       (insert closing-block)
  12300       (indent-according-to-mode))
  12301     ))
  12302 
  12303 (defun web-mode-closing-block (type)
  12304   (cond
  12305    ((string= web-mode-engine "php")              (concat "<?php end" type "; ?>"))
  12306    ((string= web-mode-engine "django")           (concat "{% end" type " %}"))
  12307    ((string= web-mode-engine "ctemplate")        (concat "{{/" type "}}"))
  12308    ((string= web-mode-engine "blade")
  12309     (if (string= type "section") (concat "@show") (concat "@end" type)))
  12310    ((string= web-mode-engine "dust")             (concat "{/" type "}"))
  12311    ((string= web-mode-engine "mako")             (concat "% end" type))
  12312    ((string= web-mode-engine "closure")          (concat "{/" type "}"))
  12313    ((string= web-mode-engine "smarty")           (concat "{/" type "}"))
  12314    ((string= web-mode-engine "expressionengine") (concat "{/" type "}"))
  12315    ((string= web-mode-engine "xoops")            (concat "<{/" type "}>"))
  12316    ((string= web-mode-engine "svelte")           (concat "{/" type "}"))
  12317    ((string= web-mode-engine "underscore")        "<% } %>")
  12318    ((string= web-mode-engine "lsp")               "<% ) %>")
  12319    ((string= web-mode-engine "erb")               "<% } %>")
  12320    ((string= web-mode-engine "erb")               "<% end %>")
  12321    ((string= web-mode-engine "artanis")           "<% ) %>")
  12322    ((string= web-mode-engine "hero")              "<% } %>")
  12323    ((string= web-mode-engine "go")                "{{end}}")
  12324    ((string= web-mode-engine "velocity")          "#end")
  12325    ((string= web-mode-engine "velocity")          "#{end}")
  12326    ((string= web-mode-engine "template-toolkit")  "[% end %]")
  12327    ((member web-mode-engine '("asp" "jsp"))
  12328     (if (string-match-p "[:.]" type) (concat "</" type ">") "<% } %>"))
  12329    (t nil)
  12330    ) ;cond
  12331   )
  12332 
  12333 ;;---- POSITION ----------------------------------------------------------------
  12334 
  12335 (defun web-mode-comment-beginning-position (&optional pos)
  12336   (unless pos (setq pos (point)))
  12337   (car (web-mode-comment-boundaries pos)))
  12338 
  12339 (defun web-mode-comment-end-position (&optional pos)
  12340   (unless pos (setq pos (point)))
  12341   (cdr (web-mode-comment-boundaries pos)))
  12342 
  12343 (defun web-mode-part-opening-paren-position (pos &optional limit)
  12344   (save-restriction
  12345     (unless limit (setq limit nil))
  12346     (goto-char pos)
  12347     (let* ((n -1)
  12348            (paren (char-after))
  12349            (pairs '((?\) . "[)(]")
  12350                     (?\] . "[\]\[]")
  12351                     (?\} . "[}{]")
  12352                     (?\> . "[><]")))
  12353            (regexp (cdr (assoc paren pairs)))
  12354            (continue (not (null regexp)))
  12355            (counter 0))
  12356       (while (and continue (re-search-backward regexp limit t))
  12357         (cond
  12358          ((> (setq counter (1+ counter)) 500)
  12359           (message "part-opening-paren-position ** warning **")
  12360           (setq continue nil))
  12361          ((or (web-mode-is-comment-or-string)
  12362               (get-text-property (point) 'block-side))
  12363           )
  12364          ((eq (char-after) paren)
  12365           (setq n (1- n)))
  12366          (t
  12367           (setq n (1+ n))
  12368           (setq continue (not (= n 0))))
  12369          )
  12370         ) ;while
  12371       (if (= n 0) (point) nil)
  12372       )))
  12373 
  12374 (defun web-mode-token-opening-paren-position (pos limit context)
  12375   (save-restriction
  12376     (unless limit (setq limit nil))
  12377     (goto-char pos)
  12378     (let* ((n -1)
  12379            (paren (char-after))
  12380            (pairs '((?\) . "[)(]")
  12381                     (?\] . "[\]\[]")
  12382                     (?\} . "[}{]")
  12383                     (?\> . "[><]")))
  12384            (regexp (cdr (assoc paren pairs)))
  12385            (continue (not (null regexp)))
  12386            (counter 0))
  12387       (while (and continue (re-search-backward regexp limit t))
  12388         (cond
  12389          ((> (setq counter (1+ counter)) 200)
  12390           (message "token-opening-paren-position ** warning **")
  12391           (setq continue nil))
  12392          ((get-text-property (point) 'block-side)
  12393           )
  12394          ((eq (char-after) paren)
  12395           (setq n (1- n)))
  12396          (t
  12397           (setq n (1+ n))
  12398           (setq continue (not (= n 0))))
  12399          )
  12400         ) ;while
  12401       (if (= n 0) (point) nil)
  12402       )))
  12403 
  12404 (defun web-mode-closing-paren-position (&optional pos limit)
  12405   (save-excursion
  12406     (unless pos (setq pos (point)))
  12407     (unless limit (setq limit nil))
  12408     (goto-char pos)
  12409     (let* ((n 0)
  12410            (block-side (and (get-text-property pos 'block-side)
  12411                             (not (string= web-mode-engine "razor"))))
  12412            (paren (char-after))
  12413            (pairs '((?\( . "[)(]")
  12414                     (?\[ . "[\]\[]")
  12415                     (?\{ . "[}{]")
  12416                     (?\< . "[><]")))
  12417            (regexp (cdr (assoc paren pairs)))
  12418            (continue (not (null regexp))))
  12419       (while (and continue (re-search-forward regexp limit t))
  12420         (cond
  12421          ((or (web-mode-is-comment-or-string (1- (point)))
  12422               (and block-side (not (get-text-property (point) 'block-side))))
  12423           ;;(message "pt=%S" (point))
  12424           )
  12425          ((eq (char-before) paren)
  12426           (setq n (1+ n)))
  12427          (t
  12428           (setq n (1- n))
  12429           (setq continue (not (= n 0)))
  12430           )
  12431          ) ;cond
  12432         ) ;while
  12433       (if (= n 0) (1- (point)) nil)
  12434       )))
  12435 
  12436 (defun web-mode-closing-delimiter-position (delimiter &optional pos limit)
  12437   (unless pos (setq pos (point)))
  12438   (unless limit (setq limit nil))
  12439   (save-excursion
  12440     (goto-char pos)
  12441     (setq pos nil)
  12442     (let ((continue t))
  12443       (while (and continue (re-search-forward delimiter limit t))
  12444         (setq continue nil
  12445               pos (1- (point)))
  12446         ) ;while
  12447       pos)))
  12448 
  12449 (defun web-mode-tag-match-position (&optional pos)
  12450   (unless pos (setq pos (point)))
  12451   (save-excursion
  12452     (web-mode-tag-match pos)
  12453     (if (= pos (point)) nil (point))))
  12454 
  12455 (defun web-mode-tag-beginning-position (&optional pos)
  12456   (unless pos (setq pos (point)))
  12457   (let (beg end depth)
  12458     (setq depth (get-text-property pos 'jsx-depth))
  12459     (when (and depth (get-text-property pos 'tag-attr-beg))
  12460        (setq depth (get-text-property (1- pos) 'jsx-depth)))
  12461     (cond
  12462      ((null pos)
  12463       (setq end nil))
  12464      ((get-text-property pos 'tag-beg)
  12465       (setq beg pos))
  12466      ((and (> pos 1) (get-text-property (1- pos) 'tag-beg))
  12467       (setq beg (1- pos)))
  12468      ((get-text-property pos 'tag-type)
  12469       (setq beg (previous-single-property-change pos 'tag-beg))
  12470       (when beg (setq beg (1- beg)))
  12471       (cond
  12472        ((not (get-text-property beg 'tag-beg))
  12473         (setq beg nil))
  12474        ((and depth (not (eq depth (get-text-property beg 'jsx-depth))))
  12475         (let ((continue (> beg (point-min))))
  12476           (while continue
  12477             (setq beg (previous-single-property-change beg 'tag-beg))
  12478             (when beg (setq beg (1- beg)))
  12479             (cond
  12480              ((null beg)
  12481               (setq continue nil))
  12482              ((not (get-text-property beg 'tag-beg))
  12483               (setq continue nil
  12484                     beg nil))
  12485              ((eq depth (get-text-property beg 'jsx-depth))
  12486               (setq continue nil))
  12487              ) ;cond
  12488             ) ;while
  12489           ) ;let
  12490         )
  12491        ) ;cond
  12492       )
  12493      (t
  12494       (setq beg nil))
  12495      ) ;cond
  12496     beg))
  12497 
  12498 (defun web-mode-tag-end-position (&optional pos)
  12499   (unless pos (setq pos (point)))
  12500   (let (end depth)
  12501     (setq depth (get-text-property pos 'jsx-depth))
  12502     (when (and depth (get-text-property pos 'tag-attr-beg))
  12503       (setq depth (get-text-property (1- pos) 'jsx-depth)))
  12504     (cond
  12505      ((null pos)
  12506       (setq end nil))
  12507      ((get-text-property pos 'tag-end)
  12508       (setq end pos))
  12509      ((get-text-property pos 'tag-type)
  12510       (setq end (next-single-property-change pos 'tag-end))
  12511       (cond
  12512        ((not (get-text-property end 'tag-end))
  12513         (setq end nil))
  12514        ((and depth (not (eq depth (get-text-property end 'jsx-depth))))
  12515         (let ((continue (< end (point-max))))
  12516           (while continue
  12517             (setq end (1+ end))
  12518             (setq end (next-single-property-change end 'tag-end))
  12519             (cond
  12520              ((null end)
  12521               (setq continue nil))
  12522              ((not (get-text-property end 'tag-end))
  12523               (setq continue nil
  12524                     end nil))
  12525              ((eq depth (get-text-property end 'jsx-depth))
  12526               (setq continue nil))
  12527              ) ;cond
  12528             ) ;while
  12529           ) ;let
  12530         )
  12531        ) ;cond
  12532       )
  12533      (t
  12534       (setq end nil))
  12535      ) ;cond
  12536     end))
  12537 
  12538 ;; TODO: prendre en compte jsx-depth
  12539 (defun web-mode-tag-next-position (&optional pos limit)
  12540   (unless pos (setq pos (point)))
  12541   (unless limit (setq limit (point-max)))
  12542   (cond
  12543    ((or (>= pos (point-max)) (>= pos limit)) nil)
  12544    (t
  12545     (when (get-text-property pos 'tag-beg) (setq pos (1+ pos)))
  12546     (setq pos (next-single-property-change pos 'tag-beg))
  12547     (if (and pos (<= pos limit)) pos nil))
  12548    ))
  12549 
  12550 ;; TODO: prendre en compte jsx-depth
  12551 (defun web-mode-tag-previous-position (&optional pos limit)
  12552   (unless pos (setq pos (point)))
  12553   (unless limit (setq limit (point-min)))
  12554   (cond
  12555    ((or (<= pos (point-min)) (<= pos limit)) nil)
  12556    (t
  12557     (when (get-text-property pos 'tag-beg) (setq pos (1- pos)))
  12558     (web-mode-go (previous-single-property-change pos 'tag-beg) -1))
  12559    ))
  12560 
  12561 ;; TODO: prendre en compte jsx-depth
  12562 (defun web-mode-attribute-beginning-position (&optional pos)
  12563   (unless pos (setq pos (point)))
  12564   (cond
  12565    ((null (get-text-property pos 'tag-attr))
  12566     nil)
  12567    ((get-text-property pos 'tag-attr-beg)
  12568     pos)
  12569    ((and (> pos (point-min)) (get-text-property (1- pos) 'tag-attr-beg))
  12570     (1- pos))
  12571    (t
  12572     (setq pos (previous-single-property-change pos 'tag-attr-beg))
  12573     (setq pos (1- pos)))
  12574    ))
  12575 
  12576 ;; TODO: retoucher en incluant un param limit et en s'inspirant de
  12577 ;;       web-mode-attribute-next-position
  12578 (defun web-mode-attribute-end-position (&optional pos)
  12579   (unless pos (setq pos (point)))
  12580   (let (beg end depth flags)
  12581     ;;(message "pos=%S" pos)
  12582     (setq depth (get-text-property pos 'jsx-depth))
  12583     (cond
  12584      ((null pos)
  12585       (setq end nil))
  12586      ((get-text-property pos 'tag-attr-end)
  12587       (setq end pos))
  12588      ((get-text-property pos 'tag-attr)
  12589       (setq end (next-single-property-change pos 'tag-attr-end))
  12590       (when (and depth
  12591                  end
  12592                  (setq beg (web-mode-attribute-beginning-position end))
  12593                  (setq flags (get-text-property pos 'tag-attr-beg))
  12594                  (eq (logand flags 4) 4))
  12595         (setq depth (1- (get-text-property beg 'jsx-depth)))
  12596         ;;(message "%S %S" beg end)
  12597         )
  12598       (cond
  12599        ((not (get-text-property end 'tag-attr-end))
  12600         (setq end nil))
  12601        ((and depth
  12602              (eq depth (get-text-property end 'jsx-depth))
  12603              (not (eq depth (get-text-property end 'jsx-end))))
  12604         )
  12605        ((and depth (eq (1+ depth) (get-text-property end 'jsx-depth)))
  12606         )
  12607        ((and depth (not (eq (1+ depth) (get-text-property end 'jsx-depth))))
  12608         (let ((continue (< end (point-max))))
  12609           (while continue
  12610             (setq end (1+ end))
  12611             (setq end (next-single-property-change end 'tag-attr-end))
  12612             (cond
  12613              ((null end)
  12614               (setq continue nil))
  12615              ((not (get-text-property end 'tag-attr-end))
  12616               (setq continue nil
  12617                     end nil))
  12618              ((eq (1+ depth) (get-text-property end 'jsx-depth))
  12619               (setq continue nil))
  12620              ) ;cond
  12621             ) ;while
  12622           ) ;let
  12623         )
  12624        ) ;cond
  12625       )
  12626      (t
  12627       (setq end nil))
  12628      ) ;cond
  12629     end))
  12630 
  12631 ;; attention si pos est au debut d'un spread attributes, cela
  12632 ;; risque de poser pb
  12633 (defun web-mode-attribute-next-position (&optional pos limit)
  12634   (unless pos (setq pos (point)))
  12635   (unless limit (setq limit (point-max)))
  12636   (let (continue depth)
  12637     (when (get-text-property pos 'tag-attr-beg)
  12638       (setq pos (1+ pos)))
  12639     (if (< pos limit)
  12640         (setq continue t
  12641               depth (get-text-property pos 'jsx-depth))
  12642       (setq continue nil
  12643             pos nil))
  12644     (while continue
  12645       (setq pos (next-single-property-change pos 'tag-attr-beg))
  12646       (cond
  12647        ((null pos)
  12648         (setq continue nil))
  12649        ((>= pos limit)
  12650         (setq continue nil
  12651               pos nil))
  12652        ((null depth)
  12653         (setq continue nil))
  12654        ((and (eq (get-text-property pos 'tag-attr-beg) 4)
  12655              (eq (1+ depth) (get-text-property pos 'jsx-depth)))
  12656         (setq continue nil))
  12657        ((eq depth (get-text-property pos 'jsx-depth))
  12658         (setq continue nil))
  12659        (t
  12660         (setq pos (1+ pos)
  12661               continue (< pos limit)))
  12662        )
  12663       ) ;while
  12664     pos))
  12665 
  12666 (defun web-mode-attribute-previous-position (&optional pos limit)
  12667   (unless pos (setq pos (point)))
  12668   (unless limit (setq limit (point-min)))
  12669   (let (continue depth)
  12670     (cond
  12671      ((and (> pos (point-min)) (get-text-property (1- pos) 'tag-attr-beg))
  12672       (setq pos (1- pos)
  12673             continue nil))
  12674      (t
  12675       (when (get-text-property pos 'tag-attr-beg)
  12676         (setq pos (1- pos)))
  12677       (if (> pos limit)
  12678           (setq continue t
  12679                 depth (get-text-property pos 'jsx-depth))
  12680         (setq continue nil
  12681               pos nil))
  12682       ) ;t
  12683      ) ;cond
  12684     (while continue
  12685       (setq pos (previous-single-property-change pos 'tag-attr-beg))
  12686       (cond
  12687        ((null pos)
  12688         (setq continue nil))
  12689        ((< pos limit)
  12690         (setq continue nil
  12691               pos nil))
  12692        ;;((null depth)
  12693        ;; (setq continue nil))
  12694        ((and depth (eq depth (get-text-property pos 'jsx-depth)))
  12695         (setq  pos (1- pos)
  12696                continue nil))
  12697        (depth
  12698         (setq pos nil
  12699               continue (> pos limit)))
  12700        (t
  12701         (setq pos (1- pos)
  12702               continue nil))
  12703        ) ;cond
  12704       ) ;while
  12705     pos))
  12706 
  12707 ;; TODO: prendre en compte jsx-depth
  12708 (defun web-mode-element-beginning-position (&optional pos)
  12709   (unless pos (setq pos (point)))
  12710   (cond
  12711    ((null (get-text-property pos 'tag-type))
  12712     (setq pos (web-mode-element-parent-position)))
  12713    ((eq (get-text-property pos 'tag-type) 'end)
  12714     (setq pos (web-mode-tag-match-position pos))
  12715     (setq pos (if (get-text-property pos 'tag-beg) pos nil)))
  12716    ((member (get-text-property pos 'tag-type) '(start void))
  12717     (setq pos (web-mode-tag-beginning-position pos)))
  12718    (t
  12719     (setq pos nil))
  12720    ) ;cond
  12721   pos)
  12722 
  12723 ;; TODO: prendre en compte jsx-depth
  12724 (defun web-mode-element-end-position (&optional pos)
  12725   (unless pos (setq pos (point)))
  12726   (cond
  12727    ((null (get-text-property pos 'tag-type))
  12728     (setq pos (web-mode-element-parent-position pos))
  12729     (when pos
  12730       (setq pos (web-mode-tag-match-position pos))
  12731       (when pos (setq pos (web-mode-tag-end-position pos)))
  12732       )
  12733     )
  12734    ((member (get-text-property pos 'tag-type) '(end void comment))
  12735     (setq pos (web-mode-tag-end-position pos))
  12736     )
  12737    ((member (get-text-property pos 'tag-type) '(start))
  12738     (setq pos (web-mode-tag-match-position pos))
  12739     (when pos (setq pos (web-mode-tag-end-position pos))))
  12740    (t
  12741     (setq pos nil))
  12742    ) ;cond
  12743   pos)
  12744 
  12745 (defun web-mode-element-child-position (&optional pos)
  12746   (save-excursion
  12747     (let (child close)
  12748       (unless pos (setq pos (point)))
  12749       (goto-char pos)
  12750       (cond
  12751        ((eq (get-text-property pos 'tag-type) 'start)
  12752         (web-mode-tag-match)
  12753         (setq close (point))
  12754         (goto-char pos)
  12755         )
  12756        ((eq (get-text-property pos 'tag-type) 'void)
  12757         )
  12758        ((eq (get-text-property pos 'tag-type) 'end)
  12759         (web-mode-tag-beginning)
  12760         (setq close (point))
  12761         (web-mode-tag-match)
  12762         )
  12763        ((web-mode-element-parent-position pos)
  12764         (setq pos (point))
  12765         (web-mode-tag-match)
  12766         (setq close (point))
  12767         (goto-char pos)
  12768         )
  12769        ) ;cond
  12770       (when (and close
  12771                  (web-mode-element-next)
  12772                  (< (point) close))
  12773         (setq child (point))
  12774         )
  12775       child)))
  12776 
  12777 (defun web-mode-element-parent-position (&optional pos)
  12778   (let (n tag-type tag-name (continue t) (tags (make-hash-table :test 'equal)))
  12779     (save-excursion
  12780       (if pos (goto-char pos))
  12781       (while (and continue (web-mode-tag-previous))
  12782         (setq pos (point)
  12783               tag-type (get-text-property pos 'tag-type)
  12784               tag-name (get-text-property pos 'tag-name)
  12785               n (gethash tag-name tags 0))
  12786         (when (member tag-type '(end start))
  12787           (if (eq tag-type 'end)
  12788               (puthash tag-name (1- n) tags)
  12789             (puthash tag-name (1+ n) tags)
  12790             (when (= n 0) (setq continue nil))
  12791             ) ;if
  12792           ) ;when
  12793         ) ;while
  12794       ) ;save-excursion
  12795     (if (null continue) pos nil)))
  12796 
  12797 (defun web-mode-element-previous-position (&optional pos limit)
  12798   (unless pos (setq pos (point)))
  12799   (unless limit (setq limit (point-min)))
  12800   (save-excursion
  12801     (goto-char pos)
  12802     (let ((continue (not (bobp)))
  12803           (props '(start void comment)))
  12804       (while continue
  12805         (setq pos (web-mode-tag-previous))
  12806         (cond
  12807          ((or (null pos) (< (point) limit))
  12808           (setq continue nil
  12809                 pos nil))
  12810          ((member (get-text-property (point) 'tag-type) props)
  12811           (setq continue nil))
  12812          )
  12813         ) ;while
  12814       pos)))
  12815 
  12816 (defun web-mode-element-next-position (&optional pos limit)
  12817   (unless pos (setq pos (point)))
  12818   (unless limit (setq limit (point-max)))
  12819   (save-excursion
  12820     (goto-char pos)
  12821     (let ((continue (not (eobp)))
  12822           (props '(start void comment)))
  12823       (while continue
  12824         (setq pos (web-mode-tag-next))
  12825         (cond
  12826          ((or (null pos) (> (point) limit))
  12827           (setq continue nil
  12828                 pos nil))
  12829          ((member (get-text-property (point) 'tag-type) props)
  12830           (setq continue nil))
  12831          )
  12832         ) ;while
  12833 ;;      (message "pos=%S" pos)
  12834       pos)))
  12835 
  12836 (defun web-mode-part-end-position (&optional pos)
  12837   (unless pos (setq pos (point)))
  12838   (cond
  12839    ((member web-mode-content-type web-mode-part-content-types)
  12840     (setq pos (point-max)))
  12841    ((not (get-text-property pos 'part-side))
  12842     (setq pos nil))
  12843    ((= pos (point-max))
  12844     (setq pos nil))
  12845    ((not (get-text-property (1+ pos) 'part-side))
  12846     pos)
  12847    (t
  12848     (setq pos (next-single-property-change pos 'part-side)))
  12849    ) ;cond
  12850   pos)
  12851 
  12852 (defun web-mode-part-beginning-position (&optional pos)
  12853   (unless pos (setq pos (point)))
  12854   (cond
  12855    (web-mode-part-beg
  12856     (setq pos web-mode-part-beg))
  12857    ((member web-mode-content-type web-mode-part-content-types)
  12858     (setq pos (point-min)
  12859           web-mode-part-beg (point-min)))
  12860    ((not (get-text-property pos 'part-side))
  12861     (setq pos nil))
  12862    ((= pos (point-min))
  12863     (setq pos nil))
  12864    ((not (get-text-property (1- pos) 'part-side))
  12865     pos)
  12866    (t
  12867     (setq pos (previous-single-property-change pos 'part-side)))
  12868    ) ;cond
  12869   pos)
  12870 
  12871 (defun web-mode-part-next-position (&optional pos)
  12872   (unless pos (setq pos (point)))
  12873   (cond
  12874    ((and (= pos (point-min)) (get-text-property pos 'part-side))
  12875     )
  12876    ((not (get-text-property pos 'part-side))
  12877     (setq pos (next-single-property-change pos 'part-side)))
  12878    ((and (setq pos (web-mode-part-end-position pos)) (>= pos (point-max)))
  12879     (setq pos nil))
  12880    ((and (setq pos (1+ pos)) (not (get-text-property pos 'part-side)))
  12881     (setq pos (next-single-property-change pos 'part-side)))
  12882    ) ;cond
  12883   pos)
  12884 
  12885 (defun web-mode-block-match-position (&optional pos)
  12886   (unless pos (setq pos (point)))
  12887   (save-excursion
  12888     (web-mode-block-match pos)
  12889     (if (= pos (point)) nil (point))))
  12890 
  12891 ;; type may be nil
  12892 (defun web-mode-block-control-previous-position (type &optional pos)
  12893   (unless pos (setq pos (point)))
  12894   (let ((continue t) controls)
  12895     (while continue
  12896       (setq pos (web-mode-block-previous-position pos))
  12897       (cond
  12898        ((null pos)
  12899         (setq continue nil
  12900               pos nil))
  12901        ((null type)
  12902         (setq continue nil))
  12903        ((and (setq controls (web-mode-block-controls-get pos))
  12904              (eq (car (car controls)) type))
  12905         (setq continue nil))
  12906        ) ;cond
  12907       ) ;while
  12908     pos))
  12909 
  12910 (defun web-mode-inside-block-control (&optional pos)
  12911   (unless pos (setq pos (point)))
  12912   (setq pos (web-mode-block-control-previous-position nil pos))
  12913   (if (and pos (member (car (car (web-mode-block-controls-get pos))) '(open inside)))
  12914       pos
  12915     nil))
  12916 
  12917 (defun web-mode-block-opening-paren-position (pos limit)
  12918   (save-excursion
  12919     (when (> limit pos)
  12920       (message "block-opening-paren-position: limit(%S) > pos(%S)" limit pos))
  12921     (goto-char pos)
  12922     (let (c
  12923           n
  12924           pt
  12925           (continue (> pos limit))
  12926           (pairs '((?\) . ?\()
  12927                    (?\] . ?\[)
  12928                    (?\} . ?\{)))
  12929           (h (make-hash-table :test 'equal))
  12930           (regexp "[\]\[)(}{]"))
  12931       (while (and continue (re-search-backward regexp limit t))
  12932         (cond
  12933          ((web-mode-is-comment-or-string)
  12934           )
  12935          (t
  12936           (setq c (char-after))
  12937           (cond
  12938            ((member c '(?\( ?\{ ?\[))
  12939             (setq n (gethash c h 0))
  12940             (if (= n 0)
  12941                 (setq continue nil
  12942                       pt (point))
  12943               (puthash c (1+ n) h)
  12944               ))
  12945            (t
  12946             (setq c (cdr (assoc c pairs)))
  12947             (setq n (gethash c h 0))
  12948             (puthash c (1- n) h))
  12949            ) ;cond
  12950           ) ;t
  12951          ) ;cond
  12952         ) ;while
  12953       pt)))
  12954 
  12955 (defun web-mode-block-code-beginning-position (&optional pos)
  12956   (unless pos (setq pos (point)))
  12957   (when (and (setq pos (web-mode-block-beginning-position pos))
  12958              (eq (get-text-property pos 'block-token) 'delimiter-beg))
  12959     (setq pos (next-single-property-change pos 'block-token)))
  12960   pos)
  12961 
  12962 (defun web-mode-block-beginning-position (&optional pos)
  12963   (unless pos (setq pos (point)))
  12964   (cond
  12965    ((or (and (get-text-property pos 'block-side) (= pos (point-min)))
  12966         (get-text-property pos 'block-beg))
  12967     )
  12968    ((and (> pos (point-min)) (get-text-property (1- pos) 'block-beg))
  12969     (setq pos (1- pos)))
  12970    ((get-text-property pos 'block-side)
  12971     (setq pos (previous-single-property-change pos 'block-beg))
  12972     (setq pos (if (and pos (> pos (point-min))) (1- pos) (point-min))))
  12973    (t
  12974     (setq pos nil))
  12975    ) ;cond
  12976   pos)
  12977 
  12978 (defun web-mode-block-string-beginning-position (pos &optional block-beg)
  12979   (unless pos (setq pos (point)))
  12980   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  12981   (let (char (ori pos) (continue (not (null pos))))
  12982     (while continue
  12983       (setq char (char-after pos))
  12984       (cond
  12985        ((< pos block-beg)
  12986         (setq continue nil
  12987               pos block-beg))
  12988        ((and (member (get-text-property pos 'block-token) '(string comment))
  12989              (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  12990         (setq pos (web-mode-block-token-beginning-position pos))
  12991         )
  12992        ((member char '(?\) ?\]))
  12993         (setq pos (web-mode-block-opening-paren-position pos block-beg))
  12994         (setq pos (1- pos))
  12995         )
  12996        ((and (> ori pos) (member char '(?\( ?\= ?\[ ?\? ?\: ?\; ?\, ?\`)))
  12997         (if (and (eq char ?\:) ; #1024
  12998                  (web-mode-looking-at ":" pos))
  12999             (setq pos (1- pos))
  13000           (web-mode-looking-at ".[ \t\n]*" pos)
  13001           (setq pos (+ pos (length (match-string-no-properties 0)))
  13002                 continue nil)
  13003           )
  13004         )
  13005        ((web-mode-looking-at "\\(return\\|echo\\|include\\|print\\)[ \n]" pos)
  13006         (setq pos (+ pos (length (match-string-no-properties 0)))
  13007               continue nil))
  13008        (t
  13009         (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?;,`:]\\|\\(return\\|echo\\|include\\|print\\)" block-beg))
  13010         (when (not pos)
  13011           (message "block-string-beginning-position ** search failure **")
  13012           (setq continue nil
  13013                 pos block-beg)))
  13014        ) ;cond
  13015       ) ;while
  13016     ;;(message "pos=%S" pos)
  13017     pos))
  13018 
  13019 (defun web-mode-block-statement-beginning-position (pos block-beg is-ternary)
  13020   (unless pos (setq pos (point)))
  13021   (setq pos (1- pos))
  13022   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13023   (let (char (continue (not (null pos))))
  13024     (while continue
  13025       (setq char (char-after pos))
  13026       (cond
  13027        ((< pos block-beg)
  13028         (setq continue nil
  13029               pos block-beg))
  13030        ((and (member (get-text-property pos 'block-token) '(string comment))
  13031              (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13032         (setq pos (web-mode-block-token-beginning-position pos)))
  13033        ((member char '(?\) ?\] ?\}))
  13034         (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13035         (setq pos (1- pos)))
  13036        ((and (eq char ?\=)
  13037              (web-mode-looking-back "[<>!=]+" pos block-beg t))
  13038         (setq pos (- pos 1 (length (match-string-no-properties 0))))
  13039         ;;(setq pos (1- pos))
  13040         ;;(message "%S pos=%S" (match-string-no-properties 0) pos)
  13041         )
  13042        ((member char '(?\( ?\[ ?\{ ?\=))
  13043         (setq continue nil)
  13044         (web-mode-looking-at ".[ \t\n]*" pos)
  13045         (setq pos (+ pos (length (match-string-no-properties 0)))))
  13046        ((web-mode-looking-at "\\(return\\|echo\\|include\\|print\\)[ \n]" pos)
  13047         (setq pos (+ pos (length (match-string-no-properties 0)))
  13048               continue nil))
  13049        (t
  13050         (setq pos (web-mode-rsb-position pos "[\]\[}{)(=]\\|\\(return\\|echo\\|include\\|print\\)" block-beg))
  13051         (when (not pos)
  13052           (message "block-statement-beginning-position ** search failure **")
  13053           (setq continue nil
  13054                 pos block-beg)))
  13055        ) ;cond
  13056       ) ;while
  13057     pos))
  13058 
  13059 (defun web-mode-block-args-beginning-position (pos &optional block-beg)
  13060   (unless pos (setq pos (point)))
  13061   (setq pos (1- pos)) ;#512
  13062   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13063   (let (char (continue (not (null pos))))
  13064     (while continue
  13065       (setq char (char-after pos))
  13066       (cond
  13067        ((< pos block-beg)
  13068         (message "block-args-beginning-position ** failure **")
  13069         (setq continue nil
  13070               pos block-beg))
  13071        ((and (member (get-text-property pos 'block-token) '(string comment))
  13072              (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13073         (setq pos (web-mode-block-token-beginning-position pos)))
  13074        ((member char '(?\) ?\] ?\}))
  13075         (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13076         (setq pos (1- pos)))
  13077        ((member char '(?\( ?\[ ?\{))
  13078         (setq continue nil)
  13079         (web-mode-looking-at ".[ \t\n]*" pos)
  13080         (setq pos (+ pos (length (match-string-no-properties 0)))))
  13081        ((and (string= web-mode-engine "php")
  13082              (web-mode-looking-at "\\(extends\\|implements\\)[ \n]" pos))
  13083         (setq pos (+ pos (length (match-string-no-properties 0)))
  13084               continue nil))
  13085        (t
  13086         (setq pos (web-mode-rsb-position pos "[\]\[}{)(]\\|\\(extends\\|implements\\)" block-beg))
  13087         (when (not pos)
  13088           (message "block-args-beginning-position ** search failure **")
  13089           (setq pos block-beg
  13090                 continue nil))
  13091         ) ;t
  13092        ) ;cond
  13093       ) ;while
  13094     pos))
  13095 
  13096 (defun web-mode-block-calls-beginning-position (pos &optional block-beg)
  13097   (unless pos (setq pos (point)))
  13098   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13099   (let (char (continue (not (null pos))))
  13100     (while continue
  13101       (setq char (char-after pos))
  13102       (cond
  13103        ((< pos block-beg)
  13104         (message "block-calls-beginning-position ** failure **")
  13105         (setq continue nil
  13106               pos block-beg))
  13107        ((and (member (get-text-property pos 'block-token) '(string comment))
  13108              (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13109         (setq pos (web-mode-block-token-beginning-position pos)))
  13110        ((member char '(?\) ?\]))
  13111         (setq pos (web-mode-block-opening-paren-position pos block-beg))
  13112         (setq pos (1- pos)))
  13113        ((member char '(?\( ?\[ ?\{ ?\} ?\= ?\? ?\: ?\; ?\,))
  13114         (web-mode-looking-at ".[ \t\n]*" pos)
  13115         (setq pos (+ pos (length (match-string-no-properties 0)))
  13116               continue nil))
  13117        ((web-mode-looking-at "\\(return\\|else\\)[ \n]" pos)
  13118         (setq pos (+ pos (length (match-string-no-properties 0)))
  13119               continue nil))
  13120        (t
  13121         (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,]\\|\\(return\\|else\\)" block-beg))
  13122         (when (not pos)
  13123           (message "block-calls-beginning-position ** search failure **")
  13124           (setq pos block-beg
  13125                 continue nil))
  13126         ) ;t
  13127        ) ;cond
  13128       ) ;while
  13129     pos))
  13130 
  13131 (defun web-mode-javascript-string-beginning-position (pos &optional reg-beg)
  13132   (unless pos (setq pos (point)))
  13133   (let ((char nil)
  13134         (blockside (get-text-property pos 'block-side))
  13135         (i 0)
  13136         (continue (not (null pos))))
  13137     (unless reg-beg
  13138       (if blockside
  13139           (setq reg-beg (web-mode-block-beginning-position pos))
  13140         (setq reg-beg (web-mode-part-beginning-position pos)))
  13141       )
  13142     (while continue
  13143       (setq char (char-after pos))
  13144       (cond
  13145        ((> (setq i (1+ i)) 20000)
  13146         (message "javascript-string-beginning-position ** warning (%S) **" pos)
  13147         (setq continue nil
  13148               pos nil))
  13149        ((null pos)
  13150         (message "javascript-string-beginning-position ** invalid pos **")
  13151         (setq continue nil))
  13152        ((< pos reg-beg)
  13153         (message "javascript-string-beginning-position ** failure **")
  13154         (setq continue nil
  13155               pos reg-beg))
  13156        ((and blockside
  13157              (member (get-text-property pos 'block-token) '(string comment))
  13158              (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13159         (setq pos (web-mode-block-token-beginning-position pos)))
  13160        ((and (not blockside)
  13161              (member (get-text-property pos 'part-token) '(string comment))
  13162              (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13163         (setq pos (web-mode-part-token-beginning-position pos)))
  13164        ((and (not blockside)
  13165              (get-text-property pos 'block-side))
  13166         (when (setq pos (web-mode-block-beginning-position pos))
  13167           (setq pos (1- pos))))
  13168        ((member char '(?\) ?\] ?\}))
  13169         (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13170         (setq pos (1- pos)))
  13171        ((member char '(?\( ?\{ ?\[ ?\= ?\? ?\: ?\; ?\, ?\& ?\|))
  13172         (setq continue nil)
  13173         (web-mode-looking-at ".[ \t\n]*" pos)
  13174         (setq pos (+ pos (length (match-string-no-properties 0)))))
  13175        ((web-mode-looking-at "\\(return\\)[ \n]" pos)
  13176         (setq pos (+ pos (length (match-string-no-properties 0)))
  13177               continue nil))
  13178        (t
  13179         (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,&|]\\|\\(return\\)" reg-beg))
  13180         (when (not pos)
  13181           (message "javascript-string-beginning-position ** search failure **")
  13182           (setq continue nil
  13183                 pos reg-beg)))
  13184        ) ;cond
  13185       ) ;while
  13186     ;;(message "js-statement-beg:%S" pos)
  13187     pos))
  13188 
  13189 ;; TODO: reg-beg : jsx-beg
  13190 ;; TODO: skipper les expr dont la depth est superieure
  13191 
  13192 ;; NOTE: blockside is useful for ejs
  13193 (defun web-mode-javascript-statement-beginning-position (pos reg-beg is-ternary)
  13194   (unless pos (setq pos (point)))
  13195   (setq pos (1- pos))
  13196   (let ((char nil)
  13197         (blockside (get-text-property pos 'block-side))
  13198         (i 0)
  13199         (is-jsx (string= web-mode-content-type "jsx"))
  13200         (depth-o nil) (depth-l nil)
  13201         (continue (not (null pos)))
  13202         (regexp "[\]\[}{)(=:]\\|\\(return\\)"))
  13203     (when is-ternary
  13204       (setq regexp (concat regexp "\\|[><]")))
  13205     (setq depth-o (get-text-property pos 'jsx-depth))
  13206     (unless reg-beg
  13207       (cond
  13208        (blockside
  13209         (setq reg-beg (web-mode-block-beginning-position pos)))
  13210        (is-jsx
  13211         (setq reg-beg (web-mode-jsx-depth-beginning-position pos)))
  13212        (t
  13213         (setq reg-beg (web-mode-part-beginning-position pos)))
  13214        ) ;cond
  13215       ) ;unless
  13216     (while continue
  13217       (setq char (char-after pos))
  13218       (cond
  13219        ((> (setq i (1+ i)) 20000)
  13220         (message "javascript-statement-beginning-position ** warning (%S) **" pos)
  13221         (setq continue nil
  13222               pos nil))
  13223        ((null pos)
  13224         (message "javascript-statement-beginning-position ** invalid pos **")
  13225         (setq continue nil))
  13226        ((< pos reg-beg)
  13227         (when (not is-jsx)
  13228           (message "javascript-statement-beginning-position ** failure **"))
  13229         (setq continue nil
  13230               pos reg-beg))
  13231        ((and is-jsx
  13232              (progn (setq depth-l (get-text-property pos 'jsx-depth)) t)
  13233              (not (eq depth-l depth-o)))
  13234         ;;(message "%S > depth-o(%S) depth-l(%S)" pos depth-o depth-l)
  13235         (setq pos (previous-single-property-change pos 'jsx-depth))
  13236         (setq pos (1- pos))
  13237         ;;(message "--> %S %S" pos (get-text-property pos 'jsx-depth))
  13238         )
  13239        ((and blockside
  13240              (member (get-text-property pos 'block-token) '(string comment))
  13241              (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13242         (setq pos (web-mode-block-token-beginning-position pos)))
  13243        ((and (not blockside)
  13244              (member (get-text-property pos 'part-token) '(string comment))
  13245              (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13246         (setq pos (web-mode-part-token-beginning-position pos)))
  13247        ((and (not blockside)
  13248              (get-text-property pos 'block-side))
  13249         (when (setq pos (web-mode-block-beginning-position pos))
  13250           (setq pos (1- pos))))
  13251        ((member char '(?\) ?\] ?\}))
  13252         (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13253         (setq pos (1- pos)))
  13254        ((and (eq char ?\=)
  13255              (web-mode-looking-back "[<>!=]+" pos reg-beg t))
  13256         (setq pos (- pos 1 (length (match-string-no-properties 0)))))
  13257        ((member char '(?\( ?\{ ?\[ ?\= ?\< ?\>))
  13258         (web-mode-looking-at ".[ \t\n]*" pos)
  13259         (setq continue nil
  13260               pos (+ pos (length (match-string-no-properties 0)))))
  13261 
  13262        ((web-mode-looking-at "\\(return\\)[ \n]" pos)
  13263         (setq continue nil
  13264               pos (+ pos (length (match-string-no-properties 0)))))
  13265        ((and (eq char ?\:)
  13266              (web-mode-looking-back "[{,][ \t\n]*[[:alnum:]_]+[ ]*" pos))
  13267         (web-mode-looking-at ".[ \t\n]*" pos)
  13268         (setq continue nil
  13269               pos (+ pos (length (match-string-no-properties 0)))))
  13270        (t
  13271         (setq pos (web-mode-rsb-position pos regexp reg-beg))
  13272         (when (not pos)
  13273           (cond
  13274            (is-jsx
  13275             (when (web-mode-looking-at "[ \n]*" reg-beg)
  13276               (setq pos (+ reg-beg (length (match-string-no-properties 0)))))
  13277             (setq continue nil))
  13278            (t
  13279             (message "javascript-statement-beginning-position ** search failure **")
  13280             (setq continue nil
  13281                   pos reg-beg))
  13282            ) ;cond
  13283           )
  13284         ) ;t
  13285        ) ;cond
  13286       ) ;while
  13287     ;;(message "%S -------" pos)
  13288     pos))
  13289 
  13290 (defun web-mode-javascript-args-beginning-position (pos &optional reg-beg)
  13291   (unless pos (setq pos (point)))
  13292   (setq pos (1- pos))
  13293   (let ((char nil)
  13294         (blockside (get-text-property pos 'block-side))
  13295         (i 0)
  13296         (continue (not (null pos))))
  13297     (unless reg-beg
  13298       (if blockside
  13299           (setq reg-beg (web-mode-block-beginning-position pos))
  13300         (setq reg-beg (web-mode-part-beginning-position pos)))
  13301       )
  13302     (while continue
  13303       (setq char (char-after pos))
  13304       ;;(message "pos(%S) char(%c)" pos char)
  13305       (cond
  13306        ((> (setq i (1+ i)) 20000)
  13307         (message "javascript-args-beginning-position ** warning (%S) **" pos)
  13308         (setq continue nil
  13309               pos nil))
  13310        ((null pos)
  13311         (message "javascript-args-beginning-position ** invalid pos **")
  13312         (setq continue nil))
  13313        ((< pos reg-beg)
  13314         (message "javascript-args-beginning-position ** failure(position) **")
  13315         (setq continue nil
  13316               pos reg-beg))
  13317        ((and blockside
  13318              (member (get-text-property pos 'block-token) '(string comment))
  13319              (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13320         (setq pos (web-mode-block-token-beginning-position pos)))
  13321        ((and (not blockside)
  13322              (member (get-text-property pos 'part-token) '(string comment))
  13323              (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13324         (setq pos (web-mode-part-token-beginning-position pos)))
  13325        ((and (not blockside)
  13326              (get-text-property pos 'block-side))
  13327         (when (setq pos (web-mode-block-beginning-position pos))
  13328           (setq pos (1- pos)))
  13329         )
  13330        ((member char '(?\) ?\] ?\}))
  13331         (when (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13332           (setq pos (1- pos))))
  13333        ((member char '(?\( ?\[ ?\{))
  13334         (web-mode-looking-at ".[ ]*" pos)
  13335         (setq pos (+ pos (length (match-string-no-properties 0)))
  13336               continue nil)
  13337         )
  13338        ((web-mode-looking-at "\\(var\\|let\\|return\\|const\\)[ \n]" pos)
  13339         (setq pos (+ pos (length (match-string-no-properties 0)))
  13340               continue nil))
  13341        (t
  13342         (setq pos (web-mode-rsb-position pos "[\]\[}{)(]\\|\\(var\\|let\\|return\\|const\\)" reg-beg))
  13343         (when (not pos)
  13344           (message "javascript-args-beginning-position ** search failure **")
  13345           (setq continue nil
  13346                 pos reg-beg)))
  13347        ) ;cond
  13348       ) ;while
  13349     ;;(message "=%S" pos)
  13350     pos))
  13351 
  13352 (defun web-mode-javascript-calls-beginning-position (pos &optional reg-beg)
  13353   (unless pos (setq pos (point)))
  13354   ;;(message "pos=%S" pos)
  13355   (let ((char nil)
  13356         (dot-pos nil)
  13357         (blockside (get-text-property pos 'block-side))
  13358         (i 0)
  13359         (continue (not (null pos))))
  13360     (unless reg-beg
  13361       (setq reg-beg (if blockside
  13362                         (web-mode-block-beginning-position pos)
  13363                       (web-mode-part-beginning-position pos))))
  13364     (while continue
  13365       (setq char (char-after pos))
  13366       ;;(message "%S| %S=%c" reg-beg pos char)
  13367       (cond
  13368        ((> (setq i (1+ i)) 20000)
  13369         (message "javascript-calls-beginning-position ** warning (%S) **" pos)
  13370         (setq continue nil
  13371               pos nil))
  13372        ((null pos)
  13373         (message "javascript-calls-beginning-position ** invalid pos **")
  13374         (setq continue nil))
  13375        ((< pos reg-beg)
  13376         (setq continue nil
  13377               pos reg-beg))
  13378        ((and blockside
  13379              (member (get-text-property pos 'block-token) '(string comment))
  13380              (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token)))
  13381         (setq pos (web-mode-block-token-beginning-position pos)))
  13382        ((and (not blockside)
  13383              (member (get-text-property pos 'part-token) '(string comment))
  13384              (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token)))
  13385         (setq pos (web-mode-part-token-beginning-position pos)))
  13386        ((and (not blockside)
  13387              (get-text-property pos 'block-side))
  13388         (when (setq pos (web-mode-block-beginning-position pos))
  13389           (setq pos (1- pos))))
  13390        ((and (member char '(?\.)) (> i 1))
  13391         (setq dot-pos pos
  13392               pos (1- pos)))
  13393        ((member char '(?\) ?\]))
  13394         (when (setq pos (web-mode-part-opening-paren-position pos reg-beg))
  13395           (setq pos (1- pos)))
  13396         )
  13397        ((member char '(?\( ?\{ ?\} ?\[ ?\= ?\? ?\: ?\; ?\, ?\& ?\| ?\>))
  13398         (web-mode-looking-at ".[ \t\n]*" pos)
  13399         (setq pos (+ pos (length (match-string-no-properties 0)))
  13400               continue nil))
  13401        ((web-mode-looking-at "\\(return\\|else\\|const\\)[ \n]" pos)
  13402         (setq pos (+ pos (length (match-string-no-properties 0)))
  13403               continue nil))
  13404        (t
  13405         (setq pos (web-mode-rsb-position pos "[\]\[}{)(=?:;,&|>.]\\|\\(return\\|else\\|const\\)" reg-beg))
  13406         (when (not pos)
  13407           (message "javascript-calls-beginning-position ** search failure **")
  13408           (setq pos reg-beg
  13409                 continue nil))
  13410         ) ;t
  13411        ) ;cond
  13412       ) ;while
  13413     ;;(message "pos=%S dot-pos=%S" pos dot-pos)
  13414     (if (null pos) pos (cons pos dot-pos))
  13415     ))
  13416 
  13417 (defun web-mode-part-token-beginning-position (&optional pos)
  13418   (unless pos (setq pos (point)))
  13419   (cond
  13420    ((not (get-text-property pos 'part-token))
  13421     nil)
  13422    ((or (= pos (point-min))
  13423         (and (> pos (point-min))
  13424              (not (get-text-property (1- pos) 'part-token))))
  13425     pos)
  13426    (t
  13427     (setq pos (previous-single-property-change pos 'part-token))
  13428     (if (and pos (> pos (point-min))) pos (point-min)))
  13429    ))
  13430 
  13431 (defun web-mode-part-token-end-position (&optional pos)
  13432   (unless pos (setq pos (point)))
  13433   (cond
  13434    ((not (get-text-property pos 'part-token))
  13435     nil)
  13436    ((or (= pos (point-max))
  13437         (not (get-text-property (1+ pos) 'part-token)))
  13438     pos)
  13439    (t
  13440     (1- (next-single-property-change pos 'part-token)))
  13441    ))
  13442 
  13443 (defun web-mode-block-token-beginning-position (&optional pos)
  13444   (unless pos (setq pos (point)))
  13445   (cond
  13446    ((not (get-text-property pos 'block-token))
  13447     nil)
  13448    ((or (= pos (point-min))
  13449         (and (> pos (point-min))
  13450              (not (get-text-property (1- pos) 'block-token))))
  13451     pos)
  13452    (t
  13453     (setq pos (previous-single-property-change pos 'block-token))
  13454     (if (and pos (> pos (point-min))) pos (point-min)))
  13455    ))
  13456 
  13457 (defun web-mode-block-token-end-position (&optional pos)
  13458   (unless pos (setq pos (point)))
  13459   (cond
  13460    ((not (get-text-property pos 'block-token))
  13461     nil)
  13462    ((or (= pos (point-max))
  13463         (not (get-text-property (1+ pos) 'block-token)))
  13464     pos)
  13465    (t
  13466     (1- (next-single-property-change pos 'block-token)))
  13467    ))
  13468 
  13469 (defun web-mode-block-code-end-position (&optional pos)
  13470   (unless pos (setq pos (point)))
  13471   (setq pos (web-mode-block-end-position pos))
  13472   (cond
  13473    ((not pos)
  13474     nil)
  13475    ((and (eq (get-text-property pos 'block-token) 'delimiter-end)
  13476          (eq (get-text-property (1- pos) 'block-token) 'delimiter-end))
  13477     (previous-single-property-change pos 'block-token))
  13478    ((= pos (1- (point-max))) ;; TODO: comparer plutot avec line-end-position
  13479     (point-max))
  13480    (t
  13481     pos)
  13482    ))
  13483 
  13484 (defun web-mode-block-end-position (&optional pos)
  13485   (unless pos (setq pos (point)))
  13486   (cond
  13487    ((get-text-property pos 'block-end)
  13488     pos)
  13489    ((get-text-property pos 'block-side)
  13490     (or (next-single-property-change pos 'block-end)
  13491         (point-max)))
  13492    (t
  13493     nil)
  13494    ))
  13495 
  13496 (defun web-mode-block-previous-position (&optional pos)
  13497   (unless pos (setq pos (point)))
  13498   (cond
  13499    ((= pos (point-min))
  13500     (setq pos nil))
  13501    ((get-text-property pos 'block-side)
  13502     (setq pos (web-mode-block-beginning-position pos))
  13503     (cond
  13504      ((or (null pos) (= pos (point-min)))
  13505       (setq pos nil)
  13506       )
  13507      ((and (setq pos (previous-single-property-change pos 'block-beg))
  13508            (> pos (point-min)))
  13509       (setq pos (1- pos))
  13510       )
  13511      )
  13512     ) ;block-side
  13513    ((get-text-property (1- pos) 'block-side)
  13514     (setq pos (web-mode-block-beginning-position (1- pos)))
  13515     )
  13516    (t
  13517     (setq pos (previous-single-property-change pos 'block-side))
  13518     (cond
  13519      ((and (null pos) (get-text-property (point-min) 'block-beg))
  13520       (setq pos (point-min)))
  13521      ((and pos (> pos (point-min)))
  13522       (setq pos (web-mode-block-beginning-position (1- pos))))
  13523      )
  13524     )
  13525    ) ;conf
  13526   pos)
  13527 
  13528 (defun web-mode-block-next-position (&optional pos limit)
  13529   (unless pos (setq pos (point)))
  13530   (unless limit (setq limit (point-max)))
  13531   (cond
  13532    ((and (get-text-property pos 'block-side)
  13533          (setq pos (web-mode-block-end-position pos))
  13534          (< pos (point-max))
  13535          (setq pos (1+ pos)))
  13536     (unless (get-text-property pos 'block-beg)
  13537       (setq pos (next-single-property-change pos 'block-side)))
  13538     )
  13539    (t
  13540     (setq pos (next-single-property-change pos 'block-side)))
  13541    ) ;cond
  13542   (if (and pos (<= pos limit)) pos nil))
  13543 
  13544 (defun web-mode-is-css-string (pos)
  13545   (let (beg)
  13546     (cond
  13547      ((and (setq beg (web-mode-part-token-beginning-position pos))
  13548            (web-mode-looking-at-p "`" beg)
  13549            (web-mode-looking-back "\\(styled[[:alnum:].]+\\|css\\)" beg))
  13550       beg)
  13551      (t
  13552       nil)
  13553      ) ;cond
  13554     ))
  13555 
  13556 ;; Relay.QL , gql, graphql
  13557 (defun web-mode-is-ql-string (pos prefix-regexp)
  13558   (let (beg)
  13559     (cond
  13560      ((and (setq beg (web-mode-part-token-beginning-position pos))
  13561            (web-mode-looking-back prefix-regexp beg))
  13562       beg)
  13563      (t
  13564       nil)
  13565      ) ;cond
  13566     ))
  13567 
  13568 (defun web-mode-is-html-string (pos)
  13569   (let (beg)
  13570     (cond
  13571      ((and (setq beg (web-mode-part-token-beginning-position pos))
  13572            (web-mode-looking-at-p "`[ \t\n]*<[a-zA-Z]" beg)
  13573            (web-mode-looking-back "\\(template\\|html\\)\\([ ]*[=:][ ]*\\)?" beg))
  13574       beg)
  13575      (t
  13576       nil)
  13577      ) ;cond
  13578     ))
  13579 
  13580 ;;---- EXCURSION ---------------------------------------------------------------
  13581 
  13582 (defun web-mode-backward-sexp (n)
  13583   (interactive "p")
  13584   (if (< n 0) (web-mode-forward-sexp (- n))
  13585     (let (pos)
  13586       (dotimes (_ n)
  13587         (skip-chars-backward "[:space:]")
  13588         (setq pos (point))
  13589         (cond
  13590          ((bobp) nil)
  13591          ((get-text-property (1- pos) 'block-end)
  13592           (backward-char 1)
  13593           (web-mode-block-beginning))
  13594          ((get-text-property (1- pos) 'block-token)
  13595           (backward-char 1)
  13596           (web-mode-block-token-beginning))
  13597          ((get-text-property (1- pos) 'part-token)
  13598           (backward-char 1)
  13599           (web-mode-part-token-beginning))
  13600          ((get-text-property (1- pos) 'tag-end)
  13601           (backward-char 1)
  13602           (web-mode-element-beginning))
  13603          ((get-text-property (1- pos) 'tag-attr)
  13604           (backward-char 1)
  13605           (web-mode-attribute-beginning))
  13606          ((get-text-property (1- pos) 'tag-type)
  13607           (backward-char 1)
  13608           (web-mode-tag-beginning))
  13609          ((get-text-property (1- pos) 'jsx-end)
  13610           (backward-char 1)
  13611           (web-mode-jsx-beginning))
  13612          (t
  13613           (let ((forward-sexp-function nil))
  13614             (backward-sexp))
  13615           ) ;case t
  13616          ) ;cond
  13617         ) ;dotimes
  13618       ))) ;let if defun
  13619 
  13620 (defun web-mode-forward-sexp (n)
  13621   (interactive "p")
  13622   (if (< n 0) (web-mode-backward-sexp (- n))
  13623     (let (pos)
  13624       (dotimes (_ n)
  13625         (skip-chars-forward "[:space:]")
  13626         (setq pos (point))
  13627         (cond
  13628          ((eobp) nil)
  13629          ((get-text-property pos 'block-beg)
  13630           (web-mode-block-end))
  13631          ((get-text-property pos 'block-token)
  13632           (web-mode-block-token-end))
  13633          ((get-text-property pos 'part-token)
  13634           (web-mode-part-token-end))
  13635          ((get-text-property pos 'tag-beg)
  13636           (web-mode-element-end))
  13637          ((get-text-property pos 'tag-attr)
  13638           (web-mode-attribute-end))
  13639          ((get-text-property pos 'tag-type)
  13640           (web-mode-tag-end))
  13641          ((get-text-property pos 'jsx-beg)
  13642           (web-mode-jsx-end))
  13643          (t
  13644           (let ((forward-sexp-function nil))
  13645             (forward-sexp))
  13646           ) ;case t
  13647          ) ;cond
  13648         ) ;dotimes
  13649       ))) ;let if defun
  13650 
  13651 (defun web-mode-comment-beginning ()
  13652   "Fetch current comment beg."
  13653   (interactive)
  13654   (web-mode-go (web-mode-comment-beginning-position (point))))
  13655 
  13656 (defun web-mode-comment-end ()
  13657   "Fetch current comment end."
  13658   (interactive)
  13659   (web-mode-go (web-mode-comment-end-position (point)) 1))
  13660 
  13661 (defun web-mode-tag-beginning ()
  13662   "Fetch current html tag beg."
  13663   (interactive)
  13664   (web-mode-go (web-mode-tag-beginning-position (point))))
  13665 
  13666 (defun web-mode-tag-end ()
  13667   "Fetch current html tag end."
  13668   (interactive)
  13669   (web-mode-go (web-mode-tag-end-position (point)) 1))
  13670 
  13671 (defun web-mode-tag-previous ()
  13672   "Fetch previous tag."
  13673   (interactive)
  13674   (web-mode-go (web-mode-tag-previous-position (point))))
  13675 
  13676 (defun web-mode-tag-next ()
  13677   "Fetch next tag. Might be html comment or server tag (e.g. jsp)."
  13678   (interactive)
  13679   (web-mode-go (web-mode-tag-next-position (point))))
  13680 
  13681 (defun web-mode-attribute-beginning ()
  13682   "Fetch html attribute beginning."
  13683   (interactive)
  13684   (web-mode-go (web-mode-attribute-beginning-position (point))))
  13685 
  13686 (defun web-mode-attribute-end ()
  13687   "Fetch html attribute end."
  13688   (interactive)
  13689   (web-mode-go (web-mode-attribute-end-position (point)) 1))
  13690 
  13691 (defun web-mode-attribute-next (&optional arg)
  13692   "Fetch next attribute."
  13693   (interactive "p")
  13694   (unless arg (setq arg 1))
  13695   (cond
  13696    ((= arg 1) (web-mode-go (web-mode-attribute-next-position (point))))
  13697    ((< arg 1) (web-mode-element-previous (* arg -1)))
  13698    (t
  13699     (while (>= arg 1)
  13700       (setq arg (1- arg))
  13701       (web-mode-go (web-mode-attribute-next-position (point)))
  13702       )
  13703     )
  13704    )
  13705   )
  13706 
  13707 (defun web-mode-attribute-previous (&optional arg)
  13708   "Fetch previous attribute."
  13709   (interactive "p")
  13710   (unless arg (setq arg 1))
  13711   (unless arg (setq arg 1))
  13712   (cond
  13713    ((= arg 1) (web-mode-go (web-mode-attribute-previous-position (point))))
  13714    ((< arg 1) (web-mode-element-next (* arg -1)))
  13715    (t
  13716     (while (>= arg 1)
  13717       (setq arg (1- arg))
  13718       (web-mode-go (web-mode-attribute-previous-position (point)))
  13719       )
  13720     )
  13721    )
  13722   )
  13723 
  13724 (defun web-mode-element-previous (&optional arg)
  13725   "Fetch previous element."
  13726   (interactive "p")
  13727   (unless arg (setq arg 1))
  13728   (cond
  13729    ((= arg 1) (web-mode-go (web-mode-element-previous-position (point))))
  13730    ((< arg 1) (web-mode-element-next (* arg -1)))
  13731    (t
  13732     (while (>= arg 1)
  13733       (setq arg (1- arg))
  13734       (web-mode-go (web-mode-element-previous-position (point)))
  13735       ) ;while
  13736     ) ;t
  13737    ) ;cond
  13738   )
  13739 
  13740 (defun web-mode-element-next (&optional arg)
  13741   "Fetch next element."
  13742   (interactive "p")
  13743   (unless arg (setq arg 1))
  13744   (cond
  13745    ((= arg 1) (web-mode-go (web-mode-element-next-position (point))))
  13746    ((< arg 1) (web-mode-element-previous (* arg -1)))
  13747    (t
  13748     (while (>= arg 1)
  13749       (setq arg (1- arg))
  13750       (web-mode-go (web-mode-element-next-position (point)))
  13751       ) ;while
  13752     ) ;t
  13753    ) ;cond
  13754   )
  13755 
  13756 (defun web-mode-element-sibling-next ()
  13757   "Fetch next sibling element."
  13758   (interactive)
  13759   (let ((pos (point)))
  13760     (save-excursion
  13761       (cond
  13762        ((not (get-text-property pos 'tag-type))
  13763         (if (and (web-mode-element-parent)
  13764                  (web-mode-tag-match)
  13765                  (web-mode-tag-next)
  13766                  (member (get-text-property (point) 'tag-type) '(start void comment)))
  13767             (setq pos (point))
  13768           (setq pos nil))
  13769         )
  13770        ((member (get-text-property pos 'tag-type) '(start void))
  13771         (if (and (web-mode-tag-match)
  13772                  (web-mode-tag-next)
  13773                  (member (get-text-property (point) 'tag-type) '(start void comment)))
  13774             (setq pos (point))
  13775           (setq pos nil))
  13776         )
  13777        ((and (web-mode-tag-next)
  13778              (member (get-text-property (point) 'tag-type) '(start void comment)))
  13779         (setq pos (point)))
  13780        (t
  13781         (setq pos nil))
  13782        ) ;cond
  13783       ) ;save-excursion
  13784     (web-mode-go pos)))
  13785 
  13786 (defun web-mode-element-sibling-previous ()
  13787   "Fetch previous sibling element."
  13788   (interactive)
  13789   (let ((pos (point)))
  13790     (save-excursion
  13791       (cond
  13792        ((not (get-text-property pos 'tag-type))
  13793         (if (and (web-mode-element-parent)
  13794                  (web-mode-tag-previous)
  13795                  (web-mode-element-beginning))
  13796             (setq pos (point))
  13797           (setq pos nil))
  13798         )
  13799        ((eq (get-text-property pos 'tag-type) 'start)
  13800         (if (and (web-mode-tag-beginning)
  13801                  (web-mode-tag-previous)
  13802                  (web-mode-element-beginning))
  13803             (setq pos (point))
  13804           (setq pos nil))
  13805         )
  13806        ((and (web-mode-element-beginning)
  13807              (web-mode-tag-previous)
  13808              (web-mode-element-beginning))
  13809         (setq pos (point)))
  13810        (t
  13811         (setq pos nil))
  13812        ) ;cond
  13813       ) ;save-excursion
  13814     (web-mode-go pos)))
  13815 
  13816 (defun web-mode-element-beginning ()
  13817   "Move to beginning of element."
  13818   (interactive)
  13819   (web-mode-go (web-mode-element-beginning-position (point))))
  13820 
  13821 (defun web-mode-element-end ()
  13822   "Move to end of element."
  13823   (interactive)
  13824   (web-mode-go (web-mode-element-end-position (point)) 1))
  13825 
  13826 (defun web-mode-element-parent ()
  13827   "Fetch parent element."
  13828   (interactive)
  13829   (web-mode-go (web-mode-element-parent-position (point))))
  13830 
  13831 (defun web-mode-element-child ()
  13832   "Fetch child element."
  13833   (interactive)
  13834   (web-mode-go (web-mode-element-child-position (point))))
  13835 
  13836 (defun web-mode-dom-traverse ()
  13837   "Traverse html dom tree."
  13838   (interactive)
  13839   (cond
  13840    ((web-mode-element-child)
  13841     )
  13842    ((web-mode-element-sibling-next)
  13843     )
  13844    ((and (web-mode-element-parent)
  13845          (not (web-mode-element-sibling-next)))
  13846     (goto-char (point-min)))
  13847    (t
  13848     (goto-char (point-min)))
  13849    ) ;cond
  13850   )
  13851 
  13852 (defun web-mode-closing-paren (limit)
  13853   (let ((pos (web-mode-closing-paren-position (point) limit)))
  13854     (if (or (null pos) (> pos limit))
  13855         nil
  13856       (goto-char pos)
  13857       pos)
  13858     ))
  13859 
  13860 (defun web-mode-part-next ()
  13861   "Move point to the beginning of the next part."
  13862   (interactive)
  13863   (web-mode-go (web-mode-part-next-position (point))))
  13864 
  13865 (defun web-mode-part-beginning ()
  13866   "Move point to the beginning of the current part."
  13867   (interactive)
  13868   (web-mode-go (web-mode-part-beginning-position (point))))
  13869 
  13870 (defun web-mode-part-end ()
  13871   "Move point to the end of the current part."
  13872   (interactive)
  13873   (web-mode-go (web-mode-part-end-position (point)) 1))
  13874 
  13875 (defun web-mode-block-previous ()
  13876   "Move point to the beginning of the previous block."
  13877   (interactive)
  13878   (web-mode-go (web-mode-block-previous-position (point))))
  13879 
  13880 (defun web-mode-block-next ()
  13881   "Move point to the beginning of the next block."
  13882   (interactive)
  13883   (web-mode-go (web-mode-block-next-position (point))))
  13884 
  13885 (defun web-mode-block-beginning ()
  13886   "Move point to the beginning of the current block."
  13887   (interactive)
  13888   (web-mode-go (web-mode-block-beginning-position (point))))
  13889 
  13890 (defun web-mode-block-end ()
  13891   "Move point to the end of the current block."
  13892   (interactive)
  13893   (web-mode-go (web-mode-block-end-position (point)) 1))
  13894 
  13895 (defun web-mode-block-token-beginning ()
  13896   (web-mode-go (web-mode-block-token-beginning-position (point))))
  13897 
  13898 (defun web-mode-block-token-end ()
  13899   (web-mode-go (web-mode-block-token-end-position (point)) 1))
  13900 
  13901 (defun web-mode-part-token-beginning ()
  13902   (web-mode-go (web-mode-part-token-beginning-position (point))))
  13903 
  13904 (defun web-mode-part-token-end ()
  13905   (web-mode-go (web-mode-part-token-end-position (point)) 1))
  13906 
  13907 (defun web-mode-block-opening-paren (limit)
  13908   (web-mode-go (web-mode-block-opening-paren-position (point) limit)))
  13909 
  13910 (defun web-mode-block-string-beginning (&optional pos block-beg)
  13911   (unless pos (setq pos (point)))
  13912   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13913   (web-mode-go (web-mode-block-string-beginning-position pos block-beg)))
  13914 
  13915 (defun web-mode-block-statement-beginning (pos block-beg is-ternary)
  13916   (unless pos (setq pos (point)))
  13917   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13918   (web-mode-go (web-mode-block-statement-beginning-position pos block-beg is-ternary)))
  13919 
  13920 (defun web-mode-block-args-beginning (&optional pos block-beg)
  13921   (unless pos (setq pos (point)))
  13922   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13923   (web-mode-go (web-mode-block-args-beginning-position pos block-beg)))
  13924 
  13925 (defun web-mode-block-calls-beginning (&optional pos block-beg)
  13926   (unless pos (setq pos (point)))
  13927   (unless block-beg (setq block-beg (web-mode-block-beginning-position pos)))
  13928   (web-mode-go (web-mode-block-calls-beginning-position pos block-beg)))
  13929 
  13930 (defun web-mode-javascript-string-beginning (&optional pos reg-beg)
  13931   (unless pos (setq pos (point)))
  13932   (unless reg-beg
  13933     (if (get-text-property pos 'block-side)
  13934         (setq reg-beg (web-mode-block-beginning-position pos))
  13935       (setq reg-beg (web-mode-part-beginning-position pos))))
  13936   (web-mode-go (web-mode-javascript-string-beginning-position pos reg-beg)))
  13937 
  13938 (defun web-mode-javascript-statement-beginning (pos reg-beg is-ternary)
  13939   (unless pos (setq pos (point)))
  13940   (unless reg-beg
  13941     (if (get-text-property pos 'block-side)
  13942         (setq reg-beg (web-mode-block-beginning-position pos))
  13943       (setq reg-beg (web-mode-part-beginning-position pos))))
  13944   (web-mode-go (web-mode-javascript-statement-beginning-position pos reg-beg is-ternary)))
  13945 
  13946 (defun web-mode-javascript-args-beginning (&optional pos reg-beg)
  13947   (unless pos (setq pos (point)))
  13948   (unless reg-beg
  13949     (setq reg-beg (if (get-text-property pos 'block-side)
  13950                       (web-mode-block-beginning-position pos)
  13951                     (web-mode-part-beginning-position pos))))
  13952   ;;(message "reg-beg%S" reg-beg)
  13953   (web-mode-go (web-mode-javascript-args-beginning-position pos reg-beg)))
  13954 
  13955 (defun web-mode-javascript-calls-beginning (&optional pos reg-beg)
  13956   (unless pos (setq pos (point)))
  13957   (unless reg-beg
  13958     (if (get-text-property pos 'block-side)
  13959         (setq reg-beg (web-mode-block-beginning-position pos))
  13960       (setq reg-beg (web-mode-part-beginning-position pos))))
  13961   (let (pair)
  13962     (setq pair (web-mode-javascript-calls-beginning-position pos reg-beg))
  13963     (when pair (web-mode-go (car pair)))
  13964     ))
  13965 
  13966 (defun web-mode-go (pos &optional offset)
  13967   (unless offset (setq offset 0))
  13968   (when pos
  13969     (cond
  13970      ((and (> offset 0) (<= (+ pos offset) (point-max)))
  13971       (setq pos (+ pos offset)))
  13972      ((and (< offset 0) (>= (+ pos offset) (point-min)))
  13973       (setq pos (+ pos offset)))
  13974      ) ;cond
  13975     (goto-char pos))
  13976   pos)
  13977 
  13978 ;;---- SEARCH ------------------------------------------------------------------
  13979 
  13980 (defun web-mode-rsf-balanced (regexp-open regexp-close &optional limit noerror)
  13981   (unless noerror (setq noerror t))
  13982   (let ((continue t)
  13983         (level 1)
  13984         (pos (point))
  13985         ret
  13986         (regexp (concat regexp-open "\\|" regexp-close)))
  13987     (while continue
  13988       (setq ret (re-search-forward regexp limit noerror))
  13989       (cond
  13990        ((null ret)
  13991         (setq continue nil)
  13992         )
  13993        (t
  13994         (if (string-match-p regexp-open (match-string-no-properties 0))
  13995             (setq level (1+ level))
  13996           (setq level (1- level)))
  13997         (when (< level 1)
  13998           (setq continue nil)
  13999           )
  14000         ) ;t
  14001        ) ;cond
  14002       ) ;while
  14003     (when (not (= level 0)) (goto-char pos))
  14004     ret))
  14005 
  14006 (defun web-mode-block-sb (expr &optional limit noerror)
  14007   (unless limit (setq limit (web-mode-block-beginning-position (point))))
  14008   (unless noerror (setq noerror t))
  14009   (let ((continue t) ret)
  14010     (while continue
  14011       (setq ret (search-backward expr limit noerror))
  14012       (when (or (null ret)
  14013                 (not (get-text-property (point) 'block-token)))
  14014         (setq continue nil)
  14015         ) ;when
  14016       ) ;while
  14017     ret))
  14018 
  14019 (defun web-mode-block-sf (expr &optional limit noerror)
  14020   (unless limit (setq limit (web-mode-block-end-position (point))))
  14021   (unless noerror (setq noerror t))
  14022   (let ((continue t) ret)
  14023     (while continue
  14024       (setq ret (search-forward expr limit noerror))
  14025       (when (or (null ret)
  14026                 (not (get-text-property (point) 'block-token)))
  14027         (setq continue nil)
  14028         ) ;when
  14029       ) ;while
  14030     ret))
  14031 
  14032 (defun web-mode-block-rsb (regexp &optional limit noerror)
  14033   (unless limit (setq limit (web-mode-block-beginning-position (point))))
  14034   (unless noerror (setq noerror t))
  14035   (let ((continue t) ret)
  14036     (while continue
  14037       (setq ret (re-search-backward regexp limit noerror))
  14038       (when (or (null ret)
  14039                 (not (get-text-property (point) 'block-token)))
  14040         (setq continue nil)
  14041         ) ;when
  14042       ) ;while
  14043     ret))
  14044 
  14045 (defun web-mode-block-rsf (regexp &optional limit noerror)
  14046   (unless limit (setq limit (web-mode-block-end-position (point))))
  14047   (unless noerror (setq noerror t))
  14048   (let ((continue t) ret)
  14049     (while continue
  14050       (setq ret (re-search-forward regexp limit noerror))
  14051       (when (or (null ret)
  14052                 (not (get-text-property (point) 'block-token)))
  14053         (setq continue nil)
  14054         ) ;when
  14055       ) ;while
  14056     ret))
  14057 
  14058 (defun web-mode-part-sb (expr &optional limit noerror)
  14059   (unless limit (setq limit (web-mode-part-beginning-position (point))))
  14060   (unless noerror (setq noerror t))
  14061   (let ((continue t) ret)
  14062     (while continue
  14063       (setq ret (search-backward expr limit noerror))
  14064       (when (or (null ret)
  14065                 (and (not (get-text-property (point) 'part-token))
  14066                      (not (get-text-property (point) 'block-side)))
  14067                 )
  14068         (setq continue nil)
  14069         ) ;when
  14070       ) ;while
  14071     ret))
  14072 
  14073 (defun web-mode-part-sf (expr &optional limit noerror)
  14074   (unless limit (setq limit (web-mode-part-end-position (point))))
  14075   (unless noerror (setq noerror t))
  14076   (let ((continue t) ret)
  14077     (while continue
  14078       (setq ret (search-forward expr limit noerror))
  14079       (when (or (null ret)
  14080                 (and (not (get-text-property (point) 'part-token))
  14081                      (not (get-text-property (point) 'block-side)))
  14082                 )
  14083         (setq continue nil)
  14084         ) ;when
  14085       ) ;while
  14086     ret))
  14087 
  14088 (defun web-mode-part-rsb (regexp &optional limit noerror)
  14089   (unless limit (setq limit (web-mode-part-beginning-position (point))))
  14090   (unless noerror (setq noerror t))
  14091   (let ((continue t) ret)
  14092     (while continue
  14093       (setq ret (re-search-backward regexp limit noerror))
  14094       (when (or (null ret)
  14095                 (and (not (get-text-property (point) 'part-token))
  14096                      (not (get-text-property (point) 'block-side)))
  14097                 )
  14098         (setq continue nil)
  14099         ) ;when
  14100       ) ;while
  14101     ret))
  14102 
  14103 (defun web-mode-part-rsf (regexp &optional limit noerror)
  14104   (unless limit (setq limit (web-mode-part-end-position (point))))
  14105   (unless noerror (setq noerror t))
  14106   (let ((continue t) ret)
  14107     (while continue
  14108       (setq ret (re-search-forward regexp limit t))
  14109       (when (or (null ret)
  14110                 (and (not (get-text-property (point) 'part-token))
  14111                      (not (get-text-property (point) 'block-side)))
  14112                 )
  14113         (setq continue nil)
  14114         ) ;when
  14115       ) ;while
  14116     ret))
  14117 
  14118 (defun web-mode-javascript-rsb (regexp &optional limit noerror)
  14119   (unless limit (setq limit (web-mode-part-beginning-position (point))))
  14120   (unless noerror (setq noerror t))
  14121   (let ((continue t) ret)
  14122     (while continue
  14123       (setq ret (re-search-backward regexp limit noerror))
  14124       (when (or (null ret)
  14125                 (and (not (get-text-property (point) 'part-token))
  14126                      (not (get-text-property (point) 'block-side))
  14127                      (not (get-text-property (point) 'jsx-depth)))
  14128                 )
  14129         (setq continue nil)
  14130         ) ;when
  14131       ) ;while
  14132     ret))
  14133 
  14134 (defun web-mode-javascript-rsf (regexp &optional limit noerror)
  14135   (unless limit (setq limit (web-mode-part-end-position (point))))
  14136   (unless noerror (setq noerror t))
  14137   (let ((continue t) ret)
  14138     (while continue
  14139       (setq ret (re-search-forward regexp limit t))
  14140       (when (or (null ret)
  14141                 (and (not (get-text-property (point) 'part-token))
  14142                      (not (get-text-property (point) 'block-side))
  14143                      (not (get-text-property (point) 'jsx-depth)))
  14144                 )
  14145         (setq continue nil)
  14146         ) ;when
  14147       ) ;while
  14148     ret))
  14149 
  14150 (defun web-mode-dom-sf (expr &optional limit noerror)
  14151   (unless noerror (setq noerror t))
  14152   (let ((continue t) ret)
  14153     (while continue
  14154       (setq ret (search-forward expr limit noerror))
  14155       (if (or (null ret)
  14156               (not (get-text-property (- (point) (length expr)) 'block-side)))
  14157           (setq continue nil))
  14158       )
  14159     ret))
  14160 
  14161 (defun web-mode-dom-rsf (regexp &optional limit noerror)
  14162   (unless noerror (setq noerror t))
  14163   (let ((continue t) (ret nil))
  14164     (while continue
  14165       (setq ret (re-search-forward regexp limit noerror))
  14166       ;;      (message "ret=%S point=%S limit=%S i=%S" ret (point) limit 0)
  14167       (cond
  14168        ((null ret)
  14169         (setq continue nil))
  14170        ((or (get-text-property (match-beginning 0) 'block-side)
  14171             (get-text-property (match-beginning 0) 'part-token))
  14172         )
  14173        (t
  14174         (setq continue nil))
  14175        ) ;cond
  14176       ) ;while
  14177     ret))
  14178 
  14179 (defun web-mode-rsb-position (pos regexp &optional limit noerror)
  14180   (unless noerror (setq noerror t))
  14181   (save-excursion
  14182     (goto-char pos)
  14183     (if (re-search-backward regexp limit noerror) (point) nil)
  14184     ))
  14185 
  14186 (defun web-mode-rsb (regexp &optional limit noerror)
  14187   (unless noerror (setq noerror t))
  14188   (let ((continue t) ret)
  14189     (while continue
  14190       (setq ret (re-search-backward regexp limit noerror))
  14191       (if (or (null ret)
  14192               (not (web-mode-is-comment-or-string)))
  14193           (setq continue nil)))
  14194     ret))
  14195 
  14196 (defun web-mode-rsf (regexp &optional limit noerror)
  14197   (unless noerror (setq noerror t))
  14198   (let ((continue t) ret)
  14199     (while continue
  14200       (setq ret (re-search-forward regexp limit noerror))
  14201       (if (or (null ret)
  14202               (not (web-mode-is-comment-or-string)))
  14203           (setq continue nil))
  14204       )
  14205     ret))
  14206 
  14207 (defun web-mode-sb (expr &optional limit noerror)
  14208   (unless noerror (setq noerror t))
  14209   (let ((continue t) ret)
  14210     (while continue
  14211       (setq ret (search-backward expr limit noerror))
  14212       (if (or (null ret)
  14213               (not (web-mode-is-comment-or-string)))
  14214           (setq continue nil)))
  14215     ret))
  14216 
  14217 (defun web-mode-sf (expr &optional limit noerror)
  14218   (unless noerror (setq noerror t))
  14219   (let ((continue t) ret)
  14220     (while continue
  14221       (setq ret (search-forward expr limit noerror))
  14222       (if (or (null ret)
  14223               (not (web-mode-is-comment-or-string)))
  14224           (setq continue nil)))
  14225     ret))
  14226 
  14227 (defun web-mode-content-rsf (regexp &optional limit noerror)
  14228   (unless noerror (setq noerror t))
  14229   (let ((continue t) ret beg end)
  14230     (while continue
  14231       (setq ret (re-search-forward regexp limit noerror)
  14232             beg (if (null ret) (point) (match-beginning 0))
  14233             end (if (null ret) (point) (1- (match-end 0))))
  14234       (if (or (null ret)
  14235               (and (web-mode-is-content beg)
  14236                    (web-mode-is-content end)))
  14237           (setq continue nil)))
  14238     ret))
  14239 
  14240 ;;---- ADVICES -----------------------------------------------------------------
  14241 
  14242 (defadvice ac-start (before web-mode-set-up-ac-sources activate)
  14243   "Set `ac-sources' based on current language before running auto-complete."
  14244   (when (equal major-mode 'web-mode)
  14245     ;; set ignore each time to nil. User has to implement a hook to change it
  14246     ;; for each completion
  14247     (setq web-mode-ignore-ac-start-advice nil)
  14248     (run-hooks 'web-mode-before-auto-complete-hooks)
  14249     (unless web-mode-ignore-ac-start-advice
  14250       (when web-mode-ac-sources-alist
  14251         (let ((new-web-mode-ac-sources
  14252                (assoc (web-mode-language-at-pos)
  14253                       web-mode-ac-sources-alist)))
  14254           (setq ac-sources (cdr new-web-mode-ac-sources)))))))
  14255 
  14256 ;;---- MINOR MODE ADDONS -------------------------------------------------------
  14257 
  14258 (defun web-mode-yasnippet-exit-hook ()
  14259   "Yasnippet exit hook"
  14260   (when (and (boundp 'yas-snippet-beg) (boundp 'yas-snippet-end))
  14261     (indent-region yas-snippet-beg yas-snippet-end)))
  14262 
  14263 (defun web-mode-imenu-index ()
  14264   (interactive)
  14265   "Returns imenu items."
  14266   (let (toc-index
  14267         line)
  14268     (save-excursion
  14269       (goto-char (point-min))
  14270       (while (not (eobp))
  14271         (setq line (buffer-substring-no-properties
  14272                     (line-beginning-position)
  14273                     (line-end-position)))
  14274         (let (found
  14275               (i 0)
  14276               item
  14277               regexp
  14278               type
  14279               type-idx
  14280               content
  14281               content-idx
  14282               content-regexp
  14283               close-tag-regexp
  14284               concat-str
  14285               jumpto
  14286               str)
  14287           (while (and (not found ) (< i (length web-mode-imenu-regexp-list)))
  14288             (setq item (nth i web-mode-imenu-regexp-list))
  14289             (setq regexp (nth 0 item))
  14290             (setq type-idx (nth 1 item))
  14291             (setq content-idx (nth 2 item))
  14292             (setq concat-str (nth 3 item))
  14293             (when (not (numberp content-idx))
  14294               (setq content-regexp (nth 2 item)
  14295                     close-tag-regexp (nth 4 item)
  14296                     content-idx nil))
  14297 
  14298             (when (string-match regexp line)
  14299 
  14300               (cond
  14301                (content-idx
  14302                 (setq type (match-string type-idx line))
  14303                 (setq content (match-string content-idx line))
  14304                 (setq str (concat type concat-str content))
  14305                 (setq jumpto (line-beginning-position)))
  14306                (t
  14307                 (let (limit)
  14308                   (setq type (match-string type-idx line))
  14309                   (goto-char (line-beginning-position))
  14310                   (save-excursion
  14311                     (setq limit (re-search-forward close-tag-regexp (point-max) t)))
  14312 
  14313                   (when limit
  14314                     (when (re-search-forward content-regexp limit t)
  14315                       (setq content (match-string 1))
  14316                       (setq str (concat type concat-str content))
  14317                       (setq jumpto (line-beginning-position))
  14318                       )
  14319                     )))
  14320                )
  14321               (when str (setq toc-index
  14322                               (cons (cons str jumpto)
  14323                                     toc-index)
  14324                               )
  14325                     (setq found t))
  14326               )
  14327             (setq i (1+ i))))
  14328         (forward-line)
  14329         (goto-char (line-end-position)) ;; make sure we are at eobp
  14330         ))
  14331     (nreverse toc-index)))
  14332 
  14333 ;;---- UNIT TESTING ------------------------------------------------------------
  14334 
  14335 (defun web-mode-test ()
  14336   "Executes web-mode unit tests. See `web-mode-tests-directory'."
  14337   (interactive)
  14338   (let (files ret regexp)
  14339     (setq regexp "^[[:alnum:]][[:alnum:]._]+\\'")
  14340     (setq files (directory-files web-mode-tests-directory t regexp))
  14341     (dolist (file files)
  14342       (cond
  14343        ((eq (string-to-char (file-name-nondirectory file)) ?\_)
  14344         (delete-file file))
  14345        (t
  14346         (setq ret (web-mode-test-process file)))
  14347        ) ;cond
  14348       ) ;dolist
  14349     ))
  14350 
  14351 (defun web-mode-test-process (file)
  14352   (with-temp-buffer
  14353     (let (out sig1 sig2 success err)
  14354       (setq-default indent-tabs-mode nil)
  14355       (if (string-match-p "sql" file)
  14356           (setq web-mode-enable-sql-detection t)
  14357         (setq web-mode-enable-sql-detection nil))
  14358       (insert-file-contents file)
  14359       (set-visited-file-name file)
  14360       (web-mode)
  14361       (setq sig1 (md5 (current-buffer)))
  14362       (delete-horizontal-space)
  14363       (while (not (eobp))
  14364         (forward-line)
  14365         (delete-horizontal-space)
  14366         (end-of-line))
  14367       (web-mode-buffer-indent)
  14368       (setq sig2 (md5 (current-buffer)))
  14369       (setq success (string= sig1 sig2))
  14370       (setq out (concat (if success "ok" "ko") " : " (file-name-nondirectory file) "\n"))
  14371       (princ out)
  14372       (setq err (concat (file-name-directory file) "_err." (file-name-nondirectory file)))
  14373       (if success
  14374           (when (file-readable-p err)
  14375             (delete-file err))
  14376         (write-file err)
  14377         (message "[%s]" (buffer-string))
  14378         ) ;if
  14379       out)))
  14380 
  14381 ;;---- MISC --------------------------------------------------------------------
  14382 
  14383 (defun web-mode-set-engine (engine)
  14384   "Set the engine for the current buffer."
  14385   (interactive
  14386    (list (completing-read
  14387           "Engine: "
  14388           (let (engines)
  14389             (dolist (elt web-mode-engines)
  14390               (setq engines (append engines (list (car elt)))))
  14391             engines))))
  14392   (setq web-mode-content-type "html"
  14393         web-mode-engine (web-mode-engine-canonical-name engine)
  14394         web-mode-minor-engine engine)
  14395   (web-mode-on-engine-setted)
  14396   (web-mode-buffer-fontify))
  14397 
  14398 (defun web-mode-set-content-type (content-type)
  14399   "Set the content-type for the current buffer"
  14400   (interactive (list (completing-read "Content-type: " web-mode-part-content-types)))
  14401   (setq web-mode-content-type content-type)
  14402   (when (called-interactively-p 'any)
  14403     )
  14404   (web-mode-buffer-fontify))
  14405 
  14406 (defun web-mode-on-engine-setted ()
  14407   (let (elt elts)
  14408 
  14409     (when (string= web-mode-engine "razor") (setq web-mode-enable-block-face t))
  14410     ;;(setq web-mode-engine-attr-regexp (cdr (assoc web-mode-engine web-mode-engine-attr-regexps)))
  14411     (setq web-mode-engine-token-regexp (cdr (assoc web-mode-engine web-mode-engine-token-regexps)))
  14412 
  14413     ;;(message "%S %S %S" web-mode-engine web-mode-engine-attr-regexp web-mode-engine-token-regexp)
  14414 
  14415     (when (null web-mode-minor-engine)
  14416       (setq web-mode-minor-engine "none"))
  14417 
  14418     (setq elt (assoc web-mode-engine web-mode-engine-open-delimiter-regexps))
  14419     (cond
  14420      (elt
  14421       (setq web-mode-block-regexp (cdr elt)))
  14422      ((string= web-mode-engine "archibus")
  14423       (setq web-mode-block-regexp nil))
  14424      (t
  14425       (setq web-mode-engine "none"))
  14426      )
  14427 
  14428     (unless (boundp 'web-mode-extra-auto-pairs)
  14429       (setq web-mode-extra-auto-pairs nil))
  14430 
  14431     (setq web-mode-auto-pairs
  14432           (append
  14433            (cdr (assoc web-mode-engine web-mode-engines-auto-pairs))
  14434            (cdr (assoc nil web-mode-engines-auto-pairs))
  14435            (cdr (assoc web-mode-engine web-mode-extra-auto-pairs))
  14436            (cdr (assoc nil web-mode-extra-auto-pairs))))
  14437 
  14438     (unless (boundp 'web-mode-extra-snippets)
  14439       (setq web-mode-extra-snippets nil))
  14440 
  14441     (setq elts
  14442           (append
  14443            (cdr (assoc web-mode-engine web-mode-extra-snippets))
  14444            (cdr (assoc nil             web-mode-extra-snippets))
  14445            (cdr (assoc web-mode-engine web-mode-engines-snippets))
  14446            (cdr (assoc nil             web-mode-engines-snippets))))
  14447 
  14448     ;;(message "%S" elts)
  14449 
  14450     (dolist (elt elts)
  14451       (unless (assoc (car elt) web-mode-snippets)
  14452         (setq web-mode-snippets (cons elt web-mode-snippets)))
  14453       )
  14454 
  14455     (setq web-mode-engine-font-lock-keywords
  14456           (symbol-value (cdr (assoc web-mode-engine web-mode-engines-font-lock-keywords))))
  14457 
  14458     (when (and (string= web-mode-minor-engine "jinja")
  14459                (not (member "endtrans" web-mode-django-control-blocks)))
  14460       (add-to-list 'web-mode-django-control-blocks "endtrans")
  14461       (setq web-mode-django-control-blocks-regexp
  14462             (regexp-opt web-mode-django-control-blocks t))
  14463       )
  14464 
  14465     (when (string= web-mode-engine "spip")
  14466       (modify-syntax-entry ?# "w" (syntax-table)))
  14467 
  14468 ;;    (message "%S" (symbol-value (cdr (assoc web-mode-engine web-mode-engines-font-lock-keywords))))
  14469 
  14470     ))
  14471 
  14472 (defun web-mode-detect-engine ()
  14473   (save-excursion
  14474     (goto-char (point-min))
  14475     (when (re-search-forward "-\\*- engine:[ ]*\\([[:alnum:]-]+\\)[ ]*-\\*-" web-mode-chunk-length t)
  14476       (setq web-mode-minor-engine (match-string-no-properties 1))
  14477       (setq web-mode-engine (web-mode-engine-canonical-name web-mode-minor-engine)))
  14478     web-mode-minor-engine))
  14479 
  14480 (defun web-mode-guess-engine-and-content-type ()
  14481   (let (buff-name found)
  14482 
  14483     (setq buff-name (buffer-file-name))
  14484     (unless buff-name (setq buff-name (buffer-name)))
  14485     (setq web-mode-is-scratch (string= buff-name "*scratch*"))
  14486     (setq web-mode-content-type nil)
  14487 
  14488     (when (boundp 'web-mode-content-types-alist)
  14489       (setq found nil)
  14490       (dolist (elt web-mode-content-types-alist)
  14491         (when (and (not found) (string-match-p (cdr elt) buff-name))
  14492           (setq web-mode-content-type (car elt)
  14493                 found t))
  14494         ) ;dolist
  14495       ) ;when
  14496 
  14497     (unless web-mode-content-type
  14498       (setq found nil)
  14499       (dolist (elt web-mode-content-types)
  14500         (when (and (not found) (string-match-p (cdr elt) buff-name))
  14501           (setq web-mode-content-type (car elt)
  14502                 found t)
  14503           ;;(message "%S" web-mode-content-type)
  14504           ) ;when
  14505         ) ;dolist
  14506       ) ;unless
  14507 
  14508     (when (boundp 'web-mode-engines-alist)
  14509       (setq found nil)
  14510       (dolist (elt web-mode-engines-alist)
  14511         (cond
  14512          ((stringp (cdr elt))
  14513           (when (string-match-p (cdr elt) buff-name)
  14514             (setq web-mode-engine (car elt))))
  14515          ((functionp (cdr elt))
  14516           (when (funcall (cdr elt))
  14517             (setq web-mode-engine (car elt))))
  14518          ) ;cond
  14519         ) ;dolist
  14520       ) ;when
  14521 
  14522     (unless web-mode-engine
  14523       (setq found nil)
  14524       (dolist (elt web-mode-engine-file-regexps)
  14525         ;;(message "%S %S" (cdr elt) buff-name)
  14526         (when (and (not found) (string-match-p (cdr elt) buff-name))
  14527           (setq web-mode-engine (car elt)
  14528                 found t))
  14529         )
  14530       )
  14531 
  14532     (when (and (or (null web-mode-engine) (string= web-mode-engine "none"))
  14533                (string-match-p "php" (buffer-substring-no-properties
  14534                                       (line-beginning-position)
  14535                                       (line-end-position))))
  14536       (setq web-mode-engine "php"))
  14537 
  14538     (when (and (string= web-mode-content-type "javascript")
  14539                (string-match-p "@jsx"
  14540                                (buffer-substring-no-properties
  14541                                 (point-min)
  14542                                 (if (< (point-max) web-mode-chunk-length)
  14543                                     (point-max)
  14544                                   web-mode-chunk-length)
  14545                                 )))
  14546       (setq web-mode-content-type "jsx"))
  14547 
  14548     (when web-mode-engine
  14549       (setq web-mode-minor-engine web-mode-engine
  14550             web-mode-engine (web-mode-engine-canonical-name web-mode-engine))
  14551       )
  14552 
  14553     (when (and (or (null web-mode-engine)
  14554                    (string= web-mode-engine "none"))
  14555                web-mode-enable-engine-detection)
  14556       (web-mode-detect-engine))
  14557 
  14558     (web-mode-on-engine-setted)
  14559 
  14560     ))
  14561 
  14562 (defun web-mode-engine-canonical-name (name)
  14563   (let (engine)
  14564     (cond
  14565      ((null name)
  14566       nil)
  14567      ((assoc name web-mode-engines)
  14568       name)
  14569      (t
  14570       (dolist (elt web-mode-engines)
  14571         (when (and (null engine) (member name (cdr elt)))
  14572           (setq engine (car elt)))
  14573         ) ;dolist
  14574       engine)
  14575      )))
  14576 
  14577 (defun web-mode-on-after-save ()
  14578   (when web-mode-is-scratch
  14579     (web-mode-guess-engine-and-content-type)
  14580     (web-mode-buffer-fontify))
  14581   nil)
  14582 
  14583 (defun web-mode-on-exit ()
  14584   (web-mode-with-silent-modifications
  14585    (put-text-property (point-min) (point-max) 'invisible nil)
  14586    (remove-overlays)
  14587    (remove-hook 'change-major-mode-hook 'web-mode-on-exit t)
  14588    ))
  14589 
  14590 (defun web-mode-file-link (file)
  14591   "Insert a link to a file in html document. This function can be
  14592 extended to support more filetypes by customizing
  14593 `web-mode-links'."
  14594   (interactive
  14595    (list (file-relative-name (read-file-name "Link file: "))))
  14596   (let ((matched nil)
  14597         (point-line (line-number-at-pos))
  14598         (point-column (current-column)))
  14599     (dolist (type web-mode-links)
  14600       (when (string-match (car type) file)
  14601         (setq matched t)
  14602         (when (nth 2 type)
  14603           (goto-char (point-min))
  14604           (search-forward "</head>")
  14605           (backward-char 7)
  14606           (open-line 1))
  14607         (insert (format (cadr type) file))
  14608         (indent-for-tab-command)
  14609         (when (nth 2 type)
  14610           ;; return point where it was and fix indentation
  14611           (forward-line)
  14612           (indent-for-tab-command)
  14613           (if (> point-line (- (line-number-at-pos) 2))
  14614               (forward-line (+ (- point-line (line-number-at-pos)) 1))
  14615             (forward-line (- point-line (line-number-at-pos))))
  14616           (move-to-column point-column))
  14617         ;; move point back if needed
  14618         (backward-char (nth 3 type))))
  14619     (when (not matched)
  14620       (user-error "Unknown file type"))))
  14621 
  14622 (defun web-mode-reload ()
  14623   "Reload web-mode."
  14624   (interactive)
  14625   (web-mode-with-silent-modifications
  14626     (put-text-property (point-min) (point-max) 'invisible nil)
  14627     (remove-overlays)
  14628     (setq font-lock-unfontify-region-function 'font-lock-default-unfontify-region)
  14629     (load "web-mode.el")
  14630     (setq web-mode-change-beg nil
  14631           web-mode-change-end nil)
  14632     (web-mode)
  14633     ))
  14634 
  14635 (defun web-mode-measure (msg)
  14636   (let (sub)
  14637     (when (null web-mode-time) (setq web-mode-time (current-time)))
  14638     (setq sub (time-subtract (current-time) web-mode-time))
  14639     (when nil
  14640       (save-excursion
  14641         (let ((n 0))
  14642           (goto-char (point-min))
  14643           (while (web-mode-tag-next)
  14644             (setq n (1+ n))
  14645             )
  14646           (message "%S tags found" n)
  14647           )))
  14648     (message "%18s: time elapsed = %Ss %9Sµs" msg (nth 1 sub) (nth 2 sub))
  14649     ))
  14650 
  14651 (defun web-mode-reveal ()
  14652   "Display text properties at point."
  14653   (interactive)
  14654   (let (symbols out)
  14655     (setq out (format
  14656                "[point=%S engine=%S minor=%S content-type=%S language-at-pos=%S]\n"
  14657                (point)
  14658                web-mode-engine
  14659                web-mode-minor-engine
  14660                web-mode-content-type
  14661                (web-mode-language-at-pos (point))))
  14662     (setq symbols (append web-mode-scan-properties '(font-lock-face face)))
  14663     (dolist (symbol symbols)
  14664       (when symbol
  14665         (setq out (concat out (format "%s(%S) " (symbol-name symbol) (get-text-property (point) symbol)))))
  14666       )
  14667     (message "%s\n" out)
  14668     ;;(message "syntax-class=%S" (syntax-class (syntax-after (point))))
  14669     (message nil)))
  14670 
  14671 (defun web-mode-toggle-tracing ()
  14672   "Toggle tracing."
  14673   (interactive)
  14674   (if web-mode-trace
  14675       (setq web-mode-trace nil)
  14676     (message "** tracing on ** point(%S) web-mode-change-beg(%S) web-mode-change-end(%S) web-mode-skip-fontification(%S)"
  14677              (point) web-mode-change-beg web-mode-change-end web-mode-skip-fontification)
  14678     (setq web-mode-trace t)))
  14679 
  14680 (defun web-mode-debug ()
  14681   "Display informations useful for debugging."
  14682   (interactive)
  14683   (let ((modes nil)
  14684         (customs '(web-mode-enable-current-column-highlight web-mode-enable-current-element-highlight indent-tabs-mode))
  14685         (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)))
  14686     (message "\n")
  14687     (message "--- WEB-MODE DEBUG BEG ---")
  14688     (message "versions: emacs(%S.%S) web-mode(%S)"
  14689              emacs-major-version emacs-minor-version web-mode-version)
  14690     (message "vars: engine(%S) minor(%S) content-type(%S) file(%S)"
  14691              web-mode-engine
  14692              web-mode-minor-engine
  14693              web-mode-content-type
  14694              (or (buffer-file-name) (buffer-name)))
  14695     (message "system: window(%S) config(%S)" window-system system-configuration)
  14696     (message "colors: fg(%S) bg(%S) "
  14697              (cdr (assoc 'foreground-color default-frame-alist))
  14698              (cdr (assoc 'background-color default-frame-alist)))
  14699     (mapc (lambda (mode)
  14700             (condition-case nil
  14701                 (if (and (symbolp mode) (symbol-value mode) (not (member mode ignore)))
  14702                     (push mode modes))
  14703               (error nil))
  14704             ) ;lambda
  14705           minor-mode-list)
  14706     (message "minor modes: %S" modes)
  14707     (message "vars:")
  14708     (dolist (custom customs)
  14709       (message (format "%s=%S " (symbol-name custom) (symbol-value custom))))
  14710     (message "--- WEB-MODE DEBUG END ---")
  14711     (switch-to-buffer "*Messages*")
  14712     (goto-char (point-max))
  14713     (recenter)
  14714   ))
  14715 
  14716 (provide 'web-mode)
  14717 
  14718 ;;; web-mode.el ends here
  14719 
  14720 ;; Local Variables:
  14721 ;; coding: utf-8
  14722 ;; indent-tabs-mode: nil
  14723 ;; End: