aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2014-10-20 12:36:34 -0400
committerStefan Monnier2014-10-20 12:36:34 -0400
commitbc0e9e47b645ecd8da86eb8ae5810ebf2fd62b97 (patch)
treecd9aff1fe18c0593b94e03523debeb124685ffd3
parent57fe1632f0dc40042dfb6593f81f451165987637 (diff)
downloademacs-bc0e9e47b645ecd8da86eb8ae5810ebf2fd62b97.tar.gz
emacs-bc0e9e47b645ecd8da86eb8ae5810ebf2fd62b97.zip
* lisp/textmodes/css-mode.el (scss-mode): New major-mode.
(css-mode-syntax-table): Use d style comment, to ease the scss case. (css-ident-re): Allow things like @-moz-keyframes. (scss--hash-re): New const. (css--font-lock-keywords): New function, extracted from css-font-lock-keywords. (css-font-lock-keywords): Use it. (scss-mode-syntax-table, scss-font-lock-keywords): New vars. (scss-smie--not-interpolation-p): New function. (css-smie--forward-token, css-smie--backward-token): Use it. (css-mode): Remove left-over code. * test/indent/scss-mode.scss: New file. * test/indent/css-mode.css: Add a few uneventful examples.
-rw-r--r--etc/NEWS1
-rw-r--r--lisp/ChangeLog13
-rw-r--r--lisp/textmodes/css-mode.el79
-rw-r--r--test/ChangeLog29
-rw-r--r--test/indent/css-mode.css10
-rw-r--r--test/indent/scss-mode.scss57
6 files changed, 164 insertions, 25 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 91cad1315a6..e49fd748a90 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -273,6 +273,7 @@ These emulations of old editors are believed to be no longer relevant
273 273
274* New Modes and Packages in Emacs 25.1 274* New Modes and Packages in Emacs 25.1
275 275
276** scss-mode (a minor variant of css-mode)
276 277
277* Incompatible Lisp Changes in Emacs 25.1 278* Incompatible Lisp Changes in Emacs 25.1
278 279
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 3f75bbdc355..b27f8a0d17e 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,12 @@
12014-10-20 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * textmodes/css-mode.el (scss-mode): New major-mode.
4 (css-mode-syntax-table): Use d style comment, to ease the scss case.
5 (css-ident-re): Allow things like @-moz-keyframes.
6 (scss--hash-re): New const.
7 (css--font-lock-keywords): New function, extracted from
8 css-font-lock-keywords.
9
12014-10-19 Ulf Jasper <ulf.jasper@web.de> 102014-10-19 Ulf Jasper <ulf.jasper@web.de>
2 11
3 * net/newst-backend.el: Require url-parse. 12 * net/newst-backend.el: Require url-parse.
@@ -26,8 +35,8 @@
26 * net/newst-reader.el (newsticker-html-renderer): Whitespace. 35 * net/newst-reader.el (newsticker-html-renderer): Whitespace.
27 (newsticker--print-extra-elements) 36 (newsticker--print-extra-elements)
28 (newsticker--do-print-extra-element): Documentation 37 (newsticker--do-print-extra-element): Documentation
29 (newsticker--image-read): Optionally limit image height. Use 38 (newsticker--image-read): Optionally limit image height.
30 imagemagick if possible. 39 Use imagemagick if possible.
31 (newsticker--icon-read): New. 40 (newsticker--icon-read): New.
32 41
33 * net/newst-treeview.el (newsticker--treeview-item-show): Limit height of feed logo. 42 * net/newst-treeview.el (newsticker--treeview-item-show): Limit height of feed logo.
diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el
index 1a07269c9e9..175964392e9 100644
--- a/lisp/textmodes/css-mode.el
+++ b/lisp/textmodes/css-mode.el
@@ -185,7 +185,7 @@
185 (let ((st (make-syntax-table))) 185 (let ((st (make-syntax-table)))
186 ;; C-style comments. 186 ;; C-style comments.
187 (modify-syntax-entry ?/ ". 14" st) 187 (modify-syntax-entry ?/ ". 14" st)
188 (modify-syntax-entry ?* ". 23" st) 188 (modify-syntax-entry ?* ". 23b" st)
189 ;; Strings. 189 ;; Strings.
190 (modify-syntax-entry ?\" "\"" st) 190 (modify-syntax-entry ?\" "\"" st)
191 (modify-syntax-entry ?\' "\"" st) 191 (modify-syntax-entry ?\' "\"" st)
@@ -210,11 +210,15 @@
210 "\\\\\\(?:[^\000-\037\177]\\|[0-9a-fA-F]+[ \n\t\r\f]?\\)") 210 "\\\\\\(?:[^\000-\037\177]\\|[0-9a-fA-F]+[ \n\t\r\f]?\\)")
211(defconst css-nmchar-re (concat "\\(?:[-[:alnum:]]\\|" css-escapes-re "\\)")) 211(defconst css-nmchar-re (concat "\\(?:[-[:alnum:]]\\|" css-escapes-re "\\)"))
212(defconst css-nmstart-re (concat "\\(?:[[:alpha:]]\\|" css-escapes-re "\\)")) 212(defconst css-nmstart-re (concat "\\(?:[[:alpha:]]\\|" css-escapes-re "\\)"))
213(defconst css-ident-re (concat css-nmstart-re css-nmchar-re "*")) 213(defconst css-ident-re ;; (concat css-nmstart-re css-nmchar-re "*")
214 ;; Apparently, "at rules" names can start with a dash, e.g. @-moz-keyframes.
215 (concat css-nmchar-re "+"))
214(defconst css-proprietary-nmstart-re ;; Vendor-specific properties. 216(defconst css-proprietary-nmstart-re ;; Vendor-specific properties.
215 (concat "[-_]" (regexp-opt '("ms" "moz" "o" "khtml" "webkit")) "-")) 217 (concat "[-_]" (regexp-opt '("ms" "moz" "o" "khtml" "webkit")) "-"))
216(defconst css-name-re (concat css-nmchar-re "+")) 218(defconst css-name-re (concat css-nmchar-re "+"))
217 219
220(defconst scss--hash-re "#\\(?:{[$-_[:alnum:]]+}\\|[[:alnum:]]+\\)")
221
218(defface css-selector '((t :inherit font-lock-function-name-face)) 222(defface css-selector '((t :inherit font-lock-function-name-face))
219 "Face to use for selectors." 223 "Face to use for selectors."
220 :group 'css) 224 :group 'css)
@@ -224,24 +228,44 @@
224(defface css-proprietary-property '((t :inherit (css-property italic))) 228(defface css-proprietary-property '((t :inherit (css-property italic)))
225 "Face to use for vendor-specific properties.") 229 "Face to use for vendor-specific properties.")
226 230
227(defvar css-font-lock-keywords 231(defun css--font-lock-keywords (&optional sassy)
228 `(("!\\s-*important" . font-lock-builtin-face) 232 `((,(concat "!\\s-*"
233 (regexp-opt (append (if sassy '("global"))
234 '("important"))))
235 (0 font-lock-builtin-face))
229 ;; Atrules keywords. IDs not in css-at-ids are valid (ignored). 236 ;; Atrules keywords. IDs not in css-at-ids are valid (ignored).
230 ;; In fact the regexp should probably be 237 ;; In fact the regexp should probably be
231 ;; (,(concat "\\(@" css-ident-re "\\)\\([ \t\n][^;{]*\\)[;{]") 238 ;; (,(concat "\\(@" css-ident-re "\\)\\([ \t\n][^;{]*\\)[;{]")
232 ;; (1 font-lock-builtin-face)) 239 ;; (1 font-lock-builtin-face))
233 ;; Since "An at-rule consists of everything up to and including the next 240 ;; Since "An at-rule consists of everything up to and including the next
234 ;; semicolon (;) or the next block, whichever comes first." 241 ;; semicolon (;) or the next block, whichever comes first."
235 (,(concat "@" css-ident-re) . font-lock-builtin-face) 242 (,(concat "@" css-ident-re) (0 font-lock-builtin-face))
236 ;; Selectors. 243 ;; Selectors.
237 ;; FIXME: attribute selectors don't work well because they may contain 244 ;; FIXME: attribute selectors don't work well because they may contain
238 ;; strings which have already been highlighted as f-l-string-face and 245 ;; strings which have already been highlighted as f-l-string-face and
239 ;; thus prevent this highlighting from being applied (actually now that 246 ;; thus prevent this highlighting from being applied (actually now that
240 ;; I use `append' this should work better). But really the part of the 247 ;; I use `keep' this should work better). But really the part of the
241 ;; selector between [...] should simply not be highlighted. 248 ;; selector between [...] should simply not be highlighted.
242 (,(concat "^\\([ \t]*[^@:{}\n][^:{}]+\\(?::" (regexp-opt css-pseudo-ids t) 249 (,(concat
243 "\\(?:([^)]+)\\)?[^:{\n]*\\)*\\)\\(?:\n[ \t]*\\)*{") 250 "^[ \t]*\\("
244 (1 'css-selector append)) 251 (if (not sassy)
252 ;; We don't allow / as first char, so as not to
253 ;; take a comment as the beginning of a selector.
254 "[^@/:{} \t\n][^:{}]+"
255 ;; Same as for non-sassy except we do want to allow { and }
256 ;; chars in selectors in the case of #{$foo}
257 ;; variable interpolation!
258 (concat "\\(?:" scss--hash-re
259 "\\|[^@/:{} \t\n#]\\)"
260 "[^:{}#]*\\(?:" scss--hash-re "[^:{}#]*\\)*"))
261 "\\(?::" (regexp-opt css-pseudo-ids t)
262 "\\(?:([^\)]+)\\)?"
263 (if (not sassy)
264 "[^:{}\n]*"
265 (concat "[^:{}\n#]*\\(?:" scss--hash-re "[^:{}\n#]*\\)*"))
266 "\\)*"
267 "\\)\\(?:\n[ \t]*\\)*{")
268 (1 'css-selector keep))
245 ;; In the above rule, we allow the open-brace to be on some subsequent 269 ;; In the above rule, we allow the open-brace to be on some subsequent
246 ;; line. This will only work if we properly mark the intervening text 270 ;; line. This will only work if we properly mark the intervening text
247 ;; as being part of a multiline element (and even then, this only 271 ;; as being part of a multiline element (and even then, this only
@@ -260,6 +284,8 @@
260 "\\)\\s-*:") 284 "\\)\\s-*:")
261 (1 (if (match-end 2) 'css-proprietary-property 'css-property))))) 285 (1 (if (match-end 2) 'css-proprietary-property 'css-property)))))
262 286
287(defvar css-font-lock-keywords (css--font-lock-keywords))
288
263(defvar css-font-lock-defaults 289(defvar css-font-lock-defaults
264 '(css-font-lock-keywords nil t)) 290 '(css-font-lock-keywords nil t))
265 291
@@ -277,6 +303,7 @@
277(defun css-smie--forward-token () 303(defun css-smie--forward-token ()
278 (cond 304 (cond
279 ((and (eq (char-before) ?\}) 305 ((and (eq (char-before) ?\})
306 (scss-smie--not-interpolation-p)
280 ;; FIXME: If the next char is not whitespace, what should we do? 307 ;; FIXME: If the next char is not whitespace, what should we do?
281 (or (memq (char-after) '(?\s ?\t ?\n)) 308 (or (memq (char-after) '(?\s ?\t ?\n))
282 (looking-at comment-start-skip))) 309 (looking-at comment-start-skip)))
@@ -293,7 +320,8 @@
293 (forward-comment (- (point))) 320 (forward-comment (- (point)))
294 (cond 321 (cond
295 ;; FIXME: If the next char is not whitespace, what should we do? 322 ;; FIXME: If the next char is not whitespace, what should we do?
296 ((and (eq (char-before) ?\}) (> pos (point))) ";") 323 ((and (eq (char-before) ?\}) (scss-smie--not-interpolation-p)
324 (> pos (point))) ";")
297 ((memq (char-before) '(?\; ?\, ?\:)) 325 ((memq (char-before) '(?\; ?\, ?\:))
298 (forward-char -1) (string (char-after))) 326 (forward-char -1) (string (char-after)))
299 (t (smie-default-backward-token))))) 327 (t (smie-default-backward-token)))))
@@ -315,7 +343,6 @@
315 (setq-local comment-end "*/") 343 (setq-local comment-end "*/")
316 (setq-local comment-end-skip "[ \t]*\\*+/") 344 (setq-local comment-end-skip "[ \t]*\\*+/")
317 (setq-local parse-sexp-ignore-comments t) 345 (setq-local parse-sexp-ignore-comments t)
318 (setq-local indent-line-function 'css-indent-line)
319 (setq-local fill-paragraph-function 'css-fill-paragraph) 346 (setq-local fill-paragraph-function 'css-fill-paragraph)
320 (setq-local add-log-current-defun-function #'css-current-defun-name) 347 (setq-local add-log-current-defun-function #'css-current-defun-name)
321 (smie-setup css-smie-grammar #'css-smie-rules 348 (smie-setup css-smie-grammar #'css-smie-rules
@@ -406,5 +433,35 @@
406 (if (looking-at "^[ \t]*\\([^{\r\n]*[^ {\t\r\n]\\)") 433 (if (looking-at "^[ \t]*\\([^{\r\n]*[^ {\t\r\n]\\)")
407 (match-string-no-properties 1)))))) 434 (match-string-no-properties 1))))))
408 435
436;;; SCSS mode
437
438(defvar scss-mode-syntax-table
439 (let ((st (make-syntax-table css-mode-syntax-table)))
440 (modify-syntax-entry ?/ ". 124" st)
441 (modify-syntax-entry ?\n ">" st)
442 st))
443
444(defvar scss-font-lock-keywords
445 (append `((,(concat "$" css-ident-re) (0 font-lock-variable-name-face)))
446 (css--font-lock-keywords 'sassy)
447 `((,(concat "@mixin[ \t]+\\(" css-ident-re "\\)[ \t]*(")
448 (1 font-lock-function-name-face)))))
449
450(defun scss-smie--not-interpolation-p ()
451 (save-excursion
452 (forward-char -1)
453 (or (zerop (skip-chars-backward "[:alnum:]"))
454 (not (looking-back "#{\\$" (- (point) 3))))))
455
456;;;###autoload (add-to-list 'auto-mode-alist '("\\.scss\\'" . scss-mode))
457;;;###autoload
458(define-derived-mode scss-mode css-mode "SCSS"
459 "Major mode to edit \"Sassy CSS\" files."
460 (setq-local comment-start "// ")
461 (setq-local comment-end "")
462 (setq-local comment-start-skip "/[*/]+[ t]*")
463 (setq-local comment-end-skip "[ \t]*\\(?:\n\\|\\*+/\\)")
464 (setq-local font-lock-defaults '(scss-font-lock-keywords nil t)))
465
409(provide 'css-mode) 466(provide 'css-mode)
410;;; css-mode.el ends here 467;;; css-mode.el ends here
diff --git a/test/ChangeLog b/test/ChangeLog
index ea11f9429f0..a5ac25a92a1 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,8 @@
12014-10-20 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * indent/scss-mode.scss: New file.
4 * indent/css-mode.css: Add a few uneventful examples.
5
12014-10-15 Eli Zaretskii <eliz@gnu.org> 62014-10-15 Eli Zaretskii <eliz@gnu.org>
2 7
3 * BidiCharacterTest.txt: New file, from Unicode. 8 * BidiCharacterTest.txt: New file, from Unicode.
@@ -28,8 +33,8 @@
28 33
292014-09-26 Leo Liu <sdl.web@gmail.com> 342014-09-26 Leo Liu <sdl.web@gmail.com>
30 35
31 * automated/cl-lib.el (cl-digit-char-p, cl-parse-integer): New 36 * automated/cl-lib.el (cl-digit-char-p, cl-parse-integer):
32 tests. (Bug#18557) 37 New tests. (Bug#18557)
33 38
342014-09-24 Ulf Jasper <ulf.jasper@web.de> 392014-09-24 Ulf Jasper <ulf.jasper@web.de>
35 40
@@ -39,8 +44,8 @@
39 44
402014-09-09 Eli Zaretskii <eliz@gnu.org> 452014-09-09 Eli Zaretskii <eliz@gnu.org>
41 46
42 * automated/fns-tests.el (fns-tests-collate-sort): Bind 47 * automated/fns-tests.el (fns-tests-collate-sort):
43 w32-collate-ignore-punctuation to t when sorting according to 48 Bind w32-collate-ignore-punctuation to t when sorting according to
44 UTS#10 rules. 49 UTS#10 rules.
45 50
462014-09-07 Michael Albinus <michael.albinus@gmx.de> 512014-09-07 Michael Albinus <michael.albinus@gmx.de>
@@ -555,8 +560,8 @@
555 560
556 * automated/subword-tests.el (subword-tests2): More subword tests. 561 * automated/subword-tests.el (subword-tests2): More subword tests.
557 562
558 * automated/cl-lib.el (cl-lib-keyword-names-versus-values): New 563 * automated/cl-lib.el (cl-lib-keyword-names-versus-values):
559 test: correct parsing of keyword arguments. 564 New test: correct parsing of keyword arguments.
560 565
5612014-03-22 Dmitry Gutov <dgutov@yandex.ru> 5662014-03-22 Dmitry Gutov <dgutov@yandex.ru>
562 567
@@ -651,8 +656,8 @@
651 656
6522014-02-17 Michael Albinus <michael.albinus@gmx.de> 6572014-02-17 Michael Albinus <michael.albinus@gmx.de>
653 658
654 * automated/tramp-tests.el (tramp-test28-shell-command): Perform 659 * automated/tramp-tests.el (tramp-test28-shell-command):
655 an initial `sit-for' prior the while loop. 660 Perform an initial `sit-for' prior the while loop.
656 661
6572014-02-16 Michael Albinus <michael.albinus@gmx.de> 6622014-02-16 Michael Albinus <michael.albinus@gmx.de>
658 663
@@ -674,8 +679,8 @@
674 679
675 * automated/tramp-tests.el (tramp-test26-process-file): Improve test. 680 * automated/tramp-tests.el (tramp-test26-process-file): Improve test.
676 (tramp-test27-start-file-process): Use "_p" as argument of lambda. 681 (tramp-test27-start-file-process): Use "_p" as argument of lambda.
677 (tramp-test28-shell-command): Improve `shell-command' test. Add 682 (tramp-test28-shell-command): Improve `shell-command' test.
678 `async-shell-command' tests. 683 Add `async-shell-command' tests.
679 684
6802014-02-04 Michael Albinus <michael.albinus@gmx.de> 6852014-02-04 Michael Albinus <michael.albinus@gmx.de>
681 686
@@ -731,8 +736,8 @@
731 736
7322014-01-13 Michael Albinus <michael.albinus@gmx.de> 7372014-01-13 Michael Albinus <michael.albinus@gmx.de>
733 738
734 * automated/ert-tests.el (ert-test-record-backtrace): Reenable 739 * automated/ert-tests.el (ert-test-record-backtrace):
735 test case with adapted test string. (Bug#13064) 740 Reenable test case with adapted test string. (Bug#13064)
736 741
7372013-12-28 Glenn Morris <rgm@gnu.org> 7422013-12-28 Glenn Morris <rgm@gnu.org>
738 743
diff --git a/test/indent/css-mode.css b/test/indent/css-mode.css
index 4dbab06975c..564ac16f954 100644
--- a/test/indent/css-mode.css
+++ b/test/indent/css-mode.css
@@ -1,7 +1,17 @@
1/* asdfasdf */
2
1.xxx 3.xxx
2{ 4{
3} 5}
4 6
7article[role="main"] {
8 width: 60%;
9}
10
11/* asdfasdf */
12@foo x2 {
13 bla:toto;
14}
5.x2 15.x2
6{ 16{
7 foo: bar; 17 foo: bar;
diff --git a/test/indent/scss-mode.scss b/test/indent/scss-mode.scss
new file mode 100644
index 00000000000..7a29929efca
--- /dev/null
+++ b/test/indent/scss-mode.scss
@@ -0,0 +1,57 @@
1// Comment!
2
3nav {
4 ul {
5 margin: 0; /* More comment */
6 padding: 0;
7 list-style: none;
8 }
9
10 li { display: inline-block; }
11
12 a {
13 display: block;
14 padding: 6px 12px;
15 text-decoration: none;
16 }
17}
18nav ul {
19 margin: 0;
20 padding: 0;
21 list-style: none;
22}
23
24nav li {
25 display: inline-block;
26}
27
28nav a var
29{
30 display: block;
31 padding: 6px 12px;
32 text-decoration: none;
33}
34
35$name: foo;
36$attr: border;
37p.#{$name} var
38{
39 x#{$attr}-color: blue;
40}
41article[role="main"] {
42 $toto: 500 !global;
43 float: left;
44 width: 600px / 888px * 100%;
45 height: 100px / 888px * 100%;
46}
47
48@import 'reset';
49
50@mixin border-radius($radius) {
51 -webkit-border-radius: $radius;
52 -moz-border-radius: $radius;
53 -ms-border-radius: $radius;
54 border-radius: $radius;
55}
56
57.box { @include border-radius(10px); }