]> git.eshelyaron.com Git - emacs.git/commitdiff
* lisp/textmodes/css-mode.el (scss-mode): New major-mode.
authorStefan Monnier <monnier@iro.umontreal.ca>
Mon, 20 Oct 2014 16:36:34 +0000 (12:36 -0400)
committerStefan Monnier <monnier@iro.umontreal.ca>
Mon, 20 Oct 2014 16:36:34 +0000 (12:36 -0400)
(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.

etc/NEWS
lisp/ChangeLog
lisp/textmodes/css-mode.el
test/ChangeLog
test/indent/css-mode.css
test/indent/scss-mode.scss [new file with mode: 0644]

index 91cad1315a67792d427d2be57477d83cba84bb59..e49fd748a90cd33a56070298680aa9f868e35eb1 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -273,6 +273,7 @@ These emulations of old editors are believed to be no longer relevant
 \f
 * New Modes and Packages in Emacs 25.1
 
+** scss-mode (a minor variant of css-mode)
 \f
 * Incompatible Lisp Changes in Emacs 25.1
 
index 3f75bbdc355cbd0d9415f0f51da8d173fdb80093..b27f8a0d17ec2fe441ebc4c71e07dacc63820cd2 100644 (file)
@@ -1,3 +1,12 @@
+2014-10-20  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * 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.
+
 2014-10-19  Ulf Jasper  <ulf.jasper@web.de>
 
        * net/newst-backend.el: Require url-parse.
@@ -26,8 +35,8 @@
        * net/newst-reader.el (newsticker-html-renderer): Whitespace.
        (newsticker--print-extra-elements)
        (newsticker--do-print-extra-element): Documentation
-       (newsticker--image-read): Optionally limit image height.  Use
-       imagemagick if possible.
+       (newsticker--image-read): Optionally limit image height.
+       Use imagemagick if possible.
        (newsticker--icon-read): New.
 
        * net/newst-treeview.el (newsticker--treeview-item-show): Limit height of feed logo.
index 1a07269c9e9144e90c2c5e3c0ac4318dde2011d7..175964392e940f83bfe8c31843d914c0a87dedb7 100644 (file)
   (let ((st (make-syntax-table)))
     ;; C-style comments.
     (modify-syntax-entry ?/ ". 14" st)
-    (modify-syntax-entry ?* ". 23" st)
+    (modify-syntax-entry ?* ". 23b" st)
     ;; Strings.
     (modify-syntax-entry ?\" "\"" st)
     (modify-syntax-entry ?\' "\"" st)
   "\\\\\\(?:[^\000-\037\177]\\|[0-9a-fA-F]+[ \n\t\r\f]?\\)")
 (defconst css-nmchar-re (concat "\\(?:[-[:alnum:]]\\|" css-escapes-re "\\)"))
 (defconst css-nmstart-re (concat "\\(?:[[:alpha:]]\\|" css-escapes-re "\\)"))
-(defconst css-ident-re (concat css-nmstart-re css-nmchar-re "*"))
+(defconst css-ident-re ;; (concat css-nmstart-re css-nmchar-re "*")
+  ;; Apparently, "at rules" names can start with a dash, e.g. @-moz-keyframes.
+  (concat css-nmchar-re "+"))
 (defconst css-proprietary-nmstart-re ;; Vendor-specific properties.
   (concat "[-_]" (regexp-opt '("ms" "moz" "o" "khtml" "webkit")) "-"))
 (defconst css-name-re (concat css-nmchar-re "+"))
 
+(defconst scss--hash-re "#\\(?:{[$-_[:alnum:]]+}\\|[[:alnum:]]+\\)")
+
 (defface css-selector '((t :inherit font-lock-function-name-face))
   "Face to use for selectors."
   :group 'css)
 (defface css-proprietary-property '((t :inherit (css-property italic)))
   "Face to use for vendor-specific properties.")
 
-(defvar css-font-lock-keywords
-  `(("!\\s-*important" . font-lock-builtin-face)
+(defun css--font-lock-keywords (&optional sassy)
+  `((,(concat "!\\s-*"
+              (regexp-opt (append (if sassy '("global"))
+                                  '("important"))))
+     (0 font-lock-builtin-face))
     ;; Atrules keywords.  IDs not in css-at-ids are valid (ignored).
     ;; In fact the regexp should probably be
     ;; (,(concat "\\(@" css-ident-re "\\)\\([ \t\n][^;{]*\\)[;{]")
     ;;  (1 font-lock-builtin-face))
     ;; Since "An at-rule consists of everything up to and including the next
     ;; semicolon (;) or the next block, whichever comes first."
-    (,(concat "@" css-ident-re) . font-lock-builtin-face)
+    (,(concat "@" css-ident-re) (0 font-lock-builtin-face))
     ;; Selectors.
     ;; FIXME: attribute selectors don't work well because they may contain
     ;; strings which have already been highlighted as f-l-string-face and
     ;; thus prevent this highlighting from being applied (actually now that
-    ;; I use `append' this should work better).  But really the part of the
+    ;; I use `keep' this should work better).  But really the part of the
     ;; selector between [...] should simply not be highlighted.
-    (,(concat "^\\([ \t]*[^@:{}\n][^:{}]+\\(?::" (regexp-opt css-pseudo-ids t)
-              "\\(?:([^)]+)\\)?[^:{\n]*\\)*\\)\\(?:\n[ \t]*\\)*{")
-     (1 'css-selector append))
+    (,(concat
+       "^[ \t]*\\("
+       (if (not sassy)
+           ;; We don't allow / as first char, so as not to
+           ;; take a comment as the beginning of a selector.
+           "[^@/:{} \t\n][^:{}]+"
+         ;; Same as for non-sassy except we do want to allow { and }
+         ;; chars in selectors in the case of #{$foo}
+         ;; variable interpolation!
+         (concat "\\(?:" scss--hash-re
+                 "\\|[^@/:{} \t\n#]\\)"
+                 "[^:{}#]*\\(?:" scss--hash-re "[^:{}#]*\\)*"))
+       "\\(?::" (regexp-opt css-pseudo-ids t)
+       "\\(?:([^\)]+)\\)?"
+       (if (not sassy)
+           "[^:{}\n]*"
+         (concat "[^:{}\n#]*\\(?:" scss--hash-re "[^:{}\n#]*\\)*"))
+       "\\)*"
+       "\\)\\(?:\n[ \t]*\\)*{")
+     (1 'css-selector keep))
     ;; In the above rule, we allow the open-brace to be on some subsequent
     ;; line.  This will only work if we properly mark the intervening text
     ;; as being part of a multiline element (and even then, this only
               "\\)\\s-*:")
      (1 (if (match-end 2) 'css-proprietary-property 'css-property)))))
 
+(defvar css-font-lock-keywords (css--font-lock-keywords))
+
 (defvar css-font-lock-defaults
   '(css-font-lock-keywords nil t))
 
 (defun css-smie--forward-token ()
   (cond
    ((and (eq (char-before) ?\})
+         (scss-smie--not-interpolation-p)
          ;; FIXME: If the next char is not whitespace, what should we do?
          (or (memq (char-after) '(?\s ?\t ?\n))
              (looking-at comment-start-skip)))
     (forward-comment (- (point)))
     (cond
      ;; FIXME: If the next char is not whitespace, what should we do?
-     ((and (eq (char-before) ?\}) (> pos (point))) ";")
+     ((and (eq (char-before) ?\}) (scss-smie--not-interpolation-p)
+           (> pos (point))) ";")
      ((memq (char-before) '(?\; ?\, ?\:))
       (forward-char -1) (string (char-after)))
      (t (smie-default-backward-token)))))
   (setq-local comment-end "*/")
   (setq-local comment-end-skip "[ \t]*\\*+/")
   (setq-local parse-sexp-ignore-comments t)
-  (setq-local indent-line-function 'css-indent-line)
   (setq-local fill-paragraph-function 'css-fill-paragraph)
   (setq-local add-log-current-defun-function #'css-current-defun-name)
   (smie-setup css-smie-grammar #'css-smie-rules
        (if (looking-at "^[ \t]*\\([^{\r\n]*[^ {\t\r\n]\\)")
            (match-string-no-properties 1))))))
 
+;;; SCSS mode
+
+(defvar scss-mode-syntax-table
+  (let ((st (make-syntax-table css-mode-syntax-table)))
+    (modify-syntax-entry ?/ ". 124" st)
+    (modify-syntax-entry ?\n ">" st)
+    st))
+
+(defvar scss-font-lock-keywords
+  (append `((,(concat "$" css-ident-re) (0 font-lock-variable-name-face)))
+          (css--font-lock-keywords 'sassy)
+          `((,(concat "@mixin[ \t]+\\(" css-ident-re "\\)[ \t]*(")
+             (1 font-lock-function-name-face)))))
+
+(defun scss-smie--not-interpolation-p ()
+  (save-excursion
+    (forward-char -1)
+    (or (zerop (skip-chars-backward "[:alnum:]"))
+        (not (looking-back "#{\\$" (- (point) 3))))))
+
+;;;###autoload (add-to-list 'auto-mode-alist '("\\.scss\\'" . scss-mode))
+;;;###autoload
+(define-derived-mode scss-mode css-mode "SCSS"
+  "Major mode to edit \"Sassy CSS\" files."
+  (setq-local comment-start "// ")
+  (setq-local comment-end "")
+  (setq-local comment-start-skip "/[*/]+[ t]*")
+  (setq-local comment-end-skip "[ \t]*\\(?:\n\\|\\*+/\\)")
+  (setq-local font-lock-defaults '(scss-font-lock-keywords nil t)))
+
 (provide 'css-mode)
 ;;; css-mode.el ends here
index ea11f9429f0186bcdf6826326dade37c5fa1208b..a5ac25a92a10ed77393b817c99deb946134331aa 100644 (file)
@@ -1,3 +1,8 @@
+2014-10-20  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * indent/scss-mode.scss: New file.
+       * indent/css-mode.css: Add a few uneventful examples.
+
 2014-10-15  Eli Zaretskii  <eliz@gnu.org>
 
        * BidiCharacterTest.txt: New file, from Unicode.
@@ -28,8 +33,8 @@
 
 2014-09-26  Leo Liu  <sdl.web@gmail.com>
 
-       * automated/cl-lib.el (cl-digit-char-p, cl-parse-integer): New
-       tests.  (Bug#18557)
+       * automated/cl-lib.el (cl-digit-char-p, cl-parse-integer):
+       New tests.  (Bug#18557)
 
 2014-09-24  Ulf Jasper  <ulf.jasper@web.de>
 
@@ -39,8 +44,8 @@
 
 2014-09-09  Eli Zaretskii  <eliz@gnu.org>
 
-       * automated/fns-tests.el (fns-tests-collate-sort): Bind
-       w32-collate-ignore-punctuation to t when sorting according to
+       * automated/fns-tests.el (fns-tests-collate-sort):
+       Bind w32-collate-ignore-punctuation to t when sorting according to
        UTS#10 rules.
 
 2014-09-07  Michael Albinus  <michael.albinus@gmx.de>
 
        * automated/subword-tests.el (subword-tests2): More subword tests.
 
-       * automated/cl-lib.el (cl-lib-keyword-names-versus-values): New
-       test: correct parsing of keyword arguments.
+       * automated/cl-lib.el (cl-lib-keyword-names-versus-values):
+       New test: correct parsing of keyword arguments.
 
 2014-03-22  Dmitry Gutov  <dgutov@yandex.ru>
 
 
 2014-02-17  Michael Albinus  <michael.albinus@gmx.de>
 
-       * automated/tramp-tests.el (tramp-test28-shell-command): Perform
-       an initial `sit-for' prior the while loop.
+       * automated/tramp-tests.el (tramp-test28-shell-command):
+       Perform an initial `sit-for' prior the while loop.
 
 2014-02-16  Michael Albinus  <michael.albinus@gmx.de>
 
 
        * automated/tramp-tests.el (tramp-test26-process-file): Improve test.
        (tramp-test27-start-file-process): Use "_p" as argument of lambda.
-       (tramp-test28-shell-command): Improve `shell-command' test.  Add
-       `async-shell-command' tests.
+       (tramp-test28-shell-command): Improve `shell-command' test.
+       Add `async-shell-command' tests.
 
 2014-02-04  Michael Albinus  <michael.albinus@gmx.de>
 
 
 2014-01-13  Michael Albinus  <michael.albinus@gmx.de>
 
-       * automated/ert-tests.el (ert-test-record-backtrace): Reenable
-       test case with adapted test string.  (Bug#13064)
+       * automated/ert-tests.el (ert-test-record-backtrace):
+       Reenable test case with adapted test string.  (Bug#13064)
 
 2013-12-28  Glenn Morris  <rgm@gnu.org>
 
index 4dbab06975c9630f9436f0f39a3eb2c9a7a1806b..564ac16f954ef22a1ca8acf911b6842e2c6276dc 100644 (file)
@@ -1,7 +1,17 @@
+/* asdfasdf */
+
 .xxx
 {
 }
 
+article[role="main"] {
+    width: 60%;
+}
+
+/* asdfasdf */
+@foo x2 {
+    bla:toto;
+}
 .x2
 {
     foo: bar;
diff --git a/test/indent/scss-mode.scss b/test/indent/scss-mode.scss
new file mode 100644 (file)
index 0000000..7a29929
--- /dev/null
@@ -0,0 +1,57 @@
+// Comment!
+
+nav {
+    ul {
+        margin: 0;              /* More comment */
+        padding: 0;
+        list-style: none;
+    }
+
+    li { display: inline-block; }
+
+    a {
+        display: block;
+        padding: 6px 12px;
+        text-decoration: none;
+    }
+}
+nav ul {
+  margin: 0;
+  padding: 0;
+  list-style: none;
+}
+
+nav li {
+  display: inline-block;
+}
+
+nav a var
+{
+  display: block;
+  padding: 6px 12px;
+  text-decoration: none;
+}
+
+$name: foo;
+$attr: border;
+p.#{$name} var
+{
+    x#{$attr}-color: blue;
+}
+article[role="main"] {
+    $toto: 500 !global;
+    float: left;
+    width: 600px / 888px * 100%;
+    height: 100px / 888px * 100%;
+}
+
+@import 'reset';
+
+@mixin border-radius($radius) {
+    -webkit-border-radius: $radius;
+    -moz-border-radius: $radius;
+    -ms-border-radius: $radius;
+    border-radius: $radius;
+}
+
+.box { @include border-radius(10px); }