company-css.el (19808B)
1 ;;; company-css.el --- company-mode completion backend for css-mode -*- lexical-binding: t -*- 2 3 ;; Copyright (C) 2009-2011, 2013-2015, 2018 Free Software Foundation, Inc. 4 5 ;; Author: Nikolaj Schumacher 6 7 ;; This file is part of GNU Emacs. 8 9 ;; GNU Emacs is free software: you can redistribute it and/or modify 10 ;; it under the terms of the GNU General Public License as published by 11 ;; the Free Software Foundation, either version 3 of the License, or 12 ;; (at your option) any later version. 13 14 ;; GNU Emacs is distributed in the hope that it will be useful, 15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 ;; GNU General Public License for more details. 18 19 ;; You should have received a copy of the GNU General Public License 20 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. 21 22 ;;; Commentary: 23 ;; 24 ;; In Emacs >= 26, company-capf is used instead. 25 26 ;;; Code: 27 28 (require 'company) 29 (require 'cl-lib) 30 31 (declare-function web-mode-language-at-pos "web-mode" (&optional pos)) 32 33 (defconst company-css-property-alist 34 ;; see http://www.w3.org/TR/CSS21/propidx.html 35 '(("azimuth" angle "left-side" "far-left" "left" "center-left" "center" 36 "center-right" "right" "far-right" "right-side" "behind" "leftwards" 37 "rightwards") 38 ("background" background-color background-image background-repeat 39 background-attachment background-position 40 background-clip background-origin background-size) 41 ("background-attachment" "scroll" "fixed") 42 ("background-color" color "transparent") 43 ("background-image" uri "none") 44 ("background-position" percentage length "left" "center" "right" percentage 45 length "top" "center" "bottom" "left" "center" "right" "top" "center" 46 "bottom") 47 ("background-repeat" "repeat" "repeat-x" "repeat-y" "no-repeat") 48 ("border" border-width border-style border-color) 49 ("border-bottom" border) 50 ("border-bottom-color" border-color) 51 ("border-bottom-style" border-style) 52 ("border-bottom-width" border-width) 53 ("border-collapse" "collapse" "separate") 54 ("border-color" color "transparent") 55 ("border-left" border) 56 ("border-left-color" border-color) 57 ("border-left-style" border-style) 58 ("border-left-width" border-width) 59 ("border-right" border) 60 ("border-right-color" border-color) 61 ("border-right-style" border-style) 62 ("border-right-width" border-width) 63 ("border-spacing" length length) 64 ("border-style" border-style) 65 ("border-top" border) 66 ("border-top-color" border-color) 67 ("border-top-style" border-style) 68 ("border-top-width" border-width) 69 ("border-width" border-width) 70 ("bottom" length percentage "auto") 71 ("caption-side" "top" "bottom") 72 ("clear" "none" "left" "right" "both") 73 ("clip" shape "auto") 74 ("color" color) 75 ("content" "normal" "none" string uri counter "attr()" "open-quote" 76 "close-quote" "no-open-quote" "no-close-quote") 77 ("counter-increment" identifier integer "none") 78 ("counter-reset" identifier integer "none") 79 ("cue" cue-before cue-after) 80 ("cue-after" uri "none") 81 ("cue-before" uri "none") 82 ("cursor" uri "*" "auto" "crosshair" "default" "pointer" "move" "e-resize" 83 "ne-resize" "nw-resize" "n-resize" "se-resize" "sw-resize" "s-resize" 84 "w-resize" "text" "wait" "help" "progress") 85 ("direction" "ltr" "rtl") 86 ("display" "inline" "block" "list-item" "run-in" "inline-block" "table" 87 "inline-table" "table-row-group" "table-header-group" "table-footer-group" 88 "table-row" "table-column-group" "table-column" "table-cell" 89 "table-caption" "none") 90 ("elevation" angle "below" "level" "above" "higher" "lower") 91 ("empty-cells" "show" "hide") 92 ("float" "left" "right" "none") 93 ("font" font-style font-weight font-size "/" line-height 94 font-family "caption" "icon" "menu" "message-box" "small-caption" 95 "status-bar" "normal" "small-caps" 96 ;; CSS3 97 font-stretch) 98 ("font-family" family-name generic-family) 99 ("font-size" absolute-size relative-size length percentage) 100 ("font-style" "normal" "italic" "oblique") 101 ("font-weight" "normal" "bold" "bolder" "lighter" "100" "200" "300" "400" 102 "500" "600" "700" "800" "900") 103 ("height" length percentage "auto") 104 ("left" length percentage "auto") 105 ("letter-spacing" "normal" length) 106 ("line-height" "normal" number length percentage) 107 ("list-style" list-style-type list-style-position list-style-image) 108 ("list-style-image" uri "none") 109 ("list-style-position" "inside" "outside") 110 ("list-style-type" "disc" "circle" "square" "decimal" "decimal-leading-zero" 111 "lower-roman" "upper-roman" "lower-greek" "lower-latin" "upper-latin" 112 "armenian" "georgian" "lower-alpha" "upper-alpha" "none") 113 ("margin" margin-width) 114 ("margin-bottom" margin-width) 115 ("margin-left" margin-width) 116 ("margin-right" margin-width) 117 ("margin-top" margin-width) 118 ("max-height" length percentage "none") 119 ("max-width" length percentage "none") 120 ("min-height" length percentage) 121 ("min-width" length percentage) 122 ("orphans" integer) 123 ("outline" outline-color outline-style outline-width) 124 ("outline-color" color "invert") 125 ("outline-style" border-style) 126 ("outline-width" border-width) 127 ("overflow" "visible" "hidden" "scroll" "auto" 128 ;; CSS3: 129 "no-display" "no-content") 130 ("padding" padding-width) 131 ("padding-bottom" padding-width) 132 ("padding-left" padding-width) 133 ("padding-right" padding-width) 134 ("padding-top" padding-width) 135 ("page-break-after" "auto" "always" "avoid" "left" "right") 136 ("page-break-before" "auto" "always" "avoid" "left" "right") 137 ("page-break-inside" "avoid" "auto") 138 ("pause" time percentage) 139 ("pause-after" time percentage) 140 ("pause-before" time percentage) 141 ("pitch" frequency "x-low" "low" "medium" "high" "x-high") 142 ("pitch-range" number) 143 ("play-during" uri "mix" "repeat" "auto" "none") 144 ("position" "static" "relative" "absolute" "fixed") 145 ("quotes" string string "none") 146 ("richness" number) 147 ("right" length percentage "auto") 148 ("speak" "normal" "none" "spell-out") 149 ("speak-header" "once" "always") 150 ("speak-numeral" "digits" "continuous") 151 ("speak-punctuation" "code" "none") 152 ("speech-rate" number "x-slow" "slow" "medium" "fast" "x-fast" "faster" 153 "slower") 154 ("stress" number) 155 ("table-layout" "auto" "fixed") 156 ("text-align" "left" "right" "center" "justify") 157 ("text-indent" length percentage) 158 ("text-transform" "capitalize" "uppercase" "lowercase" "none") 159 ("top" length percentage "auto") 160 ("unicode-bidi" "normal" "embed" "bidi-override") 161 ("vertical-align" "baseline" "sub" "super" "top" "text-top" "middle" 162 "bottom" "text-bottom" percentage length) 163 ("visibility" "visible" "hidden" "collapse") 164 ("voice-family" specific-voice generic-voice "*" specific-voice 165 generic-voice) 166 ("volume" number percentage "silent" "x-soft" "soft" "medium" "loud" 167 "x-loud") 168 ("white-space" "normal" "pre" "nowrap" "pre-wrap" "pre-line") 169 ("widows" integer) 170 ("width" length percentage "auto") 171 ("word-spacing" "normal" length) 172 ("z-index" "auto" integer) 173 ;; CSS3 174 ("align-content" align-stretch "space-between" "space-around") 175 ("align-items" align-stretch "baseline") 176 ("align-self" align-items "auto") 177 ("animation" animation-name animation-duration animation-timing-function 178 animation-delay animation-iteration-count animation-direction 179 animation-fill-mode) 180 ("animation-delay" time) 181 ("animation-direction" "normal" "reverse" "alternate" "alternate-reverse") 182 ("animation-duration" time) 183 ("animation-fill-mode" "none" "forwards" "backwards" "both") 184 ("animation-iteration-count" integer "infinite") 185 ("animation-name" "none") 186 ("animation-play-state" "paused" "running") 187 ("animation-timing-function" transition-timing-function 188 "step-start" "step-end" "steps(,)") 189 ("backface-visibility" "visible" "hidden") 190 ("background-clip" background-origin) 191 ("background-origin" "border-box" "padding-box" "content-box") 192 ("background-size" length percentage "auto" "cover" "contain") 193 ("border-image" border-image-outset border-image-repeat border-image-source 194 border-image-slice border-image-width) 195 ("border-image-outset" length) 196 ("border-image-repeat" "stretch" "repeat" "round" "space") 197 ("border-image-source" uri "none") 198 ("border-image-slice" length) 199 ("border-image-width" length percentage) 200 ("border-radius" length) 201 ("border-top-left-radius" length) 202 ("border-top-right-radius" length) 203 ("border-bottom-left-radius" length) 204 ("border-bottom-right-radius" length) 205 ("box-decoration-break" "slice" "clone") 206 ("box-shadow" length color) 207 ("box-sizing" "content-box" "border-box") 208 ("break-after" "auto" "always" "avoid" "left" "right" "page" "column" 209 "avoid-page" "avoid-column") 210 ("break-before" break-after) 211 ("break-inside" "avoid" "auto") 212 ("columns" column-width column-count) 213 ("column-count" integer) 214 ("column-fill" "auto" "balance") 215 ("column-gap" length "normal") 216 ("column-rule" column-rule-width column-rule-style column-rule-color) 217 ("column-rule-color" color) 218 ("column-rule-style" border-style) 219 ("column-rule-width" border-width) 220 ("column-span" "all" "none") 221 ("column-width" length "auto") 222 ("filter" url "blur()" "brightness()" "contrast()" "drop-shadow()" 223 "grayscale()" "hue-rotate()" "invert()" "opacity()" "saturate()" "sepia()") 224 ("flex" flex-grow flex-shrink flex-basis) 225 ("flex-basis" percentage length "auto") 226 ("flex-direction" "row" "row-reverse" "column" "column-reverse") 227 ("flex-flow" flex-direction flex-wrap) 228 ("flex-grow" number) 229 ("flex-shrink" number) 230 ("flex-wrap" "nowrap" "wrap" "wrap-reverse") 231 ("font-feature-setting" normal string number) 232 ("font-kerning" "auto" "normal" "none") 233 ("font-language-override" "normal" string) 234 ("font-size-adjust" "none" number) 235 ("font-stretch" "normal" "ultra-condensed" "extra-condensed" "condensed" 236 "semi-condensed" "semi-expanded" "expanded" "extra-expanded" "ultra-expanded") 237 ("font-synthesis" "none" "weight" "style") 238 ("font-variant" font-variant-alternates font-variant-caps 239 font-variant-east-asian font-variant-ligatures font-variant-numeric 240 font-variant-position) 241 ("font-variant-alternates" "normal" "historical-forms" "stylistic()" 242 "styleset()" "character-variant()" "swash()" "ornaments()" "annotation()") 243 ("font-variant-caps" "normal" "small-caps" "all-small-caps" "petite-caps" 244 "all-petite-caps" "unicase" "titling-caps") 245 ("font-variant-east-asian" "jis78" "jis83" "jis90" "jis04" "simplified" 246 "traditional" "full-width" "proportional-width" "ruby") 247 ("font-variant-ligatures" "normal" "none" "common-ligatures" 248 "no-common-ligatures" "discretionary-ligatures" "no-discretionary-ligatures" 249 "historical-ligatures" "no-historical-ligatures" "contextual" "no-contextual") 250 ("font-variant-numeric" "normal" "ordinal" "slashed-zero" 251 "lining-nums" "oldstyle-nums" "proportional-nums" "tabular-nums" 252 "diagonal-fractions" "stacked-fractions") 253 ("font-variant-position" "normal" "sub" "super") 254 ("hyphens" "none" "manual" "auto") 255 ("justify-content" align-common "space-between" "space-around") 256 ("line-break" "auto" "loose" "normal" "strict") 257 ("marquee-direction" "forward" "reverse") 258 ("marquee-play-count" integer "infinite") 259 ("marquee-speed" "slow" "normal" "fast") 260 ("marquee-style" "scroll" "slide" "alternate") 261 ("opacity" number) 262 ("order" number) 263 ("outline-offset" length) 264 ("overflow-x" overflow) 265 ("overflow-y" overflow) 266 ("overflow-style" "auto" "marquee-line" "marquee-block") 267 ("overflow-wrap" "normal" "break-word") 268 ("perspective" "none" length) 269 ("perspective-origin" percentage length "left" "center" "right" "top" "bottom") 270 ("resize" "none" "both" "horizontal" "vertical") 271 ("tab-size" integer length) 272 ("text-align-last" "auto" "start" "end" "left" "right" "center" "justify") 273 ("text-decoration" text-decoration-color text-decoration-line text-decoration-style) 274 ("text-decoration-color" color) 275 ("text-decoration-line" "none" "underline" "overline" "line-through" "blink") 276 ("text-decoration-style" "solid" "double" "dotted" "dashed" "wavy") 277 ("text-overflow" "clip" "ellipsis") 278 ("text-shadow" color length) 279 ("text-underline-position" "auto" "under" "left" "right") 280 ("transform" "matrix(,,,,,)" "translate(,)" "translateX()" "translateY()" 281 "scale()" "scaleX()" "scaleY()" "rotate()" "skewX()" "skewY()" "none") 282 ("transform-origin" perspective-origin) 283 ("transform-style" "flat" "preserve-3d") 284 ("transition" transition-property transition-duration 285 transition-timing-function transition-delay) 286 ("transition-delay" time) 287 ("transition-duration" time) 288 ("transition-timing-function" 289 "ease" "linear" "ease-in" "ease-out" "ease-in-out" "cubic-bezier(,,,)") 290 ("transition-property" "none" "all" identifier) 291 ("word-wrap" overflow-wrap) 292 ("word-break" "normal" "break-all" "keep-all")) 293 "A list of CSS properties and their possible values.") 294 295 (defconst company-css-value-classes 296 '((absolute-size "xx-small" "x-small" "small" "medium" "large" "x-large" 297 "xx-large") 298 (align-common "flex-start" "flex-end" "center") 299 (align-stretch align-common "stretch") 300 (border-style "none" "hidden" "dotted" "dashed" "solid" "double" "groove" 301 "ridge" "inset" "outset") 302 (border-width "thick" "medium" "thin") 303 (color "aqua" "black" "blue" "fuchsia" "gray" "green" "lime" "maroon" "navy" 304 "olive" "orange" "purple" "red" "silver" "teal" "white" "yellow") 305 (counter "counter(,)") 306 (family-name "Courier" "Helvetica" "Times") 307 (generic-family "serif" "sans-serif" "cursive" "fantasy" "monospace") 308 (generic-voice "male" "female" "child") 309 (margin-width "auto") ;; length percentage 310 (relative-size "larger" "smaller") 311 (shape "rect(,,,)") 312 (uri "url()")) 313 "A list of CSS property value classes and their contents.") 314 ;; missing, because not completable 315 ;; <angle><frequency><identifier><integer><length><number><padding-width> 316 ;; <percentage><specific-voice><string><time><uri> 317 318 (defconst company-css-html-tags 319 '("a" "abbr" "acronym" "address" "applet" "area" "b" "base" "basefont" "bdo" 320 "big" "blockquote" "body" "br" "button" "caption" "center" "cite" "code" 321 "col" "colgroup" "dd" "del" "dfn" "dir" "div" "dl" "dt" "em" "fieldset" 322 "font" "form" "frame" "frameset" "h1" "h2" "h3" "h4" "h5" "h6" "head" "hr" 323 "html" "i" "iframe" "img" "input" "ins" "isindex" "kbd" "label" "legend" 324 "li" "link" "map" "menu" "meta" "noframes" "noscript" "object" "ol" 325 "optgroup" "option" "p" "param" "pre" "q" "s" "samp" "script" "select" 326 "small" "span" "strike" "strong" "style" "sub" "sup" "table" "tbody" "td" 327 "textarea" "tfoot" "th" "thead" "title" "tr" "tt" "u" "ul" "var" 328 ;; HTML5 329 "section" "article" "aside" "header" "footer" "nav" "figure" "figcaption" 330 "time" "mark" "main") 331 "A list of HTML tags for use in CSS completion.") 332 333 (defconst company-css-pseudo-classes 334 '("active" "after" "before" "first" "first-child" "first-letter" "first-line" 335 "focus" "hover" "lang" "left" "link" "right" "visited") 336 "Identifiers for CSS pseudo-elements and pseudo-classes.") 337 338 (defconst company-css-property-cache (make-hash-table :size 115 :test 'equal)) 339 340 (defun company-css-property-values (attribute) 341 "Access the `company-css-property-alist' cached and flattened." 342 (or (gethash attribute company-css-property-cache) 343 (let (results) 344 (dolist (value (cdr (assoc attribute company-css-property-alist))) 345 (if (symbolp value) 346 (dolist (child (or (cdr (assoc value company-css-value-classes)) 347 (company-css-property-values 348 (symbol-name value)))) 349 (push child results)) 350 (push value results))) 351 (setq results (sort results 'string<)) 352 (puthash attribute 353 (if (fboundp 'delete-consecutive-dups) 354 (delete-consecutive-dups results) 355 (delete-dups results)) 356 company-css-property-cache) 357 results))) 358 359 ;;; bracket detection 360 361 (defconst company-css-braces-syntax-table 362 (let ((table (make-syntax-table))) 363 (setf (aref table ?{) '(4 . 125)) 364 (setf (aref table ?}) '(5 . 123)) 365 table) 366 "A syntax table giving { and } paren syntax.") 367 368 (defun company-css-inside-braces-p () 369 "Return non-nil, if point is within matched { and }." 370 (ignore-errors 371 (with-syntax-table company-css-braces-syntax-table 372 (let ((parse-sexp-ignore-comments t)) 373 (scan-lists (point) -1 1))))) 374 375 ;;; tags 376 (defconst company-css-tag-regexp 377 (concat "\\(?:\\`\\|}\\)[[:space:]]*" 378 ;; multiple 379 "\\(?:" 380 ;; previous tags: 381 "\\(?:#\\|\\_<[[:alpha:]]\\)[[:alnum:]-#]*\\(?:\\[[^]]*\\]\\)?" 382 ;; space or selectors 383 "\\(?:[[:space:]]+\\|[[:space:]]*[+,>][[:space:]]*\\)" 384 "\\)*" 385 "\\(\\(?:#\\|\\_<[[:alpha:]]\\)\\(?:[[:alnum:]-#]*\\_>\\)?\\_>\\|\\)" 386 "\\=") 387 "A regular expression matching CSS tags.") 388 389 ;;; pseudo id 390 (defconst company-css-pseudo-regexp 391 (concat "\\(?:\\`\\|}\\)[[:space:]]*" 392 ;; multiple 393 "\\(?:" 394 ;; previous tags: 395 "\\(?:#\\|\\_<[[:alpha:]]\\)[[:alnum:]-#]*\\(?:\\[[^]]*\\]\\)?" 396 ;; space or delimiters 397 "\\(?:[[:space:]]+\\|[[:space:]]*[+,>][[:space:]]*\\)" 398 "\\)*" 399 "\\(?:\\(?:\\#\\|\\_<[[:alpha:]]\\)[[:alnum:]-#]*\\):" 400 "\\([[:alpha:]-]+\\_>\\|\\)\\_>\\=") 401 "A regular expression matching CSS pseudo classes.") 402 403 ;;; properties 404 405 (defun company-css-grab-property () 406 "Return the CSS property before point, if any. 407 Returns \"\" if no property found, but feasible at this position." 408 (when (company-css-inside-braces-p) 409 (company-grab-symbol))) 410 411 ;;; values 412 (defconst company-css-property-value-regexp 413 "\\_<\\([[:alpha:]-]+\\):\\(?:[^{};]*[[:space:]]+\\)?\\([^{};]*\\_>\\|\\)\\=" 414 "A regular expression matching CSS tags.") 415 416 ;;;###autoload 417 (defun company-css (command &optional arg &rest _ignored) 418 "`company-mode' completion backend for `css-mode'." 419 (interactive (list 'interactive)) 420 (cl-case command 421 (interactive (company-begin-backend 'company-css)) 422 (prefix (and (or (derived-mode-p 'css-mode) 423 (and (derived-mode-p 'web-mode) 424 (string= (web-mode-language-at-pos) "css"))) 425 (or (company-grab company-css-tag-regexp 1) 426 (company-grab company-css-pseudo-regexp 1) 427 (company-grab company-css-property-value-regexp 2 428 (line-beginning-position)) 429 (company-css-grab-property)))) 430 (candidates 431 (cond 432 ((company-grab company-css-tag-regexp 1) 433 (all-completions arg company-css-html-tags)) 434 ((company-grab company-css-pseudo-regexp 1) 435 (all-completions arg company-css-pseudo-classes)) 436 ((company-grab company-css-property-value-regexp 2 437 (line-beginning-position)) 438 (all-completions arg 439 (company-css-property-values 440 (company-grab company-css-property-value-regexp 1)))) 441 ((company-css-grab-property) 442 (all-completions arg company-css-property-alist)))) 443 (sorted t))) 444 445 (provide 'company-css) 446 ;;; company-css.el ends here