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