]> code.delx.au - gnu-emacs-elpa/blob - company-css.el
Added back-end file headers.
[gnu-emacs-elpa] / company-css.el
1 ;;; company-css.el --- a company-mode completion back-end for css-mode
2 ;;
3 ;; Copyright (C) 2009 Nikolaj Schumacher
4 ;;
5 ;; This file is part of company.
6 ;;
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.
11 ;;
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.
16 ;;
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/>.
19
20 (require 'company)
21 (eval-when-compile (require 'cl))
22
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"
27 "rightwards")
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"
35 "bottom")
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)
54 ("border-top" border)
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")
62 ("clip" shape "auto")
63 ("color" color)
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"
84 "status-bar")
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)
110 ("orphans" integer)
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")
132 ("richness" number)
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"
139 "slower")
140 ("stress" number)
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
152 generic-voice)
153 ("volume" number percentage "silent" "x-soft" "soft" "medium" "loud"
154 "x-loud")
155 ("white-space" "normal" "pre" "nowrap" "pre-wrap" "pre-line")
156 ("widows" integer)
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.")
161
162 (defconst company-css-value-classes
163 '((absolute-size "xx-small" "x-small" "small" "medium" "large" "x-large"
164 "xx-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")
175 (shape "rect(,,,)")
176 (uri "url()"))
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>
181
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.")
193
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.")
198
199 (defconst company-css-property-cache (make-hash-table :size 115 :test 'equal))
200
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)
204 (let (results)
205 (dolist (value (cdr (assoc attribute company-css-property-alist)))
206 (if (symbolp value)
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)
214 results)))
215
216 ;;; bracket detection
217
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))
222 table)
223 "A syntax table giving { and } paren syntax.")
224
225 (defun company-css-inside-braces-p ()
226 "Return non-nil, if point is within matched { and }."
227 (ignore-errors
228 (with-syntax-table company-css-braces-syntax-table
229 (let ((parse-sexp-ignore-comments t))
230 (scan-lists (point) -1 1)))))
231
232 ;;; tags
233 (defconst company-css-tag-regexp
234 (concat "\\(?:\\`\\|}\\)[[:space:]]*"
235 ;; multiple
236 "\\(?:"
237 ;; previous tags:
238 "\\(?:#\\|\\_<[[:alpha:]]\\)[[:alnum:]-#]*\\(?:\\[[^]]*\\]\\)?"
239 ;; space or selectors
240 "\\(?:[[:space:]]+\\|[[:space:]]*[+,>][[:space:]]*\\)"
241 "\\)*"
242 "\\(\\(?:#\\|\\_<[[:alpha:]]\\)\\(?:[[:alnum:]-#]*\\_>\\)?\\_>\\|\\)"
243 "\\=")
244 "A regular expression matching CSS tags")
245
246 ;;; pseudo id
247 (defconst company-css-pseudo-regexp
248 (concat "\\(?:\\`\\|}\\)[[:space:]]*"
249 ;; multiple
250 "\\(?:"
251 ;; previous tags:
252 "\\(?:#\\|\\_<[[:alpha:]]\\)[[:alnum:]-#]*\\(?:\\[[^]]*\\]\\)?"
253 ;; space or delimiters
254 "\\(?:[[:space:]]+\\|[[:space:]]*[+,>][[:space:]]*\\)"
255 "\\)*"
256 "\\(?:\\(?:\\#\\|\\_<[[:alpha:]]\\)[[:alnum:]-#]*\\):"
257 "\\([[:alpha:]-]+\\_>\\|\\)\\_>\\=")
258 "A regular expression matching CSS pseudo classes")
259
260 ;;; properties
261
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 (or (company-grab "\\_<[[:alpha:]-]+\\_>\\=")
267 (company-grab "{\\|[[:space:]]" 1))))
268
269 ;;; values
270 (defconst company-css-property-value-regexp
271 "\\_<\\([[:alpha:]-]+\\):\\(?:[^};]*[[:space:]]+\\)?\\([^};]*\\_>\\|\\)\\="
272 "A regular expression matching CSS tags")
273
274 (defun company-css (command &optional arg &rest ignored)
275 (case command
276 ('prefix (and (eq major-mode 'css-mode)
277 (or (company-grab company-css-tag-regexp 1)
278 (company-grab company-css-pseudo-regexp 1)
279 (company-grab company-css-property-value-regexp 2)
280 (company-css-grab-property))))
281 ('candidates
282 (cond
283 ((company-grab company-css-tag-regexp 1)
284 (all-completions arg company-css-html-tags))
285 ((company-grab company-css-pseudo-regexp 1)
286 (all-completions arg company-css-pseudo-classes))
287 ((company-grab company-css-property-value-regexp 2)
288 (all-completions arg
289 (company-css-property-values
290 (company-grab company-css-property-value-regexp 1))))
291 ((company-css-grab-property)
292 (all-completions arg company-css-property-alist))))
293 ('sorted t)))
294
295 (provide 'company-css)
296 ;;; company-css.el ends here