1 ;;; css-simple-completion.el --- Partly context aware css completion
3 ;; Author: Lennart Borgman (lennart O borgman A gmail O com)
4 ;; Created: 2009-11-22 Sun
6 ;; Last-Updated: 2009-11-22 Sun
11 ;; Features that might be required by this library:
15 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
19 ;; Simple partly context aware completion. Context is based on
22 ;; This can be combined with with flymake-css.el that can check the
26 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
31 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
33 ;; This program is free software; you can redistribute it and/or
34 ;; modify it under the terms of the GNU General Public License as
35 ;; published by the Free Software Foundation; either version 3, or
36 ;; (at your option) any later version.
38 ;; This program is distributed in the hope that it will be useful,
39 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
40 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41 ;; General Public License for more details.
43 ;; You should have received a copy of the GNU General Public License
44 ;; along with this program; see the file COPYING. If not, write to
45 ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
46 ;; Floor, Boston, MA 02110-1301, USA.
48 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
52 ;; Fix-me: bad structure, does not fit completion frameworks
53 (defun css-simple-completing-w-pred (regexp matnum prompt collection)
55 (when (looking-back regexp (line-beginning-position) t)
56 (setq pre (downcase (match-string matnum)))
57 (setq len (length pre))
58 (setq start (match-beginning matnum))
59 (unless (try-completion pre collection)
61 (throw 'result (list start
62 (completing-read prompt
65 (and (>= (length alt) len)
67 (substring alt 0 len))))
71 (defun css-simple-complete ()
72 "Try to complete at current point.
73 This tries to complete keywords, but no CSS values.
75 This is of course a pity since the value syntax is a bit
76 complicated. However you can at least check the syntax with
77 flymake-css if you want to."
79 (let ((context (css-simple-guess-context))
90 (css-simple-completing-w-pred "\\<[a-z0-9-]*" 0 "Media type: " css-media-ids))
93 (css-simple-completing-w-pred "@\\([a-z0-9-]*\\)" 1 "At rule: @" css-at-ids))
96 (css-simple-completing-w-pred "\\<[a-z-]*" 0 "CSS property name: " css-property-ids))
98 ( 'css-simple-selectors
100 ;; Fix-me: Break out the first two
101 (when (looking-back "\\W#\\([a-z0-9-]*\\)")
102 (setq cur (match-string 1))
103 (setq start (match-beginning 1))
104 (throw 'result (list (point)
105 (read-string (concat "Html tag Id: " cur)))))
106 (when (looking-back "\\W\\.\\([a-z0-9-]*\\)")
107 (setq cur (match-string 1))
108 (setq start (match-beginning 1))
109 (throw 'result (list (point)
110 (read-string (concat "CSS class name: " cur)))))
112 (css-simple-completing-w-pred "[a-z0-9]:\\([a-z0-9-]*\\)" 1 "Pseudo id: " css-pseudo-ids)
114 (css-simple-completing-w-pred "[a-z0-9-]+" 0 "HTML tag: " (cddr css-simple-selectors))
116 (when (looking-back "\\<\\(?:#\\|\\.\\)")
119 (setq pre (completing-read "HTML tag, id or CSS class: " css-simple-selectors nil nil pre))
120 (if (string= (substring pre 0 1) "#")
121 (if (or (= 1 (length pre))
122 (and (> (length pre) 2)
123 (string= (substring pre 0 3) "# (")))
124 (throw 'result (list (point) (concat "#" (read-string "Html tag id: #"))))
125 (throw 'result (list (point) pre)))
126 (if (string= (substring pre 0 1) ".")
127 (if (or (= 1 (length pre))
128 (and (> (length pre) 2)
129 (string= (substring pre 0 3) ". (")))
130 (throw 'result (list (point) (concat "." (read-string "CSS class name: ."))))
131 (throw 'result (list (point) pre)))
132 (when (member pre css-simple-selectors)
133 (throw 'result (list (point) pre)))))
135 (message "result=%S" result)
137 (let ((str (cadr result))
138 (len (- (point) (car result))))
139 (insert (substring str len)))
140 (message "No matching alternatives"))))
142 (defun css-simple-guess-context ()
143 "Try to find a context matching none constant.
144 Return the symbol corresponding to the context or nil if none
147 The symbols are the names of the defconst holding the possibly
150 * Note: This function assumes that comments are fontified before
152 ;; Kind of hand-written backward parser ... ;-)
153 (let ((ignore-case t) ;; fix-me
155 (after-colon (and (not (bobp)) (eq (char-before) ?:)))
159 ;; No completion in comments.
160 (when (eq (get-text-property (point) 'face)
161 'font-lock-comment-face)
164 ;; If we are not on whitespace then don't complete
165 (css-simple-skip-backwards-to-code)
167 (= (char-syntax (char-after)) ?\ )
171 ;; Skip backwards to see if after first selector
172 (let ((here2 (1+ (point))))
173 (while (/= here2 (point))
175 (css-simple-skip-backwards-to-code)
176 (when (and (not (bobp))
177 (eq (char-before) ?,))
179 (skip-chars-backward "#.:a-z0-9-")))
182 (eq (char-before) ?}))
183 (throw 'return 'css-simple-selectors))
186 (when (memq (char-before) '( ?{ ?\; ))
187 (throw 'return 'css-property-ids))
189 ;; If we are in the value we can't complete there yet.
190 (when (eq (char-before) ?:)
196 (skip-chars-backward "a-z0-9-")
197 (when (eq (char-before) ?@)
198 (throw 'return 'css-at-ids))
201 (when (looking-back "@media\\W+")
202 (throw 'return 'css-media-ids))
206 ;;; Fix-me: complete these ...
207 ;;css-descriptor-ids ;; Removed or?
209 (defun css-simple-skip-backwards-to-code ()
210 "Skip backwards until we reach code.
211 Requires that comments are fontified."
212 (let ((here (1+ (point))))
213 (while (/= here (point))
215 (skip-syntax-backward " ")
217 (when (memq (get-text-property (1- (point)) 'face)
218 '(font-lock-comment-face font-lock-comment-delimiter-face))
219 (goto-char (or (previous-single-property-change (1- (point)) 'face)
222 (defconst css-simple-selectors
226 "a" "abbr" "acronym" "address" "applet" "area" "b" "base" "basefont" "bdo" "big"
227 "blockquote" "body" "br" "button" "caption" "center" "cite" "code" "col"
228 "colgroup" "dd" "del" "dfn" "dir" "div" "dl" "dt" "em" "fieldset" "font" "form"
229 "frame" "frameset" "head" "h1" "h2" "h3" "h4" "h5" "h6" "hr" "html" "i" "iframe" "img"
230 "input" "ins" "kbd" "label" "legend" "li" "link" "map" "menu" "meta" "noframes"
231 "noscript" "object" "ol" "optgroup" "option" "p" "param" "pre" "q" "s" "samp"
232 "script" "select" "small" "span" "strike" "strong" "style" "sub" "sup" "table"
233 "tbody" "td" "textarea" "tfoot" "th" "thead" "title" "tr" "tt" "u" "ul" "var"
236 (provide 'css-simple-completion)
237 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
238 ;;; css-simple-completion.el ends here