mirror of https://github.com/Chizi123/.emacs.d.git

Chizi123
2018-11-18 8f6f2705a38e2515b6c57fda12c5be29fb9a798f
commit | author | age
5cb5f7 1 ;;; company-css.el --- company-mode completion backend for css-mode  -*- lexical-binding: t -*-
C 2
3 ;; Copyright (C) 2009, 2011, 2014, 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 <http://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