]> code.delx.au - gnu-emacs-elpa/blob - company-css.el
company-css-value-classes: fix border-width infloop
[gnu-emacs-elpa] / company-css.el
1 ;;; company-css.el --- company-mode completion back-end for css-mode
2
3 ;; Copyright (C) 2009, 2011, 2014 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 ;;; Code:
25
26 (require 'company)
27 (require 'cl-lib)
28
29 (defconst company-css-property-alist
30 ;; see http://www.w3.org/TR/CSS21/propidx.html
31 '(("azimuth" angle "left-side" "far-left" "left" "center-left" "center"
32 "center-right" "right" "far-right" "right-side" "behind" "leftwards"
33 "rightwards")
34 ("background" background-color background-image background-repeat
35 background-attachment background-position)
36 ("background-attachment" "scroll" "fixed")
37 ("background-color" color "transparent")
38 ("background-image" uri "none")
39 ("background-position" percentage length "left" "center" "right" percentage
40 length "top" "center" "bottom" "left" "center" "right" "top" "center"
41 "bottom")
42 ("background-repeat" "repeat" "repeat-x" "repeat-y" "no-repeat")
43 ("border" border-width border-style border-color)
44 ("border-bottom" border)
45 ("border-bottom-color" border-color)
46 ("border-bottom-style" border-style)
47 ("border-bottom-width" border-width)
48 ("border-collapse" "collapse" "separate")
49 ("border-color" color "transparent")
50 ("border-left" border)
51 ("border-left-color" border-color)
52 ("border-left-style" border-style)
53 ("border-left-width" border-width)
54 ("border-right" border)
55 ("border-right-color" border-color)
56 ("border-right-style" border-style)
57 ("border-right-width" border-width)
58 ("border-spacing" length length)
59 ("border-style" border-style)
60 ("border-top" border)
61 ("border-top-color" border-color)
62 ("border-top-style" border-style)
63 ("border-top-width" border-width)
64 ("border-width" border-width)
65 ("bottom" length percentage "auto")
66 ("caption-side" "top" "bottom")
67 ("clear" "none" "left" "right" "both")
68 ("clip" shape "auto")
69 ("color" color)
70 ("content" "normal" "none" string uri counter "attr()" "open-quote"
71 "close-quote" "no-open-quote" "no-close-quote")
72 ("counter-increment" identifier integer "none")
73 ("counter-reset" identifier integer "none")
74 ("cue" cue-before cue-after)
75 ("cue-after" uri "none")
76 ("cue-before" uri "none")
77 ("cursor" uri "*" "auto" "crosshair" "default" "pointer" "move" "e-resize"
78 "ne-resize" "nw-resize" "n-resize" "se-resize" "sw-resize" "s-resize"
79 "w-resize" "text" "wait" "help" "progress")
80 ("direction" "ltr" "rtl")
81 ("display" "inline" "block" "list-item" "run-in" "inline-block" "table"
82 "inline-table" "table-row-group" "table-header-group" "table-footer-group"
83 "table-row" "table-column-group" "table-column" "table-cell"
84 "table-caption" "none")
85 ("elevation" angle "below" "level" "above" "higher" "lower")
86 ("empty-cells" "show" "hide")
87 ("float" "left" "right" "none")
88 ("font" font-style font-variant font-weight font-size "/" line-height
89 font-family "caption" "icon" "menu" "message-box" "small-caption"
90 "status-bar")
91 ("font-family" family-name generic-family)
92 ("font-size" absolute-size relative-size length percentage)
93 ("font-style" "normal" "italic" "oblique")
94 ("font-variant" "normal" "small-caps")
95 ("font-weight" "normal" "bold" "bolder" "lighter" "100" "200" "300" "400"
96 "500" "600" "700" "800" "900")
97 ("height" length percentage "auto")
98 ("left" length percentage "auto")
99 ("letter-spacing" "normal" length)
100 ("line-height" "normal" number length percentage)
101 ("list-style" list-style-type list-style-position list-style-image)
102 ("list-style-image" uri "none")
103 ("list-style-position" "inside" "outside")
104 ("list-style-type" "disc" "circle" "square" "decimal" "decimal-leading-zero"
105 "lower-roman" "upper-roman" "lower-greek" "lower-latin" "upper-latin"
106 "armenian" "georgian" "lower-alpha" "upper-alpha" "none")
107 ("margin" margin-width)
108 ("margin-bottom" margin-width)
109 ("margin-left" margin-width)
110 ("margin-right" margin-width)
111 ("margin-top" margin-width)
112 ("max-height" length percentage "none")
113 ("max-width" length percentage "none")
114 ("min-height" length percentage)
115 ("min-width" length percentage)
116 ("orphans" integer)
117 ("outline" outline-color outline-style outline-width)
118 ("outline-color" color "invert")
119 ("outline-style" border-style)
120 ("outline-width" border-width)
121 ("overflow" "visible" "hidden" "scroll" "auto")
122 ("padding" padding-width)
123 ("padding-bottom" padding-width)
124 ("padding-left" padding-width)
125 ("padding-right" padding-width)
126 ("padding-top" padding-width)
127 ("page-break-after" "auto" "always" "avoid" "left" "right")
128 ("page-break-before" "auto" "always" "avoid" "left" "right")
129 ("page-break-inside" "avoid" "auto")
130 ("pause" time percentage)
131 ("pause-after" time percentage)
132 ("pause-before" time percentage)
133 ("pitch" frequency "x-low" "low" "medium" "high" "x-high")
134 ("pitch-range" number)
135 ("play-during" uri "mix" "repeat" "auto" "none")
136 ("position" "static" "relative" "absolute" "fixed")
137 ("quotes" string string "none")
138 ("richness" number)
139 ("right" length percentage "auto")
140 ("speak" "normal" "none" "spell-out")
141 ("speak-header" "once" "always")
142 ("speak-numeral" "digits" "continuous")
143 ("speak-punctuation" "code" "none")
144 ("speech-rate" number "x-slow" "slow" "medium" "fast" "x-fast" "faster"
145 "slower")
146 ("stress" number)
147 ("table-layout" "auto" "fixed")
148 ("text-align" "left" "right" "center" "justify")
149 ("text-decoration" "none" "underline" "overline" "line-through" "blink")
150 ("text-indent" length percentage)
151 ("text-transform" "capitalize" "uppercase" "lowercase" "none")
152 ("top" length percentage "auto")
153 ("unicode-bidi" "normal" "embed" "bidi-override")
154 ("vertical-align" "baseline" "sub" "super" "top" "text-top" "middle"
155 "bottom" "text-bottom" percentage length)
156 ("visibility" "visible" "hidden" "collapse")
157 ("voice-family" specific-voice generic-voice "*" specific-voice
158 generic-voice)
159 ("volume" number percentage "silent" "x-soft" "soft" "medium" "loud"
160 "x-loud")
161 ("white-space" "normal" "pre" "nowrap" "pre-wrap" "pre-line")
162 ("widows" integer)
163 ("width" length percentage "auto")
164 ("word-spacing" "normal" length)
165 ("z-index" "auto" integer))
166 "A list of CSS properties and their possible values.")
167
168 (defconst company-css-value-classes
169 '((absolute-size "xx-small" "x-small" "small" "medium" "large" "x-large"
170 "xx-large")
171 (border-style "none" "hidden" "dotted" "dashed" "solid" "double" "groove"
172 "ridge" "inset" "outset")
173 (border-width "thick" "medium" "thin")
174 (color "aqua" "black" "blue" "fuchsia" "gray" "green" "lime" "maroon" "navy"
175 "olive" "orange" "purple" "red" "silver" "teal" "white" "yellow")
176 (counter "counter(,)")
177 (family-name "Courier" "Helvetica" "Times")
178 (generic-family "serif" "sans-serif" "cursive" "fantasy" "monospace")
179 (generic-voice "male" "female" "child")
180 (margin-width "auto") ;; length percentage
181 (relative-size "larger" "smaller")
182 (shape "rect(,,,)")
183 (uri "url()"))
184 "A list of CSS property value classes and their contents.")
185 ;; missing, because not completable
186 ;; <angle><frequency><identifier><integer><length><number><padding-width>
187 ;; <percentage><specific-voice><string><time><uri>
188
189 (defconst company-css-html-tags
190 '("a" "abbr" "acronym" "address" "applet" "area" "b" "base" "basefont" "bdo"
191 "big" "blockquote" "body" "br" "button" "caption" "center" "cite" "code"
192 "col" "colgroup" "dd" "del" "dfn" "dir" "div" "dl" "dt" "em" "fieldset"
193 "font" "form" "frame" "frameset" "h1" "h2" "h3" "h4" "h5" "h6" "head" "hr"
194 "html" "i" "iframe" "img" "input" "ins" "isindex" "kbd" "label" "legend"
195 "li" "link" "map" "menu" "meta" "noframes" "noscript" "object" "ol"
196 "optgroup" "option" "p" "param" "pre" "q" "s" "samp" "script" "select"
197 "small" "span" "strike" "strong" "style" "sub" "sup" "table" "tbody" "td"
198 "textarea" "tfoot" "th" "thead" "title" "tr" "tt" "u" "ul" "var")
199 "A list of HTML tags for use in CSS completion.")
200
201 (defconst company-css-pseudo-classes
202 '("active" "after" "before" "first" "first-child" "first-letter" "first-line"
203 "focus" "hover" "lang" "left" "link" "right" "visited")
204 "Identifiers for CSS pseudo-elements and pseudo-classes.")
205
206 (defconst company-css-property-cache (make-hash-table :size 115 :test 'equal))
207
208 (defun company-css-property-values (attribute)
209 "Access the `company-css-property-alist' cached and flattened."
210 (or (gethash attribute company-css-property-cache)
211 (let (results)
212 (dolist (value (cdr (assoc attribute company-css-property-alist)))
213 (if (symbolp value)
214 (dolist (child (or (cdr (assoc value company-css-value-classes))
215 (company-css-property-values
216 (symbol-name value))))
217 (add-to-list 'results child))
218 (add-to-list 'results value)))
219 (setq results (sort results 'string<))
220 (puthash attribute results company-css-property-cache)
221 results)))
222
223 ;;; bracket detection
224
225 (defconst company-css-braces-syntax-table
226 (let ((table (make-syntax-table)))
227 (setf (aref table ?{) '(4 . 125))
228 (setf (aref table ?}) '(5 . 123))
229 table)
230 "A syntax table giving { and } paren syntax.")
231
232 (defun company-css-inside-braces-p ()
233 "Return non-nil, if point is within matched { and }."
234 (ignore-errors
235 (with-syntax-table company-css-braces-syntax-table
236 (let ((parse-sexp-ignore-comments t))
237 (scan-lists (point) -1 1)))))
238
239 ;;; tags
240 (defconst company-css-tag-regexp
241 (concat "\\(?:\\`\\|}\\)[[:space:]]*"
242 ;; multiple
243 "\\(?:"
244 ;; previous tags:
245 "\\(?:#\\|\\_<[[:alpha:]]\\)[[:alnum:]-#]*\\(?:\\[[^]]*\\]\\)?"
246 ;; space or selectors
247 "\\(?:[[:space:]]+\\|[[:space:]]*[+,>][[:space:]]*\\)"
248 "\\)*"
249 "\\(\\(?:#\\|\\_<[[:alpha:]]\\)\\(?:[[:alnum:]-#]*\\_>\\)?\\_>\\|\\)"
250 "\\=")
251 "A regular expression matching CSS tags.")
252
253 ;;; pseudo id
254 (defconst company-css-pseudo-regexp
255 (concat "\\(?:\\`\\|}\\)[[:space:]]*"
256 ;; multiple
257 "\\(?:"
258 ;; previous tags:
259 "\\(?:#\\|\\_<[[:alpha:]]\\)[[:alnum:]-#]*\\(?:\\[[^]]*\\]\\)?"
260 ;; space or delimiters
261 "\\(?:[[:space:]]+\\|[[:space:]]*[+,>][[:space:]]*\\)"
262 "\\)*"
263 "\\(?:\\(?:\\#\\|\\_<[[:alpha:]]\\)[[:alnum:]-#]*\\):"
264 "\\([[:alpha:]-]+\\_>\\|\\)\\_>\\=")
265 "A regular expression matching CSS pseudo classes.")
266
267 ;;; properties
268
269 (defun company-css-grab-property ()
270 "Return the CSS property before point, if any.
271 Returns \"\" if no property found, but feasible at this position."
272 (when (company-css-inside-braces-p)
273 (company-grab-symbol)))
274
275 ;;; values
276 (defconst company-css-property-value-regexp
277 "\\_<\\([[:alpha:]-]+\\):\\(?:[^};]*[[:space:]]+\\)?\\([^};]*\\_>\\|\\)\\="
278 "A regular expression matching CSS tags.")
279
280 ;;;###autoload
281 (defun company-css (command &optional arg &rest ignored)
282 "`company-mode' completion back-end for `css-mode'."
283 (interactive (list 'interactive))
284 (cl-case command
285 (interactive (company-begin-backend 'company-css))
286 (prefix (and (derived-mode-p 'css-mode)
287 (or (company-grab company-css-tag-regexp 1)
288 (company-grab company-css-pseudo-regexp 1)
289 (company-grab company-css-property-value-regexp 2)
290 (company-css-grab-property))))
291 (candidates
292 (cond
293 ((company-grab company-css-tag-regexp 1)
294 (all-completions arg company-css-html-tags))
295 ((company-grab company-css-pseudo-regexp 1)
296 (all-completions arg company-css-pseudo-classes))
297 ((company-grab company-css-property-value-regexp 2)
298 (all-completions arg
299 (company-css-property-values
300 (company-grab company-css-property-value-regexp 1))))
301 ((company-css-grab-property)
302 (all-completions arg company-css-property-alist))))
303 (sorted t)))
304
305 (provide 'company-css)
306 ;;; company-css.el ends here