;;; css-mode.el --- Major mode to edit CSS files -*- lexical-binding: t -*-
-;; Copyright (C) 2006-2015 Free Software Foundation, Inc.
+;; Copyright (C) 2006-2016 Free Software Foundation, Inc.
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
;; Maintainer: Simen Heggestøyl <simenheg@gmail.com>
'("charset" "font-face" "import" "media" "namespace" "page")
"Identifiers that appear in the form @foo.")
+(defconst css-bang-ids
+ '("important")
+ "Identifiers that appear in the form !foo.")
+
+(defconst scss-bang-ids
+ '("default" "global" "optional")
+ "Additional identifiers that appear in the form !foo in SCSS.")
+
(defconst css-descriptor-ids
'("ascent" "baseline" "bbox" "cap-height" "centerline" "definition-src"
"descent" "font-family" "font-size" "font-stretch" "font-style"
"list-style" "list-style-image" "list-style-position"
"list-style-type" "margin" "margin-bottom" "margin-left"
"margin-right" "margin-top" "max-height" "max-width" "min-height"
- "min-width" "orphans" "overflow" "padding" "padding-bottom"
- "padding-left" "padding-right" "padding-top" "page-break-after"
+ "min-width" "padding" "padding-bottom" "padding-left"
+ "padding-right" "padding-top" "page-break-after"
"page-break-before" "page-break-inside" "pause" "pause-after"
"pause-before" "pitch" "pitch-range" "play-during" "position"
"quotes" "richness" "right" "speak" "speak-header" "speak-numeral"
"speak-punctuation" "speech-rate" "stress" "table-layout" "top"
"unicode-bidi" "vertical-align" "visibility" "voice-family" "volume"
- "widows" "width" "z-index"
+ "width" "z-index"
;; CSS Animations
;; (http://www.w3.org/TR/css3-animations/#property-index)
"font-variant-east-asian" "font-variant-ligatures"
"font-variant-numeric" "font-variant-position" "font-weight"
+ ;; CSS Fragmentation Module Level 3
+ ;; (https://www.w3.org/TR/css-break-3/#property-index)
+ "box-decoration-break" "break-after" "break-before" "break-inside"
+ "orphans" "widows"
+
+ ;; CSS Multi-column Layout Module
+ ;; (https://www.w3.org/TR/css3-multicol/#property-index)
+ ;; "break-after", "break-before", and "break-inside" are left out
+ ;; below, because they're already included in CSS Fragmentation
+ ;; Module Level 3.
+ "column-count" "column-fill" "column-gap" "column-rule"
+ "column-rule-color" "column-rule-style" "column-rule-width"
+ "column-span" "column-width" "columns"
+
+ ;; CSS Overflow Module Level 3
+ ;; (http://www.w3.org/TR/css-overflow-3/#property-index)
+ "max-lines" "overflow" "overflow-x" "overflow-y"
+
;; CSS Text Decoration Module Level 3
;; (http://dev.w3.org/csswg/css-text-decor-3/#property-index)
"text-decoration" "text-decoration-color" "text-decoration-line"
(modify-syntax-entry ?- "_" st)
st))
+(eval-and-compile
+ (defconst css--uri-re
+ (concat
+ "url\\((\\)[[:space:]]*\\(?:\\\\.\\|[^()[:space:]\n'\"]\\)+"
+ "[[:space:]]*\\()\\)")))
+
+(defconst css-syntax-propertize-function
+ (syntax-propertize-rules
+ (css--uri-re (1 "|") (2 "|"))))
+
(defconst css-escapes-re
"\\\\\\(?:[^\000-\037\177]\\|[0-9a-fA-F]+[ \n\t\r\f]?\\)")
(defconst css-nmchar-re (concat "\\(?:[-[:alnum:]]\\|" css-escapes-re "\\)"))
(defun css--font-lock-keywords (&optional sassy)
`((,(concat "!\\s-*"
- (regexp-opt (append (if sassy '("global"))
- '("important"))))
+ (regexp-opt (append (if sassy scss-bang-ids)
+ css-bang-ids)))
(0 font-lock-builtin-face))
;; Atrules keywords. IDs not in css-at-ids are valid (ignored).
;; In fact the regexp should probably be
;; 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) (0 font-lock-builtin-face))
+ ;; Variables.
+ (,(concat "--" css-ident-re) (0 font-lock-variable-name-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
(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][^:{}]+"
+ "[^@/:{}() \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 "[^:{}#]*\\)*"))
+ "\\|[^@/:{}() \t\n#]\\)"
+ "[^:{}()#]*\\(?:" scss--hash-re "[^:{}()#]*\\)*"))
;; Even though pseudo-elements should be prefixed by ::, a
;; single colon is accepted for backward compatibility.
"\\(?:\\(:" (regexp-opt (append css-pseudo-class-ids
css-pseudo-element-ids) t)
"\\|\\::" (regexp-opt css-pseudo-element-ids t) "\\)"
- "\\(?:([^\)]+)\\)?"
+ "\\(?:([^)]+)\\)?"
(if (not sassy)
- "[^:{}\n]*"
- (concat "[^:{}\n#]*\\(?:" scss--hash-re "[^:{}\n#]*\\)*"))
+ "[^:{}()\n]*"
+ (concat "[^:{}()\n#]*\\(?:" scss--hash-re "[^:{}()\n#]*\\)*"))
"\\)*"
"\\)\\(?:\n[ \t]*\\)*{")
(1 'css-selector keep))
"\\(?:\\(" css-proprietary-nmstart-re "\\)\\|"
css-nmstart-re "\\)" css-nmchar-re "*"
"\\)\\s-*:")
- (1 (if (match-end 2) 'css-proprietary-property 'css-property)))))
+ (1 (if (match-end 2) 'css-proprietary-property 'css-property)))
+ ;; Make sure the parens in a url(...) expression receive the
+ ;; default face. This is done because the parens may sometimes
+ ;; receive generic string delimiter syntax (see
+ ;; `css-syntax-propertize-function').
+ (,css--uri-re
+ (1 'default t) (2 'default t))))
(defvar css-font-lock-keywords (css--font-lock-keywords))
(defcustom css-indent-offset 4
"Basic size of one indentation step."
:version "22.2"
- :type 'integer)
+ :type 'integer
+ :safe 'integerp)
(require 'smie)
(`(:elem . arg) 0)
(`(:list-intro . ,(or `";" `"")) t) ;"" stands for BOB (bug#15467).
(`(:before . "{")
- (when (smie-rule-hanging-p)
+ (when (or (smie-rule-hanging-p) (smie-rule-bolp))
(smie-backward-sexp ";")
(smie-indent-virtual)))
(`(:before . ,(or "{" "("))
(setq-local comment-start-skip "/\\*+[ \t]*")
(setq-local comment-end "*/")
(setq-local comment-end-skip "[ \t]*\\*+/")
+ (setq-local syntax-propertize-function
+ css-syntax-propertize-function)
(setq-local fill-paragraph-function #'css-fill-paragraph)
(setq-local adaptive-fill-function #'css-adaptive-fill)
(setq-local add-log-current-defun-function #'css-current-defun-name)
(let ((st (make-syntax-table css-mode-syntax-table)))
(modify-syntax-entry ?/ ". 124" st)
(modify-syntax-entry ?\n ">" st)
+ ;; Variable names are prefixed by $.
+ (modify-syntax-entry ?$ "'" st)
st))
(defvar scss-font-lock-keywords