diff options
| -rw-r--r-- | lisp/textmodes/css-mode.el | 44 | ||||
| -rw-r--r-- | test/manual/indent/css-mode.css | 27 | ||||
| -rw-r--r-- | test/manual/indent/scss-mode.scss | 18 |
3 files changed, 85 insertions, 4 deletions
diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el index 19f74daec63..65a599d6d43 100644 --- a/lisp/textmodes/css-mode.el +++ b/lisp/textmodes/css-mode.el | |||
| @@ -32,10 +32,11 @@ | |||
| 32 | 32 | ||
| 33 | ;;; Code: | 33 | ;;; Code: |
| 34 | 34 | ||
| 35 | (require 'eww) | ||
| 35 | (require 'seq) | 36 | (require 'seq) |
| 36 | (require 'sgml-mode) | 37 | (require 'sgml-mode) |
| 37 | (require 'smie) | 38 | (require 'smie) |
| 38 | (require 'eww) | 39 | (require 'subr-x) |
| 39 | 40 | ||
| 40 | (defgroup css nil | 41 | (defgroup css nil |
| 41 | "Cascading Style Sheets (CSS) editing mode." | 42 | "Cascading Style Sheets (CSS) editing mode." |
| @@ -741,7 +742,30 @@ cannot be completed sensibly: `custom-ident', | |||
| 741 | 742 | ||
| 742 | (defconst css-smie-grammar | 743 | (defconst css-smie-grammar |
| 743 | (smie-prec2->grammar | 744 | (smie-prec2->grammar |
| 744 | (smie-precs->prec2 '((assoc ";") (assoc ",") (left ":"))))) | 745 | (smie-precs->prec2 |
| 746 | '((assoc ";") | ||
| 747 | ;; Colons that belong to a CSS property. These get a higher | ||
| 748 | ;; precedence than other colons, such as colons in selectors, | ||
| 749 | ;; which are represented by a plain ":" token. | ||
| 750 | (left ":-property") | ||
| 751 | (assoc ",") | ||
| 752 | (assoc ":"))))) | ||
| 753 | |||
| 754 | (defun css--colon-inside-selector-p () | ||
| 755 | "Return t if point looks to be inside a CSS selector. | ||
| 756 | This function is intended to be good enough to help SMIE during | ||
| 757 | tokenization, but should not be regarded as a reliable function | ||
| 758 | for determining wheter point is within a selector." | ||
| 759 | (save-excursion | ||
| 760 | (re-search-forward "[{};)]" nil t) | ||
| 761 | (eq (char-before) ?\{))) | ||
| 762 | |||
| 763 | (defun css--colon-inside-funcall () | ||
| 764 | "Return t if point is inside a function call." | ||
| 765 | (when-let (opening-paren-pos (nth 1 (syntax-ppss))) | ||
| 766 | (save-excursion | ||
| 767 | (goto-char opening-paren-pos) | ||
| 768 | (eq (char-after) ?\()))) | ||
| 745 | 769 | ||
| 746 | (defun css-smie--forward-token () | 770 | (defun css-smie--forward-token () |
| 747 | (cond | 771 | (cond |
| @@ -755,7 +779,13 @@ cannot be completed sensibly: `custom-ident', | |||
| 755 | ";") | 779 | ";") |
| 756 | ((progn (forward-comment (point-max)) | 780 | ((progn (forward-comment (point-max)) |
| 757 | (looking-at "[;,:]")) | 781 | (looking-at "[;,:]")) |
| 758 | (forward-char 1) (match-string 0)) | 782 | (forward-char 1) |
| 783 | (if (equal (match-string 0) ":") | ||
| 784 | (if (or (css--colon-inside-selector-p) | ||
| 785 | (css--colon-inside-funcall)) | ||
| 786 | ":" | ||
| 787 | ":-property") | ||
| 788 | (match-string 0))) | ||
| 759 | (t (smie-default-forward-token)))) | 789 | (t (smie-default-forward-token)))) |
| 760 | 790 | ||
| 761 | (defun css-smie--backward-token () | 791 | (defun css-smie--backward-token () |
| @@ -766,7 +796,13 @@ cannot be completed sensibly: `custom-ident', | |||
| 766 | ((and (eq (char-before) ?\}) (scss-smie--not-interpolation-p) | 796 | ((and (eq (char-before) ?\}) (scss-smie--not-interpolation-p) |
| 767 | (> pos (point))) ";") | 797 | (> pos (point))) ";") |
| 768 | ((memq (char-before) '(?\; ?\, ?\:)) | 798 | ((memq (char-before) '(?\; ?\, ?\:)) |
| 769 | (forward-char -1) (string (char-after))) | 799 | (forward-char -1) |
| 800 | (if (eq (char-after) ?\:) | ||
| 801 | (if (or (css--colon-inside-selector-p) | ||
| 802 | (css--colon-inside-funcall)) | ||
| 803 | ":" | ||
| 804 | ":-property") | ||
| 805 | (string (char-after)))) | ||
| 770 | (t (smie-default-backward-token))))) | 806 | (t (smie-default-backward-token))))) |
| 771 | 807 | ||
| 772 | (defun css-smie-rules (kind token) | 808 | (defun css-smie-rules (kind token) |
diff --git a/test/manual/indent/css-mode.css b/test/manual/indent/css-mode.css index 3a00739bfc4..0845c02c299 100644 --- a/test/manual/indent/css-mode.css +++ b/test/manual/indent/css-mode.css | |||
| @@ -43,3 +43,30 @@ article:hover | |||
| 43 | { | 43 | { |
| 44 | color: black; | 44 | color: black; |
| 45 | } | 45 | } |
| 46 | |||
| 47 | /* bug:13425 */ | ||
| 48 | div:first-child, | ||
| 49 | div:last-child, | ||
| 50 | div[disabled], | ||
| 51 | div::before { | ||
| 52 | font: 15px "Helvetica Neue", | ||
| 53 | Helvetica, | ||
| 54 | Arial, | ||
| 55 | "Nimbus Sans L", | ||
| 56 | sans-serif; | ||
| 57 | font: 15px "Helvetica Neue", Helvetica, Arial, | ||
| 58 | "Nimbus Sans L", sans-serif; | ||
| 59 | transform: matrix(1.0, 2.0, | ||
| 60 | 3.0, 4.0, | ||
| 61 | 5.0, 6.0); | ||
| 62 | transform: matrix( | ||
| 63 | 1.0, 2.0, | ||
| 64 | 3.0, 4.0, | ||
| 65 | 5.0, 6.0 | ||
| 66 | ); | ||
| 67 | } | ||
| 68 | @font-face { | ||
| 69 | src: url("Sans-Regular.eot") format("eot"), | ||
| 70 | url("Sans-Regular.woff") format("woff"), | ||
| 71 | url("Sans-Regular.ttf") format("truetype"); | ||
| 72 | } | ||
diff --git a/test/manual/indent/scss-mode.scss b/test/manual/indent/scss-mode.scss index e1ec90a5299..d2a4f5cc1d1 100644 --- a/test/manual/indent/scss-mode.scss +++ b/test/manual/indent/scss-mode.scss | |||
| @@ -74,3 +74,21 @@ $list: ( | |||
| 74 | ('e', #000000, #fff) | 74 | ('e', #000000, #fff) |
| 75 | ('f', #000000, #fff) | 75 | ('f', #000000, #fff) |
| 76 | ); | 76 | ); |
| 77 | |||
| 78 | // bug:13425 | ||
| 79 | div:first-child, | ||
| 80 | div:last-child { | ||
| 81 | @include foo-mixin( | ||
| 82 | $foo: 'foo', | ||
| 83 | $bar: 'bar', | ||
| 84 | ); | ||
| 85 | |||
| 86 | font: 15px "Helvetica Neue", Helvetica, Arial, | ||
| 87 | "Nimbus Sans L", sans-serif; | ||
| 88 | |||
| 89 | div:first-child, | ||
| 90 | div:last-child { | ||
| 91 | font: 15px "Helvetica Neue", Helvetica, Arial, | ||
| 92 | "Nimbus Sans L", sans-serif; | ||
| 93 | } | ||
| 94 | } | ||